Skip to content

Commit

Permalink
#440 feat: added support for task lists in PR
Browse files Browse the repository at this point in the history
  • Loading branch information
tunix committed Oct 17, 2016
1 parent 6b01cd8 commit 36286e0
Show file tree
Hide file tree
Showing 9 changed files with 1,150 additions and 6 deletions.
1 change: 1 addition & 0 deletions .node-version
@@ -0,0 +1 @@
5.7.1
78 changes: 78 additions & 0 deletions server/checks/PullRequestTasks.js
@@ -0,0 +1,78 @@
import Check, { getPayloadFn } from './Check'
import { PULL_REQUEST } from '../model/GithubEvents'
import { logger } from '../../common/debug'

const CHECK_TYPE = 'pullrequesttasks'
const CONTEXT = 'zappr/pr/tasks'
const info = logger(CHECK_TYPE, 'info')
const error = logger(CHECK_TYPE, 'error')
const debug = logger(CHECK_TYPE)
const createStatePayload = getPayloadFn(CONTEXT)

export function countOpenTasks(prBody, repoName = "", prNo = "") {
const regex = /(-|\*) \[(\s|x)\]/g;
let count = 0;
let match;

while ((match = regex.exec(prBody)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (match.index === regex.lastIndex) {
regex.lastIndex++;
}

let task = match[0];
let marker = match[2];

debug(`${repoName}#${prNo}: Processing task: ${task}`);

if (marker === " ") {
count++;
}
}

info(`${repoName}#${prNo}: PR has ${count} open tasks.`);

return count;
}

export default class PullRequestTasks extends Check {
static TYPE = CHECK_TYPE;
static CONTEXT = CONTEXT;
static HOOK_EVENTS = [PULL_REQUEST];
static NAME = 'Pull request tasks check'

constructor(github) {
super()
this.github = github;
}

async execute(config, hookPayload, token) {
const {action, repository, number, pull_request} = hookPayload
const repoOwner = repository.owner.login
const repoName = repository.name
const fullName = repository.full_name
let status;

try {
if (pull_request.state === 'open' && ['opened', 'edited', 'reopened'].indexOf(action) !== -1) {
let openTaskCount = countOpenTasks(pull_request.body, repoName, number);
let msg;

if (openTaskCount > 0) {
info(`${fullName}#${number}: Failed the PR due to open tasks.`);
status = createStatePayload(`PR has ${openTaskCount} open tasks.`, 'failure');
} else {
msg = `PR has no open tasks.`;
info(`${fullName}#${number}: ${msg}`);
status = createStatePayload(msg);
}

await this.github.setCommitStatus(repoOwner, repoName, pull_request.head.sha, status, token);
}
} catch (e) {
error(`${fullName}#${number}: Could not execute Pull Request Tasks check`, e)
status = createStatePayload(`Error: ${e.message}`, 'error')
await this.github.setCommitStatus(repoOwner, repoName, pull_request.head.sha, status, token);
}
}
}
9 changes: 6 additions & 3 deletions server/checks/index.js
Expand Up @@ -3,21 +3,24 @@ import Autobranch from './Autobranch'
import CommitMessage from './CommitMessage'
import Specification from './Specification'
import PullRequestLabels from './PullRequestLabels'
import PullRequestTasks from './PullRequestTasks'

const CHECKS = {
[Approval.TYPE]: Approval,
[Autobranch.TYPE]: Autobranch,
[CommitMessage.TYPE]: CommitMessage,
[Specification.TYPE]: Specification,
[PullRequestLabels.TYPE]: PullRequestLabels
[PullRequestLabels.TYPE]: PullRequestLabels,
[PullRequestTasks.TYPE]: PullRequestTasks
}

export const CHECK_NAMES = {
[Approval.TYPE]: Approval.NAME,
[Autobranch.TYPE]: Autobranch.NAME,
[CommitMessage.TYPE]: CommitMessage.NAME,
[Specification.TYPE]: Specification.NAME,
[PullRequestLabels.TYPE]: PullRequestLabels.NAME
[PullRequestLabels.TYPE]: PullRequestLabels.NAME,
[PullRequestTasks.TYPE]: PullRequestTasks.NAME
}

export const CHECK_TYPES = Object.keys(CHECKS)
Expand All @@ -26,4 +29,4 @@ export function getCheckByType(type) {
return CHECKS[type]
}

export { Approval, Autobranch, CommitMessage, Specification, PullRequestLabels }
export { Approval, Autobranch, CommitMessage, Specification, PullRequestLabels, PullRequestTasks }
9 changes: 8 additions & 1 deletion server/handler/HookHandler.js
Expand Up @@ -3,7 +3,8 @@ import {
Autobranch,
CommitMessage,
Specification,
PullRequestLabels
PullRequestLabels,
PullRequestTasks
} from '../checks'
import createAuditService from '../service/AuditServiceCreator'
import { logger } from '../../common/debug'
Expand Down Expand Up @@ -34,6 +35,7 @@ class HookHandler {
this.commitMessage = new CommitMessage(this.githubService)
this.specification = new Specification(this.githubService)
this.pullrequestlabels = new PullRequestLabels(this.githubService)
this.pullrequesttasks = new PullRequestTasks(this.githubService)
}

/**
Expand Down Expand Up @@ -85,6 +87,11 @@ class HookHandler {
this.pullrequestlabels.execute(config, payload, token)
)
}
if (PullRequestTasks.isTriggeredBy(event)) {
getToken(repo, PullRequestTasks.TYPE).then(token =>
this.pullrequesttasks.execute(config, payload, token)
)
}
}
return {
message: "THANKS"
Expand Down
4 changes: 2 additions & 2 deletions server/model/GithubEvents.js
Expand Up @@ -60,8 +60,8 @@ export const PUBLIC = 'public'
*/
export const PULL_REQUEST_REVIEW_COMMENT = 'pull_request_review_comment'
/**
* Any time a Pull Request is assigned, unassigned, labeled, unlabeled, opened, closed, reopened, or synchronized
* (updated due to a new push in the branch that the pull request is tracking).
* Any time a Pull Request is assigned, unassigned, labeled, unlabeled, opened, edited, closed, reopened,
* or synchronized (updated due to a new push in the branch that the pull request is tracking).
*/
export const PULL_REQUEST = 'pull_request'
/**
Expand Down

0 comments on commit 36286e0

Please sign in to comment.