Skip to content

Commit 3efd5b6

Browse files
fix: install CodeBoarding engine from PyPI
Amp-Thread-ID: https://ampcode.com/threads/T-019edcb0-130a-713d-8e97-997ec5e29b33 Co-authored-by: Amp <amp@ampcode.com>
1 parent fbb0900 commit 3efd5b6

4 files changed

Lines changed: 54 additions & 99 deletions

File tree

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ Review mode does not need `contents: write`: PR-specific generated files are sto
262262
| `mode` | both | `review` | `review` posts the PR architecture-diff comment; `sync` analyzes on push and commits the architecture (`analysis.json` + rendered docs) to `target_branch`, keeping it versioned and current. |
263263
| `github_token` | both | `${{ github.token }}` | Token for GitHub API calls; in review mode it posts or updates the PR comment. |
264264
| `push_token` | sync | `${{ github.token }}` | Token used for sync-mode pushes to `target_branch`. The workflow token can push when the workflow grants `permissions: contents: write`. Separate from `github_token` so commenting can use a GitHub App token while the push uses the workflow token. |
265-
| `engine_ref` | both | `v0.12.1` | CodeBoarding engine ref. Pin for reproducibility. |
265+
| `codeboarding_version` | both | `0.12.2` | CodeBoarding PyPI package version used as the analysis engine. Pin for reproducibility. |
266266
| `depth_level` | both | empty (`2` for cold starts) | Analysis depth, 1 to 3, used for first analysis and `force_full` rebuilds. Once `.codeboarding/analysis.json` exists, its `metadata.depth_level` is the source of truth for incremental analysis and fallback-full recovery. |
267267
| `render_depth` | review | `1` | Display depth for the PR diagram. Keep `1` for a clean top-level view. |
268268
| `diagram_direction` | review | `LR` | Mermaid direction: `LR`, `TD`, `TB`, `RL`, or `BT`. |
@@ -296,7 +296,7 @@ Outputs of the mode that did not run are empty strings.
296296

297297
## Notes
298298

299-
- No checkout step is required in your workflow. This action checks out the target (the PR in review mode, the pushed commit in sync mode) and the CodeBoarding engine internally.
299+
- No checkout step is required in your workflow. This action checks out the target (the PR in review mode, the pushed commit in sync mode) and installs the CodeBoarding engine from PyPI internally.
300300
- GitHub withholds secrets from fork PRs on `pull_request`, so fork runs fail early if an LLM key is unavailable.
301301
- Do not use `pull_request_target` for this action. It can expose secrets to PR-head code.
302302
- GitHub renders Mermaid in strict mode, so node click-through links are not supported in the PR diagram.
@@ -313,8 +313,9 @@ Full local pipeline:
313313

314314
```bash
315315
export OPENROUTER_API_KEY=sk-or-...
316-
scripts/run_local.sh --repo /path/to/repo --base <base-ref> --head <head-ref> \
317-
--engine /path/to/CodeBoarding
316+
python -m pip install codeboarding==0.12.2
317+
codeboarding-setup --auto-install-npm
318+
scripts/run_local.sh --repo /path/to/repo --base <base-ref> --head <head-ref>
318319
```
319320

320321
Useful flags:

action.yml

