Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 17 additions & 25 deletions .claude/SKILLS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@ This directory contains Claude Code skills that are automatically applied when w
- Includes proper attribution footers
- Follows conventional commits specification

### Restructure Commits

**Location:** `skills/restructure-commits/` (canonical, harness-neutral); `.claude/skills/restructure-commits/` and `.cursor/rules/restructure-commits.mdc` are thin adapters

**Description:** Model-neutral procedure for rewriting a branch into component-based commits (API, Dependencies, Vendor, CLI, HO, CPO, E2E, Docs, Tooling) without changing its file content.

**Use when:**

- User asks to "redo commits", "restructure commits", "squash by component", or "organize commits"
- Preparing a branch for PR review or cleaning history after review feedback

**Covers:**

- Ownership rules in `ownership.json`, generated from repository facts by `generate_ownership.py` (`make update`)
- `commit_layout.py` to plan, stage, and verify commits; `make verify-commit-layout` is the completion gate
- Safe preflight: PR base resolution, backup branch, tree snapshot, and `--force-with-lease` against the recorded SHA

### Effective Go

**Location:** `.claude/skills/effective-go/`
Expand Down Expand Up @@ -224,31 +241,6 @@ Skills are automatically invoked by Claude based on context. You don't need to d

Commands are manually invoked using `/command-name` syntax.

### Restructure Commits

**Location:** `.claude/commands/restructure-commits.md`

**Description:** Reorganizes all commits on a feature branch into logical, component-based commits that match HyperShift's architecture.

**Usage:**

```
/restructure-commits
```

**Use when:**

- User asks to "redo commits", "restructure commits", "squash by component", or "organize commits"
- Preparing a branch for PR review with clean commit history
- Branch has many small/WIP commits that should be consolidated

**Covers:**

- Component-based commit grouping (API, Vendor, CLI, HO, CPO, E2E, Docs)
- Soft reset and re-staging workflow
- Conventional commit messages with correct type/scope per component
- Edge cases for file categorization (support/, testdata/, API tests)

### Fix HyperShift Repo Robot PR

**Location:** `.claude/commands/fix-hypershift-repo-robot-pr.md`
Expand Down
124 changes: 2 additions & 122 deletions .claude/skills/restructure-commits/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,125 +3,5 @@ name: restructure-commits
description: Restructure branch commits into logical component-based commits for HyperShift PRs
---

# Restructure Commits by Component

Reorganize all commits on a feature branch into logical, component-based commits that match HyperShift's architecture.

## When to Use

- User asks to "redo commits", "restructure commits", "squash by component", or "organize commits"
- Preparing a branch for PR review with clean commit history
- Branch has many small/WIP commits that should be consolidated

## Component Categories and File Mapping

Commits are created in this order. Each commit groups files by architectural boundary.

| Order | Component | Scope | File Patterns |
|-------|-----------|-------|---------------|
| 1 | API | `api` | `api/` (types, deepcopy, CRD manifests, go.mod) — **excluding** `*_test.go` |
| 2 | Vendor | `api` | `vendor/`, `client/`, `cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/` |
| 3 | CLI | `cli` | `cmd/cluster/`, `cmd/install/`, `cmd/nodepool/`, `product-cli/` (source, tests, testdata) |
| 4 | HO | `hypershift-operator` | `hypershift-operator/`, `support/`, `karpenter-operator/`, `kubevirtexternalinfra/`, `pkg/`, `manifests/`, `shared-ingress/`, `sharedingress-config-generator/` |
| 5 | CPO | `control-plane-operator` | `control-plane-operator/`, `control-plane-pki-operator/`, `availability-prober/`, `dnsresolver/`, `etcd-backup/`, `etcd-defrag/`, `etcd-recovery/`, `ignition-server/`, `kas-bootstrap/`, `konnectivity-https-proxy/`, `konnectivity-socks5-proxy/`, `kubernetes-default-proxy/`, `sync-fg-configmap/`, `sync-global-pullsecret/`, `token-minter/` |
| 6 | E2E | `e2e` | `test/`, `api/**/*_test.go` |
| 7 | Docs | `docs` | `docs/`, `examples/` |

**Excluded from restructuring:** `bin/` (build output), `hack/`, `contrib/`, `hypershift-ci-python/`, `self-managed-azure-ci-setup/`, and `.claude*/` are build tooling, CI helpers, or dev config. If changed, include them in the most relevant commit based on their purpose. When ambiguous, prefer HO.

