chore(ci): adopt CNCF/k8s label conventions
Add .github/labels.yml as the canonical label set, synced into the repository by .github/workflows/labels.yaml using EndBug/label-sync. Conventions follow the Kubernetes scheme: https://github.com/kubernetes/test-infra/blob/master/label_sync/labels.md Six namespaced groups: kind/, priority/, triage/, lifecycle/, area/, do-not-merge/. Cozystack-specific labels preserved (epic, community, security/*, size:*). Migration via aliases keeps references on existing issues and PRs: - bug -> kind/bug - enhancement -> kind/feature - documentation -> kind/documentation - question -> kind/support - frozen -> lifecycle/frozen - stale -> lifecycle/stale - do-not-merge -> do-not-merge/work-in-progress delete-other-labels is false on the initial rollout; redundant labels ("do not merge", duplicate, invalid, wontfix) stay until a follow-up PR removes them after stabilisation. The labels workflow has a validate job (python3 schema check) that runs on PR. Sync runs only on push to main, weekly cron, and manual dispatch. Schema invariants: - 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 PR auto-labeling (.github/workflows/pr-labeler.yaml): - Parses PR title as Conventional Commits header (type, scope, !). - type -> kind/* (feat -> kind/feature, fix -> kind/bug, docs -> kind/documentation, chore/refactor -> kind/cleanup; style, perf, test, build, ci, revert -> no kind label). - scope -> area/* via embedded mapping; composite scopes split on comma. Bracket-style fallback ([scope] description) maps area/* but cannot infer kind/*. - '[Backport release-1.x]' prefix is stripped; area/release and backport labels are added. - '!' after type or 'BREAKING CHANGE:' footer in body adds kind/breaking-change. - Unmapped scope or non-conventional title adds area/uncategorized to flag for human review. - Additive only — never removes existing labels. Hardcoded label references updated: - .github/ISSUE_TEMPLATE/bug_report.md (bug -> kind/bug) - .github/workflows/tags.yaml (documentation -> kind/documentation) AGENTS.md gains an Activation entry pointing agents to labels.yml as the source of truth and to contributing.md for the title auto-labeling table. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
This commit is contained in:
parent
52edffbb9a
commit
c8ed1c652c
7 changed files with 707 additions and 4 deletions
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
labels: 'bug'
|
||||
labels: 'kind/bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
|
|
|||
371
.github/labels.yml
vendored
Normal file
371
.github/labels.yml
vendored
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
# Cozystack repository labels
|
||||
#
|
||||
# Label conventions follow the Kubernetes scheme:
|
||||
# https://github.com/kubernetes/test-infra/blob/master/label_sync/labels.md
|
||||
#
|
||||
# Synced into the repository by .github/workflows/labels.yaml
|
||||
# (EndBug/label-sync@v2). Edit this file via pull request — UI changes
|
||||
# will be overwritten on the next sync.
|
||||
#
|
||||
# Constraints (enforced by the validate job in labels.yaml):
|
||||
# - description ≤ 100 characters (GitHub REST API limit)
|
||||
# - color is a 6-character hex string (no leading #)
|
||||
# - label names are unique
|
||||
# - aliases do not collide with top-level names
|
||||
#
|
||||
# Categories:
|
||||
# kind/ issue or PR type
|
||||
# priority/ urgency
|
||||
# triage/ review state
|
||||
# lifecycle/ issue or PR lifecycle
|
||||
# area/ subsystem; extensible — add when 3+ open issues exist
|
||||
# do-not-merge/ PR merge blockers
|
||||
# security/ security-finding severity and status (Cozystack-specific)
|
||||
# size: PR size (auto-applied)
|
||||
#
|
||||
# `aliases:` lets EndBug/label-sync rename existing labels without losing
|
||||
# references on already-tagged issues and PRs.
|
||||
#
|
||||
# GitHub-default labels not migrated here (`wontfix`, `invalid`) currently
|
||||
# carry zero issues/PRs in this repo and will be removed in a follow-up
|
||||
# cleanup PR rather than aliased to a different namespace.
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# kind/ — issue or PR type
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
- name: kind/bug
|
||||
color: 'd73a4a'
|
||||
description: Categorizes issue or PR as related to a bug
|
||||
aliases: ['bug']
|
||||
|
||||
- name: kind/feature
|
||||
color: 'a2eeef'
|
||||
description: Categorizes issue or PR as related to a new feature
|
||||
aliases: ['enhancement']
|
||||
|
||||
- name: kind/documentation
|
||||
color: '0075ca'
|
||||
description: Categorizes issue or PR as related to documentation
|
||||
aliases: ['documentation']
|
||||
|
||||
- name: kind/support
|
||||
color: 'd876e3'
|
||||
description: Categorizes issue as a support question
|
||||
aliases: ['question']
|
||||
|
||||
- name: kind/cleanup
|
||||
color: 'c7def8'
|
||||
description: Categorizes issue or PR as related to cleanup of code, process, or technical debt
|
||||
|
||||
- name: kind/regression
|
||||
color: 'e11d21'
|
||||
description: Categorizes issue or PR as related to a regression from a prior release
|
||||
|
||||
- name: kind/flake
|
||||
color: 'f7c6c7'
|
||||
description: Categorizes issue or PR as related to a flaky test
|
||||
|
||||
- name: kind/failing-test
|
||||
color: 'e11d21'
|
||||
description: Categorizes issue or PR as related to a consistently or frequently failing test
|
||||
|
||||
- name: kind/api-change
|
||||
color: 'c7def8'
|
||||
description: Categorizes issue or PR as related to adding, removing, or otherwise changing an API
|
||||
|
||||
- name: kind/breaking-change
|
||||
color: 'e11d21'
|
||||
description: Indicates the change introduces a breaking API or behaviour change
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# priority/ — urgency
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
- name: priority/critical-urgent
|
||||
color: 'e11d21'
|
||||
description: Highest priority. Must be actively worked on as someone's top priority right now
|
||||
|
||||
- name: priority/important-soon
|
||||
color: 'eb6420'
|
||||
description: Must be staffed and worked on either currently, or very soon, ideally in time for the next release
|
||||
|
||||
- name: priority/important-longterm
|
||||
color: 'fbca04'
|
||||
description: Important over the long term, but may not be staffed and/or may need multiple releases to complete
|
||||
|
||||
- name: priority/backlog
|
||||
color: 'fef2c0'
|
||||
description: General backlog priority. Lower than priority/important-longterm
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# triage/ — review state
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
- name: triage/needs-triage
|
||||
color: 'ededed'
|
||||
description: Indicates an issue needs triage by a maintainer
|
||||
|
||||
- name: triage/accepted
|
||||
color: '0e8a16'
|
||||
description: Indicates an issue is ready to be actively worked on
|
||||
|
||||
- name: triage/needs-information
|
||||
color: 'fbca04'
|
||||
description: Indicates an issue needs more information in order to work on it
|
||||
|
||||
- name: triage/not-reproducible
|
||||
color: 'fbca04'
|
||||
description: Indicates an issue can not be reproduced as described
|
||||
|
||||
- name: triage/duplicate
|
||||
color: 'cfd3d7'
|
||||
description: Indicates an issue is a duplicate of another issue
|
||||
aliases: ['duplicate']
|
||||
|
||||
- name: triage/unresolved
|
||||
color: 'cfd3d7'
|
||||
description: Indicates an issue that can not or will not be resolved
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# lifecycle/ — issue or PR lifecycle
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
- name: lifecycle/active
|
||||
color: '1d76db'
|
||||
description: Indicates that an issue or PR is actively being worked on by a contributor
|
||||
|
||||
- name: lifecycle/frozen
|
||||
color: 'db5dd6'
|
||||
description: Indicates that an issue or PR should not be auto-closed due to staleness
|
||||
aliases: ['frozen']
|
||||
|
||||
- name: lifecycle/stale
|
||||
color: 'dadada'
|
||||
description: Denotes an issue or PR has remained open with no activity and has become stale
|
||||
aliases: ['stale']
|
||||
|
||||
- name: lifecycle/rotten
|
||||
color: '795548'
|
||||
description: Denotes an issue or PR that has aged beyond stale and will be auto-closed
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# area/ — subsystem (extensible)
|
||||
# Add a new area/* when there are 3+ open issues on the topic.
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
- name: area/api
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to the cozystack-api aggregated API server
|
||||
|
||||
- name: area/ai
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to AI agent guides, AGENTS.md, docs/agents/
|
||||
|
||||
- name: area/build
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to image build infrastructure, multi-arch support
|
||||
|
||||
- name: area/ci
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to CI workflows, GitHub Actions, automation
|
||||
|
||||
- name: area/dashboard
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to the dashboard / UI
|
||||
|
||||
- name: area/extra
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to tenant-specific modules (packages/extra/)
|
||||
|
||||
- name: area/database
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse)
|
||||
|
||||
- name: area/kubernetes
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to the tenant Kubernetes app
|
||||
|
||||
- name: area/monitoring
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to the monitoring stack (vlogs, vmstack, grafana, workloadmonitor)
|
||||
|
||||
- name: area/networking
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to networking (ingress, gateway, vpn, metallb, cilium, kube-ovn)
|
||||
|
||||
- name: area/platform
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to platform infrastructure (bundle, flux, talos, installer)
|
||||
|
||||
- name: area/release
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to release tooling (changelog, backport, release pipeline)
|
||||
|
||||
- name: area/storage
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor)
|
||||
|
||||
- name: area/testing
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to testing (e2e, bats, unit tests)
|
||||
|
||||
- name: area/virtualization
|
||||
color: 'bfd4f2'
|
||||
description: Issues or PRs related to virtualization (kubevirt, cdi, vmi, vm-import)
|
||||
|
||||
- name: area/uncategorized
|
||||
color: 'fbca04'
|
||||
description: PR auto-labeler could not map title scope to a known area/*; please review
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# do-not-merge/ — PR merge blockers (Prow convention)
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
- name: do-not-merge/work-in-progress
|
||||
color: 'e11d21'
|
||||
description: Indicates that a PR should not merge because it is a work in progress
|
||||
# Both legacy spellings collapse here. EndBug processes aliases sequentially;
|
||||
# the second rename hits a name collision and logs a warning — the legacy
|
||||
# label survives and gets cleaned up in the follow-up dedup PR.
|
||||
aliases: ['do-not-merge', 'do not merge']
|
||||
|
||||
- name: do-not-merge/hold
|
||||
color: 'e11d21'
|
||||
description: Indicates that a PR should not merge because someone has issued /hold
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# Cozystack-specific (preserved)
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
- name: epic
|
||||
color: 'A335EE'
|
||||
description: A large development increment that brings definite value to Cozystack users
|
||||
|
||||
- name: community
|
||||
color: '97458A'
|
||||
description: Community contributions are welcome in this issue
|
||||
|
||||
- name: help wanted
|
||||
color: '008672'
|
||||
description: Extra attention is needed
|
||||
|
||||
- name: good first issue
|
||||
color: '7057ff'
|
||||
description: Good for newcomers
|
||||
|
||||
- name: quality-of-life
|
||||
color: 'aaaaaa'
|
||||
description: QoL improvements
|
||||
|
||||
- name: upstream-issue
|
||||
color: 'aaaaaa'
|
||||
description: Requires resolving an issue in an upstream project
|
||||
|
||||
- name: backport
|
||||
color: 'FBCA04'
|
||||
description: Should change be backported on previous release
|
||||
|
||||
- name: backport-previous
|
||||
color: 'fbd876'
|
||||
description: Backport target — previous release line
|
||||
|
||||
- name: release
|
||||
color: 'aaaaaa'
|
||||
description: Releasing a new Cozystack version
|
||||
|
||||
- name: automated
|
||||
color: 'ededed'
|
||||
description: Created by automation
|
||||
|
||||
- name: debug
|
||||
color: '704479'
|
||||
description: Debugging in progress
|
||||
|
||||
- name: sponsored
|
||||
color: '00FF00'
|
||||
description: Sponsored work
|
||||
|
||||
- name: lgtm
|
||||
color: '238636'
|
||||
description: This PR has been approved by a maintainer
|
||||
|
||||
- name: ok-to-test
|
||||
color: '00FF00'
|
||||
description: Indicates a non-member PR is safe to run CI on
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# size: — PR size (auto-applied by sizing bot)
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
- name: 'size:XS'
|
||||
color: '00ff00'
|
||||
description: This PR changes 0-9 lines, ignoring generated files
|
||||
|
||||
- name: 'size:S'
|
||||
color: '77b800'
|
||||
description: This PR changes 10-29 lines, ignoring generated files
|
||||
|
||||
- name: 'size:M'
|
||||
color: 'ebb800'
|
||||
description: This PR changes 30-99 lines, ignoring generated files
|
||||
|
||||
- name: 'size:L'
|
||||
color: 'eb9500'
|
||||
description: This PR changes 100-499 lines, ignoring generated files
|
||||
|
||||
- name: 'size:XL'
|
||||
color: 'ff823f'
|
||||
description: This PR changes 500-999 lines, ignoring generated files
|
||||
|
||||
- name: 'size:XXL'
|
||||
color: 'ffb8b8'
|
||||
description: This PR changes 1000+ lines, ignoring generated files
|
||||
|
||||
# ──────────────────────────────────────────────
|
||||
# security/ — security-finding severity and status
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
- name: security
|
||||
color: 'aaaaaa'
|
||||
description: Security-related issues and features
|
||||
|
||||
- name: security/critical
|
||||
color: 'd73a4a'
|
||||
description: Critical security vulnerability
|
||||
|
||||
- name: security/high
|
||||
color: 'e99695'
|
||||
description: High severity security finding
|
||||
|
||||
- name: security/medium
|
||||
color: 'f9c513'
|
||||
description: Medium severity security finding
|
||||
|
||||
- name: security/low
|
||||
color: '0e8a16'
|
||||
description: Low severity security finding
|
||||
|
||||
- name: security/triage-needed
|
||||
color: 'fbca04'
|
||||
description: Needs security triage
|
||||
|
||||
- name: security/confirmed
|
||||
color: '1d76db'
|
||||
description: Confirmed vulnerability
|
||||
|
||||
- name: security/false-positive
|
||||
color: 'c5def5'
|
||||
description: Triaged as false positive
|
||||
|
||||
- name: security/accepted-risk
|
||||
color: 'bfd4f2'
|
||||
description: Risk accepted with justification
|
||||
|
||||
- name: security/in-progress
|
||||
color: '0075ca'
|
||||
description: Fix in progress
|
||||
|
||||
- name: security/fixed
|
||||
color: '0e8a16'
|
||||
description: Fix released
|
||||
84
.github/workflows/labels.yaml
vendored
Normal file
84
.github/workflows/labels.yaml
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
name: Labels
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/labels.yml
|
||||
- .github/workflows/labels.yaml
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- .github/labels.yml
|
||||
- .github/workflows/labels.yaml
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '17 4 * * 1' # Mondays at 04:17 UTC
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: labels-sync
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Validate labels.yml schema
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import re, sys, yaml
|
||||
|
||||
path = '.github/labels.yml'
|
||||
data = yaml.safe_load(open(path))
|
||||
errors = []
|
||||
|
||||
# 1. description ≤ 100 chars (GitHub REST API limit)
|
||||
for label in data:
|
||||
desc = label.get('description', '') or ''
|
||||
if len(desc) > 100:
|
||||
errors.append(f"{label['name']}: description {len(desc)} chars (max 100)")
|
||||
|
||||
# 2. color is 6-char hex without leading #
|
||||
for label in data:
|
||||
color = label.get('color', '') or ''
|
||||
if not re.match(r'^[0-9A-Fa-f]{6}$', color):
|
||||
errors.append(f"{label['name']}: bad color {color!r} (must be 6-char hex without #)")
|
||||
|
||||
# 3. unique top-level names
|
||||
names = [label['name'] for label in data]
|
||||
dups = sorted({n for n in names if names.count(n) > 1})
|
||||
for n in dups:
|
||||
errors.append(f"duplicate name: {n}")
|
||||
|
||||
# 4. aliases do not collide with any top-level name
|
||||
name_set = set(names)
|
||||
for label in data:
|
||||
for alias in (label.get('aliases') or []):
|
||||
if alias in name_set:
|
||||
errors.append(f"alias {alias!r} (under {label['name']!r}) collides with a top-level name")
|
||||
|
||||
if errors:
|
||||
for err in errors:
|
||||
print(f"::error::{err}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"labels.yml schema OK ({len(data)} labels)")
|
||||
PY
|
||||
|
||||
sync:
|
||||
needs: validate
|
||||
if: github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: EndBug/label-sync@v2
|
||||
with:
|
||||
config-file: .github/labels.yml
|
||||
delete-other-labels: false
|
||||
199
.github/workflows/pr-labeler.yaml
vendored
Normal file
199
.github/workflows/pr-labeler.yaml
vendored
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
name: PR Auto-Label
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, edited, reopened, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
label:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Apply labels from PR title
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
// Conventional Commits types accepted by Cozystack (per docs/agents/contributing.md):
|
||||
// feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
// Mapping below maps a subset to kind/* — types not listed do not produce a kind/*.
|
||||
const typeToKind = {
|
||||
feat: 'kind/feature',
|
||||
fix: 'kind/bug',
|
||||
docs: 'kind/documentation',
|
||||
chore: 'kind/cleanup',
|
||||
refactor: 'kind/cleanup',
|
||||
// style, perf, test, build, ci, revert — no kind mapping
|
||||
};
|
||||
|
||||
// scope -> area/* mapping. Keys are the scopes observed in cozystack issues
|
||||
// and PRs. Add new entries when a scope recurs (3+ times).
|
||||
const scopeToArea = {
|
||||
// area/api
|
||||
'api': 'area/api',
|
||||
'cozystack-api': 'area/api',
|
||||
|
||||
// area/ai
|
||||
'agents': 'area/ai',
|
||||
'ai': 'area/ai',
|
||||
|
||||
// area/build
|
||||
'build': 'area/build',
|
||||
|
||||
// area/ci
|
||||
'ci': 'area/ci',
|
||||
|
||||
// area/dashboard
|
||||
'dashboard': 'area/dashboard',
|
||||
|
||||
// area/database
|
||||
'postgres': 'area/database',
|
||||
'postgres-operator': 'area/database',
|
||||
'mariadb': 'area/database',
|
||||
'mariadb-operator': 'area/database',
|
||||
'redis': 'area/database',
|
||||
'etcd': 'area/database',
|
||||
'kafka': 'area/database',
|
||||
'clickhouse': 'area/database',
|
||||
|
||||
// area/extra
|
||||
'extra': 'area/extra',
|
||||
|
||||
// area/kubernetes
|
||||
'kubernetes': 'area/kubernetes',
|
||||
'apps/kubernetes': 'area/kubernetes',
|
||||
|
||||
// area/monitoring
|
||||
'monitoring': 'area/monitoring',
|
||||
'vlogs': 'area/monitoring',
|
||||
'vmstack': 'area/monitoring',
|
||||
'grafana': 'area/monitoring',
|
||||
'workloadmonitor': 'area/monitoring',
|
||||
|
||||
// area/networking
|
||||
'ingress': 'area/networking',
|
||||
'ingress-nginx': 'area/networking',
|
||||
'gateway': 'area/networking',
|
||||
'vpn': 'area/networking',
|
||||
'metallb': 'area/networking',
|
||||
'cilium': 'area/networking',
|
||||
'kube-ovn': 'area/networking',
|
||||
'tcp-balancer': 'area/networking',
|
||||
'securitygroups': 'area/networking',
|
||||
'cozy-proxy': 'area/networking',
|
||||
|
||||
// area/platform
|
||||
'platform': 'area/platform',
|
||||
'bundle': 'area/platform',
|
||||
'flux': 'area/platform',
|
||||
'fluxcd': 'area/platform',
|
||||
'cluster-api': 'area/platform',
|
||||
'talos': 'area/platform',
|
||||
'installer': 'area/platform',
|
||||
'cozyctl': 'area/platform',
|
||||
'cozystack-engine': 'area/platform',
|
||||
'cozy-lib': 'area/platform',
|
||||
|
||||
// area/release
|
||||
'backport': 'area/release',
|
||||
'release': 'area/release',
|
||||
|
||||
// area/storage
|
||||
'seaweedfs': 'area/storage',
|
||||
'seaweedfs-cosi-driver': 'area/storage',
|
||||
'bucket': 'area/storage',
|
||||
'linstor': 'area/storage',
|
||||
'velero': 'area/storage',
|
||||
'harbor': 'area/storage',
|
||||
'backups': 'area/storage',
|
||||
|
||||
// area/testing
|
||||
'tests': 'area/testing',
|
||||
'e2e': 'area/testing',
|
||||
|
||||
// area/virtualization
|
||||
'kubevirt': 'area/virtualization',
|
||||
'cdi': 'area/virtualization',
|
||||
'vmi': 'area/virtualization',
|
||||
'vm-import': 'area/virtualization',
|
||||
'virtual-machine': 'area/virtualization',
|
||||
'hami': 'area/virtualization',
|
||||
'gpu-operator': 'area/virtualization',
|
||||
};
|
||||
|
||||
const pr = context.payload.pull_request;
|
||||
const title = pr.title || '';
|
||||
const body = pr.body || '';
|
||||
const existing = new Set(pr.labels.map(l => l.name));
|
||||
const toAdd = new Set();
|
||||
|
||||
// 1. Strip "[Backport release-1.x]" prefix if present.
|
||||
const backportMatch = title.match(/^\[Backport ([^\]]+)\]\s+(.+)$/);
|
||||
const cleanTitle = backportMatch ? backportMatch[2] : title;
|
||||
if (backportMatch) {
|
||||
toAdd.add('area/release');
|
||||
toAdd.add('backport');
|
||||
}
|
||||
|
||||
// 2. Try Conventional Commits form: type(scope)?(!)?: description
|
||||
const conv = cleanTitle.match(/^([a-z]+)(?:\(([^)]+)\))?(!)?:\s*.+$/);
|
||||
// 3. Fall back to bracket form: [scope] description
|
||||
const bracket = !conv && cleanTitle.match(/^\[([^\]]+)\]\s+.+$/);
|
||||
|
||||
let type = null, scopeStr = null, breaking = false;
|
||||
if (conv) {
|
||||
type = conv[1];
|
||||
scopeStr = conv[2] || null;
|
||||
breaking = !!conv[3];
|
||||
} else if (bracket) {
|
||||
scopeStr = bracket[1];
|
||||
}
|
||||
|
||||
// 4. Detect BREAKING CHANGE: footer in body.
|
||||
if (/^BREAKING CHANGE:/m.test(body)) {
|
||||
breaking = true;
|
||||
}
|
||||
|
||||
// 5. Apply kind/* from type.
|
||||
if (type && typeToKind[type]) {
|
||||
toAdd.add(typeToKind[type]);
|
||||
}
|
||||
|
||||
// 6. Apply area/* from scope. Composite scopes split on comma.
|
||||
const scopes = (scopeStr || '')
|
||||
.split(/,\s*/)
|
||||
.map(s => s.trim())
|
||||
.filter(Boolean);
|
||||
for (const s of scopes) {
|
||||
if (scopeToArea[s]) {
|
||||
toAdd.add(scopeToArea[s]);
|
||||
}
|
||||
}
|
||||
|
||||
// 7. kind/breaking-change.
|
||||
if (breaking) {
|
||||
toAdd.add('kind/breaking-change');
|
||||
}
|
||||
|
||||
// 8. Fallback: no area/* applied -> area/uncategorized.
|
||||
const hasArea = [...toAdd].some(l => l.startsWith('area/'));
|
||||
if (!hasArea) {
|
||||
toAdd.add('area/uncategorized');
|
||||
}
|
||||
|
||||
// 9. Additive only — never remove existing labels.
|
||||
const newLabels = [...toAdd].filter(l => !existing.has(l));
|
||||
if (newLabels.length === 0) {
|
||||
core.info('No new labels to apply');
|
||||
return;
|
||||
}
|
||||
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
labels: newLabels,
|
||||
});
|
||||
core.info(`Applied labels: ${newLabels.join(', ')}`);
|
||||
6
.github/workflows/tags.yaml
vendored
6
.github/workflows/tags.yaml
vendored
|
|
@ -223,7 +223,7 @@ jobs:
|
|||
repo: context.repo.repo,
|
||||
head,
|
||||
base,
|
||||
title: `Release v${version}`,
|
||||
title: `chore(release): cut v${version}`,
|
||||
body: `This PR prepares the release \`v${version}\`.`,
|
||||
draft: false
|
||||
});
|
||||
|
|
@ -411,7 +411,7 @@ jobs:
|
|||
repo: context.repo.repo,
|
||||
head: changelogBranch,
|
||||
base: baseBranch,
|
||||
title: `docs: add changelog for v${version}`,
|
||||
title: `docs(release): add changelog for v${version}`,
|
||||
body: `This PR adds the changelog for release \`v${version}\`.\n\n✅ Changelog has been automatically generated in \`docs/changelogs/v${version}.md\`.`,
|
||||
draft: false
|
||||
});
|
||||
|
|
@ -421,7 +421,7 @@ jobs:
|
|||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.data.number,
|
||||
labels: ['documentation', 'automated']
|
||||
labels: ['kind/documentation', 'automated']
|
||||
});
|
||||
|
||||
console.log(`Created PR #${pr.data.number} for changelog`);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@ working with the **Cozystack** project.
|
|||
- Read: [`contributing.md`](./docs/agents/contributing.md)
|
||||
- Action: Read the file to understand git workflow, commit format, PR process
|
||||
|
||||
- **Issue and PR labeling, triage** (e.g., "label this issue", "what label should I use", "triage this", "categorize")
|
||||
- Read: [`.github/labels.yml`](./.github/labels.yml)
|
||||
- Action: Use labels defined there. Conventions follow the Kubernetes scheme — `kind/*` (type), `area/*` (subsystem), `priority/*` (urgency), `triage/*` (review state), `lifecycle/*` (auto-close), `do-not-merge/*` (PR blockers), `security/*` (severity)
|
||||
- For `area/*`: accuracy outweighs reuse. If no existing `area/*` truly fits the change, propose a new one via PR (extend `labels.yml` and the scope mapping in `pr-labeler.yaml`) — do not shoehorn the change into a wrong area. `area/uncategorized` is the auto-labeler fallback; treat it as a signal to pick a fit, create a new area, or correct the PR title
|
||||
- PR titles: a Conventional Commits header (`type(scope): description`, types from [`contributing.md`](./docs/agents/contributing.md)) auto-applies `kind/*` and `area/*` via `.github/workflows/pr-labeler.yaml`. Append `!` (or add a `BREAKING CHANGE:` footer) to apply `kind/breaking-change`
|
||||
|
||||
**Important rules:**
|
||||
- ✅ **ONLY read the file if the task matches the documented process scope** - do not read files for tasks that don't match their purpose
|
||||
- ✅ **ALWAYS read the file FIRST** before starting the task (when applicable)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,49 @@ 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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue