Skip to content

Commit a677530

Browse files
Ilanit Steinclaude
andcommitted
docs: update documentation for latest CLI changes and review feedback
Update all doc files to reflect 35 commits merged to main since the original PR: --stage flag replaced with positional arguments, --overwrite added to export/apply/validate, transform default behavior changed to create stages for all plugins, --skip-plugins and --instructions-file flags added, --api-resources mutual exclusion expanded, and --plugin-priorities/--stage-name/--plugin-name flags removed. Address reviewer feedback: use verb-first commit/PR titles instead of conventional commit prefixes (aufi), add community plugin maintenance note (aufi), fix conditional Required status for transfer-pvc nginx flags (CodeRabbit), add defensive JSONPatch parent-object checks in plugin examples (CodeRabbit), add nil check for GetAnnotations (CodeRabbit), and resolve apply stage-specific flag contradiction (CodeRabbit). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2f4ff88 commit a677530

9 files changed

Lines changed: 112 additions & 83 deletions

File tree

CONTRIBUTING.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,17 @@ fmt.Errorf("expected *unstructured.Unstructured but got %T", u)
5959
- Always check type assertions and provide informative error messages
6060
- Include the actual resource type and API resource name in errors
6161

62-
## Commit Messages
62+
## Commit and PR Title Conventions
6363

64-
Use conventional commits format:
64+
Use verb-first titles that describe what the change does:
6565

66-
- `fix:` for bug fixes
67-
- `feat:` for new features
68-
- `refactor:` for code restructuring
69-
- `test:` for test additions
70-
- `docs:` for documentation
66+
- `Fix` for bug fixes (e.g., `Fix transform error on empty namespace`)
67+
- `Add` for new features (e.g., `Add crane validate command`)
68+
- `Update` for enhancements (e.g., `Update crane-lib with resources whiteout`)
69+
- `Refactor` for code restructuring
70+
- `Remove` for removals
7171

72-
Include issue references where applicable: `fix: improve error messages (#197)`
72+
Include issue references where applicable: `Fix transform error on empty namespace (#197)`
7373

7474
## Pull Request Guidelines
7575

docs/commands/apply.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Apply transformations to exported resources and produce final manifests.
55
## Synopsis
66

77
```bash
8-
crane apply [flags]
8+
crane apply [stage...] [flags]
99
```
1010

1111
## Description
@@ -21,9 +21,11 @@ Kustomize is embedded directly in the Crane binary (via the krusty API), so no e
2121
| `--export-dir` | `-e` | `export` | The path where exported resources are saved (kept for consistency; not used by apply) |
2222
| `--transform-dir` | `-t` | `transform` | The path where transform stage directories are located |
2323
| `--output-dir` | `-o` | `output` | The path where final manifests are written |
24-
| `--stage` | | | Apply a specific stage only (e.g., `10_KubernetesPlugin`). If not specified, all stages are applied |
2524
| `--kustomize-args` | | | Additional arguments for kustomize (e.g., `--enable-helm --helm-command=helm3`) |
2625
| `--skip-cluster-scoped` | | `false` | Exclude cluster-scoped resources (ClusterRole, ClusterRoleBinding, CRD, etc.) from output. Useful for non-admin migration scenarios |
26+
| `--overwrite` | | `false` | Overwrite the output directory if it already exists |
27+
28+
Stages are specified as positional arguments (e.g., `crane apply 10_KubernetesPlugin`). Stages can be specified by directory name or plugin name. If no stages are specified, all discovered stages are applied sequentially.
2729

2830
## Output Structure
2931

@@ -61,7 +63,7 @@ crane apply --transform-dir ./migration/transform --output-dir ./migration/outpu
6163
### Apply a specific stage only
6264

6365
```bash
64-
crane apply --stage 10_KubernetesPlugin
66+
crane apply 10_KubernetesPlugin
6567
```
6668