## Procedure

### 1. Identify merge base and changed files

```bash
BASE_BRANCH=$(gh pr view --json baseRefName -q .baseRefName 2>/dev/null || echo "main")
MERGE_BASE=$(git merge-base ${BASE_BRANCH} HEAD)
git log --oneline ${MERGE_BASE}..HEAD # review existing commits
git diff ${MERGE_BASE}..HEAD --name-only | sort # all changed files
```

### 2. Reset to merge base (keep changes)

```bash
git reset --soft ${MERGE_BASE} # keep everything staged
git reset HEAD # unstage everything
```

### 3. Stage and commit each component group

For each component (in order), stage matching files and commit:

```bash
# Example: API commit (exclude test files — they belong in E2E)
git add api/ && git reset HEAD 'api/**/*_test.go' 2>/dev/null || true
git commit # use conventional commit format

# Example: Vendor commit
git add vendor/ client/ \
"cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/"
git commit

# ... repeat for CLI, HO, CPO, E2E, Docs
```

### 4. Verify and force push

```bash
git status # must be clean
git log --oneline ${BASE_BRANCH}..HEAD # verify commit structure
git push --force-with-lease # requires user confirmation
```

## Commit Message Conventions

**Always invoke the git-commit-format skill first** for the full formatting rules (line length, footer, Co-Authored-By, etc.). This section provides the component-specific type and scope, plus guidance on writing the subject and body.

### Writing the subject

1. Look at the actual changes in the component to determine what was done
2. Pick the type and scope from the table below
3. Write a concise subject that summarizes the *purpose* of the changes, not just "update files"
4. Use imperative mood: "add", "update", "remove" — not "added", "adds", "adding"

| Component | Type(Scope) | Example Subject |
|-----------|-------------|-----------------|
| API | `feat(api):` | `feat(api): add FooBar CRD and platform config` |
| Vendor | `chore(api):` | `chore(api): regenerate CRDs, clients, deepcopy, and vendor` |
| CLI | `feat(cli):` | `feat(cli): add --foo-bar flags for cluster creation` |
| HO | `feat(hypershift-operator):` | `feat(hypershift-operator): add FooBar controller` |
| CPO | `feat(control-plane-operator):` | `feat(control-plane-operator): add FooBar controllers` |
| E2E | `test(e2e):` | `test(e2e): add FooBar e2e and validation tests` |
| Docs | `docs:` | `docs: add FooBar documentation and architecture reference` |

### Writing the body

Review the staged changes and write a body that describes *what* was added or changed. Use bullet points when there are multiple distinct changes. The body should give a reviewer enough context to understand the commit without reading every file. Each line must be under 140 characters (gitlint enforced).

### Notes

- Vendor commit is always `chore(api):` since it's regenerated output from the API commit
- E2E commit is always `test(e2e):` regardless of what's being tested
- Docs commit has no scope parentheses — just `docs:`

## Edge Cases

- **Empty component:** Skip the commit if no files match that component.
- **Support packages:** `support/` goes with HO (commit 4), not CPO.
- **Control plane sidecars:** `control-plane-pki-operator/`, `availability-prober/`, `dnsresolver/`, `etcd-*`, `ignition-server/`, `kas-bootstrap/`, `konnectivity-*`, `kubernetes-default-proxy/`, `sync-fg-configmap/`, `sync-global-pullsecret/`, `token-minter/` all go with CPO (commit 5) since they are control plane components managed by CPO.
- **Shared ingress:** `shared-ingress/` and `sharedingress-config-generator/` go with HO (commit 4), not CPO, since they are part of the hypershift-operator.
- **Karpenter operator:** `karpenter-operator/` goes with HO (commit 4) since it is managed by the hypershift-operator.
- **Shared test fixtures in CPO:** `control-plane-operator/**/testdata/` stays with CPO.
- **Generated CRD install manifests:** `cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/` goes with Vendor (commit 2), not CLI.
- **API go.mod:** `api/go.mod` goes with API (commit 1), not Vendor.
- **API test files:** `api/**/*_test.go` (UX API validation tests) go with E2E (commit 6), not API. Stage API non-test files first, then include API test files when staging E2E.
- **Documentation files:** `docs/` and `examples/` go with Docs (commit 7), not Vendor. This includes mkdocs config, how-to guides, architecture references, and aggregated docs. The `docs/content/reference/api.md` (generated API reference) also goes here.
- **Build/CI tooling:** `hack/`, `contrib/`, `hypershift-ci-python/`, `self-managed-azure-ci-setup/` are not mapped to a default component. Include in the most relevant commit based on purpose, or HO when ambiguous.

