Metadata-Version: 2.4
Name: forgewatch-ci
Version: 0.1.1
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Rust
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Software Development :: Testing
License-File: LICENSE
Summary: Single-binary, local-first CI runner: YAML pipelines, DAG scheduling, artifact cache, and a live web dashboard. Ships the Rust binary as a console script, ruff-style.
Keywords: ci,cd,pipeline,automation,devtools,cli
Author: Makeph
License: MIT
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/Makeph/forgewatch
Project-URL: Issues, https://github.com/Makeph/forgewatch/issues
Project-URL: Repository, https://github.com/Makeph/forgewatch

# forgewatch

[![CI](https://github.com/Makeph/forgewatch/actions/workflows/ci.yml/badge.svg)](https://github.com/Makeph/forgewatch/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

**A single-binary, local-first CI runner.** Define a pipeline in YAML, run it
from your terminal, or watch it re-run on every save — with a live web dashboard
that streams logs as they happen. No Docker, no cloud, no daemon fleet. One Rust
binary, one SQLite file, zero external services.

Think of it as the CI you actually run *on your machine*: the same pipeline that
runs in the cloud, but fast, offline, and observable — great for tightening the
edit → build → test loop before you ever push.

```
┌──────────────────────────────────────────────────────────────┐
│  forgewatch serve --watch                                      │
│    • parses forgewatch.yml                                     │
│    • schedules jobs as a DAG (needs:)                          │
│    • runs steps as subprocesses, streams stdout/stderr         │
│    • caches unchanged jobs by content hash                     │
│    • serves a live dashboard at http://127.0.0.1:7878          │
└──────────────────────────────────────────────────────────────┘
```

## Features

- **DAG scheduling** — jobs declare `needs:`; independent jobs run concurrently,
  dependents wait, cycles are rejected up front.
- **Content-addressed cache** — a job's `cache_key` globs are hashed; on a match
  the job is skipped and its `cache` outputs restored. Rebuild only what changed.
- **Live dashboard** — a self-contained web UI (zero external requests) streams
  logs over Server-Sent Events, with per-job status cards and full run history.
- **Watch mode** — edits matching `watch:` globs re-trigger the pipeline,
  debounced, so saving a file kicks off a build automatically.
- **Full history** — every run, job, and log line is persisted in a WAL-mode
  SQLite database, so you can replay any past build in the dashboard.
- **Single binary** — Rust + Tokio + axum. Copy it anywhere and go.

## Install

```sh
cargo install --path .
# or
cargo build --release   # -> target/release/forgewatch
```

## Quickstart

```sh
forgewatch init                 # writes a starter forgewatch.yml
forgewatch run                  # run once, stream logs to the terminal
forgewatch serve --watch        # dashboard at http://127.0.0.1:7878, auto-rerun
```

## Pipeline format

```yaml
name: demo-ci

# Files that re-trigger the pipeline in `serve --watch`.
watch:
  - "src/**/*"

# Environment inherited by every job and step.
env:
  APP: forgewatch

jobs:
  - name: lint
    steps:
      - name: check
        run: cargo clippy --all-targets

  - name: build
    needs: [lint]              # runs after lint succeeds
    cache_key:                 # hash these inputs...
      - "src/**/*"
      - "Cargo.toml"
    cache:                     # ...restore these outputs on a cache hit
      - "target/release"
    steps:
      - name: compile
        run: cargo build --release

  - name: test
    needs: [build]
    steps:
      - name: unit
        run: cargo test
      - name: bench
        continue_on_error: true   # a non-zero exit here won't fail the job
        run: cargo bench
```

### Step fields

| field               | meaning                                                        |
|---------------------|----------------------------------------------------------------|
| `run`               | command line to execute (required)                             |
| `shell`             | shell override, e.g. `bash -c` (default: `cmd /C` on Windows, `sh -c` elsewhere) |
| `workdir`           | working directory, relative to the pipeline file              |
| `env`               | step-level environment (overrides job/pipeline)               |
| `continue_on_error` | if `true`, a non-zero exit does not fail the job              |

> **Shell note:** variable expansion follows the shell. `$VAR` works under
> `sh`/`bash`; on the Windows default (`cmd`) use `%VAR%`, or set
> `shell: bash -c` for a step.

## Commands

| command                       | description                                        |
|-------------------------------|----------------------------------------------------|
| `forgewatch init`             | scaffold a starter `forgewatch.yml`                |
| `forgewatch run [-f file]`    | run once; exit code is non-zero if any job fails   |
| `forgewatch serve [-f file] [-p port] [-w]` | serve the dashboard; `-w` enables watch mode |

State lives in `.forgewatch/` next to your pipeline (`runs.db` + `cache/`).

## Examples

Runnable pipelines live in [`examples/`](examples):

| example | shows |
|---|---|
| [`demo`](examples/demo/forgewatch.yml) | DAG deps, job caching, `continue_on_error` |
| [`parallel`](examples/parallel/forgewatch.yml) | fan-out / fan-in — concurrent jobs in one wave |
| [`rust-ci`](examples/rust-ci/forgewatch.yml) | real-world Rust CI template (fmt → clippy/build → test) |

```sh
forgewatch run --file examples/parallel/forgewatch.yml
```

## How it fits together

```
main.rs      CLI (init / run / serve)
config       YAML pipeline schema  ......... model.rs
engine       DAG scheduler + streaming steps  engine.rs
store        SQLite run/job/log history ..... store.rs
cache        content-addressed job cache .... cache.rs
watch        debounced filesystem trigger ... watch.rs
server       axum API + SSE + embedded UI ... server.rs + web/index.html
```

## License

MIT — see [LICENSE](LICENSE).

