mirror of
https://github.com/awalsh128/cache-apt-pkgs-action.git
synced 2026-11-13 21:36:56 +00:00
Manifest.from built every entry with an empty file list and buildFileList was never called, so tar.create was handed no paths. node-tar throws "no paths specified to add to archive" for that, so every cache miss failed before saving. The runner now builds each manifest entry from buildFileList and passes the manifest to archiveAndSave. Packages with no files (e.g. metapackages) are skipped on archive and on restore since tar can't create an empty archive. Manifest.from is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
126 lines
3.6 KiB
TypeScript
126 lines
3.6 KiB
TypeScript
import {
|
|
createPackageManager,
|
|
type CommandRunner,
|
|
type PackageName,
|
|
} from "ts-apt";
|
|
import { Cache, CacheKey } from "./cache.js";
|
|
import { Manifest, ManifestEntry } from "./manifest.js";
|
|
import { ActionPackageNames, buildFileList } from "./packages.js";
|
|
import winston from "winston";
|
|
|
|
type EmptyPackageBehavior = "error" | "warn" | "ignore";
|
|
|
|
const FORCE_UPDATE_INCREMENT = "0";
|
|
|
|
/** Inputs accepted by the GitHub Action runtime. */
|
|
export interface ActionInputs {
|
|
readonly packages: string;
|
|
readonly version: string;
|
|
readonly executeInstallScripts: boolean;
|
|
readonly emptyPackagesBehavior: EmptyPackageBehavior;
|
|
readonly debug: boolean;
|
|
}
|
|
|
|
/** Outputs emitted by the GitHub Action runtime. */
|
|
export interface ActionOutputs {
|
|
readonly cacheHit: boolean;
|
|
readonly packageVersionList: string;
|
|
readonly allPackageVersionList: string;
|
|
}
|
|
|
|
/** Orchestrates package normalization, cache restore/save, install, and outputs. */
|
|
export class ActionRunner {
|
|
private readonly cache: Cache;
|
|
private readonly commandRunner: CommandRunner;
|
|
private readonly logger: winston.Logger;
|
|
|
|
constructor(
|
|
cache: Cache,
|
|
commandRunner: CommandRunner,
|
|
logger: winston.Logger,
|
|
) {
|
|
this.cache = cache;
|
|
this.commandRunner = commandRunner;
|
|
this.logger = logger;
|
|
}
|
|
|
|
/**
|
|
* Converts manifest entries into the action output CSV format.
|
|
*
|
|
* @param manifest Parsed manifest.
|
|
* @returns Comma-delimited name=version list.
|
|
*/
|
|
private toCsv(manifest: Manifest): string {
|
|
return manifest.entries
|
|
.map((entry) => entry.packageName.serialize())
|
|
.join(",");
|
|
}
|
|
|
|
/**
|
|
* Executes the end-to-end action flow and returns action outputs.
|
|
*
|
|
* @param inputs Validated action inputs.
|
|
* @returns Action outputs consumed by the workflow runtime.
|
|
*/
|
|
async runAction(inputs: ActionInputs): Promise<ActionOutputs> {
|
|
const packageNames = ActionPackageNames.fromInput(inputs.packages);
|
|
const cacheKey = new CacheKey(
|
|
inputs.version,
|
|
FORCE_UPDATE_INCREMENT,
|
|
process.arch,
|
|
packageNames,
|
|
);
|
|
|
|
let manifest = await this.cache.loadAndRestore(
|
|
cacheKey,
|
|
inputs.executeInstallScripts,
|
|
);
|
|
const cacheHit = manifest !== undefined;
|
|
|
|
if (!cacheHit) {
|
|
const installManager = await createPackageManager(
|
|
true,
|
|
this.logger,
|
|
this.logger,
|
|
);
|
|
const packageInfos = await installManager.install(packageNames.toArray());
|
|
// Collect each package's installed files so the archives have content.
|
|
const entries = await Promise.all(
|
|
packageInfos.map(
|
|
async (info) =>
|
|
new ManifestEntry(
|
|
info.name,
|
|
await buildFileList(info.name, installManager),
|
|
),
|
|
),
|
|
);
|
|
manifest = new Manifest(new Date(), entries, cacheKey);
|
|
await this.cache.archiveAndSave(manifest);
|
|
}
|
|
|
|
return {
|
|
cacheHit,
|
|
packageVersionList: this.toCsv(manifest!),
|
|
allPackageVersionList: this.toCsv(manifest!),
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Public entrypoint used by src/index.ts and tests.
|
|
*
|
|
* @param inputs Validated action inputs.
|
|
* @param commandRunner Command runner used by package operations.
|
|
* @param logger Logger instance used for command and restore diagnostics.
|
|
* @returns Action outputs consumed by the workflow runtime.
|
|
*/
|
|
export async function runAction(
|
|
inputs: ActionInputs,
|
|
commandRunner: CommandRunner,
|
|
cache: Cache,
|
|
logger: winston.Logger,
|
|
): Promise<ActionOutputs> {
|
|
const actionRunner = new ActionRunner(cache, commandRunner, logger);
|
|
return await actionRunner.runAction(inputs);
|
|
}
|