Lines changed: 31 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ inputs:
3131
description: 'Token used for sync-mode git pushes to target_branch. Defaults to the workflow github.token, which can push when the calling workflow grants "permissions: contents: write". Kept separate from github_token so commenting can use a GitHub App token while the push uses the workflow token (whose write access the consumer controls).'
3232
required: false
3333
default: ${{ github.token }}
34-
engine_ref:
35-
description: 'Git ref (tag/branch/SHA) of CodeBoarding/CodeBoarding used as the analysis engine. Pinned to a release for reproducibility; override to track a newer ref.'
34+
codeboarding_version:
35+
description: 'CodeBoarding PyPI package version used as the analysis engine. Pin for reproducibility; set to a newer released version to opt into newer engine releases.'
3636
required: false
37-
default: 'v0.12.1'
37+
default: '0.12.2'
3838
depth_level:
3939
description: 'Analysis depth (1-3) for cold-start or force_full rebuilds. Once .codeboarding/analysis.json exists, its metadata.depth_level is the source of truth for incremental analysis and fallback-full recovery. Empty (default): 2 for cold starts.'
4040
required: false
@@ -142,7 +142,7 @@ runs:
142142
# interleave only because they share the LLM-key lifecycle, NOT because they
143143
# are unrelated:
144144
# 1. GUARD — resolve mode + event eligibility + SHAs (one source of truth)
145-
# 2. SHARED SETUP — checkout engine + target, Python/Node/uv, caches, LLM-key prep
145+
# 2. SHARED SETUP — checkout target, Python/Node/uv, install CodeBoarding, caches, LLM-key prep
146146
# 3. ANALYSIS (key live) — review: base/seed/head/health ; sync: seed/analyze
147147
# 4. Drop LLM key, then OUTPUT (no key) — review: diff→artifact→comment ; sync: render→commit
148148
# The binding between the modes is the committed .codeboarding/analysis.json
@@ -397,15 +397,6 @@ runs:
397397
9.0.x
398398
10.0.x
399399
400-
- name: Checkout CodeBoarding engine
401-
if: steps.guard.outputs.skip != 'true'
402-
uses: actions/checkout@v4
403-
with:
404-
repository: CodeBoarding/CodeBoarding
405-
ref: ${{ inputs.engine_ref }}
406-
path: codeboarding-engine
407-
persist-credentials: false
408-
409400
# Review mode: the PR head repo at the head SHA. Sync mode: this repo at the
410401
# pushed/selected SHA. Always credential-free — sync pushes authenticate
411402
# explicitly via push_token.
@@ -474,54 +465,36 @@ runs:
474465
with:
475466
node-version: '20'
476467

477-
- name: Install uv
478-
if: steps.guard.outputs.skip != 'true'
479-
uses: astral-sh/setup-uv@v4
480-
with:
481-
enable-cache: true # cache ~/.cache/uv (wheels/builds) for fast cold installs
482-
483-
- name: Cache uv venv (engine)
484-
if: steps.guard.outputs.skip != 'true'
485-
uses: actions/cache@v4
486-
with:
487-
path: codeboarding-engine/.venv
488-
# No restore-keys: a lockfile change must force a clean cold venv, not
489-
# restore a venv built from a different lock (`uv pip install -e .` won't
490-
# downgrade/sync already-installed transitive deps back to this uv.lock).
491-
key: cb-uv-${{ runner.os }}-${{ hashFiles('codeboarding-engine/pyproject.toml', 'codeboarding-engine/uv.lock') }}
492-
493468
- name: Cache LSP servers
494469
if: steps.guard.outputs.skip != 'true'
495470
uses: actions/cache@v4
496471
with:
497472
path: |
498-
codeboarding-engine/static_analyzer/servers/node_modules
499-
codeboarding-engine/static_analyzer/servers/bin
500-
key: cb-lsp-${{ runner.os }}-v1
473+
~/.codeboarding/servers
474+
key: cb-lsp-${{ runner.os }}-${{ inputs.codeboarding_version }}-v1
501475
restore-keys: |
502476
cb-lsp-${{ runner.os }}-
503477
504-
- name: Install Python dependencies
478+
- name: Install CodeBoarding package
505479
if: steps.guard.outputs.skip != 'true'
506480
shell: bash
507-
working-directory: codeboarding-engine
481+
env:
482+
CODEBOARDING_VERSION: ${{ inputs.codeboarding_version }}
508483
run: |
509-
# Reuse the cached venv when it's healthy, but rebuild it if its interpreter
510-
# symlink is dead. The cache key is the lockfiles only, NOT the Python patch
511-
# version, so when setup-python provisions a newer patch (e.g. 3.13.13 ->
512-
# 3.13.14) and GitHub GCs the old toolcache dir, the cached `.venv/bin/python3`
513-
# symlink dangles. A bare `test -d .venv` would then reuse it and `uv pip
514-
# install -e .` fails with "Broken symlink … was the underlying Python
515-
# interpreter removed?". Probing the interpreter recreates the venv instead.
516-
.venv/bin/python -c '' 2>/dev/null || uv venv # rebuild on missing/broken venv
517-
uv pip install -e .
484+
set -euo pipefail
485+
SPEC="$CODEBOARDING_VERSION"
486+
case "$SPEC" in
487+
'' ) SPEC='' ;;
488+
[0-9]* ) SPEC="==$SPEC" ;;
489+
esac
490+
python -m pip install --upgrade pip
491+
python -m pip install "codeboarding${SPEC}"
518492
519493
- name: Install LSP servers
520494
if: steps.guard.outputs.skip != 'true'
521495
shell: bash
522-
working-directory: codeboarding-engine
523496
run: |
524-
uv run python install.py --auto-install-npm
497+
codeboarding-setup --auto-install-npm
525498
526499
- name: Prepare & verify LLM key
527500
if: steps.guard.outputs.skip != 'true'
@@ -755,7 +728,7 @@ runs:
755728
# inputs. So a free-tier run (oidc, forced Gemini) and a BYO OpenRouter-key
756729
# run with no model pinned would share a key yet produce different base
757730
# analyses; the mode discriminator keeps them from reusing each other's cache.
758-
key: cb-base-v2-${{ runner.os }}-${{ steps.base.outputs.baseline_sha }}-d${{ steps.resolve_depth.outputs.depth }}-${{ inputs.engine_ref }}-${{ steps.llm.outputs.mode }}-${{ inputs.llm_provider }}-${{ inputs.agent_model }}-${{ inputs.parsing_model }}
731+
key: cb-base-v2-${{ runner.os }}-${{ steps.base.outputs.baseline_sha }}-d${{ steps.resolve_depth.outputs.depth }}-${{ inputs.codeboarding_version }}-${{ steps.llm.outputs.mode }}-${{ inputs.llm_provider }}-${{ inputs.agent_model }}-${{ inputs.parsing_model }}
759732

