Skip to content

Commit 9b008f6

Browse files
authored
Publish with NPM 11 (#47)
1 parent 55a2361 commit 9b008f6

4 files changed

Lines changed: 115 additions & 6 deletions

File tree

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "skyux-sdk-actions",
3-
"version": "1.1.0",
3+
"version": "1.1.1",
44
"description": "GitHub actions for SKY UX libraries.",
55
"main": "lib/main.js",
66
"scripts": {

src/utility/npm-publish.spec.ts

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ describe('npmPublish', () => {
6060
notifySlack: slackSpy,
6161
});
6262

63-
spawnSpy = jasmine.createSpy('spawn');
63+
spawnSpy = jasmine.createSpy('spawn').and.returnValue(Promise.resolve(''));
6464

6565
mock('./spawn', {
6666
spawn: spawnSpy,
@@ -113,7 +113,9 @@ describe('npmPublish', () => {
113113
it('should publish to NPM without npm-token', async () => {
114114
mockNpmToken = '';
115115

116-
const { npmPublish } = getUtil();
116+
const { npmPublish, nodeVersionGetter } = getUtil();
117+
118+
spyOn(nodeVersionGetter, 'getVersion').and.returnValue('v24.0.0');
117119

118120
await npmPublish();
119121

@@ -216,4 +218,89 @@ describe('npmPublish', () => {
216218
'Aborted publishing to NPM because the version listed in package.json (1.0.0) does not match the git tag (1.1.0)!',
217219
);
218220
});
221+
222+
it('should use npm from Node.js 24 when current Node version is below 24 and no token is provided', async () => {
223+
mockNpmToken = '';
224+
225+
const { npmPublish, nodeVersionGetter } = getUtil();
226+
227+
spyOn(nodeVersionGetter, 'getVersion').and.returnValue('v20.0.0');
228+
229+
spawnSpy.and.callFake((command: string, _args: string[]) => {
230+
if (command === 'sh') {
231+
return Promise.resolve('/mock/nvm/versions/node/v24.0.0/bin/npm');
232+
}
233+
return Promise.resolve();
234+
});
235+
236+
await npmPublish();
237+
238+
expect(spawnSpy).toHaveBeenCalledWith('sh', [
239+
'-c',
240+
'ls $NVM_DIR/versions/node/v24.*/bin/npm',
241+
]);
242+
expect(spawnSpy).toHaveBeenCalledWith(
243+
'/mock/nvm/versions/node/v24.0.0/bin/npm',
244+
['publish', '--access', 'public', '--tag', 'latest'],
245+
{
246+
cwd: path.join(process.cwd(), 'MOCK_WORKING_DIRECTORY', 'dist'),
247+
stdio: 'inherit',
248+
},
249+
);
250+
});
251+
252+
it('should fail if Node.js 24 is not available when current Node version is below 24 and no token is provided', async () => {
253+
mockNpmToken = '';
254+
255+
const { npmPublish, nodeVersionGetter } = getUtil();
256+
257+
spyOn(nodeVersionGetter, 'getVersion').and.returnValue('v20.0.0');
258+
259+
await expectAsync(npmPublish()).toBeRejectedWith(
260+
'Aborted publishing to NPM with trusted publishing because NPM from Node.js 24 could not be found!',
261+
);
262+
263+
expect(spawnSpy).toHaveBeenCalledWith('sh', [
264+
'-c',
265+
'ls $NVM_DIR/versions/node/v24.*/bin/npm',
266+
]);
267+
});
268+
269+
it('should use regular npm when Node version is 24 or above and no token is provided', async () => {
270+
mockNpmToken = '';
271+
272+
const { npmPublish, nodeVersionGetter } = getUtil();
273+
274+
spyOn(nodeVersionGetter, 'getVersion').and.returnValue('v24.0.0');
275+
276+
await npmPublish();
277+
278+
expect(spawnSpy).toHaveBeenCalledWith(
279+
'npm',
280+
['publish', '--access', 'public', '--tag', 'latest'],
281+
{
282+
cwd: path.join(process.cwd(), 'MOCK_WORKING_DIRECTORY', 'dist'),
283+
stdio: 'inherit',
284+
},
285+
);
286+
expect(spawnSpy).not.toHaveBeenCalledWith('ls', jasmine.any(Array));
287+
});
288+
289+
it('should use regular npm when token is provided regardless of Node version', async () => {
290+
const { npmPublish, nodeVersionGetter } = getUtil();
291+
292+
spyOn(nodeVersionGetter, 'getVersion').and.returnValue('v20.0.0');
293+
294+
await npmPublish();
295+
296+
expect(spawnSpy).toHaveBeenCalledWith(
297+
'npm',
298+
['publish', '--access', 'public', '--tag', 'latest'],
299+
{
300+
cwd: path.join(process.cwd(), 'MOCK_WORKING_DIRECTORY', 'dist'),
301+
stdio: 'inherit',
302+
},
303+
);
304+
expect(spawnSpy).not.toHaveBeenCalledWith('ls', jasmine.any(Array));
305+
});
219306
});

src/utility/npm-publish.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@ import * as core from '@actions/core';
22

33
import * as fs from 'fs-extra';
44
import * as path from 'path';
5+
import * as semver from 'semver';
56

67
import { getTag } from './context';
78
import { notifySlack } from './notify-slack';
89
import { PackageMetadata } from './package-metadata';
910
import { spawn } from './spawn';
1011

12+
// Export for testing purposes
13+
/* istanbul ignore next */
14+
export const nodeVersionGetter = {
15+
getVersion: () => process.version,
16+
};
17+
1118
export async function npmPublish(distPath?: string): Promise<PackageMetadata> {
1219
distPath =
1320
distPath ||
@@ -37,12 +44,27 @@ export async function npmPublish(distPath?: string): Promise<PackageMetadata> {
3744
`Preparing to publish ${packageName}@${version} to NPM from ${distPath}...`,
3845
);
3946

47+
let npmCommand: string | undefined = 'npm';
4048
if (npmToken) {
4149
await fs.ensureFile(npmFilePath);
4250
fs.writeFileSync(
4351
npmFilePath,
4452
`//registry.npmjs.org/:_authToken=${npmToken}`,
4553
);
54+
} else if (semver.lt(nodeVersionGetter.getVersion(), '24.0.0')) {
55+
// Use npm from Node.js 24 if no token is provided to use NPM 11 and trusted publishing.
56+
npmCommand = await spawn('sh', [
57+
'-c',
58+
'ls $NVM_DIR/versions/node/v24.*/bin/npm',
59+
]).then((result) => result?.trim().split('\n').shift());
60+
if (!npmCommand) {
61+
core.setFailed(
62+
'Aborted publishing to NPM with trusted publishing because NPM from Node.js 24 could not be found!',
63+
);
64+
return Promise.reject(
65+
'Aborted publishing to NPM with trusted publishing because NPM from Node.js 24 could not be found!',
66+
);
67+
}
4668
}
4769

4870
const npmArgs = ['publish', '--access', 'public', '--tag', npmTag];
@@ -54,7 +76,7 @@ export async function npmPublish(distPath?: string): Promise<PackageMetadata> {
5476
}
5577

5678
try {
57-
await spawn('npm', npmArgs, {
79+
await spawn(npmCommand, npmArgs, {
5880
cwd: distPath,
5981
stdio: 'inherit',
6082
});

0 commit comments

Comments
 (0)