assign-approved-pr-to-test: Filter out statuses from `e2e-tests-check-bot` in `getReviewApprovalState` when state is `unstable`

This commit is contained in:
Pedro Pombeiro 2019-01-22 14:00:23 +01:00
parent 733794a7c3
commit bc135c4c2e
No known key found for this signature in database
GPG Key ID: A65DEB11E4BBC647
6 changed files with 695 additions and 309 deletions

View File

@ -38,6 +38,7 @@ To get your environment set up, go through the following steps:
```
After this, you can start the bot by running the following:
```sh
npm start
```
@ -119,7 +120,7 @@ Examples of settings that can be configured:
- `bounty-project-board/awaiting-approval-label-name`: Name of the label used in issues to declare that an issue is awaiting approval to become a bounty
- `bounty-project-board/bounty-label-name`: Name of the label used in issues to declare that an issue is a bounty
- `bounty-project-board/bounty-size-label-name-regex`: Regular expression that matches the bounty size label and returns a group containing the size itself
- `bounty-project-board/post-approved-bounties-to-slack-room`: Name of the Slack room where to cross-post approved bounties
- `bounty-project-board/post-approved-bounties-to-slack-room`: Name of the Slack room where to cross-post approved bounties
- Automated tests settings:
- `automated-tests/repo-full-name`: Full name of the repo to watch in project cards in order to automatically run automated tests CI job (e.g. `status-im/status-react`)

View File

@ -22,11 +22,28 @@ const botName = 'assign-approved-pr-to-test'
module.exports = robot => {
createScheduler(robot, { interval: 10 * 60 * 1000, delay: !process.env.DISABLE_DELAY })
robot.on('schedule.repository', context => checkOpenPullRequests(robot, context))
robot.on('pull_request.opened', context => handleOpenedPullRequest(robot, context))
}
// This method creates a sentinel status in new PRs so that they can't be merged before an e2e test run has successfully completed
async function handleOpenedPullRequest (robot, context) {
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
const projectBoardConfig = config ? config['project-board'] : null
const automatedTestsConfig = config ? config['automated-tests'] : null
if (!projectBoardConfig || !automatedTestsConfig) {
return
}
await context.github.repos.createStatus(context.repo({
context: 'Mobile e2e tests',
description: 'Tests will run once the PR is moved to the TO TEST column',
sha: context.payload.pull_request.head.sha,
state: 'error'
}))
}
async function checkOpenPullRequests (robot, context) {
const { github, payload } = context
const repo = payload.repository
const { github, payload: { repository: repo } } = context
const repoInfo = context.repo()
const config = await getConfig(context, 'github-bot.yml', defaultConfig(robot, '.github/github-bot.yml'))
const projectBoardConfig = config ? config['project-board'] : null
@ -94,7 +111,12 @@ async function assignPullRequestToCorrectColumn (context, robot, repo, pullReque
let state = null
try {
state = await gitHubHelpers.getReviewApprovalState(github, robot, prInfo, testedPullRequestLabelName)
// Ignore statuses created by us
const filterFn = (status) => !(status.context === 'Mobile e2e tests' &&
status.creator &&
(status.creator.login === 'status-github-bot[bot]' || status.creator.login === 'e2e-tests-check-bot[bot]'))
state = await gitHubHelpers.getReviewApprovalState(context, robot, prInfo, testedPullRequestLabelName, filterFn)
} catch (err) {
robot.log.error(`${botName} - Couldn't calculate the PR approval state: ${err}`, prInfo)
}

View File

@ -9,7 +9,7 @@
// Author:
// PombeirP
//const Slack = require('./lib/slack')
// const Slack = require('./lib/slack')
const memjs = require('memjs')
module.exports = async (robot) => {

View File

@ -35,10 +35,13 @@ async function _getPullRequestReviewStates (github, prInfo) {
return Array.from(finalReviewsMap.values())
}
async function _getReviewApprovalState (github, robot, prInfo, testedPullRequestLabelName) {
async function _getReviewApprovalState (context, robot, prInfo, testedPullRequestLabelName, filterIgnoredStatusContextFn) {
const { github } = context
// Get detailed pull request
const pullRequestPayload = await github.pullRequests.get(prInfo)
const pullRequest = pullRequestPayload.data
context.payload.pull_request = pullRequest
if (pullRequest.mergeable !== null && pullRequest.mergeable !== undefined && !pullRequest.mergeable) {
robot.log.debug(`pullRequest.mergeable is ${pullRequest.mergeable}, considering as failed`)
return 'failed'
@ -57,6 +60,15 @@ async function _getReviewApprovalState (github, robot, prInfo, testedPullRequest
case 'dirty':
state = 'failed'
break
case 'unstable':
if (filterIgnoredStatusContextFn) {
const isSuccess = await _isPullRequestStatusSuccessIgnoringContext(context, filterIgnoredStatusContextFn, pullRequest)
if (isSuccess) {
state = 'approved'
robot.log.debug(`All important statuses are successful, so considering state as $${state}`)
}
}
break
}
robot.log.debug(`pullRequest.mergeable_state is ${pullRequest.mergeable_state}, considering state as ${state}`)
@ -179,3 +191,44 @@ async function _getPullRequestCurrentStatusForContext (context, statusContext, p
return (statuses.find(status => status.context === statusContext) || {}).state
}
async function _isPullRequestStatusSuccessIgnoringContext (context, filterIgnoredStatusContextFn, pullRequest) {
if (!pullRequest) {
pullRequest = context.payload.pull_request
}
const statuses = await context.github.paginate(
context.github.repos.listStatusesForRef(context.repo({
ref: pullRequest.head.sha,
per_page: 100
})),
res => res.data)
const contexts = {}
for (let i = statuses.length - 1; i >= 0; i--) {
const status = statuses[i]
if (filterIgnoredStatusContextFn(status)) {
contexts[status.context] = status.state
}
}
let isSuccess = true
for (const context in contexts) {
if (contexts.hasOwnProperty(context)) {
const state = contexts[context]
switch (state) {
case 'pending':
case 'error':
isSuccess = false
break
}
if (!isSuccess) {
break
}
}
}
return isSuccess
}

910
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -19,18 +19,18 @@
"joi": "^13.7.0",
"mem-cache": "0.0.5",
"memjs": "^1.2.0",
"probot": "^5.0.1",
"probot": "^7.5.0",
"probot-config": "^0.1.0",
"probot-scheduler": "^1.2.0"
},
"devDependencies": {
"eslint-config-standard": "^11.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-import": "^2.15.0",
"eslint-plugin-node": "^5.2.1",
"eslint-plugin-promise": "^3.8.0",
"eslint-plugin-standard": "^3.1.0",
"ethereumjs-util": "^5.2.0",
"husky": "^1.1.1",
"husky": "^1.3.1",
"jest": "^22.4.4",
"smee-client": "^1.0.2",
"standard": "^10.0.3"