fix: include cause of parsing errors in action output logs (#431)
This commit is contained in:
+5
-4
@@ -55,6 +55,7 @@ export default class Content {
|
||||
* @returns {Content} - the parsed JSON payload to use in requests.
|
||||
*/
|
||||
getContentPayload(config) {
|
||||
const errors = [];
|
||||
if (!config.inputs.payload) {
|
||||
throw new SlackError(
|
||||
config.core,
|
||||
@@ -71,8 +72,7 @@ export default class Content {
|
||||
return /** @type {Content} */ (content);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
config.core.debug("Failed to parse input payload as YAML");
|
||||
config.core.debug(error.message);
|
||||
errors.push(error);
|
||||
}
|
||||
}
|
||||
try {
|
||||
@@ -90,11 +90,12 @@ export default class Content {
|
||||
}
|
||||
return JSON.parse(trimmed);
|
||||
} catch (/** @type {any} */ error) {
|
||||
errors.unshift(error);
|
||||
throw new SlackError(
|
||||
config.core,
|
||||
"Invalid input! Failed to parse contents of the provided payload",
|
||||
{
|
||||
cause: error,
|
||||
cause: { values: errors },
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -140,7 +141,7 @@ export default class Content {
|
||||
config.core,
|
||||
"Invalid input! Failed to parse contents of the provided payload file",
|
||||
{
|
||||
cause: error,
|
||||
cause: { values: [error] },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
+6
-1
@@ -1,12 +1,17 @@
|
||||
import core from "@actions/core";
|
||||
|
||||
/**
|
||||
* @typedef Cause
|
||||
* @property {Error[]} [values] - Caught exceptions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SlackError is a custom error wrapper for known errors of Slack GitHub Action.
|
||||
*/
|
||||
export default class SlackError extends Error {
|
||||
/**
|
||||
* @typedef Options
|
||||
* @property {Error} [cause] - thrown exception of this error.
|
||||
* @property {Cause} [cause] - Reason for an error.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
+11
-3
@@ -6,13 +6,21 @@ import send from "./send.js";
|
||||
* from the send.js file for testing purposes.
|
||||
*/
|
||||
try {
|
||||
send(core);
|
||||
await send(core);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
core.error(error.message);
|
||||
core.debug(`${error.name} cause: ${error.cause}`);
|
||||
core.debug(`${error.name} stack: ${error.stack}`);
|
||||
/** @type {import('./errors.js').Cause} */
|
||||
const causes = /** @type {any} */ (error.cause);
|
||||
if (causes?.values) {
|
||||
for (const cause of causes.values) {
|
||||
core.info(`${cause.stack}`);
|
||||
}
|
||||
} else {
|
||||
core.info(`${error.stack}`);
|
||||
}
|
||||
} else {
|
||||
core.error(`${error}`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
+56
-1
@@ -1,6 +1,7 @@
|
||||
import path from "node:path";
|
||||
import core from "@actions/core";
|
||||
import { assert } from "chai";
|
||||
import { YAMLException } from "js-yaml";
|
||||
import Config from "../src/config.js";
|
||||
import Content from "../src/content.js";
|
||||
import SlackError from "../src/errors.js";
|
||||
@@ -190,6 +191,11 @@ describe("content", () => {
|
||||
err.message,
|
||||
"Invalid input! Failed to parse contents of the provided payload",
|
||||
);
|
||||
assert.isDefined(err.cause?.values);
|
||||
assert.equal(err.cause.values.length, 2);
|
||||
const [jsonError, yamlError] = err.cause.values;
|
||||
assert.isTrue(jsonError instanceof SyntaxError);
|
||||
assert.isTrue(yamlError instanceof YAMLException);
|
||||
} else {
|
||||
assert.fail("Failed to throw a SlackError", err);
|
||||
}
|
||||
@@ -334,8 +340,10 @@ describe("content", () => {
|
||||
err.message,
|
||||
"Invalid input! Failed to parse contents of the provided payload file",
|
||||
);
|
||||
assert.isDefined(err.cause?.values);
|
||||
assert.equal(err.cause.values.length, 1);
|
||||
assert.include(
|
||||
err.cause.message,
|
||||
err.cause.values[0].message,
|
||||
"Invalid input! Failed to parse file extension unknown.md",
|
||||
);
|
||||
} else {
|
||||
@@ -343,5 +351,52 @@ describe("content", () => {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("fails if invalid JSON exists in the input payload", async () => {
|
||||
mocks.core.getInput.withArgs("payload-file-path").returns("example.json");
|
||||
mocks.fs.readFileSync
|
||||
.withArgs(path.resolve("example.json"), "utf-8")
|
||||
.returns(`{
|
||||
"message": "a truncated file without an end`);
|
||||
try {
|
||||
await send(mocks.core);
|
||||
assert.fail("Failed to throw for invalid JSON");
|
||||
} catch (err) {
|
||||
if (err instanceof SlackError) {
|
||||
assert.include(
|
||||
err.message,
|
||||
"Invalid input! Failed to parse contents of the provided payload file",
|
||||
);
|
||||
assert.isDefined(err.cause?.values);
|
||||
assert.equal(err.cause.values.length, 1);
|
||||
assert.isTrue(err.cause.values[0] instanceof SyntaxError);
|
||||
} else {
|
||||
assert.fail("Failed to throw a SlackError", err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("fails if invalid YAML exists in the input payload", async () => {
|
||||
mocks.core.getInput.withArgs("payload-file-path").returns("example.yaml");
|
||||
mocks.fs.readFileSync
|
||||
.withArgs(path.resolve("example.yaml"), "utf-8")
|
||||
.returns(`- "message": "assigned": "values"`);
|
||||
try {
|
||||
await send(mocks.core);
|
||||
assert.fail("Failed to throw for invalid YAML");
|
||||
} catch (err) {
|
||||
if (err instanceof SlackError) {
|
||||
assert.include(
|
||||
err.message,
|
||||
"Invalid input! Failed to parse contents of the provided payload file",
|
||||
);
|
||||
assert.isDefined(err.cause?.values);
|
||||
assert.equal(err.cause.values.length, 1);
|
||||
assert.isTrue(err.cause.values[0] instanceof YAMLException);
|
||||
} else {
|
||||
assert.fail("Failed to throw a SlackError", err);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user