760733
# A committed analysis.json gives the head analysis stable component ids,
761734
# but the engine's incremental path ALSO needs the base static_analysis.pkl
@@ -768,10 +741,7 @@ runs:
768741
id: seedbase
769742
continue-on-error: true
770743
shell: bash
771-
working-directory: codeboarding-engine
772744
env:
773-
STATIC_ANALYSIS_CONFIG: ${{ github.workspace }}/codeboarding-engine/static_analysis_config.yml
774-
PROJECT_ROOT: ${{ github.workspace }}/codeboarding-engine
775745
CACHING_DOCUMENTATION: 'false'
776746
ENABLE_MONITORING: 'false'
777747
ACTION_PATH: ${{ github.action_path }}
@@ -786,7 +756,7 @@ runs:
786756
git -C "$TARGET" worktree prune
787757
rm -rf "$BASE_SRC"
788758
git -C "$TARGET" worktree add --detach "$BASE_SRC" "$BASELINE_SHA"
789-
if uv run python "$ACTION_PATH/scripts/engine_adapter.py" seed \
759+
if python "$ACTION_PATH/scripts/engine_adapter.py" seed \
790760
--repo "$BASE_SRC" \
791761
--out "$BASE_DIR" \
792762
--source-sha "$BASELINE_SHA" \
@@ -805,10 +775,7 @@ runs:
805775
- name: Generate base analysis (no committed baseline)
806776
if: steps.guard.outputs.skip != 'true' && steps.guard.outputs.mode == 'review' && steps.base.outputs.committed == 'false' && steps.basecache.outputs.cache-hit != 'true'
807777
shell: bash
808-
working-directory: codeboarding-engine
809778
env:
810-
STATIC_ANALYSIS_CONFIG: ${{ github.workspace }}/codeboarding-engine/static_analysis_config.yml
811-
PROJECT_ROOT: ${{ github.workspace }}/codeboarding-engine
812779
DIAGRAM_DEPTH_LEVEL: ${{ steps.resolve_depth.outputs.depth }}
813780
CACHING_DOCUMENTATION: 'false'
814781
ENABLE_MONITORING: 'false'
@@ -846,7 +813,7 @@ runs:
846813
git -C "$TARGET" worktree prune
847814
rm -rf "$BASE_SRC"
848815
git -C "$TARGET" worktree add --detach "$BASE_SRC" "$BASE_SHA"
849-
uv run python "$ACTION_PATH/scripts/engine_adapter.py" base \
816+
python "$ACTION_PATH/scripts/engine_adapter.py" base \
850817
--repo "$BASE_SRC" \
851818
--out "$BASE_DIR" \
852819
--name "$REPO_NAME" \
@@ -874,16 +841,13 @@ runs:
874841
# inputs. So a free-tier run (oidc, forced Gemini) and a BYO OpenRouter-key
875842
# run with no model pinned would share a key yet produce different base
876843
# analyses; the mode discriminator keeps them from reusing each other's cache.
877-
key: cb-base-v2-${{ runner.os }}-${{ steps.base.outputs.baseline_sha }}-d${{ steps.resolve_depth.outputs.depth }}-${{ inputs.engine_ref }}-${{ steps.llm.outputs.mode }}-${{ inputs.llm_provider }}-${{ inputs.agent_model }}-${{ inputs.parsing_model }}
844+
key: cb-base-v2-${{ runner.os }}-${{ steps.base.outputs.baseline_sha }}-d${{ steps.resolve_depth.outputs.depth }}-${{ inputs.codeboarding_version }}-${{ steps.llm.outputs.mode }}-${{ inputs.llm_provider }}-${{ inputs.agent_model }}-${{ inputs.parsing_model }}
878845

