Merge pull request #93 from DeterminateSystems/update-detsys-ts

Update detsys-ts
This commit is contained in:
Luc Perkins 2024-05-29 16:32:28 -03:00 committed by GitHub
commit c6857b9a9d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 1336 additions and 799 deletions

View file

@ -59,6 +59,7 @@ jobs:
logger: pretty logger: pretty
log-directives: nix_installer=trace log-directives: nix_installer=trace
backtrace: full backtrace: full
_internal-strict-mode: true
- name: echo $PATH - name: echo $PATH
run: echo $PATH run: echo $PATH
@ -90,6 +91,7 @@ jobs:
logger: pretty logger: pretty
log-directives: nix_installer=trace log-directives: nix_installer=trace
backtrace: full backtrace: full
_internal-strict-mode: true
- name: Test `nix` with `$GITHUB_PATH` - name: Test `nix` with `$GITHUB_PATH`
if: success() || failure() if: success() || failure()
run: | run: |
@ -107,6 +109,7 @@ jobs:
reinstall: true reinstall: true
extra-conf: | extra-conf: |
use-sqlite-wal = true use-sqlite-wal = true
_internal-strict-mode: true
- name: Test `nix` with `$GITHUB_PATH` - name: Test `nix` with `$GITHUB_PATH`
if: success() || failure() if: success() || failure()
run: | run: |
@ -148,6 +151,7 @@ jobs:
logger: pretty logger: pretty
log-directives: nix_installer=trace log-directives: nix_installer=trace
backtrace: full backtrace: full
_internal-strict-mode: true
- name: echo $PATH - name: echo $PATH
run: echo $PATH run: echo $PATH
- name: Test `nix` with `$GITHUB_PATH` - name: Test `nix` with `$GITHUB_PATH`
@ -176,6 +180,7 @@ jobs:
logger: pretty logger: pretty
log-directives: nix_installer=trace log-directives: nix_installer=trace
backtrace: full backtrace: full
_internal-strict-mode: true
- name: Test `nix` with `$GITHUB_PATH` - name: Test `nix` with `$GITHUB_PATH`
if: success() || failure() if: success() || failure()
run: | run: |
@ -193,6 +198,7 @@ jobs:
reinstall: true reinstall: true
extra-conf: | extra-conf: |
use-sqlite-wal = true use-sqlite-wal = true
_internal-strict-mode: true
- name: Test `nix` with `$GITHUB_PATH` - name: Test `nix` with `$GITHUB_PATH`
if: success() || failure() if: success() || failure()
run: | run: |
@ -234,5 +240,6 @@ jobs:
uses: ./ uses: ./
with: with:
source-${{ matrix.inputs.key }}: ${{ matrix.inputs.value }} source-${{ matrix.inputs.key }}: ${{ matrix.inputs.value }}
_internal-strict-mode: true
- name: Ensure that the expected Nix version ${{ matrix.inputs.nix-version }} is installed via alternative source-${{ matrix.inputs.key }} - name: Ensure that the expected Nix version ${{ matrix.inputs.nix-version }} is installed via alternative source-${{ matrix.inputs.key }}
run: .github/verify-version.sh ${{ matrix.inputs.nix-version }} run: .github/verify-version.sh ${{ matrix.inputs.nix-version }}

View file

@ -19,6 +19,7 @@ inputs:
default: false default: false
force-docker-shim: force-docker-shim:
description: Force the use of Docker as a process supervisor. This setting is automatically enabled when necessary. description: Force the use of Docker as a process supervisor. This setting is automatically enabled when necessary.
required: false
default: false default: false
github-token: github-token:
description: A GitHub token for making authenticated requests (which have a higher rate-limit quota than unauthenticated requests) description: A GitHub token for making authenticated requests (which have a higher rate-limit quota than unauthenticated requests)
@ -79,6 +80,9 @@ inputs:
nix-build-user-prefix: nix-build-user-prefix:
description: The Nix build user prefix (user numbers will be postfixed) description: The Nix build user prefix (user numbers will be postfixed)
required: false required: false
source-binary:
description: Run a version of the nix-installer binary from somewhere already on disk. Conflicts with all other `source-*` options. Intended only for testing this Action.
required: false
source-branch: source-branch:
description: The branch of `nix-installer` to use (conflicts with `source-tag`, `source-revision`, `source-pr`) description: The branch of `nix-installer` to use (conflicts with `source-tag`, `source-revision`, `source-pr`)
required: false required: false
@ -129,6 +133,10 @@ inputs:
nix-installer-url: nix-installer-url:
description: (deprecated) A URL pointing to a `nix-installer.sh` script description: (deprecated) A URL pointing to a `nix-installer.sh` script
required: false required: false
_internal-strict-mode:
description: Whether to fail when any errors are thrown. Used only to test the Action; do not set this in your own workflows.
required: false
default: false
runs: runs:
using: "node20" using: "node20"

