Skip to content

feat(tabs): add CycleMostRecentTab as third Ctrl+Tab behavior option #3462

feat(tabs): add CycleMostRecentTab as third Ctrl+Tab behavior option

feat(tabs): add CycleMostRecentTab as third Ctrl+Tab behavior option #3462

Workflow file for this run

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"