Nicolas Garnier
8 years ago
5 changed files with 95 additions and 38 deletions
@ -0,0 +1,37 @@ |
|||
# Post GitHUb commits to Slack channel. |
|||
|
|||
This sample shows how to automatically post GitHub commits to a Slack channel using an HTTPS Cloud Function. |
|||
|
|||
Further reading: |
|||
- Slack Webhooks API: https://api.slack.com/incoming-webhooks |
|||
- Firebase SDK: https://firebase.google.com/docs/functions |
|||
- GitHUb Webhooks: https://developer.github.com/webhooks/creating/ |
|||
|
|||
## Functions Code |
|||
|
|||
See file [functions/index.js](functions/index.js) for the code. |
|||
|
|||
Handling the Google Actions requests is done using the [Google Actions SDK](https://www.npmjs.com/package/actions-on-google). |
|||
|
|||
The dependencies are listed in [functions/package.json](functions/package.json). |
|||
|
|||
|
|||
## Deploy and test |
|||
|
|||
To test this sample action: |
|||
|
|||
- Create a Firebase Project using the [Firebase Developer Console](https://console.firebase.google.com) |
|||
- Configure this sample to use your project using `firebase --use add` and select your project. |
|||
- [Add a WebHook to your GitHub repo](https://help.github.com/articles/about-webhooks/) with the following settings: |
|||
- Payload URL: `https://us-central1-<FIREBASE_PROJECT_ID>.cloudfunctions.net/githubWebhook` |
|||
- Content type: `application/json` |
|||
- Secret: `A_SECRET_YOU_DEFINE` |
|||
- Which events would you like to trigger this webhook? `Just the push event.` |
|||
- [Add an **Incomming Webhook**](https://my.slack.com/services/new/incoming-webhook/) to your Slack channel and take note of the **Webhook URL**. |
|||
- Set the `slack.webhook_url` and `github.secret` Google Cloud environment variables to match the email and password of the Gmail account used to send emails. For this use: |
|||
```bash |
|||
firebase functions:config:set slack.webhook_url="https://hooks.slack.com/services/..." github.secret="A_SECRET_YOU_DEFINED_WHEN_SETTING_UP_THE_GITHUB_WEBHOOK" |
|||
``` |
|||
- Deploy your project using `firebase deploy` |
|||
- Make your action available for testing using the `gactions preview action.json` |
|||
- Test your Action on the [Google Home Web Simulator](https://g.co/actionswebsim) by saying "Talk to My Action" |
@ -0,0 +1 @@ |
|||
{} |
@ -1,48 +1,64 @@ |
|||
const pubsub = require('@google-cloud/pubsub')(functions.config().firebase); |
|||
const githubTopic = functions.config().github.topic; |
|||
/** |
|||
* Copyright 2016 Google Inc. All Rights Reserved. |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
'use strict'; |
|||
|
|||
const functions = require('firebase-functions'); |
|||
const rp = require('request-promise'); |
|||
const crypto = require('crypto'); |
|||
|
|||
exports.githubWebhook = functions.https.onRequest((request, response) => { |
|||
/** |
|||
* Webhook that will be called each time there is a new GitHub commit and will post a message to |
|||
* Slack. |
|||
*/ |
|||
exports.githubWebhook = functions.https.onRequest((req, res) => { |
|||
const cipher = 'sha1'; |
|||
const signature = request.headers['x-hub-signature']; |
|||
const hmac = require('crypto') |
|||
.createHmac(cipher, functions.config().github.secret) |
|||
.update(JSON.stringify(request.body, null, 2)) |
|||
.digest('hex'); |
|||
const signature = req.headers['x-hub-signature']; |
|||
|
|||
// TODO: Configure the `github.secret` Google Cloud environment variables.
|
|||
const hmac = crypto.createHmac(cipher, functions.config().github.secret) |
|||
// The JSON body is automatically parsed by Cloud Functions so we re-stringify it.
|
|||
.update(JSON.stringify(req.body, null, 0)) |
|||
.digest('hex'); |
|||
const expectedSignature = `${cipher}=${hmac}`; |
|||
|
|||
// Skipping verification, since JSON.stringify fails hmac, need the raw post
|
|||
if (true || signature === expectedSignature) { |
|||
pubsub.topic(githubTopic).publish( |
|||
request.body, |
|||
(err, messageIds, apiResponse) => { |
|||
if (err) { |
|||
console.error(err); |
|||
response.status(500).send('Something went wrong.'); |
|||
} else { |
|||
response.status(200).send(''); |
|||
} |
|||
} |
|||
); |
|||
// Check that the body of the request has been signed with the GitHub Secret.
|
|||
if (signature === expectedSignature) { |
|||
postToSlack(req.body.compare, req.body.commits.length, req.body.repository).then(() => { |
|||
res.end(); |
|||
}).catch(error => { |
|||
console.error(error); |
|||
res.status(500).send('Something went wrong while posting the message to Slack.'); |
|||
}); |
|||
} else { |
|||
console.error(`x-hub-signature ${signature} did not match ${expectedSignature}`); |
|||
response.status(403).send('Your x-hub-signature\'s bad and you should feel bad!'); |
|||
console.error('x-hub-signature', signature, 'did not match', expectedSignature); |
|||
res.status(403).send('Your x-hub-signature\'s bad and you should feel bad!'); |
|||
} |
|||
}); |
|||
|
|||
|
|||
exports.githubAnnouncer = functions.pubsub.topic(githubTopic).onPublish(event => { |
|||
const payload = JSON.parse(event.data.json.payload); |
|||
if (payload.ref === null) { return null; } |
|||
const commits = payload.commits.length; |
|||
const repo = payload.repository; |
|||
const url = payload.compare; |
|||
/** |
|||
* Post a message to Slack about the new GitHub commit. |
|||
*/ |
|||
function postToSlack(url, commits, repo) { |
|||
return rp({ |
|||
method: 'POST', |
|||
uri: functions.config().slack.webhookurl, |
|||
// TODO: Configure the `slack.webhook_url` Google Cloud environment variables.
|
|||
uri: functions.config().slack.webhook_url, |
|||
body: { |
|||
text: `<${url}|${commits} new commit${commits > 1 ? 's' : ''}> pushed to <${repo.url}|${repo.name}>.` |
|||
text: `<${url}|${commits} new commit${commits > 1 ? 's' : ''}> pushed to <${repo.url}|${repo.full_name}>.` |
|||
}, |
|||
json: true |
|||
}); |
|||
}); |
|||
} |
|||
|
Loading…
Reference in new issue