Metadata-Version: 2.4
Name: glreview
Version: 0.5.0
Summary: GitLab code review tracking for scientific software
Author-email: Chad Hanna <chad.hanna@ligo.org>
License: MIT
Project-URL: Homepage, https://git.ligo.org/chad.hanna/glreview
Project-URL: Documentation, https://git.ligo.org/chad.hanna/glreview
Project-URL: Repository, https://git.ligo.org/chad.hanna/glreview
Project-URL: Issues, https://git.ligo.org/chad.hanna/glreview/-/issues
Keywords: gitlab,code-review,scientific-software,ci-cd
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Version Control :: Git
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: click>=8.0
Requires-Dist: jinja2>=3.0
Requires-Dist: python-gitlab>=4.0
Requires-Dist: tomli>=2.0; python_version < "3.11"
Provides-Extra: test
Requires-Dist: pytest>=8.0; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Provides-Extra: lint
Requires-Dist: black; extra == "lint"
Requires-Dist: flake8; extra == "lint"
Requires-Dist: flake8-bandit; extra == "lint"
Requires-Dist: flake8-black; extra == "lint"
Requires-Dist: flake8-bugbear; extra == "lint"
Requires-Dist: flake8-future-annotations; extra == "lint"
Requires-Dist: flake8-isort; extra == "lint"
Requires-Dist: flake8-pyproject; extra == "lint"
Requires-Dist: isort; extra == "lint"
Requires-Dist: mypy; extra == "lint"
Provides-Extra: dev
Requires-Dist: glreview[test]; extra == "dev"
Requires-Dist: glreview[lint]; extra == "dev"

# glreview

Track code review coverage with git-level precision. Know exactly which modules have been reviewed, at which commit, and what changed since.

## The Problem

Code review is usually per-PR, but that doesn't answer: "Has this module ever been thoroughly reviewed?" Teams maintaining critical software need to know:

- Which files have never been reviewed?
- Which reviews are stale because the code changed?
- How much of the codebase has review coverage?

glreview tracks review status per-module, persisted in git, integrated with GitLab issues.

## What It Looks Like

```
$ glreview status

Review Status
─────────────────────────────────────────────────────
Reviewed:     12 modules (2,450 lines)  ██████████░░ 48%
In Progress:   2 modules (380 lines)
Needs Review: 11 modules (1,890 lines)

Stale (changed since review):
  src/core/engine.py      changed 3 days ago
  src/utils/helpers.py    changed 1 week ago

In Progress:
  src/api/handlers.py     issue #142, @alice

Needs Review:
  src/auth/oauth.py       245 lines
  src/core/scheduler.py   189 lines
  src/api/middleware.py   156 lines
```

## Installation

**Prerequisites:** Python 3.9+, git repository, GitLab project

```bash
pip install glreview
```

