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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"Bash(git commit*)"
],
"deny": [
"Bash(git stash*)",
"Bash(git revert*)",
"Bash(git checkout*)",
"Bash(git rebase*)",
Expand Down
6 changes: 3 additions & 3 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Committed pre-push hook. Runs the fast lint gate (`make fmt clippy`) before any push so formatting/clippy failures are caught locally
# Committed pre-push hook. Runs the fast gate (`make fmt-check clippy`) before any push so formatting/clippy failures are caught locally
# Enable once per clone: make install-hooks (sets core.hooksPath=.githooks)
# Bypass in an emergency: git push --no-verify
set -euo pipefail
Expand All @@ -8,8 +8,8 @@ set -euo pipefail
repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"

echo "pre-push: running lint checks (fmt + clippy)…"
if ! make fmt clippy; then
echo "pre-push: running lint checks (fmt-check + clippy)…"
if ! make fmt-check clippy; then
echo
echo "pre-push: lint checks failed - push aborted." >&2
echo "Fix the issues above, or bypass with 'git push --no-verify' (not recommended)." >&2
Expand Down
13 changes: 12 additions & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -449,9 +449,20 @@ jobs:
sed 's/^version = ".*"/version = "'"$V"'"/' Cargo.toml > Cargo.toml.tmp && mv Cargo.toml.tmp Cargo.toml
cargo update --workspace

# Build release with embedded UI
# Build release with embedded UI.
#
# Add `OPERATOR_RELEASE: "1"` below once OPERATOR_LICENSE_PUBLIC_KEYS and
# OPERATOR_LICENSE_ISSUER exist as repository secrets. build.rs then
# refuses to produce an artifact without them, because a build with no
# verification keys rejects every licence - a silent, total Premium
# outage. Until then the keys are passed through when set and the build
# succeeds either way.
- name: Build release
run: cargo build --locked --release --features embed-ui --target ${{ matrix.target }}
env:
OPERATOR_LICENSE_PUBLIC_KEYS: ${{ secrets.OPERATOR_LICENSE_PUBLIC_KEYS }}
OPERATOR_LICENSE_ISSUER: ${{ secrets.OPERATOR_LICENSE_ISSUER }}
OPERATOR_PURCHASE_URL: ${{ vars.OPERATOR_PURCHASE_URL }}

- name: Rename binary
shell: bash
Expand Down
47 changes: 29 additions & 18 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,32 @@ Write superpowers plans to `superpowers/plans/` and design specs to `superpowers

### Mandatory Before Committing

All changes MUST pass these checks before committing. Run them with `make check`, which mirrors the CI `lint-test` job exactly:
All changes MUST pass these checks before committing. Run them with `make check`,
which is `fmt-check` + `lint` + `test` - each verb striped across every module:

```bash
make check
# equivalent to the exact CI commands:
cargo fmt --all -- --check # Format check
cargo clippy --locked --all-targets --all-features -- -D warnings # Lint (warnings are errors)
cargo test --locked # Run all tests
make relay # crates/relay (not a workspace member)
make fmt-ts # oxfmt --check, every JS/TS subproject
make lint-ts # oxlint, every JS/TS subproject
make lint-shell # shellcheck -S warning
# fmt-check: report-only formatting, per module
make fmt-check-rust # cargo fmt --check: root, crates/relay, opr8r, zed-extension
make fmt-check-ts # oxfmt --check, every JS/TS subproject
make fmt-check-tf # terraform fmt -check -diff (coder-module)
# lint: warnings are errors everywhere
make lint-rust # clippy --locked --all-targets --all-features, all 4 crates
make lint-ts # oxlint --type-aware, every JS/TS subproject
make lint-shell # shellcheck -S warning
make lint-helm # helm lint charts/operator
make lint-tf # terraform validate + rendered coder_script check
# test
make test-rust # cargo test --locked --all-features, all 3 crates
make test-ts # webcomponents + coder-module suites
```

`make fmt` is the same striping in rewrite mode (`cargo fmt`, `bun run fmt`,
`terraform fmt`); only `fmt-check` gates. `make relay` / `make opr8r` /
`make vscode-extension` run every gate for one module when only it changed.
Display-bound suites stay off `make test`: `make vscode-extension` (Electron)
and `make storybook` (browser + axe) are run on their own.

Formatting and linting are enforced for every subproject, not just the main
crate. Rust uses `cargo fmt`/`clippy` (root, `crates/relay`, `opr8r`,
`zed-extension`), JS/TS uses root-installed `oxfmt` + `oxlint` (`ui`,
Expand All @@ -65,8 +77,8 @@ excluded by `.oxfmtrc.json` / `.oxlintrc.jsonc` and must never be reformatted.
> deprecation that only surfaces under `--all-targets`), which is how a clippy
> failure can pass locally yet break CI. Always use the full command above.

Install the pre-push hook once per clone so the fast lint gate (fmt + clippy,
no tests) runs automatically before every push; the full `make check` remains
Install the pre-push hook once per clone so the fast gate (`fmt-check` +
root `clippy`, no tests) runs automatically before every push; the full `make check` remains
the expectation before opening a PR:

```bash
Expand Down Expand Up @@ -127,13 +139,12 @@ make check
## Quick Reference

```bash
make check # Full CI-parity gate (Rust + relay + JS/TS + shell)
bun run fmt # Format every JS/TS subproject in place
bun run lint # oxlint across every JS/TS subproject
make install-hooks # Install the lint-only pre-push hook (once per clone)
cargo fmt # Format code
cargo clippy --locked --all-targets --all-features -- -D warnings # Lint (CI parity)
cargo test # Run all tests
make check # Full gate: fmt-check + lint + test, every module
make fmt # Rewrite formatting in every module
make lint # Every linter: clippy, oxlint, shellcheck, helm, terraform
make test # Rust + fast JS/TS suites
make vscode-extension # Compile + lint the extension (incl. the webview bundle)
make install-hooks # Install the fast pre-push hook (once per clone)
cargo test <name> # Run specific test
cargo run # Run TUI
cargo run -- queue # CLI: show queue
Expand Down
13 changes: 2 additions & 11 deletions Dockerfile.local
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,11 @@ RUN apt-get update \

WORKDIR /src

# bindings/ is committed (CI only verifies freshness), so `make bindings` --
# i.e. a full cargo test run -- is not needed to type the frontend.
COPY bindings/ ./bindings/

# webcomponents first: ui/ resolves @operator/webcomponents to
# ../webcomponents/dist/index.js by vite alias, a dist-artifact dependency
# rather than a package dependency, so the order is load-bearing.
COPY webcomponents/ ./webcomponents/
RUN cd webcomponents && bun install --frozen-lockfile && bun run build

# ui/src/index.css @imports the brand tokens from the docs site, which is the
# single source of truth for them (docs/design-system/). The SPA build needs
# that one file even though nothing else of docs/ is involved.
# ui/src/index.css @imports the brand tokens from the docs site, which is the source of truth for them (docs/design-system/).
COPY docs/assets/css/ ./docs/assets/css/
COPY ui/ ./ui/
RUN cd ui && bun install --frozen-lockfile && bun run build
Expand All @@ -38,8 +30,7 @@ COPY --from=web /src/ui/dist ./ui/dist

RUN cargo build --release --locked --bin operator

# opr8r is a separate cargo project with its own Cargo.lock, not a workspace
# member, so it needs its own invocation.
# opr8r is a separate cargo project with its own Cargo.lock, not a workspace member, so it needs its own invocation.
RUN cd opr8r && cargo build --release --locked

# Mirrors Dockerfile; only the operator/opr8r binary source differs.
Expand Down
128 changes: 103 additions & 25 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,38 +1,72 @@
# Operator developer tasks.
#
# `make check` mirrors the CI `lint-test` job exactly so a clean local run means
# a clean CI run. `make install-hooks` wires the committed pre-push hook, which
# runs the fast lint gate (fmt + clippy, no tests) before every push.
# The three verbs stripe across every module: `make fmt` rewrites, `make
# fmt-check`, `make lint` and `make test` gate. `make check` runs all three
# gates and is the pre-PR bar. `make install-hooks` wires the committed pre-push
# hook, which runs the fast gate (root fmt-check + clippy, no tests).

.PHONY: check fmt fmt-check lint test clippy build run install-hooks bindings \
webcomponents storybook ui docs vscode-extension relay opr8r \
fmt-rust fmt-ts fmt-tf fmt-check-rust fmt-check-ts fmt-check-tf \
lint-rust lint-ts lint-shell lint-helm lint-tf test-rust test-ts

# CI installs terraform; local dev machines may only have OpenTofu.
TF := $(shell command -v terraform >/dev/null 2>&1 && echo terraform || echo tofu)

# Full gate. The commands below are the same ones CI runs, so a clean local run
# means a clean CI run.
check: fmt-check lint test

# Rewrite formatting in every module. `fmt-check` is the same pass in report
# mode, and is what `check` and the pre-push hook run.
fmt: fmt-rust fmt-ts fmt-tf

fmt-check: fmt-check-rust fmt-check-ts fmt-check-tf

# crates/relay, opr8r and zed-extension have their own Cargo.lock and are not
# workspace members, so `--all` never reaches them.
fmt-rust:
cargo fmt --all
cd crates/relay && cargo fmt
cd opr8r && cargo fmt
cd zed-extension && cargo fmt

fmt-check-rust:
cargo fmt --all -- --check
cd crates/relay && cargo fmt -- --check
cd opr8r && cargo fmt -- --check
cd zed-extension && cargo fmt -- --check

# oxfmt is installed once at the repo root and covers every hand-written JS/TS
# subproject.
fmt-ts:
bun install --frozen-lockfile
bun run fmt

.PHONY: check fmt clippy test build run install-hooks bindings webcomponents storybook ui docs \
fmt-ts lint-ts lint-shell relay
fmt-check-ts:
bun install --frozen-lockfile
bun run fmt:check

# Full CI-parity gate. Keep these commands byte-identical to
# .github/workflows/build.yaml so local and CI never disagree.
check: fmt clippy test relay fmt-ts lint-ts lint-shell
fmt-tf:
cd coder-module && $(TF) fmt

fmt:
cargo fmt --all -- --check
fmt-check-tf:
cd coder-module && $(TF) fmt -check -diff

lint: lint-rust lint-ts lint-shell lint-helm lint-tf

# Root workspace only: the fast gate the pre-push hook pairs with fmt-check.
clippy:
cargo clippy --locked --all-targets --all-features -- -D warnings

test:
cargo test --locked

# crates/relay has its own Cargo.lock and is not a workspace member, so the
# targets above never reach it.
relay:
cd crates/relay && cargo fmt -- --check
# zed-extension compiles to wasm, so its lints only resolve under that target.
lint-rust: clippy
cd crates/relay && cargo clippy --locked --all-targets --all-features -- -D warnings
cd crates/relay && cargo test --locked --all-features

# oxfmt/oxlint are installed once at the repo root and cover every hand-written
# JS/TS subproject. `bun run fmt` (no :check) rewrites instead of reporting.
fmt-ts:
bun install --frozen-lockfile
bun run fmt:check
cd opr8r && cargo clippy --locked --all-targets --all-features -- -D warnings
cd zed-extension && cargo clippy --locked --target wasm32-wasip1 -- -D warnings

# The type-aware lints resolve each subproject's node_modules and copy-types
# output, so install those first (`make ui`, `make vscode-extension`).
lint-ts:
bun run lint:ui
bun run lint:webcomponents
Expand All @@ -43,6 +77,39 @@ lint-ts:
lint-shell:
shellcheck -S warning scripts/*.sh scripts/ci/*.sh .githooks/*

lint-helm:
helm lint charts/operator

# The rendered coder_script is what actually runs in a workspace, so a bash
# syntax error there is a broken module.
lint-tf:
cd coder-module && $(TF) init -input=false && $(TF) validate
scripts/ci/check-coder-module.sh

test: test-rust test-ts

test-rust:
cargo test --locked --all-features
cd crates/relay && cargo test --locked --all-features
cd opr8r && cargo test --locked --all-features

# Display-bound suites (vscode-extension, storybook) stay on their own targets.
test-ts:
bun install --frozen-lockfile
cd webcomponents && bun install --frozen-lockfile && bun run test
cd coder-module && bun test

# Every gate for one module, for when only that module changed.
relay:
cd crates/relay && cargo fmt -- --check
cd crates/relay && cargo clippy --locked --all-targets --all-features -- -D warnings
cd crates/relay && cargo test --locked --all-features

opr8r:
cd opr8r && cargo fmt -- --check
cd opr8r && cargo clippy --locked --all-targets --all-features -- -D warnings
cd opr8r && cargo test --locked --all-features

# Optimized release binary at target/release/operator.
build:
cargo build --release
Expand Down Expand Up @@ -73,6 +140,17 @@ storybook: webcomponents
ui: webcomponents
cd ui && bun install --frozen-lockfile && bun run build

# The VS Code extension. Mirrors the compile steps of the CI
# `test-vscode-extension` job; `compile:webview` type-checks the webview bundle,
# which no other target reaches. Depends on `bindings` because copy-types copies
# them into vscode-extension/src/generated.
vscode-extension: bindings
cd vscode-extension && npm ci
cd vscode-extension && npm run compile
cd vscode-extension && npm run compile:webview
cd vscode-extension && npm run lint
cd vscode-extension && npm run fmt:check

# Full docs pipeline: bindings, generated reference docs and the hosted
# collection bundle, the shared components bundle, then Jekyll. Mirrors the
# ordering in .github/workflows/docs.yml.
Expand All @@ -89,4 +167,4 @@ docs: webcomponents
# One-time per clone: route git hooks at the committed .githooks/ directory.
install-hooks:
git config core.hooksPath .githooks
@echo "pre-push hook installed (runs 'make fmt clippy')"
@echo "pre-push hook installed (runs 'make fmt-check clippy')"
Loading
Loading