From dccc3175bf4d231fff9b94056cc8a54e72462e4c Mon Sep 17 00:00:00 2001 From: Luc Perkins Date: Thu, 23 May 2024 19:19:07 -0300 Subject: [PATCH] Update detsys-ts --- dist/index.js | 168 ++++++++++++++++------------------ dist/index.js.map | 2 +- pnpm-lock.yaml | 13 +-- src/index.ts | 9 +- src/inputs.ts | 10 -- src/update-flake-lock.test.ts | 21 ----- 6 files changed, 89 insertions(+), 134 deletions(-) delete mode 100644 src/inputs.ts diff --git a/dist/index.js b/dist/index.js index a2e8065..e838d26 100644 --- a/dist/index.js +++ b/dist/index.js @@ -39513,7 +39513,7 @@ module.exports = { parallel : __nccwpck_require__(644), serial : __nccwpck_require__(4501), - serialOrdered : __nccwpck_require__(3958) + serialOrdered : __nccwpck_require__(2362) }; @@ -39844,7 +39844,7 @@ function parallel(list, iterator, callback) /***/ 4501: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { -var serialOrdered = __nccwpck_require__(3958); +var serialOrdered = __nccwpck_require__(2362); // Public API module.exports = serial; @@ -39865,7 +39865,7 @@ function serial(list, iterator, callback) /***/ }), -/***/ 3958: +/***/ 2362: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { var iterate = __nccwpck_require__(5748) @@ -93710,7 +93710,7 @@ const external_node_path_namespaceObject = __WEBPACK_EXTERNAL_createRequire(impo const external_node_stream_promises_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:stream/promises"); ;// CONCATENATED MODULE: external "node:zlib" const external_node_zlib_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:zlib"); -;// CONCATENATED MODULE: ./node_modules/.pnpm/github.com+DeterminateSystems+detsys-ts@ed02129aed8e4d6402d920152652877189bece70_3whmnlhrx56zhgtsjnkrhnutfu/node_modules/detsys-ts/dist/index.js +;// CONCATENATED MODULE: ./node_modules/.pnpm/github.com+DeterminateSystems+detsys-ts@1c510e3aff595c88769d3706895ecebbc625ff2c_5f3ck3sx4ossruvxt6hpzqrwhy/node_modules/detsys-ts/dist/index.js var __defProp = Object.defineProperty; var __export = (target, all) => { for (var name in all) @@ -94018,6 +94018,7 @@ function hashEnvironmentVariables(prefix, variables) { var inputs_exports = {}; __export(inputs_exports, { getArrayOfStrings: () => getArrayOfStrings, + getArrayOfStringsOrNull: () => getArrayOfStringsOrNull, getBool: () => getBool, getMultilineStringOrNull: () => getMultilineStringOrNull, getNumberOrNull: () => getNumberOrNull, @@ -94034,6 +94035,14 @@ var getArrayOfStrings = (name, separator) => { const original = getString(name); return handleString(original, separator); }; +var getArrayOfStringsOrNull = (name, separator) => { + const original = getStringOrNull(name); + if (original === null) { + return null; + } else { + return handleString(original, separator); + } +}; var handleString = (input, separator) => { const sepChar = separator === "comma" ? "," : /\s+/; const trimmed = input.trim(); @@ -94172,6 +94181,7 @@ var EVENT_ARTIFACT_CACHE_HIT = "artifact_cache_hit"; var EVENT_ARTIFACT_CACHE_MISS = "artifact_cache_miss"; var EVENT_ARTIFACT_CACHE_PERSIST = "artifact_cache_persist"; var EVENT_PREFLIGHT_REQUIRE_NIX_DENIED = "preflight-require-nix-denied"; +var FACT_ARTIFACT_FETCHED_FROM_CACHE = "artifact_fetched_from_cache"; var FACT_ENDED_WITH_EXCEPTION = "ended_with_exception"; var FACT_FINAL_EXCEPTION = "final_exception"; var FACT_OS = "$os"; @@ -94284,16 +94294,6 @@ var DetSysAction = class { stapleFile(name, location) { this.exceptionAttachments.set(name, location); } - setExecutionPhase() { - const phase = core.getState(STATE_KEY_EXECUTION_PHASE); - if (phase === "") { - core.saveState(STATE_KEY_EXECUTION_PHASE, "post"); - this.executionPhase = "main"; - } else { - this.executionPhase = "post"; - } - this.facts.execution_phase = this.executionPhase; - } /** * Execute the Action as defined. */ @@ -94303,7 +94303,55 @@ var DetSysAction = class { process.exitCode = 1; }); } - // Whether the + getTemporaryName() { + const tmpDir = process.env["RUNNER_TEMP"] || (0,external_node_os_.tmpdir)(); + return external_node_path_namespaceObject.join(tmpDir, `${this.actionOptions.name}-${(0,external_node_crypto_namespaceObject.randomUUID)()}`); + } + addFact(key, value) { + this.facts[key] = value; + } + getDiagnosticsUrl() { + return this.actionOptions.diagnosticsUrl; + } + getUniqueId() { + return this.identity.run_differentiator || process.env.RUNNER_TRACKING_ID || (0,external_node_crypto_namespaceObject.randomUUID)(); + } + getCorrelationHashes() { + return this.identity; + } + recordEvent(eventName, context = {}) { + this.events.push({ + event_name: `${this.actionOptions.eventPrefix}${eventName}`, + context, + correlation: this.identity, + facts: this.facts, + timestamp: /* @__PURE__ */ new Date(), + uuid: (0,external_node_crypto_namespaceObject.randomUUID)() + }); + } + /** + * Unpacks the closure returned by `fetchArtifact()`, imports the + * contents into the Nix store, and returns the path of the executable at + * `/nix/store/STORE_PATH/bin/${bin}`. + */ + async unpackClosure(bin) { + const artifact = await this.fetchArtifact(); + const { stdout } = await (0,external_node_util_.promisify)(external_node_child_process_namespaceObject.exec)( + `cat "${artifact}" | xz -d | nix-store --import` + ); + const paths = stdout.split(external_node_os_.EOL); + const lastPath = paths.at(-2); + return `${lastPath}/bin/${bin}`; + } + /** + * Fetches the executable at the URL determined by the `source-*` inputs and + * other facts, `chmod`s it, and returns the path to the executable on disk. + */ + async fetchExecutable() { + const binaryPath = await this.fetchArtifact(); + await (0,promises_namespaceObject.chmod)(binaryPath, promises_namespaceObject.constants.S_IXUSR | promises_namespaceObject.constants.S_IXGRP); + return binaryPath; + } get isMain() { return this.executionPhase === "main"; } @@ -94359,52 +94407,25 @@ var DetSysAction = class { await this.complete(); } } - addFact(key, value) { - this.facts[key] = value; - } - getDiagnosticsUrl() { - return this.actionOptions.diagnosticsUrl; - } - getUniqueId() { - return this.identity.run_differentiator || process.env.RUNNER_TRACKING_ID || (0,external_node_crypto_namespaceObject.randomUUID)(); - } - getCorrelationHashes() { - return this.identity; - } - recordEvent(eventName, context = {}) { - this.events.push({ - event_name: `${this.actionOptions.eventPrefix}${eventName}`, - context, - correlation: this.identity, - facts: this.facts, - timestamp: /* @__PURE__ */ new Date(), - uuid: (0,external_node_crypto_namespaceObject.randomUUID)() - }); - } /** - * Fetches a file in `.xz` format, imports its contents into the Nix store, - * and returns the path of the executable at `/nix/store/STORE_PATH/bin/${bin}`. - */ - async unpackClosure(bin) { - const artifact = this.fetchArtifact(); - const { stdout } = await (0,external_node_util_.promisify)(external_node_child_process_namespaceObject.exec)( - `cat "${artifact}" | xz -d | nix-store --import` - ); - const paths = stdout.split(external_node_os_.EOL); - const lastPath = paths.at(-2); - return `${lastPath}/bin/${bin}`; - } - /** - * Fetch an artifact, such as a tarball, from the URL determined by the `source-*` - * inputs and other factors. + * Fetch an artifact, such as a tarball, from the location determined by the + * `source-*` inputs. If `source-binary` is specified, this will return a path + * to a binary on disk; otherwise, the artifact will be downloaded from the + * URL determined by the other `source-*` inputs (`source-url`, `source-pr`, + * etc.). */ async fetchArtifact() { + const sourceBinary = getStringOrNull("source-binary"); + if (sourceBinary !== null && sourceBinary !== "") { + core.debug(`Using the provided source binary at ${sourceBinary}`); + return sourceBinary; + } core.startGroup( `Downloading ${this.actionOptions.name} for ${this.architectureFetchSuffix}` ); try { - core.info(`Fetching from ${this.getUrl()}`); - const correlatedUrl = this.getUrl(); + core.info(`Fetching from ${this.getSourceUrl()}`); + const correlatedUrl = this.getSourceUrl(); correlatedUrl.searchParams.set("ci", "github"); correlatedUrl.searchParams.set( "correlation", @@ -94415,16 +94436,16 @@ var DetSysAction = class { const v = versionCheckup.headers.etag; this.addFact(FACT_SOURCE_URL_ETAG, v); core.debug( - `Checking the tool cache for ${this.getUrl()} at ${v}` + `Checking the tool cache for ${this.getSourceUrl()} at ${v}` ); const cached = await this.getCachedVersion(v); if (cached) { - this.facts["artifact_fetched_from_cache"] = true; + this.facts[FACT_ARTIFACT_FETCHED_FROM_CACHE] = true; core.debug(`Tool cache hit.`); return cached; } } - this.facts["artifact_fetched_from_cache"] = false; + this.facts[FACT_ARTIFACT_FETCHED_FROM_CACHE] = false; core.debug( `No match from the cache, re-fetching from the redirect: ${versionCheckup.url}` ); @@ -94450,15 +94471,6 @@ var DetSysAction = class { core.endGroup(); } } - /** - * Fetches the executable at the URL determined by the `source-*` inputs and - * other facts, `chmod`s it, and returns the path to the executable on disk. - */ - async fetchExecutable() { - const binaryPath = await this.fetchArtifact(); - await (0,promises_namespaceObject.chmod)(binaryPath, promises_namespaceObject.constants.S_IXUSR | promises_namespaceObject.constants.S_IXGRP); - return binaryPath; - } /** * A helper function for failing on error only if strict mode is enabled. * This is intended only for CI environments testing Actions themselves. @@ -94472,7 +94484,7 @@ var DetSysAction = class { this.recordEvent(`complete_${this.executionPhase}`); await this.submitEvents(); } - getUrl() { + getSourceUrl() { const p = this.sourceParameters; if (p.url) { this.addFact(FACT_SOURCE_URL, p.url); @@ -94657,10 +94669,6 @@ var DetSysAction = class { } this.events = []; } - getTemporaryName() { - const _tmpdir = process.env["RUNNER_TEMP"] || (0,external_node_os_.tmpdir)(); - return external_node_path_namespaceObject.join(_tmpdir, `${this.actionOptions.name}-${(0,external_node_crypto_namespaceObject.randomUUID)()}`); - } }; function stringifyError(error2) { return error2 instanceof Error || typeof error2 == "string" ? error2.toString() : JSON.stringify(error2); @@ -94754,17 +94762,6 @@ function mungeDiagnosticEndpoint(inputUrl) { // EXTERNAL MODULE: external "fs" var external_fs_ = __nccwpck_require__(7147); ;// CONCATENATED MODULE: ./dist/index.js -// src/inputs.ts -function determineFlakeDirectories(input) { - const sepChar = /\s+/; - const trimmed = input.trim(); - if (trimmed === "") { - return []; - } else { - return trimmed.split(sepChar).map((s) => s.trim()); - } -} - // src/nix.ts function makeNixCommandArgs(nixOptions, flakeInputs, commitMessage) { const flakeInputFlags = flakeInputs.flatMap((input) => [ @@ -94792,12 +94789,7 @@ var UpdateFlakeLockAction = class extends DetSysAction { this.flakeInputs = inputs_exports.getArrayOfStrings("inputs", "space"); this.nixOptions = inputs_exports.getArrayOfStrings("nix-options", "space"); this.pathToFlakeDir = inputs_exports.getStringOrNull("path-to-flake-dir"); - const flakeDirsInput = inputs_exports.getStringOrNull("flake-dirs"); - if (flakeDirsInput !== null) { - this.flakeDirs = determineFlakeDirectories(flakeDirsInput); - } else { - this.flakeDirs = null; - } + this.flakeDirs = inputs_exports.getArrayOfStringsOrNull("flake-dirs", "space"); this.validateInputs(); } async main() { diff --git a/dist/index.js.map b/dist/index.js.map index b3b2c4d..22b0b19 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/inputs.ts","../src/nix.ts","../src/index.ts"],"sourcesContent":["// Helper function for nullable input fields into an array of strings\nexport function determineFlakeDirectories(input: string): string[] {\n const sepChar = /\\s+/;\n const trimmed = input.trim();\n if (trimmed === \"\") {\n return [];\n } else {\n return trimmed.split(sepChar).map((s: string) => s.trim());\n }\n}\n","// Build the Nix args out of inputs from the Actions environment\nexport function makeNixCommandArgs(\n nixOptions: string[],\n flakeInputs: string[],\n commitMessage: string,\n): string[] {\n const flakeInputFlags = flakeInputs.flatMap((input) => [\n \"--update-input\",\n input,\n ]);\n\n const updateLockMechanism = flakeInputFlags.length === 0 ? \"update\" : \"lock\";\n\n return nixOptions\n .concat([\"flake\", updateLockMechanism])\n .concat(flakeInputFlags)\n .concat([\"--commit-lock-file\", \"--commit-lockfile-summary\", commitMessage]);\n}\n","import { determineFlakeDirectories } from \"./inputs.js\";\nimport { makeNixCommandArgs } from \"./nix.js\";\nimport * as actionsCore from \"@actions/core\";\nimport * as actionsExec from \"@actions/exec\";\nimport { DetSysAction, inputs } from \"detsys-ts\";\nimport * as fs from \"fs\";\n\nconst EVENT_EXECUTION_FAILURE = \"execution_failure\";\n\nclass UpdateFlakeLockAction extends DetSysAction {\n private commitMessage: string;\n private nixOptions: string[];\n private flakeInputs: string[];\n private pathToFlakeDir: string | null;\n private flakeDirs: string[] | null;\n\n constructor() {\n super({\n name: \"update-flake-lock\",\n fetchStyle: \"universal\",\n requireNix: \"fail\",\n });\n\n this.commitMessage = inputs.getString(\"commit-msg\");\n this.flakeInputs = inputs.getArrayOfStrings(\"inputs\", \"space\");\n this.nixOptions = inputs.getArrayOfStrings(\"nix-options\", \"space\");\n this.pathToFlakeDir = inputs.getStringOrNull(\"path-to-flake-dir\");\n\n const flakeDirsInput = inputs.getStringOrNull(\"flake-dirs\");\n if (flakeDirsInput !== null) {\n this.flakeDirs = determineFlakeDirectories(flakeDirsInput);\n } else {\n this.flakeDirs = null;\n }\n\n this.validateInputs();\n }\n\n async main(): Promise {\n await this.updateFlakeLock();\n }\n\n // No post phase\n async post(): Promise {}\n\n async updateFlakeLock(): Promise {\n if (this.flakeDirs !== null && this.flakeDirs.length > 0) {\n actionsCore.debug(\n `Running flake lock update in multiple directories: ${this.flakeDirs.map((dir) => `\\`${dir}\\``).join(\" \")}`,\n );\n\n for (const directory of this.flakeDirs) {\n await this.updateFlakeInDirectory(directory);\n }\n } else {\n // Set directory to root if not specified\n const flakeDir = this.pathToFlakeDir ?? \".\";\n await this.updateFlakeInDirectory(flakeDir);\n }\n }\n\n private async updateFlakeInDirectory(flakeDir: string): Promise {\n this.ensureDirectoryExists(flakeDir);\n this.ensureDirectoryIsFlake(flakeDir);\n\n actionsCore.debug(`Running flake lock update in directory \\`${flakeDir}\\``);\n\n // Nix command of this form:\n // nix ${maybe nix options} flake ${\"update\" or \"lock\"} ${maybe --update-input flags} --commit-lock-file --commit-lockfile-summary ${commit message}\n // Example commands:\n // nix --extra-substituters https://example.com flake lock --update-input nixpkgs --commit-lock-file --commit-lockfile-summary \"updated flake.lock\"\n // nix flake update --commit-lock-file --commit-lockfile-summary \"updated flake.lock\"\n const nixCommandArgs: string[] = makeNixCommandArgs(\n this.nixOptions,\n this.flakeInputs,\n this.commitMessage,\n );\n\n actionsCore.debug(\n JSON.stringify({\n directory: flakeDir,\n options: this.nixOptions,\n inputs: this.flakeInputs,\n message: this.commitMessage,\n args: nixCommandArgs,\n }),\n );\n\n const execOptions: actionsExec.ExecOptions = {\n cwd: flakeDir,\n };\n\n const exitCode = await actionsExec.exec(\"nix\", nixCommandArgs, execOptions);\n\n if (exitCode !== 0) {\n this.recordEvent(EVENT_EXECUTION_FAILURE, {\n exitCode,\n });\n actionsCore.setFailed(\n `non-zero exit code of ${exitCode} detected while updating directory \\`${flakeDir}\\``,\n );\n } else {\n actionsCore.info(\n `flake.lock file in \\`${flakeDir}\\` was successfully updated`,\n );\n }\n }\n\n private validateInputs(): void {\n // Ensure that either `path-to-flake-dir` or `flake-dirs` is set to a meaningful value but not both\n if (\n this.flakeDirs !== null &&\n this.flakeDirs.length > 0 &&\n this.pathToFlakeDir !== null &&\n this.pathToFlakeDir !== \"\"\n ) {\n throw new Error(\n \"Both `path-to-flake-dir` and `flake-dirs` are set, whereas only one can be\",\n );\n }\n\n // Ensure that `flake-dirs` isn't an empty array if set\n if (this.flakeDirs !== null && this.flakeDirs.length === 0) {\n throw new Error(\n \"The `flake-dirs` input is set to an empty array; it must contain at least one directory\",\n );\n }\n\n // Ensure that both `flake-dirs` and `inputs` aren't set at the same time\n if (\n this.flakeDirs !== null &&\n this.flakeDirs.length > 0 &&\n this.flakeInputs.length > 0\n ) {\n throw new Error(\n `You've set both \\`flake-dirs\\` and \\`inputs\\` but you can only set one`,\n );\n }\n }\n\n private ensureDirectoryExists(flakeDir: string): void {\n actionsCore.debug(`Checking that flake directory \\`${flakeDir}\\` exists`);\n\n // Ensure the directory exists\n fs.access(flakeDir, fs.constants.F_OK, (err) => {\n if (err !== null) {\n throw new Error(`Directory \\`${flakeDir}\\` doesn't exist`);\n } else {\n actionsCore.debug(`Flake directory \\`${flakeDir}\\` exists`);\n }\n });\n }\n\n private ensureDirectoryIsFlake(flakeDir: string): void {\n const flakeDotNix = `${flakeDir}/flake.nix`;\n if (!fs.existsSync(flakeDotNix)) {\n throw new Error(\n `Directory \\`${flakeDir}\\` is not a valid flake as it doesn't contain a \\`flake.nix\\``,\n );\n } else {\n actionsCore.debug(`Directory \\`${flakeDir}\\` is a valid flake`);\n }\n }\n}\n\nfunction main(): void {\n new UpdateFlakeLockAction().execute();\n}\n\nmain();\n"],"mappings":"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","names":[]} \ No newline at end of file +{"version":3,"sources":["../src/nix.ts","../src/index.ts"],"sourcesContent":["// Build the Nix args out of inputs from the Actions environment\nexport function makeNixCommandArgs(\n nixOptions: string[],\n flakeInputs: string[],\n commitMessage: string,\n): string[] {\n const flakeInputFlags = flakeInputs.flatMap((input) => [\n \"--update-input\",\n input,\n ]);\n\n const updateLockMechanism = flakeInputFlags.length === 0 ? \"update\" : \"lock\";\n\n return nixOptions\n .concat([\"flake\", updateLockMechanism])\n .concat(flakeInputFlags)\n .concat([\"--commit-lock-file\", \"--commit-lockfile-summary\", commitMessage]);\n}\n","import { makeNixCommandArgs } from \"./nix.js\";\nimport * as actionsCore from \"@actions/core\";\nimport * as actionsExec from \"@actions/exec\";\nimport { DetSysAction, inputs } from \"detsys-ts\";\nimport * as fs from \"fs\";\n\nconst EVENT_EXECUTION_FAILURE = \"execution_failure\";\n\nclass UpdateFlakeLockAction extends DetSysAction {\n private commitMessage: string;\n private nixOptions: string[];\n private flakeInputs: string[];\n private pathToFlakeDir: string | null;\n private flakeDirs: string[] | null;\n\n constructor() {\n super({\n name: \"update-flake-lock\",\n fetchStyle: \"universal\",\n requireNix: \"fail\",\n });\n\n this.commitMessage = inputs.getString(\"commit-msg\");\n this.flakeInputs = inputs.getArrayOfStrings(\"inputs\", \"space\");\n this.nixOptions = inputs.getArrayOfStrings(\"nix-options\", \"space\");\n this.pathToFlakeDir = inputs.getStringOrNull(\"path-to-flake-dir\");\n this.flakeDirs = inputs.getArrayOfStringsOrNull(\"flake-dirs\", \"space\");\n\n this.validateInputs();\n }\n\n async main(): Promise {\n await this.updateFlakeLock();\n }\n\n // No post phase\n async post(): Promise {}\n\n async updateFlakeLock(): Promise {\n if (this.flakeDirs !== null && this.flakeDirs.length > 0) {\n actionsCore.debug(\n `Running flake lock update in multiple directories: ${this.flakeDirs.map((dir) => `\\`${dir}\\``).join(\" \")}`,\n );\n\n for (const directory of this.flakeDirs) {\n await this.updateFlakeInDirectory(directory);\n }\n } else {\n // Set directory to root if not specified\n const flakeDir = this.pathToFlakeDir ?? \".\";\n await this.updateFlakeInDirectory(flakeDir);\n }\n }\n\n private async updateFlakeInDirectory(flakeDir: string): Promise {\n this.ensureDirectoryExists(flakeDir);\n this.ensureDirectoryIsFlake(flakeDir);\n\n actionsCore.debug(`Running flake lock update in directory \\`${flakeDir}\\``);\n\n // Nix command of this form:\n // nix ${maybe nix options} flake ${\"update\" or \"lock\"} ${maybe --update-input flags} --commit-lock-file --commit-lockfile-summary ${commit message}\n // Example commands:\n // nix --extra-substituters https://example.com flake lock --update-input nixpkgs --commit-lock-file --commit-lockfile-summary \"updated flake.lock\"\n // nix flake update --commit-lock-file --commit-lockfile-summary \"updated flake.lock\"\n const nixCommandArgs: string[] = makeNixCommandArgs(\n this.nixOptions,\n this.flakeInputs,\n this.commitMessage,\n );\n\n actionsCore.debug(\n JSON.stringify({\n directory: flakeDir,\n options: this.nixOptions,\n inputs: this.flakeInputs,\n message: this.commitMessage,\n args: nixCommandArgs,\n }),\n );\n\n const execOptions: actionsExec.ExecOptions = {\n cwd: flakeDir,\n };\n\n const exitCode = await actionsExec.exec(\"nix\", nixCommandArgs, execOptions);\n\n if (exitCode !== 0) {\n this.recordEvent(EVENT_EXECUTION_FAILURE, {\n exitCode,\n });\n actionsCore.setFailed(\n `non-zero exit code of ${exitCode} detected while updating directory \\`${flakeDir}\\``,\n );\n } else {\n actionsCore.info(\n `flake.lock file in \\`${flakeDir}\\` was successfully updated`,\n );\n }\n }\n\n private validateInputs(): void {\n // Ensure that either `path-to-flake-dir` or `flake-dirs` is set to a meaningful value but not both\n if (\n this.flakeDirs !== null &&\n this.flakeDirs.length > 0 &&\n this.pathToFlakeDir !== null &&\n this.pathToFlakeDir !== \"\"\n ) {\n throw new Error(\n \"Both `path-to-flake-dir` and `flake-dirs` are set, whereas only one can be\",\n );\n }\n\n // Ensure that `flake-dirs` isn't an empty array if set\n if (this.flakeDirs !== null && this.flakeDirs.length === 0) {\n throw new Error(\n \"The `flake-dirs` input is set to an empty array; it must contain at least one directory\",\n );\n }\n\n // Ensure that both `flake-dirs` and `inputs` aren't set at the same time\n if (\n this.flakeDirs !== null &&\n this.flakeDirs.length > 0 &&\n this.flakeInputs.length > 0\n ) {\n throw new Error(\n `You've set both \\`flake-dirs\\` and \\`inputs\\` but you can only set one`,\n );\n }\n }\n\n private ensureDirectoryExists(flakeDir: string): void {\n actionsCore.debug(`Checking that flake directory \\`${flakeDir}\\` exists`);\n\n // Ensure the directory exists\n fs.access(flakeDir, fs.constants.F_OK, (err) => {\n if (err !== null) {\n throw new Error(`Directory \\`${flakeDir}\\` doesn't exist`);\n } else {\n actionsCore.debug(`Flake directory \\`${flakeDir}\\` exists`);\n }\n });\n }\n\n private ensureDirectoryIsFlake(flakeDir: string): void {\n const flakeDotNix = `${flakeDir}/flake.nix`;\n if (!fs.existsSync(flakeDotNix)) {\n throw new Error(\n `Directory \\`${flakeDir}\\` is not a valid flake as it doesn't contain a \\`flake.nix\\``,\n );\n } else {\n actionsCore.debug(`Directory \\`${flakeDir}\\` is a valid flake`);\n }\n }\n}\n\nfunction main(): void {\n new UpdateFlakeLockAction().execute();\n}\n\nmain();\n"],"mappings":"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","names":[]} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1dbf8dd..f248541 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ dependencies: version: 1.1.1 detsys-ts: specifier: github:DeterminateSystems/detsys-ts - version: github.com/DeterminateSystems/detsys-ts/ed02129aed8e4d6402d920152652877189bece70 + version: github.com/DeterminateSystems/detsys-ts/1c510e3aff595c88769d3706895ecebbc625ff2c devDependencies: '@trivago/prettier-plugin-sort-imports': @@ -1518,7 +1518,7 @@ packages: hasBin: true dependencies: caniuse-lite: 1.0.30001621 - electron-to-chromium: 1.4.777 + electron-to-chromium: 1.4.781 node-releases: 2.0.14 update-browserslist-db: 1.0.16(browserslist@4.23.0) dev: true @@ -1811,8 +1811,8 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true - /electron-to-chromium@1.4.777: - resolution: {integrity: sha512-n02NCwLJ3wexLfK/yQeqfywCblZqLcXphzmid5e8yVPdtEcida7li0A5WQKghHNG0FeOMCzeFOzEbtAh5riXFw==} + /electron-to-chromium@1.4.781: + resolution: {integrity: sha512-aBI40ltvcWJQDW+V803FY6HjXAfi5xCWzpa3vSM/NGg7GfKEvI7ftzW4Gb2XKTRO4WsxDG7YG8ykrr/pG9bkKQ==} dev: true /emoji-regex@8.0.0: @@ -2765,6 +2765,7 @@ packages: /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. dependencies: once: 1.4.0 wrappy: 1.0.2 @@ -4455,8 +4456,8 @@ packages: engines: {node: '>=12.20'} dev: true - github.com/DeterminateSystems/detsys-ts/ed02129aed8e4d6402d920152652877189bece70: - resolution: {tarball: https://codeload.github.com/DeterminateSystems/detsys-ts/tar.gz/ed02129aed8e4d6402d920152652877189bece70} + github.com/DeterminateSystems/detsys-ts/1c510e3aff595c88769d3706895ecebbc625ff2c: + resolution: {tarball: https://codeload.github.com/DeterminateSystems/detsys-ts/tar.gz/1c510e3aff595c88769d3706895ecebbc625ff2c} name: detsys-ts version: 1.0.0 dependencies: diff --git a/src/index.ts b/src/index.ts index cacffc1..5bd1e9c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,3 @@ -import { determineFlakeDirectories } from "./inputs.js"; import { makeNixCommandArgs } from "./nix.js"; import * as actionsCore from "@actions/core"; import * as actionsExec from "@actions/exec"; @@ -25,13 +24,7 @@ class UpdateFlakeLockAction extends DetSysAction { this.flakeInputs = inputs.getArrayOfStrings("inputs", "space"); this.nixOptions = inputs.getArrayOfStrings("nix-options", "space"); this.pathToFlakeDir = inputs.getStringOrNull("path-to-flake-dir"); - - const flakeDirsInput = inputs.getStringOrNull("flake-dirs"); - if (flakeDirsInput !== null) { - this.flakeDirs = determineFlakeDirectories(flakeDirsInput); - } else { - this.flakeDirs = null; - } + this.flakeDirs = inputs.getArrayOfStringsOrNull("flake-dirs", "space"); this.validateInputs(); } diff --git a/src/inputs.ts b/src/inputs.ts deleted file mode 100644 index 1b965fc..0000000 --- a/src/inputs.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Helper function for nullable input fields into an array of strings -export function determineFlakeDirectories(input: string): string[] { - const sepChar = /\s+/; - const trimmed = input.trim(); - if (trimmed === "") { - return []; - } else { - return trimmed.split(sepChar).map((s: string) => s.trim()); - } -} diff --git a/src/update-flake-lock.test.ts b/src/update-flake-lock.test.ts index a5aeaf5..f23fff3 100644 --- a/src/update-flake-lock.test.ts +++ b/src/update-flake-lock.test.ts @@ -1,4 +1,3 @@ -import { determineFlakeDirectories } from "./inputs.js"; import { makeNixCommandArgs } from "./nix.js"; import { expect, test } from "vitest"; @@ -73,23 +72,3 @@ test("Nix command arguments", () => { expect(args).toStrictEqual(expected); }); }); - -test("Flake directory parsing", () => { - type TestCase = { - input: string; - outputs: string[]; - }; - - const testCases: TestCase[] = [ - { input: "", outputs: [] }, - { input: "one two three", outputs: ["one", "two", "three"] }, - { - input: ` one two three `, - outputs: ["one", "two", "three"], - }, - ]; - - testCases.forEach(({ input, outputs }) => { - expect(determineFlakeDirectories(input)).toStrictEqual(outputs); - }); -});