diff --git a/apps/docs/docs.json b/apps/docs/docs.json index b5353a13a..ecc4da365 100644 --- a/apps/docs/docs.json +++ b/apps/docs/docs.json @@ -30,7 +30,13 @@ }, { "group": "Codemod Platform", - "pages": ["scanner", "migrations", "insights", "codemod-studio"] + "pages": [ + "scanner", + "migrations", + "insights", + "codemod-studio", + "workflows" + ] }, { "group": "OSS & Community", diff --git a/apps/docs/workflows.mdx b/apps/docs/workflows.mdx new file mode 100644 index 000000000..410a1a510 --- /dev/null +++ b/apps/docs/workflows.mdx @@ -0,0 +1,499 @@ +--- +title: 'Codemod CLI' +description: Run, validate, and automate code-modification workflows locally or in the cloud. +icon: 'code' +--- + +--- + +Codemod CLI is a self-hosted workflow engine for code-base changes—codemods, grep-style edits, automated lint fixes, and more. Define once in YAML; run unchanged on your laptop **or** in the Codemod platform. + +## Core Features + +- **Single binary, no server** — works anywhere you have a shell +- **Schema-validated shared state** — tasks share one JSON document +- **Dynamic matrix fan-out** — tasks appear/disappear as state arrays change +- **Manual gates** — pause tasks until you trigger them +- **Durable & resumable** — state survives crashes or reboots +- **Parallel scheduling** — independent nodes run when dependencies allow +- **Host-shell execution** — commands run directly on your machine (container runtimes on the roadmap) + +--- + +## Quick Start + + + + ```bash + cargo install codemod-cli + ``` + + + ```yaml workflow.yaml + version: "1" + nodes: + - id: hello + name: Hello World + type: automatic + steps: + - name: Say hello + run: echo "Hello, World!" + ``` + + + ```bash + codemod validate -w workflow.yaml + codemod run -w workflow.yaml + codemod run ./my-workflow/ # run a bundle folder + ``` + + + + +Registry identifiers such as `my-registry/react-mods:latest` are on the roadmap. + + +--- + +## Directory Layout + +``` +my-workflow/ +├─ workflow.yaml +├─ scripts/ +└─ rules/ +``` + +The folder—called a **workflow bundle**—is the root when you run `codemod run ./my-workflow/`. `$CODEMOD_PATH` points here inside every task. + + +A workflow bundle is a directory containing your workflow.yaml and any scripts, rules, or assets referenced by your workflow. + +- When you run codemod run ./my-workflow/, the directory is used as the root for all relative paths. +- You can also run a workflow directly from a file: +
+ codemod run -w workflow.yaml + + +Registry support (run workflows from remote sources) is planned for the future. + +
+ +## Workflow File + +```yaml workflow.yaml +version: "1" +state: + schema: [] +templates: [] +nodes: [] +``` + +A workflow has four top-level keys: + +| Key | Required | Purpose | +|-----|----------|---------| +| `version` | ✓ | Declare workflow schema version (default: `"1"`). | +| [`state`](#shared-state) | | Declares shared-state schema. | +| [`templates`](#templates) | | Re-usable blocks. | +| [`nodes`](#nodes) | ✓ | Executable DAG. | + +--- + +## Shared State + +```yaml +state: + schema: + - name: shards + type: array + items: + type: object + properties: + team: { type: string } + shardId: { type: string } +``` + +--- + +## Templates + +```yaml +templates: + - id: checkout-repo + name: Checkout Repository + inputs: + - name: repo_url + type: string + required: true + steps: + - name: Clone + run: git clone ${{inputs.repo_url}} repo +``` + +**Template Inputs & Usage**: + +Templates can define required or optional inputs, which are referenced in their steps. + +To use a template in a node step: + +```yaml +steps: + - name: Checkout + uses: + - template: checkout-repo + inputs: + repo_url: ${{params.repo_url}} +``` + +--- +## Nodes & Steps + +### Nodes + +```yaml +nodes: + - id: build + name: Build + type: automatic + steps: + - name: npm install + run: npm ci +``` + + + Unique within the workflow. + + + Display name. + + + `automatic` (default) or `manual`. + + + Upstream node IDs. + + + `{ type: manual }` → approval gate. + + + Matrix configuration. + + + Ordered list of steps. + +Container/runtime configuration (e.g., Docker). +Environment variables for the node or step. + +### Step + + + Step label. + + + Inline shell command to execute. +
+ Provide either run or uses, not both. +
+ + Template call(s). +
+ Provide either run or uses, not both. +
+ + +## Matrix Strategy + +```yaml +nodes: + - id: matrix-codemod + name: Matrix Codemod + strategy: + type: matrix + from_state: shards + steps: + - name: Codemod + run: node codemod.js --team=$team --shard=$shardId +``` + + +When the array referenced by `from_state` changes, Codemod CLI: + +1. Creates new tasks for new items. +2. Marks tasks as `WontDo` if their item is removed. +3. Leaves existing tasks untouched if their item remains. + + +Matrix nodes have a master task that tracks the status of all generated tasks. + + + +--- + +## Manual Trigger + +```yaml +nodes: + - id: manual-approval + name: Manual Approval + trigger: + type: manual + steps: + - name: Wait for approval + run: echo "Waiting for manual approval" +``` + + +Manual tasks are assigned unique UUIDs. You can resume: + +- All paused tasks: + ```bash + codemod resume -i --trigger-all + ``` +- A specific task: + ```bash + codemod resume -i -t + ``` + + +--- + +## State Updates + +| Syntax | Meaning | Example | +|----------------|----------------------------------------------|----------------------------------------------| +| `KEY=VAL` | Set state key to value | `count=10` | +| `KEY@=VAL` | Append value to array at state key | `shards@={"team":"core","shardId":"1"}` | +| Dot notation | Set nested state fields | `config.retries=5` | +| JSON values | Use valid JSON for objects/arrays | `user={"name":"Alice","id":123}` | + + +All state updates must be valid JSON if not a primitive. Updates are applied only if the task exits successfully. + + + + +You can specify how a node or template runs: + +```yaml +runtime: + type: docker + image: node:18-alpine +``` + +Supported types: `docker`, `podman`, `direct` (host shell). + + + + +Workflow state is persisted after every task. If interrupted, you can resume from the last saved state—no work is lost. + + + + +For matrix nodes, a master task aggregates the status of all generated tasks. +If all child tasks complete, the master is `Completed`. If any fail, the master is `Failed`. + + + +If your workflow has a cycle: + +```yaml +nodes: + - id: a + depends_on: [b] + - id: b + depends_on: [a] +``` + +You'll see: + +```bash +✗ Workflow definition is invalid +Error: Cyclic dependency detected: a → b → a +``` + + + + +--- + +## End-to-End Example + +```yaml +version: "1" +state: + schema: + - name: shards + type: array + items: + type: object + properties: + team: { type: string } + shardId: { type: string } +templates: + - id: checkout-repo + name: Checkout Repository + inputs: + - name: repo_url + type: string + required: true + steps: + - name: Clone + run: git clone ${{inputs.repo_url}} repo +nodes: + - id: make-shards + name: Make Shards + type: automatic + steps: + - name: Write shards + run: echo 'shards@={"team":"core","shardId":"1"}' >> "$STATE_OUTPUTS" + - id: matrix-codemod + name: Matrix Codemod + strategy: + type: matrix + from_state: shards + trigger: + type: manual + steps: + - name: Codemod + run: node codemod.js --team=$team --shard=$shardId + - name: PR + run: codemodctl pr create +``` + +--- + +## Task Statuses + + + Queued; waiting for runner. + + + Currently executing. + + + Succeeded; diff applied. + + + Script exited non-zero; diff discarded. + + + Waiting for manual approval. + + + Dependencies not finished. + + + Matrix item removed; task skipped. + + + +## Variable Resolution + +- **Parameter:** `${{params.branch}}` — Supplied at runtime +- **Environment:** `${{env.CI}}` — Host env var +- **Shared State:** `${{state.counter}}` — Live JSON value + + +In matrix tasks, each object key becomes an environment variable (e.g., `$team`, `$shardId`, …). + + +--- + +## CLI Commands + +### `codemod validate` +Lint workflow & print issues. + + + Path to the workflow file. + + +### `codemod run` +Start a run. + + + Path to the workflow file. + + + Path to a workflow bundle directory. + + +### `codemod resume` +Resume or trigger tasks. + + + Run ID to resume. + + + Resume all paused tasks. + + + Resume a single task by UUID. + + +### `codemod graph` +Render DAG image. + + + Path to the workflow file. + + + Output PNG file for the DAG image. + + + +## Task Statuses + + + Queued; waiting for runner. + + + Currently executing. + + + Succeeded; diff applied. + + + Script exited non-zero; diff discarded. + + + Waiting for manual approval. + + + Dependencies not finished. + + + Matrix item removed; task skipped. + + + +## Validation Checks + +`codemod validate` catches issues before execution: + +| Check | Ensures | +|-------|---------| +| Schema validation | YAML matches spec | +| Unique IDs | Node & template IDs unique | +| Dependency validation | Every `depends_on` exists | +| Cyclic dependency detection | DAG has no cycles | +| Template references | All `template:` IDs exist | +| Matrix validation | `from_state` matches schema | +| State schema validation | `state.schema` is valid | +| Variable syntax | `${{…}}` uses `params`, `env`, `state` | + +--- + +## Roadmap + + + Support for runtime: docker and other container runtimes, allowing tasks to run in isolated environments. + + + Ability to pass parameters to workflows via --param key=value flags. + + + Support for matrix strategies within matrix strategies, enabling more complex task fan-out. + \ No newline at end of file