Use Result-based version of detsys-ts #81

Closed
lucperkins wants to merge 4 commits from detsys-ts-results into main
4 changed files with 730 additions and 181 deletions

775
dist/index.js generated vendored

File diff suppressed because it is too large Load diff

View file

@ -28,7 +28,7 @@
"@actions/core": "^1.10.1",
"@actions/exec": "^1.1.1",
"@actions/github": "^5.1.1",
"detsys-ts": "github:DeterminateSystems/detsys-ts",
"detsys-ts": "github:DeterminateSystems/detsys-ts#ts-results",
"string-argv": "^0.3.2"
},
"devDependencies": {

View file

@ -15,8 +15,8 @@ dependencies:
specifier: ^5.1.1
version: 5.1.1
detsys-ts:
specifier: github:DeterminateSystems/detsys-ts
version: github.com/DeterminateSystems/detsys-ts/cd38b227c4d6faca10aed591b1f8863ef7b93dce
specifier: github:DeterminateSystems/detsys-ts#ts-results
version: github.com/DeterminateSystems/detsys-ts/abd5b78c8e24857812017ab2da0f962095811f10
string-argv:
specifier: ^0.3.2
version: 0.3.2
@ -5019,6 +5019,13 @@ packages:
}
dev: true
/ts-results@3.3.0:
resolution:
{
integrity: sha512-FWqxGX2NHp5oCyaMd96o2y2uMQmSu8Dey6kvyuFdRJ2AzfmWo3kWa4UsPlCGlfQ/qu03m09ZZtppMoY8EMHuiA==,
}
dev: false
/tsconfig-paths@3.15.0:
resolution:
{
@ -5440,10 +5447,10 @@ packages:
engines: { node: ">=10" }
dev: true
github.com/DeterminateSystems/detsys-ts/cd38b227c4d6faca10aed591b1f8863ef7b93dce:
github.com/DeterminateSystems/detsys-ts/abd5b78c8e24857812017ab2da0f962095811f10:
resolution:
{
tarball: https://codeload.github.com/DeterminateSystems/detsys-ts/tar.gz/cd38b227c4d6faca10aed591b1f8863ef7b93dce,
tarball: https://codeload.github.com/DeterminateSystems/detsys-ts/tar.gz/abd5b78c8e24857812017ab2da0f962095811f10,
}
name: detsys-ts
version: 1.0.0
@ -5452,6 +5459,7 @@ packages:
"@actions/core": 1.10.1
"@actions/exec": 1.1.1
got: 14.2.1
ts-results: 3.3.0
transitivePeerDependencies:
- encoding
dev: false

View file

@ -7,7 +7,7 @@ import fs from "node:fs";
import { userInfo } from "node:os";
import stringArgv from "string-argv";
import * as path from "path";
import { IdsToolbox, inputs, platform } from "detsys-ts";
import { IdsToolbox, inputs, platform, result } from "detsys-ts";
import { randomUUID } from "node:crypto";
// Nix installation events
@ -73,9 +73,22 @@ class NixInstallerAction {
fetchStyle: "nix-style",
legacySourcePrefix: "nix-installer",
requireNix: "ignore",
hookMain: async () => {
await this.detectAndForceDockerShim();
await this.install();
return result.SUCCESS;
},
hookPost: async () => {
await this.cleanupDockerShim();
await this.reportOverall();
return result.SUCCESS;
},
});
this.platform = platform.getNixPlatform(platform.getArchOs());
const archOs = result.valueOrFail(platform.getArchOs());
const nixPlatform = result.valueOrFail(platform.getNixPlatform(archOs));
this.platform = nixPlatform;
this.nixPackageUrl = inputs.getStringOrNull("nix-package-url");
this.backtrace = inputs.getStringOrNull("backtrace");
this.extraArgs = inputs.getStringOrNull("extra-args");
@ -307,7 +320,9 @@ class NixInstallerAction {
return foundDockerSockMount;
}
private async executionEnvironment(): Promise<ExecuteEnvironment> {
private async executionEnvironment(): Promise<
result.Result<ExecuteEnvironment>
> {
const executionEnv: ExecuteEnvironment = {};
const runnerOs = process.env["RUNNER_OS"];
@ -366,14 +381,14 @@ class NixInstallerAction {
// TODO: Error if the user uses these on not-MacOS
if (this.macEncrypt !== null) {
if (runnerOs !== "macOS") {
throw new Error("`mac-encrypt` while `$RUNNER_OS` was not `macOS`");
return result.Err("`mac-encrypt` while `$RUNNER_OS` was not `macOS`");
}
executionEnv.NIX_INSTALLER_ENCRYPT = this.macEncrypt;
}
if (this.macCaseSensitive !== null) {
if (runnerOs !== "macOS") {
throw new Error(
return result.Err(
"`mac-case-sensitive` while `$RUNNER_OS` was not `macOS`",
);
}
@ -382,7 +397,7 @@ class NixInstallerAction {
if (this.macVolumeLabel !== null) {
if (runnerOs !== "macOS") {
throw new Error(
return result.Err(
"`mac-volume-label` while `$RUNNER_OS` was not `macOS`",
);
}
@ -391,7 +406,7 @@ class NixInstallerAction {
if (this.macRootDisk !== null) {
if (runnerOs !== "macOS") {
throw new Error("`mac-root-disk` while `$RUNNER_OS` was not `macOS`");
return result.Err("`mac-root-disk` while `$RUNNER_OS` was not `macOS`");
}
executionEnv.NIX_INSTALLER_ROOT_DISK = this.macRootDisk;
}
@ -407,7 +422,7 @@ class NixInstallerAction {
// TODO: Error if the user uses these on MacOS
if (this.init !== null) {
if (runnerOs === "macOS") {
throw new Error(
return result.Err(
"`init` is not a valid option when `$RUNNER_OS` is `macOS`",
);
}
@ -468,11 +483,13 @@ class NixInstallerAction {
executionEnv.NIX_INSTALLER_INIT = "none";
}
return executionEnv;
return result.Ok(executionEnv);
}
private async executeInstall(binaryPath: string): Promise<number> {
const executionEnv = await this.executionEnvironment();
private async executeInstall(
binaryPath: string,
): Promise<result.Result<number>> {
const executionEnv = result.valueOrFail(await this.executionEnvironment());
actionsCore.debug(
`Execution environment: ${JSON.stringify(executionEnv, null, 4)}`,
);
@ -482,8 +499,9 @@ class NixInstallerAction {
this.idslib.addFact(FACT_NIX_INSTALLER_PLANNER, this.planner);
args.push(this.planner);
} else {
this.idslib.addFact(FACT_NIX_INSTALLER_PLANNER, getDefaultPlanner());
args.push(getDefaultPlanner());
const defaultPlanner = result.valueOrFail(getDefaultPlanner());
this.idslib.addFact(FACT_NIX_INSTALLER_PLANNER, defaultPlanner);
args.push(defaultPlanner);
}
if (this.extraArgs) {
@ -503,12 +521,12 @@ class NixInstallerAction {
this.idslib.recordEvent(EVENT_INSTALL_NIX_FAILURE, {
exitCode,
});
throw new Error(`Non-zero exit code of \`${exitCode}\` detected`);
return result.Err(`Non-zero exit code of \`${exitCode}\` detected`);
}
this.idslib.recordEvent(EVENT_INSTALL_NIX_SUCCESS);
return exitCode;
return result.Ok(exitCode);
}
async install(): Promise<void> {
@ -553,7 +571,7 @@ class NixInstallerAction {
await this.setGithubPath();
}
async spawnDockerShim(): Promise<void> {
async spawnDockerShim(): Promise<result.Result<void>> {
actionsCore.startGroup(
"Configuring the Docker shim as the Nix Daemon's process supervisor",
);
@ -571,7 +589,7 @@ class NixInstallerAction {
} else if (runnerArch === "ARM64") {
arch = "ARM64";
} else {
throw Error("Architecture not supported in Docker shim mode.");
return result.Err("Architecture not supported in Docker shim mode.");
}
actionsCore.debug("Loading image: determinate-nix-shim:latest...");
{
@ -598,7 +616,7 @@ class NixInstallerAction {
);
if (exitCode !== 0) {
throw new Error(
return result.Err(
`Failed to build the shim image, exit code: \`${exitCode}\``,
);
}
@ -659,7 +677,7 @@ class NixInstallerAction {
);
if (exitCode !== 0) {
throw new Error(
return result.Err(
`Failed to start the Nix daemon through Docker, exit code: \`${exitCode}\``,
);
}
@ -667,8 +685,9 @@ class NixInstallerAction {
actionsCore.endGroup();
return;
return result.Ok(undefined);
}
async cleanupDockerShim(): Promise<void> {
const containerId = actionsCore.getState("docker_shim_container_id");
@ -751,7 +770,7 @@ class NixInstallerAction {
return netrcPath;
}
async executeUninstall(): Promise<number> {
async executeUninstall(): Promise<result.Result<number>> {
this.idslib.recordEvent(EVENT_UNINSTALL_NIX);
const exitCode = await actionsExec.exec(
`/nix/nix-installer`,
@ -765,10 +784,10 @@ class NixInstallerAction {
);
if (exitCode !== 0) {
throw new Error(`Non-zero exit code of \`${exitCode}\` detected`);
return result.Err(`Non-zero exit code of \`${exitCode}\` detected`);
}
return exitCode;
return result.Ok(exitCode);
}
async detectExisting(): Promise<boolean> {
@ -783,7 +802,7 @@ class NixInstallerAction {
}
}
private async setupKvm(): Promise<boolean> {
private async setupKvm(): Promise<result.Result<boolean>> {
this.idslib.recordEvent(EVENT_SETUP_KVM);
const currentUser = userInfo();
const isRoot = currentUser.uid === 0;
@ -817,7 +836,7 @@ class NixInstallerAction {
);
if (writeFileExitCode !== 0) {
throw new Error(
return result.Err(
`Non-zero exit code of \`${writeFileExitCode}\` detected while writing '${kvmRules}'`,
);
}
@ -826,7 +845,7 @@ class NixInstallerAction {
action: string,
command: string,
args: string[],
): Promise<void> => {
): Promise<result.Result<void>> => {
if (!isRoot) {
args = [command, ...args];
command = "sudo";
@ -850,23 +869,29 @@ class NixInstallerAction {
});
if (reloadExitCode !== 0) {
throw new Error(
return result.Err(
`Non-zero exit code of \`${reloadExitCode}\` detected while ${action}.`,
);
}
return result.Ok(undefined);
};
await debugRootRunThrow("reloading udev rules", "udevadm", [
"control",
"--reload-rules",
]);
await result.failOnError(
debugRootRunThrow("reloading udev rules", "udevadm", [
"control",
"--reload-rules",
]),
);
await debugRootRunThrow("triggering udev against kvm", "udevadm", [
"trigger",
"--name-match=kvm",
]);
await result.failOnError(
debugRootRunThrow("triggering udev against kvm", "udevadm", [
"trigger",
"--name-match=kvm",
]),
);
return true;
return result.Ok(true);
} catch {
if (isRoot) {
await actionsExec.exec("rm", ["-f", kvmRules]);
@ -874,7 +899,7 @@ class NixInstallerAction {
await actionsExec.exec("sudo", ["rm", "-f", kvmRules]);
}
return false;
return result.Ok(false);
}
}
@ -974,31 +999,20 @@ type ExecuteEnvironment = {
NIX_INSTALLER_LOGGER?: string;
};
function getDefaultPlanner(): string {
function getDefaultPlanner(): result.Result<string> {
const envOs = process.env["RUNNER_OS"];
if (envOs === "macOS") {
return "macos";
return result.Ok("macos");
} else if (envOs === "Linux") {
return "linux";
return result.Ok("linux");
} else {
throw new Error(`Unsupported \`RUNNER_OS\` (currently \`${envOs}\`)`);
return result.Err(`Unsupported \`RUNNER_OS\` (currently \`${envOs}\`)`);
}
}
function main(): void {
const installer = new NixInstallerAction();
installer.idslib.onMain(async () => {
await installer.detectAndForceDockerShim();
await installer.install();
});
installer.idslib.onPost(async () => {
await installer.cleanupDockerShim();
await installer.reportOverall();
});
installer.idslib.execute();
}