mirror of
				https://github.com/actions/setup-node.git
				synced 2025-11-04 05:19:11 +08:00 
			
		
		
		
	feat: support private mirrors (#1240)
* feat: support private mirrors * chore: change fallback message with mirrors
This commit is contained in:
		
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
								
							@@ -76,6 +76,21 @@ See [action.yml](action.yml)
 | 
			
		||||
    # Set always-auth option in npmrc file.
 | 
			
		||||
    # Default: ''
 | 
			
		||||
    always-auth: ''
 | 
			
		||||
 | 
			
		||||
    # Optional mirror to download binaries from.
 | 
			
		||||
    # Artifacts need to match the official Node.js
 | 
			
		||||
    # Example:
 | 
			
		||||
    # V8 Canaray Build: <mirror_url>/download/v8-canary
 | 
			
		||||
    # RC Build: <mirror_url>/download/rc
 | 
			
		||||
    # Official: Build <mirror_url>/dist
 | 
			
		||||
    # Nightly build: <mirror_url>/download/nightly
 | 
			
		||||
    # Default: ''
 | 
			
		||||
    mirror: ''
 | 
			
		||||
 | 
			
		||||
    # Optional mirror token.
 | 
			
		||||
    # The token will be used as a bearer token in the Authorization header
 | 
			
		||||
    # Default: ''
 | 
			
		||||
    mirror-token: ''
 | 
			
		||||
```
 | 
			
		||||
<!-- end usage -->
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -498,6 +498,70 @@ describe('setup-node', () => {
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    it.each([
 | 
			
		||||
      [
 | 
			
		||||
        '20.0.0-v8-canary',
 | 
			
		||||
        '20.0.0-v8-canary20221103f7e2421e91',
 | 
			
		||||
        '20.0.0-v8-canary20221030fefe1c0879',
 | 
			
		||||
        'https://my_mirror.org/download/v8-canary/v20.0.0-v8-canary20221103f7e2421e91/node-v20.0.0-v8-canary20221103f7e2421e91-linux-x64.tar.gz'
 | 
			
		||||
      ],
 | 
			
		||||
      [
 | 
			
		||||
        '20-v8-canary',
 | 
			
		||||
        '20.0.0-v8-canary20221103f7e2421e91',
 | 
			
		||||
        '20.0.0-v8-canary20221030fefe1c0879',
 | 
			
		||||
        'https://my_mirror.org/download/v8-canary/v20.0.0-v8-canary20221103f7e2421e91/node-v20.0.0-v8-canary20221103f7e2421e91-linux-x64.tar.gz'
 | 
			
		||||
      ],
 | 
			
		||||
      [
 | 
			
		||||
        '19.0.0-v8-canary',
 | 
			
		||||
        '19.0.0-v8-canary202210187d6960f23f',
 | 
			
		||||
        '19.0.0-v8-canary202210172ec229fc56',
 | 
			
		||||
        'https://my_mirror.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz'
 | 
			
		||||
      ],
 | 
			
		||||
      [
 | 
			
		||||
        '19-v8-canary',
 | 
			
		||||
        '19.0.0-v8-canary202210187d6960f23f',
 | 
			
		||||
        '19.0.0-v8-canary202210172ec229fc56',
 | 
			
		||||
        'https://my_mirror.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz'
 | 
			
		||||
      ]
 | 
			
		||||
    ])(
 | 
			
		||||
      'get %s version from dist if check-latest is true',
 | 
			
		||||
      async (input, expectedVersion, foundVersion, expectedUrl) => {
 | 
			
		||||
        const foundToolPath = path.normalize(`/cache/node/${foundVersion}/x64`);
 | 
			
		||||
        const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
 | 
			
		||||
 | 
			
		||||
        inputs['node-version'] = input;
 | 
			
		||||
        inputs['check-latest'] = 'true';
 | 
			
		||||
        os['arch'] = 'x64';
 | 
			
		||||
        os['platform'] = 'linux';
 | 
			
		||||
        inputs['mirror'] = 'https://my_mirror.org';
 | 
			
		||||
        inputs['mirror-token'] = 'faketoken';
 | 
			
		||||
 | 
			
		||||
        findSpy.mockReturnValue(foundToolPath);
 | 
			
		||||
        findAllVersionsSpy.mockReturnValue([
 | 
			
		||||
          '20.0.0-v8-canary20221030fefe1c0879',
 | 
			
		||||
          '19.0.0-v8-canary202210172ec229fc56',
 | 
			
		||||
          '20.0.0-v8-canary2022102310ff1e5a8d'
 | 
			
		||||
        ]);
 | 
			
		||||
        dlSpy.mockImplementation(async () => '/some/temp/path');
 | 
			
		||||
        exSpy.mockImplementation(async () => '/some/other/temp/path');
 | 
			
		||||
        cacheSpy.mockImplementation(async () => toolPath);
 | 
			
		||||
 | 
			
		||||
        // act
 | 
			
		||||
        await main.run();
 | 
			
		||||
 | 
			
		||||
        // assert
 | 
			
		||||
        expect(findAllVersionsSpy).toHaveBeenCalled();
 | 
			
		||||
        expect(logSpy).toHaveBeenCalledWith(
 | 
			
		||||
          `Acquiring ${expectedVersion} - ${os.arch} from ${expectedUrl}`
 | 
			
		||||
        );
 | 
			
		||||
        expect(logSpy).toHaveBeenCalledWith('Extracting ...');
 | 
			
		||||
        expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...');
 | 
			
		||||
        expect(cnSpy).toHaveBeenCalledWith(
 | 
			
		||||
          `::add-path::${path.join(toolPath, 'bin')}${osm.EOL}`
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('setup-node v8 canary tests', () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -315,7 +315,7 @@ describe('setup-node', () => {
 | 
			
		||||
    await main.run();
 | 
			
		||||
 | 
			
		||||
    workingUrls.forEach(url => {
 | 
			
		||||
      expect(dlSpy).toHaveBeenCalledWith(url);
 | 
			
		||||
      expect(dlSpy).toHaveBeenCalledWith(url, undefined, undefined);
 | 
			
		||||
    });
 | 
			
		||||
    expect(cnSpy).toHaveBeenCalledWith(`::add-path::${toolPath}${osm.EOL}`);
 | 
			
		||||
  });
 | 
			
		||||
@@ -449,6 +449,54 @@ describe('setup-node', () => {
 | 
			
		||||
    }
 | 
			
		||||
  }, 100000);
 | 
			
		||||
 | 
			
		||||
  it('acquires specified architecture of node from mirror', async () => {
 | 
			
		||||
    for (const {arch, version, osSpec} of [
 | 
			
		||||
      {
 | 
			
		||||
        arch: 'x86',
 | 
			
		||||
        version: '18.0.0-nightly202110204cb3e06ed8',
 | 
			
		||||
        osSpec: 'win32'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        arch: 'x86',
 | 
			
		||||
        version: '20.0.0-nightly2022101987cdf7d412',
 | 
			
		||||
        osSpec: 'win32'
 | 
			
		||||
      }
 | 
			
		||||
    ]) {
 | 
			
		||||
      os.platform = osSpec;
 | 
			
		||||
      os.arch = arch;
 | 
			
		||||
      const fileExtension = os.platform === 'win32' ? '7z' : 'tar.gz';
 | 
			
		||||
      const platform = {
 | 
			
		||||
        linux: 'linux',
 | 
			
		||||
        darwin: 'darwin',
 | 
			
		||||
        win32: 'win'
 | 
			
		||||
      }[os.platform];
 | 
			
		||||
 | 
			
		||||
      inputs['node-version'] = version;
 | 
			
		||||
      inputs['architecture'] = arch;
 | 
			
		||||
      inputs['always-auth'] = false;
 | 
			
		||||
      inputs['token'] = 'faketoken';
 | 
			
		||||
      inputs['mirror'] = 'https://my-mirror.org';
 | 
			
		||||
      inputs['mirror-token'] = 'my-mirror-token';
 | 
			
		||||
 | 
			
		||||
      const expectedUrl = `https://my-mirror.org/download/nightly/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;
 | 
			
		||||
 | 
			
		||||
      // ... but not in the local cache
 | 
			
		||||
      findSpy.mockImplementation(() => '');
 | 
			
		||||
      findAllVersionsSpy.mockImplementation(() => []);
 | 
			
		||||
 | 
			
		||||
      dlSpy.mockImplementation(async () => '/some/temp/path');
 | 
			
		||||
      const toolPath = path.normalize(`/cache/node/${version}/${arch}`);
 | 
			
		||||
      exSpy.mockImplementation(async () => '/some/other/temp/path');
 | 
			
		||||
      cacheSpy.mockImplementation(async () => toolPath);
 | 
			
		||||
 | 
			
		||||
      await main.run();
 | 
			
		||||
      expect(dlSpy).toHaveBeenCalled();
 | 
			
		||||
      expect(logSpy).toHaveBeenCalledWith(
 | 
			
		||||
        `Acquiring ${version} - ${arch} from ${expectedUrl}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }, 100000);
 | 
			
		||||
 | 
			
		||||
  describe('nightly versions', () => {
 | 
			
		||||
    it.each([
 | 
			
		||||
      [
 | 
			
		||||
 
 | 
			
		||||
@@ -282,6 +282,43 @@ describe('setup-node', () => {
 | 
			
		||||
    expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('falls back to a version from node dist from mirror', async () => {
 | 
			
		||||
    os.platform = 'linux';
 | 
			
		||||
    os.arch = 'x64';
 | 
			
		||||
 | 
			
		||||
    // a version which is not in the manifest but is in node dist
 | 
			
		||||
    const versionSpec = '11.15.0';
 | 
			
		||||
    const mirror = 'https://my_mirror_url';
 | 
			
		||||
    inputs['node-version'] = versionSpec;
 | 
			
		||||
    inputs['always-auth'] = false;
 | 
			
		||||
    inputs['token'] = 'faketoken';
 | 
			
		||||
    inputs['mirror'] = mirror;
 | 
			
		||||
    inputs['mirror-token'] = 'faketoken';
 | 
			
		||||
 | 
			
		||||
    // ... but not in the local cache
 | 
			
		||||
    findSpy.mockImplementation(() => '');
 | 
			
		||||
 | 
			
		||||
    dlSpy.mockImplementation(async () => '/some/temp/path');
 | 
			
		||||
    const toolPath = path.normalize('/cache/node/11.15.0/x64');
 | 
			
		||||
    exSpy.mockImplementation(async () => '/some/other/temp/path');
 | 
			
		||||
    cacheSpy.mockImplementation(async () => toolPath);
 | 
			
		||||
 | 
			
		||||
    await main.run();
 | 
			
		||||
 | 
			
		||||
    const expPath = path.join(toolPath, 'bin');
 | 
			
		||||
 | 
			
		||||
    expect(getManifestSpy).toHaveBeenCalled();
 | 
			
		||||
    expect(logSpy).toHaveBeenCalledWith(
 | 
			
		||||
      `Attempting to download ${versionSpec}...`
 | 
			
		||||
    );
 | 
			
		||||
    expect(logSpy).toHaveBeenCalledWith(
 | 
			
		||||
      `Not found in manifest. Falling back to download directly from ${mirror}`
 | 
			
		||||
    );
 | 
			
		||||
    expect(dlSpy).toHaveBeenCalled();
 | 
			
		||||
    expect(exSpy).toHaveBeenCalled();
 | 
			
		||||
    expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('falls back to a version from node dist', async () => {
 | 
			
		||||
    os.platform = 'linux';
 | 
			
		||||
    os.arch = 'x64';
 | 
			
		||||
@@ -828,4 +865,46 @@ describe('setup-node', () => {
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('acquires specified architecture of node from mirror', async () => {
 | 
			
		||||
    for (const {arch, version, osSpec} of [
 | 
			
		||||
      {arch: 'x86', version: '12.16.2', osSpec: 'win32'},
 | 
			
		||||
      {arch: 'x86', version: '14.0.0', osSpec: 'win32'}
 | 
			
		||||
    ]) {
 | 
			
		||||
      os.platform = osSpec;
 | 
			
		||||
      os.arch = arch;
 | 
			
		||||
      const fileExtension = os.platform === 'win32' ? '7z' : 'tar.gz';
 | 
			
		||||
      const platform = {
 | 
			
		||||
        linux: 'linux',
 | 
			
		||||
        darwin: 'darwin',
 | 
			
		||||
        win32: 'win'
 | 
			
		||||
      }[os.platform];
 | 
			
		||||
 | 
			
		||||
      inputs['node-version'] = version;
 | 
			
		||||
      inputs['architecture'] = arch;
 | 
			
		||||
      inputs['always-auth'] = false;
 | 
			
		||||
      inputs['token'] = 'faketoken';
 | 
			
		||||
      inputs['mirror'] = 'https://my_mirror_url';
 | 
			
		||||
      inputs['mirror-token'] = 'faketoken';
 | 
			
		||||
 | 
			
		||||
      const expectedUrl =
 | 
			
		||||
        arch === 'x64'
 | 
			
		||||
          ? `https://github.com/actions/node-versions/releases/download/${version}/node-${version}-${platform}-${arch}.zip`
 | 
			
		||||
          : `https://my_mirror_url/dist/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;
 | 
			
		||||
 | 
			
		||||
      // ... but not in the local cache
 | 
			
		||||
      findSpy.mockImplementation(() => '');
 | 
			
		||||
 | 
			
		||||
      dlSpy.mockImplementation(async () => '/some/temp/path');
 | 
			
		||||
      const toolPath = path.normalize(`/cache/node/${version}/${arch}`);
 | 
			
		||||
      exSpy.mockImplementation(async () => '/some/other/temp/path');
 | 
			
		||||
      cacheSpy.mockImplementation(async () => toolPath);
 | 
			
		||||
 | 
			
		||||
      await main.run();
 | 
			
		||||
      expect(dlSpy).toHaveBeenCalled();
 | 
			
		||||
      expect(logSpy).toHaveBeenCalledWith(
 | 
			
		||||
        `Acquiring ${version} - ${arch} from ${expectedUrl}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }, 100000);
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,10 @@ inputs:
 | 
			
		||||
    description: 'Used to specify a package manager for caching in the default directory. Supported values: npm, yarn, pnpm.'
 | 
			
		||||
  cache-dependency-path:
 | 
			
		||||
    description: 'Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. Supports wildcards or a list of file names for caching multiple dependencies.'
 | 
			
		||||
  mirror:
 | 
			
		||||
    description: 'Used to specify an alternative mirror to downlooad Node.js binaries from'
 | 
			
		||||
  mirror-token:
 | 
			
		||||
    description: 'The token used as Authorization header when fetching from the mirror'
 | 
			
		||||