6769
### Skip cluster-scoped resources
@@ -87,7 +89,8 @@ kubectl apply -f output/output.yaml
8789

8890
| Error | Cause | Solution |
8991
|-------|-------|----------|
90-
| `kustomization.yaml validation failed` | Invalid Kustomize syntax or missing resource files | Run `crane apply --stage <stage>` to isolate the failing stage |
92+
| `kustomization.yaml validation failed` | Invalid Kustomize syntax or missing resource files | Run `crane apply <stage>` to isolate the failing stage |
93+
| `output directory "X" already exists` | Output directory from a previous run | Use `--overwrite` to replace it |
9194
| `invalid stage name` | Stage name doesn't follow `<number>_<name>` format | Use a valid stage name like `10_KubernetesPlugin` |
9295
| `invalid kustomize-args` | Unsupported or malformed kustomize arguments | Check supported kustomize flags |
9396

docs/commands/export.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ When custom resources are found in the namespace, Crane automatically collects t
3030
| `--as-extras` | | | Extra impersonation info (format: `key=val1,val2;key2=val3`) |
3131
| `--qps` | `-q` | `100` | Query-per-second rate for API requests |
3232
| `--burst` | `-b` | `1000` | API burst rate |
33+
| `--overwrite` | | `false` | Overwrite the export directory if it already exists |
3334

3435
Standard kubeconfig flags (`--kubeconfig`, `--context`, `--cluster`, `--as`, `--as-group`, etc.) are also available.
3536

37+
> **Note:** `--context` is mutually exclusive with `--cluster`, `--server`, `--user`, and `--token`.
38+
3639
## Output Structure
3740

3841
```text
@@ -101,6 +104,8 @@ crane export -n my-app --crd-skip-group monitoring.coreos.com
101104
| `namespaces "X" not found` | Namespace does not exist | Verify namespace name |
102105
| `cannot verify namespace exists` | Insufficient RBAC (warning only) | Export proceeds; verify namespace exists manually |
103106
| `extras requires specifying a user or group` | `--as-extras` used without `--as` | Add `--as` or `--as-group` flag |
107+
| `export directory "X" already exists` | Export directory from a previous run | Use `--overwrite` to replace it |
108+
| Non-zero exit with aggregated error | All namespace list calls returned Forbidden | Ensure service account has list permissions on at least one namespace |
104109

105110
## Next Steps
106111

docs/commands/transfer-pvc.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ The above command transfers PVC (along with PV data) named `<pvc_name>` in the n
3333
| `--destination-image` | string | No | Custom image to use for destination rsync Pod |
3434
| `--source-image` | string | No | Custom image to use for source rsync Pod |
3535
| `--endpoint` | string | No | Kind of endpoint to create in destination cluster (see [Endpoint Options](#endpoint-options)) |
36-
| `--ingress-class` | string | No | Ingress class when endpoint is nginx-ingress |
37-
| `--subdomain` | string | No | Custom subdomain to use for the endpoint |
36+
| `--ingress-class` | string | When endpoint is nginx-ingress | Ingress class when endpoint is nginx-ingress |
37+
| `--subdomain` | string | When endpoint is nginx-ingress | Custom subdomain to use for the endpoint |
3838
| `--output` | string | No | Output transfer stats in the specified file |
3939
| `--verify` | bool | No | Verify transferred files using checksums |
4040

docs/commands/transform.md

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ You can edit resources in the `resources/` directory:
5858
vi transform/10_KubernetesPlugin/resources/Deployment_apps_v1_default_wordpress.yaml
5959

6060
# Preview changes
61-
crane apply --stage 10_KubernetesPlugin
61+
crane apply 10_KubernetesPlugin
6262

6363
# Apply changes
6464
kubectl apply -f output/output.yaml
@@ -128,21 +128,32 @@ transform/.work/
128128

129129
```bash
130130
# Default: discover and run all existing stages
131-
# If no stages exist, creates default 10_KubernetesPlugin stage
131+
# If no stages exist, creates stages for all available plugins
132132
crane transform
133133

