0
1
Fork 0

Compare commits

...

4 Commits

Author SHA1 Message Date
Matthew Hughes 3e4717deba
Merge be5f1f14e1 into 99176a8f9a 2024-04-15 15:36:26 +01:00
Andy Brody 99176a8f9a
Update README.md with V5 release notes (#459) 2024-04-15 09:19:11 -05:00
Matthew Hughes be5f1f14e1 Prefer installing version from `toolchain` directive
Prefer this over the version from the `go` directive. Per the docs[1]

> The toolchain line declares a suggested toolchain to use with the
module or workspace

It seems reasonable to use this, since running this action in a
directory containing a `go.mod` (or `go.work`) suggests the user is
wishing to work _with the module or workspace_.

See (TODO link issue)
2024-03-03 09:48:10 +00:00
Matthew Hughes f54e8eea6b Configure environment to avoid toolchain installs
Force `go` to always use the local toolchain (i.e. the one the one that
shipped with the go command being run) via setting the `GOTOOLCHAIN`
environment variable to `local`[1]:

> When GOTOOLCHAIN is set to local, the go command always runs the
bundled Go toolchain.

This is how things are setup in the official Docker images (e.g.[2], see
also the discussion around that change[3]). The motivation behind this
is to:

* Reduce duplicate work, the action will install a version of Go, a
  toolchain will be detected, the toolchain will be detected and then
  another version of Go installed
* Avoid Unexpected behaviour: if you specify this action runs with some Go
  version (e.g. `1.21.0`) but your go.mod contains a `toolchain` or `go`
  directive for a newer version (e.g. `1.22.0`) then, without any other
  configuration/environment setup, any go commands will be run using go
  `1.22.0`
* TODO: link image

This will be a **breaking change** for some workflows. Given a `go.mod`
like:

    module proj

    go 1.22.0

Then running any `go` command, e.g. `go mod tidy`, in an environment
where only go versions before `1.22.0` were installed would previously
trigger a toolchain download of Go `1.22.0` and that version being used
to execute the command. With this change the above would error out with
something like:

> go: go.mod requires go >= 1.22.0 (running go 1.21.7;
GOTOOLCHAIN=local)

[1] https://go.dev/doc/toolchain#select
[2] dae3405a32/Dockerfile-linux.template (L163)
[3] https://github.com/docker-library/golang/issues/472
2024-03-03 09:06:34 +00:00
5 changed files with 126 additions and 9 deletions

View File

@ -8,6 +8,14 @@ This action sets up a go environment for use in actions by:
- Optionally downloading and caching a version of Go by version and adding to `PATH`.
- Registering problem matchers for error output.
# V5
The V5 edition of the action offers:
- Upgraded Node.js runtime from node16 to node20
See full release notes on the [releases page](https://github.com/actions/setup-go/releases).
# V4
The V4 edition of the action offers:

View File

@ -265,7 +265,7 @@ describe('setup-go', () => {
expect(logSpy).toHaveBeenCalledWith(`Setup go version spec 1.13.0`);
});
it('does not export any variables for Go versions >=1.9', async () => {
it('does not export GOROOT for Go versions >=1.9', async () => {
inputs['go-version'] = '1.13.0';
inSpy.mockImplementation(name => inputs[name]);
@ -278,7 +278,7 @@ describe('setup-go', () => {
});
await main.run();
expect(vars).toStrictEqual({});
expect(vars).not.toHaveProperty('GOROOT');
});
it('exports GOROOT for Go versions <1.9', async () => {
@ -294,9 +294,7 @@ describe('setup-go', () => {
});
await main.run();
expect(vars).toStrictEqual({
GOROOT: toolPath
});
expect(vars).toHaveProperty('GOROOT', toolPath);
});
it('finds a version of go already in the cache', async () => {
@ -966,4 +964,68 @@ use .
}
);
});
describe('go-version-file-toolchain', () => {
const goModContents = `module example.com/mymodule
go 1.14
toolchain go1.21.0
require (
example.com/othermodule v1.2.3
example.com/thismodule v1.2.3
example.com/thatmodule v1.2.3
)
replace example.com/thatmodule => ../thatmodule
exclude example.com/thismodule v1.3.0
`;
const goWorkContents = `go 1.19
toolchain go1.21.0
use .
`;
it('reads version from toolchain directive in go.mod', async () => {
inputs['go-version-file'] = 'go.mod';
existsSpy.mockImplementation(() => true);
readFileSpy.mockImplementation(() => Buffer.from(goModContents));
await main.run();
expect(logSpy).toHaveBeenCalledWith('Setup go version spec 1.21.0');
expect(logSpy).toHaveBeenCalledWith('Attempting to download 1.21.0...');
expect(logSpy).toHaveBeenCalledWith('matching 1.21.0...');
});
it('reads version from toolchain directive in go.work', async () => {
inputs['go-version-file'] = 'go.work';
existsSpy.mockImplementation(() => true);
readFileSpy.mockImplementation(() => Buffer.from(goWorkContents));
await main.run();
expect(logSpy).toHaveBeenCalledWith('Setup go version spec 1.21.0');
expect(logSpy).toHaveBeenCalledWith('Attempting to download 1.21.0...');
expect(logSpy).toHaveBeenCalledWith('matching 1.21.0...');
});
});
it('exports GOTOOLCHAIN and sets it in current process env', async () => {
inputs['go-version'] = '1.21.0';
inSpy.mockImplementation(name => inputs[name]);
const vars: {[key: string]: string} = {};
exportVarSpy.mockImplementation((name: string, val: string) => {
vars[name] = val;
});
await main.run();
expect(vars).toStrictEqual({GOTOOLCHAIN: 'local'});
expect(process.env).toHaveProperty('GOTOOLCHAIN', 'local');
});
});

