mirror of
https://code.forgejo.org/actions/cache.git
synced 2025-04-22 16:53:57 +08:00
save state
This commit is contained in:
parent
ab5323b726
commit
0ad6d2d6f2
13 changed files with 595 additions and 1301 deletions
95
src/cache.service.ts
Normal file
95
src/cache.service.ts
Normal file
|
@ -0,0 +1,95 @@
|
|||
import * as utils from "@actions/cache/lib/internal/cacheUtils";
|
||||
import { createTar, listTar } from "@actions/cache/lib/internal/tar";
|
||||
import * as core from "@actions/core";
|
||||
import { S3 } from "aws-sdk";
|
||||
import filesize from "filesize";
|
||||
import fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
export class CacheService {
|
||||
private _client: S3;
|
||||
private _bucket: string;
|
||||
|
||||
constructor(
|
||||
accessKeyId: string,
|
||||
secretAccessKey: string,
|
||||
region: string,
|
||||
bucket: string
|
||||
) {
|
||||
this._client = new S3({
|
||||
region: region,
|
||||
credentials: {
|
||||
accessKeyId: accessKeyId,
|
||||
secretAccessKey: secretAccessKey
|
||||
}
|
||||
});
|
||||
this._bucket = bucket;
|
||||
}
|
||||
|
||||
async restoreCache(
|
||||
paths: string[],
|
||||
primaryKey: string,
|
||||
restoreKeys: string[]
|
||||
): Promise<string | undefined> {
|
||||
return "";
|
||||
}
|
||||
|
||||
async saveCache(paths: string[], key: string): Promise<string> {
|
||||
const compressionMethod = await utils.getCompressionMethod();
|
||||
|
||||
const cachePaths = await utils.resolvePaths(paths);
|
||||
core.debug("Cache Paths:");
|
||||
core.debug(`${JSON.stringify(cachePaths)}`);
|
||||
|
||||
const archiveFolder = await utils.createTempDirectory();
|
||||
const archivePath = path.join(
|
||||
archiveFolder,
|
||||
utils.getCacheFileName(compressionMethod)
|
||||
);
|
||||
|
||||
core.debug(`Archive Path: ${archivePath}`);
|
||||
|
||||
try {
|
||||
await createTar(archiveFolder, cachePaths, compressionMethod);
|
||||
if (core.isDebug()) {
|
||||
await listTar(archivePath, compressionMethod);
|
||||
}
|
||||
|
||||
core.info(
|
||||
`Archive Size: ${filesize(fs.statSync(archivePath).size)}`
|
||||
);
|
||||
|
||||
core.debug(`Saving Cache (ID: ${key})`);
|
||||
await this.uploadToS3(key, archivePath);
|
||||
} finally {
|
||||
// Try to delete the archive to save space
|
||||
try {
|
||||
await utils.unlinkFile(archivePath);
|
||||
} catch (error) {
|
||||
core.debug(`Failed to delete archive: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
private async uploadToS3(key: string, archivePath: string): Promise<void> {
|
||||
const client = new S3();
|
||||
// Read in the file, convert it to base64, store to S3
|
||||
fs.readFile(archivePath, (err, data) => {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
const base64data = data.toString("base64");
|
||||
|
||||
client
|
||||
.putObject({
|
||||
Bucket: this._bucket,
|
||||
Key: key,
|
||||
Body: base64data
|
||||
})
|
||||
.send();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -2,7 +2,11 @@ export enum Inputs {
|
|||
Key = "key",
|
||||
Path = "path",
|
||||
RestoreKeys = "restore-keys",
|
||||
UploadChunkSize = "upload-chunk-size"
|
||||
UploadChunkSize = "upload-chunk-size",
|
||||
Region = "region",
|
||||
AccessKeyId = "access-key-id",
|
||||
SecretAccessKey = "secret-access-key",
|
||||
Bucket = "bucket"
|
||||
}
|
||||
|
||||
export enum Outputs {
|
||||
|
|
|
@ -1,29 +1,11 @@
|
|||
import * as cache from "@actions/cache";
|
||||
import * as core from "@actions/core";
|
||||
|
||||
import { Events, Inputs, State } from "./constants";
|
||||
import { CacheService } from "./cache.service";
|
||||
import { Inputs, State } from "./constants";
|
||||
import * as utils from "./utils/actionUtils";
|
||||
|
||||
async function run(): Promise<void> {
|
||||
try {
|
||||
if (utils.isGhes()) {
|
||||
utils.logWarning(
|
||||
"Cache action is not supported on GHES. See https://github.com/actions/cache/issues/505 for more details"
|
||||
);
|
||||
utils.setCacheHitOutput(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate inputs, this can cause task failure
|
||||
if (!utils.isValidEvent()) {
|
||||
utils.logWarning(
|
||||
`Event Validation Error: The event type ${
|
||||
process.env[Events.Key]
|
||||
} is not supported because it's not tied to a branch or tag ref.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const primaryKey = core.getInput(Inputs.Key, { required: true });
|
||||
core.saveState(State.CachePrimaryKey, primaryKey);
|
||||
|
||||
|
@ -33,6 +15,13 @@ async function run(): Promise<void> {
|
|||
});
|
||||
|
||||
try {
|
||||
const cache: CacheService = new CacheService(
|
||||
core.getInput(Inputs.AccessKeyId),
|
||||
core.getInput(Inputs.SecretAccessKey),
|
||||
core.getInput(Inputs.Region),
|
||||
core.getInput(Inputs.Bucket)
|
||||
);
|
||||
|
||||
const cacheKey = await cache.restoreCache(
|
||||
cachePaths,
|
||||
primaryKey,
|
||||
|
@ -56,12 +45,8 @@ async function run(): Promise<void> {
|
|||
|
||||
core.info(`Cache restored from key: ${cacheKey}`);
|
||||
} catch (error) {
|
||||
if (error.name === cache.ValidationError.name) {
|
||||
throw error;
|
||||
} else {
|
||||
utils.logWarning(error.message);
|
||||
utils.setCacheHitOutput(false);
|
||||
}
|
||||
utils.logWarning(error.message);
|
||||
utils.setCacheHitOutput(false);
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
|
|
39
src/save.ts
39
src/save.ts
|
@ -1,7 +1,8 @@
|
|||
import * as cache from "@actions/cache";
|
||||
import {} from "@actions/cache";
|
||||
import * as core from "@actions/core";
|
||||
|
||||
import { Events, Inputs, State } from "./constants";
|
||||
import { CacheService } from "./cache.service";
|
||||
import { Inputs, State } from "./constants";
|
||||
import * as utils from "./utils/actionUtils";
|
||||
|
||||
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
||||
|
@ -11,22 +12,6 @@ process.on("uncaughtException", e => utils.logWarning(e.message));
|
|||
|
||||
async function run(): Promise<void> {
|
||||
try {
|
||||
if (utils.isGhes()) {
|
||||
utils.logWarning(
|
||||
"Cache action is not supported on GHES. See https://github.com/actions/cache/issues/505 for more details"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!utils.isValidEvent()) {
|
||||
utils.logWarning(
|
||||
`Event Validation Error: The event type ${
|
||||
process.env[Events.Key]
|
||||
} is not supported because it's not tied to a branch or tag ref.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const state = utils.getCacheState();
|
||||
|
||||
// Inputs are re-evaluted before the post action, so we want the original key used for restore
|
||||
|
@ -48,18 +33,16 @@ async function run(): Promise<void> {
|
|||
});
|
||||
|
||||
try {
|
||||
await cache.saveCache(cachePaths, primaryKey, {
|
||||
uploadChunkSize: utils.getInputAsInt(Inputs.UploadChunkSize)
|
||||
});
|
||||
const cache: CacheService = new CacheService(
|
||||
core.getInput(Inputs.AccessKeyId),
|
||||
core.getInput(Inputs.SecretAccessKey),
|
||||
core.getInput(Inputs.Region),
|
||||
core.getInput(Inputs.Bucket)
|
||||
);
|
||||
await cache.saveCache(cachePaths, primaryKey);
|
||||
core.info(`Cache saved with key: ${primaryKey}`);
|
||||
} catch (error) {
|
||||
if (error.name === cache.ValidationError.name) {
|
||||
throw error;
|
||||
} else if (error.name === cache.ReserveCacheError.name) {
|
||||
core.info(error.message);
|
||||
} else {
|
||||
utils.logWarning(error.message);
|
||||
}
|
||||
utils.logWarning(error.message);
|
||||
}
|
||||
} catch (error) {
|
||||
utils.logWarning(error.message);
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import { Inputs } from "../constants";
|
||||
|
||||
// See: https://github.com/actions/toolkit/blob/master/packages/core/src/core.ts#L67
|
||||
function getInputName(name: string): string {
|
||||
return `INPUT_${name.replace(/ /g, "_").toUpperCase()}`;
|
||||
}
|
||||
|
||||
export function setInput(name: string, value: string): void {
|
||||
process.env[getInputName(name)] = value;
|
||||
}
|
||||
|
||||
interface CacheInput {
|
||||
path: string;
|
||||
key: string;
|
||||
restoreKeys?: string[];
|
||||
}
|
||||
|
||||
export function setInputs(input: CacheInput): void {
|
||||
setInput(Inputs.Path, input.path);
|
||||
setInput(Inputs.Key, input.key);
|
||||
input.restoreKeys &&
|
||||
setInput(Inputs.RestoreKeys, input.restoreKeys.join("\n"));
|
||||
}
|
||||
|
||||
export function clearInputs(): void {
|
||||
delete process.env[getInputName(Inputs.Path)];
|
||||
delete process.env[getInputName(Inputs.Key)];
|
||||
delete process.env[getInputName(Inputs.RestoreKeys)];
|
||||
delete process.env[getInputName(Inputs.UploadChunkSize)];
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue