diff --git a/.github/workflows/enforce-labelling.yml b/.github/workflows/enforce-labelling.yml new file mode 100644 index 000000000..5617a5bd5 --- /dev/null +++ b/.github/workflows/enforce-labelling.yml @@ -0,0 +1,103 @@ +name: PR and Issue Validation + +on: + pull_request: + # one limitation here is that there's no trigger to re-run any time we "connect" or "disconnect" an issue + types: [opened, edited, labeled, unlabeled, synchronize] + issues: + types: [opened, edited, labeled, unlabeled, closed] + +jobs: + validate-pr: + runs-on: ubuntu-latest + steps: + - name: Check out the repository + uses: actions/checkout@v2 + + - name: Validate PR has labels + id: check_labels + run: | + PR_LABELS=$(jq -r '.pull_request.labels | length' $GITHUB_EVENT_PATH) + if [ "$PR_LABELS" -eq "0" ]; then + echo "No labels found on the pull request." + exit 1 + fi + + - name: Validate PR is linked to an issue + id: check_linked_issues + run: | + PR_NUMBER=$(jq -r '.pull_request.number' $GITHUB_EVENT_PATH) + REPO_OWNER=$(jq -r '.repository.owner.login' $GITHUB_EVENT_PATH) + REPO_NAME=$(jq -r '.repository.name' $GITHUB_EVENT_PATH) + TIMELINE_JSON=$(curl -s "https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/issues/$PR_NUMBER/timeline") + + # Count the number of times the timeline sees a "connected" event and subract the number of "disconnected" events + # We might also consider using the "cross-referenced" event in the future if actual connecting/disconnecting is too heavy-handed + LINKED_ISSUES=$(echo "$TIMELINE_JSON" | jq ' + reduce .[] as $event ( + 0; + if $event.event == "connected" then + . + 1 + elif $event.event == "disconnected" then + . - 1 + else + . + end + )') + + # If the sum is 0, then no linked issues were found + if [ "$LINKED_ISSUES" -eq "0" ]; then + echo "❌ No linked issues found in the pull request." + exit 1 + elif [ "$LINKED_ISSUES" -lt "0" ]; then + echo "Error: More disconnected events than connected events. This shouldn't be possible and likely indicates a big ol' 🪲" + exit 1 + else + echo "Linked issues found: $LINKED_ISSUES" + fi + + validate-issue: + runs-on: ubuntu-latest + if: github.event.action == 'closed' + steps: + - name: Check out the repository + uses: actions/checkout@v2 + + - name: Validate issue has labels + id: check_labels + run: | + ISSUE_LABELS=$(jq -r '.issue.labels | length' $GITHUB_EVENT_PATH) + if [ "$ISSUE_LABELS" -eq "0" ]; then + echo "No labels found on the issue." + exit 1 + fi + + - name: Validate issue is linked to a PR + id: check_linked_prs + run: | + ISSUE_NUMBER=$(jq -r '.issue.number' $GITHUB_EVENT_PATH) + REPO_OWNER=$(jq -r '.repository.owner.login' $GITHUB_EVENT_PATH) + REPO_NAME=$(jq -r '.repository.name' $GITHUB_EVENT_PATH) + TIMELINE_JSON=$(curl -s "https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/issues/$ISSUE_NUMBER/timeline") + + LINKED_PRS=$(echo "$TIMELINE_JSON" | jq ' + reduce .[] as $event ( + 0; + if $event.event == "connected" then + . + 1 + elif $event.event == "disconnected" then + . - 1 + else + . + end + )') + + if [ "$LINKED_PRS" -eq "0" ]; then + echo "❌ No linked pull requests found in the issue." + exit 1 + elif [ "$LINKED_PRS" -lt "0" ]; then + echo "Error: More disconnected events than connected events. This shouldn't be possible and likely indicates a big ol' 🪲" + exit 1 + else + echo "Linked PRs found: $LINKED_PRS" + fi