|  | 
|  | 1 | +name: "Manage Stale Issues, PRs & Unmerged Branches" | 
|  | 2 | +on: | 
|  | 3 | +  schedule: | 
|  | 4 | +    - cron: '30 1 * * *'  # Runs daily at 1:30 AM UTC | 
|  | 5 | +  workflow_dispatch:  # Allows manual triggering | 
|  | 6 | +permissions: | 
|  | 7 | +  contents: write | 
|  | 8 | +  issues: write | 
|  | 9 | +  pull-requests: write | 
|  | 10 | +jobs: | 
|  | 11 | +  stale: | 
|  | 12 | +    runs-on: ubuntu-latest | 
|  | 13 | +    steps: | 
|  | 14 | +      - name: Mark Stale Issues and PRs | 
|  | 15 | +        uses: actions/stale@v9 | 
|  | 16 | +        with: | 
|  | 17 | +          stale-issue-message: "This issue is stale because it has been open 180 days with no activity. Remove stale label or comment, or it will be closed in 30 days." | 
|  | 18 | +          stale-pr-message: "This PR is stale because it has been open 180 days with no activity. Please update or it will be closed in 30 days." | 
|  | 19 | +          days-before-stale: 180 | 
|  | 20 | +          days-before-close: 30 | 
|  | 21 | +          exempt-issue-labels: "keep" | 
|  | 22 | +          exempt-pr-labels: "keep" | 
|  | 23 | +  cleanup-branches: | 
|  | 24 | +    runs-on: ubuntu-latest | 
|  | 25 | +    steps: | 
|  | 26 | +      - name: Checkout Repository | 
|  | 27 | +        uses: actions/checkout@v4 | 
|  | 28 | +        with: | 
|  | 29 | +          fetch-depth: 0  # Fetch full history for accurate branch checks | 
|  | 30 | +      - name: Fetch All Branches | 
|  | 31 | +        run: git fetch --all --prune | 
|  | 32 | +      - name: List Merged Branches With No Activity in Last 3 Months | 
|  | 33 | +        run: | | 
|  | 34 | +           | 
|  | 35 | +          echo "Branch Name,Last Commit Date,Committer,Committed In Branch,Action" > merged_branches_report.csv | 
|  | 36 | +           | 
|  | 37 | +          for branch in $(git for-each-ref --format '%(refname:short) %(committerdate:unix)' refs/remotes/origin | awk -v date=$(date -d '3 months ago' +%s) '$2 < date {print $1}'); do | 
|  | 38 | +            if [[ "$branch" != "origin/main" && "$branch" != "origin/dev" ]]; then | 
|  | 39 | +              branch_name=${branch#origin/} | 
|  | 40 | +              # Ensure the branch exists locally before getting last commit date | 
|  | 41 | +              git fetch origin "$branch_name" || echo "Could not fetch branch: $branch_name" | 
|  | 42 | +              last_commit_date=$(git log -1 --format=%ci "origin/$branch_name" || echo "Unknown") | 
|  | 43 | +              committer_name=$(git log -1 --format=%cn "origin/$branch_name" || echo "Unknown") | 
|  | 44 | +              committed_in_branch=$(git branch -r --contains "origin/$branch_name" | tr -d ' ' | paste -sd "," -) | 
|  | 45 | +              echo "$branch_name,$last_commit_date,$committer_name,$committed_in_branch,Delete" >> merged_branches_report.csv | 
|  | 46 | +            fi | 
|  | 47 | +          done | 
|  | 48 | +      - name: List PR Approved and Merged Branches Older Than 30 Days | 
|  | 49 | +        run: | | 
|  | 50 | +           | 
|  | 51 | +          for branch in $(gh api repos/${{ github.repository }}/pulls --jq '.[] | select(.merged_at != null and (.base.ref == "main" or .base.ref == "dev")) | select(.merged_at | fromdateiso8601 < (now - 2592000)) | .head.ref'); do | 
|  | 52 | +            # Ensure the branch exists locally before getting last commit date | 
|  | 53 | +            git fetch origin "$branch" || echo "Could not fetch branch: $branch" | 
|  | 54 | +            last_commit_date=$(git log -1 --format=%ci origin/$branch || echo "Unknown") | 
|  | 55 | +            committer_name=$(git log -1 --format=%cn origin/$branch || echo "Unknown") | 
|  | 56 | +            committed_in_branch=$(git branch -r --contains "origin/$branch" | tr -d ' ' | paste -sd "," -) | 
|  | 57 | +            echo "$branch,$last_commit_date,$committer_name,$committed_in_branch,Delete" >> merged_branches_report.csv | 
|  | 58 | +          done | 
|  | 59 | +        env: | 
|  | 60 | +          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | 
|  | 61 | +      - name: List Open PR Branches With No Activity in Last 3 Months | 
|  | 62 | +        run: | | 
|  | 63 | +           | 
|  | 64 | +          for branch in $(gh api repos/${{ github.repository }}/pulls --state open --jq '.[] | select(.base.ref == "main" or .base.ref == "dev") | .head.ref'); do | 
|  | 65 | +            # Ensure the branch exists locally before getting last commit date | 
|  | 66 | +            git fetch origin "$branch" || echo "Could not fetch branch: $branch" | 
|  | 67 | +            last_commit_date=$(git log -1 --format=%ci origin/$branch || echo "Unknown") | 
|  | 68 | +            committer_name=$(git log -1 --format=%cn origin/$branch || echo "Unknown") | 
|  | 69 | +            if [[ $(date -d "$last_commit_date" +%s) -lt $(date -d '3 months ago' +%s) ]]; then | 
|  | 70 | +              # If no commit in the last 3 months, mark for deletion | 
|  | 71 | +              committed_in_branch=$(git branch -r --contains "origin/$branch" | tr -d ' ' | paste -sd "," -) | 
|  | 72 | +              echo "$branch,$last_commit_date,$committer_name,$committed_in_branch,Delete" >> merged_branches_report.csv | 
|  | 73 | +            fi | 
|  | 74 | +          done | 
|  | 75 | +        env: | 
|  | 76 | +          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | 
|  | 77 | +      - name: Upload CSV Report of Inactive Branches | 
|  | 78 | +        uses: actions/upload-artifact@v4 | 
|  | 79 | +        with: | 
|  | 80 | +          name: merged-branches-report | 
|  | 81 | +          path: merged_branches_report.csv | 
|  | 82 | +          retention-days: 30 | 
0 commit comments