diff --git a/__tests__/authutil.test.ts b/__tests__/authutil.test.ts
index 0ed596d..ef1a6fa 100644
--- a/__tests__/authutil.test.ts
+++ b/__tests__/authutil.test.ts
@@ -1,308 +1,308 @@
-import io = require('@actions/io');
-import fs = require('fs');
-import path = require('path');
-
-const fakeSourcesDirForTesting = path.join(
- __dirname,
- 'runner',
- path.join(
- Math.random()
- .toString(36)
- .substring(7)
- ),
- 's'
-);
-
-const invalidNuGetConfig: string = ``;
-
-const emptyNuGetConfig: string = `
-
-`;
-
-const nugetorgNuGetConfig: string = `
-
-
-
-
-`;
-
-const gprnugetorgNuGetConfig: string = `
-
-
-
-
-
-`;
-
-const gprNuGetConfig: string = `
-
-
-
-
-`;
-
-const twogprNuGetConfig: string = `
-
-
-
-
-
-`;
-
-const spaceNuGetConfig: string = `
-
-
-
-
-`;
-
-const azureartifactsNuGetConfig: string = `
-
-
-
-
-`;
-
-const azureartifactsnugetorgNuGetConfig: string = `
-
-
-
-
-
-`;
-
-// We want a NuGet.config one level above the sources directory, so it doesn't trample a user's NuGet.config but is still picked up by NuGet/dotnet.
-const nugetConfigFile = path.join(fakeSourcesDirForTesting, '../nuget.config');
-
-process.env['GITHUB_REPOSITORY'] = 'OwnerName/repo';
-process.env['RUNNER_TEMP'] = fakeSourcesDirForTesting;
-import * as auth from '../src/authutil';
-
-describe('authutil tests', () => {
- beforeEach(async () => {
- await io.rmRF(fakeSourcesDirForTesting);
- await io.mkdirP(fakeSourcesDirForTesting);
- }, 100000);
-
- beforeEach(() => {
- if (fs.existsSync(nugetConfigFile)) {
- fs.unlinkSync(nugetConfigFile);
- }
- process.env['INPUT_OWNER'] = '';
- process.env['NUGET_AUTH_TOKEN'] = '';
- });
-
- it('No existing config, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- await auth.configAuthentication(
- 'https://nuget.pkg.github.com/OwnerName/index.json'
- );
- expect(fs.existsSync(nugetConfigFile)).toBe(true);
- expect(
- fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
- ).toMatchSnapshot();
- });
-
- it('No existing config, auth token environment variable not provided, throws', async () => {
- let thrown = false;
- try {
- await auth.configAuthentication(
- 'https://nuget.pkg.github.com/OwnerName/index.json'
- );
- } catch {
- thrown = true;
- }
- expect(thrown).toBe(true);
- });
-
- it('No existing config, sets up a full NuGet.config with URL and other owner/PAT for GPR', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- process.env['INPUT_OWNER'] = 'otherorg';
- await auth.configAuthentication(
- 'https://nuget.pkg.github.com/otherorg/index.json'
- );
- expect(fs.existsSync(nugetConfigFile)).toBe(true);
- expect(
- fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
- ).toMatchSnapshot();
- });
-
- it('Existing config (invalid), tries to parse an invalid NuGet.config and throws', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- const inputNuGetConfigPath: string = path.join(
- fakeSourcesDirForTesting,
- 'nuget.config'
- );
- fs.writeFileSync(inputNuGetConfigPath, invalidNuGetConfig);
- let thrown = false;
- try {
- await auth.configAuthentication(
- 'https://nuget.pkg.github.com/OwnerName/index.json'
- );
- } catch {
- thrown = true;
- }
- expect(thrown).toBe(true);
- });
-
- it('Existing config w/ no sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- const inputNuGetConfigPath: string = path.join(
- fakeSourcesDirForTesting,
- 'nuget.config'
- );
- fs.writeFileSync(inputNuGetConfigPath, emptyNuGetConfig);
- await auth.configAuthentication(
- 'https://nuget.pkg.github.com/OwnerName/index.json'
- );
- expect(fs.existsSync(nugetConfigFile)).toBe(true);
- expect(
- fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
- ).toMatchSnapshot();
- });
-
- it('Existing config w/ no GPR sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- const inputNuGetConfigPath: string = path.join(
- fakeSourcesDirForTesting,
- 'nuget.config'
- );
- fs.writeFileSync(inputNuGetConfigPath, nugetorgNuGetConfig);
- await auth.configAuthentication(
- 'https://nuget.pkg.github.com/OwnerName/index.json'
- );
- expect(fs.existsSync(nugetConfigFile)).toBe(true);
- expect(
- fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
- ).toMatchSnapshot();
- });
-
- it('Existing config w/ only GPR source, sets up a partial NuGet.config user/PAT for GPR', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- const inputNuGetConfigPath: string = path.join(
- fakeSourcesDirForTesting,
- 'nuget.config'
- );
- fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
- await auth.configAuthentication(
- 'https://nuget.pkg.github.com/OwnerName/index.json'
- );
- expect(fs.existsSync(nugetConfigFile)).toBe(true);
- expect(
- fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
- ).toMatchSnapshot();
- });
-
- it('Existing config w/ GPR source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- const inputNuGetConfigPath: string = path.join(
- fakeSourcesDirForTesting,
- 'nuget.config'
- );
- fs.writeFileSync(inputNuGetConfigPath, gprnugetorgNuGetConfig);
- await auth.configAuthentication(
- 'https://nuget.pkg.github.com/OwnerName/index.json'
- );
- expect(fs.existsSync(nugetConfigFile)).toBe(true);
- expect(
- fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
- ).toMatchSnapshot();
- });
-
- it('Existing config w/ two GPR sources, sets up a partial NuGet.config user/PAT for GPR', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- const inputNuGetConfigPath: string = path.join(
- fakeSourcesDirForTesting,
- 'nuget.config'
- );
- fs.writeFileSync(inputNuGetConfigPath, twogprNuGetConfig);
- await auth.configAuthentication('https://nuget.pkg.github.com');
- expect(fs.existsSync(nugetConfigFile)).toBe(true);
- expect(
- fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
- ).toMatchSnapshot();
- });
-
- it('Existing config w/ spaces in key, throws for now', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- const inputNuGetConfigPath: string = path.join(
- fakeSourcesDirForTesting,
- 'nuget.config'
- );
- fs.writeFileSync(inputNuGetConfigPath, spaceNuGetConfig);
- let thrown = false;
- try {
- await auth.configAuthentication(
- 'https://nuget.pkg.github.com/OwnerName/index.json'
- );
- } catch {
- thrown = true;
- }
- expect(thrown).toBe(true);
- });
-
- it('Existing config not in repo root, sets up a partial NuGet.config user/PAT for GPR', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- const inputNuGetConfigDirectory: string = path.join(
- fakeSourcesDirForTesting,
- 'subfolder'
- );
- const inputNuGetConfigPath: string = path.join(
- inputNuGetConfigDirectory,
- 'nuget.config'
- );
- fs.mkdirSync(inputNuGetConfigDirectory, {recursive: true});
- fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
- await auth.configAuthentication(
- 'https://nuget.pkg.github.com/OwnerName/index.json',
- 'subfolder/nuget.config'
- );
- expect(fs.existsSync(nugetConfigFile)).toBe(true);
- expect(
- fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
- ).toMatchSnapshot();
- });
-
- it('Existing config w/ only Azure Artifacts source, sets up a partial NuGet.config user/PAT for GPR', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- const inputNuGetConfigPath: string = path.join(
- fakeSourcesDirForTesting,
- 'nuget.config'
- );
- fs.writeFileSync(inputNuGetConfigPath, azureartifactsNuGetConfig);
- await auth.configAuthentication(
- 'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json'
- );
- expect(fs.existsSync(nugetConfigFile)).toBe(true);
- expect(
- fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
- ).toMatchSnapshot();
- });
-
- it('Existing config w/ Azure Artifacts source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- const inputNuGetConfigPath: string = path.join(
- fakeSourcesDirForTesting,
- 'nuget.config'
- );
- fs.writeFileSync(inputNuGetConfigPath, azureartifactsnugetorgNuGetConfig);
- await auth.configAuthentication(
- 'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json'
- );
- expect(fs.existsSync(nugetConfigFile)).toBe(true);
- expect(
- fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
- ).toMatchSnapshot();
- });
-
- it('No existing config, sets up a full NuGet.config with URL and token for other source', async () => {
- process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
- await auth.configAuthentication(
- 'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json'
- );
- expect(fs.existsSync(nugetConfigFile)).toBe(true);
- expect(
- fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
- ).toMatchSnapshot();
- });
-});
+import io = require('@actions/io');
+import fs = require('fs');
+import path = require('path');
+
+const fakeSourcesDirForTesting = path.join(
+ __dirname,
+ 'runner',
+ path.join(
+ Math.random()
+ .toString(36)
+ .substring(7)
+ ),
+ 's'
+);
+
+const invalidNuGetConfig: string = ``;
+
+const emptyNuGetConfig: string = `
+
+`;
+
+const nugetorgNuGetConfig: string = `
+
+
+
+
+`;
+
+const gprnugetorgNuGetConfig: string = `
+
+
+
+
+
+`;
+
+const gprNuGetConfig: string = `
+
+
+
+
+`;
+
+const twogprNuGetConfig: string = `
+
+
+
+
+
+`;
+
+const spaceNuGetConfig: string = `
+
+
+
+
+`;
+
+const azureartifactsNuGetConfig: string = `
+
+
+
+
+`;
+
+const azureartifactsnugetorgNuGetConfig: string = `
+
+
+
+
+
+`;
+
+// We want a NuGet.config one level above the sources directory, so it doesn't trample a user's NuGet.config but is still picked up by NuGet/dotnet.
+const nugetConfigFile = path.join(fakeSourcesDirForTesting, '../nuget.config');
+
+process.env['GITHUB_REPOSITORY'] = 'OwnerName/repo';
+process.env['RUNNER_TEMP'] = fakeSourcesDirForTesting;
+import * as auth from '../src/authutil';
+
+describe('authutil tests', () => {
+ beforeEach(async () => {
+ await io.rmRF(fakeSourcesDirForTesting);
+ await io.mkdirP(fakeSourcesDirForTesting);
+ }, 100000);
+
+ beforeEach(() => {
+ if (fs.existsSync(nugetConfigFile)) {
+ fs.unlinkSync(nugetConfigFile);
+ }
+ process.env['INPUT_OWNER'] = '';
+ process.env['NUGET_AUTH_TOKEN'] = '';
+ });
+
+ it('No existing config, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ await auth.configAuthentication(
+ 'https://nuget.pkg.github.com/OwnerName/index.json'
+ );
+ expect(fs.existsSync(nugetConfigFile)).toBe(true);
+ expect(
+ fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
+ ).toMatchSnapshot();
+ });
+
+ it('No existing config, auth token environment variable not provided, throws', async () => {
+ let thrown = false;
+ try {
+ await auth.configAuthentication(
+ 'https://nuget.pkg.github.com/OwnerName/index.json'
+ );
+ } catch {
+ thrown = true;
+ }
+ expect(thrown).toBe(true);
+ });
+
+ it('No existing config, sets up a full NuGet.config with URL and other owner/PAT for GPR', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ process.env['INPUT_OWNER'] = 'otherorg';
+ await auth.configAuthentication(
+ 'https://nuget.pkg.github.com/otherorg/index.json'
+ );
+ expect(fs.existsSync(nugetConfigFile)).toBe(true);
+ expect(
+ fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
+ ).toMatchSnapshot();
+ });
+
+ it('Existing config (invalid), tries to parse an invalid NuGet.config and throws', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ const inputNuGetConfigPath: string = path.join(
+ fakeSourcesDirForTesting,
+ 'nuget.config'
+ );
+ fs.writeFileSync(inputNuGetConfigPath, invalidNuGetConfig);
+ let thrown = false;
+ try {
+ await auth.configAuthentication(
+ 'https://nuget.pkg.github.com/OwnerName/index.json'
+ );
+ } catch {
+ thrown = true;
+ }
+ expect(thrown).toBe(true);
+ });
+
+ it('Existing config w/ no sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ const inputNuGetConfigPath: string = path.join(
+ fakeSourcesDirForTesting,
+ 'nuget.config'
+ );
+ fs.writeFileSync(inputNuGetConfigPath, emptyNuGetConfig);
+ await auth.configAuthentication(
+ 'https://nuget.pkg.github.com/OwnerName/index.json'
+ );
+ expect(fs.existsSync(nugetConfigFile)).toBe(true);
+ expect(
+ fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
+ ).toMatchSnapshot();
+ });
+
+ it('Existing config w/ no GPR sources, sets up a full NuGet.config with URL and user/PAT for GPR', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ const inputNuGetConfigPath: string = path.join(
+ fakeSourcesDirForTesting,
+ 'nuget.config'
+ );
+ fs.writeFileSync(inputNuGetConfigPath, nugetorgNuGetConfig);
+ await auth.configAuthentication(
+ 'https://nuget.pkg.github.com/OwnerName/index.json'
+ );
+ expect(fs.existsSync(nugetConfigFile)).toBe(true);
+ expect(
+ fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
+ ).toMatchSnapshot();
+ });
+
+ it('Existing config w/ only GPR source, sets up a partial NuGet.config user/PAT for GPR', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ const inputNuGetConfigPath: string = path.join(
+ fakeSourcesDirForTesting,
+ 'nuget.config'
+ );
+ fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
+ await auth.configAuthentication(
+ 'https://nuget.pkg.github.com/OwnerName/index.json'
+ );
+ expect(fs.existsSync(nugetConfigFile)).toBe(true);
+ expect(
+ fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
+ ).toMatchSnapshot();
+ });
+
+ it('Existing config w/ GPR source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ const inputNuGetConfigPath: string = path.join(
+ fakeSourcesDirForTesting,
+ 'nuget.config'
+ );
+ fs.writeFileSync(inputNuGetConfigPath, gprnugetorgNuGetConfig);
+ await auth.configAuthentication(
+ 'https://nuget.pkg.github.com/OwnerName/index.json'
+ );
+ expect(fs.existsSync(nugetConfigFile)).toBe(true);
+ expect(
+ fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
+ ).toMatchSnapshot();
+ });
+
+ it('Existing config w/ two GPR sources, sets up a partial NuGet.config user/PAT for GPR', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ const inputNuGetConfigPath: string = path.join(
+ fakeSourcesDirForTesting,
+ 'nuget.config'
+ );
+ fs.writeFileSync(inputNuGetConfigPath, twogprNuGetConfig);
+ await auth.configAuthentication('https://nuget.pkg.github.com');
+ expect(fs.existsSync(nugetConfigFile)).toBe(true);
+ expect(
+ fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
+ ).toMatchSnapshot();
+ });
+
+ it('Existing config w/ spaces in key, throws for now', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ const inputNuGetConfigPath: string = path.join(
+ fakeSourcesDirForTesting,
+ 'nuget.config'
+ );
+ fs.writeFileSync(inputNuGetConfigPath, spaceNuGetConfig);
+ let thrown = false;
+ try {
+ await auth.configAuthentication(
+ 'https://nuget.pkg.github.com/OwnerName/index.json'
+ );
+ } catch {
+ thrown = true;
+ }
+ expect(thrown).toBe(true);
+ });
+
+ it('Existing config not in repo root, sets up a partial NuGet.config user/PAT for GPR', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ const inputNuGetConfigDirectory: string = path.join(
+ fakeSourcesDirForTesting,
+ 'subfolder'
+ );
+ const inputNuGetConfigPath: string = path.join(
+ inputNuGetConfigDirectory,
+ 'nuget.config'
+ );
+ fs.mkdirSync(inputNuGetConfigDirectory, {recursive: true});
+ fs.writeFileSync(inputNuGetConfigPath, gprNuGetConfig);
+ await auth.configAuthentication(
+ 'https://nuget.pkg.github.com/OwnerName/index.json',
+ 'subfolder/nuget.config'
+ );
+ expect(fs.existsSync(nugetConfigFile)).toBe(true);
+ expect(
+ fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
+ ).toMatchSnapshot();
+ });
+
+ it('Existing config w/ only Azure Artifacts source, sets up a partial NuGet.config user/PAT for GPR', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ const inputNuGetConfigPath: string = path.join(
+ fakeSourcesDirForTesting,
+ 'nuget.config'
+ );
+ fs.writeFileSync(inputNuGetConfigPath, azureartifactsNuGetConfig);
+ await auth.configAuthentication(
+ 'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json'
+ );
+ expect(fs.existsSync(nugetConfigFile)).toBe(true);
+ expect(
+ fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
+ ).toMatchSnapshot();
+ });
+
+ it('Existing config w/ Azure Artifacts source and NuGet.org, sets up a partial NuGet.config user/PAT for GPR', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ const inputNuGetConfigPath: string = path.join(
+ fakeSourcesDirForTesting,
+ 'nuget.config'
+ );
+ fs.writeFileSync(inputNuGetConfigPath, azureartifactsnugetorgNuGetConfig);
+ await auth.configAuthentication(
+ 'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json'
+ );
+ expect(fs.existsSync(nugetConfigFile)).toBe(true);
+ expect(
+ fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
+ ).toMatchSnapshot();
+ });
+
+ it('No existing config, sets up a full NuGet.config with URL and token for other source', async () => {
+ process.env['NUGET_AUTH_TOKEN'] = 'TEST_FAKE_AUTH_TOKEN';
+ await auth.configAuthentication(
+ 'https://pkgs.dev.azure.com/amullans/_packaging/GitHubBuilds/nuget/v3/index.json'
+ );
+ expect(fs.existsSync(nugetConfigFile)).toBe(true);
+ expect(
+ fs.readFileSync(nugetConfigFile, {encoding: 'utf8'})
+ ).toMatchSnapshot();
+ });
+});
diff --git a/__tests__/installer.test.ts b/__tests__/installer.test.ts
index bafd74c..6709453 100644
--- a/__tests__/installer.test.ts
+++ b/__tests__/installer.test.ts
@@ -27,15 +27,16 @@ describe('version tests', () => {
}
);
- each([['3.1.x', '3.1'], ['1.1.*', '1.1'], ['2.0', '2.0']]).test(
- "Generic version '%s' should be '%s'",
- (vers, resVers) => {
- let versInfo = new installer.DotNetVersionInfo(vers);
+ each([
+ ['3.1.x', '3.1'],
+ ['1.1.*', '1.1'],
+ ['2.0', '2.0']
+ ]).test("Generic version '%s' should be '%s'", (vers, resVers) => {
+ let versInfo = new installer.DotNetVersionInfo(vers);
- expect(versInfo.isExactVersion()).toBe(false);
- expect(versInfo.version()).toBe(resVers);
- }
- );
+ expect(versInfo.isExactVersion()).toBe(false);
+ expect(versInfo.version()).toBe(resVers);
+ });
each([
'',
diff --git a/dist/index.js b/dist/index.js
index a7814cd..54b0a68 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -17816,9 +17816,11 @@ class SxSDotnetCoreInstaller {
console.log(`Setting up .NET SDK from ${toolPath}...`);
let entries = fs_2.readdirSync(toolPath);
for (var entry of entries) {
- yield io.cp(path.join(toolPath, entry), dest, { recursive: true, force: true });
+ yield io.cp(path.join(toolPath, entry), dest, {
+ recursive: true,
+ force: true
+ });
}
- ;
}
// cache SxS directory as a tool
let cachedDir = yield tc.cacheDir(dest, this.cachedToolName, 'sxs', this.arch);
diff --git a/package-lock.json b/package-lock.json
index 6b4beb6..7638939 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3688,9 +3688,9 @@
"dev": true
},
"prettier": {
- "version": "1.18.2",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz",
- "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==",
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
+ "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
"dev": true
},
"pretty-format": {
diff --git a/package.json b/package.json
index 21f6a73..d35094b 100644
--- a/package.json
+++ b/package.json
@@ -40,7 +40,7 @@
"@zeit/ncc": "^0.21.0",
"jest": "^26.0.1",
"jest-circus": "^26.0.1",
- "prettier": "^1.17.1",
+ "prettier": "^1.19.1",
"ts-jest": "^26.0.0",
"typescript": "^3.9.2",
"wget-improved": "^3.0.2"
diff --git a/src/authutil.ts b/src/authutil.ts
index 69f3750..621fb79 100644
--- a/src/authutil.ts
+++ b/src/authutil.ts
@@ -1,136 +1,136 @@
-import * as fs from 'fs';
-import * as path from 'path';
-import * as core from '@actions/core';
-import * as github from '@actions/github';
-import * as xmlbuilder from 'xmlbuilder';
-import * as xmlParser from 'fast-xml-parser';
-
-export function configAuthentication(
- feedUrl: string,
- existingFileLocation: string = ''
-) {
- const existingNuGetConfig: string = path.resolve(
- process.env['RUNNER_TEMP'] || process.cwd(),
- existingFileLocation == '' ? 'nuget.config' : existingFileLocation
- );
-
- const tempNuGetConfig: string = path.resolve(
- process.env['RUNNER_TEMP'] || process.cwd(),
- '../',
- 'nuget.config'
- );
-
- writeFeedToFile(feedUrl, existingNuGetConfig, tempNuGetConfig);
-}
-
-function writeFeedToFile(
- feedUrl: string,
- existingFileLocation: string,
- tempFileLocation: string
-) {
- console.log(
- `dotnet-auth: Finding any source references in ${existingFileLocation}, writing a new temporary configuration file with credentials to ${tempFileLocation}`
- );
- let xml: xmlbuilder.XMLElement;
- let sourceKeys: string[] = [];
- let owner: string = core.getInput('owner');
- let sourceUrl: string = feedUrl;
- if (!owner) {
- owner = github.context.repo.owner;
- }
-
- if (!process.env.NUGET_AUTH_TOKEN || process.env.NUGET_AUTH_TOKEN == '') {
- throw new Error(
- 'The NUGET_AUTH_TOKEN environment variable was not provided. In this step, add the following: \r\nenv:\r\n NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}'
- );
- }
-
- if (fs.existsSync(existingFileLocation)) {
- // get key from existing NuGet.config so NuGet/dotnet can match credentials
- const curContents: string = fs.readFileSync(existingFileLocation, 'utf8');
- var json = xmlParser.parse(curContents, {ignoreAttributes: false});
-
- if (typeof json.configuration == 'undefined') {
- throw new Error(`The provided NuGet.config seems invalid.`);
- }
- if (typeof json.configuration.packageSources != 'undefined') {
- if (typeof json.configuration.packageSources.add != 'undefined') {
- // file has at least one
- if (typeof json.configuration.packageSources.add[0] == 'undefined') {
- // file has only one
- if (
- json.configuration.packageSources.add['@_value']
- .toLowerCase()
- .includes(feedUrl.toLowerCase())
- ) {
- let key = json.configuration.packageSources.add['@_key'];
- sourceKeys.push(key);
- core.debug(`Found a URL with key ${key}`);
- }
- } else {
- // file has 2+
- for (
- let i = 0;
- i < json.configuration.packageSources.add.length;
- i++
- ) {
- const source = json.configuration.packageSources.add[i];
- const value = source['@_value'];
- core.debug(`source '${value}'`);
- if (value.toLowerCase().includes(feedUrl.toLowerCase())) {
- let key = source['@_key'];
- sourceKeys.push(key);
- core.debug(`Found a URL with key ${key}`);
- }
- }
- }
- }
- }
- }
-
- xml = xmlbuilder
- .create('configuration')
- .ele('config')
- .ele('add', {key: 'defaultPushSource', value: sourceUrl})
- .up()
- .up();
-
- if (sourceKeys.length == 0) {
- let keystring = 'Source';
- xml = xml
- .ele('packageSources')
- .ele('add', {key: keystring, value: sourceUrl})
- .up()
- .up();
- sourceKeys.push(keystring);
- }
- xml = xml.ele('packageSourceCredentials');
-
- sourceKeys.forEach(key => {
- if (key.indexOf(' ') > -1) {
- throw new Error(
- "This action currently can't handle source names with spaces. Remove the space from your repo's NuGet.config and try again."
- );
- }
-
- xml = xml
- .ele(key)
- .ele('add', {key: 'Username', value: owner})
- .up()
- .ele('add', {
- key: 'ClearTextPassword',
- value: process.env.NUGET_AUTH_TOKEN
- })
- .up()
- .up();
- });
-
- // If NuGet fixes itself such that on Linux it can look for environment variables in the config file (it doesn't seem to work today),
- // use this for the value above
- // process.platform == 'win32'
- // ? '%NUGET_AUTH_TOKEN%'
- // : '$NUGET_AUTH_TOKEN'
-
- var output = xml.end({pretty: true});
- fs.writeFileSync(tempFileLocation, output);
-}
+import * as fs from 'fs';
+import * as path from 'path';
+import * as core from '@actions/core';
+import * as github from '@actions/github';
+import * as xmlbuilder from 'xmlbuilder';
+import * as xmlParser from 'fast-xml-parser';
+
+export function configAuthentication(
+ feedUrl: string,
+ existingFileLocation: string = ''
+) {
+ const existingNuGetConfig: string = path.resolve(
+ process.env['RUNNER_TEMP'] || process.cwd(),
+ existingFileLocation == '' ? 'nuget.config' : existingFileLocation
+ );
+
+ const tempNuGetConfig: string = path.resolve(
+ process.env['RUNNER_TEMP'] || process.cwd(),
+ '../',
+ 'nuget.config'
+ );
+
+ writeFeedToFile(feedUrl, existingNuGetConfig, tempNuGetConfig);
+}
+
+function writeFeedToFile(
+ feedUrl: string,
+ existingFileLocation: string,
+ tempFileLocation: string
+) {
+ console.log(
+ `dotnet-auth: Finding any source references in ${existingFileLocation}, writing a new temporary configuration file with credentials to ${tempFileLocation}`
+ );
+ let xml: xmlbuilder.XMLElement;
+ let sourceKeys: string[] = [];
+ let owner: string = core.getInput('owner');
+ let sourceUrl: string = feedUrl;
+ if (!owner) {
+ owner = github.context.repo.owner;
+ }
+
+ if (!process.env.NUGET_AUTH_TOKEN || process.env.NUGET_AUTH_TOKEN == '') {
+ throw new Error(
+ 'The NUGET_AUTH_TOKEN environment variable was not provided. In this step, add the following: \r\nenv:\r\n NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}'
+ );
+ }
+
+ if (fs.existsSync(existingFileLocation)) {
+ // get key from existing NuGet.config so NuGet/dotnet can match credentials
+ const curContents: string = fs.readFileSync(existingFileLocation, 'utf8');
+ var json = xmlParser.parse(curContents, {ignoreAttributes: false});
+
+ if (typeof json.configuration == 'undefined') {
+ throw new Error(`The provided NuGet.config seems invalid.`);
+ }
+ if (typeof json.configuration.packageSources != 'undefined') {
+ if (typeof json.configuration.packageSources.add != 'undefined') {
+ // file has at least one
+ if (typeof json.configuration.packageSources.add[0] == 'undefined') {
+ // file has only one
+ if (
+ json.configuration.packageSources.add['@_value']
+ .toLowerCase()
+ .includes(feedUrl.toLowerCase())
+ ) {
+ let key = json.configuration.packageSources.add['@_key'];
+ sourceKeys.push(key);
+ core.debug(`Found a URL with key ${key}`);
+ }
+ } else {
+ // file has 2+
+ for (
+ let i = 0;
+ i < json.configuration.packageSources.add.length;
+ i++
+ ) {
+ const source = json.configuration.packageSources.add[i];
+ const value = source['@_value'];
+ core.debug(`source '${value}'`);
+ if (value.toLowerCase().includes(feedUrl.toLowerCase())) {
+ let key = source['@_key'];
+ sourceKeys.push(key);
+ core.debug(`Found a URL with key ${key}`);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ xml = xmlbuilder
+ .create('configuration')
+ .ele('config')
+ .ele('add', {key: 'defaultPushSource', value: sourceUrl})
+ .up()
+ .up();
+
+ if (sourceKeys.length == 0) {
+ let keystring = 'Source';
+ xml = xml
+ .ele('packageSources')
+ .ele('add', {key: keystring, value: sourceUrl})
+ .up()
+ .up();
+ sourceKeys.push(keystring);
+ }
+ xml = xml.ele('packageSourceCredentials');
+
+ sourceKeys.forEach(key => {
+ if (key.indexOf(' ') > -1) {
+ throw new Error(
+ "This action currently can't handle source names with spaces. Remove the space from your repo's NuGet.config and try again."
+ );
+ }
+
+ xml = xml
+ .ele(key)
+ .ele('add', {key: 'Username', value: owner})
+ .up()
+ .ele('add', {
+ key: 'ClearTextPassword',
+ value: process.env.NUGET_AUTH_TOKEN
+ })
+ .up()
+ .up();
+ });
+
+ // If NuGet fixes itself such that on Linux it can look for environment variables in the config file (it doesn't seem to work today),
+ // use this for the value above
+ // process.platform == 'win32'
+ // ? '%NUGET_AUTH_TOKEN%'
+ // : '$NUGET_AUTH_TOKEN'
+
+ var output = xml.end({pretty: true});
+ fs.writeFileSync(tempFileLocation, output);
+}
diff --git a/src/installer.ts b/src/installer.ts
index 0120c57..fb7c3a5 100644
--- a/src/installer.ts
+++ b/src/installer.ts
@@ -1,549 +1,552 @@
-// Load tempDirectory before it gets wiped by tool-cache
-let tempDirectory = process.env['RUNNER_TEMPDIRECTORY'] || '';
-import * as core from '@actions/core';
-import * as exec from '@actions/exec';
-import * as io from '@actions/io';
-import * as tc from '@actions/tool-cache';
-import hc = require('@actions/http-client');
-import {chmodSync} from 'fs';
-import {readdirSync} from 'fs';
-import * as os from 'os';
-import * as path from 'path';
-import * as semver from 'semver';
-import uuidV4 from 'uuid/v4'
-
-const IS_WINDOWS = process.platform === 'win32';
-
-if (!tempDirectory) {
- let baseLocation;
- if (IS_WINDOWS) {
- // On windows use the USERPROFILE env variable
- baseLocation = process.env['USERPROFILE'] || 'C:\\';
- } else {
- if (process.platform === 'darwin') {
- baseLocation = '/Users';
- } else {
- baseLocation = '/home';
- }
- }
- tempDirectory = path.join(baseLocation, 'actions', 'temp');
-}
-
-/**
- * Represents the inputted version information
- */
-export class DotNetVersionInfo {
- private fullversion: string;
- private isExactVersionSet: boolean = false;
-
- constructor(version: string) {
- // Check for exact match
- if (semver.valid(semver.clean(version) || '') != null) {
- this.fullversion = semver.clean(version) as string;
- this.isExactVersionSet = true;
-
- return;
- }
-
- //Note: No support for previews when using generic
- let parts: string[] = version.split('.');
-
- if (parts.length < 2 || parts.length > 3) this.throwInvalidVersionFormat();
-
- if (parts.length == 3 && parts[2] !== 'x' && parts[2] !== '*') {
- this.throwInvalidVersionFormat();
- }
-
- let major = this.getVersionNumberOrThrow(parts[0]);
- let minor = this.getVersionNumberOrThrow(parts[1]);
-
- this.fullversion = major + '.' + minor;
- }
-
- private getVersionNumberOrThrow(input: string): number {
- try {
- if (!input || input.trim() === '') this.throwInvalidVersionFormat();
-
- let number = Number(input);
-
- if (Number.isNaN(number) || number < 0) this.throwInvalidVersionFormat();
-
- return number;
- } catch {
- this.throwInvalidVersionFormat();
- return -1;
- }
- }
-
- private throwInvalidVersionFormat() {
- throw 'Invalid version format! Supported: 1.2.3, 1.2, 1.2.x, 1.2.*';
- }
-
- /**
- * If true exacatly one version should be resolved
- */
- public isExactVersion(): boolean {
- return this.isExactVersionSet;
- }
-
- public version(): string {
- return this.fullversion;
- }
-}
-
-/**
- * Represents a resolved version from the Web-Api
- */
-class ResolvedVersionInfo {
- downloadUrls: string[];
- resolvedVersion: string;
-
- constructor(downloadUrls: string[], resolvedVersion: string) {
- if (downloadUrls.length === 0) {
- throw 'DownloadUrls can not be empty';
- }
-
- if (!resolvedVersion) {
- throw 'Resolved version is invalid';
- }
-
- this.downloadUrls = downloadUrls;
- this.resolvedVersion = resolvedVersion;
- }
-}
-
-export class DotnetCoreInstaller {
- constructor(version: string) {
- this.versionInfo = new DotNetVersionInfo(version);
- this.cachedToolName = 'dncs';
- this.arch = 'x64';
- }
-
- public async installDotnet(): Promise {
- // Check cache
- let toolPath: string = '';
- let osSuffixes = await this.detectMachineOS();
- let parts = osSuffixes[0].split('-');
- if (parts.length > 1) {
- this.arch = parts[1];
- }
-
- // If version is not generic -> look up cache
- if (this.versionInfo.isExactVersion())
- toolPath = this.getLocalTool(this.versionInfo.version());
-
- if (!toolPath) {
- // download, extract, cache
- console.log('Getting a download url', this.versionInfo.version());
- let resolvedVersionInfo = await this.resolveInfos(
- osSuffixes,
- this.versionInfo
- );
-
- //Check if cache exists for resolved version
- toolPath = this.getLocalTool(resolvedVersionInfo.resolvedVersion);
- if (!toolPath) {
- //If not exists install it
- toolPath = await this.downloadAndInstall(resolvedVersionInfo);
- } else {
- console.log('Using cached tool');
- }
- } else {
- console.log('Using cached tool');
- }
-
- // Need to set this so that .NET Core global tools find the right locations.
- core.exportVariable('DOTNET_ROOT', toolPath);
-
- // Prepend the tools path. instructs the agent to prepend for future tasks
- core.addPath(toolPath);
-
- return toolPath;
- }
-
- private getLocalTool(version: string): string {
- console.log('Checking tool cache', version);
- return tc.find(this.cachedToolName, version, this.arch);
- }
-
- private async detectMachineOS(): Promise {
- let osSuffix: string[] = [];
- let output = '';
-
- let resultCode = 0;
- if (IS_WINDOWS) {
- let escapedScript = path
- .join(__dirname, '..', 'externals', 'get-os-platform.ps1')
- .replace(/'/g, "''");
- let command = `& '${escapedScript}'`;
-
- const powershellPath = await io.which('powershell', true);
- resultCode = await exec.exec(
- `"${powershellPath}"`,
- [
- '-NoLogo',
- '-Sta',
- '-NoProfile',
- '-NonInteractive',
- '-ExecutionPolicy',
- 'Unrestricted',
- '-Command',
- command
- ],
- {
- listeners: {
- stdout: (data: Buffer) => {
- output += data.toString();
- }
- }
- }
- );
- } else {
- let scriptPath = path.join(
- __dirname,
- '..',
- 'externals',
- 'get-os-distro.sh'
- );
- chmodSync(scriptPath, '777');
-
- const toolPath = await io.which(scriptPath, true);
- resultCode = await exec.exec(`"${toolPath}"`, [], {
- listeners: {
- stdout: (data: Buffer) => {
- output += data.toString();
- }
- }
- });
- }
-
- if (resultCode != 0) {
- throw `Failed to detect os with result code ${resultCode}. Output: ${output}`;
- }
-
- let index;
- if ((index = output.indexOf('Primary:')) >= 0) {
- let primary = output.substr(index + 'Primary:'.length).split(os.EOL)[0];
- osSuffix.push(primary);
- }
-
- if ((index = output.indexOf('Legacy:')) >= 0) {
- let legacy = output.substr(index + 'Legacy:'.length).split(os.EOL)[0];
- osSuffix.push(legacy);
- }
-
- if (osSuffix.length == 0) {
- throw 'Could not detect platform';
- }
-
- return osSuffix;
- }
-
- private async downloadAndInstall(resolvedVersionInfo: ResolvedVersionInfo) {
- let downloaded = false;
- let downloadPath = '';
- for (const url of resolvedVersionInfo.downloadUrls) {
- try {
- downloadPath = await tc.downloadTool(url);
- downloaded = true;
- break;
- } catch (error) {
- console.log('Could not Download', url, JSON.stringify(error));
- }
- }
-
- if (!downloaded) {
- throw 'Failed to download package';
- }
-
- // extract
- console.log('Extracting Package', downloadPath);
- let extPath: string = IS_WINDOWS
- ? await tc.extractZip(downloadPath)
- : await tc.extractTar(downloadPath);
-
- // cache tool
- console.log('Caching tool');
- let cachedDir = await tc.cacheDir(
- extPath,
- this.cachedToolName,
- resolvedVersionInfo.resolvedVersion,
- this.arch
- );
-
- console.log('Successfully installed', resolvedVersionInfo.resolvedVersion);
- return cachedDir;
- }
-
- // OsSuffixes - The suffix which is a part of the file name ex- linux-x64, windows-x86
- // Type - SDK / Runtime
- // versionInfo - versionInfo of the SDK/Runtime
- async resolveInfos(
- osSuffixes: string[],
- versionInfo: DotNetVersionInfo
- ): Promise {
- const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
- allowRetries: true,
- maxRetries: 3
- });
-
- const releasesJsonUrl: string = await this.getReleasesJsonUrl(
- httpClient,
- versionInfo.version().split('.')
- );
-
- const releasesResponse = await httpClient.getJson(releasesJsonUrl);
- const releasesResult = releasesResponse.result || {};
- let releasesInfo: any[] = releasesResult['releases'];
- releasesInfo = releasesInfo.filter((releaseInfo: any) => {
- return (
- semver.satisfies(
- releaseInfo['sdk']['version'],
- versionInfo.version()
- ) ||
- semver.satisfies(
- releaseInfo['sdk']['version-display'],
- versionInfo.version()
- )
- );
- });
-
- // Exclude versions that are newer than the latest if using not exact
- if (!versionInfo.isExactVersion()) {
- let latestSdk: string = releasesResult['latest-sdk'];
-
- releasesInfo = releasesInfo.filter((releaseInfo: any) =>
- semver.lte(releaseInfo['sdk']['version'], latestSdk)
- );
- }
-
- // Sort for latest version
- releasesInfo = releasesInfo.sort((a, b) =>
- semver.rcompare(a['sdk']['version'], b['sdk']['version'])
- );
-
- let downloadedVersion: string = '';
- let downloadUrls: string[] = [];
-
- if (releasesInfo.length != 0) {
- let release = releasesInfo[0];
-
- downloadedVersion = release['sdk']['version'];
-
- let files: any[] = release['sdk']['files'];
- files = files.filter((file: any) => {
- if (file['rid'] == osSuffixes[0] || file['rid'] == osSuffixes[1]) {
- return (
- file['url'].endsWith('.zip') || file['url'].endsWith('.tar.gz')
- );
- }
- });
-
- if (files.length > 0) {
- files.forEach((file: any) => {
- downloadUrls.push(file['url']);
- });
- } else {
- throw `The specified version's download links are not correctly formed in the supported versions document => ${releasesJsonUrl}`;
- }
- } else {
- console.log(
- `Could not fetch download information for version ${versionInfo.version()}`
- );
-
- if (versionInfo.isExactVersion()) {
- console.log('Using fallback');
-
- downloadUrls = await this.getFallbackDownloadUrls(
- versionInfo.version()
- );
- downloadedVersion = versionInfo.version();
- } else {
- console.log('Unable to use fallback, version is generic!');
- }
- }
-
- if (downloadUrls.length == 0) {
- throw `Could not construct download URL. Please ensure that specified version ${versionInfo.version()}/${downloadedVersion} is valid.`;
- }
-
- core.debug(`Got download urls ${downloadUrls}`);
-
- return new ResolvedVersionInfo(downloadUrls, downloadedVersion);
- }
-
- private async getReleasesJsonUrl(
- httpClient: hc.HttpClient,
- versionParts: string[]
- ): Promise {
- const response = await httpClient.getJson(DotNetCoreIndexUrl);
- const result = response.result || {};
- let releasesInfo: any[] = result['releases-index'];
- releasesInfo = releasesInfo.filter((info: any) => {
- // channel-version is the first 2 elements of the version (e.g. 2.1), filter out versions that don't match 2.1.x.
- const sdkParts: string[] = info['channel-version'].split('.');
- if (versionParts.length >= 2 && versionParts[1] != 'x') {
- return versionParts[0] == sdkParts[0] && versionParts[1] == sdkParts[1];
- }
- return versionParts[0] == sdkParts[0];
- });
- if (releasesInfo.length === 0) {
- throw `Could not find info for version ${versionParts.join(
- '.'
- )} at ${DotNetCoreIndexUrl}`;
- }
- return releasesInfo[0]['releases.json'];
- }
-
- private async getFallbackDownloadUrls(version: string): Promise {
- let primaryUrlSearchString: string;
- let legacyUrlSearchString: string;
- let output = '';
- let resultCode = 0;
-
- if (IS_WINDOWS) {
- let escapedScript = path
- .join(__dirname, '..', 'externals', 'install-dotnet.ps1')
- .replace(/'/g, "''");
- let command = `& '${escapedScript}' -Version ${version} -DryRun`;
-
- const powershellPath = await io.which('powershell', true);
- resultCode = await exec.exec(
- `"${powershellPath}"`,
- [
- '-NoLogo',
- '-Sta',
- '-NoProfile',
- '-NonInteractive',
- '-ExecutionPolicy',
- 'Unrestricted',
- '-Command',
- command
- ],
- {
- listeners: {
- stdout: (data: Buffer) => {
- output += data.toString();
- }
- }
- }
- );
-
- primaryUrlSearchString = 'dotnet-install: Primary named payload URL: ';
- legacyUrlSearchString = 'dotnet-install: Legacy named payload URL: ';
- } else {
- let escapedScript = path
- .join(__dirname, '..', 'externals', 'install-dotnet.sh')
- .replace(/'/g, "''");
- chmodSync(escapedScript, '777');
-
- const scriptPath = await io.which(escapedScript, true);
- resultCode = await exec.exec(
- `"${scriptPath}"`,
- ['--version', version, '--dry-run'],
- {
- listeners: {
- stdout: (data: Buffer) => {
- output += data.toString();
- }
- }
- }
- );
-
- primaryUrlSearchString = 'dotnet-install: Primary named payload URL: ';
- legacyUrlSearchString = 'dotnet-install: Legacy named payload URL: ';
- }
-
- if (resultCode != 0) {
- throw `Failed to get download urls with result code ${resultCode}. ${output}`;
- }
-
- let primaryUrl: string = '';
- let legacyUrl: string = '';
- if (!!output && output.length > 0) {
- let lines: string[] = output.split(os.EOL);
-
- // Fallback to \n if initial split doesn't work (not consistent across versions)
- if (lines.length === 1) {
- lines = output.split('\n');
- }
- if (!!lines && lines.length > 0) {
- lines.forEach((line: string) => {
- if (!line) {
- return;
- }
- var primarySearchStringIndex = line.indexOf(primaryUrlSearchString);
- if (primarySearchStringIndex > -1) {
- primaryUrl = line.substring(
- primarySearchStringIndex + primaryUrlSearchString.length
- );
- return;
- }
-
- var legacySearchStringIndex = line.indexOf(legacyUrlSearchString);
- if (legacySearchStringIndex > -1) {
- legacyUrl = line.substring(
- legacySearchStringIndex + legacyUrlSearchString.length
- );
- return;
- }
- });
- }
- }
-
- return [primaryUrl, legacyUrl];
- }
-
- private versionInfo: DotNetVersionInfo;
- private cachedToolName: string;
- private arch: string;
-}
-
-export class SxSDotnetCoreInstaller {
- constructor(toolPaths: Array) {
- this.toolPaths = toolPaths;
- this.cachedToolName = 'dncs';
- this.arch = 'x64';
- }
-
- public async setupSxs() {
- // create a temp dir
- const tempDirectory = process.env['RUNNER_TEMP'] || '';
- const dest = path.join(tempDirectory, uuidV4());
- await io.mkdirP(dest)
-
- console.log(`Setting up SxS .NET SDK installation in ${dest}...`);
-
- // copy all the SDK versions into a temporary SxS directory
- for(var toolPath of this.toolPaths) {
- console.log(`Setting up .NET SDK from ${toolPath}...`);
- let entries = readdirSync(toolPath);
- for (var entry of entries) {
- await io.cp(path.join(toolPath, entry), dest, { recursive: true, force: true });
- };
- }
-
- // cache SxS directory as a tool
- let cachedDir = await tc.cacheDir(
- dest,
- this.cachedToolName,
- 'sxs',
- this.arch
- );
-
- console.log(`SxS .NET SDK installation in ${cachedDir}`)
-
- // Need to set this so that .NET Core global tools find the right locations.
- core.exportVariable('DOTNET_ROOT', cachedDir);
-
- // Prepend the tools path. instructs the agent to prepend for future tasks
- core.addPath(cachedDir);
- }
-
- private toolPaths: Array;
- private cachedToolName: string;
- private arch: string;
-}
-
-const DotNetCoreIndexUrl: string =
- 'https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/releases-index.json';
+// Load tempDirectory before it gets wiped by tool-cache
+let tempDirectory = process.env['RUNNER_TEMPDIRECTORY'] || '';
+import * as core from '@actions/core';
+import * as exec from '@actions/exec';
+import * as io from '@actions/io';
+import * as tc from '@actions/tool-cache';
+import hc = require('@actions/http-client');
+import {chmodSync} from 'fs';
+import {readdirSync} from 'fs';
+import * as os from 'os';
+import * as path from 'path';
+import * as semver from 'semver';
+import uuidV4 from 'uuid/v4';
+
+const IS_WINDOWS = process.platform === 'win32';
+
+if (!tempDirectory) {
+ let baseLocation;
+ if (IS_WINDOWS) {
+ // On windows use the USERPROFILE env variable
+ baseLocation = process.env['USERPROFILE'] || 'C:\\';
+ } else {
+ if (process.platform === 'darwin') {
+ baseLocation = '/Users';
+ } else {
+ baseLocation = '/home';
+ }
+ }
+ tempDirectory = path.join(baseLocation, 'actions', 'temp');
+}
+
+/**
+ * Represents the inputted version information
+ */
+export class DotNetVersionInfo {
+ private fullversion: string;
+ private isExactVersionSet: boolean = false;
+
+ constructor(version: string) {
+ // Check for exact match
+ if (semver.valid(semver.clean(version) || '') != null) {
+ this.fullversion = semver.clean(version) as string;
+ this.isExactVersionSet = true;
+
+ return;
+ }
+
+ //Note: No support for previews when using generic
+ let parts: string[] = version.split('.');
+
+ if (parts.length < 2 || parts.length > 3) this.throwInvalidVersionFormat();
+
+ if (parts.length == 3 && parts[2] !== 'x' && parts[2] !== '*') {
+ this.throwInvalidVersionFormat();
+ }
+
+ let major = this.getVersionNumberOrThrow(parts[0]);
+ let minor = this.getVersionNumberOrThrow(parts[1]);
+
+ this.fullversion = major + '.' + minor;
+ }
+
+ private getVersionNumberOrThrow(input: string): number {
+ try {
+ if (!input || input.trim() === '') this.throwInvalidVersionFormat();
+
+ let number = Number(input);
+
+ if (Number.isNaN(number) || number < 0) this.throwInvalidVersionFormat();
+
+ return number;
+ } catch {
+ this.throwInvalidVersionFormat();
+ return -1;
+ }
+ }
+
+ private throwInvalidVersionFormat() {
+ throw 'Invalid version format! Supported: 1.2.3, 1.2, 1.2.x, 1.2.*';
+ }
+
+ /**
+ * If true exacatly one version should be resolved
+ */
+ public isExactVersion(): boolean {
+ return this.isExactVersionSet;
+ }
+
+ public version(): string {
+ return this.fullversion;
+ }
+}
+
+/**
+ * Represents a resolved version from the Web-Api
+ */
+class ResolvedVersionInfo {
+ downloadUrls: string[];
+ resolvedVersion: string;
+
+ constructor(downloadUrls: string[], resolvedVersion: string) {
+ if (downloadUrls.length === 0) {
+ throw 'DownloadUrls can not be empty';
+ }
+
+ if (!resolvedVersion) {
+ throw 'Resolved version is invalid';
+ }
+
+ this.downloadUrls = downloadUrls;
+ this.resolvedVersion = resolvedVersion;
+ }
+}
+
+export class DotnetCoreInstaller {
+ constructor(version: string) {
+ this.versionInfo = new DotNetVersionInfo(version);
+ this.cachedToolName = 'dncs';
+ this.arch = 'x64';
+ }
+
+ public async installDotnet(): Promise {
+ // Check cache
+ let toolPath: string = '';
+ let osSuffixes = await this.detectMachineOS();
+ let parts = osSuffixes[0].split('-');
+ if (parts.length > 1) {
+ this.arch = parts[1];
+ }
+
+ // If version is not generic -> look up cache
+ if (this.versionInfo.isExactVersion())
+ toolPath = this.getLocalTool(this.versionInfo.version());
+
+ if (!toolPath) {
+ // download, extract, cache
+ console.log('Getting a download url', this.versionInfo.version());
+ let resolvedVersionInfo = await this.resolveInfos(
+ osSuffixes,
+ this.versionInfo
+ );
+
+ //Check if cache exists for resolved version
+ toolPath = this.getLocalTool(resolvedVersionInfo.resolvedVersion);
+ if (!toolPath) {
+ //If not exists install it
+ toolPath = await this.downloadAndInstall(resolvedVersionInfo);
+ } else {
+ console.log('Using cached tool');
+ }
+ } else {
+ console.log('Using cached tool');
+ }
+
+ // Need to set this so that .NET Core global tools find the right locations.
+ core.exportVariable('DOTNET_ROOT', toolPath);
+
+ // Prepend the tools path. instructs the agent to prepend for future tasks
+ core.addPath(toolPath);
+
+ return toolPath;
+ }
+
+ private getLocalTool(version: string): string {
+ console.log('Checking tool cache', version);
+ return tc.find(this.cachedToolName, version, this.arch);
+ }
+
+ private async detectMachineOS(): Promise {
+ let osSuffix: string[] = [];
+ let output = '';
+
+ let resultCode = 0;
+ if (IS_WINDOWS) {
+ let escapedScript = path
+ .join(__dirname, '..', 'externals', 'get-os-platform.ps1')
+ .replace(/'/g, "''");
+ let command = `& '${escapedScript}'`;
+
+ const powershellPath = await io.which('powershell', true);
+ resultCode = await exec.exec(
+ `"${powershellPath}"`,
+ [
+ '-NoLogo',
+ '-Sta',
+ '-NoProfile',
+ '-NonInteractive',
+ '-ExecutionPolicy',
+ 'Unrestricted',
+ '-Command',
+ command
+ ],
+ {
+ listeners: {
+ stdout: (data: Buffer) => {
+ output += data.toString();
+ }
+ }
+ }
+ );
+ } else {
+ let scriptPath = path.join(
+ __dirname,
+ '..',
+ 'externals',
+ 'get-os-distro.sh'
+ );
+ chmodSync(scriptPath, '777');
+
+ const toolPath = await io.which(scriptPath, true);
+ resultCode = await exec.exec(`"${toolPath}"`, [], {
+ listeners: {
+ stdout: (data: Buffer) => {
+ output += data.toString();
+ }
+ }
+ });
+ }
+
+ if (resultCode != 0) {
+ throw `Failed to detect os with result code ${resultCode}. Output: ${output}`;
+ }
+
+ let index;
+ if ((index = output.indexOf('Primary:')) >= 0) {
+ let primary = output.substr(index + 'Primary:'.length).split(os.EOL)[0];
+ osSuffix.push(primary);
+ }
+
+ if ((index = output.indexOf('Legacy:')) >= 0) {
+ let legacy = output.substr(index + 'Legacy:'.length).split(os.EOL)[0];
+ osSuffix.push(legacy);
+ }
+
+ if (osSuffix.length == 0) {
+ throw 'Could not detect platform';
+ }
+
+ return osSuffix;
+ }
+
+ private async downloadAndInstall(resolvedVersionInfo: ResolvedVersionInfo) {
+ let downloaded = false;
+ let downloadPath = '';
+ for (const url of resolvedVersionInfo.downloadUrls) {
+ try {
+ downloadPath = await tc.downloadTool(url);
+ downloaded = true;
+ break;
+ } catch (error) {
+ console.log('Could not Download', url, JSON.stringify(error));
+ }
+ }
+
+ if (!downloaded) {
+ throw 'Failed to download package';
+ }
+
+ // extract
+ console.log('Extracting Package', downloadPath);
+ let extPath: string = IS_WINDOWS
+ ? await tc.extractZip(downloadPath)
+ : await tc.extractTar(downloadPath);
+
+ // cache tool
+ console.log('Caching tool');
+ let cachedDir = await tc.cacheDir(
+ extPath,
+ this.cachedToolName,
+ resolvedVersionInfo.resolvedVersion,
+ this.arch
+ );
+
+ console.log('Successfully installed', resolvedVersionInfo.resolvedVersion);
+ return cachedDir;
+ }
+
+ // OsSuffixes - The suffix which is a part of the file name ex- linux-x64, windows-x86
+ // Type - SDK / Runtime
+ // versionInfo - versionInfo of the SDK/Runtime
+ async resolveInfos(
+ osSuffixes: string[],
+ versionInfo: DotNetVersionInfo
+ ): Promise {
+ const httpClient = new hc.HttpClient('actions/setup-dotnet', [], {
+ allowRetries: true,
+ maxRetries: 3
+ });
+
+ const releasesJsonUrl: string = await this.getReleasesJsonUrl(
+ httpClient,
+ versionInfo.version().split('.')
+ );
+
+ const releasesResponse = await httpClient.getJson(releasesJsonUrl);
+ const releasesResult = releasesResponse.result || {};
+ let releasesInfo: any[] = releasesResult['releases'];
+ releasesInfo = releasesInfo.filter((releaseInfo: any) => {
+ return (
+ semver.satisfies(
+ releaseInfo['sdk']['version'],
+ versionInfo.version()
+ ) ||
+ semver.satisfies(
+ releaseInfo['sdk']['version-display'],
+ versionInfo.version()
+ )
+ );
+ });
+
+ // Exclude versions that are newer than the latest if using not exact
+ if (!versionInfo.isExactVersion()) {
+ let latestSdk: string = releasesResult['latest-sdk'];
+
+ releasesInfo = releasesInfo.filter((releaseInfo: any) =>
+ semver.lte(releaseInfo['sdk']['version'], latestSdk)
+ );
+ }
+
+ // Sort for latest version
+ releasesInfo = releasesInfo.sort((a, b) =>
+ semver.rcompare(a['sdk']['version'], b['sdk']['version'])
+ );
+
+ let downloadedVersion: string = '';
+ let downloadUrls: string[] = [];
+
+ if (releasesInfo.length != 0) {
+ let release = releasesInfo[0];
+
+ downloadedVersion = release['sdk']['version'];
+
+ let files: any[] = release['sdk']['files'];
+ files = files.filter((file: any) => {
+ if (file['rid'] == osSuffixes[0] || file['rid'] == osSuffixes[1]) {
+ return (
+ file['url'].endsWith('.zip') || file['url'].endsWith('.tar.gz')
+ );
+ }
+ });
+
+ if (files.length > 0) {
+ files.forEach((file: any) => {
+ downloadUrls.push(file['url']);
+ });
+ } else {
+ throw `The specified version's download links are not correctly formed in the supported versions document => ${releasesJsonUrl}`;
+ }
+ } else {
+ console.log(
+ `Could not fetch download information for version ${versionInfo.version()}`
+ );
+
+ if (versionInfo.isExactVersion()) {
+ console.log('Using fallback');
+
+ downloadUrls = await this.getFallbackDownloadUrls(
+ versionInfo.version()
+ );
+ downloadedVersion = versionInfo.version();
+ } else {
+ console.log('Unable to use fallback, version is generic!');
+ }
+ }
+
+ if (downloadUrls.length == 0) {
+ throw `Could not construct download URL. Please ensure that specified version ${versionInfo.version()}/${downloadedVersion} is valid.`;
+ }
+
+ core.debug(`Got download urls ${downloadUrls}`);
+
+ return new ResolvedVersionInfo(downloadUrls, downloadedVersion);
+ }
+
+ private async getReleasesJsonUrl(
+ httpClient: hc.HttpClient,
+ versionParts: string[]
+ ): Promise {
+ const response = await httpClient.getJson(DotNetCoreIndexUrl);
+ const result = response.result || {};
+ let releasesInfo: any[] = result['releases-index'];
+ releasesInfo = releasesInfo.filter((info: any) => {
+ // channel-version is the first 2 elements of the version (e.g. 2.1), filter out versions that don't match 2.1.x.
+ const sdkParts: string[] = info['channel-version'].split('.');
+ if (versionParts.length >= 2 && versionParts[1] != 'x') {
+ return versionParts[0] == sdkParts[0] && versionParts[1] == sdkParts[1];
+ }
+ return versionParts[0] == sdkParts[0];
+ });
+ if (releasesInfo.length === 0) {
+ throw `Could not find info for version ${versionParts.join(
+ '.'
+ )} at ${DotNetCoreIndexUrl}`;
+ }
+ return releasesInfo[0]['releases.json'];
+ }
+
+ private async getFallbackDownloadUrls(version: string): Promise {
+ let primaryUrlSearchString: string;
+ let legacyUrlSearchString: string;
+ let output = '';
+ let resultCode = 0;
+
+ if (IS_WINDOWS) {
+ let escapedScript = path
+ .join(__dirname, '..', 'externals', 'install-dotnet.ps1')
+ .replace(/'/g, "''");
+ let command = `& '${escapedScript}' -Version ${version} -DryRun`;
+
+ const powershellPath = await io.which('powershell', true);
+ resultCode = await exec.exec(
+ `"${powershellPath}"`,
+ [
+ '-NoLogo',
+ '-Sta',
+ '-NoProfile',
+ '-NonInteractive',
+ '-ExecutionPolicy',
+ 'Unrestricted',
+ '-Command',
+ command
+ ],
+ {
+ listeners: {
+ stdout: (data: Buffer) => {
+ output += data.toString();
+ }
+ }
+ }
+ );
+
+ primaryUrlSearchString = 'dotnet-install: Primary named payload URL: ';
+ legacyUrlSearchString = 'dotnet-install: Legacy named payload URL: ';
+ } else {
+ let escapedScript = path
+ .join(__dirname, '..', 'externals', 'install-dotnet.sh')
+ .replace(/'/g, "''");
+ chmodSync(escapedScript, '777');
+
+ const scriptPath = await io.which(escapedScript, true);
+ resultCode = await exec.exec(
+ `"${scriptPath}"`,
+ ['--version', version, '--dry-run'],
+ {
+ listeners: {
+ stdout: (data: Buffer) => {
+ output += data.toString();
+ }
+ }
+ }
+ );
+
+ primaryUrlSearchString = 'dotnet-install: Primary named payload URL: ';
+ legacyUrlSearchString = 'dotnet-install: Legacy named payload URL: ';
+ }
+
+ if (resultCode != 0) {
+ throw `Failed to get download urls with result code ${resultCode}. ${output}`;
+ }
+
+ let primaryUrl: string = '';
+ let legacyUrl: string = '';
+ if (!!output && output.length > 0) {
+ let lines: string[] = output.split(os.EOL);
+
+ // Fallback to \n if initial split doesn't work (not consistent across versions)
+ if (lines.length === 1) {
+ lines = output.split('\n');
+ }
+ if (!!lines && lines.length > 0) {
+ lines.forEach((line: string) => {
+ if (!line) {
+ return;
+ }
+ var primarySearchStringIndex = line.indexOf(primaryUrlSearchString);
+ if (primarySearchStringIndex > -1) {
+ primaryUrl = line.substring(
+ primarySearchStringIndex + primaryUrlSearchString.length
+ );
+ return;
+ }
+
+ var legacySearchStringIndex = line.indexOf(legacyUrlSearchString);
+ if (legacySearchStringIndex > -1) {
+ legacyUrl = line.substring(
+ legacySearchStringIndex + legacyUrlSearchString.length
+ );
+ return;
+ }
+ });
+ }
+ }
+
+ return [primaryUrl, legacyUrl];
+ }
+
+ private versionInfo: DotNetVersionInfo;
+ private cachedToolName: string;
+ private arch: string;
+}
+
+export class SxSDotnetCoreInstaller {
+ constructor(toolPaths: Array) {
+ this.toolPaths = toolPaths;
+ this.cachedToolName = 'dncs';
+ this.arch = 'x64';
+ }
+
+ public async setupSxs() {
+ // create a temp dir
+ const tempDirectory = process.env['RUNNER_TEMP'] || '';
+ const dest = path.join(tempDirectory, uuidV4());
+ await io.mkdirP(dest);
+
+ console.log(`Setting up SxS .NET SDK installation in ${dest}...`);
+
+ // copy all the SDK versions into a temporary SxS directory
+ for (var toolPath of this.toolPaths) {
+ console.log(`Setting up .NET SDK from ${toolPath}...`);
+ let entries = readdirSync(toolPath);
+ for (var entry of entries) {
+ await io.cp(path.join(toolPath, entry), dest, {
+ recursive: true,
+ force: true
+ });
+ }
+ }
+
+ // cache SxS directory as a tool
+ let cachedDir = await tc.cacheDir(
+ dest,
+ this.cachedToolName,
+ 'sxs',
+ this.arch
+ );
+
+ console.log(`SxS .NET SDK installation in ${cachedDir}`);
+
+ // Need to set this so that .NET Core global tools find the right locations.
+ core.exportVariable('DOTNET_ROOT', cachedDir);
+
+ // Prepend the tools path. instructs the agent to prepend for future tasks
+ core.addPath(cachedDir);
+ }
+
+ private toolPaths: Array;
+ private cachedToolName: string;
+ private arch: string;
+}
+
+const DotNetCoreIndexUrl: string =
+ 'https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/releases-index.json';
diff --git a/src/setup-dotnet.ts b/src/setup-dotnet.ts
index 1637fa5..a69c1e3 100644
--- a/src/setup-dotnet.ts
+++ b/src/setup-dotnet.ts
@@ -34,12 +34,14 @@ export async function run() {
let versions = version.split(',');
console.log(`Specified .NET verions: ${versions}`);
for (var currentVersion of versions) {
- console.log(`Installing .NET SDK ${currentVersion}...`)
- const dotnetInstaller = new installer.DotnetCoreInstaller(currentVersion);
+ console.log(`Installing .NET SDK ${currentVersion}...`);
+ const dotnetInstaller = new installer.DotnetCoreInstaller(
+ currentVersion
+ );
toolPaths.push(await dotnetInstaller.installDotnet());
}
if (toolPaths.length > 0) {
- console.log(`Setting up SxS .NET SDK versions...`)
+ console.log(`Setting up SxS .NET SDK versions...`);
const sxsInstall = new installer.SxSDotnetCoreInstaller(toolPaths);
await sxsInstall.setupSxs();
}