aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Matteo Bertucci <[email protected]>2020-11-30 15:10:39 +0100
committerGravatar GitHub <[email protected]>2020-11-30 15:10:39 +0100
commit95e740f8950a630fd82e9b04bb0f095d1c184233 (patch)
treeff9debada1f312951304a7c94941f706b95f3660
parentAdd myself to CODEOWNERS of CI files (diff)
parentUpdate CODEOWNERS for Den4200. (diff)
Merge pull request #532 from python-discord/sebastiaan/ci/add-core-dev-approval-check
Add check for core dev approvals on pull requests
-rw-r--r--.github/CODEOWNERS9
-rw-r--r--.github/workflows/review-check.yaml166
2 files changed, 169 insertions, 6 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 4a702e0c..6afbfb31 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,10 +1,7 @@
-# Request Dennis for any PR
-* @Den4200
-
# CI & Docker
-.github/workflows/** @Akarys42 @SebastiaanZ
-Dockerfile @Akarys42
-docker-compose.yml @Akarys42
+.github/workflows/** @Akarys42 @SebastiaanZ @Den4200
+Dockerfile @Akarys42 @Den4200
+docker-compose.yml @Akarys42 @Den4200
# Tools
Pipfile* @Akarys42
diff --git a/.github/workflows/review-check.yaml b/.github/workflows/review-check.yaml
new file mode 100644
index 00000000..3e45a4b5
--- /dev/null
+++ b/.github/workflows/review-check.yaml
@@ -0,0 +1,166 @@
+name: Review Check
+
+# This workflow needs to trigger in two situations:
+#
+# 1. When a pull request is opened, reopened, or synchronized (new commit)
+# This is accomplished using the `pull_request_target` event that triggers in
+# precisely those situations by default. I've opted for `pull_request_target`
+# as we don't need to have access to the PR's code and it's safer to make the
+# secrets we need available to the workflow compared to `pull_request`.
+#
+# The reason we need to run the workflow for this event is because we need to
+# make sure that our check is part of the check suite for the current commit.
+#
+# 2. When a review is added or dismissed.
+# Whenever reviews are submitted or dismissed, the number of Core Developer
+# approvals may obviously change.
+#
+# ---
+#
+# Unfortunately, having two different event triggers means that can't let
+# this workflow fail on its own, as GitHub actions registers a separate check
+# run result per event trigger. As both triggers need to share the success/fail
+# state, we get around that by registering a custom "status".
+on:
+ pull_request_review:
+ types:
+ - submitted
+ - dismissed
+ pull_request_target:
+
+
+jobs:
+ review-check:
+ name: Check Core Dev Reviews
+ runs-on: ubuntu-latest
+
+ steps:
+ # Fetch the latest Opinionated reviews from users with write
+ # access. We can't narrow it down using a specific team here
+ # yet, so we'll do that later.
+ - uses: octokit/[email protected]
+ id: reviews
+ with:
+ query: |
+ query ($repository: String!, $pr: Int!) {
+ repository(owner: "python-discord", name: $repository) {
+ pullRequest(number: $pr) {
+ latestOpinionatedReviews(last: 100, writersOnly: true) {
+ nodes{
+ author{
+ login
+ }
+ state
+ }
+ }
+ }
+ }
+ }
+ repository: ${{ github.event.repository.name }}
+ pr: ${{ github.event.pull_request.number }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }}
+
+ # Fetch the members of the Core Developers team so we can
+ # check if any of them actually approved this PR.
+ - uses: octokit/[email protected]
+ id: core_developers
+ with:
+ query: |
+ query {
+ organization(login: "python-discord") {
+ team(slug: "core-developers") {
+ members(first: 100) {
+ nodes {
+ login
+ }
+ }
+ }
+ }
+ }
+ env:
+ GITHUB_TOKEN: ${{ secrets.TEAM_TOKEN }}
+
+ # I've opted for a Python script, as that's what most of us
+ # are familiar with. We do need to setup Python for that.
+ - name: Setup python
+ id: python
+ uses: actions/setup-python@v2
+ with:
+ python-version: '3.9'
+
+ # This is a small, inline Python script that looks for the
+ # intersection between approving reviewers and the core dev
+ # team. If that intersection exists, we have at least one
+ # approving Core Developer.
+ #
+ # I've opted to keep this inline as it's relatively small
+ # and this workflow will be added to multiple repositories.
+ - name: Check for Accepting Core Developers
+ id: core_dev_reviews
+ run: |
+ python -c 'import json
+ reviews = json.loads("""${{ steps.reviews.outputs.data }}""")
+ reviewers = {
+ review["author"]["login"]
+ for review in reviews["repository"]["pullRequest"]["latestOpinionatedReviews"]["nodes"]
+ if review["state"] == "APPROVED"
+ }
+ core_devs = json.loads("""${{ steps.core_developers.outputs.data }}""")
+ core_devs = {
+ member["login"] for member in core_devs["organization"]["team"]["members"]["nodes"]
+ }
+ approving_core_devs = reviewers & core_devs
+ approval_check = "success" if approving_core_devs else "failure"
+ print(f"::set-output name=approval_check::{approval_check}")
+ '
+
+ # This step registers a a new status for the head commit of the pull
+ # request. If a status with the same context and description already
+ # exists, it will be overwritten. The reason we have to do this is
+ # because workflows run for the separate `pull_request_target` and
+ #`pull_request_review` events need to share a single result state.
+ - name: Add Core Dev Approval status check
+ uses: octokit/[email protected]
+ with:
+ route: POST /repos/:repository/statuses/:sha
+ repository: ${{ github.repository }}
+ sha: ${{ github.event.pull_request.head.sha }}
+ state: ${{ steps.core_dev_reviews.outputs.approval_check }}
+ description: At least one core developer needs to approve this PR
+ context: Core Dev Approval
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ # If we have at least one Core Developer approval, this step
+ # removes the 'waiting for core dev approval' label if it's
+ # still present for the PR.
+ - name: Remove "waiting for core dev approval" if a core dev approved this PR
+ if: >-
+ steps.core_dev_reviews.outputs.approval_check == 'success' &&
+ contains(github.event.pull_request.labels.*.name, 'waiting for core dev approval')
+ uses: octokit/[email protected]
+ with:
+ route: DELETE /repos/:repository/issues/:number/labels/:label
+ repository: ${{ github.repository }}
+ number: ${{ github.event.pull_request.number }}
+ label: needs core dev approval
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ # If we have do not have one Core Developer approval, this step
+ # adds the 'waiting for core dev approval' label if it's not
+ # already present for the PR.
+ - name: Add "waiting for core dev approval" if no core dev has approved yet
+ if: >-
+ steps.core_dev_reviews.outputs.approval_check == 'failure' &&
+ !contains(github.event.pull_request.labels.*.name, 'waiting for core dev approval')
+ uses: octokit/[email protected]
+ with:
+ route: POST /repos/:repository/issues/:number/labels
+ repository: ${{ github.repository }}
+ number: ${{ github.event.pull_request.number }}
+ labels: |
+ - needs core dev approval
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}