diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml new file mode 100644 index 00000000..08ff5b89 --- /dev/null +++ b/.github/workflows/pr-title.yml @@ -0,0 +1,41 @@ +# Release Please builds the changelog from the PR title of squash-merged pull +# requests. A title that is not a Conventional Commit (for example one that +# starts with an emoji) is silently ignored and the change never reaches the +# release notes, so reject it before merging. + +name: PR Title + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +permissions: + contents: read + +jobs: + conventional-title: + name: Conventional Commit title + runs-on: ubuntu-latest + # Only the release PR that the Release Please bot opens from this repository + # is exempt (it is titled "Next Release "). A branch name alone + # must not be enough, otherwise any fork branch could skip the check. + if: >- + ${{ !( + github.event.pull_request.head.repo.full_name == github.repository + && github.event.pull_request.user.login == 'github-actions[bot]' + && startsWith(github.head_ref, 'release-please--') + ) }} + + steps: + # The title is passed via env (never interpolated into the script) and + # only used as regex match data, so it cannot inject shell commands. + - name: Check PR title + env: + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + pattern='^(feat|fix|refactor|perf|docs|style|chore|test|build|ci|revert)(\([^()]+\))?!?: [^[:space:]].*$' + if [[ ! "$PR_TITLE" =~ $pattern ]]; then + echo "::error title=Invalid PR title::The title must follow Conventional Commits, e.g. 'feat(hyva): add readiness check'. Do not start it with an emoji." + echo "Allowed types: feat, fix, refactor, perf, docs, style, chore, test, build, ci, revert" + exit 1 + fi diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index dbfdf78c..d9466eec 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -37,7 +37,11 @@ lint: paths: - .ddev/web-build/** enabled: - - pinact@5.0.2 + # pinact 5 is not supported by the trunk plugins (v1.11.0 still passes + # single-dash flags), so every workflow change fails with a + # "pinact/config-error". Stay on 4.x until + # https://github.com/trunk-io/plugins/issues/1177 is fixed. + - pinact@4.1.1 - svgo@4.1.0 - taplo@0.10.0 - checkov@3.4.2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5ecb69ed..25a3efea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,7 +53,9 @@ feat!: remove legacy theme builder API fix!: change command argument order ``` -**Individual Commits**: Your individual commits within the PR can use any format you prefer. We use **squash-merge**, so only the PR title becomes the commit message in the `main` branch. +**Individual Commits**: Your individual commits within the PR can use any format you prefer (including emojis). We use **squash-merge**, so only the PR title becomes the commit message in the `main` branch. + +**PR titles must not start with an emoji.** Release Please cannot parse such titles and silently drops the change from the changelog. The `PR Title` check fails for titles that are not valid Conventional Commits. ### For Maintainers (Direct Commits) @@ -81,6 +83,7 @@ All pull requests are merged using **squash-merge** to maintain a clean, linear - ✅ PR title becomes the commit message - ✅ All PR commits are squashed into a single commit - ✅ Easier to follow project history and revert changes if needed +- ⚠️ Do not use "Create a merge commit" or "Rebase and merge": Release Please then only sees the individual commits and ignores everything that is not a Conventional Commit ---