Add triage workflow.
				
					
				
			This commit is contained in:
		
							parent
							
								
									570edcc0cc
								
							
						
					
					
						commit
						cbda2c0f98
					
				
							
								
								
									
										195
									
								
								.github/workflows/triage.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								.github/workflows/triage.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,195 @@
 | 
			
		||||
name: Triage
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  pull_request_target:
 | 
			
		||||
    types:
 | 
			
		||||
      - opened
 | 
			
		||||
      - synchronize
 | 
			
		||||
      - reopened
 | 
			
		||||
      - closed
 | 
			
		||||
      - labeled
 | 
			
		||||
      - unlabeled
 | 
			
		||||
  schedule:
 | 
			
		||||
    - cron: '0 */3 * * *' # every 3 hours
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  review:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    if: startsWith(github.repository, 'Homebrew/')
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Re-run this workflow
 | 
			
		||||
        if: github.event_name == 'schedule' || github.event.action == 'closed'
 | 
			
		||||
        uses: reitermarkus/rerun-workflow@cf91bee6964dfde64eccbf5600c3ea206af11359
 | 
			
		||||
        with:
 | 
			
		||||
          token: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
 | 
			
		||||
          continuous-label: waiting for feedback
 | 
			
		||||
          trigger-labels: critical
 | 
			
		||||
          workflow: triage.yml
 | 
			
		||||
      - name: Review pull request
 | 
			
		||||
        if: >
 | 
			
		||||
          (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') &&
 | 
			
		||||
            github.event.action != 'closed'
 | 
			
		||||
        uses: actions/github-script@v3
 | 
			
		||||
        with:
 | 
			
		||||
          github-token: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
 | 
			
		||||
          script: |
 | 
			
		||||
            async function approvePullRequest(pullRequestNumber) {
 | 
			
		||||
              const reviews = await approvalsByAuthenticatedUser(pullRequestNumber)
 | 
			
		||||
 | 
			
		||||
              if (reviews.length > 0) {
 | 
			
		||||
                return
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              await github.pulls.createReview({
 | 
			
		||||
                ...context.repo,
 | 
			
		||||
                pull_number: pullRequestNumber,
 | 
			
		||||
                event: 'APPROVE',
 | 
			
		||||
              })
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            async function findComment(pullRequestNumber, id) {
 | 
			
		||||
              const { data: comments } = await github.issues.listComments({
 | 
			
		||||
                owner: context.repo.owner,
 | 
			
		||||
                repo: context.repo.repo,
 | 
			
		||||
                issue_number: pullRequestNumber,
 | 
			
		||||
              })
 | 
			
		||||
 | 
			
		||||
              const regex = new RegExp(`<!--\\s*#${id}\\s*-->`)
 | 
			
		||||
              return comments.filter(comment => comment.body.match(regex))[0]
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            async function createOrUpdateComment(pullRequestNumber, id, message) {
 | 
			
		||||
              const beginComment = await findComment(pullRequestNumber, id)
 | 
			
		||||
 | 
			
		||||
              const body = `<!-- #${id} -->\n\n${message}`
 | 
			
		||||
              if (beginComment) {
 | 
			
		||||
                await github.issues.updateComment({
 | 
			
		||||
                  ...context.repo,
 | 
			
		||||
                  comment_id: beginComment.id,
 | 
			
		||||
                  body,
 | 
			
		||||
                })
 | 
			
		||||
              } else {
 | 
			
		||||
                await github.issues.createComment({
 | 
			
		||||
                  ...context.repo,
 | 
			
		||||
                  issue_number: pullRequestNumber,
 | 
			
		||||
                  body,
 | 
			
		||||
                })
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            async function approvalsByAuthenticatedUser(pullRequestNumber) {
 | 
			
		||||
              const { data: user } = await github.users.getAuthenticated()
 | 
			
		||||
 | 
			
		||||
              const { data: reviews } = await github.pulls.listReviews({
 | 
			
		||||
                ...context.repo,
 | 
			
		||||
                pull_number: pullRequestNumber,
 | 
			
		||||
              })
 | 
			
		||||
 | 
			
		||||
              const approvals = reviews.filter(review => review.state == 'APPROVED')
 | 
			
		||||
              return approvals.filter(review => review.user.login == user.login)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            async function dismissApprovals(pullRequestNumber, message) {
 | 
			
		||||
              const reviews = await approvalsByAuthenticatedUser(pullRequestNumber)
 | 
			
		||||
              for (const review of reviews) {
 | 
			
		||||
                await github.pulls.dismissReview({
 | 
			
		||||
                  ...context.repo,
 | 
			
		||||
                  pull_number: pullRequestNumber,
 | 
			
		||||
                  review_id: review.id,
 | 
			
		||||
                  message: message
 | 
			
		||||
                });
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            async function reviewPullRequest(pullRequestNumber) {
 | 
			
		||||
              const { data: pullRequest } = await github.pulls.get({
 | 
			
		||||
                owner: context.repo.owner,
 | 
			
		||||
                repo: context.repo.repo,
 | 
			
		||||
                pull_number: pullRequestNumber,
 | 
			
		||||
              })
 | 
			
		||||
 | 
			
		||||
              if (pullRequest.author_association != 'MEMBER') {
 | 
			
		||||
                core.warning('Pull request author is not a member.')
 | 
			
		||||
                return
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              const reviewLabel = 'waiting for feedback'
 | 
			
		||||
              const criticalLabel = 'critical'
 | 
			
		||||
 | 
			
		||||
              const labels = pullRequest.labels.map(label => label.name)
 | 
			
		||||
              const hasReviewLabel = labels.includes(reviewLabel)
 | 
			
		||||
              const hasCriticalLabel = labels.includes(criticalLabel)
 | 
			
		||||
 | 
			
		||||
              const reviewStartDate = new Date(pullRequest.created_at)
 | 
			
		||||
              const reviewEndDate = new Date(reviewStartDate)
 | 
			
		||||
              switch (reviewStartDate.getDay()) {
 | 
			
		||||
                // Skip from Friday to Monday and from Saturday to Tuesday.
 | 
			
		||||
                case 5:
 | 
			
		||||
                case 6:
 | 
			
		||||
                  reviewEndDate.setDate(reviewStartDate.getDate() + 3)
 | 
			
		||||
                  break
 | 
			
		||||
                // Skip from Sunday to Tuesday.
 | 
			
		||||
                case 0:
 | 
			
		||||
                  reviewEndDate.setDate(reviewStartDate.getDate() + 2)
 | 
			
		||||
                  break
 | 
			
		||||
                default:
 | 
			
		||||
                  reviewEndDate.setDate(reviewStartDate.getDate() + 1)
 | 
			
		||||
                  break
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              const currentDate = new Date()
 | 
			
		||||
              const reviewEnded = currentDate > reviewEndDate
 | 
			
		||||
 | 
			
		||||
              function formatDate(date) {
 | 
			
		||||
                return date.toISOString().replace(/\.\d+Z$/, ' UTC').replace('T', ' at ')
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              if (reviewEnded || hasCriticalLabel) {
 | 
			
		||||
                let message
 | 
			
		||||
                if (hasCriticalLabel && !reviewEnded) {
 | 
			
		||||
                  if (hasReviewLabel) {
 | 
			
		||||
                    message = `Review period cancelled due to \`${criticalLabel}\` label.`
 | 
			
		||||
                  } else {
 | 
			
		||||
                    message = `Review period skipped due to \`${criticalLabel}\` label.`
 | 
			
		||||
                  }
 | 
			
		||||
                } else {
 | 
			
		||||
                  message = 'Review period ended.'
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (hasReviewLabel) {
 | 
			
		||||
                  await github.issues.removeLabel({
 | 
			
		||||
                    ...context.repo,
 | 
			
		||||
                    issue_number: pullRequestNumber,
 | 
			
		||||
                    name: reviewLabel,
 | 
			
		||||
                  })
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                core.info(message)
 | 
			
		||||
                await createOrUpdateComment(pullRequestNumber, 'review-period-end', message)
 | 
			
		||||
                await approvePullRequest(pullRequestNumber)
 | 
			
		||||
              } else {
 | 
			
		||||
                const message = `Review period will end on ${formatDate(reviewEndDate)}.`
 | 
			
		||||
                core.warning(message)
 | 
			
		||||
 | 
			
		||||
                await dismissApprovals(pullRequestNumber, 'Review period has not ended yet.')
 | 
			
		||||
                await createOrUpdateComment(pullRequestNumber, 'review-period-begin', message)
 | 
			
		||||
 | 
			
		||||
                const endComment = await findComment(pullRequestNumber, 'review-period-end')
 | 
			
		||||
                if (endComment) {
 | 
			
		||||
                  await github.issues.deleteComment({
 | 
			
		||||
                    ...context.repo,
 | 
			
		||||
                    comment_id: endComment.id,
 | 
			
		||||
                  })
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                await github.issues.addLabels({
 | 
			
		||||
                  ...context.repo,
 | 
			
		||||
                  issue_number: pullRequestNumber,
 | 
			
		||||
                  labels: [reviewLabel],
 | 
			
		||||
                })
 | 
			
		||||
 | 
			
		||||
                core.setFailed('Review period has not ended yet.')
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await reviewPullRequest(context.issue.number)
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user