Skip to content

Commit 1ae8f4b

Browse files
Implement "check-latest" flag to check if pre-cached version is latest one (#165)
1 parent 0e2f9cd commit 1ae8f4b

File tree

8 files changed

+325
-53
lines changed

8 files changed

+325
-53
lines changed

Diff for: .github/workflows/build-test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
runs-on: ${{ matrix.operating-system }}
1717
strategy:
1818
matrix:
19-
operating-system: [ubuntu-latest, windows-latest]
19+
operating-system: [ubuntu-latest, windows-latest, macos-latest]
2020
steps:
2121
- uses: actions/checkout@v2
2222
- name: Setup node 12

Diff for: .github/workflows/versions.yml

+70-18
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,88 @@ on:
1212
- '**.md'
1313

1414
jobs:
15-
versions:
15+
local-cache:
1616
runs-on: ${{ matrix.operating-system }}
1717
strategy:
1818
fail-fast: false
1919
matrix:
20-
operating-system: [ubuntu-latest, windows-latest]
21-
defaults:
22-
run:
20+
operating-system: [ubuntu-latest, windows-latest, macos-latest]
21+
node-version: [10, 12, 14]
22+
steps:
23+
- uses: actions/checkout@v2
24+
- name: Setup Node
25+
uses: ./
26+
with:
27+
node-version: ${{ matrix.node-version }}
28+
- name: Verify node and npm
29+
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
2330
shell: bash
31+
32+
manifest:
33+
runs-on: ${{ matrix.operating-system }}
34+
strategy:
35+
fail-fast: false
36+
matrix:
37+
operating-system: [ubuntu-latest, windows-latest, macos-latest]
38+
node-version: [10.15, 12.16.0, 14.2.0]
2439
steps:
2540
- uses: actions/checkout@v2
26-
# test version that falls through to node dist
27-
- name: Setup node 11 from dist
41+
- name: Setup Node
2842
uses: ./
2943
with:
30-
node-version: 11
44+
node-version: ${{ matrix.node-version }}
3145
- name: Verify node and npm
32-
run: __tests__/verify-node.sh 11
33-
# test old versions which didn't have npm and layout different
34-
- name: Setup node 0.12.18 from dist
35-
uses: ./
46+
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
47+
shell: bash
48+
49+
check-latest:
50+
runs-on: ${{ matrix.operating-system }}
51+
strategy:
52+
fail-fast: false
53+
matrix:
54+
operating-system: [ubuntu-latest, windows-latest, macos-latest]
55+
node-version: [10, 11, 12, 14]
56+
steps:
57+
- uses: actions/checkout@v2
58+
- name: Setup Node and check latest
59+
uses: ./
3660
with:
37-
node-version: 0.12.18
38-
- name: Verify node
61+
node-version: ${{ matrix.node-version }}
62+
check-latest: true
63+
- name: Verify node and npm
64+
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
3965
shell: bash
40-
run: __tests__/verify-node.sh 0.12.18 SKIP_NPM
41-
# test version from node manifest
42-
- name: Setup node 12.16.2 from manifest
66+
67+
node-dist:
68+
runs-on: ${{ matrix.operating-system }}
69+
strategy:
70+
fail-fast: false
71+
matrix:
72+
operating-system: [ubuntu-latest, windows-latest, macos-latest]
73+
node-version: [11, 13]
74+
steps:
75+
- uses: actions/checkout@v2
76+
- name: Setup Node from dist
4377
uses: ./
4478
with:
45-
node-version: 12.16.2
79+
node-version: ${{ matrix.node-version }}
4680
- name: Verify node and npm
47-
run: __tests__/verify-node.sh 12
81+
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
82+
shell: bash
83+
84+
old-versions:
85+
runs-on: ${{ matrix.operating-system }}
86+
strategy:
87+
fail-fast: false
88+
matrix:
89+
operating-system: [ubuntu-latest, windows-latest, macos-latest]
90+
steps:
91+
- uses: actions/checkout@v2
92+
# test old versions which didn't have npm and layout different
93+
- name: Setup node 0.12.18 from dist
94+
uses: ./
95+
with:
96+
node-version: 0.12.18
97+
- name: Verify node
98+
run: __tests__/verify-node.sh 0.12.18 SKIP_NPM
99+
shell: bash

Diff for: README.md

+14
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,20 @@ steps:
4141
- run: npm test
4242
```
4343

44+
Check latest version:
45+
> In basic example, without `check-latest` flag, the action tries to resolve version from local cache firstly and download only if it is not found. Local cache on image is updated with a couple of weeks latency.
46+
`check-latest` flag forces the action to check if the cached version is the latest one. It reduces latency significantly but it is much more likely to incur version downloading.
47+
```yaml
48+
steps:
49+
- uses: actions/checkout@v2
50+
- uses: actions/setup-node@v2
51+
with:
52+
node-version: '12'
53+
check-latest: true
54+
- run: npm install
55+
- run: npm test
56+
```
57+
4458
Matrix Testing:
4559
```yaml
4660
jobs:

Diff for: __tests__/installer.test.ts

+154-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import path from 'path';
88
import * as main from '../src/main';
99
import * as im from '../src/installer';
1010
import * as auth from '../src/authutil';
11+
import {context} from '@actions/github';
1112

1213
let nodeTestManifest = require('./data/versions-manifest.json');
1314
let nodeTestDist = require('./data/node-dist-index.json');
@@ -24,6 +25,7 @@ describe('setup-node', () => {
2425
let findSpy: jest.SpyInstance;
2526
let cnSpy: jest.SpyInstance;
2627
let logSpy: jest.SpyInstance;
28+
let warningSpy: jest.SpyInstance;
2729
let getManifestSpy: jest.SpyInstance;
2830
let getDistSpy: jest.SpyInstance;
2931
let platSpy: jest.SpyInstance;
@@ -77,8 +79,9 @@ describe('setup-node', () => {
7779

7880
// writes
7981
cnSpy = jest.spyOn(process.stdout, 'write');
80-
logSpy = jest.spyOn(console, 'log');
82+
logSpy = jest.spyOn(core, 'info');
8183
dbgSpy = jest.spyOn(core, 'debug');
84+
warningSpy = jest.spyOn(core, 'warning');
8285
cnSpy.mockImplementation(line => {
8386
// uncomment to debug
8487
// process.stderr.write('write:' + line + '\n');
@@ -333,4 +336,154 @@ describe('setup-node', () => {
333336

334337
expect(cnSpy).toHaveBeenCalledWith(`::error::${errMsg}${osm.EOL}`);
335338
});
339+
340+
describe('check-latest flag', () => {
341+
it('use local version and dont check manifest if check-latest is not specified', async () => {
342+
os.platform = 'linux';
343+
os.arch = 'x64';
344+
345+
inputs['node-version'] = '12';
346+
inputs['check-latest'] = 'false';
347+
348+
const toolPath = path.normalize('/cache/node/12.16.1/x64');
349+
findSpy.mockReturnValue(toolPath);
350+
await main.run();
351+
352+
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
353+
expect(logSpy).not.toHaveBeenCalledWith(
354+
'Attempt to resolve the latest version from manifest...'
355+
);
356+
});
357+
358+
it('check latest version and resolve it from local cache', async () => {
359+
os.platform = 'linux';
360+
os.arch = 'x64';
361+
362+
inputs['node-version'] = '12';
363+
inputs['check-latest'] = 'true';
364+
365+
const toolPath = path.normalize('/cache/node/12.16.2/x64');
366+
findSpy.mockReturnValue(toolPath);
367+
dlSpy.mockImplementation(async () => '/some/temp/path');
368+
exSpy.mockImplementation(async () => '/some/other/temp/path');
369+
cacheSpy.mockImplementation(async () => toolPath);
370+
371+
await main.run();
372+
373+
expect(logSpy).toHaveBeenCalledWith(
374+
'Attempt to resolve the latest version from manifest...'
375+
);
376+
expect(logSpy).toHaveBeenCalledWith("Resolved as '12.16.2'");
377+
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
378+
});
379+
380+
it('check latest version and install it from manifest', async () => {
381+
os.platform = 'linux';
382+
os.arch = 'x64';
383+
384+
inputs['node-version'] = '12';
385+
inputs['check-latest'] = 'true';
386+
387+
findSpy.mockImplementation(() => '');
388+
dlSpy.mockImplementation(async () => '/some/temp/path');
389+
const toolPath = path.normalize('/cache/node/12.16.2/x64');
390+
exSpy.mockImplementation(async () => '/some/other/temp/path');
391+
cacheSpy.mockImplementation(async () => toolPath);
392+
const expectedUrl =
393+
'https://github.com/actions/node-versions/releases/download/12.16.2-20200423.28/node-12.16.2-linux-x64.tar.gz';
394+
395+
await main.run();
396+
397+
expect(logSpy).toHaveBeenCalledWith(
398+
'Attempt to resolve the latest version from manifest...'
399+
);
400+
expect(logSpy).toHaveBeenCalledWith("Resolved as '12.16.2'");
401+
expect(logSpy).toHaveBeenCalledWith(
402+
`Acquiring 12.16.2 from ${expectedUrl}`
403+
);
404+
expect(logSpy).toHaveBeenCalledWith('Extracting ...');
405+
});
406+
407+
it('fallback to dist if version if not found in manifest', async () => {
408+
os.platform = 'linux';
409+
os.arch = 'x64';
410+
411+
// a version which is not in the manifest but is in node dist
412+
let versionSpec = '11';
413+
414+
inputs['node-version'] = versionSpec;
415+
inputs['check-latest'] = 'true';
416+
inputs['always-auth'] = false;
417+
inputs['token'] = 'faketoken';
418+
419+
// ... but not in the local cache
420+
findSpy.mockImplementation(() => '');
421+
422+
dlSpy.mockImplementation(async () => '/some/temp/path');
423+
let toolPath = path.normalize('/cache/node/11.11.0/x64');
424+
exSpy.mockImplementation(async () => '/some/other/temp/path');
425+
cacheSpy.mockImplementation(async () => toolPath);
426+
427+
await main.run();
428+
429+
let expPath = path.join(toolPath, 'bin');
430+
431+
expect(dlSpy).toHaveBeenCalled();
432+
expect(exSpy).toHaveBeenCalled();
433+
expect(logSpy).toHaveBeenCalledWith(
434+
'Attempt to resolve the latest version from manifest...'
435+
);
436+
expect(logSpy).toHaveBeenCalledWith(
437+
`Failed to resolve version ${versionSpec} from manifest`
438+
);
439+
expect(logSpy).toHaveBeenCalledWith(
440+
`Attempting to download ${versionSpec}...`
441+
);
442+
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
443+
});
444+
445+
it('fallback to dist if manifest is not available', async () => {
446+
os.platform = 'linux';
447+
os.arch = 'x64';
448+
449+
// a version which is not in the manifest but is in node dist
450+
let versionSpec = '12';
451+
452+
inputs['node-version'] = versionSpec;
453+
inputs['check-latest'] = 'true';
454+
inputs['always-auth'] = false;
455+
inputs['token'] = 'faketoken';
456+
457+
// ... but not in the local cache
458+
findSpy.mockImplementation(() => '');
459+
getManifestSpy.mockImplementation(() => {
460+
throw new Error('Unable to download manifest');
461+
});
462+
463+
dlSpy.mockImplementation(async () => '/some/temp/path');
464+
let toolPath = path.normalize('/cache/node/12.11.0/x64');
465+
exSpy.mockImplementation(async () => '/some/other/temp/path');
466+
cacheSpy.mockImplementation(async () => toolPath);
467+
468+
await main.run();
469+
470+
let expPath = path.join(toolPath, 'bin');
471+
472+
expect(dlSpy).toHaveBeenCalled();
473+
expect(exSpy).toHaveBeenCalled();
474+
expect(logSpy).toHaveBeenCalledWith(
475+
'Attempt to resolve the latest version from manifest...'
476+
);
477+
expect(logSpy).toHaveBeenCalledWith(
478+
'Unable to resolve version from manifest...'
479+
);
480+
expect(logSpy).toHaveBeenCalledWith(
481+
`Failed to resolve version ${versionSpec} from manifest`
482+
);
483+
expect(logSpy).toHaveBeenCalledWith(
484+
`Attempting to download ${versionSpec}...`
485+
);
486+
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
487+
});
488+
});
336489
});

Diff for: action.yml

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ inputs:
77
default: 'false'
88
node-version:
99
description: 'Version Spec of the version to use. Examples: 12.x, 10.15.1, >=10.15.0'
10+
check-latest:
11+
description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec'
12+
default: false
1013
registry-url:
1114
description: 'Optional registry to set up for auth. Will set the registry in a project level .npmrc and .yarnrc file, and set up auth to read in from env.NODE_AUTH_TOKEN'
1215
scope:

0 commit comments

Comments
 (0)