├── .npmignore ├── Procfile ├── index.js ├── .github └── CODEOWNERS ├── .gitignore ├── .travis.yml ├── images ├── avatar.png ├── badge-blue-large.png ├── badge-blue-small.png ├── logo-blue-large.png ├── logo-blue-medium.png ├── logo-blue-small.png ├── logo-white-large.png ├── logo-white-small.png ├── badge-blue-medium.png ├── badge-white-large.png ├── badge-white-medium.png ├── badge-white-small.png └── logo-white-medium.png ├── lib ├── commands.js ├── messages.js ├── cli.js ├── helpers.js └── server.js ├── bin └── pr-police ├── test ├── messages.js ├── cli.js └── server.js ├── commitlint.config.js ├── CHANGELOG.md ├── package.json ├── LICENSE ├── app.json └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | images 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: node index.js 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('./lib/server')() 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @Talkdesk/admin-team 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .env 3 | node_modules 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - stable 5 | - 6 6 | -------------------------------------------------------------------------------- /images/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/avatar.png -------------------------------------------------------------------------------- /lib/commands.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'what needs review?', 3 | '!review' 4 | ] 5 | -------------------------------------------------------------------------------- /images/badge-blue-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/badge-blue-large.png -------------------------------------------------------------------------------- /images/badge-blue-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/badge-blue-small.png -------------------------------------------------------------------------------- /images/logo-blue-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/logo-blue-large.png -------------------------------------------------------------------------------- /images/logo-blue-medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/logo-blue-medium.png -------------------------------------------------------------------------------- /images/logo-blue-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/logo-blue-small.png -------------------------------------------------------------------------------- /images/logo-white-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/logo-white-large.png -------------------------------------------------------------------------------- /images/logo-white-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/logo-white-small.png -------------------------------------------------------------------------------- /images/badge-blue-medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/badge-blue-medium.png -------------------------------------------------------------------------------- /images/badge-white-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/badge-white-large.png -------------------------------------------------------------------------------- /images/badge-white-medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/badge-white-medium.png -------------------------------------------------------------------------------- /images/badge-white-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/badge-white-small.png -------------------------------------------------------------------------------- /images/logo-white-medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Talkdesk/pr-police/HEAD/images/logo-white-medium.png -------------------------------------------------------------------------------- /bin/pr-police: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const minimist = require('minimist') 4 | 5 | require('../lib/cli')(minimist(process.argv.slice(2))) 6 | -------------------------------------------------------------------------------- /test/messages.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const messages = require('../lib/messages') 3 | 4 | test('it exports an object', (t) => { 5 | t.plan(1) 6 | 7 | t.equals(typeof messages, 'object') 8 | }) 9 | -------------------------------------------------------------------------------- /lib/messages.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | GITHUB_ERROR: ':rotating_light: Could not fetch pull requests...', 3 | NO_PULL_REQUESTS: ':cop: No pull requests are waiting for review! :tada:', 4 | PR_LIST_HEADER: ':cop: The following pull requests are waiting for a review:' 5 | } 6 | -------------------------------------------------------------------------------- /test/cli.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const proxyquire = require('proxyquire') 3 | const sinon = require('sinon') 4 | 5 | test('when passing no arguments calls server function', (t) => { 6 | t.plan(1) 7 | 8 | const serverStub = sinon.stub().callsFake(() => null) 9 | const cli = proxyquire('../lib/cli', { './server': serverStub }) 10 | 11 | cli({ _: [] }) 12 | 13 | t.ok(serverStub.called) 14 | }) 15 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | const server = require('./server') 2 | const meta = require('../package.json') 3 | 4 | module.exports = function (args) { 5 | if (args.help) { 6 | showUsage() 7 | process.exit(0) 8 | } else if (args.version) { 9 | showVersion() 10 | process.exit(0) 11 | } else if (args._.length > 0) { 12 | showUsage() 13 | process.exit(-1) 14 | } else { 15 | server() 16 | } 17 | } 18 | 19 | function showUsage () { 20 | console.log(meta.name + ' [--version] [--help]\n') 21 | console.log('\t--version show version info') 22 | console.log('\t--help show this usage info') 23 | } 24 | 25 | function showVersion () { 26 | console.log(meta.name + ' version ' + meta.version) 27 | } 28 | -------------------------------------------------------------------------------- /lib/helpers.js: -------------------------------------------------------------------------------- 1 | const commands = require('./commands') 2 | 3 | const isDirectMessage = function isDirectMessage (msg) { 4 | // slack direct messages channel id start with D 5 | return msg.type === 'message' && msg.channel.charAt(0) === 'D' 6 | } 7 | 8 | const isBotMessage = function isBotMessage (msg) { 9 | return msg.subtype && msg.subtype === 'bot_message' 10 | } 11 | 12 | const isMessage = function isMessage (msg) { 13 | return msg.type === 'message' 14 | } 15 | 16 | // for now all commands execute the same operation 17 | const isBotCommand = function isBotCommand (msg) { 18 | return commands.some((command) => msg.text === command) 19 | } 20 | 21 | module.exports = { isDirectMessage, isBotMessage, isMessage, isBotCommand } 22 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | 'body-leading-blank': [1, 'always'], 4 | 'footer-leading-blank': [1, 'always'], 5 | 'header-max-length': [2, 'always', 72], 6 | 'scope-case': [2, 'always', 'lower-case'], 7 | 'subject-case': [ 8 | 2, 9 | 'never', 10 | ['sentence-case', 'start-case', 'pascal-case', 'upper-case'] 11 | ], 12 | 'subject-empty': [2, 'never'], 13 | 'subject-full-stop': [2, 'never', '.'], 14 | 'type-case': [2, 'always', 'lower-case'], 15 | 'type-empty': [2, 'never'], 16 | 'type-enum': [ 17 | 2, 18 | 'always', 19 | [ 20 | 'build', 21 | 'chore', 22 | 'ci', 23 | 'docs', 24 | 'feat', 25 | 'fix', 26 | 'perf', 27 | 'refactor', 28 | 'revert', 29 | 'style', 30 | 'test' 31 | ] 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/server.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const proxyquire = require('proxyquire') 3 | const sinon = require('sinon') 4 | 5 | const SlackbotsMock = function SlackbotsMock () {} 6 | SlackbotsMock.prototype.on = sinon.stub() 7 | SlackbotsMock.prototype.on.withArgs('start').yields(true) 8 | 9 | const envMock = { 10 | SLACK_TOKEN: 'foo', 11 | GH_TOKEN: 'foo', 12 | SLACK_CHANNELS: 'foo', 13 | GH_REPOS: 'foo', 14 | CHECK_INTERVAL: '1' 15 | } 16 | 17 | const pullhubMock = sinon.stub().resolves([]) 18 | const clock = sinon.useFakeTimers() 19 | 20 | const server = proxyquire('../lib/server', { 21 | slackbots: SlackbotsMock, 22 | pullhub: pullhubMock 23 | }) 24 | 25 | test('it throws error on missing required env var', (t) => { 26 | t.plan(1) 27 | 28 | t.throws(server, Error) 29 | }) 30 | 31 | test('it calls slackbots onStart handler', (t) => { 32 | t.plan(1) 33 | 34 | process.env = envMock 35 | 36 | server() 37 | clock.tick(envMock.CHECK_INTERVAL) 38 | t.ok(SlackbotsMock.prototype.on.calledWith('start')) 39 | }) 40 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # 1.2.0 (2017-05-11) 3 | 4 | 5 | ### Features 6 | 7 | * add cli to server ([703820b](https://github.com/Talkdesk/pr-police/commit/703820b)) 8 | 9 | 10 | 11 | 12 | # 1.1.0 (2017-05-03) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * remove checkForPRs first call ([d9d5fbb](https://github.com/Talkdesk/pr-police/commit/d9d5fbb)) 18 | * remove invalid logo key from apps.json ([94717d9](https://github.com/Talkdesk/pr-police/commit/94717d9)) 19 | 20 | 21 | ### Features 22 | 23 | * add different text when no PRs need review ([cd0901c](https://github.com/Talkdesk/pr-police/commit/cd0901c)) 24 | * add support for bot commands ([4767f3e](https://github.com/Talkdesk/pr-police/commit/4767f3e)) 25 | * add support for slack private groups ([3d55c24](https://github.com/Talkdesk/pr-police/commit/3d55c24)) 26 | * first version of the slackbot ([ce7b1a9](https://github.com/Talkdesk/pr-police/commit/ce7b1a9)) 27 | * only get pull requests on a fixed hour ([914641d](https://github.com/Talkdesk/pr-police/commit/914641d)) 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pr-police", 3 | "version": "1.2.0", 4 | "description": "Slackbot that warns about open pull requests with given labels", 5 | "main": "index.js", 6 | "scripts": { 7 | "pretest": "standard", 8 | "test": "tape test/*.js | faucet", 9 | "start": "node index.js", 10 | "commitmsg": "commitlint -e", 11 | "version": "standard-changelog" 12 | }, 13 | "keywords": [ 14 | "slackbot", 15 | "pull", 16 | "request", 17 | "github", 18 | "labels" 19 | ], 20 | "bin": { 21 | "pr-police": "./bin/pr-police" 22 | }, 23 | "author": "rogeriopvl", 24 | "license": "MIT", 25 | "dependencies": { 26 | "minimist": "^1.2.0", 27 | "moment": "^2.18.1", 28 | "pullhub": "^1.1.0", 29 | "slackbots": "^1.2.0", 30 | "ws": ">=3.3.1" 31 | }, 32 | "devDependencies": { 33 | "commitlint": "^7.6.1", 34 | "faucet": "^0.0.1", 35 | "husky": "^1.3.1", 36 | "proxyquire": "^2.1.0", 37 | "sinon": "^7.3.2", 38 | "standard": "^12.0.1", 39 | "standard-changelog": "^2.0.11", 40 | "tape": "^4.11.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Talkdesk Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pr-police", 3 | "description": "A slack bot that reminds you of open PRs for review in your chosen repos", 4 | "repository": "https://github.com/Talkdesk/pr-police", 5 | "keywords": ["pull", "request", "police", "github", "node", "slackbot", "slack"], 6 | "logo": "https://raw.githubusercontent.com/Talkdesk/pr-police/master/images/badge-white-small.png", 7 | "formation": { 8 | "worker": { 9 | "quantity": 1, 10 | "size": "free" 11 | } 12 | }, 13 | "env": { 14 | "DAYS_TO_RUN": { 15 | "description": "Which days of the week to run on (locale-specific), comma-separated", 16 | "value": "Monday,Tuesday,Wednesday,Thursday,Friday" 17 | }, 18 | "DEBUG": { 19 | "description": "Debug flag to enable more verbose logging", 20 | "value": false 21 | }, 22 | "GH_TOKEN": { 23 | "description": "Github account token to access needed repositories", 24 | "value": "secret" 25 | }, 26 | "SLACK_TOKEN": { 27 | "description": "Slack token for bot", 28 | "value": "secret" 29 | }, 30 | "GH_REPOS": { 31 | "description": "Repositories to watch in user/repo format, comma separated", 32 | "value": "johndoe/somerepo,johndoe/anotherrepo" 33 | }, 34 | "GH_EXCLUDE_LABELS": { 35 | "description": "Repository labels that will exclude pull requests, comma-separated. Supercedes GH_LABELS", 36 | "value": "", 37 | "required": false 38 | }, 39 | "GH_LABELS": { 40 | "description": "Repository labels to filter pull requests, comma separated", 41 | "value": "", 42 | "required": false 43 | }, 44 | "SLACK_CHANNELS": { 45 | "description": "Slack channels to post the announcements, comma separated. Required if SLACK_GROUPS is empty.", 46 | "value": "", 47 | "required": false 48 | }, 49 | "SLACK_GROUPS": { 50 | "description": "Slack private groups to post the announcements, comma separated. Required if SLACK_CHANNEL is empty.", 51 | "value": "", 52 | "required": false 53 | }, 54 | 55 | "SLACK_BOT_NAME": { 56 | "description": "The name of the bot on your slack organization", 57 | "value": "", 58 | "required": false 59 | }, 60 | "SLACK_BOT_ICON": { 61 | "description": "URL of the bot icon to show when posting messages", 62 | "value": "", 63 | "required": false 64 | }, 65 | "TIMES_TO_RUN": { 66 | "description": "What times of day to run (24-hour format), comma-separated", 67 | "value": "0900", 68 | "required": false 69 | }, 70 | "TZ": { 71 | "description": "The timezone the server should use. Heroku default is UTC. Uses tz database timezone format. Example: 'America/Los_Angeles'", 72 | "value": "", 73 | "required": false 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/server.js: -------------------------------------------------------------------------------- 1 | const Slackbot = require('slackbots') 2 | const pullhub = require('pullhub') 3 | const moment = require('moment') 4 | const messages = require('./messages') 5 | const { 6 | isDirectMessage, 7 | isBotMessage, 8 | isMessage, 9 | isBotCommand 10 | } = require('./helpers') 11 | 12 | module.exports = function server () { 13 | const env = process.env 14 | const requiredEnvs = ['SLACK_TOKEN', 'GH_TOKEN', 'GH_REPOS'] 15 | 16 | if (!requiredEnvs.every((k) => !!env[k])) { 17 | throw ( 18 | new Error('Missing one of this required ENV vars: ' + requiredEnvs.join(',')) 19 | ) 20 | } 21 | 22 | const rawDaysToRun = (env.DAYS_TO_RUN || 'Monday,Tuesday,Wednesday,Thursday,Friday').split(',') 23 | const daysToRun = new Set(rawDaysToRun.map((day) => day.toLowerCase())) 24 | 25 | const channels = env.SLACK_CHANNELS ? env.SLACK_CHANNELS.split(',') : [] 26 | const timesToRun = new Set(env.TIMES_TO_RUN ? env.TIMES_TO_RUN.split(',').map((t) => parseInt(t)) : [900]) 27 | const groups = env.SLACK_GROUPS ? env.SLACK_GROUPS.split(',') : [] 28 | const repos = env.GH_REPOS ? env.GH_REPOS.split(',') : [] 29 | const excludeLabels = new Set(env.GH_EXCLUDE_LABELS ? env.GH_EXCLUDE_LABELS.split(',') : []) 30 | const labels = env.GH_LABELS 31 | const checkInterval = 60000 // Run every minute (60000) 32 | const botParams = { icon_url: env.SLACK_BOT_ICON } 33 | 34 | const bot = new Slackbot({ 35 | token: env.SLACK_TOKEN, 36 | name: env.SLACK_BOT_NAME || 'Pr. Police' 37 | }) 38 | 39 | bot.on('start', () => { 40 | setInterval(() => { 41 | const now = moment() 42 | const runToday = daysToRun.has(now.format('dddd').toLowerCase()) 43 | const runThisMinute = timesToRun.has(parseInt(now.format('kmm'))) 44 | const readableTimestamp = now.format('dddd YYYY-DD-MM h:mm a') 45 | 46 | if (runToday && runThisMinute) { 47 | console.log(`Running at: ${readableTimestamp}`) 48 | 49 | getPullRequests() 50 | .then(buildMessage) 51 | .then(notifyAllChannels) 52 | } else { 53 | console.log(`Nothing to run at: ${readableTimestamp}`) 54 | } 55 | }, checkInterval) 56 | }) 57 | 58 | bot.on('message', (data) => { 59 | if ((isMessage(data) && isBotCommand(data)) || 60 | (isDirectMessage(data) && !isBotMessage(data))) { 61 | getPullRequests() 62 | .then(buildMessage) 63 | .then((message) => { 64 | bot.postMessage(data.channel, message, botParams) 65 | }) 66 | } 67 | }) 68 | 69 | bot.on('error', (err) => { 70 | console.error(err) 71 | }) 72 | 73 | function getPullRequests () { 74 | console.log('Checking for pull requests...') 75 | 76 | return pullhub(repos, labels).catch((err) => { console.error(err) }) 77 | } 78 | 79 | function buildMessage (data) { 80 | if (!data) { 81 | return Promise.resolve(messages.GITHUB_ERROR) 82 | } 83 | 84 | const headers = [ messages.PR_LIST_HEADER, '\n' ] 85 | const excludeLabelsConfigured = !!excludeLabels.length 86 | 87 | let includedPrs = data 88 | if (excludeLabelsConfigured) { 89 | includedPrs = data.filter((pr) => { 90 | const hasExcludedLabel = pr.labels.reduce((acc, label) => acc || excludeLabels.has(label), false) 91 | return !hasExcludedLabel 92 | }) 93 | } 94 | 95 | const prMessages = includedPrs.map((pr) => `:star: ${pr.title} | ${pr.html_url}`) 96 | 97 | if (prMessages.length < 1) { 98 | return Promise.resolve(messages.NO_PULL_REQUESTS) 99 | } else { 100 | return Promise.resolve(headers.concat(prMessages).join('\n')) 101 | } 102 | } 103 | 104 | function notifyAllChannels (message) { 105 | channels.map((channel) => { 106 | bot.postMessageToChannel(channel, message, botParams) 107 | }) 108 | 109 | groups.map((group) => { 110 | bot.postMessageToGroup(group, message, botParams) 111 | }) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :warning: Pr. Police is deprecated and no longer supported :warning: 2 | 3 | GitHub has incorporated a similar feature and now enables [you](https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/managing-your-scheduled-reminders), your [team](https://docs.github.com/en/github/setting-up-and-managing-organizations-and-teams/managing-scheduled-reminders-for-your-team) or [organization](https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/managing-your-scheduled-reminders) to be reminded when pull requests are waiting for review. 4 | 5 | -------------------- 6 | 7 | # Pr. Police 8 | 9 | ![Pr. Police logo](https://raw.githubusercontent.com/Talkdesk/pr-police/master/images/logo-blue-small.png) 10 | 11 | ## About 12 | 13 | Pr. Police is a slackbot that sends to configured slack channels a listing of open pull requests that are waiting for a review. It supports watching multiple repositories, and filtering the pull requests by label. 14 | 15 | This project is part of the Talkdesk Hackathon April 2017. 16 | 17 | ## Running the bot 18 | 19 | ### The quick and easy way 20 | 21 | The easiest way to get an instance of Pr. Police up and running is to deploy it to Heroku by clicking on the button below. 22 | 23 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) 24 | 25 | You'll still need to fill in all the environment variables. For more info on this, head down to the Configuration section. 26 | 27 | 28 | ### Via NPM 29 | 30 | npm install pr-police 31 | 32 | ### Manually 33 | 34 | Git clone this repository then: 35 | 36 | npm install 37 | 38 | #### Run 39 | 40 | npm start 41 | 42 | This will start the server locally until `Ctrl-C` is pressed. 43 | 44 | **Note:** You will need to pass all the required env vars. 45 | 46 | ## Configuration 47 | 48 | Pr. Police has the following environment variables available: 49 | 50 | ##### `DEBUG` 51 | Debug flag used to enable more verbose logging. Default: `false` 52 | 53 | ##### `DAYS_TO_RUN` 54 | Which days of the week to run on. Default: `Monday,Tuesday,Wednesday,Thursday,Friday` 55 | 56 | ##### `GH_TOKEN` 57 | The github account token to access the repos. Required. 58 | 59 | ##### `SLACK_TOKEN` 60 | The slack token for the bot to access your slack team. Required. 61 | 62 | ##### `GH_REPOS` 63 | The list of repositories to watch. The format is `user/repo` and comma separated. Required. 64 | 65 | Example: `rogeriopvl/gulp-ejs,rogeriopvl/pullhub,talkdesk/pr-police` 66 | 67 | ##### `GH_EXCLUDE_LABELS` 68 | The list of labels that will cause a pull-request to be excluded. So imagine, your team uses the label `in-progress` for pull-requests not yet requiring review, you'll have to fill in: `in-progress`. Supercedes `GH_LABELS`. Multiple labels are comma separated. 69 | 70 | Example: `do-not-merge,in-progress,needs-work` 71 | 72 | ##### `GH_LABELS` 73 | The list of labels to filter pull-requests. So imagine, your team uses the label `needs review` for pull-requests waiting for review, you'll have to fill in: `needs review`. Multiple labels are comma separated. Optional. 74 | 75 | NOTE: Omitting both `GH_EXCLUDE_LABELS` and `GH_LABELS` will result in _all_ open pull-requests being reported for the specified `GH_REPOS`. 76 | 77 | ##### `SLACK_CHANNELS` 78 | The list of channel names on your team where Pr. Police will post the announcements. Multiple channels are comma separated. Either `SLACK_CHANNELS` or `SLACK_GROUPS` is required. 79 | 80 | Example: `notifications` 81 | 82 | ##### `SLACK_GROUPS` 83 | The list of private group names on your team where Pr. Police will post the announcements. Multiple channels are comma separated. Either `SLACK_CHANNELS` or `SLACK_GROUPS` is required. 84 | 85 | ##### `SLACK_BOT_NAME` 86 | The name of your Pr. Police bot on slack. Optional. 87 | 88 | ##### `SLACK_BOT_ICON` 89 | URL of the icon for the slack bot when sending messages. 90 | 91 | ##### `TIMES_TO_RUN` 92 | What times of day to run (24-hour format, leading zeroes are not necessary). Multiple times are comma-separated. Default: `0900`. 93 | 94 | ##### `TZ` 95 | The timezone the server should use. Heroku default is UTC. Uses tz database timezone format. Example: `America/Los_Angeles`. 96 | 97 | ## Heroku configuration 98 | 99 | If heroku attempts to start a web process instead of a worker, you may need to run: `heroku ps:scale web=0 worker=1 -a {HEROKU_APP_NAME}` 100 | 101 | ## Credits 102 | 103 | Pr. Police was developed by [Rogério Vicente](https://github.com/rogeriopvl) during one of Talkdesk's internal hackathons. 104 | 105 | Artwork created by [Micaela Neto](https://cargocollective.com/micaelaneto) 106 | --------------------------------------------------------------------------------