jenkins improvements
This commit is contained in:
parent
401a56a4c6
commit
15e1e2321e
6
Makefile
6
Makefile
@ -1,4 +1,4 @@
|
||||
.PHONY: fmt fmt-check clippy test-local test-debugger-socket clean coverage coverage-xml coverage-json coverage-report-json coverage-domain-list coverage-domain-evidence test ci cobertura
|
||||
.PHONY: fmt fmt-check clippy test-local test-debugger-socket clean coverage coverage-xml coverage-json coverage-report-json coverage-domain-list coverage-domain-evidence coverage-domain-gate test ci ci-domains cobertura
|
||||
|
||||
fmt:
|
||||
cargo fmt
|
||||
@ -40,6 +40,10 @@ coverage-domain-evidence:
|
||||
fi
|
||||
./scripts/coverage-domain-evidence.sh "$(DOMAIN)"
|
||||
|
||||
coverage-domain-gate:
|
||||
./scripts/coverage-domain-evidence.sh --check-all
|
||||
|
||||
test: fmt-check clippy test-local test-debugger-socket
|
||||
ci: clean fmt-check clippy coverage coverage-report-json
|
||||
ci-domains: clean fmt-check clippy coverage coverage-report-json coverage-xml coverage-json coverage-domain-gate
|
||||
cobertura: coverage-xml coverage-json
|
||||
|
||||
@ -83,7 +83,7 @@ The desktop runtime opens a native window through the host layer, so this last c
|
||||
|
||||
The repository uses a two-layer runtime-edge coverage model:
|
||||
|
||||
- a mandatory global workspace coverage gate in CI;
|
||||
- a mandatory CI gate based on canonical runtime-edge domains;
|
||||
- domain-oriented review evidence for the canonical runtime-edge domains.
|
||||
|
||||
Current canonical domains:
|
||||
@ -99,6 +99,7 @@ Global coverage artifacts:
|
||||
```bash
|
||||
make ci
|
||||
make cobertura
|
||||
make ci-domains
|
||||
```
|
||||
|
||||
This produces:
|
||||
@ -119,6 +120,10 @@ make coverage-domain-evidence DOMAIN=host-dependent
|
||||
Per-domain baselines currently start around `60`.
|
||||
That does not waive test obligations. It means the project is adopting explicit domain evidence immediately while tightening quantitative expectations incrementally over time.
|
||||
|
||||
`make ci-domains` is the CI entrypoint used by Jenkins.
|
||||
It runs the standard coverage pipeline, produces the HTML/XML/JSON artifacts, and fails when any canonical domain falls below its configured `baseline_percent`.
|
||||
The CI gate currently compares domain `lines` coverage against each domain baseline.
|
||||
|
||||
When a PR changes the observable contract of a canonical domain, it is expected to:
|
||||
|
||||
- add or adjust tests for that domain; or
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
{"type":"discussion","id":"DSC-0021","status":"done","ticket":"asset-entry-codec-enum-with-metadata","title":"Asset Entry Codec Enum Contract","created_at":"2026-04-09","updated_at":"2026-04-09","tags":["asset","runtime","codec","metadata"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0024","file":"lessons/DSC-0021-asset-entry-codec-enum-contract/LSN-0024-string-on-the-wire-enum-in-runtime.md","status":"done","created_at":"2026-04-09","updated_at":"2026-04-09"}]}
|
||||
{"type":"discussion","id":"DSC-0022","status":"done","ticket":"tile-bank-vs-glyph-bank-domain-naming","title":"Glyph Bank Domain Naming Contract","created_at":"2026-04-09","updated_at":"2026-04-10","tags":["gfx","runtime","naming","domain-model"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0025","file":"lessons/DSC-0022-glyph-bank-domain-naming/LSN-0025-rename-artifact-by-meaning-not-by-token.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
||||
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"legacy-runtime-learn-import","title":"Import legacy runtime learn into discussion lessons","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["migration","tech-debt"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0001-prometeu-learn-index.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0002","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0002-historical-asset-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0003","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0003-historical-audio-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0004","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0004-historical-cartridge-boot-protocol-and-manifest-authority.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0005","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0005-historical-game-memcard-slots-surface-and-semantics.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0006","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0006-historical-gfx-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0007","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0007-historical-retired-fault-and-input-decisions.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0008","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0008-historical-vm-core-and-assets.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0009","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0009-mental-model-asset-management.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0010","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0010-mental-model-audio.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0011","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0011-mental-model-gfx.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0012","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0012-mental-model-input.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0013","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0013-mental-model-observability-and-debugging.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0014","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0014-mental-model-portability-and-cross-platform.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0015","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0015-mental-model-save-memory-and-memcard.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0016","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0016-mental-model-status-first-and-fault-thinking.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0017","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0017-mental-model-time-and-cycles.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0018","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0018-mental-model-touch.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
|
||||
{"type":"discussion","id":"DSC-0002","status":"open","ticket":"runtime-edge-test-plan","title":"Agenda - Runtime Edge Test Plan","created_at":"2026-03-27","updated_at":"2026-04-20","tags":[],"agendas":[{"id":"AGD-0001","file":"workflow/agendas/AGD-0001-runtime-edge-test-plan.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-20"}],"decisions":[{"id":"DEC-0020","file":"workflow/decisions/DEC-0020-runtime-edge-coverage-governance-by-domain.md","status":"in_progress","created_at":"2026-04-20","updated_at":"2026-04-20","ref_agenda":"AGD-0001"}],"plans":[{"id":"PLN-0037","file":"workflow/plans/PLN-0037-runtime-edge-coverage-governance-foundation.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]},{"id":"PLN-0038","file":"workflow/plans/PLN-0038-firmware-and-host-dependent-domain-coverage-expansion.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]},{"id":"PLN-0039","file":"workflow/plans/PLN-0039-incremental-runtime-domain-suite-split-and-baselines.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0002","status":"open","ticket":"runtime-edge-test-plan","title":"Agenda - Runtime Edge Test Plan","created_at":"2026-03-27","updated_at":"2026-04-21","tags":[],"agendas":[{"id":"AGD-0001","file":"workflow/agendas/AGD-0001-runtime-edge-test-plan.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-20"}],"decisions":[{"id":"DEC-0020","file":"workflow/decisions/DEC-0020-runtime-edge-coverage-governance-by-domain.md","status":"in_progress","created_at":"2026-04-20","updated_at":"2026-04-21","ref_agenda":"AGD-0001"}],"plans":[{"id":"PLN-0037","file":"workflow/plans/PLN-0037-runtime-edge-coverage-governance-foundation.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-21","ref_decisions":["DEC-0020"]},{"id":"PLN-0038","file":"workflow/plans/PLN-0038-firmware-and-host-dependent-domain-coverage-expansion.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]},{"id":"PLN-0039","file":"workflow/plans/PLN-0039-incremental-runtime-domain-suite-split-and-baselines.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0003","status":"open","ticket":"packed-cartridge-loader-pmc","title":"Agenda - Packed Cartridge Loader PMC","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0002","file":"workflow/agendas/AGD-0002-packed-cartridge-loader-pmc.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0004","status":"open","ticket":"system-run-cart","title":"Agenda - System Run Cart","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0003","file":"workflow/agendas/AGD-0003-system-run-cart.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0005","status":"open","ticket":"system-fault-semantics-and-control-surface","title":"Agenda - System Fault Semantics and Control Surface","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0004","file":"workflow/agendas/AGD-0004-system-fault-semantics-and-control-surface.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
||||
|
||||
@ -26,7 +26,7 @@ The runtime edge is no longer broadly untested. The repository now already conta
|
||||
|
||||
The remaining problem is governance, not raw test absence.
|
||||
|
||||
Global coverage metrics already exist through `cargo llvm-cov`, and CI already enforces a workspace-wide minimum gate. That is useful, but insufficient on its own. A good aggregated number does not guarantee that firmware transitions, boot flow, host-dependent surfaces, or domain-specific status-first contracts are covered at the right level.
|
||||
Global coverage metrics already exist through `cargo llvm-cov`. A single aggregated workspace gate proved useful, but insufficient on its own. A good aggregated number does not guarantee that firmware transitions, boot flow, host-dependent surfaces, or domain-specific status-first contracts are covered at the right level.
|
||||
|
||||
The project therefore needs an explicit domain-based acceptance model for tests:
|
||||
|
||||
@ -37,9 +37,9 @@ The project therefore needs an explicit domain-based acceptance model for tests:
|
||||
|
||||
## Decisao
|
||||
|
||||
PROMETEU SHALL govern runtime-edge test sufficiency through a two-layer model:
|
||||
PROMETEU SHALL govern runtime-edge test sufficiency through a domain-first model:
|
||||
|
||||
1. a mandatory global coverage gate enforced in CI; and
|
||||
1. a mandatory CI gate enforced from the canonical runtime-edge domains; and
|
||||
2. a domain-based acceptance gate driven by mandatory scenarios plus domain-scoped coverage evidence.
|
||||
|
||||
The canonical domains SHALL be:
|
||||
@ -61,6 +61,7 @@ No PR that changes the observable contract of a canonical domain SHALL be accept
|
||||
- an explicit justification that the observable contract did not change.
|
||||
|
||||
Improved aggregate coverage SHALL NOT be accepted as sufficient evidence on its own when the changed behavior belongs to a canonical domain with mandatory scenarios.
|
||||
Workspace-wide aggregate coverage MAY still be generated as a report artifact, but it SHALL NOT be the authoritative CI acceptance gate.
|
||||
|
||||
## Rationale
|
||||
|
||||
@ -100,11 +101,12 @@ The correct role of coverage is supporting evidence, not sole authority.
|
||||
|
||||
## Invariantes / Contrato
|
||||
|
||||
### Global Coverage Contract
|
||||
### CI Coverage Contract
|
||||
|
||||
- CI MUST keep a workspace-wide coverage gate.
|
||||
- The current `llvm-cov` based global gate remains valid as the operational baseline.
|
||||
- CI MUST enforce coverage from the canonical runtime-edge domains instead of a workspace-wide aggregate percentage.
|
||||
- The current `llvm-cov` toolchain remains valid as the operational baseline.
|
||||
- Changing the tooling is out of scope for this decision.
|
||||
- The authoritative quantitative CI gate is each domain `baseline_percent`, evaluated against domain `lines` coverage.
|
||||
|
||||
### Domain Gate Contract
|
||||
|
||||
@ -188,13 +190,15 @@ Mandatory scenarios:
|
||||
### Tooling / CI
|
||||
|
||||
- Existing `llvm-cov` and Jenkins integration remain valid.
|
||||
- Future plans may add domain reporting, thresholds, or helper commands without changing this baseline decision.
|
||||
- Jenkins MUST call repository helpers that compute and enforce the domain coverage gate.
|
||||
- Workspace aggregate reports may continue to be published for inspection, but they are not the merge gate.
|
||||
|
||||
## Referencias
|
||||
|
||||
- `AGD-0001`
|
||||
- `Makefile`
|
||||
- `files/config/Jenkinsfile`
|
||||
- `files/config/runtime-edge-coverage-domains.json`
|
||||
- `docs/specs/runtime/12-firmware-pos-and-prometeuhub.md`
|
||||
- `crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs`
|
||||
- `crates/console/prometeu-system/src/services/fs/virtual_fs.rs`
|
||||
@ -202,8 +206,8 @@ Mandatory scenarios:
|
||||
|
||||
## Propagacao Necessaria
|
||||
|
||||
- Create an execution plan that turns the domain model into concrete work items.
|
||||
- Create or revise execution plans that turn the domain model into concrete CI and review work items.
|
||||
- Define how domain evidence will be gathered during review.
|
||||
- Decide whether to add helper commands or scripts for domain-oriented coverage inspection.
|
||||
- Keep helper commands or scripts as the canonical interface for domain-oriented coverage inspection and CI enforcement.
|
||||
- Prioritize firmware and host-dependent expansion first.
|
||||
- Define an incremental split strategy for the monolithic runtime test suite.
|
||||
|
||||
@ -21,7 +21,7 @@ Its goal is to turn the decision into concrete review and CI mechanics without c
|
||||
|
||||
Define the repository-level mechanics for:
|
||||
|
||||
- global coverage gate continuity;
|
||||
- domain coverage gate enforcement in CI;
|
||||
- domain-scoped coverage evidence during review;
|
||||
- baseline tracking that can start at `0` per domain and tighten later;
|
||||
- reviewer-visible rules for when domain tests are mandatory.
|
||||
@ -29,7 +29,7 @@ Define the repository-level mechanics for:
|
||||
## Escopo
|
||||
|
||||
- Add repository commands or scripts for domain-oriented coverage evidence collection.
|
||||
- Add repository-facing documentation that explains the global gate plus domain evidence workflow.
|
||||
- Add repository-facing documentation that explains the domain gate plus domain evidence workflow.
|
||||
- Align CI/coverage outputs with the new governance model without replacing `llvm-cov`.
|
||||
|
||||
## Fora de Escopo
|
||||
@ -51,7 +51,8 @@ Add one repository-visible command path that produces:
|
||||
|
||||
- existing global HTML/XML/JSON coverage artifacts;
|
||||
- a documented procedure for mapping changed files/modules to one of the canonical domains;
|
||||
- an initial baseline format that records per-domain coverage starting from `0`.
|
||||
- an initial baseline format that records per-domain coverage starting from `0`;
|
||||
- a CI-friendly command that fails when a domain baseline is not met.
|
||||
|
||||
**File(s):**
|
||||
- `Makefile`
|
||||
@ -68,7 +69,7 @@ Prefer simple wrappers over new tooling. For example:
|
||||
|
||||
- capture `llvm-cov` JSON/HTML consistently;
|
||||
- filter or summarize target files/modules for a domain;
|
||||
- emit review-friendly evidence artifacts without changing the authoritative global gate.
|
||||
- emit review-friendly evidence artifacts while also enforcing the authoritative domain gate.
|
||||
|
||||
**File(s):**
|
||||
- `Makefile`
|
||||
@ -86,6 +87,7 @@ Document that any PR touching a canonical domain must either:
|
||||
- justify why the observable contract did not change.
|
||||
|
||||
Document that domain coverage evidence is mandatory review input even when domain thresholds are still at baseline `0`.
|
||||
Document that Jenkins consumes the repository helper target directly instead of re-implementing the gate inline.
|
||||
|
||||
**File(s):**
|
||||
- `README.md`
|
||||
@ -94,10 +96,10 @@ Document that domain coverage evidence is mandatory review input even when domai
|
||||
### Step 4 - Align CI outputs with the governance model
|
||||
|
||||
**What:**
|
||||
Make the existing coverage pipeline clearly compatible with domain review.
|
||||
Make the existing coverage pipeline clearly compatible with domain review and domain-based CI failure.
|
||||
|
||||
**How:**
|
||||
Keep the current global Jenkins gate unchanged while ensuring produced artifacts are sufficient for domain inspection.
|
||||
Make Jenkins call a repository helper target that runs the coverage pipeline, produces the existing artifacts, and fails from domain baselines.
|
||||
If needed, archive additional summaries or helper outputs generated by the new scripts.
|
||||
|
||||
**File(s):**
|
||||
@ -106,10 +108,10 @@ If needed, archive additional summaries or helper outputs generated by the new s
|
||||
|
||||
## Criterios de Aceite
|
||||
|
||||
- [ ] The repository exposes a documented way to collect domain-oriented coverage evidence without replacing the global `llvm-cov` gate.
|
||||
- [ ] The repository exposes a documented way to collect domain-oriented coverage evidence and enforce domain baselines in CI.
|
||||
- [ ] Review guidance explicitly states when domain tests are mandatory.
|
||||
- [ ] Domain baselines are represented in a form that can start at `0` and increase later.
|
||||
- [ ] Existing global coverage enforcement remains intact.
|
||||
- [ ] Jenkins uses a repository-owned helper target for the coverage gate.
|
||||
|
||||
## Tests / Validacao
|
||||
|
||||
@ -122,9 +124,10 @@ If needed, archive additional summaries or helper outputs generated by the new s
|
||||
|
||||
- Show that the global coverage artifacts still build.
|
||||
- Show an example of domain evidence collection for at least one domain.
|
||||
- Show that the domain gate fails when a baseline is missed.
|
||||
|
||||
## Riscos
|
||||
|
||||
- Overdesigning domain evidence collection before real reviewer usage patterns exist.
|
||||
- Accidentally creating a second competing coverage authority instead of a reviewer aid.
|
||||
- Letting Jenkins re-encode policy logic instead of consuming the repository helper target.
|
||||
- Spreading policy text across too many documents and making the rule hard to find.
|
||||
|
||||
43
files/config/Jenkinsfile
vendored
43
files/config/Jenkinsfile
vendored
@ -6,10 +6,6 @@ pipeline {
|
||||
CARGO_TARGET_DIR = 'target'
|
||||
|
||||
CARGO_TERM_COLOR = 'always'
|
||||
|
||||
MIN_LINES = '60'
|
||||
MIN_FUNCTIONS = '60'
|
||||
MIN_REGIONS = '60'
|
||||
}
|
||||
|
||||
stages {
|
||||
@ -17,45 +13,12 @@ pipeline {
|
||||
steps {
|
||||
sh '''
|
||||
set -eux
|
||||
make ci cobertura
|
||||
|
||||
LINES=$(jq -r '.data[0].totals.lines.percent' target/llvm-cov/summary.json)
|
||||
FUNCTIONS=$(jq -r '.data[0].totals.functions.percent' target/llvm-cov/summary.json)
|
||||
REGIONS=$(jq -r '.data[0].totals.regions.percent' target/llvm-cov/summary.json)
|
||||
|
||||
echo "Coverage summary:"
|
||||
echo " Lines: ${LINES}%"
|
||||
echo " Functions: ${FUNCTIONS}%"
|
||||
echo " Regions: ${REGIONS}%"
|
||||
|
||||
FAIL=0
|
||||
|
||||
awk "BEGIN { exit !(${LINES} < ${MIN_LINES}) }" && {
|
||||
echo "Lines coverage ${LINES}% is below minimum ${MIN_LINES}%"
|
||||
FAIL=1
|
||||
} || true
|
||||
|
||||
awk "BEGIN { exit !(${FUNCTIONS} < ${MIN_FUNCTIONS}) }" && {
|
||||
echo "Functions coverage ${FUNCTIONS}% is below minimum ${MIN_FUNCTIONS}%"
|
||||
FAIL=1
|
||||
} || true
|
||||
|
||||
awk "BEGIN { exit !(${REGIONS} < ${MIN_REGIONS}) }" && {
|
||||
echo "Regions coverage ${REGIONS}% is below minimum ${MIN_REGIONS}%"
|
||||
FAIL=1
|
||||
} || true
|
||||
|
||||
if [ "$FAIL" -ne 0 ]; then
|
||||
echo "Coverage gate failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Coverage gate passed."
|
||||
make ci-domains
|
||||
'''
|
||||
// withChecks(name: 'Test', includeStage: true) {
|
||||
// sh '''
|
||||
// set -eux
|
||||
// make ci cobertura
|
||||
// make ci-domains
|
||||
// '''
|
||||
// recordCoverage(
|
||||
// tools: [[parser: 'COBERTURA', pattern: 'target/llvm-cov/cobertura.xml']],
|
||||
@ -92,4 +55,4 @@ pipeline {
|
||||
}
|
||||
} // Reports
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"version": 1,
|
||||
"domains": {
|
||||
"system/runtime": {
|
||||
"baseline_percent": 66,
|
||||
"baseline_percent": 68,
|
||||
"paths": [
|
||||
"crates/console/prometeu-system/src/virtual_machine_runtime.rs",
|
||||
"crates/console/prometeu-system/src/virtual_machine_runtime/"
|
||||
@ -16,7 +16,7 @@
|
||||
]
|
||||
},
|
||||
"asset/bank": {
|
||||
"baseline_percent": 80,
|
||||
"baseline_percent": 86,
|
||||
"paths": [
|
||||
"crates/console/prometeu-hal/src/asset",
|
||||
"crates/console/prometeu-hal/src/asset.rs",
|
||||
@ -27,7 +27,7 @@
|
||||
]
|
||||
},
|
||||
"firmware": {
|
||||
"baseline_percent": 74,
|
||||
"baseline_percent": 76,
|
||||
"paths": [
|
||||
"crates/console/prometeu-firmware/src/"
|
||||
]
|
||||
|
||||
@ -4,12 +4,37 @@ set -euo pipefail
|
||||
ROOT="$(git rev-parse --show-toplevel)"
|
||||
CONFIG_PATH="${ROOT}/files/config/runtime-edge-coverage-domains.json"
|
||||
DEFAULT_REPORT="${ROOT}/target/llvm-cov/report.json"
|
||||
GREEN=$'\033[32m'
|
||||
RED=$'\033[31m'
|
||||
CYAN=$'\033[36m'
|
||||
RESET=$'\033[0m'
|
||||
|
||||
line_percent() {
|
||||
jq -r --arg domain "${1}" --arg root "${ROOT}" '
|
||||
.domains[$domain].paths as $paths
|
||||
| def matches_domain:
|
||||
. as $file
|
||||
| any($paths[]; . as $p | ($file.filename | startswith($root + "/" + $p) or startswith("./" + $p) or startswith($p)));
|
||||
def pct($covered; $count):
|
||||
if $count > 0 then (($covered * 10000 / $count | floor) / 100) else 0 end;
|
||||
reduce (
|
||||
input.data[]?.files[]?
|
||||
| select(matches_domain)
|
||||
) as $file (
|
||||
{lines: {count: 0, covered: 0}};
|
||||
.lines.count += ($file.summary.lines.count // 0)
|
||||
| .lines.covered += ($file.summary.lines.covered // 0)
|
||||
)
|
||||
| pct(.lines.covered; .lines.count)
|
||||
' "${CONFIG_PATH}" "${2}"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
coverage-domain-evidence.sh --list
|
||||
coverage-domain-evidence.sh <domain> [report.json]
|
||||
coverage-domain-evidence.sh [--check] [--show-summary-details] [--show-paths] [--show-tracked-files] [--show-matched-files] [--verbose] <domain> [report.json]
|
||||
coverage-domain-evidence.sh [--show-summary-details] [--show-paths] [--show-tracked-files] [--show-matched-files] [--verbose] --check-all [report.json]
|
||||
|
||||
The report path defaults to target/llvm-cov/report.json and is expected to be
|
||||
generated by `make ci` or `make coverage-report-json`.
|
||||
@ -31,9 +56,87 @@ if [[ "$1" == "--list" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
DOMAIN="$1"
|
||||
CHECK_MODE=0
|
||||
CHECK_ALL=0
|
||||
SHOW_PATHS=0
|
||||
SHOW_TRACKED_FILES=0
|
||||
SHOW_MATCHED_FILES=0
|
||||
SHOW_SUMMARY_DETAILS=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--check)
|
||||
CHECK_MODE=1
|
||||
shift
|
||||
;;
|
||||
--check-all)
|
||||
CHECK_MODE=1
|
||||
CHECK_ALL=1
|
||||
shift
|
||||
;;
|
||||
--show-paths)
|
||||
SHOW_PATHS=1
|
||||
shift
|
||||
;;
|
||||
--show-summary-details)
|
||||
SHOW_SUMMARY_DETAILS=1
|
||||
shift
|
||||
;;
|
||||
--show-tracked-files)
|
||||
SHOW_TRACKED_FILES=1
|
||||
shift
|
||||
;;
|
||||
--show-matched-files)
|
||||
SHOW_MATCHED_FILES=1
|
||||
shift
|
||||
;;
|
||||
--verbose)
|
||||
SHOW_SUMMARY_DETAILS=1
|
||||
SHOW_PATHS=1
|
||||
SHOW_TRACKED_FILES=1
|
||||
SHOW_MATCHED_FILES=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
echo "unknown option: $1" >&2
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ${CHECK_ALL} -eq 1 ]]; then
|
||||
REPORT_PATH="${1:-${DEFAULT_REPORT}}"
|
||||
FAIL=0
|
||||
|
||||
while IFS= read -r domain; do
|
||||
ARGS=(--check)
|
||||
[[ ${SHOW_SUMMARY_DETAILS} -eq 1 ]] && ARGS+=(--show-summary-details)
|
||||
[[ ${SHOW_PATHS} -eq 1 ]] && ARGS+=(--show-paths)
|
||||
[[ ${SHOW_TRACKED_FILES} -eq 1 ]] && ARGS+=(--show-tracked-files)
|
||||
[[ ${SHOW_MATCHED_FILES} -eq 1 ]] && ARGS+=(--show-matched-files)
|
||||
"${BASH_SOURCE[0]}" "${ARGS[@]}" "${domain}" "${REPORT_PATH}" || FAIL=1
|
||||
echo
|
||||
done < <(jq -r '.domains | keys[]' "${CONFIG_PATH}")
|
||||
|
||||
exit "${FAIL}"
|
||||
fi
|
||||
|
||||
DOMAIN="${1:-}"
|
||||
REPORT_PATH="${2:-${DEFAULT_REPORT}}"
|
||||
|
||||
if [[ -z "${DOMAIN}" ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! jq -e --arg domain "${DOMAIN}" '.domains[$domain]' "${CONFIG_PATH}" >/dev/null; then
|
||||
echo "unknown domain: ${DOMAIN}" >&2
|
||||
echo "available domains:" >&2
|
||||
@ -43,33 +146,35 @@ fi
|
||||
|
||||
BASELINE="$(jq -r --arg domain "${DOMAIN}" '.domains[$domain].baseline_percent' "${CONFIG_PATH}")"
|
||||
|
||||
echo "Runtime edge coverage evidence"
|
||||
echo "Domain: ${DOMAIN}"
|
||||
echo "Baseline percent: ${BASELINE}"
|
||||
echo
|
||||
if [[ ${SHOW_PATHS} -eq 1 ]]; then
|
||||
echo "Mapped repository paths:"
|
||||
jq -r --arg domain "${DOMAIN}" '.domains[$domain].paths[]' "${CONFIG_PATH}" | while IFS= read -r prefix; do
|
||||
echo " - ${prefix}"
|
||||
done
|
||||
echo
|
||||
fi
|
||||
|
||||
echo "Mapped repository paths:"
|
||||
jq -r --arg domain "${DOMAIN}" '.domains[$domain].paths[]' "${CONFIG_PATH}" | while IFS= read -r prefix; do
|
||||
echo " - ${prefix}"
|
||||
done
|
||||
echo
|
||||
|
||||
echo "Tracked files present in repository:"
|
||||
while IFS= read -r path; do
|
||||
(
|
||||
cd "${ROOT}"
|
||||
rg --files . | sed 's#^\./##'
|
||||
) | rg "^${path//\//\\/}" || true
|
||||
done < <(jq -r --arg domain "${DOMAIN}" '.domains[$domain].paths[]' "${CONFIG_PATH}")
|
||||
echo
|
||||
if [[ ${SHOW_TRACKED_FILES} -eq 1 ]]; then
|
||||
echo "Tracked files present in repository:"
|
||||
while IFS= read -r path; do
|
||||
(
|
||||
cd "${ROOT}"
|
||||
rg --files . | sed 's#^\./##'
|
||||
) | rg "^${path//\//\\/}" || true
|
||||
done < <(jq -r --arg domain "${DOMAIN}" '.domains[$domain].paths[]' "${CONFIG_PATH}")
|
||||
echo
|
||||
fi
|
||||
|
||||
if [[ ! -f "${REPORT_PATH}" ]]; then
|
||||
echo "Coverage report not found: ${REPORT_PATH}"
|
||||
echo "Generate it with: make coverage-report-json"
|
||||
if [[ ${CHECK_MODE} -eq 1 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
jq -r --arg domain "${DOMAIN}" --arg root "${ROOT}" '
|
||||
jq -r --arg domain "${DOMAIN}" --arg root "${ROOT}" --argjson baseline "${BASELINE}" --argjson show_matched_files "${SHOW_MATCHED_FILES}" --argjson show_summary_details "${SHOW_SUMMARY_DETAILS}" '
|
||||
.domains[$domain].paths as $paths
|
||||
| def matches_domain:
|
||||
. as $file
|
||||
@ -94,12 +199,44 @@ jq -r --arg domain "${DOMAIN}" --arg root "${ROOT}" '
|
||||
| .regions.count += ($file.summary.regions.count // 0)
|
||||
| .regions.covered += ($file.summary.regions.covered // 0)
|
||||
)
|
||||
| "Coverage summary from " + $domain + ":",
|
||||
" files_in_report: " + (.files | length | tostring),
|
||||
" lines: " + (pct(.lines.covered; .lines.count) | tostring) + "% (" + (.lines.covered|tostring) + "/" + (.lines.count|tostring) + ")",
|
||||
" functions: " + (pct(.functions.covered; .functions.count) | tostring) + "% (" + (.functions.covered|tostring) + "/" + (.functions.count|tostring) + ")",
|
||||
" regions: " + (pct(.regions.covered; .regions.count) | tostring) + "% (" + (.regions.covered|tostring) + "/" + (.regions.count|tostring) + ")",
|
||||
"",
|
||||
"Matched report files:",
|
||||
(.files[]? | " - " + .)
|
||||
| . + {line_percent: pct(.lines.covered; .lines.count)}
|
||||
| (if $show_summary_details == 1 then "lines: " + (.line_percent | tostring) + "% (" + (.lines.covered|tostring) + "/" + (.lines.count|tostring) + ")" else empty end),
|
||||
(if $show_summary_details == 1 then " files_in_report: " + (.files | length | tostring) else empty end),
|
||||
(if $show_summary_details == 1 then
|
||||
" functions: " + (pct(.functions.covered; .functions.count) | tostring) + "% (" + (.functions.covered|tostring) + "/" + (.functions.count|tostring) + ")"
|
||||
else empty end),
|
||||
(if $show_summary_details == 1 then
|
||||
" regions: " + (pct(.regions.covered; .regions.count) | tostring) + "% (" + (.regions.covered|tostring) + "/" + (.regions.count|tostring) + ")"
|
||||
else empty end),
|
||||
(if $show_matched_files == 1 then "" else empty end),
|
||||
(if $show_matched_files == 1 then "Matched report files:" else empty end),
|
||||
(if $show_matched_files == 1 then (.files[]? | " - " + .) else empty end)
|
||||
' "${CONFIG_PATH}" "${REPORT_PATH}"
|
||||
|
||||
LINE_PERCENT="$(line_percent "${DOMAIN}" "${REPORT_PATH}")"
|
||||
|
||||
if awk "BEGIN { exit !(${LINE_PERCENT} >= ${BASELINE}) }"; then
|
||||
GATE_STATUS="${GREEN}PASS${RESET}"
|
||||
else
|
||||
GATE_STATUS="${RED}FAIL${RESET}"
|
||||
fi
|
||||
|
||||
LINE="Domain: ${DOMAIN} :: GATE(lines>=baseline) [${CYAN}${LINE_PERCENT}%${RESET} >= ${RED}${BASELINE}%${RESET}]: ${GATE_STATUS}"
|
||||
VISIBLE_LINE="Domain: ${DOMAIN} :: GATE(lines>=baseline) [${LINE_PERCENT}% >= ${BASELINE}%]: PASS"
|
||||
if awk "BEGIN { exit !(${LINE_PERCENT} >= ${BASELINE}) }"; then
|
||||
VISIBLE_LINE="Domain: ${DOMAIN} :: GATE(lines>=baseline) [${LINE_PERCENT}% >= ${BASELINE}%]: PASS"
|
||||
else
|
||||
VISIBLE_LINE="Domain: ${DOMAIN} :: GATE(lines>=baseline) [${LINE_PERCENT}% >= ${BASELINE}%]: FAIL"
|
||||
fi
|
||||
LINE_WIDTH="${#VISIBLE_LINE}"
|
||||
BORDER="$(printf '═%.0s' $(seq 1 "${LINE_WIDTH}"))"
|
||||
echo "╔${BORDER}╗"
|
||||
echo "║${LINE}║"
|
||||
echo "╚${BORDER}╝"
|
||||
|
||||
if [[ ${CHECK_MODE} -eq 1 ]]; then
|
||||
awk "BEGIN { exit !(${LINE_PERCENT} < ${BASELINE}) }" && {
|
||||
echo "Domain coverage gate failed for ${DOMAIN}: ${LINE_PERCENT}% is below baseline ${BASELINE}%"
|
||||
exit 1
|
||||
} || true
|
||||
fi
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user