1469
dist/index.js generated vendored

File diff suppressed because it is too large Load diff

View file

@ -33,9 +33,9 @@
}, },
"devDependencies": { "devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/node": "^20.12.11", "@types/node": "^20.12.13",
"@types/uuid": "^9.0.8", "@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^7.8.0", "@typescript-eslint/eslint-plugin": "^7.11.0",
"@vercel/ncc": "^0.38.1", "@vercel/ncc": "^0.38.1",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-import-resolver-typescript": "^3.6.1", "eslint-import-resolver-typescript": "^3.6.1",

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@ import fs from "node:fs";
import { userInfo } from "node:os"; import { userInfo } from "node:os";
import stringArgv from "string-argv"; import stringArgv from "string-argv";
import * as path from "path"; import * as path from "path";
import { IdsToolbox, inputs, platform } from "detsys-ts"; import { DetSysAction, inputs, platform } from "detsys-ts";
import { randomUUID } from "node:crypto"; import { randomUUID } from "node:crypto";
// Nix installation events // Nix installation events
@ -34,8 +34,14 @@ const FACT_IN_ACT = "in_act";
const FACT_IN_NAMESPACE_SO = "in_namespace_so"; const FACT_IN_NAMESPACE_SO = "in_namespace_so";
const FACT_NIX_INSTALLER_PLANNER = "nix_installer_planner"; const FACT_NIX_INSTALLER_PLANNER = "nix_installer_planner";
class NixInstallerAction { type WorkflowConclusion =
idslib: IdsToolbox; | "success"
| "failure"
| "cancelled"
| "unavailable"
| "no-jobs";
class NixInstallerAction extends DetSysAction {
platform: string; platform: string;
nixPackageUrl: string | null; nixPackageUrl: string | null;
backtrace: string | null; backtrace: string | null;
@ -45,7 +51,7 @@ class NixInstallerAction {
kvm: boolean; kvm: boolean;
githubServerUrl: string | null; githubServerUrl: string | null;
githubToken: string | null; githubToken: string | null;
forceDockerShim: boolean | null; forceDockerShim: boolean;
init: string | null; init: string | null;
localRoot: string | null; localRoot: string | null;
logDirectives: string | null; logDirectives: string | null;
@ -65,10 +71,11 @@ class NixInstallerAction {
planner: string | null; planner: string | null;
reinstall: boolean; reinstall: boolean;
startDaemon: boolean; startDaemon: boolean;
trustRunnerUser: boolean | null; trustRunnerUser: boolean;
runnerOs: string | undefined;
constructor() { constructor() {
this.idslib = new IdsToolbox({ super({
name: "nix-installer", name: "nix-installer",
fetchStyle: "nix-style", fetchStyle: "nix-style",
legacySourcePrefix: "nix-installer", legacySourcePrefix: "nix-installer",
@ -105,15 +112,43 @@ class NixInstallerAction {
this.reinstall = inputs.getBool("reinstall"); this.reinstall = inputs.getBool("reinstall");
this.startDaemon = inputs.getBool("start-daemon"); this.startDaemon = inputs.getBool("start-daemon");
this.trustRunnerUser = inputs.getBool("trust-runner-user"); this.trustRunnerUser = inputs.getBool("trust-runner-user");
this.runnerOs = process.env["RUNNER_OS"];
} }
async detectAndForceDockerShim(): Promise<void> { async main(): Promise<void> {
const runnerOs = process.env["RUNNER_OS"]; await this.detectAndForceDockerShim();
await this.install();
}
// Detect if we're in a GHA runner which is Linux, doesn't have Systemd, and does have Docker. async post(): Promise<void> {
// This is a common case in self-hosted runners, providers like [Namespace](https://namespace.so/), await this.cleanupDockerShim();
// and especially GitHub Enterprise Server. await this.reportOverall();
if (runnerOs !== "Linux") { }
private get isMacOS(): boolean {
return this.runnerOs === "macOS";
}
private get isLinux(): boolean {
return this.runnerOs === "Linux";
}
private get isRunningInAct(): boolean {
return process.env["ACT"] !== undefined && !(process.env["NOT_ACT"] === "");
}
private get isRunningInNamespaceRunner(): boolean {
return (
process.env["NSC_VM_ID"] !== undefined &&
!(process.env["NOT_NAMESPACE"] === "true")
);
}
// Detect if we're in a GHA runner which is Linux, doesn't have Systemd, and does have Docker.
// This is a common case in self-hosted runners, providers like [Namespace](https://namespace.so/),
// and especially GitHub Enterprise Server.
async detectAndForceDockerShim(): Promise<void> {
if (!this.isLinux) {
if (this.forceDockerShim) { if (this.forceDockerShim) {
actionsCore.warning( actionsCore.warning(
"Ignoring force-docker-shim which is set to true, as it is only supported on Linux.", "Ignoring force-docker-shim which is set to true, as it is only supported on Linux.",
@ -123,7 +158,7 @@ class NixInstallerAction {
return; return;
} }
if (process.env["ACT"] && !process.env["NOT_ACT"]) { if (this.isRunningInAct) {
actionsCore.debug( actionsCore.debug(
"Not bothering to detect if the docker shim should be used, as it is typically incompatible with act.", "Not bothering to detect if the docker shim should be used, as it is typically incompatible with act.",
); );
@ -134,7 +169,7 @@ class NixInstallerAction {
throwIfNoEntry: false, throwIfNoEntry: false,
}); });
if (systemdCheck?.isDirectory()) { if (systemdCheck?.isDirectory()) {
this.idslib.addFact(FACT_HAS_SYSTEMD, true); this.addFact(FACT_HAS_SYSTEMD, true);
if (this.forceDockerShim) { if (this.forceDockerShim) {
actionsCore.warning( actionsCore.warning(
"Systemd is detected, but ignoring it since force-docker-shim is enabled.", "Systemd is detected, but ignoring it since force-docker-shim is enabled.",
@ -143,13 +178,13 @@ class NixInstallerAction {
return; return;
} }
} }
this.idslib.addFact(FACT_HAS_SYSTEMD, false); this.addFact(FACT_HAS_SYSTEMD, false);
actionsCore.debug( actionsCore.debug(
"Linux detected without systemd, testing for Docker with `docker info` as an alternative daemon supervisor.", "Linux detected without systemd, testing for Docker with `docker info` as an alternative daemon supervisor.",
); );
this.idslib.addFact(FACT_HAS_DOCKER, false); // Set to false here, and only in the success case do we set it to true this.addFact(FACT_HAS_DOCKER, false); // Set to false here, and only in the success case do we set it to true
let exitCode; let exitCode;
try { try {
exitCode = await actionsExec.exec("docker", ["info"], { exitCode = await actionsExec.exec("docker", ["info"], {
@ -183,7 +218,7 @@ class NixInstallerAction {
return; return;
} }
} }
this.idslib.addFact(FACT_HAS_DOCKER, true); this.addFact(FACT_HAS_DOCKER, true);
if ( if (
!this.forceDockerShim && !this.forceDockerShim &&
@ -316,11 +351,10 @@ class NixInstallerAction {
private async executionEnvironment(): Promise<ExecuteEnvironment> { private async executionEnvironment(): Promise<ExecuteEnvironment> {
const executionEnv: ExecuteEnvironment = {}; const executionEnv: ExecuteEnvironment = {};
const runnerOs = process.env["RUNNER_OS"];
executionEnv.NIX_INSTALLER_NO_CONFIRM = "true"; executionEnv.NIX_INSTALLER_NO_CONFIRM = "true";
executionEnv.NIX_INSTALLER_DIAGNOSTIC_ATTRIBUTION = JSON.stringify( executionEnv.NIX_INSTALLER_DIAGNOSTIC_ATTRIBUTION = JSON.stringify(
this.idslib.getCorrelationHashes(), this.getCorrelationHashes(),
); );
if (this.backtrace !== null) { if (this.backtrace !== null) {
@ -368,18 +402,18 @@ class NixInstallerAction {
} }
executionEnv.NIX_INSTALLER_DIAGNOSTIC_ENDPOINT = executionEnv.NIX_INSTALLER_DIAGNOSTIC_ENDPOINT =
this.idslib.getDiagnosticsUrl()?.toString() ?? ""; this.getDiagnosticsUrl()?.toString() ?? "";
// TODO: Error if the user uses these on not-MacOS // TODO: Error if the user uses these on not-MacOS
if (this.macEncrypt !== null) { if (this.macEncrypt !== null) {
if (runnerOs !== "macOS") { if (!this.isMacOS) {
throw new Error("`mac-encrypt` while `$RUNNER_OS` was not `macOS`"); throw new Error("`mac-encrypt` while `$RUNNER_OS` was not `macOS`");
} }
executionEnv.NIX_INSTALLER_ENCRYPT = this.macEncrypt; executionEnv.NIX_INSTALLER_ENCRYPT = this.macEncrypt;
} }
if (this.macCaseSensitive !== null) { if (this.macCaseSensitive !== null) {
if (runnerOs !== "macOS") { if (!this.isMacOS) {
throw new Error( throw new Error(
"`mac-case-sensitive` while `$RUNNER_OS` was not `macOS`", "`mac-case-sensitive` while `$RUNNER_OS` was not `macOS`",
); );
@ -388,7 +422,7 @@ class NixInstallerAction {
} }
if (this.macVolumeLabel !== null) { if (this.macVolumeLabel !== null) {
if (runnerOs !== "macOS") { if (!this.isMacOS) {
throw new Error( throw new Error(
"`mac-volume-label` while `$RUNNER_OS` was not `macOS`", "`mac-volume-label` while `$RUNNER_OS` was not `macOS`",
); );
@ -397,7 +431,7 @@ class NixInstallerAction {
} }
if (this.macRootDisk !== null) { if (this.macRootDisk !== null) {
if (runnerOs !== "macOS") { if (!this.isMacOS) {
throw new Error("`mac-root-disk` while `$RUNNER_OS` was not `macOS`"); throw new Error("`mac-root-disk` while `$RUNNER_OS` was not `macOS`");
} }
executionEnv.NIX_INSTALLER_ROOT_DISK = this.macRootDisk; executionEnv.NIX_INSTALLER_ROOT_DISK = this.macRootDisk;
@ -413,7 +447,7 @@ class NixInstallerAction {
// TODO: Error if the user uses these on MacOS // TODO: Error if the user uses these on MacOS
if (this.init !== null) { if (this.init !== null) {
if (runnerOs === "macOS") { if (this.isMacOS) {
throw new Error( throw new Error(
"`init` is not a valid option when `$RUNNER_OS` is `macOS`", "`init` is not a valid option when `$RUNNER_OS` is `macOS`",
); );
@ -459,16 +493,16 @@ class NixInstallerAction {
} }
executionEnv.NIX_INSTALLER_EXTRA_CONF = extraConf; executionEnv.NIX_INSTALLER_EXTRA_CONF = extraConf;
if (process.env["ACT"] && !process.env["NOT_ACT"]) { if (this.isRunningInAct) {
this.idslib.addFact(FACT_IN_ACT, true); this.addFact(FACT_IN_ACT, true);
actionsCore.info( actionsCore.info(
"Detected `$ACT` environment, assuming this is a https://github.com/nektos/act created container, set `NOT_ACT=true` to override this. This will change the setting of the `init` to be compatible with `act`", "Detected `$ACT` environment, assuming this is a https://github.com/nektos/act created container, set `NOT_ACT=true` to override this. This will change the setting of the `init` to be compatible with `act`",
); );
executionEnv.NIX_INSTALLER_INIT = "none"; executionEnv.NIX_INSTALLER_INIT = "none";
} }
if (process.env["NSC_VM_ID"] && !process.env["NOT_NAMESPACE"]) { if (this.isRunningInNamespaceRunner) {
this.idslib.addFact(FACT_IN_NAMESPACE_SO, true); this.addFact(FACT_IN_NAMESPACE_SO, true);
actionsCore.info( actionsCore.info(
"Detected Namespace runner, assuming this is a https://namespace.so created container, set `NOT_NAMESPACE=true` to override this. This will change the setting of the `init` to be compatible with Namespace", "Detected Namespace runner, assuming this is a https://namespace.so created container, set `NOT_NAMESPACE=true` to override this. This will change the setting of the `init` to be compatible with Namespace",
); );
@ -486,11 +520,11 @@ class NixInstallerAction {
const args = ["install"]; const args = ["install"];
if (this.planner) { if (this.planner) {
this.idslib.addFact(FACT_NIX_INSTALLER_PLANNER, this.planner); this.addFact(FACT_NIX_INSTALLER_PLANNER, this.planner);
args.push(this.planner); args.push(this.planner);
} else { } else {
this.idslib.addFact(FACT_NIX_INSTALLER_PLANNER, getDefaultPlanner()); this.addFact(FACT_NIX_INSTALLER_PLANNER, this.defaultPlanner);
args.push(getDefaultPlanner()); args.push(this.defaultPlanner);
} }
if (this.extraArgs) { if (this.extraArgs) {
@ -498,7 +532,7 @@ class NixInstallerAction {
args.concat(extraArgs); args.concat(extraArgs);
} }
this.idslib.recordEvent(EVENT_INSTALL_NIX_START); this.recordEvent(EVENT_INSTALL_NIX_START);
const exitCode = await actionsExec.exec(binaryPath, args, { const exitCode = await actionsExec.exec(binaryPath, args, {
env: { env: {
...executionEnv, ...executionEnv,
@ -507,13 +541,13 @@ class NixInstallerAction {
}); });
if (exitCode !== 0) { if (exitCode !== 0) {
this.idslib.recordEvent(EVENT_INSTALL_NIX_FAILURE, { this.recordEvent(EVENT_INSTALL_NIX_FAILURE, {
exitCode, exitCode,
}); });
throw new Error(`Non-zero exit code of \`${exitCode}\` detected`); throw new Error(`Non-zero exit code of \`${exitCode}\` detected`);
} }
this.idslib.recordEvent(EVENT_INSTALL_NIX_SUCCESS); this.recordEvent(EVENT_INSTALL_NIX_SUCCESS);
return exitCode; return exitCode;
} }
@ -613,7 +647,7 @@ class NixInstallerAction {
{ {
actionsCore.debug("Starting the Nix daemon through Docker..."); actionsCore.debug("Starting the Nix daemon through Docker...");
this.idslib.recordEvent(EVENT_START_DOCKER_SHIM); this.recordEvent(EVENT_START_DOCKER_SHIM);
const exitCode = await actionsExec.exec( const exitCode = await actionsExec.exec(
"docker", "docker",
[ [
@ -640,7 +674,7 @@ class NixInstallerAction {
"always", "always",
"--init", "--init",
"--name", "--name",
`determinate-nix-shim-${this.idslib.getUniqueId()}-${randomUUID()}`, `determinate-nix-shim-${this.getUniqueId()}-${randomUUID()}`,
"determinate-nix-shim:latest", "determinate-nix-shim:latest",
], ],
{ {
@ -703,7 +737,7 @@ class NixInstallerAction {
} }
if (cleaned) { if (cleaned) {
this.idslib.recordEvent(EVENT_CLEAN_UP_DOCKER_SHIM); this.recordEvent(EVENT_CLEAN_UP_DOCKER_SHIM);
} else { } else {
actionsCore.warning( actionsCore.warning(
"Giving up on cleaning up the nix daemon container", "Giving up on cleaning up the nix daemon container",
@ -732,7 +766,7 @@ class NixInstallerAction {
} }
async flakehubLogin(): Promise<string> { async flakehubLogin(): Promise<string> {
this.idslib.recordEvent(EVENT_LOGIN_TO_FLAKEHUB); this.recordEvent(EVENT_LOGIN_TO_FLAKEHUB);
const netrcPath = `${process.env["RUNNER_TEMP"]}/determinate-nix-installer-netrc`; const netrcPath = `${process.env["RUNNER_TEMP"]}/determinate-nix-installer-netrc`;
const jwt = await actionsCore.getIDToken("api.flakehub.com"); const jwt = await actionsCore.getIDToken("api.flakehub.com");
@ -759,7 +793,7 @@ class NixInstallerAction {
} }
async executeUninstall(): Promise<number> { async executeUninstall(): Promise<number> {
this.idslib.recordEvent(EVENT_UNINSTALL_NIX); this.recordEvent(EVENT_UNINSTALL_NIX);
const exitCode = await actionsExec.exec( const exitCode = await actionsExec.exec(
`/nix/nix-installer`, `/nix/nix-installer`,
["uninstall"], ["uninstall"],
@ -791,7 +825,7 @@ class NixInstallerAction {
} }
private async setupKvm(): Promise<boolean> { private async setupKvm(): Promise<boolean> {
this.idslib.recordEvent(EVENT_SETUP_KVM); this.recordEvent(EVENT_SETUP_KVM);
const currentUser = userInfo(); const currentUser = userInfo();
const isRoot = currentUser.uid === 0; const isRoot = currentUser.uid === 0;
const maybeSudo = isRoot ? "" : "sudo"; const maybeSudo = isRoot ? "" : "sudo";
@ -887,7 +921,7 @@ class NixInstallerAction {
private async fetchBinary(): Promise<string> { private async fetchBinary(): Promise<string> {
if (!this.localRoot) { if (!this.localRoot) {
return await this.idslib.fetchExecutable(); return await this.fetchExecutable();
} else { } else {
const localPath = join(this.localRoot, `nix-installer-${this.platform}`); const localPath = join(this.localRoot, `nix-installer-${this.platform}`);
actionsCore.info(`Using binary ${localPath}`); actionsCore.info(`Using binary ${localPath}`);
@ -897,7 +931,7 @@ class NixInstallerAction {
async reportOverall(): Promise<void> { async reportOverall(): Promise<void> {
try { try {
this.idslib.recordEvent(EVENT_CONCLUDE_WORKFLOW, { this.recordEvent(EVENT_CONCLUDE_WORKFLOW, {
conclusion: await this.getWorkflowConclusion(), conclusion: await this.getWorkflowConclusion(),
}); });
} catch (e) { } catch (e) {
@ -906,7 +940,7 @@ class NixInstallerAction {
} }
private async getWorkflowConclusion(): Promise< private async getWorkflowConclusion(): Promise<
undefined | "success" | "failure" | "cancelled" | "unavailable" | "no-jobs" undefined | WorkflowConclusion
> { > {
if (this.githubToken == null) { if (this.githubToken == null) {
return undefined; return undefined;
@ -953,6 +987,18 @@ class NixInstallerAction {
return "unavailable"; return "unavailable";
} }
} }
private get defaultPlanner(): string {
if (this.isMacOS) {
return "macos";
} else if (this.isLinux) {
return "linux";
} else {
throw new Error(
`Unsupported \`RUNNER_OS\` (currently \`${this.runnerOs}\`)`,
);
}
}
} }
type ExecuteEnvironment = { type ExecuteEnvironment = {
@ -981,32 +1027,8 @@ type ExecuteEnvironment = {
NIX_INSTALLER_LOGGER?: string; NIX_INSTALLER_LOGGER?: string;
}; };
function getDefaultPlanner(): string {
const envOs = process.env["RUNNER_OS"];
if (envOs === "macOS") {
return "macos";
} else if (envOs === "Linux") {
return "linux";
} else {
throw new Error(`Unsupported \`RUNNER_OS\` (currently \`${envOs}\`)`);
}
}
function main(): void { function main(): void {
const installer = new NixInstallerAction(); new NixInstallerAction().execute();
installer.idslib.onMain(async () => {
await installer.detectAndForceDockerShim();
await installer.install();
});
installer.idslib.onPost(async () => {
await installer.cleanupDockerShim();
await installer.reportOverall();
});
installer.idslib.execute();
} }
main(); main();