For AI-assisted review features, also install [Claude Code](https://claude.ai/code).

## Quick Start

### 1. Configure source patterns

Add to `pyproject.toml`:

```toml
[tool.glreview]
sources = ["src/**/*.py"]
exclude = ["**/test_*.py", "**/_version.py"]
```

### 2. Set up GitLab authentication

```bash
export GITLAB_PRIVATE_TOKEN=glpat-xxxxxxxxxxxx

# For self-hosted GitLab:
export GITLAB_URL=https://gitlab.example.com
```

### 3. Initialize

```bash
glreview init
```

This creates `.glreview/registry.json`. Commit it to version control.

### 4. Start reviewing

```bash
# See what needs review
glreview status

# Start a review (creates GitLab issue)
glreview start src/mymodule.py --assignee @reviewer

# After reviewer closes the issue, sign off
glreview signoff src/mymodule.py

# Commit the updated registry
git add .glreview/ && git commit -m "review: src/mymodule.py"
```

## Core Workflow

### Review lifecycle

```
┌─────────────┐
│ needs_review│◄──────────────────┐
└──────┬──────┘                   │
       │ start                    │ cancel (or code changes)
       ▼                          │
┌─────────────┐                   │
│ in_progress │───────────────────┤
└──────┬──────┘                   │
       │ signoff                  │
       ▼                          │
┌─────────────┐                   │
│  reviewed   │───────────────────┘
└─────────────┘
```

### Starting a review

```bash
# Basic - creates GitLab issue
glreview start src/module.py

# With assignee
glreview start src/module.py --assignee @alice

# Link to existing issue instead of creating new
glreview start src/module.py --issue "https://gitlab.com/.../issues/42"
```

### Signing off

```bash
# Standard signoff (verifies GitLab issue is closed)
glreview signoff src/module.py

# Skip issue verification
glreview signoff src/module.py --skip-verify

# With explicit reviewer name
glreview signoff src/module.py --reviewer @bob
```

### Handling changes during review

If code changes while a review is in progress:

```bash
# See what changed
glreview diff src/module.py --since-start

# Option 1: Acknowledge changes and sign off anyway
glreview signoff src/module.py --acknowledge

# Option 2: Cancel and restart at current commit
glreview cancel src/module.py --restart
```

### Viewing diffs

```bash
# Changes since last review (deciding whether to re-review)
glreview diff src/module.py

# Changes during current review (before signing off)
glreview diff src/module.py --since-start

# Open in GitLab web UI
glreview diff src/module.py --web
```

## AI-Assisted Review (Optional)

glreview integrates with Claude Code for automated code analysis. This is entirely optional - the core workflow works without it.

### Setup

```bash
# Verify Claude CLI is installed
claude --version

# Generate project context (one-time)
glreview claude-init
```

This creates `.glreview/context.json` with project conventions, module relationships, and test file mappings. Commit it to version control.

### Running AI review

```bash
# Run review and post findings to GitLab issue
glreview claude-review src/module.py

# Print findings to terminal only (don't post)
glreview claude-review src/module.py --no-post

# Preview the prompt without running
glreview claude-review src/module.py --dry-run
```

Reviews evaluate six criteria:
- **Correctness** - Logic errors, wrong results, unhandled edge cases
- **Error Handling** - Input validation, failure handling, resource leaks
- **Code Quality** - DRY, organization, naming, appropriate abstractions
- **Testing** - Coverage, meaningful assertions, edge cases
- **Documentation** - Non-obvious decisions explained, API documented
- **Risk** - Security, performance, data integrity (when applicable)

Each finding is rated **OK**, **SUGGESTED**, or **REQUIRED**.

### Fixing issues

```bash
# Interactive - choose which items to fix
glreview claude-fix src/module.py

# Batch - fix all REQUIRED items automatically
glreview claude-fix src/module.py --batch

# Create a merge request with the fixes
glreview claude-fix src/module.py --batch --create-mr

# Specify a target branch for the MR
glreview claude-fix src/module.py --batch --create-mr --target-branch develop
```

The `--create-mr` flag automates the full workflow: creates a branch (`fix/review-{module}-{issue}`), commits the changes, pushes to origin, and opens a GitLab merge request that references the review issue. In interactive mode, you'll be prompted to confirm before the MR is created.

### Updating context

```bash
# After significant codebase changes
glreview claude-sync

# View context for a module
glreview claude-context src/module.py
```

## Batch Operations

Start reviews for multiple modules at once:

```bash
# Start reviews for all modules needing review
glreview batch-start

# Preview what would happen
glreview batch-start --dry-run

# Also run Claude review for each (posts to issues)
glreview batch-start --claude-review
```

## CI Integration

Validate review coverage in your pipeline with `glreview ci`. No push tokens or git plumbing required — the registry is committed by developers as part of their normal workflow.

### Setup

1. Keep `.glreview/` committed in your repo (run `glreview sync` locally when adding/removing source files)
2. Add to `.gitlab-ci.yml`:

```yaml
review:
  stage: review
  image: python:3.12
  script:
    - pip install glreview
    - glreview ci --report REVIEW_COVERAGE.md
  artifacts:
    paths:
      - REVIEW_COVERAGE.md
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
```

Run `glreview ci-config` for a complete example including release gates.

### Enforcing coverage

```bash
# Block releases without 100% review coverage
glreview ci --fail-under 100
```

### Staleness checks

```bash
# Fail if reviewed files have changed since last review
glreview check
```

## Configuration Reference

Full `pyproject.toml` options:

```toml
[tool.glreview]
# Source file patterns (required)
sources = ["src/**/*.py", "lib/**/*.py"]

# Patterns to exclude
exclude = ["**/test_*.py", "**/_version.py", "**/conftest.py"]

# Registry file location (default: .glreview/registry.json)
registry = ".glreview/registry.json"

# Default labels for created issues
issue_labels = ["review::pending", "team::backend"]

# Custom issue template (Jinja2)
issue_template = ".glreview/issue_template.md"

# Reviewer teams (use with --assignee @team/security)
[tool.glreview.teams]
security = ["@alice", "@bob"]
frontend = ["@carol", "@dave"]

# Custom instructions injected into Claude prompts (optional)
[tool.glreview.claude]
fix_instructions = """
After making fixes:
- Run `python -m pytest tests/ -x` to verify nothing is broken
- Run `ruff check src/` for lint compliance
"""
review_instructions = """
This project uses numpy-style docstrings.
All public functions must have type annotations.
"""
```

### Custom issue templates

Create a Jinja2 template with access to these variables:

| Variable | Description |
|----------|-------------|
| `path` | Module path |
| `lines` | Line count |
| `current_commit` | Current git commit |
| `previous_commit` | Last reviewed commit (re-reviews) |
| `diff_url` | GitLab compare URL (re-reviews) |
| `classes` | List of public classes |
| `functions` | List of public functions |

## Commands

| Command | Description |
|---------|-------------|
| `init` | Initialize glreview in a project |
| `status` | Show review progress and what needs attention |
| `start PATH` | Start a review, create GitLab issue |
| `signoff PATH` | Sign off on completed review |
| `cancel PATH` | Cancel review (--restart to restart at HEAD) |
| `diff PATH` | Show changes since last review |
| `sync` | Sync registry with filesystem changes |
| `list` | List all tracked modules |
| `report` | Generate coverage report (markdown/json/badge) |
| `ci` | Run sync + coverage check for CI pipelines |
| `check` | CI check for changes to reviewed files |
| `batch-start` | Start reviews for all pending modules |
| `reviewers` | List configured reviewers |
| `ci-config` | Print recommended CI configuration |
| `claude-review PATH` | Run AI code review |
| `claude-fix PATH` | Fix issues from AI review (--create-mr to open MR) |
| `claude-init` | Generate AI project context |
| `claude-sync` | Update AI context |
| `claude-context` | View AI context |

Use `glreview COMMAND --help` for detailed options.

## Troubleshooting

**"Module not found in registry"**
Run `glreview sync` to add new files, or check your `sources` patterns in pyproject.toml.

**"GitLab API not available"**
Set `GITLAB_PRIVATE_TOKEN`. For self-hosted GitLab, also set `GITLAB_URL`.

**"Issue not closed"**
Close the GitLab issue before signing off. Use `--skip-verify` to bypass this check.

**"File changed during review"**
Code was modified after `start`. Use `--acknowledge` to sign off anyway, or `cancel --restart` to restart.

**Claude commands not working**
Install Claude Code CLI: https://claude.ai/code

## License

MIT
