Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project Management: Prompt user to link GitHub account to WordPress.org profile #21221

Merged
merged 14 commits into from
Apr 1, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
273 changes: 273 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
5 changes: 5 additions & 0 deletions packages/project-management-automation/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion packages/project-management-automation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,50 +1,131 @@
/**
* 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' );

/** @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 */

/**
* 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 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'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to display the prompt regardless of branch? If they are opening a PR, it shows they are interested in contributing. Why not catch them the first time regardless of branch?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to display the prompt regardless of branch? If they are opening a PR, it shows they are interested in contributing. Why not catch them the first time regardless of branch?

Unfortunately, it's not possible, related to this point from the original comment:

due to permission constraints of GitHub Actions, labels cannot be applied by actions if the originating repository is a fork of Gutenberg.

A commit pushed to a branch originating from a fork would fall under these restrictions.

It works for commits to master, since it's within the source repository, committed by someone with permissions to push to master.

);
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 }`
);

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;
}

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' ],
} );

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;
4 changes: 2 additions & 2 deletions packages/project-management-automation/lib/add-milestone.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @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<string,*>} WebhookPayloadPushCommit
*
* @property {string} message Commit message.
* @property {WebhookPayloadPushCommitAuthor} author Commit author.
*
* @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;
5 changes: 2 additions & 3 deletions packages/project-management-automation/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ const automations = [
task: ifNotFork( assignFixedIssues ),
},
{
event: 'pull_request',
action: 'opened',
task: ifNotFork( addFirstTimeContributorLabel ),
event: 'push',
task: addFirstTimeContributorLabel,
},
{
event: 'push',
Expand Down
Loading