From e6a4b3c3a9a3a31feb94595f0d15ea20f2df58d5 Mon Sep 17 00:00:00 2001 From: Swarup Ghosh Date: Wed, 6 May 2026 16:40:04 +0530 Subject: [PATCH 1/2] Adapter for ambient-code Co-authored-by: Claude Opus 4.6 Signed-off-by: Swarup Ghosh --- .gitignore | 1 - .../.ambient/ambient.json | 6 + .../commands/oape.api-generate-tests.md | 312 ++++++++++ .../.claude/commands/oape.api-generate.md | 415 +++++++++++++ .../.claude/commands/oape.api-implement.md | 547 ++++++++++++++++++ .../.claude/commands/oape.e2e-generate.md | 331 +++++++++++ .../.claude/commands/oape.init.md | 196 +++++++ .../.claude/commands/oape.pr.md | 220 +++++++ .../.claude/commands/oape.review.md | 202 +++++++ .../.claude/commands/oape.speedrun.md | 188 ++++++ .../.claude/skills/controller/SKILL.md | 169 ++++++ .../.claude/skills/effective-go/SKILL.md | 125 ++++ .../.claude/skills/summary/SKILL.md | 144 +++++ .../workflows/operator-feature-dev/CLAUDE.md | 71 +++ .../workflows/operator-feature-dev/README.md | 127 ++++ 15 files changed, 3053 insertions(+), 1 deletion(-) create mode 100644 ambient-workflows/workflows/operator-feature-dev/.ambient/ambient.json create mode 100644 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate-tests.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-implement.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.e2e-generate.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.init.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.pr.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.review.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.speedrun.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/.claude/skills/controller/SKILL.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/.claude/skills/effective-go/SKILL.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/.claude/skills/summary/SKILL.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/CLAUDE.md create mode 100644 ambient-workflows/workflows/operator-feature-dev/README.md diff --git a/.gitignore b/.gitignore index 01f499d..bee8a64 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ __pycache__ -.claude diff --git a/ambient-workflows/workflows/operator-feature-dev/.ambient/ambient.json b/ambient-workflows/workflows/operator-feature-dev/.ambient/ambient.json new file mode 100644 index 0000000..98abbe8 --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.ambient/ambient.json @@ -0,0 +1,6 @@ +{ + "name": "Operator Feature Dev", + "description": "Multi-PR OpenShift operator feature development pipeline. Takes an Enhancement Proposal URL and generates a complete implementation across 3 PRs: API type definitions with integration tests, controller/reconciler implementation, and E2E tests.", + "systemPrompt": "You are Atlas, an expert colleague for OpenShift operator feature development from Enhancement Proposals.\n\nAt the start of the session, run the controller skill — it defines the workflow phases, how to execute them, and how to recommend next steps.", + "startupPrompt": "Greet the user as Atlas, their operator feature development assistant. Explain that you guide them through implementing an OpenShift operator feature from an Enhancement Proposal, producing 3 PRs: (1) API type definitions with integration tests, (2) controller/reconciler implementation, (3) E2E tests. Ask them to provide an Enhancement Proposal PR URL and the target operator repository URL to get started." +} diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate-tests.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate-tests.md new file mode 100644 index 0000000..bbcfed3 --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate-tests.md @@ -0,0 +1,312 @@ +# /oape.api-generate-tests - Generate integration tests for API types + +## Purpose + +Generate `.testsuite.yaml` integration test files for OpenShift API type +definitions. Reads Go type definitions, CRD manifests, and validation markers +to produce comprehensive test suites covering create, update, validation, and +error scenarios. + +This command should be run AFTER API types and CRD manifests have been generated. + +## Arguments + +- `$ARGUMENTS`: `` + +## Process + +### Phase 0: Prechecks + +All prechecks must pass before proceeding. If ANY fails, STOP immediately. + +#### Precheck 1 -- Verify Repository and Tools + +```bash +if ! git rev-parse --is-inside-work-tree &> /dev/null 2>&1; then + echo "PRECHECK FAILED: Not inside a git repository." + exit 1 +fi + +REPO_ROOT=$(git rev-parse --show-toplevel) + +if [ ! -f "$REPO_ROOT/go.mod" ]; then + echo "PRECHECK FAILED: No go.mod found at repository root." + exit 1 +fi + +GO_MODULE=$(head -1 "$REPO_ROOT/go.mod" | awk '{print $2}') +echo "Repository root: $REPO_ROOT" +echo "Go module: $GO_MODULE" +``` + +#### Precheck 2 -- Identify Target API Types + +```bash +TARGET_PATH="$ARGUMENTS" + +if [ -z "$TARGET_PATH" ]; then + echo "PRECHECK FAILED: No target path provided." + echo "Usage: /oape.api-generate-tests " + exit 1 +fi +``` + +```thinking +Determine which API types to generate tests for: +1. User provided a specific types file path -> use it directly +2. User provided an API directory -> find all types files in it + +Extract: API group, version, kind, resource plural, all fields with types, +validation markers, and godoc. +``` + +#### Precheck 3 -- Verify CRD Manifests Exist + +```bash +# For openshift/api repos +find "$REPO_ROOT" -type d -name 'zz_generated.crd-manifests' -not -path '*/vendor/*' | head -5 + +# For operator repos +find "$REPO_ROOT" -type d -name 'bases' -path '*/crd/*' -not -path '*/vendor/*' | head -5 +``` + +If no CRD manifests found: + +```text +WARNING: No CRD manifests found. Run 'make update' or 'make manifests' first. +Test suites reference CRD manifests -- tests will fail without them. +``` + +--- + +### Phase 1: Read API Types and CRD Manifests + +Read the target Go types file(s) and extract all information needed for test +generation: + +```thinking +From the Go types, extract every field, type, marker, and validation rule: +1. Top-level CRD types (structs with +kubebuilder:object:root=true or +genclient) +2. For each CRD type: kind, API group, version, resource plural, scope, singleton +3. Every spec and status field: name, type, optional/required, pointer semantics +4. All validation markers: enums, min/max, minLength/maxLength, minItems/maxItems, + pattern, format, XValidation CEL rules +5. Enum types and allowed values +6. Discriminated unions: discriminator field, member types +7. Immutable fields (XValidation rules referencing oldSelf) +8. Default values +9. Feature gate annotations (+openshift:enable:FeatureGate) +10. Nested object validation +11. Map key/value constraints +12. Any other kubebuilder or OpenShift marker + +The list above is guidance, not exhaustive. Extract ALL markers found. +``` + +Also read CRD manifest(s) to get: full CRD name, OpenAPI v3 schema, feature +set annotations. + +### Phase 2: Identify Test Directory and Existing Tests + +Determine where test files should be placed: + +**openshift/api:** + +```text +//tests/./ +``` + +**Operator repos:** + +```text +api//tests/./ +``` + +or + +```text +api///tests/./ +``` + +Check for existing test files to avoid duplicating tests. + +### Phase 3: Generate Test Suites + +Generate `.testsuite.yaml` files covering these categories. Derive specific test +cases from the types and validation rules read in Phase 1. + +#### Category 1 -- Minimal Valid Create + +Every test suite MUST include at least one test that creates a minimal valid +instance with only required fields populated. + +#### Category 2 -- Valid Field Values + +For each field in the spec: + +- Test that valid values are accepted and persisted correctly +- For enum fields: test each allowed enum value +- For optional fields: test with and without the field +- For fields with defaults: verify the default is applied + +#### Category 3 -- Invalid Field Values (Validation Failures) + +For each field with validation rules: + +- Enum fields: test a value not in the allowed set -> `expectedError` +- Pattern fields: test a value that doesn't match -> `expectedError` +- Min/max constraints: test values at and beyond boundaries -> `expectedError` +- Required fields: test omission -> `expectedError` +- CEL validation rules: test inputs that violate each rule -> `expectedError` + +#### Category 4 -- Update Scenarios + +For fields that can be updated: + +- Test valid updates (change field value) -> `expected` +- For immutable fields: test that updates are rejected -> `expectedError` +- For fields with update-specific validation: test boundary cases + +#### Category 5 -- Singleton Name Validation + +If the CRD is a cluster-scoped singleton (name must be "cluster"): + +- Test creation with `resourceName: cluster` -> success +- Test creation with `resourceName: not-cluster` -> `expectedError` + +#### Category 6 -- Discriminated Unions + +If the type uses discriminated unions: + +- Test each valid discriminator + member combination -> `expected` +- Test mismatched discriminator + member -> `expectedError` +- Test missing required member -> `expectedError` + +#### Category 7 -- Feature-Gated Fields + +If fields are gated behind a FeatureGate: + +- Stable/default test suite: setting gated field is rejected -> `expectedError` +- TechPreview test suite: gated field is accepted -> `expected` + +#### Category 8 -- Status Subresource + +If the type has a status subresource: + +- Test valid status updates +- Test invalid status updates -> `expectedStatusError` + +#### Category 9 -- Additional Coverage + +```thinking +Re-examine every marker, annotation, CEL rule, godoc comment, and structural +detail. Ask: is there any validation behavior or edge case NOT already covered? + +Examples: cross-field dependencies, mutually exclusive fields, nested object +validation, list item uniqueness, map key/value constraints, string format +validations, complex CEL rules, defaulting interactions, zero values vs nil. +``` + +### Phase 4: Write Test Suite Files + +Write `.testsuite.yaml` file(s) following this format: + +```yaml +apiVersion: apiextensions.k8s.io/v1 +name: "" +crdName: . +tests: + onCreate: + - name: Should be able to create a minimal + initial: | + apiVersion: / + kind: + spec: {} + expected: | + apiVersion: / + kind: + spec: {} + - name: Should reject with invalid + initial: | + apiVersion: / + kind: + spec: + : + expectedError: "" + onUpdate: + - name: Should not allow changing immutable field + initial: | + apiVersion: / + kind: + spec: + : + updated: | + apiVersion: / + kind: + spec: + : + expectedError: "" +``` + +#### File Naming Conventions + +Derive from existing patterns: + +**openshift/api repos:** + +- `stable..testsuite.yaml` +- `techpreview..testsuite.yaml` +- `stable...testsuite.yaml` + +**Operator repos:** + +- `.testsuite.yaml` + +### Phase 5: Output Summary + +Write `artifacts/operator-feature-dev/api/test-generation-summary.md`: + +```text +=== API Test Generation Summary === + +Target API: / +CRD Name: . + +Generated Test Files: + - -- onCreate tests, onUpdate tests + +Test Coverage: + onCreate: + - Minimal valid create + - : valid values ( tests) + - : invalid values ( tests) + - Singleton name validation + onUpdate: + - Immutable field : rejected + - Valid update for + +Next Steps: + 1. Review the generated test suites + 2. Run the integration tests + 3. Verify coverage: make verify + 4. Add additional edge-case tests as needed +``` + +## Behavioral Rules + +1. **Derive from source**: All test values and expectations MUST come from + actual Go types, validation markers, and CRD manifests. +2. **Match existing style**: If the repo has test suites, match their naming, + formatting, and detail level exactly. +3. **Comprehensive but focused**: Test every field and validation rule found, + but don't invent scenarios not supported by the schema. +4. **Error messages**: For `expectedError` fields, use substrings from the + actual CRD validation rules. +5. **Minimal YAML**: Include only fields relevant to each specific test case. +6. **Surgical additions**: When adding to an existing suite, preserve all + existing tests and append new ones. + +## Output + +- Generated `.testsuite.yaml` files in the appropriate test directory +- Summary saved to `artifacts/operator-feature-dev/api/test-generation-summary.md` diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate.md new file mode 100644 index 0000000..92d133a --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate.md @@ -0,0 +1,415 @@ +# /oape.api-generate - Generate API type definitions from an Enhancement Proposal + +## Purpose + +Read an OpenShift Enhancement Proposal PR and/or a design document, extract the +required API changes, and generate compliant Go type definitions in the correct +paths of the current operator repository. Refreshes API conventions from +authoritative sources on every run. + +## Arguments + +- `$ARGUMENTS`: ` [--design-doc ]` + +At least one input source (EP or design document) must be provided. When both +are provided, the design document takes precedence for implementation details. + +## Process + +### Phase 0: Prechecks + +All prechecks must pass before proceeding. If ANY fails, STOP immediately. + +#### Precheck 1 -- Parse and Validate Input Arguments + +```bash +ARGS="$ARGUMENTS" +ENHANCEMENT_PR="" +DESIGN_DOC_URL="" +ENHANCEMENT_PR_NUMBER="" + +# Extract --design-doc argument if present +if echo "$ARGS" | grep -q '\-\-design-doc'; then + DESIGN_DOC_URL=$(echo "$ARGS" | sed -n 's/.*--design-doc[[:space:]]\+\([^[:space:]]\+\).*/\1/p') + ENHANCEMENT_PR=$(echo "$ARGS" | sed 's/--design-doc[[:space:]]\+[^[:space:]]\+//' | xargs) +else + ENHANCEMENT_PR="$ARGS" +fi + +if [ -z "$ENHANCEMENT_PR" ] && [ -z "$DESIGN_DOC_URL" ]; then + echo "PRECHECK FAILED: No input provided." + echo "Usage: /oape.api-generate [--design-doc ]" + exit 1 +fi + +if [ -n "$ENHANCEMENT_PR" ]; then + if ! echo "$ENHANCEMENT_PR" | grep -qE '^https://github\.com/openshift/enhancements/pull/[0-9]+/?$'; then + echo "PRECHECK FAILED: Invalid enhancement PR URL." + echo "Expected: https://github.com/openshift/enhancements/pull/" + echo "Got: $ENHANCEMENT_PR" + exit 1 + fi + ENHANCEMENT_PR_NUMBER=$(echo "$ENHANCEMENT_PR" | grep -oE '[0-9]+$') + echo "Enhancement PR #$ENHANCEMENT_PR_NUMBER validated." +fi + +if [ -n "$DESIGN_DOC_URL" ]; then + if ! echo "$DESIGN_DOC_URL" | grep -qE '^https://gist\.github(usercontent)?\.com/'; then + echo "PRECHECK FAILED: Invalid design document URL." + echo "Expected: https://gist.github.com/[username/]" + echo "Got: $DESIGN_DOC_URL" + exit 1 + fi + echo "Design document URL validated: $DESIGN_DOC_URL" +fi +``` + +#### Precheck 2 -- Verify Required Tools + +```bash +MISSING_TOOLS="" + +if ! command -v gh &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS gh"; fi +if ! command -v go &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS go"; fi +if ! command -v git &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS git"; fi + +if [ -n "$MISSING_TOOLS" ]; then + echo "PRECHECK FAILED: Missing required tools:$MISSING_TOOLS" + exit 1 +fi + +if ! gh auth status &> /dev/null 2>&1; then + echo "PRECHECK FAILED: GitHub CLI is not authenticated." + echo "Run 'gh auth login' to authenticate." + exit 1 +fi + +echo "All required tools are available and authenticated." +``` + +#### Precheck 3 -- Verify Current Repository + +```bash +if ! git rev-parse --is-inside-work-tree &> /dev/null 2>&1; then + echo "PRECHECK FAILED: Not inside a git repository." + exit 1 +fi + +REPO_ROOT=$(git rev-parse --show-toplevel) + +if [ ! -f "$REPO_ROOT/go.mod" ]; then + echo "PRECHECK FAILED: No go.mod found at repository root." + exit 1 +fi + +GO_MODULE=$(head -1 "$REPO_ROOT/go.mod" | awk '{print $2}') +echo "Go module: $GO_MODULE" + +if grep -q "github.com/openshift/api" "$REPO_ROOT/go.mod"; then + echo "Confirmed: Repository depends on github.com/openshift/api" +elif echo "$GO_MODULE" | grep -q "github.com/openshift/api"; then + echo "Confirmed: This IS the openshift/api repository." +else + echo "PRECHECK FAILED: Not an OpenShift operator repository." + echo "go.mod does not reference github.com/openshift/api." + exit 1 +fi +``` + +#### Precheck 4 -- Verify Enhancement PR is Accessible (if provided) + +```bash +if [ -n "$ENHANCEMENT_PR_NUMBER" ]; then + PR_STATE=$(gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json state --jq '.state' 2>/dev/null) + + if [ -z "$PR_STATE" ]; then + echo "PRECHECK FAILED: Unable to access enhancement PR #$ENHANCEMENT_PR_NUMBER." + exit 1 + fi + + PR_TITLE=$(gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json title --jq '.title') + echo "Enhancement PR #$ENHANCEMENT_PR_NUMBER: $PR_TITLE ($PR_STATE)" +fi +``` + +#### Precheck 5 -- Verify Design Document is Accessible (if provided) + +```bash +if [ -n "$DESIGN_DOC_URL" ]; then + GIST_ID=$(echo "$DESIGN_DOC_URL" | grep -oE '[a-f0-9]{32}' | head -1) + + if [ -z "$GIST_ID" ]; then + GIST_ID=$(echo "$DESIGN_DOC_URL" | sed 's|.*/||' | sed 's|[?#].*||') + fi + + if [ -z "$GIST_ID" ]; then + echo "PRECHECK FAILED: Could not extract gist ID from URL." + exit 1 + fi + + GIST_INFO=$(gh api "gists/$GIST_ID" --jq '.description // "Untitled"' 2>/dev/null) + + if [ -z "$GIST_INFO" ]; then + echo "PRECHECK FAILED: Unable to access design document gist." + exit 1 + fi + + echo "Design document gist verified: $GIST_INFO" +fi +``` + +#### Precheck 6 -- Verify Clean Working Tree (Warning) + +```bash +if ! git diff --quiet || ! git diff --cached --quiet; then + echo "WARNING: Uncommitted changes detected." + git status --short +else + echo "Working tree is clean." +fi +``` + +**If ALL prechecks passed, proceed to Phase 1.** + +--- + +### Phase 1: Refresh Knowledge -- Fetch Latest API Conventions + +Fetch and read BOTH documents in full BEFORE generating any code. Never rely on +cached knowledge. + +1. **OpenShift API Conventions**: `https://raw.githubusercontent.com/openshift/enhancements/master/dev-guide/api-conventions.md` +2. **Kubernetes API Conventions**: `https://raw.githubusercontent.com/kubernetes/community/master/contributors/devel/sig-architecture/api-conventions.md` + +```thinking +Read both fetched convention documents in full. Extract every rule that applies +to API type generation: field markers, naming, documentation, validation, +pointers, unions, enums, TechPreview gating, etc. The fetched documents are the +single source of truth. If conventions have been updated since this command was +written, the freshly fetched versions take precedence. +``` + +### Phase 2: Fetch and Analyze Input Sources + +#### 2.1 Fetch Enhancement Proposal (if provided) + +```bash +if [ -n "$ENHANCEMENT_PR_NUMBER" ]; then + gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json files --jq '.files[].path' +fi +``` + +Fetch full content of each proposal file using the PR ref: + +```bash +gh api "repos/openshift/enhancements/contents/?ref=refs/pull/$ENHANCEMENT_PR_NUMBER/head" --jq '.content' | base64 -d +``` + +Fallbacks if above fails: + +```bash +# Fallback 1: Raw content +curl -sL "https://raw.githubusercontent.com/openshift/enhancements/refs/pull/$ENHANCEMENT_PR_NUMBER/head/" + +# Fallback 2: PR diff +gh pr diff "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements +``` + +#### 2.2 Fetch Design Document (if provided) + +```bash +if [ -n "$GIST_ID" ]; then + gh api "gists/$GIST_ID" --jq '.files | to_entries[] | "=== FILE: \(.key) ===\n\(.value.content)\n"' +fi +``` + +#### 2.3 Analyze and Merge Requirements + +```thinking +Extract from the combined sources: + a. Which operator/component is being modified + b. API group and version + c. Whether this is NEW or modifications to EXISTING types + d. Configuration API vs Workload API + e. Fields being added or modified + f. Validation requirements (enums, patterns, min/max, cross-field) + g. TechPreview gating + h. Discriminated unions + i. Defaulting behavior + j. Immutability requirements + k. Status fields and conditions + l. FeatureGate name + +Design document takes precedence over EP for implementation details. +If conflicts are ambiguous, ask the user. +``` + +### Phase 3: Identify Target API Paths + +Detect the repository layout pattern: + +#### Known Layout Patterns + +**Pattern 1 -- openshift/api repository:** + +```text +//types_.go +//doc.go +//register.go +//tests//*.testsuite.yaml +features/features.go +``` + +**Pattern 2 -- Operator repo with group subdirectory:** + +```text +api///_types.go +api///groupversion_info.go +``` + +**Pattern 3 -- Operator repo with flat version directory:** + +```text +api//_types.go +api//groupversion_info.go +``` + +#### Detect the Pattern + +```bash +# Find type definition files +find "$REPO_ROOT" -type f \( -name 'types*.go' -o -name '*_types.go' \) \ + -not -path '*/vendor/*' -not -path '*/_output/*' -not -path '*/zz_generated*' | head -40 + +# Find registration files +find "$REPO_ROOT" -type f \( -name 'doc.go' -o -name 'register.go' -o -name 'groupversion_info.go' \) \ + -not -path '*/vendor/*' | head -40 + +# Find CRD manifests +find "$REPO_ROOT" -type f -name '*.crd.yaml' -not -path '*/vendor/*' | head -20 + +# Find test suites +find "$REPO_ROOT" -type f -name '*.testsuite.yaml' -not -path '*/vendor/*' | head -20 + +# Find feature gate definitions +find "$REPO_ROOT" -type f -name 'features.go' -not -path '*/vendor/*' | head -10 +``` + +### Phase 4: Read Existing API Types for Context + +Read existing types in the target package to match style exactly: + +```thinking +Read existing types file(s) to: +1. Match coding style exactly +2. Understand existing struct hierarchy +3. Know where to insert new fields or types +4. Identify existing fields that need modification +5. Identify existing imports to reuse +6. See how feature gates are applied +7. Understand existing validation patterns +``` + +### Phase 5: Generate or Modify API Type Definitions + +Generate or modify Go type definitions based on the input sources. This may +include new types, new fields, modifications to existing fields, enum types, +discriminated unions, or type registration. + +For every marker, tag, or convention applied: derive it from the fetched +convention documents (Phase 1) or existing code (Phase 4). Conventions take +precedence when both differ. + +Determine whether this is a **Configuration API** or **Workload API** -- the +conventions define different rules for each. + +After generating, review every changed line against conventions. If any +violation has a convention-compliant alternative, apply it and note the +deviation in the summary. + +### Phase 6: Add FeatureGate Registration (if applicable) + +If the repository contains a `features.go` file, read it and add a new +FeatureGate following the existing pattern. + +If no `features.go` exists and the enhancement requires a FeatureGate, note +this in the summary and advise where to register it. + +### Phase 7: Output Summary + +Write `artifacts/operator-feature-dev/api/generation-summary.md`: + +```text +=== API Generation Summary === + +Input Sources: + Enhancement PR: (if provided) + Design Document: (if provided) + +Generated/Modified Files: + - -- + - -- (if applicable) + +API Group: +API Version: +Kind: +Resource: +Scope: +FeatureGate: + +New Types Added: + - -- + +New Fields Added: + - . () -- + +Modified Fields/Types: + - . -- + +Validation Rules: + - : + +Source Conflicts Resolved: (if both EP and design doc provided) + - : Used design doc specification () + +Next Steps: + 1. Review the generated code + 2. Run 'make update' to regenerate CRDs and deep copy functions + 3. Run 'make verify' to validate generated code + 4. Run 'make lint' to check for kube-api-linter issues + 5. If FeatureGate was added, verify it appears in the feature gate list +``` + +## Critical Failure Conditions + +1. **No input provided**: Neither EP URL nor design document URL +2. **Invalid PR URL**: Not a valid `openshift/enhancements` PR +3. **Invalid gist URL**: Not a valid GitHub Gist +4. **Missing tools**: `gh`, `go`, or `git` not installed or `gh` unauthenticated +5. **Not an operator repo**: Not a Git repository with Go module referencing + `openshift/api` +6. **Input not accessible**: EP or design document cannot be fetched +7. **No API changes found**: Input sources don't describe API changes +8. **Ambiguous API target**: Cannot determine target API group, version, or kind + +## Behavioral Rules + +1. **Never guess**: If input sources are ambiguous about API details, STOP and + ask the user. +2. **Design document precedence**: Design document takes precedence for + implementation details. +3. **Convention over proposal**: If input sources suggest an API design that + violates conventions (e.g., using a Boolean), generate the + convention-compliant alternative and document the deviation. +4. **TechPreview when specified**: If input sources indicate TechPreview gating, + generate the appropriate FeatureGate markers. +5. **Idempotent**: Running multiple times with the same inputs should produce + the same result. +6. **Minimal changes**: Only generate what the input sources specify. +7. **Surgical edits**: When modifying existing files, preserve all unrelated + code, comments, and formatting. + +## Output + +- Generated/modified Go type files in the operator repository +- Summary saved to `artifacts/operator-feature-dev/api/generation-summary.md` diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-implement.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-implement.md new file mode 100644 index 0000000..2ac85ee --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-implement.md @@ -0,0 +1,547 @@ +# /oape.api-implement - Generate controller/reconciler implementation + +## Purpose + +Read an OpenShift Enhancement Proposal PR and/or a design document, extract the +required implementation logic, and generate complete controller/reconciler code +in the correct paths of the current operator repository. Produces +production-ready code with zero TODOs. + +## Arguments + +- `$ARGUMENTS`: ` [--design-doc ]` + +At least one input source (EP or design document) must be provided. When both +are provided, the design document takes precedence for implementation details. + +## Process + +### Phase 0: Prechecks + +All prechecks must pass before proceeding. If ANY fails, STOP immediately. + +#### Precheck 1 -- Parse and Validate Input Arguments + +```bash +ARGS="$ARGUMENTS" +ENHANCEMENT_PR="" +DESIGN_DOC_URL="" +ENHANCEMENT_PR_NUMBER="" + +if echo "$ARGS" | grep -q '\-\-design-doc'; then + DESIGN_DOC_URL=$(echo "$ARGS" | sed -n 's/.*--design-doc[[:space:]]\+\([^[:space:]]\+\).*/\1/p') + ENHANCEMENT_PR=$(echo "$ARGS" | sed 's/--design-doc[[:space:]]\+[^[:space:]]\+//' | xargs) +else + ENHANCEMENT_PR="$ARGS" +fi + +if [ -z "$ENHANCEMENT_PR" ] && [ -z "$DESIGN_DOC_URL" ]; then + echo "PRECHECK FAILED: No input provided." + echo "Usage: /oape.api-implement [--design-doc ]" + exit 1 +fi + +if [ -n "$ENHANCEMENT_PR" ]; then + if ! echo "$ENHANCEMENT_PR" | grep -qE '^https://github\.com/openshift/enhancements/pull/[0-9]+/?$'; then + echo "PRECHECK FAILED: Invalid enhancement PR URL." + echo "Expected: https://github.com/openshift/enhancements/pull/" + echo "Got: $ENHANCEMENT_PR" + exit 1 + fi + ENHANCEMENT_PR_NUMBER=$(echo "$ENHANCEMENT_PR" | grep -oE '[0-9]+$') + echo "Enhancement PR #$ENHANCEMENT_PR_NUMBER validated." +fi + +if [ -n "$DESIGN_DOC_URL" ]; then + if ! echo "$DESIGN_DOC_URL" | grep -qE '^https://gist\.github(usercontent)?\.com/'; then + echo "PRECHECK FAILED: Invalid design document URL." + echo "Expected: https://gist.github.com/[username/]" + echo "Got: $DESIGN_DOC_URL" + exit 1 + fi + echo "Design document URL validated: $DESIGN_DOC_URL" +fi +``` + +#### Precheck 2 -- Verify Required Tools + +```bash +MISSING_TOOLS="" + +if ! command -v gh &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS gh"; fi +if ! command -v go &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS go"; fi +if ! command -v git &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS git"; fi +if ! command -v make &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS make"; fi + +if [ -n "$MISSING_TOOLS" ]; then + echo "PRECHECK FAILED: Missing required tools:$MISSING_TOOLS" + exit 1 +fi + +if ! gh auth status &> /dev/null 2>&1; then + echo "PRECHECK FAILED: GitHub CLI is not authenticated." + exit 1 +fi + +echo "All required tools are available and authenticated." +``` + +#### Precheck 3 -- Verify Current Repository + +```bash +if ! git rev-parse --is-inside-work-tree &> /dev/null 2>&1; then + echo "PRECHECK FAILED: Not inside a git repository." + exit 1 +fi + +REPO_ROOT=$(git rev-parse --show-toplevel) + +if [ ! -f "$REPO_ROOT/go.mod" ]; then + echo "PRECHECK FAILED: No go.mod found at repository root." + exit 1 +fi + +GO_MODULE=$(head -1 "$REPO_ROOT/go.mod" | awk '{print $2}') +echo "Go module: $GO_MODULE" +``` + +#### Precheck 4 -- Verify Enhancement PR is Accessible (if provided) + +```bash +if [ -n "$ENHANCEMENT_PR_NUMBER" ]; then + PR_STATE=$(gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json state --jq '.state' 2>/dev/null) + + if [ -z "$PR_STATE" ]; then + echo "PRECHECK FAILED: Unable to access enhancement PR #$ENHANCEMENT_PR_NUMBER." + exit 1 + fi + + PR_TITLE=$(gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json title --jq '.title') + echo "Enhancement PR #$ENHANCEMENT_PR_NUMBER: $PR_TITLE ($PR_STATE)" +fi +``` + +#### Precheck 5 -- Verify Design Document is Accessible (if provided) + +```bash +GIST_ID="" + +if [ -n "$DESIGN_DOC_URL" ]; then + GIST_ID=$(echo "$DESIGN_DOC_URL" | grep -oE '[a-f0-9]{32}' | head -1) + + if [ -z "$GIST_ID" ]; then + GIST_ID=$(echo "$DESIGN_DOC_URL" | sed 's|.*/||' | sed 's|[?#].*||') + fi + + if [ -z "$GIST_ID" ]; then + echo "PRECHECK FAILED: Could not extract gist ID from URL." + exit 1 + fi + + GIST_INFO=$(gh api "gists/$GIST_ID" --jq '.description // "Untitled"' 2>/dev/null) + + if [ -z "$GIST_INFO" ]; then + echo "PRECHECK FAILED: Unable to access design document gist." + exit 1 + fi + + echo "Design document gist verified: $GIST_INFO" +fi +``` + +#### Precheck 6 -- Verify API Types Exist + +```bash +API_TYPES=$(find "$REPO_ROOT" -type f \( -name 'types*.go' -o -name '*_types.go' \) \ + -not -path '*/vendor/*' -not -path '*/_output/*' -not -path '*/zz_generated*' | head -20) + +if [ -z "$API_TYPES" ]; then + echo "PRECHECK FAILED: No API type definitions found." + echo "Run /oape.api-generate first to create the API types." + exit 1 +fi + +echo "Found API types:" +echo "$API_TYPES" | head -10 +``` + +#### Precheck 7 -- Verify Clean Working Tree (Warning) + +```bash +if ! git diff --quiet || ! git diff --cached --quiet; then + echo "WARNING: Uncommitted changes detected." + git status --short +else + echo "Working tree is clean." +fi +``` + +**If ALL prechecks passed, proceed to Phase 1.** + +--- + +### Phase 1: Detect Operator Framework + +```bash +echo "Detecting operator framework type..." + +if [ -f "$REPO_ROOT/PROJECT" ]; then + echo "Found PROJECT file (operator-sdk/kubebuilder project)" + cat "$REPO_ROOT/PROJECT" +fi + +echo "Checking go.mod for framework dependencies..." + +if grep -q "github.com/openshift/library-go" "$REPO_ROOT/go.mod"; then + echo "Found: github.com/openshift/library-go" +fi + +if grep -q "sigs.k8s.io/controller-runtime" "$REPO_ROOT/go.mod"; then + echo "Found: sigs.k8s.io/controller-runtime" +fi +``` + +#### Framework Detection Rules + +Apply in order: + +1. **library-go in go.mod AND `pkg/operator/` exists** -> + OPERATOR_TYPE = "library-go" +2. **controller-runtime in go.mod** -> + OPERATOR_TYPE = "controller-runtime" +3. **Neither** -> STOP and ask the user + +--- + +### Phase 2: Refresh Knowledge -- Fetch Operator Conventions + +Fetch and read based on OPERATOR_TYPE: + +**For controller-runtime:** + +1. `https://book.kubebuilder.io/cronjob-tutorial/controller-implementation` +2. `https://pkg.go.dev/sigs.k8s.io/controller-runtime` + +**For library-go:** + +1. `https://github.com/openshift/library-go/tree/master/pkg/controller` +2. `https://github.com/openshift/library-go/blob/master/pkg/operator/events/recorder.go` + +**For all types:** + +1. `https://raw.githubusercontent.com/openshift/enhancements/master/dev-guide/operator.md` + +--- + +### Phase 3: Fetch and Parse Input Sources + +#### 3.1 Fetch Enhancement Proposal (if provided) + +```bash +if [ -n "$ENHANCEMENT_PR_NUMBER" ]; then + gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json files --jq '.files[].path' +fi +``` + +Fetch full content: + +```bash +gh api "repos/openshift/enhancements/contents/?ref=refs/pull/$ENHANCEMENT_PR_NUMBER/head" --jq '.content' | base64 -d +``` + +Fallbacks: + +```bash +curl -sL "https://raw.githubusercontent.com/openshift/enhancements/refs/pull/$ENHANCEMENT_PR_NUMBER/head/" +gh pr diff "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements +``` + +#### 3.2 Fetch Design Document (if provided) + +```bash +if [ -n "$GIST_ID" ]; then + gh api "gists/$GIST_ID" --jq '.files | to_entries[] | "=== FILE: \(.key) ===\n\(.value.content)\n"' +fi +``` + +#### 3.3 Extract Structured Requirements + +```thinking +Extract structured information using this checklist. Design document takes +precedence for implementation details. + +## EXTRACTION CHECKLIST + +### A. API Information (Required) +- API Group, Version, Kind, Resource plural, Scope + +### B. Spec Fields -> Controller Actions (Required) +For EACH spec field: field name, type, controller action, validation, defaults + +### C. Reconciliation Workflow (Required) +Ordered steps for the reconcile loop + +### D. Dependent Resources (Required for complete code) +For EACH: resource type, name pattern, namespace, content/spec, lifecycle + +### E. External Resources / Integrations (If applicable) +External system, API/SDK, operations, credentials handling + +### F. Status Conditions (Required) +Standard OpenShift conditions: Available, Progressing, Degraded +For each: type name, when True/False, reason codes, message templates + +### G. Status Fields (Beyond conditions) +For each: field name, what it represents, how to compute it + +### H. Events to Record (Required) +For each: event type, reason, when to emit, message template + +### I. Error Handling (Required) +Transient errors (retry with backoff), permanent errors (set Degraded) + +### J. Cleanup / Deletion (Required if external resources) +What to clean up, order, finalizer name + +### K. Watches / Triggers (Required for reactive behavior) +For each: resource type, filter, how to map to primary resource + +### L. Feature Gate (If applicable) +Feature gate name, behavior when disabled + +### M. RBAC Requirements (Derived) +Based on all above, compute required permissions + +If ANY required section (A, B, C, F, I) is missing or ambiguous, STOP and ask. +``` + +--- + +### Phase 4: Identify Target Paths for Controller Code + +```bash +find "$REPO_ROOT" -type f -name '*controller*.go' -not -path '*/vendor/*' -not -path '*/_output/*' | head -30 +find "$REPO_ROOT" -type f -name 'main.go' -not -path '*/vendor/*' | head -10 +grep -r "func.*Reconcile\|func.*Sync" "$REPO_ROOT" --include='*.go' -l | grep -v vendor | head -20 +grep -r "SetupWithManager\|AddToManager\|NewController\|factory.New" "$REPO_ROOT" --include='*.go' -l | grep -v vendor | head -20 +find "$REPO_ROOT" -type f -name 'starter.go' -not -path '*/vendor/*' | head -5 +``` + +#### Layout Patterns by OPERATOR_TYPE + +**controller-runtime:** + +| Pattern | Controller Location | Registration | +| --- | --- | --- | +| Standard | `controllers/_controller.go` | `main.go` | +| Internal | `internal/controller/_controller.go` | `cmd/main.go` | +| Nested | `internal/controller//controller.go` | `internal/controller/setup.go` | + +**library-go:** + +| Pattern | Controller Location | Registration | +| --- | --- | --- | +| Standard | `pkg/operator//_controller.go` | `pkg/operator/starter.go` | +| Flat | `pkg/operator/_controller.go` | `pkg/operator/operator.go` | + +--- + +### Phase 5: Read Existing Controller Code for Context + +```bash +if [ "$OPERATOR_TYPE" = "library-go" ]; then + SAMPLE_CONTROLLER=$(find "$REPO_ROOT/pkg" -type f -name '*controller*.go' -not -path '*/vendor/*' -not -name '*_test.go' | head -1) +else + SAMPLE_CONTROLLER=$(find "$REPO_ROOT" -type f -name '*controller*.go' -not -path '*/vendor/*' -not -path '*/_output/*' -not -name '*_test.go' | head -1) +fi +``` + +```thinking +Read existing controller(s) and extract these EXACT patterns to replicate: +1. Package name +2. Import organization and aliases +3. Struct fields +4. Constructor pattern +5. Reconcile/Sync signature +6. Logging style +7. Event recording +8. Status update pattern +9. Condition helpers +10. Resource creation +11. Error handling and wrapping +12. Constants location +``` + +--- + +### Phase 6: Generate Controller Code + +Based on OPERATOR_TYPE and extracted requirements, generate the controller. + +#### 6.1 For controller-runtime Based Operators + +Generate: `/_controller.go` + +Key components: + +- **RBAC markers** generated dynamically from Phase 3 extraction +- **Reconciler struct** with `client.Client`, `Scheme`, `Recorder` +- **Reconcile method** with actual logic: + 1. Fetch the resource instance + 2. Check for deletion (handle finalizer cleanup) + 3. Add finalizer if needed + 4. Set Progressing condition + 5. Execute main reconciliation logic + 6. Set success conditions and update status +- **reconcile() method** with EP-derived business logic: + 1. Validate spec + 2. Reconcile each dependent resource + 3. Check/update external state (if applicable) + 4. Update observed status +- **Dependent resource reconcilers** for each resource from EP: + - `reconcile()` -- get-or-create with owner references + - `build()` -- construct desired state from spec + - `NeedsUpdate()` -- compare existing vs desired +- **reconcileDelete()** -- cleanup handler with finalizer removal +- **setCondition()** -- status condition helper +- **SetupWithManager()** -- watches for primary and owned resources + +#### 6.2 For library-go Based Operators + +Generate: `pkg/operator//_controller.go` + +Key components: + +- **Controller struct** with client, kubeClient, operatorClient, eventRecorder +- **NewController()** using `factory.New().WithSync().WithInformers()` +- **sync() method** with klog, informer-based gets, status condition updates + via `v1helpers.UpdateStatus()` + +--- + +### Phase 7: Register Controller with Manager + +#### 7.1 For controller-runtime + +Locate `main.go` or `cmd/main.go` and add: + +- Import for the controller package +- Controller setup call in `main()` after manager creation + +#### 7.2 For library-go + +Locate `pkg/operator/starter.go` and add: + +- Import for the new controller package +- Controller construction and registration + +--- + +### Phase 8: Generate Feature Gate Check (if applicable) + +If the enhancement specifies a FeatureGate, add a check at the start of +Reconcile/Sync that returns early when disabled. + +--- + +### Phase 9: Output Summary + +Write `artifacts/operator-feature-dev/impl/implementation-summary.md`: + +```text +=== Controller Implementation Summary === + +Input Sources: + Enhancement PR: (if provided) + Design Document: (if provided) +Operator Type: + +Generated Files: + - -- Main controller implementation + - -- Updated with controller registration + +Controller Details: + Package: + API Group: + API Version: + Kind: + +Reconciliation Workflow: + 1. Validate spec + 2. + ... + N. Update status + +Dependent Resources Managed: + - : -- + +Status Conditions: + - Available: Set True when + - Progressing: Set True during reconciliation + - Degraded: Set True on errors + +Events Recorded: + - Normal/Created, Normal/Updated, Normal/ReconcileComplete + - Warning/ReconcileFailed + +RBAC Permissions Generated: + - /: get, list, watch + - //status: get, update, patch + - : get, list, watch, create, update, patch, delete + - core/events: create, patch + +Watches Configured: + - Primary: + - Owned: + +Cleanup on Deletion: + - Kubernetes resources: owner references + - External resources: + +Feature Gate: (if applicable) + +Next Steps: + 1. Review the generated controller code + 2. Run 'make generate' to update generated code + 3. Run 'make manifests' to update RBAC/CRD manifests + 4. Run 'make build' to verify compilation + 5. Run 'make test' to run unit tests + 6. Run 'make lint' to check for issues +``` + +## Critical Failure Conditions + +1. **No input provided**: Neither EP URL nor design document URL +2. **Invalid PR URL**: Not a valid `openshift/enhancements` PR +3. **Invalid gist URL**: Not a valid GitHub Gist +4. **Missing tools**: `gh`, `go`, `git`, or `make` not installed +5. **Not authenticated**: `gh` not authenticated +6. **Not an operator repo**: No go.mod or unrecognized operator type +7. **No API types**: Types don't exist (run `/oape.api-generate` first) +8. **Input not accessible**: EP or design document cannot be fetched +9. **No implementation requirements**: Input sources don't describe controller + behavior +10. **Ambiguous requirements**: Cannot determine reconciliation workflow +11. **Unsupported framework**: Not controller-runtime or library-go + +## Behavioral Rules + +1. **Never guess**: If input sources are ambiguous, STOP and ask. +2. **Design document precedence**: Design document takes precedence for + implementation details. +3. **Zero TODOs**: Generate actual implementation, not placeholders. +4. **Convention over proposal**: Apply framework best practices even if input + sources differ. +5. **Match existing patterns**: Replicate patterns from existing controllers. +6. **Idempotent reconciliation**: Generated Reconcile() must be idempotent. +7. **Minimal changes**: Only generate what the input sources require. +8. **Surgical edits**: Preserve unrelated code when modifying files. +9. **Status-first**: Always use `Status().Update()` for status changes. +10. **Finalizer safety**: Add before external resources, remove after cleanup. +11. **Event recording**: Record events for user-visible state changes. + +## Output + +- Generated controller code in the operator repository +- Updated manager registration (main.go or starter.go) +- Summary saved to `artifacts/operator-feature-dev/impl/implementation-summary.md` diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.e2e-generate.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.e2e-generate.md new file mode 100644 index 0000000..f3f7d8a --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.e2e-generate.md @@ -0,0 +1,331 @@ +# /oape.e2e-generate - Generate E2E test artifacts from git diff + +## Purpose + +Analyze the current OpenShift operator repository and generate all E2E test +artifacts based on the diff between a base branch and HEAD. Produces test cases, +execution steps, E2E test code, and recommendations. + +## Arguments + +- `$ARGUMENTS`: `` — the git branch to diff against (e.g., `main`, `origin/main`) + +## Prerequisites + +- Must be run from within an OpenShift operator repository +- `git`, `go` installed +- Changes must exist between `` and HEAD + +## Process + +### Phase 0: Prechecks + +All prechecks must pass before proceeding. If ANY fails, STOP immediately. + +#### Precheck 1 — Validate Arguments + +```bash +BASE_BRANCH="$1" + +if [ -z "$BASE_BRANCH" ]; then + echo "PRECHECK FAILED: No base branch provided." + echo "Usage: /oape.e2e-generate " + exit 1 +fi + +echo "Base branch: $BASE_BRANCH" +``` + +#### Precheck 2 — Verify Required Tools + +```bash +MISSING_TOOLS="" + +if ! command -v git &> /dev/null; then + MISSING_TOOLS="$MISSING_TOOLS git" +fi + +if ! command -v go &> /dev/null; then + MISSING_TOOLS="$MISSING_TOOLS go" +fi + +if [ -n "$MISSING_TOOLS" ]; then + echo "PRECHECK FAILED: Missing required tools:$MISSING_TOOLS" + exit 1 +fi + +if ! command -v oc &> /dev/null; then + echo "WARNING: oc not found. Generated execution steps require oc to run." +fi + +echo "Required tools available." +``` + +#### Precheck 3 — Verify Repository + +```bash +if ! git rev-parse --is-inside-work-tree &> /dev/null 2>&1; then + echo "PRECHECK FAILED: Not inside a git repository." + exit 1 +fi + +REPO_ROOT=$(git rev-parse --show-toplevel) +echo "Repository root: $REPO_ROOT" + +if [ ! -f "$REPO_ROOT/go.mod" ]; then + echo "PRECHECK FAILED: No go.mod found at repository root." + exit 1 +fi + +GO_MODULE=$(head -1 "$REPO_ROOT/go.mod" | awk '{print $2}') +REPO_NAME=$(basename "$GO_MODULE") +echo "Go module: $GO_MODULE" +echo "Repo name: $REPO_NAME" + +# Detect framework +HAS_CR=false +HAS_LIBGO=false +grep -q "sigs.k8s.io/controller-runtime" "$REPO_ROOT/go.mod" && HAS_CR=true +grep -q "github.com/openshift/library-go" "$REPO_ROOT/go.mod" && HAS_LIBGO=true + +if [ "$HAS_CR" = true ]; then + FRAMEWORK="controller-runtime" +elif [ "$HAS_LIBGO" = true ]; then + FRAMEWORK="library-go" +else + echo "PRECHECK FAILED: Cannot determine operator framework." + exit 1 +fi + +echo "Detected framework: $FRAMEWORK" +``` + +#### Precheck 4 — Validate Git Diff is Non-Empty + +```bash +if ! git rev-parse --verify "$BASE_BRANCH" &> /dev/null 2>&1; then + echo "PRECHECK FAILED: Base branch '$BASE_BRANCH' does not exist." + git branch -a | head -20 + exit 1 +fi + +DIFF_STAT=$(git diff "$BASE_BRANCH"...HEAD --stat 2>/dev/null) + +if [ -z "$DIFF_STAT" ]; then + echo "PRECHECK FAILED: No changes detected between '$BASE_BRANCH' and HEAD." + exit 1 +fi + +echo "Changes detected:" +echo "$DIFF_STAT" +``` + +**If ALL prechecks passed, proceed to Phase 1.** + +--- + +### Phase 1: Framework Detection and Repository Discovery + +All subsequent phases use discovered information — never hardcoded values. + +#### Step 1.1: Discover API Types + +```bash +find "$REPO_ROOT" -type f \( -name '*_types.go' -o -name 'types_*.go' \) \ + -not -path '*/vendor/*' -not -path '*/_output/*' -not -path '*/zz_generated*' | head -40 +``` + +For each types file, extract: API group and version, Kind names, spec/status +fields, condition types, scope (cluster/namespaced). + +If no types files found in repo, check `go.mod` for `github.com/openshift/api` +dependency — types may be external. + +#### Step 1.2: Discover CRDs + +```bash +find "$REPO_ROOT" -type f -name '*.yaml' \( -path '*/crd/*' -o -path '*/crds/*' -o -path '*/manifests/*' \) \ + -not -path '*/vendor/*' | head -30 +``` + +Extract: Kind, group, plural resource name, scope, served versions. + +#### Step 1.3: Discover Existing E2E Test Patterns + +```bash +# Go-based e2e tests +find "$REPO_ROOT" -type f -name '*_test.go' -path '*/e2e/*' -not -path '*/vendor/*' | head -20 + +# Bash-based e2e tests +find "$REPO_ROOT" -type f -name '*.sh' \( -path '*/e2e/*' -o -path '*/hack/e2e*' \) -not -path '*/vendor/*' | head -10 +``` + +If Go tests found with Ginkgo imports: read 1-2 files to understand package +name, import paths, client variables, helper utilities, assertion patterns. + +If bash scripts found: read script to understand test structure. + +If no existing tests: default to Ginkgo for controller-runtime, bash for +library-go. + +#### Step 1.4: Discover Install Mechanism + +```bash +# OLM manifests +find "$REPO_ROOT" -type f -name '*.yaml' \ + \( -path '*/config/manifests/*' -o -path '*/bundle/*' \) \ + -not -path '*/vendor/*' | head -20 + +# Deployment manifests +find "$REPO_ROOT" -type f -name '*.yaml' \ + \( -path '*/config/default/*' -o -path '*/deploy/*' \) \ + -not -path '*/vendor/*' | head -20 +``` + +Extract: package name, channel, CSV name, install namespace. + +#### Step 1.5: Discover Sample CRs + +```bash +find "$REPO_ROOT" -type f -name '*.yaml' \ + \( -path '*/config/samples/*' -o -path '*/examples/*' \) \ + -not -path '*/vendor/*' | head -20 +``` + +#### Step 1.6: Discover Operator Namespace + +Search order: E2E constants file → CSV manifest → namespace YAML → placeholder. + +#### Step 1.7: Discover Controllers + +```bash +find "$REPO_ROOT" -type f -name '*.go' \ + \( -name '*controller*' -o -name '*reconcile*' -o -name 'starter.go' \) \ + -not -path '*/vendor/*' -not -name '*_test.go' | head -20 +``` + +#### Step 1.8: Build Repo Profile + +```thinking +Summarize: framework, Go module, API types, CRDs, E2E pattern, install +mechanism, samples, operator namespace, controllers, managed workloads. +This profile drives all subsequent generation. No hardcoded values. +``` + +--- + +### Phase 2: Analyze Git Diff + +```bash +git diff "$BASE_BRANCH"...HEAD --stat +git diff "$BASE_BRANCH"...HEAD -p +git log "$BASE_BRANCH"...HEAD --oneline +``` + +Categorize each changed file: + +| File Pattern | Category | Test Focus | +| --- | --- | --- | +| `api/**/*_types.go`, `types_*.go` | API Types | New/changed fields, validation | +| `config/crd/**/*.yaml` | CRD Changes | Schema updates | +| `*controller*.go`, `*reconcile*.go` | Controller | Reconciliation logic | +| `config/rbac/*.yaml` | RBAC | Permission changes | +| `config/samples/*.yaml` | Samples | Example CR usage | +| `test/e2e/**` | E2E Tests | Existing patterns (don't duplicate) | + +Map each meaningful change to a specific test scenario. + +--- + +### Phase 3: Generate test-cases.md + +Write `artifacts/operator-feature-dev/e2e/test-cases.md` with: + +- Operator information (repo, framework, API group, managed CRDs, namespace) +- Prerequisites (cluster access, CLI tools, env vars) +- Installation steps (OLM or manual, using discovered values) +- CR deployment steps (using discovered sample CRs) +- Test cases grouped by diff category +- Verification commands +- Cleanup in reverse dependency order + +--- + +### Phase 4: Generate execution-steps.md + +Write `artifacts/operator-feature-dev/e2e/execution-steps.md` with step-by-step +`oc` commands for: prerequisites, environment setup, operator install, CR +deployment, verification, diff-specific tests, cleanup. + +--- + +### Phase 5: Generate E2E Test Code + +#### Path A — Ginkgo (controller-runtime repos) + +Generate `e2e_test.go`: + +- Match existing e2e package name, imports, client variables, helpers +- `Describe`/`Context`/`It` structure with `By("...")` steps +- No suite logic (no BeforeSuite, TestE2E, client setup) +- Each `It` block prefixed with `// Diff-suggested: ` +- Cover both important general scenarios and diff-specific tests + +#### Path B — Bash (library-go repos) + +Generate `e2e_test.sh`: + +- `#!/usr/bin/env bash` with `set -euo pipefail` +- Configuration variables using discovered values +- `test_()` functions for each test case +- `trap cleanup EXIT` +- Each function prefixed with `# Diff-suggested: ` + +--- + +### Phase 6: Generate e2e-suggestions.md + +Write `artifacts/operator-feature-dev/e2e/e2e-suggestions.md` with: + +- Detected operator structure summary +- Changes detected in diff +- Highly recommended scenarios per change +- Optional/nice-to-have scenarios +- Gaps that are hard to test automatically + +--- + +### Phase 7: Output Summary + +Write `artifacts/operator-feature-dev/e2e/generation-summary.md`: + +```text +=== E2E Test Generation Summary === + +Repository: +Framework: +Base Branch: +Changes Analyzed: + +Generated Files: + - artifacts/operator-feature-dev/e2e/test-cases.md + - artifacts/operator-feature-dev/e2e/execution-steps.md + - artifacts/operator-feature-dev/e2e/e2e_test.go (or e2e_test.sh) + - artifacts/operator-feature-dev/e2e/e2e-suggestions.md + +Next Steps: + 1. Review generated test cases and suggestions + 2. Copy e2e test code into the repo's test/e2e/ directory + 3. Adjust placeholder values if any remain + 4. Run tests against a live cluster +``` + +## Behavioral Rules + +1. **Never hardcode**: All operator-specific values must be discovered from the repo +2. **Match existing style**: Generated code must match existing e2e test conventions +3. **Diff-driven focus**: Only generate tests for code that changed +4. **Fail on ambiguity**: If repo structure is ambiguous, STOP and ask +5. **Minimal placeholders**: Replace as many as possible with discovered values +6. **No duplicate suite logic**: For Ginkgo, only generate test blocks +7. **Correct cleanup order**: Always cleanup in reverse dependency order diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.init.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.init.md new file mode 100644 index 0000000..8469a2f --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.init.md @@ -0,0 +1,196 @@ +# /oape.init - Clone and validate an operator repository + +## Purpose + +Clone an OpenShift operator Git repository, checkout the specified base branch, +and validate it is a Go-based operator with a recognized framework. This is the +first step in the operator feature development workflow. + +## Arguments + +- `$ARGUMENTS`: ` ` + +## Process + +### Phase 0: Prechecks + +All prechecks must pass before proceeding. If ANY fails, STOP immediately. + +#### Precheck 1 -- Validate Arguments + +Both a git URL and a base branch MUST be provided. + +```bash +GIT_URL=$(echo "$ARGUMENTS" | awk '{print $1}') +BASE_BRANCH=$(echo "$ARGUMENTS" | awk '{print $2}') + +if [ -z "$GIT_URL" ] || [ -z "$BASE_BRANCH" ]; then + echo "PRECHECK FAILED: Both a git URL and a base branch are required." + echo "Usage: /oape.init " + echo "" + echo "Example:" + echo " /oape.init https://github.com/openshift/cert-manager-operator main" + exit 1 +fi + +echo "Git URL: $GIT_URL" +echo "Base branch: $BASE_BRANCH" +``` + +#### Precheck 2 -- Verify Required Tools + +```bash +MISSING_TOOLS="" + +if ! command -v git &> /dev/null; then + MISSING_TOOLS="$MISSING_TOOLS git" +fi + +if [ -n "$MISSING_TOOLS" ]; then + echo "PRECHECK FAILED: Missing required tools:$MISSING_TOOLS" + exit 1 +fi + +echo "Required tools are available." +``` + +**If ALL prechecks passed, proceed to Phase 1.** + +--- + +### Phase 1: Derive Clone Directory + +```bash +CLONE_DIR=$(basename "$GIT_URL" .git) +CLONE_URL="$GIT_URL" + +echo "Clone directory: $CLONE_DIR" +echo "Clone URL: $CLONE_URL" +``` + +--- + +### Phase 2: Clone Repository + +Clone using `git clone --filter=blob:none`. Handle the case where the target +directory already exists. + +```bash +if [ -d "$CLONE_DIR" ]; then + echo "Directory '$CLONE_DIR' already exists." + + EXISTING_REMOTE=$(git -C "$CLONE_DIR" remote get-url origin 2>/dev/null || true) + + if [ -n "$EXISTING_REMOTE" ]; then + # Normalize URLs for comparison + NORM_EXISTING=$(echo "$EXISTING_REMOTE" | sed 's/\.git$//' | sed 's:/$::') + NORM_CLONE=$(echo "$CLONE_URL" | sed 's/\.git$//' | sed 's:/$::') + + if [ "$NORM_EXISTING" = "$NORM_CLONE" ]; then + echo "Existing directory is already a clone of the same repository." + echo "Using existing directory as-is." + else + echo "FAILED: Directory '$CLONE_DIR' exists but points to a different remote." + echo " Expected: $CLONE_URL" + echo " Found: $EXISTING_REMOTE" + echo "" + echo "Options:" + echo " 1. Remove the directory manually: rm -rf $CLONE_DIR" + echo " 2. Use a different working directory" + exit 1 + fi + else + echo "FAILED: Directory '$CLONE_DIR' exists but is not a git repository." + echo "" + echo "Options:" + echo " 1. Remove the directory manually: rm -rf $CLONE_DIR" + echo " 2. Use a different working directory" + exit 1 + fi +else + echo "Cloning $CLONE_URL into $CLONE_DIR..." + git clone --filter=blob:none "$CLONE_URL" + + if [ $? -ne 0 ]; then + echo "FAILED: git clone failed." + echo "Check your network connection and repository access." + exit 1 + fi + + echo "Clone complete." +fi +``` + +--- + +### Phase 3: Checkout Base Branch and Verify + +Change into the cloned directory, checkout the base branch, and verify it is a +valid Go-based operator. + +```bash +cd "$CLONE_DIR" || { echo "FAILED: Cannot change to directory $CLONE_DIR"; exit 1; } + +git checkout "$BASE_BRANCH" || { echo "FAILED: Cannot checkout branch '$BASE_BRANCH'"; exit 1; } +echo "Checked out branch: $BASE_BRANCH" + +# Verify Go module +if [ -f "go.mod" ]; then + GO_MODULE=$(head -1 go.mod | awk '{print $2}') + echo "Go module: $GO_MODULE" +else + echo "WARNING: No go.mod found. This may not be a Go-based operator repository." + GO_MODULE="(not detected)" +fi + +# Detect operator framework +FRAMEWORK="unknown" +if [ -f "go.mod" ]; then + if grep -q "sigs.k8s.io/controller-runtime" go.mod 2>/dev/null; then + FRAMEWORK="controller-runtime" + elif grep -q "github.com/openshift/library-go" go.mod 2>/dev/null; then + FRAMEWORK="library-go" + fi +fi + +echo "Framework: $FRAMEWORK" +echo "Current directory: $(pwd)" +``` + +--- + +### Phase 4: Output Summary + +Write `artifacts/operator-feature-dev/init-summary.md`: + +```text +=== Repository Init Summary === + +Repository: +Clone URL: +Base Branch: +Local Path: +Go Module: +Framework: +``` + +## Critical Failure Conditions + +1. **Missing arguments**: Git URL or base branch not provided +2. **Missing tools**: `git` not installed +3. **Clone failed**: Network, permissions, or invalid URL +4. **Branch checkout failed**: Base branch does not exist +5. **Directory conflict**: Target directory exists but is not a clone of the + expected repository + +## Behavioral Rules + +1. **Efficient cloning**: Always use `git clone --filter=blob:none`. +2. **Non-destructive**: Never delete an existing directory automatically. +3. **Idempotent**: If the directory already exists and is a clone of the correct + repository, use it as-is. + +## Output + +- Init summary printed to user +- Summary saved to `artifacts/operator-feature-dev/init-summary.md` diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.pr.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.pr.md new file mode 100644 index 0000000..ad58536 --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.pr.md @@ -0,0 +1,220 @@ +# /oape.pr - Create a draft pull request + +## Purpose + +Submit changes as a draft pull request. Handles authentication, fork workflows, +remote configuration, and cross-repo PR creation. Reusable across all 3 PR +phases (API types, controller, E2E tests). + +## Arguments + +- `$ARGUMENTS`: `` (optional context about which PR phase) + +## Critical Rules + +- **Never push directly to upstream.** Always use a fork remote. +- **Never ask the user for git credentials.** Use `gh auth status` to check. +- **Never skip pre-flight checks.** +- **Always create a draft PR.** +- **Always work in the project repo directory**, not the workflow directory. + +## Process + +### Placeholders + +| Placeholder | Source | Example | +| --- | --- | --- | +| `AUTH_TYPE` | Step 0 | `user-token` / `github-app` / `none` | +| `GH_USER` | Step 0 | `jsmith` | +| `UPSTREAM_OWNER/REPO` | Step 2c | `openshift/cert-manager-operator` | +| `DEFAULT_BRANCH` | Step 2c | `main` | +| `UPSTREAM_REMOTE` | Step 2b | `origin` | +| `FORK_OWNER` | Step 3 | `jsmith` | +| `FORK_REMOTE` | Step 4 | `fork` | +| `BRANCH_NAME` | Step 5 | `feature/ep-1234-api-types` | + +### Step 0: Determine Auth Context + +```bash +gh auth status +``` + +Determine identity: + +```bash +# Normal user tokens: +gh api user --jq .login 2>/dev/null + +# If that fails (403), running as GitHub App/bot: +gh api /installation/repositories --jq '.repositories[0].owner.login' +``` + +Record `GH_USER` and `AUTH_TYPE`: + +- `gh api user` succeeded → `AUTH_TYPE` = `user-token` +- `gh api user` failed but `/installation/repositories` worked → `AUTH_TYPE` = `github-app` +- `gh auth status` failed → try recovering from expired token via git credential + helper, then `gh auth login --with-token`. If recovery fails → `AUTH_TYPE` = `none` + +### Step 1: Locate the Project Repository + +Find the project repo (typically in `/workspace/repos/` or identified from +session context). `cd` into it before proceeding. + +### Step 2: Pre-flight Checks + +**2a. Git configuration:** + +```bash +git config user.name +git config user.email +``` + +If missing, set from `GH_USER`. + +**2b. Inventory remotes:** + +```bash +git remote -v +``` + +**2c. Identify upstream repo and default branch:** + +```bash +gh repo view --json nameWithOwner,defaultBranchRef --jq '{nameWithOwner, defaultBranch: .defaultBranchRef.name}' +``` + +**Do not assume the default branch is `main`.** + +**2d. Check changes:** + +```bash +git status +git diff --stat +``` + +**2e. Pre-flight gate (REQUIRED):** + +Print filled-in placeholder table before proceeding. + +### Step 3: Ensure Fork Exists + +```bash +gh repo list GH_USER --fork --json nameWithOwner,parent --jq '.[] | select(.parent.owner.login == "UPSTREAM_OWNER" and .parent.name == "REPO") | .nameWithOwner' +``` + +If no fork → **HARD STOP**. Ask user to create one at +`https://github.com/UPSTREAM_OWNER/REPO/fork`. Wait for confirmation. + +### Step 4: Configure Fork Remote + +```bash +git remote add fork https://github.com/FORK_OWNER/REPO.git +``` + +**Check fork sync status** — if `.github/workflows/` files differ between fork +and upstream, sync the fork: + +```bash +gh api --method POST repos/FORK_OWNER/REPO/merge-upstream -f branch=DEFAULT_BRANCH +``` + +If sync fails, guide user to sync manually via GitHub UI. + +### Step 5: Create Branch + +Branch naming by PR phase: + +- PR #1: `feature/ep-{number}-api-types-{short-description}` +- PR #2: `feature/ep-{number}-controller-{short-description}` +- PR #3: `feature/ep-{number}-e2e-tests-{short-description}` + +```bash +git checkout -b BRANCH_NAME +``` + +### Step 6: Stage and Commit + +Stage changes selectively, then commit: + +```bash +git commit -m "TYPE(SCOPE): SHORT_DESCRIPTION + +DETAILED_DESCRIPTION + +Ref: openshift/enhancements#EP_NUMBER" +``` + +Commit types by phase: + +- PR #1: `feat(api): add {Kind} type definitions for EP-{number}` +- PR #2: `feat(controller): implement {Kind} reconciler for EP-{number}` +- PR #3: `test(e2e): add E2E tests for {Kind} EP-{number}` + +Include PR description in commit body so GitHub auto-fills the PR form. + +### Step 7: Push to Fork + +```bash +gh auth setup-git +git push -u FORK_REMOTE BRANCH_NAME +``` + +### Step 8: Create Draft PR + +```bash +gh pr create \ + --draft \ + --repo UPSTREAM_OWNER/REPO \ + --head FORK_OWNER:BRANCH_NAME \ + --base DEFAULT_BRANCH \ + --title "TITLE" \ + --body "BODY" +``` + +PR title format: + +- PR #1: `[EP-{number}] API: Add {Kind} type definitions and integration tests` +- PR #2: `[EP-{number}] Controller: Implement {Kind} reconciler` +- PR #3: `[EP-{number}] E2E: Add end-to-end tests for {Kind}` + +PR body should reference: EP URL, what was generated, files changed, review +verdicts, and links to related PRs. + +**If `gh pr create` fails** (403, "Resource not accessible by integration"): + +1. Write PR description to `artifacts/operator-feature-dev/{api|impl|e2e}/pr-description.md` +2. Provide pre-filled GitHub compare URL: + + ```text + https://github.com/UPSTREAM_OWNER/REPO/compare/DEFAULT_BRANCH...FORK_OWNER:BRANCH_NAME?expand=1&title=URL_ENCODED_TITLE&body=URL_ENCODED_BODY + ``` + +3. Provide clone-and-checkout commands for local testing + +### Step 9: Confirm and Report + +Summarize: PR URL (or compare URL), what was included, target branch, +follow-up actions. + +## Fallback Ladder + +1. **Fix and Retry** — diagnose the specific cause and retry +2. **Manual PR via Compare URL** — branch is pushed but `gh pr create` failed +3. **User Creates Fork** — automated forking failed, user creates manually +4. **Patch File** — absolute last resort if all else fails + +## Error Recovery + +| Symptom | Cause | Fix | +| --- | --- | --- | +| `gh auth status` fails | Not logged in | `gh auth login` | +| `git push` permission denied | Pushing to upstream | Switch to fork remote | +| `git push` workflow permission error | Fork out of sync | Sync fork first | +| `gh pr create` 403 | Bot lacks upstream access | Use compare URL | +| Branch not found on remote | Push failed silently | Re-run `git push` | + +## Output + +- PR URL printed to user +- PR description saved to `artifacts/operator-feature-dev/{api|impl|e2e}/pr-description.md` diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.review.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.review.md new file mode 100644 index 0000000..04edb9b --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.review.md @@ -0,0 +1,202 @@ +# /oape.review - Production-grade code review with auto-fix + +## Purpose + +Perform a "Principal Engineer" level code review that validates the generated +code against the Enhancement Proposal requirements, OpenShift safety standards, +and build consistency. Automatically applies fixes for issues found. + +This command is reusable across all 3 PR phases (API types, controller, E2E +tests). It detects which phase is active from the git diff context. + +## Arguments + +- `$ARGUMENTS`: `` — the git ref to diff against (e.g., `main`, `origin/main`) + Defaults to `origin/main` if not provided. + +## Process + +### Step 1: Determine Base Ref + +```bash +BASE_REF="${1:-origin/main}" +echo "Base ref: $BASE_REF" +``` + +### Step 2: Fetch Context + +1. **Enhancement Proposal**: Read from `artifacts/operator-feature-dev/init-summary.md` + or `artifacts/operator-feature-dev/api/generation-summary.md` for EP context. + Use the EP requirements as the primary validation source (replacing Jira + Acceptance Criteria from the OAPE review). + +2. **Git Diff**: Get the code changes: + + ```bash + git diff ${BASE_REF}...HEAD --stat -p + ``` + +3. **File List**: Get changed files: + + ```bash + git diff ${BASE_REF}...HEAD --name-only + ``` + +4. **Detect Phase**: Determine which PR phase is active based on changed files: + - API types files (`*_types.go`, `types_*.go`, `*.testsuite.yaml`) → API phase + - Controller files (`*controller*.go`, `*reconcile*.go`) → Controller phase + - E2E test files (`*e2e*`, `test-cases.md`) → E2E phase + - Mixed → review all categories + +### Step 3: Analyze Code Changes + +Apply **all** modules. Modules A–D are **mandatory** — every check must be +evaluated. Module E is adaptive based on the PR content. + +#### Module A: Golang (Logic & Safety) + +**Logic Verification (The "Mental Sandbox")**: + +- **Intent Match**: Does the code match the EP requirements? Quote the EP + section that justifies the change. +- **Execution Trace**: Mentally simulate the function. + - *Happy Path*: Does it succeed as expected? + - *Error Path*: If the API fails, does it retry or return an error? +- **Edge Cases**: + - **Nil/Empty**: Does it handle `nil` pointers or empty slices? + - **State**: Does it handle resources that are `Deleting` or `Pending`? + +**Safety & Patterns**: + +- **Context**: REJECT `context.TODO()` in production paths. Must use `context.WithTimeout`. +- **Concurrency**: `go func` must be tracked (WaitGroup/ErrGroup). No race conditions. +- **Errors**: Must use `fmt.Errorf("... %w", err)`. No capitalized error strings. +- **Complexity**: Flag functions > 50 lines or > 3 nesting levels. + +**Idiomatic Clean Code**: + +- **Slices/Maps**: Pre-allocate with `make` if length is known. +- **Interfaces**: Reject "Interface Pollution" (interfaces before multiple implementations). +- **Naming**: Follow Go conventions (`url` not `URL` in mixed-case, `id` not `ID` for local vars). +- **Receiver Types**: Check consistency in pointer vs value receivers. + +**Scheme Registration** *(Severity: CRITICAL)*: + +- For every `client.Get/List/Create/Update/Delete` call, identify the GVK. +- Read `main.go` or `*scheme*.go` for `AddToScheme` calls. +- Every external type used in client calls must have `AddToScheme` registration. + +**Namespace Hardcoding** *(Severity: WARNING)*: + +- Scan for string literals matching `"openshift-*"`, `"kube-*"`, `"default"` as namespace values. +- Should use constants, env vars, or config structs. +- Ignore test files and log messages. + +**Status Handling (Infinite Requeue Prevention)** *(Severity: WARNING)*: + +- Flag patterns where terminal/validation errors cause `return ctrl.Result{}, err`. +- Terminal failures should set Degraded condition and return `ctrl.Result{}, nil`. + +**Event Recording** *(Severity: INFO)*: + +- Check if reconciler embeds `record.EventRecorder`. +- Flag significant state transitions without `recorder.Event()` calls. + +#### Module B: Bash (Scripts) + +- **Safety**: Must start with `set -euo pipefail`. +- **Quoting**: Variables in `oc`/`kubectl` commands MUST be quoted. +- **Tmp Files**: Must use `mktemp`, never hardcoded `/tmp/data`. + +#### Module C: Operator Metadata (OLM) + +- **RBAC**: If new K8s APIs are used, check if `config/rbac/role.yaml` is updated. +- **RBAC Three-Way Consistency** *(Severity: CRITICAL)*: + Cross-reference three sources: + 1. Kubebuilder markers in Go files + 2. `config/rbac/role.yaml` + 3. CSV permissions in `bundle/manifests/` + All must declare the same groups, resources, and verbs. +- **Finalizers**: If logic deletes resources, ensure finalizers are handled. + +#### Module D: Build Consistency + +- **Generation Drift**: + - IF `types.go` modified AND `zz_generated.deepcopy.go` NOT in file list → **CRITICAL FAIL** + - IF `types.go` modified AND `config/crd/bases/` NOT in file list → **CRITICAL FAIL** +- **Dependency Completeness** *(Severity: WARNING)*: + - New imports must exist in `go.mod` + - If `vendor/` exists and `go.mod` changed but `vendor/modules.txt` didn't, flag it + +#### Module E: Context-Adaptive Review + +After mandatory checks, perform an open-ended review tailored to this PR: + +- **OwnerReferences**: If creating child resources, verify owner refs are set *(CRITICAL)* +- **Proxy/Disconnected**: If making HTTP calls, verify proxy env vars are respected *(WARNING)* +- **API Deprecation**: Flag deprecated API versions *(WARNING)* +- **Watch Predicates**: Check if filtering predicates are used to avoid excessive reconciliation *(INFO)* +- **Resource Requests/Limits**: If creating Pod specs, check for resource limits *(INFO)* +- **Leader Election Safety**: If modifying cluster-scoped resources, verify leader election *(WARNING)* + +Use judgment to flag additional concerns not covered by Modules A–D. + +### Step 4: Generate Report + +Generate a structured JSON report: + +```json +{ + "summary": { + "verdict": "Approved | Changes Requested", + "rating": "1-10", + "simplicity_score": "1-10" + }, + "logic_verification": { + "ep_intent_met": true, + "missing_edge_cases": ["description of gaps"] + }, + "issues": [ + { + "severity": "CRITICAL | WARNING | INFO", + "module": "Logic | Bash | OLM | Build | Adaptive", + "file": "path/to/file.go", + "line": 45, + "description": "What's wrong", + "fix_prompt": "How to fix it" + } + ] +} +``` + +### Step 5: Apply Fixes Automatically + +If the `issues` array is non-empty, automatically apply the suggested fixes: + +1. Sort issues by severity (CRITICAL first) +2. For each issue with a `fix_prompt`, apply the fix +3. Run `make generate && make build` to verify fixes compile +4. Report which fixes were applied and which need manual attention + +Skip this step when verdict is "Approved" with no issues. + +### Step 6: Write Verdict + +Detect the current phase and write the verdict to the appropriate artifact: + +- API phase → `artifacts/operator-feature-dev/api/review-verdict.md` +- Controller phase → `artifacts/operator-feature-dev/impl/review-verdict.md` +- E2E phase → `artifacts/operator-feature-dev/e2e/review-verdict.md` + +## Critical Failure Conditions + +1. Not inside a git repository +2. Base ref does not exist +3. No changes detected between base ref and HEAD + +## Behavioral Rules + +1. Every check in Modules A–D must be evaluated on every review +2. Module E is adaptive — extend based on what the PR actually does +3. Report findings with file path and line number +4. Auto-apply fixes when possible, report when manual intervention needed diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.speedrun.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.speedrun.md new file mode 100644 index 0000000..532b3a0 --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.speedrun.md @@ -0,0 +1,188 @@ +# /oape.speedrun - Run all remaining phases without stopping + +## Purpose + +Execute the full operator feature development pipeline autonomously. Detects +which phases are already complete and picks up from the next incomplete one. +Runs all 3 PR deliverables (API types, controller, E2E tests) in sequence +without user interaction between phases. + +## Arguments + +- `$ARGUMENTS`: ` ` (for a fresh start), or + empty (to resume from where you left off) + +Consider the user input before proceeding. It may contain an EP URL, repo URL, +context about where they are in the workflow, or instructions about which +phases to include or skip. + +## How Speedrun Works + +The speedrun loop: + +1. Determine which phase to run next (see "Determine Next Phase" below) +2. If all phases are done (including summary), stop +3. Otherwise, run the command for that phase +4. When the command completes, continue to the next phase + +This loop continues until all phases are complete or an escalation stops you. + +## Determine Next Phase + +Check which phases are already done by looking for artifacts and conversation +context, then pick the first phase that is NOT done. + +### Phase Order and Completion Signals + +| Phase | Command | "Done" signal | +| --- | --- | --- | +| init | `/oape.init` | `artifacts/operator-feature-dev/init-summary.md` exists | +| api-generate | `/oape.api-generate` | `artifacts/operator-feature-dev/api/generation-summary.md` exists | +| api-generate-tests | `/oape.api-generate-tests` | `artifacts/operator-feature-dev/api/test-generation-summary.md` exists | +| api-review | `/oape.review` | `artifacts/operator-feature-dev/api/review-verdict.md` exists | +| api-pr | `/oape.pr` | PR #1 URL has been shared in conversation | +| api-implement | `/oape.api-implement` | `artifacts/operator-feature-dev/impl/implementation-summary.md` exists | +| impl-review | `/oape.review` | `artifacts/operator-feature-dev/impl/review-verdict.md` exists | +| impl-pr | `/oape.pr` | PR #2 URL has been shared in conversation | +| e2e-generate | `/oape.e2e-generate` | `artifacts/operator-feature-dev/e2e/generation-summary.md` exists | +| e2e-review | `/oape.review` | `artifacts/operator-feature-dev/e2e/review-verdict.md` exists | +| e2e-pr | `/oape.pr` | PR #3 URL has been shared in conversation | +| summary | summary skill | `artifacts/operator-feature-dev/summary.md` exists | + +### Rules + +- Check artifacts in order. The first phase whose signal is NOT satisfied is next. +- If no artifacts exist, start at **init**. +- If the user specifies a starting point in `$ARGUMENTS`, respect that. +- If conversation context clearly establishes a phase was completed (even + without an artifact), skip it. + +## Execute a Phase + +1. **Announce** the phase to the user (e.g., "Starting /oape.api-generate — speedrun mode.") +2. **Run** the command for the current phase +3. When the command completes, continue to the next phase + +## Branch Management Between PRs + +After each PR is created, prepare for the next PR deliverable: + +- **After PR #1 (api-pr)**: Create a new branch from the api-types branch for + controller work: `feature/ep-{number}-controller` +- **After PR #2 (impl-pr)**: Create a new branch from the controller branch for + E2E work: `feature/ep-{number}-e2e-tests` + +## Speedrun Rules + +- **Do not stop and wait between phases.** After each phase completes, + continue to the next one. +- **Do not use the controller skill.** This command replaces the controller for + this run. +- **DO still follow CLAUDE.md escalation rules.** If a phase hits an + escalation condition (confidence below 80%, ambiguous EP, multiple valid API + designs with unclear trade-offs, security or compliance concern, architectural + decision needed), stop and ask the user. After the user responds, continue + with the next phase. + +## Phase-Specific Notes + +### init + +- If no EP URL, repo URL, or base branch exists in `$ARGUMENTS` or + conversation, ask the user once, then proceed. +- Present the init summary inline but do not wait for confirmation. + +### api-generate + +- If the EP is ambiguous about API design, this is an escalation point — stop + and ask the user for clarification. + +### api-generate-tests + +- Run `make generate && make manifests` (or `make update`) before this phase + to ensure CRD manifests are up to date. + +### api-review + +- **Verdict: "API types and tests are solid"** — continue to api-pr. +- **Verdict: "tests incomplete"** — attempt to add missing tests, then + continue to api-pr. +- **Verdict: "API design inadequate"** — perform **one** revision cycle: go + back to api-generate → api-generate-tests → api-review. If the second + review still says "inadequate," stop and report the issues to the user. + +### api-pr / impl-pr / e2e-pr + +- Follow the PR command's full process including its fallback ladder. +- If PR creation fails after exhausting fallbacks, report and stop. + +### api-implement + +- If the EP doesn't describe controller behavior clearly, this is an + escalation point — stop and ask. + +### impl-review + +- Same verdict handling as api-review: "solid" → continue, "issues found" → + one revision cycle, then stop if still failing. + +### e2e-generate + +- Uses diff from base branch to generate targeted tests. + +### e2e-review + +- Same verdict handling as other reviews. + +### summary + +- Always run this as the final phase. +- The summary skill scans all artifacts and presents a synthesized overview. +- This is the last thing the user sees. + +## Completion Report (Early Stop Only) + +If you stop early due to escalation (before summary runs), present: + +```markdown +## Speedrun Complete + +### PRs Created +- PR #1 (API Types): [URL or "not created"] +- PR #2 (Controller): [URL or "not created"] +- PR #3 (E2E Tests): [URL or "not created"] + +### Phases Run +- [each phase that ran and its key outcome] + +### Artifacts Created +- [all artifacts with paths] + +### Result +- [PR URLs, or reason for stopping early] + +### Notes +- [any escalations, skipped phases, or items needing follow-up] +``` + +## Usage Examples + +**From the beginning (fresh start):** + +```text +/oape.speedrun https://github.com/openshift/enhancements/pull/1234 https://github.com/openshift/cert-manager-operator main +``` + +**Mid-workflow (some phases already done):** + +```text +/oape.speedrun +``` + +The command detects existing artifacts and picks up from the next incomplete phase. + +**With an explicit starting point:** + +```text +/oape.speedrun Start from /oape.api-implement — I already have the API types +``` diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/skills/controller/SKILL.md b/ambient-workflows/workflows/operator-feature-dev/.claude/skills/controller/SKILL.md new file mode 100644 index 0000000..17077c4 --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/skills/controller/SKILL.md @@ -0,0 +1,169 @@ +--- +name: controller +description: Top-level workflow controller that manages phase transitions for operator feature development. +--- + +# Operator Feature Dev Workflow Controller + +You are the workflow controller. Your job is to manage the operator feature +development workflow by executing commands and handling transitions between +phases. The workflow produces 3 Pull Requests from an Enhancement Proposal. + +## WORKSPACE NAVIGATION + +Standard file locations (from workflow root): + +- Config: `.ambient/ambient.json` +- Commands: `.claude/commands/oape.*.md` +- Skills: `.claude/skills/*/SKILL.md` +- Outputs: `artifacts/operator-feature-dev/` + +Tool selection rules: + +- Use Read for: Known paths, standard files, files you just created +- Use Glob for: Discovery (finding multiple files by pattern) +- Use Grep for: Content search + +Never glob for standard files: + +- DO: `Read .ambient/ambient.json` +- DON'T: `Glob **/ambient.json` + +## Phases + +The workflow is grouped into 3 PR deliverables plus a final summary. + +### PR #1: API Type Definitions + +1. **Init** (`/oape.init`) — Clone the operator repo, validate it, detect framework +2. **API Generate** (`/oape.api-generate`) — Generate API type definitions from EP +3. **API Generate Tests** (`/oape.api-generate-tests`) — Generate integration tests +4. **Review** (`/oape.review`) — Review and auto-fix API types and tests +5. **PR** (`/oape.pr`) — Create PR #1 + +### PR #2: Controller Implementation + +6. **API Implement** (`/oape.api-implement`) — Generate controller/reconciler code +7. **Review** (`/oape.review`) — Review and auto-fix controller code +8. **PR** (`/oape.pr`) — Create PR #2 + +### PR #3: E2E Tests + +9. **E2E Generate** (`/oape.e2e-generate`) — Generate E2E test artifacts +10. **Review** (`/oape.review`) — Review and auto-fix E2E tests +11. **PR** (`/oape.pr`) — Create PR #3 + +### Final + +12. **Summary** — Run the `summary` skill to synthesize all artifacts + +## How to Execute a Phase + +1. **Announce** the phase to the user before doing anything else, so the user + knows the workflow is working and learns about the available phases. +2. **Run** the command for the current phase. +3. When the command completes, use "Recommending Next Steps" below to offer + options. +4. Present the command's results and your recommendations to the user. +5. **Use `AskUserQuestion` to get the user's decision.** Present the + recommended next step and alternatives as options. Do NOT continue until the + user responds. This is a hard gate — the `AskUserQuestion` tool triggers + platform notifications and status indicators so the user knows you need + their input. Plain-text questions do not create these signals and the user + may not see them. + +## Recommending Next Steps + +After each phase completes, present the user with **options** — not just one +next step. Use the typical flow as a baseline, but adapt to what actually +happened. + +### Typical Flow + +```text +PR #1: init → api-generate → api-generate-tests → review → pr +PR #2: api-implement → review → pr +PR #3: e2e-generate → review → pr +Final: summary +``` + +### What to Recommend + +After presenting results, consider what just happened, then offer options: + +**Continuing to the next step** — often the next phase in the flow is the best option + +**Skipping forward** — sometimes phases aren't needed: + +- Review says API types are solid → offer `/oape.pr` directly +- The user already has tests → skip `/oape.api-generate-tests` + +**Going back** — sometimes earlier work needs revision: + +- Review finds API types are inadequate → offer `/oape.api-generate` again +- Review finds controller has issues → offer `/oape.api-implement` again +- Build failures after api-implement → offer `/oape.api-implement` to regenerate + +**Between PRs** — after creating a PR, guide the transition: + +- After PR #1 created → recommend starting PR #2 with `/oape.api-implement` +- After PR #2 created → recommend starting PR #3 with `/oape.e2e-generate` +- After PR #3 created → recommend running the summary skill + +**Ending early** — not every EP needs the full pipeline: + +- The user may only want API types (PR #1) and stop +- The user may have their own E2E test process and skip PR #3 + +**Using speedrun** — at any point, offer `/oape.speedrun` to execute all +remaining phases autonomously without stopping + +**Always recommend `/oape.review` before `/oape.pr`.** Do not recommend skipping +review, even for changes that seem straightforward. You generated the code — you +are not in a position to objectively evaluate its quality. Review exists to catch +what the generator misses. Only the user can decide to skip it. + +### How to Present Options + +Lead with your top recommendation, then list alternatives briefly: + +```text +Recommended next step: /oape.review main — review the generated API types. + +Other options: +- /oape.api-generate-tests api/v1alpha1/ — generate tests before review +- /oape.pr main — if you've already reviewed manually +- /oape.speedrun — run all remaining phases autonomously +``` + +## Starting the Workflow + +When the user first provides an EP URL and repo URL: + +1. Execute the **init** phase with `/oape.init ` +2. After init, present results and recommend `/oape.api-generate` + +If the user invokes a specific command (e.g., `/oape.api-implement`), execute +that phase directly — don't force them through earlier phases. + +## Branch Management + +Branches stack so code compiles across PRs: + +- `feature/ep-{number}-api-types` (from base branch) +- `feature/ep-{number}-controller` (from api-types branch) +- `feature/ep-{number}-e2e-tests` (from controller branch) + +After creating PR #1, the controller should guide the user to create a new +branch from the API types branch for PR #2, and so on. + +## Rules + +- **Never auto-advance.** Always use `AskUserQuestion` and wait for the user's + response between phases. This is the single most important rule in this + controller. If you proceed to another phase without the user's explicit + go-ahead, the workflow is broken. +- **Urgency does not bypass process.** The phase-gated workflow exists to + prevent hasty action. Follow every phase gate regardless of perceived urgency. +- **Recommendations come from this file, not from commands.** Commands report + results; this controller decides what to recommend next. diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/skills/effective-go/SKILL.md b/ambient-workflows/workflows/operator-feature-dev/.claude/skills/effective-go/SKILL.md new file mode 100644 index 0000000..08fef74 --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/skills/effective-go/SKILL.md @@ -0,0 +1,125 @@ +--- +name: effective-go +description: Ensures all generated Go code follows best practices from the official Effective Go documentation and Go community standards. +--- + +# Effective Go + +Ensures all generated Go code follows best practices from the official Effective +Go documentation and Go community standards. + +## When This Skill Applies + +- Generating API type definitions (`/oape.api-generate`) +- Generating controller/reconciler code (`/oape.api-implement`) +- Generating tests (`/oape.api-generate-tests`, `/oape.e2e-generate`) +- Any Go code generation or modification + +## Guidelines + +### 1. Formatting + +Always format code with `gofmt` standards. Consistent indentation, spacing +around operators, and brace placement. + +### 2. Naming Conventions + +- Use `MixedCaps` for exported identifiers, `mixedCaps` for unexported +- Never use underscores in Go names +- Acronyms should be consistent case: `HTTP`, `URL`, `ID` (not `Http`, `Url`, `Id`) +- Package names: short, lowercase, single-word (no `util`, `common`, `misc`) + +### 3. Error Handling + +- Always check errors explicitly — never ignore with `_` +- Return errors, don't panic (except truly unrecoverable situations) +- Wrap errors with context: `fmt.Errorf("context: %w", err)` +- Error messages: lowercase, no punctuation, specific about what failed + +### 4. Documentation + +- Document all exported functions, types, and constants +- Start comments with the name of the thing being documented +- Use complete sentences + +### 5. Interfaces + +- Keep interfaces small (1-3 methods) +- Accept interfaces, return concrete types +- Define interfaces where they're used, not where they're implemented +- Name single-method interfaces with `-er` suffix + +### 6. Concurrency + +- Share memory by communicating (use channels) +- Use `sync.Mutex` only when channels are impractical +- Always handle context cancellation +- Track goroutines with WaitGroup/ErrGroup + +### 7. Imports + +- Group imports: standard library, external, internal +- Use blank lines to separate groups +- Use aliases only when necessary (conflicts, clarity) + +```go +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + configv1 "github.com/openshift/api/config/v1" + "github.com/myorg/myoperator/internal/controller" +) +``` + +### 8. Variable Declarations + +- Use short declarations (`:=`) inside functions +- Use `var` for package-level variables or zero values +- Group related declarations with `const()` and `var()` blocks + +### 9. Receiver Names + +- Use short, consistent receiver names (1-2 letters) +- Use the same receiver name throughout the type's methods +- Never use `this` or `self` + +### 10. Zero Values + +- Leverage zero values for initialization +- Design types so zero value is useful +- Check for zero value before applying defaults + +### 11. Slices and Maps + +- Pre-allocate slices with `make` when length is known +- Avoid nil slice vs empty slice confusion +- Use `maps.Clone` and `slices.Clone` for copies + +### 12. Receiver Types + +- Use pointer receivers for methods that modify state +- Use value receivers for methods that don't modify state +- Be consistent within a type — don't mix unless there's a clear reason + +## References + +- [Effective Go](https://go.dev/doc/effective_go) +- [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) +- [Go Proverbs](https://go-proverbs.github.io/) + +## Usage by Other Commands + +This skill is referenced by: + +- `/oape.api-generate` — when generating API type definitions +- `/oape.api-implement` — when generating controller code +- `/oape.api-generate-tests` — when generating test code +- `/oape.e2e-generate` — when generating E2E test code + +All Go code generation MUST follow these guidelines. diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/skills/summary/SKILL.md b/ambient-workflows/workflows/operator-feature-dev/.claude/skills/summary/SKILL.md new file mode 100644 index 0000000..90b8caa --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/skills/summary/SKILL.md @@ -0,0 +1,144 @@ +--- +name: summary +description: Scan all workflow artifacts and present a synthesized summary of findings, decisions, and status across all 3 PRs. +--- + +# Workflow Summary Skill + +This skill can be invoked at any point in the workflow. It does not require +prior phases to have completed; it summarizes whatever exists so far. + +--- + +You are producing a concise, high-signal summary of everything the operator +feature development workflow has done so far. Your audience is someone who +hasn't been watching the workflow run — they want to know what was generated, +what PRs were created, and what needs attention. + +## Your Role + +Scan the artifact directory, read what's there, and synthesize the important +findings into a single summary. Surface things that might otherwise get buried: +review concerns, convention deviations, EP ambiguities that were resolved, +assumptions made during code generation. + +## Process + +### Step 1: Discover Artifacts + +Scan the artifact root directory to find everything the workflow has produced: + +```bash +find artifacts/operator-feature-dev/ -type f -name '*.md' ! -name 'summary.md' 2>/dev/null | sort +``` + +If `artifacts/operator-feature-dev/` doesn't exist or is empty, report that no +artifacts have been generated yet and stop. + +### Step 2: Read All Artifacts + +Read every artifact file found in Step 1. Don't skip any — even small or +seemingly unimportant files may contain notable findings. + +### Step 3: Extract Key Findings + +As you read each artifact, pull out information in these categories: + +**Enhancement Proposal** + +- EP URL and title +- Key API requirements extracted +- Any ambiguities resolved during generation + +**PR #1: API Type Definitions** + +- API group, version, kind generated +- Types and fields added or modified +- FeatureGate registration (if applicable) +- Integration tests generated and coverage +- Review verdict and any concerns +- PR URL and status + +**PR #2: Controller Implementation** + +- Framework detected (controller-runtime vs library-go) +- Reconciliation workflow implemented +- Dependent resources managed +- RBAC permissions generated +- Review verdict and any concerns +- PR URL and status + +**PR #3: E2E Tests** + +- Test format (Ginkgo vs bash) +- Test coverage (which scenarios) +- Review verdict and any concerns +- PR URL and status + +**Convention Deviations** + +- Any places where the EP conflicted with OpenShift/Kubernetes API conventions +- What was generated instead and why + +**Outstanding Items** + +- Assumptions made without user confirmation +- Review concerns that are still outstanding +- Known limitations or edge cases not covered +- Follow-up work recommended + +### Step 4: Present the Summary + +Present the summary directly to the user using this structure: + +```markdown +## Operator Feature Dev Summary + +**Enhancement Proposal:** [EP URL and title] +**Status:** [where the workflow stopped — e.g., "All 3 PRs created", "PR #1 created, PR #2 in progress"] + +### PRs Created +- PR #1 (API Types): [URL or "not created"] +- PR #2 (Controller): [URL or "not created"] +- PR #3 (E2E Tests): [URL or "not created"] + +### Key Findings +- [The most important things the user should know — 3-5 bullet points max] + +### Decisions Made +- [Any choices made during generation, especially convention deviations or EP ambiguity resolutions] + +### Outstanding Concerns +- [Review caveats, untested edge cases, unconfirmed assumptions — or "None"] + +### Artifacts +- [List of all artifact files with one-line descriptions] +``` + +Keep it tight. The value of this summary is density — if it's as long as the +artifacts themselves, it's not a summary. + +### Step 5: Write the Summary Artifact + +Save the summary to `artifacts/operator-feature-dev/summary.md`. + +## Rules + +- **Read, don't assume.** Base everything on what the artifacts actually say, + not on what you think happened during the workflow. +- **Flag what's missing.** If a phase was skipped or an artifact is absent, + say so. "No E2E tests were generated" is useful information. +- **Don't editorialize.** Report what the artifacts say. If the review flagged + a concern, include it. Don't soften it. +- **Keep it short.** The whole point is that nobody reads the full artifacts. + If your summary is more than ~50 lines of Markdown, cut it down. + +## Output + +- Summary presented directly to the user (inline) +- Summary saved to `artifacts/operator-feature-dev/summary.md` + +## When This Phase Is Done + +The summary is the deliverable. Present it and stop — there is no next phase +to recommend. diff --git a/ambient-workflows/workflows/operator-feature-dev/CLAUDE.md b/ambient-workflows/workflows/operator-feature-dev/CLAUDE.md new file mode 100644 index 0000000..06347ab --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/CLAUDE.md @@ -0,0 +1,71 @@ +# Operator Feature Dev Workflow + +Multi-PR OpenShift operator feature development from Enhancement Proposals: + +1. **Init** (`/oape.init`) — Clone repo, validate operator, detect framework +2. **API Generate** (`/oape.api-generate`) — Generate API type definitions from EP +3. **API Generate Tests** (`/oape.api-generate-tests`) — Generate integration tests for API types +4. **Review** (`/oape.review`) — Review and auto-fix issues +5. **PR** (`/oape.pr`) — Create pull request +6. **API Implement** (`/oape.api-implement`) — Generate controller/reconciler code +7. **E2E Generate** (`/oape.e2e-generate`) — Generate E2E test artifacts +8. **Speedrun** (`/oape.speedrun`) — Run all remaining phases without stopping +9. **Summary** — Synthesize all artifacts into a final status report + +Commands handle atomic operations. The controller skill manages phase +transitions and recommendations. The speedrun command runs all remaining +phases autonomously. Artifacts go in `artifacts/operator-feature-dev/`. + +## Principles + +- Show code, not concepts. Link to `file:line`, not abstract descriptions. +- Derive from conventions, not memory. Fetch and read OpenShift/Kubernetes API conventions on every run. +- Never guess. If the Enhancement Proposal is ambiguous about API details, stop and ask. +- Be thorough and complete: When generating API types, search for all existing types in the package and match style exactly. +- Don't assume tools are missing. Check for version managers (`uv`, `pyenv`, `nvm`) before concluding a runtime isn't available. + +## Hard Limits + +- No direct commits to `main` — always use feature branches +- No token or secret logging — use `len(token)`, redact in logs +- No force-push, hard reset, or destructive git operations +- No modifying security-critical code without human review +- No skipping CI checks (`--no-verify`, `--no-gpg-sign`) +- Never generate code with TODOs — produce production-ready implementations +- Never hardcode operator-specific values — discover from the repository + +## Safety + +- Show your plan with TodoWrite before executing +- Indicate confidence: High (90-100%), Medium (70-89%), Low (<70%) +- Flag risks and assumptions upfront +- Provide rollback instructions for every change + +## Quality + +- Follow the project's existing coding standards and conventions +- Zero tolerance for test failures — fix them, don't skip them +- Conventional commits: `type(scope): description` +- All PRs include EP reference (e.g., `Ref: openshift/enhancements#1234`) + +## Escalation + +Stop and request human guidance when: + +- Enhancement Proposal is ambiguous about API design +- Multiple valid API approaches exist with unclear trade-offs +- Convention-compliant design conflicts with EP requirements +- An architectural decision is required +- The change affects API contracts or introduces breaking changes +- A security or compliance concern arises +- Confidence on the proposed approach is below 80% + +## Working With the Project + +This workflow gets deployed into different operator repos. Respect the target project: + +- Read and follow the project's own `CLAUDE.md` if one exists +- Adopt the project's coding style, not your own preferences +- Match existing controller patterns exactly +- Use the project's existing test framework and patterns +- When in doubt about project conventions, check git history and existing code diff --git a/ambient-workflows/workflows/operator-feature-dev/README.md b/ambient-workflows/workflows/operator-feature-dev/README.md new file mode 100644 index 0000000..1737473 --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/README.md @@ -0,0 +1,127 @@ +# Operator Feature Dev Workflow + +Multi-PR OpenShift operator feature development from Enhancement Proposals. Takes an EP URL and generates a complete implementation across 3 Pull Requests. + +## What It Does + +Given an Enhancement Proposal PR URL and an operator repository URL, this workflow generates: + +1. **PR #1 — API Type Definitions**: Go type definitions with markers, validation, godoc, FeatureGate registration, and `.testsuite.yaml` integration tests +2. **PR #2 — Controller Implementation**: Complete controller/reconciler code with reconciliation logic, dependent resource management, RBAC markers, and status handling +3. **PR #3 — E2E Tests**: End-to-end test artifacts (test cases, execution steps, and Ginkgo/bash test code) based on git diff + +## Directory Structure + +```text +workflows/operator-feature-dev/ +├── .ambient/ +│ └── ambient.json # Workflow configuration +├── .claude/ +│ ├── commands/ # Atomic, argument-driven operations +│ │ ├── oape.init.md # Clone and validate operator repo +│ │ ├── oape.api-generate.md # Generate API types from EP +│ │ ├── oape.api-generate-tests.md # Generate integration tests +│ │ ├── oape.api-implement.md # Generate controller/reconciler +│ │ ├── oape.e2e-generate.md # Generate E2E test artifacts +│ │ ├── oape.review.md # Code review with auto-fix +│ │ ├── oape.pr.md # Create pull request +│ │ └── oape.speedrun.md # Autonomous full pipeline +│ └── skills/ # Orchestration + cross-cutting +│ ├── controller/SKILL.md # Phase transition orchestrator +│ ├── effective-go/SKILL.md # Go best practices +│ └── summary/SKILL.md # Final synthesis +├── CLAUDE.md # Hard limits and safety rules +└── README.md +``` + +## Quick Start + +1. Start the workflow in ACP +2. Provide an Enhancement Proposal PR URL and operator repo URL +3. The controller guides you through each phase, or use `/oape.speedrun` for autonomous execution + +### Example Session + +```text +User: I want to implement EP https://github.com/openshift/enhancements/pull/1234 + in https://github.com/openshift/cert-manager-operator, base branch main + +Atlas: [runs /oape.init, then guides through each phase] +``` + +### Speedrun (Autonomous) + +```text +/oape.speedrun https://github.com/openshift/enhancements/pull/1234 https://github.com/openshift/cert-manager-operator main +``` + +## Commands + +| Command | Arguments | Purpose | +| --- | --- | --- | +| `/oape.init` | ` ` | Clone repo, detect framework | +| `/oape.api-generate` | ` [--design-doc ]` | Generate API type definitions | +| `/oape.api-generate-tests` | `` | Generate integration tests | +| `/oape.api-implement` | ` [--design-doc ]` | Generate controller/reconciler | +| `/oape.e2e-generate` | `` | Generate E2E test artifacts | +| `/oape.review` | `` | Code review with auto-fix | +| `/oape.pr` | `` | Create draft pull request | +| `/oape.speedrun` | ` ` | Run all phases autonomously | + +## Workflow Phases + +```text +PR #1: /oape.init → /oape.api-generate → /oape.api-generate-tests → /oape.review → /oape.pr +PR #2: /oape.api-implement → /oape.review → /oape.pr +PR #3: /oape.e2e-generate → /oape.review → /oape.pr +Final: summary skill +``` + +## Artifacts + +All artifacts are written to `artifacts/operator-feature-dev/`: + +```text +artifacts/operator-feature-dev/ +├── init-summary.md +├── api/ +│ ├── generation-summary.md +│ ├── test-generation-summary.md +│ ├── review-verdict.md +│ └── pr-description.md +├── impl/ +│ ├── implementation-summary.md +│ ├── review-verdict.md +│ └── pr-description.md +├── e2e/ +│ ├── test-cases.md +│ ├── execution-steps.md +│ ├── e2e-suggestions.md +│ ├── generation-summary.md +│ ├── review-verdict.md +│ └── pr-description.md +└── summary.md +``` + +## Prerequisites + +- `git` — Git installed +- `go` — Go toolchain installed +- `gh` — GitHub CLI installed and authenticated +- Access to `openshift/enhancements` repository +- Target operator repository must be a Go-based OpenShift operator + +## Supported Frameworks + +- **controller-runtime** (kubebuilder/operator-sdk) — most common +- **library-go** (OpenShift core operators) — uses SyncFunc pattern + +## Testing + +Use the ACP "Custom Workflow" feature to test without merging: + +| Field | Value | +| --- | --- | +| **URL** | Your fork's git URL | +| **Branch** | Your branch name | +| **Path** | `workflows/operator-feature-dev` | From fc70a373415b3af4f33712842577005b910f7e64 Mon Sep 17 00:00:00 2001 From: Swarup Ghosh Date: Thu, 7 May 2026 14:53:42 +0530 Subject: [PATCH 2/2] symlink redundant files --- .../.claude/commands/SKILL.md | 1 + .../commands/oape.api-generate-tests.md | 313 +--------- .../.claude/commands/oape.api-generate.md | 416 +------------ .../.claude/commands/oape.api-implement.md | 548 +----------------- .../.claude/commands/oape.e2e-generate.md | 332 +---------- .../.claude/commands/oape.init.md | 197 +------ .../.claude/commands/oape.review.md | 203 +------ .../.claude/skills/effective-go/SKILL.md | 126 +--- 8 files changed, 8 insertions(+), 2128 deletions(-) create mode 120000 ambient-workflows/workflows/operator-feature-dev/.claude/commands/SKILL.md mode change 100644 => 120000 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate-tests.md mode change 100644 => 120000 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate.md mode change 100644 => 120000 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-implement.md mode change 100644 => 120000 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.e2e-generate.md mode change 100644 => 120000 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.init.md mode change 100644 => 120000 ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.review.md mode change 100644 => 120000 ambient-workflows/workflows/operator-feature-dev/.claude/skills/effective-go/SKILL.md diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/SKILL.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/SKILL.md new file mode 120000 index 0000000..eb2943c --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/SKILL.md @@ -0,0 +1 @@ +../../../../../../plugins/oape/skills/effective-go/SKILL.md \ No newline at end of file diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate-tests.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate-tests.md deleted file mode 100644 index bbcfed3..0000000 --- a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate-tests.md +++ /dev/null @@ -1,312 +0,0 @@ -# /oape.api-generate-tests - Generate integration tests for API types - -## Purpose - -Generate `.testsuite.yaml` integration test files for OpenShift API type -definitions. Reads Go type definitions, CRD manifests, and validation markers -to produce comprehensive test suites covering create, update, validation, and -error scenarios. - -This command should be run AFTER API types and CRD manifests have been generated. - -## Arguments - -- `$ARGUMENTS`: `` - -## Process - -### Phase 0: Prechecks - -All prechecks must pass before proceeding. If ANY fails, STOP immediately. - -#### Precheck 1 -- Verify Repository and Tools - -```bash -if ! git rev-parse --is-inside-work-tree &> /dev/null 2>&1; then - echo "PRECHECK FAILED: Not inside a git repository." - exit 1 -fi - -REPO_ROOT=$(git rev-parse --show-toplevel) - -if [ ! -f "$REPO_ROOT/go.mod" ]; then - echo "PRECHECK FAILED: No go.mod found at repository root." - exit 1 -fi - -GO_MODULE=$(head -1 "$REPO_ROOT/go.mod" | awk '{print $2}') -echo "Repository root: $REPO_ROOT" -echo "Go module: $GO_MODULE" -``` - -#### Precheck 2 -- Identify Target API Types - -```bash -TARGET_PATH="$ARGUMENTS" - -if [ -z "$TARGET_PATH" ]; then - echo "PRECHECK FAILED: No target path provided." - echo "Usage: /oape.api-generate-tests " - exit 1 -fi -``` - -```thinking -Determine which API types to generate tests for: -1. User provided a specific types file path -> use it directly -2. User provided an API directory -> find all types files in it - -Extract: API group, version, kind, resource plural, all fields with types, -validation markers, and godoc. -``` - -#### Precheck 3 -- Verify CRD Manifests Exist - -```bash -# For openshift/api repos -find "$REPO_ROOT" -type d -name 'zz_generated.crd-manifests' -not -path '*/vendor/*' | head -5 - -# For operator repos -find "$REPO_ROOT" -type d -name 'bases' -path '*/crd/*' -not -path '*/vendor/*' | head -5 -``` - -If no CRD manifests found: - -```text -WARNING: No CRD manifests found. Run 'make update' or 'make manifests' first. -Test suites reference CRD manifests -- tests will fail without them. -``` - ---- - -### Phase 1: Read API Types and CRD Manifests - -Read the target Go types file(s) and extract all information needed for test -generation: - -```thinking -From the Go types, extract every field, type, marker, and validation rule: -1. Top-level CRD types (structs with +kubebuilder:object:root=true or +genclient) -2. For each CRD type: kind, API group, version, resource plural, scope, singleton -3. Every spec and status field: name, type, optional/required, pointer semantics -4. All validation markers: enums, min/max, minLength/maxLength, minItems/maxItems, - pattern, format, XValidation CEL rules -5. Enum types and allowed values -6. Discriminated unions: discriminator field, member types -7. Immutable fields (XValidation rules referencing oldSelf) -8. Default values -9. Feature gate annotations (+openshift:enable:FeatureGate) -10. Nested object validation -11. Map key/value constraints -12. Any other kubebuilder or OpenShift marker - -The list above is guidance, not exhaustive. Extract ALL markers found. -``` - -Also read CRD manifest(s) to get: full CRD name, OpenAPI v3 schema, feature -set annotations. - -### Phase 2: Identify Test Directory and Existing Tests - -Determine where test files should be placed: - -**openshift/api:** - -```text -//tests/./ -``` - -**Operator repos:** - -```text -api//tests/./ -``` - -or - -```text -api///tests/./ -``` - -Check for existing test files to avoid duplicating tests. - -### Phase 3: Generate Test Suites - -Generate `.testsuite.yaml` files covering these categories. Derive specific test -cases from the types and validation rules read in Phase 1. - -#### Category 1 -- Minimal Valid Create - -Every test suite MUST include at least one test that creates a minimal valid -instance with only required fields populated. - -#### Category 2 -- Valid Field Values - -For each field in the spec: - -- Test that valid values are accepted and persisted correctly -- For enum fields: test each allowed enum value -- For optional fields: test with and without the field -- For fields with defaults: verify the default is applied - -#### Category 3 -- Invalid Field Values (Validation Failures) - -For each field with validation rules: - -- Enum fields: test a value not in the allowed set -> `expectedError` -- Pattern fields: test a value that doesn't match -> `expectedError` -- Min/max constraints: test values at and beyond boundaries -> `expectedError` -- Required fields: test omission -> `expectedError` -- CEL validation rules: test inputs that violate each rule -> `expectedError` - -#### Category 4 -- Update Scenarios - -For fields that can be updated: - -- Test valid updates (change field value) -> `expected` -- For immutable fields: test that updates are rejected -> `expectedError` -- For fields with update-specific validation: test boundary cases - -#### Category 5 -- Singleton Name Validation - -If the CRD is a cluster-scoped singleton (name must be "cluster"): - -- Test creation with `resourceName: cluster` -> success -- Test creation with `resourceName: not-cluster` -> `expectedError` - -#### Category 6 -- Discriminated Unions - -If the type uses discriminated unions: - -- Test each valid discriminator + member combination -> `expected` -- Test mismatched discriminator + member -> `expectedError` -- Test missing required member -> `expectedError` - -#### Category 7 -- Feature-Gated Fields - -If fields are gated behind a FeatureGate: - -- Stable/default test suite: setting gated field is rejected -> `expectedError` -- TechPreview test suite: gated field is accepted -> `expected` - -#### Category 8 -- Status Subresource - -If the type has a status subresource: - -- Test valid status updates -- Test invalid status updates -> `expectedStatusError` - -#### Category 9 -- Additional Coverage - -```thinking -Re-examine every marker, annotation, CEL rule, godoc comment, and structural -detail. Ask: is there any validation behavior or edge case NOT already covered? - -Examples: cross-field dependencies, mutually exclusive fields, nested object -validation, list item uniqueness, map key/value constraints, string format -validations, complex CEL rules, defaulting interactions, zero values vs nil. -``` - -### Phase 4: Write Test Suite Files - -Write `.testsuite.yaml` file(s) following this format: - -```yaml -apiVersion: apiextensions.k8s.io/v1 -name: "" -crdName: . -tests: - onCreate: - - name: Should be able to create a minimal - initial: | - apiVersion: / - kind: - spec: {} - expected: | - apiVersion: / - kind: - spec: {} - - name: Should reject with invalid - initial: | - apiVersion: / - kind: - spec: - : - expectedError: "" - onUpdate: - - name: Should not allow changing immutable field - initial: | - apiVersion: / - kind: - spec: - : - updated: | - apiVersion: / - kind: - spec: - : - expectedError: "" -``` - -#### File Naming Conventions - -Derive from existing patterns: - -**openshift/api repos:** - -- `stable..testsuite.yaml` -- `techpreview..testsuite.yaml` -- `stable...testsuite.yaml` - -**Operator repos:** - -- `.testsuite.yaml` - -### Phase 5: Output Summary - -Write `artifacts/operator-feature-dev/api/test-generation-summary.md`: - -```text -=== API Test Generation Summary === - -Target API: / -CRD Name: . - -Generated Test Files: - - -- onCreate tests, onUpdate tests - -Test Coverage: - onCreate: - - Minimal valid create - - : valid values ( tests) - - : invalid values ( tests) - - Singleton name validation - onUpdate: - - Immutable field : rejected - - Valid update for - -Next Steps: - 1. Review the generated test suites - 2. Run the integration tests - 3. Verify coverage: make verify - 4. Add additional edge-case tests as needed -``` - -## Behavioral Rules - -1. **Derive from source**: All test values and expectations MUST come from - actual Go types, validation markers, and CRD manifests. -2. **Match existing style**: If the repo has test suites, match their naming, - formatting, and detail level exactly. -3. **Comprehensive but focused**: Test every field and validation rule found, - but don't invent scenarios not supported by the schema. -4. **Error messages**: For `expectedError` fields, use substrings from the - actual CRD validation rules. -5. **Minimal YAML**: Include only fields relevant to each specific test case. -6. **Surgical additions**: When adding to an existing suite, preserve all - existing tests and append new ones. - -## Output - -- Generated `.testsuite.yaml` files in the appropriate test directory -- Summary saved to `artifacts/operator-feature-dev/api/test-generation-summary.md` diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate-tests.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate-tests.md new file mode 120000 index 0000000..d407c5b --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate-tests.md @@ -0,0 +1 @@ +../../../../../plugins/oape/commands/api-generate-tests.md \ No newline at end of file diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate.md deleted file mode 100644 index 92d133a..0000000 --- a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate.md +++ /dev/null @@ -1,415 +0,0 @@ -# /oape.api-generate - Generate API type definitions from an Enhancement Proposal - -## Purpose - -Read an OpenShift Enhancement Proposal PR and/or a design document, extract the -required API changes, and generate compliant Go type definitions in the correct -paths of the current operator repository. Refreshes API conventions from -authoritative sources on every run. - -## Arguments - -- `$ARGUMENTS`: ` [--design-doc ]` - -At least one input source (EP or design document) must be provided. When both -are provided, the design document takes precedence for implementation details. - -## Process - -### Phase 0: Prechecks - -All prechecks must pass before proceeding. If ANY fails, STOP immediately. - -#### Precheck 1 -- Parse and Validate Input Arguments - -```bash -ARGS="$ARGUMENTS" -ENHANCEMENT_PR="" -DESIGN_DOC_URL="" -ENHANCEMENT_PR_NUMBER="" - -# Extract --design-doc argument if present -if echo "$ARGS" | grep -q '\-\-design-doc'; then - DESIGN_DOC_URL=$(echo "$ARGS" | sed -n 's/.*--design-doc[[:space:]]\+\([^[:space:]]\+\).*/\1/p') - ENHANCEMENT_PR=$(echo "$ARGS" | sed 's/--design-doc[[:space:]]\+[^[:space:]]\+//' | xargs) -else - ENHANCEMENT_PR="$ARGS" -fi - -if [ -z "$ENHANCEMENT_PR" ] && [ -z "$DESIGN_DOC_URL" ]; then - echo "PRECHECK FAILED: No input provided." - echo "Usage: /oape.api-generate [--design-doc ]" - exit 1 -fi - -if [ -n "$ENHANCEMENT_PR" ]; then - if ! echo "$ENHANCEMENT_PR" | grep -qE '^https://github\.com/openshift/enhancements/pull/[0-9]+/?$'; then - echo "PRECHECK FAILED: Invalid enhancement PR URL." - echo "Expected: https://github.com/openshift/enhancements/pull/" - echo "Got: $ENHANCEMENT_PR" - exit 1 - fi - ENHANCEMENT_PR_NUMBER=$(echo "$ENHANCEMENT_PR" | grep -oE '[0-9]+$') - echo "Enhancement PR #$ENHANCEMENT_PR_NUMBER validated." -fi - -if [ -n "$DESIGN_DOC_URL" ]; then - if ! echo "$DESIGN_DOC_URL" | grep -qE '^https://gist\.github(usercontent)?\.com/'; then - echo "PRECHECK FAILED: Invalid design document URL." - echo "Expected: https://gist.github.com/[username/]" - echo "Got: $DESIGN_DOC_URL" - exit 1 - fi - echo "Design document URL validated: $DESIGN_DOC_URL" -fi -``` - -#### Precheck 2 -- Verify Required Tools - -```bash -MISSING_TOOLS="" - -if ! command -v gh &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS gh"; fi -if ! command -v go &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS go"; fi -if ! command -v git &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS git"; fi - -if [ -n "$MISSING_TOOLS" ]; then - echo "PRECHECK FAILED: Missing required tools:$MISSING_TOOLS" - exit 1 -fi - -if ! gh auth status &> /dev/null 2>&1; then - echo "PRECHECK FAILED: GitHub CLI is not authenticated." - echo "Run 'gh auth login' to authenticate." - exit 1 -fi - -echo "All required tools are available and authenticated." -``` - -#### Precheck 3 -- Verify Current Repository - -```bash -if ! git rev-parse --is-inside-work-tree &> /dev/null 2>&1; then - echo "PRECHECK FAILED: Not inside a git repository." - exit 1 -fi - -REPO_ROOT=$(git rev-parse --show-toplevel) - -if [ ! -f "$REPO_ROOT/go.mod" ]; then - echo "PRECHECK FAILED: No go.mod found at repository root." - exit 1 -fi - -GO_MODULE=$(head -1 "$REPO_ROOT/go.mod" | awk '{print $2}') -echo "Go module: $GO_MODULE" - -if grep -q "github.com/openshift/api" "$REPO_ROOT/go.mod"; then - echo "Confirmed: Repository depends on github.com/openshift/api" -elif echo "$GO_MODULE" | grep -q "github.com/openshift/api"; then - echo "Confirmed: This IS the openshift/api repository." -else - echo "PRECHECK FAILED: Not an OpenShift operator repository." - echo "go.mod does not reference github.com/openshift/api." - exit 1 -fi -``` - -#### Precheck 4 -- Verify Enhancement PR is Accessible (if provided) - -```bash -if [ -n "$ENHANCEMENT_PR_NUMBER" ]; then - PR_STATE=$(gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json state --jq '.state' 2>/dev/null) - - if [ -z "$PR_STATE" ]; then - echo "PRECHECK FAILED: Unable to access enhancement PR #$ENHANCEMENT_PR_NUMBER." - exit 1 - fi - - PR_TITLE=$(gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json title --jq '.title') - echo "Enhancement PR #$ENHANCEMENT_PR_NUMBER: $PR_TITLE ($PR_STATE)" -fi -``` - -#### Precheck 5 -- Verify Design Document is Accessible (if provided) - -```bash -if [ -n "$DESIGN_DOC_URL" ]; then - GIST_ID=$(echo "$DESIGN_DOC_URL" | grep -oE '[a-f0-9]{32}' | head -1) - - if [ -z "$GIST_ID" ]; then - GIST_ID=$(echo "$DESIGN_DOC_URL" | sed 's|.*/||' | sed 's|[?#].*||') - fi - - if [ -z "$GIST_ID" ]; then - echo "PRECHECK FAILED: Could not extract gist ID from URL." - exit 1 - fi - - GIST_INFO=$(gh api "gists/$GIST_ID" --jq '.description // "Untitled"' 2>/dev/null) - - if [ -z "$GIST_INFO" ]; then - echo "PRECHECK FAILED: Unable to access design document gist." - exit 1 - fi - - echo "Design document gist verified: $GIST_INFO" -fi -``` - -#### Precheck 6 -- Verify Clean Working Tree (Warning) - -```bash -if ! git diff --quiet || ! git diff --cached --quiet; then - echo "WARNING: Uncommitted changes detected." - git status --short -else - echo "Working tree is clean." -fi -``` - -**If ALL prechecks passed, proceed to Phase 1.** - ---- - -### Phase 1: Refresh Knowledge -- Fetch Latest API Conventions - -Fetch and read BOTH documents in full BEFORE generating any code. Never rely on -cached knowledge. - -1. **OpenShift API Conventions**: `https://raw.githubusercontent.com/openshift/enhancements/master/dev-guide/api-conventions.md` -2. **Kubernetes API Conventions**: `https://raw.githubusercontent.com/kubernetes/community/master/contributors/devel/sig-architecture/api-conventions.md` - -```thinking -Read both fetched convention documents in full. Extract every rule that applies -to API type generation: field markers, naming, documentation, validation, -pointers, unions, enums, TechPreview gating, etc. The fetched documents are the -single source of truth. If conventions have been updated since this command was -written, the freshly fetched versions take precedence. -``` - -### Phase 2: Fetch and Analyze Input Sources - -#### 2.1 Fetch Enhancement Proposal (if provided) - -```bash -if [ -n "$ENHANCEMENT_PR_NUMBER" ]; then - gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json files --jq '.files[].path' -fi -``` - -Fetch full content of each proposal file using the PR ref: - -```bash -gh api "repos/openshift/enhancements/contents/?ref=refs/pull/$ENHANCEMENT_PR_NUMBER/head" --jq '.content' | base64 -d -``` - -Fallbacks if above fails: - -```bash -# Fallback 1: Raw content -curl -sL "https://raw.githubusercontent.com/openshift/enhancements/refs/pull/$ENHANCEMENT_PR_NUMBER/head/" - -# Fallback 2: PR diff -gh pr diff "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements -``` - -#### 2.2 Fetch Design Document (if provided) - -```bash -if [ -n "$GIST_ID" ]; then - gh api "gists/$GIST_ID" --jq '.files | to_entries[] | "=== FILE: \(.key) ===\n\(.value.content)\n"' -fi -``` - -#### 2.3 Analyze and Merge Requirements - -```thinking -Extract from the combined sources: - a. Which operator/component is being modified - b. API group and version - c. Whether this is NEW or modifications to EXISTING types - d. Configuration API vs Workload API - e. Fields being added or modified - f. Validation requirements (enums, patterns, min/max, cross-field) - g. TechPreview gating - h. Discriminated unions - i. Defaulting behavior - j. Immutability requirements - k. Status fields and conditions - l. FeatureGate name - -Design document takes precedence over EP for implementation details. -If conflicts are ambiguous, ask the user. -``` - -### Phase 3: Identify Target API Paths - -Detect the repository layout pattern: - -#### Known Layout Patterns - -**Pattern 1 -- openshift/api repository:** - -```text -//types_.go -//doc.go -//register.go -//tests//*.testsuite.yaml -features/features.go -``` - -**Pattern 2 -- Operator repo with group subdirectory:** - -```text -api///_types.go -api///groupversion_info.go -``` - -**Pattern 3 -- Operator repo with flat version directory:** - -```text -api//_types.go -api//groupversion_info.go -``` - -#### Detect the Pattern - -```bash -# Find type definition files -find "$REPO_ROOT" -type f \( -name 'types*.go' -o -name '*_types.go' \) \ - -not -path '*/vendor/*' -not -path '*/_output/*' -not -path '*/zz_generated*' | head -40 - -# Find registration files -find "$REPO_ROOT" -type f \( -name 'doc.go' -o -name 'register.go' -o -name 'groupversion_info.go' \) \ - -not -path '*/vendor/*' | head -40 - -# Find CRD manifests -find "$REPO_ROOT" -type f -name '*.crd.yaml' -not -path '*/vendor/*' | head -20 - -# Find test suites -find "$REPO_ROOT" -type f -name '*.testsuite.yaml' -not -path '*/vendor/*' | head -20 - -# Find feature gate definitions -find "$REPO_ROOT" -type f -name 'features.go' -not -path '*/vendor/*' | head -10 -``` - -### Phase 4: Read Existing API Types for Context - -Read existing types in the target package to match style exactly: - -```thinking -Read existing types file(s) to: -1. Match coding style exactly -2. Understand existing struct hierarchy -3. Know where to insert new fields or types -4. Identify existing fields that need modification -5. Identify existing imports to reuse -6. See how feature gates are applied -7. Understand existing validation patterns -``` - -### Phase 5: Generate or Modify API Type Definitions - -Generate or modify Go type definitions based on the input sources. This may -include new types, new fields, modifications to existing fields, enum types, -discriminated unions, or type registration. - -For every marker, tag, or convention applied: derive it from the fetched -convention documents (Phase 1) or existing code (Phase 4). Conventions take -precedence when both differ. - -Determine whether this is a **Configuration API** or **Workload API** -- the -conventions define different rules for each. - -After generating, review every changed line against conventions. If any -violation has a convention-compliant alternative, apply it and note the -deviation in the summary. - -### Phase 6: Add FeatureGate Registration (if applicable) - -If the repository contains a `features.go` file, read it and add a new -FeatureGate following the existing pattern. - -If no `features.go` exists and the enhancement requires a FeatureGate, note -this in the summary and advise where to register it. - -### Phase 7: Output Summary - -Write `artifacts/operator-feature-dev/api/generation-summary.md`: - -```text -=== API Generation Summary === - -Input Sources: - Enhancement PR: (if provided) - Design Document: (if provided) - -Generated/Modified Files: - - -- - - -- (if applicable) - -API Group: -API Version: -Kind: -Resource: -Scope: -FeatureGate: - -New Types Added: - - -- - -New Fields Added: - - . () -- - -Modified Fields/Types: - - . -- - -Validation Rules: - - : - -Source Conflicts Resolved: (if both EP and design doc provided) - - : Used design doc specification () - -Next Steps: - 1. Review the generated code - 2. Run 'make update' to regenerate CRDs and deep copy functions - 3. Run 'make verify' to validate generated code - 4. Run 'make lint' to check for kube-api-linter issues - 5. If FeatureGate was added, verify it appears in the feature gate list -``` - -## Critical Failure Conditions - -1. **No input provided**: Neither EP URL nor design document URL -2. **Invalid PR URL**: Not a valid `openshift/enhancements` PR -3. **Invalid gist URL**: Not a valid GitHub Gist -4. **Missing tools**: `gh`, `go`, or `git` not installed or `gh` unauthenticated -5. **Not an operator repo**: Not a Git repository with Go module referencing - `openshift/api` -6. **Input not accessible**: EP or design document cannot be fetched -7. **No API changes found**: Input sources don't describe API changes -8. **Ambiguous API target**: Cannot determine target API group, version, or kind - -## Behavioral Rules - -1. **Never guess**: If input sources are ambiguous about API details, STOP and - ask the user. -2. **Design document precedence**: Design document takes precedence for - implementation details. -3. **Convention over proposal**: If input sources suggest an API design that - violates conventions (e.g., using a Boolean), generate the - convention-compliant alternative and document the deviation. -4. **TechPreview when specified**: If input sources indicate TechPreview gating, - generate the appropriate FeatureGate markers. -5. **Idempotent**: Running multiple times with the same inputs should produce - the same result. -6. **Minimal changes**: Only generate what the input sources specify. -7. **Surgical edits**: When modifying existing files, preserve all unrelated - code, comments, and formatting. - -## Output - -- Generated/modified Go type files in the operator repository -- Summary saved to `artifacts/operator-feature-dev/api/generation-summary.md` diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate.md new file mode 120000 index 0000000..c3e3366 --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-generate.md @@ -0,0 +1 @@ +../../../../../plugins/oape/commands/api-generate.md \ No newline at end of file diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-implement.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-implement.md deleted file mode 100644 index 2ac85ee..0000000 --- a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-implement.md +++ /dev/null @@ -1,547 +0,0 @@ -# /oape.api-implement - Generate controller/reconciler implementation - -## Purpose - -Read an OpenShift Enhancement Proposal PR and/or a design document, extract the -required implementation logic, and generate complete controller/reconciler code -in the correct paths of the current operator repository. Produces -production-ready code with zero TODOs. - -## Arguments - -- `$ARGUMENTS`: ` [--design-doc ]` - -At least one input source (EP or design document) must be provided. When both -are provided, the design document takes precedence for implementation details. - -## Process - -### Phase 0: Prechecks - -All prechecks must pass before proceeding. If ANY fails, STOP immediately. - -#### Precheck 1 -- Parse and Validate Input Arguments - -```bash -ARGS="$ARGUMENTS" -ENHANCEMENT_PR="" -DESIGN_DOC_URL="" -ENHANCEMENT_PR_NUMBER="" - -if echo "$ARGS" | grep -q '\-\-design-doc'; then - DESIGN_DOC_URL=$(echo "$ARGS" | sed -n 's/.*--design-doc[[:space:]]\+\([^[:space:]]\+\).*/\1/p') - ENHANCEMENT_PR=$(echo "$ARGS" | sed 's/--design-doc[[:space:]]\+[^[:space:]]\+//' | xargs) -else - ENHANCEMENT_PR="$ARGS" -fi - -if [ -z "$ENHANCEMENT_PR" ] && [ -z "$DESIGN_DOC_URL" ]; then - echo "PRECHECK FAILED: No input provided." - echo "Usage: /oape.api-implement [--design-doc ]" - exit 1 -fi - -if [ -n "$ENHANCEMENT_PR" ]; then - if ! echo "$ENHANCEMENT_PR" | grep -qE '^https://github\.com/openshift/enhancements/pull/[0-9]+/?$'; then - echo "PRECHECK FAILED: Invalid enhancement PR URL." - echo "Expected: https://github.com/openshift/enhancements/pull/" - echo "Got: $ENHANCEMENT_PR" - exit 1 - fi - ENHANCEMENT_PR_NUMBER=$(echo "$ENHANCEMENT_PR" | grep -oE '[0-9]+$') - echo "Enhancement PR #$ENHANCEMENT_PR_NUMBER validated." -fi - -if [ -n "$DESIGN_DOC_URL" ]; then - if ! echo "$DESIGN_DOC_URL" | grep -qE '^https://gist\.github(usercontent)?\.com/'; then - echo "PRECHECK FAILED: Invalid design document URL." - echo "Expected: https://gist.github.com/[username/]" - echo "Got: $DESIGN_DOC_URL" - exit 1 - fi - echo "Design document URL validated: $DESIGN_DOC_URL" -fi -``` - -#### Precheck 2 -- Verify Required Tools - -```bash -MISSING_TOOLS="" - -if ! command -v gh &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS gh"; fi -if ! command -v go &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS go"; fi -if ! command -v git &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS git"; fi -if ! command -v make &> /dev/null; then MISSING_TOOLS="$MISSING_TOOLS make"; fi - -if [ -n "$MISSING_TOOLS" ]; then - echo "PRECHECK FAILED: Missing required tools:$MISSING_TOOLS" - exit 1 -fi - -if ! gh auth status &> /dev/null 2>&1; then - echo "PRECHECK FAILED: GitHub CLI is not authenticated." - exit 1 -fi - -echo "All required tools are available and authenticated." -``` - -#### Precheck 3 -- Verify Current Repository - -```bash -if ! git rev-parse --is-inside-work-tree &> /dev/null 2>&1; then - echo "PRECHECK FAILED: Not inside a git repository." - exit 1 -fi - -REPO_ROOT=$(git rev-parse --show-toplevel) - -if [ ! -f "$REPO_ROOT/go.mod" ]; then - echo "PRECHECK FAILED: No go.mod found at repository root." - exit 1 -fi - -GO_MODULE=$(head -1 "$REPO_ROOT/go.mod" | awk '{print $2}') -echo "Go module: $GO_MODULE" -``` - -#### Precheck 4 -- Verify Enhancement PR is Accessible (if provided) - -```bash -if [ -n "$ENHANCEMENT_PR_NUMBER" ]; then - PR_STATE=$(gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json state --jq '.state' 2>/dev/null) - - if [ -z "$PR_STATE" ]; then - echo "PRECHECK FAILED: Unable to access enhancement PR #$ENHANCEMENT_PR_NUMBER." - exit 1 - fi - - PR_TITLE=$(gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json title --jq '.title') - echo "Enhancement PR #$ENHANCEMENT_PR_NUMBER: $PR_TITLE ($PR_STATE)" -fi -``` - -#### Precheck 5 -- Verify Design Document is Accessible (if provided) - -```bash -GIST_ID="" - -if [ -n "$DESIGN_DOC_URL" ]; then - GIST_ID=$(echo "$DESIGN_DOC_URL" | grep -oE '[a-f0-9]{32}' | head -1) - - if [ -z "$GIST_ID" ]; then - GIST_ID=$(echo "$DESIGN_DOC_URL" | sed 's|.*/||' | sed 's|[?#].*||') - fi - - if [ -z "$GIST_ID" ]; then - echo "PRECHECK FAILED: Could not extract gist ID from URL." - exit 1 - fi - - GIST_INFO=$(gh api "gists/$GIST_ID" --jq '.description // "Untitled"' 2>/dev/null) - - if [ -z "$GIST_INFO" ]; then - echo "PRECHECK FAILED: Unable to access design document gist." - exit 1 - fi - - echo "Design document gist verified: $GIST_INFO" -fi -``` - -#### Precheck 6 -- Verify API Types Exist - -```bash -API_TYPES=$(find "$REPO_ROOT" -type f \( -name 'types*.go' -o -name '*_types.go' \) \ - -not -path '*/vendor/*' -not -path '*/_output/*' -not -path '*/zz_generated*' | head -20) - -if [ -z "$API_TYPES" ]; then - echo "PRECHECK FAILED: No API type definitions found." - echo "Run /oape.api-generate first to create the API types." - exit 1 -fi - -echo "Found API types:" -echo "$API_TYPES" | head -10 -``` - -#### Precheck 7 -- Verify Clean Working Tree (Warning) - -```bash -if ! git diff --quiet || ! git diff --cached --quiet; then - echo "WARNING: Uncommitted changes detected." - git status --short -else - echo "Working tree is clean." -fi -``` - -**If ALL prechecks passed, proceed to Phase 1.** - ---- - -### Phase 1: Detect Operator Framework - -```bash -echo "Detecting operator framework type..." - -if [ -f "$REPO_ROOT/PROJECT" ]; then - echo "Found PROJECT file (operator-sdk/kubebuilder project)" - cat "$REPO_ROOT/PROJECT" -fi - -echo "Checking go.mod for framework dependencies..." - -if grep -q "github.com/openshift/library-go" "$REPO_ROOT/go.mod"; then - echo "Found: github.com/openshift/library-go" -fi - -if grep -q "sigs.k8s.io/controller-runtime" "$REPO_ROOT/go.mod"; then - echo "Found: sigs.k8s.io/controller-runtime" -fi -``` - -#### Framework Detection Rules - -Apply in order: - -1. **library-go in go.mod AND `pkg/operator/` exists** -> - OPERATOR_TYPE = "library-go" -2. **controller-runtime in go.mod** -> - OPERATOR_TYPE = "controller-runtime" -3. **Neither** -> STOP and ask the user - ---- - -### Phase 2: Refresh Knowledge -- Fetch Operator Conventions - -Fetch and read based on OPERATOR_TYPE: - -**For controller-runtime:** - -1. `https://book.kubebuilder.io/cronjob-tutorial/controller-implementation` -2. `https://pkg.go.dev/sigs.k8s.io/controller-runtime` - -**For library-go:** - -1. `https://github.com/openshift/library-go/tree/master/pkg/controller` -2. `https://github.com/openshift/library-go/blob/master/pkg/operator/events/recorder.go` - -**For all types:** - -1. `https://raw.githubusercontent.com/openshift/enhancements/master/dev-guide/operator.md` - ---- - -### Phase 3: Fetch and Parse Input Sources - -#### 3.1 Fetch Enhancement Proposal (if provided) - -```bash -if [ -n "$ENHANCEMENT_PR_NUMBER" ]; then - gh pr view "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements --json files --jq '.files[].path' -fi -``` - -Fetch full content: - -```bash -gh api "repos/openshift/enhancements/contents/?ref=refs/pull/$ENHANCEMENT_PR_NUMBER/head" --jq '.content' | base64 -d -``` - -Fallbacks: - -```bash -curl -sL "https://raw.githubusercontent.com/openshift/enhancements/refs/pull/$ENHANCEMENT_PR_NUMBER/head/" -gh pr diff "$ENHANCEMENT_PR_NUMBER" --repo openshift/enhancements -``` - -#### 3.2 Fetch Design Document (if provided) - -```bash -if [ -n "$GIST_ID" ]; then - gh api "gists/$GIST_ID" --jq '.files | to_entries[] | "=== FILE: \(.key) ===\n\(.value.content)\n"' -fi -``` - -#### 3.3 Extract Structured Requirements - -```thinking -Extract structured information using this checklist. Design document takes -precedence for implementation details. - -## EXTRACTION CHECKLIST - -### A. API Information (Required) -- API Group, Version, Kind, Resource plural, Scope - -### B. Spec Fields -> Controller Actions (Required) -For EACH spec field: field name, type, controller action, validation, defaults - -### C. Reconciliation Workflow (Required) -Ordered steps for the reconcile loop - -### D. Dependent Resources (Required for complete code) -For EACH: resource type, name pattern, namespace, content/spec, lifecycle - -### E. External Resources / Integrations (If applicable) -External system, API/SDK, operations, credentials handling - -### F. Status Conditions (Required) -Standard OpenShift conditions: Available, Progressing, Degraded -For each: type name, when True/False, reason codes, message templates - -### G. Status Fields (Beyond conditions) -For each: field name, what it represents, how to compute it - -### H. Events to Record (Required) -For each: event type, reason, when to emit, message template - -### I. Error Handling (Required) -Transient errors (retry with backoff), permanent errors (set Degraded) - -### J. Cleanup / Deletion (Required if external resources) -What to clean up, order, finalizer name - -### K. Watches / Triggers (Required for reactive behavior) -For each: resource type, filter, how to map to primary resource - -### L. Feature Gate (If applicable) -Feature gate name, behavior when disabled - -### M. RBAC Requirements (Derived) -Based on all above, compute required permissions - -If ANY required section (A, B, C, F, I) is missing or ambiguous, STOP and ask. -``` - ---- - -### Phase 4: Identify Target Paths for Controller Code - -```bash -find "$REPO_ROOT" -type f -name '*controller*.go' -not -path '*/vendor/*' -not -path '*/_output/*' | head -30 -find "$REPO_ROOT" -type f -name 'main.go' -not -path '*/vendor/*' | head -10 -grep -r "func.*Reconcile\|func.*Sync" "$REPO_ROOT" --include='*.go' -l | grep -v vendor | head -20 -grep -r "SetupWithManager\|AddToManager\|NewController\|factory.New" "$REPO_ROOT" --include='*.go' -l | grep -v vendor | head -20 -find "$REPO_ROOT" -type f -name 'starter.go' -not -path '*/vendor/*' | head -5 -``` - -#### Layout Patterns by OPERATOR_TYPE - -**controller-runtime:** - -| Pattern | Controller Location | Registration | -| --- | --- | --- | -| Standard | `controllers/_controller.go` | `main.go` | -| Internal | `internal/controller/_controller.go` | `cmd/main.go` | -| Nested | `internal/controller//controller.go` | `internal/controller/setup.go` | - -**library-go:** - -| Pattern | Controller Location | Registration | -| --- | --- | --- | -| Standard | `pkg/operator//_controller.go` | `pkg/operator/starter.go` | -| Flat | `pkg/operator/_controller.go` | `pkg/operator/operator.go` | - ---- - -### Phase 5: Read Existing Controller Code for Context - -```bash -if [ "$OPERATOR_TYPE" = "library-go" ]; then - SAMPLE_CONTROLLER=$(find "$REPO_ROOT/pkg" -type f -name '*controller*.go' -not -path '*/vendor/*' -not -name '*_test.go' | head -1) -else - SAMPLE_CONTROLLER=$(find "$REPO_ROOT" -type f -name '*controller*.go' -not -path '*/vendor/*' -not -path '*/_output/*' -not -name '*_test.go' | head -1) -fi -``` - -```thinking -Read existing controller(s) and extract these EXACT patterns to replicate: -1. Package name -2. Import organization and aliases -3. Struct fields -4. Constructor pattern -5. Reconcile/Sync signature -6. Logging style -7. Event recording -8. Status update pattern -9. Condition helpers -10. Resource creation -11. Error handling and wrapping -12. Constants location -``` - ---- - -### Phase 6: Generate Controller Code - -Based on OPERATOR_TYPE and extracted requirements, generate the controller. - -#### 6.1 For controller-runtime Based Operators - -Generate: `/_controller.go` - -Key components: - -- **RBAC markers** generated dynamically from Phase 3 extraction -- **Reconciler struct** with `client.Client`, `Scheme`, `Recorder` -- **Reconcile method** with actual logic: - 1. Fetch the resource instance - 2. Check for deletion (handle finalizer cleanup) - 3. Add finalizer if needed - 4. Set Progressing condition - 5. Execute main reconciliation logic - 6. Set success conditions and update status -- **reconcile() method** with EP-derived business logic: - 1. Validate spec - 2. Reconcile each dependent resource - 3. Check/update external state (if applicable) - 4. Update observed status -- **Dependent resource reconcilers** for each resource from EP: - - `reconcile()` -- get-or-create with owner references - - `build()` -- construct desired state from spec - - `NeedsUpdate()` -- compare existing vs desired -- **reconcileDelete()** -- cleanup handler with finalizer removal -- **setCondition()** -- status condition helper -- **SetupWithManager()** -- watches for primary and owned resources - -#### 6.2 For library-go Based Operators - -Generate: `pkg/operator//_controller.go` - -Key components: - -- **Controller struct** with client, kubeClient, operatorClient, eventRecorder -- **NewController()** using `factory.New().WithSync().WithInformers()` -- **sync() method** with klog, informer-based gets, status condition updates - via `v1helpers.UpdateStatus()` - ---- - -### Phase 7: Register Controller with Manager - -#### 7.1 For controller-runtime - -Locate `main.go` or `cmd/main.go` and add: - -- Import for the controller package -- Controller setup call in `main()` after manager creation - -#### 7.2 For library-go - -Locate `pkg/operator/starter.go` and add: - -- Import for the new controller package -- Controller construction and registration - ---- - -### Phase 8: Generate Feature Gate Check (if applicable) - -If the enhancement specifies a FeatureGate, add a check at the start of -Reconcile/Sync that returns early when disabled. - ---- - -### Phase 9: Output Summary - -Write `artifacts/operator-feature-dev/impl/implementation-summary.md`: - -```text -=== Controller Implementation Summary === - -Input Sources: - Enhancement PR: (if provided) - Design Document: (if provided) -Operator Type: - -Generated Files: - - -- Main controller implementation - - -- Updated with controller registration - -Controller Details: - Package: - API Group: - API Version: - Kind: - -Reconciliation Workflow: - 1. Validate spec - 2. - ... - N. Update status - -Dependent Resources Managed: - - : -- - -Status Conditions: - - Available: Set True when - - Progressing: Set True during reconciliation - - Degraded: Set True on errors - -Events Recorded: - - Normal/Created, Normal/Updated, Normal/ReconcileComplete - - Warning/ReconcileFailed - -RBAC Permissions Generated: - - /: get, list, watch - - //status: get, update, patch - - : get, list, watch, create, update, patch, delete - - core/events: create, patch - -Watches Configured: - - Primary: - - Owned: - -Cleanup on Deletion: - - Kubernetes resources: owner references - - External resources: - -Feature Gate: (if applicable) - -Next Steps: - 1. Review the generated controller code - 2. Run 'make generate' to update generated code - 3. Run 'make manifests' to update RBAC/CRD manifests - 4. Run 'make build' to verify compilation - 5. Run 'make test' to run unit tests - 6. Run 'make lint' to check for issues -``` - -## Critical Failure Conditions - -1. **No input provided**: Neither EP URL nor design document URL -2. **Invalid PR URL**: Not a valid `openshift/enhancements` PR -3. **Invalid gist URL**: Not a valid GitHub Gist -4. **Missing tools**: `gh`, `go`, `git`, or `make` not installed -5. **Not authenticated**: `gh` not authenticated -6. **Not an operator repo**: No go.mod or unrecognized operator type -7. **No API types**: Types don't exist (run `/oape.api-generate` first) -8. **Input not accessible**: EP or design document cannot be fetched -9. **No implementation requirements**: Input sources don't describe controller - behavior -10. **Ambiguous requirements**: Cannot determine reconciliation workflow -11. **Unsupported framework**: Not controller-runtime or library-go - -## Behavioral Rules - -1. **Never guess**: If input sources are ambiguous, STOP and ask. -2. **Design document precedence**: Design document takes precedence for - implementation details. -3. **Zero TODOs**: Generate actual implementation, not placeholders. -4. **Convention over proposal**: Apply framework best practices even if input - sources differ. -5. **Match existing patterns**: Replicate patterns from existing controllers. -6. **Idempotent reconciliation**: Generated Reconcile() must be idempotent. -7. **Minimal changes**: Only generate what the input sources require. -8. **Surgical edits**: Preserve unrelated code when modifying files. -9. **Status-first**: Always use `Status().Update()` for status changes. -10. **Finalizer safety**: Add before external resources, remove after cleanup. -11. **Event recording**: Record events for user-visible state changes. - -## Output - -- Generated controller code in the operator repository -- Updated manager registration (main.go or starter.go) -- Summary saved to `artifacts/operator-feature-dev/impl/implementation-summary.md` diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-implement.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-implement.md new file mode 120000 index 0000000..0831fe8 --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.api-implement.md @@ -0,0 +1 @@ +../../../../../plugins/oape/commands/api-implement.md \ No newline at end of file diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.e2e-generate.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.e2e-generate.md deleted file mode 100644 index f3f7d8a..0000000 --- a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.e2e-generate.md +++ /dev/null @@ -1,331 +0,0 @@ -# /oape.e2e-generate - Generate E2E test artifacts from git diff - -## Purpose - -Analyze the current OpenShift operator repository and generate all E2E test -artifacts based on the diff between a base branch and HEAD. Produces test cases, -execution steps, E2E test code, and recommendations. - -## Arguments - -- `$ARGUMENTS`: `` — the git branch to diff against (e.g., `main`, `origin/main`) - -## Prerequisites - -- Must be run from within an OpenShift operator repository -- `git`, `go` installed -- Changes must exist between `` and HEAD - -## Process - -### Phase 0: Prechecks - -All prechecks must pass before proceeding. If ANY fails, STOP immediately. - -#### Precheck 1 — Validate Arguments - -```bash -BASE_BRANCH="$1" - -if [ -z "$BASE_BRANCH" ]; then - echo "PRECHECK FAILED: No base branch provided." - echo "Usage: /oape.e2e-generate " - exit 1 -fi - -echo "Base branch: $BASE_BRANCH" -``` - -#### Precheck 2 — Verify Required Tools - -```bash -MISSING_TOOLS="" - -if ! command -v git &> /dev/null; then - MISSING_TOOLS="$MISSING_TOOLS git" -fi - -if ! command -v go &> /dev/null; then - MISSING_TOOLS="$MISSING_TOOLS go" -fi - -if [ -n "$MISSING_TOOLS" ]; then - echo "PRECHECK FAILED: Missing required tools:$MISSING_TOOLS" - exit 1 -fi - -if ! command -v oc &> /dev/null; then - echo "WARNING: oc not found. Generated execution steps require oc to run." -fi - -echo "Required tools available." -``` - -#### Precheck 3 — Verify Repository - -```bash -if ! git rev-parse --is-inside-work-tree &> /dev/null 2>&1; then - echo "PRECHECK FAILED: Not inside a git repository." - exit 1 -fi - -REPO_ROOT=$(git rev-parse --show-toplevel) -echo "Repository root: $REPO_ROOT" - -if [ ! -f "$REPO_ROOT/go.mod" ]; then - echo "PRECHECK FAILED: No go.mod found at repository root." - exit 1 -fi - -GO_MODULE=$(head -1 "$REPO_ROOT/go.mod" | awk '{print $2}') -REPO_NAME=$(basename "$GO_MODULE") -echo "Go module: $GO_MODULE" -echo "Repo name: $REPO_NAME" - -# Detect framework -HAS_CR=false -HAS_LIBGO=false -grep -q "sigs.k8s.io/controller-runtime" "$REPO_ROOT/go.mod" && HAS_CR=true -grep -q "github.com/openshift/library-go" "$REPO_ROOT/go.mod" && HAS_LIBGO=true - -if [ "$HAS_CR" = true ]; then - FRAMEWORK="controller-runtime" -elif [ "$HAS_LIBGO" = true ]; then - FRAMEWORK="library-go" -else - echo "PRECHECK FAILED: Cannot determine operator framework." - exit 1 -fi - -echo "Detected framework: $FRAMEWORK" -``` - -#### Precheck 4 — Validate Git Diff is Non-Empty - -```bash -if ! git rev-parse --verify "$BASE_BRANCH" &> /dev/null 2>&1; then - echo "PRECHECK FAILED: Base branch '$BASE_BRANCH' does not exist." - git branch -a | head -20 - exit 1 -fi - -DIFF_STAT=$(git diff "$BASE_BRANCH"...HEAD --stat 2>/dev/null) - -if [ -z "$DIFF_STAT" ]; then - echo "PRECHECK FAILED: No changes detected between '$BASE_BRANCH' and HEAD." - exit 1 -fi - -echo "Changes detected:" -echo "$DIFF_STAT" -``` - -**If ALL prechecks passed, proceed to Phase 1.** - ---- - -### Phase 1: Framework Detection and Repository Discovery - -All subsequent phases use discovered information — never hardcoded values. - -#### Step 1.1: Discover API Types - -```bash -find "$REPO_ROOT" -type f \( -name '*_types.go' -o -name 'types_*.go' \) \ - -not -path '*/vendor/*' -not -path '*/_output/*' -not -path '*/zz_generated*' | head -40 -``` - -For each types file, extract: API group and version, Kind names, spec/status -fields, condition types, scope (cluster/namespaced). - -If no types files found in repo, check `go.mod` for `github.com/openshift/api` -dependency — types may be external. - -#### Step 1.2: Discover CRDs - -```bash -find "$REPO_ROOT" -type f -name '*.yaml' \( -path '*/crd/*' -o -path '*/crds/*' -o -path '*/manifests/*' \) \ - -not -path '*/vendor/*' | head -30 -``` - -Extract: Kind, group, plural resource name, scope, served versions. - -#### Step 1.3: Discover Existing E2E Test Patterns - -```bash -# Go-based e2e tests -find "$REPO_ROOT" -type f -name '*_test.go' -path '*/e2e/*' -not -path '*/vendor/*' | head -20 - -# Bash-based e2e tests -find "$REPO_ROOT" -type f -name '*.sh' \( -path '*/e2e/*' -o -path '*/hack/e2e*' \) -not -path '*/vendor/*' | head -10 -``` - -If Go tests found with Ginkgo imports: read 1-2 files to understand package -name, import paths, client variables, helper utilities, assertion patterns. - -If bash scripts found: read script to understand test structure. - -If no existing tests: default to Ginkgo for controller-runtime, bash for -library-go. - -#### Step 1.4: Discover Install Mechanism - -```bash -# OLM manifests -find "$REPO_ROOT" -type f -name '*.yaml' \ - \( -path '*/config/manifests/*' -o -path '*/bundle/*' \) \ - -not -path '*/vendor/*' | head -20 - -# Deployment manifests -find "$REPO_ROOT" -type f -name '*.yaml' \ - \( -path '*/config/default/*' -o -path '*/deploy/*' \) \ - -not -path '*/vendor/*' | head -20 -``` - -Extract: package name, channel, CSV name, install namespace. - -#### Step 1.5: Discover Sample CRs - -```bash -find "$REPO_ROOT" -type f -name '*.yaml' \ - \( -path '*/config/samples/*' -o -path '*/examples/*' \) \ - -not -path '*/vendor/*' | head -20 -``` - -#### Step 1.6: Discover Operator Namespace - -Search order: E2E constants file → CSV manifest → namespace YAML → placeholder. - -#### Step 1.7: Discover Controllers - -```bash -find "$REPO_ROOT" -type f -name '*.go' \ - \( -name '*controller*' -o -name '*reconcile*' -o -name 'starter.go' \) \ - -not -path '*/vendor/*' -not -name '*_test.go' | head -20 -``` - -#### Step 1.8: Build Repo Profile - -```thinking -Summarize: framework, Go module, API types, CRDs, E2E pattern, install -mechanism, samples, operator namespace, controllers, managed workloads. -This profile drives all subsequent generation. No hardcoded values. -``` - ---- - -### Phase 2: Analyze Git Diff - -```bash -git diff "$BASE_BRANCH"...HEAD --stat -git diff "$BASE_BRANCH"...HEAD -p -git log "$BASE_BRANCH"...HEAD --oneline -``` - -Categorize each changed file: - -| File Pattern | Category | Test Focus | -| --- | --- | --- | -| `api/**/*_types.go`, `types_*.go` | API Types | New/changed fields, validation | -| `config/crd/**/*.yaml` | CRD Changes | Schema updates | -| `*controller*.go`, `*reconcile*.go` | Controller | Reconciliation logic | -| `config/rbac/*.yaml` | RBAC | Permission changes | -| `config/samples/*.yaml` | Samples | Example CR usage | -| `test/e2e/**` | E2E Tests | Existing patterns (don't duplicate) | - -Map each meaningful change to a specific test scenario. - ---- - -### Phase 3: Generate test-cases.md - -Write `artifacts/operator-feature-dev/e2e/test-cases.md` with: - -- Operator information (repo, framework, API group, managed CRDs, namespace) -- Prerequisites (cluster access, CLI tools, env vars) -- Installation steps (OLM or manual, using discovered values) -- CR deployment steps (using discovered sample CRs) -- Test cases grouped by diff category -- Verification commands -- Cleanup in reverse dependency order - ---- - -### Phase 4: Generate execution-steps.md - -Write `artifacts/operator-feature-dev/e2e/execution-steps.md` with step-by-step -`oc` commands for: prerequisites, environment setup, operator install, CR -deployment, verification, diff-specific tests, cleanup. - ---- - -### Phase 5: Generate E2E Test Code - -#### Path A — Ginkgo (controller-runtime repos) - -Generate `e2e_test.go`: - -- Match existing e2e package name, imports, client variables, helpers -- `Describe`/`Context`/`It` structure with `By("...")` steps -- No suite logic (no BeforeSuite, TestE2E, client setup) -- Each `It` block prefixed with `// Diff-suggested: ` -- Cover both important general scenarios and diff-specific tests - -#### Path B — Bash (library-go repos) - -Generate `e2e_test.sh`: - -- `#!/usr/bin/env bash` with `set -euo pipefail` -- Configuration variables using discovered values -- `test_()` functions for each test case -- `trap cleanup EXIT` -- Each function prefixed with `# Diff-suggested: ` - ---- - -### Phase 6: Generate e2e-suggestions.md - -Write `artifacts/operator-feature-dev/e2e/e2e-suggestions.md` with: - -- Detected operator structure summary -- Changes detected in diff -- Highly recommended scenarios per change -- Optional/nice-to-have scenarios -- Gaps that are hard to test automatically - ---- - -### Phase 7: Output Summary - -Write `artifacts/operator-feature-dev/e2e/generation-summary.md`: - -```text -=== E2E Test Generation Summary === - -Repository: -Framework: -Base Branch: -Changes Analyzed: - -Generated Files: - - artifacts/operator-feature-dev/e2e/test-cases.md - - artifacts/operator-feature-dev/e2e/execution-steps.md - - artifacts/operator-feature-dev/e2e/e2e_test.go (or e2e_test.sh) - - artifacts/operator-feature-dev/e2e/e2e-suggestions.md - -Next Steps: - 1. Review generated test cases and suggestions - 2. Copy e2e test code into the repo's test/e2e/ directory - 3. Adjust placeholder values if any remain - 4. Run tests against a live cluster -``` - -## Behavioral Rules - -1. **Never hardcode**: All operator-specific values must be discovered from the repo -2. **Match existing style**: Generated code must match existing e2e test conventions -3. **Diff-driven focus**: Only generate tests for code that changed -4. **Fail on ambiguity**: If repo structure is ambiguous, STOP and ask -5. **Minimal placeholders**: Replace as many as possible with discovered values -6. **No duplicate suite logic**: For Ginkgo, only generate test blocks -7. **Correct cleanup order**: Always cleanup in reverse dependency order diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.e2e-generate.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.e2e-generate.md new file mode 120000 index 0000000..be126d1 --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.e2e-generate.md @@ -0,0 +1 @@ +../../../../../plugins/oape/commands/e2e-generate.md \ No newline at end of file diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.init.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.init.md deleted file mode 100644 index 8469a2f..0000000 --- a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.init.md +++ /dev/null @@ -1,196 +0,0 @@ -# /oape.init - Clone and validate an operator repository - -## Purpose - -Clone an OpenShift operator Git repository, checkout the specified base branch, -and validate it is a Go-based operator with a recognized framework. This is the -first step in the operator feature development workflow. - -## Arguments - -- `$ARGUMENTS`: ` ` - -## Process - -### Phase 0: Prechecks - -All prechecks must pass before proceeding. If ANY fails, STOP immediately. - -#### Precheck 1 -- Validate Arguments - -Both a git URL and a base branch MUST be provided. - -```bash -GIT_URL=$(echo "$ARGUMENTS" | awk '{print $1}') -BASE_BRANCH=$(echo "$ARGUMENTS" | awk '{print $2}') - -if [ -z "$GIT_URL" ] || [ -z "$BASE_BRANCH" ]; then - echo "PRECHECK FAILED: Both a git URL and a base branch are required." - echo "Usage: /oape.init " - echo "" - echo "Example:" - echo " /oape.init https://github.com/openshift/cert-manager-operator main" - exit 1 -fi - -echo "Git URL: $GIT_URL" -echo "Base branch: $BASE_BRANCH" -``` - -#### Precheck 2 -- Verify Required Tools - -```bash -MISSING_TOOLS="" - -if ! command -v git &> /dev/null; then - MISSING_TOOLS="$MISSING_TOOLS git" -fi - -if [ -n "$MISSING_TOOLS" ]; then - echo "PRECHECK FAILED: Missing required tools:$MISSING_TOOLS" - exit 1 -fi - -echo "Required tools are available." -``` - -**If ALL prechecks passed, proceed to Phase 1.** - ---- - -### Phase 1: Derive Clone Directory - -```bash -CLONE_DIR=$(basename "$GIT_URL" .git) -CLONE_URL="$GIT_URL" - -echo "Clone directory: $CLONE_DIR" -echo "Clone URL: $CLONE_URL" -``` - ---- - -### Phase 2: Clone Repository - -Clone using `git clone --filter=blob:none`. Handle the case where the target -directory already exists. - -```bash -if [ -d "$CLONE_DIR" ]; then - echo "Directory '$CLONE_DIR' already exists." - - EXISTING_REMOTE=$(git -C "$CLONE_DIR" remote get-url origin 2>/dev/null || true) - - if [ -n "$EXISTING_REMOTE" ]; then - # Normalize URLs for comparison - NORM_EXISTING=$(echo "$EXISTING_REMOTE" | sed 's/\.git$//' | sed 's:/$::') - NORM_CLONE=$(echo "$CLONE_URL" | sed 's/\.git$//' | sed 's:/$::') - - if [ "$NORM_EXISTING" = "$NORM_CLONE" ]; then - echo "Existing directory is already a clone of the same repository." - echo "Using existing directory as-is." - else - echo "FAILED: Directory '$CLONE_DIR' exists but points to a different remote." - echo " Expected: $CLONE_URL" - echo " Found: $EXISTING_REMOTE" - echo "" - echo "Options:" - echo " 1. Remove the directory manually: rm -rf $CLONE_DIR" - echo " 2. Use a different working directory" - exit 1 - fi - else - echo "FAILED: Directory '$CLONE_DIR' exists but is not a git repository." - echo "" - echo "Options:" - echo " 1. Remove the directory manually: rm -rf $CLONE_DIR" - echo " 2. Use a different working directory" - exit 1 - fi -else - echo "Cloning $CLONE_URL into $CLONE_DIR..." - git clone --filter=blob:none "$CLONE_URL" - - if [ $? -ne 0 ]; then - echo "FAILED: git clone failed." - echo "Check your network connection and repository access." - exit 1 - fi - - echo "Clone complete." -fi -``` - ---- - -### Phase 3: Checkout Base Branch and Verify - -Change into the cloned directory, checkout the base branch, and verify it is a -valid Go-based operator. - -```bash -cd "$CLONE_DIR" || { echo "FAILED: Cannot change to directory $CLONE_DIR"; exit 1; } - -git checkout "$BASE_BRANCH" || { echo "FAILED: Cannot checkout branch '$BASE_BRANCH'"; exit 1; } -echo "Checked out branch: $BASE_BRANCH" - -# Verify Go module -if [ -f "go.mod" ]; then - GO_MODULE=$(head -1 go.mod | awk '{print $2}') - echo "Go module: $GO_MODULE" -else - echo "WARNING: No go.mod found. This may not be a Go-based operator repository." - GO_MODULE="(not detected)" -fi - -# Detect operator framework -FRAMEWORK="unknown" -if [ -f "go.mod" ]; then - if grep -q "sigs.k8s.io/controller-runtime" go.mod 2>/dev/null; then - FRAMEWORK="controller-runtime" - elif grep -q "github.com/openshift/library-go" go.mod 2>/dev/null; then - FRAMEWORK="library-go" - fi -fi - -echo "Framework: $FRAMEWORK" -echo "Current directory: $(pwd)" -``` - ---- - -### Phase 4: Output Summary - -Write `artifacts/operator-feature-dev/init-summary.md`: - -```text -=== Repository Init Summary === - -Repository: -Clone URL: -Base Branch: -Local Path: -Go Module: -Framework: -``` - -## Critical Failure Conditions - -1. **Missing arguments**: Git URL or base branch not provided -2. **Missing tools**: `git` not installed -3. **Clone failed**: Network, permissions, or invalid URL -4. **Branch checkout failed**: Base branch does not exist -5. **Directory conflict**: Target directory exists but is not a clone of the - expected repository - -## Behavioral Rules - -1. **Efficient cloning**: Always use `git clone --filter=blob:none`. -2. **Non-destructive**: Never delete an existing directory automatically. -3. **Idempotent**: If the directory already exists and is a clone of the correct - repository, use it as-is. - -## Output - -- Init summary printed to user -- Summary saved to `artifacts/operator-feature-dev/init-summary.md` diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.init.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.init.md new file mode 120000 index 0000000..3af5d64 --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.init.md @@ -0,0 +1 @@ +../../../../../plugins/oape/commands/init.md \ No newline at end of file diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.review.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.review.md deleted file mode 100644 index 04edb9b..0000000 --- a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.review.md +++ /dev/null @@ -1,202 +0,0 @@ -# /oape.review - Production-grade code review with auto-fix - -## Purpose - -Perform a "Principal Engineer" level code review that validates the generated -code against the Enhancement Proposal requirements, OpenShift safety standards, -and build consistency. Automatically applies fixes for issues found. - -This command is reusable across all 3 PR phases (API types, controller, E2E -tests). It detects which phase is active from the git diff context. - -## Arguments - -- `$ARGUMENTS`: `` — the git ref to diff against (e.g., `main`, `origin/main`) - Defaults to `origin/main` if not provided. - -## Process - -### Step 1: Determine Base Ref - -```bash -BASE_REF="${1:-origin/main}" -echo "Base ref: $BASE_REF" -``` - -### Step 2: Fetch Context - -1. **Enhancement Proposal**: Read from `artifacts/operator-feature-dev/init-summary.md` - or `artifacts/operator-feature-dev/api/generation-summary.md` for EP context. - Use the EP requirements as the primary validation source (replacing Jira - Acceptance Criteria from the OAPE review). - -2. **Git Diff**: Get the code changes: - - ```bash - git diff ${BASE_REF}...HEAD --stat -p - ``` - -3. **File List**: Get changed files: - - ```bash - git diff ${BASE_REF}...HEAD --name-only - ``` - -4. **Detect Phase**: Determine which PR phase is active based on changed files: - - API types files (`*_types.go`, `types_*.go`, `*.testsuite.yaml`) → API phase - - Controller files (`*controller*.go`, `*reconcile*.go`) → Controller phase - - E2E test files (`*e2e*`, `test-cases.md`) → E2E phase - - Mixed → review all categories - -### Step 3: Analyze Code Changes - -Apply **all** modules. Modules A–D are **mandatory** — every check must be -evaluated. Module E is adaptive based on the PR content. - -#### Module A: Golang (Logic & Safety) - -**Logic Verification (The "Mental Sandbox")**: - -- **Intent Match**: Does the code match the EP requirements? Quote the EP - section that justifies the change. -- **Execution Trace**: Mentally simulate the function. - - *Happy Path*: Does it succeed as expected? - - *Error Path*: If the API fails, does it retry or return an error? -- **Edge Cases**: - - **Nil/Empty**: Does it handle `nil` pointers or empty slices? - - **State**: Does it handle resources that are `Deleting` or `Pending`? - -**Safety & Patterns**: - -- **Context**: REJECT `context.TODO()` in production paths. Must use `context.WithTimeout`. -- **Concurrency**: `go func` must be tracked (WaitGroup/ErrGroup). No race conditions. -- **Errors**: Must use `fmt.Errorf("... %w", err)`. No capitalized error strings. -- **Complexity**: Flag functions > 50 lines or > 3 nesting levels. - -**Idiomatic Clean Code**: - -- **Slices/Maps**: Pre-allocate with `make` if length is known. -- **Interfaces**: Reject "Interface Pollution" (interfaces before multiple implementations). -- **Naming**: Follow Go conventions (`url` not `URL` in mixed-case, `id` not `ID` for local vars). -- **Receiver Types**: Check consistency in pointer vs value receivers. - -**Scheme Registration** *(Severity: CRITICAL)*: - -- For every `client.Get/List/Create/Update/Delete` call, identify the GVK. -- Read `main.go` or `*scheme*.go` for `AddToScheme` calls. -- Every external type used in client calls must have `AddToScheme` registration. - -**Namespace Hardcoding** *(Severity: WARNING)*: - -- Scan for string literals matching `"openshift-*"`, `"kube-*"`, `"default"` as namespace values. -- Should use constants, env vars, or config structs. -- Ignore test files and log messages. - -**Status Handling (Infinite Requeue Prevention)** *(Severity: WARNING)*: - -- Flag patterns where terminal/validation errors cause `return ctrl.Result{}, err`. -- Terminal failures should set Degraded condition and return `ctrl.Result{}, nil`. - -**Event Recording** *(Severity: INFO)*: - -- Check if reconciler embeds `record.EventRecorder`. -- Flag significant state transitions without `recorder.Event()` calls. - -#### Module B: Bash (Scripts) - -- **Safety**: Must start with `set -euo pipefail`. -- **Quoting**: Variables in `oc`/`kubectl` commands MUST be quoted. -- **Tmp Files**: Must use `mktemp`, never hardcoded `/tmp/data`. - -#### Module C: Operator Metadata (OLM) - -- **RBAC**: If new K8s APIs are used, check if `config/rbac/role.yaml` is updated. -- **RBAC Three-Way Consistency** *(Severity: CRITICAL)*: - Cross-reference three sources: - 1. Kubebuilder markers in Go files - 2. `config/rbac/role.yaml` - 3. CSV permissions in `bundle/manifests/` - All must declare the same groups, resources, and verbs. -- **Finalizers**: If logic deletes resources, ensure finalizers are handled. - -#### Module D: Build Consistency - -- **Generation Drift**: - - IF `types.go` modified AND `zz_generated.deepcopy.go` NOT in file list → **CRITICAL FAIL** - - IF `types.go` modified AND `config/crd/bases/` NOT in file list → **CRITICAL FAIL** -- **Dependency Completeness** *(Severity: WARNING)*: - - New imports must exist in `go.mod` - - If `vendor/` exists and `go.mod` changed but `vendor/modules.txt` didn't, flag it - -#### Module E: Context-Adaptive Review - -After mandatory checks, perform an open-ended review tailored to this PR: - -- **OwnerReferences**: If creating child resources, verify owner refs are set *(CRITICAL)* -- **Proxy/Disconnected**: If making HTTP calls, verify proxy env vars are respected *(WARNING)* -- **API Deprecation**: Flag deprecated API versions *(WARNING)* -- **Watch Predicates**: Check if filtering predicates are used to avoid excessive reconciliation *(INFO)* -- **Resource Requests/Limits**: If creating Pod specs, check for resource limits *(INFO)* -- **Leader Election Safety**: If modifying cluster-scoped resources, verify leader election *(WARNING)* - -Use judgment to flag additional concerns not covered by Modules A–D. - -### Step 4: Generate Report - -Generate a structured JSON report: - -```json -{ - "summary": { - "verdict": "Approved | Changes Requested", - "rating": "1-10", - "simplicity_score": "1-10" - }, - "logic_verification": { - "ep_intent_met": true, - "missing_edge_cases": ["description of gaps"] - }, - "issues": [ - { - "severity": "CRITICAL | WARNING | INFO", - "module": "Logic | Bash | OLM | Build | Adaptive", - "file": "path/to/file.go", - "line": 45, - "description": "What's wrong", - "fix_prompt": "How to fix it" - } - ] -} -``` - -### Step 5: Apply Fixes Automatically - -If the `issues` array is non-empty, automatically apply the suggested fixes: - -1. Sort issues by severity (CRITICAL first) -2. For each issue with a `fix_prompt`, apply the fix -3. Run `make generate && make build` to verify fixes compile -4. Report which fixes were applied and which need manual attention - -Skip this step when verdict is "Approved" with no issues. - -### Step 6: Write Verdict - -Detect the current phase and write the verdict to the appropriate artifact: - -- API phase → `artifacts/operator-feature-dev/api/review-verdict.md` -- Controller phase → `artifacts/operator-feature-dev/impl/review-verdict.md` -- E2E phase → `artifacts/operator-feature-dev/e2e/review-verdict.md` - -## Critical Failure Conditions - -1. Not inside a git repository -2. Base ref does not exist -3. No changes detected between base ref and HEAD - -## Behavioral Rules - -1. Every check in Modules A–D must be evaluated on every review -2. Module E is adaptive — extend based on what the PR actually does -3. Report findings with file path and line number -4. Auto-apply fixes when possible, report when manual intervention needed diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.review.md b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.review.md new file mode 120000 index 0000000..953a20f --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/commands/oape.review.md @@ -0,0 +1 @@ +../../../../../plugins/oape/commands/review.md \ No newline at end of file diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/skills/effective-go/SKILL.md b/ambient-workflows/workflows/operator-feature-dev/.claude/skills/effective-go/SKILL.md deleted file mode 100644 index 08fef74..0000000 --- a/ambient-workflows/workflows/operator-feature-dev/.claude/skills/effective-go/SKILL.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -name: effective-go -description: Ensures all generated Go code follows best practices from the official Effective Go documentation and Go community standards. ---- - -# Effective Go - -Ensures all generated Go code follows best practices from the official Effective -Go documentation and Go community standards. - -## When This Skill Applies - -- Generating API type definitions (`/oape.api-generate`) -- Generating controller/reconciler code (`/oape.api-implement`) -- Generating tests (`/oape.api-generate-tests`, `/oape.e2e-generate`) -- Any Go code generation or modification - -## Guidelines - -### 1. Formatting - -Always format code with `gofmt` standards. Consistent indentation, spacing -around operators, and brace placement. - -### 2. Naming Conventions - -- Use `MixedCaps` for exported identifiers, `mixedCaps` for unexported -- Never use underscores in Go names -- Acronyms should be consistent case: `HTTP`, `URL`, `ID` (not `Http`, `Url`, `Id`) -- Package names: short, lowercase, single-word (no `util`, `common`, `misc`) - -### 3. Error Handling - -- Always check errors explicitly — never ignore with `_` -- Return errors, don't panic (except truly unrecoverable situations) -- Wrap errors with context: `fmt.Errorf("context: %w", err)` -- Error messages: lowercase, no punctuation, specific about what failed - -### 4. Documentation - -- Document all exported functions, types, and constants -- Start comments with the name of the thing being documented -- Use complete sentences - -### 5. Interfaces - -- Keep interfaces small (1-3 methods) -- Accept interfaces, return concrete types -- Define interfaces where they're used, not where they're implemented -- Name single-method interfaces with `-er` suffix - -### 6. Concurrency - -- Share memory by communicating (use channels) -- Use `sync.Mutex` only when channels are impractical -- Always handle context cancellation -- Track goroutines with WaitGroup/ErrGroup - -### 7. Imports - -- Group imports: standard library, external, internal -- Use blank lines to separate groups -- Use aliases only when necessary (conflicts, clarity) - -```go -import ( - "context" - "fmt" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - configv1 "github.com/openshift/api/config/v1" - "github.com/myorg/myoperator/internal/controller" -) -``` - -### 8. Variable Declarations - -- Use short declarations (`:=`) inside functions -- Use `var` for package-level variables or zero values -- Group related declarations with `const()` and `var()` blocks - -### 9. Receiver Names - -- Use short, consistent receiver names (1-2 letters) -- Use the same receiver name throughout the type's methods -- Never use `this` or `self` - -### 10. Zero Values - -- Leverage zero values for initialization -- Design types so zero value is useful -- Check for zero value before applying defaults - -### 11. Slices and Maps - -- Pre-allocate slices with `make` when length is known -- Avoid nil slice vs empty slice confusion -- Use `maps.Clone` and `slices.Clone` for copies - -### 12. Receiver Types - -- Use pointer receivers for methods that modify state -- Use value receivers for methods that don't modify state -- Be consistent within a type — don't mix unless there's a clear reason - -## References - -- [Effective Go](https://go.dev/doc/effective_go) -- [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) -- [Go Proverbs](https://go-proverbs.github.io/) - -## Usage by Other Commands - -This skill is referenced by: - -- `/oape.api-generate` — when generating API type definitions -- `/oape.api-implement` — when generating controller code -- `/oape.api-generate-tests` — when generating test code -- `/oape.e2e-generate` — when generating E2E test code - -All Go code generation MUST follow these guidelines. diff --git a/ambient-workflows/workflows/operator-feature-dev/.claude/skills/effective-go/SKILL.md b/ambient-workflows/workflows/operator-feature-dev/.claude/skills/effective-go/SKILL.md new file mode 120000 index 0000000..eb2943c --- /dev/null +++ b/ambient-workflows/workflows/operator-feature-dev/.claude/skills/effective-go/SKILL.md @@ -0,0 +1 @@ +../../../../../../plugins/oape/skills/effective-go/SKILL.md \ No newline at end of file