Skip to content

Commit

Permalink
Add workflow to label community PRs and Issues. (woocommerce#34309)
Browse files Browse the repository at this point in the history
* Add workflow to label community PRs and Issues.

* Move most of the logic for the script to check for community contributors into a separate module
  • Loading branch information
jonathansadowski authored Aug 23, 2022
1 parent 852dc0c commit dc2c7a4
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 0 deletions.
60 changes: 60 additions & 0 deletions .github/workflows/community-label.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Add Community Label

on:
issues:
types: [opened]
pull_request_target:
types: [opened]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
verify:
name: Verify
runs-on: ubuntu-20.04
outputs:
issueId: ${{ steps.check.outputs.issueId }}
run: ${{ steps.check.outputs.run }}
steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Check if user is a community contributor
id: check
uses: actions/github-script@v6
with:
script: |
const isCommunityContributor = require( './.github/workflows/scripts/is-community-contributor.js' );
const config = {
types: [ 'pull_request', 'issue' ],
orgs: [ 'woocommerce', 'automattic' ],
};
( async ( { github, context, config } ) => {
try {
const isCommunity = await isCommunityContributor( { github, context, config } );
console.log( '::set-output name=run::%s', isCommunity ? 'true' : 'false' );
} catch ( e ) {
console.log( '::set-output name=run::false' );
}
} )( { github, context, config } );
label_community:
name: Label Community Issues and PRs
runs-on: ubuntu-20.04
needs: verify
if: needs.verify.outputs.run == 'true'
steps:
- name: label
uses: actions/github-script@v6
with:
script: |
github.rest.issues.addLabels( {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: [ 'type: community contribution' ]
} );
92 changes: 92 additions & 0 deletions .github/workflows/scripts/is-community-contributor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
const getUserFromContext = ( types, context ) => {
for ( const type of types ) {
if ( context.payload[ type ] && context.payload[ type ].user && context.payload[ type ].user.login ) {
return context.payload[ type ].user;
}
}
return false;
};

const userIsBot = user => user.type && user.type === 'Bot';

const userInOrg = async ( github, username, org ) => {
console.log( 'Checking for user %s in org %s', username, org );
try {
// First attempt to check memberships.
const result = await github.request( 'GET /orgs/{org}/memberships/{username}', {
org,
username,
} );

if ( result && Math.floor( result.status / 100 ) === 2 ) {
console.log( 'User %s found in %s via membership check', username, org );
return true;
}
} catch ( error ) {
// A 404 status means the user is definitively not in the organization.
if ( error.status === 404 ) {
console.log( 'User %s NOT found in %s via membership check', username, org );
return false;
}

try {
// For anything else, we should also check public memberships.
const result = await github.request( 'GET /orgs/{org}/public_members/{username}', {
org,
username,
} );

if ( result && Math.floor( result.status / 100 ) === 2 ) {
console.log( 'User %s found in %s via public membership check', username, org );
return true;
}
} catch ( error ) {
if ( error.status === 404 ) {
console.log( 'User %s NOT found in %s via public membership check', username, org );
return false;
}
}
}
// If we've gotten to this point, status is unknown.
throw new Error( "Unable to determine user's membership in org" );
};

const userInNonCommunityOrgs = async ( orgs, github, username ) => {
let checked = 0;
for ( const org of orgs ) {
try {
const isUserInOrg = await userInOrg( github, username, org );
if ( isUserInOrg ) {
return true;
}
// If no error was thrown, increment checked.
checked++;
} catch( e ) {} // Do nothing.
}

if ( checked !== orgs.length ) {
throw new Error( "Unable to check user's membership in all orgs." );
}

return false;
};

const isCommunityContributor = async ( { github, context, config } ) => {
const user = getUserFromContext( config.types, context );
if ( ! user ) {
throw new Error( 'Unable to get user from context' );
}
console.log( 'Checking user %s', user.login );

if ( userIsBot( user ) ) {
// Bots are not community contributors.
console.log( 'User detected as bot, skipping' );
return false;
}

const isInNonCommunityOrgs = await userInNonCommunityOrgs( config.orgs, github, user.login );

return ! isInNonCommunityOrgs;
};

module.exports = isCommunityContributor;

0 comments on commit dc2c7a4

Please sign in to comment.