Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions .github/workflows/codeowner_assignment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: Codeowner assignment

on: [pull_request]

jobs:
codeowner_assignment:
name: Codeowner assignment
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write

steps:
- uses: actions/checkout@v4

- uses: actions/create-github-app-token@v2.0.6
id: token
with:
app-id: ${{ vars.CODEOWNER_ASSIGNMENT_GITHUB_APP_ID }}
private-key: ${{ secrets.CODEOWNER_ASSIGNMENT_PRI_KEY }}
owner: ${{ github.repository_owner }}
repositories: |
sentry-docs

- name: Parse CODEOWNERS and assign reviewers
id: assign-reviewers
env:
PR_NUMBER: ${{ github.event.number }}
GH_TOKEN: ${{ steps.token.outputs.token }}
run: |
# locate CODEOWNERS file exists
if [[ -f .github/CODEOWNERS ]]; then
codeowner_path=".github/CODEOWNERS"
elif [[ -f CODEOWNERS ]]; then
codeowner_path="CODEOWNERS"
else
echo "CODEOWNERS file not found, skipping."
exit 0
fi

# Get changed files in the PR
git fetch origin ${{ github.event.pull_request.base.ref }} \
${{ github.event.pull_request.head.ref }}
CHANGED_FILES=$(git diff --name-only origin/${{ github.event.pull_request.base.ref }} \
origin/${{ github.event.pull_request.head.ref }})

echo "----------------------------------------"
echo "Changed files:"
echo "$CHANGED_FILES" | tr ' ' '\n' | sed 's/^/- /'
echo "----------------------------------------"

# Parse CODEOWNERS and find commented lines
# Add newline to the end of the file if it doesn't have one, otherwise sed will not read the last line
sed -i -e '$a\' $codeowner_path

while read -r LINE; do
# Skip lines that are not commented, GitHub will take care of un-commented lines
if [[ ! "$LINE" =~ ^# ]]; then continue; fi

# Extract pattern and reviewer from the commented line
PATTERN=$(echo "$LINE" | sed -E 's/^#\s*([^@]+).*$/\1/' | xargs)
# Capture both individual users and GitHub teams reviewers that have "/" in the name
REVIEWERS=$(echo "$LINE" | grep -o "@[a-zA-Z0-9_-]\+\(/[a-zA-Z0-9_-]\+\)\?" | tr '\n' ' ' | xargs)

# Skip if no reviewers found
if [[ -z "$REVIEWERS" ]]; then
continue
fi

# Convert pattern to a regex for matching
REGEX_PATTERN=$(echo "$PATTERN" | sed -e 's/\./\\./g' -e 's/\*/.*/g' -e 's/\?/./g' -e 's|^/||')

# Match changed files to the pattern
for FILE in $CHANGED_FILES; do
# For glob patterns(e.g. "**/"), use a different matching approach
if [[ "$PATTERN" == *"*"* ]]; then
# Special handling for **/ pattern
if [[ "$PATTERN" == "**/"* ]]; then
# Get the filename part after **/
FILENAME=${PATTERN#**/}
# Match either the filename directly or with any path prefix
if [[ "$FILE" == "$FILENAME" ]] || [[ "$FILE" == */"$FILENAME" ]]; then
echo "File $FILE matches glob pattern $PATTERN"
# Assign each reviewer
for REVIEWER in $REVIEWERS; do
# Remove @ symbol from reviewer name
REVIEWER_NAME=${REVIEWER#@}
echo " - Assigning $REVIEWER_NAME to review changes in $FILE"
gh pr edit $PR_NUMBER --add-reviewer "$REVIEWER_NAME"
done
fi
else
# Convert other glob patterns to regex for matching
GLOB_PATTERN=$(echo "$PATTERN" | sed -e 's/\./\\./g' -e 's/\*/.*/g' -e 's/\?/./g')
if [[ "$FILE" =~ $GLOB_PATTERN ]]; then
echo "File $FILE matches glob pattern $PATTERN"
# Assign each reviewer
for REVIEWER in $REVIEWERS; do
# Remove @ symbol from reviewer name
REVIEWER_NAME=${REVIEWER#@}
echo " - Assigning $REVIEWER_NAME to review changes in $FILE"
gh pr edit $PR_NUMBER --add-reviewer "$REVIEWER_NAME"
done
fi
fi
else
# Original directory matching logic
if [[ "$FILE" == ${REGEX_PATTERN}* ]]; then
echo "File $FILE matches pattern $PATTERN"
# Assign each reviewer
for REVIEWER in $REVIEWERS; do
# Remove @ symbol from reviewer name
REVIEWER_NAME=${REVIEWER#@}
echo " - Assigning $REVIEWER_NAME to review changes in $FILE"
gh pr edit $PR_NUMBER --add-reviewer "$REVIEWER_NAME"
done
fi
fi
done
done < $codeowner_path