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
106 changes: 101 additions & 5 deletions .github/scripts/select-shared-release-artifact.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ usage() {
[[ $# -ge 1 && $# -le 2 ]] || usage
output_file="$1"
max_wait_seconds="${2:-360}"
producer_max_wait_seconds="${PRODUCER_MAX_WAIT_SECONDS:-420}"
producer_artifact_grace_seconds="${PRODUCER_ARTIFACT_GRACE_SECONDS:-30}"
poll_seconds="${SELECTOR_POLL_SECONDS:-15}"

: "${GH_TOKEN:?GH_TOKEN must contain a short-lived Actions token}"
: "${GITHUB_REPOSITORY:?GITHUB_REPOSITORY must be set}"
Expand All @@ -21,10 +24,18 @@ max_wait_seconds="${2:-360}"
[[ "$GITHUB_SHA" =~ ^[0-9a-f]{40}$ ]] || usage
[[ "$GITHUB_PR_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] || usage
[[ "$max_wait_seconds" =~ ^[0-9]+$ ]] || usage
[[ "$producer_max_wait_seconds" =~ ^[0-9]+$ ]] || usage
[[ "$producer_artifact_grace_seconds" =~ ^[0-9]+$ ]] || usage
[[ "$poll_seconds" =~ ^[0-9]+$ ]] || usage

artifact_name="node-subtensor-release-$GITHUB_SHA"
workflow_path=.github/workflows/runtime-checks.yml
started=$(date -u +%s)
producer_completed_seen=
producer_run_id=
producer_job_status=
producer_job_conclusion=
last_producer_state=

write_miss() {
{
Expand All @@ -33,6 +44,28 @@ write_miss() {
} >> "$output_file"
}

find_latest_producer_run() {
local producer_runs
producer_runs=$(gh api \
-H 'Accept: application/vnd.github+json' \
"repos/$GITHUB_REPOSITORY/actions/runs?event=pull_request&head_sha=$GITHUB_PR_HEAD_SHA&per_page=100" \
2>/dev/null || true)
jq -er \
--arg repository_id "$GITHUB_REPOSITORY_ID" \
--arg sha "$GITHUB_PR_HEAD_SHA" \
--arg workflow_path "$workflow_path" '
[.workflow_runs[]
| select(.head_sha == $sha)
| select((.head_repository.id | tostring) == $repository_id)
| select(.path == $workflow_path)
| select(.event == "pull_request")
| select((.id | type) == "number" and .id > 0)]
| sort_by(.created_at)
| reverse
| (.[0].id // empty)
' <<< "$producer_runs" 2>/dev/null || true
}

while true; do
artifacts=$(gh api \
-H 'Accept: application/vnd.github+json' \
Expand Down Expand Up @@ -94,13 +127,76 @@ while true; do
)
fi

if [[ -z "$producer_run_id" ]]; then
producer_run_id=$(find_latest_producer_run)
fi

# Once discovered, latch the exact release-producing job. Transient API
# failures must not make us forget a producer and cross back to the shorter
# discovery timeout.
if [[ -n "$producer_run_id" ]]; then
producer_jobs=$(gh api \
-H 'Accept: application/vnd.github+json' \
"repos/$GITHUB_REPOSITORY/actions/runs/$producer_run_id/jobs?filter=latest&per_page=100" \
2>/dev/null || true)
producer_job=$(
jq -cer '
[.jobs[] | select(.name == "build release node")]
| sort_by(.started_at // .created_at)
| reverse
| .[0]
' <<< "$producer_jobs" 2>/dev/null || true
)
current_status=$(jq -r '.status // empty' <<< "$producer_job" 2>/dev/null || true)
if [[ -n "$current_status" ]]; then
producer_job_status=$current_status
producer_job_conclusion=$(jq -r '.conclusion // empty' <<< "$producer_job" 2>/dev/null || true)
fi
fi

producer_state=not-found
if [[ -n "$producer_run_id" ]]; then
producer_state=${producer_job_status:-job-pending}
[[ -z "$producer_job_conclusion" ]] || producer_state="$producer_state/$producer_job_conclusion"
fi
if [[ "$producer_state" != "$last_producer_state" ]]; then
echo "Runtime Checks release producer: $producer_state"
last_producer_state=$producer_state
fi

elapsed=$(($(date -u +%s) - started))
if (( elapsed >= max_wait_seconds )); then
if [[ "$producer_job_status" == completed && "$producer_job_conclusion" == success ]]; then
[[ -n "$producer_completed_seen" ]] || producer_completed_seen=$(date -u +%s)
completed_elapsed=$(($(date -u +%s) - producer_completed_seen))
if (( completed_elapsed >= producer_artifact_grace_seconds )); then
write_miss
echo "Runtime Checks release producer completed without a verified artifact after ${completed_elapsed}s of API propagation grace; using the local build fallback."
exit 0
fi
elif [[ "$producer_job_status" == completed ]]; then
replacement_run_id=$(find_latest_producer_run)
if [[ -n "$replacement_run_id" && "$replacement_run_id" != "$producer_run_id" ]]; then
echo "Runtime Checks replaced producer run $producer_run_id with $replacement_run_id."
producer_run_id=$replacement_run_id
producer_job_status=
producer_job_conclusion=
producer_completed_seen=
continue
fi
write_miss
echo "Runtime Checks release producer completed (${producer_job_conclusion:-unknown}); using the local build fallback."
exit 0
elif [[ -n "$producer_run_id" ]]; then
producer_completed_seen=
if (( elapsed >= producer_max_wait_seconds )); then
write_miss
echo "Runtime Checks release producer was still ${producer_job_status:-pending} after ${elapsed}s; using the local build fallback."
exit 0
fi
elif (( elapsed >= max_wait_seconds )); then
write_miss
echo "No exact-commit TypeScript release artifact appeared after ${elapsed}s; using the local build fallback."
echo "No exact-commit Runtime Checks producer appeared after ${elapsed}s; using the local build fallback."
exit 0
fi
remaining=$((max_wait_seconds - elapsed))
(( remaining > 10 )) || sleep "$remaining"
(( remaining <= 10 )) || sleep 10
sleep "$poll_seconds"
done
48 changes: 48 additions & 0 deletions .github/scripts/split-typescript-e2e-plan.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env bash

set -euo pipefail

if [[ $# -ne 1 ]]; then
echo "usage: $0 OUTPUT_FILE" >&2
exit 2
fi

output_file=$1
: "${STATE_MATRIX:?STATE_MATRIX must contain the trusted state matrix}"
: "${BUILD_MATRIX:?BUILD_MATRIX must contain the trusted build matrix}"

jq -e '
type == "object" and
(.include | type == "array") and
all(.include[]; type == "object" and (.binary == "fast" or .binary == "release"))
' <<< "$STATE_MATRIX" >/dev/null
jq -e '
type == "object" and
(.include | type == "array") and
all(.include[]; type == "object" and (.variant == "fast" or .variant == "release"))
' <<< "$BUILD_MATRIX" >/dev/null

fast_state_matrix=$(jq -c '{include: [.include[] | select(.binary == "fast")]}' <<< "$STATE_MATRIX")
release_state_matrix=$(jq -c '{include: [.include[] | select(.binary == "release")]}' <<< "$STATE_MATRIX")
fast_state_count=$(jq '.include | length' <<< "$fast_state_matrix")
release_state_count=$(jq '.include | length' <<< "$release_state_matrix")
fast_build=$(jq -r 'any(.include[]; .variant == "fast")' <<< "$BUILD_MATRIX")
release_build=$(jq -r 'any(.include[]; .variant == "release")' <<< "$BUILD_MATRIX")

if (( fast_state_count > 0 )) && [[ "$fast_build" != true ]]; then
echo "fast state jobs were planned without a fast binary build" >&2
exit 1
fi
if (( release_state_count > 0 )) && [[ "$release_build" != true ]]; then
echo "release state jobs were planned without a release binary build" >&2
exit 1
fi

{
echo "fast_state_count=$fast_state_count"
echo "fast_state_matrix=$fast_state_matrix"
echo "release_state_count=$release_state_count"
echo "release_state_matrix=$release_state_matrix"
echo "fast_build=$fast_build"
echo "release_build=$release_build"
} >> "$output_file"
15 changes: 15 additions & 0 deletions .github/scripts/test-classify-typescript-e2e-changes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,24 @@ fi
grep -Fq 'ref: ${{ github.event_name == '\''pull_request'\'' && github.event.pull_request.base.sha || github.sha }}' "$workflow"
grep -Fq '.trusted-e2e-filter/ts-tests/scripts/e2e-shard-plan.mjs' "$workflow"
grep -Fq '.proposed-e2e-plan/ts-tests/e2e-shards.json' "$workflow"
grep -Fq '.trusted-e2e-filter/.github/scripts/split-typescript-e2e-plan.sh' "$workflow"
grep -Fq '.proposed-e2e-plan/.github/scripts/split-typescript-e2e-plan.sh' "$workflow"
grep -Fq 'matrix: ${{ fromJSON(needs.changes.outputs.shield_matrix) }}' "$workflow"
grep -Fq 'matrix: ${{ fromJSON(needs.changes.outputs.fast_state_matrix) }}' "$workflow"
grep -Fq 'matrix: ${{ fromJSON(needs.changes.outputs.release_state_matrix) }}' "$workflow"
grep -Fq 'needs: [trusted-pr, changes, build-fast]' "$workflow"
grep -Fq 'needs: [trusted-pr, changes, build-release]' "$workflow"
grep -Fq 'needs: [trusted-pr, changes, select-release-artifact]' "$workflow"
grep -Fq 'needs: [trusted-pr, changes, build-fast, run-fast-e2e-tests, sharding-audit-fast]' "$workflow"
grep -Fq 'needs: [trusted-pr, changes, build-release, run-shield-tests, sharding-audit-release]' "$workflow"
grep -Fq 'fast_build: ${{ steps.lanes.outputs.fast_build }}' "$workflow"
grep -Fq 'release_build: ${{ steps.lanes.outputs.release_build }}' "$workflow"
grep -Fq 'name: Audit canonical unsharded ${{ matrix.test }}' "$workflow"
grep -Fq 'EVM_SELECTED: ${{ needs.changes.outputs.evm }}' "$workflow"
grep -Fq 'SHIELD_SELECTED: ${{ needs.changes.outputs.shield }}' "$workflow"
if grep -Eq '^ build:$' "$workflow"; then
echo "TypeScript E2E consumers must not depend on a combined build matrix." >&2
exit 1
fi

echo "typescript E2E change classifier tests passed"
Loading
Loading