Use GitHub releases to download Go versions. (#58)

This commit is contained in:
Dmitry Shibanov 2020-06-29 18:41:13 +03:00 committed by GitHub
parent 0f551ac199
commit 1616116e1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 4156 additions and 9837 deletions

View File

@ -1,51 +1,74 @@
name: go-versions
name: Validate 'setup-go'
on:
push:
branches:
- master
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
push:
branches:
- master
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
schedule:
- cron: 0 0 * * *
jobs:
run:
name: Go
runs-on: ${{ matrix.operating-system }}
local-cache:
name: Setup local-cache version
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
operating-system: [ubuntu-latest, windows-latest, macos-latest]
os: [macos-latest, windows-latest, ubuntu-latest]
go: [1.12, 1.13, 1.14]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: setup-go ${{ matrix.go }}
uses: ./
with:
go-version: ${{ matrix.go }}
- name: verify go
run: __tests__/verify-go.sh ${{ matrix.go }}
shell: bash
setup-versions-from-manifest:
name: Setup ${{ matrix.go }} ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
go: [1.12.16, 1.13.11, 1.14.3]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: setup-go ${{ matrix.go }}
uses: ./
with:
go-version: ${{ matrix.go }}
- name: verify go
run: __tests__/verify-go.sh ${{ matrix.go }}
shell: bash
setup-versions-from-dist:
name: Setup ${{ matrix.go }} ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
go: [1.7, 1.8.6]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: setup-go ^1.13.6
- name: setup-go ${{ matrix.go }}
uses: ./
with:
go-version: ^1.13.6
- name: validate version
run: go version | grep "go1."
- name: setup-go 1.13
uses: ./
with:
go-version: 1.13
- name: validate version
run: go version | grep "go1.13."
- name: setup-go 1.12.9
uses: ./
with:
go-version: 1.12.9
- name: validate version
run: go version | grep "go1.12.9"
- name: dump env
go-version: ${{ matrix.go }}
- name: verify go
run: __tests__/verify-go.sh ${{ matrix.go }}
shell: bash
run: |
echo $PATH
echo go versions in tool cache:
echo $(ls $RUNNER_TOOL_CACHE/go)

View File

@ -0,0 +1,77 @@
[
{
"version": "1.12.17",
"stable": true,
"release_url": "https://github.com/actions/go-versions/releases/tag/1.12.17-20200616.21",
"files": [
{
"filename": "go-1.12.17-darwin-x64.tar.gz",
"arch": "x64",
"platform": "darwin",
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.17-20200616.21/go-1.12.17-darwin-x64.tar.gz"
},
{
"filename": "go-1.12.17-linux-x64.tar.gz",
"arch": "x64",
"platform": "linux",
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.17-20200616.21/go-1.12.17-linux-x64.tar.gz"
},
{
"filename": "go-1.12.17-win32-x64.zip",
"arch": "x64",
"platform": "win32",
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.17-20200616.21/go-1.12.17-win32-x64.zip"
}
]
},
{
"version": "1.12.16",
"stable": true,
"release_url": "https://github.com/actions/go-versions/releases/tag/1.12.16-20200616.20",
"files": [
{
"filename": "go-1.12.16-darwin-x64.tar.gz",
"arch": "x64",
"platform": "darwin",
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.16-20200616.20/go-1.12.16-darwin-x64.tar.gz"
},
{
"filename": "go-1.12.16-linux-x64.tar.gz",
"arch": "x64",
"platform": "linux",
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.16-20200616.20/go-1.12.16-linux-x64.tar.gz"
},
{
"filename": "go-1.12.16-win32-x64.zip",
"arch": "x64",
"platform": "win32",
"download_url": "https://github.com/actions/go-versions/releases/download/1.12.16-20200616.20/go-1.12.16-win32-x64.zip"
}
]
},
{
"version": "1.9.7",
"stable": true,
"release_url": "https://github.com/actions/go-versions/releases/tag/1.9.7-20200616.1",
"files": [
{
"filename": "go-1.9.7-darwin-x64.tar.gz",
"arch": "x64",
"platform": "darwin",
"download_url": "https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-darwin-x64.tar.gz"
},
{
"filename": "go-1.9.7-linux-x64.tar.gz",
"arch": "x64",
"platform": "linux",
"download_url": "https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-linux-x64.tar.gz"
},
{
"filename": "go-1.9.7-win32-x64.zip",
"arch": "x64",
"platform": "win32",
"download_url": "https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-win32-x64.zip"
}
]
}
]

View File

@ -3,13 +3,14 @@ import * as io from '@actions/io';
import * as tc from '@actions/tool-cache';
import fs from 'fs';
import cp from 'child_process';
import osm = require('os');
import osm from 'os';
import path from 'path';
import * as main from '../src/main';
import * as im from '../src/installer';
let goJsonData = require('./data/golang-dl.json');
let matchers = require('../matchers.json');
let goTestManifest = require('./data/versions-manifest.json');
let matcherPattern = matchers.problemMatcher[0].pattern[0];
let matcherRegExp = new RegExp(matcherPattern.regexp);
@ -32,6 +33,7 @@ describe('setup-go', () => {
let existsSpy: jest.SpyInstance;
let mkdirpSpy: jest.SpyInstance;
let execSpy: jest.SpyInstance;
let getManifestSpy: jest.SpyInstance;
beforeEach(() => {
// @actions/core
@ -52,18 +54,22 @@ describe('setup-go', () => {
dlSpy = jest.spyOn(tc, 'downloadTool');
exSpy = jest.spyOn(tc, 'extractTar');
cacheSpy = jest.spyOn(tc, 'cacheDir');
getSpy = jest.spyOn(im, 'getVersions');
getSpy = jest.spyOn(im, 'getVersionsDist');
getManifestSpy = jest.spyOn(tc, 'getManifestFromRepo');
// io
whichSpy = jest.spyOn(io, 'which');
existsSpy = jest.spyOn(fs, 'existsSync');
mkdirpSpy = jest.spyOn(io, 'mkdirP');
// gets
getManifestSpy.mockImplementation(() => <tc.IToolRelease[]>goTestManifest);
// writes
cnSpy = jest.spyOn(process.stdout, 'write');
logSpy = jest.spyOn(console, 'log');
dbgSpy = jest.spyOn(main, '_debug');
getSpy.mockImplementation(() => <im.IGoVersion[]>goJsonData);
logSpy = jest.spyOn(core, 'info');
dbgSpy = jest.spyOn(core, 'debug');
getSpy.mockImplementation(() => <im.IGoVersion[] | null>goJsonData);
cnSpy.mockImplementation(line => {
// uncomment to debug
// process.stderr.write('write:' + line + '\n');
@ -86,27 +92,43 @@ describe('setup-go', () => {
afterAll(async () => {}, 100000);
it('can query versions', async () => {
let versions: im.IGoVersion[] | null = await im.getVersions(
'https://non.existant.com/path'
it('can find 1.9.7 from manifest on osx', async () => {
os.platform = 'darwin';
os.arch = 'x64';
let match = await im.getInfoFromManifest('1.9.7', true, 'mocktoken');
expect(match).toBeDefined();
expect(match!.resolvedVersion).toBe('1.9.7');
expect(match!.type).toBe('manifest');
expect(match!.downloadUrl).toBe(
'https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-darwin-x64.tar.gz'
);
expect(versions).toBeDefined();
let l: number = versions ? versions.length : 0;
expect(l).toBe(91);
});
it('finds stable match for exact version', async () => {
it('can find 1.9 from manifest on linux', async () => {
os.platform = 'linux';
os.arch = 'x64';
let match = await im.getInfoFromManifest('1.9.7', true, 'mocktoken');
expect(match).toBeDefined();
expect(match!.resolvedVersion).toBe('1.9.7');
expect(match!.type).toBe('manifest');
expect(match!.downloadUrl).toBe(
'https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-linux-x64.tar.gz'
);
});
it('can find 1.9 from manifest on windows', async () => {
os.platform = 'win32';
os.arch = 'x64';
// get request is already mocked
// spec: 1.13.7 => 1.13.7 (exact)
let match: im.IGoVersion | undefined = await im.findMatch('1.13.7', true);
let match = await im.getInfoFromManifest('1.9.7', true, 'mocktoken');
expect(match).toBeDefined();
let version: string = match ? match.version : '';
expect(version).toBe('go1.13.7');
let fileName = match ? match.files[0].filename : '';
expect(fileName).toBe('go1.13.7.windows-amd64.zip');
expect(match!.resolvedVersion).toBe('1.9.7');
expect(match!.type).toBe('manifest');
expect(match!.downloadUrl).toBe(
'https://github.com/actions/go-versions/releases/download/1.9.7/go-1.9.7-win32-x64.zip'
);
});
it('finds stable match for exact dot zero version', async () => {
@ -208,6 +230,7 @@ describe('setup-go', () => {
await main.run();
let expPath = path.join(toolPath, 'bin');
expect(logSpy).toHaveBeenCalledWith(`Found in cache @ ${toolPath}`);
});
it('finds a version in the cache and adds it to the path', async () => {
@ -261,10 +284,124 @@ describe('setup-go', () => {
await main.run();
expect(cnSpy).toHaveBeenCalledWith(
`::error::Could not find a version that satisfied version spec: 9.99.9${osm.EOL}`
`::error::Unable to find Go version '9.99.9' for platform linux and architecture x64.${osm.EOL}`
);
});
it('downloads a version from a manifest match', async () => {
os.platform = 'linux';
os.arch = 'x64';
// a version which is in the manifest
let versionSpec = '1.12.16';
inputs['go-version'] = versionSpec;
inputs['token'] = 'faketoken';
let expectedUrl =
'https://github.com/actions/go-versions/releases/download/1.12.16-20200616.20/go-1.12.16-linux-x64.tar.gz';
// ... but not in the local cache
findSpy.mockImplementation(() => '');
dlSpy.mockImplementation(async () => '/some/temp/path');
let toolPath = path.normalize('/cache/go/1.12.16/x64');
exSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
let expPath = path.join(toolPath, 'bin');
expect(dlSpy).toHaveBeenCalled();
expect(exSpy).toHaveBeenCalled();
expect(logSpy).not.toHaveBeenCalledWith(
'Not found in manifest. Falling back to download directly from Go'
);
expect(logSpy).toHaveBeenCalledWith(
`Acquiring 1.12.16 from ${expectedUrl}`
);
expect(logSpy).toHaveBeenCalledWith(`Added go to the path`);
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
});
it('downloads a major and minor from a manifest match', async () => {
os.platform = 'linux';
os.arch = 'x64';
// a version which is in the manifest
let versionSpec = '1.12';
inputs['go-version'] = versionSpec;
inputs['token'] = 'faketoken';
let expectedUrl =
'https://github.com/actions/go-versions/releases/download/1.12.17-20200616.21/go-1.12.17-linux-x64.tar.gz';
// ... but not in the local cache
findSpy.mockImplementation(() => '');
dlSpy.mockImplementation(async () => '/some/temp/path');
let toolPath = path.normalize('/cache/go/1.12.17/x64');
exSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
let expPath = path.join(toolPath, 'bin');
expect(dlSpy).toHaveBeenCalled();
expect(exSpy).toHaveBeenCalled();
expect(logSpy).not.toHaveBeenCalledWith(
'Not found in manifest. Falling back to download directly from Go'
);
expect(logSpy).toHaveBeenCalledWith(
`Acquiring 1.12.17 from ${expectedUrl}`
);
expect(logSpy).toHaveBeenCalledWith(`Added go to the path`);
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
});
it('falls back to a version from node dist', async () => {
os.platform = 'linux';
os.arch = 'x64';
// a version which is not in the manifest but is in node dist
let versionSpec = '1.12.14';
inputs['go-version'] = versionSpec;
inputs['token'] = 'faketoken';
let expectedUrl =
'https://github.com/actions/go-versions/releases/download/1.12.14-20200616.18/go-1.12.14-linux-x64.tar.gz';
// ... but not in the local cache
findSpy.mockImplementation(() => '');
dlSpy.mockImplementation(async () => '/some/temp/path');
let toolPath = path.normalize('/cache/go/1.12.14/x64');
exSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
let expPath = path.join(toolPath, 'bin');
expect(logSpy).toHaveBeenCalledWith('Setup go stable version spec 1.12.14');
expect(findSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith('Attempting to download 1.12.14...');
expect(dlSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith('matching 1.12.14...');
expect(exSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith(
'Not found in manifest. Falling back to download directly from Go'
);
expect(logSpy).toHaveBeenCalledWith(`Install from dist`);
expect(logSpy).toHaveBeenCalledWith(`Added go to the path`);
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
});
it('reports a failed download', async () => {
let errMsg = 'unhandled download message';
os.platform = 'linux';
@ -283,22 +420,6 @@ describe('setup-go', () => {
);
});
it('reports empty query results', async () => {
let errMsg = 'unhandled download message';
os.platform = 'linux';
os.arch = 'x64';
inputs['go-version'] = '1.13.1';
findSpy.mockImplementation(() => '');
getSpy.mockImplementation(() => null);
await main.run();
expect(cnSpy).toHaveBeenCalledWith(
`::error::Failed to download version 1.13.1: Error: golang download url did not return results${osm.EOL}`
);
});
it('does not add BIN if go is not in path', async () => {
whichSpy.mockImplementation(async () => {
return '';

14
__tests__/verify-go.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
if [ -z "$1" ]; then
echo "Must supply go version argument"
exit 1
fi
go_version="$(go version)"
echo "Found go version '$go_version'"
if [ -z "$(echo $go_version | grep $1)" ]; then
echo "Unexpected version"
exit 1
fi

View File

@ -7,6 +7,9 @@ inputs:
stable:
description: 'Whether to download only stable versions'
default: 'true'
token:
description: Used to pull node distributions from go-versions. Since there's a default, this is typically not supplied by the user.
default: ${{ github.token }}
runs:
using: 'node12'
main: 'dist/index.js'

679
dist/index.js vendored
View File

@ -354,13 +354,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const os = __webpack_require__(87);
const events = __webpack_require__(614);
const child = __webpack_require__(129);
const path = __webpack_require__(622);
const io = __webpack_require__(1);
const ioUtil = __webpack_require__(672);
const os = __importStar(__webpack_require__(87));
const events = __importStar(__webpack_require__(614));
const child = __importStar(__webpack_require__(129));
const path = __importStar(__webpack_require__(622));
const io = __importStar(__webpack_require__(1));
const ioUtil = __importStar(__webpack_require__(672));
/* eslint-disable @typescript-eslint/unbound-method */
const IS_WINDOWS = process.platform === 'win32';
/*
@ -804,6 +811,12 @@ class ToolRunner extends events.EventEmitter {
resolve(exitCode);
}
});
if (this.options.input) {
if (!cp.stdin) {
throw new Error('child process missing stdin');
}
cp.stdin.end(this.options.input);
}
});
});
}
@ -941,6 +954,119 @@ module.exports = require("tls");
/***/ }),
/***/ 31:
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const semver = __importStar(__webpack_require__(280));
const core_1 = __webpack_require__(470);
// needs to be require for core node modules to be mocked
/* eslint @typescript-eslint/no-require-imports: 0 */
const os = __webpack_require__(87);
const cp = __webpack_require__(129);
const fs = __webpack_require__(747);
function _findMatch(versionSpec, stable, candidates, archFilter) {
return __awaiter(this, void 0, void 0, function* () {
const platFilter = os.platform();
let result;
let match;
let file;
for (const candidate of candidates) {
const version = candidate.version;
core_1.debug(`check ${version} satisfies ${versionSpec}`);
if (semver.satisfies(version, versionSpec) &&
(!stable || candidate.stable === stable)) {
file = candidate.files.find(item => {
core_1.debug(`${item.arch}===${archFilter} && ${item.platform}===${platFilter}`);
let chk = item.arch === archFilter && item.platform === platFilter;
if (chk && item.platform_version) {
const osVersion = module.exports._getOsVersion();
if (osVersion === item.platform_version) {
chk = true;
}
else {
chk = semver.satisfies(osVersion, item.platform_version);
}
}
return chk;
});
if (file) {
core_1.debug(`matched ${candidate.version}`);
match = candidate;
break;
}
}
}
if (match && file) {
// clone since we're mutating the file list to be only the file that matches
result = Object.assign({}, match);
result.files = [file];
}
return result;
});
}
exports._findMatch = _findMatch;
function _getOsVersion() {
// TODO: add windows and other linux, arm variants
// right now filtering on version is only an ubuntu and macos scenario for tools we build for hosted (python)
const plat = os.platform();
let version = '';
if (plat === 'darwin') {
version = cp.execSync('sw_vers -productVersion').toString();
}
else if (plat === 'linux') {
// lsb_release process not in some containers, readfile
// Run cat /etc/lsb-release
// DISTRIB_ID=Ubuntu
// DISTRIB_RELEASE=18.04
// DISTRIB_CODENAME=bionic
// DISTRIB_DESCRIPTION="Ubuntu 18.04.4 LTS"
const lsbContents = module.exports._readLinuxVersionFile();
if (lsbContents) {
const lines = lsbContents.split('\n');
for (const line of lines) {
const parts = line.split('=');
if (parts.length === 2 && parts[0].trim() === 'DISTRIB_RELEASE') {
version = parts[1].trim();
break;
}
}
}
}
return version;
}
exports._getOsVersion = _getOsVersion;
function _readLinuxVersionFile() {
const lsbFile = '/etc/lsb-release';
let contents = '';
if (fs.existsSync(lsbFile)) {
contents = fs.readFileSync(lsbFile).toString();
}
return contents;
}
exports._readLinuxVersionFile = _readLinuxVersionFile;
//# sourceMappingURL=manifest.js.map
/***/ }),
/***/ 87:
/***/ (function(module) {
@ -1259,32 +1385,46 @@ main_1.run();
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.addBinToPath = exports.run = void 0;
const core = __importStar(__webpack_require__(470));
const io = __importStar(__webpack_require__(1));
const tc = __importStar(__webpack_require__(533));
const installer = __importStar(__webpack_require__(749));
const path_1 = __importDefault(__webpack_require__(622));
const child_process_1 = __importDefault(__webpack_require__(129));
const fs_1 = __importDefault(__webpack_require__(747));
const url_1 = __webpack_require__(835);
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
@ -1296,35 +1436,28 @@ function run() {
// stable will be true unless false is the exact input
// since getting unstable versions should be explicit
let stable = (core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
console.log(`Setup go ${stable ? 'stable' : ''} version spec ${versionSpec}`);
core.info(`Setup go ${stable ? 'stable' : ''} version spec ${versionSpec}`);
if (versionSpec) {
let installDir = tc.find('go', versionSpec);
if (!installDir) {
console.log(`A version satisfying ${versionSpec} not found locally, attempting to download ...`);
installDir = yield installer.downloadGo(versionSpec, stable);
console.log('Installed');
}
if (installDir) {
core.exportVariable('GOROOT', installDir);
core.addPath(path_1.default.join(installDir, 'bin'));
console.log('Added go to the path');
let added = addBinToPath();
core.debug(`add bin ${added}`);
}
else {
throw new Error(`Could not find a version that satisfied version spec: ${versionSpec}`);
}
let token = core.getInput('token');
let auth = !token || isGhes() ? undefined : `token ${token}`;
const installDir = yield installer.getGo(versionSpec, stable, auth);
core.exportVariable('GOROOT', installDir);
core.addPath(path_1.default.join(installDir, 'bin'));
core.info('Added go to the path');
let added = yield addBinToPath();
core.debug(`add bin ${added}`);
core.info(`Successfully setup go version ${versionSpec}`);
}
// add problem matchers
const matchersPath = path_1.default.join(__dirname, '..', 'matchers.json');
console.log(`##[add-matcher]${matchersPath}`);
core.info(`##[add-matcher]${matchersPath}`);
// output the version actually being used
let goPath = yield io.which('go');
let goVersion = (child_process_1.default.execSync(`${goPath} version`) || '').toString();
console.log(goVersion);
core.info(goVersion);
core.startGroup('go env');
let goEnv = (child_process_1.default.execSync(`${goPath} env`) || '').toString();
console.log(goEnv);
core.info(goEnv);
core.endGroup();
}
catch (error) {
@ -1337,23 +1470,23 @@ function addBinToPath() {
return __awaiter(this, void 0, void 0, function* () {
let added = false;
let g = yield io.which('go');
_debug(`which go :${g}:`);
core.debug(`which go :${g}:`);
if (!g) {
_debug('go not in the path');
core.debug('go not in the path');
return added;
}
let buf = child_process_1.default.execSync('go env GOPATH');
if (buf) {
let gp = buf.toString().trim();
_debug(`go env GOPATH :${gp}:`);
core.debug(`go env GOPATH :${gp}:`);
if (!fs_1.default.existsSync(gp)) {
// some of the hosted images have go install but not profile dir
_debug(`creating ${gp}`);
core.debug(`creating ${gp}`);
io.mkdirP(gp);
}
let bp = path_1.default.join(gp, 'bin');
if (!fs_1.default.existsSync(bp)) {
_debug(`creating ${bp}`);
core.debug(`creating ${bp}`);
io.mkdirP(bp);
}
core.addPath(bp);
@ -1363,10 +1496,10 @@ function addBinToPath() {
});
}
exports.addBinToPath = addBinToPath;
function _debug(message) {
core.debug(message);
function isGhes() {
const ghUrl = new url_1.URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
}
exports._debug = _debug;
/***/ }),
@ -3070,14 +3203,28 @@ class Command {
return cmdStr;
}
}
/**
* Sanitizes an input into a string so it can be passed into issueCommand safely
* @param input input to sanitize into a string
*/
function toCommandValue(input) {
if (input === null || input === undefined) {
return '';
}
else if (typeof input === 'string' || input instanceof String) {
return input;
}
return JSON.stringify(input);
}
exports.toCommandValue = toCommandValue;
function escapeData(s) {
return (s || '')
return toCommandValue(s)
.replace(/%/g, '%25')
.replace(/\r/g, '%0D')
.replace(/\n/g, '%0A');
}
function escapeProperty(s) {
return (s || '')
return toCommandValue(s)
.replace(/%/g, '%25')
.replace(/\r/g, '%0D')
.replace(/\n/g, '%0A')
@ -3133,11 +3280,13 @@ var ExitCode;
/**
* Sets env variable for this action and future actions in the job
* @param name the name of the variable to set
* @param val the value of the variable
* @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function exportVariable(name, val) {
process.env[name] = val;
command_1.issueCommand('set-env', { name }, val);
const convertedVal = command_1.toCommandValue(val);
process.env[name] = convertedVal;
command_1.issueCommand('set-env', { name }, convertedVal);
}
exports.exportVariable = exportVariable;
/**
@ -3176,12 +3325,22 @@ exports.getInput = getInput;
* Sets the value of an output.
*
* @param name name of the output to set
* @param value value to store
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function setOutput(name, value) {
command_1.issueCommand('set-output', { name }, value);
}
exports.setOutput = setOutput;
/**
* Enables or disables the echoing of commands into stdout for the rest of the step.
* Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set.
*
*/
function setCommandEcho(enabled) {
command_1.issue('echo', enabled ? 'on' : 'off');
}
exports.setCommandEcho = setCommandEcho;
//-----------------------------------------------------------------------
// Results
//-----------------------------------------------------------------------
@ -3198,6 +3357,13 @@ exports.setFailed = setFailed;
//-----------------------------------------------------------------------
// Logging Commands
//-----------------------------------------------------------------------
/**
* Gets whether Actions Step Debug is on or not
*/
function isDebug() {
return process.env['RUNNER_DEBUG'] === '1';
}
exports.isDebug = isDebug;
/**
* Writes debug message to user log
* @param message debug message
@ -3208,18 +3374,18 @@ function debug(message) {
exports.debug = debug;
/**
* Adds an error issue
* @param message error issue message
* @param message error issue message. Errors will be converted to string via toString()
*/
function error(message) {
command_1.issue('error', message);
command_1.issue('error', message instanceof Error ? message.toString() : message);
}
exports.error = error;
/**
* Adds an warning issue
* @param message warning issue message
* @param message warning issue message. Errors will be converted to string via toString()
*/
function warning(message) {
command_1.issue('warning', message);
command_1.issue('warning', message instanceof Error ? message.toString() : message);
}
exports.warning = warning;
/**
@ -3277,8 +3443,9 @@ exports.group = group;
* Saves state for current action, the state can only be retrieved by this action's post job execution.
*
* @param name name of the state to store
* @param value value to store
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function saveState(name, value) {
command_1.issueCommand('save-state', { name }, value);
}
@ -3325,6 +3492,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(__webpack_require__(470));
const io = __importStar(__webpack_require__(1));
const fs = __importStar(__webpack_require__(747));
const mm = __importStar(__webpack_require__(31));
const os = __importStar(__webpack_require__(87));
const path = __importStar(__webpack_require__(622));
const httpm = __importStar(__webpack_require__(539));
@ -3350,9 +3518,10 @@ const userAgent = 'actions/tool-cache';
*
* @param url url of tool to download
* @param dest path to download tool
* @param auth authorization header
* @returns path to downloaded tool
*/
function downloadTool(url, dest) {
function downloadTool(url, dest, auth) {
return __awaiter(this, void 0, void 0, function* () {
dest = dest || path.join(_getTempDirectory(), v4_1.default());
yield io.mkdirP(path.dirname(dest));
@ -3363,7 +3532,7 @@ function downloadTool(url, dest) {
const maxSeconds = _getGlobal('TEST_DOWNLOAD_TOOL_RETRY_MAX_SECONDS', 20);
const retryHelper = new retry_helper_1.RetryHelper(maxAttempts, minSeconds, maxSeconds);
return yield retryHelper.execute(() => __awaiter(this, void 0, void 0, function* () {
return yield downloadToolAttempt(url, dest || '');
return yield downloadToolAttempt(url, dest || '', auth);
}), (err) => {
if (err instanceof HTTPError && err.httpStatusCode) {
// Don't retry anything less than 500, except 408 Request Timeout and 429 Too Many Requests
@ -3379,7 +3548,7 @@ function downloadTool(url, dest) {
});
}
exports.downloadTool = downloadTool;
function downloadToolAttempt(url, dest) {
function downloadToolAttempt(url, dest, auth) {
return __awaiter(this, void 0, void 0, function* () {
if (fs.existsSync(dest)) {
throw new Error(`Destination file path ${dest} already exists`);
@ -3388,7 +3557,14 @@ function downloadToolAttempt(url, dest) {
const http = new httpm.HttpClient(userAgent, [], {
allowRetries: false
});
const response = yield http.get(url);
let headers;
if (auth) {
core.debug('set auth');
headers = {
authorization: auth
};
}
const response = yield http.get(url, headers);
if (response.message.statusCode !== 200) {
const err = new HTTPError(response.message.statusCode);
core.debug(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
@ -3443,9 +3619,10 @@ function extract7z(file, dest, _7zPath) {
process.chdir(dest);
if (_7zPath) {
try {
const logLevel = core.isDebug() ? '-bb1' : '-bb0';
const args = [
'x',
'-bb1',
logLevel,
'-bd',
'-sccUTF-8',
file
@ -3521,7 +3698,16 @@ function extractTar(file, dest, flags = 'xz') {
core.debug(versionOutput.trim());
const isGnuTar = versionOutput.toUpperCase().includes('GNU TAR');
// Initialize args
const args = [flags];
let args;
if (flags instanceof Array) {
args = flags;
}
else {
args = [flags];
}
if (core.isDebug() && !flags.includes('v')) {
args.push('-v');
}
let destArg = dest;
let fileArg = file;
if (IS_WINDOWS && isGnuTar) {
@ -3571,7 +3757,7 @@ function extractZipWin(file, dest) {
const escapedDest = dest.replace(/'/g, "''").replace(/"|\n|\r/g, '');
const command = `$ErrorActionPreference = 'Stop' ; try { Add-Type -AssemblyName System.IO.Compression.FileSystem } catch { } ; [System.IO.Compression.ZipFile]::ExtractToDirectory('${escapedFile}', '${escapedDest}')`;
// run powershell
const powershellPath = yield io.which('powershell');
const powershellPath = yield io.which('powershell', true);
const args = [
'-NoLogo',
'-Sta',
@ -3587,8 +3773,12 @@ function extractZipWin(file, dest) {
}
function extractZipNix(file, dest) {
return __awaiter(this, void 0, void 0, function* () {
const unzipPath = yield io.which('unzip');
yield exec_1.exec(`"${unzipPath}"`, [file], { cwd: dest });
const unzipPath = yield io.which('unzip', true);
const args = [file];
if (!core.isDebug()) {
args.unshift('-q');
}
yield exec_1.exec(`"${unzipPath}"`, args, { cwd: dest });
});
}
/**
@ -3716,6 +3906,51 @@ function findAllVersions(toolName, arch) {
return versions;
}
exports.findAllVersions = findAllVersions;
function getManifestFromRepo(owner, repo, auth, branch = 'master') {
return __awaiter(this, void 0, void 0, function* () {
let releases = [];
const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${branch}`;
const http = new httpm.HttpClient('tool-cache');
const headers = {};
if (auth) {
core.debug('set auth');
headers.authorization = auth;
}
const response = yield http.getJson(treeUrl, headers);
if (!response.result) {
return releases;
}
let manifestUrl = '';
for (const item of response.result.tree) {
if (item.path === 'versions-manifest.json') {
manifestUrl = item.url;
break;
}
}
headers['accept'] = 'application/vnd.github.VERSION.raw';
let versionsRaw = yield (yield http.get(manifestUrl, headers)).readBody();
if (versionsRaw) {
// shouldn't be needed but protects against invalid json saved with BOM
versionsRaw = versionsRaw.replace(/^\uFEFF/, '');
try {
releases = JSON.parse(versionsRaw);
}
catch (_a) {
core.debug('Invalid json');
}
}
return releases;
});
}
exports.getManifestFromRepo = getManifestFromRepo;
function findFromManifest(versionSpec, stable, manifest, archFilter = os.arch()) {
return __awaiter(this, void 0, void 0, function* () {
// wrap the internal impl
const match = yield mm._findMatch(versionSpec, stable, manifest, archFilter);
return match;
});
}
exports.findFromManifest = findFromManifest;
function _createExtractFolder(dest) {
return __awaiter(this, void 0, void 0, function* () {
if (!dest) {
@ -3838,6 +4073,7 @@ var HttpCodes;
HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout";
HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict";
HttpCodes[HttpCodes["Gone"] = 410] = "Gone";
HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests";
HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError";
HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented";
HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway";
@ -3862,8 +4098,18 @@ function getProxyUrl(serverUrl) {
return proxyUrl ? proxyUrl.href : '';
}
exports.getProxyUrl = getProxyUrl;
const HttpRedirectCodes = [HttpCodes.MovedPermanently, HttpCodes.ResourceMoved, HttpCodes.SeeOther, HttpCodes.TemporaryRedirect, HttpCodes.PermanentRedirect];
const HttpResponseRetryCodes = [HttpCodes.BadGateway, HttpCodes.ServiceUnavailable, HttpCodes.GatewayTimeout];
const HttpRedirectCodes = [
HttpCodes.MovedPermanently,
HttpCodes.ResourceMoved,
HttpCodes.SeeOther,
HttpCodes.TemporaryRedirect,
HttpCodes.PermanentRedirect
];
const HttpResponseRetryCodes = [
HttpCodes.BadGateway,
HttpCodes.ServiceUnavailable,
HttpCodes.GatewayTimeout
];
const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
const ExponentialBackoffCeiling = 10;
const ExponentialBackoffTimeSlice = 5;
@ -3988,18 +4234,22 @@ class HttpClient {
*/
async request(verb, requestUrl, data, headers) {
if (this._disposed) {
throw new Error("Client has already been disposed.");
throw new Error('Client has already been disposed.');
}
let parsedUrl = url.parse(requestUrl);
let info = this._prepareRequest(verb, parsedUrl, headers);
// Only perform retries on reads since writes may not be idempotent.
let maxTries = (this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1) ? this._maxRetries + 1 : 1;
let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1
? this._maxRetries + 1
: 1;
let numTries = 0;
let response;
while (numTries < maxTries) {
response = await this.requestRaw(info, data);
// Check if it's an authentication challenge
if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) {
if (response &&
response.message &&
response.message.statusCode === HttpCodes.Unauthorized) {
let authenticationHandler;
for (let i = 0; i < this.handlers.length; i++) {
if (this.handlers[i].canHandleAuthentication(response)) {
@ -4017,21 +4267,32 @@ class HttpClient {
}
}
let redirectsRemaining = this._maxRedirects;
while (HttpRedirectCodes.indexOf(response.message.statusCode) != -1
&& this._allowRedirects
&& redirectsRemaining > 0) {
const redirectUrl = response.message.headers["location"];
while (HttpRedirectCodes.indexOf(response.message.statusCode) != -1 &&
this._allowRedirects &&
redirectsRemaining > 0) {
const redirectUrl = response.message.headers['location'];
if (!redirectUrl) {
// if there's no location to redirect to, we won't
break;
}
let parsedRedirectUrl = url.parse(redirectUrl);
if (parsedUrl.protocol == 'https:' && parsedUrl.protocol != parsedRedirectUrl.protocol && !this._allowRedirectDowngrade) {
throw new Error("Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.");
if (parsedUrl.protocol == 'https:' &&
parsedUrl.protocol != parsedRedirectUrl.protocol &&
!this._allowRedirectDowngrade) {
throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
}
// we need to finish reading the response before reassigning response
// which will leak the open socket.
await response.readBody();
// strip authorization header if redirected to a different hostname
if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
for (let header in headers) {
// header names are case insensitive
if (header.toLowerCase() === 'authorization') {
delete headers[header];
}
}
}
// let's make the request with the new redirectUrl
info = this._prepareRequest(verb, parsedRedirectUrl, headers);
response = await this.requestRaw(info, data);
@ -4082,8 +4343,8 @@ class HttpClient {
*/
requestRawWithCallback(info, data, onResult) {
let socket;
if (typeof (data) === 'string') {
info.options.headers["Content-Length"] = Buffer.byteLength(data, 'utf8');
if (typeof data === 'string') {
info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
}
let callbackCalled = false;
let handleResult = (err, res) => {
@ -4096,7 +4357,7 @@ class HttpClient {
let res = new HttpClientResponse(msg);
handleResult(null, res);
});
req.on('socket', (sock) => {
req.on('socket', sock => {
socket = sock;
});
// If we ever get disconnected, we want the socket to timeout eventually
@ -4111,10 +4372,10 @@ class HttpClient {
// res should have headers
handleResult(err, null);
});
if (data && typeof (data) === 'string') {
if (data && typeof data === 'string') {
req.write(data, 'utf8');
}
if (data && typeof (data) !== 'string') {
if (data && typeof data !== 'string') {
data.on('close', function () {
req.end();
});
@ -4141,31 +4402,34 @@ class HttpClient {
const defaultPort = usingSsl ? 443 : 80;
info.options = {};
info.options.host = info.parsedUrl.hostname;
info.options.port = info.parsedUrl.port ? parseInt(info.parsedUrl.port) : defaultPort;
info.options.path = (info.parsedUrl.pathname || '') + (info.parsedUrl.search || '');
info.options.port = info.parsedUrl.port
? parseInt(info.parsedUrl.port)
: defaultPort;
info.options.path =
(info.parsedUrl.pathname || '') + (info.parsedUrl.search || '');
info.options.method = method;
info.options.headers = this._mergeHeaders(headers);
if (this.userAgent != null) {
info.options.headers["user-agent"] = this.userAgent;
info.options.headers['user-agent'] = this.userAgent;
}
info.options.agent = this._getAgent(info.parsedUrl);
// gives handlers an opportunity to participate
if (this.handlers) {
this.handlers.forEach((handler) => {
this.handlers.forEach(handler => {
handler.prepareRequest(info.options);
});
}
return info;
}
_mergeHeaders(headers) {
const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => (c[k.toLowerCase()] = obj[k], c), {});
const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
if (this.requestOptions && this.requestOptions.headers) {
return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers));
}
return lowercaseKeys(headers || {});
}
_getExistingOrDefaultHeader(additionalHeaders, header, _default) {
const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => (c[k.toLowerCase()] = obj[k], c), {});
const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
let clientHeader;
if (this.requestOptions && this.requestOptions.headers) {
clientHeader = lowercaseKeys(this.requestOptions.headers)[header];
@ -4203,7 +4467,7 @@ class HttpClient {
proxyAuth: proxyUrl.auth,
host: proxyUrl.hostname,
port: proxyUrl.port
},
}
};
let tunnelAgent;
const overHttps = proxyUrl.protocol === 'https:';
@ -4230,7 +4494,9 @@ class HttpClient {
// we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process
// http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options
// we have to cast it to any and change it directly
agent.options = Object.assign(agent.options || {}, { rejectUnauthorized: false });
agent.options = Object.assign(agent.options || {}, {
rejectUnauthorized: false
});
}
return agent;
}
@ -4291,7 +4557,7 @@ class HttpClient {
msg = contents;
}
else {
msg = "Failed request: (" + statusCode + ")";
msg = 'Failed request: (' + statusCode + ')';
}
let err = new Error(msg);
// attach statusCode and body obj (if available) to the error object
@ -4565,14 +4831,16 @@ function bytesToUuid(buf, offset) {
var i = offset || 0;
var bth = byteToHex;
// join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4
return ([bth[buf[i++]], bth[buf[i++]],
bth[buf[i++]], bth[buf[i++]], '-',
bth[buf[i++]], bth[buf[i++]], '-',
bth[buf[i++]], bth[buf[i++]], '-',
bth[buf[i++]], bth[buf[i++]], '-',
bth[buf[i++]], bth[buf[i++]],
bth[buf[i++]], bth[buf[i++]],
bth[buf[i++]], bth[buf[i++]]]).join('');
return ([
bth[buf[i++]], bth[buf[i++]],
bth[buf[i++]], bth[buf[i++]], '-',
bth[buf[i++]], bth[buf[i++]], '-',
bth[buf[i++]], bth[buf[i++]], '-',
bth[buf[i++]], bth[buf[i++]], '-',
bth[buf[i++]], bth[buf[i++]],
bth[buf[i++]], bth[buf[i++]],
bth[buf[i++]], bth[buf[i++]]
]).join('');
}
module.exports = bytesToUuid;
@ -4586,6 +4854,7 @@ module.exports = bytesToUuid;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getArch = exports.getPlatform = void 0;
let os = __webpack_require__(87);
function getPlatform() {
// darwin and linux match already
@ -4634,58 +4903,167 @@ module.exports = require("fs");
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeSemver = exports.getVersionsDist = exports.findMatch = exports.getInfoFromManifest = exports.extractGoArchive = exports.getGo = void 0;
const tc = __importStar(__webpack_require__(533));
const core = __importStar(__webpack_require__(470));
const path = __importStar(__webpack_require__(622));
const semver = __importStar(__webpack_require__(280));
const httpm = __importStar(__webpack_require__(539));
const sys = __importStar(__webpack_require__(737));
const core_1 = __webpack_require__(470);
function downloadGo(versionSpec, stable) {
const os_1 = __importDefault(__webpack_require__(87));
function getGo(versionSpec, stable, auth) {
return __awaiter(this, void 0, void 0, function* () {
let osPlat = os_1.default.platform();
let osArch = os_1.default.arch();
// check cache
let toolPath;
toolPath = tc.find('go', versionSpec);
// If not found in cache, download
if (toolPath) {
core.info(`Found in cache @ ${toolPath}`);
return toolPath;
}
core.info(`Attempting to download ${versionSpec}...`);
let downloadPath = '';
let info = null;
//
// Try download from internal distribution (popular versions only)
//
try {
let match = yield findMatch(versionSpec, stable);
if (match) {
// download
core_1.debug(`match ${match.version}`);
let downloadUrl = `https://storage.googleapis.com/golang/${match.files[0].filename}`;
console.log(`Downloading from ${downloadUrl}`);
let downloadPath = yield tc.downloadTool(downloadUrl);
core_1.debug(`downloaded to ${downloadPath}`);
// extract
console.log('Extracting ...');
let extPath = sys.getPlatform() == 'windows'
? yield tc.extractZip(downloadPath)
: yield tc.extractTar(downloadPath);
core_1.debug(`extracted to ${extPath}`);
// extracts with a root folder that matches the fileName downloaded
const toolRoot = path.join(extPath, 'go');
toolPath = yield tc.cacheDir(toolRoot, 'go', makeSemver(match.version));
info = yield getInfoFromManifest(versionSpec, stable, auth);
if (info) {
downloadPath = yield installGoVersion(info, auth);
}
else {
core.info('Not found in manifest. Falling back to download directly from Go');
}
}
catch (error) {
throw new Error(`Failed to download version ${versionSpec}: ${error}`);
catch (err) {
if (err instanceof tc.HTTPError &&
(err.httpStatusCode === 403 || err.httpStatusCode === 429)) {
core.info(`Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded`);
}
else {
core.info(err.message);
}
core.debug(err.stack);
core.info('Falling back to download directly from Go');
}
return toolPath;
//
// Download from storage.googleapis.com
//
if (!downloadPath) {
info = yield getInfoFromDist(versionSpec, stable);
if (!info) {
throw new Error(`Unable to find Go version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.`);
}
try {
core.info('Install from dist');
downloadPath = yield installGoVersion(info, undefined);
}
catch (err) {
throw new Error(`Failed to download version ${versionSpec}: ${err}`);
}
}
return downloadPath;
});
}
exports.getGo = getGo;
function installGoVersion(info, auth) {
return __awaiter(this, void 0, void 0, function* () {
core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`);
const downloadPath = yield tc.downloadTool(info.downloadUrl, undefined, auth);
core.info('Extracting Go...');
let extPath = yield extractGoArchive(downloadPath);
core.info(`Successfully extracted go to ${extPath}`);
if (info.type === 'dist') {
extPath = path.join(extPath, 'go');
}
core.info('Adding to the cache ...');
const cachedDir = yield tc.cacheDir(extPath, 'go', makeSemver(info.resolvedVersion));
core.info(`Successfully cached go to ${cachedDir}`);
return cachedDir;
});
}
function extractGoArchive(archivePath) {
return __awaiter(this, void 0, void 0, function* () {
const arch = os_1.default.arch();
let extPath;
if (arch === 'win32') {
extPath = yield tc.extractZip(archivePath);
}
else {
extPath = yield tc.extractTar(archivePath);
}
return extPath;
});
}
exports.extractGoArchive = extractGoArchive;
function getInfoFromManifest(versionSpec, stable, auth) {
return __awaiter(this, void 0, void 0, function* () {
let info = null;
const releases = yield tc.getManifestFromRepo('actions', 'go-versions', auth);
core.info(`matching ${versionSpec}...`);
const rel = yield tc.findFromManifest(versionSpec, stable, releases);
if (rel && rel.files.length > 0) {
info = {};
info.type = 'manifest';
info.resolvedVersion = rel.version;
info.downloadUrl = rel.files[0].download_url;
info.fileName = rel.files[0].filename;
}
return info;
});
}
exports.getInfoFromManifest = getInfoFromManifest;
function getInfoFromDist(versionSpec, stable) {
return __awaiter(this, void 0, void 0, function* () {
let version;
version = yield findMatch(versionSpec, stable);
if (!version) {
return null;
}
let downloadUrl = `https://storage.googleapis.com/golang/${version.files[0].filename}`;
return {
type: 'dist',
downloadUrl: downloadUrl,
resolvedVersion: version.version,
fileName: version.files[0].filename
};
});
}
exports.downloadGo = downloadGo;
function findMatch(versionSpec, stable) {
return __awaiter(this, void 0, void 0, function* () {
let archFilter = sys.getArch();
@ -4693,7 +5071,7 @@ function findMatch(versionSpec, stable) {
let result;
let match;
const dlUrl = 'https://golang.org/dl/?mode=json&include=all';
let candidates = yield module.exports.getVersions(dlUrl);
let candidates = yield module.exports.getVersionsDist(dlUrl);
if (!candidates) {
throw new Error(`golang download url did not return results`);
}
@ -4707,15 +5085,15 @@ function findMatch(versionSpec, stable) {
if (parts.length == 2) {
version = version + '.0';
}
core_1.debug(`check ${version} satisfies ${versionSpec}`);
core.debug(`check ${version} satisfies ${versionSpec}`);
if (semver.satisfies(version, versionSpec) &&
(!stable || candidate.stable === stable)) {
goFile = candidate.files.find(file => {
core_1.debug(`${file.arch}===${archFilter} && ${file.os}===${platFilter}`);
core.debug(`${file.arch}===${archFilter} && ${file.os}===${platFilter}`);
return file.arch === archFilter && file.os === platFilter;
});
if (goFile) {
core_1.debug(`matched ${candidate.version}`);
core.debug(`matched ${candidate.version}`);
match = candidate;
break;
}
@ -4730,14 +5108,17 @@ function findMatch(versionSpec, stable) {
});
}
exports.findMatch = findMatch;
function getVersions(dlUrl) {
function getVersionsDist(dlUrl) {
return __awaiter(this, void 0, void 0, function* () {
// this returns versions descending so latest is first
let http = new httpm.HttpClient('setup-go');
let http = new httpm.HttpClient('setup-go', [], {
allowRedirects: true,
maxRedirects: 3
});
return (yield http.getJson(dlUrl)).result;
});
}
exports.getVersions = getVersions;
exports.getVersionsDist = getVersionsDist;
//
// Convert the go version syntax into semver for semver matching
// 1.13.1 => 1.13.1
@ -4826,12 +5207,10 @@ function getProxyUrl(reqUrl) {
}
let proxyVar;
if (usingSsl) {
proxyVar = process.env["https_proxy"] ||
process.env["HTTPS_PROXY"];
proxyVar = process.env['https_proxy'] || process.env['HTTPS_PROXY'];
}
else {
proxyVar = process.env["http_proxy"] ||
process.env["HTTP_PROXY"];
proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY'];
}
if (proxyVar) {
proxyUrl = url.parse(proxyVar);
@ -4843,7 +5222,7 @@ function checkBypass(reqUrl) {
if (!reqUrl.hostname) {
return false;
}
let noProxy = process.env["no_proxy"] || process.env["NO_PROXY"] || '';
let noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
if (!noProxy) {
return false;
}
@ -4864,7 +5243,10 @@ function checkBypass(reqUrl) {
upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`);
}
// Compare request host against noproxy
for (let upperNoProxyItem of noProxy.split(',').map(x => x.trim().toUpperCase()).filter(x => x)) {
for (let upperNoProxyItem of noProxy
.split(',')
.map(x => x.trim().toUpperCase())
.filter(x => x)) {
if (upperReqHosts.some(x => x === upperNoProxyItem)) {
return true;
}
@ -4967,8 +5349,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const tr = __webpack_require__(9);
const tr = __importStar(__webpack_require__(9));
/**
* Exec a command.
* Output will be streamed to the live console.

12644
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -23,10 +23,10 @@
"author": "GitHub",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.2.2",
"@actions/core": "^1.2.3",
"@actions/http-client": "^1.0.6",
"@actions/io": "^1.0.2",
"@actions/tool-cache": "^1.3.3",
"@actions/tool-cache": "^1.5.5",
"semver": "^6.1.1"
},
"devDependencies": {
@ -39,6 +39,6 @@
"nock": "^10.0.6",
"prettier": "^1.17.1",
"ts-jest": "^24.0.2",
"typescript": "^3.5.1"
"typescript": "^3.8.3"
}
}

View File

@ -1,46 +1,12 @@
import * as tc from '@actions/tool-cache';
import * as core from '@actions/core';
import * as path from 'path';
import * as semver from 'semver';
import * as httpm from '@actions/http-client';
import * as sys from './system';
import {debug} from '@actions/core';
import os from 'os';
export async function downloadGo(
versionSpec: string,
stable: boolean
): Promise<string | undefined> {
let toolPath: string | undefined;
try {
let match: IGoVersion | undefined = await findMatch(versionSpec, stable);
if (match) {
// download
debug(`match ${match.version}`);
let downloadUrl: string = `https://storage.googleapis.com/golang/${match.files[0].filename}`;
console.log(`Downloading from ${downloadUrl}`);
let downloadPath: string = await tc.downloadTool(downloadUrl);
debug(`downloaded to ${downloadPath}`);
// extract
console.log('Extracting ...');
let extPath: string =
sys.getPlatform() == 'windows'
? await tc.extractZip(downloadPath)
: await tc.extractTar(downloadPath);
debug(`extracted to ${extPath}`);
// extracts with a root folder that matches the fileName downloaded
const toolRoot = path.join(extPath, 'go');
toolPath = await tc.cacheDir(toolRoot, 'go', makeSemver(match.version));
}
} catch (error) {
throw new Error(`Failed to download version ${versionSpec}: ${error}`);
}
return toolPath;
}
type InstallationType = 'dist' | 'manifest';
export interface IGoVersionFile {
filename: string;
@ -55,6 +21,160 @@ export interface IGoVersion {
files: IGoVersionFile[];
}
export interface IGoVersionInfo {
type: InstallationType;
downloadUrl: string;
resolvedVersion: string;
fileName: string;
}
export async function getGo(
versionSpec: string,
stable: boolean,
auth: string | undefined
) {
let osPlat: string = os.platform();
let osArch: string = os.arch();
// check cache
let toolPath: string;
toolPath = tc.find('go', versionSpec);
// If not found in cache, download
if (toolPath) {
core.info(`Found in cache @ ${toolPath}`);
return toolPath;
}
core.info(`Attempting to download ${versionSpec}...`);
let downloadPath = '';
let info: IGoVersionInfo | null = null;
//
// Try download from internal distribution (popular versions only)
//
try {
info = await getInfoFromManifest(versionSpec, stable, auth);
if (info) {
downloadPath = await installGoVersion(info, auth);
} else {
core.info(
'Not found in manifest. Falling back to download directly from Go'
);
}
} catch (err) {
if (
err instanceof tc.HTTPError &&
(err.httpStatusCode === 403 || err.httpStatusCode === 429)
) {
core.info(
`Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded`
);
} else {
core.info(err.message);
}
core.debug(err.stack);
core.info('Falling back to download directly from Go');
}
//
// Download from storage.googleapis.com
//
if (!downloadPath) {
info = await getInfoFromDist(versionSpec, stable);
if (!info) {
throw new Error(
`Unable to find Go version '${versionSpec}' for platform ${osPlat} and architecture ${osArch}.`
);
}
try {
core.info('Install from dist');
downloadPath = await installGoVersion(info, undefined);
} catch (err) {
throw new Error(`Failed to download version ${versionSpec}: ${err}`);
}
}
return downloadPath;
}
async function installGoVersion(
info: IGoVersionInfo,
auth: string | undefined
): Promise<string> {
core.info(`Acquiring ${info.resolvedVersion} from ${info.downloadUrl}`);
const downloadPath = await tc.downloadTool(info.downloadUrl, undefined, auth);
core.info('Extracting Go...');
let extPath = await extractGoArchive(downloadPath);
core.info(`Successfully extracted go to ${extPath}`);
if (info.type === 'dist') {
extPath = path.join(extPath, 'go');
}
core.info('Adding to the cache ...');
const cachedDir = await tc.cacheDir(
extPath,
'go',
makeSemver(info.resolvedVersion)
);
core.info(`Successfully cached go to ${cachedDir}`);
return cachedDir;
}
export async function extractGoArchive(archivePath: string): Promise<string> {
const arch = os.arch();
let extPath: string;
if (arch === 'win32') {
extPath = await tc.extractZip(archivePath);
} else {
extPath = await tc.extractTar(archivePath);
}
return extPath;
}
export async function getInfoFromManifest(
versionSpec: string,
stable: boolean,
auth: string | undefined
): Promise<IGoVersionInfo | null> {
let info: IGoVersionInfo | null = null;
const releases = await tc.getManifestFromRepo('actions', 'go-versions', auth);
core.info(`matching ${versionSpec}...`);
const rel = await tc.findFromManifest(versionSpec, stable, releases);
if (rel && rel.files.length > 0) {
info = <IGoVersionInfo>{};
info.type = 'manifest';
info.resolvedVersion = rel.version;
info.downloadUrl = rel.files[0].download_url;
info.fileName = rel.files[0].filename;
}
return info;
}
async function getInfoFromDist(
versionSpec: string,
stable: boolean
): Promise<IGoVersionInfo | null> {
let version: IGoVersion | undefined;
version = await findMatch(versionSpec, stable);
if (!version) {
return null;
}
let downloadUrl: string = `https://storage.googleapis.com/golang/${version.files[0].filename}`;
return <IGoVersionInfo>{
type: 'dist',
downloadUrl: downloadUrl,
resolvedVersion: version.version,
fileName: version.files[0].filename
};
}
export async function findMatch(
versionSpec: string,
stable: boolean
@ -66,7 +186,9 @@ export async function findMatch(
let match: IGoVersion | undefined;
const dlUrl: string = 'https://golang.org/dl/?mode=json&include=all';
let candidates: IGoVersion[] | null = await module.exports.getVersions(dlUrl);
let candidates: IGoVersion[] | null = await module.exports.getVersionsDist(
dlUrl
);
if (!candidates) {
throw new Error(`golang download url did not return results`);
}
@ -83,18 +205,20 @@ export async function findMatch(
version = version + '.0';
}
debug(`check ${version} satisfies ${versionSpec}`);
core.debug(`check ${version} satisfies ${versionSpec}`);
if (
semver.satisfies(version, versionSpec) &&
(!stable || candidate.stable === stable)
) {
goFile = candidate.files.find(file => {
debug(`${file.arch}===${archFilter} && ${file.os}===${platFilter}`);
core.debug(
`${file.arch}===${archFilter} && ${file.os}===${platFilter}`
);
return file.arch === archFilter && file.os === platFilter;
});
if (goFile) {
debug(`matched ${candidate.version}`);
core.debug(`matched ${candidate.version}`);
match = candidate;
break;
}
@ -110,9 +234,14 @@ export async function findMatch(
return result;
}
export async function getVersions(dlUrl: string): Promise<IGoVersion[] | null> {
export async function getVersionsDist(
dlUrl: string
): Promise<IGoVersion[] | null> {
// this returns versions descending so latest is first
let http: httpm.HttpClient = new httpm.HttpClient('setup-go');
let http: httpm.HttpClient = new httpm.HttpClient('setup-go', [], {
allowRedirects: true,
maxRedirects: 3
});
return (await http.getJson<IGoVersion[]>(dlUrl)).result;
}

View File

@ -1,10 +1,10 @@
import * as core from '@actions/core';
import * as io from '@actions/io';
import * as tc from '@actions/tool-cache';
import * as installer from './installer';
import path from 'path';
import cp from 'child_process';
import fs from 'fs';
import {URL} from 'url';
export async function run() {
try {
@ -18,47 +18,35 @@ export async function run() {
// since getting unstable versions should be explicit
let stable = (core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
console.log(
`Setup go ${stable ? 'stable' : ''} version spec ${versionSpec}`
);
core.info(`Setup go ${stable ? 'stable' : ''} version spec ${versionSpec}`);
if (versionSpec) {
let installDir: string | undefined = tc.find('go', versionSpec);
let token = core.getInput('token');
let auth = !token || isGhes() ? undefined : `token ${token}`;
if (!installDir) {
console.log(
`A version satisfying ${versionSpec} not found locally, attempting to download ...`
);
installDir = await installer.downloadGo(versionSpec, stable);
console.log('Installed');
}
const installDir = await installer.getGo(versionSpec, stable, auth);
if (installDir) {
core.exportVariable('GOROOT', installDir);
core.addPath(path.join(installDir, 'bin'));
console.log('Added go to the path');
core.exportVariable('GOROOT', installDir);
core.addPath(path.join(installDir, 'bin'));
core.info('Added go to the path');
let added = addBinToPath();
core.debug(`add bin ${added}`);
} else {
throw new Error(
`Could not find a version that satisfied version spec: ${versionSpec}`
);
}
let added = await addBinToPath();
core.debug(`add bin ${added}`);
core.info(`Successfully setup go version ${versionSpec}`);
}
// add problem matchers
const matchersPath = path.join(__dirname, '..', 'matchers.json');
console.log(`##[add-matcher]${matchersPath}`);
core.info(`##[add-matcher]${matchersPath}`);
// output the version actually being used
let goPath = await io.which('go');
let goVersion = (cp.execSync(`${goPath} version`) || '').toString();
console.log(goVersion);
core.info(goVersion);
core.startGroup('go env');
let goEnv = (cp.execSync(`${goPath} env`) || '').toString();
console.log(goEnv);
core.info(goEnv);
core.endGroup();
} catch (error) {
core.setFailed(error.message);
@ -68,25 +56,25 @@ export async function run() {
export async function addBinToPath(): Promise<boolean> {
let added = false;
let g = await io.which('go');
_debug(`which go :${g}:`);
core.debug(`which go :${g}:`);
if (!g) {
_debug('go not in the path');
core.debug('go not in the path');
return added;
}
let buf = cp.execSync('go env GOPATH');
if (buf) {
let gp = buf.toString().trim();
_debug(`go env GOPATH :${gp}:`);
core.debug(`go env GOPATH :${gp}:`);
if (!fs.existsSync(gp)) {
// some of the hosted images have go install but not profile dir
_debug(`creating ${gp}`);
core.debug(`creating ${gp}`);
io.mkdirP(gp);
}
let bp = path.join(gp, 'bin');
if (!fs.existsSync(bp)) {
_debug(`creating ${bp}`);
core.debug(`creating ${bp}`);
io.mkdirP(bp);
}
@ -96,6 +84,9 @@ export async function addBinToPath(): Promise<boolean> {
return added;
}
export function _debug(message: string) {
core.debug(message);
function isGhes(): boolean {
const ghUrl = new URL(
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
);
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
}