mirror of
https://github.com/actions/setup-go.git
synced 2026-09-16 10:21:29 +00:00
Implementation of caching functionality for setup-go action (#228)
This commit is contained in:
@@ -9,6 +9,7 @@ allowed:
|
||||
- mit
|
||||
- cc0-1.0
|
||||
- unlicense
|
||||
- 0bsd
|
||||
|
||||
reviewed:
|
||||
npm:
|
||||
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Generated
Generated
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
@@ -15,7 +15,8 @@ The V3 edition of the action offers:
|
||||
- Adds `GOBIN` to the `PATH`
|
||||
- Proxy support
|
||||
- Check latest version
|
||||
- Bug fixes (including issues around version matching and semver)
|
||||
- Caching packages dependencies
|
||||
- Bug Fixes (including issues around version matching and semver)
|
||||
|
||||
The action will first check the local cache for a version match. If a version is not found locally, it will pull it from the `main` branch of the [go-versions](https://github.com/actions/go-versions/blob/main/versions-manifest.json) repository. On miss or failure, it will fall back to downloading directly from [go dist](https://storage.googleapis.com/golang). To change the default behavior, please use the [check-latest input](#check-latest-version).
|
||||
|
||||
@@ -94,6 +95,36 @@ steps:
|
||||
check-latest: true
|
||||
- run: go run hello.go
|
||||
```
|
||||
## Caching dependency files and build outputs:
|
||||
|
||||
The action has a built-in functionality for caching and restoring go modules and build outputs. It uses [actions/cache](https://github.com/actions/cache) under the hood but requires less configuration settings. The `cache` input is optional, and caching is turned off by default.
|
||||
|
||||
The action defaults to search for the dependency file - go.sum in the repository root, and uses its hash as a part of the cache key. Use `cache-dependency-path` input for cases when multiple dependency files are used, or they are located in different subdirectories.
|
||||
|
||||
**Caching without specifying dependency file path**
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.17'
|
||||
check-latest: true
|
||||
cache: true
|
||||
- run: go run hello.go
|
||||
```
|
||||
|
||||
**Caching in monorepos**
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.17'
|
||||
check-latest: true
|
||||
cache: true
|
||||
cache-dependency-path: subdir/go.sum
|
||||
- run: go run hello.go
|
||||
```
|
||||
## Getting go version from the go.mod file
|
||||
|
||||
The `go-version-file` input accepts a path to a `go.mod` file containing the version of Go to be used by a project. As the `go.mod` file contains only major and minor (e.g. 1.18) tags, the action will search for the latest available patch version sequentially in the runner's directory with the cached tools, in the [version-manifest.json](https://github.com/actions/go-versions/blob/main/versions-manifest.json) file or at the go servers.
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import * as cache from '@actions/cache';
|
||||
import * as core from '@actions/core';
|
||||
import * as glob from '@actions/glob';
|
||||
|
||||
import * as cacheRestore from '../src/cache-restore';
|
||||
import * as cacheUtils from '../src/cache-utils';
|
||||
import {PackageManagerInfo} from '../src/package-managers';
|
||||
|
||||
describe('restoreCache', () => {
|
||||
//Arrange
|
||||
let hashFilesSpy = jest.spyOn(glob, 'hashFiles');
|
||||
let getCacheDirectoryPathSpy = jest.spyOn(
|
||||
cacheUtils,
|
||||
'getCacheDirectoryPath'
|
||||
);
|
||||
let restoreCacheSpy = jest.spyOn(cache, 'restoreCache');
|
||||
let infoSpy = jest.spyOn(core, 'info');
|
||||
let setOutputSpy = jest.spyOn(core, 'setOutput');
|
||||
|
||||
const packageManager = 'default';
|
||||
const cacheDependencyPath = 'path';
|
||||
|
||||
beforeEach(() => {
|
||||
getCacheDirectoryPathSpy.mockImplementation(
|
||||
(PackageManager: PackageManagerInfo) => {
|
||||
return new Promise<string[]>(resolve => {
|
||||
resolve(['cache_directory_path', 'cache_directory_path']);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if dependency file path is not valid', async () => {
|
||||
//Arrange
|
||||
hashFilesSpy.mockImplementation((somePath: string) => {
|
||||
return new Promise<string>(resolve => {
|
||||
resolve('');
|
||||
});
|
||||
});
|
||||
|
||||
//Act + Assert
|
||||
expect(async () => {
|
||||
await cacheRestore.restoreCache(packageManager, cacheDependencyPath);
|
||||
}).rejects.toThrowError(
|
||||
'Some specified paths were not resolved, unable to cache dependencies.'
|
||||
);
|
||||
});
|
||||
|
||||
it('should inform if cache hit is not occured', async () => {
|
||||
//Arrange
|
||||
hashFilesSpy.mockImplementation((somePath: string) => {
|
||||
return new Promise<string>(resolve => {
|
||||
resolve('file_hash');
|
||||
});
|
||||
});
|
||||
|
||||
restoreCacheSpy.mockImplementation(() => {
|
||||
return new Promise<string>(resolve => {
|
||||
resolve('');
|
||||
});
|
||||
});
|
||||
|
||||
//Act + Assert
|
||||
await cacheRestore.restoreCache(packageManager, cacheDependencyPath);
|
||||
expect(infoSpy).toBeCalledWith(`Cache is not found`);
|
||||
});
|
||||
|
||||
it('should set output if cache hit is occured', async () => {
|
||||
//Arrange
|
||||
hashFilesSpy.mockImplementation((somePath: string) => {
|
||||
return new Promise<string>(resolve => {
|
||||
resolve('file_hash');
|
||||
});
|
||||
});
|
||||
|
||||
restoreCacheSpy.mockImplementation(() => {
|
||||
return new Promise<string>(resolve => {
|
||||
resolve('cache_key');
|
||||
});
|
||||
});
|
||||
|
||||
//Act + Assert
|
||||
await cacheRestore.restoreCache(packageManager, cacheDependencyPath);
|
||||
expect(setOutputSpy).toBeCalledWith('cache-hit', true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,179 @@
|
||||
import * as exec from '@actions/exec';
|
||||
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';
|
||||
|
||||
describe('getCommandOutput', () => {
|
||||
//Arrange
|
||||
let getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
|
||||
it('should return trimmed stdout in case of successful exit code', async () => {
|
||||
//Arrange
|
||||
const stdoutResult = ' stdout ';
|
||||
const trimmedStdout = stdoutResult.trim();
|
||||
|
||||
getExecOutputSpy.mockImplementation((commandLine: string) => {
|
||||
return new Promise<exec.ExecOutput>(resolve => {
|
||||
resolve({exitCode: 0, stdout: stdoutResult, stderr: ''});
|
||||
});
|
||||
});
|
||||
|
||||
//Act + Assert
|
||||
return cacheUtils
|
||||
.getCommandOutput('command')
|
||||
.then(data => expect(data).toBe(trimmedStdout));
|
||||
});
|
||||
|
||||
it('should return error in case of unsuccessful exit code', async () => {
|
||||
//Arrange
|
||||
const stderrResult = 'error message';
|
||||
|
||||
getExecOutputSpy.mockImplementation((commandLine: string) => {
|
||||
return new Promise<exec.ExecOutput>(resolve => {
|
||||
resolve({exitCode: 10, stdout: '', stderr: stderrResult});
|
||||
});
|
||||
});
|
||||
|
||||
//Act + Assert
|
||||
expect(async () => {
|
||||
await cacheUtils.getCommandOutput('command');
|
||||
}).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPackageManagerInfo', () => {
|
||||
it('should return package manager info in case of valid package manager name', async () => {
|
||||
//Arrange
|
||||
const packageManagerName = 'default';
|
||||
const expectedResult = {
|
||||
dependencyFilePattern: 'go.sum',
|
||||
cacheFolderCommandList: ['go env GOMODCACHE', 'go env GOCACHE']
|
||||
};
|
||||
|
||||
//Act + Assert
|
||||
return cacheUtils
|
||||
.getPackageManagerInfo(packageManagerName)
|
||||
.then(data => expect(data).toEqual(expectedResult));
|
||||
});
|
||||
|
||||
it('should throw the error in case of invalid package manager name', async () => {
|
||||
//Arrange
|
||||
const packageManagerName = 'invalidName';
|
||||
|
||||
//Act + Assert
|
||||
expect(async () => {
|
||||
await cacheUtils.getPackageManagerInfo(packageManagerName);
|
||||
}).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCacheDirectoryPath', () => {
|
||||
//Arrange
|
||||
let getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
|
||||
|
||||
const validPackageManager: PackageManagerInfo = {
|
||||
dependencyFilePattern: 'go.sum',
|
||||
cacheFolderCommandList: ['go env GOMODCACHE', 'go env GOCACHE']
|
||||
};
|
||||
|
||||
it('should return path to the cache folders which specified package manager uses', async () => {
|
||||
//Arrange
|
||||
getExecOutputSpy.mockImplementation((commandLine: string) => {
|
||||
return new Promise<exec.ExecOutput>(resolve => {
|
||||
resolve({exitCode: 0, stdout: 'path/to/cache/folder', stderr: ''});
|
||||
});
|
||||
});
|
||||
|
||||
const expectedResult = ['path/to/cache/folder', 'path/to/cache/folder'];
|
||||
|
||||
//Act + Assert
|
||||
return cacheUtils
|
||||
.getCacheDirectoryPath(validPackageManager)
|
||||
.then(data => expect(data).toEqual(expectedResult));
|
||||
});
|
||||
|
||||
it('should throw if the specified package name is invalid', async () => {
|
||||
getExecOutputSpy.mockImplementation((commandLine: string) => {
|
||||
return new Promise<exec.ExecOutput>(resolve => {
|
||||
resolve({exitCode: 10, stdout: '', stderr: 'Error message'});
|
||||
});
|
||||
});
|
||||
|
||||
//Act + Assert
|
||||
expect(async () => {
|
||||
await cacheUtils.getCacheDirectoryPath(validPackageManager);
|
||||
}).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isCacheFeatureAvailable', () => {
|
||||
//Arrange
|
||||
let isFeatureAvailableSpy = jest.spyOn(cache, 'isFeatureAvailable');
|
||||
let warningSpy = jest.spyOn(core, 'warning');
|
||||
|
||||
it('should return true when cache feature is available', () => {
|
||||
//Arrange
|
||||
isFeatureAvailableSpy.mockImplementation(() => {
|
||||
return true;
|
||||
});
|
||||
|
||||
let functionResult;
|
||||
|
||||
//Act
|
||||
functionResult = cacheUtils.isCacheFeatureAvailable();
|
||||
|
||||
//Assert
|
||||
expect(functionResult).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should warn when cache feature is unavailable and GHES is not used ', () => {
|
||||
//Arrange
|
||||
isFeatureAvailableSpy.mockImplementation(() => {
|
||||
return false;
|
||||
});
|
||||
|
||||
process.env['GITHUB_SERVER_URL'] = 'https://github.com';
|
||||
|
||||
let warningMessage =
|
||||
'The runner was not able to contact the cache service. Caching will be skipped';
|
||||
|
||||
//Act
|
||||
cacheUtils.isCacheFeatureAvailable();
|
||||
|
||||
//Assert
|
||||
expect(warningSpy).toHaveBeenCalledWith(warningMessage);
|
||||
});
|
||||
|
||||
it('should return false when cache feature is unavailable', () => {
|
||||
//Arrange
|
||||
isFeatureAvailableSpy.mockImplementation(() => {
|
||||
return false;
|
||||
});
|
||||
|
||||
process.env['GITHUB_SERVER_URL'] = 'https://github.com';
|
||||
|
||||
let functionResult;
|
||||
|
||||
//Act
|
||||
functionResult = cacheUtils.isCacheFeatureAvailable();
|
||||
|
||||
//Assert
|
||||
expect(functionResult).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should throw when cache feature is unavailable and GHES is used', () => {
|
||||
//Arrange
|
||||
isFeatureAvailableSpy.mockImplementation(() => {
|
||||
return false;
|
||||
});
|
||||
|
||||
process.env['GITHUB_SERVER_URL'] = 'https://nongithub.com';
|
||||
|
||||
let errorMessage =
|
||||
'Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.';
|
||||
|
||||
//Act + Assert
|
||||
expect(() => cacheUtils.isCacheFeatureAvailable()).toThrow(errorMessage);
|
||||
});
|
||||
});
|
||||
@@ -89,7 +89,7 @@ describe('setup-go', () => {
|
||||
});
|
||||
logSpy.mockImplementation(line => {
|
||||
// uncomment to debug
|
||||
process.stderr.write('log:' + line + '\n');
|
||||
//process.stderr.write('log:' + line + '\n');
|
||||
});
|
||||
dbgSpy.mockImplementation(msg => {
|
||||
// uncomment to see debug output
|
||||
@@ -98,7 +98,7 @@ describe('setup-go', () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
//jest.resetAllMocks();
|
||||
jest.clearAllMocks();
|
||||
//jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
+11
-2
@@ -12,9 +12,18 @@ inputs:
|
||||
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 }}
|
||||
cache:
|
||||
description: Used to specify whether caching is needed. Set to true, if you'd like to enable caching.
|
||||
default: false
|
||||
cache-dependency-path:
|
||||
description: 'Used to specify the path to a dependency file - go.sum'
|
||||
outputs:
|
||||
go-version:
|
||||
description: 'The installed Go version. Useful when given a version range as input.'
|
||||
description: 'The installed Go version. Useful when given a version range as input.'
|
||||
cache-hit:
|
||||
description: 'A boolean value to indicate if a cache was hit'
|
||||
runs:
|
||||
using: 'node16'
|
||||
main: 'dist/index.js'
|
||||
main: 'dist/setup/index.js'
|
||||
post: 'dist/cache-save/index.js'
|
||||
post-if: success()
|
||||
|
||||
Vendored
+59595
File diff suppressed because one or more lines are too long
Vendored
-6409
File diff suppressed because it is too large
Load Diff
Vendored
+62136
File diff suppressed because one or more lines are too long
Generated
+2644
-1871
File diff suppressed because it is too large
Load Diff
+4
-1
@@ -5,7 +5,7 @@
|
||||
"description": "setup go action",
|
||||
"main": "lib/setup-go.js",
|
||||
"scripts": {
|
||||
"build": "tsc && ncc build",
|
||||
"build": "tsc && ncc build -o dist/setup src/setup-go.ts && ncc build -o dist/cache-save src/cache-save.ts",
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts",
|
||||
"test": "jest --coverage",
|
||||
@@ -23,7 +23,10 @@
|
||||
"author": "GitHub",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/cache": "^2.0.2",
|
||||
"@actions/core": "^1.6.0",
|
||||
"@actions/exec": "^1.1.0",
|
||||
"@actions/glob": "^0.2.0",
|
||||
"@actions/http-client": "^1.0.6",
|
||||
"@actions/io": "^1.0.2",
|
||||
"@actions/tool-cache": "^1.5.5",
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import * as cache from '@actions/cache';
|
||||
import * as core from '@actions/core';
|
||||
import * as glob from '@actions/glob';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
import {State, Outputs} from './constants';
|
||||
import {PackageManagerInfo} from './package-managers';
|
||||
import {getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils';
|
||||
|
||||
export const restoreCache = async (
|
||||
packageManager: string,
|
||||
cacheDependencyPath?: string
|
||||
) => {
|
||||
const packageManagerInfo = await getPackageManagerInfo(packageManager);
|
||||
const platform = process.env.RUNNER_OS;
|
||||
const versionSpec = core.getInput('go-version');
|
||||
|
||||
const cachePaths = await getCacheDirectoryPath(packageManagerInfo);
|
||||
|
||||
const dependencyFilePath = cacheDependencyPath
|
||||
? cacheDependencyPath
|
||||
: findDependencyFile(packageManagerInfo);
|
||||
const fileHash = await glob.hashFiles(dependencyFilePath);
|
||||
|
||||
if (!fileHash) {
|
||||
throw new Error(
|
||||
'Some specified paths were not resolved, unable to cache dependencies.'
|
||||
);
|
||||
}
|
||||
|
||||
const primaryKey = `setup-go-${platform}-go-${versionSpec}-${fileHash}`;
|
||||
core.debug(`primary key is ${primaryKey}`);
|
||||
|
||||
core.saveState(State.CachePrimaryKey, primaryKey);
|
||||
|
||||
const cacheKey = await cache.restoreCache(cachePaths, primaryKey);
|
||||
core.setOutput(Outputs.CacheHit, Boolean(cacheKey));
|
||||
|
||||
if (!cacheKey) {
|
||||
core.info(`Cache is not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
core.saveState(State.CacheMatchedKey, cacheKey);
|
||||
core.info(`Cache restored from key: ${cacheKey}`);
|
||||
};
|
||||
|
||||
const findDependencyFile = (packageManager: PackageManagerInfo) => {
|
||||
let dependencyFile = packageManager.dependencyFilePattern;
|
||||
const workspace = process.env.GITHUB_WORKSPACE!;
|
||||
const rootContent = fs.readdirSync(workspace);
|
||||
|
||||
const goSumFileExists = rootContent.includes(dependencyFile);
|
||||
if (!goSumFileExists) {
|
||||
throw new Error(
|
||||
`Dependencies file is not found in ${workspace}. Supported file pattern: ${dependencyFile}`
|
||||
);
|
||||
}
|
||||
|
||||
return path.join(workspace, dependencyFile);
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
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';
|
||||
|
||||
// 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
|
||||
// throw an uncaught exception. Instead of failing this action, just warn.
|
||||
process.on('uncaughtException', e => {
|
||||
const warningPrefix = '[warning]';
|
||||
core.info(`${warningPrefix}${e.message}`);
|
||||
});
|
||||
|
||||
export async function run() {
|
||||
try {
|
||||
await cachePackages();
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
const cachePackages = async () => {
|
||||
const cacheInput = core.getBooleanInput('cache');
|
||||
if (!cacheInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
const packageManager = 'default';
|
||||
|
||||
const state = core.getState(State.CacheMatchedKey);
|
||||
const primaryKey = core.getState(State.CachePrimaryKey);
|
||||
|
||||
const packageManagerInfo = await getPackageManagerInfo(packageManager);
|
||||
|
||||
const cachePaths = await getCacheDirectoryPath(packageManagerInfo);
|
||||
|
||||
const nonExistingPaths = cachePaths.filter(
|
||||
cachePath => !fs.existsSync(cachePath)
|
||||
);
|
||||
|
||||
if (nonExistingPaths.length === cachePaths.length) {
|
||||
throw new Error(`There are no cache folders on the disk`);
|
||||
}
|
||||
|
||||
if (nonExistingPaths.length) {
|
||||
logWarning(
|
||||
`Cache folder path is retrieved but doesn't exist on disk: ${nonExistingPaths.join(
|
||||
', '
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
if (primaryKey === state) {
|
||||
core.info(
|
||||
`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await cache.saveCache(cachePaths, primaryKey);
|
||||
core.info(`Cache saved with the key: ${primaryKey}`);
|
||||
} catch (error) {
|
||||
if (error.name === cache.ValidationError.name) {
|
||||
throw error;
|
||||
} else if (error.name === cache.ReserveCacheError.name) {
|
||||
core.info(error.message);
|
||||
} else {
|
||||
core.warning(`${error.message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function logWarning(message: string): void {
|
||||
const warningPrefix = '[warning]';
|
||||
core.info(`${warningPrefix}${message}`);
|
||||
}
|
||||
|
||||
run();
|
||||
@@ -0,0 +1,75 @@
|
||||
import * as cache from '@actions/cache';
|
||||
import * as core from '@actions/core';
|
||||
import * as exec from '@actions/exec';
|
||||
import {supportedPackageManagers, PackageManagerInfo} from './package-managers';
|
||||
|
||||
export const getCommandOutput = async (toolCommand: string) => {
|
||||
let {stdout, stderr, exitCode} = await exec.getExecOutput(
|
||||
toolCommand,
|
||||
undefined,
|
||||
{ignoreReturnCode: true}
|
||||
);
|
||||
|
||||
if (exitCode) {
|
||||
stderr = !stderr.trim()
|
||||
? `The '${toolCommand}' command failed with exit code: ${exitCode}`
|
||||
: stderr;
|
||||
throw new Error(stderr);
|
||||
}
|
||||
|
||||
return stdout.trim();
|
||||
};
|
||||
|
||||
export const getPackageManagerInfo = async (packageManager: string) => {
|
||||
if (!supportedPackageManagers[packageManager]) {
|
||||
throw new Error(
|
||||
`It's not possible to use ${packageManager}, please, check correctness of the package manager name spelling.`
|
||||
);
|
||||
}
|
||||
const obtainedPackageManager = supportedPackageManagers[packageManager];
|
||||
|
||||
return obtainedPackageManager;
|
||||
};
|
||||
|
||||
export const getCacheDirectoryPath = async (
|
||||
packageManagerInfo: PackageManagerInfo
|
||||
) => {
|
||||
let pathList = await Promise.all(
|
||||
packageManagerInfo.cacheFolderCommandList.map(command =>
|
||||
getCommandOutput(command)
|
||||
)
|
||||
);
|
||||
|
||||
const emptyPaths = pathList.filter(item => !item);
|
||||
|
||||
if (emptyPaths.length) {
|
||||
throw new Error(`Could not get cache folder paths.`);
|
||||
}
|
||||
|
||||
return pathList;
|
||||
};
|
||||
|
||||
export function isGhes(): boolean {
|
||||
const ghUrl = new URL(
|
||||
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
|
||||
);
|
||||
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
||||
}
|
||||
|
||||
export function isCacheFeatureAvailable(): boolean {
|
||||
if (!cache.isFeatureAvailable()) {
|
||||
if (isGhes()) {
|
||||
throw new Error(
|
||||
'Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.'
|
||||
);
|
||||
} else {
|
||||
core.warning(
|
||||
'The runner was not able to contact the cache service. Caching will be skipped'
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export enum State {
|
||||
CachePrimaryKey = 'CACHE_KEY',
|
||||
CacheMatchedKey = 'CACHE_RESULT'
|
||||
}
|
||||
|
||||
export enum Outputs {
|
||||
CacheHit = 'cache-hit'
|
||||
}
|
||||
+10
-9
@@ -3,9 +3,10 @@ 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 {isGhes, isCacheFeatureAvailable} from './cache-utils';
|
||||
import cp from 'child_process';
|
||||
import fs from 'fs';
|
||||
import {URL} from 'url';
|
||||
|
||||
export async function run() {
|
||||
try {
|
||||
@@ -15,6 +16,7 @@ export async function run() {
|
||||
//
|
||||
const versionSpec = resolveVersionInput();
|
||||
|
||||
const cache = core.getBooleanInput('cache');
|
||||
core.info(`Setup go version spec ${versionSpec}`);
|
||||
|
||||
if (versionSpec) {
|
||||
@@ -39,8 +41,14 @@ export async function run() {
|
||||
core.info(`Successfully set up Go version ${versionSpec}`);
|
||||
}
|
||||
|
||||
if (cache && isCacheFeatureAvailable()) {
|
||||
const packageManager = 'default';
|
||||
const cacheDependencyPath = core.getInput('cache-dependency-path');
|
||||
await restoreCache(packageManager, cacheDependencyPath);
|
||||
}
|
||||
|
||||
// add problem matchers
|
||||
const matchersPath = path.join(__dirname, '..', 'matchers.json');
|
||||
const matchersPath = path.join(__dirname, '../..', 'matchers.json');
|
||||
core.info(`##[add-matcher]${matchersPath}`);
|
||||
|
||||
// output the version actually being used
|
||||
@@ -90,13 +98,6 @@ export async function addBinToPath(): Promise<boolean> {
|
||||
return added;
|
||||
}
|
||||
|
||||
function isGhes(): boolean {
|
||||
const ghUrl = new URL(
|
||||
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
|
||||
);
|
||||
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
|
||||
}
|
||||
|
||||
export function parseGoVersion(versionString: string): string {
|
||||
// get the installed version as an Action output
|
||||
// based on go/src/cmd/go/internal/version/version.go:
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
type SupportedPackageManagers = {
|
||||
[prop: string]: PackageManagerInfo;
|
||||
};
|
||||
|
||||
export interface PackageManagerInfo {
|
||||
dependencyFilePattern: string;
|
||||
cacheFolderCommandList: string[];
|
||||
}
|
||||
|
||||
export const supportedPackageManagers: SupportedPackageManagers = {
|
||||
default: {
|
||||
dependencyFilePattern: 'go.sum',
|
||||
cacheFolderCommandList: ['go env GOMODCACHE', 'go env GOCACHE']
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user