testreporthub 1.0.0__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.
- testreporthub-1.0.0/.github/workflows/release.yaml +48 -0
- testreporthub-1.0.0/.github/workflows/test.yaml +27 -0
- testreporthub-1.0.0/.gitignore +39 -0
- testreporthub-1.0.0/PKG-INFO +116 -0
- testreporthub-1.0.0/README.md +91 -0
- testreporthub-1.0.0/VISION.md +80 -0
- testreporthub-1.0.0/action/action.yaml +178 -0
- testreporthub-1.0.0/examples/run_demo.sh +10 -0
- testreporthub-1.0.0/pyproject.toml +42 -0
- testreporthub-1.0.0/src/testreporthub/__init__.py +3 -0
- testreporthub-1.0.0/src/testreporthub/__main__.py +4 -0
- testreporthub-1.0.0/src/testreporthub/aggregator.py +61 -0
- testreporthub-1.0.0/src/testreporthub/cli.py +343 -0
- testreporthub-1.0.0/src/testreporthub/db.py +406 -0
- testreporthub-1.0.0/src/testreporthub/models.py +107 -0
- testreporthub-1.0.0/src/testreporthub/parsers/__init__.py +4 -0
- testreporthub-1.0.0/src/testreporthub/parsers/base.py +27 -0
- testreporthub-1.0.0/src/testreporthub/parsers/cypress_json.py +92 -0
- testreporthub-1.0.0/src/testreporthub/parsers/junit_xml.py +114 -0
- testreporthub-1.0.0/src/testreporthub/parsers/newman_json.py +99 -0
- testreporthub-1.0.0/src/testreporthub/parsers/playwright_json.py +145 -0
- testreporthub-1.0.0/src/testreporthub/parsers/registry.py +51 -0
- testreporthub-1.0.0/src/testreporthub/reporter.py +83 -0
- testreporthub-1.0.0/tests/conftest.py +8 -0
- testreporthub-1.0.0/tests/fixtures/cypress.json +31 -0
- testreporthub-1.0.0/tests/fixtures/junit.xml +15 -0
- testreporthub-1.0.0/tests/fixtures/junit2.xml +15 -0
- testreporthub-1.0.0/tests/fixtures/newman.json +28 -0
- testreporthub-1.0.0/tests/fixtures/playwright.json +41 -0
- testreporthub-1.0.0/tests/test_aggregator.py +15 -0
- testreporthub-1.0.0/tests/test_db.py +230 -0
- testreporthub-1.0.0/tests/test_models.py +22 -0
- testreporthub-1.0.0/tests/test_parser.py +53 -0
- testreporthub-1.0.0/tests/test_reporter.py +19 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
id-token: write # Required for PyPI trusted publishing
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: '3.11'
|
|
21
|
+
|
|
22
|
+
- name: Install build tools
|
|
23
|
+
run: pip install build
|
|
24
|
+
|
|
25
|
+
- name: Build package
|
|
26
|
+
run: python -m build
|
|
27
|
+
|
|
28
|
+
- name: Upload artifacts
|
|
29
|
+
uses: actions/upload-artifact@v4
|
|
30
|
+
with:
|
|
31
|
+
name: python-package
|
|
32
|
+
path: dist/
|
|
33
|
+
|
|
34
|
+
publish:
|
|
35
|
+
needs: build
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
environment:
|
|
38
|
+
name: pypi
|
|
39
|
+
url: https://pypi.org/p/testreporthub
|
|
40
|
+
steps:
|
|
41
|
+
- name: Download artifacts
|
|
42
|
+
uses: actions/download-artifact@v4
|
|
43
|
+
with:
|
|
44
|
+
name: python-package
|
|
45
|
+
path: dist/
|
|
46
|
+
|
|
47
|
+
- name: Publish to PyPI
|
|
48
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# .github/workflows/qa.yml
|
|
2
|
+
name: QA
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
test:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
steps:
|
|
9
|
+
- uses: actions/checkout@v4
|
|
10
|
+
|
|
11
|
+
- name: Run Playwright tests
|
|
12
|
+
run: npx playwright test --reporter=json
|
|
13
|
+
|
|
14
|
+
- name: Run pytest
|
|
15
|
+
run: pytest --junitxml=junit.xml
|
|
16
|
+
|
|
17
|
+
- name: Unify & enforce quality
|
|
18
|
+
uses: krishnakv-25/testreporthub@v1
|
|
19
|
+
with:
|
|
20
|
+
inputs: 'junit.xml playwright-report.json'
|
|
21
|
+
output: 'unified-report.html'
|
|
22
|
+
labels: 'org=acme,app=checkout-service,env=${{ github.ref_name }}'
|
|
23
|
+
enable-quality-gate: 'true'
|
|
24
|
+
min-pass-rate: '95'
|
|
25
|
+
max-flake-rate: '5'
|
|
26
|
+
max-regressions: '0'
|
|
27
|
+
fail-on-failed: 'true'
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
cat << 'EOF' > .gitignore
|
|
2
|
+
# Python
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.py[cod]
|
|
5
|
+
*$py.class
|
|
6
|
+
*.egg-info/
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.egg
|
|
10
|
+
|
|
11
|
+
# Virtual environments
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
env/
|
|
15
|
+
|
|
16
|
+
# IDEs
|
|
17
|
+
.vscode/
|
|
18
|
+
.idea/
|
|
19
|
+
*.swp
|
|
20
|
+
*.swo
|
|
21
|
+
|
|
22
|
+
# Local databases and reports
|
|
23
|
+
*.db
|
|
24
|
+
report.html
|
|
25
|
+
demo-report.html
|
|
26
|
+
unified-report.html
|
|
27
|
+
|
|
28
|
+
# OS files
|
|
29
|
+
.DS_Store
|
|
30
|
+
Thumbs.db
|
|
31
|
+
|
|
32
|
+
# Test artifacts
|
|
33
|
+
.pytest_cache/
|
|
34
|
+
.coverage
|
|
35
|
+
htmlcov/
|
|
36
|
+
|
|
37
|
+
# VHS demo artifacts (keep the .tape, not the generated files)
|
|
38
|
+
assets/*.gif
|
|
39
|
+
EOF
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: testreporthub
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Unified test reporting: ingest JUnit/Cypress/Playwright/Newman and emit one searchable HTML report.
|
|
5
|
+
Author: TestReportHub Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: cypress,junit,playwright,qa,reports,testing
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Software Development :: Testing
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Requires-Dist: click>=8.1
|
|
18
|
+
Requires-Dist: defusedxml>=0.7
|
|
19
|
+
Requires-Dist: jinja2>=3.1
|
|
20
|
+
Requires-Dist: pydantic>=2.5
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# TestReportHub
|
|
27
|
+
|
|
28
|
+
**One command. One report. Every framework.**
|
|
29
|
+
|
|
30
|
+
TestReportHub ingests test execution reports from different frameworks...
|
|
31
|
+
(JUnit XML, Cypress, Playwright, Newman/Postman), normalizes them into a
|
|
32
|
+
single data model, and emits a self-contained, searchable HTML quality report.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install testreporthub
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or from source:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone https://github.com/your-org/testreporthub.git
|
|
44
|
+
cd testreporthub
|
|
45
|
+
pip install -e .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quick start
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Ingest anything — JUnit XML, Cypress, Playwright, Newman
|
|
52
|
+
trh collect ./results/ -o report.html
|
|
53
|
+
|
|
54
|
+
# Auto-detect formats (default)
|
|
55
|
+
trh collect ./cypress/results ./playwright/results ./junit.xml
|
|
56
|
+
|
|
57
|
+
# Force a specific format
|
|
58
|
+
trh collect ./legacy.xml --format junit
|
|
59
|
+
|
|
60
|
+
# Open the report
|
|
61
|
+
open report.html
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 🚀 CI/CD Integration
|
|
65
|
+
|
|
66
|
+
TestReportHub is designed to run in your CI pipeline. It provides machine-readable outputs and strict exit codes.
|
|
67
|
+
|
|
68
|
+
### Fail the build on failures
|
|
69
|
+
```bash
|
|
70
|
+
# Exits with code 1 if any test failed or errored
|
|
71
|
+
trh collect ./results/ -o report.json --fail-on-failed --fail-on-error
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Supported formats
|
|
75
|
+
|
|
76
|
+
| Format | Source | Flag |
|
|
77
|
+
| --- | --- | --- |
|
|
78
|
+
| JUnit XML | pytest, Java, Go, Rust, etc. | `--format junit` |
|
|
79
|
+
| Cypress JSON | Mocha-based reporter | `--format cypress` |
|
|
80
|
+
| Playwright JSON | `--reporter=json` | `--format playwright` |
|
|
81
|
+
| Newman JSON | Postman collections | `--format newman` |
|
|
82
|
+
|
|
83
|
+
## Normalized model
|
|
84
|
+
|
|
85
|
+
Every test is normalized to:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
id, name, full_name, suite, framework, status, duration_ms,
|
|
89
|
+
started_at, message, trace, error_type, tags, metadata, attachments
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Statuses: `passed`, `failed`, `skipped`, `error`, `xfailed`.
|
|
93
|
+
|
|
94
|
+
## Why this matters
|
|
95
|
+
|
|
96
|
+
Teams usually have test results scattered across UI, API, regression,
|
|
97
|
+
and legacy automation. TestReportHub gives you:
|
|
98
|
+
|
|
99
|
+
* one command to collect results
|
|
100
|
+
* one normalized test-result model
|
|
101
|
+
* one unified report
|
|
102
|
+
* one place to understand failures
|
|
103
|
+
|
|
104
|
+
It's also the foundation for **TestPulse** — flaky-test detection and
|
|
105
|
+
failure intelligence — but the MVP stays small on purpose.
|
|
106
|
+
|
|
107
|
+
## Development
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pip install -e ".[dev]"
|
|
111
|
+
pytest
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# TestReportHub
|
|
2
|
+
|
|
3
|
+
**One command. One report. Every framework.**
|
|
4
|
+
|
|
5
|
+
TestReportHub ingests test execution reports from different frameworks...
|
|
6
|
+
(JUnit XML, Cypress, Playwright, Newman/Postman), normalizes them into a
|
|
7
|
+
single data model, and emits a self-contained, searchable HTML quality report.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install testreporthub
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or from source:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
git clone https://github.com/your-org/testreporthub.git
|
|
19
|
+
cd testreporthub
|
|
20
|
+
pip install -e .
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Ingest anything — JUnit XML, Cypress, Playwright, Newman
|
|
27
|
+
trh collect ./results/ -o report.html
|
|
28
|
+
|
|
29
|
+
# Auto-detect formats (default)
|
|
30
|
+
trh collect ./cypress/results ./playwright/results ./junit.xml
|
|
31
|
+
|
|
32
|
+
# Force a specific format
|
|
33
|
+
trh collect ./legacy.xml --format junit
|
|
34
|
+
|
|
35
|
+
# Open the report
|
|
36
|
+
open report.html
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 🚀 CI/CD Integration
|
|
40
|
+
|
|
41
|
+
TestReportHub is designed to run in your CI pipeline. It provides machine-readable outputs and strict exit codes.
|
|
42
|
+
|
|
43
|
+
### Fail the build on failures
|
|
44
|
+
```bash
|
|
45
|
+
# Exits with code 1 if any test failed or errored
|
|
46
|
+
trh collect ./results/ -o report.json --fail-on-failed --fail-on-error
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Supported formats
|
|
50
|
+
|
|
51
|
+
| Format | Source | Flag |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| JUnit XML | pytest, Java, Go, Rust, etc. | `--format junit` |
|
|
54
|
+
| Cypress JSON | Mocha-based reporter | `--format cypress` |
|
|
55
|
+
| Playwright JSON | `--reporter=json` | `--format playwright` |
|
|
56
|
+
| Newman JSON | Postman collections | `--format newman` |
|
|
57
|
+
|
|
58
|
+
## Normalized model
|
|
59
|
+
|
|
60
|
+
Every test is normalized to:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
id, name, full_name, suite, framework, status, duration_ms,
|
|
64
|
+
started_at, message, trace, error_type, tags, metadata, attachments
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Statuses: `passed`, `failed`, `skipped`, `error`, `xfailed`.
|
|
68
|
+
|
|
69
|
+
## Why this matters
|
|
70
|
+
|
|
71
|
+
Teams usually have test results scattered across UI, API, regression,
|
|
72
|
+
and legacy automation. TestReportHub gives you:
|
|
73
|
+
|
|
74
|
+
* one command to collect results
|
|
75
|
+
* one normalized test-result model
|
|
76
|
+
* one unified report
|
|
77
|
+
* one place to understand failures
|
|
78
|
+
|
|
79
|
+
It's also the foundation for **TestPulse** — flaky-test detection and
|
|
80
|
+
failure intelligence — but the MVP stays small on purpose.
|
|
81
|
+
|
|
82
|
+
## Development
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install -e ".[dev]"
|
|
86
|
+
pytest
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
MIT
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# TestReportHub Vision
|
|
2
|
+
|
|
3
|
+
TestReportHub is the data ingestion layer for **TestPulse**, a test-failure intelligence platform.
|
|
4
|
+
|
|
5
|
+
## Two-Tier Architecture
|
|
6
|
+
|
|
7
|
+
### Tier 1: TestReportHub (Local CLI)
|
|
8
|
+
**Target user:** Individual engineer
|
|
9
|
+
**Scope:** One repo, one run
|
|
10
|
+
**Storage:** Stateless HTML/JSON, optional local SQLite
|
|
11
|
+
**Value:** "Show me this run, unified across frameworks"
|
|
12
|
+
|
|
13
|
+
Commands:
|
|
14
|
+
- `trh collect` — generate unified report
|
|
15
|
+
- `trh ingest` — persist to local SQLite with labels
|
|
16
|
+
- `trh flaky` — find flaky tests
|
|
17
|
+
- `trh compare` — diff two runs
|
|
18
|
+
- `trh history` — trend analysis
|
|
19
|
+
- `trh quality-gate` — enforce quality thresholds
|
|
20
|
+
|
|
21
|
+
### Tier 2: TestPulse (Hosted SaaS)
|
|
22
|
+
**Target user:** QA leads, engineering managers
|
|
23
|
+
**Scope:** Entire org, all time
|
|
24
|
+
**Storage:** Hosted database
|
|
25
|
+
**Value:** "Show me the health of checkout-service across all environments"
|
|
26
|
+
|
|
27
|
+
Features (future):
|
|
28
|
+
- Multi-tenant web dashboard
|
|
29
|
+
- Team-based access control
|
|
30
|
+
- Slack/Jira integrations
|
|
31
|
+
- ML-based flake prediction
|
|
32
|
+
- Failure clustering and root-cause hints
|
|
33
|
+
- SLO tracking per app/env
|
|
34
|
+
|
|
35
|
+
## The Bridge: Labels
|
|
36
|
+
|
|
37
|
+
The `--label` flag on `trh ingest` is the bridge between tiers. Labels like `org=acme,app=checkout,env=staging` map directly to the hierarchy in TestPulse.
|
|
38
|
+
|
|
39
|
+
Local CLI users get hierarchical filtering for free. When they're ready for the SaaS, their data model is already compatible.
|
|
40
|
+
|
|
41
|
+
## Design Principles
|
|
42
|
+
|
|
43
|
+
1. **Zero-config by default.** `pip install testreporthub` should be the only setup.
|
|
44
|
+
2. **Self-contained outputs.** HTML reports have no external dependencies.
|
|
45
|
+
3. **Labels over schema.** Don't hardcode org/app/env — use flexible key-value labels.
|
|
46
|
+
4. **CLI-first, UI-later.** The SaaS is a UI on top of the same data model.
|
|
47
|
+
5. **Fail fast in CI.** Quality gates should block deployments when quality drops.
|
|
48
|
+
|
|
49
|
+
## Roadmap
|
|
50
|
+
|
|
51
|
+
### v1.0 (Current)
|
|
52
|
+
- [x] Parsers: JUnit, Cypress, Playwright, Newman
|
|
53
|
+
- [x] HTML report with search/filter
|
|
54
|
+
- [x] JSON/NDJSON output
|
|
55
|
+
- [x] CI exit codes
|
|
56
|
+
- [x] SQLite backend with labels
|
|
57
|
+
- [x] Intelligence: flaky, compare, history, quality-gate
|
|
58
|
+
- [x] GitHub Action
|
|
59
|
+
- [x] PyPI release
|
|
60
|
+
|
|
61
|
+
### v1.1 (Next)
|
|
62
|
+
- [ ] Streaming parsers for 100MB+ files
|
|
63
|
+
- [ ] Attachment bundling (screenshots/videos in report)
|
|
64
|
+
- [ ] Secret redaction (`--redact`)
|
|
65
|
+
- [ ] HTML trend charts in report
|
|
66
|
+
- [ ] More parsers: Jest, Mocha, Robot, Cucumber
|
|
67
|
+
|
|
68
|
+
### v2.0 (TestPulse Preview)
|
|
69
|
+
- [ ] Hosted SaaS launch
|
|
70
|
+
- [ ] Web dashboard with hierarchy navigation
|
|
71
|
+
- [ ] Slack notifications on quality gate breaches
|
|
72
|
+
- [ ] Jira/GitHub issue creation from failures
|
|
73
|
+
- [ ] Team-based access control
|
|
74
|
+
|
|
75
|
+
## What TestReportHub is NOT
|
|
76
|
+
|
|
77
|
+
- Not a test runner
|
|
78
|
+
- Not a test framework
|
|
79
|
+
- Not a replacement for Allure/ReportPortal (it complements them)
|
|
80
|
+
- Not a SaaS (yet — that's TestPulse)
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
name: 'TestReportHub'
|
|
2
|
+
description: 'Unify test reports and enforce quality gates across org/app/env hierarchies.'
|
|
3
|
+
author: 'TestReportHub Contributors'
|
|
4
|
+
branding:
|
|
5
|
+
icon: 'check-circle'
|
|
6
|
+
color: 'blue'
|
|
7
|
+
|
|
8
|
+
inputs:
|
|
9
|
+
# Collection inputs
|
|
10
|
+
inputs:
|
|
11
|
+
description: 'Space-separated list of files or directories to ingest.'
|
|
12
|
+
required: true
|
|
13
|
+
output:
|
|
14
|
+
description: 'Path to the output report file.'
|
|
15
|
+
required: false
|
|
16
|
+
default: 'unified-report.html'
|
|
17
|
+
format:
|
|
18
|
+
description: 'Output format: html, json, or ndjson.'
|
|
19
|
+
required: false
|
|
20
|
+
default: 'html'
|
|
21
|
+
|
|
22
|
+
# Labels (hierarchy)
|
|
23
|
+
labels:
|
|
24
|
+
description: 'Comma-separated key=value labels (e.g., "org=acme,app=checkout,env=staging").'
|
|
25
|
+
required: false
|
|
26
|
+
default: ''
|
|
27
|
+
|
|
28
|
+
# Quality gate
|
|
29
|
+
enable-quality-gate:
|
|
30
|
+
description: 'Run quality gate checks after ingestion.'
|
|
31
|
+
required: false
|
|
32
|
+
default: 'false'
|
|
33
|
+
min-pass-rate:
|
|
34
|
+
description: 'Minimum pass rate (%) for quality gate.'
|
|
35
|
+
required: false
|
|
36
|
+
default: '95'
|
|
37
|
+
max-flake-rate:
|
|
38
|
+
description: 'Maximum flaky test rate (%) for quality gate.'
|
|
39
|
+
required: false
|
|
40
|
+
default: '5'
|
|
41
|
+
max-regressions:
|
|
42
|
+
description: 'Maximum allowed regressions vs previous run.'
|
|
43
|
+
required: false
|
|
44
|
+
default: '0'
|
|
45
|
+
|
|
46
|
+
# Failure behavior
|
|
47
|
+
fail-on-failed:
|
|
48
|
+
description: 'Fail the action if any tests failed.'
|
|
49
|
+
required: false
|
|
50
|
+
default: 'false'
|
|
51
|
+
fail-on-error:
|
|
52
|
+
description: 'Fail the action if any tests errored.'
|
|
53
|
+
required: false
|
|
54
|
+
default: 'false'
|
|
55
|
+
|
|
56
|
+
# Persistence
|
|
57
|
+
db-path:
|
|
58
|
+
description: 'Path to the SQLite database for historical tracking.'
|
|
59
|
+
required: false
|
|
60
|
+
default: 'testpulse.db'
|
|
61
|
+
|
|
62
|
+
# Version
|
|
63
|
+
version:
|
|
64
|
+
description: 'TestReportHub version to install from PyPI.'
|
|
65
|
+
required: false
|
|
66
|
+
default: 'latest'
|
|
67
|
+
|
|
68
|
+
outputs:
|
|
69
|
+
report-path:
|
|
70
|
+
description: 'Path to the generated report'
|
|
71
|
+
value: ${{ inputs.output }}
|
|
72
|
+
quality-gate-passed:
|
|
73
|
+
description: 'Whether the quality gate passed (true/false/na)'
|
|
74
|
+
value: ${{ steps.quality-gate.outputs.passed }}
|
|
75
|
+
|
|
76
|
+
runs:
|
|
77
|
+
using: 'composite'
|
|
78
|
+
steps:
|
|
79
|
+
- name: Setup Python
|
|
80
|
+
uses: actions/setup-python@v5
|
|
81
|
+
with:
|
|
82
|
+
python-version: '3.11'
|
|
83
|
+
|
|
84
|
+
- name: Install TestReportHub
|
|
85
|
+
shell: bash
|
|
86
|
+
run: |
|
|
87
|
+
if [ "${{ inputs.version }}" = "latest" ]; then
|
|
88
|
+
pip install testreporthub
|
|
89
|
+
else
|
|
90
|
+
pip install testreporthub==${{ inputs.version }}
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
- name: Build CLI command
|
|
94
|
+
id: build-cmd
|
|
95
|
+
shell: bash
|
|
96
|
+
run: |
|
|
97
|
+
# Parse space-separated inputs into array
|
|
98
|
+
INPUTS_ARRAY=(${{ inputs.inputs }})
|
|
99
|
+
|
|
100
|
+
COLLECT_CMD="trh collect"
|
|
101
|
+
for input in "${INPUTS_ARRAY[@]}"; do
|
|
102
|
+
COLLECT_CMD="$COLLECT_CMD \"$input\""
|
|
103
|
+
done
|
|
104
|
+
COLLECT_CMD="$COLLECT_CMD -o ${{ inputs.output }} --format ${{ inputs.format }}"
|
|
105
|
+
|
|
106
|
+
if [ "${{ inputs.fail-on-failed }}" = "true" ]; then
|
|
107
|
+
COLLECT_CMD="$COLLECT_CMD --fail-on-failed"
|
|
108
|
+
fi
|
|
109
|
+
if [ "${{ inputs.fail-on-error }}" = "true" ]; then
|
|
110
|
+
COLLECT_CMD="$COLLECT_CMD --fail-on-error"
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
echo "collect_cmd=$COLLECT_CMD" >> $GITHUB_OUTPUT
|
|
114
|
+
|
|
115
|
+
- name: Generate Unified Report
|
|
116
|
+
shell: bash
|
|
117
|
+
run: |
|
|
118
|
+
echo "Running: ${{ steps.build-cmd.outputs.collect_cmd }}"
|
|
119
|
+
eval ${{ steps.build-cmd.outputs.collect_cmd }}
|
|
120
|
+
|
|
121
|
+
- name: Ingest to database (with labels)
|
|
122
|
+
if: inputs.enable-quality-gate == 'true'
|
|
123
|
+
shell: bash
|
|
124
|
+
run: |
|
|
125
|
+
INPUTS_ARRAY=(${{ inputs.inputs }})
|
|
126
|
+
INGEST_CMD="trh ingest"
|
|
127
|
+
for input in "${INPUTS_ARRAY[@]}"; do
|
|
128
|
+
INGEST_CMD="$INGEST_CMD \"$input\""
|
|
129
|
+
done
|
|
130
|
+
INGEST_CMD="$INGEST_CMD --db ${{ inputs.db-path }}"
|
|
131
|
+
|
|
132
|
+
# Parse comma-separated labels
|
|
133
|
+
if [ -n "${{ inputs.labels }}" ]; then
|
|
134
|
+
IFS=',' read -ra LABEL_PAIRS <<< "${{ inputs.labels }}"
|
|
135
|
+
for pair in "${LABEL_PAIRS[@]}"; do
|
|
136
|
+
INGEST_CMD="$INGEST_CMD --label $pair"
|
|
137
|
+
done
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
echo "Running: $INGEST_CMD"
|
|
141
|
+
eval $INGEST_CMD
|
|
142
|
+
|
|
143
|
+
- name: Run Quality Gate
|
|
144
|
+
if: inputs.enable-quality-gate == 'true'
|
|
145
|
+
id: quality-gate
|
|
146
|
+
shell: bash
|
|
147
|
+
run: |
|
|
148
|
+
GATE_CMD="trh quality-gate --db ${{ inputs.db-path }}"
|
|
149
|
+
GATE_CMD="$GATE_CMD --min-pass-rate ${{ inputs.min-pass-rate }}"
|
|
150
|
+
GATE_CMD="$GATE_CMD --max-flake-rate ${{ inputs.max-flake-rate }}"
|
|
151
|
+
GATE_CMD="$GATE_CMD --max-regressions ${{ inputs.max-regressions }}"
|
|
152
|
+
GATE_CMD="$GATE_CMD --fail-on-breach"
|
|
153
|
+
|
|
154
|
+
# Add label filters
|
|
155
|
+
if [ -n "${{ inputs.labels }}" ]; then
|
|
156
|
+
IFS=',' read -ra LABEL_PAIRS <<< "${{ inputs.labels }}"
|
|
157
|
+
for pair in "${LABEL_PAIRS[@]}"; do
|
|
158
|
+
GATE_CMD="$GATE_CMD --label $pair"
|
|
159
|
+
done
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
echo "Running: $GATE_CMD"
|
|
163
|
+
if eval $GATE_CMD; then
|
|
164
|
+
echo "passed=true" >> $GITHUB_OUTPUT
|
|
165
|
+
else
|
|
166
|
+
echo "passed=false" >> $GITHUB_OUTPUT
|
|
167
|
+
exit 1
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
- name: Upload Report Artifact
|
|
171
|
+
if: always()
|
|
172
|
+
uses: actions/upload-artifact@v4
|
|
173
|
+
with:
|
|
174
|
+
name: testreporthub-report-${{ github.run_id }}
|
|
175
|
+
path: |
|
|
176
|
+
${{ inputs.output }}
|
|
177
|
+
${{ inputs.db-path }}
|
|
178
|
+
retention-days: 30
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
cd "$(dirname "$0")/.."
|
|
5
|
+
pip install -e . >/dev/null
|
|
6
|
+
|
|
7
|
+
# Collect every fixture and write a unified report.
|
|
8
|
+
trh collect tests/fixtures -o demo-report.html
|
|
9
|
+
|
|
10
|
+
echo "✓ Wrote demo-report.html — open it in a browser."
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "testreporthub"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Unified test reporting: ingest JUnit/Cypress/Playwright/Newman and emit one searchable HTML report."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "TestReportHub Contributors" }]
|
|
13
|
+
keywords = ["testing", "reports", "junit", "cypress", "playwright", "qa"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Topic :: Software Development :: Testing",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.9",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"click>=8.1",
|
|
26
|
+
"pydantic>=2.5",
|
|
27
|
+
"defusedxml>=0.7",
|
|
28
|
+
"jinja2>=3.1",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
dev = ["pytest>=8.0", "pytest-cov"]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
trh = "testreporthub.cli:main"
|
|
36
|
+
testreporthub = "testreporthub.cli:main"
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.wheel]
|
|
39
|
+
packages = ["src/testreporthub"]
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
testpaths = ["tests"]
|