164 lines
5.0 KiB
TypeScript
Raw Normal View History

2024-04-26 14:19:53 -03:00
import { makeNixCommandArgs } from "./nix.js";
2024-04-26 11:55:19 -03:00
import * as actionsCore from "@actions/core";
import * as actionsExec from "@actions/exec";
2024-05-22 15:40:01 -03:00
import { DetSysAction, inputs } from "detsys-ts";
import * as fs from "fs";
2024-04-21 19:42:23 -03:00
2024-04-26 11:55:19 -03:00
const EVENT_EXECUTION_FAILURE = "execution_failure";
2024-05-22 15:40:01 -03:00
class UpdateFlakeLockAction extends DetSysAction {
2024-04-21 19:42:23 -03:00
private commitMessage: string;
2024-04-26 14:19:53 -03:00
private nixOptions: string[];
private flakeInputs: string[];
2024-04-26 11:55:19 -03:00
private pathToFlakeDir: string | null;
2024-05-23 16:09:06 -03:00
private flakeDirs: string[] | null;
2024-04-21 19:42:23 -03:00
constructor() {
2024-05-22 15:40:01 -03:00
super({
2024-04-21 19:42:23 -03:00
name: "update-flake-lock",
fetchStyle: "universal",
requireNix: "fail",
2024-05-22 15:40:01 -03:00
});
2024-04-21 19:42:23 -03:00
this.commitMessage = inputs.getString("commit-msg");
2024-05-09 18:13:07 -04:00
this.flakeInputs = inputs.getArrayOfStrings("inputs", "space");
2024-05-09 15:26:43 -04:00
this.nixOptions = inputs.getArrayOfStrings("nix-options", "space");
2024-04-26 11:55:19 -03:00
this.pathToFlakeDir = inputs.getStringOrNull("path-to-flake-dir");
2024-05-23 19:19:07 -03:00
this.flakeDirs = inputs.getArrayOfStringsOrNull("flake-dirs", "space");
2024-05-23 16:09:06 -03:00
this.validateInputs();
2024-04-21 19:42:23 -03:00
}
2024-05-22 15:40:01 -03:00
async main(): Promise<void> {
2024-05-23 15:48:19 -03:00
await this.updateFlakeLock();
2024-05-22 15:40:01 -03:00
}
// No post phase
async post(): Promise<void> {}
2024-05-23 15:48:19 -03:00
async updateFlakeLock(): Promise<void> {
2024-05-23 15:16:12 -03:00
if (this.flakeDirs !== null && this.flakeDirs.length > 0) {
actionsCore.debug(
`Running flake lock update in multiple directories: ${this.flakeDirs.map((dir) => `\`${dir}\``).join(" ")}`,
2024-05-23 15:16:12 -03:00
);
for (const directory of this.flakeDirs) {
2024-05-23 15:48:19 -03:00
await this.updateFlakeInDirectory(directory);
2024-05-23 15:16:12 -03:00
}
} else {
2024-05-23 15:19:56 -03:00
// Set directory to root if not specified
const flakeDir = this.pathToFlakeDir ?? ".";
2024-05-23 15:48:19 -03:00
await this.updateFlakeInDirectory(flakeDir);
2024-05-23 15:16:12 -03:00
}
}
2024-05-23 15:48:19 -03:00
private async updateFlakeInDirectory(flakeDir: string): Promise<void> {
this.ensureDirectoryExists(flakeDir);
this.ensureDirectoryIsFlake(flakeDir);
actionsCore.debug(`Running flake lock update in directory \`${flakeDir}\``);
2024-05-23 15:16:12 -03:00
2024-04-26 11:55:19 -03:00
// Nix command of this form:
2024-05-09 15:47:03 -04:00
// nix ${maybe nix options} flake ${"update" or "lock"} ${maybe --update-input flags} --commit-lock-file --commit-lockfile-summary ${commit message}
// Example commands:
2024-05-06 17:45:12 -04:00
// nix --extra-substituters https://example.com flake lock --update-input nixpkgs --commit-lock-file --commit-lockfile-summary "updated flake.lock"
2024-05-09 15:45:38 -04:00
// nix flake update --commit-lock-file --commit-lockfile-summary "updated flake.lock"
2024-04-26 14:19:53 -03:00
const nixCommandArgs: string[] = makeNixCommandArgs(
this.nixOptions,
this.flakeInputs,
this.commitMessage,
);
2024-04-26 11:55:19 -03:00
2024-05-06 17:34:23 -04:00
actionsCore.debug(
JSON.stringify({
2024-05-23 15:19:56 -03:00
directory: flakeDir,
2024-05-06 17:34:23 -04:00
options: this.nixOptions,
inputs: this.flakeInputs,
message: this.commitMessage,
args: nixCommandArgs,
}),
);
2024-05-22 15:40:01 -03:00
const execOptions: actionsExec.ExecOptions = {
2024-05-23 15:19:56 -03:00
cwd: flakeDir,
2024-05-22 15:40:01 -03:00
};
2024-04-26 11:55:19 -03:00
2024-05-06 16:13:34 -04:00
const exitCode = await actionsExec.exec("nix", nixCommandArgs, execOptions);
2024-04-21 19:50:32 -03:00
2024-04-26 11:55:19 -03:00
if (exitCode !== 0) {
2024-05-22 15:40:01 -03:00
this.recordEvent(EVENT_EXECUTION_FAILURE, {
2024-04-26 11:55:19 -03:00
exitCode,
});
2024-05-23 15:16:12 -03:00
actionsCore.setFailed(
`non-zero exit code of ${exitCode} detected while updating directory \`${flakeDir}\``,
2024-05-23 15:16:12 -03:00
);
2024-04-26 11:55:19 -03:00
} else {
2024-05-23 15:16:12 -03:00
actionsCore.info(
`flake.lock file in \`${flakeDir}\` was successfully updated`,
2024-05-23 15:16:12 -03:00
);
2024-04-26 11:55:19 -03:00
}
2024-04-21 19:50:32 -03:00
}
private validateInputs(): void {
2024-05-23 15:55:25 -03:00
// Ensure that either `path-to-flake-dir` or `flake-dirs` is set to a meaningful value but not both
if (
this.flakeDirs !== null &&
this.flakeDirs.length > 0 &&
2024-05-23 15:42:03 -03:00
this.pathToFlakeDir !== null &&
this.pathToFlakeDir !== ""
) {
throw new Error(
2024-05-23 15:55:25 -03:00
"Both `path-to-flake-dir` and `flake-dirs` are set, whereas only one can be",
);
}
2024-05-23 15:55:25 -03:00
// Ensure that `flake-dirs` isn't an empty array if set
if (this.flakeDirs !== null && this.flakeDirs.length === 0) {
throw new Error(
"The `flake-dirs` input is set to an empty array; it must contain at least one directory",
);
}
2024-05-23 15:55:25 -03:00
// Ensure that both `flake-dirs` and `inputs` aren't set at the same time
if (
this.flakeDirs !== null &&
this.flakeDirs.length > 0 &&
this.flakeInputs.length > 0
) {
throw new Error(
`You've set both \`flake-dirs\` and \`inputs\` but you can only set one`,
);
}
}
private ensureDirectoryExists(flakeDir: string): void {
actionsCore.debug(`Checking that flake directory \`${flakeDir}\` exists`);
// Ensure the directory exists
fs.access(flakeDir, fs.constants.F_OK, (err) => {
if (err !== null) {
throw new Error(`Directory \`${flakeDir}\` doesn't exist`);
} else {
actionsCore.debug(`Flake directory \`${flakeDir}\` exists`);
}
});
}
private ensureDirectoryIsFlake(flakeDir: string): void {
const flakeDotNix = `${flakeDir}/flake.nix`;
if (!fs.existsSync(flakeDotNix)) {
throw new Error(
`Directory \`${flakeDir}\` is not a valid flake as it doesn't contain a \`flake.nix\``,
);
} else {
actionsCore.debug(`Directory \`${flakeDir}\` is a valid flake`);
}
}
2024-04-21 19:42:23 -03:00
}
function main(): void {
2024-05-22 15:40:01 -03:00
new UpdateFlakeLockAction().execute();
2024-04-21 19:42:23 -03:00
}
2024-04-21 19:17:03 -03:00
main();