mirror of
https://github.com/actions/setup-go.git
synced 2025-09-05 06:41:07 +08:00
Improve toolchain handling (#460)
* 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: if the `toolchain` version in `go.mod` was
greated than the `go` version, the version from the `go` directive
would be installed, then Go would detect the `toolchain` version and
additionally install that
* 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`
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
* 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_.
Link: https://go.dev/doc/toolchain#config [1]
Issue: https://github.com/actions/setup-go/issues/457
* squash! Configure environment to avoid toolchain installs
Only modify env if `GOTOOLCHAIN` is not set
* squash! Prefer installing version from `toolchain` directive
Avoid installing from `toolchain` if `GOTOOLCHAIN` is `local`, also
better regex for matching toolchain directive
This commit is contained in:
@@ -129,6 +129,9 @@ describe('setup-go', () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// clear out env var set during 'run'
|
||||
delete process.env[im.GOTOOLCHAIN_ENV_VAR];
|
||||
|
||||
//jest.resetAllMocks();
|
||||
jest.clearAllMocks();
|
||||
//jest.restoreAllMocks();
|
||||
@@ -285,7 +288,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]);
|
||||
|
||||
@@ -298,7 +301,7 @@ describe('setup-go', () => {
|
||||
});
|
||||
|
||||
await main.run();
|
||||
expect(vars).toStrictEqual({});
|
||||
expect(vars).not.toHaveProperty('GOROOT');
|
||||
});
|
||||
|
||||
it('exports GOROOT for Go versions <1.9', async () => {
|
||||
@@ -314,9 +317,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 () => {
|
||||
@@ -989,4 +990,104 @@ use .
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('go-version-file-toolchain', () => {
|
||||
const goVersions = ['1.22.0', '1.21rc2', '1.18'];
|
||||
const placeholderVersion = '1.19';
|
||||
const buildGoMod = (
|
||||
goVersion: string,
|
||||
toolchainVersion: string
|
||||
) => `module example.com/mymodule
|
||||
|
||||
go ${goVersion}
|
||||
|
||||
toolchain go${toolchainVersion}
|
||||
|
||||
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 buildGoWork = (
|
||||
goVersion: string,
|
||||
toolchainVersion: string
|
||||
) => `go 1.19
|
||||
|
||||
toolchain go${toolchainVersion}
|
||||
|
||||
use .
|
||||
|
||||
`;
|
||||
|
||||
goVersions.forEach(version => {
|
||||
[
|
||||
{
|
||||
goVersionfile: 'go.mod',
|
||||
fileContents: Buffer.from(buildGoMod(placeholderVersion, version)),
|
||||
expected_version: version,
|
||||
desc: 'from toolchain directive'
|
||||
},
|
||||
{
|
||||
goVersionfile: 'go.work',
|
||||
fileContents: Buffer.from(buildGoMod(placeholderVersion, version)),
|
||||
expected_version: version,
|
||||
desc: 'from toolchain directive'
|
||||
},
|
||||
{
|
||||
goVersionfile: 'go.mod',
|
||||
fileContents: Buffer.from(buildGoMod(placeholderVersion, version)),
|
||||
gotoolchain_env: 'local',
|
||||
expected_version: placeholderVersion,
|
||||
desc: 'from go directive when GOTOOLCHAIN is local'
|
||||
},
|
||||
{
|
||||
goVersionfile: 'go.work',
|
||||
fileContents: Buffer.from(buildGoMod(placeholderVersion, version)),
|
||||
gotoolchain_env: 'local',
|
||||
expected_version: placeholderVersion,
|
||||
desc: 'from go directive when GOTOOLCHAIN is local'
|
||||
}
|
||||
].forEach(test => {
|
||||
it(`reads version (${version}) in ${test.goVersionfile} ${test.desc}`, async () => {
|
||||
inputs['go-version-file'] = test.goVersionfile;
|
||||
if (test.gotoolchain_env !== undefined) {
|
||||
process.env[im.GOTOOLCHAIN_ENV_VAR] = test.gotoolchain_env;
|
||||
}
|
||||
existsSpy.mockImplementation(() => true);
|
||||
readFileSpy.mockImplementation(() => Buffer.from(test.fileContents));
|
||||
|
||||
await main.run();
|
||||
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
`Setup go version spec ${test.expected_version}`
|
||||
);
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
`Attempting to download ${test.expected_version}...`
|
||||
);
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
`matching ${test.expected_version}...`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user