mirror of
https://github.com/actions/setup-go.git
synced 2026-04-02 01:44:21 +03:00
* feat: add go-download-base-url input for custom Go distributions
Add support for downloading Go from custom sources such as Microsoft Go
(aka.ms). Users can specify a custom download base URL via the
`go-download-base-url` input or the `GO_DOWNLOAD_BASE_URL` environment
variable (input takes precedence).
When a custom URL is provided, the action skips the GitHub-hosted
manifest and attempts to resolve versions from the custom URL's JSON
listing. If the listing is unavailable (as with aka.ms redirect links),
it falls back to constructing the download URL directly from the
version, platform, and architecture.
Usage:
- uses: actions/setup-go@v6
with:
go-version: '1.25'
go-download-base-url: 'https://aka.ms/golang/release/latest'
Changes:
- action.yml: add go-download-base-url optional input
- installer.ts: add getInfoFromDirectDownload() for URL construction
fallback, thread custom URL through getGo/getInfoFromDist/findMatch
- main.ts: read new input and GO_DOWNLOAD_BASE_URL env var
- setup-go.test.ts: add 12 unit tests for custom URL behavior
- microsoft-validation.yml: add E2E workflow testing Microsoft build of Go
across ubuntu/windows/macos with versions 1.24 and 1.25
- README.md: document new input with Microsoft build of Go examples
* run prettier
* fixup PR review
* revert cache-save
* fixup
* handle distinct cache
* skip json for known URL
* fix bug in JSON with custom URL
192 lines
5.7 KiB
TypeScript
192 lines
5.7 KiB
TypeScript
import * as core from '@actions/core';
|
|
import * as io from '@actions/io';
|
|
import * as installer from './installer';
|
|
import * as semver from 'semver';
|
|
import path from 'path';
|
|
import {restoreCache} from './cache-restore';
|
|
import {isCacheFeatureAvailable} from './cache-utils';
|
|
import cp from 'child_process';
|
|
import fs from 'fs';
|
|
import os from 'os';
|
|
import {Architecture} from './types';
|
|
|
|
export async function run() {
|
|
try {
|
|
//
|
|
// versionSpec is optional. If supplied, install / use from the tool cache
|
|
// If not supplied then problem matchers will still be setup. Useful for self-hosted.
|
|
//
|
|
const versionSpec = resolveVersionInput();
|
|
setGoToolchain();
|
|
|
|
const cache = core.getBooleanInput('cache');
|
|
core.info(`Setup go version spec ${versionSpec}`);
|
|
|
|
let arch = core.getInput('architecture') as Architecture;
|
|
|
|
if (!arch) {
|
|
arch = os.arch() as Architecture;
|
|
}
|
|
|
|
if (versionSpec) {
|
|
const token = core.getInput('token');
|
|
const auth = !token ? undefined : `token ${token}`;
|
|
|
|
const checkLatest = core.getBooleanInput('check-latest');
|
|
|
|
const goDownloadBaseUrl =
|
|
core.getInput('go-download-base-url') ||
|
|
process.env['GO_DOWNLOAD_BASE_URL'] ||
|
|
undefined;
|
|
|
|
if (goDownloadBaseUrl) {
|
|
core.info(`Using custom Go download base URL: ${goDownloadBaseUrl}`);
|
|
}
|
|
|
|
const installDir = await installer.getGo(
|
|
versionSpec,
|
|
checkLatest,
|
|
auth,
|
|
arch,
|
|
goDownloadBaseUrl
|
|
);
|
|
|
|
const installDirVersion = path.basename(path.dirname(installDir));
|
|
|
|
core.addPath(path.join(installDir, 'bin'));
|
|
core.info('Added go to the path');
|
|
|
|
const version = installer.makeSemver(installDirVersion);
|
|
// Go versions less than 1.9 require GOROOT to be set
|
|
if (semver.lt(version, '1.9.0')) {
|
|
core.info('Setting GOROOT for Go version < 1.9');
|
|
core.exportVariable('GOROOT', installDir);
|
|
}
|
|
|
|
core.info(`Successfully set up Go version ${versionSpec}`);
|
|
} else {
|
|
core.info(
|
|
'[warning]go-version input was not specified. The action will try to use pre-installed version.'
|
|
);
|
|
}
|
|
|
|
const added = await addBinToPath();
|
|
core.debug(`add bin ${added}`);
|
|
|
|
const goPath = await io.which('go');
|
|
const goVersion = (cp.execSync(`${goPath} version`) || '').toString();
|
|
|
|
if (cache && isCacheFeatureAvailable()) {
|
|
const packageManager = 'default';
|
|
const cacheDependencyPath = core.getInput('cache-dependency-path');
|
|
try {
|
|
await restoreCache(
|
|
parseGoVersion(goVersion),
|
|
packageManager,
|
|
cacheDependencyPath
|
|
);
|
|
} catch (error) {
|
|
core.warning(`Restore cache failed: ${(error as Error).message}`);
|
|
}
|
|
}
|
|
|
|
// add problem matchers
|
|
const matchersPath = path.join(__dirname, '../..', 'matchers.json');
|
|
core.info(`##[add-matcher]${matchersPath}`);
|
|
|
|
// output the version actually being used
|
|
core.info(goVersion);
|
|
|
|
core.setOutput('go-version', parseGoVersion(goVersion));
|
|
|
|
core.startGroup('go env');
|
|
const goEnv = (cp.execSync(`${goPath} env`) || '').toString();
|
|
core.info(goEnv);
|
|
core.endGroup();
|
|
} catch (error) {
|
|
core.setFailed((error as Error).message);
|
|
}
|
|
}
|
|
|
|
export async function addBinToPath(): Promise<boolean> {
|
|
let added = false;
|
|
const g = await io.which('go');
|
|
core.debug(`which go :${g}:`);
|
|
if (!g) {
|
|
core.debug('go not in the path');
|
|
return added;
|
|
}
|
|
|
|
const buf = cp.execSync('go env GOPATH');
|
|
if (buf.length > 1) {
|
|
const gp = buf.toString().trim();
|
|
core.debug(`go env GOPATH :${gp}:`);
|
|
if (!fs.existsSync(gp)) {
|
|
// some of the hosted images have go install but not profile dir
|
|
core.debug(`creating ${gp}`);
|
|
await io.mkdirP(gp);
|
|
}
|
|
|
|
const bp = path.join(gp, 'bin');
|
|
if (!fs.existsSync(bp)) {
|
|
core.debug(`creating ${bp}`);
|
|
await io.mkdirP(bp);
|
|
}
|
|
|
|
core.addPath(bp);
|
|
added = true;
|
|
}
|
|
return added;
|
|
}
|
|
|
|
export function parseGoVersion(versionString: string): string {
|
|
// get the installed version as an Action output
|
|
// based on go/src/cmd/go/internal/version/version.go:
|
|
// fmt.Printf("go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
|
// expecting go<version> for runtime.Version()
|
|
return versionString.split(' ')[2].slice('go'.length);
|
|
}
|
|
|
|
function resolveVersionInput(): string {
|
|
let version = core.getInput('go-version');
|
|
const versionFilePath = core.getInput('go-version-file');
|
|
|
|
if (version && versionFilePath) {
|
|
core.warning(
|
|
'Both go-version and go-version-file inputs are specified, only go-version will be used'
|
|
);
|
|
}
|
|
|
|
if (version) {
|
|
return version;
|
|
}
|
|
|
|
if (versionFilePath) {
|
|
if (!fs.existsSync(versionFilePath)) {
|
|
throw new Error(
|
|
`The specified go version file at: ${versionFilePath} does not exist`
|
|
);
|
|
}
|
|
version = installer.parseGoVersionFile(versionFilePath);
|
|
}
|
|
|
|
return version;
|
|
}
|
|
|
|
function setGoToolchain() {
|
|
// docs: https://go.dev/doc/toolchain
|
|
// "local indicates the bundled Go toolchain (the one that shipped with the go command being run)"
|
|
// this is so any 'go' command is run with the selected Go version
|
|
// and doesn't trigger a toolchain download and run commands with that
|
|
// see e.g. issue #424
|
|
// and a similar discussion: https://github.com/docker-library/golang/issues/472.
|
|
// Set the value in process env so any `go` commands run as child-process
|
|
// don't cause toolchain downloads
|
|
process.env[installer.GOTOOLCHAIN_ENV_VAR] = installer.GOTOOLCHAIN_LOCAL_VAL;
|
|
// and in the runner env so e.g. a user running `go mod tidy` won't cause it
|
|
core.exportVariable(
|
|
installer.GOTOOLCHAIN_ENV_VAR,
|
|
installer.GOTOOLCHAIN_LOCAL_VAL
|
|
);
|
|
}
|