## Quick Checklist

- [ ] Determined base branch from PR (defaults to `main`)
- [ ] Reviewed all changed files before starting
- [ ] Reset with `--soft` (no data loss)
- [ ] Committed in correct order: API, Vendor, CLI, HO, CPO, E2E, Docs
- [ ] Working tree is clean after all commits
- [ ] Confirmed force push with user before executing
Read and follow the canonical procedure in `../../../skills/restructure-commits/SKILL.md` (repository path
`skills/restructure-commits/SKILL.md`) whenever restructuring, squashing, or reorganizing branch commits.
6 changes: 6 additions & 0 deletions .cursor/rules/restructure-commits.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
description: restructuring, squashing, or reorganizing branch commits into component-based commits
alwaysApply: false
---

Read and follow the canonical procedure in `../../skills/restructure-commits/SKILL.md` whenever restructuring commits.
18 changes: 18 additions & 0 deletions .github/workflows/test-commit-layout-reusable.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Unit Tests (Restructure Commits) (Reusable)

on:
workflow_call:

permissions:
contents: read

jobs:
test-commit-layout:
name: Restructure Commits
runs-on: arc-runner-set
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- run: make test-commit-layout
17 changes: 17 additions & 0 deletions .github/workflows/test-commit-layout.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Unit Tests (Restructure Commits)

on:
pull_request:
branches:
- main
paths:
- 'skills/restructure-commits/**'
- 'Makefile'
- '.github/workflows/test-commit-layout.yaml'
- '.github/workflows/test-commit-layout-reusable.yaml'

jobs:
test-commit-layout:
uses: openshift/hypershift/.github/workflows/test-commit-layout-reusable.yaml@main
Comment thread
coderabbitai[bot] marked this conversation as resolved.
permissions:
contents: read
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Project documentation is published via MkDocs. The site structure and navigation
| **E2E v2 test framework** | [test/e2e/v2/AGENTS.md](test/e2e/v2/AGENTS.md) |
| **Envtest (CEL validation tests)** | [test/envtest/README.md](test/envtest/README.md) — YAML-driven, runs across k8s 1.31–1.37, supports feature gate filtering |
| **CEL over webhooks** | [.claude/rules/webhook-validation.md](.claude/rules/webhook-validation.md) |
| **Restructuring commits** | [skills/restructure-commits/SKILL.md](skills/restructure-commits/SKILL.md) — component-based commit layout; verify with `make verify-commit-layout` |
| **Code formatting** | [DEVELOPMENT.md](DEVELOPMENT.md) — code quality commands and conventions |
| **Unit test conventions** | [TESTING.md](TESTING.md) — naming, placement, and creation requirements |
| **Design invariants** | [docs/content/reference/goals-and-design-invariants.md](docs/content/reference/goals-and-design-invariants.md) |
Expand Down
6 changes: 3 additions & 3 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,15 +292,15 @@ Use the `git-commit-format` skill for full details and examples.

### Restructuring Commits Before PR Submission

Before creating a PR or after addressing review comments, use the `restructure-commits` skill to reorganize all branch commits into logical, component-based commits. This ensures every PR has a clean, reviewable commit history grouped by architectural boundary.
Before creating a PR or after addressing review comments, follow [`skills/restructure-commits/SKILL.md`](skills/restructure-commits/SKILL.md) to reorganize all branch commits into logical, component-based commits. Any agent or human can follow it; its ownership rules are generated into `ownership.json` by `make update`, and `make verify-commit-layout BASE=<merge-base>` must pass before pushing.

## Pull Requests

See [CONTRIBUTING.md](CONTRIBUTING.md) for the full contribution guidelines. Key points for agents:

### Before Creating a PR

