Branch Deletion Phase One (PR Creation) #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Branch Deletion Phase One (PR Creation) | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| on: | |
| schedule: | |
| - cron: '00 22 1 * *' # 10PM on 1st of every month | |
| workflow_dispatch: | |
| inputs: | |
| min_age_days: | |
| description: "Minimum age in days since merge" | |
| required: true | |
| default: 27 | |
| type: number | |
| jobs: | |
| identify-branches: | |
| if: github.repository_owner == 'mendix' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| persist-credentials: true | |
| - name: Setup jq | |
| run: sudo apt-get install -y jq | |
| - name: Create timestamp file | |
| run: | | |
| echo "Last scan for stale merged branches: $(TZ='Europe/Amsterdam' date +'%Y-%m-%d %H:%M:%S %Z (UTC%:z)')" > branch-cleanup-timestamp.txt | |
| - name: Fetch all branches | |
| run: | | |
| git fetch origin '+refs/heads/*:refs/remotes/origin/*' --prune | |
| - name: Process branches | |
| id: branch-data | |
| env: | |
| MIN_AGE_DAYS: ${{ github.event.inputs.min_age_days || '27' }} | |
| run: | | |
| set -e | |
| ALL_BRANCHES=$(git branch -r | grep -v "origin/HEAD" | sed 's/origin\///') | |
| MIN_AGE_DAYS=${MIN_AGE_DAYS:-27} | |
| echo "MIN_AGE_DAYS=${MIN_AGE_DAYS}" | |
| PROTECTED_COUNT=0 | |
| MERGED_COUNT=0 | |
| UNMERGED_COUNT=0 | |
| PROTECTED_BRANCHES=() | |
| MERGED_BRANCHES_TO_PROCESS=() | |
| BRANCHES_TO_DELETE=() | |
| BRANCHES_TOO_RECENT=() | |
| UNMERGED_BRANCHES=() | |
| CURRENT_DATE=$(date +%Y%m%d) | |
| echo "CURRENT_DATE=$CURRENT_DATE" >> $GITHUB_ENV | |
| for BRANCH in $ALL_BRANCHES; do | |
| branch_lower=$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]') | |
| if [[ $branch_lower == *backup* || $branch_lower =~ ^(development|main|master|production)(-[0-9]+)?$ ]]; then | |
| PROTECTED_BRANCHES+=("$BRANCH") | |
| PROTECTED_COUNT=$((PROTECTED_COUNT+1)) | |
| elif git branch -r --merged origin/development | grep -q "origin/$BRANCH"; then | |
| MERGED_BRANCHES_TO_PROCESS+=("$BRANCH") | |
| MERGED_COUNT=$((MERGED_COUNT+1)) | |
| else | |
| UNMERGED_BRANCHES+=("$BRANCH") | |
| UNMERGED_COUNT=$((UNMERGED_COUNT+1)) | |
| fi | |
| done | |
| echo "branch totals: protected=${PROTECTED_COUNT} merged=${MERGED_COUNT} unmerged=${UNMERGED_COUNT}" | |
| for BRANCH in "${MERGED_BRANCHES_TO_PROCESS[@]}"; do | |
| MERGE_HASH=$(git log --grep="Merge branch.*$BRANCH" origin/development -n 1 --pretty=format:"%H" || true) | |
| if [ -z "$MERGE_HASH" ]; then | |
| MERGE_HASH=$(git log -n 1 origin/$BRANCH --pretty=format:"%H" || true) | |
| fi | |
| if [ -z "$MERGE_HASH" ]; then | |
| echo "WARN: no merge commit found for $BRANCH — skipping" | |
| UNMERGED_BRANCHES+=("$BRANCH (no-merge-hash)") | |
| UNMERGED_COUNT=$((UNMERGED_COUNT+1)) | |
| continue | |
| fi | |
| MERGE_DATE_EPOCH=$(git show -s --format=%ct $MERGE_HASH 2>/dev/null || true) | |
| if [ -z "$MERGE_DATE_EPOCH" ]; then | |
| echo "WARN: could not read commit date for $BRANCH (hash=$MERGE_HASH) — skipping" | |
| UNMERGED_BRANCHES+=("$BRANCH (no-merge-date)") | |
| UNMERGED_COUNT=$((UNMERGED_COUNT+1)) | |
| continue | |
| fi | |
| DAYS_AGO=$(( ($(date +%s) - MERGE_DATE_EPOCH) / 86400 )) | |
| if [[ $DAYS_AGO -ge $MIN_AGE_DAYS ]]; then | |
| BRANCHES_TO_DELETE+=("$BRANCH (${DAYS_AGO}d since merge)") | |
| else | |
| BRANCHES_TOO_RECENT+=("$BRANCH (${DAYS_AGO}d since merge)") | |
| fi | |
| echo "checked $BRANCH: hash=$MERGE_HASH date=$MERGE_DATE_EPOCH days=${DAYS_AGO}" | |
| done | |
| echo "HAS_BRANCHES=$([ ${#BRANCHES_TO_DELETE[@]} -gt 0 ] && echo true || echo false)" >> $GITHUB_ENV | |
| echo "BRANCHES_TO_DELETE=$(printf -- '- %s\n' "${BRANCHES_TO_DELETE[@]}" | jq -Rs .)" >> $GITHUB_ENV | |
| echo "PROTECTED_BRANCHES=$(printf -- '- %s\n' "${PROTECTED_BRANCHES[@]}" | jq -Rs .)" >> $GITHUB_ENV | |
| echo "BRANCHES_TOO_RECENT=$(printf -- '- %s\n' "${BRANCHES_TOO_RECENT[@]}" | jq -Rs .)" >> $GITHUB_ENV | |
| echo "UNMERGED_BRANCHES=$(printf -- '- %s\n' "${UNMERGED_BRANCHES[@]}" | jq -Rs .)" >> $GITHUB_ENV | |
| - name: Create Deletion PR | |
| if: env.HAS_BRANCHES == 'true' | |
| uses: peter-evans/create-pull-request@v6 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| title: "[Auto] Branch Deletion Candidates - ${{ env.CURRENT_DATE }}" | |
| body: | | |
| ### Branches for Deletion | |
| ${{ fromJSON(env.BRANCHES_TO_DELETE) }} | |
| ### Protected Branches | |
| ${{ fromJSON(env.PROTECTED_BRANCHES) }} | |
| ### Recent Merges (too recent to delete) | |
| ${{ fromJSON(env.BRANCHES_TOO_RECENT) }} | |
| ### Unmerged Branches | |
| ${{ fromJSON(env.UNMERGED_BRANCHES) }} | |
| base: development | |
| labels: Internal WIP | |
| assignees: MarkvanMents,OlufunkeMoronfolu | |
| reviewers: MarkvanMents,OlufunkeMoronfolu | |
| commit-message: "Add branch cleanup candidates for ${{ env.CURRENT_DATE }}" | |
| add-paths: | | |
| branch-cleanup-timestamp.txt | |
| author: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" | |
| committer: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" |