From d6e8355844732cf921d462ef182562006016fade Mon Sep 17 00:00:00 2001 From: sergiov-ni Date: Thu, 21 Aug 2025 08:20:49 -0700 Subject: [PATCH] feat: enforce runner metadata env vars in summary script\n\nEnsures generate-ci-summary requires RUNNER_LABEL, RUNNER_TYPE, or SKIP_DRY_RUN to proceed and adds tests. REQ-033 --- artifacts/linux/requirements-summary.md | 3 +- artifacts/linux/summary-standard.md | 4 +- artifacts/linux/summary.md | 6 +- artifacts/linux/traceability-standard.md | 91 ++++++------- artifacts/linux/traceability.json | 127 ++++++++++-------- artifacts/linux/traceability.md | 91 ++++++------- ci_evidence.txt | 2 +- scripts/__tests__/generate-ci-summary.test.js | 18 ++- scripts/generate-ci-summary.ts | 11 ++ test-results/node-junit.xml | 117 ++++++++-------- 10 files changed, 255 insertions(+), 215 deletions(-) diff --git a/artifacts/linux/requirements-summary.md b/artifacts/linux/requirements-summary.md index 9e7c3061..358d63ed 100644 --- a/artifacts/linux/requirements-summary.md +++ b/artifacts/linux/requirements-summary.md @@ -12,7 +12,7 @@ | REQ-031 | Parsing logic validates presence of required fields and reports missing or malformed data. | | 1 | 1 | 0 | 0 | 100.00 | | REQ-032 | Parser tolerates and retains unknown attributes for future extensibility. | | 1 | 1 | 0 | 0 | 100.00 | | REQ-033 | Tests ending with SelfHosted.Workflow.Tests.ps1 execute only in dry run mode unless the workflow targets a self-hosted Windows runner labeled self-hosted-windows-lv. | | 1 | 1 | 0 | 0 | 100.00 | -| Unmapped | | | 48 | 48 | 0 | 0 | 100.00 | +| Unmapped | | | 49 | 49 | 0 | 0 | 100.00 | ### Requirement Testcases | Requirement ID | Test ID | Status | @@ -49,6 +49,7 @@ | Unmapped | fails-when-requirement-lacks-test-coverage | Passed | | Unmapped | fails-when-tests-are-unmapped | Passed | | Unmapped | fails-when-tests-reference-unknown-requirements | Passed | +| Unmapped | fails-without-runner-metadata | Passed | | Unmapped | formaterror-handles-plain-objects | Passed | | Unmapped | formaterror-handles-primitives | Passed | | Unmapped | formaterror-handles-real-error-objects | Passed | diff --git a/artifacts/linux/summary-standard.md b/artifacts/linux/summary-standard.md index ba8667be..dea79ac3 100644 --- a/artifacts/linux/summary-standard.md +++ b/artifacts/linux/summary-standard.md @@ -1,7 +1,7 @@ ### Test Summary | OS | Passed | Failed | Skipped | Duration (s) | Pass Rate (%) | | --- | --- | --- | --- | --- | --- | -| overall | 59 | 0 | 0 | 15.06 | 100.00 | -| linux | 59 | 0 | 0 | 15.06 | 100.00 | +| overall | 60 | 0 | 0 | 23.74 | 100.00 | +| linux | 60 | 0 | 0 | 23.74 | 100.00 | _For detailed per-test information, see [traceability-standard.md](traceability-standard.md)._ \ No newline at end of file diff --git a/artifacts/linux/summary.md b/artifacts/linux/summary.md index 843d3c3b..848d78d4 100644 --- a/artifacts/linux/summary.md +++ b/artifacts/linux/summary.md @@ -1,8 +1,8 @@ ### Test Summary | OS | Passed | Failed | Skipped | Duration (s) | Pass Rate (%) | | --- | --- | --- | --- | --- | --- | -| overall | 59 | 0 | 0 | 15.06 | 100.00 | -| linux | 59 | 0 | 0 | 15.06 | 100.00 | +| overall | 60 | 0 | 0 | 23.74 | 100.00 | +| linux | 60 | 0 | 0 | 23.74 | 100.00 | ### Requirement Summary | Requirement ID | Description | Owner | Total Tests | Passed | Failed | Skipped | Pass Rate (%) | @@ -18,6 +18,6 @@ | REQ-031 | Parsing logic validates presence of required fields and reports missing or malformed data. | | 1 | 1 | 0 | 0 | 100.00 | | REQ-032 | Parser tolerates and retains unknown attributes for future extensibility. | | 1 | 1 | 0 | 0 | 100.00 | | REQ-033 | Tests ending with SelfHosted.Workflow.Tests.ps1 execute only in dry run mode unless the workflow targets a self-hosted Windows runner labeled self-hosted-windows-lv. | | 1 | 1 | 0 | 0 | 100.00 | -| Unmapped | | | 48 | 48 | 0 | 0 | 100.00 | +| Unmapped | | | 49 | 49 | 0 | 0 | 100.00 | _For detailed per-test information, see [traceability.md](traceability.md)._ \ No newline at end of file diff --git a/artifacts/linux/traceability-standard.md b/artifacts/linux/traceability-standard.md index 8cb2d138..6dd24a87 100644 --- a/artifacts/linux/traceability-standard.md +++ b/artifacts/linux/traceability-standard.md @@ -4,37 +4,37 @@ | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-023 | parses-nested-junit-structures | Passed | 0.006 | | | +| REQ-023 | parses-nested-junit-structures | Passed | 0.011 | | | #### REQ-024 (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-024 | captures-root-testsuites-attributes | Passed | 0.005 | | | +| REQ-024 | captures-root-testsuites-attributes | Passed | 0.003 | | | #### REQ-025 (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-025 | captures-testsuite-attributes | Passed | 0.001 | | | +| REQ-025 | captures-testsuite-attributes | Passed | 0.006 | | | #### REQ-026 (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-026 | captures-suite-properties | Passed | 0.001 | | | +| REQ-026 | captures-suite-properties | Passed | 0.002 | | | #### REQ-027 (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-027 | captures-testcase-attributes-and-skipped-message | Passed | 0.008 | | | +| REQ-027 | captures-testcase-attributes-and-skipped-message | Passed | 0.001 | | | #### REQ-028 (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-028 | extracts-requirement-identifiers | Passed | 0.002 | | | +| REQ-028 | extracts-requirement-identifiers | Passed | 0.003 | | | #### REQ-029 (100% passed) @@ -46,7 +46,7 @@ | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-030 | builds-traceability-matrix-with-skipped-reasons | Passed | 0.001 | | | +| REQ-030 | builds-traceability-matrix-with-skipped-reasons | Passed | 0.002 | | | #### REQ-031 (100% passed) @@ -64,59 +64,60 @@ | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-033 | throws-error-for-malformed-xml | Passed | 0.001 | | | +| REQ-033 | throws-error-for-malformed-xml | Passed | 0.004 | | |
Unmapped (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| Unmapped | associates-classname-with-requirement | Passed | 0.012 | | | -| Unmapped | buildissuebranchname-formats-branch-name | Passed | 0.001 | | | -| Unmapped | buildissuebranchname-rejects-non-numeric-input | Passed | 0.001 | | | +| Unmapped | associates-classname-with-requirement | Passed | 0.016 | | | +| Unmapped | buildissuebranchname-formats-branch-name | Passed | 0.003 | | | +| Unmapped | buildissuebranchname-rejects-non-numeric-input | Passed | 0.002 | | | | Unmapped | buildprofile1.iconeditor.addtokentolabview.dispatcher.dry-runs-add-token-to-labview-with-expected-arguments- | Passed | 0.482 | | | | Unmapped | buildprofile1.iconeditor.applyvipc.dispatcher.dry-runs-apply-vipc-with-expected-arguments- | Passed | 0.042 | | | | Unmapped | buildprofile1.iconeditor.buildvipackage.dispatcher.dry-runs-build-vi-package-with-expected-arguments- | Passed | 0.106 | | | | Unmapped | buildprofile1.iconeditor.closelabview.dispatcher.dry-runs-close-labview-with-expected-arguments- | Passed | 0.036 | | | -| Unmapped | buildsummary-splits-totals-by-os | Passed | 0.000 | | | -| Unmapped | collecttestcases-captures-requirement-property | Passed | 0.009 | | | -| Unmapped | collecttestcases-uses-evidence-property-and-falls-back-to-directory-scan | Passed | 0.009 | | | -| Unmapped | collecttestcases-uses-machine-name-property-for-owner | Passed | 0.003 | | | +| Unmapped | buildsummary-splits-totals-by-os | Passed | 0.001 | | | +| Unmapped | collecttestcases-captures-requirement-property | Passed | 0.020 | | | +| Unmapped | collecttestcases-uses-evidence-property-and-falls-back-to-directory-scan | Passed | 0.008 | | | +| Unmapped | collecttestcases-uses-machine-name-property-for-owner | Passed | 0.008 | | | | Unmapped | computestatuscounts-tallies-test-statuses | Passed | 0.000 | | | -| Unmapped | detects-downloaded-artifacts-path | Passed | 0.894 | | | -| Unmapped | dispatchers-and-parameters-include-descriptions | Passed | 0.002 | | | -| Unmapped | errors-when-strict-unmapped-mode-enabled | Passed | 0.952 | | | -| Unmapped | escapemarkdown-escapes-special-characters | Passed | 0.002 | | | +| Unmapped | detects-downloaded-artifacts-path | Passed | 1.285 | | | +| Unmapped | dispatchers-and-parameters-include-descriptions | Passed | 0.009 | | | +| Unmapped | errors-when-strict-unmapped-mode-enabled | Passed | 1.270 | | | +| Unmapped | escapemarkdown-escapes-special-characters | Passed | 0.001 | | | | Unmapped | escapemarkdown-leaves-plain-text-untouched | Passed | 0.000 | | | -| Unmapped | fails-when-commit-lacks-requirement-reference | Passed | 0.759 | | | -| Unmapped | fails-when-requirement-lacks-test-coverage | Passed | 0.749 | | | -| Unmapped | fails-when-tests-are-unmapped | Passed | 0.766 | | | -| Unmapped | fails-when-tests-reference-unknown-requirements | Passed | 0.813 | | | +| Unmapped | fails-when-commit-lacks-requirement-reference | Passed | 1.298 | | | +| Unmapped | fails-when-requirement-lacks-test-coverage | Passed | 1.526 | | | +| Unmapped | fails-when-tests-are-unmapped | Passed | 1.205 | | | +| Unmapped | fails-when-tests-reference-unknown-requirements | Passed | 1.266 | | | +| Unmapped | fails-without-runner-metadata | Passed | 0.825 | | | | Unmapped | formaterror-handles-plain-objects | Passed | 0.000 | | | | Unmapped | formaterror-handles-primitives | Passed | 0.000 | | | -| Unmapped | formaterror-handles-real-error-objects | Passed | 0.001 | | | -| Unmapped | formaterror-handles-unstringifiable-values | Passed | 0.000 | | | -| Unmapped | generate-ci-summary-features | Passed | 0.021 | | | -| Unmapped | groups-owners-and-includes-requirements-and-evidence | Passed | 0.856 | | | -| Unmapped | grouptomarkdown-omits-numeric-identifiers | Passed | 0.001 | | | +| Unmapped | formaterror-handles-real-error-objects | Passed | 0.003 | | | +| Unmapped | formaterror-handles-unstringifiable-values | Passed | 0.001 | | | +| Unmapped | generate-ci-summary-features | Passed | 0.026 | | | +| Unmapped | groups-owners-and-includes-requirements-and-evidence | Passed | 1.361 | | | +| Unmapped | grouptomarkdown-omits-numeric-identifiers | Passed | 0.003 | | | | Unmapped | grouptomarkdown-supports-optional-limit-for-truncation | Passed | 0.001 | | | | Unmapped | handles-root-level-testcases | Passed | 0.001 | | | -| Unmapped | handles-zipped-junit-artifacts | Passed | 0.721 | | | -| Unmapped | ignores-stale-junit-files-outside-artifacts-path | Passed | 0.804 | | | -| Unmapped | loadrequirements-logs-warning-on-invalid-json | Passed | 0.017 | | | -| Unmapped | loadrequirements-merges-multiple-files | Passed | 0.003 | | | -| Unmapped | loadrequirements-warns-and-skips-invalid-entries | Passed | 0.004 | | | -| Unmapped | logs-a-warning-when-no-junit-files-are-found | Passed | 0.845 | | | -| Unmapped | partitions-requirement-groups-by-runner\_type | Passed | 0.763 | | | -| Unmapped | passes-with-coverage-and-requirement-reference | Passed | 0.818 | | | -| Unmapped | requirementssummarytomarkdown-escapes-pipes-in-description | Passed | 0.000 | | | -| Unmapped | skips-invalid-junit-files-and-still-generates-summary | Passed | 0.994 | | | +| Unmapped | handles-zipped-junit-artifacts | Passed | 1.055 | | | +| Unmapped | ignores-stale-junit-files-outside-artifacts-path | Passed | 1.161 | | | +| Unmapped | loadrequirements-logs-warning-on-invalid-json | Passed | 0.045 | | | +| Unmapped | loadrequirements-merges-multiple-files | Passed | 0.012 | | | +| Unmapped | loadrequirements-warns-and-skips-invalid-entries | Passed | 0.015 | | | +| Unmapped | logs-a-warning-when-no-junit-files-are-found | Passed | 1.294 | | | +| Unmapped | partitions-requirement-groups-by-runner\_type | Passed | 1.050 | | | +| Unmapped | passes-with-coverage-and-requirement-reference | Passed | 1.298 | | | +| Unmapped | requirementssummarytomarkdown-escapes-pipes-in-description | Passed | 0.001 | | | +| Unmapped | skips-invalid-junit-files-and-still-generates-summary | Passed | 1.517 | | | | Unmapped | summarytomarkdown-handles-no-tests | Passed | 0.000 | | | -| Unmapped | summarytomarkdown-sorts-os-alphabetically-and-escapes-special-characters | Passed | 0.000 | | | -| Unmapped | throws-when-no-junit-files-found-and-strict-mode-enabled | Passed | 0.671 | | | -| Unmapped | uses-latest-artifact-directory-when-multiple-are-present | Passed | 0.866 | | | -| Unmapped | warns-when-all-tests-are-unmapped | Passed | 1.048 | | | -| Unmapped | writeerrorsummary-appends-error-details-to-summary-file | Passed | 0.006 | | | -| Unmapped | writeerrorsummary-skips-summary-file-for-non-error-throws | Passed | 0.003 | | | -| Unmapped | writes-outputs-to-os-specific-directory | Passed | 0.946 | | | +| Unmapped | summarytomarkdown-sorts-os-alphabetically-and-escapes-special-characters | Passed | 0.001 | | | +| Unmapped | throws-when-no-junit-files-found-and-strict-mode-enabled | Passed | 0.849 | | | +| Unmapped | uses-latest-artifact-directory-when-multiple-are-present | Passed | 1.241 | | | +| Unmapped | warns-when-all-tests-are-unmapped | Passed | 1.603 | | | +| Unmapped | writeerrorsummary-appends-error-details-to-summary-file | Passed | 0.005 | | | +| Unmapped | writeerrorsummary-skips-summary-file-for-non-error-throws | Passed | 0.004 | | | +| Unmapped | writes-outputs-to-os-specific-directory | Passed | 1.750 | | |
\ No newline at end of file diff --git a/artifacts/linux/traceability.json b/artifacts/linux/traceability.json index 168158df..847c286d 100644 --- a/artifacts/linux/traceability.json +++ b/artifacts/linux/traceability.json @@ -9,7 +9,7 @@ "name": "[REQ-023] parses nested JUnit structures", "className": "test", "status": "Passed", - "duration": 0.006212, + "duration": 0.010802, "requirements": [ "REQ-023" ], @@ -26,7 +26,7 @@ "name": "[REQ-024] captures root testsuites attributes", "className": "test", "status": "Passed", - "duration": 0.005192, + "duration": 0.002729, "requirements": [ "REQ-024" ], @@ -43,7 +43,7 @@ "name": "[REQ-025] captures testsuite attributes", "className": "test", "status": "Passed", - "duration": 0.000669, + "duration": 0.006149, "requirements": [ "REQ-025" ], @@ -60,7 +60,7 @@ "name": "[REQ-026] captures suite properties", "className": "test", "status": "Passed", - "duration": 0.000506, + "duration": 0.001994, "requirements": [ "REQ-026" ], @@ -77,7 +77,7 @@ "name": "[REQ-027] captures testcase attributes and skipped message", "className": "test", "status": "Passed", - "duration": 0.007769, + "duration": 0.001389, "requirements": [ "REQ-027" ], @@ -94,7 +94,7 @@ "name": "[REQ-028] extracts requirement identifiers", "className": "test", "status": "Passed", - "duration": 0.001575, + "duration": 0.003376, "requirements": [ "REQ-028" ], @@ -111,7 +111,7 @@ "name": "[REQ-029] aggregates status by requirement and suite", "className": "test", "status": "Passed", - "duration": 0.001939, + "duration": 0.002179, "requirements": [ "REQ-029" ], @@ -128,7 +128,7 @@ "name": "[REQ-030] builds traceability matrix with skipped reasons", "className": "test", "status": "Passed", - "duration": 0.001094, + "duration": 0.002123, "requirements": [ "REQ-030" ], @@ -145,7 +145,7 @@ "name": "[REQ-031] validates missing fields", "className": "test", "status": "Passed", - "duration": 0.000691, + "duration": 0.001122, "requirements": [ "REQ-031" ], @@ -162,7 +162,7 @@ "name": "[REQ-032] preserves unknown attributes", "className": "test", "status": "Passed", - "duration": 0.000569, + "duration": 0.000799, "requirements": [ "REQ-032" ], @@ -179,7 +179,7 @@ "name": "[REQ-033] throws error for malformed XML", "className": "test", "status": "Passed", - "duration": 0.001253, + "duration": 0.00418, "requirements": [ "REQ-033" ], @@ -195,7 +195,7 @@ "name": "associates classname with requirement", "className": "test", "status": "Passed", - "duration": 0.011747, + "duration": 0.015669, "requirements": [], "os": "linux" }, @@ -204,7 +204,7 @@ "name": "buildIssueBranchName formats branch name", "className": "test", "status": "Passed", - "duration": 0.001276, + "duration": 0.003472, "requirements": [], "os": "linux" }, @@ -213,7 +213,7 @@ "name": "buildIssueBranchName rejects non-numeric input", "className": "test", "status": "Passed", - "duration": 0.001038, + "duration": 0.001627, "requirements": [], "os": "linux" }, @@ -258,7 +258,7 @@ "name": "buildSummary splits totals by OS", "className": "test", "status": "Passed", - "duration": 0.000311, + "duration": 0.000891, "requirements": [], "os": "linux" }, @@ -267,7 +267,7 @@ "name": "collectTestCases captures requirement property", "className": "test", "status": "Passed", - "duration": 0.008665, + "duration": 0.019617, "requirements": [], "os": "linux" }, @@ -276,7 +276,7 @@ "name": "collectTestCases uses evidence property and falls back to directory scan", "className": "test", "status": "Passed", - "duration": 0.008942, + "duration": 0.008364, "requirements": [], "os": "linux" }, @@ -285,7 +285,7 @@ "name": "collectTestCases uses machine-name property for owner", "className": "test", "status": "Passed", - "duration": 0.0032, + "duration": 0.008127, "requirements": [], "os": "linux" }, @@ -294,7 +294,7 @@ "name": "computeStatusCounts tallies test statuses", "className": "test", "status": "Passed", - "duration": 0.00031, + "duration": 0.00049, "requirements": [], "os": "linux" }, @@ -303,7 +303,7 @@ "name": "detects downloaded artifacts path", "className": "test", "status": "Passed", - "duration": 0.894465, + "duration": 1.285456, "requirements": [], "os": "linux" }, @@ -312,7 +312,7 @@ "name": "Dispatchers and parameters include descriptions", "className": "test", "status": "Passed", - "duration": 0.00239, + "duration": 0.008556, "requirements": [], "os": "linux" }, @@ -321,7 +321,7 @@ "name": "errors when strict unmapped mode enabled", "className": "test", "status": "Passed", - "duration": 0.951951, + "duration": 1.270083, "requirements": [], "os": "linux" }, @@ -330,7 +330,7 @@ "name": "escapeMarkdown escapes special characters", "className": "test", "status": "Passed", - "duration": 0.0022, + "duration": 0.001408, "requirements": [], "os": "linux" }, @@ -339,7 +339,7 @@ "name": "escapeMarkdown leaves plain text untouched", "className": "test", "status": "Passed", - "duration": 0.000172, + "duration": 0.000199, "requirements": [], "os": "linux" }, @@ -348,7 +348,7 @@ "name": "fails when commit lacks requirement reference", "className": "test", "status": "Passed", - "duration": 0.759453, + "duration": 1.297728, "requirements": [], "os": "linux" }, @@ -357,7 +357,7 @@ "name": "fails when requirement lacks test coverage", "className": "test", "status": "Passed", - "duration": 0.748901, + "duration": 1.525556, "requirements": [], "os": "linux" }, @@ -366,7 +366,7 @@ "name": "fails when tests are unmapped", "className": "test", "status": "Passed", - "duration": 0.765915, + "duration": 1.204814, "requirements": [], "os": "linux" }, @@ -375,7 +375,16 @@ "name": "fails when tests reference unknown requirements", "className": "test", "status": "Passed", - "duration": 0.81344, + "duration": 1.266281, + "requirements": [], + "os": "linux" + }, + { + "id": "fails-without-runner-metadata", + "name": "fails without runner metadata", + "className": "test", + "status": "Passed", + "duration": 0.8252, "requirements": [], "os": "linux" }, @@ -384,7 +393,7 @@ "name": "formatError handles plain objects", "className": "test", "status": "Passed", - "duration": 0.000229, + "duration": 0.000455, "requirements": [], "os": "linux" }, @@ -393,7 +402,7 @@ "name": "formatError handles primitives", "className": "test", "status": "Passed", - "duration": 0.000106, + "duration": 0.000323, "requirements": [], "os": "linux" }, @@ -402,7 +411,7 @@ "name": "formatError handles real Error objects", "className": "test", "status": "Passed", - "duration": 0.001221, + "duration": 0.00265, "requirements": [], "os": "linux" }, @@ -411,7 +420,7 @@ "name": "formatError handles unstringifiable values", "className": "test", "status": "Passed", - "duration": 0.000187, + "duration": 0.00055, "requirements": [], "os": "linux" }, @@ -420,7 +429,7 @@ "name": "generate-ci-summary features", "className": "test", "status": "Passed", - "duration": 0.020691, + "duration": 0.026061, "requirements": [], "os": "linux" }, @@ -429,7 +438,7 @@ "name": "groups owners and includes requirements and evidence", "className": "test", "status": "Passed", - "duration": 0.855927, + "duration": 1.361341, "requirements": [], "os": "linux" }, @@ -438,7 +447,7 @@ "name": "groupToMarkdown omits numeric identifiers", "className": "test", "status": "Passed", - "duration": 0.001157, + "duration": 0.002602, "requirements": [], "os": "linux" }, @@ -447,7 +456,7 @@ "name": "groupToMarkdown supports optional limit for truncation", "className": "test", "status": "Passed", - "duration": 0.000608, + "duration": 0.000886, "requirements": [], "os": "linux" }, @@ -456,7 +465,7 @@ "name": "handles root-level testcases", "className": "test", "status": "Passed", - "duration": 0.000832, + "duration": 0.000869, "requirements": [], "os": "linux" }, @@ -465,7 +474,7 @@ "name": "handles zipped JUnit artifacts", "className": "test", "status": "Passed", - "duration": 0.720984, + "duration": 1.054579, "requirements": [], "os": "linux" }, @@ -474,7 +483,7 @@ "name": "ignores stale JUnit files outside artifacts path", "className": "test", "status": "Passed", - "duration": 0.804072, + "duration": 1.160572, "requirements": [], "os": "linux" }, @@ -483,7 +492,7 @@ "name": "loadRequirements logs warning on invalid JSON", "className": "test", "status": "Passed", - "duration": 0.016972, + "duration": 0.045129, "requirements": [], "os": "linux" }, @@ -492,7 +501,7 @@ "name": "loadRequirements merges multiple files", "className": "test", "status": "Passed", - "duration": 0.002667, + "duration": 0.011535, "requirements": [], "os": "linux" }, @@ -501,7 +510,7 @@ "name": "loadRequirements warns and skips invalid entries", "className": "test", "status": "Passed", - "duration": 0.003562, + "duration": 0.015018, "requirements": [], "os": "linux" }, @@ -510,7 +519,7 @@ "name": "logs a warning when no JUnit files are found", "className": "test", "status": "Passed", - "duration": 0.845258, + "duration": 1.294323, "requirements": [], "os": "linux" }, @@ -519,7 +528,7 @@ "name": "partitions requirement groups by runner_type", "className": "test", "status": "Passed", - "duration": 0.762931, + "duration": 1.050325, "requirements": [], "os": "linux" }, @@ -528,7 +537,7 @@ "name": "passes with coverage and requirement reference", "className": "test", "status": "Passed", - "duration": 0.818483, + "duration": 1.297657, "requirements": [], "os": "linux" }, @@ -537,7 +546,7 @@ "name": "requirementsSummaryToMarkdown escapes pipes in description", "className": "test", "status": "Passed", - "duration": 0.000342, + "duration": 0.000956, "requirements": [], "os": "linux" }, @@ -546,7 +555,7 @@ "name": "skips invalid JUnit files and still generates summary", "className": "test", "status": "Passed", - "duration": 0.99408, + "duration": 1.517327, "requirements": [], "os": "linux" }, @@ -555,7 +564,7 @@ "name": "summaryToMarkdown handles no tests", "className": "test", "status": "Passed", - "duration": 0.000204, + "duration": 0.000396, "requirements": [], "os": "linux" }, @@ -564,7 +573,7 @@ "name": "summaryToMarkdown sorts OS alphabetically and escapes special characters", "className": "test", "status": "Passed", - "duration": 0.000471, + "duration": 0.000721, "requirements": [], "os": "linux" }, @@ -573,7 +582,7 @@ "name": "throws when no JUnit files found and strict mode enabled", "className": "test", "status": "Passed", - "duration": 0.670756, + "duration": 0.849162, "requirements": [], "os": "linux" }, @@ -582,7 +591,7 @@ "name": "uses latest artifact directory when multiple are present", "className": "test", "status": "Passed", - "duration": 0.865636, + "duration": 1.240923, "requirements": [], "os": "linux" }, @@ -591,7 +600,7 @@ "name": "warns when all tests are unmapped", "className": "test", "status": "Passed", - "duration": 1.048228, + "duration": 1.603055, "requirements": [], "os": "linux" }, @@ -600,7 +609,7 @@ "name": "writeErrorSummary appends error details to summary file", "className": "test", "status": "Passed", - "duration": 0.005534, + "duration": 0.005131, "requirements": [], "os": "linux" }, @@ -609,7 +618,7 @@ "name": "writeErrorSummary skips summary file for non-Error throws", "className": "test", "status": "Passed", - "duration": 0.002942, + "duration": 0.004137, "requirements": [], "os": "linux" }, @@ -618,7 +627,7 @@ "name": "writes outputs to OS-specific directory", "className": "test", "status": "Passed", - "duration": 0.945781, + "duration": 1.750139, "requirements": [], "os": "linux" } @@ -627,18 +636,18 @@ ], "totals": { "overall": { - "passed": 59, + "passed": 60, "failed": 0, "skipped": 0, - "duration": 15.057706000000003, + "duration": 23.743201999999997, "rate": 100 }, "byOs": { "linux": { - "passed": 59, + "passed": 60, "failed": 0, "skipped": 0, - "duration": 15.057706000000003, + "duration": 23.743201999999997, "rate": 100 } } diff --git a/artifacts/linux/traceability.md b/artifacts/linux/traceability.md index 8cb2d138..6dd24a87 100644 --- a/artifacts/linux/traceability.md +++ b/artifacts/linux/traceability.md @@ -4,37 +4,37 @@ | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-023 | parses-nested-junit-structures | Passed | 0.006 | | | +| REQ-023 | parses-nested-junit-structures | Passed | 0.011 | | | #### REQ-024 (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-024 | captures-root-testsuites-attributes | Passed | 0.005 | | | +| REQ-024 | captures-root-testsuites-attributes | Passed | 0.003 | | | #### REQ-025 (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-025 | captures-testsuite-attributes | Passed | 0.001 | | | +| REQ-025 | captures-testsuite-attributes | Passed | 0.006 | | | #### REQ-026 (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-026 | captures-suite-properties | Passed | 0.001 | | | +| REQ-026 | captures-suite-properties | Passed | 0.002 | | | #### REQ-027 (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-027 | captures-testcase-attributes-and-skipped-message | Passed | 0.008 | | | +| REQ-027 | captures-testcase-attributes-and-skipped-message | Passed | 0.001 | | | #### REQ-028 (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-028 | extracts-requirement-identifiers | Passed | 0.002 | | | +| REQ-028 | extracts-requirement-identifiers | Passed | 0.003 | | | #### REQ-029 (100% passed) @@ -46,7 +46,7 @@ | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-030 | builds-traceability-matrix-with-skipped-reasons | Passed | 0.001 | | | +| REQ-030 | builds-traceability-matrix-with-skipped-reasons | Passed | 0.002 | | | #### REQ-031 (100% passed) @@ -64,59 +64,60 @@ | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| REQ-033 | throws-error-for-malformed-xml | Passed | 0.001 | | | +| REQ-033 | throws-error-for-malformed-xml | Passed | 0.004 | | |
Unmapped (100% passed) | Requirement | Test ID | Status | Duration (s) | Owner | Evidence | | --- | --- | --- | --- | --- | --- | -| Unmapped | associates-classname-with-requirement | Passed | 0.012 | | | -| Unmapped | buildissuebranchname-formats-branch-name | Passed | 0.001 | | | -| Unmapped | buildissuebranchname-rejects-non-numeric-input | Passed | 0.001 | | | +| Unmapped | associates-classname-with-requirement | Passed | 0.016 | | | +| Unmapped | buildissuebranchname-formats-branch-name | Passed | 0.003 | | | +| Unmapped | buildissuebranchname-rejects-non-numeric-input | Passed | 0.002 | | | | Unmapped | buildprofile1.iconeditor.addtokentolabview.dispatcher.dry-runs-add-token-to-labview-with-expected-arguments- | Passed | 0.482 | | | | Unmapped | buildprofile1.iconeditor.applyvipc.dispatcher.dry-runs-apply-vipc-with-expected-arguments- | Passed | 0.042 | | | | Unmapped | buildprofile1.iconeditor.buildvipackage.dispatcher.dry-runs-build-vi-package-with-expected-arguments- | Passed | 0.106 | | | | Unmapped | buildprofile1.iconeditor.closelabview.dispatcher.dry-runs-close-labview-with-expected-arguments- | Passed | 0.036 | | | -| Unmapped | buildsummary-splits-totals-by-os | Passed | 0.000 | | | -| Unmapped | collecttestcases-captures-requirement-property | Passed | 0.009 | | | -| Unmapped | collecttestcases-uses-evidence-property-and-falls-back-to-directory-scan | Passed | 0.009 | | | -| Unmapped | collecttestcases-uses-machine-name-property-for-owner | Passed | 0.003 | | | +| Unmapped | buildsummary-splits-totals-by-os | Passed | 0.001 | | | +| Unmapped | collecttestcases-captures-requirement-property | Passed | 0.020 | | | +| Unmapped | collecttestcases-uses-evidence-property-and-falls-back-to-directory-scan | Passed | 0.008 | | | +| Unmapped | collecttestcases-uses-machine-name-property-for-owner | Passed | 0.008 | | | | Unmapped | computestatuscounts-tallies-test-statuses | Passed | 0.000 | | | -| Unmapped | detects-downloaded-artifacts-path | Passed | 0.894 | | | -| Unmapped | dispatchers-and-parameters-include-descriptions | Passed | 0.002 | | | -| Unmapped | errors-when-strict-unmapped-mode-enabled | Passed | 0.952 | | | -| Unmapped | escapemarkdown-escapes-special-characters | Passed | 0.002 | | | +| Unmapped | detects-downloaded-artifacts-path | Passed | 1.285 | | | +| Unmapped | dispatchers-and-parameters-include-descriptions | Passed | 0.009 | | | +| Unmapped | errors-when-strict-unmapped-mode-enabled | Passed | 1.270 | | | +| Unmapped | escapemarkdown-escapes-special-characters | Passed | 0.001 | | | | Unmapped | escapemarkdown-leaves-plain-text-untouched | Passed | 0.000 | | | -| Unmapped | fails-when-commit-lacks-requirement-reference | Passed | 0.759 | | | -| Unmapped | fails-when-requirement-lacks-test-coverage | Passed | 0.749 | | | -| Unmapped | fails-when-tests-are-unmapped | Passed | 0.766 | | | -| Unmapped | fails-when-tests-reference-unknown-requirements | Passed | 0.813 | | | +| Unmapped | fails-when-commit-lacks-requirement-reference | Passed | 1.298 | | | +| Unmapped | fails-when-requirement-lacks-test-coverage | Passed | 1.526 | | | +| Unmapped | fails-when-tests-are-unmapped | Passed | 1.205 | | | +| Unmapped | fails-when-tests-reference-unknown-requirements | Passed | 1.266 | | | +| Unmapped | fails-without-runner-metadata | Passed | 0.825 | | | | Unmapped | formaterror-handles-plain-objects | Passed | 0.000 | | | | Unmapped | formaterror-handles-primitives | Passed | 0.000 | | | -| Unmapped | formaterror-handles-real-error-objects | Passed | 0.001 | | | -| Unmapped | formaterror-handles-unstringifiable-values | Passed | 0.000 | | | -| Unmapped | generate-ci-summary-features | Passed | 0.021 | | | -| Unmapped | groups-owners-and-includes-requirements-and-evidence | Passed | 0.856 | | | -| Unmapped | grouptomarkdown-omits-numeric-identifiers | Passed | 0.001 | | | +| Unmapped | formaterror-handles-real-error-objects | Passed | 0.003 | | | +| Unmapped | formaterror-handles-unstringifiable-values | Passed | 0.001 | | | +| Unmapped | generate-ci-summary-features | Passed | 0.026 | | | +| Unmapped | groups-owners-and-includes-requirements-and-evidence | Passed | 1.361 | | | +| Unmapped | grouptomarkdown-omits-numeric-identifiers | Passed | 0.003 | | | | Unmapped | grouptomarkdown-supports-optional-limit-for-truncation | Passed | 0.001 | | | | Unmapped | handles-root-level-testcases | Passed | 0.001 | | | -| Unmapped | handles-zipped-junit-artifacts | Passed | 0.721 | | | -| Unmapped | ignores-stale-junit-files-outside-artifacts-path | Passed | 0.804 | | | -| Unmapped | loadrequirements-logs-warning-on-invalid-json | Passed | 0.017 | | | -| Unmapped | loadrequirements-merges-multiple-files | Passed | 0.003 | | | -| Unmapped | loadrequirements-warns-and-skips-invalid-entries | Passed | 0.004 | | | -| Unmapped | logs-a-warning-when-no-junit-files-are-found | Passed | 0.845 | | | -| Unmapped | partitions-requirement-groups-by-runner\_type | Passed | 0.763 | | | -| Unmapped | passes-with-coverage-and-requirement-reference | Passed | 0.818 | | | -| Unmapped | requirementssummarytomarkdown-escapes-pipes-in-description | Passed | 0.000 | | | -| Unmapped | skips-invalid-junit-files-and-still-generates-summary | Passed | 0.994 | | | +| Unmapped | handles-zipped-junit-artifacts | Passed | 1.055 | | | +| Unmapped | ignores-stale-junit-files-outside-artifacts-path | Passed | 1.161 | | | +| Unmapped | loadrequirements-logs-warning-on-invalid-json | Passed | 0.045 | | | +| Unmapped | loadrequirements-merges-multiple-files | Passed | 0.012 | | | +| Unmapped | loadrequirements-warns-and-skips-invalid-entries | Passed | 0.015 | | | +| Unmapped | logs-a-warning-when-no-junit-files-are-found | Passed | 1.294 | | | +| Unmapped | partitions-requirement-groups-by-runner\_type | Passed | 1.050 | | | +| Unmapped | passes-with-coverage-and-requirement-reference | Passed | 1.298 | | | +| Unmapped | requirementssummarytomarkdown-escapes-pipes-in-description | Passed | 0.001 | | | +| Unmapped | skips-invalid-junit-files-and-still-generates-summary | Passed | 1.517 | | | | Unmapped | summarytomarkdown-handles-no-tests | Passed | 0.000 | | | -| Unmapped | summarytomarkdown-sorts-os-alphabetically-and-escapes-special-characters | Passed | 0.000 | | | -| Unmapped | throws-when-no-junit-files-found-and-strict-mode-enabled | Passed | 0.671 | | | -| Unmapped | uses-latest-artifact-directory-when-multiple-are-present | Passed | 0.866 | | | -| Unmapped | warns-when-all-tests-are-unmapped | Passed | 1.048 | | | -| Unmapped | writeerrorsummary-appends-error-details-to-summary-file | Passed | 0.006 | | | -| Unmapped | writeerrorsummary-skips-summary-file-for-non-error-throws | Passed | 0.003 | | | -| Unmapped | writes-outputs-to-os-specific-directory | Passed | 0.946 | | | +| Unmapped | summarytomarkdown-sorts-os-alphabetically-and-escapes-special-characters | Passed | 0.001 | | | +| Unmapped | throws-when-no-junit-files-found-and-strict-mode-enabled | Passed | 0.849 | | | +| Unmapped | uses-latest-artifact-directory-when-multiple-are-present | Passed | 1.241 | | | +| Unmapped | warns-when-all-tests-are-unmapped | Passed | 1.603 | | | +| Unmapped | writeerrorsummary-appends-error-details-to-summary-file | Passed | 0.005 | | | +| Unmapped | writeerrorsummary-skips-summary-file-for-non-error-throws | Passed | 0.004 | | | +| Unmapped | writes-outputs-to-os-specific-directory | Passed | 1.750 | | |
\ No newline at end of file diff --git a/ci_evidence.txt b/ci_evidence.txt index 0999005d..6b3faf4a 100644 --- a/ci_evidence.txt +++ b/ci_evidence.txt @@ -1 +1 @@ -{"pipeline":"Unknown","git_sha":"18df35a724af7429bac01805085922dddf3b9b85","req_status":{"REQ-023":"PASS","REQ-024":"PASS","REQ-025":"PASS","REQ-026":"PASS","REQ-027":"PASS","REQ-028":"PASS","REQ-029":"PASS","REQ-030":"PASS","REQ-031":"PASS","REQ-032":"PASS","REQ-033":"PASS"}} \ No newline at end of file +{"pipeline":"Unknown","git_sha":"74b28b12cf04f046cf9f89dfedf9a33e093d7e34","req_status":{"REQ-023":"PASS","REQ-024":"PASS","REQ-025":"PASS","REQ-026":"PASS","REQ-027":"PASS","REQ-028":"PASS","REQ-029":"PASS","REQ-030":"PASS","REQ-031":"PASS","REQ-032":"PASS","REQ-033":"PASS"}} \ No newline at end of file diff --git a/scripts/__tests__/generate-ci-summary.test.js b/scripts/__tests__/generate-ci-summary.test.js index ed205bde..a75898a5 100644 --- a/scripts/__tests__/generate-ci-summary.test.js +++ b/scripts/__tests__/generate-ci-summary.test.js @@ -277,6 +277,7 @@ test('writes outputs to OS-specific directory', async () => { TEST_RESULTS_GLOBS: junitPath, EVIDENCE_DIR: tmp, RUNNER_OS: 'Windows', + RUNNER_LABEL: 'ubuntu-latest', }; await execFileP('node_modules/.bin/tsx', ['scripts/generate-ci-summary.ts'], { env }); @@ -312,6 +313,7 @@ test('skips invalid JUnit files and still generates summary', async () => { TEST_RESULTS_GLOBS: `${goodPath} ${badPath}`, EVIDENCE_DIR: dir, RUNNER_OS: 'Linux', + RUNNER_LABEL: 'ubuntu-latest', }; const { stderr } = await execFileP('node_modules/.bin/tsx', ['scripts/generate-ci-summary.ts'], { env }); @@ -343,6 +345,7 @@ test('warns when all tests are unmapped', async () => { EVIDENCE_DIR: dir, REQ_MAPPING_FILE: reqPath, RUNNER_OS: 'Linux', + RUNNER_LABEL: 'ubuntu-latest', }; const { stderr } = await execFileP('node_modules/.bin/tsx', ['scripts/generate-ci-summary.ts'], { env }); @@ -368,6 +371,7 @@ test('errors when strict unmapped mode enabled', async () => { REQ_MAPPING_FILE: reqPath, RUNNER_OS: 'Linux', REQUIRE_REQUIREMENTS_MAPPING: '1', + RUNNER_LABEL: 'ubuntu-latest', }; await assert.rejects( @@ -389,6 +393,7 @@ test('ignores stale JUnit files outside artifacts path', async () => { await fs.writeFile(stalePath, ''); const env = { ...process.env, RUNNER_OS: 'Linux' }; + env.RUNNER_LABEL = 'ubuntu-latest'; await execFileP('node_modules/.bin/tsx', ['scripts/generate-ci-summary.ts'], { env }); const trace = await fs.readFile(path.join('artifacts', 'linux', 'traceability.md'), 'utf8'); @@ -401,7 +406,7 @@ test('ignores stale JUnit files outside artifacts path', async () => { test('throws when no JUnit files found and strict mode enabled', async () => { await fs.rm('artifacts', { recursive: true, force: true }); - const env = { ...process.env, REQUIRE_TEST_RESULTS: '1', RUNNER_OS: 'Linux' }; + const env = { ...process.env, REQUIRE_TEST_RESULTS: '1', RUNNER_OS: 'Linux', RUNNER_LABEL: 'ubuntu-latest' }; await assert.rejects( execFileP('node_modules/.bin/tsx', ['scripts/generate-ci-summary.ts'], { env }), /No JUnit files found/, @@ -431,6 +436,7 @@ test('partitions requirement groups by runner_type', async () => { EVIDENCE_DIR: dir, REQ_MAPPING_FILE: reqPath, RUNNER_OS: 'Linux', + RUNNER_LABEL: 'ubuntu-latest', }; await execFileP('node_modules/.bin/tsx', ['scripts/generate-ci-summary.ts'], { env }); @@ -469,6 +475,7 @@ test('handles zipped JUnit artifacts', async () => { REQ_MAPPING_FILE: reqPath, DISPATCHER_REGISTRY: dispPath, RUNNER_OS: 'Linux', + RUNNER_LABEL: 'ubuntu-latest', }; await execFileP('node_modules/.bin/tsx', ['scripts/generate-ci-summary.ts'], { env }); @@ -479,3 +486,12 @@ test('handles zipped JUnit artifacts', async () => { await fs.rm('artifacts', { recursive: true, force: true }); await fs.rm(tmp, { recursive: true, force: true }); }); + +test('fails without runner metadata', async () => { + await fs.rm('artifacts', { recursive: true, force: true }); + const env = { ...process.env, RUNNER_OS: 'Linux' }; + await assert.rejects( + execFileP('node_modules/.bin/tsx', ['scripts/generate-ci-summary.ts'], { env }), + /RUNNER_LABEL, RUNNER_TYPE, or SKIP_DRY_RUN must be set/, + ); +}); diff --git a/scripts/generate-ci-summary.ts b/scripts/generate-ci-summary.ts index 56f403db..608c2eb9 100644 --- a/scripts/generate-ci-summary.ts +++ b/scripts/generate-ci-summary.ts @@ -23,6 +23,17 @@ import { collectTestCases } from './summary/tests.ts'; import { loadRequirements, mapToRequirements, redact } from './summary/requirements.ts'; async function main() { + const hasRunnerMeta = Boolean( + process.env.RUNNER_LABEL || + process.env.RUNNER_TYPE || + process.env.SKIP_DRY_RUN, + ); + if (!hasRunnerMeta) { + console.error( + 'At least one of RUNNER_LABEL, RUNNER_TYPE, or SKIP_DRY_RUN must be set', + ); + process.exit(1); + } const mappingFiles = (process.env.REQ_MAPPING_FILE || 'requirements.json') .split(',') .map((s) => s.trim()) diff --git a/test-results/node-junit.xml b/test-results/node-junit.xml index a2a81f29..02ff843e 100644 --- a/test-results/node-junit.xml +++ b/test-results/node-junit.xml @@ -1,66 +1,67 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - +