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
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,39 @@ jobs:
- name: Install graphviz (codeshot renders via `dot`)
run: sudo apt-get update && sudo apt-get install -y graphviz
- run: npm test

diagrams:
name: Diagrams are current (codeshot --check)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "20"

# codeshot renders through graphviz. --check compares diagram STRUCTURE
# (node/edge set) for svg, not rendered bytes, so the CI graphviz version
# need not match the one that generated the committed image.
- name: Install graphviz
run: sudo apt-get update && sudo apt-get install -y graphviz

# The index codeshot reads. Pinned (repo convention: pin dependency versions).
- name: Install codegraph
run: npm install -g @colbymchenry/codegraph@1.4.1

# `init` builds the initial index in a fresh checkout (`index` rebuilds an
# existing one and errors if the repo was never initialized — which a CI
# checkout, with no committed .codegraph, never was).
- name: Build the codegraph index
run: |
codegraph init .
codegraph status . # visibility: a partial index prints an unresolved-refs warning

# Blocking gate: fail the PR if either committed diagram no longer matches
# what the current code produces. Structural compare = graphviz-version proof.
- name: Check committed diagrams are current
run: |
node render/callgraph.js --architecture --path . --format svg \
--out docs/architecture.svg --embed TECHNICAL.md --check
node render/callgraph.js buildDot --path . --format svg \
--out docs/buildDot-callgraph.svg --embed TECHNICAL.md --check
8 changes: 5 additions & 3 deletions TECHNICAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,13 @@ See [README.md](README.md#design-decisions)'s "Design decisions" section for why

### Example: Codeshot, drawn by Codeshot

The diagram below is not hand-drawn — it was produced by running Codeshot on its own CodeGraph index (`codeshot buildDot --path . --format svg --out docs/buildDot-callgraph.svg`) and committed verbatim. It draws the call trail of `buildDot`, the pure heart of the tool:
The diagram below is not hand-drawn — it was produced by running Codeshot on its own CodeGraph index (`codeshot buildDot --path . --format svg --out docs/buildDot-callgraph.svg --embed TECHNICAL.md`) and committed verbatim. It draws the call trail of `buildDot`, the pure heart of the tool:

![Call graph of buildDot, generated by Codeshot](docs/buildDot-callgraph.svg)
<!-- codeshot:buildDot:start -->
![buildDot call graph — generated by codeshot](docs/buildDot-callgraph.svg)
<!-- codeshot:buildDot:end -->

It doubles as a live legend for the [Visual Encoding](#visual-encoding) rules below. `main` calls `buildDot` at a real call site, so that edge is a solid indigo arrow. `test/run.js` only does `require('./render/callgraph.js')` — a module-level import, not a function-level call — so CodeGraph reports it as `"kind":"file"` and Codeshot draws it dotted/gray, labeled `file`, rather than pretending it's a confirmed call. (That file-kind styling wins even though `run.js` is a test file, which would otherwise be dashed — the precedence rule described in [Visual Encoding](#visual-encoding).) On the right, the five callees are the pure helpers `buildDot` composes to turn caller/callee arrays into a DOT string. Regenerate it any time with the command above.
It doubles as a live legend for the [Visual Encoding](#visual-encoding) rules below. `main` calls `buildDot` at a real call site, so that edge is a solid indigo arrow. `test/run.js` only does `require('./render/callgraph.js')` — a module-level import, not a function-level call — so CodeGraph reports it as `"kind":"file"` and Codeshot draws it dotted/gray, labeled `file`, rather than pretending it's a confirmed call. (That file-kind styling wins even though `run.js` is a test file, which would otherwise be dashed — the precedence rule described in [Visual Encoding](#visual-encoding).) On the right, the callees are the pure helpers `buildDot` composes to turn caller/callee arrays into a DOT string. Regenerate it any time with the command above; `--check` (see [USAGE.md](USAGE.md)) fails CI if the code drifts from this committed picture.

**Why is `buildDot` exported from a file that also runs as a CLI?**
`render/callgraph.js` guards its `main()` call with `if (require.main === module)`, so `node render/callgraph.js <symbol>` still runs the CLI, but `require('./render/callgraph.js')` (used by `test/run.js`) gets `{ buildDot, isTestRef }` without executing anything. This keeps the test suite dependency-free — no test framework, no mocking of `execFileSync`.
Expand Down
14 changes: 10 additions & 4 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,16 @@ codeshot --architecture --path . --embed TECHNICAL.md --format svg --check
```

Drop that into CI or a pre-commit hook to fail the build when someone changes
the code but not the diagram. One caveat, inherent to any "regenerate and diff
a binary artifact" check: it compares rendered bytes, so CI must use the same
`graphviz` version that generated the committed image, or it will report a
spurious mismatch.
the code but not the diagram. For `svg` output (the recommended `--embed`
format) `--check` compares the diagram's **structure** — the set of nodes and
call edges — not the raw rendered bytes, so it is **graphviz-version
independent**: the committed image and the CI machine can run different
`graphviz` builds without a spurious mismatch. By design it only fails on
*structural* drift (a caller/callee/edge appearing or disappearing); a
cosmetic-only change with the identical graph — e.g. a re-color — is not
flagged. Non-`svg` formats (png, svgz, …) have no recoverable structure and
fall back to a raw byte-compare, which does require CI to use the same
`graphviz` version that generated the committed image.

## What to Do When Something Breaks

Expand Down
Loading
Loading