Initial public release of Warp.
Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
name: Check Approvals
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, ready_for_review]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
jobs:
|
||||
check_owners:
|
||||
name: Check OWNERS approval
|
||||
runs-on: ubuntu-latest
|
||||
# Skip draft PRs.
|
||||
if: github.event.pull_request.draft == false
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
# We don't actually need the contents of the files, just their names.
|
||||
filter: blob:none
|
||||
|
||||
- name: Get changed files
|
||||
id: changed_files
|
||||
run: |
|
||||
HEAD_SHA=${{ github.event.pull_request.head.sha }}
|
||||
BASE_SHA=${{ github.event.pull_request.base.sha }}
|
||||
MERGE_BASE=$(git merge-base "$BASE_SHA" "$HEAD_SHA")
|
||||
CHANGED_FILES=$(git diff --name-only "$MERGE_BASE" "$HEAD_SHA" | tr '\n' ' ')
|
||||
echo "files=$CHANGED_FILES" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Get PR approvers
|
||||
id: approvers
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
PR_NUMBER=${{ github.event.pull_request.number }}
|
||||
PR_AUTHOR=${{ github.event.pull_request.user.login }}
|
||||
|
||||
# Get all approved reviews.
|
||||
REVIEWERS=$(gh pr view "$PR_NUMBER" --json reviews --jq '[.reviews[] | select(.state == "APPROVED") | .author.login] | unique | join(" ")')
|
||||
|
||||
# Combine PR author (self-approves) with reviewers.
|
||||
ALL_APPROVERS="$PR_AUTHOR $REVIEWERS"
|
||||
echo "approvers=$ALL_APPROVERS" >> "$GITHUB_OUTPUT"
|
||||
echo "has_reviewers=$( [[ -n "$REVIEWERS" ]] && echo true || echo false )" >> "$GITHUB_OUTPUT"
|
||||
echo "PR author: $PR_AUTHOR"
|
||||
echo "Reviewers who approved: $REVIEWERS"
|
||||
echo "All approvers: $ALL_APPROVERS"
|
||||
|
||||
- name: Check OWNERS approval
|
||||
env:
|
||||
CHANGED_FILES: ${{ steps.changed_files.outputs.files }}
|
||||
APPROVERS: ${{ steps.approvers.outputs.approvers }}
|
||||
run: |
|
||||
set -e
|
||||
|
||||
# Convert approvers to an array.
|
||||
read -ra APPROVER_ARRAY <<< "$APPROVERS"
|
||||
|
||||
# Function to get owners for a file by walking up the directory tree.
|
||||
get_owners_for_file() {
|
||||
local file="$1"
|
||||
local dir
|
||||
dir=$(dirname "$file")
|
||||
local owners=()
|
||||
|
||||
# Walk up the directory tree.
|
||||
while [[ "$dir" != "." && "$dir" != "/" ]]; do
|
||||
if [[ -f "$dir/OWNERS" ]]; then
|
||||
# Read owners file, skip comments and empty lines.
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
# Skip comments and empty lines.
|
||||
line=$(echo "$line" | sed 's/#.*//' | xargs)
|
||||
if [[ -n "$line" ]]; then
|
||||
owners+=("$line")
|
||||
fi
|
||||
done < "$dir/OWNERS"
|
||||
fi
|
||||
dir=$(dirname "$dir")
|
||||
done
|
||||
|
||||
# Check root directory.
|
||||
if [[ -f "OWNERS" ]]; then
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
line=$(echo "$line" | sed 's/#.*//' | xargs)
|
||||
if [[ -n "$line" ]]; then
|
||||
owners+=("$line")
|
||||
fi
|
||||
done < "OWNERS"
|
||||
fi
|
||||
|
||||
# Return unique owners.
|
||||
printf '%s\n' "${owners[@]}" | sort -u | tr '\n' ' ' | sed 's/ $//'
|
||||
}
|
||||
|
||||
# Function to check if any approver is in the owners list.
|
||||
has_owner_approval() {
|
||||
local owners="$1"
|
||||
for approver in "${APPROVER_ARRAY[@]}"; do
|
||||
if echo "$owners" | grep -qw "$approver"; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
MISSING_APPROVAL=()
|
||||
FILES_CHECKED=0
|
||||
|
||||
for file in $CHANGED_FILES; do
|
||||
# Skip if file doesn't exist (deleted files).
|
||||
FILES_CHECKED=$((FILES_CHECKED + 1))
|
||||
|
||||
OWNERS=$(get_owners_for_file "$file")
|
||||
|
||||
if [[ -z "$OWNERS" ]]; then
|
||||
# No OWNERS files in ancestry - automatically passes.
|
||||
echo "✓ $file (no OWNERS requirement)"
|
||||
continue
|
||||
fi
|
||||
|
||||
if has_owner_approval "$OWNERS"; then
|
||||
echo "✓ $file"
|
||||
else
|
||||
echo "✗ $file (owners: $OWNERS)"
|
||||
MISSING_APPROVAL+=("$file")
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Files checked: $FILES_CHECKED"
|
||||
echo "Approvers: ${APPROVER_ARRAY[*]}"
|
||||
|
||||
# Save missing files for comment step (must happen before exit).
|
||||
echo "MISSING_FILES<<EOF" >> "$GITHUB_ENV"
|
||||
for file in "${MISSING_APPROVAL[@]}"; do
|
||||
OWNERS=$(get_owners_for_file "$file")
|
||||
echo "- \`$file\` (needs approval from: $OWNERS)" >> "$GITHUB_ENV"
|
||||
done
|
||||
echo "EOF" >> "$GITHUB_ENV"
|
||||
|
||||
if [[ ${#MISSING_APPROVAL[@]} -gt 0 ]]; then
|
||||
echo ""
|
||||
echo "::error::The following files are missing OWNERS approval:"
|
||||
for file in "${MISSING_APPROVAL[@]}"; do
|
||||
OWNERS=$(get_owners_for_file "$file")
|
||||
echo "::error:: - $file (needs approval from: $OWNERS)"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "All files have required OWNERS approval."
|
||||
|
||||
- name: Comment on PR about missing approvals
|
||||
if: failure() && github.event_name == 'pull_request_review' && steps.approvers.outputs.has_reviewers == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
PR_NUMBER=${{ github.event.pull_request.number }}
|
||||
gh pr comment "$PR_NUMBER" --body "The following files still need approval from their OWNERS:\n\n$MISSING_FILES"
|
||||
Reference in New Issue
Block a user