| name: validate-pr |
| |
| concurrency: |
| group: ${{ github.workflow }}-${{ github.ref }} |
| cancel-in-progress: true |
| |
| permissions: |
| contents: read |
| |
| on: |
| pull_request: |
| types: [opened, edited, labeled, unlabeled, synchronize] |
| |
| jobs: |
| check-labels: |
| runs-on: ubuntu-24.04 |
| timeout-minutes: 120 # guardrails timeout for the whole job |
| steps: |
| - name: Missing `area/` label |
| if: always() && contains(join(github.event.pull_request.labels.*.name, ','), 'impact/') && !contains(join(github.event.pull_request.labels.*.name, ','), 'area/') |
| run: | |
| echo "::error::Every PR with an 'impact/*' label should also have an 'area/*' label" |
| exit 1 |
| - name: Missing `kind/` label |
| if: always() && contains(join(github.event.pull_request.labels.*.name, ','), 'impact/') && !contains(join(github.event.pull_request.labels.*.name, ','), 'kind/') |
| run: | |
| echo "::error::Every PR with an 'impact/*' label should also have a 'kind/*' label" |
| exit 1 |
| - name: OK |
| run: exit 0 |
| |
| check-changelog: |
| runs-on: ubuntu-24.04 |
| timeout-minutes: 120 # guardrails timeout for the whole job |
| env: |
| HAS_IMPACT_LABEL: ${{ contains(join(github.event.pull_request.labels.*.name, ','), 'impact/') }} |
| PR_BODY: | |
| ${{ github.event.pull_request.body }} |
| steps: |
| - name: Check changelog description |
| run: | |
| # Extract the `markdown changelog` note code block |
| block=$(echo -n "$PR_BODY" | tr -d '\r' | awk '/^```markdown changelog$/{flag=1;next}/^```$/{flag=0}flag') |
| |
| # Strip empty lines |
| desc=$(echo "$block" | awk NF) |
| |
| if [ "$HAS_IMPACT_LABEL" = "true" ]; then |
| if [ -z "$desc" ]; then |
| echo "::error::Changelog section is empty. Please provide a description for the changelog." |
| exit 1 |
| fi |
| |
| len=$(echo -n "$desc" | wc -c) |
| if [[ $len -le 6 ]]; then |
| echo "::error::Description looks too short: $desc" |
| exit 1 |
| fi |
| else |
| if [ -n "$desc" ]; then |
| echo "::error::PR has a changelog description, but no changelog label" |
| echo "::error::Please add the relevant 'impact/' label to the PR or remove the changelog description" |
| exit 1 |
| fi |
| fi |
| |
| echo "This PR will be included in the release notes with the following note:" |
| echo "$desc" |
| |
| check-pr-branch: |
| runs-on: ubuntu-24.04 |
| timeout-minutes: 120 # guardrails timeout for the whole job |
| env: |
| PR_TITLE: ${{ github.event.pull_request.title }} |
| steps: |
| # Backports or PR that target a release branch directly should mention the target branch in the title, for example: |
| # [X.Y backport] Some change that needs backporting to X.Y |
| # [X.Y] Change directly targeting the X.Y branch |
| - name: Check release branch |
| id: title_branch |
| run: | |
| # If PR targets a different branch than master, the PR title should mention the target branch in square brackets, for example: |
| # [27.1 backport] Some change that needs backporting to 27.1 |
| # [27.1] Change directly targeting the 27.1 branch |
| # [docker-29.x] Change directly targeting the docker-29.x branch |
| # [docker-29.x backport] Some change that needs backporting to docker-29.x |
| |
| # get the intended major version prefix ("[27.1 backport]" -> "27.") from the PR title. |
| target_branch=$(echo "$PR_TITLE" | sed -nE 's/^\[([^]]+)\].*/\1/p' | sed 's/ backport$//') |
| |
| echo "target_branch: $target_branch" |
| echo "GITHUB_BASE_REF: $GITHUB_BASE_REF" |
| |
| # If the PR is opened against the master branch and the target branch is not specified, exit early. |
| if [[ "$GITHUB_BASE_REF" == "master" && "$target_branch" == "" ]]; then |
| exit 0 |
| fi |
| |
| if [[ "$target_branch" != "$GITHUB_BASE_REF" ]]; then |
| echo "::error::PR is opened against the $GITHUB_BASE_REF branch, but its title suggests otherwise." |
| exit 1 |
| fi |