pr-approval-check: refactor, fix pagination, fix approval logic #10
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: | |
| request-team-review: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| pull-requests: write | |
| steps: | |
| - name: Request team review | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const teamSlug = "OSS"; | |
| try { | |
| await github.rest.pulls.requestReviewers({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.payload.pull_request.number, | |
| team_reviewers: [teamSlug] // Note: team_reviewers for teams | |
| }); | |
| console.log(`✅ Successfully requested review from @${context.repo.owner}/${teamSlug}`); | |
| } catch (error) { | |
| // Don't fail if team already requested or other non-critical error | |
| console.log(`⚠️ Could not request team review: ${error.message}`); | |
| } | |
| 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 approvers = reviews.filter(review => review.state === 'APPROVED').map(a => a.user.login); | |
| console.log(`Found ${approvers.length} approvers`); | |
| if (approvers.length === 0) { | |
| console.log('No approvers 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); | |
| }); | |
| } catch (error) { | |
| console.log('Error fetching child teams, will only check parent team:', error.status); | |
| } | |
| 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/product-eng: ${username}`); | |
| return true; | |
| } | |
| } catch (error) { | |
| if (error.status !== 404) { | |
| console.error(`⚠️ Error checking membership for ${username} in @trufflesecurity team:`, error.status); | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| // Get all teams to check (parent + children) | |
| const teamsToCheck = await getTeamsToCheck(); | |
| let hasProductEngApproval = false; | |
| let approverLogin = null; | |
| for (const approver of approvers) { | |
| const membershipCheck = await isUserMemberOfAnyTeam(approver, teamsToCheck); | |
| if (membershipCheck.isMember) { | |
| hasProductEngApproval = true; | |
| approverLogin = approver; | |
| 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/product-eng team member (${approverLogin})` | |
| }); | |
| } 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' | |
| }); | |
| } | |