feat: include an 'api' option to customize the slack api method url (#409)
This commit is contained in:
@@ -452,6 +452,26 @@ Behind the scenes, [automatic retries][retries] are handled with the
|
||||
[`@slack/web-api`][slack-web-api] package for Slack API methods, and
|
||||
[`axios-retry`][axios-retry] when sending with a webhook.
|
||||
|
||||
### Sending to a custom API URL
|
||||
|
||||
In certain circumstances, such as testing the sent payload, a
|
||||
[custom API URL][custom-api-url] can be used to change where `method` requests
|
||||
are sent:
|
||||
|
||||
```yaml
|
||||
- name: Send to a custom API URL
|
||||
uses: slackapi/[email protected]
|
||||
with:
|
||||
api: http://localhost:8080
|
||||
method: chat.postMessage
|
||||
token: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
payload: |
|
||||
channel: ${{ secrets.SLACK_CHANNEL_ID }}
|
||||
text: "What's happening on localhost?"
|
||||
```
|
||||
|
||||
The default value of `api` is "https://slack.com/api/" for steps using `method`.
|
||||
|
||||
## Expected outputs
|
||||
|
||||
Each technique above [outputs values][github-outputs] that can be used as inputs
|
||||
@@ -517,6 +537,7 @@ All contributions are encouraged! Check out the
|
||||
[config-tokens]: https://api.slack.com/reference/manifests#config-tokens
|
||||
[contributing]: .github/contributing.md
|
||||
[conversation]: https://api.slack.com/types/conversation
|
||||
[custom-api-url]: https://tools.slack.dev/node-slack-sdk/web-api/#custom-api-url
|
||||
[epoch]: https://en.wikipedia.org/wiki/Unix_time
|
||||
[event-context]: https://github.com/actions/toolkit/blob/main/packages/github/src/context.ts#L6
|
||||
[event-payload]: https://docs.github.com/en/webhooks/webhook-events-and-payloads
|
||||
|
||||
@@ -2,6 +2,9 @@ name: "Slack: Send to Slack"
|
||||
author: "slackapi"
|
||||
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"
|
||||
inputs:
|
||||
api:
|
||||
description: "A custom API URL to send Slack API method requests to."
|
||||
required: false
|
||||
errors:
|
||||
default: "false"
|
||||
description: "If the step exits with an error on errors or continues."
|
||||
|
||||
@@ -26,6 +26,7 @@ export default class Client {
|
||||
agent: this.proxies(config)?.httpsAgent,
|
||||
logger: config.logger,
|
||||
retryConfig: this.retries(config.inputs.retries),
|
||||
slackApiUrl: config.inputs.api || undefined,
|
||||
});
|
||||
try {
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,7 @@ export default class Config {
|
||||
|
||||
/**
|
||||
* @typedef Inputs - Values provided to this job.
|
||||
* @property {string?} api - A custom API URL to send method requests to.
|
||||
* @property {boolean} errors - If the job should exit after errors or succeed.
|
||||
* @property {string?} method - The Slack API method to call.
|
||||
* @property {string?} payload - Request contents from the provided input.
|
||||
@@ -101,6 +102,7 @@ export default class Config {
|
||||
this.logger = new Logger(core).logger;
|
||||
this.webapi = webapi;
|
||||
this.inputs = {
|
||||
api: core.getInput("api"),
|
||||
errors: core.getBooleanInput("errors"),
|
||||
method: core.getInput("method"),
|
||||
payload: core.getInput("payload"),
|
||||
|
||||
+15
-13
@@ -73,6 +73,7 @@ describe("client", () => {
|
||||
core: core,
|
||||
logger: new Logger(core).logger,
|
||||
inputs: {
|
||||
api: "http://localhost:8080/api",
|
||||
method: "pins.add",
|
||||
retries: "10",
|
||||
token: "xoxb-example-002",
|
||||
@@ -86,6 +87,7 @@ describe("client", () => {
|
||||
agent: undefined,
|
||||
logger: config.logger,
|
||||
retryConfig: webapi.retryPolicies.tenRetriesInAboutThirtyMinutes,
|
||||
slackApiUrl: "http://localhost:8080/api",
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -110,10 +112,10 @@ describe("client", () => {
|
||||
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
|
||||
mocks.core.getInput.withArgs("token").returns("xoxb-example");
|
||||
mocks.core.getInput.withArgs("payload").returns(JSON.stringify(args));
|
||||
mocks.api.resolves(response);
|
||||
mocks.calls.resolves(response);
|
||||
await send(mocks.core);
|
||||
assert.deepEqual(mocks.api.getCall(0).firstArg, "chat.postMessage");
|
||||
assert.deepEqual(mocks.api.getCall(0).lastArg, args);
|
||||
assert.deepEqual(mocks.calls.getCall(0).firstArg, "chat.postMessage");
|
||||
assert.deepEqual(mocks.calls.getCall(0).lastArg, args);
|
||||
assert.equal(mocks.core.setOutput.getCall(0).firstArg, "ok");
|
||||
assert.equal(mocks.core.setOutput.getCall(0).lastArg, true);
|
||||
assert.equal(mocks.core.setOutput.getCall(1).firstArg, "response");
|
||||
@@ -158,10 +160,10 @@ describe("client", () => {
|
||||
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
|
||||
mocks.core.getInput.withArgs("token").returns("xoxb-example");
|
||||
mocks.core.getInput.withArgs("payload").returns(JSON.stringify(args));
|
||||
mocks.api.resolves(response);
|
||||
mocks.calls.resolves(response);
|
||||
await send(mocks.core);
|
||||
assert.deepEqual(mocks.api.getCall(0).firstArg, "chat.postMessage");
|
||||
assert.deepEqual(mocks.api.getCall(0).lastArg, args);
|
||||
assert.deepEqual(mocks.calls.getCall(0).firstArg, "chat.postMessage");
|
||||
assert.deepEqual(mocks.calls.getCall(0).lastArg, args);
|
||||
assert.equal(mocks.core.setOutput.getCall(0).firstArg, "ok");
|
||||
assert.equal(mocks.core.setOutput.getCall(0).lastArg, true);
|
||||
assert.equal(mocks.core.setOutput.getCall(1).firstArg, "response");
|
||||
@@ -194,9 +196,9 @@ describe("client", () => {
|
||||
mocks.core.getInput.withArgs("method").returns("files.uploadV2");
|
||||
mocks.core.getInput.withArgs("token").returns("xoxp-example");
|
||||
mocks.core.getInput.withArgs("payload").returns(JSON.stringify(args));
|
||||
mocks.api.resolves(response);
|
||||
mocks.calls.resolves(response);
|
||||
await send(mocks.core);
|
||||
assert.deepEqual(mocks.api.getCall(0).lastArg, args);
|
||||
assert.deepEqual(mocks.calls.getCall(0).lastArg, args);
|
||||
assert.equal(mocks.core.setOutput.getCall(0).firstArg, "ok");
|
||||
assert.equal(mocks.core.setOutput.getCall(0).lastArg, true);
|
||||
assert.equal(mocks.core.setOutput.getCall(1).firstArg, "response");
|
||||
@@ -231,7 +233,7 @@ describe("client", () => {
|
||||
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
|
||||
mocks.core.getInput.withArgs("token").returns("xoxb-example");
|
||||
mocks.core.getInput.withArgs("payload").returns(`"text": "hello"`);
|
||||
mocks.api.rejects(errors.requestErrorWithOriginal(response, true));
|
||||
mocks.calls.rejects(errors.requestErrorWithOriginal(response, true));
|
||||
await send(mocks.core);
|
||||
assert.fail("Expected an error but none was found");
|
||||
} catch (error) {
|
||||
@@ -266,7 +268,7 @@ describe("client", () => {
|
||||
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
|
||||
mocks.core.getInput.withArgs("token").returns("xoxb-example");
|
||||
mocks.core.getInput.withArgs("payload").returns(`"text": "hello"`);
|
||||
mocks.api.rejects(errors.httpErrorFromResponse(response));
|
||||
mocks.calls.rejects(errors.httpErrorFromResponse(response));
|
||||
await send(mocks.core);
|
||||
assert.fail("Expected an error but none was found");
|
||||
} catch (error) {
|
||||
@@ -302,7 +304,7 @@ describe("client", () => {
|
||||
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
|
||||
mocks.core.getInput.withArgs("token").returns("xoxb-example");
|
||||
mocks.core.getInput.withArgs("payload").returns(`"text": "hello"`);
|
||||
mocks.api.rejects(errors.platformErrorFromResult(response));
|
||||
mocks.calls.rejects(errors.platformErrorFromResult(response));
|
||||
await send(mocks.core);
|
||||
assert.fail("Expected an error but none was found");
|
||||
} catch (error) {
|
||||
@@ -331,7 +333,7 @@ describe("client", () => {
|
||||
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
|
||||
mocks.core.getInput.withArgs("token").returns("xoxb-example");
|
||||
mocks.core.getInput.withArgs("payload").returns(`"text": "hello"`);
|
||||
mocks.api.rejects(errors.platformErrorFromResult(response));
|
||||
mocks.calls.rejects(errors.platformErrorFromResult(response));
|
||||
await send(mocks.core);
|
||||
assert.fail("Expected an error but none was found");
|
||||
} catch (error) {
|
||||
@@ -357,7 +359,7 @@ describe("client", () => {
|
||||
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
|
||||
mocks.core.getInput.withArgs("token").returns("xoxb-example");
|
||||
mocks.core.getInput.withArgs("payload").returns(`"text": "hello"`);
|
||||
mocks.api.rejects(errors.rateLimitedErrorWithDelay(12));
|
||||
mocks.calls.rejects(errors.rateLimitedErrorWithDelay(12));
|
||||
await send(mocks.core);
|
||||
assert.fail("Expected an error but none was found");
|
||||
} catch (error) {
|
||||
|
||||
@@ -19,6 +19,7 @@ describe("config", () => {
|
||||
|
||||
describe("inputs", () => {
|
||||
it("valid values are collected from the action inputs", async () => {
|
||||
mocks.core.getInput.withArgs("api").returns("http://localhost:8080");
|
||||
mocks.core.getBooleanInput.withArgs("errors").returns(true);
|
||||
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
|
||||
mocks.core.getInput.withArgs("payload").returns('"hello": "world"');
|
||||
@@ -26,6 +27,7 @@ describe("config", () => {
|
||||
mocks.core.getInput.withArgs("retries").returns("0");
|
||||
mocks.core.getInput.withArgs("token").returns("xoxb-example");
|
||||
const config = new Config(mocks.core);
|
||||
assert.equal(config.inputs.api, "http://localhost:8080");
|
||||
assert.equal(config.inputs.errors, true);
|
||||
assert.equal(config.inputs.method, "chat.postMessage");
|
||||
assert.equal(config.inputs.payload, '"hello": "world"');
|
||||
|
||||
+2
-2
@@ -43,8 +43,8 @@ export class Mock {
|
||||
*/
|
||||
constructor() {
|
||||
this.sandbox = sinon.createSandbox();
|
||||
this.api = sinon.stub(webapi.WebClient.prototype, "apiCall");
|
||||
this.axios = this.sandbox.stub(axios);
|
||||
this.calls = sinon.stub(webapi.WebClient.prototype, "apiCall");
|
||||
this.core = this.sandbox.stub(core);
|
||||
this.fs = this.sandbox.stub(fs);
|
||||
this.webapi = {
|
||||
@@ -63,8 +63,8 @@ export class Mock {
|
||||
*/
|
||||
reset() {
|
||||
this.sandbox.reset();
|
||||
this.api.resetHistory();
|
||||
this.axios.post.resetHistory();
|
||||
this.calls.resetHistory();
|
||||
this.core.getInput.reset();
|
||||
this.core.getInput.withArgs("errors").returns("false");
|
||||
this.core.getInput.withArgs("retries").returns("5");
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ describe("send", () => {
|
||||
|
||||
it("token", async () => {
|
||||
process.env.SLACK_WEBHOOK_URL = "https://example.com"; // https://github.com/slackapi/slack-github-action/issues/373
|
||||
mocks.api.resolves({ ok: true });
|
||||
mocks.calls.resolves({ ok: true });
|
||||
mocks.core.getInput.withArgs("method").returns("chat.postMessage");
|
||||
mocks.core.getInput.withArgs("token").returns("xoxb-example");
|
||||
mocks.core.getInput.withArgs("payload").returns('"text": "hello"');
|
||||
|
||||
Reference in New Issue
Block a user