134-
# Run specific stage only (creates it if doesn't exist)
135-
crane transform --stage 10_KubernetesPlugin
134+
# Run specific stages only (creates them if they don't exist)
135+
crane transform 10_KubernetesPlugin
136+
137+
# Run multiple specific stages
138+
crane transform 10_KubernetesPlugin 20_OpenshiftPlugin
136139

137140
# Create a new plugin-based stage automatically
138141
# Stage name ending with "Plugin" will use that plugin
139-
crane transform --stage 35_OpenshiftPlugin
142+
crane transform 35_OpenshiftPlugin
140143

141144
# Create a new pass-through stage for manual editing
142145
# Stage name NOT ending with "Plugin" creates empty pass-through
143-
crane transform --stage 40_CustomManualEdits
146+
crane transform 40_CustomManualEdits
147+
148+
# Skip specific plugins when running all stages
149+
crane transform --skip-plugins OpenshiftPlugin
150+
151+
# Use a declarative instructions file (mutually exclusive with positional stage args)
152+
crane transform --instructions-file instructions.yaml
144153
```
145154

155+
Shell autocompletion is available for plugin and stage names.
156+
146157
### Applying Transforms
147158

148159
```bash
@@ -176,7 +187,9 @@ output/
176187

177188
## Automatic Stage Creation
178189

179-
Crane automatically creates new stages when you reference them with `--stage`. The stage name determines whether a plugin will be used or if it's a pass-through stage for manual editing.
190+
When no stages exist in the transform directory, `crane transform` automatically creates stages for **all available plugins** (not just KubernetesPlugin). Plugins are sorted alphabetically and assigned priorities starting at 10, incrementing by 5. Use `--skip-plugins` to exclude specific plugins from this default behavior.
191+
192+
You can also create new stages by specifying them as positional arguments. The stage name determines whether a plugin will be used or if it's a pass-through stage for manual editing.
180193

181194
### Stage Naming Convention
182195

@@ -198,7 +211,7 @@ Stage names ending with `Plugin` **must** have a corresponding plugin installed.
198211

199212
```bash
200213
# Creates a stage using OpenshiftPlugin
201-
crane transform --stage 20_OpenshiftPlugin
214+
crane transform 20_OpenshiftPlugin
202215

203216
# Output:
204217
# - resources/ (from previous stage or export)
@@ -209,7 +222,7 @@ crane transform --stage 20_OpenshiftPlugin
209222
**If the plugin doesn't exist, you'll get an error:**
210223

211224
```bash
212-
crane transform --stage 20_NonexistentPlugin
225+
crane transform 20_NonexistentPlugin
213226
# Error: stage 20_NonexistentPlugin requires plugin 'NonexistentPlugin'
214227
# but it was not found (available plugins: KubernetesPlugin, NamespaceCleanup)
215228
```
@@ -220,7 +233,7 @@ Stage names **not** ending with `Plugin` create pass-through stages where resour
220233

221234
```bash
222235
# Creates a pass-through stage for manual editing
223-
crane transform --stage 30_CustomEdits
236+
crane transform 30_CustomEdits
224237

225238
# Output:
226239
# - resources/ (copied unchanged from previous stage)
@@ -334,7 +347,7 @@ kubectl kustomize transform/10_KubernetesPlugin/
334347

335348
```bash
336349
# Create a custom stage for manual edits
337-
crane transform --stage 40_CustomEdits
350+
crane transform 40_CustomEdits
338351

339352
# Edit resources
340353
vi transform/40_CustomEdits/resources/Deployment_apps_v1_default_wordpress.yaml
@@ -361,10 +374,10 @@ crane transform
361374
crane transform --force
362375

363376
# Run specific plugin stage (regenerates automatically)
364-
crane transform --stage 10_KubernetesPlugin
377+
crane transform 10_KubernetesPlugin
365378

366379
# Run specific custom stage (requires --force if directory not empty)
367-
crane transform --stage 40_CustomEdits --force
380+
crane transform 40_CustomEdits --force
368381
```
369382

