From 640989cb11cb9b90100f0ae3fe6cc6faed2467ed Mon Sep 17 00:00:00 2001 From: Raoul Date: Wed, 7 Oct 2026 10:42:41 +0000 Subject: [PATCH 1/6] Version bump --- package/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/version b/package/version index 1ec9b0b6..a2d633db 100644 --- a/package/version +++ b/package/version @@ -1 +1 @@ -0.1.60 +0.1.61 From 90e961b8fe893cee80f710dd701129a97528ac95 Mon Sep 17 00:00:00 2001 From: Raoul Date: Wed, 7 Oct 2026 11:26:07 +0000 Subject: [PATCH 2/6] Added script for pushing to the nix caches --- nix/kontrol-node/build-systems-overlay.nix | 7 +- package/release.sh | 187 +++++++++++++++++++++ 2 files changed, 192 insertions(+), 2 deletions(-) create mode 100755 package/release.sh diff --git a/nix/kontrol-node/build-systems-overlay.nix b/nix/kontrol-node/build-systems-overlay.nix index d27c1151..7567b17f 100644 --- a/nix/kontrol-node/build-systems-overlay.nix +++ b/nix/kontrol-node/build-systems-overlay.nix @@ -10,8 +10,11 @@ let # `setuptools-scm[toml]` in pyproject.toml would be written as # `foo.setuptools-scm = [ "toml" ]` in Nix buildSystemOverrides = { - # add dependencies here, e.g.: - # pyperclip.setuptools = [ ]; + # git dependencies are built from source, but uv.lock does not record their build systems + kevm-pyk.hatchling = [ ]; + kontrol.hatchling = [ ]; + # sdist-only on PyPI + typing.setuptools = [ ]; }; in mapAttrs ( diff --git a/package/release.sh b/package/release.sh new file mode 100755 index 00000000..adb0736e --- /dev/null +++ b/package/release.sh @@ -0,0 +1,187 @@ +#!/usr/bin/env bash +# +# Interactive, local replacement for the former `release.yml` / `update.yml` GitHub workflows. +# +# Everything is built from the local checkout. As with any flake, Nix ignores untracked files. +# +# Steps (each one asks for confirmation before running): +# 1. Create GitHub release `v` targeting HEAD. +# 2. Build `kontrol-node` and push its full build closure to the `k-framework` Cachix cache. +# 3. Publish and pin `kontrol-node` in the `k-framework-binary` Cachix cache (what `kup install` uses). +# +# Steps 1 and 3 reference HEAD on GitHub, so they are skipped unless the working tree is clean and +# HEAD is pushed. Step 2 also runs on uncommitted changes. +# +# Credentials are read from the environment, or prompted for (input hidden) when missing: +# GH_TOKEN GitHub token for `gh` (only needed if `gh auth status` fails) +# CACHIX_PUBLIC_TOKEN Cachix auth token for `k-framework` +# CACHIX_PRIVATE_KFB_TOKEN Cachix auth token for `k-framework-binary` +# +# Do NOT run this script with `bash -x`: tracing would print the credentials. + +set -euo pipefail + +REPO="runtimeverification/kontrol-node" +PACKAGE="${PACKAGE:-kontrol-node}" +KEEP_DAYS="${KEEP_DAYS:-180}" +SOURCE_CACHE="k-framework" +BINARY_CACHE="k-framework-binary" + +usage() { + cat <&2 ; } +warn() { echo -e "\033[1;33m[WARN]\033[0m $*" >&2 ; } +fatal() { echo -e "\033[1;31m[FATAL]\033[0m $*" >&2 ; exit 1 ; } + +ASSUME_YES=false + +confirm() { + local prompt="$1" answer + if ${ASSUME_YES}; then return 0; fi + read -rp "${prompt} [Y/n] " answer &2 + [[ -n "${value}" ]] || fatal "${var} must not be empty." + printf -v "${var}" '%s' "${value}" +} + +nix_() { nix --extra-experimental-features 'nix-command flakes' "$@" ; } + +# Puts tool $1 on PATH, building flake $2 if it is not installed. +ensure_tool() { + local tool="$1" flake="$2" out + command -v "${tool}" &>/dev/null && return + notif "${tool} not found, building ${flake} ..." + out="$(nix_ build "${flake}" --no-link --print-out-paths | head -n1)" + export PATH="${out}/bin:${PATH}" +} + +# --- Steps ------------------------------------------------------------------------------------ + +step_github_release() { + if ! gh auth status &>/dev/null; then + require_secret GH_TOKEN "GitHub token" + fi + local existing + if existing="$(GH_TOKEN="${GH_TOKEN:-}" gh release view "${TAG}" --repo "${REPO}" --json tagName --jq .tagName 2>/dev/null)"; then + warn "Release ${existing} already exists, skipping." + return + fi + GH_TOKEN="${GH_TOKEN:-}" gh release create "${TAG}" --repo "${REPO}" --target "${REV}" --title "${TAG}" --notes '' + notif "Created release ${TAG}." +} + +step_source_cache() { + require_secret CACHIX_PUBLIC_TOKEN "Cachix token for ${SOURCE_CACHE}" + ensure_tool cachix nixpkgs#cachix + notif "Building ${FLAKE_REF} ..." + nix_ build "${FLAKE_REF}" --no-link --print-build-logs + local drv + drv="$(nix_ path-info --derivation "${FLAKE_REF}")" + notif "Pushing build closure of ${drv} to ${SOURCE_CACHE} ..." + nix-store --query --requisites --include-outputs "${drv}" \ + | CACHIX_AUTH_TOKEN="${CACHIX_PUBLIC_TOKEN}" cachix push "${SOURCE_CACHE}" +} + +step_binary_cache() { + require_secret CACHIX_PRIVATE_KFB_TOKEN "Cachix token for ${BINARY_CACHE}" + ensure_tool cachix nixpkgs#cachix + ensure_tool kup github:runtimeverification/kup + # kup builds the local directory and pins the result under `github:/#`. + notif "Publishing ${FLAKE_REF} to ${BINARY_CACHE} (keep ${KEEP_DAYS} days) ..." + CACHIX_AUTH_TOKEN="${CACHIX_PRIVATE_KFB_TOKEN}" kup publish --keep-days "${KEEP_DAYS}" "${BINARY_CACHE}" "${FLAKE_REF}" +} + +# --- Main ------------------------------------------------------------------------------------- + +while [[ $# -gt 0 ]]; do + case "$1" in + --yes|-y) ASSUME_YES=true ; shift ;; + -h|--help) usage ; exit 0 ;; + *) usage ; fatal "Unknown argument: $1" ;; + esac +done + +for tool in git gh nix nix-store; do + command -v "${tool}" &>/dev/null || fatal "Required tool not found: ${tool}" +done + +cd "$(git rev-parse --show-toplevel)" + +notif "Fetching origin ..." +git fetch --quiet origin + +REV="$(git rev-parse HEAD)" +VERSION="$(tr -d '[:space:]' < package/version)" +TAG="v${VERSION}" +FLAKE_REF="${PWD}#${PACKAGE}" +SYSTEM="$(nix_ eval --impure --raw --expr builtins.currentSystem)" + +DIRTY=false +STATE="clean" +if [[ -n "$(git status --porcelain --untracked-files=no)" ]]; then + DIRTY=true + STATE="uncommitted changes (included in the build)" +fi +PUSHED=true +if [[ -z "$(git branch --remotes --contains "${REV}")" ]]; then + PUSHED=false + STATE="${STATE}, HEAD not pushed" +fi + +cat >&2 <|| +STEPS=( + "step_github_release|true|Create GitHub release ${TAG}" + "step_source_cache|false|Push build closure to the ${SOURCE_CACHE} cache" + "step_binary_cache|true|Publish ${PACKAGE} to the ${BINARY_CACHE} cache (kup)" +) + +for entry in "${STEPS[@]}"; do + IFS='|' read -r fn needs_published title <<< "${entry}" + echo >&2 + if ${needs_published} && { ${DIRTY} || ! ${PUSHED}; }; then + warn "Skipped: ${title} (needs a clean working tree with HEAD pushed to GitHub)" + elif confirm "${title}?"; then + notif "${title}" + "${fn}" + else + warn "Skipped: ${title}" + fi +done + +echo >&2 +notif "Done." From c3e090aa3b3f9843f5560b6fb96b2a17ba6e7d40 Mon Sep 17 00:00:00 2001 From: Raoul <raoul.schaffranek@runtimeverification.com> Date: Wed, 7 Oct 2026 11:26:50 +0000 Subject: [PATCH 3/6] Version bump --- package/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/version b/package/version index a2d633db..fbde3d5a 100644 --- a/package/version +++ b/package/version @@ -1 +1 @@ -0.1.61 +0.1.62 From 8369efb879cdb610e1a62084c34d0d462bd5fe90 Mon Sep 17 00:00:00 2001 From: Raoul <raoul.schaffranek@runtimeverification.com> Date: Wed, 7 Oct 2026 11:32:52 +0000 Subject: [PATCH 4/6] Rename tokens for readability --- package/release.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package/release.sh b/package/release.sh index adb0736e..b4288cb3 100755 --- a/package/release.sh +++ b/package/release.sh @@ -14,8 +14,8 @@ # # Credentials are read from the environment, or prompted for (input hidden) when missing: # GH_TOKEN GitHub token for `gh` (only needed if `gh auth status` fails) -# CACHIX_PUBLIC_TOKEN Cachix auth token for `k-framework` -# CACHIX_PRIVATE_KFB_TOKEN Cachix auth token for `k-framework-binary` +# CACHIX_SOURCE_TOKEN Cachix auth token for `k-framework` +# CACHIX_BINARY_TOKEN Cachix auth token for `k-framework-binary` # # Do NOT run this script with `bash -x`: tracing would print the credentials. @@ -35,7 +35,7 @@ Builds and publishes the local checkout. --yes Run all steps without asking for confirmation. -Environment: GH_TOKEN, CACHIX_PUBLIC_TOKEN, CACHIX_PRIVATE_KFB_TOKEN, +Environment: GH_TOKEN, CACHIX_SOURCE_TOKEN, CACHIX_BINARY_TOKEN, PACKAGE (default: kontrol-node), KEEP_DAYS (default: 180). EOF } @@ -94,7 +94,7 @@ step_github_release() { } step_source_cache() { - require_secret CACHIX_PUBLIC_TOKEN "Cachix token for ${SOURCE_CACHE}" + require_secret CACHIX_SOURCE_TOKEN "Cachix token for ${SOURCE_CACHE}" ensure_tool cachix nixpkgs#cachix notif "Building ${FLAKE_REF} ..." nix_ build "${FLAKE_REF}" --no-link --print-build-logs @@ -102,16 +102,16 @@ step_source_cache() { drv="$(nix_ path-info --derivation "${FLAKE_REF}")" notif "Pushing build closure of ${drv} to ${SOURCE_CACHE} ..." nix-store --query --requisites --include-outputs "${drv}" \ - | CACHIX_AUTH_TOKEN="${CACHIX_PUBLIC_TOKEN}" cachix push "${SOURCE_CACHE}" + | CACHIX_AUTH_TOKEN="${CACHIX_SOURCE_TOKEN}" cachix push "${SOURCE_CACHE}" } step_binary_cache() { - require_secret CACHIX_PRIVATE_KFB_TOKEN "Cachix token for ${BINARY_CACHE}" + require_secret CACHIX_BINARY_TOKEN "Cachix token for ${BINARY_CACHE}" ensure_tool cachix nixpkgs#cachix ensure_tool kup github:runtimeverification/kup # kup builds the local directory and pins the result under `github:<origin>/<HEAD>#<package>`. notif "Publishing ${FLAKE_REF} to ${BINARY_CACHE} (keep ${KEEP_DAYS} days) ..." - CACHIX_AUTH_TOKEN="${CACHIX_PRIVATE_KFB_TOKEN}" kup publish --keep-days "${KEEP_DAYS}" "${BINARY_CACHE}" "${FLAKE_REF}" + CACHIX_AUTH_TOKEN="${CACHIX_BINARY_TOKEN}" kup publish --keep-days "${KEEP_DAYS}" "${BINARY_CACHE}" "${FLAKE_REF}" } # --- Main ------------------------------------------------------------------------------------- From caec8c72540f65c1abc8143e6452e8f790ed6b2a Mon Sep 17 00:00:00 2001 From: Raoul <raoul.schaffranek@runtimeverification.com> Date: Wed, 7 Oct 2026 11:56:33 +0000 Subject: [PATCH 5/6] Fix version lookup --- package/release.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/package/release.sh b/package/release.sh index b4288cb3..7be3fdd2 100755 --- a/package/release.sh +++ b/package/release.sh @@ -86,7 +86,7 @@ step_github_release() { fi local existing if existing="$(GH_TOKEN="${GH_TOKEN:-}" gh release view "${TAG}" --repo "${REPO}" --json tagName --jq .tagName 2>/dev/null)"; then - warn "Release ${existing} already exists, skipping." + warn "Release ${existing} already exists at HEAD, skipping." return fi GH_TOKEN="${GH_TOKEN:-}" gh release create "${TAG}" --repo "${REPO}" --target "${REV}" --title "${TAG}" --notes '' @@ -151,12 +151,24 @@ if [[ -z "$(git branch --remotes --contains "${REV}")" ]]; then STATE="${STATE}, HEAD not pushed" fi +# Consumers resolve a version through its tag, so publishing any commit other than the tagged one +# under this version would be inconsistent. An annotated tag's commit is its peeled `^{}` entry. +TAG_REV="$(git ls-remote --tags origin \ + | awk -v ref="refs/tags/${TAG}" '$2 == ref {c = $1} $2 == ref "^{}" {p = $1} END {print (p ? p : c)}')" +if [[ -z "${TAG_REV}" ]]; then + TAG_STATE="new" +elif [[ "${TAG_REV}" == "${REV}" ]]; then + TAG_STATE="exists at HEAD" +else + fatal "Tag ${TAG} already points at ${TAG_REV}, not HEAD (${REV}). Bump package/version or check out ${TAG}." +fi + cat >&2 <<EOF Commit: ${REV} $(git log -1 --format='%s (%an, %ad)' --date=short "${REV}") State: ${STATE} - Version: ${VERSION} (tag ${TAG}) + Version: ${VERSION} (tag ${TAG}: ${TAG_STATE}) Package: ${FLAKE_REF} System: ${SYSTEM} (only this system's binaries are cached; run on other machines for more) From 60554639ed5e3a732611790ead8c99e93a4ce1da Mon Sep 17 00:00:00 2001 From: Raoul <raoul.schaffranek@runtimeverification.com> Date: Wed, 7 Oct 2026 11:57:55 +0000 Subject: [PATCH 6/6] Version bump --- pyproject.toml | 2 +- src/kontrol_node/__init__.py | 2 +- uv.lock | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7f5f3534..f7331280 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "kontrol-node" -version = "0.1.60" +version = "0.1.62" description = "A local testnet node powered by KEVM" readme = "README.md" requires-python = ">=3.10,<4" diff --git a/src/kontrol_node/__init__.py b/src/kontrol_node/__init__.py index ce29fa19..d61fd559 100644 --- a/src/kontrol_node/__init__.py +++ b/src/kontrol_node/__init__.py @@ -5,4 +5,4 @@ if TYPE_CHECKING: from typing import Final -VERSION: Final = '0.1.60' +VERSION: Final = '0.1.62' diff --git a/uv.lock b/uv.lock index e9d56dc0..e3abc8ca 100644 --- a/uv.lock +++ b/uv.lock @@ -817,7 +817,7 @@ dependencies = [ [[package]] name = "kontrol-node" -version = "0.1.60" +version = "0.1.62" source = { editable = "." } dependencies = [ { name = "kontrol" },