| name: validate-milestone |
| |
| concurrency: |
| group: ${{ github.workflow }}-${{ github.ref }} |
| cancel-in-progress: true |
| |
| permissions: |
| contents: read |
| pull-requests: read |
| |
| on: |
| pull_request: |
| types: [opened, reopened, edited, synchronize, milestoned, demilestoned] |
| |
| jobs: |
| validate-milestone: |
| if: ${{ github.event.pull_request.state == 'open' }} |
| runs-on: ubuntu-24.04 |
| timeout-minutes: 5 |
| steps: |
| - name: Validate milestone matches docker next version |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 |
| env: |
| MILESTONE: ${{ github.event.pull_request.milestone.title }} |
| with: |
| script: | |
| const files = await github.paginate(github.rest.pulls.listFiles, { |
| owner: context.repo.owner, |
| repo: context.repo.repo, |
| pull_number: context.payload.pull_request.number, |
| }); |
| core.info(`Modified files: ${files.map(f => f.filename).join(', ')}`); |
| |
| const touchesVersions = files.some(f => f.filename === 'releases/versions.yaml'); |
| core.info(`Touches version: ${touchesVersions}`); |
| |
| // Use the PR's version when it bumps the file, base branch otherwise. |
| // It's fine to trust the author in this case, it's not meant to be |
| // a security gate, just a helpful check for maintainers. |
| const ref = touchesVersions |
| ? context.payload.pull_request.head.sha |
| : context.payload.pull_request.base.ref; |
| |
| core.info(`Base ref: ${ref}`); |
| |
| const resp = await github.rest.repos.getContent({ |
| owner: context.repo.owner, |
| repo: context.repo.repo, |
| path: 'releases/versions.yaml', |
| ref, |
| }); |
| const content = Buffer.from(resp.data.content, resp.data.encoding).toString('utf8'); |
| const line = content.split('\n').find(l => l.includes('next:')); |
| if (!line) { |
| core.setFailed('Could not find docker.next in releases/versions.yaml'); |
| return; |
| } |
| const expected = line.trim().replace('next: ', '').replaceAll('"', ''); |
| const milestone = process.env.MILESTONE; |
| |
| if (!milestone) { |
| core.setFailed(`PR must have a milestone set (expected: ${expected})`); |
| return; |
| } |
| if (milestone !== expected) { |
| core.setFailed(`Milestone '${milestone}' does not match docker next version '${expected}'`); |
| return; |
| } |
| core.info(`Milestone: ${milestone} ✓`); |