370383
### 4. Working with Multiple Stages
@@ -374,11 +387,11 @@ crane transform --stage 40_CustomEdits --force
374387
crane transform
375388

376389
# Automatically add more plugin stages
377-
crane transform --stage 20_OpenshiftPlugin
378-
crane transform --stage 30_ImagestreamPlugin
390+
crane transform 20_OpenshiftPlugin
391+
crane transform 30_ImagestreamPlugin
379392

380393
# Add a manual editing stage
381-
crane transform --stage 40_CustomEdits
394+
crane transform 40_CustomEdits
382395

383396
# Edit the manual stage (example: edit a specific deployment)
384397
vi transform/40_CustomEdits/resources/Deployment_apps_v1_default_wordpress.yaml
@@ -402,11 +415,11 @@ crane transform
402415
# Creates: 10_KubernetesPlugin/
403416

404417
# 3. Add OpenShift-specific transformations
405-
crane transform --stage 20_OpenshiftPlugin
418+
crane transform 20_OpenshiftPlugin
406419
# Creates: 20_OpenshiftPlugin/ using OpenshiftPlugin
407420

408421
# 4. Add a manual customization stage
409-
crane transform --stage 50_CustomLabels
422+
crane transform 50_CustomLabels
410423
# Creates: 50_CustomLabels/ as pass-through (resources copied from previous stage)
411424

412425
# 5. Manually add custom labels
@@ -483,7 +496,7 @@ crane transform --force
483496
git diff transform/
484497

485498
# Option 3: Only regenerate plugin stages (they auto-regenerate)
486-
crane transform --stage 10_KubernetesPlugin
499+
crane transform 10_KubernetesPlugin
487500

