-
Notifications
You must be signed in to change notification settings - Fork 381
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create Slack integration for Google Cloud Build
Posts notifications to a Slack channel whenever a Google Cloud Build completes.
- Loading branch information
Showing
8 changed files
with
838 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# This file specifies files that are *not* uploaded to Google Cloud Platform | ||
# using gcloud. It follows the same syntax as .gitignore, with the addition of | ||
# "#!include" directives (which insert the entries of the given .gitignore-style | ||
# file at that point). | ||
# | ||
# For more information, run: | ||
# $ gcloud topic gcloudignore | ||
# | ||
.gcloudignore | ||
# If you would like to upload your .git directory, .gitignore file or files | ||
# from your .gitignore file, remove the corresponding line | ||
# below: | ||
.git | ||
.gitignore | ||
|
||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Slack Notifications for Google Cloud Build | ||
|
||
> This is not an officially supported Google product. | ||
This Google Cloud Function sends a notification to a Slack channel whenever a | ||
Google Cloud Build completes. | ||
|
||
![Success notification](success.png) | ||
![Failure notification](failure.png) | ||
|
||
## Installation | ||
|
||
### Create a Slack Webhook | ||
|
||
Follow | ||
[Slack's "Getting Started with Incoming Webhooks" instructions](https://api.slack.com/messaging/webhooks) | ||
to create a Slack app and incoming webhook URL. This URL will be required in the | ||
next installation step. | ||
|
||
### Deploy Google Cloud Function | ||
|
||
If you don't already have a Google Cloud project, [create one now](https://cloud.google.com/resource-manager/docs/creating-managing-projects). Ensure that you have the [Google Cloud SDK](https://cloud.google.com/sdk/) installed as well. | ||
|
||
Run the following command to deploy this Google Cloud Function, after changing | ||
`$PROJECT` to your | ||
[Google Cloud project ID](https://cloud.google.com/resource-manager/docs/creating-managing-projects#identifying_projects) | ||
and `$SLACK_WEBHOOK_URL` to the webhook URL you created in the previous | ||
installation step. You may also customise `$FUNC_NAME` and `$STAGE_BUCKET`. | ||
|
||
```shell | ||
# Required parameters | ||
$ PROJECT="YOUR-GOOGLE-CLOUD-PROJECT-ID" | ||
$ SLACK_WEBHOOK_URL="YOUR-SLACK-WEBHOOK-URL" | ||
# Customisable parameters | ||
$ FUNC_NAME="cloudbuild2slack" | ||
$ STAGE_BUCKET="${PROJECT}-cloudbuild2slack" | ||
|
||
$ gcloud --project="${PROJECT}" functions deploy "${FUNC_NAME}" \ | ||
--stage-bucket="${STAGE_BUCKET}" \ | ||
--trigger-topic="cloud-builds" \ | ||
--runtime="nodejs10" \ | ||
--set-env-vars="SLACK_WEBHOOK_URL=${SLACK_WEBHOOK_URL}" | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
const { | ||
IncomingWebhook | ||
} = require('@slack/webhook'); | ||
|
||
const { | ||
auth | ||
} = require('google-auth-library'); | ||
|
||
const webhook = new IncomingWebhook(process.env.SLACK_WEBHOOK_URL); | ||
|
||
// Add additional statues to list if you'd like: | ||
// QUEUED, WORKING, CANCELLED | ||
const interestingStatuses = ['SUCCESS', 'FAILURE', 'INTERNAL_ERROR', 'TIMEOUT']; | ||
|
||
// cloudbuildToSlack reads from a Google Cloud Build Pub/Sub topic and writes | ||
// to a Slack webhook. | ||
module.exports.cloudbuildToSlack = async (pubSubEvent, context) => { | ||
if (!pubSubEvent.data) { | ||
console.info("No `data` field in pubSubEvent"); | ||
return; | ||
} | ||
const build = eventToBuild(pubSubEvent.data); | ||
|
||
// Skip if the current status is not in the status list. | ||
if (interestingStatuses.indexOf(build.status) === -1) { | ||
console.log("Build status %s is ignored", build.status); | ||
return; | ||
} | ||
|
||
// Send message to Slack. | ||
const message = await createSlackMessage(build); | ||
await webhook.send(message); | ||
}; | ||
|
||
// eventToBuild transforms pubsub event message to a build object. | ||
const eventToBuild = (data) => { | ||
return JSON.parse(Buffer.from(data, 'base64').toString()); | ||
} | ||
|
||
const getTrigger = async (triggerId) => { | ||
const client = await auth.getClient({ | ||
scopes: 'https://www.googleapis.com/auth/cloud-platform', | ||
}); | ||
const projectId = await auth.getProjectId(); | ||
const res = await client.request({ | ||
url: `https://cloudbuild.googleapis.com/v1/projects/${projectId}/triggers/${triggerId}`, | ||
}); | ||
return res.data; | ||
} | ||
|
||
// createSlackMessage creates a message from a build object. | ||
const createSlackMessage = async (build) => { | ||
const buildStatus = build.statusDetail || build.status; | ||
const trigger = await getTrigger(build.buildTriggerId); | ||
|
||
let { | ||
REPO_NAME: repo, | ||
BRANCH_NAME: branch, | ||
} = build.substitutions; | ||
|
||
// If there was no substitution containing the repository name, | ||
// take it from build.source. Unfortunately, this name will be the name | ||
// used by Google Cloud Source Repositories, not the name on GitHub. | ||
if (!repo && build.source.repoSource) { | ||
repo = build.source.repoSource.repoName; | ||
} | ||
|
||
let messagePrefix, color; | ||
switch (build.status) { | ||
case 'TIMEOUT': | ||
messagePrefix = "Timeout of "; | ||
color = 'danger'; | ||
break; | ||
case 'FAILURE': | ||
messagePrefix = "Failed to "; | ||
color = 'danger'; | ||
break; | ||
case 'INTERNAL_ERROR': | ||
messagePrefix = "Internal error while trying to "; | ||
color = 'warning'; | ||
break; | ||
case 'SUCCESS': | ||
messagePrefix = "Completed "; | ||
color = 'good'; | ||
break; | ||
} | ||
|
||
let message = { | ||
text: `${messagePrefix}'${trigger.description}' for ${repo} repo`, | ||
attachments: [{ | ||
fallback: buildStatus, | ||
color: color, | ||
fields: [{ | ||
title: 'Status', | ||
value: buildStatus, | ||
short: true, | ||
}, { | ||
title: 'Build Logs', | ||
value: build.logUrl, | ||
}], | ||
}], | ||
}; | ||
|
||
if (branch) { | ||
message.attachments[0].fields.push({ | ||
title: 'Branch', | ||
value: branch, | ||
}) | ||
} | ||
|
||
return message | ||
} |
Oops, something went wrong.