Remove toolchain directories from the cache
This commit is contained in:
parent
bfd2fb341f
commit
75d73b8577
|
@ -0,0 +1,40 @@
|
|||
name: Validate 'setup-go'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
schedule:
|
||||
- cron: 0 0 * * *
|
||||
|
||||
jobs:
|
||||
local-cache:
|
||||
name: Setup local-cache version
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
go: [1.21]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: substitute go.mod with toolchain
|
||||
run: |
|
||||
cp __tests__/toolchain.go.mod go.mod
|
||||
shell: bash
|
||||
|
||||
- name: setup-go ${{ matrix.go }}
|
||||
uses: ./
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- name: verify go
|
||||
run: __tests__/verify-go.sh ${{ matrix.go }}
|
||||
shell: bash
|
|
@ -3,6 +3,8 @@ import * as cache from '@actions/cache';
|
|||
import * as core from '@actions/core';
|
||||
import * as cacheUtils from '../src/cache-utils';
|
||||
import {PackageManagerInfo} from '../src/package-managers';
|
||||
import fs, {ObjectEncodingOptions, PathLike} from 'fs';
|
||||
import {getToolchainDirectoriesFromCachedDirectories} from '../src/cache-utils';
|
||||
|
||||
describe('getCommandOutput', () => {
|
||||
//Arrange
|
||||
|
@ -209,3 +211,178 @@ describe('isCacheFeatureAvailable', () => {
|
|||
expect(warningSpy).toHaveBeenCalledWith(warningMessage);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseGoModForToolchainVersion', () => {
|
||||
const readFileSyncSpy = jest.spyOn(fs, 'readFileSync');
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return null when go.mod file not exist', async () => {
|
||||
//Arrange
|
||||
//Act
|
||||
const toolchainVersion = cacheUtils.parseGoModForToolchainVersion(
|
||||
'/tmp/non/exist/foo.bar'
|
||||
);
|
||||
//Assert
|
||||
expect(toolchainVersion).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null when go.mod file is empty', async () => {
|
||||
//Arrange
|
||||
readFileSyncSpy.mockImplementation(() => '');
|
||||
//Act
|
||||
const toolchainVersion = cacheUtils.parseGoModForToolchainVersion('go.mod');
|
||||
//Assert
|
||||
expect(toolchainVersion).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null when go.mod file does not contain toolchain version', async () => {
|
||||
//Arrange
|
||||
readFileSyncSpy.mockImplementation(() =>
|
||||
`
|
||||
module example-mod
|
||||
|
||||
go 1.21.0
|
||||
|
||||
require golang.org/x/tools v0.13.0
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
)
|
||||
`.replace(/^\s+/gm, '')
|
||||
);
|
||||
//Act
|
||||
const toolchainVersion = cacheUtils.parseGoModForToolchainVersion('go.mod');
|
||||
//Assert
|
||||
expect(toolchainVersion).toBeNull();
|
||||
});
|
||||
|
||||
it('should return go version when go.mod file contains go version', () => {
|
||||
//Arrange
|
||||
readFileSyncSpy.mockImplementation(() =>
|
||||
`
|
||||
module example-mod
|
||||
|
||||
go 1.21.0
|
||||
|
||||
toolchain go1.21.1
|
||||
|
||||
require golang.org/x/tools v0.13.0
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
)
|
||||
`.replace(/^\s+/gm, '')
|
||||
);
|
||||
|
||||
//Act
|
||||
const toolchainVersion = cacheUtils.parseGoModForToolchainVersion('go.mod');
|
||||
//Assert
|
||||
expect(toolchainVersion).toBe('1.21.1');
|
||||
});
|
||||
|
||||
it('should return go version when go.mod file contains more than one go version', () => {
|
||||
//Arrange
|
||||
readFileSyncSpy.mockImplementation(() =>
|
||||
`
|
||||
module example-mod
|
||||
|
||||
go 1.21.0
|
||||
|
||||
toolchain go1.21.0
|
||||
toolchain go1.21.1
|
||||
|
||||
require golang.org/x/tools v0.13.0
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
)
|
||||
`.replace(/^\s+/gm, '')
|
||||
);
|
||||
|
||||
//Act
|
||||
const toolchainVersion = cacheUtils.parseGoModForToolchainVersion('go.mod');
|
||||
//Assert
|
||||
expect(toolchainVersion).toBe('1.21.1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getToolchainDirectoriesFromCachedDirectories', () => {
|
||||
const readdirSyncSpy = jest.spyOn(fs, 'readdirSync');
|
||||
const existsSyncSpy = jest.spyOn(fs, 'existsSync');
|
||||
const lstatSync = jest.spyOn(fs, 'lstatSync');
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return empty array when cacheDirectories is empty', async () => {
|
||||
const toolcacheDirectories = getToolchainDirectoriesFromCachedDirectories(
|
||||
'foo',
|
||||
[]
|
||||
);
|
||||
expect(toolcacheDirectories).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return empty array when cacheDirectories does not contain /go/pkg', async () => {
|
||||
readdirSyncSpy.mockImplementation(dir =>
|
||||
[`${dir}1`, `${dir}2`, `${dir}3`].map(s => {
|
||||
const de = new fs.Dirent();
|
||||
de.name = s;
|
||||
de.isDirectory = () => true;
|
||||
return de;
|
||||
})
|
||||
);
|
||||
|
||||
const toolcacheDirectories = getToolchainDirectoriesFromCachedDirectories(
|
||||
'1.1.1',
|
||||
['foo', 'bar']
|
||||
);
|
||||
expect(toolcacheDirectories).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return empty array when cacheDirectories does not contain toolchain@v[0-9.]+-go{goVersion}', async () => {
|
||||
readdirSyncSpy.mockImplementation(dir =>
|
||||
[`${dir}1`, `${dir}2`, `${dir}3`].map(s => {
|
||||
const de = new fs.Dirent();
|
||||
de.name = s;
|
||||
de.isDirectory = () => true;
|
||||
return de;
|
||||
})
|
||||
);
|
||||
|
||||
const toolcacheDirectories = getToolchainDirectoriesFromCachedDirectories(
|
||||
'foo',
|
||||
['foo/go/pkg/mod', 'bar']
|
||||
);
|
||||
expect(toolcacheDirectories).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return one entry when cacheDirectories contains toolchain@v[0-9.]+-go{goVersion} in /pkg/mod', async () => {
|
||||
let seqNo = 1;
|
||||
readdirSyncSpy.mockImplementation(dir =>
|
||||
[`toolchain@v0.0.1-go1.1.1.arch-${seqNo++}`].map(s => {
|
||||
const de = new fs.Dirent();
|
||||
de.name = s;
|
||||
de.isDirectory = () => true;
|
||||
return de;
|
||||
})
|
||||
);
|
||||
existsSyncSpy.mockReturnValue(true);
|
||||
// @ts-ignore - jest does not have relaxed mocks, so we ignore not-implemented methods
|
||||
lstatSync.mockImplementation(() => ({isDirectory: () => true}));
|
||||
|
||||
const toolcacheDirectories = getToolchainDirectoriesFromCachedDirectories(
|
||||
'1.1.1',
|
||||
['/foo/go/pkg/mod', 'bar']
|
||||
);
|
||||
expect(toolcacheDirectories).toEqual([
|
||||
'/foo/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.1.1.arch-1'
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
module example-mod
|
||||
|
||||
go 1.21.0
|
||||
|
||||
toolchain go1.21.0
|
||||
toolchain go1.21.1
|
||||
|
||||
require golang.org/x/tools v0.13.0
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
)
|
|
@ -0,0 +1,52 @@
|
|||
import {isSelfHosted} from '../src/utils';
|
||||
|
||||
describe('utils', () => {
|
||||
describe('isSelfHosted', () => {
|
||||
let AGENT_ISSELFHOSTED: string | undefined;
|
||||
let RUNNER_ENVIRONMENT: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
AGENT_ISSELFHOSTED = process.env['AGENT_ISSELFHOSTED'];
|
||||
delete process.env['AGENT_ISSELFHOSTED'];
|
||||
RUNNER_ENVIRONMENT = process.env['RUNNER_ENVIRONMENT'];
|
||||
delete process.env['RUNNER_ENVIRONMENT'];
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (AGENT_ISSELFHOSTED === undefined) {
|
||||
delete process.env['AGENT_ISSELFHOSTED'];
|
||||
} else {
|
||||
process.env['AGENT_ISSELFHOSTED'] = AGENT_ISSELFHOSTED;
|
||||
}
|
||||
if (RUNNER_ENVIRONMENT === undefined) {
|
||||
delete process.env['RUNNER_ENVIRONMENT'];
|
||||
} else {
|
||||
process.env['RUNNER_ENVIRONMENT'] = RUNNER_ENVIRONMENT;
|
||||
}
|
||||
});
|
||||
|
||||
it('isSelfHosted should be true if no environment variables set', () => {
|
||||
expect(isSelfHosted()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('isSelfHosted should be true if environment variable is not set to denote GitHub hosted', () => {
|
||||
process.env['RUNNER_ENVIRONMENT'] = 'some';
|
||||
expect(isSelfHosted()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('isSelfHosted should be true if environment variable set to denote Azure Pipelines self hosted', () => {
|
||||
process.env['AGENT_ISSELFHOSTED'] = '1';
|
||||
expect(isSelfHosted()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('isSelfHosted should be false if environment variable set to denote GitHub hosted', () => {
|
||||
process.env['RUNNER_ENVIRONMENT'] = 'github-hosted';
|
||||
expect(isSelfHosted()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('isSelfHosted should be false if environment variable is not set to denote Azure Pipelines self hosted', () => {
|
||||
process.env['AGENT_ISSELFHOSTED'] = 'some';
|
||||
expect(isSelfHosted()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -58546,6 +58546,15 @@ const cachePackages = () => __awaiter(void 0, void 0, void 0, function* () {
|
|||
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
|
||||
return;
|
||||
}
|
||||
const toolchainVersion = core.getState(constants_1.State.ToolchainVersion);
|
||||
// toolchainVersion is always null for self-hosted runners
|
||||
if (toolchainVersion) {
|
||||
const toolchainDirectories = cache_utils_1.getToolchainDirectoriesFromCachedDirectories(toolchainVersion, cachePaths);
|
||||
toolchainDirectories.forEach(toolchainDirectory => {
|
||||
core.warning(`Toolchain version ${toolchainVersion} will be removed from cache: ${toolchainDirectory}`);
|
||||
fs_1.default.rmSync(toolchainDirectory, { recursive: true });
|
||||
});
|
||||
}
|
||||
const cacheId = yield cache.saveCache(cachePaths, primaryKey);
|
||||
if (cacheId === -1) {
|
||||
return;
|
||||
|
@ -58594,12 +58603,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
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.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectoryPath = exports.getPackageManagerInfo = exports.getCommandOutput = void 0;
|
||||
exports.getToolchainDirectoriesFromCachedDirectories = exports.parseGoModForToolchainVersion = exports.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectoryPath = exports.getPackageManagerInfo = exports.getCommandOutput = void 0;
|
||||
const cache = __importStar(__nccwpck_require__(7799));
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const exec = __importStar(__nccwpck_require__(1514));
|
||||
const package_managers_1 = __nccwpck_require__(6663);
|
||||
const fs_1 = __importDefault(__nccwpck_require__(7147));
|
||||
const getCommandOutput = (toolCommand) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
let { stdout, stderr, exitCode } = yield exec.getExecOutput(toolCommand, undefined, { ignoreReturnCode: true });
|
||||
if (exitCode) {
|
||||
|
@ -58654,6 +58667,42 @@ function isCacheFeatureAvailable() {
|
|||
return false;
|
||||
}
|
||||
exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
|
||||
function parseGoModForToolchainVersion(goModPath) {
|
||||
try {
|
||||
const goMod = fs_1.default.readFileSync(goModPath, 'utf8');
|
||||
const matches = Array.from(goMod.matchAll(/^toolchain\s+go(\S+)/gm));
|
||||
if (matches && matches.length > 0) {
|
||||
return matches[matches.length - 1][1];
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
if (error.message && error.message.startsWith('ENOENT')) {
|
||||
core.warning(`go.mod file not found at ${goModPath}, can't parse toolchain version`);
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
exports.parseGoModForToolchainVersion = parseGoModForToolchainVersion;
|
||||
function isDirent(item) {
|
||||
return item instanceof fs_1.default.Dirent;
|
||||
}
|
||||
function getToolchainDirectoriesFromCachedDirectories(goVersion, cacheDirectories) {
|
||||
const re = new RegExp(`^toolchain@v[0-9.]+-go${goVersion}\\.`);
|
||||
return (cacheDirectories
|
||||
// This line should be replaced with separating the cache directory from build artefact directory
|
||||
// see PoC PR: https://github.com/actions/setup-go/pull/426
|
||||
// Till then, the workaround is expected to work in most cases, and it won't cause any harm
|
||||
.filter(dir => dir.endsWith('/pkg/mod'))
|
||||
.map(dir => `${dir}/golang.org`)
|
||||
.flatMap(dir => fs_1.default
|
||||
.readdirSync(dir)
|
||||
.map(subdir => (isDirent(subdir) ? subdir.name : dir))
|
||||
.filter(subdir => re.test(subdir))
|
||||
.map(subdir => `${dir}/${subdir}`)));
|
||||
}
|
||||
exports.getToolchainDirectoriesFromCachedDirectories = getToolchainDirectoriesFromCachedDirectories;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
@ -58669,6 +58718,7 @@ var State;
|
|||
(function (State) {
|
||||
State["CachePrimaryKey"] = "CACHE_KEY";
|
||||
State["CacheMatchedKey"] = "CACHE_RESULT";
|
||||
State["ToolchainVersion"] = "TOOLCACHE_VERSION";
|
||||
})(State = exports.State || (exports.State = {}));
|
||||
var Outputs;
|
||||
(function (Outputs) {
|
||||
|
|
|
@ -61191,6 +61191,7 @@ const path_1 = __importDefault(__nccwpck_require__(1017));
|
|||
const fs_1 = __importDefault(__nccwpck_require__(7147));
|
||||
const constants_1 = __nccwpck_require__(9042);
|
||||
const cache_utils_1 = __nccwpck_require__(1678);
|
||||
const utils_1 = __nccwpck_require__(1314);
|
||||
const restoreCache = (versionSpec, packageManager, cacheDependencyPath) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
const packageManagerInfo = yield cache_utils_1.getPackageManagerInfo(packageManager);
|
||||
const platform = process.env.RUNNER_OS;
|
||||
|
@ -61198,6 +61199,15 @@ const restoreCache = (versionSpec, packageManager, cacheDependencyPath) => __awa
|
|||
const dependencyFilePath = cacheDependencyPath
|
||||
? cacheDependencyPath
|
||||
: findDependencyFile(packageManagerInfo);
|
||||
// In order to do not duplicate evaluation of dependency paths, we get
|
||||
// toolchain Version here and pass to the saveCache via the state
|
||||
if (!utils_1.isSelfHosted()) {
|
||||
const toolchainVersion = cacheDependencyPath && path_1.default.basename(cacheDependencyPath) === 'go.mod'
|
||||
? cache_utils_1.parseGoModForToolchainVersion(cacheDependencyPath)
|
||||
: null;
|
||||
toolchainVersion &&
|
||||
core.saveState(constants_1.State.ToolchainVersion, toolchainVersion);
|
||||
}
|
||||
const fileHash = yield glob.hashFiles(dependencyFilePath);
|
||||
if (!fileHash) {
|
||||
throw new Error('Some specified paths were not resolved, unable to cache dependencies.');
|
||||
|
@ -61264,12 +61274,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
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.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectoryPath = exports.getPackageManagerInfo = exports.getCommandOutput = void 0;
|
||||
exports.getToolchainDirectoriesFromCachedDirectories = exports.parseGoModForToolchainVersion = exports.isCacheFeatureAvailable = exports.isGhes = exports.getCacheDirectoryPath = exports.getPackageManagerInfo = exports.getCommandOutput = void 0;
|
||||
const cache = __importStar(__nccwpck_require__(7799));
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const exec = __importStar(__nccwpck_require__(1514));
|
||||
const package_managers_1 = __nccwpck_require__(6663);
|
||||
const fs_1 = __importDefault(__nccwpck_require__(7147));
|
||||
const getCommandOutput = (toolCommand) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
let { stdout, stderr, exitCode } = yield exec.getExecOutput(toolCommand, undefined, { ignoreReturnCode: true });
|
||||
if (exitCode) {
|
||||
|
@ -61324,6 +61338,42 @@ function isCacheFeatureAvailable() {
|
|||
return false;
|
||||
}
|
||||
exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
|
||||
function parseGoModForToolchainVersion(goModPath) {
|
||||
try {
|
||||
const goMod = fs_1.default.readFileSync(goModPath, 'utf8');
|
||||
const matches = Array.from(goMod.matchAll(/^toolchain\s+go(\S+)/gm));
|
||||
if (matches && matches.length > 0) {
|
||||
return matches[matches.length - 1][1];
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
if (error.message && error.message.startsWith('ENOENT')) {
|
||||
core.warning(`go.mod file not found at ${goModPath}, can't parse toolchain version`);
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
exports.parseGoModForToolchainVersion = parseGoModForToolchainVersion;
|
||||
function isDirent(item) {
|
||||
return item instanceof fs_1.default.Dirent;
|
||||
}
|
||||
function getToolchainDirectoriesFromCachedDirectories(goVersion, cacheDirectories) {
|
||||
const re = new RegExp(`^toolchain@v[0-9.]+-go${goVersion}\\.`);
|
||||
return (cacheDirectories
|
||||
// This line should be replaced with separating the cache directory from build artefact directory
|
||||
// see PoC PR: https://github.com/actions/setup-go/pull/426
|
||||
// Till then, the workaround is expected to work in most cases, and it won't cause any harm
|
||||
.filter(dir => dir.endsWith('/pkg/mod'))
|
||||
.map(dir => `${dir}/golang.org`)
|
||||
.flatMap(dir => fs_1.default
|
||||
.readdirSync(dir)
|
||||
.map(subdir => (isDirent(subdir) ? subdir.name : dir))
|
||||
.filter(subdir => re.test(subdir))
|
||||
.map(subdir => `${dir}/${subdir}`)));
|
||||
}
|
||||
exports.getToolchainDirectoriesFromCachedDirectories = getToolchainDirectoriesFromCachedDirectories;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
@ -61339,6 +61389,7 @@ var State;
|
|||
(function (State) {
|
||||
State["CachePrimaryKey"] = "CACHE_KEY";
|
||||
State["CacheMatchedKey"] = "CACHE_RESULT";
|
||||
State["ToolchainVersion"] = "TOOLCACHE_VERSION";
|
||||
})(State = exports.State || (exports.State = {}));
|
||||
var Outputs;
|
||||
(function (Outputs) {
|
||||
|
@ -61495,8 +61546,7 @@ function cacheWindowsDir(extPath, tool, version, arch) {
|
|||
if (os_1.default.platform() !== 'win32')
|
||||
return false;
|
||||
// make sure the action runs in the hosted environment
|
||||
if (process.env['RUNNER_ENVIRONMENT'] !== 'github-hosted' &&
|
||||
process.env['AGENT_ISSELFHOSTED'] === '1')
|
||||
if (utils_1.isSelfHosted())
|
||||
return false;
|
||||
const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'];
|
||||
if (!defaultToolCacheRoot)
|
||||
|
@ -61975,12 +62025,21 @@ exports.getArch = getArch;
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.StableReleaseAlias = void 0;
|
||||
exports.isSelfHosted = exports.StableReleaseAlias = void 0;
|
||||
var StableReleaseAlias;
|
||||
(function (StableReleaseAlias) {
|
||||
StableReleaseAlias["Stable"] = "stable";
|
||||
StableReleaseAlias["OldStable"] = "oldstable";
|
||||
})(StableReleaseAlias = exports.StableReleaseAlias || (exports.StableReleaseAlias = {}));
|
||||
const isSelfHosted = () => process.env['AGENT_ISSELFHOSTED'] === '1' ||
|
||||
(process.env['AGENT_ISSELFHOSTED'] === undefined &&
|
||||
process.env['RUNNER_ENVIRONMENT'] !== 'github-hosted');
|
||||
exports.isSelfHosted = isSelfHosted;
|
||||
/* the above is simplified from:
|
||||
process.env['RUNNER_ENVIRONMENT'] === undefined && process.env['AGENT_ISSELFHOSTED'] === '1'
|
||||
||
|
||||
process.env['AGENT_ISSELFHOSTED'] === undefined && process.env['RUNNER_ENVIRONMENT'] !== 'github-hosted'
|
||||
*/
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,12 @@ import fs from 'fs';
|
|||
|
||||
import {State, Outputs} from './constants';
|
||||
import {PackageManagerInfo} from './package-managers';
|
||||
import {getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils';
|
||||
import {
|
||||
getCacheDirectoryPath,
|
||||
getPackageManagerInfo,
|
||||
parseGoModForToolchainVersion
|
||||
} from './cache-utils';
|
||||
import {isSelfHosted} from './utils';
|
||||
|
||||
export const restoreCache = async (
|
||||
versionSpec: string,
|
||||
|
@ -21,6 +26,18 @@ export const restoreCache = async (
|
|||
const dependencyFilePath = cacheDependencyPath
|
||||
? cacheDependencyPath
|
||||
: findDependencyFile(packageManagerInfo);
|
||||
|
||||
// In order to do not duplicate evaluation of dependency paths, we get
|
||||
// toolchain Version here and pass to the saveCache via the state
|
||||
if (!isSelfHosted()) {
|
||||
const toolchainVersion =
|
||||
cacheDependencyPath && path.basename(cacheDependencyPath) === 'go.mod'
|
||||
? parseGoModForToolchainVersion(cacheDependencyPath)
|
||||
: null;
|
||||
toolchainVersion &&
|
||||
core.saveState(State.ToolchainVersion, toolchainVersion);
|
||||
}
|
||||
|
||||
const fileHash = await glob.hashFiles(dependencyFilePath);
|
||||
|
||||
if (!fileHash) {
|
||||
|
|
|
@ -2,7 +2,11 @@ import * as core from '@actions/core';
|
|||
import * as cache from '@actions/cache';
|
||||
import fs from 'fs';
|
||||
import {State} from './constants';
|
||||
import {getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils';
|
||||
import {
|
||||
getCacheDirectoryPath,
|
||||
getPackageManagerInfo,
|
||||
getToolchainDirectoriesFromCachedDirectories
|
||||
} from './cache-utils';
|
||||
|
||||
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
||||
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
|
||||
|
@ -73,6 +77,21 @@ const cachePackages = async () => {
|
|||
return;
|
||||
}
|
||||
|
||||
const toolchainVersion = core.getState(State.ToolchainVersion);
|
||||
// toolchainVersion is always null for self-hosted runners
|
||||
if (toolchainVersion) {
|
||||
const toolchainDirectories = getToolchainDirectoriesFromCachedDirectories(
|
||||
toolchainVersion,
|
||||
cachePaths
|
||||
);
|
||||
toolchainDirectories.forEach(toolchainDirectory => {
|
||||
core.warning(
|
||||
`Toolchain version ${toolchainVersion} will be removed from cache: ${toolchainDirectory}`
|
||||
);
|
||||
fs.rmSync(toolchainDirectory, {recursive: true});
|
||||
});
|
||||
}
|
||||
|
||||
const cacheId = await cache.saveCache(cachePaths, primaryKey);
|
||||
if (cacheId === -1) {
|
||||
return;
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as cache from '@actions/cache';
|
|||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import {supportedPackageManagers, PackageManagerInfo} from './package-managers';
|
||||
import fs from 'fs';
|
||||
|
||||
export const getCommandOutput = async (toolCommand: string) => {
|
||||
let {stdout, stderr, exitCode} = await exec.getExecOutput(
|
||||
|
@ -83,3 +84,50 @@ export function isCacheFeatureAvailable(): boolean {
|
|||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
export function parseGoModForToolchainVersion(
|
||||
goModPath: string
|
||||
): string | null {
|
||||
try {
|
||||
const goMod = fs.readFileSync(goModPath, 'utf8');
|
||||
const matches = Array.from(goMod.matchAll(/^toolchain\s+go(\S+)/gm));
|
||||
if (matches && matches.length > 0) {
|
||||
return matches[matches.length - 1][1];
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.message && error.message.startsWith('ENOENT')) {
|
||||
core.warning(
|
||||
`go.mod file not found at ${goModPath}, can't parse toolchain version`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isDirent(item: fs.Dirent | string): item is fs.Dirent {
|
||||
return item instanceof fs.Dirent;
|
||||
}
|
||||
|
||||
export function getToolchainDirectoriesFromCachedDirectories(
|
||||
goVersion: string,
|
||||
cacheDirectories: string[]
|
||||
): string[] {
|
||||
const re = new RegExp(`^toolchain@v[0-9.]+-go${goVersion}\\.`);
|
||||
return (
|
||||
cacheDirectories
|
||||
// This line should be replaced with separating the cache directory from build artefact directory
|
||||
// see PoC PR: https://github.com/actions/setup-go/pull/426
|
||||
// Till then, the workaround is expected to work in most cases, and it won't cause any harm
|
||||
.filter(dir => dir.endsWith('/pkg/mod'))
|
||||
.map(dir => `${dir}/golang.org`)
|
||||
.flatMap(dir =>
|
||||
fs
|
||||
.readdirSync(dir)
|
||||
.map(subdir => (isDirent(subdir) ? subdir.name : dir))
|
||||
.filter(subdir => re.test(subdir))
|
||||
.map(subdir => `${dir}/${subdir}`)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export enum State {
|
||||
CachePrimaryKey = 'CACHE_KEY',
|
||||
CacheMatchedKey = 'CACHE_RESULT'
|
||||
CacheMatchedKey = 'CACHE_RESULT',
|
||||
ToolchainVersion = 'TOOLCACHE_VERSION'
|
||||
}
|
||||
|
||||
export enum Outputs {
|
||||
|
|
|
@ -6,7 +6,7 @@ import * as httpm from '@actions/http-client';
|
|||
import * as sys from './system';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import {StableReleaseAlias} from './utils';
|
||||
import {isSelfHosted, StableReleaseAlias} from './utils';
|
||||
|
||||
type InstallationType = 'dist' | 'manifest';
|
||||
|
||||
|
@ -175,11 +175,7 @@ async function cacheWindowsDir(
|
|||
if (os.platform() !== 'win32') return false;
|
||||
|
||||
// make sure the action runs in the hosted environment
|
||||
if (
|
||||
process.env['RUNNER_ENVIRONMENT'] !== 'github-hosted' &&
|
||||
process.env['AGENT_ISSELFHOSTED'] === '1'
|
||||
)
|
||||
return false;
|
||||
if (isSelfHosted()) return false;
|
||||
|
||||
const defaultToolCacheRoot = process.env['RUNNER_TOOL_CACHE'];
|
||||
if (!defaultToolCacheRoot) return false;
|
||||
|
|
10
src/utils.ts
10
src/utils.ts
|
@ -2,3 +2,13 @@ export enum StableReleaseAlias {
|
|||
Stable = 'stable',
|
||||
OldStable = 'oldstable'
|
||||
}
|
||||
|
||||
export const isSelfHosted = (): boolean =>
|
||||
process.env['AGENT_ISSELFHOSTED'] === '1' ||
|
||||
(process.env['AGENT_ISSELFHOSTED'] === undefined &&
|
||||
process.env['RUNNER_ENVIRONMENT'] !== 'github-hosted');
|
||||
/* the above is simplified from:
|
||||
process.env['RUNNER_ENVIRONMENT'] === undefined && process.env['AGENT_ISSELFHOSTED'] === '1'
|
||||
||
|
||||
process.env['AGENT_ISSELFHOSTED'] === undefined && process.env['RUNNER_ENVIRONMENT'] !== 'github-hosted'
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue