Metadata-Version: 2.4
Name: opentia
Version: 1.0.5
Summary: Test Impact Analysis for C# / .NET, Java, and Node.js — selects only tests affected by a git diff.
Author-email: byterey <byterey@gmail.com>
License: MIT
Keywords: testing,test-impact-analysis,dotnet,csharp,java,nodejs,tia
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# opentia — Test Impact Analysis

Analyses a git diff and selects only the tests whose execution path could have been affected by the change. Skips the full suite on every push.

**No external dependencies** — Python 3.8+ stdlib only.

**Language support:** C# / .NET, Java (Maven / Gradle), and Node.js (Jest / Vitest — single packages and npm workspaces).

---

## Requirements

| Tool | Version | Purpose |
|---|---|---|
| Python | 3.8+ | Run opentia |
| Git | any | Diff source |

---

## Installation

```bash
pip install opentia
```

This installs the `opentia` command on your `PATH`.

---

## Quick start

```bash
# Analyse the last commit
opentia --base HEAD~1 --root <path-to-your-project>

# Analyse uncommitted (staged + unstaged) changes — no commit needed
opentia --unstaged --root <path-to-your-project>

# Analyse and immediately run the selected tests
opentia --base HEAD~1 --root <path-to-your-project> --run
```

`--root` is where your `.sln` / `.csproj` / `pom.xml` / `build.gradle` / `package.json` lives. It does not need to be the git root — opentia locates the actual git root automatically.

---

## Usage reference

```
opentia [OPTIONS] [-- TEST_ARGS]

  --base REF      Git ref to diff against (e.g. HEAD~1, main, origin/main)
  --head REF      Head ref to diff from (default: HEAD)
  --root DIR      Directory containing project files (default: .)
  --strategy      project | convention | symbol | hybrid (default: hybrid)
  --output, -o    human | json | github-actions | azure-devops (default: human)
  --run           Execute the test command after analysis
  --unstaged      Analyse working-tree changes instead of a git diff
  --              Everything after this is forwarded to the test runner
```

### Output formats

```bash
# Human-readable (default)
opentia --base HEAD~1 --root .

# JSON — pipe into scripts or CI steps
opentia --base HEAD~1 --root . --output json

# GitHub Actions
opentia --base HEAD~1 --root . --output github-actions

# Azure DevOps
opentia --base HEAD~1 --root . --output azure-devops
```

### JSON output fields

```jsonc
{
  "run_all": false,               // true = targeted selection was abandoned
  "language": "dotnet",          // dotnet | java | node
  "test_filter": "FullyQualifiedName~PricingServiceTests",
  "test_project_paths": ["...SampleApp.Services.Tests.csproj"],
  "affected_test_projects": ["SampleApp.Services.Tests"],
  "affected_test_classes": ["PricingServiceTests"],
  "test_command": "dotnet test \"...\" --filter \"...\"",
  "reason": "Analysis complete",
  "strategy_notes": []            // warnings / fallback explanations
}
```

---

## Node.js projects

opentia detects Jest and Vitest automatically. For **npm workspaces**, each sub-package is analysed independently and the dependency graph is resolved across `workspace:*` references — changing a shared package triggers tests in every package that depends on it.

The test command is always a single `npx jest` (or `npx vitest run`) invocation run from the workspace root with a `--testPathPattern` filter.

## Mixed-language monorepos

Each `opentia` run uses one adapter — .NET, Java, or Node — based on what it finds under `--root`. Point `--root` at each language root separately:

```bash
opentia --base HEAD~1 --root ./backend    # Java or .NET tests
opentia --base HEAD~1 --root ./frontend   # Node.js tests
```

In CI, run both steps. Each one exits cleanly with "no tests to run" when its language has no changes — nothing is wasted.

---

## CI integration

### GitHub Actions — pull request

```yaml
on:
  pull_request:
    branches: [main, staging]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Test Impact Analysis
        id: tia
        run: opentia --base ${{ github.event.pull_request.base.sha }} --root . --output github-actions

      - name: Run affected tests
        if: steps.tia.outputs.has_tests == 'true'
        run: ${{ steps.tia.outputs.test_command }}
```

Available outputs: `test_filter`, `run_all`, `has_tests`, `test_project_paths`, `test_command`.

### GitHub Actions — push to branch

```yaml
- name: Test Impact Analysis
  id: tia
  run: opentia --base ${{ github.event.before }} --root . --output github-actions

- name: Run affected tests
  if: steps.tia.outputs.has_tests == 'true'
  run: ${{ steps.tia.outputs.test_command }}
```

### Azure DevOps

```yaml
- script: opentia --base $(System.PullRequest.TargetBranchName) --root . --output azure-devops
  displayName: Test Impact Analysis

- script: $(testCommand)
  condition: eq(variables['hasTests'], 'true')
  displayName: Run affected tests
```

Available variables: `testFilter`, `runAllTests`, `hasTests`, `testProjectPaths`, `testCommand`.
