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>
84 lines
2.3 KiB
YAML
84 lines
2.3 KiB
YAML
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
|