Require product eng approval for PRs #8
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Approval Check | |
| on: | |
| pull_request_review: | |
| types: [submitted] | |
| pull_request: | |
| types: [opened, reopened, synchronize] | |
| jobs: | |
| check-product-eng-approval: | |
| name: Check Product Eng Approval | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check for Product Engineering approval | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const { data: reviews } = await github.rest.pulls.listReviews({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.payload.pull_request.number | |
| }); | |
| console.log(`Found ${reviews.length} reviews`); | |
| // Get approved reviews | |
| const approvals = reviews.filter(review => review.state === 'APPROVED'); | |
| console.log(`Found ${approvals.length} approvals`); | |
| if (approvals.length === 0) { | |
| console.log('No approvals found'); | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: context.payload.pull_request.head.sha, | |
| state: 'pending', | |
| context: 'product-eng-approval', | |
| description: 'Waiting for approval from @trufflesecurity/product-eng team member' | |
| }); | |
| return; | |
| } | |
| // Helper function to get all teams to check (parent + children) | |
| async function getTeamsToCheck() { | |
| const teamsToCheck = ['product-eng']; // Start with parent team | |
| try { | |
| // Get child teams of product-eng | |
| const { data: childTeams } = await github.rest.teams.listChildInOrg({ | |
| org: 'trufflesecurity', | |
| team_slug: 'product-eng' | |
| }); | |
| // Add child team slugs | |
| childTeams.forEach(team => { | |
| teamsToCheck.push(team.slug); | |
| }); | |
| console.log(`Teams to check: ${teamsToCheck.join(', ')}`); | |
| } catch (error) { | |
| console.log('Error fetching child teams, will only check parent team:', error.message); | |
| } | |
| return teamsToCheck; | |
| } | |
| // Helper function to check if user is member of any team | |
| async function isUserMemberOfAnyTeam(username, teams) { | |
| for (const teamSlug of teams) { | |
| try { | |
| const { data: membership } = await github.rest.teams.getMembershipForUserInOrg({ | |
| org: 'trufflesecurity', | |
| team_slug: teamSlug, | |
| username: username | |
| }); | |
| if (membership.state === 'active') { | |
| console.log(`✅ Found active member of @trufflesecurity/${teamSlug}: ${username}`); | |
| return { isMember: true, teamSlug }; | |
| } | |
| } catch (error) { | |
| // User is not a member of this team (404) or other error | |
| console.log(`❌ ${username} is not a member of @trufflesecurity/${teamSlug}`); | |
| } | |
| } | |
| return { isMember: false, teamSlug: null }; | |
| } | |
| // Get all teams to check (parent + children) | |
| const teamsToCheck = await getTeamsToCheck(); | |
| // Check if any approver is a member of product-eng or its child teams | |
| let hasProductEngApproval = false; | |
| let approverInfo = null; | |
| for (const approval of approvals) { | |
| const membershipCheck = await isUserMemberOfAnyTeam(approval.user.login, teamsToCheck); | |
| if (membershipCheck.isMember) { | |
| hasProductEngApproval = true; | |
| approverInfo = { | |
| username: approval.user.login, | |
| teamSlug: membershipCheck.teamSlug | |
| }; | |
| break; | |
| } | |
| } | |
| if (hasProductEngApproval) { | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: context.payload.pull_request.head.sha, | |
| state: 'success', | |
| context: 'product-eng-approval', | |
| description: `✅ Approved by @trufflesecurity/${approverInfo.teamSlug} member (${approverInfo.username})` | |
| }); | |
| } else { | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: context.payload.pull_request.head.sha, | |
| state: 'failure', | |
| context: 'product-eng-approval', | |
| description: '❌ Requires approval from @trufflesecurity/product-eng team member' | |
| }); | |
| } |