From cc8c3c9256ab14374c57d852d872873ef7eab5e0 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Wed, 26 Mar 2025 16:42:55 -0700 Subject: [PATCH 1/8] fix: require a custom 'api' url to send to instead of absolute urls as a 'method' --- src/client.js | 1 + test/client.spec.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/client.js b/src/client.js index e476a885..30ed68a1 100644 --- a/src/client.js +++ b/src/client.js @@ -24,6 +24,7 @@ export default class Client { } const client = new config.webapi.WebClient(config.inputs.token, { agent: this.proxies(config)?.httpsAgent, + allowAbsoluteUrls: false, logger: config.logger, retryConfig: this.retries(config.inputs.retries), slackApiUrl: config.inputs.api || undefined, diff --git a/test/client.spec.js b/test/client.spec.js index 58f2dcdb..e4664c58 100644 --- a/test/client.spec.js +++ b/test/client.spec.js @@ -85,6 +85,7 @@ describe("client", () => { assert.isTrue( spy.calledWith("xoxb-example-002", { agent: undefined, + allowAbsoluteUrls: false, logger: config.logger, retryConfig: webapi.retryPolicies.tenRetriesInAboutThirtyMinutes, slackApiUrl: "http://localhost:8080/api", From f4bd26364a025b9033258793d22f6521c8afdaa0 Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 22 Apr 2025 13:07:54 -0700 Subject: [PATCH 2/8] fix: include cause of parsing errors in action output logs --- src/content.js | 7 ++++--- src/errors.js | 7 ++++++- src/index.js | 16 +++++++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/content.js b/src/content.js index 6594a32d..a571a38f 100644 --- a/src/content.js +++ b/src/content.js @@ -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 }, }, ); } diff --git a/src/errors.js b/src/errors.js index b2d4ce0c..3d0d87b1 100644 --- a/src/errors.js +++ b/src/errors.js @@ -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. */ /** diff --git a/src/index.js b/src/index.js index fcdf2277..120af89b 100644 --- a/src/index.js +++ b/src/index.js @@ -6,13 +6,23 @@ 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.startGroup("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 && causes.values) { + for (const cause of causes.values) { + core.info(`${cause.stack}`); + } + } else { + core.info(`${error.stack}`); + } + core.endGroup() } else { core.error(`${error}`); } + throw error; } From cccb0cdc15faf806550fbadd254c2f538fc9707e Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 22 Apr 2025 13:10:07 -0700 Subject: [PATCH 3/8] fix: run the linter for consistent formatting applied --- src/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 120af89b..ae8edfb9 100644 --- a/src/index.js +++ b/src/index.js @@ -9,18 +9,18 @@ try { await send(core); } catch (error) { if (error instanceof Error) { - core.startGroup("Error") + core.startGroup("Error"); core.error(error.message); /** @type {import('./errors.js').Cause} */ const causes = /** @type {any} */ (error.cause); - if (causes && causes.values) { + if (causes?.values) { for (const cause of causes.values) { core.info(`${cause.stack}`); } } else { core.info(`${error.stack}`); } - core.endGroup() + core.endGroup(); } else { core.error(`${error}`); } From 7a98fc3c2078ab83a78a4a7a4a1cdff47e410b3b Mon Sep 17 00:00:00 2001 From: Eden Zimbelman Date: Tue, 22 Apr 2025 13:21:53 -0700 Subject: [PATCH 4/8] feat: remove error groups that hide outputs as a default --- src/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/index.js b/src/index.js index ae8edfb9..ff3b701b 100644 --- a/src/index.js +++ b/src/index.js @@ -9,7 +9,6 @@ try { await send(core); } catch (error) { if (error instanceof Error) { - core.startGroup("Error"); core.error(error.message); /** @type {import('./errors.js').Cause} */ const causes = /** @type {any} */ (error.cause); @@ -20,7 +19,6 @@ try { } else { core.info(`${error.stack}`); } - core.endGroup(); } else { core.error(`${error}`); } From c145b1f3e798472e9593816c10e2fe582c957d3b Mon Sep 17 00:00:00 2001 From: "@zimeg" Date: Wed, 30 Apr 2025 20:30:11 -0700 Subject: [PATCH 5/8] test: confirm input arguments and content are sent to the api --- test/client.spec.js | 84 ++++++++++++++++++++++++++++++++++++++++----- test/index.spec.js | 9 ++++- 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/test/client.spec.js b/test/client.spec.js index e4664c58..d426c808 100644 --- a/test/client.spec.js +++ b/test/client.spec.js @@ -60,37 +60,105 @@ describe("client", () => { } } }); + }); - it("uses input arguments when constructing the web api client", async () => { - const spy = sinon.spy(mocks.webapi, "WebClient"); + describe("api", async () => { + it("uses arguments to send to a slack api method", async () => { + const apis = sinon.stub().resolves({ ok: true }); + const constructors = sinon + .stub(mocks.webapi, "WebClient") + .returns({ apiCall: apis }); /** * @type {Config} */ const config = { content: { - values: {}, + values: { + channel: "CHANNELHERE", + timestamp: "1234567890.000000", + }, }, core: core, logger: new Logger(core).logger, inputs: { - api: "http://localhost:8080/api", method: "pins.add", - retries: "10", token: "xoxb-example-002", }, webapi: mocks.webapi, }; await new Client().post(config); - assert.isTrue(spy.calledWithNew()); + assert.isTrue(constructors.calledWithNew()); + assert.isTrue( + constructors.calledWith("xoxb-example-002", { + agent: undefined, + allowAbsoluteUrls: false, + logger: config.logger, + retryConfig: webapi.retryPolicies.fiveRetriesInFiveMinutes, + slackApiUrl: undefined, + }), + ); + assert.isTrue(apis.calledOnce); + assert.isTrue( + apis.calledWith("pins.add", { + channel: "CHANNELHERE", + timestamp: "1234567890.000000", + }), + ); + assert.isTrue(config.core.setOutput.calledWith("ok", true)); + }); + + it("uses arguments to send to a custom api method", async () => { + const apis = sinon.stub().resolves({ done: true, response: "Infinite" }); + const constructors = sinon + .stub(mocks.webapi, "WebClient") + .returns({ apiCall: apis }); + /** + * @type {Config} + */ + const config = { + content: { + values: { + model: "llama3.2", + prompt: "How many sides does a circle have?", + stream: false, + }, + }, + core: core, + logger: new Logger(core).logger, + inputs: { + api: "http://localhost:11434/api/", + method: "generate", + retries: "10", + token: "ollamapassword", + }, + webapi: mocks.webapi, + }; + await new Client().post(config); + assert.isTrue(constructors.calledWithNew()); assert.isTrue( - spy.calledWith("xoxb-example-002", { + constructors.calledWith("ollamapassword", { agent: undefined, allowAbsoluteUrls: false, logger: config.logger, retryConfig: webapi.retryPolicies.tenRetriesInAboutThirtyMinutes, - slackApiUrl: "http://localhost:8080/api", + slackApiUrl: "http://localhost:11434/api/", + }), + ); + assert.isTrue(apis.calledOnce); + assert.isTrue( + apis.calledWith("generate", { + model: "llama3.2", + prompt: "How many sides does a circle have?", + stream: false, }), ); + assert.isTrue(config.core.setOutput.calledWith("ok", undefined)); + assert.isTrue( + config.core.setOutput.calledWith( + "response", + JSON.stringify({ done: true, response: "Infinite" }), + ), + ); }); }); diff --git a/test/index.spec.js b/test/index.spec.js index 186db60d..e3348b01 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -44,7 +44,7 @@ export class Mock { constructor() { this.sandbox = sinon.createSandbox(); this.axios = this.sandbox.stub(axios); - this.calls = sinon.stub(webapi.WebClient.prototype, "apiCall"); + this.calls = this.sandbox.stub(webapi.WebClient.prototype, "apiCall"); this.core = this.sandbox.stub(core); this.fs = this.sandbox.stub(fs); this.webapi = { @@ -66,6 +66,13 @@ export class Mock { this.axios.post.resetHistory(); this.calls.resetHistory(); this.core.getInput.reset(); + this.webapi = { + WebClient: function () { + this.apiCall = () => ({ + ok: true, + }); + }, + }; this.core.getInput.withArgs("errors").returns("false"); this.core.getInput.withArgs("retries").returns("5"); process.env.SLACK_TOKEN = ""; From b266e08441ec31a93c5cc196d9bf7cc8ea768bbb Mon Sep 17 00:00:00 2001 From: "@zimeg" Date: Wed, 30 Apr 2025 20:34:43 -0700 Subject: [PATCH 6/8] revert: remove unrelated changes that somehow found this branch --- src/errors.js | 7 +------ src/index.js | 14 +++----------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/errors.js b/src/errors.js index 3d0d87b1..b2d4ce0c 100644 --- a/src/errors.js +++ b/src/errors.js @@ -1,17 +1,12 @@ 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 {Cause} [cause] - Reason for an error. + * @property {Error} [cause] - thrown exception of this error. */ /** diff --git a/src/index.js b/src/index.js index ff3b701b..fcdf2277 100644 --- a/src/index.js +++ b/src/index.js @@ -6,21 +6,13 @@ import send from "./send.js"; * from the send.js file for testing purposes. */ try { - await send(core); + send(core); } catch (error) { if (error instanceof Error) { core.error(error.message); - /** @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}`); - } + core.debug(`${error.name} cause: ${error.cause}`); + core.debug(`${error.name} stack: ${error.stack}`); } else { core.error(`${error}`); } - throw error; } From 9c840f0558b71c2a07be8f36f8b68f6463b42e16 Mon Sep 17 00:00:00 2001 From: "@zimeg" Date: Wed, 30 Apr 2025 20:37:59 -0700 Subject: [PATCH 7/8] revert: remove unrelated changes that somehow found this branch --- src/content.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content.js b/src/content.js index a571a38f..5be6ef87 100644 --- a/src/content.js +++ b/src/content.js @@ -55,7 +55,6 @@ 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, @@ -72,7 +71,8 @@ export default class Content { return /** @type {Content} */ (content); } catch (error) { if (error instanceof Error) { - errors.push(error); + config.core.debug("Failed to parse input payload as YAML"); + config.core.debug(error.message); } } try { @@ -95,7 +95,7 @@ export default class Content { config.core, "Invalid input! Failed to parse contents of the provided payload", { - cause: { values: errors }, + cause: error, }, ); } From ced6b72c0d7007dcd5f5904dec70a9864221cb4c Mon Sep 17 00:00:00 2001 From: "@zimeg" Date: Wed, 30 Apr 2025 20:38:43 -0700 Subject: [PATCH 8/8] revert: remove unrelated changes that somehow found this branch --- src/content.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/content.js b/src/content.js index 5be6ef87..6594a32d 100644 --- a/src/content.js +++ b/src/content.js @@ -90,7 +90,6 @@ 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",