Sources modified

This commit is contained in:
Sergey Dolin 2023-09-15 22:43:13 +02:00
parent bfd2fb341f
commit cf004f0dc3
10 changed files with 274 additions and 92 deletions

View file

@ -6,9 +6,10 @@ import fs from 'fs';
import {State, Outputs} from './constants';
import {PackageManagerInfo} from './package-managers';
import {getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils';
import {getBuildCachePath, getCacheDirectoryPath, getPackageManagerInfo} from './cache-utils';
import {getInput} from "@actions/core";
export const restoreCache = async (
export const restoreModCache = async (
versionSpec: string,
packageManager: string,
cacheDependencyPath?: string
@ -25,27 +26,68 @@ export const restoreCache = async (
if (!fileHash) {
throw new Error(
'Some specified paths were not resolved, unable to cache dependencies.'
'Some specified paths were not resolved, unable to cache modules.'
);
}
const linuxVersion =
process.env.RUNNER_OS === 'Linux' ? `${process.env.ImageOS}-` : '';
const primaryKey = `setup-go-${platform}-${linuxVersion}go-${versionSpec}-${fileHash}`;
core.debug(`primary key is ${primaryKey}`);
const cacheIdInput = getInput('cache-id')
const cacheId = cacheIdInput ? `${cacheIdInput}-` : ''
const primaryKey = `setup-go-${platform}-${linuxVersion}go-${versionSpec}-${cacheId}${fileHash}`;
core.debug(`Primary key for modules cache is ${primaryKey}`);
core.saveState(State.CachePrimaryKey, primaryKey);
core.saveState(State.CacheModPrimaryKey, primaryKey);
const cacheKey = await cache.restoreCache(cachePaths, primaryKey);
core.setOutput(Outputs.CacheHit, Boolean(cacheKey));
core.setOutput(Outputs.CacheModHit, Boolean(cacheKey));
if (!cacheKey) {
core.info(`Cache is not found`);
core.setOutput(Outputs.CacheHit, false);
core.info(`Modules cache is not found`);
core.setOutput(Outputs.CacheModHit, false);
return;
}
core.saveState(State.CacheMatchedKey, cacheKey);
core.saveState(State.CacheModMatchedKey, cacheKey);
core.info(`Modules cache restored from key: ${cacheKey}`);
};
export const restoreBuildCache = async (
versionSpec: string,
cacheBuildPath: string
) => {
const platform = process.env.RUNNER_OS;
const cachePath = await getBuildCachePath()
const fileHash = await glob.hashFiles(cacheBuildPath);
if (!fileHash) {
throw new Error(
`The paths ${cacheBuildPath} were not resolved, unable to cache intermediate build files.`
);
}
const linuxVersion =
process.env.RUNNER_OS === 'Linux' ? `${process.env.ImageOS}-` : '';
const cacheIdInput = getInput('cache-id')
const cacheId = cacheIdInput ? `${cacheIdInput}-` : ''
const keyPrefix = `setup-go-build-${platform}-${linuxVersion}go-${versionSpec}-${cacheId}`;
const primaryKey = `${keyPrefix}-${fileHash}`;
core.debug(`Primary key for intermediate build files cache is ${primaryKey}`);
core.saveState(State.CacheBuildPrimaryKey, primaryKey);
const cacheKey = await cache.restoreCache([cachePath], primaryKey, [keyPrefix]);
core.setOutput(Outputs.CacheBuildHit, Boolean(cacheKey));
if (!cacheKey) {
core.info(`Cache is not found`);
core.setOutput(Outputs.CacheBuildHit, false);
return;
}
core.saveState(State.CacheBuildMatchedKey, cacheKey);
core.info(`Cache restored from key: ${cacheKey}`);
};

View file

@ -2,7 +2,13 @@ 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 {
getBuildCachePath,
getCacheDirectoryPath,
getPackageManagerInfo,
needBuildCache,
needModCache
} 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
@ -13,8 +19,11 @@ process.on('uncaughtException', e => {
});
export async function run() {
if (core.getInput('cache-lookup-only').toLowerCase() === 'true')
return;
try {
await cachePackages();
await cacheBuild();
} catch (error) {
let message = 'Unknown error!';
if (error instanceof Error) {
@ -28,15 +37,15 @@ export async function run() {
}
const cachePackages = async () => {
const cacheInput = core.getBooleanInput('cache');
if (!cacheInput) {
const needCache = needModCache()
if (!needCache) {
return;
}
const packageManager = 'default';
const state = core.getState(State.CacheMatchedKey);
const primaryKey = core.getState(State.CachePrimaryKey);
const state = core.getState(State.CacheModMatchedKey);
const primaryKey = core.getState(State.CacheModPrimaryKey);
const packageManagerInfo = await getPackageManagerInfo(packageManager);
@ -80,6 +89,48 @@ const cachePackages = async () => {
core.info(`Cache saved with the key: ${primaryKey}`);
};
const cacheBuild = async () => {
const needCache = needBuildCache()
if (!needCache) {
return;
}
const state = core.getState(State.CacheBuildMatchedKey);
const primaryKey = core.getState(State.CacheBuildPrimaryKey);
const cachePath = await getBuildCachePath()
if (!fs.existsSync(cachePath)) {
core.warning('There are no intermediate build files cache folders on the disk');
return;
}
if (!fs.existsSync(cachePath)) {
logWarning( `Cache folder path is retrieved but doesn't exist on disk: ${cachePath}` );
return;
}
if (!primaryKey) {
core.info(
'Primary key for intermediate build files cache was not generated. Please check the log messages above for more errors or information'
);
return;
}
if (primaryKey === state) {
core.info(
`Cache hit occurred on the primary key ${primaryKey} for intermediate build files cache, not saving cache.`
);
return;
}
const cacheId = await cache.saveCache([cachePath], primaryKey);
if (cacheId === -1) {
return;
}
core.info(`Cache saved with the key: ${primaryKey}`);
};
function logWarning(message: string): void {
const warningPrefix = '[warning]';
core.info(`${warningPrefix}${message}`);

View file

@ -1,85 +1,124 @@
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as _ from 'lodash'
import {supportedPackageManagers, PackageManagerInfo} from './package-managers';
import * as glob from "@actions/glob";
export const getCommandOutput = async (toolCommand: string) => {
let {stdout, stderr, exitCode} = await exec.getExecOutput(
toolCommand,
undefined,
{ignoreReturnCode: true}
);
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);
}
if (exitCode) {
stderr = !stderr.trim()
? `The '${toolCommand}' command failed with exit code: ${exitCode}`
: stderr;
throw new Error(stderr);
}
return stdout.trim();
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];
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;
return obtainedPackageManager;
};
export const getCacheDirectoryPath = async (
packageManagerInfo: PackageManagerInfo
packageManagerInfo: PackageManagerInfo
) => {
const pathOutputs = await Promise.allSettled(
packageManagerInfo.cacheFolderCommandList.map(async command =>
getCommandOutput(command)
)
);
const pathOutputs = await Promise.allSettled(
packageManagerInfo.cacheFolderCommandList.map(async command =>
getCommandOutput(command)
)
);
const results = pathOutputs.map(item => {
if (item.status === 'fulfilled') {
return item.value;
} else {
core.info(`[warning]getting cache directory path failed: ${item.reason}`);
const results = pathOutputs.map(item => {
if (item.status === 'fulfilled') {
return item.value;
} else {
core.info(`[warning]getting cache directory path failed: ${item.reason}`);
}
return '';
});
const cachePaths = results.filter(item => item);
if (!cachePaths.length) {
throw new Error(`Could not get cache folder paths.`);
}
return '';
});
const cachePaths = results.filter(item => item);
if (!cachePaths.length) {
throw new Error(`Could not get cache folder paths.`);
}
return cachePaths;
return cachePaths;
};
export function isGhes(): boolean {
const ghUrl = new URL(
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
);
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
const ghUrl = new URL(
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
);
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
}
/**
* Memoize it in order to avoid confusing multiple messages
*/
export function isCacheFeatureAvailable(): boolean {
if (cache.isFeatureAvailable()) {
return true;
}
if (cache.isFeatureAvailable()) {
return true;
}
if (isGhes()) {
core.warning(
'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.'
);
return false;
}
if (isGhes()) {
core.warning(
'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.'
'The runner was not able to contact the cache service. Caching will be skipped'
);
return false;
}
core.warning(
'The runner was not able to contact the cache service. Caching will be skipped'
);
return false;
}
/**
* Checks if the caching of dependencies is requested
* - `cache-mod` input takes precedence over `cache` input if set
*/
export function needModCache(): Boolean {
const cache = core.getBooleanInput('cache');
const modCache = core.getInput('cache-mod').toLowerCase()
return (modCache === 'true' || cache && modCache !== 'false')
}
/**
* Checks if the caching of intermediate build files is requested
* - `cache-mod` input takes precedence over `cache` input if set
*/
export function needBuildCache(): Boolean {
const cache = core.getBooleanInput('cache');
const buildCache = core.getInput('cache-build').toLowerCase()
return (buildCache === 'true' || cache && buildCache !== 'false')
}
export function getModDependenciesPath(): string {
return core.getInput('cache-dependency-path')
}
export function getBuildDependenciesPath(): string {
return core.getInput('cache-build-path') || "**/*.go"
}
export function getBuildCachePath(): Promise<string> {
return getCommandOutput('go env GOCACHE')
}

View file

@ -1,8 +1,11 @@
export enum State {
CachePrimaryKey = 'CACHE_KEY',
CacheMatchedKey = 'CACHE_RESULT'
CacheModPrimaryKey = 'CACHE_KEY',
CacheModMatchedKey = 'CACHE_RESULT',
CacheBuildPrimaryKey = 'CACHE_BUILD_KEY',
CacheBuildMatchedKey = 'CACHE_BUILD_RESULT'
}
export enum Outputs {
CacheHit = 'cache-hit'
CacheModHit = 'cache-hit',
CacheBuildHit = 'cache-build-hit'
}

View file

@ -3,8 +3,14 @@ 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 {restoreBuildCache, restoreModCache} from './cache-restore';
import {
getBuildDependenciesPath,
getModDependenciesPath,
isCacheFeatureAvailable,
needBuildCache,
needModCache
} from './cache-utils';
import cp from 'child_process';
import fs from 'fs';
import os from 'os';
@ -17,7 +23,6 @@ export async function run() {
//
const versionSpec = resolveVersionInput();
const cache = core.getBooleanInput('cache');
core.info(`Setup go version spec ${versionSpec}`);
let arch = core.getInput('architecture');
@ -64,17 +69,30 @@ export async function run() {
const goPath = await io.which('go');
const goVersion = (cp.execSync(`${goPath} version`) || '').toString();
if (cache && isCacheFeatureAvailable()) {
const cacheFeatureAvailable = isCacheFeatureAvailable()
if (needModCache() && cacheFeatureAvailable) {
const packageManager = 'default';
const cacheDependencyPath = core.getInput('cache-dependency-path');
const cacheDependencyPath = getModDependenciesPath()
try {
await restoreCache(
await restoreModCache(
parseGoVersion(goVersion),
packageManager,
cacheDependencyPath
);
} catch (error) {
core.warning(`Restore cache failed: ${error.message}`);
core.warning(`Restore modules cache failed: ${error.message}`);
}
}
if (needBuildCache() && cacheFeatureAvailable) {
const cacheBuildPath = getBuildDependenciesPath()
try {
await restoreBuildCache(
parseGoVersion(goVersion),
cacheBuildPath
);
} catch (error) {
core.warning(`Restore modules cache failed: ${error.message}`);
}
}
@ -110,7 +128,7 @@ export async function addBinToPath(): Promise<boolean> {
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
// some of hosted images have go install but not profile dir
core.debug(`creating ${gp}`);
await io.mkdirP(gp);
}

View file

@ -10,6 +10,6 @@ export interface PackageManagerInfo {
export const supportedPackageManagers: SupportedPackageManagers = {
default: {
dependencyFilePattern: 'go.sum',
cacheFolderCommandList: ['go env GOMODCACHE', 'go env GOCACHE']
cacheFolderCommandList: ['go env GOMODCACHE']
}
};