488501
# Note: Plugin stages (ending with "Plugin") regenerate automatically without --force
489502
# Custom stages (not ending with "Plugin") require --force to protect manual edits
@@ -496,7 +509,7 @@ crane transform --stage 10_KubernetesPlugin
496509
**Solution**:
497510
```bash
498511
# Validate by applying a single stage
499-
crane apply --stage 10_KubernetesPlugin
512+
crane apply 10_KubernetesPlugin
500513

501514
# Check for missing files
502515
ls -la transform/10_KubernetesPlugin/resources/

docs/commands/validate.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Incompatible resources are written to a `failures/` directory under the validate
1818

1919
### Offline Validation
2020

21-
Use `--api-resources` to validate offline against a captured API surface JSON file (produced by `scripts/capture-api-surface.sh`) when the target cluster is not directly reachable. This is mutually exclusive with `--context`/`--kubeconfig`.
21+
Use `--api-resources` to validate offline against a captured API surface JSON file (produced by `scripts/capture-api-surface.sh`) when the target cluster is not directly reachable. This is mutually exclusive with `--context`, `--kubeconfig`, `--server`, `--token`, `--cluster`, and `--user`.
2222

2323
## Flags
2424

@@ -27,7 +27,8 @@ Use `--api-resources` to validate offline against a captured API surface JSON fi
2727
| `--input-dir` | `-i` | `output` | Path to the apply output directory containing final manifests |
2828
| `--validate-dir` | | `validate` | Path where validation results and failures are saved |
2929
| `--output` | `-o` | `json` | Report file format: `json` or `yaml` |
30-
| `--api-resources` | | | Path to API surface JSON file for offline validation (mutually exclusive with `--context`/`--kubeconfig`) |
30+
| `--api-resources` | | | Path to API surface JSON file for offline validation (mutually exclusive with `--context`/`--kubeconfig`/`--server`/`--token`/`--cluster`/`--user`) |
31+
| `--overwrite` | | `false` | Overwrite the validate directory if it already exists |
3132

3233
Standard kubeconfig flags (`--kubeconfig`, `--context`, `--cluster`, etc.) are also available to specify the target cluster for live validation.
3334

@@ -94,7 +95,8 @@ crane validate --context target-cluster
9495
|-------|-------|----------|
9596
| `input-dir "X" is not a directory` | Path doesn't exist or isn't a directory | Run `crane apply` first to generate output |
9697
| `loading kubeconfig` | Cannot connect to target cluster | Check kubeconfig and `--context` flag, or use `--api-resources` for offline mode |
97-
| `--api-resources and --context are mutually exclusive` | Both offline and live flags specified | Use one mode or the other |
98+
| `--api-resources and --context are mutually exclusive` | Both offline and live flags specified | Use one mode or the other. `--api-resources` is also mutually exclusive with `--kubeconfig`, `--server`, `--token`, `--cluster`, and `--user` |
99+
| `validate directory "X" already exists` | Validate directory from a previous run | Use `--overwrite` to replace it |
98100
| Validation failures | GVKs not available on target cluster | Install required CRDs/operators on target, or transform manifests to use supported API versions |
99101

100102
## Next Steps

docs/development/plugin-development.md

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,12 @@ func main() {
8181

8282
var patches []PatchOp
8383

84-
// Example: add a migration label
84+
// Example: add a migration label (ensure parent object exists first)
85+
patches = append(patches, PatchOp{
86+
Op: "add",
87+
Path: "/metadata/labels",
88+
Value: map[string]interface{}{},
89+
})
8590
patches = append(patches, PatchOp{
8691
Op: "add",
8792
Path: "/metadata/labels/migrated-by",
@@ -90,11 +95,13 @@ func main() {
9095

9196
// Example: remove a specific annotation
9297
annotations := resource.GetAnnotations()
93-
if _, ok := annotations["source-cluster-only"]; ok {
94-
patches = append(patches, PatchOp{
95-
Op: "remove",
96-
Path: "/metadata/annotations/source-cluster-only",
97-
})
98+
if annotations != nil {
99+
if _, ok := annotations["source-cluster-only"]; ok {
100+
patches = append(patches, PatchOp{
101+
Op: "remove",
102+
Path: "/metadata/annotations/source-cluster-only",
103+
})
104+
}
98105
}
99106

100107
if err := json.NewEncoder(os.Stdout).Encode(patches); err != nil {
@@ -115,9 +122,11 @@ go build -o ~/.local/share/crane/plugins/MyCustomPlugin
115122
```bash
116123
#!/bin/bash
117124
# Simple plugin that adds a label to all resources
125+
# Note: ensure /metadata/labels exists before adding child keys
118126

119127
cat <<EOF
120128
[
129+
{"op": "add", "path": "/metadata/labels", "value": {}},
121130
{"op": "add", "path": "/metadata/labels/environment", "value": "production"}
122131
]
123132
EOF
@@ -147,7 +156,7 @@ Stage naming convention:
147156
cat sample-deployment.json | ./MyCustomPlugin
148157

149158
# Test in a full pipeline
150-
crane transform --stage 20_MyCustomPlugin
159+
crane transform 20_MyCustomPlugin
151160
crane apply
152161
```
153162

@@ -181,7 +190,7 @@ Plugins are executed in stage order (by the numeric prefix). Lower numbers run f
181190
## Best Practices
182191

183192
1. **Idempotent**: Running the plugin multiple times should produce the same result
184-
2. **Defensive**: Check if fields exist before removing them
193+
2. **Defensive**: Check if fields and parent objects exist before modifying them
185194
3. **Focused**: Each plugin should handle one concern
186195
4. **Documented**: Include usage instructions and examples
187196
5. **Tested**: Cover edge cases (missing fields, different resource types)

0 commit comments

Comments
 (0)