Run CoffeeScript files through http://decaffeinate-project.org to convert to ES6 and use async/await. Part of #1
This commit is contained in:
parent
ffb8159dcd
commit
44d04f8e35
|
@ -1,110 +0,0 @@
|
||||||
# Description:
|
|
||||||
# Script that listens to new GitHub pull requests
|
|
||||||
# and assigns them to the REVIEW column on the "Pipeline for QA" project
|
|
||||||
#
|
|
||||||
# Dependencies:
|
|
||||||
# github: "^13.1.0"
|
|
||||||
# hubot-github-webhook-listener: "^0.9.1"
|
|
||||||
# hubot-slack: "^4.4.0"
|
|
||||||
#
|
|
||||||
# Notes:
|
|
||||||
# The hard-coded names for the project board and review column are just below.
|
|
||||||
# These could be read from a config file (e.g. YAML)
|
|
||||||
# TODO: Rewrite this file with ES6 to benefit from async/await
|
|
||||||
#
|
|
||||||
# Author:
|
|
||||||
# PombeirP
|
|
||||||
|
|
||||||
projectBoardName = "Pipeline for QA"
|
|
||||||
reviewColumnName = "REVIEW"
|
|
||||||
notifyRoomName = "core"
|
|
||||||
|
|
||||||
module.exports = (robot) ->
|
|
||||||
|
|
||||||
context = require('./github-context.coffee')
|
|
||||||
|
|
||||||
robot.on "github-repo-event", (repo_event) ->
|
|
||||||
githubPayload = repo_event.payload
|
|
||||||
|
|
||||||
switch(repo_event.eventType)
|
|
||||||
when "pull_request"
|
|
||||||
context.initialize(robot, robot.brain.get "github-app_id")
|
|
||||||
# Make sure we don't listen to our own messages
|
|
||||||
return if context.equalsRobotName(robot, githubPayload.pull_request.user.login)
|
|
||||||
|
|
||||||
action = githubPayload.action
|
|
||||||
if action == "opened"
|
|
||||||
# A new PR was opened
|
|
||||||
assignPullRequestToReview context.github(), githubPayload, robot
|
|
||||||
|
|
||||||
assignPullRequestToReview = (github, githubPayload, robot) ->
|
|
||||||
ownerName = githubPayload.repository.owner.login
|
|
||||||
repoName = githubPayload.repository.name
|
|
||||||
prNumber = githubPayload.pull_request.number
|
|
||||||
robot.logger.info "assignPullRequestToReview - " +
|
|
||||||
"Handling Pull Request ##{prNumber} on repo #{ownerName}/#{repoName}"
|
|
||||||
|
|
||||||
# Fetch repo projects
|
|
||||||
# TODO: The repo project and project column info should be cached
|
|
||||||
# in order to improve performance and reduce roundtrips
|
|
||||||
github.projects.getRepoProjects {
|
|
||||||
owner: ownerName,
|
|
||||||
repo: repoName,
|
|
||||||
state: "open"
|
|
||||||
}, (err, ghprojects) ->
|
|
||||||
if err
|
|
||||||
robot.logger.error "Couldn't fetch the github projects for repo: #{err}",
|
|
||||||
ownerName, repoName
|
|
||||||
return
|
|
||||||
|
|
||||||
# Find "Pipeline for QA" project
|
|
||||||
project = findProject ghprojects.data, projectBoardName
|
|
||||||
if !project
|
|
||||||
robot.logger.warn "Couldn't find project #{projectBoardName}" +
|
|
||||||
" in repo #{ownerName}/#{repoName}"
|
|
||||||
return
|
|
||||||
|
|
||||||
robot.logger.debug "Fetched #{project.name} project (#{project.id})"
|
|
||||||
|
|
||||||
# Fetch REVIEW column ID
|
|
||||||
github.projects.getProjectColumns { project_id: project.id }, (err, ghcolumns) ->
|
|
||||||
if err
|
|
||||||
robot.logger.error "Couldn't fetch the github columns for project: #{err}",
|
|
||||||
ownerName, repoName, project.id
|
|
||||||
return
|
|
||||||
|
|
||||||
column = findColumn ghcolumns.data, reviewColumnName
|
|
||||||
if !column
|
|
||||||
robot.logger.warn "Couldn't find #{projectBoardName} column" +
|
|
||||||
" in project #{project.name}"
|
|
||||||
return
|
|
||||||
|
|
||||||
robot.logger.debug "Fetched #{column.name} column (#{column.id})"
|
|
||||||
|
|
||||||
# Create project card for the PR in the REVIEW column
|
|
||||||
github.projects.createProjectCard {
|
|
||||||
column_id: column.id,
|
|
||||||
content_type: 'PullRequest',
|
|
||||||
content_id: githubPayload.pull_request.id
|
|
||||||
}, (err, ghcard) ->
|
|
||||||
if err
|
|
||||||
robot.logger.error "Couldn't create project card for the PR: #{err}",
|
|
||||||
column.id, githubPayload.pull_request.id
|
|
||||||
return
|
|
||||||
|
|
||||||
robot.logger.debug "Created card: #{ghcard.data.url}", ghcard.data.id
|
|
||||||
|
|
||||||
# Send message to Slack
|
|
||||||
robot.messageRoom notifyRoomName,
|
|
||||||
"Moved PR #{githubPayload.pull_request.number} to " +
|
|
||||||
"#{reviewColumnName} in #{projectBoardName} project"
|
|
||||||
|
|
||||||
findProject = (projects, name) ->
|
|
||||||
for idx, project of projects
|
|
||||||
return project if project.name == name
|
|
||||||
return null
|
|
||||||
|
|
||||||
findColumn = (columns, name) ->
|
|
||||||
for idx, column of columns
|
|
||||||
return column if column.name == name
|
|
||||||
return null
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
// Description:
|
||||||
|
// Script that listens to new GitHub pull requests
|
||||||
|
// and assigns them to the REVIEW column on the "Pipeline for QA" project
|
||||||
|
//
|
||||||
|
// Dependencies:
|
||||||
|
// github: "^13.1.0"
|
||||||
|
// hubot-github-webhook-listener: "^0.9.1"
|
||||||
|
// hubot-slack: "^4.4.0"
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// The hard-coded names for the project board and review column are just below.
|
||||||
|
// These could be read from a config file (e.g. YAML)
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// PombeirP
|
||||||
|
|
||||||
|
const projectBoardName = "Pipeline for QA";
|
||||||
|
const reviewColumnName = "REVIEW";
|
||||||
|
const notifyRoomName = "core";
|
||||||
|
|
||||||
|
module.exports = function(robot) {
|
||||||
|
|
||||||
|
const context = require('./github-context.js');
|
||||||
|
|
||||||
|
return robot.on("github-repo-event", function(repo_event) {
|
||||||
|
const githubPayload = repo_event.payload;
|
||||||
|
|
||||||
|
switch(repo_event.eventType) {
|
||||||
|
case "pull_request":
|
||||||
|
context.initialize(robot, robot.brain.get("github-app_id"));
|
||||||
|
|
||||||
|
// Make sure we don't listen to our own messages
|
||||||
|
if (context.equalsRobotName(robot, githubPayload.pull_request.user.login)) { return; }
|
||||||
|
|
||||||
|
var { action } = githubPayload;
|
||||||
|
if (action === "opened") {
|
||||||
|
// A new PR was opened
|
||||||
|
return assignPullRequestToReview(context.github(), githubPayload, robot);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
async function assignPullRequestToReview(github, githubPayload, robot) {
|
||||||
|
const ownerName = githubPayload.repository.owner.login;
|
||||||
|
const repoName = githubPayload.repository.name;
|
||||||
|
const prNumber = githubPayload.pull_request.number;
|
||||||
|
|
||||||
|
robot.logger.info(`assignPullRequestToReview - Handling Pull Request #${prNumber} on repo ${ownerName}/${repoName}`);
|
||||||
|
|
||||||
|
// Fetch repo projects
|
||||||
|
// TODO: The repo project and project column info should be cached
|
||||||
|
// in order to improve performance and reduce roundtrips
|
||||||
|
try {
|
||||||
|
ghprojects = await github.projects.getRepoProjects({
|
||||||
|
owner: ownerName,
|
||||||
|
repo: repoName,
|
||||||
|
state: "open"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Find "Pipeline for QA" project
|
||||||
|
const project = ghprojects.data.find(function(p) { return p.name === projectBoardName });
|
||||||
|
if (!project) {
|
||||||
|
robot.logger.warn(`Couldn't find project ${projectBoardName} in repo ${ownerName}/${repoName}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
robot.logger.debug(`Fetched ${project.name} project (${project.id})`);
|
||||||
|
|
||||||
|
// Fetch REVIEW column ID
|
||||||
|
try {
|
||||||
|
ghcolumns = await github.projects.getProjectColumns({ project_id: project.id });
|
||||||
|
|
||||||
|
const column = ghcolumns.data.find(function(c) { return c.name === reviewColumnName });
|
||||||
|
if (!column) {
|
||||||
|
robot.logger.warn(`Couldn't find ${projectBoardName} column in project ${project.name}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
robot.logger.debug(`Fetched ${column.name} column (${column.id})`);
|
||||||
|
|
||||||
|
// Create project card for the PR in the REVIEW column
|
||||||
|
try {
|
||||||
|
ghcard = await github.projects.createProjectCard({
|
||||||
|
column_id: column.id,
|
||||||
|
content_type: 'PullRequest',
|
||||||
|
content_id: githubPayload.pull_request.id
|
||||||
|
});
|
||||||
|
|
||||||
|
robot.logger.debug(`Created card: ${ghcard.data.url}`, ghcard.data.id);
|
||||||
|
|
||||||
|
// Send message to Slack
|
||||||
|
robot.messageRoom(notifyRoomName, `Moved PR ${githubPayload.pull_request.number} to ${reviewColumnName} in ${projectBoardName} project`
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
robot.logger.error(`Couldn't create project card for the PR: ${err}`, column.id, githubPayload.pull_request.id);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
robot.logger.error(`Couldn't fetch the github columns for project: ${err}`, ownerName, repoName, project.id);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
robot.logger.error(`Couldn't fetch the github projects for repo: ${err}`, ownerName, repoName);
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,106 +0,0 @@
|
||||||
# Description:
|
|
||||||
# Example scripts for you to examine and try out.
|
|
||||||
#
|
|
||||||
# Notes:
|
|
||||||
# They are commented out by default, because most of them are pretty silly and
|
|
||||||
# wouldn't be useful and amusing enough for day to day huboting.
|
|
||||||
# Uncomment the ones you want to try and experiment with.
|
|
||||||
#
|
|
||||||
# These are from the scripting documentation: https://github.com/github/hubot/blob/master/docs/scripting.md
|
|
||||||
|
|
||||||
module.exports = (robot) ->
|
|
||||||
|
|
||||||
# robot.hear /badger/i, (res) ->
|
|
||||||
# res.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"
|
|
||||||
#
|
|
||||||
# robot.respond /open the (.*) doors/i, (res) ->
|
|
||||||
# doorType = res.match[1]
|
|
||||||
# if doorType is "pod bay"
|
|
||||||
# res.reply "I'm afraid I can't let you do that."
|
|
||||||
# else
|
|
||||||
# res.reply "Opening #{doorType} doors"
|
|
||||||
#
|
|
||||||
# robot.hear /I like pie/i, (res) ->
|
|
||||||
# res.emote "makes a freshly baked pie"
|
|
||||||
#
|
|
||||||
# lulz = ['lol', 'rofl', 'lmao']
|
|
||||||
#
|
|
||||||
# robot.respond /lulz/i, (res) ->
|
|
||||||
# res.send res.random lulz
|
|
||||||
#
|
|
||||||
# robot.topic (res) ->
|
|
||||||
# res.send "#{res.message.text}? That's a Paddlin'"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# enterReplies = ['Hi', 'Target Acquired', 'Firing', 'Hello friend.', 'Gotcha', 'I see you']
|
|
||||||
# leaveReplies = ['Are you still there?', 'Target lost', 'Searching']
|
|
||||||
#
|
|
||||||
# robot.enter (res) ->
|
|
||||||
# res.send res.random enterReplies
|
|
||||||
# robot.leave (res) ->
|
|
||||||
# res.send res.random leaveReplies
|
|
||||||
#
|
|
||||||
# answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING
|
|
||||||
#
|
|
||||||
# robot.respond /what is the answer to the ultimate question of life/, (res) ->
|
|
||||||
# unless answer?
|
|
||||||
# res.send "Missing HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING in environment: please set and try again"
|
|
||||||
# return
|
|
||||||
# res.send "#{answer}, but what is the question?"
|
|
||||||
#
|
|
||||||
# robot.respond /you are a little slow/, (res) ->
|
|
||||||
# setTimeout () ->
|
|
||||||
# res.send "Who you calling 'slow'?"
|
|
||||||
# , 60 * 1000
|
|
||||||
#
|
|
||||||
# annoyIntervalId = null
|
|
||||||
#
|
|
||||||
# robot.respond /annoy me/, (res) ->
|
|
||||||
# if annoyIntervalId
|
|
||||||
# res.send "AAAAAAAAAAAEEEEEEEEEEEEEEEEEEEEEEEEIIIIIIIIHHHHHHHHHH"
|
|
||||||
# return
|
|
||||||
#
|
|
||||||
# res.send "Hey, want to hear the most annoying sound in the world?"
|
|
||||||
# annoyIntervalId = setInterval () ->
|
|
||||||
# res.send "AAAAAAAAAAAEEEEEEEEEEEEEEEEEEEEEEEEIIIIIIIIHHHHHHHHHH"
|
|
||||||
# , 1000
|
|
||||||
#
|
|
||||||
# robot.respond /unannoy me/, (res) ->
|
|
||||||
# if annoyIntervalId
|
|
||||||
# res.send "GUYS, GUYS, GUYS!"
|
|
||||||
# clearInterval(annoyIntervalId)
|
|
||||||
# annoyIntervalId = null
|
|
||||||
# else
|
|
||||||
# res.send "Not annoying you right now, am I?"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# robot.router.post '/hubot/chatsecrets/:room', (req, res) ->
|
|
||||||
# room = req.params.room
|
|
||||||
# data = JSON.parse req.body.payload
|
|
||||||
# secret = data.secret
|
|
||||||
#
|
|
||||||
# robot.messageRoom room, "I have a secret: #{secret}"
|
|
||||||
#
|
|
||||||
# res.send 'OK'
|
|
||||||
#
|
|
||||||
# robot.error (err, res) ->
|
|
||||||
# robot.logger.error "DOES NOT COMPUTE"
|
|
||||||
#
|
|
||||||
# if res?
|
|
||||||
# res.reply "DOES NOT COMPUTE"
|
|
||||||
#
|
|
||||||
# robot.respond /have a soda/i, (res) ->
|
|
||||||
# # Get number of sodas had (coerced to a number).
|
|
||||||
# sodasHad = robot.brain.get('totalSodas') * 1 or 0
|
|
||||||
#
|
|
||||||
# if sodasHad > 4
|
|
||||||
# res.reply "I'm too fizzy.."
|
|
||||||
#
|
|
||||||
# else
|
|
||||||
# res.reply 'Sure!'
|
|
||||||
#
|
|
||||||
# robot.brain.set 'totalSodas', sodasHad+1
|
|
||||||
#
|
|
||||||
# robot.respond /sleep it off/i, (res) ->
|
|
||||||
# robot.brain.set 'totalSodas', 0
|
|
||||||
# res.reply 'zzzzz'
|
|
|
@ -1,81 +0,0 @@
|
||||||
# Description:
|
|
||||||
# Script that keeps GitHub-related context to be shared among scripts
|
|
||||||
#
|
|
||||||
# Dependencies:
|
|
||||||
# github: "^13.1.0"
|
|
||||||
# jwt-simple: "^0.5.1"
|
|
||||||
#
|
|
||||||
# Author:
|
|
||||||
# PombeirP
|
|
||||||
|
|
||||||
GitHubApi = require('github')
|
|
||||||
|
|
||||||
RegExp cachedRobotNameRegex = null
|
|
||||||
initialized = false
|
|
||||||
githubAPI = new GitHubApi { version: "3.0.0" }
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
|
|
||||||
github: -> githubAPI
|
|
||||||
|
|
||||||
initialize: (robot, integrationID) ->
|
|
||||||
return if initialized
|
|
||||||
|
|
||||||
token = robot.brain.get('github-token')
|
|
||||||
if token
|
|
||||||
initialized = true
|
|
||||||
process.env.HUBOT_GITHUB_TOKEN = token
|
|
||||||
robot.logger.debug "Reused cached GitHub token"
|
|
||||||
githubAPI.authenticate({ type: 'token', token: token })
|
|
||||||
return
|
|
||||||
|
|
||||||
pemFilePath = './status-github-bot.pem'
|
|
||||||
|
|
||||||
jwt = require('jwt-simple')
|
|
||||||
|
|
||||||
# Private key contents
|
|
||||||
privateKey = ''
|
|
||||||
try
|
|
||||||
fs = require('fs')
|
|
||||||
privateKey = fs.readFileSync pemFilePath
|
|
||||||
catch err
|
|
||||||
robot.logger.error "Couldn't read #{pemFilePath} file contents: #{err}"
|
|
||||||
return
|
|
||||||
|
|
||||||
now = Math.round(Date.now() / 1000)
|
|
||||||
# Generate the JWT
|
|
||||||
payload = {
|
|
||||||
# issued at time
|
|
||||||
iat: now,
|
|
||||||
# JWT expiration time (10 minute maximum)
|
|
||||||
exp: now + (1 * 60),
|
|
||||||
# GitHub App's identifier
|
|
||||||
iss: integrationID
|
|
||||||
}
|
|
||||||
|
|
||||||
jwt = jwt.encode(payload, privateKey, 'RS256')
|
|
||||||
githubAPI.authenticate({
|
|
||||||
type: 'integration',
|
|
||||||
token: jwt
|
|
||||||
})
|
|
||||||
robot.logger.debug "Configured integration authentication with JWT", jwt
|
|
||||||
|
|
||||||
initialized = true
|
|
||||||
|
|
||||||
equalsRobotName: (robot, str) ->
|
|
||||||
return getRegexForRobotName(robot).test(str)
|
|
||||||
}
|
|
||||||
|
|
||||||
getRegexForRobotName = (robot) ->
|
|
||||||
# This comes straight out of Hubot's Robot.coffee
|
|
||||||
# - they didn't get a nice way of extracting that method though
|
|
||||||
if !cachedRobotNameRegex
|
|
||||||
name = robot.name.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
|
|
||||||
|
|
||||||
if robot.alias
|
|
||||||
alias = robot.alias.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
|
|
||||||
namePattern = "^\\s*[@]?(?:#{alias}|#{name})"
|
|
||||||
else
|
|
||||||
namePattern = "^\\s*[@]?#{name}"
|
|
||||||
cachedRobotNameRegex = new RegExp(namePattern, 'i')
|
|
||||||
return cachedRobotNameRegex
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
// Description:
|
||||||
|
// Script that keeps GitHub-related context to be shared among scripts
|
||||||
|
//
|
||||||
|
// Dependencies:
|
||||||
|
// github: "^13.1.0"
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// PombeirP
|
||||||
|
|
||||||
|
const GitHubApi = require('github');
|
||||||
|
|
||||||
|
let cachedRobotNameRegex;
|
||||||
|
let initialized = false;
|
||||||
|
const githubAPI = new GitHubApi({
|
||||||
|
timeout: 15000,
|
||||||
|
requestMedia: 'application/vnd.github.v3+json'
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
github() { return githubAPI; },
|
||||||
|
|
||||||
|
initialize(robot, integrationID) {
|
||||||
|
if (initialized) { return; }
|
||||||
|
|
||||||
|
const token = robot.brain.get('github-token');
|
||||||
|
if (token) {
|
||||||
|
initialized = true;
|
||||||
|
process.env.HUBOT_GITHUB_TOKEN = token;
|
||||||
|
robot.logger.debug("Reused cached GitHub token");
|
||||||
|
githubAPI.authenticate({ type: 'token', token });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pemFilePath = './status-github-bot.pem';
|
||||||
|
|
||||||
|
const jwtLib = require('jwt-simple');
|
||||||
|
|
||||||
|
// Private key contents
|
||||||
|
let privateKey = '';
|
||||||
|
try {
|
||||||
|
const fs = require('fs');
|
||||||
|
privateKey = fs.readFileSync(pemFilePath);
|
||||||
|
} catch (err) {
|
||||||
|
robot.logger.error(`Couldn't read ${pemFilePath} file contents: ${err}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = Math.round(Date.now() / 1000);
|
||||||
|
// Generate the JWT
|
||||||
|
const payload = {
|
||||||
|
// issued at time
|
||||||
|
iat: now,
|
||||||
|
// JWT expiration time (10 minute maximum)
|
||||||
|
exp: now + (1 * 60),
|
||||||
|
// GitHub App's identifier
|
||||||
|
iss: integrationID
|
||||||
|
};
|
||||||
|
|
||||||
|
jwt = jwtLib.encode(payload, privateKey, 'RS256');
|
||||||
|
githubAPI.authenticate({
|
||||||
|
type: 'integration',
|
||||||
|
token: jwt
|
||||||
|
});
|
||||||
|
robot.logger.debug("Configured integration authentication with JWT", jwt);
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
equalsRobotName(robot, str) {
|
||||||
|
return getRegexForRobotName(robot).test(str);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function getRegexForRobotName(robot) {
|
||||||
|
// This comes straight out of Hubot's Robot.coffee
|
||||||
|
// - they didn't get a nice way of extracting that method though
|
||||||
|
if (!cachedRobotNameRegex) {
|
||||||
|
let namePattern;
|
||||||
|
const name = robot.name.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
||||||
|
|
||||||
|
if (robot.alias) {
|
||||||
|
const alias = robot.alias.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
||||||
|
namePattern = `^\\s*[@]?(?:${alias}|${name})`;
|
||||||
|
} else {
|
||||||
|
namePattern = `^\\s*[@]?${name}`;
|
||||||
|
}
|
||||||
|
cachedRobotNameRegex = new RegExp(namePattern, 'i');
|
||||||
|
}
|
||||||
|
return cachedRobotNameRegex;
|
||||||
|
};
|
|
@ -1,76 +0,0 @@
|
||||||
# Description:
|
|
||||||
# Script that handles the installation of the GitHub app
|
|
||||||
#
|
|
||||||
# Dependencies:
|
|
||||||
# github: "^13.1.0"
|
|
||||||
# hubot-github-webhook-listener: "^0.9.1"
|
|
||||||
#
|
|
||||||
# Author:
|
|
||||||
# PombeirP
|
|
||||||
|
|
||||||
module.exports = (robot) ->
|
|
||||||
|
|
||||||
context = require('./github-context.coffee')
|
|
||||||
|
|
||||||
robot.on "github-repo-event", (repo_event) ->
|
|
||||||
githubPayload = repo_event.payload
|
|
||||||
|
|
||||||
switch(repo_event.eventType)
|
|
||||||
when "integration_installation"
|
|
||||||
# Make sure we don't listen to our own messages
|
|
||||||
return if context.equalsRobotName(robot, githubPayload.sender.login)
|
|
||||||
|
|
||||||
action = githubPayload.action
|
|
||||||
switch action
|
|
||||||
when "created"
|
|
||||||
# App was installed on an organization
|
|
||||||
robot.logger.info "Initializing installation for app with ID " +
|
|
||||||
"#{githubPayload.installation.app_id} and " +
|
|
||||||
"installation ID #{githubPayload.installation.id}"
|
|
||||||
|
|
||||||
robot.brain.set 'github-app_install-payload', JSON.stringify(githubPayload)
|
|
||||||
robot.brain.set 'github-app_id', githubPayload.installation.app_id
|
|
||||||
robot.brain.set 'github-app_repositories',
|
|
||||||
(x.full_name for x in githubPayload.repositories).join()
|
|
||||||
|
|
||||||
context.initialize(robot, githubPayload.installation.app_id)
|
|
||||||
|
|
||||||
perms = githubPayload.installation.permissions
|
|
||||||
robot.logger.error formatPermMessage('repository_projects', 'write') unless perms.repository_projects == 'write'
|
|
||||||
robot.logger.error formatPermMessage('metadata', 'read') unless perms.metadata == 'read'
|
|
||||||
robot.logger.error formatPermMessage('issues', 'read') unless perms.issues == 'read'
|
|
||||||
robot.logger.error formatPermMessage('pull_requests', 'write') unless perms.pull_requests == 'write'
|
|
||||||
|
|
||||||
robot.logger.error "Please enable 'pull_request' events " +
|
|
||||||
"in the app configuration on github.com" unless 'pull_request' in githubPayload.installation.events
|
|
||||||
|
|
||||||
createAccessToken robot, context.github(), githubPayload.installation.id
|
|
||||||
when "deleted"
|
|
||||||
# App was uninstalled from an organization
|
|
||||||
robot.logger.info "Removing installation for app " +
|
|
||||||
"with ID #{githubPayload.installation.app_id} and " +
|
|
||||||
"installation ID #{githubPayload.installation.id}"
|
|
||||||
|
|
||||||
robot.brain.set 'github-app_id', null
|
|
||||||
robot.brain.set 'github-app_install-payload', null
|
|
||||||
robot.brain.set 'github-app_repositories', null
|
|
||||||
robot.brain.set 'github-token', null
|
|
||||||
process.env.HUBOT_GITHUB_TOKEN = null
|
|
||||||
|
|
||||||
createAccessToken = (robot, github, id) ->
|
|
||||||
github.apps.createInstallationToken { installation_id: id }, (err, response) ->
|
|
||||||
if err
|
|
||||||
robot.logger.error "Couldn't create installation token: #{err}", id
|
|
||||||
return
|
|
||||||
|
|
||||||
console.error response.data.token
|
|
||||||
robot.brain.set 'github-token', response.data.token
|
|
||||||
# TODO: Set Redis expiration date to value from response.data.expires_at
|
|
||||||
process.env.HUBOT_GITHUB_TOKEN = response.data.token
|
|
||||||
github.authenticate({
|
|
||||||
type: 'token',
|
|
||||||
token: response.data.token
|
|
||||||
})
|
|
||||||
|
|
||||||
formatPermMessage = (permName, perm) ->
|
|
||||||
"Please enable '#{permName}' #{perm} permission in the app configuration on github.com"
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
// Description:
|
||||||
|
// Script that handles the installation of the GitHub app
|
||||||
|
//
|
||||||
|
// Dependencies:
|
||||||
|
// github: "^13.1.0"
|
||||||
|
// hubot-github-webhook-listener: "^0.9.1"
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// PombeirP
|
||||||
|
|
||||||
|
module.exports = function(robot) {
|
||||||
|
|
||||||
|
const context = require('./github-context.js');
|
||||||
|
|
||||||
|
return robot.on("github-repo-event", async function(repo_event) {
|
||||||
|
const githubPayload = repo_event.payload;
|
||||||
|
|
||||||
|
robot.logger.debug(`Received ${repo_event.eventType}/${githubPayload.action} event from GitHub`);
|
||||||
|
|
||||||
|
switch(repo_event.eventType) {
|
||||||
|
case "integration_installation":
|
||||||
|
// Make sure we don't listen to our own messages
|
||||||
|
if (context.equalsRobotName(robot, githubPayload.sender.login)) { return; }
|
||||||
|
|
||||||
|
var { action } = githubPayload;
|
||||||
|
switch (action) {
|
||||||
|
case "created":
|
||||||
|
// App was installed on an organization
|
||||||
|
robot.logger.info(`Initializing installation for app with ID ${githubPayload.installation.app_id} and installation ID ${githubPayload.installation.id}`);
|
||||||
|
|
||||||
|
robot.brain.set('github-app_install-payload', JSON.stringify(githubPayload));
|
||||||
|
robot.brain.set('github-app_id', githubPayload.installation.app_id);
|
||||||
|
robot.brain.set('github-app_repositories', githubPayload.repositories.map((x) => x.full_name).join());
|
||||||
|
|
||||||
|
context.initialize(robot, githubPayload.installation.app_id);
|
||||||
|
|
||||||
|
var perms = githubPayload.installation.permissions;
|
||||||
|
if (perms.repository_projects !== 'write') { robot.logger.error(formatPermMessage('repository_projects', 'write')); }
|
||||||
|
if (perms.metadata !== 'read') { robot.logger.error(formatPermMessage('metadata', 'read')); }
|
||||||
|
if (perms.issues !== 'read') { robot.logger.error(formatPermMessage('issues', 'read')); }
|
||||||
|
if (perms.pull_requests !== 'write') { robot.logger.error(formatPermMessage('pull_requests', 'write')); }
|
||||||
|
|
||||||
|
if (!githubPayload.installation.events.includes('pull_request')) {
|
||||||
|
robot.logger.error("Please enable 'pull_request' events in the app configuration on github.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
await createAccessToken(robot, context.github(), githubPayload.installation.id);
|
||||||
|
break;
|
||||||
|
case "deleted":
|
||||||
|
// App was uninstalled from an organization
|
||||||
|
robot.logger.info(`Removing installation for app with ID ${githubPayload.installation.app_id} and installation ID ${githubPayload.installation.id}`);
|
||||||
|
|
||||||
|
robot.brain.set('github-app_id', null);
|
||||||
|
robot.brain.set('github-app_install-payload', null);
|
||||||
|
robot.brain.set('github-app_repositories', null);
|
||||||
|
robot.brain.set('github-token', null);
|
||||||
|
process.env.HUBOT_GITHUB_TOKEN = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
async function createAccessToken(robot, github, id) {
|
||||||
|
try {
|
||||||
|
response = await github.apps.createInstallationToken({ installation_id: id });
|
||||||
|
|
||||||
|
robot.brain.set('github-token', response.data.token);
|
||||||
|
// TODO: Set Redis expiration date to value from response.data.expires_at
|
||||||
|
process.env.HUBOT_GITHUB_TOKEN = response.data.token;
|
||||||
|
github.authenticate({
|
||||||
|
type: 'token',
|
||||||
|
token: response.data.token
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
robot.logger.error(`Couldn't create installation token: ${err}`, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var formatPermMessage = (permName, perm) => `Please enable '${permName}' ${perm} permission in the app configuration on github.com`;
|
|
@ -1,69 +0,0 @@
|
||||||
# Description:
|
|
||||||
# Script that listens to new GitHub pull requests
|
|
||||||
# and greets the user if it is their first PR on the repo
|
|
||||||
#
|
|
||||||
# Dependencies:
|
|
||||||
# github: "^13.1.0"
|
|
||||||
# hubot-github-webhook-listener: "^0.9.1"
|
|
||||||
#
|
|
||||||
# Notes:
|
|
||||||
# TODO: Rewrite this file with ES6 to benefit from async/await
|
|
||||||
#
|
|
||||||
# Author:
|
|
||||||
# PombeirP
|
|
||||||
|
|
||||||
module.exports = (robot) ->
|
|
||||||
|
|
||||||
context = require('./github-context.coffee')
|
|
||||||
|
|
||||||
robot.on "github-repo-event", (repo_event) ->
|
|
||||||
githubPayload = repo_event.payload
|
|
||||||
|
|
||||||
switch(repo_event.eventType)
|
|
||||||
when "pull_request"
|
|
||||||
context.initialize(robot, robot.brain.get "github-app_id")
|
|
||||||
# Make sure we don't listen to our own messages
|
|
||||||
return if context.equalsRobotName(robot, githubPayload.pull_request.user.login)
|
|
||||||
|
|
||||||
action = githubPayload.action
|
|
||||||
if action == "opened"
|
|
||||||
# A new PR was opened
|
|
||||||
greetNewContributor context.github(), githubPayload, robot
|
|
||||||
|
|
||||||
greetNewContributor = (github, githubPayload, robot) ->
|
|
||||||
# TODO: Read the welcome message from a (per-repo?) file (e.g. status-react.welcome-msg.md)
|
|
||||||
welcomeMessage = "Thanks for making your first PR here!"
|
|
||||||
ownerName = githubPayload.repository.owner.login
|
|
||||||
repoName = githubPayload.repository.name
|
|
||||||
prNumber = githubPayload.pull_request.number
|
|
||||||
robot.logger.info "greetNewContributor - " +
|
|
||||||
"Handling Pull Request ##{prNumber} on repo #{ownerName}/#{repoName}"
|
|
||||||
|
|
||||||
github.issues.getForRepo {
|
|
||||||
owner: ownerName,
|
|
||||||
repo: repoName
|
|
||||||
state: 'all',
|
|
||||||
creator: githubPayload.pull_request.user.login
|
|
||||||
}, (err, ghissues) ->
|
|
||||||
if err
|
|
||||||
robot.logger.error "Couldn't fetch the user's github issues for repo: #{err}",
|
|
||||||
ownerName, repoName
|
|
||||||
return
|
|
||||||
|
|
||||||
userPullRequests = ghissues.data.filter (issue) -> issue.pull_request
|
|
||||||
if userPullRequests.length == 1
|
|
||||||
github.issues.createComment {
|
|
||||||
owner: ownerName,
|
|
||||||
repo: repoName,
|
|
||||||
number: prNumber,
|
|
||||||
body: welcomeMessage
|
|
||||||
}, (err, result) ->
|
|
||||||
if err
|
|
||||||
robot.logger.error("Couldn't fetch the github projects for repo: #{err}",
|
|
||||||
ownerName, repoName) unless err.code == 404
|
|
||||||
return
|
|
||||||
robot.logger.info "Commented on PR with welcome message", ownerName, repoName
|
|
||||||
else
|
|
||||||
robot.logger.debug(
|
|
||||||
"This is not the user's first PR on the repo, ignoring",
|
|
||||||
ownerName, repoName, githubPayload.pull_request.user.login)
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Description:
|
||||||
|
// Script that listens to new GitHub pull requests
|
||||||
|
// and greets the user if it is their first PR on the repo
|
||||||
|
//
|
||||||
|
// Dependencies:
|
||||||
|
// github: "^13.1.0"
|
||||||
|
// hubot-github-webhook-listener: "^0.9.1"
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// PombeirP
|
||||||
|
|
||||||
|
module.exports = function(robot) {
|
||||||
|
|
||||||
|
const context = require('./github-context.js');
|
||||||
|
|
||||||
|
return robot.on("github-repo-event", function(repo_event) {
|
||||||
|
const githubPayload = repo_event.payload;
|
||||||
|
|
||||||
|
switch(repo_event.eventType) {
|
||||||
|
case "pull_request":
|
||||||
|
context.initialize(robot, robot.brain.get("github-app_id"));
|
||||||
|
// Make sure we don't listen to our own messages
|
||||||
|
if (context.equalsRobotName(robot, githubPayload.pull_request.user.login)) { return; }
|
||||||
|
|
||||||
|
var { action } = githubPayload;
|
||||||
|
if (action === "opened") {
|
||||||
|
// A new PR was opened
|
||||||
|
return greetNewContributor(context.github(), githubPayload, robot);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
async function greetNewContributor(github, githubPayload, robot) {
|
||||||
|
// TODO: Read the welcome message from a (per-repo?) file (e.g. status-react.welcome-msg.md)
|
||||||
|
const welcomeMessage = "Thanks for making your first PR here!";
|
||||||
|
const ownerName = githubPayload.repository.owner.login;
|
||||||
|
const repoName = githubPayload.repository.name;
|
||||||
|
const prNumber = githubPayload.pull_request.number;
|
||||||
|
|
||||||
|
robot.logger.info(`greetNewContributor - Handling Pull Request #${prNumber} on repo ${ownerName}/${repoName}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ghissues = await github.issues.getForRepo({
|
||||||
|
owner: ownerName,
|
||||||
|
repo: repoName,
|
||||||
|
state: 'all',
|
||||||
|
creator: githubPayload.pull_request.user.login
|
||||||
|
})
|
||||||
|
|
||||||
|
const userPullRequests = ghissues.data.filter(issue => issue.pull_request);
|
||||||
|
if (userPullRequests.length === 1) {
|
||||||
|
try {
|
||||||
|
await github.issues.createComment({
|
||||||
|
owner: ownerName,
|
||||||
|
repo: repoName,
|
||||||
|
number: prNumber,
|
||||||
|
body: welcomeMessage
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code !== 404) {
|
||||||
|
robot.logger.error(`Couldn't create comment on PR: ${err}`, ownerName, repoName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
robot.logger.debug("This is not the user's first PR on the repo, ignoring", ownerName, repoName, githubPayload.pull_request.user.login);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
robot.logger.error(`Couldn't fetch the user's github issues for repo: ${err}`, ownerName, repoName);
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue