From e82a3fc37d9c5fe9fae5ff9f6c438893f321321e Mon Sep 17 00:00:00 2001 From: Pavel Zwerschke Date: Wed, 11 Oct 2023 18:12:54 +0200 Subject: [PATCH] Improve error messages (#160) --- .github/workflows/test.yml | 20 +++++++++++ dist/index.js | 70 ++++++++++++++++++++++++++++++-------- dist/post.js | 55 +++++++++++++++++++++++------- package.json | 1 + src/main.ts | 15 +++++++- src/options.ts | 40 +++++++++++++++++++--- 6 files changed, 168 insertions(+), 33 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 18ac217..8d57298 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -287,3 +287,23 @@ jobs: # pytest # - run: exit 1 # if: success() + + # incorrect-version: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # - uses: ./ + # with: + # micromamba-version: '1.2.3' + # - run: exit 1 + # if: success() + + # incorrect-log-level: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # - uses: ./ + # with: + # log-level: foo + # - run: exit 1 + # if: success() diff --git a/dist/index.js b/dist/index.js index 2b97c0f..c8279b4 100644 --- a/dist/index.js +++ b/dist/index.js @@ -41913,9 +41913,9 @@ var init_requestPolicy = __esm({ /** * The main method to implement that manipulates a request/response. */ - constructor(_nextPolicy, _options) { + constructor(_nextPolicy, _options2) { this._nextPolicy = _nextPolicy; - this._options = _options; + this._options = _options2; } /** * Get whether or not a log with the provided log level should be logged. @@ -48658,10 +48658,10 @@ var init_userAgentPolicy = __esm({ init_httpHeaders(); getDefaultUserAgentHeaderName = getDefaultUserAgentKey; UserAgentPolicy = class extends BaseRequestPolicy { - constructor(_nextPolicy, _options, headerKey, headerValue) { - super(_nextPolicy, _options); + constructor(_nextPolicy, _options2, headerKey, headerValue) { + super(_nextPolicy, _options2); this._nextPolicy = _nextPolicy; - this._options = _options; + this._options = _options2; this.headerKey = headerKey; this.headerValue = headerValue; } @@ -50087,7 +50087,7 @@ var init_ProxyTracer = __esm({ ProxyTracer2.prototype.startSpan = function(name, options2, context3) { return this._getTracer().startSpan(name, options2, context3); }; - ProxyTracer2.prototype.startActiveSpan = function(_name, _options, _context, _fn) { + ProxyTracer2.prototype.startActiveSpan = function(_name, _options2, _context, _fn) { var tracer = this._getTracer(); return Reflect.apply(tracer.startActiveSpan, tracer, arguments); }; @@ -50117,7 +50117,7 @@ var init_NoopTracerProvider = __esm({ function() { function NoopTracerProvider2() { } - NoopTracerProvider2.prototype.getTracer = function(_name, _version, _options) { + NoopTracerProvider2.prototype.getTracer = function(_name, _version, _options2) { return new NoopTracer(); }; return NoopTracerProvider2; @@ -65319,7 +65319,7 @@ var init_Credential = __esm({ * @param _nextPolicy - * @param _options - */ - create(_nextPolicy, _options) { + create(_nextPolicy, _options2) { throw new Error("Method should be implemented in children classes."); } }; @@ -76688,6 +76688,7 @@ var import_promises = __toESM(require("fs/promises")); var import_fs = require("fs"); var import_os2 = __toESM(require("os")); var import_path3 = __toESM(require("path")); +var import_process2 = require("process"); var coreDefault5 = __toESM(require_core()); var io = __toESM(require_io()); var import_tool_cache = __toESM(require_tool_cache()); @@ -83132,6 +83133,7 @@ var coreMocked = { // src/options.ts var path = __toESM(require("path")); var os2 = __toESM(require("os")); +var import_process = require("process"); var coreDefault = __toESM(require_core()); var import_Either = __toESM(require_Either()); @@ -83157,12 +83159,19 @@ var PATHS = { var postCleanupSchema = enumType(["none", "shell-init", "environment", "all"]); var logLevelSchema = enumType(["off", "critical", "error", "warning", "info", "debug", "trace"]); var shellSchema = enumType(["none", "bash", "cmd.exe", "fish", "powershell", "tcsh", "xonsh", "zsh"]); -var parseOrUndefined = (key, schema2) => { +var parseOrUndefined = (key, schema2, errorMessage) => { const input = core2.getInput(key); if (input === "") { return void 0; } - return schema2.parse(input); + const maybeResult = schema2.safeParse(input); + if (!maybeResult.success) { + if (!errorMessage) { + throw new Error(`${key} is not valid: ${maybeResult.error.message}`); + } + throw new Error(errorMessage); + } + return maybeResult.data; }; var parseOrUndefinedJSON = (key, schema2) => { const input = core2.getInput(key); @@ -83262,10 +83271,15 @@ var getOptions = () => { environmentFile: parseOrUndefined("environment-file", stringType()), environmentName: parseOrUndefined("environment-name", stringType()), createArgs: parseOrUndefinedList("create-args", stringType()), - logLevel: parseOrUndefined("log-level", logLevelSchema), + logLevel: parseOrUndefined( + "log-level", + logLevelSchema, + "log-level must be either one of `off`, `critical`, `error`, `warning`, `info`, `debug`, `trace`." + ), micromambaVersion: parseOrUndefined( "micromamba-version", - unionType([literalType("latest"), stringType().regex(/^\d+\.\d+\.\d+-\d+$/)]) + unionType([literalType("latest"), stringType().regex(/^\d+\.\d+\.\d+-\d+$/)]), + "micromamba-version must be either `latest` or a version matching `1.2.3-0`." ), micromambaUrl: parseOrUndefined("micromamba-url", stringType().url()), initShell: parseOrUndefinedList("init-shell", shellSchema), @@ -83286,7 +83300,23 @@ var getOptions = () => { assertOptions(options2); return options2; }; -var options = getOptions(); +var _options; +try { + _options = getOptions(); +} catch (error) { + if (core2.isDebug()) { + throw error; + } + if (error instanceof Error) { + core2.setFailed(error.message); + (0, import_process.exit)(1); + } else if (typeof error === "string") { + core2.setFailed(error); + (0, import_process.exit)(1); + } + throw error; +} +var options = _options; // src/util.ts var core3 = process.env.MOCKING ? coreMocked : coreDefault2; @@ -83656,7 +83686,19 @@ var run = async () => { setEnvVariables(); await generateInfo(); }; -run(); +run().catch((error) => { + if (core6.isDebug()) { + throw error; + } + if (error instanceof Error) { + core6.setFailed(error.message); + (0, import_process2.exit)(1); + } else if (typeof error === "string") { + core6.setFailed(error); + (0, import_process2.exit)(1); + } + throw error; +}); /*! Bundled license information: undici/lib/fetch/body.js: diff --git a/dist/post.js b/dist/post.js index c639910..4914b33 100644 --- a/dist/post.js +++ b/dist/post.js @@ -39988,9 +39988,9 @@ var init_requestPolicy = __esm({ /** * The main method to implement that manipulates a request/response. */ - constructor(_nextPolicy, _options) { + constructor(_nextPolicy, _options2) { this._nextPolicy = _nextPolicy; - this._options = _options; + this._options = _options2; } /** * Get whether or not a log with the provided log level should be logged. @@ -46733,10 +46733,10 @@ var init_userAgentPolicy = __esm({ init_httpHeaders(); getDefaultUserAgentHeaderName = getDefaultUserAgentKey; UserAgentPolicy = class extends BaseRequestPolicy { - constructor(_nextPolicy, _options, headerKey, headerValue) { - super(_nextPolicy, _options); + constructor(_nextPolicy, _options2, headerKey, headerValue) { + super(_nextPolicy, _options2); this._nextPolicy = _nextPolicy; - this._options = _options; + this._options = _options2; this.headerKey = headerKey; this.headerValue = headerValue; } @@ -48162,7 +48162,7 @@ var init_ProxyTracer = __esm({ ProxyTracer2.prototype.startSpan = function(name, options2, context3) { return this._getTracer().startSpan(name, options2, context3); }; - ProxyTracer2.prototype.startActiveSpan = function(_name, _options, _context, _fn) { + ProxyTracer2.prototype.startActiveSpan = function(_name, _options2, _context, _fn) { var tracer = this._getTracer(); return Reflect.apply(tracer.startActiveSpan, tracer, arguments); }; @@ -48192,7 +48192,7 @@ var init_NoopTracerProvider = __esm({ function() { function NoopTracerProvider2() { } - NoopTracerProvider2.prototype.getTracer = function(_name, _version, _options) { + NoopTracerProvider2.prototype.getTracer = function(_name, _version, _options2) { return new NoopTracer(); }; return NoopTracerProvider2; @@ -63394,7 +63394,7 @@ var init_Credential = __esm({ * @param _nextPolicy - * @param _options - */ - create(_nextPolicy, _options) { + create(_nextPolicy, _options2) { throw new Error("Method should be implemented in children classes."); } }; @@ -74814,6 +74814,7 @@ var coreMocked = { // src/options.ts var path = __toESM(require("path")); var os2 = __toESM(require("os")); +var import_process = require("process"); var coreDefault = __toESM(require_core()); // node_modules/.pnpm/zod@3.22.4/node_modules/zod/lib/index.mjs @@ -78421,12 +78422,19 @@ var PATHS = { var postCleanupSchema = enumType(["none", "shell-init", "environment", "all"]); var logLevelSchema = enumType(["off", "critical", "error", "warning", "info", "debug", "trace"]); var shellSchema = enumType(["none", "bash", "cmd.exe", "fish", "powershell", "tcsh", "xonsh", "zsh"]); -var parseOrUndefined = (key, schema2) => { +var parseOrUndefined = (key, schema2, errorMessage) => { const input = core.getInput(key); if (input === "") { return void 0; } - return schema2.parse(input); + const maybeResult = schema2.safeParse(input); + if (!maybeResult.success) { + if (!errorMessage) { + throw new Error(`${key} is not valid: ${maybeResult.error.message}`); + } + throw new Error(errorMessage); + } + return maybeResult.data; }; var parseOrUndefinedJSON = (key, schema2) => { const input = core.getInput(key); @@ -78526,10 +78534,15 @@ var getOptions = () => { environmentFile: parseOrUndefined("environment-file", stringType()), environmentName: parseOrUndefined("environment-name", stringType()), createArgs: parseOrUndefinedList("create-args", stringType()), - logLevel: parseOrUndefined("log-level", logLevelSchema), + logLevel: parseOrUndefined( + "log-level", + logLevelSchema, + "log-level must be either one of `off`, `critical`, `error`, `warning`, `info`, `debug`, `trace`." + ), micromambaVersion: parseOrUndefined( "micromamba-version", - unionType([literalType("latest"), stringType().regex(/^\d+\.\d+\.\d+-\d+$/)]) + unionType([literalType("latest"), stringType().regex(/^\d+\.\d+\.\d+-\d+$/)]), + "micromamba-version must be either `latest` or a version matching `1.2.3-0`." ), micromambaUrl: parseOrUndefined("micromamba-url", stringType().url()), initShell: parseOrUndefinedList("init-shell", shellSchema), @@ -78550,7 +78563,23 @@ var getOptions = () => { assertOptions(options2); return options2; }; -var options = getOptions(); +var _options; +try { + _options = getOptions(); +} catch (error) { + if (core.isDebug()) { + throw error; + } + if (error instanceof Error) { + core.setFailed(error.message); + (0, import_process.exit)(1); + } else if (typeof error === "string") { + core.setFailed(error); + (0, import_process.exit)(1); + } + throw error; +} +var options = _options; // src/util.ts var fs = __toESM(require("fs/promises")); diff --git a/package.json b/package.json index e9a2a7b..e0b96a4 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "build": "tsup", "dev": "tsup --watch", "lint": "eslint ./src --ext ts", + "lint:fix": "eslint ./src --ext ts --fix", "all": "npm run build && npm run lint" }, "repository": { diff --git a/src/main.ts b/src/main.ts index 5ec7f36..3e3651e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,6 +2,7 @@ import fs from 'fs/promises' import { constants as fsConstants } from 'fs' // fs.constants is not available in fs/promises for node < 18.4.0 import os from 'os' import path from 'path' +import { exit } from 'process' import * as coreDefault from '@actions/core' import * as io from '@actions/io' import { downloadTool } from '@actions/tool-cache' @@ -184,4 +185,16 @@ const run = async () => { await generateInfo() } -run() +run().catch((error) => { + if (core.isDebug()) { + throw error + } + if (error instanceof Error) { + core.setFailed(error.message) + exit(1) + } else if (typeof error === 'string') { + core.setFailed(error) + exit(1) + } + throw error +}) diff --git a/src/options.ts b/src/options.ts index f55b7be..8416c93 100644 --- a/src/options.ts +++ b/src/options.ts @@ -1,5 +1,6 @@ import * as path from 'path' import * as os from 'os' +import { exit } from 'process' import * as coreDefault from '@actions/core' import * as z from 'zod' import { left, right } from 'fp-ts/lib/Either' @@ -68,13 +69,20 @@ export type ShellType = Exclude export type MicromambaSourceType = Either // Either -const parseOrUndefined = (key: string, schema: z.ZodSchema): T | undefined => { +const parseOrUndefined = (key: string, schema: z.ZodSchema, errorMessage?: string): T | undefined => { const input = core.getInput(key) // GitHub actions sets empty inputs to the empty string, but we want undefined if (input === '') { return undefined } - return schema.parse(input) + const maybeResult = schema.safeParse(input) + if (!maybeResult.success) { + if (!errorMessage) { + throw new Error(`${key} is not valid: ${maybeResult.error.message}`) + } + throw new Error(errorMessage) + } + return maybeResult.data } const parseOrUndefinedJSON = (key: string, schema: z.ZodSchema): T | undefined => { @@ -213,10 +221,15 @@ const getOptions = () => { environmentFile: parseOrUndefined('environment-file', z.string()), environmentName: parseOrUndefined('environment-name', z.string()), createArgs: parseOrUndefinedList('create-args', z.string()), - logLevel: parseOrUndefined('log-level', logLevelSchema), + logLevel: parseOrUndefined( + 'log-level', + logLevelSchema, + 'log-level must be either one of `off`, `critical`, `error`, `warning`, `info`, `debug`, `trace`.' + ), micromambaVersion: parseOrUndefined( 'micromamba-version', - z.union([z.literal('latest'), z.string().regex(/^\d+\.\d+\.\d+-\d+$/)]) + z.union([z.literal('latest'), z.string().regex(/^\d+\.\d+\.\d+-\d+$/)]), + 'micromamba-version must be either `latest` or a version matching `1.2.3-0`.' ), micromambaUrl: parseOrUndefined('micromamba-url', z.string().url()), initShell: parseOrUndefinedList('init-shell', shellSchema), @@ -238,4 +251,21 @@ const getOptions = () => { return options } -export const options = getOptions() +let _options: Options +try { + _options = getOptions() +} catch (error) { + if (core.isDebug()) { + throw error + } + if (error instanceof Error) { + core.setFailed(error.message) + exit(1) + } else if (typeof error === 'string') { + core.setFailed(error) + exit(1) + } + throw error +} + +export const options = _options