diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b7594a1ba7..91d001e078 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,10 +1,11 @@ Please check the following: 1. Make sure you are targeting the `main` branch, pull requests on release branches are only allowed for backports. -2. Make sure you have read contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md . -3. For documentations contribution, please go to https://gitea.com/gitea/docs -4. Describe what your pull request does and which issue you're targeting (if any). -5. It is recommended to enable "Allow edits by maintainers", so maintainers can help more easily. -6. Your input here will be included in the commit message when this PR has been merged. If you don't want some content to be included, please separate them with a line like `---`. -7. Delete all these tips before posting. +2. Use a Conventional Commits PR title, for example `fix(repo): handle empty branch names`. +3. Make sure you have read contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md . +4. For documentations contribution, please go to https://gitea.com/gitea/docs +5. Describe what your pull request does and which issue you're targeting (if any). +6. It is recommended to enable "Allow edits by maintainers", so maintainers can help more easily. +7. Your input here will be included in the commit message when this PR has been merged. If you don't want some content to be included, please separate them with a line like `---`. +8. Delete all these tips before posting. diff --git a/.github/workflows/pull-pr-title.yml b/.github/workflows/pull-pr-title.yml new file mode 100644 index 0000000000..59b0e78c40 --- /dev/null +++ b/.github/workflows/pull-pr-title.yml @@ -0,0 +1,28 @@ +name: pr-title + +on: + pull_request: + types: + - opened + - edited + - reopened + - synchronize + - ready_for_review + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + lint-pr-title: + if: github.event.pull_request.draft == false + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - run: make lint-pr-title + env: + PR_TITLE: ${{ github.event.pull_request.title }} diff --git a/AGENTS.md b/AGENTS.md index fd87f432b7..276023f234 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,6 +7,7 @@ - Run single playwright e2e test files with `GITEA_TEST_E2E_FLAGS='' make test-e2e` - Add the current year into the copyright header of new `.go` files - Ensure no trailing whitespace in edited files +- Use Conventional Commits format for commit messages and PR titles (e.g. `type(scope): subject`) - Never force-push, amend, or squash unless asked. Use new commits and normal push for pull request updates - Preserve existing code comments, do not remove or rewrite comments that are still relevant - In TypeScript, use `!` (non-null assertion) instead of `?.`/`??` when a value is known to always exist diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f1871f1470..c62950d84b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -189,6 +189,22 @@ In the PR title, describe the problem you are fixing, not how you are fixing it. Use the first comment as a summary of your PR. \ In the PR summary, you can describe exactly how you are fixing this problem. +PR titles must follow the [Conventional Commits](https://www.conventionalcommits.org/) format, because PRs are squash-merged and the PR title becomes the resulting commit message: + +```text +type(scope)!: subject +``` + +The allowed types are `build`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, and `test`. The generic `chore` type is intentionally not accepted; pick a more descriptive type instead. + +Examples: + +```text +fix(web): prevent avatar upload crash on empty file +feat(api): add pagination to repo hooks list +ci(workflows): lint PR titles with commitlint +``` + Keep this summary up-to-date as the PR evolves. \ If your PR changes the UI, you must add **after** screenshots in the PR summary. \ If you are not implementing a new feature, you should also post **before** screenshots for comparison. diff --git a/Makefile b/Makefile index 2466435b17..b6aa9371e5 100644 --- a/Makefile +++ b/Makefile @@ -321,6 +321,10 @@ lint-md: node_modules ## lint markdown files lint-md-fix: node_modules ## lint markdown files and fix issues pnpm exec markdownlint --fix *.md +.PHONY: lint-pr-title +lint-pr-title: ## lint PR title against Conventional Commits (set PR_TITLE=...) + @node ./tools/lint-pr-title.js + .PHONY: lint-spell lint-spell: ## lint spelling @git ls-files $(SPELLCHECK_FILES) | xargs go run $(MISSPELL_PACKAGE) -dict assets/misspellings.csv -error diff --git a/tools/lint-pr-title.js b/tools/lint-pr-title.js new file mode 100644 index 0000000000..2df340f186 --- /dev/null +++ b/tools/lint-pr-title.js @@ -0,0 +1,19 @@ +#!/usr/bin/env node +import {env, exit} from 'node:process'; + +const allowedTypes = 'build, ci, docs, feat, fix, perf, refactor, revert, style, test'; +const title = env.PR_TITLE; + +if (!title) { + console.error('Missing PR_TITLE'); + exit(1); +} + +const validTitlePattern = new RegExp(`^(${allowedTypes.replaceAll(', ', '|')})(\\([\\w.-]+\\))?(!)?: .+$`); + +if (!validTitlePattern.test(title)) { + console.error(`Invalid PR title: ${title}`); + console.error('Expected format: type(scope): subject'); + console.error(`Allowed types: ${allowedTypes}`); + exit(1); +}