From dedce7fb6aa0e5fff5e85ca26152b536f82e08f9 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 27 Mar 2020 15:42:51 -0400 Subject: [PATCH 01/14] Project Management Automation: Add getAssociatedPullRequest utility --- .../lib/add-milestone.js | 4 +- .../lib/get-associated-pull-request.js | 27 ++++++++++++++ .../lib/test/add-milestone.js | 10 ++--- .../lib/test/get-associated-pull-request.js | 37 +++++++++++++++++++ 4 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 packages/project-management-automation/lib/get-associated-pull-request.js create mode 100644 packages/project-management-automation/lib/test/get-associated-pull-request.js diff --git a/packages/project-management-automation/lib/add-milestone.js b/packages/project-management-automation/lib/add-milestone.js index e1e8ae39bc99f4..1716a8bea4f024 100644 --- a/packages/project-management-automation/lib/add-milestone.js +++ b/packages/project-management-automation/lib/add-milestone.js @@ -2,6 +2,7 @@ * Internal dependencies */ const debug = require( './debug' ); +const getAssociatedPullRequest = require( './get-associated-pull-request' ); /** @typedef {import('@octokit/rest').HookError} HookError */ /** @typedef {import('@actions/github').GitHub} GitHub */ @@ -45,8 +46,7 @@ async function addMilestone( payload, octokit ) { return; } - const match = payload.commits[ 0 ].message.match( /\(#(\d+)\)$/m ); - const prNumber = match && match[ 1 ]; + const prNumber = getAssociatedPullRequest( payload.commits[ 0 ] ); if ( ! prNumber ) { debug( 'add-milestone: Commit is not a squashed PR. Aborting' ); return; diff --git a/packages/project-management-automation/lib/get-associated-pull-request.js b/packages/project-management-automation/lib/get-associated-pull-request.js new file mode 100644 index 00000000000000..3125a2db75dc5c --- /dev/null +++ b/packages/project-management-automation/lib/get-associated-pull-request.js @@ -0,0 +1,27 @@ +/** + * Minimal type detail of GitHub Push webhook event payload, for lack of their + * own. + * + * @typedef {Record} WebhookPayloadPushCommit + * + * @property {string} message Commit message. + * + * @see https://developer.github.com/v3/activity/events/types/#pushevent + */ + +/** + * Given a commit object, returns a promise resolving with the pull request + * number associated with the commit, or null if an associated pull request + * cannot be determined. + * + * @param {WebhookPayloadPushCommit} commit Commit object. + * + * @return {number?} Pull request number, or null if it cannot be + * determined. + */ +function getAssociatedPullRequest( commit ) { + const match = commit.message.match( /\(#(\d+)\)$/m ); + return match && Number( match[ 1 ] ); +} + +module.exports = getAssociatedPullRequest; diff --git a/packages/project-management-automation/lib/test/add-milestone.js b/packages/project-management-automation/lib/test/add-milestone.js index 63f49811f9692e..13ecd80aa9b0a2 100644 --- a/packages/project-management-automation/lib/test/add-milestone.js +++ b/packages/project-management-automation/lib/test/add-milestone.js @@ -63,7 +63,7 @@ describe( 'addMilestone', () => { expect( octokit.issues.get ).toHaveBeenCalledWith( { owner: 'WordPress', repo: 'gutenberg', - issue_number: '123', + issue_number: 123, } ); expect( octokit.issues.createMilestone ).not.toHaveBeenCalled(); expect( octokit.issues.listMilestonesForRepo ).not.toHaveBeenCalled(); @@ -124,7 +124,7 @@ describe( 'addMilestone', () => { expect( octokit.issues.get ).toHaveBeenCalledWith( { owner: 'WordPress', repo: 'gutenberg', - issue_number: '123', + issue_number: 123, } ); expect( octokit.repos.getContents ).toHaveBeenCalledWith( { owner: 'WordPress', @@ -144,7 +144,7 @@ describe( 'addMilestone', () => { expect( octokit.issues.update ).toHaveBeenCalledWith( { owner: 'WordPress', repo: 'gutenberg', - issue_number: '123', + issue_number: 123, milestone: 12, } ); } ); @@ -202,7 +202,7 @@ describe( 'addMilestone', () => { expect( octokit.issues.get ).toHaveBeenCalledWith( { owner: 'WordPress', repo: 'gutenberg', - issue_number: '123', + issue_number: 123, } ); expect( octokit.repos.getContents ).toHaveBeenCalledWith( { owner: 'WordPress', @@ -222,7 +222,7 @@ describe( 'addMilestone', () => { expect( octokit.issues.update ).toHaveBeenCalledWith( { owner: 'WordPress', repo: 'gutenberg', - issue_number: '123', + issue_number: 123, milestone: 12, } ); } ); diff --git a/packages/project-management-automation/lib/test/get-associated-pull-request.js b/packages/project-management-automation/lib/test/get-associated-pull-request.js new file mode 100644 index 00000000000000..1e00d636e94e2a --- /dev/null +++ b/packages/project-management-automation/lib/test/get-associated-pull-request.js @@ -0,0 +1,37 @@ +/** + * Internal dependencies + */ +import getAssociatedPullRequest from '../get-associated-pull-request'; + +/** @typedef {import('../get-associated-pull-request').WebhookPayloadPushCommit} WebhookPayloadPushCommit */ + +/** + * An example commit which can be associated with a pull request, e.g. a pull + * request merge commit. + * + * @type {WebhookPayloadPushCommit} + */ +const VALID_COMMIT = { + message: + 'Components: SlotFill: Guard property access to possibly-undefined slot (#21205)', +}; + +/** + * An example commit which cannot be associated with a pull request, e.g. when + * someone commits directly to master. + * + * @type {WebhookPayloadPushCommit} + */ +const INVALID_COMMIT = { + message: 'Add basic placeholder content to post title, content, and date.', +}; + +describe( 'getAssociatedPullRequest', () => { + it( 'should return the pull request number associated with a commit', () => { + expect( getAssociatedPullRequest( VALID_COMMIT ) ).toBe( 21205 ); + } ); + + it( 'should return null if a pull request cannot be determined', () => { + expect( getAssociatedPullRequest( INVALID_COMMIT ) ).toBeNull(); + } ); +} ); From 4e236231c9dfde42dda014b3cc004060738a4e1c Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 27 Mar 2020 16:12:31 -0400 Subject: [PATCH 02/14] Project Management Automation: Add First-Time Contributor label on push --- .../lib/add-first-time-contributor-label.js | 38 +++++++++--- .../lib/get-associated-pull-request.js | 14 ++++- .../lib/index.js | 5 +- .../test/add-first-time-contributor-label.js | 62 ++++++++++++++++--- 4 files changed, 98 insertions(+), 21 deletions(-) diff --git a/packages/project-management-automation/lib/add-first-time-contributor-label.js b/packages/project-management-automation/lib/add-first-time-contributor-label.js index 661a2412b03ac5..9986d422d195a4 100644 --- a/packages/project-management-automation/lib/add-first-time-contributor-label.js +++ b/packages/project-management-automation/lib/add-first-time-contributor-label.js @@ -2,22 +2,40 @@ * Internal dependencies */ const debug = require( './debug' ); +const getAssociatedPullRequest = require( './get-associated-pull-request' ); /** @typedef {import('@actions/github').GitHub} GitHub */ -/** @typedef {import('@octokit/webhooks').WebhookPayloadPullRequest} WebhookPayloadPullRequest */ +/** @typedef {import('@octokit/webhooks').WebhookPayloadPush} WebhookPayloadPush */ +/** @typedef {import('./get-associated-pull-request').WebhookPayloadPushCommit} WebhookPayloadPushCommit */ /** - * Adds the 'First Time Contributor' label to PRs opened by contributors that - * have not yet made a commit. + * Adds the 'First Time Contributor' label to PRs merged on behalf of + * contributors that have not yet made a commit. * - * @param {WebhookPayloadPullRequest} payload Pull request event payload. - * @param {GitHub} octokit Initialized Octokit REST client. + * @param {WebhookPayloadPush} payload Push event payload. + * @param {GitHub} octokit Initialized Octokit REST client. */ async function addFirstTimeContributorLabel( payload, octokit ) { - const owner = payload.repository.owner.login; - const repo = payload.repository.name; - const author = payload.pull_request.user.login; + if ( payload.ref !== 'refs/heads/master' ) { + debug( + 'add-first-time-contributor-label: Commit is not to `master`. Aborting' + ); + return; + } + const commit = + /** @type {WebhookPayloadPushCommit} */ ( payload.commits[ 0 ] ); + const pullRequest = getAssociatedPullRequest( commit ); + if ( ! pullRequest ) { + debug( + 'add-first-time-contributor-label: Cannot determine pull request associated with commit. Aborting' + ); + return; + } + + const repo = payload.repository.name; + const owner = payload.repository.owner.login; + const author = commit.author.username; debug( `add-first-time-contributor-label: Searching for commits in ${ owner }/${ repo } by @${ author }` ); @@ -36,13 +54,13 @@ async function addFirstTimeContributorLabel( payload, octokit ) { } debug( - `add-first-time-contributor-label: Adding 'First Time Contributor' label to issue #${ payload.pull_request.number }` + `add-first-time-contributor-label: Adding 'First Time Contributor' label to issue #${ pullRequest }` ); await octokit.issues.addLabels( { owner, repo, - issue_number: payload.pull_request.number, + issue_number: pullRequest, labels: [ 'First-time Contributor' ], } ); } diff --git a/packages/project-management-automation/lib/get-associated-pull-request.js b/packages/project-management-automation/lib/get-associated-pull-request.js index 3125a2db75dc5c..6ec267a26a5b8e 100644 --- a/packages/project-management-automation/lib/get-associated-pull-request.js +++ b/packages/project-management-automation/lib/get-associated-pull-request.js @@ -1,10 +1,22 @@ +/** + * @typedef WebhookPayloadPushCommitAuthor + * + * @property {string} name Author name. + * @property {string} email Author email. + * @property {string} username Author username. + */ + /** * Minimal type detail of GitHub Push webhook event payload, for lack of their * own. * + * TODO: If GitHub improves this on their own webhook payload types, this type + * should no longer be necessary. + * * @typedef {Record} WebhookPayloadPushCommit * - * @property {string} message Commit message. + * @property {string} message Commit message. + * @property {WebhookPayloadPushCommitAuthor} author Commit author. * * @see https://developer.github.com/v3/activity/events/types/#pushevent */ diff --git a/packages/project-management-automation/lib/index.js b/packages/project-management-automation/lib/index.js index 630bda89440e93..a11293fcb0323f 100644 --- a/packages/project-management-automation/lib/index.js +++ b/packages/project-management-automation/lib/index.js @@ -42,9 +42,8 @@ const automations = [ task: ifNotFork( assignFixedIssues ), }, { - event: 'pull_request', - action: 'opened', - task: ifNotFork( addFirstTimeContributorLabel ), + event: 'push', + task: addFirstTimeContributorLabel, }, { event: 'push', diff --git a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js b/packages/project-management-automation/lib/test/add-first-time-contributor-label.js index ac8e5d59f26a0c..9583f0abe502ca 100644 --- a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js +++ b/packages/project-management-automation/lib/test/add-first-time-contributor-label.js @@ -5,12 +5,17 @@ import addFirstTimeContributorLabel from '../add-first-time-contributor-label'; describe( 'addFirstTimeContributorLabel', () => { const payload = { - pull_request: { - user: { - login: 'matt', + ref: 'refs/heads/master', + commits: [ + { + message: 'Add a feature from pull request (#123)', + author: { + name: 'Ghost', + email: 'ghost@example.invalid', + username: 'ghost', + }, }, - number: 123, - }, + ], repository: { owner: { login: 'WordPress', @@ -19,6 +24,49 @@ describe( 'addFirstTimeContributorLabel', () => { }, }; + it( 'does nothing if not a commit to master', async () => { + const payloadForBranchPush = { + ...payload, + ref: 'refs/heads/update/chicken-branch', + }; + + const octokit = { + search: { + commits: jest.fn(), + }, + }; + + await addFirstTimeContributorLabel( payloadForBranchPush, octokit ); + + expect( octokit.search.commits ).not.toHaveBeenCalled(); + } ); + + it( 'does nothing if commit pull request undeterminable', async () => { + const payloadDirectToMaster = { + ...payload, + commits: [ + { + message: 'Add a feature direct to master', + author: { + name: 'Ghost', + email: 'ghost@example.invalid', + username: 'ghost', + }, + }, + ], + }; + + const octokit = { + search: { + commits: jest.fn(), + }, + }; + + await addFirstTimeContributorLabel( payloadDirectToMaster, octokit ); + + expect( octokit.search.commits ).not.toHaveBeenCalled(); + } ); + it( 'does nothing if the user has commits', async () => { const octokit = { search: { @@ -38,7 +86,7 @@ describe( 'addFirstTimeContributorLabel', () => { await addFirstTimeContributorLabel( payload, octokit ); expect( octokit.search.commits ).toHaveBeenCalledWith( { - q: 'repo:WordPress/gutenberg+author:matt', + q: 'repo:WordPress/gutenberg+author:ghost', } ); expect( octokit.issues.addLabels ).not.toHaveBeenCalled(); } ); @@ -62,7 +110,7 @@ describe( 'addFirstTimeContributorLabel', () => { await addFirstTimeContributorLabel( payload, octokit ); expect( octokit.search.commits ).toHaveBeenCalledWith( { - q: 'repo:WordPress/gutenberg+author:matt', + q: 'repo:WordPress/gutenberg+author:ghost', } ); expect( octokit.issues.addLabels ).toHaveBeenCalledWith( { owner: 'WordPress', From d3226da628dc9e31fe25771d64033fd89bdffff6 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 27 Mar 2020 16:45:42 -0400 Subject: [PATCH 03/14] Project Management Automation: Include as dependency in root package --- package-lock.json | 9 +++++++++ package.json | 1 + 2 files changed, 10 insertions(+) diff --git a/package-lock.json b/package-lock.json index 780e7c3ace7092..e8d66c71eef445 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11532,6 +11532,15 @@ "@babel/runtime": "^7.8.3" } }, + "@wordpress/project-management-automation": { + "version": "file:packages/project-management-automation", + "dev": true, + "requires": { + "@actions/core": "^1.0.0", + "@actions/github": "^1.0.0", + "@babel/runtime": "^7.8.3" + } + }, "@wordpress/redux-routine": { "version": "file:packages/redux-routine", "requires": { diff --git a/package.json b/package.json index 0780154cbfc06d..4009e42c903dda 100644 --- a/package.json +++ b/package.json @@ -110,6 +110,7 @@ "@wordpress/npm-package-json-lint-config": "file:packages/npm-package-json-lint-config", "@wordpress/postcss-themes": "file:packages/postcss-themes", "@wordpress/prettier-config": "file:packages/prettier-config", + "@wordpress/project-management-automation": "file:packages/project-management-automation", "@wordpress/scripts": "file:packages/scripts", "babel-loader": "8.0.6", "babel-plugin-emotion": "10.0.27", From 6d099645a664aee5b5282fa7d9764dc08683037f Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 27 Mar 2020 17:42:41 -0400 Subject: [PATCH 04/14] Project Management Automation: Prompt user to link GitHub account to profile --- package-lock.json | 266 +++++++++++++++++- .../lib/add-first-time-contributor-label.js | 63 +++++ .../test/add-first-time-contributor-label.js | 98 +++++++ .../package.json | 3 +- 4 files changed, 428 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e8d66c71eef445..0a2fb92c8987bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6716,6 +6716,12 @@ "any-observable": "^0.3.0" } }, + "@sindresorhus/is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.0.tgz", + "integrity": "sha512-lXKXfypKo644k4Da4yXkPCrwcvn6SlUW2X2zFbuflKHNjf0w9htru01bo26uMhleMXsDmnZ12eJLdrAZa9MANg==", + "dev": true + }, "@storybook/addon-a11y": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-5.3.2.tgz", @@ -9885,6 +9891,15 @@ } } }, + "@szmarczak/http-timer": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", + "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.0" + } + }, "@tannin/compile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tannin/compile/-/compile-1.0.3.tgz", @@ -9968,6 +9983,18 @@ "@types/babel-types": "*" } }, + "@types/cacheable-request": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", + "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -9997,6 +10024,12 @@ "integrity": "sha512-+o2igcuZA3xtOoFH56s+MCZVidwlJNcJID57DSCyawS2i910yG9vkwehCjJNZ6ImhCR5S9DbvIJKyYHcMyOfMw==", "dev": true }, + "@types/http-cache-semantics": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", + "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==", + "dev": true + }, "@types/is-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.0.tgz", @@ -10052,6 +10085,15 @@ "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", "dev": true }, + "@types/keyv": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", + "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/lodash": { "version": "4.14.149", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz", @@ -10152,6 +10194,15 @@ "integrity": "sha512-BnnRkgWYijCIndUn+LgoqKHX/hNpJC5G03B9y7mZya/C2gUQTSn75fEj3ZP1/Rl2E6EYeXh2/7/8UNEZ4X7HuQ==", "dev": true }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/sprintf-js": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@types/sprintf-js/-/sprintf-js-1.1.2.tgz", @@ -11538,7 +11589,8 @@ "requires": { "@actions/core": "^1.0.0", "@actions/github": "^1.0.0", - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.8.3", + "got": "^10.7.0" } }, "@wordpress/redux-routine": { @@ -14791,6 +14843,64 @@ "unset-value": "^1.0.0" } }, + "cacheable-lookup": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz", + "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==", + "dev": true, + "requires": { + "@types/keyv": "^3.1.1", + "keyv": "^4.0.0" + } + }, + "cacheable-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", + "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", @@ -15310,6 +15420,23 @@ "is-supported-regexp-flag": "^1.0.0" } }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + }, + "dependencies": { + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + } + } + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -17004,6 +17131,15 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "decompress-response": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", + "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", + "dev": true, + "requires": { + "mimic-response": "^2.0.0" + } + }, "decompress-zip": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/decompress-zip/-/decompress-zip-0.2.2.tgz", @@ -17111,6 +17247,12 @@ "clone": "^1.0.2" } }, + "defer-to-connect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz", + "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==", + "dev": true + }, "define-properties": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", @@ -17685,6 +17827,12 @@ "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "dev": true }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, "duplexify": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", @@ -21385,6 +21533,56 @@ "delegate": "^3.1.2" } }, + "got": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", + "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==", + "dev": true, + "requires": { + "@sindresorhus/is": "^2.0.0", + "@szmarczak/http-timer": "^4.0.0", + "@types/cacheable-request": "^6.0.1", + "cacheable-lookup": "^2.0.0", + "cacheable-request": "^7.0.1", + "decompress-response": "^5.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^5.0.0", + "lowercase-keys": "^2.0.0", + "mimic-response": "^2.1.0", + "p-cancelable": "^2.0.0", + "p-event": "^4.0.0", + "responselike": "^2.0.0", + "to-readable-stream": "^2.0.0", + "type-fest": "^0.10.0" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "type-fest": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", + "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==", + "dev": true + } + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -26668,6 +26866,12 @@ "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", "dev": true }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -26794,6 +26998,15 @@ "set-immediate-shim": "~1.0.1" } }, + "keyv": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.0.tgz", + "integrity": "sha512-U7ioE8AimvRVLfw4LffyOIRhL2xVgmE8T22L6i0BucSnBUyv4w+I7VN/zVZwRKHOI6ZRUcdMdWHQ8KSUvGpEog==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -27787,6 +28000,12 @@ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", "dev": true }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, "lowlight": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.11.0.tgz", @@ -29336,6 +29555,12 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "dev": true + }, "min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", @@ -31332,6 +31557,12 @@ "os-tmpdir": "^1.0.0" } }, + "p-cancelable": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", + "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==", + "dev": true + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -31347,6 +31578,15 @@ "p-reduce": "^1.0.0" } }, + "p-event": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz", + "integrity": "sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==", + "dev": true, + "requires": { + "p-timeout": "^2.0.1" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -31413,6 +31653,15 @@ "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", "dev": true }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -36112,6 +36361,15 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "responselike": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "dev": true, + "requires": { + "lowercase-keys": "^2.0.0" + } + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -39605,6 +39863,12 @@ } } }, + "to-readable-stream": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", + "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==", + "dev": true + }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", diff --git a/packages/project-management-automation/lib/add-first-time-contributor-label.js b/packages/project-management-automation/lib/add-first-time-contributor-label.js index 9986d422d195a4..68ef6c61e0bd9c 100644 --- a/packages/project-management-automation/lib/add-first-time-contributor-label.js +++ b/packages/project-management-automation/lib/add-first-time-contributor-label.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +const got = /** @type {*} */ ( require( 'got' ) ); // See: https://github.com/sindresorhus/got/issues/1137 + /** * Internal dependencies */ @@ -8,6 +13,30 @@ const getAssociatedPullRequest = require( './get-associated-pull-request' ); /** @typedef {import('@octokit/webhooks').WebhookPayloadPush} WebhookPayloadPush */ /** @typedef {import('./get-associated-pull-request').WebhookPayloadPushCommit} WebhookPayloadPushCommit */ +/** + * Base endpoint URL for WordPress.org profile lookup by GitHub username. + * + * @type {string} + */ +const BASE_PROFILE_LOOKUP_API_URL = + 'https://profiles.wordpress.org/wp-json/wporg-github/v1/lookup/'; + +/** + * Message of comment prompting contributor to link their GitHub account from + * their WordPress.org profile for props credit. + * + * @type {string} + */ +const ACCOUNT_LINK_PROMPT = + 'Congratulations on your first merged pull request! We would like to ' + + 'give you credit for your contribution in the next WordPress release, but ' + + 'we were unable to find a WordPress.org profile associated with your ' + + 'GitHub account. At your convenience, please visit the following URL and ' + + 'click "link your GitHub account" under "GitHub Username" to initiate ' + + 'the process to link your accounts:\n\nhttps://profiles.wordpress.org/me/profile/edit/\n\n' + + 'If you do not have a WordPress.org account, you can create one at the ' + + 'following page:\n\nhttps://login.wordpress.org/register'; + /** * Adds the 'First Time Contributor' label to PRs merged on behalf of * contributors that have not yet made a commit. @@ -63,6 +92,40 @@ async function addFirstTimeContributorLabel( payload, octokit ) { issue_number: pullRequest, labels: [ 'First-time Contributor' ], } ); + + debug( + `add-first-time-contributor-label: Checking for WordPress username associated with @${ author }` + ); + + let dotOrgUsername; + try { + const response = await got( + BASE_PROFILE_LOOKUP_API_URL + author, + /** @type {import('got').Options} */ ( { + responseType: 'json', + } ) + ); + dotOrgUsername = response.body.slug; + } catch ( error ) { + debug( + `add-first-time-contributor-label: Error retrieving from profile API:\n\n${ error.toString() }` + ); + return; + } + + if ( dotOrgUsername ) { + debug( + `add-first-time-contributor-label: User already known as ${ dotOrgUsername }. No need to prompt for account link!` + ); + return; + } + + await octokit.issues.createComment( { + owner, + repo, + issue_number: pullRequest, + body: ACCOUNT_LINK_PROMPT, + } ); } module.exports = addFirstTimeContributorLabel; diff --git a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js b/packages/project-management-automation/lib/test/add-first-time-contributor-label.js index 9583f0abe502ca..dbd2d05da71383 100644 --- a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js +++ b/packages/project-management-automation/lib/test/add-first-time-contributor-label.js @@ -1,9 +1,20 @@ +/** + * External dependencies + */ +import got from 'got'; + /** * Internal dependencies */ import addFirstTimeContributorLabel from '../add-first-time-contributor-label'; +jest.mock( 'got', () => jest.fn() ); + describe( 'addFirstTimeContributorLabel', () => { + beforeEach( () => { + got.mockReset(); + } ); + const payload = { ref: 'refs/heads/master', commits: [ @@ -104,9 +115,90 @@ describe( 'addFirstTimeContributorLabel', () => { }, issues: { addLabels: jest.fn(), + createComment: jest.fn(), + }, + }; + + got.mockReturnValue( Promise.resolve( { body: { slug: 'ghostwp' } } ) ); + + await addFirstTimeContributorLabel( payload, octokit ); + + expect( octokit.search.commits ).toHaveBeenCalledWith( { + q: 'repo:WordPress/gutenberg+author:ghost', + } ); + expect( octokit.issues.addLabels ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + issue_number: 123, + labels: [ 'First-time Contributor' ], + } ); + expect( octokit.issues.createComment ).not.toHaveBeenCalled(); + } ); + + it( 'aborts if the request to retrieve WordPress.org user profile fails', async () => { + const octokit = { + search: { + commits: jest.fn( () => + Promise.resolve( { + data: { + total_count: 0, + }, + } ) + ), + }, + issues: { + addLabels: jest.fn(), + createComment: jest.fn(), + }, + }; + + got.mockImplementation( () => { + throw new Error( 'Whoops!' ); + } ); + + await addFirstTimeContributorLabel( payload, octokit ); + + expect( octokit.search.commits ).toHaveBeenCalledWith( { + q: 'repo:WordPress/gutenberg+author:ghost', + } ); + expect( octokit.issues.addLabels ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + issue_number: 123, + labels: [ 'First-time Contributor' ], + } ); + expect( octokit.issues.createComment ).not.toHaveBeenCalled(); + } ); + + it( 'prompts the user to link their GitHub account to their WordPress.org profile', async () => { + const octokit = { + search: { + commits: jest.fn( () => + Promise.resolve( { + data: { + total_count: 0, + }, + } ) + ), + }, + issues: { + addLabels: jest.fn(), + createComment: jest.fn(), }, }; + got.mockReturnValue( + Promise.resolve( { + body: { + code: 'user_not_linked', + message: 'Github Account not linked.', + data: { + status: 404, + }, + }, + } ) + ); + await addFirstTimeContributorLabel( payload, octokit ); expect( octokit.search.commits ).toHaveBeenCalledWith( { @@ -118,5 +210,11 @@ describe( 'addFirstTimeContributorLabel', () => { issue_number: 123, labels: [ 'First-time Contributor' ], } ); + expect( octokit.issues.createComment ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + issue_number: 123, + body: expect.stringMatching( /^Congratulations/ ), + } ); } ); } ); diff --git a/packages/project-management-automation/package.json b/packages/project-management-automation/package.json index 4e1d7bcf3e3681..209057612ad39f 100644 --- a/packages/project-management-automation/package.json +++ b/packages/project-management-automation/package.json @@ -21,7 +21,8 @@ "dependencies": { "@actions/core": "^1.0.0", "@actions/github": "^1.0.0", - "@babel/runtime": "^7.8.3" + "@babel/runtime": "^7.8.3", + "got": "^10.7.0" }, "publishConfig": { "access": "public" From 7a5f6ee9f03261914bf47d991a6c608e42d8da44 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 27 Mar 2020 17:48:35 -0400 Subject: [PATCH 05/14] Project Management Automation: Update documentation for first contribution prompt --- packages/project-management-automation/CHANGELOG.md | 5 +++++ packages/project-management-automation/README.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/project-management-automation/CHANGELOG.md b/packages/project-management-automation/CHANGELOG.md index c7363d0d385105..e75d78df1491c0 100644 --- a/packages/project-management-automation/CHANGELOG.md +++ b/packages/project-management-automation/CHANGELOG.md @@ -3,6 +3,11 @@ ### New feature - Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) +- The "Add First Time Contributor Label" task now prompts the user to link their GitHub account to their WordPress.org profile if neccessary for props credit. + +### Improvements + +- The "Add First Time Contributor Label" task now runs retroactively on pushes to master, due to [permission constraints](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token#permissions-for-the-github_token) of GitHub Actions. ## 1.0.0 (2019-08-29) diff --git a/packages/project-management-automation/README.md b/packages/project-management-automation/README.md index 40c85f70a67233..ad152b4b5c7edb 100644 --- a/packages/project-management-automation/README.md +++ b/packages/project-management-automation/README.md @@ -2,7 +2,7 @@ This is a [GitHub Action](https://help.github.com/en/categories/automating-your-workflow-with-github-actions) which contains various automation to assist with managing the Gutenberg GitHub repository: -- `add-first-time-contributor-label`: Adds the 'First Time Contributor' label to PRs opened by contributors that have not yet made a commit. +- `add-first-time-contributor-label`: Adds the 'First Time Contributor' label to PRs merged on behalf of contributors that have not previously made a contribution, and prompts the user to link their GitHub account to their WordPress.org profile if neccessary for props credit. - `add-milestone`: Assigns the correct milestone to PRs once merged. - `assign-fixed-issues`: Assigns any issues 'fixed' by a newly opened PR to the author of that PR. From 9bd7760c73345e819fb0e06455ef9f93326b588b Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 27 Mar 2020 18:12:59 -0400 Subject: [PATCH 06/14] Project Management Automation: Check for single commit of author --- .../lib/add-first-time-contributor-label.js | 12 +-- .../test/add-first-time-contributor-label.js | 82 +++++++++++-------- 2 files changed, 52 insertions(+), 42 deletions(-) diff --git a/packages/project-management-automation/lib/add-first-time-contributor-label.js b/packages/project-management-automation/lib/add-first-time-contributor-label.js index 68ef6c61e0bd9c..baadaf8c36e4c3 100644 --- a/packages/project-management-automation/lib/add-first-time-contributor-label.js +++ b/packages/project-management-automation/lib/add-first-time-contributor-label.js @@ -69,15 +69,15 @@ async function addFirstTimeContributorLabel( payload, octokit ) { `add-first-time-contributor-label: Searching for commits in ${ owner }/${ repo } by @${ author }` ); - const { - data: { total_count: totalCount }, - } = await octokit.search.commits( { - q: `repo:${ owner }/${ repo }+author:${ author }`, + const { data: commits } = await octokit.repos.listCommits( { + owner, + repo, + author, } ); - if ( totalCount !== 0 ) { + if ( commits.length > 1 ) { debug( - `add-first-time-contributor-label: ${ totalCount } commits found. Aborting` + `add-first-time-contributor-label: Not the first commit for author. Aborting` ); return; } diff --git a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js b/packages/project-management-automation/lib/test/add-first-time-contributor-label.js index dbd2d05da71383..10fe51fad781eb 100644 --- a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js +++ b/packages/project-management-automation/lib/test/add-first-time-contributor-label.js @@ -19,6 +19,7 @@ describe( 'addFirstTimeContributorLabel', () => { ref: 'refs/heads/master', commits: [ { + id: '4c535288a6a2b75ff23ee96c75f7d9877e919241', message: 'Add a feature from pull request (#123)', author: { name: 'Ghost', @@ -42,14 +43,14 @@ describe( 'addFirstTimeContributorLabel', () => { }; const octokit = { - search: { - commits: jest.fn(), + repos: { + listCommits: jest.fn(), }, }; await addFirstTimeContributorLabel( payloadForBranchPush, octokit ); - expect( octokit.search.commits ).not.toHaveBeenCalled(); + expect( octokit.repos.listCommits ).not.toHaveBeenCalled(); } ); it( 'does nothing if commit pull request undeterminable', async () => { @@ -68,24 +69,25 @@ describe( 'addFirstTimeContributorLabel', () => { }; const octokit = { - search: { - commits: jest.fn(), + repos: { + listCommits: jest.fn(), }, }; await addFirstTimeContributorLabel( payloadDirectToMaster, octokit ); - expect( octokit.search.commits ).not.toHaveBeenCalled(); + expect( octokit.repos.listCommits ).not.toHaveBeenCalled(); } ); - it( 'does nothing if the user has commits', async () => { + it( 'does nothing if the user has multiple commits', async () => { const octokit = { - search: { - commits: jest.fn( () => + repos: { + listCommits: jest.fn( () => Promise.resolve( { - data: { - total_count: 100, - }, + data: [ + { sha: '4c535288a6a2b75ff23ee96c75f7d9877e919241' }, + { sha: '59b07cc57adff90630fc9d5cf2317269a0f4f158' }, + ], } ) ), }, @@ -96,20 +98,22 @@ describe( 'addFirstTimeContributorLabel', () => { await addFirstTimeContributorLabel( payload, octokit ); - expect( octokit.search.commits ).toHaveBeenCalledWith( { - q: 'repo:WordPress/gutenberg+author:ghost', + expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + author: 'ghost', } ); expect( octokit.issues.addLabels ).not.toHaveBeenCalled(); } ); - it( 'adds the label if the user does not have commits', async () => { + it( 'adds the label if this was the first commit for the user', async () => { const octokit = { - search: { - commits: jest.fn( () => + repos: { + listCommits: jest.fn( () => Promise.resolve( { - data: { - total_count: 0, - }, + data: [ + { sha: '4c535288a6a2b75ff23ee96c75f7d9877e919241' }, + ], } ) ), }, @@ -123,8 +127,10 @@ describe( 'addFirstTimeContributorLabel', () => { await addFirstTimeContributorLabel( payload, octokit ); - expect( octokit.search.commits ).toHaveBeenCalledWith( { - q: 'repo:WordPress/gutenberg+author:ghost', + expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + author: 'ghost', } ); expect( octokit.issues.addLabels ).toHaveBeenCalledWith( { owner: 'WordPress', @@ -137,12 +143,12 @@ describe( 'addFirstTimeContributorLabel', () => { it( 'aborts if the request to retrieve WordPress.org user profile fails', async () => { const octokit = { - search: { - commits: jest.fn( () => + repos: { + listCommits: jest.fn( () => Promise.resolve( { - data: { - total_count: 0, - }, + data: [ + { sha: '4c535288a6a2b75ff23ee96c75f7d9877e919241' }, + ], } ) ), }, @@ -158,8 +164,10 @@ describe( 'addFirstTimeContributorLabel', () => { await addFirstTimeContributorLabel( payload, octokit ); - expect( octokit.search.commits ).toHaveBeenCalledWith( { - q: 'repo:WordPress/gutenberg+author:ghost', + expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + author: 'ghost', } ); expect( octokit.issues.addLabels ).toHaveBeenCalledWith( { owner: 'WordPress', @@ -172,12 +180,12 @@ describe( 'addFirstTimeContributorLabel', () => { it( 'prompts the user to link their GitHub account to their WordPress.org profile', async () => { const octokit = { - search: { - commits: jest.fn( () => + repos: { + listCommits: jest.fn( () => Promise.resolve( { - data: { - total_count: 0, - }, + data: [ + { sha: '4c535288a6a2b75ff23ee96c75f7d9877e919241' }, + ], } ) ), }, @@ -201,8 +209,10 @@ describe( 'addFirstTimeContributorLabel', () => { await addFirstTimeContributorLabel( payload, octokit ); - expect( octokit.search.commits ).toHaveBeenCalledWith( { - q: 'repo:WordPress/gutenberg+author:ghost', + expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { + owner: 'WordPress', + repo: 'gutenberg', + author: 'ghost', } ); expect( octokit.issues.addLabels ).toHaveBeenCalledWith( { owner: 'WordPress', From eb1dff6a73d4b0a7af03de9eabd0afd2b2881195 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 31 Mar 2020 10:01:17 -0400 Subject: [PATCH 07/14] Project Management Automation: Fetch profile by https HEAD --- package-lock.json | 266 +----------------- .../lib/add-first-time-contributor-label.js | 28 +- .../lib/has-wordpress-profile.js | 43 +++ .../test/add-first-time-contributor-label.js | 28 +- .../package.json | 3 +- 5 files changed, 57 insertions(+), 311 deletions(-) create mode 100644 packages/project-management-automation/lib/has-wordpress-profile.js diff --git a/package-lock.json b/package-lock.json index 0a2fb92c8987bc..e8d66c71eef445 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6716,12 +6716,6 @@ "any-observable": "^0.3.0" } }, - "@sindresorhus/is": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.0.tgz", - "integrity": "sha512-lXKXfypKo644k4Da4yXkPCrwcvn6SlUW2X2zFbuflKHNjf0w9htru01bo26uMhleMXsDmnZ12eJLdrAZa9MANg==", - "dev": true - }, "@storybook/addon-a11y": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-5.3.2.tgz", @@ -9891,15 +9885,6 @@ } } }, - "@szmarczak/http-timer": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", - "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.0" - } - }, "@tannin/compile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tannin/compile/-/compile-1.0.3.tgz", @@ -9983,18 +9968,6 @@ "@types/babel-types": "*" } }, - "@types/cacheable-request": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", - "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", - "dev": true, - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "*", - "@types/node": "*", - "@types/responselike": "*" - } - }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -10024,12 +9997,6 @@ "integrity": "sha512-+o2igcuZA3xtOoFH56s+MCZVidwlJNcJID57DSCyawS2i910yG9vkwehCjJNZ6ImhCR5S9DbvIJKyYHcMyOfMw==", "dev": true }, - "@types/http-cache-semantics": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", - "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==", - "dev": true - }, "@types/is-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.0.tgz", @@ -10085,15 +10052,6 @@ "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", "dev": true }, - "@types/keyv": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", - "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/lodash": { "version": "4.14.149", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz", @@ -10194,15 +10152,6 @@ "integrity": "sha512-BnnRkgWYijCIndUn+LgoqKHX/hNpJC5G03B9y7mZya/C2gUQTSn75fEj3ZP1/Rl2E6EYeXh2/7/8UNEZ4X7HuQ==", "dev": true }, - "@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/sprintf-js": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@types/sprintf-js/-/sprintf-js-1.1.2.tgz", @@ -11589,8 +11538,7 @@ "requires": { "@actions/core": "^1.0.0", "@actions/github": "^1.0.0", - "@babel/runtime": "^7.8.3", - "got": "^10.7.0" + "@babel/runtime": "^7.8.3" } }, "@wordpress/redux-routine": { @@ -14843,64 +14791,6 @@ "unset-value": "^1.0.0" } }, - "cacheable-lookup": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz", - "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==", - "dev": true, - "requires": { - "@types/keyv": "^3.1.1", - "keyv": "^4.0.0" - } - }, - "cacheable-request": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", - "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^2.0.0" - }, - "dependencies": { - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "normalize-url": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", - "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", @@ -15420,23 +15310,6 @@ "is-supported-regexp-flag": "^1.0.0" } }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - }, - "dependencies": { - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - } - } - }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -17131,15 +17004,6 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, - "decompress-response": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", - "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", - "dev": true, - "requires": { - "mimic-response": "^2.0.0" - } - }, "decompress-zip": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/decompress-zip/-/decompress-zip-0.2.2.tgz", @@ -17247,12 +17111,6 @@ "clone": "^1.0.2" } }, - "defer-to-connect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz", - "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==", - "dev": true - }, "define-properties": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", @@ -17827,12 +17685,6 @@ "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "dev": true }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, "duplexify": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", @@ -21533,56 +21385,6 @@ "delegate": "^3.1.2" } }, - "got": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", - "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==", - "dev": true, - "requires": { - "@sindresorhus/is": "^2.0.0", - "@szmarczak/http-timer": "^4.0.0", - "@types/cacheable-request": "^6.0.1", - "cacheable-lookup": "^2.0.0", - "cacheable-request": "^7.0.1", - "decompress-response": "^5.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^5.0.0", - "lowercase-keys": "^2.0.0", - "mimic-response": "^2.1.0", - "p-cancelable": "^2.0.0", - "p-event": "^4.0.0", - "responselike": "^2.0.0", - "to-readable-stream": "^2.0.0", - "type-fest": "^0.10.0" - }, - "dependencies": { - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "type-fest": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", - "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==", - "dev": true - } - } - }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -26866,12 +26668,6 @@ "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", "dev": true }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -26998,15 +26794,6 @@ "set-immediate-shim": "~1.0.1" } }, - "keyv": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.0.tgz", - "integrity": "sha512-U7ioE8AimvRVLfw4LffyOIRhL2xVgmE8T22L6i0BucSnBUyv4w+I7VN/zVZwRKHOI6ZRUcdMdWHQ8KSUvGpEog==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -28000,12 +27787,6 @@ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", "dev": true }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - }, "lowlight": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.11.0.tgz", @@ -29555,12 +29336,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" }, - "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true - }, "min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", @@ -31557,12 +31332,6 @@ "os-tmpdir": "^1.0.0" } }, - "p-cancelable": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", - "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==", - "dev": true - }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -31578,15 +31347,6 @@ "p-reduce": "^1.0.0" } }, - "p-event": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz", - "integrity": "sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==", - "dev": true, - "requires": { - "p-timeout": "^2.0.1" - } - }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -31653,15 +31413,6 @@ "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", "dev": true }, - "p-timeout": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", - "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", - "dev": true, - "requires": { - "p-finally": "^1.0.0" - } - }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -36361,15 +36112,6 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, - "responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", - "dev": true, - "requires": { - "lowercase-keys": "^2.0.0" - } - }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -39863,12 +39605,6 @@ } } }, - "to-readable-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", - "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==", - "dev": true - }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", diff --git a/packages/project-management-automation/lib/add-first-time-contributor-label.js b/packages/project-management-automation/lib/add-first-time-contributor-label.js index baadaf8c36e4c3..864472552a3fc0 100644 --- a/packages/project-management-automation/lib/add-first-time-contributor-label.js +++ b/packages/project-management-automation/lib/add-first-time-contributor-label.js @@ -1,26 +1,14 @@ -/** - * External dependencies - */ -const got = /** @type {*} */ ( require( 'got' ) ); // See: https://github.com/sindresorhus/got/issues/1137 - /** * Internal dependencies */ const debug = require( './debug' ); const getAssociatedPullRequest = require( './get-associated-pull-request' ); +const hasWordPressProfile = require( './has-wordpress-profile' ); /** @typedef {import('@actions/github').GitHub} GitHub */ /** @typedef {import('@octokit/webhooks').WebhookPayloadPush} WebhookPayloadPush */ /** @typedef {import('./get-associated-pull-request').WebhookPayloadPushCommit} WebhookPayloadPushCommit */ -/** - * Base endpoint URL for WordPress.org profile lookup by GitHub username. - * - * @type {string} - */ -const BASE_PROFILE_LOOKUP_API_URL = - 'https://profiles.wordpress.org/wp-json/wporg-github/v1/lookup/'; - /** * Message of comment prompting contributor to link their GitHub account from * their WordPress.org profile for props credit. @@ -97,15 +85,9 @@ async function addFirstTimeContributorLabel( payload, octokit ) { `add-first-time-contributor-label: Checking for WordPress username associated with @${ author }` ); - let dotOrgUsername; + let hasProfile; try { - const response = await got( - BASE_PROFILE_LOOKUP_API_URL + author, - /** @type {import('got').Options} */ ( { - responseType: 'json', - } ) - ); - dotOrgUsername = response.body.slug; + hasProfile = await hasWordPressProfile( author ); } catch ( error ) { debug( `add-first-time-contributor-label: Error retrieving from profile API:\n\n${ error.toString() }` @@ -113,9 +95,9 @@ async function addFirstTimeContributorLabel( payload, octokit ) { return; } - if ( dotOrgUsername ) { + if ( hasProfile ) { debug( - `add-first-time-contributor-label: User already known as ${ dotOrgUsername }. No need to prompt for account link!` + `add-first-time-contributor-label: User already known. No need to prompt for account link!` ); return; } diff --git a/packages/project-management-automation/lib/has-wordpress-profile.js b/packages/project-management-automation/lib/has-wordpress-profile.js new file mode 100644 index 00000000000000..06f75bfe15e797 --- /dev/null +++ b/packages/project-management-automation/lib/has-wordpress-profile.js @@ -0,0 +1,43 @@ +/** + * External dependencies + */ +const { request } = require( 'https' ); + +/** + * Endpoint hostname for WordPress.org profile lookup by GitHub username. + * + * @type {string} + */ +const BASE_PROFILE_LOOKUP_API_HOSTNAME = 'https://profiles.wordpress.org'; + +/** + * Base path for WordPress.org profile lookup by GitHub username. + * + * @type {string} + */ +const BASE_PROFILE_LOOKUP_API_BASE_PATH = '/wp-json/wporg-github/v1/lookup/'; + +/** + * Returns a promise resolving to a boolean indicating if the given GitHub + * username can be associated with a WordPress.org profile. + * + * @param {string} githubUsername GitHub username. + * + * @return {Promise} Promise resolving to whether WordPress profile is + * known. + */ +async function hasWordPressProfile( githubUsername ) { + return new Promise( ( resolve, reject ) => { + const options = { + hostname: BASE_PROFILE_LOOKUP_API_HOSTNAME, + path: BASE_PROFILE_LOOKUP_API_BASE_PATH + githubUsername, + method: 'HEAD', + }; + + request( options, ( res ) => resolve( res.statusCode === 200 ) ) + .on( 'error', ( error ) => reject( error ) ) + .end(); + } ); +} + +module.exports = hasWordPressProfile; diff --git a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js b/packages/project-management-automation/lib/test/add-first-time-contributor-label.js index 10fe51fad781eb..dcb8693ac13a18 100644 --- a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js +++ b/packages/project-management-automation/lib/test/add-first-time-contributor-label.js @@ -1,18 +1,14 @@ -/** - * External dependencies - */ -import got from 'got'; - /** * Internal dependencies */ import addFirstTimeContributorLabel from '../add-first-time-contributor-label'; +import hasWordPressProfile from '../has-wordpress-profile'; -jest.mock( 'got', () => jest.fn() ); +jest.mock( '../has-wordpress-profile', () => jest.fn() ); describe( 'addFirstTimeContributorLabel', () => { beforeEach( () => { - got.mockReset(); + hasWordPressProfile.mockReset(); } ); const payload = { @@ -123,7 +119,7 @@ describe( 'addFirstTimeContributorLabel', () => { }, }; - got.mockReturnValue( Promise.resolve( { body: { slug: 'ghostwp' } } ) ); + hasWordPressProfile.mockReturnValue( Promise.resolve( true ) ); await addFirstTimeContributorLabel( payload, octokit ); @@ -158,8 +154,8 @@ describe( 'addFirstTimeContributorLabel', () => { }, }; - got.mockImplementation( () => { - throw new Error( 'Whoops!' ); + hasWordPressProfile.mockImplementation( () => { + return Promise.reject( new Error( 'Whoops!' ) ); } ); await addFirstTimeContributorLabel( payload, octokit ); @@ -195,17 +191,7 @@ describe( 'addFirstTimeContributorLabel', () => { }, }; - got.mockReturnValue( - Promise.resolve( { - body: { - code: 'user_not_linked', - message: 'Github Account not linked.', - data: { - status: 404, - }, - }, - } ) - ); + hasWordPressProfile.mockReturnValue( Promise.resolve( false ) ); await addFirstTimeContributorLabel( payload, octokit ); diff --git a/packages/project-management-automation/package.json b/packages/project-management-automation/package.json index 209057612ad39f..4e1d7bcf3e3681 100644 --- a/packages/project-management-automation/package.json +++ b/packages/project-management-automation/package.json @@ -21,8 +21,7 @@ "dependencies": { "@actions/core": "^1.0.0", "@actions/github": "^1.0.0", - "@babel/runtime": "^7.8.3", - "got": "^10.7.0" + "@babel/runtime": "^7.8.3" }, "publishConfig": { "access": "public" From 83ef4d69f716d50e12bf728454648f2fd6ce2cf3 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 31 Mar 2020 11:20:28 -0400 Subject: [PATCH 08/14] Project Management Automation: Fix hostname to use hostname --- .../project-management-automation/lib/has-wordpress-profile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/project-management-automation/lib/has-wordpress-profile.js b/packages/project-management-automation/lib/has-wordpress-profile.js index 06f75bfe15e797..4c81cd53991726 100644 --- a/packages/project-management-automation/lib/has-wordpress-profile.js +++ b/packages/project-management-automation/lib/has-wordpress-profile.js @@ -8,7 +8,7 @@ const { request } = require( 'https' ); * * @type {string} */ -const BASE_PROFILE_LOOKUP_API_HOSTNAME = 'https://profiles.wordpress.org'; +const BASE_PROFILE_LOOKUP_API_HOSTNAME = 'profiles.wordpress.org'; /** * Base path for WordPress.org profile lookup by GitHub username. From 26ddea3bccf87ffad278c5a59503873b2851da05 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 31 Mar 2020 11:24:20 -0400 Subject: [PATCH 09/14] Project Management Automation: Add hasWordPressProfile tests --- package-lock.json | 35 +++++++++++++++++++ package.json | 1 + .../lib/test/has-wordpress-profile.js | 31 ++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 packages/project-management-automation/lib/test/has-wordpress-profile.js diff --git a/package-lock.json b/package-lock.json index e8d66c71eef445..3fa3c2376e3c49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29833,6 +29833,35 @@ "lower-case": "^1.1.1" } }, + "nock": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", + "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.13", + "propagate": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "node-dir": { "version": "0.1.17", "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", @@ -33020,6 +33049,12 @@ "reflect.ownkeys": "^0.2.0" } }, + "propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true + }, "property-information": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.3.0.tgz", diff --git a/package.json b/package.json index 4009e42c903dda..36f8acf1966aa7 100644 --- a/package.json +++ b/package.json @@ -149,6 +149,7 @@ "metro-react-native-babel-preset": "0.55.0", "metro-react-native-babel-transformer": "0.55.0", "mkdirp": "0.5.1", + "nock": "12.0.3", "node-sass": "4.12.0", "node-watch": "0.6.0", "postcss": "7.0.13", diff --git a/packages/project-management-automation/lib/test/has-wordpress-profile.js b/packages/project-management-automation/lib/test/has-wordpress-profile.js new file mode 100644 index 00000000000000..9cb13544a245a1 --- /dev/null +++ b/packages/project-management-automation/lib/test/has-wordpress-profile.js @@ -0,0 +1,31 @@ +/** + * External dependencies + */ +import nock from 'nock'; + +/** + * Internal dependencies + */ +import hasWordPressProfile from '../has-wordpress-profile'; + +describe( 'hasWordPressProfile', () => { + it( 'resolves as false for missing profile', async () => { + nock( 'https://profiles.wordpress.org' ) + .intercept( '/wp-json/wporg-github/v1/lookup/ghost', 'HEAD' ) + .reply( 404 ); + + const result = await hasWordPressProfile( 'ghost' ); + + expect( result ).toBe( false ); + } ); + + it( 'resolves as true for known profile', async () => { + nock( 'https://profiles.wordpress.org' ) + .intercept( '/wp-json/wporg-github/v1/lookup/m', 'HEAD' ) + .reply( 200 ); + + const result = await hasWordPressProfile( 'm' ); + + expect( result ).toBe( true ); + } ); +} ); From 0d338e5fd61bd88edd6cd975143ff889d5203aa8 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 31 Mar 2020 11:24:48 -0400 Subject: [PATCH 10/14] Project Management Automation: Add request User-Agent header --- .../project-management-automation/lib/has-wordpress-profile.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/project-management-automation/lib/has-wordpress-profile.js b/packages/project-management-automation/lib/has-wordpress-profile.js index 4c81cd53991726..cb2adfdba71e0b 100644 --- a/packages/project-management-automation/lib/has-wordpress-profile.js +++ b/packages/project-management-automation/lib/has-wordpress-profile.js @@ -32,6 +32,9 @@ async function hasWordPressProfile( githubUsername ) { hostname: BASE_PROFILE_LOOKUP_API_HOSTNAME, path: BASE_PROFILE_LOOKUP_API_BASE_PATH + githubUsername, method: 'HEAD', + headers: { + 'User-Agent': 'Gutenberg/project-management-automation', + }, }; request( options, ( res ) => resolve( res.statusCode === 200 ) ) From 6bedde853584fc494fef0f3aa96f04d2d30e6f7b Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 31 Mar 2020 11:29:34 -0400 Subject: [PATCH 11/14] Project Management Automation: Update contributor prompt text --- .../lib/add-first-time-contributor-label.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/project-management-automation/lib/add-first-time-contributor-label.js b/packages/project-management-automation/lib/add-first-time-contributor-label.js index 864472552a3fc0..c81b102083dbcb 100644 --- a/packages/project-management-automation/lib/add-first-time-contributor-label.js +++ b/packages/project-management-automation/lib/add-first-time-contributor-label.js @@ -16,14 +16,14 @@ const hasWordPressProfile = require( './has-wordpress-profile' ); * @type {string} */ const ACCOUNT_LINK_PROMPT = - 'Congratulations on your first merged pull request! We would like to ' + - 'give you credit for your contribution in the next WordPress release, but ' + - 'we were unable to find a WordPress.org profile associated with your ' + - 'GitHub account. At your convenience, please visit the following URL and ' + - 'click "link your GitHub account" under "GitHub Username" to initiate ' + - 'the process to link your accounts:\n\nhttps://profiles.wordpress.org/me/profile/edit/\n\n' + - 'If you do not have a WordPress.org account, you can create one at the ' + - 'following page:\n\nhttps://login.wordpress.org/register'; + "Congratulations on your first merged pull request! We'd like to credit " + + 'you for your contribution in the post announcing the next WordPress ' + + "release, but we can't find a WordPress.org profile associated with your " + + 'GitHub account. When you have a moment, visit the following URL and ' + + 'click "link your GitHub account" under "GitHub Username" to link your ' + + 'accounts:\n\nhttps://profiles.wordpress.org/me/profile/edit/\n\nAnd if ' + + "you don't have a WordPress.org account, you can create one on this page:" + + '\n\nhttps://login.wordpress.org/register\n\nKudos!'; /** * Adds the 'First Time Contributor' label to PRs merged on behalf of From 7f00af642dcc3a81b057a728714e88c08b5a6a10 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 31 Mar 2020 11:33:28 -0400 Subject: [PATCH 12/14] Project Management Automation: Rename addFirstTimeContributorLabel to firstTimeContributor --- .../project-management-automation/README.md | 2 +- ...tor-label.js => first-time-contributor.js} | 22 +++++++++---------- .../lib/index.js | 4 ++-- ...tor-label.js => first-time-contributor.js} | 16 +++++++------- 4 files changed, 21 insertions(+), 23 deletions(-) rename packages/project-management-automation/lib/{add-first-time-contributor-label.js => first-time-contributor.js} (73%) rename packages/project-management-automation/lib/test/{add-first-time-contributor-label.js => first-time-contributor.js} (89%) diff --git a/packages/project-management-automation/README.md b/packages/project-management-automation/README.md index ad152b4b5c7edb..17726771d94e66 100644 --- a/packages/project-management-automation/README.md +++ b/packages/project-management-automation/README.md @@ -2,7 +2,7 @@ This is a [GitHub Action](https://help.github.com/en/categories/automating-your-workflow-with-github-actions) which contains various automation to assist with managing the Gutenberg GitHub repository: -- `add-first-time-contributor-label`: Adds the 'First Time Contributor' label to PRs merged on behalf of contributors that have not previously made a contribution, and prompts the user to link their GitHub account to their WordPress.org profile if neccessary for props credit. +- `first-time-contributor`: Adds the 'First Time Contributor' label to PRs merged on behalf of contributors that have not previously made a contribution, and prompts the user to link their GitHub account to their WordPress.org profile if neccessary for props credit. - `add-milestone`: Assigns the correct milestone to PRs once merged. - `assign-fixed-issues`: Assigns any issues 'fixed' by a newly opened PR to the author of that PR. diff --git a/packages/project-management-automation/lib/add-first-time-contributor-label.js b/packages/project-management-automation/lib/first-time-contributor.js similarity index 73% rename from packages/project-management-automation/lib/add-first-time-contributor-label.js rename to packages/project-management-automation/lib/first-time-contributor.js index c81b102083dbcb..c82a15fe04989c 100644 --- a/packages/project-management-automation/lib/add-first-time-contributor-label.js +++ b/packages/project-management-automation/lib/first-time-contributor.js @@ -32,11 +32,9 @@ const ACCOUNT_LINK_PROMPT = * @param {WebhookPayloadPush} payload Push event payload. * @param {GitHub} octokit Initialized Octokit REST client. */ -async function addFirstTimeContributorLabel( payload, octokit ) { +async function firstTimeContributor( payload, octokit ) { if ( payload.ref !== 'refs/heads/master' ) { - debug( - 'add-first-time-contributor-label: Commit is not to `master`. Aborting' - ); + debug( 'first-time-contributor: Commit is not to `master`. Aborting' ); return; } @@ -45,7 +43,7 @@ async function addFirstTimeContributorLabel( payload, octokit ) { const pullRequest = getAssociatedPullRequest( commit ); if ( ! pullRequest ) { debug( - 'add-first-time-contributor-label: Cannot determine pull request associated with commit. Aborting' + 'first-time-contributor: Cannot determine pull request associated with commit. Aborting' ); return; } @@ -54,7 +52,7 @@ async function addFirstTimeContributorLabel( payload, octokit ) { const owner = payload.repository.owner.login; const author = commit.author.username; debug( - `add-first-time-contributor-label: Searching for commits in ${ owner }/${ repo } by @${ author }` + `first-time-contributor: Searching for commits in ${ owner }/${ repo } by @${ author }` ); const { data: commits } = await octokit.repos.listCommits( { @@ -65,13 +63,13 @@ async function addFirstTimeContributorLabel( payload, octokit ) { if ( commits.length > 1 ) { debug( - `add-first-time-contributor-label: Not the first commit for author. Aborting` + `first-time-contributor: Not the first commit for author. Aborting` ); return; } debug( - `add-first-time-contributor-label: Adding 'First Time Contributor' label to issue #${ pullRequest }` + `first-time-contributor: Adding 'First Time Contributor' label to issue #${ pullRequest }` ); await octokit.issues.addLabels( { @@ -82,7 +80,7 @@ async function addFirstTimeContributorLabel( payload, octokit ) { } ); debug( - `add-first-time-contributor-label: Checking for WordPress username associated with @${ author }` + `first-time-contributor: Checking for WordPress username associated with @${ author }` ); let hasProfile; @@ -90,14 +88,14 @@ async function addFirstTimeContributorLabel( payload, octokit ) { hasProfile = await hasWordPressProfile( author ); } catch ( error ) { debug( - `add-first-time-contributor-label: Error retrieving from profile API:\n\n${ error.toString() }` + `first-time-contributor: Error retrieving from profile API:\n\n${ error.toString() }` ); return; } if ( hasProfile ) { debug( - `add-first-time-contributor-label: User already known. No need to prompt for account link!` + `first-time-contributor: User already known. No need to prompt for account link!` ); return; } @@ -110,4 +108,4 @@ async function addFirstTimeContributorLabel( payload, octokit ) { } ); } -module.exports = addFirstTimeContributorLabel; +module.exports = firstTimeContributor; diff --git a/packages/project-management-automation/lib/index.js b/packages/project-management-automation/lib/index.js index a11293fcb0323f..2b280d1d5d5248 100644 --- a/packages/project-management-automation/lib/index.js +++ b/packages/project-management-automation/lib/index.js @@ -8,7 +8,7 @@ const { context, GitHub } = require( '@actions/github' ); * Internal dependencies */ const assignFixedIssues = require( './assign-fixed-issues' ); -const addFirstTimeContributorLabel = require( './add-first-time-contributor-label' ); +const firstTimeContributor = require( './first-time-contributor' ); const addMilestone = require( './add-milestone' ); const debug = require( './debug' ); const ifNotFork = require( './if-not-fork' ); @@ -43,7 +43,7 @@ const automations = [ }, { event: 'push', - task: addFirstTimeContributorLabel, + task: firstTimeContributor, }, { event: 'push', diff --git a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js b/packages/project-management-automation/lib/test/first-time-contributor.js similarity index 89% rename from packages/project-management-automation/lib/test/add-first-time-contributor-label.js rename to packages/project-management-automation/lib/test/first-time-contributor.js index dcb8693ac13a18..27a328c2b5948e 100644 --- a/packages/project-management-automation/lib/test/add-first-time-contributor-label.js +++ b/packages/project-management-automation/lib/test/first-time-contributor.js @@ -1,12 +1,12 @@ /** * Internal dependencies */ -import addFirstTimeContributorLabel from '../add-first-time-contributor-label'; +import firstTimeContributor from '../first-time-contributor'; import hasWordPressProfile from '../has-wordpress-profile'; jest.mock( '../has-wordpress-profile', () => jest.fn() ); -describe( 'addFirstTimeContributorLabel', () => { +describe( 'firstTimeContributor', () => { beforeEach( () => { hasWordPressProfile.mockReset(); } ); @@ -44,7 +44,7 @@ describe( 'addFirstTimeContributorLabel', () => { }, }; - await addFirstTimeContributorLabel( payloadForBranchPush, octokit ); + await firstTimeContributor( payloadForBranchPush, octokit ); expect( octokit.repos.listCommits ).not.toHaveBeenCalled(); } ); @@ -70,7 +70,7 @@ describe( 'addFirstTimeContributorLabel', () => { }, }; - await addFirstTimeContributorLabel( payloadDirectToMaster, octokit ); + await firstTimeContributor( payloadDirectToMaster, octokit ); expect( octokit.repos.listCommits ).not.toHaveBeenCalled(); } ); @@ -92,7 +92,7 @@ describe( 'addFirstTimeContributorLabel', () => { }, }; - await addFirstTimeContributorLabel( payload, octokit ); + await firstTimeContributor( payload, octokit ); expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { owner: 'WordPress', @@ -121,7 +121,7 @@ describe( 'addFirstTimeContributorLabel', () => { hasWordPressProfile.mockReturnValue( Promise.resolve( true ) ); - await addFirstTimeContributorLabel( payload, octokit ); + await firstTimeContributor( payload, octokit ); expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { owner: 'WordPress', @@ -158,7 +158,7 @@ describe( 'addFirstTimeContributorLabel', () => { return Promise.reject( new Error( 'Whoops!' ) ); } ); - await addFirstTimeContributorLabel( payload, octokit ); + await firstTimeContributor( payload, octokit ); expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { owner: 'WordPress', @@ -193,7 +193,7 @@ describe( 'addFirstTimeContributorLabel', () => { hasWordPressProfile.mockReturnValue( Promise.resolve( false ) ); - await addFirstTimeContributorLabel( payload, octokit ); + await firstTimeContributor( payload, octokit ); expect( octokit.repos.listCommits ).toHaveBeenCalledWith( { owner: 'WordPress', From d41dbff2547e3b71f79a532a1ee0829ebba67728 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 31 Mar 2020 11:34:09 -0400 Subject: [PATCH 13/14] Project Management Automation: Expand function comment to include new behavior --- .../lib/first-time-contributor.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/project-management-automation/lib/first-time-contributor.js b/packages/project-management-automation/lib/first-time-contributor.js index c82a15fe04989c..a31093640c8909 100644 --- a/packages/project-management-automation/lib/first-time-contributor.js +++ b/packages/project-management-automation/lib/first-time-contributor.js @@ -27,7 +27,9 @@ const ACCOUNT_LINK_PROMPT = /** * Adds the 'First Time Contributor' label to PRs merged on behalf of - * contributors that have not yet made a commit. + * contributors that have not yet made a commit, and prompts the user to link + * their GitHub account to their WordPress.org profile if neccessary for props + * credit. * * @param {WebhookPayloadPush} payload Push event payload. * @param {GitHub} octokit Initialized Octokit REST client. From 4493c2292214263b4631057171422d31f2686784 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 31 Mar 2020 11:35:32 -0400 Subject: [PATCH 14/14] Project Management Automation: Expand CHANGELOG to include rename --- packages/project-management-automation/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/project-management-automation/CHANGELOG.md b/packages/project-management-automation/CHANGELOG.md index e75d78df1491c0..0e2f5ad00a4104 100644 --- a/packages/project-management-automation/CHANGELOG.md +++ b/packages/project-management-automation/CHANGELOG.md @@ -3,7 +3,7 @@ ### New feature - Include TypeScript type declarations ([#18942](https://github.com/WordPress/gutenberg/pull/18942)) -- The "Add First Time Contributor Label" task now prompts the user to link their GitHub account to their WordPress.org profile if neccessary for props credit. +- The "Add First Time Contributor Label" task now prompts the user to link their GitHub account to their WordPress.org profile if neccessary for props credit. The task has been renamed "First Time Contributor". ### Improvements