|
| 1 | +# er_build_tools |
| 2 | + |
| 3 | +Public build tools and CI utilities for Extend Robotics ROS1 repositories. The main component is `ci_tool`, an interactive CLI that reproduces CI failures locally in Docker and uses Claude Code to fix them. |
| 4 | + |
| 5 | +## Project Structure |
| 6 | + |
| 7 | +``` |
| 8 | +bin/ |
| 9 | + ci_tool/ # Main Python package |
| 10 | + __main__.py # Entry point (auto-installs missing deps) |
| 11 | + cli.py # Menu dispatch router |
| 12 | + ci_fix.py # Core workflow: reproduce -> Claude analysis -> fix -> shell |
| 13 | + ci_reproduce.py # Docker container setup for CI reproduction |
| 14 | + claude_setup.py # Install Claude + copy credentials/config into container |
| 15 | + claude_session.py # Interactive Claude session launcher |
| 16 | + containers.py # Docker lifecycle (create, exec, cp, remove) |
| 17 | + preflight.py # Auth/setup validation (fail-fast) |
| 18 | + display_progress.py # Stream-json output processor for Claude |
| 19 | + ci_context/ |
| 20 | + CLAUDE.md # CI-specific instructions for Claude inside containers |
| 21 | + setup.sh # User-facing setup script |
| 22 | + reproduce_ci.sh # Public wrapper for CI reproduction |
| 23 | +.helper_bash_functions # Sourced by users; provides colcon/rosdep helpers + ci_tool alias |
| 24 | +pylintrc # Pylint config (strict: fail-under=10.0, max-line-length=140) |
| 25 | +``` |
| 26 | + |
| 27 | +## Code Style |
| 28 | + |
| 29 | +- Python 3.6+, `from __future__ import annotations` in all modules |
| 30 | +- snake_case everywhere; PascalCase for classes only |
| 31 | +- 4-space indentation, max 140 char line length |
| 32 | +- Pylint must pass at 10.0 (`pylintrc` at repo root) |
| 33 | +- Use `# pylint: disable=...` pragmas only when essential, with justification |
| 34 | +- Interactive prompts via `InquirerPy`; terminal UI via `rich` |
| 35 | + |
| 36 | +## Conventions |
| 37 | + |
| 38 | +- **Fail fast**: `PreflightError` for expected failures, `RuntimeError` for unexpected. No silent defaults, no fallback behaviour. |
| 39 | +- **Minimal diffs**: Only change what's requested. No cosmetic cleanups, no "while I'm here" changes. |
| 40 | +- **Self-documenting code**: Verbose variable names. Comments only for maths or external doc links. |
| 41 | +- **Subprocess calls**: Use `docker_exec()` / `run_command()` from `containers.py`. Pass `check=False` when non-zero is expected; `quiet=True` to suppress echo. |
| 42 | +- **State files**: `/ros_ws/.ci_fix_state.json` inside containers (session_id, phase, attempt_count) |
| 43 | +- **Learnings persistence**: `~/.ci_tool/learnings/{org}_{repo}.md` on host, `/ros_ws/.ci_learnings.md` in container |
| 44 | + |
| 45 | +## Environment Variables |
| 46 | + |
| 47 | +- `GH_TOKEN` or `ER_SETUP_TOKEN` — GitHub token (checked in preflight) |
| 48 | +- `CI_TOOL_SCRIPTS_BRANCH` — branch of er_build_tools_internal to fetch scripts from |
| 49 | +- `IS_SANDBOX=1` — injected into all docker exec calls for Claude |
| 50 | + |
| 51 | +## Running |
| 52 | + |
| 53 | +```bash |
| 54 | +# From host |
| 55 | +source ~/.helper_bash_functions |
| 56 | +ci_tool # interactive menu |
| 57 | +ci_fix # shortcut for ci_tool fix |
| 58 | + |
| 59 | +# Lint |
| 60 | +pylint --rcfile=pylintrc bin/ci_tool/ |
| 61 | +``` |
| 62 | + |
| 63 | +## Testing |
| 64 | + |
| 65 | +No unit tests yet. Test manually by running `ci_tool` workflows end-to-end. |
| 66 | + |
| 67 | +## Common Pitfalls |
| 68 | + |
| 69 | +- Container Claude settings must use valid `defaultMode` values: `"acceptEdits"`, `"bypassPermissions"`, `"default"`, `"dontAsk"`, `"plan"`. The old `"dangerouslySkipPermissions"` is invalid. |
| 70 | +- `docker_cp_to_container` requires the container to be running. |
| 71 | +- Claude inside containers runs with `--dangerously-skip-permissions` flag (separate from the settings.json mode). |
0 commit comments