From f038ec98f9e19cb1136abf6ad0741d3877ff06ce Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 12 Nov 2025 12:15:01 -0500 Subject: [PATCH 01/14] auto spec version bump --- .github/workflows/apply-benchmark-patch.yml | 25 +++- .github/workflows/label-triggers.yml | 109 ++++++++++++++- scripts/ci/rerun_pr_workflows.py | 147 ++++++++++++++++++++ 3 files changed, 279 insertions(+), 2 deletions(-) create mode 100755 scripts/ci/rerun_pr_workflows.py diff --git a/.github/workflows/apply-benchmark-patch.yml b/.github/workflows/apply-benchmark-patch.yml index 16b499bea6..90842324c2 100644 --- a/.github/workflows/apply-benchmark-patch.yml +++ b/.github/workflows/apply-benchmark-patch.yml @@ -8,7 +8,7 @@ on: permissions: contents: write pull-requests: write - actions: read # required to list & download artifacts across workflows + actions: write # re-trigger downstream workflows after applying the patch jobs: apply: @@ -23,6 +23,14 @@ jobs: ref: ${{ github.event.pull_request.head.ref }} fetch-depth: 0 + - name: Check out automation helpers from base branch + uses: actions/checkout@v4 + with: + repository: ${{ github.repository }} + ref: ${{ github.event.pull_request.base.ref }} + path: ci-tools + fetch-depth: 1 + - name: Install GitHub CLI run: | sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get update @@ -56,8 +64,10 @@ jobs: ls -la .bench_patch || true - name: Apply and commit patch + id: apply_patch run: | set -euo pipefail + echo "changes_applied=false" >> "$GITHUB_OUTPUT" if [ ! -d ".bench_patch" ]; then echo "No .bench_patch directory found after extraction." @@ -101,6 +111,19 @@ jobs: git commit -m "auto-update benchmark weights" git push origin "HEAD:${branch}" + new_sha=$(git rev-parse HEAD) + echo "changes_applied=true" >> "$GITHUB_OUTPUT" + echo "head_sha=${new_sha}" >> "$GITHUB_OUTPUT" + + - name: Re-run pull_request workflows (except Validate-Benchmarks) + if: steps.apply_patch.outputs.changes_applied == 'true' + run: python3 ci-tools/scripts/ci/rerun_pr_workflows.py + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + PR_HEAD_SHA: ${{ steps.apply_patch.outputs.head_sha }} + EXTRA_SKIP_WORKFLOWS: Apply-Benchmark-Patch - name: Remove apply-benchmark-patch label if: ${{ success() }} diff --git a/.github/workflows/label-triggers.yml b/.github/workflows/label-triggers.yml index 8c7803b2e3..b8239a74f5 100644 --- a/.github/workflows/label-triggers.yml +++ b/.github/workflows/label-triggers.yml @@ -10,6 +10,8 @@ on: permissions: issues: write pull-requests: write + contents: write + actions: write jobs: comment_on_breaking_change: @@ -25,4 +27,109 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, body: '@opentensor/cerebrum / @opentensor/gyrus / @opentensor/cortex breaking change detected! Please prepare accordingly!' - }) \ No newline at end of file + }) + + bump_spec_version: + if: ${{ github.event.label.name == 'bump-spec-verison' }} + runs-on: ubuntu-latest + steps: + - name: Check out PR branch + uses: actions/checkout@v4 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + fetch-depth: 0 + + - name: Check out automation helpers from base branch + uses: actions/checkout@v4 + with: + repository: ${{ github.repository }} + ref: ${{ github.event.pull_request.base.ref }} + path: ci-tools + fetch-depth: 1 + + - name: Bump spec_version + id: bump_spec + run: | + set -euo pipefail + python3 <<'PY' + import os + import pathlib + import re + + path = pathlib.Path("runtime/src/lib.rs") + content = path.read_text(encoding="utf-8") + + pattern = re.compile(r"(spec_version:\s*)(\d+)") + match = pattern.search(content) + if not match: + raise SystemExit("spec_version field not found in runtime/src/lib.rs") + + old_value = int(match.group(2)) + new_value = old_value + 1 + updated = content[: match.start(2)] + str(new_value) + content[match.end(2) :] + path.write_text(updated, encoding="utf-8") + print(f"Bumped spec_version from {old_value} to {new_value}") + + output_path = os.environ["GITHUB_OUTPUT"] + with open(output_path, "a", encoding="utf-8") as handle: + handle.write(f"spec_version={new_value}\\n") + PY + + - name: Commit spec_version bump + id: commit_spec + run: | + set -euo pipefail + echo "changes_made=false" >> "$GITHUB_OUTPUT" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add runtime/src/lib.rs + + if git diff --cached --quiet; then + echo "No spec_version updates to commit." + exit 0 + fi + + version="${{ steps.bump_spec.outputs.spec_version }}" + if [ -z "$version" ]; then + version="(unknown)" + fi + + git commit -m "chore: bump spec_version to ${version}" + branch=$(git symbolic-ref --quiet --short HEAD || true) + if [ -z "$branch" ]; then + echo "Unable to determine branch name for push." >&2 + exit 1 + fi + git push origin "HEAD:${branch}" + head_sha=$(git rev-parse HEAD) + echo "changes_made=true" >> "$GITHUB_OUTPUT" + echo "head_sha=${head_sha}" >> "$GITHUB_OUTPUT" + + - name: Re-run pull_request workflows (except Validate-Benchmarks) + if: steps.commit_spec.outputs.changes_made == 'true' + run: python3 ci-tools/scripts/ci/rerun_pr_workflows.py + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + PR_HEAD_SHA: ${{ steps.commit_spec.outputs.head_sha }} + + - name: Remove bump-spec-verison label + if: ${{ success() }} + uses: actions/github-script@v6 + with: + script: | + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'bump-spec-verison' + }) + } catch (error) { + if (error.status !== 404) { + throw error + } + } diff --git a/scripts/ci/rerun_pr_workflows.py b/scripts/ci/rerun_pr_workflows.py new file mode 100755 index 0000000000..8a4e82fe69 --- /dev/null +++ b/scripts/ci/rerun_pr_workflows.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +"""Re-run the latest pull_request workflow runs for a PR.""" +from __future__ import annotations + +import json +import os +import sys +import urllib.error +import urllib.request +from typing import Dict, List, Optional, Set + +DEFAULT_SKIP_WORKFLOWS = {"Validate-Benchmarks", "Label Triggers"} +PER_PAGE = 100 +MAX_PAGES = 10 + + +def env(name: str, required: bool = True) -> str: + value = os.environ.get(name) + if required and not value: + print(f"Missing required environment variable: {name}", file=sys.stderr) + sys.exit(1) + return value.strip() if isinstance(value, str) else value + + +def github_request(url: str, token: str, method: str = "GET", payload: Optional[Dict] = None) -> Dict: + data: Optional[bytes] = None + if payload is not None: + data = json.dumps(payload).encode("utf-8") + request = urllib.request.Request(url, data=data, method=method) + request.add_header("Authorization", f"Bearer {token}") + request.add_header("Accept", "application/vnd.github+json") + if data: + request.add_header("Content-Type", "application/json") + try: + with urllib.request.urlopen(request, timeout=30) as response: + if response.status == 204: + return {} + body = response.read().decode("utf-8") + return json.loads(body) + except urllib.error.HTTPError as exc: + body = exc.read().decode("utf-8", errors="ignore") + print(f"GitHub API error ({exc.code}) for {url}:\n{body}", file=sys.stderr) + raise + + +def collect_runs( + *, + repo: str, + token: str, + pr_number: int, + skip_names: Set[str], + target_head: Optional[str] = None, +) -> List[Dict]: + runs: List[Dict] = [] + seen_workflows: Set[int] = set() + page = 1 + + while page <= MAX_PAGES: + url = ( + f"https://api.github.com/repos/{repo}/actions/runs" + f"?event=pull_request&per_page={PER_PAGE}&page={page}" + ) + payload = github_request(url, token) + batch = payload.get("workflow_runs", []) + if not batch: + break + + for run in batch: + if run.get("event") != "pull_request": + continue + + prs = run.get("pull_requests") or [] + pr_numbers = {item.get("number") for item in prs if item.get("number") is not None} + if pr_number not in pr_numbers: + continue + + if target_head and run.get("head_sha") != target_head: + continue + + name = run.get("name") or "" + if name in skip_names: + continue + + workflow_id = run.get("workflow_id") + if workflow_id in seen_workflows: + continue + + seen_workflows.add(workflow_id) + runs.append(run) + + if len(batch) < PER_PAGE: + break + page += 1 + + return runs + + +def main() -> None: + repo = env("GITHUB_REPOSITORY") + token = env("GITHUB_TOKEN") + pr_number_raw = env("PR_NUMBER") + try: + pr_number = int(pr_number_raw) + except ValueError: + print(f"Invalid PR_NUMBER value: {pr_number_raw}", file=sys.stderr) + sys.exit(1) + + head_sha = os.environ.get("PR_HEAD_SHA", "").strip() + + extra_skip = { + value.strip() + for value in os.environ.get("EXTRA_SKIP_WORKFLOWS", "").split(",") + if value.strip() + } + skip_names = DEFAULT_SKIP_WORKFLOWS | extra_skip + + runs = [] + if head_sha: + runs = collect_runs(repo=repo, token=token, pr_number=pr_number, skip_names=skip_names, target_head=head_sha) + if not runs: + print( + f"No workflow runs found for PR #{pr_number} with head {head_sha}. " + "Falling back to the latest runs for this PR.", + file=sys.stderr, + ) + + if not runs: + runs = collect_runs(repo=repo, token=token, pr_number=pr_number, skip_names=skip_names) + + if not runs: + print(f"No pull_request workflow runs found for PR #{pr_number}; nothing to re-run.") + return + + print(f"Re-running {len(runs)} workflow(s) for PR #{pr_number}.") + for run in runs: + run_id = run.get("id") + name = run.get("name") + run_number = run.get("run_number") + if run_id is None: + continue + print(f" • {name} (run #{run_number})") + rerun_url = f"https://api.github.com/repos/{repo}/actions/runs/{run_id}/rerun" + github_request(rerun_url, token, method="POST", payload={}) + + +if __name__ == "__main__": + main() From 712de637288e4e517881f244ca2736eeb119875e Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 12 Nov 2025 13:54:10 -0500 Subject: [PATCH 02/14] more things on ubuntu-latest --- .github/workflows/hotfixes.yml | 2 +- .github/workflows/label-triggers.yml | 2 +- .github/workflows/require-clean-merges.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/hotfixes.yml b/.github/workflows/hotfixes.yml index 7fcf28efb6..83de900fcd 100644 --- a/.github/workflows/hotfixes.yml +++ b/.github/workflows/hotfixes.yml @@ -10,7 +10,7 @@ permissions: jobs: handle-hotfix-pr: - runs-on: [self-hosted, type-ccx13] + runs-on: ubuntu-latest steps: - name: Check if PR is a hotfix into `main` if: > diff --git a/.github/workflows/label-triggers.yml b/.github/workflows/label-triggers.yml index b8239a74f5..47e386d5e2 100644 --- a/.github/workflows/label-triggers.yml +++ b/.github/workflows/label-triggers.yml @@ -15,7 +15,7 @@ permissions: jobs: comment_on_breaking_change: - runs-on: [self-hosted, type-ccx13] + runs-on: ubuntu-latest steps: - name: Check if 'breaking change' label is added if: github.event.label.name == 'breaking-change' diff --git a/.github/workflows/require-clean-merges.yml b/.github/workflows/require-clean-merges.yml index dd7a8829e7..a2f87ceee0 100644 --- a/.github/workflows/require-clean-merges.yml +++ b/.github/workflows/require-clean-merges.yml @@ -9,7 +9,7 @@ on: jobs: assert-clean-merges: - runs-on: [self-hosted, type-ccx13] + runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v4 @@ -34,7 +34,7 @@ jobs: else echo "MERGE_BRANCHES=devnet-ready devnet testnet main" >> $GITHUB_ENV fi - + - name: Add Fork Remote and Fetch PR Branch if: github.event.pull_request.head.repo.fork == true run: | From ea347a261caf421597a9a9c520509f954651af4d Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 12 Nov 2025 18:17:22 -0500 Subject: [PATCH 03/14] fix spelling --- .github/workflows/label-triggers.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/label-triggers.yml b/.github/workflows/label-triggers.yml index 47e386d5e2..4618f3a8df 100644 --- a/.github/workflows/label-triggers.yml +++ b/.github/workflows/label-triggers.yml @@ -30,7 +30,7 @@ jobs: }) bump_spec_version: - if: ${{ github.event.label.name == 'bump-spec-verison' }} + if: ${{ github.event.label.name == 'bump-spec-version' }} runs-on: ubuntu-latest steps: - name: Check out PR branch @@ -116,7 +116,7 @@ jobs: PR_NUMBER: ${{ github.event.pull_request.number }} PR_HEAD_SHA: ${{ steps.commit_spec.outputs.head_sha }} - - name: Remove bump-spec-verison label + - name: Remove bump-spec-version label if: ${{ success() }} uses: actions/github-script@v6 with: @@ -126,7 +126,7 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - name: 'bump-spec-verison' + name: 'bump-spec-version' }) } catch (error) { if (error.status !== 404) { From 6ea61e74893ca65f0a8024ec6a176ce45e3d7e25 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 12 Nov 2025 23:21:54 +0000 Subject: [PATCH 04/14] chore: bump spec_version to 347\n --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index f6843c50ee..9ece1dd025 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 346, + spec_version: 347, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 574ce41aaf9b464ba9d1b5c352d055d1f21f3587 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 12 Nov 2025 18:30:56 -0500 Subject: [PATCH 05/14] tweak --- .github/workflows/label-triggers.yml | 8 ++- .../rerun_pr_workflows.cpython-312.pyc | Bin 0 -> 9717 bytes scripts/ci/rerun_pr_workflows.py | 51 ++++++++++++++++-- 3 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 scripts/ci/__pycache__/rerun_pr_workflows.cpython-312.pyc diff --git a/.github/workflows/label-triggers.yml b/.github/workflows/label-triggers.yml index 4618f3a8df..7f452070af 100644 --- a/.github/workflows/label-triggers.yml +++ b/.github/workflows/label-triggers.yml @@ -73,7 +73,7 @@ jobs: output_path = os.environ["GITHUB_OUTPUT"] with open(output_path, "a", encoding="utf-8") as handle: - handle.write(f"spec_version={new_value}\\n") + handle.write(f"spec_version={new_value}\n") PY - name: Commit spec_version bump @@ -92,11 +92,13 @@ jobs: fi version="${{ steps.bump_spec.outputs.spec_version }}" + version="${version//$'\n'/}" + version="${version//$'\r'/}" if [ -z "$version" ]; then version="(unknown)" fi - git commit -m "chore: bump spec_version to ${version}" + git commit -m "chore: bump spec version to ${version}" branch=$(git symbolic-ref --quiet --short HEAD || true) if [ -z "$branch" ]; then echo "Unable to determine branch name for push." >&2 @@ -106,6 +108,7 @@ jobs: head_sha=$(git rev-parse HEAD) echo "changes_made=true" >> "$GITHUB_OUTPUT" echo "head_sha=${head_sha}" >> "$GITHUB_OUTPUT" + echo "head_ref=${branch}" >> "$GITHUB_OUTPUT" - name: Re-run pull_request workflows (except Validate-Benchmarks) if: steps.commit_spec.outputs.changes_made == 'true' @@ -115,6 +118,7 @@ jobs: GITHUB_REPOSITORY: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number }} PR_HEAD_SHA: ${{ steps.commit_spec.outputs.head_sha }} + PR_HEAD_REF: ${{ steps.commit_spec.outputs.head_ref }} - name: Remove bump-spec-version label if: ${{ success() }} diff --git a/scripts/ci/__pycache__/rerun_pr_workflows.cpython-312.pyc b/scripts/ci/__pycache__/rerun_pr_workflows.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29ac7818da2cbaa389d3694eef133608112057e7 GIT binary patch literal 9717 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 literal 0 HcmV?d00001 diff --git a/scripts/ci/rerun_pr_workflows.py b/scripts/ci/rerun_pr_workflows.py index 8a4e82fe69..741285bd5f 100755 --- a/scripts/ci/rerun_pr_workflows.py +++ b/scripts/ci/rerun_pr_workflows.py @@ -12,6 +12,12 @@ DEFAULT_SKIP_WORKFLOWS = {"Validate-Benchmarks", "Label Triggers"} PER_PAGE = 100 MAX_PAGES = 10 +DISPATCH_UNSUPPORTED_CODES = {404, 422} + + +class WorkflowDispatchNotSupported(Exception): + """Raised when a workflow cannot be triggered via workflow_dispatch.""" + pass def env(name: str, required: bool = True) -> str: @@ -43,6 +49,31 @@ def github_request(url: str, token: str, method: str = "GET", payload: Optional[ raise +def dispatch_workflow(*, repo: str, token: str, workflow_id: int, ref: str) -> None: + if not ref: + raise WorkflowDispatchNotSupported("Missing ref for workflow_dispatch.") + url = f"https://api.github.com/repos/{repo}/actions/workflows/{workflow_id}/dispatches" + payload = json.dumps({"ref": ref}).encode("utf-8") + request = urllib.request.Request(url, data=payload, method="POST") + request.add_header("Authorization", f"Bearer {token}") + request.add_header("Accept", "application/vnd.github+json") + request.add_header("Content-Type", "application/json") + try: + with urllib.request.urlopen(request, timeout=30): + return + except urllib.error.HTTPError as exc: + if exc.code in DISPATCH_UNSUPPORTED_CODES: + raise WorkflowDispatchNotSupported from exc + body = exc.read().decode("utf-8", errors="ignore") + print(f"GitHub API error ({exc.code}) for {url}:\n{body}", file=sys.stderr) + raise + + +def rerun_workflow(*, repo: str, token: str, run_id: int) -> None: + rerun_url = f"https://api.github.com/repos/{repo}/actions/runs/{run_id}/rerun" + github_request(rerun_url, token, method="POST", payload={}) + + def collect_runs( *, repo: str, @@ -106,6 +137,7 @@ def main() -> None: sys.exit(1) head_sha = os.environ.get("PR_HEAD_SHA", "").strip() + head_ref = os.environ.get("PR_HEAD_REF", "").strip() extra_skip = { value.strip() @@ -131,16 +163,27 @@ def main() -> None: print(f"No pull_request workflow runs found for PR #{pr_number}; nothing to re-run.") return - print(f"Re-running {len(runs)} workflow(s) for PR #{pr_number}.") + print(f"Triggering {len(runs)} workflow(s) for PR #{pr_number}.") for run in runs: run_id = run.get("id") name = run.get("name") run_number = run.get("run_number") + workflow_id = run.get("workflow_id") if run_id is None: continue - print(f" • {name} (run #{run_number})") - rerun_url = f"https://api.github.com/repos/{repo}/actions/runs/{run_id}/rerun" - github_request(rerun_url, token, method="POST", payload={}) + ref = head_ref or (run.get("head_branch") or "") + dispatched = False + if workflow_id is not None and ref: + try: + dispatch_workflow(repo=repo, token=token, workflow_id=workflow_id, ref=ref) + print(f" • {name} dispatched via workflow_dispatch on '{ref}'") + dispatched = True + except WorkflowDispatchNotSupported: + print(f" • {name} does not support workflow_dispatch; re-running run #{run_number}.") + + if not dispatched: + print(f" • {name} (run #{run_number}) rerun requested.") + rerun_workflow(repo=repo, token=token, run_id=run_id) if __name__ == "__main__": From b05ec3a1d486eaf5bc142b477181be4ae5dd07f4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 12 Nov 2025 23:36:52 +0000 Subject: [PATCH 06/14] chore: bump spec version to 348 --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 9ece1dd025..2171708685 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 347, + spec_version: 348, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From e75f5a1446c60d0acc86449c7e58a816748e73d4 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 12 Nov 2025 18:52:45 -0500 Subject: [PATCH 07/14] fix? --- .github/workflows/apply-benchmark-patch.yml | 1 + .github/workflows/cargo-audit.yml | 1 + .github/workflows/check-devnet.yml | 1 + .github/workflows/check-docker.yml | 1 + .github/workflows/check-finney.yml | 1 + .github/workflows/check-testnet.yml | 1 + .github/workflows/hotfixes.yml | 1 + .github/workflows/label-triggers.yml | 12 ++++++++++-- .github/workflows/require-clean-merges.yml | 1 + .github/workflows/try-runtime.yml | 1 + 10 files changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/apply-benchmark-patch.yml b/.github/workflows/apply-benchmark-patch.yml index 90842324c2..825c52a67c 100644 --- a/.github/workflows/apply-benchmark-patch.yml +++ b/.github/workflows/apply-benchmark-patch.yml @@ -4,6 +4,7 @@ name: Apply-Benchmark-Patch on: pull_request: types: [labeled] + workflow_dispatch: permissions: contents: write diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml index 9bd9795f17..322e5ff823 100644 --- a/.github/workflows/cargo-audit.yml +++ b/.github/workflows/cargo-audit.yml @@ -6,6 +6,7 @@ on: - unlabeled - synchronize - opened + workflow_dispatch: concurrency: group: cargo-audit-${{ github.ref }} cancel-in-progress: true diff --git a/.github/workflows/check-devnet.yml b/.github/workflows/check-devnet.yml index 8d3db55001..ad6e908394 100644 --- a/.github/workflows/check-devnet.yml +++ b/.github/workflows/check-devnet.yml @@ -4,6 +4,7 @@ on: pull_request: branches: [devnet, devnet-ready] types: [labeled, unlabeled, synchronize, opened] + workflow_dispatch: concurrency: group: check-devnet-${{ github.ref }} diff --git a/.github/workflows/check-docker.yml b/.github/workflows/check-docker.yml index da5054fd6d..a729a6f4e5 100644 --- a/.github/workflows/check-docker.yml +++ b/.github/workflows/check-docker.yml @@ -2,6 +2,7 @@ name: Build Docker Image on: pull_request: + workflow_dispatch: concurrency: group: check-docker-${{ github.ref }} diff --git a/.github/workflows/check-finney.yml b/.github/workflows/check-finney.yml index 6b056ef97e..50933f43c0 100644 --- a/.github/workflows/check-finney.yml +++ b/.github/workflows/check-finney.yml @@ -4,6 +4,7 @@ on: pull_request: branches: [finney, main] types: [labeled, unlabeled, synchronize, opened] + workflow_dispatch: concurrency: group: check-finney-${{ github.ref }} diff --git a/.github/workflows/check-testnet.yml b/.github/workflows/check-testnet.yml index 219d99051f..40864e2965 100644 --- a/.github/workflows/check-testnet.yml +++ b/.github/workflows/check-testnet.yml @@ -4,6 +4,7 @@ on: pull_request: branches: [testnet, testnet-ready] types: [labeled, unlabeled, synchronize, opened] + workflow_dispatch: concurrency: group: check-testnet-${{ github.ref }} diff --git a/.github/workflows/hotfixes.yml b/.github/workflows/hotfixes.yml index 83de900fcd..64c3e2996a 100644 --- a/.github/workflows/hotfixes.yml +++ b/.github/workflows/hotfixes.yml @@ -3,6 +3,7 @@ name: Handle Hotfix PRs on: pull_request: types: [opened] + workflow_dispatch: permissions: pull-requests: write diff --git a/.github/workflows/label-triggers.yml b/.github/workflows/label-triggers.yml index 7f452070af..d5aec4655a 100644 --- a/.github/workflows/label-triggers.yml +++ b/.github/workflows/label-triggers.yml @@ -6,6 +6,7 @@ on: - unlabeled - synchronize - opened + workflow_dispatch: permissions: issues: write @@ -30,7 +31,7 @@ jobs: }) bump_spec_version: - if: ${{ github.event.label.name == 'bump-spec-version' }} + if: ${{ github.event.action == 'labeled' && github.event.label.name == 'bump-spec-version' }} runs-on: ubuntu-latest steps: - name: Check out PR branch @@ -112,7 +113,14 @@ jobs: - name: Re-run pull_request workflows (except Validate-Benchmarks) if: steps.commit_spec.outputs.changes_made == 'true' - run: python3 ci-tools/scripts/ci/rerun_pr_workflows.py + run: | + set -euo pipefail + script_path="scripts/ci/rerun_pr_workflows.py" + if [ ! -f "$script_path" ]; then + script_path="ci-tools/scripts/ci/rerun_pr_workflows.py" + fi + echo "Using rerun helper at $script_path" + python3 "$script_path" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} diff --git a/.github/workflows/require-clean-merges.yml b/.github/workflows/require-clean-merges.yml index a2f87ceee0..9227647aee 100644 --- a/.github/workflows/require-clean-merges.yml +++ b/.github/workflows/require-clean-merges.yml @@ -6,6 +6,7 @@ on: - devnet-ready - devnet - testnet + workflow_dispatch: jobs: assert-clean-merges: diff --git a/.github/workflows/try-runtime.yml b/.github/workflows/try-runtime.yml index 98fa613d6a..f4ec8a11a1 100644 --- a/.github/workflows/try-runtime.yml +++ b/.github/workflows/try-runtime.yml @@ -2,6 +2,7 @@ name: Try Runtime on: pull_request: + workflow_dispatch: concurrency: group: try-runtime-${{ github.ref }} From ee2755f6ff23a98614c7f981ec7ba00ed738784e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 12 Nov 2025 23:55:14 +0000 Subject: [PATCH 08/14] chore: bump spec version to 349 --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 2171708685..8f46d2d8e2 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 348, + spec_version: 349, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From f27173c60855ff36e78fcda1d3a2c5cc09e14e95 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 12 Nov 2025 19:07:20 -0500 Subject: [PATCH 09/14] fix again --- .github/workflows/require-clean-merges.yml | 79 +++++++++++++++++++--- scripts/ci/rerun_pr_workflows.py | 24 ++++++- 2 files changed, 90 insertions(+), 13 deletions(-) diff --git a/.github/workflows/require-clean-merges.yml b/.github/workflows/require-clean-merges.yml index 9227647aee..c14c6ebdbd 100644 --- a/.github/workflows/require-clean-merges.yml +++ b/.github/workflows/require-clean-merges.yml @@ -7,6 +7,10 @@ on: - devnet - testnet workflow_dispatch: + inputs: + pr-number: + description: "Pull request number to check when running manually" + required: true jobs: assert-clean-merges: @@ -17,11 +21,64 @@ jobs: with: fetch-depth: 0 # Ensures we get all branches for merging + - name: Gather PR metadata + id: gather-pr + env: + EVENT_PR_NUMBER: ${{ github.event.pull_request.number }} + DISPATCH_PR_NUMBER: ${{ inputs.pr-number }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + run: | + set -euo pipefail + python3 <<'PY' + import json + import os + import sys + import urllib.request + + pr_number = os.environ.get("EVENT_PR_NUMBER") or os.environ.get("DISPATCH_PR_NUMBER") or "" + if not pr_number: + print("Unable to determine PR number.", file=sys.stderr) + sys.exit(1) + + repo = os.environ["GITHUB_REPOSITORY"] + token = os.environ.get("GITHUB_TOKEN") + req = urllib.request.Request(f"https://api.github.com/repos/{repo}/pulls/{pr_number}") + req.add_header("Accept", "application/vnd.github+json") + if token: + req.add_header("Authorization", f"Bearer {token}") + + with urllib.request.urlopen(req, timeout=30) as resp: + payload = json.loads(resp.read().decode("utf-8")) + + base_ref = payload["base"]["ref"] + head_ref = payload["head"]["ref"] + head_repo = payload["head"].get("repo") or {} + is_fork = bool(head_repo.get("fork")) + clone_url = head_repo.get("clone_url") or "" + + env_path = os.environ["GITHUB_ENV"] + with open(env_path, "a", encoding="utf-8") as env_file: + env_file.write(f"PR_NUMBER={pr_number}\n") + env_file.write(f"PR_BASE_REF={base_ref}\n") + env_file.write(f"PR_HEAD_REF={head_ref}\n") + env_file.write(f"PR_HEAD_IS_FORK={'true' if is_fork else 'false'}\n") + env_file.write(f"PR_HEAD_CLONE_URL={clone_url}\n") + + output_path = os.environ["GITHUB_OUTPUT"] + with open(output_path, "a", encoding="utf-8") as out: + out.write(f"pr-number={pr_number}\n") + out.write(f"base-ref={base_ref}\n") + out.write(f"head-ref={head_ref}\n") + out.write(f"is-fork={'true' if is_fork else 'false'}\n") + out.write(f"fork-clone-url={clone_url}\n") + PY + - name: Determine Target Branch and Set Merge List id: set-merge-branches run: | - TARGET_BRANCH="${{ github.event.pull_request.base.ref }}" - PR_BRANCH="${{ github.event.pull_request.head.ref }}" + TARGET_BRANCH="${{ steps.gather-pr.outputs.base-ref }}" + PR_BRANCH="${{ steps.gather-pr.outputs.head-ref }}" echo "PR_BRANCH=$PR_BRANCH" >> $GITHUB_ENV if [[ "$TARGET_BRANCH" == "devnet-ready" ]]; then @@ -37,21 +94,23 @@ jobs: fi - name: Add Fork Remote and Fetch PR Branch - if: github.event.pull_request.head.repo.fork == true + if: steps.gather-pr.outputs.is-fork == 'true' run: | - PR_BRANCH="${{ github.event.pull_request.head.ref }}" - PR_FORK="${{ github.event.pull_request.head.repo.clone_url }}" - git remote add fork $PR_FORK - git fetch --no-tags --prune fork $PR_BRANCH + PR_BRANCH="${{ steps.gather-pr.outputs.head-ref }}" + PR_FORK="${{ steps.gather-pr.outputs.fork-clone-url }}" + git remote remove fork 2>/dev/null || true + git remote add fork "$PR_FORK" + git fetch --no-tags --prune fork "$PR_BRANCH" - name: Check Merge Cleanliness run: | - TARGET_BRANCH="${{ github.event.pull_request.base.ref }}" - PR_BRANCH="${{ github.event.pull_request.head.ref }}" + TARGET_BRANCH="${{ steps.gather-pr.outputs.base-ref }}" + PR_BRANCH="${{ steps.gather-pr.outputs.head-ref }}" + IS_FORK="${{ steps.gather-pr.outputs.is-fork }}" echo "Fetching all branches..." git fetch --all --prune - if [[ "${{github.event.pull_request.head.repo.fork}}" == "true" ]]; then + if [[ "$IS_FORK" == "true" ]]; then PR_BRANCH_REF="fork/$PR_BRANCH" echo "Using fork reference: $PR_BRANCH_REF" else diff --git a/scripts/ci/rerun_pr_workflows.py b/scripts/ci/rerun_pr_workflows.py index 741285bd5f..1bbac1529c 100755 --- a/scripts/ci/rerun_pr_workflows.py +++ b/scripts/ci/rerun_pr_workflows.py @@ -49,11 +49,21 @@ def github_request(url: str, token: str, method: str = "GET", payload: Optional[ raise -def dispatch_workflow(*, repo: str, token: str, workflow_id: int, ref: str) -> None: +def dispatch_workflow( + *, + repo: str, + token: str, + workflow_id: int, + ref: str, + inputs: Optional[Dict[str, str]] = None, +) -> None: if not ref: raise WorkflowDispatchNotSupported("Missing ref for workflow_dispatch.") url = f"https://api.github.com/repos/{repo}/actions/workflows/{workflow_id}/dispatches" - payload = json.dumps({"ref": ref}).encode("utf-8") + body: Dict[str, object] = {"ref": ref} + if inputs: + body["inputs"] = inputs + payload = json.dumps(body).encode("utf-8") request = urllib.request.Request(url, data=payload, method="POST") request.add_header("Authorization", f"Bearer {token}") request.add_header("Accept", "application/vnd.github+json") @@ -146,6 +156,8 @@ def main() -> None: } skip_names = DEFAULT_SKIP_WORKFLOWS | extra_skip + dispatch_inputs = {"pr-number": str(pr_number)} + runs = [] if head_sha: runs = collect_runs(repo=repo, token=token, pr_number=pr_number, skip_names=skip_names, target_head=head_sha) @@ -175,7 +187,13 @@ def main() -> None: dispatched = False if workflow_id is not None and ref: try: - dispatch_workflow(repo=repo, token=token, workflow_id=workflow_id, ref=ref) + dispatch_workflow( + repo=repo, + token=token, + workflow_id=workflow_id, + ref=ref, + inputs=dispatch_inputs, + ) print(f" • {name} dispatched via workflow_dispatch on '{ref}'") dispatched = True except WorkflowDispatchNotSupported: From bba3086d04f41114429399f60591cf5da22a91c7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 13 Nov 2025 00:09:28 +0000 Subject: [PATCH 10/14] chore: bump spec version to 350 --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 8f46d2d8e2..e5c733d7ed 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 349, + spec_version: 350, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 70328e6a0656425a60df417101e1a14277041122 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 12 Nov 2025 19:16:33 -0500 Subject: [PATCH 11/14] fix again --- scripts/ci/rerun_pr_workflows.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/ci/rerun_pr_workflows.py b/scripts/ci/rerun_pr_workflows.py index 1bbac1529c..02c34a674d 100755 --- a/scripts/ci/rerun_pr_workflows.py +++ b/scripts/ci/rerun_pr_workflows.py @@ -81,7 +81,24 @@ def dispatch_workflow( def rerun_workflow(*, repo: str, token: str, run_id: int) -> None: rerun_url = f"https://api.github.com/repos/{repo}/actions/runs/{run_id}/rerun" - github_request(rerun_url, token, method="POST", payload={}) + request = urllib.request.Request( + rerun_url, + data=json.dumps({}).encode("utf-8"), + method="POST", + ) + request.add_header("Authorization", f"Bearer {token}") + request.add_header("Accept", "application/vnd.github+json") + request.add_header("Content-Type", "application/json") + try: + with urllib.request.urlopen(request, timeout=30): + return + except urllib.error.HTTPError as exc: + body = exc.read().decode("utf-8", errors="ignore") + if exc.code == 403 and "already running" in body.lower(): + print(f" Run {run_id} is already in progress; skipping rerun request.") + return + print(f"GitHub API error ({exc.code}) for {rerun_url}:\n{body}", file=sys.stderr) + raise def collect_runs( From 8141468fd5a5bc76cc865f59cd3f19f34f63c41c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 13 Nov 2025 00:22:33 +0000 Subject: [PATCH 12/14] chore: bump spec version to 351 --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index e5c733d7ed..11d3487f33 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 350, + spec_version: 351, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 8ab8c039dd72f7ef15ff81be72fbe6004c41c2c2 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 12 Nov 2025 19:41:00 -0500 Subject: [PATCH 13/14] cancel --- .../rerun_pr_workflows.cpython-312.pyc | Bin 9717 -> 12998 bytes scripts/ci/rerun_pr_workflows.py | 26 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/scripts/ci/__pycache__/rerun_pr_workflows.cpython-312.pyc b/scripts/ci/__pycache__/rerun_pr_workflows.cpython-312.pyc index 29ac7818da2cbaa389d3694eef133608112057e7..7f508e0aa81e0dab3efda36fae09bbf3ca4241de 100644 GIT binary patch delta 4328 zcmd5)Qm*XjGBnWjUYiMZ8Zi>q`$F+ZKg|HNx_(j{=y!i-`Etdpqa3F#&QWX zu`*`X%mWVk1Ht3BVw=Xji_RM^8A^Q|D)+hUSbDgXm$8GMux}R3*g4~(*X&1li)Nwg zq?IPi>jup-5Tt(#RMVeH-iQgiXFO#MV`3&!vVag)K+Z=mn7kIRCcKNV59a;{Q(eSg zmgdmw2%|B}YnD-N6dmLDqERj$ph0=ixC6A%pUO8lE8Xd+TK+t|64pkZX7C(?XBa%e zpbH?){2)qCJ7UTnsI6g5TVanT(AQ36chFf!ZF3<~Kb<%?IMM!vNh(xDP8m<_nUv>c z_te1Tz&Yh}x#qUqFef)mANpK=jQ-2o&`5g;0;^OfdHRFJ!A1@sHL&tls&t<{ZrR^?{pgnepv(P^qqI89* z2u3W;$Z*ITI7D-SFtth^b3Gz&j0u`RFNn(7Dzjn0&rG?D*fHZQD+C7>Xst<+u}k;- zW!SBWCD&Mg6cHs8h7HgQ_UH>%&hzD^aA+?(d*L+b(1kyJFhDw<43%iYOTbeIesB5FFlA)0z=%s)z&lEfQ*0}>34Eqyp1)qGuQ@D z6b6SzRYIy+Ly$oTAZ{YvtlkMw6k)D?NnEt(=KDs-;1W@E@}x~5#?}FaxY-c7Bsw}o zUO5Q*$pL6&o0i_l!D9jy+$}ld#iP0Xvs-3cKY2Xw+%@s^ysS*6CR4ZN`Z>A2V0O(* zuBo2Mo^ytu@4qd@=A_v4+Rvq?g2TIDLXL(z$mkF!wk}waV5cExD>&c_&b6FKXRP7z zf=!-kooszG{l?~eWL2*Hcb&iOy!`B38$kFtt5K7V6790&0r`RS@KZf=Lqwsu}s8a|5YEKxNZWlr}i>%4!SdW5$?;H$_UCu?d+^rsT);1aXx z8F}USZo;kw@vPQ?BxdVpeR+A?r|HkK*R!|GJ$h7dm>wM!TJ8@E zl~JLYMFk&3f{$8T0IxL)9nJjZ2KR>sZWsNFa*}(ICcRH^-Snb2%Bl3acNesTd@F_5 zU}MKGclqAu#Frr1dmGVyn{wG6_=r1z?HLxp^)kMAHA3cRIfTZnko~P$VvUA0PUAJR zW}J~Ov7`|S$XL^{3=8IZ!LrULhh_v;InN7_8rIOmA^SLpIUZI8bcaiZ6hJ7Zum<>5KCvj9vFr?XGI`_pQO*qD-y)Yr& z_Balg)kCv^L)bj#!Zl-V&2gepbCCuM%GBLw&Y`(9%S@!a`CR3GL^TP_)oL!lSmo+* z9cXkD?sTqVa!h(P!VQ`X;>#+d39#ZmQGGM&+LA;_7Ew!@H2^}S4>`|y_g zEHY)Jl<3pn*GzE=?TPFkXP*;`;qV^;m}V_pv-pUuDsOlj-69OyY1~>HCZv1u>FkcZD8n33EL%$$(81 z?u_yR^*I-<yuDoyc#CH04?ajJ* zrSanK54^KSZz^4>Df_*gnkC z=>EZd?a4%DUphmYqX50VgefT+yM|I~94;%S#m`)V=vs6O@51Z%^_^pV_pCpoyO}vpr&XTj0*DfPnjzGN*#d+XJm3Kw?rih`G%L`yo}O*!Ft>BuQ`|zA JfqvQG{|^P+>OBAe delta 2053 zcmZuxYfMx}6rS08?>@PA?=JgfS#}o?xGMOf)F=2Pt`Ce@wSr1vXO#s6oV|3F-Yuxa z#7HY=G=%E`H(m!w0V#p1&~A~FA5^(7~keY zB}k@!KjM(T!5oW78w97h)0`3>ZfH%` z;-UVi+MSH{b*jnqR15Um{Rx8x08a%Q?Hsjvev6!UEQdUK=qNKILE}=8{O$-l%sFV# zvjREFm626N-eO)8kR@-;Q9IVMX3b1y+#VmYA-e{zf=N@(WK2O|Op)<`WHLk^iAW-M zikbv7a^_|7t9u>UC^m2w%|cF#wSwiWiAr~hOUXUayTOcHd3V8E)~ZGfzW|_O&C=s5 zjOPDW0rF@(MXzQhL8&6*D_BEt79fzdylct83^>Id0vV|INxRfXzLy@Xx6Sf6IXHlK zP+zl-%mD5^);EypNFm%xH8{>-Cxb=?Eev*3NV5YZPn_lMgH)(zntFO-qu?ipL_|3j znv>j@dM@-_S#+)VO6g;%>WNf4Bh_9%{#a@tZSvnO!PpiTxVzT0Md0qPw^Dgp5VlB` zX*g;tXQz=uGEWX4=P)m1SKn~#I6P2+LB8lo({ zX+VP`oMzSdd{K__S)&|Vx?HswBYHnXjia|f((i(El3m`&h%kQ_DBJn6$GluPDBYjD zz@KY``EyTlg@Ry5xnRCn4Hsf-wgQLUM%~UkDdeEXAkd<)Z3Rbe&_&xdJBd|#MPI=n z>o7EAS5*A-yf_LL z(2=h!ycH0Pe?exd&umZ%C77T~PMEUh45$EVv|v{WFx}uw!D4zWFS%3`gp0`MHE%&g z?1~am1iYV`>cxwDnbgPNFooer%K-UVDI@PFP4fRq`!zz zv&+xy*;|0wG;SrIExzRD7N`$Vwc;iXOOCD`VvHUJ>{LnpeD zxC3`)j728M(lr3X9JM0XOUS!I#kOT+eyR5(L> z`W#W0-Xrna$E2yQ+9!x9I48%hsW)G{-TUZZ+YfU4oa`m%>$X~|f$aI~k4#E}+{+_cU9yQ$$td9q{2Y$#f8j3dx4>rJfBk5W;IPyLXh1rXs*p0oh z2iZ6$UD8*3j_LGQQ`a$@S-xeUKdD$>X{7I1H`3itF!x2TWbV{+t5eyj4O{mm)%LWC zj~J;I_YA73f&R`uL&v-g+jphXYWvnyLOnvCx%mJg^2_q1e4bM9aR$d2yg}Mll*xJ) zSpu=1*^A`873Gc(=$O?*`VJspt$0&>zSsq&=QSp{5kB*gu9e#?Yv5-1>=Yz7R{H-1 DSE{p) diff --git a/scripts/ci/rerun_pr_workflows.py b/scripts/ci/rerun_pr_workflows.py index 02c34a674d..c23df258cc 100755 --- a/scripts/ci/rerun_pr_workflows.py +++ b/scripts/ci/rerun_pr_workflows.py @@ -101,6 +101,29 @@ def rerun_workflow(*, repo: str, token: str, run_id: int) -> None: raise +def cancel_workflow_run(*, repo: str, token: str, run_id: int) -> bool: + cancel_url = f"https://api.github.com/repos/{repo}/actions/runs/{run_id}/cancel" + request = urllib.request.Request( + cancel_url, + data=json.dumps({}).encode("utf-8"), + method="POST", + ) + request.add_header("Authorization", f"Bearer {token}") + request.add_header("Accept", "application/vnd.github+json") + request.add_header("Content-Type", "application/json") + try: + with urllib.request.urlopen(request, timeout=30): + return True + except urllib.error.HTTPError as exc: + body = exc.read().decode("utf-8", errors="ignore") + lower = body.lower() + if exc.code in (403, 409) and ("completed" in lower or "not in progress" in lower): + print(f" Run {run_id} already finished; skipping cancel request.") + return False + print(f"GitHub API error ({exc.code}) for {cancel_url}:\n{body}", file=sys.stderr) + raise + + def collect_runs( *, repo: str, @@ -200,6 +223,9 @@ def main() -> None: workflow_id = run.get("workflow_id") if run_id is None: continue + cancelled = cancel_workflow_run(repo=repo, token=token, run_id=run_id) + if cancelled: + print(f" Cancelled existing run {run_id}.") ref = head_ref or (run.get("head_branch") or "") dispatched = False if workflow_id is not None and ref: From 6bd278e4ff92f1492611c3fd16a55eff8f1fe6bd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 13 Nov 2025 00:50:05 +0000 Subject: [PATCH 14/14] chore: bump spec version to 352 --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 11d3487f33..c90942afb9 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 351, + spec_version: 352, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,