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
64 changes: 64 additions & 0 deletions .github/actions/boundver/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: "boundver verify"
description: "Zero-setup boundver verification with optional diff-on-failure"
inputs:
config:
description: "Path to boundary config"
required: false
default: "boundary.config.json"
lock:
description: "Path to lockfile"
required: false
default: "boundary.lock.json"
source:
description: "Fingerprint source mode"
required: false
default: "head"
components:
description: "Optional comma-separated component subset"
required: false
default: ""
python-version:
description: "Python version used by action"
required: false
default: "3.12"
show-diff-on-failure:
description: "Generate and print lockfile diff on verify failure"
required: false
default: "true"
runs:
using: "composite"
steps:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}

- name: Install boundver
shell: bash
run: |
python -m pip install --upgrade pip
pip install .

- name: Verify lockfile
shell: bash
run: |
set -euo pipefail
EXTRA_ARGS=()
if [ -n "${{ inputs.components }}" ]; then
EXTRA_ARGS+=(--components "${{ inputs.components }}")
fi
boundver verify \
--config "${{ inputs.config }}" \
--lock "${{ inputs.lock }}" \
--source "${{ inputs.source }}" \
"${EXTRA_ARGS[@]}"

- name: Diff on failure
if: ${{ failure() && inputs.show-diff-on-failure == 'true' }}
shell: bash
run: |
set -euo pipefail
boundver generate --config "${{ inputs.config }}" --out /tmp/boundary.lock.new.json --source "${{ inputs.source }}" || true
if [ -f "/tmp/boundary.lock.new.json" ]; then
boundver diff "${{ inputs.lock }}" /tmp/boundary.lock.new.json || true
fi
30 changes: 30 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Publish to PyPI

on:
push:
tags:
- "v*"

jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4

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

- name: Build package
run: |
python -m pip install --upgrade pip
pip install build
python -m build

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
63 changes: 54 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ In a repository with many components and layered dependencies, you need differen

Traditional version managers require humans to answer these questions via commit messages or changelogs. boundver derives the answers from repo state — deterministically, automatically, and with no runtime dependencies beyond Git and Python 3.8+.

For tool-selection guidance and scope boundaries, see `docs/WHY_BOUNDVER.md`.

## How it works

Each component gets three fingerprints:
Expand Down Expand Up @@ -42,6 +44,8 @@ pip install boundver

# Create a starter config
boundver init
# Or auto-discover components from common manifests
boundver init --discover
# Custom path / overwrite existing
boundver init --out boundary.config.json --force

Expand Down Expand Up @@ -72,6 +76,9 @@ EOF
# Generate the lockfile
boundver generate

# Regenerate only selected components (and affected slices)
boundver generate --components auth-service,billing-service

# Deterministic output (omits generated_at)
boundver generate --deterministic

Expand All @@ -84,6 +91,12 @@ boundver status
# Verify lockfile matches repo state
boundver verify

# Verify only selected components
boundver verify --components auth-service,billing-service

# Verify only components changed since main
boundver verify --changed-from origin/main

# JSON output for automation
boundver verify --json

Expand All @@ -96,6 +109,9 @@ boundver diff old.lock.json boundary.lock.json

# Inspect a specific slice
boundver slice auth-api

# Preview discovered components
boundver discover --json
```

## Behavior matrix
Expand Down Expand Up @@ -199,8 +215,32 @@ Short term deliverables: `validate-config`, strict digest selection, explicit so

## CI integration

For lockfile merge conflict handling, see `docs/LOCKFILE_MERGE.md`.

### GitHub Actions — PR verification

#### Option A: use bundled composite action

```yaml
name: Boundary check
on: [pull_request]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: ./.github/actions/boundver
with:
config: boundary.config.json
lock: boundary.lock.json
source: head
show-diff-on-failure: "true"
```

#### Option B: explicit steps

```yaml
name: Boundary check
on: [pull_request]
Expand Down Expand Up @@ -238,6 +278,13 @@ if [ "$NEW_FP" != "$CACHED_FP" ]; then
fi
```

### Shell verifier (portability proof)

```bash
# Verifies exact/boundary fingerprints against HEAD using git + jq + sha256sum
scripts/boundver-verify.sh boundary.config.json boundary.lock.json
```

## Design decisions

- **No external dependencies.** Only Git and Python stdlib. Runs anywhere Python 3.8+ and Git are available.
Expand Down Expand Up @@ -267,18 +314,16 @@ pip install "boundver[yaml]"

Without `jsonschema`, boundver still runs and applies built-in semantic validation checks.

## Ignore behavior for `--source=working-tree`
## Release

For working-tree hashing, boundver currently uses a **built-in ignore list** (this is not `.gitignore`-aware yet):
- PyPI publish workflow: `.github/workflows/publish.yml`
- Trigger: push a version tag matching `v*` (for example `v0.3.0`)

- dot-prefixed names (e.g. `.cache`, `.venv`)
- `__pycache__`
- `node_modules`
- `*.pyc`
- `dist`
- `build`
## Ignore behavior for `--source=working-tree`

For `--source=head` and `--source=index`, content and path enumeration are Git-backed and therefore based on Git object state rather than local traversal ignores.
`--source=working-tree` prefers Git-backed tracked-file enumeration (`git ls-files`) when available.
In non-git fallback contexts, local file traversal is used.
Symlinks are hashed as link-target text (not dereferenced bytes) for cross-source consistency.

## Requirements

Expand Down
Loading
Loading