Merge branch 'main' into v-dmshib/update-ncc

This commit is contained in:
Dmitry Shibanov 2022-05-30 10:50:44 +02:00
commit dfb8fe134b
5 changed files with 213 additions and 84 deletions

View file

@ -139,3 +139,34 @@ jobs:
- name: Verify node - name: Verify node
run: __tests__/verify-arch.sh "ia32" run: __tests__/verify-arch.sh "ia32"
shell: bash shell: bash
node-latest-aliases:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [current, latest, node]
steps:
- name: Get node version
run: |
latestNodeVersion=$(curl https://nodejs.org/dist/index.json | jq -r '. [0].version')
echo "::set-output name=LATEST_NODE_VERSION::$latestNodeVersion"
id: version
shell: bash
- uses: actions/checkout@v3
- name: Setup Node
uses: ./
with:
node-version: ${{ matrix.node-version }}
- name: Retrieve version after install
run: |
updatedVersion=$(echo $(node --version))
echo "::set-output name=NODE_VERSION_UPDATED::$updatedVersion"
id: updatedVersion
shell: bash
- name: Compare versions
if: ${{ steps.version.outputs.LATEST_NODE_VERSION != steps.updatedVersion.outputs.NODE_VERSION_UPDATED}}
run: |
echo "Latest node version failed to download."
exit 1

View file

@ -11,7 +11,7 @@ This action provides the following functionality for GitHub Actions users:
- Registering problem matchers for error output - Registering problem matchers for error output
- Configuring authentication for GPR or npm - Configuring authentication for GPR or npm
# Usage ## Usage
See [action.yml](action.yml) See [action.yml](action.yml)
@ -22,8 +22,8 @@ steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: '14' node-version: 14
- run: npm install - run: npm ci
- run: npm test - run: npm test
``` ```
@ -33,13 +33,20 @@ The action will first check the local cache for a semver match. If unable to fin
For information regarding locally cached versions of Node.js on GitHub hosted runners, check out [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments). For information regarding locally cached versions of Node.js on GitHub hosted runners, check out [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments).
#### Supported version syntax ### Supported version syntax
The `node-version` input supports the following syntax: The `node-version` input supports the following values:
major versions: `12`, `14`, `16` - Major versions: `12`, `14`, `16`
more specific versions: `10.15`, `14.2.0`, `16.3.0` - More specific versions: `10.15`, `14.2.0`, `16.3.0`
nvm lts syntax: `lts/erbium`, `lts/fermium`, `lts/*` - NVM LTS syntax: `lts/erbium`, `lts/fermium`, `lts/*`
- Latest release: `latest`/`current`/`node`
**Note:** Since the latest release will not be cached always, there is possibility of hitting rate limit when downloading from dist
### Checking in lockfiles
It's **always** recommended to commit the lockfile of your package manager for security and performance reasons. For more information consult the "Working with lockfiles" section of the [Advanced usage](docs/advanced-usage.md#working-with-lockfiles) guide.
## Caching global packages data ## Caching global packages data
@ -58,9 +65,9 @@ steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: '14' node-version: 14
cache: 'npm' cache: 'npm'
- run: npm install - run: npm ci
- run: npm test - run: npm test
``` ```
@ -71,14 +78,14 @@ steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: '14' node-version: 14
cache: 'npm' cache: 'npm'
cache-dependency-path: subdir/package-lock.json cache-dependency-path: subdir/package-lock.json
- run: npm install - run: npm ci
- run: npm test - run: npm test
``` ```
## Matrix Testing: ## Matrix Testing
```yaml ```yaml
jobs: jobs:
@ -86,7 +93,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node: [ '12', '14', '16' ] node: [ 12, 14, 16 ]
name: Node ${{ matrix.node }} sample name: Node ${{ matrix.node }} sample
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@ -94,7 +101,7 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: ${{ matrix.node }} node-version: ${{ matrix.node }}
- run: npm install - run: npm ci
- run: npm test - run: npm test
``` ```
@ -109,11 +116,11 @@ jobs:
7. [Publishing to npmjs and GPR with yarn](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-yarn) 7. [Publishing to npmjs and GPR with yarn](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-yarn)
8. [Using private packages](docs/advanced-usage.md#use-private-packages) 8. [Using private packages](docs/advanced-usage.md#use-private-packages)
# License ## License
The scripts and documentation in this project are released under the [MIT License](LICENSE) The scripts and documentation in this project are released under the [MIT License](LICENSE)
# Contributions ## Contributions
Contributions are welcome! See [Contributor's Guide](docs/contributors.md) Contributions are welcome! See [Contributor's Guide](docs/contributors.md)

View file

@ -135,8 +135,15 @@ describe('setup-node', () => {
expect(versions?.length).toBe(23); expect(versions?.length).toBe(23);
}); });
it('can find 12.16.2 from manifest on osx', async () => { it.each([
os.platform = 'darwin'; ['12.16.2', 'darwin', '12.16.2', 'Erbium'],
['12', 'linux', '12.16.2', 'Erbium'],
['10', 'win32', '10.20.1', 'Dubnium'],
['*', 'linux', '14.0.0', 'Fermium']
])(
'can find %s from manifest on %s',
async (versionSpec, platform, expectedVersion, expectedLts) => {
os.platform = platform;
os.arch = 'x64'; os.arch = 'x64';
let versions: tc.IToolRelease[] | null = await tc.getManifestFromRepo( let versions: tc.IToolRelease[] | null = await tc.getManifestFromRepo(
'actions', 'actions',
@ -144,41 +151,12 @@ describe('setup-node', () => {
'mocktoken' 'mocktoken'
); );
expect(versions).toBeDefined(); expect(versions).toBeDefined();
let match = await tc.findFromManifest('12.16.2', true, versions); let match = await tc.findFromManifest(versionSpec, true, versions);
expect(match).toBeDefined(); expect(match).toBeDefined();
expect(match?.version).toBe('12.16.2'); expect(match?.version).toBe(expectedVersion);
expect((match as any).lts).toBe('Erbium'); expect((match as any).lts).toBe(expectedLts);
}); }
it('can find 12 from manifest on linux', async () => {
os.platform = 'linux';
os.arch = 'x64';
let versions: tc.IToolRelease[] | null = await tc.getManifestFromRepo(
'actions',
'node-versions',
'mocktoken'
); );
expect(versions).toBeDefined();
let match = await tc.findFromManifest('12.16.2', true, versions);
expect(match).toBeDefined();
expect(match?.version).toBe('12.16.2');
expect((match as any).lts).toBe('Erbium');
});
it('can find 10 from manifest on windows', async () => {
os.platform = 'win32';
os.arch = 'x64';
let versions: tc.IToolRelease[] | null = await tc.getManifestFromRepo(
'actions',
'node-versions',
'mocktoken'
);
expect(versions).toBeDefined();
let match = await tc.findFromManifest('10', true, versions);
expect(match).toBeDefined();
expect(match?.version).toBe('10.20.1');
expect((match as any).lts).toBe('Dubnium');
});
//-------------------------------------------------- //--------------------------------------------------
// Found in cache tests // Found in cache tests
@ -909,4 +887,57 @@ describe('setup-node', () => {
); );
}); });
}); });
describe('latest alias syntax', () => {
it.each(['latest', 'current', 'node'])(
'download the %s version if alias is provided',
async inputVersion => {
// Arrange
inputs['node-version'] = inputVersion;
os.platform = 'darwin';
os.arch = 'x64';
findSpy.mockImplementation(() => '');
getManifestSpy.mockImplementation(() => {
throw new Error('Unable to download manifest');
});
// Act
await main.run();
// assert
expect(logSpy).toHaveBeenCalledWith('Unable to download manifest');
expect(logSpy).toHaveBeenCalledWith('getting latest node version...');
}
);
});
describe('latest alias syntax from cache', () => {
it.each(['latest', 'current', 'node'])(
'download the %s version if alias is provided',
async inputVersion => {
// Arrange
inputs['node-version'] = inputVersion;
const expectedVersion = nodeTestDist[0];
os.platform = 'darwin';
os.arch = 'x64';
const toolPath = path.normalize(
`/cache/node/${expectedVersion.version}/x64`
);
findSpy.mockReturnValue(toolPath);
// Act
await main.run();
// assert
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
expect(logSpy).toHaveBeenCalledWith('getting latest node version...');
}
);
});
}); });

