Simplify JS code
This commit is contained in:
parent
a9eb8d117a
commit
8a388db71c
|
@ -24,12 +24,8 @@ module.exports = robot => {
|
||||||
robot.on('schedule.repository', context => checkOpenPullRequests(robot, context))
|
robot.on('schedule.repository', context => checkOpenPullRequests(robot, context))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getProjectFromName (github, ownerName, repoName, projectBoardName) {
|
async function getProjectFromName (github, repoInfo, projectBoardName) {
|
||||||
const ghprojectsPayload = await github.projects.getRepoProjects({
|
const ghprojectsPayload = await github.projects.getRepoProjects({ ...repoInfo, state: 'open' })
|
||||||
owner: ownerName,
|
|
||||||
repo: repoName,
|
|
||||||
state: 'open'
|
|
||||||
})
|
|
||||||
|
|
||||||
return ghprojectsPayload.data.find(p => p.name === projectBoardName)
|
return ghprojectsPayload.data.find(p => p.name === projectBoardName)
|
||||||
}
|
}
|
||||||
|
@ -37,13 +33,12 @@ async function getProjectFromName (github, ownerName, repoName, projectBoardName
|
||||||
async function checkOpenPullRequests (robot, context) {
|
async function checkOpenPullRequests (robot, context) {
|
||||||
const { github, payload } = context
|
const { github, payload } = context
|
||||||
const repo = payload.repository
|
const repo = payload.repository
|
||||||
const ownerName = repo.owner.login
|
const repoInfo = { owner: payload.repository.owner.login, repo: payload.repository.name }
|
||||||
const repoName = repo.name
|
|
||||||
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
||||||
const projectBoardConfig = config ? config['project-board'] : null
|
const projectBoardConfig = config ? config['project-board'] : null
|
||||||
|
|
||||||
if (!projectBoardConfig) {
|
if (!projectBoardConfig) {
|
||||||
robot.log.debug(`${botName} - Project board not configured in repo ${ownerName}/${repoName}, ignoring`)
|
robot.log.debug(`${botName} - Project board not configured in repo ${repoInfo.owner}/${repoInfo.repo}, ignoring`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,15 +52,15 @@ async function checkOpenPullRequests (robot, context) {
|
||||||
let project
|
let project
|
||||||
try {
|
try {
|
||||||
// Find 'Pipeline for QA' project
|
// Find 'Pipeline for QA' project
|
||||||
project = await getProjectFromName(github, ownerName, repoName, projectBoardConfig.name)
|
project = await getProjectFromName(github, repoInfo, projectBoardConfig.name)
|
||||||
if (!project) {
|
if (!project) {
|
||||||
robot.log.error(`${botName} - Couldn't find project ${projectBoardConfig.name} in repo ${ownerName}/${repoName}`)
|
robot.log.error(`${botName} - Couldn't find project ${projectBoardConfig.name} in repo ${repoInfo.owner}/${repoInfo.repo}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
robot.log.debug(`${botName} - Fetched ${project.name} project (${project.id})`)
|
robot.log.debug(`${botName} - Fetched ${project.name} project (${project.id})`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
robot.log.error(`${botName} - Couldn't fetch the github projects for repo: ${err}`, ownerName, repoName)
|
robot.log.error(`${botName} - Couldn't fetch the github projects for repo: ${err}`, repoInfo)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,85 +70,57 @@ async function checkOpenPullRequests (robot, context) {
|
||||||
const ghcolumnsPayload = await github.projects.getProjectColumns({ project_id: project.id })
|
const ghcolumnsPayload = await github.projects.getProjectColumns({ project_id: project.id })
|
||||||
ghcolumns = ghcolumnsPayload.data
|
ghcolumns = ghcolumnsPayload.data
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
robot.log.error(`${botName} - Couldn't fetch the github columns for project: ${err}`, ownerName, repoName, project.id)
|
robot.log.error(`${botName} - Couldn't fetch the github columns for project: ${err}`, repoInfo, project.id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const contributorColumn = ghcolumns.find(c => c.name === contributorColumnName)
|
|
||||||
if (!contributorColumn) {
|
|
||||||
robot.log.error(`${botName} - Couldn't find ${contributorColumnName} column in project ${project.name}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const reviewColumn = ghcolumns.find(c => c.name === reviewColumnName)
|
|
||||||
if (!reviewColumn) {
|
|
||||||
robot.log.error(`${botName} - Couldn't find ${reviewColumnName} column in project ${project.name}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const testColumn = ghcolumns.find(c => c.name === testColumnName)
|
|
||||||
if (!testColumn) {
|
|
||||||
robot.log.error(`${botName} - Couldn't find ${testColumnName} column in project ${project.name}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
robot.log.debug(`${botName} - Fetched ${contributorColumn.name} (${contributorColumn.id}), ${reviewColumn.name} (${reviewColumn.id}), ${testColumn.name} (${testColumn.id}) columns`)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Gather all open PRs in this repo
|
const contributorColumn = findColumnByName(ghcolumns, contributorColumnName)
|
||||||
const allPullRequests = await github.paginate(
|
const reviewColumn = findColumnByName(ghcolumns, reviewColumnName)
|
||||||
github.pullRequests.getAll({owner: ownerName, repo: repoName, per_page: 100}),
|
const testColumn = findColumnByName(ghcolumns, testColumnName)
|
||||||
res => res.data
|
|
||||||
)
|
|
||||||
|
|
||||||
// And make sure they are assigned to the correct project column
|
robot.log.debug(`${botName} - Fetched ${contributorColumn.name} (${contributorColumn.id}), ${reviewColumn.name} (${reviewColumn.id}), ${testColumn.name} (${testColumn.id}) columns`)
|
||||||
for (const pullRequest of allPullRequests) {
|
|
||||||
try {
|
try {
|
||||||
await assignPullRequestToCorrectColumn(github, robot, repo, pullRequest, contributorColumn, reviewColumn, testColumn, config.slack.notification.room)
|
// Gather all open PRs in this repo
|
||||||
} catch (err) {
|
const allPullRequests = await github.paginate(
|
||||||
robot.log.error(`${botName} - Unhandled exception while processing PR: ${err}`, ownerName, repoName)
|
github.pullRequests.getAll({ ...repoInfo, per_page: 100 }),
|
||||||
|
res => res.data
|
||||||
|
)
|
||||||
|
|
||||||
|
// And make sure they are assigned to the correct project column
|
||||||
|
for (const pullRequest of allPullRequests) {
|
||||||
|
try {
|
||||||
|
const columns = { contributor: contributorColumn, review: reviewColumn, test: testColumn }
|
||||||
|
await assignPullRequestToCorrectColumn(github, robot, repo, pullRequest, columns, config.slack.notification.room)
|
||||||
|
} catch (err) {
|
||||||
|
robot.log.error(`${botName} - Unhandled exception while processing PR: ${err}`, repoInfo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
robot.log.error(`${botName} - Couldn't fetch the github pull requests for repo: ${err}`, repoInfo)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
robot.log.error(`${botName} - Couldn't fetch the github pull requests for repo: ${err}`, ownerName, repoName)
|
robot.log.error(err.message, project.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function assignPullRequestToCorrectColumn (github, robot, repo, pullRequest, contributorColumn, reviewColumn, testColumn, room) {
|
async function assignPullRequestToCorrectColumn (github, robot, repo, pullRequest, columns, room) {
|
||||||
const repoOwner = repo.owner.login
|
const prInfo = { owner: repo.owner.login, repo: repo.name, number: pullRequest.number }
|
||||||
const repoName = repo.name
|
|
||||||
const prNumber = pullRequest.number
|
|
||||||
|
|
||||||
let state = null
|
let state = null
|
||||||
try {
|
try {
|
||||||
state = await gitHubHelpers.getReviewApprovalState(github, robot, repoOwner, repoName, prNumber)
|
state = await gitHubHelpers.getReviewApprovalState(github, robot, prInfo)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
robot.log.error(`${botName} - Couldn't calculate the PR approval state: ${err}`, repoOwner, repoName, prNumber)
|
robot.log.error(`${botName} - Couldn't calculate the PR approval state: ${err}`, prInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
let srcColumns, dstColumn
|
const { srcColumns, dstColumn } = getColumns(state, columns)
|
||||||
switch (state) {
|
if (!dstColumn) {
|
||||||
case 'awaiting_reviewers':
|
return
|
||||||
srcColumns = [contributorColumn, testColumn]
|
|
||||||
dstColumn = reviewColumn
|
|
||||||
break
|
|
||||||
case 'changes_requested':
|
|
||||||
srcColumns = [reviewColumn, testColumn]
|
|
||||||
dstColumn = contributorColumn
|
|
||||||
break
|
|
||||||
case 'failed':
|
|
||||||
srcColumns = [reviewColumn, testColumn]
|
|
||||||
dstColumn = contributorColumn
|
|
||||||
break
|
|
||||||
case 'approved':
|
|
||||||
srcColumns = [contributorColumn, reviewColumn]
|
|
||||||
dstColumn = testColumn
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
robot.log.debug(`${botName} - Handling Pull Request #${prNumber} on repo ${repoOwner}/${repoName}. PR should be in ${dstColumn.name} column`)
|
robot.log.debug(`${botName} - Handling Pull Request #${prInfo.number} on repo ${prInfo.owner}/${prInfo.repo}. PR should be in ${dstColumn.name} column`)
|
||||||
|
|
||||||
// Look for PR card in source column(s)
|
// Look for PR card in source column(s)
|
||||||
let existingGHCard = null
|
let existingGHCard = null
|
||||||
|
@ -181,12 +148,12 @@ async function assignPullRequestToCorrectColumn (github, robot, repo, pullReques
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.DRY_RUN || process.env.DRY_RUN_PR_TO_TEST) {
|
if (process.env.DRY_RUN || process.env.DRY_RUN_PR_TO_TEST) {
|
||||||
robot.log.info(`${botName} - Would have moved card ${existingGHCard.id} to ${dstColumn.name} for PR #${prNumber}`)
|
robot.log.info(`${botName} - Would have moved card ${existingGHCard.id} to ${dstColumn.name} for PR #${prInfo.number}`)
|
||||||
} else {
|
} else {
|
||||||
// Found in the source column, let's move it to the destination column
|
// Found in the source column, let's move it to the destination column
|
||||||
await github.projects.moveProjectCard({id: existingGHCard.id, position: 'bottom', column_id: dstColumn.id})
|
await github.projects.moveProjectCard({id: existingGHCard.id, position: 'bottom', column_id: dstColumn.id})
|
||||||
|
|
||||||
robot.log.info(`${botName} - Moved card ${existingGHCard.id} to ${dstColumn.name} for PR #${prNumber}`)
|
robot.log.info(`${botName} - Moved card ${existingGHCard.id} to ${dstColumn.name} for PR #${prInfo.number}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
slackHelper.sendMessage(robot, room, `Assigned PR to ${dstColumn.name} column\n${pullRequest.html_url}`)
|
slackHelper.sendMessage(robot, room, `Assigned PR to ${dstColumn.name} column\n${pullRequest.html_url}`)
|
||||||
|
@ -211,7 +178,7 @@ async function assignPullRequestToCorrectColumn (github, robot, repo, pullReques
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.DRY_RUN || process.env.DRY_RUN_PR_TO_TEST) {
|
if (process.env.DRY_RUN || process.env.DRY_RUN_PR_TO_TEST) {
|
||||||
robot.log.info(`Would have created card in ${dstColumn.name} column for PR #${prNumber}`)
|
robot.log.info(`Would have created card in ${dstColumn.name} column for PR #${prInfo.number}`)
|
||||||
} else {
|
} else {
|
||||||
// It wasn't in either the source nor the destination columns, let's create a new card for it in the destination column
|
// It wasn't in either the source nor the destination columns, let's create a new card for it in the destination column
|
||||||
const ghcardPayload = await github.projects.createProjectCard({
|
const ghcardPayload = await github.projects.createProjectCard({
|
||||||
|
@ -220,7 +187,7 @@ async function assignPullRequestToCorrectColumn (github, robot, repo, pullReques
|
||||||
content_id: pullRequest.id
|
content_id: pullRequest.id
|
||||||
})
|
})
|
||||||
|
|
||||||
robot.log.info(`${botName} - Created card ${ghcardPayload.data.id} in ${dstColumn.name} for PR #${prNumber}`)
|
robot.log.info(`${botName} - Created card ${ghcardPayload.data.id} in ${dstColumn.name} for PR #${prInfo.number}`)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// We normally arrive here because there is already a card for the PR in another column
|
// We normally arrive here because there is already a card for the PR in another column
|
||||||
|
@ -228,3 +195,27 @@ async function assignPullRequestToCorrectColumn (github, robot, repo, pullReques
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getColumns (state, columns) {
|
||||||
|
switch (state) {
|
||||||
|
case 'awaiting_reviewers':
|
||||||
|
return { srcColumns: [columns.contributor, columns.test], dstColumn: columns.review }
|
||||||
|
case 'changes_requested':
|
||||||
|
return { srcColumns: [columns.review, columns.test], dstColumn: columns.contributor }
|
||||||
|
case 'failed':
|
||||||
|
return { srcColumns: [columns.review, columns.test], dstColumn: columns.contributor }
|
||||||
|
case 'approved':
|
||||||
|
return { srcColumns: [columns.contributor, columns.review], dstColumn: columns.test }
|
||||||
|
default:
|
||||||
|
return { srcColumns: [], dstColumn: null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findColumnByName (ghcolumns, columnName) {
|
||||||
|
const column = ghcolumns.find(c => c.name === columnName)
|
||||||
|
if (!column) {
|
||||||
|
throw new Error(`${botName} - Couldn't find ${columnName} column`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return column
|
||||||
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
// PombeirP
|
// PombeirP
|
||||||
|
|
||||||
const defaultConfig = require('../lib/config')
|
const defaultConfig = require('../lib/config')
|
||||||
|
const slackHelper = require('../lib/slack')
|
||||||
|
|
||||||
const getConfig = require('probot-config')
|
const getConfig = require('probot-config')
|
||||||
const slackHelper = require('../lib/slack')
|
|
||||||
|
|
||||||
const botName = 'assign-new-pr-to-review'
|
const botName = 'assign-new-pr-to-review'
|
||||||
|
|
||||||
|
@ -29,8 +29,7 @@ module.exports = (robot) => {
|
||||||
async function assignPullRequestToReview (context, robot) {
|
async function assignPullRequestToReview (context, robot) {
|
||||||
const { github, payload } = context
|
const { github, payload } = context
|
||||||
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
||||||
const ownerName = payload.repository.owner.login
|
const repoInfo = { owner: payload.repository.owner.login, repo: payload.repository.name }
|
||||||
const repoName = payload.repository.name
|
|
||||||
const prNumber = payload.pull_request.number
|
const prNumber = payload.pull_request.number
|
||||||
|
|
||||||
const projectBoardConfig = config ? config['project-board'] : null
|
const projectBoardConfig = config ? config['project-board'] : null
|
||||||
|
@ -38,7 +37,7 @@ async function assignPullRequestToReview (context, robot) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
robot.log(`${botName} - Handling Pull Request #${prNumber} on repo ${ownerName}/${repoName}`)
|
robot.log(`${botName} - Handling Pull Request #${prNumber} on repo ${repoInfo.owner}/${repoInfo.repo}`)
|
||||||
|
|
||||||
// Fetch repo projects
|
// Fetch repo projects
|
||||||
// TODO: The repo project and project column info should be cached
|
// TODO: The repo project and project column info should be cached
|
||||||
|
@ -47,16 +46,12 @@ async function assignPullRequestToReview (context, robot) {
|
||||||
const projectBoardName = projectBoardConfig.name
|
const projectBoardName = projectBoardConfig.name
|
||||||
const reviewColumnName = projectBoardConfig['review-column-name']
|
const reviewColumnName = projectBoardConfig['review-column-name']
|
||||||
try {
|
try {
|
||||||
const ghprojectsPayload = await github.projects.getRepoProjects({
|
const ghprojectsPayload = await github.projects.getRepoProjects({ ...repoInfo, state: 'open' })
|
||||||
owner: ownerName,
|
|
||||||
repo: repoName,
|
|
||||||
state: 'open'
|
|
||||||
})
|
|
||||||
|
|
||||||
// Find 'Pipeline for QA' project
|
// Find 'Pipeline for QA' project
|
||||||
const project = ghprojectsPayload.data.find(p => p.name === projectBoardName)
|
const project = ghprojectsPayload.data.find(p => p.name === projectBoardName)
|
||||||
if (!project) {
|
if (!project) {
|
||||||
robot.log.error(`${botName} - Couldn't find project ${projectBoardName} in repo ${ownerName}/${repoName}`)
|
robot.log.error(`${botName} - Couldn't find project ${projectBoardName} in repo ${repoInfo.owner}/${repoInfo.repo}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,11 +69,11 @@ async function assignPullRequestToReview (context, robot) {
|
||||||
|
|
||||||
robot.log.debug(`${botName} - Fetched ${column.name} column (${column.id})`)
|
robot.log.debug(`${botName} - Fetched ${column.name} column (${column.id})`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
robot.log.error(`${botName} - Couldn't fetch the github columns for project: ${err}`, ownerName, repoName, project.id)
|
robot.log.error(`${botName} - Couldn't fetch the github columns for project: ${err}`, repoInfo, project.id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
robot.log.error(`${botName} - Couldn't fetch the github projects for repo: ${err}`, ownerName, repoName)
|
robot.log.error(`${botName} - Couldn't fetch the github projects for repo: ${err}`, repoInfo)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,7 @@ module.exports = (robot) => {
|
||||||
|
|
||||||
async function assignIssueToBountyAwaitingForApproval (context, robot, assign) {
|
async function assignIssueToBountyAwaitingForApproval (context, robot, assign) {
|
||||||
const { github, payload } = context
|
const { github, payload } = context
|
||||||
const ownerName = payload.repository.owner.login
|
const repoInfo = { owner: payload.repository.owner.login, repo: payload.repository.name }
|
||||||
const repoName = payload.repository.name
|
|
||||||
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
||||||
const projectBoardConfig = config ? config['bounty-project-board'] : null
|
const projectBoardConfig = config ? config['bounty-project-board'] : null
|
||||||
|
|
||||||
|
@ -52,9 +51,9 @@ async function assignIssueToBountyAwaitingForApproval (context, robot, assign) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assign) {
|
if (assign) {
|
||||||
robot.log(`${botName} - Handling labeling of #${payload.issue.number} with ${payload.label.name} on repo ${ownerName}/${repoName}`)
|
robot.log(`${botName} - Handling labeling of #${payload.issue.number} with ${payload.label.name} on repo ${repoInfo.owner}/${repoInfo.repo}`)
|
||||||
} else {
|
} else {
|
||||||
robot.log(`${botName} - Handling unlabeling of #${payload.issue.number} with ${payload.label.name} on repo ${ownerName}/${repoName}`)
|
robot.log(`${botName} - Handling unlabeling of #${payload.issue.number} with ${payload.label.name} on repo ${repoInfo.owner}/${repoInfo.repo}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch org projects
|
// Fetch org projects
|
||||||
|
@ -64,7 +63,7 @@ async function assignIssueToBountyAwaitingForApproval (context, robot, assign) {
|
||||||
const projectBoardName = projectBoardConfig.name
|
const projectBoardName = projectBoardConfig.name
|
||||||
const approvalColumnName = projectBoardConfig['awaiting-approval-column-name']
|
const approvalColumnName = projectBoardConfig['awaiting-approval-column-name']
|
||||||
try {
|
try {
|
||||||
const orgName = ownerName
|
const orgName = repoInfo.owner
|
||||||
|
|
||||||
const ghprojectsPayload = await github.projects.getOrgProjects({
|
const ghprojectsPayload = await github.projects.getOrgProjects({
|
||||||
org: orgName,
|
org: orgName,
|
||||||
|
@ -92,11 +91,11 @@ async function assignIssueToBountyAwaitingForApproval (context, robot, assign) {
|
||||||
|
|
||||||
robot.log.debug(`${botName} - Fetched ${column.name} column (${column.id})`)
|
robot.log.debug(`${botName} - Fetched ${column.name} column (${column.id})`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
robot.log.error(`${botName} - Couldn't fetch the github columns for project: ${err}`, ownerName, repoName, project.id)
|
robot.log.error(`${botName} - Couldn't fetch the github columns for project: ${err}`, repoInfo, project.id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
robot.log.error(`${botName} - Couldn't fetch the github projects for repo: ${err}`, ownerName, repoName)
|
robot.log.error(`${botName} - Couldn't fetch the github projects for repo: ${err}`, repoInfo)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,19 +33,18 @@ function registerForNewBounties (robot) {
|
||||||
|
|
||||||
async function notifyCollaborators (context, robot) {
|
async function notifyCollaborators (context, robot) {
|
||||||
const { github, payload } = context
|
const { github, payload } = context
|
||||||
const ownerName = payload.repository.owner.login
|
const repoInfo = { owner: payload.repository.owner.login, repo: payload.repository.name }
|
||||||
const repoName = payload.repository.name
|
|
||||||
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
||||||
const bountyProjectBoardConfig = config ? config['bounty-project-board'] : null
|
const bountyProjectBoardConfig = config ? config['bounty-project-board'] : null
|
||||||
const gitHubTeamConfig = config ? config['github-team'] : null
|
const gitHubTeamConfig = config ? config['github-team'] : null
|
||||||
|
|
||||||
if (!bountyProjectBoardConfig) {
|
if (!bountyProjectBoardConfig) {
|
||||||
robot.log.debug(`${botName} - Bounty project board not configured in repo ${ownerName}/${repoName}, ignoring`)
|
robot.log.debug(`${botName} - Bounty project board not configured in repo ${repoInfo.owner}/${repoInfo.repo}, ignoring`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gitHubTeamConfig) {
|
if (!gitHubTeamConfig) {
|
||||||
robot.log.debug(`${botName} - GitHub team not configured in repo ${ownerName}/${repoName}, ignoring`)
|
robot.log.debug(`${botName} - GitHub team not configured in repo ${repoInfo.owner}/${repoInfo.repo}, ignoring`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,9 +54,9 @@ async function notifyCollaborators (context, robot) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
robot.log(`${botName} - issue #${payload.issue.number} on ${ownerName}/${repoName} was labeled as a bounty awaiting approval. Pinging slack...`)
|
robot.log(`${botName} - issue #${payload.issue.number} on ${repoInfo.owner}/${repoInfo.repo} was labeled as a bounty awaiting approval. Pinging slack...`)
|
||||||
|
|
||||||
const slackCollaborators = await getSlackCollaborators(ownerName, repoName, github, robot, gitHubTeamConfig)
|
const slackCollaborators = await getSlackCollaborators(repoInfo, github, robot, gitHubTeamConfig)
|
||||||
|
|
||||||
// Mention the project board owner as well, if configured
|
// Mention the project board owner as well, if configured
|
||||||
const bountyProjectBoardOwner = bountyProjectBoardConfig['owner']
|
const bountyProjectBoardOwner = bountyProjectBoardConfig['owner']
|
||||||
|
@ -82,15 +81,15 @@ function randomInt (low, high) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the Slack IDs of the collaborators of this repo.
|
// Get the Slack IDs of the collaborators of this repo.
|
||||||
async function getSlackCollaborators (ownerName, repoName, github, robot, gitHubTeamConfig) {
|
async function getSlackCollaborators (repoInfo, github, robot, gitHubTeamConfig) {
|
||||||
const teamSlug = gitHubTeamConfig['slug']
|
const teamSlug = gitHubTeamConfig['slug']
|
||||||
if (!teamSlug) {
|
if (!teamSlug) {
|
||||||
robot.log.debug(`${botName} - GitHub team slug not configured in repo ${ownerName}/${repoName}, ignoring`)
|
robot.log.debug(`${botName} - GitHub team slug not configured in repo ${repoInfo.owner}/${repoInfo.repo}, ignoring`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab a list of collaborators to this repo, as an array of GitHub login usernames
|
// Grab a list of collaborators to this repo, as an array of GitHub login usernames
|
||||||
const teams = await github.paginate(github.orgs.getTeams({org: ownerName}), res => res.data)
|
const teams = await github.paginate(github.orgs.getTeams({ org: repoInfo.owner }), res => res.data)
|
||||||
const team = teams.find(t => t.slug === teamSlug)
|
const team = teams.find(t => t.slug === teamSlug)
|
||||||
if (!team) {
|
if (!team) {
|
||||||
robot.log.debug(`${botName} - GitHub team with slug ${teamSlug} was not found. Ignoring`)
|
robot.log.debug(`${botName} - GitHub team with slug ${teamSlug} was not found. Ignoring`)
|
||||||
|
|
|
@ -43,21 +43,19 @@ function executeTemplate (templateString, templateVars) {
|
||||||
async function greetNewContributor (context, robot) {
|
async function greetNewContributor (context, robot) {
|
||||||
const { github, payload } = context
|
const { github, payload } = context
|
||||||
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
||||||
const ownerName = payload.repository.owner.login
|
const repoInfo = { owner: payload.repository.owner.login, repo: payload.repository.name }
|
||||||
const repoName = payload.repository.name
|
const prInfo = { ...repoInfo, number: payload.pull_request.number }
|
||||||
const prNumber = payload.pull_request.number
|
|
||||||
|
|
||||||
const welcomeBotConfig = config ? config['welcome-bot'] : null
|
const welcomeBotConfig = config ? config['welcome-bot'] : null
|
||||||
if (!welcomeBotConfig) {
|
if (!welcomeBotConfig) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
robot.log(`${botName} - Handling Pull Request #${prNumber} on repo ${ownerName}/${repoName}`)
|
robot.log(`${botName} - Handling Pull Request #${prInfo.number} on repo ${repoInfo.owner}/${repoInfo.repo}`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const ghissuesPayload = await github.issues.getForRepo({
|
const ghissuesPayload = await github.issues.getForRepo({
|
||||||
owner: ownerName,
|
...repoInfo,
|
||||||
repo: repoName,
|
|
||||||
state: 'all',
|
state: 'all',
|
||||||
creator: payload.pull_request.user.login
|
creator: payload.pull_request.user.login
|
||||||
})
|
})
|
||||||
|
@ -65,30 +63,28 @@ async function greetNewContributor (context, robot) {
|
||||||
const userPullRequests = ghissuesPayload.data.filter(issue => issue.pull_request)
|
const userPullRequests = ghissuesPayload.data.filter(issue => issue.pull_request)
|
||||||
if (userPullRequests.length === 1) {
|
if (userPullRequests.length === 1) {
|
||||||
try {
|
try {
|
||||||
const welcomeMessage = executeTemplate(welcomeBotConfig['message-template'], { user: payload.pull_request.user.login, 'pr-number': prNumber, 'repo-name': repoName })
|
const welcomeMessage = executeTemplate(welcomeBotConfig['message-template'], { user: payload.pull_request.user.login, 'pr-number': prInfo.number, 'repo-name': repoInfo.repo })
|
||||||
|
|
||||||
if (process.env.DRY_RUN) {
|
if (process.env.DRY_RUN) {
|
||||||
robot.log(`${botName} - Would have created comment in GHI`, ownerName, repoName, prNumber, welcomeMessage)
|
robot.log(`${botName} - Would have created comment in GHI`, prInfo, welcomeMessage)
|
||||||
} else {
|
} else {
|
||||||
await github.issues.createComment({
|
await github.issues.createComment({
|
||||||
owner: ownerName,
|
...prInfo,
|
||||||
repo: repoName,
|
|
||||||
number: prNumber,
|
|
||||||
body: welcomeMessage
|
body: welcomeMessage
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send message to Slack
|
// Send message to Slack
|
||||||
slackHelper.sendMessage(robot, config.slack.notification.room, `Greeted ${payload.pull_request.user.login} on his first PR in the ${repoName} repo\n${payload.pull_request.html_url}`)
|
slackHelper.sendMessage(robot, config.slack.notification.room, `Greeted ${payload.pull_request.user.login} on his first PR in the ${repoInfo.repo} repo\n${payload.pull_request.html_url}`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code !== 404) {
|
if (err.code !== 404) {
|
||||||
robot.log.error(`${botName} - Couldn't create comment on PR: ${err}`, ownerName, repoName)
|
robot.log.error(`${botName} - Couldn't create comment on PR: ${err}`, repoInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
robot.log.debug(`${botName} - This is not the user's first PR on the repo, ignoring`, ownerName, repoName, payload.pull_request.user.login)
|
robot.log.debug(`${botName} - This is not the user's first PR on the repo, ignoring`, repoInfo, payload.pull_request.user.login)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
robot.log.error(`${botName} - Couldn't fetch the user's github issues for repo: ${err}`, ownerName, repoName)
|
robot.log.error(`${botName} - Couldn't fetch the user's github issues for repo: ${err}`, repoInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ async function processChangedProjectCard (robot, context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const repoInfo = { owner: repo.owner.login, name: repo.name }
|
||||||
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
|
||||||
const projectBoardConfig = config ? config['project-board'] : null
|
const projectBoardConfig = config ? config['project-board'] : null
|
||||||
const automatedTestsConfig = config ? config['automated-tests'] : null
|
const automatedTestsConfig = config ? config['automated-tests'] : null
|
||||||
|
@ -81,12 +82,10 @@ async function processChangedProjectCard (robot, context) {
|
||||||
return a[a.length + index]
|
return a[a.length + index]
|
||||||
}
|
}
|
||||||
|
|
||||||
let project
|
|
||||||
try {
|
try {
|
||||||
const projectId = last(inTestColumn.project_url.split('/'), -1)
|
const projectId = last(inTestColumn.project_url.split('/'), -1)
|
||||||
const projectPayload = await github.projects.getProject({ id: projectId })
|
const projectPayload = await github.projects.getProject({ id: projectId })
|
||||||
|
const project = projectPayload.data
|
||||||
project = projectPayload.data
|
|
||||||
if (project.name !== projectBoardName) {
|
if (project.name !== projectBoardName) {
|
||||||
robot.log.trace(`${botName} - Card column name doesn't match watched column name, exiting`, project.name, projectBoardName)
|
robot.log.trace(`${botName} - Card column name doesn't match watched column name, exiting`, project.name, projectBoardName)
|
||||||
return
|
return
|
||||||
|
@ -99,52 +98,52 @@ async function processChangedProjectCard (robot, context) {
|
||||||
const prNumber = last(payload.project_card.content_url.split('/'), -1)
|
const prNumber = last(payload.project_card.content_url.split('/'), -1)
|
||||||
const fullJobName = automatedTestsConfig['job-full-name']
|
const fullJobName = automatedTestsConfig['job-full-name']
|
||||||
|
|
||||||
await processPullRequest(github, robot, repo.owner.login, repo.name, prNumber, fullJobName)
|
await processPullRequest(github, robot, { ...repoInfo, number: prNumber }, fullJobName)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processPullRequest (github, robot, repoOwner, repoName, prNumber, fullJobName) {
|
async function processPullRequest (github, robot, prInfo, fullJobName) {
|
||||||
// Remove the PR from the pending PR list, if it is there
|
// Remove the PR from the pending PR list, if it is there
|
||||||
pendingPullRequests.delete(prNumber)
|
pendingPullRequests.delete(prInfo.number)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const state = await gitHubHelpers.getReviewApprovalState(github, robot, repoOwner, repoName, prNumber)
|
const state = await gitHubHelpers.getReviewApprovalState(github, robot, prInfo)
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case 'unstable':
|
case 'unstable':
|
||||||
case 'awaiting_reviewers':
|
case 'awaiting_reviewers':
|
||||||
case 'changes_requested':
|
case 'changes_requested':
|
||||||
pendingPullRequests.set(prNumber, { github: github, repoOwner: repoOwner, repoName: repoName, fullJobName: fullJobName })
|
pendingPullRequests.set(prInfo.number, { github: github, prInfo, fullJobName: fullJobName })
|
||||||
robot.log.debug(`${botName} - State is '${state}', adding to backlog to check periodically`, prNumber)
|
robot.log.debug(`${botName} - State is '${state}', adding to backlog to check periodically`, prInfo)
|
||||||
return
|
return
|
||||||
case 'failed':
|
case 'failed':
|
||||||
robot.log.debug(`${botName} - State is '${state}', exiting`, prNumber)
|
robot.log.debug(`${botName} - State is '${state}', exiting`, prInfo)
|
||||||
return
|
return
|
||||||
case 'approved':
|
case 'approved':
|
||||||
robot.log.debug(`${botName} - State is '${state}', proceeding`, prNumber)
|
robot.log.debug(`${botName} - State is '${state}', proceeding`, prInfo)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
robot.log.warn(`${botName} - State is '${state}', ignoring`, prNumber)
|
robot.log.warn(`${botName} - State is '${state}', ignoring`, prInfo)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
robot.log.error(`Couldn't calculate the PR approval state: ${err}`, repoOwner, repoName, prNumber)
|
robot.log.error(`Couldn't calculate the PR approval state: ${err}`, prInfo)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const args = { parameters: { pr_id: prNumber, apk: `--apk=${prNumber}.apk` } }
|
const args = { parameters: { pr_id: prInfo.number, apk: `--apk=${prInfo.number}.apk` } }
|
||||||
|
|
||||||
if (process.env.DRY_RUN) {
|
if (process.env.DRY_RUN) {
|
||||||
robot.log(`${botName} - Would start ${fullJobName} job in Jenkins`, prNumber, args)
|
robot.log(`${botName} - Would start ${fullJobName} job in Jenkins`, prInfo, args)
|
||||||
} else {
|
} else {
|
||||||
robot.log(`${botName} - Starting ${fullJobName} job in Jenkins`, prNumber, args)
|
robot.log(`${botName} - Starting ${fullJobName} job in Jenkins`, prInfo, args)
|
||||||
const buildId = await jenkins.job.build(fullJobName, args)
|
const buildId = await jenkins.job.build(fullJobName, args)
|
||||||
robot.log(`${botName} - Started job in Jenkins`, prNumber, buildId)
|
robot.log(`${botName} - Started job in Jenkins`, prInfo, buildId)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
robot.log.error(`${botName} - Error while triggering Jenkins build. Will retry later`, prNumber, error)
|
robot.log.error(`${botName} - Error while triggering Jenkins build. Will retry later`, prInfo, error)
|
||||||
|
|
||||||
pendingPullRequests.set(prNumber, { github: github, repoOwner: repoOwner, repoName: repoName, fullJobName: fullJobName })
|
pendingPullRequests.set(prInfo.number, { github: github, prInfo: prInfo, fullJobName: fullJobName })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,11 +152,8 @@ async function checkPendingPullRequests (robot) {
|
||||||
|
|
||||||
robot.log.trace(`${botName} - Processing ${_pendingPullRequests.size} pending PRs`)
|
robot.log.trace(`${botName} - Processing ${_pendingPullRequests.size} pending PRs`)
|
||||||
|
|
||||||
for (const kvp of _pendingPullRequests.entries()) {
|
for (const { github, prInfo, fullJobName } of _pendingPullRequests.values()) {
|
||||||
const prNumber = kvp[0]
|
await processPullRequest(github, robot, prInfo, fullJobName)
|
||||||
const { github, repoOwner, repoName, fullJobName } = kvp[1]
|
|
||||||
|
|
||||||
await processPullRequest(github, robot, repoOwner, repoName, prNumber, fullJobName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
robot.log.trace(`${botName} - Finished processing ${_pendingPullRequests.size} pending PRs`)
|
robot.log.trace(`${botName} - Finished processing ${_pendingPullRequests.size} pending PRs`)
|
||||||
|
|
29
index.js
29
index.js
|
@ -3,18 +3,7 @@ const Slack = require('./lib/slack')
|
||||||
module.exports = async (robot) => {
|
module.exports = async (robot) => {
|
||||||
console.log('Yay, the app was loaded!')
|
console.log('Yay, the app was loaded!')
|
||||||
|
|
||||||
Slack(robot, slack => {})
|
await setupSlack(robot)
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
robot.on('slack.connected', event => {
|
|
||||||
robot.log.info(`Connected to Slack`)
|
|
||||||
|
|
||||||
// Copy Slack RTM and Slack Web clients to the robot object
|
|
||||||
robot['slack'] = event.payload.slack
|
|
||||||
robot['slackWeb'] = event.payload.slackWeb
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
robot['gitHubIdMapper'] = require('./lib/github-id-mapper')(robot)
|
robot['gitHubIdMapper'] = require('./lib/github-id-mapper')(robot)
|
||||||
|
|
||||||
|
@ -32,3 +21,19 @@ module.exports = async (robot) => {
|
||||||
// To get your app running against GitHub, see:
|
// To get your app running against GitHub, see:
|
||||||
// https://probot.github.io/docs/development/
|
// https://probot.github.io/docs/development/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function setupSlack (robot) {
|
||||||
|
Slack(robot, slack => {})
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
robot.on('slack.connected', event => {
|
||||||
|
robot.log.info(`Connected to Slack`)
|
||||||
|
|
||||||
|
// Copy Slack RTM and Slack Web clients to the robot object
|
||||||
|
robot['slack'] = event.payload.slack
|
||||||
|
robot['slackWeb'] = event.payload.slackWeb
|
||||||
|
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -11,10 +11,10 @@ module.exports.getPullRequestReviewStates = _getPullRequestReviewStates
|
||||||
module.exports.getReviewApprovalState = _getReviewApprovalState
|
module.exports.getReviewApprovalState = _getReviewApprovalState
|
||||||
module.exports.getProjectCardForIssue = _getProjectCardForIssue
|
module.exports.getProjectCardForIssue = _getProjectCardForIssue
|
||||||
|
|
||||||
async function _getPullRequestReviewStates (github, repoOwner, repoName, prNumber) {
|
async function _getPullRequestReviewStates (github, prInfo) {
|
||||||
let finalReviewsMap = new Map()
|
let finalReviewsMap = new Map()
|
||||||
const ghreviews = await github.paginate(
|
const ghreviews = await github.paginate(
|
||||||
github.pullRequests.getReviews({owner: repoOwner, repo: repoName, number: prNumber, per_page: 100}),
|
github.pullRequests.getReviews({ ...prInfo, per_page: 100 }),
|
||||||
res => res.data)
|
res => res.data)
|
||||||
for (var review of ghreviews) {
|
for (var review of ghreviews) {
|
||||||
switch (review.state) {
|
switch (review.state) {
|
||||||
|
@ -29,9 +29,9 @@ async function _getPullRequestReviewStates (github, repoOwner, repoName, prNumbe
|
||||||
return Array.from(finalReviewsMap.values())
|
return Array.from(finalReviewsMap.values())
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _getReviewApprovalState (github, robot, repoOwner, repoName, prNumber) {
|
async function _getReviewApprovalState (github, robot, prInfo) {
|
||||||
// Get detailed pull request
|
// Get detailed pull request
|
||||||
const pullRequestPayload = await github.pullRequests.get({owner: repoOwner, repo: repoName, number: prNumber})
|
const pullRequestPayload = await github.pullRequests.get(prInfo)
|
||||||
const pullRequest = pullRequestPayload.data
|
const pullRequest = pullRequestPayload.data
|
||||||
if (pullRequest.mergeable !== null && pullRequest.mergeable !== undefined && !pullRequest.mergeable) {
|
if (pullRequest.mergeable !== null && pullRequest.mergeable !== undefined && !pullRequest.mergeable) {
|
||||||
robot.log.debug(`pullRequest.mergeable is ${pullRequest.mergeable}, considering as failed`)
|
robot.log.debug(`pullRequest.mergeable is ${pullRequest.mergeable}, considering as failed`)
|
||||||
|
@ -55,7 +55,7 @@ async function _getReviewApprovalState (github, robot, repoOwner, repoName, prNu
|
||||||
|
|
||||||
const threshold = 2 // Minimum number of approvers
|
const threshold = 2 // Minimum number of approvers
|
||||||
|
|
||||||
const finalReviews = await _getPullRequestReviewStates(github, repoOwner, repoName, pullRequest.number)
|
const finalReviews = await _getPullRequestReviewStates(github, prInfo)
|
||||||
robot.log.debug(finalReviews)
|
robot.log.debug(finalReviews)
|
||||||
|
|
||||||
const approvedReviews = finalReviews.filter(reviewState => reviewState === 'APPROVED')
|
const approvedReviews = finalReviews.filter(reviewState => reviewState === 'APPROVED')
|
||||||
|
|
Loading…
Reference in New Issue