# TODO: add input to control forcing to pull from cloud or dist.
 | 
			
		||||
#       escape valve for someone having issues or needing the absolute latest which isn't cached yet
 | 
			
		||||
outputs:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										54
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							@@ -97211,9 +97211,13 @@ class BaseDistribution {
 | 
			
		||||
    }
 | 
			
		||||
    getNodeJsVersions() {
 | 
			
		||||
        return __awaiter(this, void 0, void 0, function* () {
 | 
			
		||||
            const initialUrl = this.getDistributionUrl();
 | 
			
		||||
            const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
 | 
			
		||||
            const dataUrl = `${initialUrl}/index.json`;
 | 
			
		||||
            const response = yield this.httpClient.getJson(dataUrl);
 | 
			
		||||
            const headers = {};
 | 
			
		||||
            if (this.nodeInfo.mirrorToken) {
 | 
			
		||||
                headers['Authorization'] = `Bearer ${this.nodeInfo.mirrorToken}`;
 | 
			
		||||
            }
 | 
			
		||||
            const response = yield this.httpClient.getJson(dataUrl, headers);
 | 
			
		||||
            return response.result || [];
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
@@ -97228,7 +97232,7 @@ class BaseDistribution {
 | 
			
		||||
                ? `${fileName}.zip`
 | 
			
		||||
                : `${fileName}.7z`
 | 
			
		||||
            : `${fileName}.tar.gz`;
 | 
			
		||||
        const initialUrl = this.getDistributionUrl();
 | 
			
		||||
        const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
 | 
			
		||||
        const url = `${initialUrl}/v${version}/${urlFileName}`;
 | 
			
		||||
        return {
 | 
			
		||||
            downloadUrl: url,
 | 
			
		||||
@@ -97242,7 +97246,7 @@ class BaseDistribution {
 | 
			
		||||
            let downloadPath = '';
 | 
			
		||||
            core.info(`Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}`);
 | 
			
		||||
            try {
 | 
			
		||||
                downloadPath = yield tc.downloadTool(info.downloadUrl);
 | 
			
		||||
                downloadPath = yield tc.downloadTool(info.downloadUrl, undefined, this.nodeInfo.mirrorToken);
 | 
			
		||||
            }
 | 
			
		||||
            catch (err) {
 | 
			
		||||
                if (err instanceof tc.HTTPError &&
 | 
			
		||||
@@ -97266,7 +97270,7 @@ class BaseDistribution {
 | 
			
		||||
    }
 | 
			
		||||
    acquireWindowsNodeFromFallbackLocation(version_1) {
 | 
			
		||||
        return __awaiter(this, arguments, void 0, function* (version, arch = os_1.default.arch()) {
 | 
			
		||||
            const initialUrl = this.getDistributionUrl();
 | 
			
		||||
            const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
 | 
			
		||||
            const osArch = this.translateArchToDistUrl(arch);
 | 
			
		||||
            // Create temporary folder to download to
 | 
			
		||||
            const tempDownloadFolder = `temp_${(0, uuid_1.v4)()}`;
 | 
			
		||||
@@ -97280,18 +97284,18 @@ class BaseDistribution {
 | 
			
		||||
                exeUrl = `${initialUrl}/v${version}/win-${osArch}/node.exe`;
 | 
			
		||||
                libUrl = `${initialUrl}/v${version}/win-${osArch}/node.lib`;
 | 
			
		||||
                core.info(`Downloading only node binary from ${exeUrl}`);
 | 
			
		||||
                const exePath = yield tc.downloadTool(exeUrl);
 | 
			
		||||
                const exePath = yield tc.downloadTool(exeUrl, undefined, this.nodeInfo.mirrorToken);
 | 
			
		||||
                yield io.cp(exePath, path.join(tempDir, 'node.exe'));
 | 
			
		||||
                const libPath = yield tc.downloadTool(libUrl);
 | 
			
		||||
                const libPath = yield tc.downloadTool(libUrl, undefined, this.nodeInfo.mirrorToken);
 | 
			
		||||
                yield io.cp(libPath, path.join(tempDir, 'node.lib'));
 | 
			
		||||
            }
 | 
			
		||||
            catch (err) {
 | 
			
		||||
                if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
 | 
			
		||||
                    exeUrl = `${initialUrl}/v${version}/node.exe`;
 | 
			
		||||
                    libUrl = `${initialUrl}/v${version}/node.lib`;
 | 
			
		||||
                    const exePath = yield tc.downloadTool(exeUrl);
 | 
			
		||||
                    const exePath = yield tc.downloadTool(exeUrl, undefined, this.nodeInfo.mirrorToken);
 | 
			
		||||
                    yield io.cp(exePath, path.join(tempDir, 'node.exe'));
 | 
			
		||||
                    const libPath = yield tc.downloadTool(libUrl);
 | 
			
		||||
                    const libPath = yield tc.downloadTool(libUrl, undefined, this.nodeInfo.mirrorToken);
 | 
			
		||||
                    yield io.cp(libPath, path.join(tempDir, 'node.lib'));
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
@@ -97454,8 +97458,9 @@ class NightlyNodejs extends base_distribution_prerelease_1.default {
 | 
			
		||||
        super(nodeInfo);
 | 
			
		||||
        this.distribution = 'nightly';
 | 
			
		||||
    }
 | 
			
		||||
    getDistributionUrl() {
 | 
			
		||||
        return 'https://nodejs.org/download/nightly';
 | 
			
		||||
    getDistributionUrl(mirror) {
 | 
			
		||||
        const url = mirror || 'https://nodejs.org';
 | 
			
		||||
        return `${url}/download/nightly`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
exports["default"] = NightlyNodejs;
 | 
			
		||||
@@ -97553,13 +97558,13 @@ class OfficialBuilds extends base_distribution_1.default {
 | 
			
		||||
                const versionInfo = yield this.getInfoFromManifest(this.nodeInfo.versionSpec, this.nodeInfo.stable, osArch, manifest);
 | 
			
		||||
                if (versionInfo) {
 | 
			
		||||
                    core.info(`Acquiring ${versionInfo.resolvedVersion} - ${versionInfo.arch} from ${versionInfo.downloadUrl}`);
 | 
			
		||||
                    downloadPath = yield tc.downloadTool(versionInfo.downloadUrl, undefined, this.nodeInfo.auth);
 | 
			
		||||
                    downloadPath = yield tc.downloadTool(versionInfo.downloadUrl, undefined, this.nodeInfo.mirror ? this.nodeInfo.mirrorToken : this.nodeInfo.auth);
 | 
			
		||||
                    if (downloadPath) {
 | 
			
		||||
                        toolPath = yield this.extractArchive(downloadPath, versionInfo, false);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    core.info('Not found in manifest. Falling back to download directly from Node');
 | 
			
		||||
                    core.info(`Not found in manifest. Falling back to download directly from ${this.nodeInfo.mirror || 'Node'}`);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (err) {
 | 
			
		||||
@@ -97621,12 +97626,13 @@ class OfficialBuilds extends base_distribution_1.default {
 | 
			
		||||
        version = super.evaluateVersions(versions);
 | 
			
		||||
        return version;
 | 
			
		||||
    }
 | 
			
		||||
    getDistributionUrl() {
 | 
			
		||||
        return `https://nodejs.org/dist`;
 | 
			
		||||
    getDistributionUrl(mirror) {
 | 
			
		||||
        const url = mirror || 'https://nodejs.org';
 | 
			
		||||
        return `${url}/dist`;
 | 
			
		||||
    }
 | 
			
		||||
    getManifest() {
 | 
			
		||||
        core.debug('Getting manifest from actions/node-versions@main');
 | 
			
		||||
        return tc.getManifestFromRepo('actions', 'node-versions', this.nodeInfo.auth, 'main');
 | 
			
		||||
        return tc.getManifestFromRepo('actions', 'node-versions', this.nodeInfo.mirror ? this.nodeInfo.mirrorToken : this.nodeInfo.auth, 'main');
 | 
			
		||||
    }
 | 
			
		||||
    resolveLtsAliasFromManifest(versionSpec, stable, manifest) {
 | 
			
		||||
        var _a;
 | 
			
		||||
@@ -97709,8 +97715,9 @@ class RcBuild extends base_distribution_1.default {
 | 
			
		||||
    constructor(nodeInfo) {
 | 
			
		||||
        super(nodeInfo);
 | 
			
		||||
    }
 | 
			
		||||
    getDistributionUrl() {
 | 
			
		||||
        return 'https://nodejs.org/download/rc';
 | 
			
		||||
    getDistributionUrl(mirror) {
 | 
			
		||||
        const url = mirror || 'https://nodejs.org';
 | 
			
		||||
        return `${url}/download/rc`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
exports["default"] = RcBuild;
 | 
			
		||||
@@ -97733,8 +97740,9 @@ class CanaryBuild extends base_distribution_prerelease_1.default {
 | 
			
		||||
        super(nodeInfo);
 | 
			
		||||
        this.distribution = 'v8-canary';
 | 
			
		||||
    }
 | 
			
		||||
    getDistributionUrl() {
 | 
			
		||||
        return 'https://nodejs.org/download/v8-canary';
 | 
			
		||||
    getDistributionUrl(mirror) {
 | 
			
		||||
        const url = mirror || 'https://nodejs.org';
 | 
			
		||||
        return `${url}/download/v8-canary`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
exports["default"] = CanaryBuild;
 | 
			
		||||
@@ -97814,6 +97822,8 @@ function run() {
 | 
			
		||||
            if (version) {
 | 
			
		||||
                const token = core.getInput('token');
 | 
			
		||||
                const auth = !token ? undefined : `token ${token}`;
 | 
			
		||||
                const mirror = core.getInput('mirror');
 | 
			
		||||
                const mirrorToken = core.getInput('mirror-token');
 | 
			
		||||
                const stable = (core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
 | 
			
		||||
                const checkLatest = (core.getInput('check-latest') || 'false').toUpperCase() === 'TRUE';
 | 
			
		||||
                const nodejsInfo = {
 | 
			
		||||
@@ -97821,7 +97831,9 @@ function run() {
 | 
			
		||||
                    checkLatest,
 | 
			
		||||
                    auth,
 | 
			
		||||
                    stable,
 | 
			
		||||
                    arch
 | 
			
		||||
                    arch,
 | 
			
		||||
                    mirror,
 | 
			
		||||
                    mirrorToken
 | 
			
		||||
                };
 | 
			
		||||
                const nodeDistribution = (0, installer_factory_1.getNodejsDistribution)(nodejsInfo);
 | 
			
		||||
                yield nodeDistribution.setupNodeJs();
 | 
			
		||||
 
 | 
			
		||||
@@ -418,3 +418,18 @@ Please refer to the [Ensuring workflow access to your package - Configuring a pa
 | 
			
		||||
 | 
			
		||||
### always-auth input
 | 
			
		||||
The always-auth input sets `always-auth=true` in .npmrc file. With this option set [npm](https://docs.npmjs.com/cli/v6/using-npm/config#always-auth)/yarn sends the authentication credentials when making a request to the registries.
 | 
			
		||||
 | 
			
		||||
## Use private mirror
 | 
			
		||||
 | 
			
		||||
It is possible to use a private mirror hosting Node.js binaries. This mirror must be a full mirror of the official Node.js distribution.
 | 
			
		||||
The mirror URL can be set using the `mirror` input.
 | 
			
		||||
It is possible to specify a token to authenticate with the mirror using the `mirror-token` input.
 | 
			
		||||
The token will be passed as a bearer token in the `Authorization` header.
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
- uses: actions/setup-node@v4
 | 
			
		||||
  with:
 | 
			
		||||
    node-version: '14.x'
 | 
			
		||||
    mirror: 'https://nodejs.org/dist'
 | 
			
		||||
    mirror-token: 'your-mirror-token'
 | 
			
		||||
```
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ export default abstract class BaseDistribution {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected abstract getDistributionUrl(): string;
 | 
			
		||||
  protected abstract getDistributionUrl(mirror: string): string;
 | 
			
		||||
 | 
			
		||||
  public async setupNodeJs() {
 | 
			
		||||
    let nodeJsVersions: INodeVersion[] | undefined;
 | 
			
		||||
@@ -97,10 +97,19 @@ export default abstract class BaseDistribution {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected async getNodeJsVersions(): Promise<INodeVersion[]> {
 | 
			
		||||
    const initialUrl = this.getDistributionUrl();
 | 
			
		||||
    const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
 | 
			
		||||
    const dataUrl = `${initialUrl}/index.json`;
 | 
			
		||||
 | 
			
		||||
    const response = await this.httpClient.getJson<INodeVersion[]>(dataUrl);
 | 
			
		||||
    const headers = {};
 | 
			
		||||
 | 
			
		||||
    if (this.nodeInfo.mirrorToken) {
 | 
			
		||||
      headers['Authorization'] = `Bearer ${this.nodeInfo.mirrorToken}`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const response = await this.httpClient.getJson<INodeVersion[]>(
 | 
			
		||||
      dataUrl,
 | 
			
		||||
      headers
 | 
			
		||||
    );
 | 
			
		||||
    return response.result || [];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -117,7 +126,7 @@ export default abstract class BaseDistribution {
 | 
			
		||||
          ? `${fileName}.zip`
 | 
			
		||||
          : `${fileName}.7z`
 | 
			
		||||
        : `${fileName}.tar.gz`;
 | 
			
		||||
    const initialUrl = this.getDistributionUrl();
 | 
			
		||||
    const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
 | 
			
		||||
    const url = `${initialUrl}/v${version}/${urlFileName}`;
 | 
			
		||||
 | 
			
		||||
    return <INodeVersionInfo>{
 | 
			
		||||
@@ -134,7 +143,11 @@ export default abstract class BaseDistribution {
 | 
			
		||||
      `Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}`
 | 
			
		||||
    );
 | 
			
		||||
    try {
 | 
			
		||||
      downloadPath = await tc.downloadTool(info.downloadUrl);
 | 
			
		||||
      downloadPath = await tc.downloadTool(
 | 
			
		||||
        info.downloadUrl,
 | 
			
		||||
        undefined,
 | 
			
		||||
        this.nodeInfo.mirrorToken
 | 
			
		||||
      );
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      if (
 | 
			
		||||
        err instanceof tc.HTTPError &&
 | 
			
		||||
@@ -168,7 +181,7 @@ export default abstract class BaseDistribution {
 | 
			
		||||
    version: string,
 | 
			
		||||
    arch: string = os.arch()
 | 
			
		||||
  ): Promise<string> {
 | 
			
		||||
    const initialUrl = this.getDistributionUrl();
 | 
			
		||||
    const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror);
 | 
			
		||||
    const osArch: string = this.translateArchToDistUrl(arch);
 | 
			
		||||
 | 
			
		||||
    // Create temporary folder to download to
 | 
			
		||||
@@ -185,18 +198,34 @@ export default abstract class BaseDistribution {
 | 
			
		||||
 | 
			
		||||
      core.info(`Downloading only node binary from ${exeUrl}`);
 | 
			
		||||
 | 
			
		||||
      const exePath = await tc.downloadTool(exeUrl);
 | 
			
		||||
      const exePath = await tc.downloadTool(
 | 
			
		||||
        exeUrl,
 | 
			
		||||
        undefined,
 | 
			
		||||
        this.nodeInfo.mirrorToken
 | 
			
		||||
      );
 | 
			
		||||
      await io.cp(exePath, path.join(tempDir, 'node.exe'));
 | 
			
		||||
      const libPath = await tc.downloadTool(libUrl);
 | 
			
		||||
      const libPath = await tc.downloadTool(
 | 
			
		||||
        libUrl,
 | 
			
		||||
        undefined,
 | 
			
		||||
        this.nodeInfo.mirrorToken
 | 
			
		||||
      );
 | 
			
		||||
      await io.cp(libPath, path.join(tempDir, 'node.lib'));
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
 | 
			
		||||
        exeUrl = `${initialUrl}/v${version}/node.exe`;
 | 
			
		||||
        libUrl = `${initialUrl}/v${version}/node.lib`;
 | 
			
		||||
 | 
			
		||||
        const exePath = await tc.downloadTool(exeUrl);
 | 
			
		||||
        const exePath = await tc.downloadTool(
 | 
			
		||||
          exeUrl,
 | 
			
		||||
          undefined,
 | 
			
		||||
          this.nodeInfo.mirrorToken
 | 
			
		||||
        );
 | 
			
		||||
        await io.cp(exePath, path.join(tempDir, 'node.exe'));
 | 
			
		||||
        const libPath = await tc.downloadTool(libUrl);
 | 
			
		||||
        const libPath = await tc.downloadTool(
 | 
			
		||||
          libUrl,
 | 
			
		||||
          undefined,
 | 
			
		||||
          this.nodeInfo.mirrorToken
 | 
			
		||||
        );
 | 
			
		||||
        await io.cp(libPath, path.join(tempDir, 'node.lib'));
 | 
			
		||||
      } else {
 | 
			
		||||
        throw err;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@ export interface NodeInputs {
 | 
			
		||||
  auth?: string;
 | 
			
		||||
  checkLatest: boolean;
 | 
			
		||||
  stable: boolean;
 | 
			
		||||
  mirror: string;
 | 
			
		||||
  mirrorToken: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface INodeVersionInfo {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,8 @@ export default class NightlyNodejs extends BasePrereleaseNodejs {
 | 
			
		||||
    super(nodeInfo);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected getDistributionUrl(): string {
 | 
			
		||||
    return 'https://nodejs.org/download/nightly';
 | 
			
		||||
  protected getDistributionUrl(mirror: string): string {
 | 
			
		||||
    const url = mirror || 'https://nodejs.org';
 | 
			
		||||
    return `${url}/download/nightly`;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -84,7 +84,7 @@ export default class OfficialBuilds extends BaseDistribution {
 | 
			
		||||
        downloadPath = await tc.downloadTool(
 | 
			
		||||
          versionInfo.downloadUrl,
 | 
			
		||||
          undefined,
 | 
			
		||||
          this.nodeInfo.auth
 | 
			
		||||
          this.nodeInfo.mirror ? this.nodeInfo.mirrorToken : this.nodeInfo.auth
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (downloadPath) {
 | 
			
		||||
@@ -96,7 +96,9 @@ export default class OfficialBuilds extends BaseDistribution {
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        core.info(
 | 
			
		||||
          'Not found in manifest. Falling back to download directly from Node'
 | 
			
		||||
          `Not found in manifest. Falling back to download directly from ${
 | 
			
		||||
            this.nodeInfo.mirror || 'Node'
 | 
			
		||||
          }`
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
@@ -176,8 +178,9 @@ export default class OfficialBuilds extends BaseDistribution {
 | 
			
		||||
    return version;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected getDistributionUrl(): string {
 | 
			
		||||
    return `https://nodejs.org/dist`;
 | 
			
		||||
  protected getDistributionUrl(mirror: string): string {
 | 
			
		||||
    const url = mirror || 'https://nodejs.org';
 | 
			
		||||
    return `${url}/dist`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getManifest(): Promise<tc.IToolRelease[]> {
 | 
			
		||||
@@ -185,7 +188,7 @@ export default class OfficialBuilds extends BaseDistribution {
 | 
			
		||||
    return tc.getManifestFromRepo(
 | 
			
		||||
      'actions',
 | 
			
		||||
      'node-versions',
 | 
			
		||||
      this.nodeInfo.auth,
 | 
			
		||||
      this.nodeInfo.mirror ? this.nodeInfo.mirrorToken : this.nodeInfo.auth,
 | 
			
		||||
      'main'
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,8 @@ export default class RcBuild extends BaseDistribution {
 | 
			
		||||
    super(nodeInfo);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getDistributionUrl(): string {
 | 
			
		||||
    return 'https://nodejs.org/download/rc';
 | 
			
		||||
  getDistributionUrl(mirror: string): string {
 | 
			
		||||
    const url = mirror || 'https://nodejs.org';
 | 
			
		||||
    return `${url}/download/rc`;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,8 @@ export default class CanaryBuild extends BasePrereleaseNodejs {
 | 
			
		||||
    super(nodeInfo);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected getDistributionUrl(): string {
 | 
			
		||||
    return 'https://nodejs.org/download/v8-canary';
 | 
			
		||||
  protected getDistributionUrl(mirror: string): string {
 | 
			
		||||
    const url = mirror || 'https://nodejs.org';
 | 
			
		||||
    return `${url}/download/v8-canary`;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,8 @@ export async function run() {
 | 
			
		||||
    if (version) {
 | 
			
		||||
      const token = core.getInput('token');
 | 
			
		||||
      const auth = !token ? undefined : `token ${token}`;
 | 
			
		||||
      const mirror = core.getInput('mirror');
 | 
			
		||||
      const mirrorToken = core.getInput('mirror-token');
 | 
			
		||||
      const stable =
 | 
			
		||||
        (core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
 | 
			
		||||
      const checkLatest =
 | 
			
		||||
@@ -45,7 +47,9 @@ export async function run() {
 | 
			
		||||
        checkLatest,
 | 
			
		||||
        auth,
 | 
			
		||||
        stable,
 | 
			
		||||
        arch
 | 
			
		||||
        arch,
 | 
			
		||||
        mirror,
 | 
			
		||||
        mirrorToken
 | 
			
		||||
      };
 | 
			
		||||
      const nodeDistribution = getNodejsDistribution(nodejsInfo);
 | 
			
		||||
      await nodeDistribution.setupNodeJs();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user