'use strict' const githubClient = require('./github-client') const { createPrComment } = require('./github-comment') function pushStarted (options, build, cb) { const pr = findPrInRef(build.ref) // create unique logger which is easily traceable for every subsequent log statement const traceFields = { pr, job: build.identifier, gitRef: build.ref, status: build.status } const logger = options.logger.child(traceFields, true) const optsWithPr = Object.assign({ pr }, options) if (build.status === 'pending') { switch (build.identifier) { case 'node-test-pull-request': createPrComment(Object.assign({ issue_number: pr }, options), `CI: ${build.url}`) break case 'node-test-pull-request-lite-pipeline': createPrComment(Object.assign({ issue_number: pr }, options), `Lite-CI: ${build.url}`) break default: break } } findLatestCommitInPr(optsWithPr).then(latestCommit => { const statusOpts = Object.assign({ sha: latestCommit.sha, url: build.url, context: build.identifier, state: build.status, message: build.message || 'running tests' }, options) createGhStatus(statusOpts, logger).then(cb).catch(cb) }, err => { logger.error(err, 'Got error when retrieving GitHub commits for PR') return cb(err) }) } function pushEnded (options, build, cb) { const pr = findPrInRef(build.ref) // create unique logger which is easily traceable for every subsequent log statement const traceFields = { pr, job: build.identifier, gitRef: build.ref, status: build.status } const logger = options.logger.child(traceFields, true) const optsWithPr = Object.assign({ pr }, options) findLatestCommitInPr(optsWithPr).then(latestCommit => { const statusOpts = Object.assign({ sha: latestCommit.sha, url: build.url, context: build.identifier, state: build.status, message: build.message || 'all tests passed' }, options) createGhStatus(statusOpts, logger).then(cb, cb) }, err => { logger.error(err, 'Got error when retrieving GitHub commits for PR') return cb(err) }) } function findPrInRef (gitRef) { // refs/pull/12345/head return parseInt(gitRef.split('/')[2], 10) } async function findLatestCommitInPr (options, pageNumber = 1) { const res = await githubClient.pulls.listCommits({ owner: options.owner, repo: options.repo, pull_number: options.pr, page: pageNumber, per_page: 100 }) const commitMetas = res.data || [] const lastPageURL = githubClient.hasLastPage(res) if (lastPageURL) { return findLatestCommitInPr(options, pageNumberFromURL(lastPageURL)) } const lastCommitMeta = commitMetas.pop() const lastCommit = { sha: lastCommitMeta.sha, date: lastCommitMeta.commit.committer.date } return lastCommit } async function createGhStatus (options, logger) { try { await githubClient.repos.createStatus({ owner: options.owner, repo: options.repo, sha: options.sha, target_url: options.url, context: options.context, state: options.state, description: options.message }) } catch (err) { logger.error(err, 'Error while updating Jenkins / GitHub PR status') throw err } logger.info('Jenkins / Github PR status updated') } function validate (payload) { const isString = (param) => typeof (payload[param]) === 'string' return ['identifier', 'status', 'message', 'commit', 'url'].every(isString) } function pageNumberFromURL (githubUrl) { return new URL(githubUrl).searchParams.get('page') } exports.validate = validate exports.pushStarted = pushStarted exports.pushEnded = pushEnded exports.findLatestCommitInPr = findLatestCommitInPr