Update webhook example to use newer Slack app integration
MODIFY
aws-ts-pulumi-webhooks/Pulumi.yaml
aws-ts-pulumi-webhooks/Pulumi.yaml
name: aws-ts-pulumi-webhooks
runtime: nodejs
description: Lambda app that handles Pulumi webhook notifications.
+template:
+ config:
+ aws:region:
+ description: The AWS region to deploy into
+ default: us-east-2
+ aws-ts-pulumi-webhooks:slackChannel:
+ description: Channel to post messages into
+ aws-ts-pulumi-webhooks:slackWebhook:
+ description: Webhook URL from the Slack app
+ secret: true

MODIFY
aws-ts-pulumi-webhooks/README.md
aws-ts-pulumi-webhooks/README.md
@@ -28,7 +28,7 @@ After cloning this repo, run these commands from the working directory:
1. Create a [Slack App](https://api.slack.com/apps):
- - Give your app the [`chat:write`](https://api.slack.com/scopes/chat:write) scope by going to `Features -> OAuth & Permissions -> Scopes` from your Slack app's API page.
+ - Give your app the [`incoming-webhook`](https://api.slack.com/scopes/incoming-webhook) scope.
- Add your Slack app to the Slack channel in which you want to post webhook events.
@@ -38,10 +38,10 @@ After cloning this repo, run these commands from the working directory:
pulumi config set aws:region <your-region>
```
-1. Set the Slack token for your app. You can find yours by going to `Features -> OAuth & Permissions -> OAuth Tokens & Redirect URLs -> Tokens for Your Workspace` from your Slack app's API page.
+1. Set the Slack webhook for your app. You can find yours by going to `Features -> Incoming Webhooks` from your Slack app's API page.
```bash
- pulumi config set slackToken --secret <your-token>
+ pulumi config set slackWebhook --secret <webhook-url>
```
1. Set the Slack channel for your app. This should be the same channel in which you added your Slack app. For example, `#pulumi-events`.

MODIFY
aws-ts-pulumi-webhooks/index.ts
aws-ts-pulumi-webhooks/index.ts
import * as awsx from "@pulumi/awsx";
import * as pulumi from "@pulumi/pulumi";
-import { ChatPostMessageArguments, WebClient } from "@slack/web-api";
+import { IncomingWebhook, IncomingWebhookSendArguments } from "@slack/webhook";
import * as crypto from "crypto";
@@ -15,7 +15,7 @@ const stackConfig = {
// webhook's settings.
sharedSecret: config.get("sharedSecret"),
- slackToken: config.require("slackToken"),
+ slackWebhook: config.requireSecret("slackWebhook"),
slackChannel: config.require("slackChannel"),
};
@@ -47,6 +47,9 @@ function authenticateRequest(req: awsx.apigateway.Request): awsx.apigateway.Resp
return undefined;
}
+// unsecret the webhook so we can add it to the handler
+(<any>stackConfig.slackWebhook).isSecret = false;
+
const webhookHandler = new awsx.apigateway.API("pulumi-webhook-handler", {
restApiArgs: {
binaryMediaTypes: ["application/json"],
@@ -74,19 +77,18 @@ const webhookHandler = new awsx.apigateway.API("pulumi-webhook-handler", {
const parsedPayload = JSON.parse(payload);
const prettyPrintedPayload = JSON.stringify(parsedPayload, null, 2);
- const client = new WebClient(stackConfig.slackToken);
+ const webhook = new IncomingWebhook(stackConfig.slackWebhook.get());
const fallbackText = `Pulumi Service Webhook (\`${webhookKind}\`)\n` + "```\n" + prettyPrintedPayload + "```\n";
- const messageArgs: ChatPostMessageArguments = {
+ const messageArgs: IncomingWebhookSendArguments = {
channel: stackConfig.slackChannel,
text: fallbackText,
- as_user: true,
};
// Format the Slack message based on the kind of webhook received.
const formattedMessageArgs = formatSlackMessage(webhookKind, parsedPayload, messageArgs);
- await client.chat.postMessage(formattedMessageArgs);
+ await webhook.send(formattedMessageArgs);
return { statusCode: 200, body: `posted to Slack channel ${stackConfig.slackChannel}\n` };
},
}],

MODIFY
aws-ts-pulumi-webhooks/package.json
aws-ts-pulumi-webhooks/package.json
"@types/node": "^8.0.0"
},
"dependencies": {
- "@pulumi/pulumi": "^2.0.0",
"@pulumi/aws": "^3.0.0",
- "@pulumi/awsx": "^0.20.0",
- "@slack/web-api": "latest"
+ "@pulumi/awsx": "^0.22.0",
+ "@pulumi/pulumi": "^2.0.0",
+ "@slack/webhook": "^5.0.3"
}
}

MODIFY
aws-ts-pulumi-webhooks/util.ts
aws-ts-pulumi-webhooks/util.ts
// Copyright 2016-2019, Pulumi Corporation. All rights reserved.
-import { ChatPostMessageArguments } from "@slack/web-api";
+import { IncomingWebhookSendArguments } from "@slack/webhook";
// Return a formatted copy of the Slack message object, based on the kind of Pulumi webhook received.
// See the Pulumi and Slack webhook documentation for details.
// https://www.pulumi.com/docs/intro/console/extensions/webhooks/
// https://api.slack.com/docs/message-attachments
-export function formatSlackMessage(kind: string, payload: object, messageArgs: ChatPostMessageArguments): ChatPostMessageArguments {
- const cloned: ChatPostMessageArguments = Object.assign({}, messageArgs) as ChatPostMessageArguments;
+export function formatSlackMessage(kind: string, payload: object, messageArgs: IncomingWebhookSendArguments): IncomingWebhookSendArguments {
+ const cloned: IncomingWebhookSendArguments = Object.assign({}, messageArgs) as IncomingWebhookSendArguments;
switch (kind) {
case "stack":
@@ -24,7 +24,7 @@ export function formatSlackMessage(kind: string, payload: object, messageArgs: C
}
}
-function formatStack(payload: any, args: ChatPostMessageArguments): ChatPostMessageArguments {
+function formatStack(payload: any, args: IncomingWebhookSendArguments): IncomingWebhookSendArguments {
const summary = `${payload.organization.githubLogin}/${payload.projectName}/${payload.stackName} ${payload.action}.`;
args.text = summary;
args.attachments = [
@@ -47,7 +47,7 @@ function formatStack(payload: any, args: ChatPostMessageArguments): ChatPostMess
return args;
}
-function formatTeam(payload: any, args: ChatPostMessageArguments): ChatPostMessageArguments {
+function formatTeam(payload: any, args: IncomingWebhookSendArguments): IncomingWebhookSendArguments {
const summary = `${payload.organization.githubLogin} team ${payload.action}.`;
args.text = summary;
args.attachments = [
@@ -90,7 +90,7 @@ function formatTeam(payload: any, args: ChatPostMessageArguments): ChatPostMessa
return args;
}
-function formatUpdate(kind: "stack_preview" | "stack_update", payload: any, args: ChatPostMessageArguments): ChatPostMessageArguments {
+function formatUpdate(kind: "stack_preview" | "stack_update", payload: any, args: IncomingWebhookSendArguments): IncomingWebhookSendArguments {
const summary = `${payload.organization.githubLogin}/${payload.projectName}/${payload.stackName} ${payload.kind} ${payload.result}.`;
args.text = `${resultEmoji(payload.result)} ${summary}`;
args.attachments = [
@@ -131,7 +131,7 @@ function formatUpdate(kind: "stack_preview" | "stack_update", payload: any, args
return args;
}
-function formatPing(payload: any, args: ChatPostMessageArguments) {
+function formatPing(payload: any, args: IncomingWebhookSendArguments) {
args.text = payload.message;
return args;
}

Update webhook example to use newer Slack app integration (#802)