From bff17434132caf97e46893f79abadd967d654bd0 Mon Sep 17 00:00:00 2001 From: James Dryden Date: Fri, 26 Jun 2026 22:39:07 +0100 Subject: [PATCH 1/5] docs: Changelog to date --- CHANGELOG.md | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fc06ef..08a6af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,32 @@ ## 0.0.6 -### Patch Changes - -- f599cfa: Drop the `./` prefix from the `bin.zorb` path in `package.json`. npm's publish normalisation was stripping - the prefix and emitting a misleading "script name `bin/zorb.cjs` was invalid and removed" warning — the entry was - actually rewritten in place. With the prefix gone, input and normalised form match and the warning stops firing. -- 9239d4f: Testing changeset +- feat(A1): Project scaffold by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/1 +- feat(A2): YAML parsing and validation by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/2 +- A3: Task inputs by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/3 +- A4: Shell step execution by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/4 +- A5: Expression engine by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/5 +- feat(A6): secrets & env registration by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/6 +- A7: defaults: support by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/7 +- feat(A8): action step execution (uses: local) by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/8 +- feat(A9): NPM action resolution (uses: packages) by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/9 +- feat(A10): cross-file workflow references by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/10 +- feat(A11): direct action execution (zorb use) by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/11 +- feat(A12): step outputs by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/12 +- feat(A13): docker step execution by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/13 +- feat(A14): step timeouts, retries, and signal handling by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/14 +- feat(A15): zorb init and --watch mode by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/15 +- feat(A16): bundle compiled binaries for four platforms by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/16 +- feat(A17): publish release binaries via GitHub Actions by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/17 +- feat(A18): VitePress docs site by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/18 +- feat(A19): extension-less uses, multi-match warning, guide pages by @jdrydn in + https://github.com/zorb-run/zorb-cli/pull/19 +- feat(A20): shell-script integration test suite by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/20 +- fix: tighten CLI env model and --with surface by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/21 +- docs: expand site with concepts, CLI, security, cookbook, CI guide by @jdrydn in + https://github.com/zorb-run/zorb-cli/pull/22 +- feat: accept zorb.yaml + modernise action examples by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/23 +- feat(B1): expose `zorb/action` public type surface by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/24 +- ci: changesets-driven release pipeline by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/25 +- fix: Release by @jdrydn in https://github.com/zorb-run/zorb-cli/pull/26 +- ci: version packages by @github-actions[bot] in https://github.com/zorb-run/zorb-cli/pull/27 From 5492b1aef5f319c9c2598b9474c120b868831870 Mon Sep 17 00:00:00 2001 From: James Dryden Date: Fri, 26 Jun 2026 23:01:32 +0100 Subject: [PATCH 2/5] docs: expand README and rewrite CONTRIBUTING guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flesh out the README with a richer example, feature list, and NPM install instructions now that the package is published. Restructure CONTRIBUTING around four sections — tooling, working locally, integration tests, publishing packages — and replace the outdated manual-tag release notes with the changesets-driven flow introduced in #25. --- CONTRIBUTING.md | 361 +++++++++++++++++++++++++++++++++--------------- README.md | 69 +++++++-- 2 files changed, 307 insertions(+), 123 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9bc0e31..3ad2a93 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,19 +2,79 @@ Thanks for taking a look! This guide covers everything you need to hack on the CLI. -## Prerequisites +- [Tooling](#tooling) +- [Working locally](#working-locally) +- [Integration tests](#integration-tests) +- [Publishing packages](#publishing-packages) -- [Bun](https://bun.com) ≥ 1.1.0 — runtime, test runner, and bundler all in one. -- A POSIX shell (macOS or Linux). Windows isn't supported yet. +--- + +## Tooling + +`zorb` is a Bun project. Almost everything (runtime, test runner, bundler, formatter driver) runs through Bun. + +### Required + +- **[Bun](https://bun.com)** ≥ 1.3.13 — runtime, test runner, and bundler. Pinned in `engines.bun` in `package.json` and + in CI. +- A POSIX shell (macOS or Linux). Windows support is deferred. +- **Git**. ```sh # macOS brew install oven-sh/bun/bun -# or anywhere + +# anywhere curl -fsSL https://bun.com/install | bash ``` -## Setup +### Optional (for some integration tests) + +- **Docker** — needed for the Docker step suite (`integration-tests/docker/`). Tests skip cleanly when Docker isn't + present; CI's Linux runner sets `ZORB_REQUIRE_DOCKER=1` to flip a missing daemon into a hard failure. +- **Python 3** — needed for the Python action suite (`integration-tests/code/python.test.sh`). Same skip-or-require + behaviour as Docker. + +### For publishing + +Maintainers don't need anything beyond the above — releases run end-to-end on CI through GitHub Actions and +[changesets](https://github.com/changesets/changesets). You only need `npm` locally if you want to test a tarball before +publishing; see [Publishing packages](#publishing-packages). + +### Project layout + +``` +src/ + cli.ts # entrypoint: arg parsing + command dispatch + colors.ts # ANSI helper; honours NO_COLOR / FORCE_COLOR / --no-color + config.ts # workflow finder + parser + strict validator + context.ts # task execution context (env, inputs, outputs) + envfile.ts # dotenv-style parser for --env-file + expressions.ts # ${{ ... }} engine + help.ts # top-level and per-command help text + inputs.ts # input parsing / validation + logger.ts # verbosity-aware logger (writes stdout/stderr directly) + types.ts # workflow shape types + version.ts # semver + git hash for `--version` + action.ts # public `zorb/action` type surface for action authors + commands/ # one file per CLI command (init, list, run, run-watch, use) + steps/ # step executors (shell, docker, action) + utils/ # shared helpers (path resolve, etc.) +test/ # unit + spawned-CLI + binary-smoke tests +integration-tests/ # shell-script end-to-end suite (see below) +runners/ # runner.cjs (Node) + runner.py (Python) for code actions +scripts/ # build.ts, validate-schema.ts +docs/ # VitePress site (zorb.run) +examples/ # example zorb.yml files referenced from the docs +zorb.schema.json # JSON Schema for editor support (not runtime-consumed) +bin/zorb.cjs # NPM-installed dispatcher; execs dist//zorb at runtime +``` + +--- + +## Working locally + +### Setup ```sh git clone git@github.com:zorb-run/zorb-cli.git @@ -22,120 +82,90 @@ cd zorb-cli bun install ``` -## Running the CLI +### Run the CLI from source -Run the source directly while iterating: +While iterating, run the TypeScript entrypoint directly — no build required: ```sh -bun src/cli.ts --version bun src/cli.ts --help bun src/cli.ts run build +bun src/cli.ts list ``` -The `dev` script is a shortcut: +There's a shorthand: ```sh bun run dev -- run build ``` -To run the compiled binary the way users will, build it first: +### Build the binary + +For tests or to mirror how users will invoke `zorb`, compile a host-platform binary: ```sh bun run build -- --current ./dist/$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/aarch64/arm64/;s/x86_64/x64/')/zorb --version ``` -## Common commands - -| Command | What it does | -| ------------------------------- | ----------------------------------------------------------------------------------- | -| `bun run test:unit` | Unit + spawned-CLI + binary-smoke tests via `bun test` | -| `bun run test:integration` | Run the `integration-tests/` shell suite against `dist//zorb` (build first) | -| `bun run typecheck` | Type-check with `tsc --noEmit` | -| `bun run format` | Format with Prettier | -| `bun run dev` | Run the CLI from source | -| `bun run build` | Build compiled binaries for all four supported platforms into `dist/` | -| `bun run build -- --current` | Build only the host-platform binary (used by smoke tests) | -| `bun run build -- --target=