View file

@ -1,4 +1,39 @@
# Advanced usage ## Working with lockfiles
All supported package managers recommend that you **always** commit the lockfile, although implementations vary doing so generally provides the following benefits:
- Enables faster installation for CI and production environments, due to being able to skip package resolution.
- Describes a single representation of a dependency tree such that teammates, deployments, and continuous integration are guaranteed to install exactly the same dependencies.
- Provides a facility for users to "time-travel" to previous states of `node_modules` without having to commit the directory itself.
- Facilitates greater visibility of tree changes through readable source control diffs.
In order to get the most out of using your lockfile on continuous integration follow the conventions outlined below for your respective package manager.
### NPM
Ensure that `package-lock.json` is always committed, use `npm ci` instead of `npm install` when installing packages.
**See also:**
- [Documentation of `package-lock.json`](https://docs.npmjs.com/cli/v8/configuring-npm/package-lock-json)
- [Documentation of `npm ci`](https://docs.npmjs.com/cli/v8/commands/npm-ci)
### Yarn
To ensure that `yarn.lock` is always committed, use `yarn install --immutable` when installing packages.
**See also:**
- [Documentation of `yarn.lock`](https://classic.yarnpkg.com/en/docs/yarn-lock)
- [Documentation of `--frozen-lockfile` option](https://classic.yarnpkg.com/en/docs/cli/install#toc-yarn-install-frozen-lockfile)
- [QA - Should lockfiles be committed to the repoistory?](https://yarnpkg.com/getting-started/qa/#should-lockfiles-be-committed-to-the-repository)
- [Documentation of `yarn install`](https://yarnpkg.com/cli/install)
### PNPM
Ensure that `pnpm-lock.yaml` is always committed, when on CI pass `--frozen-lockfile` to `pnpm install` when installing packages.
**See also:**
- [Working with Git - Lockfiles](https://pnpm.io/git#lockfiles)
- [Documentation of `--frozen-lockfile` option](https://pnpm.io/cli/install#--frozen-lockfile)
## Check latest version ## Check latest version
@ -15,7 +50,7 @@ steps:
with: with:
node-version: '14' node-version: '14'
check-latest: true check-latest: true
- run: npm install - run: npm ci
- run: npm test - run: npm test
``` ```
@ -31,7 +66,7 @@ steps:
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
- run: npm install - run: npm ci
- run: npm test - run: npm test
``` ```
@ -51,7 +86,7 @@ jobs:
with: with:
node-version: '14' node-version: '14'
architecture: 'x64' # optional, x64 or x86. If not specified, x64 will be used by default architecture: 'x64' # optional, x64 or x86. If not specified, x64 will be used by default
- run: npm install - run: npm ci
- run: npm test - run: npm test
``` ```
@ -67,7 +102,7 @@ steps:
with: with:
node-version: '14' node-version: '14'
cache: 'yarn' cache: 'yarn'
- run: yarn install - run: yarn install --frozen-lockfile # optional, --immutable
- run: yarn test - run: yarn test
``` ```
@ -82,14 +117,14 @@ steps:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: pnpm/action-setup@646cdf48217256a3d0b80361c5a50727664284f2 - uses: pnpm/action-setup@v2
with: with:
version: 6.10.0 version: 6.32.9
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: '14' node-version: '14'
cache: 'pnpm' cache: 'pnpm'
- run: pnpm install - run: pnpm install --frozen-lockfile
- run: pnpm test - run: pnpm test
``` ```
@ -102,7 +137,7 @@ steps:
node-version: '14' node-version: '14'
cache: 'npm' cache: 'npm'
cache-dependency-path: '**/package-lock.json' cache-dependency-path: '**/package-lock.json'
- run: npm install - run: npm ci
- run: npm test - run: npm test
``` ```
@ -117,7 +152,7 @@ steps:
cache-dependency-path: | cache-dependency-path: |
server/app/package-lock.json server/app/package-lock.json
frontend/app/package-lock.json frontend/app/package-lock.json
- run: npm install - run: npm ci
- run: npm test - run: npm test
``` ```
@ -152,7 +187,7 @@ jobs:
with: with:
node-version: ${{ matrix.node_version }} node-version: ${{ matrix.node_version }}
architecture: ${{ matrix.architecture }} architecture: ${{ matrix.architecture }}
- run: npm install - run: npm ci
- run: npm test - run: npm test
``` ```
@ -164,7 +199,7 @@ steps:
with: with:
node-version: '14.x' node-version: '14.x'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
- run: npm install - run: npm ci
- run: npm publish - run: npm publish
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@ -184,7 +219,7 @@ steps:
with: with:
node-version: '14.x' node-version: '14.x'
registry-url: <registry url> registry-url: <registry url>
- run: yarn install - run: yarn install --frozen-lockfile
- run: yarn publish - run: yarn publish
env: env:
NODE_AUTH_TOKEN: ${{ secrets.YARN_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.YARN_TOKEN }}
@ -206,7 +241,7 @@ steps:
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
# Skip post-install scripts here, as a malicious # Skip post-install scripts here, as a malicious
# script could steal NODE_AUTH_TOKEN. # script could steal NODE_AUTH_TOKEN.
- run: npm install --ignore-scripts - run: npm ci --ignore-scripts
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# `npm rebuild` will run all those post-install scripts for us. # `npm rebuild` will run all those post-install scripts for us.

View file

@ -37,6 +37,7 @@ export async function getNode(
) { ) {
// Store manifest data to avoid multiple calls // Store manifest data to avoid multiple calls
let manifest: INodeRelease[] | undefined; let manifest: INodeRelease[] | undefined;
let nodeVersions: INodeVersion[] | undefined;
let osPlat: string = os.platform(); let osPlat: string = os.platform();
let osArch: string = translateArchToDistUrl(arch); let osArch: string = translateArchToDistUrl(arch);
@ -49,6 +50,12 @@ export async function getNode(
versionSpec = resolveLtsAliasFromManifest(versionSpec, stable, manifest); versionSpec = resolveLtsAliasFromManifest(versionSpec, stable, manifest);
} }
if (isLatestSyntax(versionSpec)) {
nodeVersions = await getVersionsFromDist();
versionSpec = await queryDistForMatch(versionSpec, arch, nodeVersions);
core.info(`getting latest node version...`);
}
if (checkLatest) { if (checkLatest) {
core.info('Attempt to resolve the latest version from manifest...'); core.info('Attempt to resolve the latest version from manifest...');
const resolvedVersion = await resolveVersionFromManifest( const resolvedVersion = await resolveVersionFromManifest(
@ -119,7 +126,7 @@ export async function getNode(
// Download from nodejs.org // Download from nodejs.org
// //
if (!downloadPath) { if (!downloadPath) {
info = await getInfoFromDist(versionSpec, arch); info = await getInfoFromDist(versionSpec, arch, nodeVersions);
if (!info) { if (!info) {
throw new Error( throw new Error(
`Unable to find Node version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.` `Unable to find Node version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.`
@ -265,14 +272,18 @@ async function getInfoFromManifest(
async function getInfoFromDist( async function getInfoFromDist(
versionSpec: string, versionSpec: string,
arch: string = os.arch() arch: string = os.arch(),
nodeVersions?: INodeVersion[]
): Promise<INodeVersionInfo | null> { ): Promise<INodeVersionInfo | null> {
let osPlat: string = os.platform(); let osPlat: string = os.platform();
let osArch: string = translateArchToDistUrl(arch); let osArch: string = translateArchToDistUrl(arch);
let version: string; let version: string = await queryDistForMatch(
versionSpec,
arch,
nodeVersions
);
version = await queryDistForMatch(versionSpec, arch);
if (!version) { if (!version) {
return null; return null;
} }
@ -349,7 +360,8 @@ function evaluateVersions(versions: string[], versionSpec: string): string {
async function queryDistForMatch( async function queryDistForMatch(
versionSpec: string, versionSpec: string,
arch: string = os.arch() arch: string = os.arch(),
nodeVersions?: INodeVersion[]
): Promise<string> { ): Promise<string> {
let osPlat: string = os.platform(); let osPlat: string = os.platform();
let osArch: string = translateArchToDistUrl(arch); let osArch: string = translateArchToDistUrl(arch);
@ -370,8 +382,17 @@ async function queryDistForMatch(
throw new Error(`Unexpected OS '${osPlat}'`); throw new Error(`Unexpected OS '${osPlat}'`);
} }
if (!nodeVersions) {
core.debug('No dist manifest cached');
nodeVersions = await getVersionsFromDist();
}
let versions: string[] = []; let versions: string[] = [];
let nodeVersions = await getVersionsFromDist();
if (isLatestSyntax(versionSpec)) {
core.info(`getting latest node version...`);
return nodeVersions[0].version;
}
nodeVersions.forEach((nodeVersion: INodeVersion) => { nodeVersions.forEach((nodeVersion: INodeVersion) => {
// ensure this version supports your os and platform // ensure this version supports your os and platform
@ -473,3 +494,7 @@ export function parseNodeVersionFile(contents: string): string {
} }
return nodeVersion; return nodeVersion;
} }
function isLatestSyntax(versionSpec): boolean {
return ['current', 'latest', 'node'].includes(versionSpec);
}