Skip to content

Commit

Permalink
Polishing, simplifying and Adding README to the GitHub to Slack sample
Browse files Browse the repository at this point in the history
Change-Id: I5b935399391ead5d125b69a592344471f61523b7
  • Loading branch information
Nicolas Garnier committed Mar 7, 2017
1 parent 5440151 commit 859841f
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 38 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ Uses a Firebase Storage trigger.
Demonstrates how to automatically generate a thumbnail for images that are uploaded to Firebase Storage.
Uses a Firebase Storage trigger.

### [Post GitHUb commits to Slack channel](/github-to-slack)

Demonstrates hows how to automatically post GitHub commits to a Slack channel using an HTTPS triggered Function.

### [Automatically Moderate Images](/moderate-images)

Demonstrates how to automatically moderate offensive images that are uploaded to Firebase Storage by using the Google Cloud Vision API to detect offensive images and ImageMagick to blur these images.
Expand Down
37 changes: 37 additions & 0 deletions github-to-slack/README.md
Original file line number Diff line number Diff line change
@@ -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"
1 change: 1 addition & 0 deletions github-to-slack/firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
82 changes: 49 additions & 33 deletions github-to-slack/functions/index.js
Original file line number Diff line number Diff line change
@@ -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
});
});
}
9 changes: 4 additions & 5 deletions github-to-slack/functions/package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
{
"name": "functions",
"description": "Firebase Functions",
"name": "github-to-slack-functions",
"description": "Firebase Functions that posts new GitHub commits to a Slack channel.",
"dependencies": {
"@google-cloud/pubsub": "^0.8.2",
"firebase-admin": "^4.0.5",
"crypto": "0.0.3",
"firebase-admin": "^4.1.2",
"firebase-functions": "https://storage.googleapis.com/firebase-preview-drop/node/firebase-functions/firebase-functions-preview.latest.tar.gz",
"request": "^2.80.0",
"request-promise": "^4.1.1"
}
}

0 comments on commit 859841f

Please sign in to comment.