1. Use the `restructure-commits` skill to organize commits by component (see [Restructuring Commits](#restructuring-commits-before-pr-submission) above)
1. Follow the restructure-commits procedure to organize commits by component (see [Restructuring Commits](#restructuring-commits-before-pr-submission) above)
2. Complete the proportionate validation and report the evidence described in [Pre-PR Gate](#pre-pr-gate).

### PR Title
Expand All @@ -319,7 +319,7 @@ Follow the template in `.github/PULL_REQUEST_TEMPLATE.md`.

### After Review Comments

After addressing review feedback, use the `restructure-commits` skill again to reorganize commits before force-pushing. This keeps the commit history clean for subsequent review rounds.
After addressing review feedback, follow the restructure-commits procedure again to reorganize commits before force-pushing. This keeps the commit history clean for subsequent review rounds.

## Code Conventions

Expand Down
20 changes: 20 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ CAPI_PROVIDERS := agent aws azure gcp ibmcloud kubevirt openstack

.PHONY: update
update: api-deps workspace-sync capi-sync deps api api-docs clients docs-aggregate
$(MAKE) ownership-rules

GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/golangci-lint)
$(GOLANGCI_LINT): $(TOOLS_DIR)/go.mod # Build golangci-lint from tools folder.
Expand Down Expand Up @@ -773,6 +774,25 @@ verify-tekton-pipeline-pairs: $(PYTHON_VENV_STAMP) ## Verify paired Tekton Pipel
PYTHONPATH=$(PYTHON_VENV) python3 hack/verify-tekton-pipeline-pairs.py; \
fi

COMMIT_LAYOUT := skills/restructure-commits/commit_layout.py

.PHONY: verify-commit-layout
verify-commit-layout: ## Verify component commit layout of BASE..HEAD_REF (restructure-commits gate). Set BASE; optional HEAD_REF, EXPECT_TREE.
@test -n "$(BASE)" || { echo "BASE must be set to the merge base with the PR target branch" >&2; exit 2; }
@python3 $(COMMIT_LAYOUT) verify --base "$(BASE)" --head "$(or $(HEAD_REF),HEAD)" $(if $(EXPECT_TREE),--expect-tree "$(EXPECT_TREE)")

.PHONY: ownership-rules
ownership-rules: ## Regenerate the restructure-commits ownership.json and SKILL.md table from repository facts.
python3 skills/restructure-commits/generate_ownership.py

.PHONY: test-commit-layout
test-commit-layout: $(PYTHON_VENV_STAMP) ## Test the restructure-commits layout tool and ownership generator.
@if [ -x $(PYTHON_VENV)/bin/python3 ]; then \
$(PYTHON_VENV)/bin/python3 -m pytest -q -p no:cacheprovider skills/restructure-commits; \
else \
PYTHONPATH=$(PYTHON_VENV) python3 -m pytest -q -p no:cacheprovider skills/restructure-commits; \
fi

.PHONY: verify-codespell
verify-codespell: codespell ## Verify codespell.
@$(CODESPELL) --count --ignore-words=./.codespellignore --skip="./hack/tools/bin/codespell_dist,./docs/site/*,./vendor/*,./api/vendor/*,./hack/tools/vendor/*,./api/hypershift/v1alpha1/*,./support/thirdparty/*,./docs/content/reference/*,./hack/tools/bin/*,./cmd/install/assets/*,./go.sum,./api/go.sum,./hack/workspace/go.work.sum,./api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests,./hack/tools/go.mod,./hack/tools/go.sum,./karpenter-operator/controllers/karpenter/assets/*.yaml,./dev/*,./pkg/capi/*,./hack/capi-vendor/*"
Expand Down
1 change: 1 addition & 0 deletions docs/content/how-to/ci/github-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Pull request callers resolve their reusable workflows from `main`, while post-me
| `cpo-container-sync.yaml` | `cpo-container-sync-reusable.yaml` | Validate CPO container image references are in sync |
| `dependabot-commit-fix.yaml` | `dependabot-commit-fix-reusable.yaml` | Rewrite dependabot commit messages to pass gitlint |
| `gocacheprog-test.yaml` | `gocacheprog-test-reusable.yaml` | Tests for the `contrib/ci/gocacheprog` build cache tool (path-filtered) |
| `test-commit-layout.yaml` | `test-commit-layout-reusable.yaml` | Tests for the `skills/restructure-commits` layout tool and ownership generator (path-filtered) |
| `validate-cpo-overrides.yaml` | — | Validate CPO override images contain the PRs claimed in the PR description |

!!! note
Expand Down
1 change: 1 addition & 0 deletions docs/content/reference/aggregated-docs.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading