@metasession.co/devaudit-cli 0.3.13 → 0.3.14
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.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/sdlc/files/_common/scripts/generate-bundled-changes.sh +13 -4
- package/sdlc/files/_common/scripts/generate-bundled-changes.test.sh +5 -0
- package/sdlc/files/_common/scripts/report-release-check.sh +86 -0
- package/sdlc/files/_common/scripts/report-release-check.test.sh +97 -0
- package/sdlc/files/ci/ci.yml.template +49 -12
- package/sdlc/files/ci/compliance-evidence.yml.template +32 -6
- package/sdlc/files/ci/post-deploy-prod.yml.template +149 -21
- package/sdlc/package.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metasession.co/devaudit-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.14",
|
|
4
4
|
"description": "DevAudit CLI — installs, syncs, and operates the Metasession SDLC across consumer projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@clack/prompts": "^0.8.2",
|
|
36
|
-
"@metasession.co/devaudit-plugin-sdk": "^0.3.
|
|
36
|
+
"@metasession.co/devaudit-plugin-sdk": "^0.3.14",
|
|
37
37
|
"ajv": "^8.20.0",
|
|
38
38
|
"commander": "^12.1.0",
|
|
39
39
|
"consola": "^3.2.3",
|
|
@@ -76,7 +76,7 @@ extract_ticket_title() {
|
|
|
76
76
|
printf '%s' "$line" \
|
|
77
77
|
| sed -E 's/^\*\*Requirement:\*\*[[:space:]]*//' \
|
|
78
78
|
| sed -E 's/^REQ-[0-9]+[[:space:]]*[—–:-][[:space:]]*//' \
|
|
79
|
-
| sed -E 's
|
|
79
|
+
| sed -E 's/^[[:space:]]+|[[:space:]]+$//g'
|
|
80
80
|
return 0
|
|
81
81
|
fi
|
|
82
82
|
line=$(grep -m1 '^# ' "$file" 2>/dev/null || true)
|
|
@@ -227,6 +227,7 @@ for version in "${EXPLICIT_PREDECESSORS[@]}"; do
|
|
|
227
227
|
--arg commitTo "$commit_to" \
|
|
228
228
|
--arg prNumber "$pr_number" \
|
|
229
229
|
--arg prUrl "$pr_url" \
|
|
230
|
+
--arg originalTitle "${title:-Release $version}" \
|
|
230
231
|
'. + [{
|
|
231
232
|
version: $version,
|
|
232
233
|
role: $role,
|
|
@@ -236,7 +237,14 @@ for version in "${EXPLICIT_PREDECESSORS[@]}"; do
|
|
|
236
237
|
commitFrom: (if $commitFrom == "" then null else $commitFrom end),
|
|
237
238
|
commitTo: (if $commitTo == "" then null else $commitTo end),
|
|
238
239
|
prNumber: (if $prNumber == "" then null else ($prNumber | tonumber) end),
|
|
239
|
-
prUrl: (if $prUrl == "" then null else $prUrl end)
|
|
240
|
+
prUrl: (if $prUrl == "" then null else $prUrl end),
|
|
241
|
+
originalTitle: $originalTitle,
|
|
242
|
+
evidenceInheritancePolicy: {
|
|
243
|
+
mode: "all_eligible",
|
|
244
|
+
includeCycles: true,
|
|
245
|
+
scopes: ["release", "stage", "cycle"],
|
|
246
|
+
reason: $reason
|
|
247
|
+
}
|
|
240
248
|
}]' <<<"$MEMBERS"
|
|
241
249
|
)"
|
|
242
250
|
PREDECESSOR_LINES+=("- \`${version}\` (${role}/${relationship}) — ${title:-Untitled release ticket}")
|
|
@@ -267,6 +275,7 @@ fi
|
|
|
267
275
|
GENERATOR_VERSION="$(jq -r '.version' cli/package.json 2>/dev/null || echo '0.0.0')"
|
|
268
276
|
REPOSITORY_SLUG="$(git config --get remote.origin.url 2>/dev/null | sed -E 's#(git@github.com:|https://github.com/)##; s#\.git$##' || true)"
|
|
269
277
|
GENERATED_AT="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
278
|
+
[ -n "$REPOSITORY_SLUG" ] || REPOSITORY_SLUG="${GITHUB_REPOSITORY:-local/unknown}"
|
|
270
279
|
|
|
271
280
|
MANIFEST_BASE="$(
|
|
272
281
|
jq -c -n \
|
|
@@ -277,7 +286,7 @@ MANIFEST_BASE="$(
|
|
|
277
286
|
--arg repository "$REPOSITORY_SLUG" \
|
|
278
287
|
--arg generatedAt "$GENERATED_AT" \
|
|
279
288
|
'{
|
|
280
|
-
schemaVersion:
|
|
289
|
+
schemaVersion: 2,
|
|
281
290
|
approvalRelease: { version: $version },
|
|
282
291
|
coreRelease: { version: $version },
|
|
283
292
|
members: ($members | fromjson),
|
|
@@ -291,7 +300,7 @@ MANIFEST_BASE="$(
|
|
|
291
300
|
}'
|
|
292
301
|
)"
|
|
293
302
|
|
|
294
|
-
HASH_INPUT="$(jq -
|
|
303
|
+
HASH_INPUT="$(jq -cS 'del(.generator.generatedAt)' <<<"$MANIFEST_BASE")"
|
|
295
304
|
MANIFEST_HASH="sha256:$(printf '%s' "$HASH_INPUT" | sha256sum | awk '{print $1}')"
|
|
296
305
|
MANIFEST_JSON="$(jq --arg manifestHash "$MANIFEST_HASH" '. + { manifestHash: $manifestHash }' <<<"$MANIFEST_BASE")"
|
|
297
306
|
|
|
@@ -150,6 +150,11 @@ assert_eq "member version recorded" "REQ-041" "$(jq -r '.members[0].version' "$J
|
|
|
150
150
|
assert_eq "member role recorded" "predecessor" "$(jq -r '.members[0].role' "$JSON_OUT")"
|
|
151
151
|
assert_eq "member relationship recorded" "superseded" "$(jq -r '.members[0].relationship' "$JSON_OUT")"
|
|
152
152
|
assert_eq "manifest hash present" "true" "$(jq -r 'has("manifestHash")' "$JSON_OUT")"
|
|
153
|
+
assert_eq "manifest schema v2" "2" "$(jq -r '.schemaVersion' "$JSON_OUT")"
|
|
154
|
+
assert_eq "original title recorded" "Prior tracked release" "$(jq -r '.members[0].originalTitle' "$JSON_OUT")"
|
|
155
|
+
assert_eq "inheritance policy explicit" "all_eligible" "$(jq -r '.members[0].evidenceInheritancePolicy.mode' "$JSON_OUT")"
|
|
156
|
+
EXPECTED_HASH="sha256:$(jq -cS 'del(.manifestHash, .generator.generatedAt)' "$JSON_OUT" | tr -d '\n' | sha256sum | awk '{print $1}')"
|
|
157
|
+
assert_eq "canonical manifest hash verifies" "$EXPECTED_HASH" "$(jq -r '.manifestHash' "$JSON_OUT")"
|
|
153
158
|
echo
|
|
154
159
|
|
|
155
160
|
# Test 3: ambiguous predecessor ownership fails.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Records authoritative required-check state independently of evidence upload.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
PROJECT_SLUG="" RELEASE_VERSION="" CHECK_KEY="" LABEL="" PROVIDER="github_actions"
|
|
6
|
+
STATUS="" REQUIRED="true" EXTERNAL_RUN_ID="" EXTERNAL_URL="" COMMIT_SHA="" BRANCH=""
|
|
7
|
+
STARTED_AT="" COMPLETED_AT="" DETAILS_JSON='{}'
|
|
8
|
+
|
|
9
|
+
while [ "$#" -gt 0 ]; do
|
|
10
|
+
case "$1" in
|
|
11
|
+
--project-slug) PROJECT_SLUG="$2"; shift 2 ;;
|
|
12
|
+
--release) RELEASE_VERSION="$2"; shift 2 ;;
|
|
13
|
+
--check-key) CHECK_KEY="$2"; shift 2 ;;
|
|
14
|
+
--label) LABEL="$2"; shift 2 ;;
|
|
15
|
+
--provider) PROVIDER="$2"; shift 2 ;;
|
|
16
|
+
--status) STATUS="$2"; shift 2 ;;
|
|
17
|
+
--required) REQUIRED="$2"; shift 2 ;;
|
|
18
|
+
--external-run-id) EXTERNAL_RUN_ID="$2"; shift 2 ;;
|
|
19
|
+
--external-url) EXTERNAL_URL="$2"; shift 2 ;;
|
|
20
|
+
--commit-sha) COMMIT_SHA="$2"; shift 2 ;;
|
|
21
|
+
--branch) BRANCH="$2"; shift 2 ;;
|
|
22
|
+
--started-at) STARTED_AT="$2"; shift 2 ;;
|
|
23
|
+
--completed-at) COMPLETED_AT="$2"; shift 2 ;;
|
|
24
|
+
--details-json) DETAILS_JSON="$2"; shift 2 ;;
|
|
25
|
+
*) echo "Unknown option: $1" >&2; exit 1 ;;
|
|
26
|
+
esac
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
for value in PROJECT_SLUG RELEASE_VERSION CHECK_KEY LABEL STATUS; do
|
|
30
|
+
if [ -z "${!value}" ]; then echo "Error: ${value} is required" >&2; exit 1; fi
|
|
31
|
+
done
|
|
32
|
+
case "$STATUS" in
|
|
33
|
+
queued|running|successful|failed|cancelled|timed_out|skipped|action_required|unknown) ;;
|
|
34
|
+
*) echo "Error: invalid check status '$STATUS'" >&2; exit 1 ;;
|
|
35
|
+
esac
|
|
36
|
+
jq -e 'type == "object"' >/dev/null <<<"$DETAILS_JSON" || {
|
|
37
|
+
echo "Error: --details-json must be a JSON object" >&2; exit 1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
BASE="${DEVAUDIT_BASE_URL%/}"
|
|
41
|
+
if [ -z "$BASE" ] || [ -z "${DEVAUDIT_API_KEY:-}" ]; then
|
|
42
|
+
echo "::warning::Release check reporting skipped: DevAudit URL/API key missing" >&2
|
|
43
|
+
exit 0
|
|
44
|
+
fi
|
|
45
|
+
ENCODED_SLUG=$(jq -rn --arg v "$PROJECT_SLUG" '$v|@uri')
|
|
46
|
+
ENCODED_VERSION=$(jq -rn --arg v "$RELEASE_VERSION" '$v|@uri')
|
|
47
|
+
RESOLVE=$(curl -fsS \
|
|
48
|
+
-H "Authorization: Bearer ${DEVAUDIT_API_KEY}" \
|
|
49
|
+
"${BASE}/api/ci/releases/resolve?projectSlug=${ENCODED_SLUG}&versionPrefix=${ENCODED_VERSION}" || true)
|
|
50
|
+
RELEASE_ID=$(jq -r --arg version "$RELEASE_VERSION" \
|
|
51
|
+
'if .latest.version == $version then .latest.id // empty else empty end' <<<"$RESOLVE" 2>/dev/null || true)
|
|
52
|
+
if [ -z "$RELEASE_ID" ]; then
|
|
53
|
+
echo "::warning::Release check reporting skipped: exact release ${RELEASE_VERSION} not found" >&2
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
PAYLOAD=$(jq -n \
|
|
58
|
+
--arg checkKey "$CHECK_KEY" --arg displayLabel "$LABEL" --arg provider "$PROVIDER" \
|
|
59
|
+
--arg status "$STATUS" --argjson required "$REQUIRED" \
|
|
60
|
+
--arg externalRunId "$EXTERNAL_RUN_ID" --arg externalUrl "$EXTERNAL_URL" \
|
|
61
|
+
--arg commitSha "$COMMIT_SHA" --arg branch "$BRANCH" \
|
|
62
|
+
--arg startedAt "$STARTED_AT" --arg completedAt "$COMPLETED_AT" \
|
|
63
|
+
--argjson details "$DETAILS_JSON" \
|
|
64
|
+
'{checkKey:$checkKey,label:$displayLabel,provider:$provider,status:$status,required:$required,
|
|
65
|
+
externalRunId:(if $externalRunId=="" then null else $externalRunId end),
|
|
66
|
+
externalUrl:(if $externalUrl=="" then null else $externalUrl end),
|
|
67
|
+
commitSha:(if $commitSha=="" then null else $commitSha end),
|
|
68
|
+
branch:(if $branch=="" then null else $branch end),
|
|
69
|
+
startedAt:(if $startedAt=="" then null else $startedAt end),
|
|
70
|
+
completedAt:(if $completedAt=="" then null else $completedAt end),details:$details}')
|
|
71
|
+
|
|
72
|
+
RESPONSE_FILE=$(mktemp)
|
|
73
|
+
trap 'rm -f "$RESPONSE_FILE"' EXIT
|
|
74
|
+
HTTP_CODE=$(curl -sS -o "$RESPONSE_FILE" -w '%{http_code}' \
|
|
75
|
+
-X POST "${BASE}/api/ci/releases/${RELEASE_ID}/checks" \
|
|
76
|
+
-H "Authorization: Bearer ${DEVAUDIT_API_KEY}" -H 'Content-Type: application/json' \
|
|
77
|
+
-d "$PAYLOAD")
|
|
78
|
+
if [ "$HTTP_CODE" = "404" ]; then
|
|
79
|
+
echo "::warning::Portal does not support first-class release checks yet" >&2
|
|
80
|
+
exit 0
|
|
81
|
+
fi
|
|
82
|
+
if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then
|
|
83
|
+
cat "$RESPONSE_FILE" >&2 || true
|
|
84
|
+
echo "Error: release check API returned HTTP ${HTTP_CODE}" >&2
|
|
85
|
+
exit 1
|
|
86
|
+
fi
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Focused regression tests for authoritative release-check reporting.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
HELPER="$SCRIPT_DIR/report-release-check.sh"
|
|
7
|
+
PASS=0
|
|
8
|
+
FAIL=0
|
|
9
|
+
|
|
10
|
+
ok() { echo " PASS: $1"; PASS=$((PASS + 1)); }
|
|
11
|
+
no() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
|
|
12
|
+
|
|
13
|
+
make_fixture() {
|
|
14
|
+
local dir="$1"
|
|
15
|
+
mkdir -p "$dir/bin"
|
|
16
|
+
cat > "$dir/bin/curl" <<'EOF'
|
|
17
|
+
#!/usr/bin/env bash
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
URL=""
|
|
20
|
+
OUT=""
|
|
21
|
+
BODY=""
|
|
22
|
+
ARGS=("$@")
|
|
23
|
+
for ((i=0; i<${#ARGS[@]}; i++)); do
|
|
24
|
+
case "${ARGS[$i]}" in
|
|
25
|
+
-o) OUT="${ARGS[$((i+1))]}" ;;
|
|
26
|
+
-d) BODY="${ARGS[$((i+1))]}" ;;
|
|
27
|
+
http://*|https://*) URL="${ARGS[$i]}" ;;
|
|
28
|
+
esac
|
|
29
|
+
done
|
|
30
|
+
printf 'URL:%s\nBODY:%s\n' "$URL" "$BODY" >> "${CHECK_TEST_LOG:?}"
|
|
31
|
+
if [[ "$URL" == *'/api/ci/releases/resolve'* ]]; then
|
|
32
|
+
printf '%s' "${RESOLVE_BODY:-{}}"
|
|
33
|
+
exit 0
|
|
34
|
+
fi
|
|
35
|
+
if [ -n "$OUT" ]; then printf '%s' "${CHECK_BODY:-{}}" > "$OUT"; fi
|
|
36
|
+
printf '%s' "${CHECK_STATUS:-200}"
|
|
37
|
+
EOF
|
|
38
|
+
chmod +x "$dir/bin/curl"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
run_helper() {
|
|
42
|
+
PATH="$1/bin:$PATH" \
|
|
43
|
+
CHECK_TEST_LOG="$1/curl.log" \
|
|
44
|
+
DEVAUDIT_BASE_URL="https://devaudit.example.test" \
|
|
45
|
+
DEVAUDIT_API_KEY="mc_test_dummy" \
|
|
46
|
+
"$HELPER" "${@:2}"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
base_args=(
|
|
50
|
+
--project-slug fixture-app
|
|
51
|
+
--release REQ-100
|
|
52
|
+
--check-key quality-gates
|
|
53
|
+
--label "Quality Gates"
|
|
54
|
+
--status failed
|
|
55
|
+
--external-run-id 123
|
|
56
|
+
--commit-sha abc123
|
|
57
|
+
--details-json '{"artifactUpload":"successful"}'
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
echo "=== report-release-check.sh tests ==="
|
|
61
|
+
|
|
62
|
+
dir=$(mktemp -d)
|
|
63
|
+
make_fixture "$dir"
|
|
64
|
+
RESOLVE_BODY='{"latest":{"id":"release-1","version":"REQ-100"}}' \
|
|
65
|
+
CHECK_STATUS=201 run_helper "$dir" "${base_args[@]}"
|
|
66
|
+
if grep -q '/api/ci/releases/release-1/checks' "$dir/curl.log"; then ok "posts to exact release"; else no "missing check endpoint"; fi
|
|
67
|
+
if grep -q 'status.*failed' "$dir/curl.log" && grep -q 'artifactUpload.*successful' "$dir/curl.log"; then
|
|
68
|
+
ok "keeps execution outcome separate from upload detail"
|
|
69
|
+
else
|
|
70
|
+
no "incorrect check payload"
|
|
71
|
+
fi
|
|
72
|
+
rm -rf "$dir"
|
|
73
|
+
|
|
74
|
+
dir=$(mktemp -d)
|
|
75
|
+
make_fixture "$dir"
|
|
76
|
+
RESOLVE_BODY='{"latest":{"id":"release-1","version":"REQ-100"}}' \
|
|
77
|
+
CHECK_STATUS=404 run_helper "$dir" "${base_args[@]}" >/dev/null 2>&1 && ok "tolerates older portal" || no "404 should be tolerant"
|
|
78
|
+
rm -rf "$dir"
|
|
79
|
+
|
|
80
|
+
dir=$(mktemp -d)
|
|
81
|
+
make_fixture "$dir"
|
|
82
|
+
if RESOLVE_BODY='{"latest":{"id":"release-1","version":"REQ-100"}}' \
|
|
83
|
+
CHECK_STATUS=500 CHECK_BODY='{"error":"failed"}' run_helper "$dir" "${base_args[@]}" >/dev/null 2>&1; then
|
|
84
|
+
no "500 should fail"
|
|
85
|
+
else
|
|
86
|
+
ok "fails on portal error"
|
|
87
|
+
fi
|
|
88
|
+
rm -rf "$dir"
|
|
89
|
+
|
|
90
|
+
if "$HELPER" "${base_args[@]/failed/not-a-status}" >/dev/null 2>&1; then
|
|
91
|
+
no "invalid status should fail"
|
|
92
|
+
else
|
|
93
|
+
ok "rejects invalid status"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
echo "=== report-release-check.sh: $PASS passed, $FAIL failed ==="
|
|
97
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -32,7 +32,8 @@ jobs:
|
|
|
32
32
|
# ──────────────────────────────────────────────
|
|
33
33
|
quality-gates:
|
|
34
34
|
name: Quality Gates
|
|
35
|
-
|
|
35
|
+
needs: [register-release]
|
|
36
|
+
if: ${{ always() && (github.event_name != 'pull_request' || !startsWith(github.head_ref, 'chore/close-out-')) && (github.event_name == 'pull_request' || needs.register-release.result == 'success') }}
|
|
36
37
|
runs-on: {{RUNNER}}
|
|
37
38
|
|
|
38
39
|
services:
|
|
@@ -44,6 +45,8 @@ jobs:
|
|
|
44
45
|
env:
|
|
45
46
|
{{DATABASE_ENV}}
|
|
46
47
|
{{APP_ENV}}
|
|
48
|
+
DEVAUDIT_BASE_URL_VAR: ${{ vars.DEVAUDIT_BASE_URL }}
|
|
49
|
+
DEVAUDIT_API_KEY: ${{ secrets.DEVAUDIT_API_KEY }}
|
|
47
50
|
|
|
48
51
|
steps:
|
|
49
52
|
- uses: actions/checkout@v6
|
|
@@ -54,6 +57,29 @@ jobs:
|
|
|
54
57
|
# tag each captured screenshot as feature vs regression.
|
|
55
58
|
fetch-depth: 0
|
|
56
59
|
|
|
60
|
+
- name: Start authoritative quality-gate cycle
|
|
61
|
+
if: github.event_name != 'pull_request' && github.ref_name == '{{INTEGRATION_BRANCH}}' && needs.register-release.outputs.version != 'skip'
|
|
62
|
+
run: |
|
|
63
|
+
BASE=""
|
|
64
|
+
if [ -f sdlc-config.json ]; then
|
|
65
|
+
BASE=$(jq -r '.devaudit.base_url // empty' sdlc-config.json 2>/dev/null || true)
|
|
66
|
+
fi
|
|
67
|
+
[ -n "$BASE" ] || BASE="$DEVAUDIT_BASE_URL_VAR"
|
|
68
|
+
[ -n "$BASE" ] || { echo "::warning::No DevAudit URL; cycle lifecycle disabled"; exit 0; }
|
|
69
|
+
echo "DEVAUDIT_BASE_URL=${BASE%/}" >> "$GITHUB_ENV"
|
|
70
|
+
chmod +x scripts/report-test-cycle.sh scripts/report-release-check.sh 2>/dev/null || true
|
|
71
|
+
bash scripts/report-test-cycle.sh start \
|
|
72
|
+
--project-slug {{PROJECT_SLUG}} \
|
|
73
|
+
--release "${{ needs.register-release.outputs.version }}" \
|
|
74
|
+
--sdlc-stage 2 --environment ci --cycle-kind quality_gate \
|
|
75
|
+
--provider github_actions --external-run-id "${{ github.run_id }}" \
|
|
76
|
+
--external-run-attempt "${{ github.run_attempt }}" \
|
|
77
|
+
--external-job-id "quality-gates" \
|
|
78
|
+
--idempotency-key "github:${{ github.repository }}:quality-gates.quality_gate:${{ github.run_id }}:${{ github.run_attempt }}:2:${{ needs.register-release.outputs.version }}" \
|
|
79
|
+
--commit-sha "${{ github.sha }}" --branch "${{ github.ref_name }}" \
|
|
80
|
+
--workflow-name "Quality Gates" \
|
|
81
|
+
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
|
82
|
+
|
|
57
83
|
# ── Cached installs (skip if already present on self-hosted runner) ──
|
|
58
84
|
|
|
59
85
|
- uses: actions/setup-node@v6
|
|
@@ -418,7 +444,7 @@ jobs:
|
|
|
418
444
|
# evidence — `status=failed` is itself the audit trail. `!cancelled()`
|
|
419
445
|
# still guards against partial state on operator-cancel.
|
|
420
446
|
# DevAudit-Installer#96.
|
|
421
|
-
if: ${{ always() &&
|
|
447
|
+
if: ${{ always() && github.ref_name == '{{INTEGRATION_BRANCH}}' && needs.register-release.result == 'success' }}
|
|
422
448
|
env:
|
|
423
449
|
DEVAUDIT_BASE_URL_VAR: ${{ vars.DEVAUDIT_BASE_URL }}
|
|
424
450
|
DEVAUDIT_API_KEY: ${{ secrets.DEVAUDIT_API_KEY }}
|
|
@@ -465,15 +491,12 @@ jobs:
|
|
|
465
491
|
bash scripts/report-test-cycle.sh start \
|
|
466
492
|
--project-slug {{PROJECT_SLUG}} \
|
|
467
493
|
--release "${{ needs.register-release.outputs.version }}" \
|
|
468
|
-
--sdlc-stage 2 \
|
|
469
|
-
--
|
|
470
|
-
--cycle-kind quality_gate \
|
|
471
|
-
--provider github_actions \
|
|
472
|
-
--external-run-id "${{ github.run_id }}" \
|
|
494
|
+
--sdlc-stage 2 --environment ci --cycle-kind quality_gate \
|
|
495
|
+
--provider github_actions --external-run-id "${{ github.run_id }}" \
|
|
473
496
|
--external-run-attempt "${{ github.run_attempt }}" \
|
|
497
|
+
--external-job-id "quality-gates" \
|
|
474
498
|
--idempotency-key "github:${{ github.repository }}:quality-gates.quality_gate:${{ github.run_id }}:${{ github.run_attempt }}:2:${{ needs.register-release.outputs.version }}" \
|
|
475
|
-
--commit-sha "${{ github.sha }}" \
|
|
476
|
-
--branch "${{ github.ref_name }}" \
|
|
499
|
+
--commit-sha "${{ github.sha }}" --branch "${{ github.ref_name }}" \
|
|
477
500
|
--workflow-name "Quality Gates" \
|
|
478
501
|
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
479
502
|
--output-file "$CYCLE_OUT"
|
|
@@ -882,27 +905,41 @@ jobs:
|
|
|
882
905
|
- name: Complete primary quality-gate cycle
|
|
883
906
|
if: always() && env.DEVAUDIT_BASE_URL != ''
|
|
884
907
|
run: |
|
|
885
|
-
case "${{
|
|
908
|
+
case "${{ needs.quality-gates.result }}" in
|
|
886
909
|
success) OUTCOME=passed ;;
|
|
887
910
|
cancelled) OUTCOME=cancelled ;;
|
|
888
911
|
*) OUTCOME=failed ;;
|
|
889
912
|
esac
|
|
890
|
-
chmod +x scripts/report-test-cycle.sh 2>/dev/null || true
|
|
913
|
+
chmod +x scripts/report-test-cycle.sh scripts/report-release-check.sh 2>/dev/null || true
|
|
891
914
|
bash scripts/report-test-cycle.sh complete \
|
|
892
915
|
--project-slug {{PROJECT_SLUG}} \
|
|
893
916
|
--release "${{ needs.register-release.outputs.version }}" \
|
|
894
917
|
--sdlc-stage 2 \
|
|
895
|
-
--environment
|
|
918
|
+
--environment ci \
|
|
896
919
|
--cycle-kind quality_gate \
|
|
897
920
|
--provider github_actions \
|
|
898
921
|
--external-run-id "${{ github.run_id }}" \
|
|
899
922
|
--external-run-attempt "${{ github.run_attempt }}" \
|
|
923
|
+
--external-job-id "quality-gates" \
|
|
900
924
|
--idempotency-key "github:${{ github.repository }}:quality-gates.quality_gate:${{ github.run_id }}:${{ github.run_attempt }}:2:${{ needs.register-release.outputs.version }}" \
|
|
901
925
|
--commit-sha "${{ github.sha }}" \
|
|
902
926
|
--branch "${{ github.ref_name }}" \
|
|
903
927
|
--workflow-name "Quality Gates" \
|
|
904
928
|
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
905
929
|
--outcome "$OUTCOME"
|
|
930
|
+
case "$OUTCOME" in
|
|
931
|
+
passed) CHECK_STATUS=successful ;;
|
|
932
|
+
*) CHECK_STATUS="$OUTCOME" ;;
|
|
933
|
+
esac
|
|
934
|
+
bash scripts/report-release-check.sh \
|
|
935
|
+
--project-slug {{PROJECT_SLUG}} \
|
|
936
|
+
--release "${{ needs.register-release.outputs.version }}" \
|
|
937
|
+
--check-key "quality-gates:${{ github.run_id }}:${{ github.run_attempt }}" \
|
|
938
|
+
--label "Quality Gates" --provider github_actions --status "$CHECK_STATUS" \
|
|
939
|
+
--external-run-id "${{ github.run_id }}" \
|
|
940
|
+
--external-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
|
941
|
+
--commit-sha "${{ github.sha }}" --branch "${{ github.ref_name }}" \
|
|
942
|
+
--details-json '{"executionSource":"needs.quality-gates.result","evidenceUploadJob":"${{ job.status }}"}'
|
|
906
943
|
|
|
907
944
|
- name: Summary
|
|
908
945
|
run: echo "Evidence uploaded for ${{ needs.register-release.outputs.version }} (UAT)"
|
|
@@ -768,6 +768,7 @@ jobs:
|
|
|
768
768
|
if: steps.resolve.outputs.skip != 'true' && steps.version.outputs.version != 'skip'
|
|
769
769
|
run: |
|
|
770
770
|
set -euo pipefail
|
|
771
|
+
chmod +x scripts/report-test-cycle.sh scripts/report-release-check.sh 2>/dev/null || true
|
|
771
772
|
DERIVED_RELEASE="${{ steps.version.outputs.version }}"
|
|
772
773
|
|
|
773
774
|
# Tier metadata for the portal (the operator filters/groups by
|
|
@@ -873,6 +874,7 @@ jobs:
|
|
|
873
874
|
--branch "${PRIOR_BRANCH}" \
|
|
874
875
|
--workflow-name "E2E Regression" \
|
|
875
876
|
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}" \
|
|
877
|
+
--started-at "${{ github.event.workflow_run.run_started_at }}" \
|
|
876
878
|
--output-file "$CYCLE_OUT"
|
|
877
879
|
. "$CYCLE_OUT"
|
|
878
880
|
rm -f "$CYCLE_OUT"
|
|
@@ -927,11 +929,15 @@ jobs:
|
|
|
927
929
|
REQ_FAILURES=$((REQ_FAILURES + 1))
|
|
928
930
|
fi
|
|
929
931
|
fi
|
|
930
|
-
|
|
931
|
-
REQ_OUTCOME=
|
|
932
|
-
|
|
933
|
-
REQ_OUTCOME=
|
|
934
|
-
|
|
932
|
+
case "${{ github.event.workflow_run.conclusion }}" in
|
|
933
|
+
success) REQ_OUTCOME=passed ;;
|
|
934
|
+
failure) REQ_OUTCOME=failed ;;
|
|
935
|
+
cancelled) REQ_OUTCOME=cancelled ;;
|
|
936
|
+
skipped) REQ_OUTCOME=skipped ;;
|
|
937
|
+
timed_out) REQ_OUTCOME=timed_out ;;
|
|
938
|
+
action_required) REQ_OUTCOME=action_required ;;
|
|
939
|
+
*) REQ_OUTCOME=unknown ;;
|
|
940
|
+
esac
|
|
935
941
|
bash scripts/report-test-cycle.sh complete \
|
|
936
942
|
--project-slug {{PROJECT_SLUG}} \
|
|
937
943
|
--release "${DERIVED_RELEASE}" \
|
|
@@ -946,8 +952,28 @@ jobs:
|
|
|
946
952
|
--branch "${PRIOR_BRANCH}" \
|
|
947
953
|
--workflow-name "E2E Regression" \
|
|
948
954
|
--workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}" \
|
|
949
|
-
--started-at "${
|
|
955
|
+
--started-at "${{ github.event.workflow_run.run_started_at }}" \
|
|
956
|
+
--completed-at "${{ github.event.workflow_run.updated_at }}" \
|
|
957
|
+
--outcome-reason "authoritative workflow_run conclusion: ${{ github.event.workflow_run.conclusion }}" \
|
|
950
958
|
--outcome "${REQ_OUTCOME}"
|
|
959
|
+
case "$REQ_OUTCOME" in
|
|
960
|
+
passed) CHECK_STATUS=successful ;;
|
|
961
|
+
*) CHECK_STATUS="$REQ_OUTCOME" ;;
|
|
962
|
+
esac
|
|
963
|
+
CHECK_DETAILS=$(jq -cn \
|
|
964
|
+
--arg conclusion "${{ github.event.workflow_run.conclusion }}" \
|
|
965
|
+
--argjson artifactUploadFailures "$REQ_FAILURES" \
|
|
966
|
+
'{executionSource:"workflow_run.conclusion",conclusion:$conclusion,artifactUploadFailures:$artifactUploadFailures}')
|
|
967
|
+
bash scripts/report-release-check.sh \
|
|
968
|
+
--project-slug {{PROJECT_SLUG}} --release "${DERIVED_RELEASE}" \
|
|
969
|
+
--check-key "e2e-regression:${{ github.event.workflow_run.id }}:${{ github.event.workflow_run.run_attempt }}:${REQ}" \
|
|
970
|
+
--label "E2E Regression (${REQ})" --provider github_actions --status "$CHECK_STATUS" \
|
|
971
|
+
--external-run-id "${{ github.event.workflow_run.id }}" \
|
|
972
|
+
--external-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}" \
|
|
973
|
+
--commit-sha "${{ github.event.workflow_run.head_sha }}" --branch "${PRIOR_BRANCH}" \
|
|
974
|
+
--started-at "${{ github.event.workflow_run.run_started_at }}" \
|
|
975
|
+
--completed-at "${{ github.event.workflow_run.updated_at }}" \
|
|
976
|
+
--details-json "$CHECK_DETAILS"
|
|
951
977
|
done
|
|
952
978
|
|
|
953
979
|
# Per-spec failure screenshots from test-results/ are NOT
|