` | Build a specific platform: `darwin-x64`, `darwin-arm64`, `linux-x64`, `linux-arm64` | +| Command | What it does | +| ---------------------------------- | ----------------------------------------------- | +| `bun run build` | Build binaries for all four supported platforms | +| `bun run build -- --current` | Build only the host-platform binary | +| `bun run build -- --target=` | Build a specific platform | -## Binary distribution +Supported targets: `darwin-x64`, `darwin-arm64`, `linux-x64`, `linux-arm64`. -`zorb` ships on NPM as a single package laid out like this: +The output layout is: ``` -bin/zorb.cjs # dispatcher, registered as the package's `bin` entry -dist//zorb # compiled binary for each of the four targets -dist/runners/ # action runners (runner.cjs, runner.py), shared across targets +dist/ + /zorb # compiled binary per target + runners/ # runner.cjs + runner.py, shared across targets ``` -The dispatcher inspects `process.platform` + `process.arch` and execs `../dist//zorb` with the user's args. The -compiled binary resolves `dirname(execPath)/../runners/` for code actions, so the four binaries share the single -`dist/runners/` directory. +`bin/zorb.cjs` (the NPM-installed dispatcher) inspects `process.platform` + `process.arch` and execs the matching +`dist//zorb` binary. The binary resolves `dirname(execPath)/../runners/` for code actions, so all four binaries +share the single `dist/runners/` directory. -`bun run build` produces the layout above. +### Lint and format -Set `ZORB_SKIP_SMOKE=1` to skip the binary smoke tests during local iteration (they add a one-off ~150ms compile to -`bun run test:unit`). +Formatting is Prettier-driven; there's no separate linter. -## Cutting a release +```sh +bun run format # rewrite files in place +``` -Releases live in [GitHub Releases](https://github.com/zorb-run/zorb-cli/releases). The `.github/workflows/release.yml` -workflow listens for `release: published` and uploads the platform binaries to the release. +### Typecheck -1. Bump `version` in `package.json` and commit (`chore: release vX.Y.Z`). -2. Push the commit, then tag and push the tag: - ```sh - git push origin main - git tag vX.Y.Z - git push origin vX.Y.Z - ``` - Pushing only the tag would leave the bump commit local — the release would point at a SHA the remote branch doesn't - know about. -3. Draft a release against that tag on GitHub (or `gh release create vX.Y.Z --draft`), write the notes, then publish. -4. The workflow builds all four binaries on `ubuntu-latest`, packages each as `zorb-.tar.gz` (containing - `zorb-/bin/zorb` + `zorb-/runners/`), generates a `SHA256SUMS` file, and attaches the lot to the - release. The same step extracts the linux-x64 tarball and runs a tiny code-action workflow to verify runner discovery - before publishing. +```sh +bun run typecheck +``` -Re-publishing the same release re-runs the workflow; `gh release upload --clobber` overwrites any existing assets. +Strict TypeScript with `noUncheckedIndexedAccess`. Use `!` only where the invariant is obvious from context. -## Project layout +### Unit tests -``` -src/ - cli.ts # entrypoint: arg parsing + command dispatch - colors.ts # ANSI helper; honours NO_COLOR / FORCE_COLOR / --no-color - help.ts # top-level and per-command help text - logger.ts # verbosity-aware logger (writes to stdout/stderr directly) - version.ts # semver + git hash for `--version` -test/ - cli.test.ts # spawns the CLI and asserts on stdout/stderr/exit code - colors.test.ts # unit tests for the colour helper - logger.test.ts # unit tests for the logger +```sh +bun run test:unit # or `bun test` ``` -The layout will grow over time — `src/steps/`, `src/utils/`, and `runners/` arrive alongside the features that need -them. +This runs three flavours of test under `test/`: -## Coding conventions +1. **Unit tests** for small modules (`colors`, `logger`, `envfile`, etc.) — import directly and inject fakes. +2. **Spawned-CLI tests** (`test/cli-*.test.ts`) — spawn `bun src/cli.ts ` and assert on stdout / stderr / exit + code. The helper sets `NO_COLOR=1` by default; opt out per-test for colour-related cases. +3. **Binary smoke tests** (`test/smoke.test.ts`) — compile the host binary and run `--version` against it. Adds a + one-off ~150ms compile to the suite; set `ZORB_SKIP_SMOKE=1` to skip during tight inner loops. -- **Keep it simple.** Small functions, clear names, no clever tricks. If something feels over-engineered, it probably - is. -- **Match the existing style.** Read neighbouring code before adding new patterns. -- **Prefer `undefined` over `null`**, especially in types. -- **Use `path.resolve` / `path.join`** for any filesystem paths — Windows support is deferred but not abandoned. -- **No `${{ }}` expressions inside `run:` strings.** `run:` is passed to the shell unmodified — declare values in `env:` - and read them natively. -- **Let errors bubble.** Catch only at the CLI boundary. Don't swallow. +Aim to add a test alongside any new behaviour. For new CLI commands, cover at least: missing-arg error, happy path, +`--help`. -## Output, colours, and verbosity +### Output, colours, and verbosity The logger (`src/logger.ts`) is the only thing that should write to stdout/stderr in the CLI. It bypasses `console.log`/`console.error` because Bun auto-colourises `console.error` under `FORCE_COLOR`, which would defeat `--no-color`. -Levels: - | Level | Flag | Methods that fire | | --------- | ------------------ | ------------------------------- | | `quiet` | `--quiet` | `error` | @@ -143,56 +173,163 @@ Levels: | `verbose` | `-v` / `--verbose` | + `verbose` | | `debug` | `--debug` | + `debug` | -Routing: +Routing: `info` → stdout (program output). Everything else → stderr (diagnostics, hints, errors). -- `info` → stdout (program output) -- everything else → stderr (diagnostics, hints, errors) +### Coding conventions -## Testing +- **Keep it simple.** Small functions, clear names, no clever tricks. +- **Match the existing style.** Read neighbouring code before adding new patterns. +- **Prefer `undefined` over `null`**, especially in types. +- **Use `path.resolve` / `path.join`** for any filesystem paths — Windows support is deferred but not abandoned. +- **No `${{ }}` expressions inside `run:` strings.** `run:` is passed to the shell unmodified — declare values in `env:` + and read them natively. +- **Let errors bubble.** Catch only at the CLI boundary (in `cli.ts`'s command dispatch). Don't swallow. + +### Commit style -Run `bun run test:unit` (or `bun test` directly). We have two flavours: +- One commit per logical change. +- Subject line is short and imperative: `feat(A2): YAML parser and validator`, `fix run: cwd default`, etc. +- Wrap the body at ~72 chars. Explain the _why_, not the _what_. +- No AI-tool trailers. -1. **Unit tests** for small modules (`colors`, `logger`) — import directly and inject fake streams. -2. **Subprocess tests** for the CLI (`test/cli.test.ts`) — spawn `bun src/cli.ts ` and assert on - stdout/stderr/exit code. The helper sets `NO_COLOR=1` by default so assertions stay readable; opt out per-test for - colour-related cases. +### Pull requests + +- Branch from `main`. Name branches `feat/`, `fix/`, or `chore/`. +- Before pushing: `bun run typecheck && bun run test:unit && bun run format`. Run integration tests too if you're + touching anything that bundles, spawns subprocesses, or talks to runners. +- Keep PRs small. Each commit should leave the tree green. +- **Add a changeset** for any user-visible change — see [Publishing packages](#publishing-packages). -Aim to add a test alongside any new behaviour. If you're adding a command, cover at least: missing-arg error, happy -path, `--help`. +--- -### Integration tests +## Integration tests -End-to-end shell scripts under `integration-tests/` exercise the compiled binary against real `zorb.yml` workflows. They -cover shell execution, nested workflows, code actions, and Docker steps — the surface area where bundling, runner +End-to-end shell scripts under `integration-tests/` exercise the **compiled binary** against real `zorb.yml` workflows. +They cover shell execution, nested workflows, code actions, and Docker steps — the surface area where bundling, runner discovery, and subprocess plumbing can regress in ways `bun test` won't catch. +### Suite layout + +``` +integration-tests/ + lib.sh # shared helpers (assert_*, zorb wrapper) + run.sh # discovery + runner + shell/ # shell-step behaviour + code/ # cjs + python actions + docker/ # docker-step behaviour (skipped without docker) + nested-workflows/ # uses: ./zorb. + cross-file composition +``` + +### Running them + +The harness runs the compiled binary at `dist//zorb` — it does **not** auto-build, because (a) the build belongs +to its own CI step and (b) a silent rebuild hides the wrong-binary class of bug. Build first: + ```sh -bun run build -- --current # build the host binary first -./integration-tests/run.sh # run all -./integration-tests/run.sh shell/basic.test.sh # run one test (path relative to integration-tests/) -ZORB_BIN=/path/to/zorb ./integration-tests/run.sh # point at a binary built elsewhere +bun run build -- --current ``` -The harness exits with a `build it first` hint if `dist//zorb` is missing — we don't auto-build, so the binary -under test is always one you explicitly produced. +Then: -Tests that need optional tooling (`docker`, `python3`) skip cleanly when it's missing. Set `ZORB_REQUIRE_DOCKER=1` or -`ZORB_REQUIRE_PYTHON=1` to flip a missing tool into a hard failure — CI uses these per-runner so coverage stays honest -on platforms where the tool _should_ be present (Linux ships docker; macOS GitHub-hosted runners don't). +```sh +bun run test:integration # run all +./integration-tests/run.sh shell/basic.test.sh # run one (path relative to integration-tests/) +ZORB_BIN=/path/to/zorb ./integration-tests/run.sh # point at a binary built elsewhere +``` -Adding a test: drop a `.test.sh` (and any fixtures) into one of the four suite directories, source -`integration-tests/lib.sh`, and use `zorb …` (already pointed at the binary under test) plus the `assert_*` helpers. +### Skip vs require -## Commit style +Tests that need optional tooling (Docker, Python 3) **skip cleanly** when it's missing, so the suite stays green on +machines that don't have them. -- One commit per logical change. -- Subject line is short and imperative: `A2: walk parents for zorb.yml`, `fix run: cwd default`, etc. -- Wrap the body at ~72 chars. Explain the _why_, not the _what_. -- No AI-tool trailers. +To turn a missing tool into a **hard failure** instead (so coverage stays honest), set: -## Pull requests +- `ZORB_REQUIRE_DOCKER=1` +- `ZORB_REQUIRE_PYTHON=1` -- Branch from `main`. Name branches `feat/`, `fix/`, or `chore/`. -- Before pushing: `bun run typecheck && bun run test:unit && bun run test:integration && bun run format`. -- Keep PRs small. If a milestone spans multiple files, split where it makes sense — each commit should leave the tree - green. +CI sets these per-runner — the Linux runner requires Docker; macOS GitHub-hosted runners don't have a daemon, so they +skip. + +### Adding a test + +Drop a `.test.sh` (and any fixtures) into one of the four suite directories: + +```sh +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/../lib.sh" + +zorb run my-task --with foo=bar > out.log +assert_contains out.log "expected output" +``` + +`zorb` inside a test is already pointed at the binary under test. Use `assert_*` helpers from `lib.sh` instead of +hand-rolling `[[ ]]` comparisons — error messages stay consistent. + +--- + +## Publishing packages + +Releases are driven by [changesets](https://github.com/changesets/changesets) and the `.github/workflows/release.yml` +pipeline. **No manual tagging, no manual `npm publish`** — merging a PR with a changeset is the entire mechanism. + +### Adding a changeset + +Any PR that changes user-visible behaviour needs a changeset: + +```sh +bunx changeset +``` + +Pick the bump type (`patch` / `minor` / `major`) and write a short summary — that summary lands in `CHANGELOG.md` and +the GitHub Release notes verbatim. The command creates a markdown file under `.changeset/`; commit it with the rest of +your changes. + +Skip the changeset for changes that are invisible to users (CI tweaks, internal refactors, doc-only edits in `docs/`). + +### What happens on merge to `main` + +The `Release` workflow runs on every push to `main`: + +1. **If there are unprocessed changesets** in `.changeset/`, [changesets/action](https://github.com/changesets/action) + opens (or updates) a PR titled `ci: version packages`. That PR bumps `package.json`, regenerates `CHANGELOG.md`, and + deletes the consumed changeset files. +2. **When the version PR merges,** the workflow runs again — this time there are no changesets and `package.json` has a + bumped version. `changesets/action` runs `npx changeset publish`, which: + - Runs `prepack` → `bun run build` → cross-compiles the four-platform binaries into `dist/`. + - Publishes the package to NPM via [npm Trusted Publisher](https://docs.npmjs.com/trusted-publishers) — the GitHub + OIDC token (granted by `id-token: write`) is exchanged for publish rights. No `NPM_TOKEN` required. `--provenance` + and `--access public` come from `publishConfig` in `package.json`. + - Creates a `v` GitHub Release with the new `CHANGELOG.md` section as the body + (`createGithubReleases: true`). +3. **Then,** conditional steps in the workflow package each of the four binaries as `zorb-.tar.gz` (containing + `zorb-/bin/zorb` + `zorb-/runners/`), generate a `SHA256SUMS` file, and attach the lot to the + release via `gh release upload --clobber`. + +### Common scenarios + +| Situation | What to do | +| ------------------------------------ | --------------------------------------------------------------------- | +| New feature, bugfix, breaking change | Add a changeset (`bunx changeset`) in your PR. Done. | +| CI / dev-only / doc-only change | No changeset needed. | +| Forgot a changeset on a merged PR | Open a follow-up PR with just the changeset file. | +| Multiple PRs, single release | Each PR adds its own changeset. They bundle into the next version PR. | + +### Things not to do + +- Don't bump `version` in `package.json` by hand — the version PR does it. +- Don't tag releases manually — `changesets/action` creates the `v` tag + GitHub Release as part of publish. +- Don't run `npm publish` from your laptop — Trusted Publisher provenance only works from the CI workflow. +- Don't merge the `ci: version packages` PR until you're happy with the bundled changelog. Re-running the workflow on a + later push will update the PR in place. + +### Pre-release checklist (the version PR) + +When the bot's `ci: version packages` PR is open and ready to merge: + +1. CI is green on `main` (so no regression rides along). +2. `CHANGELOG.md` reads sensibly — if a changeset summary is unclear, edit it on the version PR before merging. +3. The version bump matches the change set (patch/minor/major). If it doesn't, push an extra changeset to the source + branch and re-merge. + +That's it — merging publishes. diff --git a/README.md b/README.md index d017c94..5d8ce71 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,17 @@ # zorb -Declarative local workflow runner. Define tasks in `zorb.yml`, run them with `zorb run `. +Declarative local workflow runner. Define your project's tasks once in `zorb.yml`, run them anywhere. -> Early development — the CLI parses commands but doesn't execute tasks yet. +[![NPM version](https://img.shields.io/npm/v/zorb.svg)](https://www.npmjs.com/package/zorb) +[![License](https://img.shields.io/npm/l/zorb.svg)](./LICENSE) + +> Early development. The shape of the YAML and CLI may still shift before 1.0. + +## Why + +Most projects accumulate ad-hoc shell scripts, Makefiles, and `package.json` scripts that drift apart as the project +grows. `zorb` replaces them with a single declarative file. Tasks, inputs, environment, and step composition all live in +`zorb.yml` — and the same workflow runs locally and in CI. ## Example @@ -12,9 +21,11 @@ tasks: build: description: Build the project steps: - - run: echo "Building..." + - run: bun install --frozen-lockfile + - run: bun run build deploy: + description: Deploy to a target environment inputs: environment: type: string @@ -22,23 +33,59 @@ tasks: env: TARGET: ${{ inputs.environment }} steps: - - run: echo "Deploying to $TARGET" + - uses: ./zorb.build + - run: ./scripts/deploy.sh ``` ```sh -zorb run build -zorb run deploy --with environment=staging -zorb list -zorb --help +zorb list # list every task +zorb run build # run a task +zorb run deploy --with environment=staging # pass inputs +zorb run build --watch # re-run on file changes +zorb init # scaffold a zorb.yml +zorb --help # everything else ``` +## Features + +- **Shell, Docker, and code actions.** Run shell commands directly, inside a Docker container, or invoke JavaScript, + TypeScript, or Python actions in the same workflow. +- **Inputs, env, and expressions.** Borrows expression syntax (`${{ }}`), inputs, outputs, and secrets from GitHub + Actions — so it feels obvious from the first read. +- **Composition over orchestration.** Call other tasks (`uses: ./zorb.`) including across files. No DAG, no + `needs:`, no parallel-step config — keep workflows readable. +- **Strict environment.** Steps don't inherit your shell's environment by default. Workflows declare what they need. +- **Single binary.** Distributed via NPM as a self-contained binary per platform — no Node version juggling. + ## Install -Not yet published. See [CONTRIBUTING.md](./CONTRIBUTING.md) to run from source. +```sh +# via npm (recommended) +npm install -g zorb + +# or run without installing +npx zorb --help +``` + +Homebrew distribution is on the roadmap. + +## Documentation + +Full guide, CLI reference, workflow reference, cookbook, and CI integration notes: + +→ **** + +Quick links: + +- [Getting started](https://zorb.run/guide/getting-started) +- [Workflow reference](https://zorb.run/reference/workflow) +- [CLI reference](https://zorb.run/reference/cli) +- [Cookbook](https://zorb.run/cookbook/) -## Links +## Contributing -- Contributing: [CONTRIBUTING.md](./CONTRIBUTING.md) +Bug reports, feature ideas, and PRs are all welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for the dev loop, testing +guide, and release process. ## License From e3965b4c115f9963f4b6efd3e6a845876c1584f6 Mon Sep 17 00:00:00 2001 From: James Dryden Date: Fri, 26 Jun 2026 23:01:38 +0100 Subject: [PATCH 3/5] chore: prettier reformat Whitespace-only changes picked up by `bun run format`. --- .changeset/README.md | 6 +++--- src/action.ts | 8 +------- src/utils/resolve.ts | 6 +----- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/.changeset/README.md b/.changeset/README.md index 654c6d4..7ace9a7 100644 --- a/.changeset/README.md +++ b/.changeset/README.md @@ -1,8 +1,8 @@ # Changesets -Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works -with multi-package repos, or single-package repos to help you version and publish your code. You can -find the full documentation for it [in our repository](https://github.com/changesets/changesets). +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with +multi-package repos, or single-package repos to help you version and publish your code. You can find the full +documentation for it [in our repository](https://github.com/changesets/changesets). We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md). diff --git a/src/action.ts b/src/action.ts index 644d709..3be1395 100644 --- a/src/action.ts +++ b/src/action.ts @@ -9,13 +9,7 @@ /** Raw `with:` payload passed to an action function. Always `unknown` — validate before use. */ export type ActionInput = unknown; -type ActionOutputValue = - | string - | number - | boolean - | null - | ActionOutputValue[] - | { [key: string]: ActionOutputValue }; +type ActionOutputValue = string | number | boolean | null | ActionOutputValue[] | { [key: string]: ActionOutputValue }; type ActionOutputs = { [key: string]: ActionOutputValue }; diff --git a/src/utils/resolve.ts b/src/utils/resolve.ts index f254278..3f278bd 100644 --- a/src/utils/resolve.ts +++ b/src/utils/resolve.ts @@ -133,11 +133,7 @@ function resolveWorkflowRef( return { kind: 'workflow', workflowPath, taskName }; } -function pickWorkflowFile( - dir: string, - uses: string, - onWarning: ((message: string) => void) | undefined, -): string { +function pickWorkflowFile(dir: string, uses: string, onWarning: ((message: string) => void) | undefined): string { const matches: string[] = []; for (const ext of WORKFLOW_EXTENSIONS) { const candidate = join(dir, `zorb${ext}`); From 4360eee3043ed7d515f4743bfa858cfa70749bd5 Mon Sep 17 00:00:00 2001 From: James Dryden Date: Fri, 26 Jun 2026 23:06:09 +0100 Subject: [PATCH 4/5] chore: add changeset for 0.1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First documented release. Bumps minor (0.0.6 → 0.1.0) as the clean break — the A-track core is feature-complete and the package is now publicly installable from NPM. --- .changeset/bumpy-toes-sing.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .changeset/bumpy-toes-sing.md diff --git a/.changeset/bumpy-toes-sing.md b/.changeset/bumpy-toes-sing.md new file mode 100644 index 0000000..d4b690c --- /dev/null +++ b/.changeset/bumpy-toes-sing.md @@ -0,0 +1,16 @@ +--- +'zorb': minor +--- + +First documented release of `zorb`. The A-track core is feature-complete: + +- Shell, Docker, and code-action steps (JS, TS, CJS, MJS, Python) +- Strict workflow validation with line/column-precise errors +- `${{ }}` expression engine with operators, ternaries, and a starter filter set +- Task inputs, secrets, env registration, and cross-file composition via `uses:` +- Step controls — timeouts, retries, and clean signal handling +- `zorb init` and `--watch` mode +- Cross-compiled binaries for `darwin`/`linux` × `x64`/`arm64` published to NPM with provenance +- End-to-end shell-script integration test suite + +Install with `npm install -g zorb`. Full guide and reference at . From 8fe0f4a689b1c5cef9f11dc0b6b3ffabc1b1d7ac Mon Sep 17 00:00:00 2001 From: jdrydn Date: Fri, 26 Jun 2026 23:20:02 +0100 Subject: [PATCH 5/5] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5d8ce71..e514504 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ zorb --help # everything else - **Composition over orchestration.** Call other tasks (`uses: ./zorb.`) including across files. No DAG, no `needs:`, no parallel-step config — keep workflows readable. - **Strict environment.** Steps don't inherit your shell's environment by default. Workflows declare what they need. -- **Single binary.** Distributed via NPM as a self-contained binary per platform — no Node version juggling. +- **Native binaries.** Distributed via NPM with a tiny Node shim (`bin/zorb.cjs`) that dispatches to the right `dist//zorb` binary. ## Install