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
50 changes: 50 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Publish tig-cli

on:
release:
types: [published]

jobs:
build:
name: Build distribution
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install build tools
run: python -m pip install --upgrade pip build

- name: Build package
run: |
cd tig-cli
python -m build

- name: Upload distribution artifacts
uses: actions/upload-artifact@v4
with:
name: tig-cli-dist
path: tig-cli/dist/

publish:
name: Publish to PyPI
needs: build
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write

steps:
- name: Download distribution artifacts
uses: actions/download-artifact@v4
with:
name: tig-cli-dist
path: dist/

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
55 changes: 55 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Test tig-cli

on:
push:
branches: ["**"]
paths:
- "tig-cli/**"
- ".github/workflows/test.yml"
pull_request:
branches: ["**"]
paths:
- "tig-cli/**"
- ".github/workflows/test.yml"

jobs:
test:
name: "Test Python ${{ matrix.python-version }} on ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
python-version: ["3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
cd tig-cli
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"

- name: Run tests
run: |
cd tig-cli
python -m pytest tests/ -v --no-cov -m "not integration"

- name: Run tests with coverage
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
run: |
cd tig-cli
python -m pytest tests/ -m "not integration" --cov=tig_cli --cov-report=xml --cov-report=term-missing

- name: Upload coverage
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
uses: codecov/codecov-action@v4
with:
file: ./tig-cli/coverage.xml
fail_ci_if_error: false
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ __pycache__/
*.egg-info/
dist/
build/
.coverage
.pytest_cache/

# Logs
*.log
Expand Down
126 changes: 126 additions & 0 deletions docs/plans/2026-07-31-tig-cli-unified-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# TIG CLI Unified Design

**Date:** 2026-07-31
**Branch:** feature/tig-cli-unified
**Status:** Approved

## Summary

Replace three pip packages (`tig-cli-core`, `tig-opensource`, `tig-m20-g87`) with a single `tig-cli` package that installs one command: `tig`. The Docker image used as the backend is selected via the `CONTAINER_IMAGE` environment variable; default is the opensource image.

## Motivation

The original design had separate packages per variant (one for open-source, one for M20 G87). These were never published. A single package with env-var image selection is simpler to install, simpler to document, and sufficient for all use cases.

## Package Structure

| Old | New |
|-----|-----|
| `tig-cli-core/` | deleted |
| `tig-opensource/` | deleted |
| `tig-m20-g87/` | deleted |
| *(new)* | `tig-cli/` |

### `tig-cli/`

```
tig-cli/
├── pyproject.toml # package name: tig-cli, entrypoint: tig = tig_cli.cli:main
├── MANIFEST.in
├── README.md
└── src/
└── tig_cli/
├── __init__.py
├── container.py # ContainerManager + get_container_image()
├── path_translator.py # unchanged
└── cli.py # single main() function
tests/
├── test_path_translator.py
├── test_container.py
├── test_cli.py
└── integration/
└── test_vicar_execution.py
```

## CLI Interface

```
tig <vicar-tool> [args...]
```

**Options:**
- `--writable-path PATH` — mount additional host dir read-write inside container (repeatable)
- `--disable-path-translation` — skip automatic host→container path rewriting

**Help text** shows the active image (resolved from `CONTAINER_IMAGE` or default).

**No `--variant` or `--image` flag.** Image selection is env-var only.

## Image Configuration

```python
DEFAULT_IMAGE = "ghcr.io/nasa-ammos/tig/terrain-intelligence-generator:opensource"

def get_container_image() -> str:
return os.environ.get("CONTAINER_IMAGE", DEFAULT_IMAGE)
```

`CONTAINER_IMAGE` accepts any valid Docker image reference (full URI including registry, repo, and tag). No short-name resolution — users set the full image string.

**Examples:**
```bash
# default (opensource)
tig marsmap ...

# proprietary variant
CONTAINER_IMAGE=ghcr.io/nasa-ammos/tig/terrain-intelligence-generator:m20-g87 tig marsmap ...

# custom/local image
CONTAINER_IMAGE=my-org/custom-vicar:v2 tig marsmap ...
```

## Code Changes

### `container.py`

- `ContainerManager.__init__` signature changes from `(variant: VariantConfig, ...)` to `(image: str, ...)`
- Add `get_container_image() -> str` module-level function (reads `CONTAINER_IMAGE` env var)
- Container name prefix: fixed string `tig-vicar` (no variant-derived name)
- All other logic (mounts, lifecycle, exec, path translation) unchanged

### `cli.py`

- Remove `create_cli(variant_name)` factory pattern
- Single `main()` function decorated with `@click.command`
- Calls `get_container_image()` at invocation time
- Help text includes: `f"Active image: {get_container_image()}"`

### `variants.py`

- Deleted entirely. `VariantConfig` dataclass and `VARIANTS` registry removed.

### `__init__.py`

- Remove any variant-related imports

## Testing

- **Delete** `test_variants.py`
- **Update** `test_container.py`: replace `VariantConfig` fixtures with direct `image` string; mock `CONTAINER_IMAGE` env var via `monkeypatch.setenv`
- **Update** `test_cli.py`: test `main()` directly; test env var override; test default image
- `test_path_translator.py` — unchanged
- Integration tests — unchanged

## CI / Publishing

- `.github/workflows/test.yml` — update paths to `tig-cli/`
- `.github/workflows/publish.yml` — update to publish single `tig-cli` package
- PyPI package name: `tig-cli`
- Entrypoint command: `tig`

## What Is Not Changing

- Path translation logic (`path_translator.py`) — unchanged
- Container mount strategy (root ro + home rw + writable paths) — unchanged
- `--writable-path` and `--disable-path-translation` flags — unchanged
- Container lifecycle (ephemeral: start → exec → stop per invocation) — unchanged
Loading
Loading