879846
- name: Analyze PR head (incremental from base)
880847
if: steps.guard.outputs.skip != 'true' && steps.guard.outputs.mode == 'review'
881848
id: analyze
882849
shell: bash
883-
working-directory: codeboarding-engine
884850
env:
885-
STATIC_ANALYSIS_CONFIG: ${{ github.workspace }}/codeboarding-engine/static_analysis_config.yml
886-
PROJECT_ROOT: ${{ github.workspace }}/codeboarding-engine
887851
DIAGRAM_DEPTH_LEVEL: ${{ steps.resolve_depth.outputs.depth }}
888852
CACHING_DOCUMENTATION: 'false'
889853
ENABLE_MONITORING: 'false'
@@ -921,7 +885,7 @@ runs:
921885
# untouched as the "before" snapshot for the diff.
922886
cp -a "$BASE_DIR"/. "$HEAD_DIR"/ 2>/dev/null || true
923887
rm -rf "$HEAD_DIR/health"
924-
uv run python "$ACTION_PATH/scripts/engine_adapter.py" head \
888+
python "$ACTION_PATH/scripts/engine_adapter.py" head \
925889
--repo "$TARGET_REPO" \
926890
--out "$HEAD_DIR" \
927891
--name "$REPO_NAME" \
@@ -934,26 +898,23 @@ runs:
934898
echo "::error::Head analysis ran but analysis.json is missing."
935899
exit 1
936900
fi
937-
echo "base_analysis=$BASE_DIR/analysis.json" >> $GITHUB_OUTPUT
901+
echo "base_analysis=$BASE_DIR/analysis.json" >> "$GITHUB_OUTPUT"
938902
echo "head_analysis=$HEAD_DIR/analysis.json" >> $GITHUB_OUTPUT
939903
940904
- name: Architecture health check (best-effort)
941905
if: steps.guard.outputs.skip != 'true' && steps.guard.outputs.mode == 'review'
942906
id: health
943907
continue-on-error: true
944908
shell: bash
945-
working-directory: codeboarding-engine
946909
env:
947-
STATIC_ANALYSIS_CONFIG: ${{ github.workspace }}/codeboarding-engine/static_analysis_config.yml
948-
PROJECT_ROOT: ${{ github.workspace }}/codeboarding-engine
949910
ACTION_PATH: ${{ github.action_path }}
950911
ARTIFACT_DIR: ${{ steps.base.outputs.head_dir }}
951912
TARGET_REPO: ${{ github.workspace }}/target-repo
952913
REPO_NAME: ${{ github.event.repository.name }}
953914
run: |
954915
rm -f /tmp/cb-issues.txt
955916
# engine_adapter writes the WARNING/CRITICAL count (0 on any failure — best-effort).
956-
uv run python "$ACTION_PATH/scripts/engine_adapter.py" health \
917+
python "$ACTION_PATH/scripts/engine_adapter.py" health \
957918
--artifact-dir "$ARTIFACT_DIR" \
958919
--repo "$TARGET_REPO" \
959920
--name "$REPO_NAME" \
@@ -1027,7 +988,7 @@ runs:
1027988
path: |
1028989
${{ runner.temp }}/cb-sync/static_analysis.pkl
1029990
${{ runner.temp }}/cb-sync/static_analysis.sha
1030-
key: cb-sync-${{ runner.os }}-${{ inputs.engine_ref }}-d${{ steps.resolve_depth.outputs.depth }}-${{ steps.llm.outputs.cache_provider }}-${{ steps.llm.outputs.cache_agent_model }}-${{ steps.llm.outputs.cache_parsing_model }}-${{ steps.sync_seed.outputs.baseline_sha }}
991+
key: cb-sync-${{ runner.os }}-${{ inputs.codeboarding_version }}-d${{ steps.resolve_depth.outputs.depth }}-${{ steps.llm.outputs.cache_provider }}-${{ steps.llm.outputs.cache_agent_model }}-${{ steps.llm.outputs.cache_parsing_model }}-${{ steps.sync_seed.outputs.baseline_sha }}
1031992

