Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions .github/actions/scripts/utp-ci-assertion-helpers.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
#!/usr/bin/env bash
# Shared helpers for UTP CI batch validation (.github/actions/scripts/run-utp-tests.sh).
# Keep behavior in sync with contract tests: tests/run-utp-tests-contract.sh
#
# Severity checks go through utp-file-has-actionable-severity.cjs → normalizeTelemetryEntry
# so benign Unity noise (multicast WSAEACCES, OpenCL, StackAllocator, etc.) is remapped
# before Error/Exception/Assert are treated as failures. Do not re-special-case messages here.

_UTP_ASSERT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
_UTP_ACTIONABLE_SEVERITY_JS="${_UTP_ASSERT_DIR}/utp-file-has-actionable-severity.cjs"

# Returns 0 if the UTP file has an actionable Error/Exception/(optional Assert) after normalize.
utp_file_has_actionable_severity() {
local utp_file="$1"
local severities_re="$2"
node "$_UTP_ACTIONABLE_SEVERITY_JS" "$utp_file" "$severities_re"
}

# Returns 0 (true) if this UTP JSON log should fail an *expected-success* scenario.
utp_signals_failure_for_expected_success() {
Expand All @@ -9,18 +23,18 @@ utp_signals_failure_for_expected_success() {
case "$test_name" in
CompilerWarnings|BuildWarnings)
# Engine / allocator assert telemetry is common here; only treat Error/Exception as hard failures.
grep -qi '"severity"[[:space:]]*:[[:space:]]*"\(Error\|Exception\)"' "$utp_file" 2>/dev/null
utp_file_has_actionable_severity "$utp_file" 'Error|Exception'
;;
*)
grep -qi '"severity"[[:space:]]*:[[:space:]]*"\(Error\|Exception\|Assert\)"' "$utp_file" 2>/dev/null
utp_file_has_actionable_severity "$utp_file" 'Error|Exception|Assert'
;;
esac
}

# Returns 0 if UTP log contains any Error/Exception/Assert (used for expected-failure scenarios).
# Returns 0 if UTP log contains any actionable Error/Exception/Assert (expected-failure scenarios).
utp_signals_any_severity_problem() {
local utp_file="$1"
grep -qi '"severity"[[:space:]]*:[[:space:]]*"\(Error\|Exception\|Assert\)"' "$utp_file" 2>/dev/null
utp_file_has_actionable_severity "$utp_file" 'Error|Exception|Assert'
}

# Prints first path to an NUnit results file containing <test-case>, or nothing.
Expand Down
69 changes: 69 additions & 0 deletions .github/actions/scripts/utp-file-has-actionable-severity.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* CI helper: parse a *-utp-json.log (pretty JSON array from unity-cli, or NDJSON fixtures)
* through normalizeTelemetryEntry so benign elevated severities are remapped, then exit 0
* if any remaining severity is in the requested set.
*
* Usage: node utp-file-has-actionable-severity.cjs <file> [Error|Exception|Assert]
* Exit 0 = has actionable severity; exit 1 = none; exit 2 = usage/IO/parse error.
*
* Requires `npm run build` so dist/utp.js exists (same as scan-utp-artifacts.cjs).
*/
const fs = require('fs');
const path = require('path');

const repoRoot = path.join(__dirname, '..', '..', '..');
const distUtp = path.join(repoRoot, 'dist', 'utp.js');
if (!fs.existsSync(distUtp)) {
console.error(`utp-file-has-actionable-severity: missing ${distUtp} (run npm run build)`);
process.exit(2);
}

const { normalizeTelemetryEntry } = require(distUtp);

const filePath = process.argv[2];
const severitiesArg = process.argv[3] || 'Error|Exception|Assert';
if (!filePath) {
console.error('Usage: node utp-file-has-actionable-severity.cjs <file> [Error|Exception|Assert]');
process.exit(2);
}

const severitySet = new Set(severitiesArg.split('|').map(s => s.trim()).filter(Boolean));

function loadEntries(raw) {
const trimmed = raw.trim();
if (!trimmed) {
return [];
}
try {
const data = JSON.parse(trimmed);
return Array.isArray(data) ? data : [data];
} catch {
// NDJSON / one compact object per line (contract fixtures)
const out = [];
for (const line of trimmed.split(/\r?\n/)) {
const t = line.trim();
if (!t) {
continue;
}
out.push(JSON.parse(t));
}
return out;
}
}

let entries;
try {
entries = loadEntries(fs.readFileSync(filePath, 'utf8'));
} catch (err) {
console.error(`utp-file-has-actionable-severity: ${err.message || err}`);
process.exit(2);
}

for (const entry of entries) {
const { utp } = normalizeTelemetryEntry(entry);
if (utp && utp.severity && severitySet.has(String(utp.severity))) {
process.exit(0);
}
}

process.exit(1);
6 changes: 6 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ jobs:
contents: read
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '24'
cache: npm
- run: npm ci
- run: npm run build
- name: UTP batch assertion helpers (contract)
run: bash tests/run-utp-tests-contract.sh
setup:
Expand Down
Loading
Loading