repofail 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- repofail-0.2.4/.github/actions/repofail/README.md +45 -0
- repofail-0.2.4/.github/actions/repofail/action.yml +73 -0
- repofail-0.2.4/.gitignore +22 -0
- repofail-0.2.4/Formula/repofail.rb +66 -0
- {repofail-0.2.2 → repofail-0.2.4}/PKG-INFO +114 -7
- {repofail-0.2.2 → repofail-0.2.4}/README.md +108 -6
- repofail-0.2.4/docs/QUICKSTART.md +42 -0
- repofail-0.2.4/homebrew-tap/Formula/repofail.rb +66 -0
- repofail-0.2.4/install.sh +21 -0
- {repofail-0.2.2 → repofail-0.2.4}/pyproject.toml +11 -1
- repofail-0.2.4/repofail/__init__.py +8 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/cli.py +3 -2
- repofail-0.2.2/.gitignore +0 -8
- repofail-0.2.2/repofail/__init__.py +0 -3
- {repofail-0.2.2 → repofail-0.2.4}/.github/workflows/publish.yml +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/.github/workflows/repofail.yml +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/CONTRIBUTING.md +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/RULES.md +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/contract.json +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/docs/assets/demo-autogpt.png +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/docs/assets/repofail-logo.png +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/docs/logo.png +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/docs/screenshots/high_failure.png +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/docs/screenshots/nodefail.gif +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/contract.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/engine.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/fleet.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/format.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/models.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/risk.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/__init__.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/abi_wheel_mismatch.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/apple_silicon.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/base.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/docker_only.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/gpu_memory.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/info_signals.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/lock_file_missing.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/ml_niche.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/native_toolchain.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/node_engine.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/node_eol.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/node_windows.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/port_collision.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/python_eol.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/python_version.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/registry.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/spec_drift.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/system_libs.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/torch_cuda.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/rules/yaml_loader.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/scanner/__init__.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/scanner/ast_scan.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/scanner/host.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/scanner/parsers.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/scanner/repo.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/repofail/telemetry.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/tests/__init__.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/tests/test_cli_stage2.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/tests/test_contract.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/tests/test_fleet.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/tests/test_integration.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/tests/test_ml_rules.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/tests/test_rules.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/tests/test_scanner.py +0 -0
- {repofail-0.2.2 → repofail-0.2.4}/tests/test_telemetry.py +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# repofail GitHub Action
|
|
2
|
+
|
|
3
|
+
Run repofail on every PR: get a Markdown report as a comment and fail CI when compatibility violations exceed the threshold.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
In your repo, create `.github/workflows/repofail.yml`:
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
name: repofail
|
|
11
|
+
on:
|
|
12
|
+
pull_request:
|
|
13
|
+
branches: [main, master]
|
|
14
|
+
jobs:
|
|
15
|
+
check:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: jayvenn21/repofail/.github/actions/repofail@main
|
|
20
|
+
with:
|
|
21
|
+
path: .
|
|
22
|
+
fail_on: HIGH
|
|
23
|
+
comment: 'true'
|
|
24
|
+
upload_artifact: 'true'
|
|
25
|
+
pr_number: ${{ github.event.pull_request.number }}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Inputs
|
|
29
|
+
|
|
30
|
+
| Input | Default | Description |
|
|
31
|
+
|-------|---------|-------------|
|
|
32
|
+
| `path` | `.` | Repository path to scan |
|
|
33
|
+
| `fail_on` | `HIGH` | Fail CI when severity is HIGH, MEDIUM, or LOW |
|
|
34
|
+
| `comment` | `true` | Comment on PR with Markdown report |
|
|
35
|
+
| `upload_artifact` | `true` | Upload JSON report as workflow artifact |
|
|
36
|
+
| `pr_number` | (empty) | Set to `${{ github.event.pull_request.number }}` for PR comments |
|
|
37
|
+
|
|
38
|
+
## Behavior
|
|
39
|
+
|
|
40
|
+
1. Installs repofail from PyPI
|
|
41
|
+
2. Runs `repofail -m` and saves the report
|
|
42
|
+
3. Runs `repofail -j` for machine-readable output
|
|
43
|
+
4. Comments on the PR with the Markdown report (if `comment: true` and `pr_number` set)
|
|
44
|
+
5. Uploads `repofail.json` as an artifact (if `upload_artifact: true`)
|
|
45
|
+
6. Runs `repofail --ci` and fails the job if violations meet or exceed `fail_on`
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
name: repofail
|
|
2
|
+
description: Deterministic runtime compatibility check — fail CI or comment on PR with report
|
|
3
|
+
inputs:
|
|
4
|
+
path:
|
|
5
|
+
description: Repository path to scan (default .)
|
|
6
|
+
required: false
|
|
7
|
+
default: .
|
|
8
|
+
fail_on:
|
|
9
|
+
description: Severity threshold to fail CI (HIGH, MEDIUM, LOW)
|
|
10
|
+
required: false
|
|
11
|
+
default: HIGH
|
|
12
|
+
comment:
|
|
13
|
+
description: Comment on PR with Markdown report
|
|
14
|
+
required: false
|
|
15
|
+
default: 'true'
|
|
16
|
+
upload_artifact:
|
|
17
|
+
description: Upload JSON report as artifact
|
|
18
|
+
required: false
|
|
19
|
+
default: 'true'
|
|
20
|
+
pr_number:
|
|
21
|
+
description: Pull request number (for commenting). Set to ${{ github.event.pull_request.number }}
|
|
22
|
+
required: false
|
|
23
|
+
default: ''
|
|
24
|
+
outputs:
|
|
25
|
+
markdown_file:
|
|
26
|
+
description: Path to Markdown report file (repofail-report.md)
|
|
27
|
+
runs:
|
|
28
|
+
using: composite
|
|
29
|
+
steps:
|
|
30
|
+
- name: Install repofail
|
|
31
|
+
shell: bash
|
|
32
|
+
run: pip install repofail
|
|
33
|
+
|
|
34
|
+
- name: Run repofail (Markdown)
|
|
35
|
+
id: md
|
|
36
|
+
shell: bash
|
|
37
|
+
run: |
|
|
38
|
+
repofail -p "${{ inputs.path }}" -m > repofail-report.md || true
|
|
39
|
+
echo "markdown_file=repofail-report.md" >> $GITHUB_OUTPUT
|
|
40
|
+
|
|
41
|
+
- name: Run repofail (JSON)
|
|
42
|
+
if: inputs.upload_artifact == 'true'
|
|
43
|
+
shell: bash
|
|
44
|
+
run: repofail -p "${{ inputs.path }}" -j > repofail.json || true
|
|
45
|
+
|
|
46
|
+
- name: Comment on PR with report
|
|
47
|
+
if: inputs.comment == 'true' && inputs.pr_number != ''
|
|
48
|
+
uses: actions/github-script@v7
|
|
49
|
+
with:
|
|
50
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
51
|
+
script: |
|
|
52
|
+
const fs = require('fs');
|
|
53
|
+
const body = fs.existsSync('repofail-report.md')
|
|
54
|
+
? fs.readFileSync('repofail-report.md', 'utf8')
|
|
55
|
+
: 'repofail report not available.';
|
|
56
|
+
const comment = `## repofail · compatibility report\n\n\`\`\`\n${body}\n\`\`\``;
|
|
57
|
+
await github.rest.issues.createComment({
|
|
58
|
+
issue_number: ${{ inputs.pr_number }},
|
|
59
|
+
owner: context.repo.owner,
|
|
60
|
+
repo: context.repo.repo,
|
|
61
|
+
body: comment,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
- name: Upload repofail JSON artifact
|
|
65
|
+
if: inputs.upload_artifact == 'true' && always()
|
|
66
|
+
uses: actions/upload-artifact@v4
|
|
67
|
+
with:
|
|
68
|
+
name: repofail-report
|
|
69
|
+
path: repofail.json
|
|
70
|
+
|
|
71
|
+
- name: Run repofail (CI — fail if threshold exceeded)
|
|
72
|
+
shell: bash
|
|
73
|
+
run: repofail -p "${{ inputs.path }}" --ci --fail-on "${{ inputs.fail_on }}"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
dist/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
*.egg-info/
|
|
6
|
+
.eggs/
|
|
7
|
+
.venv/
|
|
8
|
+
.venv-check/
|
|
9
|
+
venv/
|
|
10
|
+
testenv/
|
|
11
|
+
VISION.md
|
|
12
|
+
repofail-contract.json
|
|
13
|
+
|
|
14
|
+
# Sensitive / local-only (never commit)
|
|
15
|
+
.env
|
|
16
|
+
.env.local
|
|
17
|
+
.env.*.local
|
|
18
|
+
.secrets
|
|
19
|
+
secrets.yaml
|
|
20
|
+
.credentials
|
|
21
|
+
*.pem
|
|
22
|
+
.DS_Store
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Homebrew formula for repofail
|
|
2
|
+
# To use: copy to your tap repo (e.g. homebrew-tap/Formula/repofail.rb)
|
|
3
|
+
# Then: brew tap jayvenn21/tap && brew install jayvenn21/tap/repofail
|
|
4
|
+
#
|
|
5
|
+
# Homebrew uses --no-deps when installing the main package, so all Python
|
|
6
|
+
# dependencies must be declared as resources below.
|
|
7
|
+
# If SHA256 fails after pushing a new tag, get the correct hash with:
|
|
8
|
+
# curl -sL https://github.com/jayvenn21/repofail/archive/refs/tags/vX.Y.Z.tar.gz | shasum -a 256
|
|
9
|
+
|
|
10
|
+
class Repofail < Formula
|
|
11
|
+
include Language::Python::Virtualenv
|
|
12
|
+
|
|
13
|
+
desc "Deterministic runtime compatibility analyzer"
|
|
14
|
+
homepage "https://github.com/jayvenn21/repofail"
|
|
15
|
+
url "https://github.com/jayvenn21/repofail/archive/refs/tags/v0.2.4.tar.gz"
|
|
16
|
+
sha256 "d5558cd419c8d46bdc958064cb97f963d1ea793866414c025906ec15033512ed"
|
|
17
|
+
license "MIT"
|
|
18
|
+
|
|
19
|
+
# App supports Python 3.10+. We use 3.12 for current Homebrew; change to
|
|
20
|
+
# python@3.10 or python@3.11 if you need an older interpreter.
|
|
21
|
+
depends_on "libyaml"
|
|
22
|
+
depends_on "python@3.12"
|
|
23
|
+
|
|
24
|
+
resource "click" do
|
|
25
|
+
url "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz"
|
|
26
|
+
sha256 "12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
resource "typer" do
|
|
30
|
+
url "https://files.pythonhosted.org/packages/ac/0a/d55af35db5f50f486e3eda0ada747eed773859e2699d3ce570b682a9b70a/typer-0.12.3.tar.gz"
|
|
31
|
+
sha256 "49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
resource "rich" do
|
|
35
|
+
url "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz"
|
|
36
|
+
sha256 "439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
resource "shellingham" do
|
|
40
|
+
url "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz"
|
|
41
|
+
sha256 "8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
resource "typing-extensions" do
|
|
45
|
+
url "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz"
|
|
46
|
+
sha256 "1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
resource "tomli" do
|
|
50
|
+
url "https://files.pythonhosted.org/packages/35/b9/de2a5c0144d7d75a57ff355c0c24054f965b2dc3036456ae03a51ea6264b/tomli-2.0.2.tar.gz"
|
|
51
|
+
sha256 "d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
resource "pyyaml" do
|
|
55
|
+
url "https://github.com/yaml/pyyaml/archive/refs/tags/6.0.1.tar.gz"
|
|
56
|
+
sha256 "57314c984aaa84318eed00cf5a8365afc49f87954969e295efe2ba99f3b21f7a"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def install
|
|
60
|
+
virtualenv_install_with_resources
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
test do
|
|
64
|
+
assert_match "repofail", shell_output("#{bin}/repofail --help", 0)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: repofail
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Predict why a repository will fail on your machine before you run it.
|
|
5
5
|
Author: Jayanth
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
6
11
|
Requires-Python: >=3.10
|
|
7
12
|
Requires-Dist: pyyaml>=6.0
|
|
8
13
|
Requires-Dist: tomli>=2.0; python_version < '3.11'
|
|
@@ -12,7 +17,7 @@ Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
|
12
17
|
Description-Content-Type: text/markdown
|
|
13
18
|
|
|
14
19
|
<p align="center">
|
|
15
|
-
<img src="https://raw.githubusercontent.com/jayvenn21/repofail/
|
|
20
|
+
<img src="https://raw.githubusercontent.com/jayvenn21/repofail/main/docs/logo.png" width="180" alt="repofail logo">
|
|
16
21
|
</p>
|
|
17
22
|
|
|
18
23
|
<h1 align="center">repofail</h1>
|
|
@@ -22,14 +27,16 @@ Description-Content-Type: text/markdown
|
|
|
22
27
|
</p>
|
|
23
28
|
|
|
24
29
|
<p align="center">
|
|
25
|
-
<a href="https://pypi.org/project/repofail/"><img src="https://img.shields.io/pypi/v/repofail?
|
|
30
|
+
<a href="https://pypi.org/project/repofail/"><img src="https://img.shields.io/pypi/v/repofail?color=orange" alt="PyPI"></a>
|
|
31
|
+
<img src="https://img.shields.io/pypi/pyversions/repofail" alt="Python">
|
|
32
|
+
<img src="https://img.shields.io/pypi/dm/repofail" alt="Downloads">
|
|
26
33
|
<img src="https://img.shields.io/badge/ci-passing-brightgreen">
|
|
27
|
-
<img src="https://img.shields.io/badge/python-3.10+-blue">
|
|
28
34
|
<img src="https://img.shields.io/badge/runtime-validated-success">
|
|
29
35
|
<img src="https://img.shields.io/badge/rules-20+-informational">
|
|
30
36
|
</p>
|
|
31
37
|
|
|
32
38
|
<p align="center">
|
|
39
|
+
<strong>The static analyzer for runtime compatibility.</strong><br>
|
|
33
40
|
Predict why a repository will fail on your machine before you run it.
|
|
34
41
|
</p>
|
|
35
42
|
|
|
@@ -46,11 +53,24 @@ Description-Content-Type: text/markdown
|
|
|
46
53
|
<a href="#usage">Usage</a> ·
|
|
47
54
|
<a href="#rules">Rules</a> ·
|
|
48
55
|
<a href="#ci-integration">CI</a> ·
|
|
49
|
-
<a href="#contracts">Contracts</a>
|
|
56
|
+
<a href="#contracts">Contracts</a> ·
|
|
57
|
+
<a href="#faq">FAQ</a>
|
|
50
58
|
</p>
|
|
51
59
|
|
|
52
60
|
---
|
|
53
61
|
|
|
62
|
+
## Quickstart (30 seconds)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install repofail
|
|
66
|
+
cd /path/to/any/repo
|
|
67
|
+
repofail
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
You get a compatibility score and a list of deterministic blockers (Node version, Python range, CUDA, lock file, spec drift, etc.). No install of the repo’s dependencies. No cloud. No AI.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
54
74
|
## Why This Exists
|
|
55
75
|
|
|
56
76
|
Most tools install dependencies.
|
|
@@ -90,6 +110,18 @@ Deterministic spec violation detected — engines.node requires 22.x, host is 20
|
|
|
90
110
|
|
|
91
111
|
---
|
|
92
112
|
|
|
113
|
+
## Case studies
|
|
114
|
+
|
|
115
|
+
| Scenario | Without repofail | With repofail |
|
|
116
|
+
|----------|------------------|----------------|
|
|
117
|
+
| **Node engine mismatch** | Clone → `npm install` → `EBADENGINE` → search, fix, retry | `repofail .` → "Node 22.x required, host is 20.x" + suggested fix in <1s |
|
|
118
|
+
| **CUDA on laptop** | Clone → `pip install` → run → `RuntimeError: CUDA unavailable` | `repofail .` → "Hard-coded CUDA path, host has no GPU" before you run |
|
|
119
|
+
| **Spec drift (Python)** | CI passes, local fails; pyproject says 3.11, Docker uses 3.9 | `repofail .` → "Spec drift — 3 distinct Python targets" + where they differ |
|
|
120
|
+
|
|
121
|
+
Try the demos: [node engine](https://github.com/jayvenn21/repofail-demo-node-engine), [spec drift](https://github.com/jayvenn21/repofail-demo-spec-drift), [CUDA hardcoded](https://github.com/jayvenn21/repofail-demo-cuda-hardcoded).
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
93
125
|
## Install
|
|
94
126
|
|
|
95
127
|
**From PyPI (recommended)**
|
|
@@ -98,12 +130,25 @@ Deterministic spec violation detected — engines.node requires 22.x, host is 20
|
|
|
98
130
|
pip install repofail
|
|
99
131
|
```
|
|
100
132
|
|
|
101
|
-
|
|
133
|
+
**One-liner (curl)**
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
curl -sSL https://raw.githubusercontent.com/jayvenn21/repofail/main/install.sh | bash
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**pipx (isolated CLI)**
|
|
102
140
|
|
|
103
141
|
```bash
|
|
104
142
|
pipx install repofail
|
|
105
143
|
```
|
|
106
144
|
|
|
145
|
+
**Homebrew** (formula: [jayvenn21/homebrew-tap](https://github.com/jayvenn21/homebrew-tap))
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
brew tap jayvenn21/tap
|
|
149
|
+
brew install jayvenn21/tap/repofail
|
|
150
|
+
```
|
|
151
|
+
|
|
107
152
|
**From source (development)**
|
|
108
153
|
|
|
109
154
|
```bash
|
|
@@ -142,10 +187,41 @@ repofail s # Stats: local failure counts (from -r reports)
|
|
|
142
187
|
repofail s -j # Stats with JSON output
|
|
143
188
|
```
|
|
144
189
|
|
|
190
|
+
## Exit codes
|
|
191
|
+
|
|
192
|
+
- **0** — No deterministic violations (or scan completed successfully)
|
|
193
|
+
- **1** — Violations detected (with `--ci`) or target host has issues (with `sim`)
|
|
194
|
+
- **2** — Invalid usage / bad input (e.g. not a directory, contract violation)
|
|
195
|
+
|
|
145
196
|
---
|
|
146
197
|
|
|
147
198
|
## CI integration
|
|
148
199
|
|
|
200
|
+
**Option A — Reusable action (comment on PR + fail CI)**
|
|
201
|
+
|
|
202
|
+
```yaml
|
|
203
|
+
name: repofail
|
|
204
|
+
on:
|
|
205
|
+
pull_request:
|
|
206
|
+
branches: [main, master]
|
|
207
|
+
jobs:
|
|
208
|
+
check:
|
|
209
|
+
runs-on: ubuntu-latest
|
|
210
|
+
steps:
|
|
211
|
+
- uses: actions/checkout@v4
|
|
212
|
+
- uses: jayvenn21/repofail/.github/actions/repofail@main
|
|
213
|
+
with:
|
|
214
|
+
path: .
|
|
215
|
+
fail_on: HIGH
|
|
216
|
+
comment: 'true'
|
|
217
|
+
upload_artifact: 'true'
|
|
218
|
+
pr_number: ${{ github.event.pull_request.number }}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The action installs repofail, runs a compatibility check, comments the Markdown report on the PR, uploads the JSON artifact, and fails the job if violations meet the threshold.
|
|
222
|
+
|
|
223
|
+
**Option B — Inline (no comment)**
|
|
224
|
+
|
|
149
225
|
```yaml
|
|
150
226
|
- uses: actions/checkout@v4
|
|
151
227
|
- uses: actions/setup-python@v5
|
|
@@ -164,7 +240,7 @@ repofail gen . -o contract.json
|
|
|
164
240
|
repofail check contract.json
|
|
165
241
|
```
|
|
166
242
|
|
|
167
|
-
Versioned runtime expectations. Teams share contracts. CI checks drift.
|
|
243
|
+
Versioned runtime expectations. Teams share contracts. CI checks drift. Generated contracts report the installed repofail version (from PyPI/Homebrew) so tooling stays traceable.
|
|
168
244
|
|
|
169
245
|
---
|
|
170
246
|
|
|
@@ -237,8 +313,39 @@ Extensible via `.repofail/rules.yaml`.
|
|
|
237
313
|
|
|
238
314
|
---
|
|
239
315
|
|
|
316
|
+
## FAQ
|
|
317
|
+
|
|
318
|
+
**Does repofail install or run my project?**
|
|
319
|
+
No. It only reads configs and (optionally) inspects Python/JS for patterns. No `pip install`, no `npm install`, no execution.
|
|
320
|
+
|
|
321
|
+
**Does it need the internet?**
|
|
322
|
+
No. It runs fully offline. Host inspection uses local subprocesses (e.g. `node --version`).
|
|
323
|
+
|
|
324
|
+
**Why “deterministic”?**
|
|
325
|
+
Same repo + same host → same result. No ML, no heuristics that change between runs. Rules are based on config and code.
|
|
326
|
+
|
|
327
|
+
**Can I add my own rules?**
|
|
328
|
+
Yes. Put a `.repofail/rules.yaml` (or `repofail-rules.yaml`) in the repo and define conditions on `repo.*` and `host.*`. See `repofail -e list` for built-in rule IDs.
|
|
329
|
+
|
|
330
|
+
**What if my repo is clean?**
|
|
331
|
+
You get a high score (e.g. 96–100%) and “No deterministic blockers detected.” repofail does not invent problems.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## When not to use it
|
|
336
|
+
|
|
337
|
+
- **You need dependency resolution** — use pip, npm, poetry, etc. repofail does not install or resolve.
|
|
338
|
+
- **You need security scanning** — use Dependabot, Snyk, or similar. repofail is compatibility-only.
|
|
339
|
+
- **You want “AI suggested fixes”** — repofail gives deterministic, rule-based suggestions only.
|
|
340
|
+
- **You run only in one environment** — if every dev and CI use the same OS/runtime, the value is smaller (still useful for drift and contracts).
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
240
344
|
## Testing
|
|
241
345
|
|
|
242
346
|
```bash
|
|
347
|
+
pip install -e ".[dev]"
|
|
243
348
|
pytest tests/ -v
|
|
244
349
|
```
|
|
350
|
+
|
|
351
|
+
**Quick checks:** `bash -n install.sh` (syntax). The GitHub Action runs on every PR in this repo (see [.github/workflows/repofail.yml](.github/workflows/repofail.yml)); to test the reusable action, use it in another repo’s workflow on a PR.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/jayvenn21/repofail/
|
|
2
|
+
<img src="https://raw.githubusercontent.com/jayvenn21/repofail/main/docs/logo.png" width="180" alt="repofail logo">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<h1 align="center">repofail</h1>
|
|
@@ -9,14 +9,16 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="https://pypi.org/project/repofail/"><img src="https://img.shields.io/pypi/v/repofail?
|
|
12
|
+
<a href="https://pypi.org/project/repofail/"><img src="https://img.shields.io/pypi/v/repofail?color=orange" alt="PyPI"></a>
|
|
13
|
+
<img src="https://img.shields.io/pypi/pyversions/repofail" alt="Python">
|
|
14
|
+
<img src="https://img.shields.io/pypi/dm/repofail" alt="Downloads">
|
|
13
15
|
<img src="https://img.shields.io/badge/ci-passing-brightgreen">
|
|
14
|
-
<img src="https://img.shields.io/badge/python-3.10+-blue">
|
|
15
16
|
<img src="https://img.shields.io/badge/runtime-validated-success">
|
|
16
17
|
<img src="https://img.shields.io/badge/rules-20+-informational">
|
|
17
18
|
</p>
|
|
18
19
|
|
|
19
20
|
<p align="center">
|
|
21
|
+
<strong>The static analyzer for runtime compatibility.</strong><br>
|
|
20
22
|
Predict why a repository will fail on your machine before you run it.
|
|
21
23
|
</p>
|
|
22
24
|
|
|
@@ -33,11 +35,24 @@
|
|
|
33
35
|
<a href="#usage">Usage</a> ·
|
|
34
36
|
<a href="#rules">Rules</a> ·
|
|
35
37
|
<a href="#ci-integration">CI</a> ·
|
|
36
|
-
<a href="#contracts">Contracts</a>
|
|
38
|
+
<a href="#contracts">Contracts</a> ·
|
|
39
|
+
<a href="#faq">FAQ</a>
|
|
37
40
|
</p>
|
|
38
41
|
|
|
39
42
|
---
|
|
40
43
|
|
|
44
|
+
## Quickstart (30 seconds)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install repofail
|
|
48
|
+
cd /path/to/any/repo
|
|
49
|
+
repofail
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
You get a compatibility score and a list of deterministic blockers (Node version, Python range, CUDA, lock file, spec drift, etc.). No install of the repo’s dependencies. No cloud. No AI.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
41
56
|
## Why This Exists
|
|
42
57
|
|
|
43
58
|
Most tools install dependencies.
|
|
@@ -77,6 +92,18 @@ Deterministic spec violation detected — engines.node requires 22.x, host is 20
|
|
|
77
92
|
|
|
78
93
|
---
|
|
79
94
|
|
|
95
|
+
## Case studies
|
|
96
|
+
|
|
97
|
+
| Scenario | Without repofail | With repofail |
|
|
98
|
+
|----------|------------------|----------------|
|
|
99
|
+
| **Node engine mismatch** | Clone → `npm install` → `EBADENGINE` → search, fix, retry | `repofail .` → "Node 22.x required, host is 20.x" + suggested fix in <1s |
|
|
100
|
+
| **CUDA on laptop** | Clone → `pip install` → run → `RuntimeError: CUDA unavailable` | `repofail .` → "Hard-coded CUDA path, host has no GPU" before you run |
|
|
101
|
+
| **Spec drift (Python)** | CI passes, local fails; pyproject says 3.11, Docker uses 3.9 | `repofail .` → "Spec drift — 3 distinct Python targets" + where they differ |
|
|
102
|
+
|
|
103
|
+
Try the demos: [node engine](https://github.com/jayvenn21/repofail-demo-node-engine), [spec drift](https://github.com/jayvenn21/repofail-demo-spec-drift), [CUDA hardcoded](https://github.com/jayvenn21/repofail-demo-cuda-hardcoded).
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
80
107
|
## Install
|
|
81
108
|
|
|
82
109
|
**From PyPI (recommended)**
|
|
@@ -85,12 +112,25 @@ Deterministic spec violation detected — engines.node requires 22.x, host is 20
|
|
|
85
112
|
pip install repofail
|
|
86
113
|
```
|
|
87
114
|
|
|
88
|
-
|
|
115
|
+
**One-liner (curl)**
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
curl -sSL https://raw.githubusercontent.com/jayvenn21/repofail/main/install.sh | bash
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**pipx (isolated CLI)**
|
|
89
122
|
|
|
90
123
|
```bash
|
|
91
124
|
pipx install repofail
|
|
92
125
|
```
|
|
93
126
|
|
|
127
|
+
**Homebrew** (formula: [jayvenn21/homebrew-tap](https://github.com/jayvenn21/homebrew-tap))
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
brew tap jayvenn21/tap
|
|
131
|
+
brew install jayvenn21/tap/repofail
|
|
132
|
+
```
|
|
133
|
+
|
|
94
134
|
**From source (development)**
|
|
95
135
|
|
|
96
136
|
```bash
|
|
@@ -129,10 +169,41 @@ repofail s # Stats: local failure counts (from -r reports)
|
|
|
129
169
|
repofail s -j # Stats with JSON output
|
|
130
170
|
```
|
|
131
171
|
|
|
172
|
+
## Exit codes
|
|
173
|
+
|
|
174
|
+
- **0** — No deterministic violations (or scan completed successfully)
|
|
175
|
+
- **1** — Violations detected (with `--ci`) or target host has issues (with `sim`)
|
|
176
|
+
- **2** — Invalid usage / bad input (e.g. not a directory, contract violation)
|
|
177
|
+
|
|
132
178
|
---
|
|
133
179
|
|
|
134
180
|
## CI integration
|
|
135
181
|
|
|
182
|
+
**Option A — Reusable action (comment on PR + fail CI)**
|
|
183
|
+
|
|
184
|
+
```yaml
|
|
185
|
+
name: repofail
|
|
186
|
+
on:
|
|
187
|
+
pull_request:
|
|
188
|
+
branches: [main, master]
|
|
189
|
+
jobs:
|
|
190
|
+
check:
|
|
191
|
+
runs-on: ubuntu-latest
|
|
192
|
+
steps:
|
|
193
|
+
- uses: actions/checkout@v4
|
|
194
|
+
- uses: jayvenn21/repofail/.github/actions/repofail@main
|
|
195
|
+
with:
|
|
196
|
+
path: .
|
|
197
|
+
fail_on: HIGH
|
|
198
|
+
comment: 'true'
|
|
199
|
+
upload_artifact: 'true'
|
|
200
|
+
pr_number: ${{ github.event.pull_request.number }}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The action installs repofail, runs a compatibility check, comments the Markdown report on the PR, uploads the JSON artifact, and fails the job if violations meet the threshold.
|
|
204
|
+
|
|
205
|
+
**Option B — Inline (no comment)**
|
|
206
|
+
|
|
136
207
|
```yaml
|
|
137
208
|
- uses: actions/checkout@v4
|
|
138
209
|
- uses: actions/setup-python@v5
|
|
@@ -151,7 +222,7 @@ repofail gen . -o contract.json
|
|
|
151
222
|
repofail check contract.json
|
|
152
223
|
```
|
|
153
224
|
|
|
154
|
-
Versioned runtime expectations. Teams share contracts. CI checks drift.
|
|
225
|
+
Versioned runtime expectations. Teams share contracts. CI checks drift. Generated contracts report the installed repofail version (from PyPI/Homebrew) so tooling stays traceable.
|
|
155
226
|
|
|
156
227
|
---
|
|
157
228
|
|
|
@@ -224,8 +295,39 @@ Extensible via `.repofail/rules.yaml`.
|
|
|
224
295
|
|
|
225
296
|
---
|
|
226
297
|
|
|
298
|
+
## FAQ
|
|
299
|
+
|
|
300
|
+
**Does repofail install or run my project?**
|
|
301
|
+
No. It only reads configs and (optionally) inspects Python/JS for patterns. No `pip install`, no `npm install`, no execution.
|
|
302
|
+
|
|
303
|
+
**Does it need the internet?**
|
|
304
|
+
No. It runs fully offline. Host inspection uses local subprocesses (e.g. `node --version`).
|
|
305
|
+
|
|
306
|
+
**Why “deterministic”?**
|
|
307
|
+
Same repo + same host → same result. No ML, no heuristics that change between runs. Rules are based on config and code.
|
|
308
|
+
|
|
309
|
+
**Can I add my own rules?**
|
|
310
|
+
Yes. Put a `.repofail/rules.yaml` (or `repofail-rules.yaml`) in the repo and define conditions on `repo.*` and `host.*`. See `repofail -e list` for built-in rule IDs.
|
|
311
|
+
|
|
312
|
+
**What if my repo is clean?**
|
|
313
|
+
You get a high score (e.g. 96–100%) and “No deterministic blockers detected.” repofail does not invent problems.
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## When not to use it
|
|
318
|
+
|
|
319
|
+
- **You need dependency resolution** — use pip, npm, poetry, etc. repofail does not install or resolve.
|
|
320
|
+
- **You need security scanning** — use Dependabot, Snyk, or similar. repofail is compatibility-only.
|
|
321
|
+
- **You want “AI suggested fixes”** — repofail gives deterministic, rule-based suggestions only.
|
|
322
|
+
- **You run only in one environment** — if every dev and CI use the same OS/runtime, the value is smaller (still useful for drift and contracts).
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
227
326
|
## Testing
|
|
228
327
|
|
|
229
328
|
```bash
|
|
329
|
+
pip install -e ".[dev]"
|
|
230
330
|
pytest tests/ -v
|
|
231
331
|
```
|
|
332
|
+
|
|
333
|
+
**Quick checks:** `bash -n install.sh` (syntax). The GitHub Action runs on every PR in this repo (see [.github/workflows/repofail.yml](.github/workflows/repofail.yml)); to test the reusable action, use it in another repo’s workflow on a PR.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# repofail — 30-second quickstart
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
Answers one question: **Will this repository run on this machine?**
|
|
6
|
+
|
|
7
|
+
It does **not** install your project. It reads configs and your environment, then reports compatibility issues (Node version, Python range, CUDA, lock file, spec drift, etc.) with a single score and clear evidence.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install repofail
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or: `pipx install repofail` | [install.sh](https://raw.githubusercontent.com/jayvenn21/repofail/main/install.sh) | Homebrew (see README).
|
|
16
|
+
|
|
17
|
+
## Run
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cd /path/to/any/repo
|
|
21
|
+
repofail
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
You get:
|
|
25
|
+
|
|
26
|
+
- A **compatibility score** (0–100%)
|
|
27
|
+
- **HARD FAILURES** (deterministic blockers) with evidence and suggested fixes
|
|
28
|
+
- Optional: **RUNTIME RISKS**, **STRUCTURAL PROFILE**
|
|
29
|
+
|
|
30
|
+
## CI
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
repofail --ci
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Exits 1 if HIGH (or configured) severity violations are found. Use in GitHub Actions or any CI.
|
|
37
|
+
|
|
38
|
+
## Next
|
|
39
|
+
|
|
40
|
+
- `repofail -e list` — list all rules
|
|
41
|
+
- `repofail -e spec_drift` — explain a rule
|
|
42
|
+
- [README](https://github.com/jayvenn21/repofail#readme) — full docs, FAQ, when not to use
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Homebrew formula for repofail
|
|
2
|
+
# To use: copy to your tap repo (e.g. homebrew-tap/Formula/repofail.rb)
|
|
3
|
+
# Then: brew tap jayvenn21/tap && brew install jayvenn21/tap/repofail
|
|
4
|
+
#
|
|
5
|
+
# Homebrew uses --no-deps when installing the main package, so all Python
|
|
6
|
+
# dependencies must be declared as resources below.
|
|
7
|
+
# If SHA256 fails after pushing a new tag, get the correct hash with:
|
|
8
|
+
# curl -sL https://github.com/jayvenn21/repofail/archive/refs/tags/vX.Y.Z.tar.gz | shasum -a 256
|
|
9
|
+
|
|
10
|
+
class Repofail < Formula
|
|
11
|
+
include Language::Python::Virtualenv
|
|
12
|
+
|
|
13
|
+
desc "Deterministic runtime compatibility analyzer"
|
|
14
|
+
homepage "https://github.com/jayvenn21/repofail"
|
|
15
|
+
url "https://github.com/jayvenn21/repofail/archive/refs/tags/v0.2.4.tar.gz"
|
|
16
|
+
sha256 "d5558cd419c8d46bdc958064cb97f963d1ea793866414c025906ec15033512ed"
|
|
17
|
+
license "MIT"
|
|
18
|
+
|
|
19
|
+
# App supports Python 3.10+. We use 3.12 for current Homebrew; change to
|
|
20
|
+
# python@3.10 or python@3.11 if you need an older interpreter.
|
|
21
|
+
depends_on "libyaml"
|
|
22
|
+
depends_on "python@3.12"
|
|
23
|
+
|
|
24
|
+
resource "click" do
|
|
25
|
+
url "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz"
|
|
26
|
+
sha256 "12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
resource "typer" do
|
|
30
|
+
url "https://files.pythonhosted.org/packages/ac/0a/d55af35db5f50f486e3eda0ada747eed773859e2699d3ce570b682a9b70a/typer-0.12.3.tar.gz"
|
|
31
|
+
sha256 "49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
resource "rich" do
|
|
35
|
+
url "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz"
|
|
36
|
+
sha256 "439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
resource "shellingham" do
|
|
40
|
+
url "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz"
|
|
41
|
+
sha256 "8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
resource "typing-extensions" do
|
|
45
|
+
url "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz"
|
|
46
|
+
sha256 "1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
resource "tomli" do
|
|
50
|
+
url "https://files.pythonhosted.org/packages/35/b9/de2a5c0144d7d75a57ff355c0c24054f965b2dc3036456ae03a51ea6264b/tomli-2.0.2.tar.gz"
|
|
51
|
+
sha256 "d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
resource "pyyaml" do
|
|
55
|
+
url "https://github.com/yaml/pyyaml/archive/refs/tags/6.0.1.tar.gz"
|
|
56
|
+
sha256 "57314c984aaa84318eed00cf5a8365afc49f87954969e295efe2ba99f3b21f7a"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def install
|
|
60
|
+
virtualenv_install_with_resources
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
test do
|
|
64
|
+
assert_match "repofail", shell_output("#{bin}/repofail --help", 0)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Install repofail — deterministic runtime compatibility analyzer
|
|
3
|
+
# Usage: curl -sSL https://raw.githubusercontent.com/jayvenn21/repofail/main/install.sh | bash
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
if command -v pipx &>/dev/null; then
|
|
8
|
+
echo "Installing repofail via pipx (isolated)..."
|
|
9
|
+
pipx install repofail
|
|
10
|
+
elif command -v pip3 &>/dev/null; then
|
|
11
|
+
echo "Installing repofail via pip..."
|
|
12
|
+
pip3 install repofail
|
|
13
|
+
elif command -v pip &>/dev/null; then
|
|
14
|
+
echo "Installing repofail via pip..."
|
|
15
|
+
pip install repofail
|
|
16
|
+
else
|
|
17
|
+
echo "Error: need pip or pipx. Install Python 3.10+ and run: pip install repofail"
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
echo "Done. Run: repofail --help"
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "repofail"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.4"
|
|
8
8
|
description = "Predict why a repository will fail on your machine before you run it."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -14,6 +14,13 @@ dependencies = [
|
|
|
14
14
|
"tomli>=2.0; python_version < '3.11'",
|
|
15
15
|
"pyyaml>=6.0",
|
|
16
16
|
]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
]
|
|
17
24
|
|
|
18
25
|
[project.scripts]
|
|
19
26
|
repofail = "repofail.cli:_main"
|
|
@@ -23,3 +30,6 @@ dev = [
|
|
|
23
30
|
"pytest>=7.0",
|
|
24
31
|
]
|
|
25
32
|
|
|
33
|
+
[tool.hatch.build.targets.sdist]
|
|
34
|
+
exclude = [".venv-check", ".venv-check/**", "testenv", "testenv/**", ".venv", ".venv/**", "venv", "venv/**"]
|
|
35
|
+
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
5
6
|
|
|
6
7
|
import click
|
|
7
8
|
import typer
|
|
@@ -46,7 +47,7 @@ from .engine import run_rules
|
|
|
46
47
|
from .contract import generate_contract, validate_contract, EnvironmentContract
|
|
47
48
|
from .telemetry import save_report, get_stats
|
|
48
49
|
from .rules.base import Severity
|
|
49
|
-
from .rules.registry import RULE_INFO
|
|
50
|
+
from .rules.registry import RULE_INFO
|
|
50
51
|
from .risk import estimate_success_probability
|
|
51
52
|
from .format import format_human
|
|
52
53
|
|
|
@@ -263,7 +264,7 @@ def _print_json(repo_profile, host_profile, results, verbose: bool = False) -> N
|
|
|
263
264
|
@app.command("gen")
|
|
264
265
|
def gen_cmd(
|
|
265
266
|
path: Path = typer.Argument(Path("."), exists=True, file_okay=False, dir_okay=True, resolve_path=True, help="Repo path"),
|
|
266
|
-
output: Path
|
|
267
|
+
output: Optional[Path] = typer.Option(None, "-o", help="Output file"),
|
|
267
268
|
) -> None:
|
|
268
269
|
"""Generate an environment contract from the repository."""
|
|
269
270
|
try:
|
repofail-0.2.2/.gitignore
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|