diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 000000000..dd8cf0684 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,26 @@ +changelog: + exclude: + authors: + - dependabot + - dependabot[bot] + categories: + - title: Breaking Changes + labels: + - '[Type] Breaking Change' + - title: Features & Enhancements + labels: + - '[Type] Enhancement' + - title: Bug Fixes + labels: + - '[Type] Bug' + - '[Type] Regression' + - title: Other Changes + labels: + - '*' + exclude: + labels: + - '[Type] Automated Testing' + - '[Type] Build Tooling' + - '[Type] Task' + - '[Type] Developer Documentation' + - dependencies # Added by Dependabot diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml new file mode 100644 index 000000000..701185a6d --- /dev/null +++ b/.github/workflows/label-pr.yml @@ -0,0 +1,61 @@ +name: Label PR + +on: + pull_request_target: + types: [opened, edited] + +jobs: + label: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Apply label based on Conventional Commits prefix + uses: actions/github-script@v7 + with: + script: | + const title = context.payload.pull_request.title; + const prefixMatch = title.match(/^(\w+)(?:\([^)]*\))?(!)?:/); + if (!prefixMatch) return; + + const prefix = prefixMatch[1].toLowerCase(); + const isBreaking = prefixMatch[2] === '!'; + const labelMap = { + feat: '[Type] Enhancement', + fix: '[Type] Bug', + perf: '[Type] Performance', + test: '[Type] Automated Testing', + docs: '[Type] Developer Documentation', + build: '[Type] Build Tooling', + ci: '[Type] Build Tooling', + refactor: '[Type] Task', + task: '[Type] Task', + chore: '[Type] Task', + style: '[Type] Task', + }; + + const typeLabel = isBreaking ? '[Type] Breaking Change' : labelMap[prefix]; + if (!typeLabel) return; + + const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + }); + + const allTypeLabels = [...Object.values(labelMap), '[Type] Breaking Change']; + const hasConflictingLabel = currentLabels.some( + (l) => allTypeLabels.includes(l.name) && l.name !== typeLabel + ); + + if (hasConflictingLabel) return; + + const alreadyLabeled = currentLabels.some((l) => l.name === typeLabel); + if (alreadyLabeled) return; + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + labels: [typeLabel], + }); diff --git a/AGENTS.md b/AGENTS.md index f123d2605..9b35287a1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -78,11 +78,7 @@ These commands ensure code quality and prevent lint errors from blocking commits ### Commit and Pull Request Guidelines -When creating pull requests: - -1. **Use the PR template**: Read `.github/PULL_REQUEST_TEMPLATE.md` to get the current template structure and follow it when writing the PR body. -2. **Assign a label**: Use `gh label list` to retrieve available labels and select the most relevant one for the PR. -3. **Use Conventional Commits**: Follow the Conventional Commits specification for commit messages (e.g. `feat: add new block type`, `fix: resolve toolbar bug`). +Follow the conventions documented in [Developer Workflows](./docs/code/developer-workflows.md), including Conventional Commits prefixes, PR template usage, and label assignment. ### E2E Test Interaction Guidelines diff --git a/bin/release.sh b/bin/release.sh index 81a761081..c00b60b50 100755 --- a/bin/release.sh +++ b/bin/release.sh @@ -258,8 +258,8 @@ commit_changes() { fi git add . - git commit -m "$version" - print_success "Changes committed with message: $version" + git commit -m "chore(release): $version" + print_success "Changes committed with message: chore(release): $version" } # Function to create git tag diff --git a/docs/code/README.md b/docs/code/README.md index 4338a9e20..e97cb088e 100644 --- a/docs/code/README.md +++ b/docs/code/README.md @@ -6,6 +6,7 @@ This guide is for developers who want to contribute code to GutenbergKit. - [Getting Started](./getting-started.md) - Prerequisites, setup, and running the demo apps - [Development Tools](./development-tools.md) - Development mode, React DevTools, and logging +- [Developer Workflows](./developer-workflows.md) - Commit conventions, pull requests, and labeling - [Testing](./testing.md) - Running tests and ensuring code quality - [Troubleshooting](./troubleshooting.md) - Common issues and solutions diff --git a/docs/code/developer-workflows.md b/docs/code/developer-workflows.md new file mode 100644 index 000000000..cc4ac786d --- /dev/null +++ b/docs/code/developer-workflows.md @@ -0,0 +1,49 @@ +# Developer Workflows + +This guide covers commit conventions, pull request guidelines, and labeling workflows in GutenbergKit. + +## Commit Messages + +This project follows the [Conventional Commits](https://www.conventionalcommits.org/) specification for commit messages and pull request titles. + +Format: `: ` + +Common types: + +| Type | When to use | +| ---------- | ------------------------------------------ | +| `feat` | New feature or capability | +| `fix` | Bug fix | +| `perf` | Performance improvement | +| `test` | Adding or updating tests | +| `docs` | Documentation changes | +| `build` | Build system or dependency changes | +| `ci` | CI/CD configuration changes | +| `refactor` | Code restructuring without behavior change | +| `chore` | Routine maintenance tasks | + +Examples: `feat: add offline indicator`, `fix: resolve iOS retain cycle in async flow` + +## Pull Requests + +When creating a pull request: + +1. **Use the PR template**: The template in `.github/PULL_REQUEST_TEMPLATE.md` provides the required structure. +2. **Assign a label**: Use `gh label list` to see available labels and select the most relevant one. +3. **Follow Conventional Commits**: The PR title should use the same format as commit messages above. + +### Automatic Labeling + +PRs are automatically labeled based on the Conventional Commits prefix in the title: + +| Prefix | Label applied | +| ------------------------------------ | -------------------------------- | +| `feat` | `[Type] Enhancement` | +| `fix` | `[Type] Bug` | +| `perf` | `[Type] Performance` | +| `test` | `[Type] Automated Testing` | +| `docs` | `[Type] Developer Documentation` | +| `build`, `ci` | `[Type] Build Tooling` | +| `refactor`, `task`, `chore`, `style` | `[Type] Task` | + +If you manually apply a type label before the automation runs, your choice is respected — the workflow skips re-labeling when a conflicting type label is already present. diff --git a/docs/releases.md b/docs/releases.md index dd82f1068..2ee72017d 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -39,5 +39,17 @@ The script: After the release is created, it is ready for integration into the WordPress app. +## Release Notes + +GitHub automatically generates release notes when a release is created. Notes are organized into the following categories based on PR labels: + +- **Features & Enhancements** — `[Type] Enhancement` +- **Bug Fixes** — `[Type] Bug`, `[Type] Regression` +- **Other Changes** — everything else + +Dependabot dependency bump PRs are excluded automatically. + +PRs are labeled automatically based on their Conventional Commits title prefix. See the [Developer Workflows](./code/developer-workflows.md) guide for details on the labeling rules. + [^1]: We increment the version before building and without tagging so that (1) the correct version number is included in the build's [error reporting metadata](https://github.com/wordpress-mobile/GutenbergKit/blob/8195901ec8883125dcfa102abf2b6a2a3962af3e/src/utils/exception-parser.js#L99) and (2) the Git tag includes the latest build output. [^2]: CI tasks create new Android builds for each commit. However, such infrastructure is not yet in place for iOS. Therefore, we must manually create and commit the iOS build.