Skip to content

Commit f841ea5

Browse files
authored
feat: include an 'api' option to customize the slack api method url (#409)
1 parent 21be76f commit f841ea5

8 files changed

Lines changed: 47 additions & 16 deletions

File tree

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,26 @@ Behind the scenes, [automatic retries][retries] are handled with the
452452
[`@slack/web-api`][slack-web-api] package for Slack API methods, and
453453
[`axios-retry`][axios-retry] when sending with a webhook.
454454

455+
### Sending to a custom API URL
456+
457+
In certain circumstances, such as testing the sent payload, a
458+
[custom API URL][custom-api-url] can be used to change where `method` requests
459+
are sent:
460+
461+
```yaml
462+
- name: Send to a custom API URL
463+
uses: slackapi/slack-github-action@v2.0.0
464+
with:
465+
api: http://localhost:8080
466+
method: chat.postMessage
467+
token: ${{ secrets.SLACK_BOT_TOKEN }}
468+
payload: |
469+
channel: ${{ secrets.SLACK_CHANNEL_ID }}
470+
text: "What's happening on localhost?"
471+
```
472+
473+
The default value of `api` is "https://slack.com/api/" for steps using `method`.
474+
455475
## Expected outputs
456476

457477
Each technique above [outputs values][github-outputs] that can be used as inputs
@@ -517,6 +537,7 @@ All contributions are encouraged! Check out the
517537
[config-tokens]: https://api.slack.com/reference/manifests#config-tokens
518538
[contributing]: .github/contributing.md
519539
[conversation]: https://api.slack.com/types/conversation
540+
[custom-api-url]: https://tools.slack.dev/node-slack-sdk/web-api/#custom-api-url
520541
[epoch]: https://en.wikipedia.org/wiki/Unix_time
521542
[event-context]: https://github.com/actions/toolkit/blob/main/packages/github/src/context.ts#L6
522543
[event-payload]: https://docs.github.com/en/webhooks/webhook-events-and-payloads

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ name: "Slack: Send to Slack"
22
author: "slackapi"
33
description: "Send data to Slack to start a Slack workflow in Workflow Builder, call a Slack API method, or post a message into a channel"
44
inputs:
5+
api:
6+
description: "A custom API URL to send Slack API method requests to."
7+
required: false
58
errors:
69
default: "false"
710
description: "If the step exits with an error on errors or continues."

src/client.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export default class Client {
2626
agent: this.proxies(config)?.httpsAgent,
2727
logger: config.logger,
2828
retryConfig: this.retries(config.inputs.retries),
29+
slackApiUrl: config.inputs.api || undefined,
2930
});
3031
try {
3132
/**

src/config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export default class Config {
4040

4141
/**
4242
* @typedef Inputs - Values provided to this job.
43+
* @property {string?} api - A custom API URL to send method requests to.
4344
* @property {boolean} errors - If the job should exit after errors or succeed.
4445
* @property {string?} method - The Slack API method to call.
4546
* @property {string?} payload - Request contents from the provided input.
@@ -101,6 +102,7 @@ export default class Config {
101102
this.logger = new Logger(core).logger;
102103
this.webapi = webapi;
103104
this.inputs = {
105+
api: core.getInput("api"),
104106
errors: core.getBooleanInput("errors"),
105107
method: core.getInput("method"),
106108
payload: core.getInput("payload"),

test/client.spec.js

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ describe("client", () => {
7373
core: core,
7474
logger: new Logger(core).logger,
7575
inputs: {
76+
api: "http://localhost:8080/api",
7677
method: "pins.add",
7778
retries: "10",
7879
token: "xoxb-example-002",
@@ -86,6 +87,7 @@ describe("client", () => {
8687
agent: undefined,
8788
logger: config.logger,
8889
retryConfig: webapi.retryPolicies.tenRetriesInAboutThirtyMinutes,
90+
slackApiUrl: "http://localhost:8080/api",
8991
}),
9092
);
9193
});
@@ -110,10 +112,10 @@ describe("client", () => {
110112
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
111113
mocks.core.getInput.withArgs("token").returns("xoxb-example");
112114
mocks.core.getInput.withArgs("payload").returns(JSON.stringify(args));
113-
mocks.api.resolves(response);
115+
mocks.calls.resolves(response);
114116
await send(mocks.core);
115-
assert.deepEqual(mocks.api.getCall(0).firstArg, "chat.postMessage");
116-
assert.deepEqual(mocks.api.getCall(0).lastArg, args);
117+
assert.deepEqual(mocks.calls.getCall(0).firstArg, "chat.postMessage");
118+
assert.deepEqual(mocks.calls.getCall(0).lastArg, args);
117119
assert.equal(mocks.core.setOutput.getCall(0).firstArg, "ok");
118120
assert.equal(mocks.core.setOutput.getCall(0).lastArg, true);
119121
assert.equal(mocks.core.setOutput.getCall(1).firstArg, "response");
@@ -158,10 +160,10 @@ describe("client", () => {
158160
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
159161
mocks.core.getInput.withArgs("token").returns("xoxb-example");
160162
mocks.core.getInput.withArgs("payload").returns(JSON.stringify(args));
161-
mocks.api.resolves(response);
163+
mocks.calls.resolves(response);
162164
await send(mocks.core);
163-
assert.deepEqual(mocks.api.getCall(0).firstArg, "chat.postMessage");
164-
assert.deepEqual(mocks.api.getCall(0).lastArg, args);
165+
assert.deepEqual(mocks.calls.getCall(0).firstArg, "chat.postMessage");
166+
assert.deepEqual(mocks.calls.getCall(0).lastArg, args);
165167
assert.equal(mocks.core.setOutput.getCall(0).firstArg, "ok");
166168
assert.equal(mocks.core.setOutput.getCall(0).lastArg, true);
167169
assert.equal(mocks.core.setOutput.getCall(1).firstArg, "response");
@@ -194,9 +196,9 @@ describe("client", () => {
194196
mocks.core.getInput.withArgs("method").returns("files.uploadV2");
195197
mocks.core.getInput.withArgs("token").returns("xoxp-example");
196198
mocks.core.getInput.withArgs("payload").returns(JSON.stringify(args));
197-
mocks.api.resolves(response);
199+
mocks.calls.resolves(response);
198200
await send(mocks.core);
199-
assert.deepEqual(mocks.api.getCall(0).lastArg, args);
201+
assert.deepEqual(mocks.calls.getCall(0).lastArg, args);
200202
assert.equal(mocks.core.setOutput.getCall(0).firstArg, "ok");
201203
assert.equal(mocks.core.setOutput.getCall(0).lastArg, true);
202204
assert.equal(mocks.core.setOutput.getCall(1).firstArg, "response");
@@ -231,7 +233,7 @@ describe("client", () => {
231233
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
232234
mocks.core.getInput.withArgs("token").returns("xoxb-example");
233235
mocks.core.getInput.withArgs("payload").returns(`"text": "hello"`);
234-
mocks.api.rejects(errors.requestErrorWithOriginal(response, true));
236+
mocks.calls.rejects(errors.requestErrorWithOriginal(response, true));
235237
await send(mocks.core);
236238
assert.fail("Expected an error but none was found");
237239
} catch (error) {
@@ -266,7 +268,7 @@ describe("client", () => {
266268
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
267269
mocks.core.getInput.withArgs("token").returns("xoxb-example");
268270
mocks.core.getInput.withArgs("payload").returns(`"text": "hello"`);
269-
mocks.api.rejects(errors.httpErrorFromResponse(response));
271+
mocks.calls.rejects(errors.httpErrorFromResponse(response));
270272
await send(mocks.core);
271273
assert.fail("Expected an error but none was found");
272274
} catch (error) {
@@ -302,7 +304,7 @@ describe("client", () => {
302304
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
303305
mocks.core.getInput.withArgs("token").returns("xoxb-example");
304306
mocks.core.getInput.withArgs("payload").returns(`"text": "hello"`);
305-
mocks.api.rejects(errors.platformErrorFromResult(response));
307+
mocks.calls.rejects(errors.platformErrorFromResult(response));
306308
await send(mocks.core);
307309
assert.fail("Expected an error but none was found");
308310
} catch (error) {
@@ -331,7 +333,7 @@ describe("client", () => {
331333
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
332334
mocks.core.getInput.withArgs("token").returns("xoxb-example");
333335
mocks.core.getInput.withArgs("payload").returns(`"text": "hello"`);
334-
mocks.api.rejects(errors.platformErrorFromResult(response));
336+
mocks.calls.rejects(errors.platformErrorFromResult(response));
335337
await send(mocks.core);
336338
assert.fail("Expected an error but none was found");
337339
} catch (error) {
@@ -357,7 +359,7 @@ describe("client", () => {
357359
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
358360
mocks.core.getInput.withArgs("token").returns("xoxb-example");
359361
mocks.core.getInput.withArgs("payload").returns(`"text": "hello"`);
360-
mocks.api.rejects(errors.rateLimitedErrorWithDelay(12));
362+
mocks.calls.rejects(errors.rateLimitedErrorWithDelay(12));
361363
await send(mocks.core);
362364
assert.fail("Expected an error but none was found");
363365
} catch (error) {

test/config.spec.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ describe("config", () => {
1919

2020
describe("inputs", () => {
2121
it("valid values are collected from the action inputs", async () => {
22+
mocks.core.getInput.withArgs("api").returns("http://localhost:8080");
2223
mocks.core.getBooleanInput.withArgs("errors").returns(true);
2324
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
2425
mocks.core.getInput.withArgs("payload").returns('"hello": "world"');
2526
mocks.core.getInput.withArgs("proxy").returns("https://example.com");
2627
mocks.core.getInput.withArgs("retries").returns("0");
2728
mocks.core.getInput.withArgs("token").returns("xoxb-example");
2829
const config = new Config(mocks.core);
30+
assert.equal(config.inputs.api, "http://localhost:8080");
2931
assert.equal(config.inputs.errors, true);
3032
assert.equal(config.inputs.method, "chat.postMessage");
3133
assert.equal(config.inputs.payload, '"hello": "world"');

test/index.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ export class Mock {
4343
*/
4444
constructor() {
4545
this.sandbox = sinon.createSandbox();
46-
this.api = sinon.stub(webapi.WebClient.prototype, "apiCall");
4746
this.axios = this.sandbox.stub(axios);
47+
this.calls = sinon.stub(webapi.WebClient.prototype, "apiCall");
4848
this.core = this.sandbox.stub(core);
4949
this.fs = this.sandbox.stub(fs);
5050
this.webapi = {
@@ -63,8 +63,8 @@ export class Mock {
6363
*/
6464
reset() {
6565
this.sandbox.reset();
66-
this.api.resetHistory();
6766
this.axios.post.resetHistory();
67+
this.calls.resetHistory();
6868
this.core.getInput.reset();
6969
this.core.getInput.withArgs("errors").returns("false");
7070
this.core.getInput.withArgs("retries").returns("5");

test/send.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ describe("send", () => {
4040

4141
it("token", async () => {
4242
process.env.SLACK_WEBHOOK_URL = "https://example.com"; // https://github.com/slackapi/slack-github-action/issues/373
43-
mocks.api.resolves({ ok: true });
43+
mocks.calls.resolves({ ok: true });
4444
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
4545
mocks.core.getInput.withArgs("token").returns("xoxb-example");
4646
mocks.core.getInput.withArgs("payload").returns('"text": "hello"');

0 commit comments

Comments
 (0)