26
dist/setup/index.js vendored
View File

@ -88329,8 +88329,14 @@ function parseGoVersionFile(versionFilePath) {
const contents = fs_1.default.readFileSync(versionFilePath).toString();
if (path.basename(versionFilePath) === 'go.mod' ||
path.basename(versionFilePath) === 'go.work') {
const match = contents.match(/^go (\d+(\.\d+)*)/m);
return match ? match[1] : '';
// toolchain directive: https://go.dev/ref/mod#go-mod-file-toolchain
const matchToolchain = contents.match(/^toolchain go(\d+(\.\d+)*)/m);
if (matchToolchain) {
return matchToolchain[1];
}
// go directive: https://go.dev/ref/mod#go-mod-file-go
const matchGo = contents.match(/^go (\d+(\.\d+)*)/m);
return matchGo ? matchGo[1] : '';
}
return contents.trim();
}
@ -88433,6 +88439,7 @@ const os_1 = __importDefault(__nccwpck_require__(2037));
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
setToolchain();
//
// 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.
@ -88549,6 +88556,21 @@ function resolveVersionInput() {
}
return version;
}
function setToolchain() {
// 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
const toolchain = 'local';
const toolchainVar = 'GOTOOLCHAIN';
// set the value in process env so any `go` commands run as child-process
// don't cause toolchain downloads
process.env[toolchainVar] = toolchain;
// and in the runner env so e.g. a user running `go mod tidy` won't cause it
core.exportVariable(toolchainVar, toolchain);
}
/***/ }),

View File

@ -424,8 +424,15 @@ export function parseGoVersionFile(versionFilePath: string): string {
path.basename(versionFilePath) === 'go.mod' ||
path.basename(versionFilePath) === 'go.work'
) {
const match = contents.match(/^go (\d+(\.\d+)*)/m);
return match ? match[1] : '';
// toolchain directive: https://go.dev/ref/mod#go-mod-file-toolchain
const matchToolchain = contents.match(/^toolchain go(\d+(\.\d+)*)/m);
if (matchToolchain) {
return matchToolchain[1];
}
// go directive: https://go.dev/ref/mod#go-mod-file-go
const matchGo = contents.match(/^go (\d+(\.\d+)*)/m);
return matchGo ? matchGo[1] : '';
}
return contents.trim();

View File

@ -11,6 +11,7 @@ import os from 'os';
export async function run() {
try {
setToolchain();
//
// 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.
@ -160,3 +161,20 @@ function resolveVersionInput(): string {
return version;
}
function setToolchain() {
// 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
const toolchain = 'local';
const toolchainVar = 'GOTOOLCHAIN';
// set the value in process env so any `go` commands run as child-process
// don't cause toolchain downloads
process.env[toolchainVar] = toolchain;
// and in the runner env so e.g. a user running `go mod tidy` won't cause it
core.exportVariable(toolchainVar, toolchain);
}