Skip to content

cleanup-merged-branches #63

cleanup-merged-branches

cleanup-merged-branches #63

name: cleanup-merged-branches
on:
schedule:
# Every week on Monday morning at 00:00
- cron: '0 0 * * 1'
workflow_dispatch:
inputs:
dryRun:
description: "Dry Run"
required: false
default: false
type: choice
options:
- false
- true
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
# With fetch-depth 0 the checkout action will also fetch all tags and branches.
fetch-depth: 0
token: ${{ secrets.GH_PAT }}
- name: Configure git name/email
run: |
git config user.name "IBM/Instana/Team Node.js"
git config user.email github-actions@github.com
- name: Authenticate GitHub CLI
run: |
gh auth login --with-token <<< "${{ secrets.GH_PAT }}"
- name: Delete old merged and inactive (+ closed) branches
env:
DRY_RUN: ${{ github.event.inputs.dryRun }}
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
run: |
if [[ "$(uname)" == "Darwin" ]]; then
THRESHOLD_DATE=$(date -v-60d +%s)
else
THRESHOLD_DATE=$(date +%s -d '60 days ago')
fi
git fetch --prune --all
for branch in $(git branch -r | grep -E 'origin/(chore-|docs-|fix-|feat-|test-|refactor-|ci-|build-|currency-bot-)'); do
branch_name=$(echo "$branch" | sed 's|origin/||')
# Check if branch has an open PR
open_pr_count=$(gh pr list --state open --head "$branch_name" --json number | jq '. | length')
if [[ $open_pr_count -gt 0 ]]; then
echo "Branch $branch_name has an open PR. Skipping."
continue
fi
should_delete=false
delete_reason=""
# Check if branch starts with build- or currency-bot-
# These branches can be deleted immediately if no open PR exists
if [[ "$branch_name" =~ ^(build-|currency-bot-) ]]; then
should_delete=true
delete_reason="automated branch with no open PR"
else
# For other branches, check if branch has a merged PR older than 60 days
pr_info=$(gh pr list --state merged --base main --head "$branch_name" --json mergedAt)
pr_merged_at=$(echo "$pr_info" | jq -r '.[0].mergedAt' 2>/dev/null)
if [[ -n "$pr_merged_at" && "$pr_merged_at" != "null" ]]; then
pr_merged_at_cleaned=$(echo "$pr_merged_at" | sed 's/Z$//')
pr_merged_timestamp=$(date -d "$pr_merged_at_cleaned" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%S" "$pr_merged_at_cleaned" +%s)
if [[ $pr_merged_timestamp -lt $THRESHOLD_DATE ]]; then
should_delete=true
delete_reason="merged PR older than 60 days"
fi
fi
# If not marked for deletion by merge logic, check last commit date
if [[ $should_delete == false ]]; then
last_commit_date=$(git log -1 --format=%ct "origin/$branch_name" 2>/dev/null)
if [[ -z "$last_commit_date" ]]; then
echo "Could not determine last commit date for $branch_name. Skipping."
continue
fi
if [[ $last_commit_date -lt $THRESHOLD_DATE ]]; then
should_delete=true
delete_reason="inactive for more than 60 days"
fi
fi
fi
# Delete branch if marked for deletion
if [[ $should_delete == true ]]; then
if [[ $DRY_RUN = true ]]; then
echo "Dry run: git push origin --delete $branch_name ($delete_reason)"
else
echo "Deleting branch: $branch_name ($delete_reason)"
git push origin --delete "$branch_name"
fi
else
echo "Skipping branch: $branch_name (active less than 60 days ago)."
fi
done