Skip to content

Commit 02142dc

Browse files
committed
build: switch to npm-based init checks and add npm and yarn version checking
1 parent b92f369 commit 02142dc

File tree

5 files changed

+95
-51
lines changed

5 files changed

+95
-51
lines changed

packages/release-cli/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
},
1616
"devDependencies": {
1717
"@types/prompts": "^2.4.9",
18+
"@types/semver": "^7",
1819
"typescript": "^5.7.3"
1920
},
2021
"dependencies": {
2122
"chalk": "^4",
2223
"glob": "^11.0.1",
2324
"prompts": "^2.4.2",
2425
"rimraf": "^6.0.1",
26+
"semver": "^7.7.3",
2527
"yargs": "^17.7.2"
2628
}
2729
}

packages/release-cli/src/npm_utils.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,30 @@ export const npmExecPublish = ({
5757
{ stdio: 'inherit', encoding: 'utf8' }
5858
);
5959
};
60+
61+
export const getNpmRegistryServer = async () => {
62+
const result = await execPromise('npm config get registry');
63+
const url = result.stdout.trim();
64+
65+
return {
66+
url,
67+
isOfficial: url === 'https://registry.npmjs.org/',
68+
};
69+
}
70+
71+
export const getNpmAuthenticatedUser = async () => {
72+
const result = await execPromise('npm whoami --json');
73+
const data = JSON.parse(result.stdout);
74+
75+
if (typeof data === 'string') {
76+
return data;
77+
}
78+
79+
return null;
80+
};
81+
82+
83+
export const getNpmVersion = async () => {
84+
const result = await execPromise('npm -v');
85+
return result.stdout.trim();
86+
};

packages/release-cli/src/steps/init_checks.ts

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import chalk from 'chalk';
1010
import prompts from 'prompts';
11+
import semver from 'semver';
1112

1213
import { ValidationError } from '../errors';
1314
import { type ReleaseOptions } from '../release';
@@ -18,7 +19,42 @@ import {
1819
getRemoteHeadCommitHash,
1920
isWorkingTreeClean,
2021
} from '../git_utils';
21-
import { getAuthenticatedUser, getYarnRegistryServer } from '../yarn_utils';
22+
import {
23+
getNpmAuthenticatedUser,
24+
getNpmRegistryServer,
25+
getNpmVersion,
26+
} from '../npm_utils';
27+
import { getYarnVersion } from '../yarn_utils';
28+
29+
const checkNpmYarnVersions = async (options: ReleaseOptions) => {
30+
const { logger } = options;
31+
32+
let npmVersion, yarnVersion;
33+
try {
34+
npmVersion = await getNpmVersion();
35+
} catch (err) {
36+
throw new ValidationError(
37+
'Unable to check npm version. Ensure `npm` is installed and available in PATH'
38+
);
39+
}
40+
41+
// npm v11.5.1 is required for trusted publishing
42+
if (semver.lt(npmVersion, '11.5.1')) {
43+
throw new ValidationError(
44+
'The version of npm installed on your system is lower than the required version. Please install npm v11.5.1 or newer.'
45+
);
46+
}
47+
48+
try {
49+
yarnVersion = await getYarnVersion();
50+
} catch (err) {
51+
throw new ValidationError(
52+
'Unable to check yarn version. Ensure `yarn` is installed and available in PATH'
53+
);
54+
}
55+
56+
logger.info(`Using npm v${npmVersion} and yarn v${yarnVersion}`);
57+
};
2258

