Created
May 8, 2025 21:44
-
-
Save brandtkeller/ef2dbc44acf9263a0f8c71f1a395ada0 to your computer and use it in GitHub Desktop.
Automate milestone assignment to merged pr's
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
| # File: .github/workflows/auto-milestone.yml | |
| name: Auto-Assign Next-Minor Milestone | |
| on: | |
| pull_request: | |
| types: [closed] | |
| jobs: | |
| add-milestone: | |
| if: ${{ github.event.pull_request.merged == true }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v3 | |
| with: | |
| node-version: '18' | |
| - name: Install dependencies | |
| run: npm install semver | |
| - name: Determine latest release tag | |
| id: get_latest | |
| run: | | |
| # Fetch all tags | |
| git fetch --tags | |
| # List tags sorted by semver, take the latest | |
| latest_tag=$(git tag -l 'v*.*.*' --sort=-v:refname | head -n1) | |
| echo "latest=$latest_tag" >> "$GITHUB_OUTPUT" | |
| - name: Compute next minor version | |
| id: bump_version | |
| run: | | |
| node <<'EOF' | |
| const semver = require('semver'); | |
| const latest = process.env.INPUT_LATEST; | |
| if (!latest) { | |
| console.error('No valid semver tag found.'); | |
| process.exit(1); | |
| } | |
| const next = semver.inc(latest, 'minor'); | |
| console.log(`next=${next}`); | |
| EOF | |
| env: | |
| INPUT_LATEST: ${{ steps.get_latest.outputs.latest }} | |
| shell: bash | |
| continue-on-error: false | |
| run: | | |
| # This block prints "next=x.y.z" for GITHUB_OUTPUT | |
| node <<'EOF' | |
| const semver = require('semver'); | |
| const { latest } = process.env; | |
| const next = semver.inc(latest, 'minor'); | |
| console.log(`::set-output name=next::${next}`); | |
| EOF | |
| - name: Check for existing milestone | |
| id: find_milestone | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const { data: milestones } = await github.issues.listMilestones({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open' | |
| }); | |
| const title = `v${process.env.NEXT}`; | |
| const ms = milestones.find(m => m.title === title); | |
| return ms ? ms.number : null; | |
| env: | |
| NEXT: ${{ steps.bump_version.outputs.next }} | |
| - name: Create milestone if missing | |
| if: ${{ steps.find_milestone.outputs.result == 'null' }} | |
| id: create_milestone | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const title = `v${process.env.NEXT}`; | |
| const { data: milestone } = await github.issues.createMilestone({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title, | |
| state: 'open' | |
| }); | |
| return milestone.number; | |
| env: | |
| NEXT: ${{ steps.bump_version.outputs.next }} | |
| - name: Determine milestone number | |
| run: | | |
| echo "milestone_number=${{ steps.find_milestone.outputs.result || steps.create_milestone.outputs.result }}" >> $GITHUB_OUTPUT | |
| - name: Assign milestone to PR | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const milestone_number = parseInt(process.env.MILESTONE_NUMBER, 10); | |
| const pr_number = context.payload.pull_request.number; | |
| await github.issues.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr_number, | |
| milestone: milestone_number | |
| }); | |
| env: | |
| MILESTONE_NUMBER: ${{ steps.determine_milestone_number.outputs.milestone_number }} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment