From ac00b48bcc85c5555eb28e11f596406718d8ca88 Mon Sep 17 00:00:00 2001 From: Jon Moss Date: Thu, 31 May 2018 15:43:47 -0400 Subject: [PATCH 1/3] jenkins: start CI run on new pull requests This will start a CI build on all new pull requests in nodejs/node, that are opened by project collaborators --- scripts/trigger-jenkins-build.js | 31 +++++++++ .../integration/trigger-jenkins-build.test.js | 67 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 test/integration/trigger-jenkins-build.test.js diff --git a/scripts/trigger-jenkins-build.js b/scripts/trigger-jenkins-build.js index 80a53eea..231fab78 100644 --- a/scripts/trigger-jenkins-build.js +++ b/scripts/trigger-jenkins-build.js @@ -124,4 +124,35 @@ module.exports = (app) => { githubClient.repos.checkCollaborator({ owner, repo, username: commentAuthor }, triggerBuildWhenCollaborator) }) }) + + app.on('pull_request.opened', function handlePullCreated (event, owner, repo) { + const { number, logger, pull_request } = event + const pullRequestAuthor = pull_request.user.login + const options = { + owner, + repo, + number, + logger + } + + function replyToCollabWithBuildStarted (err, buildUrl) { + if (err) { + logger.error(err, 'Error while triggering Jenkins build') + return createPrComment(options, `@${pullRequestAuthor} sadly an error occured when I tried to trigger a build :(`) + } + + createPrComment(options, `@${pullRequestAuthor} build started: ${buildUrl}`) + logger.info({ buildUrl }, 'Jenkins build started') + } + + function triggerBuildWhenCollaborator (err) { + if (err) { + return logger.debug(`Ignoring comment to me by @${pullRequestAuthor} because they are not a repo collaborator`) + } + + triggerBuild(options, replyToCollabWithBuildStarted) + } + + githubClient.repos.checkCollaborator({ owner, repo, username: pullRequestAuthor }, triggerBuildWhenCollaborator) + }) } diff --git a/test/integration/trigger-jenkins-build.test.js b/test/integration/trigger-jenkins-build.test.js new file mode 100644 index 00000000..94ae734f --- /dev/null +++ b/test/integration/trigger-jenkins-build.test.js @@ -0,0 +1,67 @@ +'use strict' + +const tap = require('tap') +const url = require('url') +const nock = require('nock') +const supertest = require('supertest') +const proxyquire = require('proxyquire') +const lolex = require('lolex') +const readFixture = require('../read-fixture') + +const app = proxyquire('../../app', { + './github-secret': { + isValid: () => true, + + // necessary to make makes proxyquire return this stub + // whenever *any* module tries to require('./github-secret') + '@global': true + } +}) + +tap.test('Sends POST request to https://ci.nodejs.org', (t) => { + const clock = lolex.install() + + const originalJobUrlValue = process.env.JENKINS_JOB_URL_NODE + const originalTokenValue = process.env.JENKINS_BUILD_TOKEN_NODE + process.env.JENKINS_JOB_URL_NODE = 'https://ci.nodejs.org/job/node-test-pull-request' + process.env.JENKINS_BUILD_TOKEN_NODE = 'myToken' + + const webhookPayload = readFixture('pull-request-opened.json') + const expectedComment = { + body: '@phillipj build started: https://ci.nodejs.org/job/node-test-pull-request/1' + } + + const collaboratorsScope = nock('https://api.github.com') + .filteringPath(ignoreQueryParams) + .get('/repos/nodejs/node/collaborators/phillipj') + .reply(200, { permission: 'admin' }) + const ciJobScope = nock('https://ci.nodejs.org') + .filteringPath(ignoreQueryParams) + .post('/job/node-test-pull-request/build') + .reply(201, '', { + 'Location': 'https://ci.nodejs.org/job/node-test-pull-request/1' + }) + const ciJobCommentScope = nock('https://api.github.com') + .filteringPath(ignoreQueryParams) + .post('/repos/nodejs/node/issues/19/comments', expectedComment) + .reply(201) + + t.plan(1) + t.tearDown(() => collaboratorsScope.done() && ciJobScope.done() && ciJobCommentScope.done() && clock.uninstall()) + + supertest(app) + .post('/hooks/github') + .set('x-github-event', 'pull_request') + .send(webhookPayload) + .expect(200) + .end((err, res) => { + process.env.JENKINS_JOB_URL_NODE = originalJobUrlValue + process.env.JENKINS_BUILD_TOKEN_NODE = originalTokenValue + clock.runAll() + t.equal(err, null) + }) +}) + +function ignoreQueryParams (pathAndQuery) { + return url.parse(pathAndQuery, true).pathname +} From 0b30cf9382c7aa1f867d9be3bdf1212e2de4bfc8 Mon Sep 17 00:00:00 2001 From: Jon Moss Date: Thu, 31 May 2018 16:54:22 -0400 Subject: [PATCH 2/3] [squash] do not comment Behavior does not work due to how Jenkins handles redirects. URL will be available via GitHub statuses, so shouldn't be a big deal. --- scripts/trigger-jenkins-build.js | 40 ++++++++++++++----- .../integration/trigger-jenkins-build.test.js | 9 +---- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/scripts/trigger-jenkins-build.js b/scripts/trigger-jenkins-build.js index 231fab78..a14a39bb 100644 --- a/scripts/trigger-jenkins-build.js +++ b/scripts/trigger-jenkins-build.js @@ -34,15 +34,39 @@ function buildTokenForRepo (repo) { return process.env[`JENKINS_BUILD_TOKEN_${repo.toUpperCase()}`] || '' } +function buildParametersForRepo (options, repo) { + if (repo === 'citgm') { + return [{ + name: 'GIT_REMOTE_REF', + value: `refs/pull/${options.number}/head` + }] + } else { + return [{ + name: 'CERTIFY_SAFE', + value: 'true' + }, + { + name: 'TARGET_GITHUB_ORG', + value: 'nodejs' + }, + { + name: 'TARGET_REPO_NAME', + value: 'node' + }, + { + name: 'PR_ID', + value: options.number + } + ] + } +} + function triggerBuild (options, cb) { const { repo } = options const base64Credentials = new Buffer(jenkinsApiCredentials).toString('base64') const authorization = `Basic ${base64Credentials}` - const buildParameters = [{ - name: 'GIT_REMOTE_REF', - value: `refs/pull/${options.number}/head` - }] - const payload = JSON.stringify({ parameter: buildParameters }) + + const payload = JSON.stringify({ parameter: buildParametersForRepo(options, repo) }) const uri = buildUrlForRepo(repo) const buildAuthToken = buildTokenForRepo(repo) @@ -138,11 +162,9 @@ module.exports = (app) => { function replyToCollabWithBuildStarted (err, buildUrl) { if (err) { logger.error(err, 'Error while triggering Jenkins build') - return createPrComment(options, `@${pullRequestAuthor} sadly an error occured when I tried to trigger a build :(`) + } else { + logger.info({ buildUrl }, 'Jenkins build started') } - - createPrComment(options, `@${pullRequestAuthor} build started: ${buildUrl}`) - logger.info({ buildUrl }, 'Jenkins build started') } function triggerBuildWhenCollaborator (err) { diff --git a/test/integration/trigger-jenkins-build.test.js b/test/integration/trigger-jenkins-build.test.js index 94ae734f..8a81dd7e 100644 --- a/test/integration/trigger-jenkins-build.test.js +++ b/test/integration/trigger-jenkins-build.test.js @@ -27,9 +27,6 @@ tap.test('Sends POST request to https://ci.nodejs.org', (t) => { process.env.JENKINS_BUILD_TOKEN_NODE = 'myToken' const webhookPayload = readFixture('pull-request-opened.json') - const expectedComment = { - body: '@phillipj build started: https://ci.nodejs.org/job/node-test-pull-request/1' - } const collaboratorsScope = nock('https://api.github.com') .filteringPath(ignoreQueryParams) @@ -41,13 +38,9 @@ tap.test('Sends POST request to https://ci.nodejs.org', (t) => { .reply(201, '', { 'Location': 'https://ci.nodejs.org/job/node-test-pull-request/1' }) - const ciJobCommentScope = nock('https://api.github.com') - .filteringPath(ignoreQueryParams) - .post('/repos/nodejs/node/issues/19/comments', expectedComment) - .reply(201) t.plan(1) - t.tearDown(() => collaboratorsScope.done() && ciJobScope.done() && ciJobCommentScope.done() && clock.uninstall()) + t.tearDown(() => collaboratorsScope.done() && ciJobScope.done() && clock.uninstall()) supertest(app) .post('/hooks/github') From 8f107375b8d249a6525bd8c743751379754651c1 Mon Sep 17 00:00:00 2001 From: Jon Moss Date: Fri, 1 Jun 2018 16:00:33 -0400 Subject: [PATCH 3/3] [squash] cleanup function name --- scripts/trigger-jenkins-build.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/trigger-jenkins-build.js b/scripts/trigger-jenkins-build.js index a14a39bb..bea53509 100644 --- a/scripts/trigger-jenkins-build.js +++ b/scripts/trigger-jenkins-build.js @@ -159,11 +159,11 @@ module.exports = (app) => { logger } - function replyToCollabWithBuildStarted (err, buildUrl) { + function logBuildStarted (err) { if (err) { logger.error(err, 'Error while triggering Jenkins build') } else { - logger.info({ buildUrl }, 'Jenkins build started') + logger.info('Jenkins build started') } }