2359
/**
2460
* Check current git branch, working tree status and more to ensure
@@ -40,7 +76,7 @@ export const stepInitChecks = async (options: ReleaseOptions) => {
4076
if (!(await isWorkingTreeClean())) {
4177
throw new ValidationError(
4278
'Git working tree is dirty. Please clean up your working tree' +
43-
' from any uncommited changes and try again.',
79+
' from any uncommited changes and try again.',
4480
`To clean local changes and restore the branch to remote state,` +
4581
` please run:\n ${chalk.yellowBright(
4682
`git reset --hard upstream/${currentBranch}`
@@ -75,14 +111,16 @@ export const stepInitChecks = async (options: ReleaseOptions) => {
75111
)}) on branch ${chalk.underline.bold(currentBranch)}`
76112
);
77113

114+
await checkNpmYarnVersions(options);
115+
78116
if (!options.skipAuthCheck) {
79-
const registryUser = await getAuthenticatedUser();
117+
const registryUser = await getNpmAuthenticatedUser();
80118
if (!registryUser) {
81119
throw new ValidationError(
82120
'Authentication to npmjs is required. Please log in before running' +
83121
' this command again.',
84122
`To authenticate run the following command:\n` +
85-
` ${chalk.yellowBright('yarn npm login')}`
123+
` ${chalk.yellowBright('npm login')}`
86124
);
87125
}
88126

@@ -91,11 +129,11 @@ export const stepInitChecks = async (options: ReleaseOptions) => {
91129
logger.info('Skipping the registry authentication check');
92130
}
93131

94-
const npmRegistry = await getYarnRegistryServer();
95-
if (npmRegistry) {
132+
const npmRegistry = await getNpmRegistryServer();
133+
if (!npmRegistry.isOfficial) {
96134
logger.warning(
97135
chalk.yellow(
98-
`A custom npm registry server (${npmRegistry}) will be used!`
136+
`A custom npm registry server (${npmRegistry.url}) will be used!`
99137
)
100138
);
101139
} else {

packages/release-cli/src/yarn_utils.ts

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -104,48 +104,7 @@ export const yarnPack = async (workspace: string)=> {
104104
return details;
105105
};
106106

107-
export const getAuthenticatedUser = async () => {
108-
try {
109-
const result = await execPromise('yarn npm whoami');
110-
// npmjs usernames can only contain alphanumeric characters and hypens
111-
const [_, username] = result.stdout.split('\n')[0].split(': ');
112-
113-
// yarn npm whoami can return `undefined` in certain cases
114-
if (!username || username === 'undefined') {
115-
return null;
116-
}
117-
118-
return username;
119-
} catch (err) {
120-
return null;
121-
}
122-
};
123-
124-
export const getYarnRegistryServer = async () => {
125-
// Yarn supports scoped and non-scoped/global settings.
126-
// We must check both to ensure we get the correct value
127-
128-
const getOutput = async (cmd: string) => {
129-
const result = await execPromise(cmd);
130-
const rawOutput = result.stdout.trim();
131-
if (rawOutput === 'undefined') {
132-
return null;
133-
}
134-
135-
const output = JSON.parse(rawOutput);
136-
if (!output || output === '') {
137-
return null;
138-
}
139-
140-
return output;
141-
}
142-
143-
const scopedOutput = await getOutput(`yarn config get 'npmScopes["elastic"].npmRegistryServer' --json`);
144-
if (scopedOutput !== null) {
145-
return scopedOutput;
146-
}
147-
148-
// return await to keep the rejection behavior the same
149-
// for both getOutput calls
150-
return await getOutput('yarn config get npmRegistryServer --json');
107+
export const getYarnVersion = async () => {
108+
const result = await execPromise('yarn -v');
109+
return result.stdout.trim();
151110
};

yarn.lock

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7158,10 +7158,12 @@ __metadata:
71587158
resolution: "@elastic/eui-release-cli@workspace:packages/release-cli"
71597159
dependencies:
71607160
"@types/prompts": "npm:^2.4.9"
7161+
"@types/semver": "npm:^7"
71617162
chalk: "npm:^4"
71627163
glob: "npm:^11.0.1"
71637164
prompts: "npm:^2.4.2"
71647165
rimraf: "npm:^6.0.1"
7166+
semver: "npm:^7.7.3"
71657167
typescript: "npm:^5.7.3"
71667168
yargs: "npm:^17.7.2"
71677169
languageName: unknown
@@ -11546,6 +11548,13 @@ __metadata:
1154611548
languageName: node
1154711549
linkType: hard
1154811550

11551+
"@types/semver@npm:^7":
11552+
version: 7.7.1
11553+
resolution: "@types/semver@npm:7.7.1"
11554+
checksum: 10c0/c938aef3bf79a73f0f3f6037c16e2e759ff40c54122ddf0b2583703393d8d3127130823facb880e694caa324eb6845628186aac1997ee8b31dc2d18fafe26268
11555+
languageName: node
11556+
linkType: hard
11557+
1154911558
"@types/semver@npm:^7.1.0, @types/semver@npm:^7.5.0":
1155011559
version: 7.5.8
1155111560
resolution: "@types/semver@npm:7.5.8"
@@ -36865,6 +36874,15 @@ __metadata:
3686536874
languageName: node
3686636875
linkType: hard
3686736876

36877+
"semver@npm:^7.7.3":
36878+
version: 7.7.3
36879+
resolution: "semver@npm:7.7.3"
36880+
bin:
36881+
semver: bin/semver.js
36882+
checksum: 10c0/4afe5c986567db82f44c8c6faef8fe9df2a9b1d98098fc1721f57c696c4c21cebd572f297fc21002f81889492345b8470473bc6f4aff5fb032a6ea59ea2bc45e
36883+
languageName: node
36884+
linkType: hard
36885+
3686836886
"send@npm:0.18.0":
3686936887
version: 0.18.0
3687036888
resolution: "send@npm:0.18.0"

0 commit comments

Comments
 (0)