1032993
# Same rationale as the review pipeline's seed step: the committed
1033994
# analysis.json supplies component ids, but the incremental path also needs
@@ -1037,10 +998,7 @@ runs:
1037998
id: sync_seedcache
1038999
continue-on-error: true
10391000
shell: bash
1040-
working-directory: codeboarding-engine
10411001
env:
1042-
STATIC_ANALYSIS_CONFIG: ${{ github.workspace }}/codeboarding-engine/static_analysis_config.yml
1043-
PROJECT_ROOT: ${{ github.workspace }}/codeboarding-engine
10441002
# The seed subcommand defaults to github_action attribution; sync-mode
10451003
# telemetry must report as sync (setdefault never clobbers this).
10461004
CODEBOARDING_SOURCE: 'sync'
@@ -1065,7 +1023,7 @@ runs:
10651023
git -C "$TARGET_REPO" worktree prune
10661024
rm -rf "$BASE_SRC"
10671025
git -C "$TARGET_REPO" worktree add --detach "$BASE_SRC" "$BASELINE_SHA"
1068-
if uv run python "$ACTION_PATH/scripts/engine_adapter.py" seed \
1026+
if python "$ACTION_PATH/scripts/engine_adapter.py" seed \
10691027
--repo "$BASE_SRC" \
10701028
--out "$ANALYSIS_DIR" \
10711029
--source-sha "$BASELINE_SHA" \
@@ -1082,10 +1040,7 @@ runs:
10821040
if: steps.guard.outputs.skip != 'true' && steps.guard.outputs.mode == 'sync'
10831041
id: sync_analyze
10841042
shell: bash
1085-
working-directory: codeboarding-engine
10861043
env:
1087-
STATIC_ANALYSIS_CONFIG: ${{ github.workspace }}/codeboarding-engine/static_analysis_config.yml
1088-
PROJECT_ROOT: ${{ github.workspace }}/codeboarding-engine
10891044
DIAGRAM_DEPTH_LEVEL: ${{ steps.resolve_depth.outputs.depth }}
10901045
CACHING_DOCUMENTATION: 'false'
10911046
ENABLE_MONITORING: 'false'
@@ -1128,7 +1083,7 @@ runs:
11281083
)
11291084
[ "$FORCE_FULL" = "true" ] && args+=(--force-full)
11301085
LOG="${RUNNER_TEMP}/cb-sync-analyze.log"
1131-
uv run python "$ACTION_PATH/scripts/engine_adapter.py" analyze "${args[@]}" | tee "$LOG"
1086+
python "$ACTION_PATH/scripts/engine_adapter.py" analyze "${args[@]}" | tee "$LOG"
11321087
MODE="$(sed -n 's/^analysis_mode=//p' "$LOG" | tail -1)"
11331088
MODE="${MODE:-unknown}"
11341089
echo "analysis_mode=$MODE" >> "$GITHUB_OUTPUT"
@@ -1359,9 +1314,7 @@ runs:
13591314
if: steps.guard.outputs.skip != 'true' && steps.guard.outputs.mode == 'sync'
13601315
id: sync_render
13611316
shell: bash
1362-
working-directory: codeboarding-engine
13631317
env:
1364-
PROJECT_ROOT: ${{ github.workspace }}/codeboarding-engine
13651318
ACTION_PATH: ${{ github.action_path }}
13661319
ANALYSIS_DIR: ${{ steps.sync_seed.outputs.cb_dir }}
13671320
RENDER_DIR: ${{ steps.sync_seed.outputs.render_dir }}
@@ -1375,14 +1328,14 @@ runs:
13751328
run: |
13761329
set -euo pipefail
13771330
REPO_REF="https://github.com/${REPOSITORY}/blob/${TARGET_BRANCH}/${OUTPUT_DIR}"
1378-
uv run python "$ACTION_PATH/scripts/engine_adapter.py" render \
1331+
python "$ACTION_PATH/scripts/engine_adapter.py" render \
13791332
--analysis "$ANALYSIS_DIR/analysis.json" \
13801333
--out "$RENDER_DIR" \
13811334
--repo-name "$REPO_NAME" \
13821335
--repo-ref "$REPO_REF" \
13831336
--format "$OUTPUT_FORMAT"
13841337
if [ "$WRITE_ARCHITECTURE_MD" = "true" ]; then
1385-
uv run python "$ACTION_PATH/scripts/engine_adapter.py" concat \
1338+
python "$ACTION_PATH/scripts/engine_adapter.py" concat \
13861339
--docs-dir "$RENDER_DIR" \
13871340
--out "$ARCHITECTURE_FILE"
13881341
fi
@@ -1412,7 +1365,7 @@ runs:
14121365
path: |
14131366
${{ runner.temp }}/cb-sync/static_analysis.pkl
14141367
${{ runner.temp }}/cb-sync/static_analysis.sha
1415-
key: cb-sync-${{ runner.os }}-${{ inputs.engine_ref }}-d${{ steps.resolve_depth.outputs.depth }}-${{ steps.llm.outputs.cache_provider }}-${{ steps.llm.outputs.cache_agent_model }}-${{ steps.llm.outputs.cache_parsing_model }}-${{ steps.guard.outputs.target_sha }}
1368+
key: cb-sync-${{ runner.os }}-${{ inputs.codeboarding_version }}-d${{ steps.resolve_depth.outputs.depth }}-${{ steps.llm.outputs.cache_provider }}-${{ steps.llm.outputs.cache_agent_model }}-${{ steps.llm.outputs.cache_parsing_model }}-${{ steps.guard.outputs.target_sha }}
14161369

14171370
- name: Commit and push synced architecture
14181371
if: steps.guard.outputs.skip != 'true' && steps.guard.outputs.mode == 'sync'

scripts/engine_adapter.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
"""CLI adapter between the action and the CodeBoarding analysis ENGINE.
22
3-
No analysis logic lives here. The engine is the separate ``CodeBoarding/
4-
CodeBoarding`` repo, checked out at runtime into ``codeboarding-engine/`` and
5-
imported lazily inside each function (``codeboarding_workflows`` etc.); this
6-
module just turns the action's shell steps into typed, tested calls into it.
7-
The lazy imports mean this file imports fine without the engine venv present —
8-
the tests stub those modules and assert we call the engine with the right args.
3+
No analysis logic lives here. The engine is the published ``codeboarding`` PyPI
4+
package installed by the action and imported lazily inside each function
5+
(``codeboarding_workflows`` etc.); this module just turns the action's shell
6+
steps into typed, tested calls into it. The lazy imports mean this file imports
7+
fine without the package present — the tests stub those modules and assert we
8+
call the engine with the right args.
99
1010
Subcommands (all paths/refs come in as argv, never interpolated into source):
1111

0 commit comments

Comments
 (0)