diff --git a/.github/actions/check-external-contributor/README.md b/.github/actions/check-external-contributor/README.md new file mode 100644 index 0000000..cb79e90 --- /dev/null +++ b/.github/actions/check-external-contributor/README.md @@ -0,0 +1,80 @@ +# Check External Contributor Action + +Automatically labels pull requests created by users who are not members of a specified GitHub team. + +## Usage + +```yaml +- uses: SolaceDev/solace-public-workflows/check-external-contributor@main + with: + github_team_slug: solace-ai + label_name: "external contributor" + github-token: ${{ secrets.GITHUB_TOKEN }} +``` + +## Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `github_team_slug` | GitHub team slug to check membership against (e.g., `solace-ai`) | Yes | - | +| `label_name` | Label to add to PR if creator is not in the team | No | `"external contributor"` | +| `github-token` | GitHub token for API access | Yes | - | + +## How it Works + +1. Checks if the PR creator is a member of the specified GitHub team +2. If not a member, adds the specified label to the PR +3. Logs the results for debugging + +## Workflow Trigger + +This action is designed to work with `pull_request_target` to safely handle external contributors: + +```yaml +on: + pull_request_target: + types: [opened, reopened] + +jobs: + check-external: + runs-on: ubuntu-latest + permissions: + pull-requests: write + issues: write +``` + +## Examples + +### Basic Example + +```yaml +name: Check External Contributor +on: + pull_request_target: + types: [opened, reopened] + +jobs: + check: + runs-on: ubuntu-latest + permissions: + pull-requests: write + issues: write + steps: + - uses: SolaceDev/solace-public-workflows/check-external-contributor@main + with: + github_team_slug: my-team + label_name: "external contributor" + github-token: ${{ secrets.GITHUB_TOKEN }} +``` + +## Permissions Required + +The GitHub token must have the following permissions: +- `pull-requests: write` - To access PR information +- `issues: write` - To add labels to PRs + +## Notes + +- Use `pull_request_target` instead of `pull_request` for security when running workflows on external PRs +- The action gracefully handles errors when checking team membership +- If the label doesn't exist, GitHub will automatically create it when adding it to the PR diff --git a/.github/actions/check-external-contributor/action.yml b/.github/actions/check-external-contributor/action.yml new file mode 100644 index 0000000..8bca977 --- /dev/null +++ b/.github/actions/check-external-contributor/action.yml @@ -0,0 +1,71 @@ +name: Check External Contributor +description: Checks if PR creator is in a GitHub team and adds a label if not + +inputs: + github_team_slug: + description: "GitHub team slug to check membership against (e.g., 'solace-ai')" + required: true + label_name: + description: "Label to add to PR if creator is not in the team" + required: false + default: "external contributor" + github-token: + description: "GitHub token for API access" + required: true + +runs: + using: composite + steps: + - name: Check if PR creator is in team + id: check-team + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + github-token: ${{ inputs.github-token }} + script: | + const teamSlug = '${{ inputs.github_team_slug }}'; + const org = context.repo.owner; + const prCreator = context.payload.pull_request.user.login; + + console.log(`🔍 Checking team membership for PR creator...`); + console.log(` - Team slug: ${teamSlug}`); + console.log(` - PR creator: ${prCreator}`); + console.log(` - Organization: ${org}`); + + try { + const { data } = await github.rest.teams.getMembershipForUserInOrg({ + org: org, + team_slug: teamSlug, + username: prCreator + }); + + core.setOutput('is_member', 'true'); + console.log(`✅ PR creator is a member of the team`); + } catch (error) { + if (error.status === 404) { + core.setOutput('is_member', 'false'); + console.log(`⚠️ PR creator is not a member of the team`); + } else { + console.log(`⚠️ Could not verify team membership (${error.message}), assuming external contributor`); + core.setOutput('is_member', 'false'); + } + } + + - name: Add external contributor label + if: steps.check-team.outputs.is_member == 'false' + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + github-token: ${{ inputs.github-token }} + script: | + const labelName = '${{ inputs.label_name }}'; + const prNumber = context.issue.number; + + console.log(`🏷️ Adding label "${labelName}" to PR #${prNumber}...`); + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + labels: [labelName] + }); + + console.log(`✅ Added label "${labelName}" to PR #${prNumber}`); \ No newline at end of file