mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-05 03:27:07 +09:00
## What this PR does Adopt CNCF/Kubernetes label conventions for issues and PRs and add automated labeling. **Canonical label file**: `.github/labels.yml`. Synced into the repository by `.github/workflows/labels.yaml` (EndBug/label-sync@v2) on push to `main`, weekly cron, and manual dispatch. UI-only label edits are overwritten — propose changes via PR to this file. ### Label namespaces Following the [Kubernetes label scheme](https://github.com/kubernetes/test-infra/blob/master/label_sync/labels.md): - `kind/*` — issue or PR type (bug, feature, documentation, support, cleanup, regression, flake, failing-test, api-change, breaking-change) - `priority/*` — urgency (critical-urgent, important-soon, important-longterm, backlog) - `triage/*` — review state (needs-triage, accepted, needs-information, not-reproducible, duplicate, unresolved) - `lifecycle/*` — issue/PR lifecycle (active, frozen, stale, rotten) - `area/*` — subsystem; 15 seeded plus `area/uncategorized` fallback. Extensible — propose a new area when no existing one fits. - `do-not-merge/*` — PR merge blockers (work-in-progress, hold) Cozystack-specific labels preserved: `epic`, `community`, `help wanted`, `good first issue`, `quality-of-life`, `upstream-issue`, `backport`, `backport-previous`, `release`, `automated`, `debug`, `sponsored`, `lgtm`, `ok-to-test`, `security/*`, `size:*`. ### `area/*` set 15 areas seeded by activity in open issues and PRs: `area/ai`, `area/api`, `area/build`, `area/ci`, `area/dashboard`, `area/database`, `area/extra`, `area/kubernetes`, `area/monitoring`, `area/networking`, `area/platform`, `area/release`, `area/storage`, `area/testing`, `area/virtualization`. Plus `area/uncategorized` as the auto-labeler fallback. ### Migration safety Existing labels are renamed via `aliases:` in `labels.yml`. GitHub preserves the label ID, so all currently tagged issues and PRs keep their tags under the new name without losing references: | Old | New | |---|---| | `bug` | `kind/bug` | | `enhancement` | `kind/feature` | | `documentation` | `kind/documentation` | | `question` | `kind/support` | | `frozen` | `lifecycle/frozen` | | `stale` | `lifecycle/stale` | | `duplicate` | `triage/duplicate` | | `do-not-merge` | `do-not-merge/work-in-progress` | | `do not merge` | `do-not-merge/work-in-progress` | `delete-other-labels: false` on the initial rollout. Generic GitHub-default labels (`wontfix`, `invalid`) are preserved untouched and will be removed in a follow-up cleanup PR. EndBug processes aliases sequentially, so the second of the two `do-not-merge*` aliases hits a name collision and logs a warning — the legacy label survives that one sync and is cleaned up in the same follow-up. ### PR auto-labeling `.github/workflows/pr-labeler.yaml` parses each PR title on `opened`, `edited`, `reopened`, and `synchronize` and applies labels additively (never removes): - **type → `kind/*`**: feat, fix, docs, chore, refactor (others get no kind) - **scope → `area/*`**: scope mapping covers all current cozystack components (full table in `docs/agents/contributing.md`) - **`!` after type or `BREAKING CHANGE:` footer**: applies `kind/breaking-change` - **`[Backport release-1.x]` prefix**: stripped before parsing; `area/release` and `backport` labels added - **Composite scope** (`feat(platform, system, apps): …`): each part mapped independently - **Bracket fallback** (`[scope] description`): maps `area/*` but cannot infer `kind/*` - **Unmapped scope or non-conventional title**: applies `area/uncategorized` for human review ### Schema validation `.github/workflows/labels.yaml` runs a `validate` job on every PR touching `labels.yml` or its workflow. Asserts: - description ≤ 100 chars (GitHub REST API limit) - color is 6-char hex without leading `#` - unique top-level names - aliases do not collide with top-level names Sync runs only on push to main, weekly cron, and manual dispatch; PR runs validate-only. ### Hardcoded label/title references updated - `.github/ISSUE_TEMPLATE/bug_report.md`: `labels: 'bug'` → `labels: 'kind/bug'` - `.github/workflows/tags.yaml`: - changelog PR labels `['documentation', 'automated']` → `['kind/documentation', 'automated']` - release PR title `Release v${version}` → `chore(release): cut v${version}` (so the auto-labeler applies `kind/cleanup` + `area/release`) - changelog PR title `docs: add changelog for v${version}` → `docs(release): add changelog for v${version}` (so the auto-labeler applies `kind/documentation` + `area/release`) ### Documentation - `AGENTS.md`: Activation entry pointing agents to `labels.yml` and the PR title auto-labeling rules. States explicitly that `area/*` accuracy outweighs reuse — propose a new area when none fits, do not shoehorn into a wrong one. - `docs/agents/contributing.md`: PR Title Auto-Labeling section with type→kind and scope→area tables. ### Out of scope (follow-up PRs) - Removal of redundant labels (`wontfix`, `invalid`, plus the surviving legacy `do not merge` if alias-rename collision keeps it) - Org-wide sync from `cozystack/.github/labels.yml` - Dosu bot configuration update for `lifecycle/stale` (requires dashboard access) ### Release note ```release-note NONE ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Automated PR labeling from Conventional Commits (type → kind/*, scope → area/*), plus a comprehensive namespaced label taxonomy. * **Chores** * Workflows to validate, sync, and auto-apply labels (including scheduled/manual runs and validation checks). * Added repository-wide label configuration and normalized bug label metadata to namespaced form. * Updated release PR titling/labeling conventions. * **Documentation** * Contributor and agent guidance on PR title conventions, label mappings, and triage procedures. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
189 lines
7.4 KiB
Markdown
189 lines
7.4 KiB
Markdown
# Contributing Conventions for AI Agents
|
|
|
|
Project-side conventions for commits, branches, and pull requests in Cozystack.
|
|
|
|
## Checklist for Creating a Pull Request
|
|
|
|
- [ ] Commit message follows Conventional Commits format
|
|
- [ ] Commit is signed off with `--signoff`
|
|
- [ ] Branch is rebased on `upstream/main` (no extra commits)
|
|
- [ ] PR body includes description and release note
|
|
- [ ] Ran `make generate` in every package whose `values.yaml`, `values.schema.json`, `Chart.yaml`, or `README.md` was touched, and committed the regenerated files
|
|
|
|
## Regenerate Artifacts Before Committing
|
|
|
|
Several files in each package are produced by `make generate` from `values.yaml` + `values.schema.json` and must stay in sync with the hand-edited sources:
|
|
|
|
- `packages/(apps|extra)/<name>/README.md` — regenerated by `cozyvalues-gen` (parameter table, formatting).
|
|
- `packages/(apps|extra)/<name>/values.schema.json` — `cozyvalues-gen` rewrites ordering and derived fields.
|
|
- `packages/system/<name>-rd/cozyrds/<name>.yaml` — produced by `hack/update-crd.sh`, which `make generate` invokes.
|
|
|
|
**Before committing edits to any of those sources**, run `make generate` inside the package and stage the full diff:
|
|
|
|
```bash
|
|
make -C packages/<apps-or-extra>/<name> generate
|
|
git add packages/<apps-or-extra>/<name>/ packages/system/<name>-rd/
|
|
```
|
|
|
|
The repo's pre-commit CI job runs `make generate` in every package and then `git diff --exit-code`. Any unstaged generator output fails the job with exit code 123 and blocks the PR. Also rerun `make generate` after a `git commit --amend` if the amended change touched any of the sources above.
|
|
|
|
To locate packages a WIP branch likely needs to be regenerated:
|
|
|
|
```bash
|
|
git diff --name-only | xargs -n1 dirname | sort -u | grep ^packages/
|
|
```
|
|
|
|
## Commit Format
|
|
|
|
Follow [Conventional Commits](https://www.conventionalcommits.org/) with `--signoff`:
|
|
|
|
```bash
|
|
git commit --signoff -m "type(scope): brief description"
|
|
```
|
|
|
|
**Types:** `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`
|
|
|
|
**Scopes** (examples — not an exhaustive list; pick the most specific scope that describes the change, and introduce a new one if a genuinely new area needs its own):
|
|
|
|
- System, e.g.: `dashboard`, `platform`, `operator`, `cilium`, `kube-ovn`, `linstor`, `fluxcd`, `cluster-api`
|
|
- Apps, e.g.: `postgres`, `mariadb`, `redis`, `kafka`, `clickhouse`, `virtual-machine`, `kubernetes`
|
|
- Other, e.g.: `api`, `hack`, `tests`, `ci`, `docs`, `agents`, `maintenance`
|
|
|
|
Breaking changes: append `!` after type/scope (`feat(api)!: ...`) or add a `BREAKING CHANGE:` footer.
|
|
|
|
**Examples:**
|
|
```bash
|
|
git commit --signoff -m "feat(dashboard): add config hash annotations to restart pods on config changes"
|
|
git commit --signoff -m "fix(postgres): update operator to version 1.2.3"
|
|
git commit --signoff -m "docs(contributing): add installation guide"
|
|
```
|
|
|
|
## PR Title Auto-Labeling
|
|
|
|
`.github/workflows/pr-labeler.yaml` parses the PR title on `opened`, `edited`, `reopened`, and `synchronize` events and applies labels additively (never removes). The title is expected to follow Conventional Commits — same format as commit messages above.
|
|
|
|
**Type → `kind/*`:**
|
|
|
|
| type | label |
|
|
| --------- | ------------------ |
|
|
| feat | kind/feature |
|
|
| fix | kind/bug |
|
|
| docs | kind/documentation |
|
|
| chore | kind/cleanup |
|
|
| refactor | kind/cleanup |
|
|
| style, perf, test, build, ci, revert | (no kind label) |
|
|
|
|
**Scope → `area/*`** (full mapping in `.github/workflows/pr-labeler.yaml`):
|
|
|
|
| scope (examples) | label |
|
|
| --- | --- |
|
|
| agents, ai | area/ai |
|
|
| api, cozystack-api | area/api |
|
|
| build | area/build |
|
|
| ci | area/ci |
|
|
| dashboard | area/dashboard |
|
|
| postgres, mariadb, redis, etcd, kafka, clickhouse, postgres-operator, mariadb-operator | area/database |
|
|
| extra | area/extra |
|
|
| kubernetes | area/kubernetes |
|
|
| monitoring, vlogs, vmstack, grafana, workloadmonitor | area/monitoring |
|
|
| ingress, gateway, vpn, metallb, cilium, kube-ovn, cozy-proxy, ... | area/networking |
|
|
| platform, bundle, flux, fluxcd, cluster-api, talos, installer, cozyctl, cozystack-engine, cozy-lib | area/platform |
|
|
| backport, release | area/release |
|
|
| seaweedfs, bucket, linstor, velero, harbor, backups | area/storage |
|
|
| tests, e2e | area/testing |
|
|
| kubevirt, cdi, vmi, vm-import, virtual-machine, hami, gpu-operator | area/virtualization |
|
|
|
|
**Special handling:**
|
|
|
|
- `[Backport release-1.x]` prefix is stripped before parsing; `area/release` and `backport` labels are added.
|
|
- Composite scope (`feat(platform, system, apps): ...`) — each comma-separated part is mapped independently.
|
|
- `!` after type or `BREAKING CHANGE:` footer in the body → `kind/breaking-change`.
|
|
- Unmapped scope or non-conventional title → `area/uncategorized` (signals the PR needs manual area selection).
|
|
- Bracket-style fallback (`[scope] description`) maps `scope` → `area/*` but cannot infer `kind/*`.
|
|
|
|
### AI Agent Attribution
|
|
|
|
When an AI agent authors or materially assists with a commit, add an `Assisted-By:` trailer naming the model:
|
|
|
|
```text
|
|
Assisted-By: Claude <noreply@anthropic.com>
|
|
Assisted-By: GPT-5 <noreply@openai.com>
|
|
Assisted-By: Gemini <noreply@google.com>
|
|
```
|
|
|
|
This sits alongside the `Signed-off-by:` trailer produced by `--signoff`. Use one trailer per model if multiple contributed.
|
|
|
|
## Rebasing on upstream/main
|
|
|
|
If the branch has extra commits, clean it up:
|
|
|
|
```bash
|
|
git fetch upstream
|
|
git checkout -b my-feature upstream/main
|
|
git cherry-pick <your-commit-hash>
|
|
git push -f origin my-feature
|
|
```
|
|
|
|
## Pull Request Body
|
|
|
|
Fill in the template at [`.github/PULL_REQUEST_TEMPLATE.md`](../../.github/PULL_REQUEST_TEMPLATE.md). It includes the required `release-note` block.
|
|
|
|
Create the PR with `gh pr create --title "type(scope): brief description" --body-file <file>`.
|
|
|
|
## Fetching Unresolved Review Comments
|
|
|
|
Cozystack uses GitHub review threads with resolution status. Only unresolved threads are actionable — resolved threads are already handled.
|
|
|
|
The REST endpoint `/pulls/{pr}/reviews` returns review summaries, not individual review comments. Use the GraphQL API to access `reviewThreads` with `isResolved` status:
|
|
|
|
```bash
|
|
gh api graphql -F owner=cozystack -F repo=cozystack -F pr=<PR_NUMBER> -f query='
|
|
query($owner: String!, $repo: String!, $pr: Int!) {
|
|
repository(owner: $owner, name: $repo) {
|
|
pullRequest(number: $pr) {
|
|
reviewThreads(first: 100) {
|
|
nodes {
|
|
isResolved
|
|
comments(first: 100) {
|
|
nodes {
|
|
id
|
|
path
|
|
line
|
|
author { login }
|
|
bodyText
|
|
url
|
|
createdAt
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .comments.nodes[]'
|
|
```
|
|
|
|
Compact one-line variant:
|
|
|
|
```bash
|
|
gh api graphql -F owner=cozystack -F repo=cozystack -F pr=<PR_NUMBER> -f query='
|
|
query($owner: String!, $repo: String!, $pr: Int!) {
|
|
repository(owner: $owner, name: $repo) {
|
|
pullRequest(number: $pr) {
|
|
reviewThreads(first: 100) {
|
|
nodes {
|
|
isResolved
|
|
comments(first: 100) {
|
|
nodes {
|
|
path
|
|
line
|
|
author { login }
|
|
bodyText
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .comments.nodes[] | "\(.path):\(.line // "N/A") - \(.author.login): \(.bodyText[:150])"'
|
|
```
|