From 87153f3c0ef785fd3c517fd59e133341c4bed4e1 Mon Sep 17 00:00:00 2001 From: thxCode Date: Mon, 12 Oct 2026 17:50:39 +0800 Subject: [PATCH 1/3] chore(deps): bump gpustack-runner to 0.1.31 and fix dependabot alerts gpustack-runner >= 0.1.29 -> >= 0.1.31. Lock-only upgrades of transitive dependencies close the open Dependabot alerts: urllib3 2.7.0 -> 2.8.0 covers GHSA-gh4c-6fx4-qh6g, GHSA-8988-9cw3-xx77 and GHSA-vxq7-64xx-v4gw; virtualenv 21.7.7 -> 21.14.7 covers GHSA-94p9-xgh2-xp45 and GHSA-9h9j-4vrj-gf7g; oauthlib 3.3.1 -> 4.0.0 covers GHSA-xpv3-w29h-x7cv and GHSA-hj66-6f7g-4r5v. Signed-off-by: thxCode --- pyproject.toml | 2 +- uv.lock | 82 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6578d74..4c5fa0b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ dependencies = [ # NB(thxCode): Pin to this Podman version for a custom patch. See gpustack_runtime/deployer/__patches__.py. "podman==5.6.0", "pyyaml", - "gpustack-runner>=0.1.29", + "gpustack-runner>=0.1.31", "nvidia-ml-py>=13.580.65", "mthreads-ml-py>=2.2.10", "argcomplete>=3.6.3", diff --git a/uv.lock b/uv.lock index a4b1354..29eb8b9 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,10 @@ version = 1 revision = 3 requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.11'", + "python_full_version < '3.11'", +] [[package]] name = "amdsmi" @@ -170,11 +174,11 @@ wheels = [ [[package]] name = "distlib" -version = "0.4.0" +version = "0.4.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/02/bd72be9134d25ed783ecbbc38a539ffaefbf90c78418c7fb7229600dbac7/distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed", size = 615141, upload-time = "2026-06-12T08:04:52.847Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, + { url = "https://files.pythonhosted.org/packages/02/08/9c41fb51ab5b43eb21674aff13df270e8ba6c4b29c8624e328dc7a9482af/distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b", size = 470628, upload-time = "2026-06-12T08:04:50.506Z" }, ] [[package]] @@ -258,7 +262,7 @@ wheels = [ [[package]] name = "gpustack-runner" -version = "0.1.29" +version = "0.1.31" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argcomplete" }, @@ -266,9 +270,9 @@ dependencies = [ { name = "packaging" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7b/5b/fcd80ec9f3b74d36c3e5e1462af5d29604585a3050d9bb6d36d50f6d4397/gpustack_runner-0.1.29.tar.gz", hash = "sha256:22c4ec21c3aee2c9d48f3535397821c85172370654ad71549d09289ca00ec393", size = 13464730, upload-time = "2026-09-01T09:23:07.718Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/cc/58ba6b213bec7c703dfa1b02c4f423056d86d61465950b7aab563176acb2/gpustack_runner-0.1.31.tar.gz", hash = "sha256:87e68cb889410db503657231667f1748055869e10d1a9bffeabc27e13a06001d", size = 13746189, upload-time = "2026-10-12T09:12:28.784Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/41/baf89298ead365239a326583b7310500cb05eda6b0113aade845181995d3/gpustack_runner-0.1.29-py3-none-any.whl", hash = "sha256:a0330f9512a4ebd0261acba41819e19e89188b47c466ca31db8499fbf9843686", size = 30850, upload-time = "2026-09-01T09:23:05.162Z" }, + { url = "https://files.pythonhosted.org/packages/21/a4/c66496c6c0a413cc10fb94d2b5efcaa5dc4d2a62aa4378b6a96f29e01ae4/gpustack_runner-0.1.31-py3-none-any.whl", hash = "sha256:f7dc1ec7b42f605ee27d6f4b8a36308c5d6f392f42a5bc27fed604f4a68f314f", size = 32461, upload-time = "2026-10-12T09:12:27.031Z" }, ] [[package]] @@ -307,7 +311,7 @@ requires-dist = [ { name = "argcomplete", specifier = ">=3.6.3" }, { name = "cachetools", specifier = ">=5.5.2" }, { name = "docker", specifier = ">=7.1.0" }, - { name = "gpustack-runner", specifier = ">=0.1.29" }, + { name = "gpustack-runner", specifier = ">=0.1.31" }, { name = "kubernetes", specifier = ">=33.1.0" }, { name = "mthreads-ml-py", specifier = ">=2.2.10" }, { name = "nvidia-ml-py", specifier = ">=13.580.65" }, @@ -565,7 +569,8 @@ version = "0.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mergedeep" }, - { name = "platformdirs" }, + { name = "platformdirs", version = "4.12.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "platformdirs", version = "4.13.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "pyyaml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } @@ -673,20 +678,20 @@ wheels = [ [[package]] name = "oauthlib" -version = "3.3.1" +version = "4.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7a/d8/a1bcc8ba112a627f8ffbdc212a78ce18d3ac07e91a5ca65d27918eee25a1/oauthlib-4.0.0.tar.gz", hash = "sha256:efb274799819440f95b4ab3b818869f1ce9ae26c5beacba0201d1a1b76b54f86", size = 187232, upload-time = "2026-09-28T06:01:18.77Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, + { url = "https://files.pythonhosted.org/packages/d9/f4/78229a1066068ca14fc60fb26cf7381cabe4382261392b90e5f9552722d4/oauthlib-4.0.0-py3-none-any.whl", hash = "sha256:624c28c13a0a59cabf9747dfa52af63be3e512a7f2714df16e91b5b3a145e6cd", size = 159715, upload-time = "2026-09-28T06:01:17.008Z" }, ] [[package]] name = "packaging" -version = "25.0" +version = "26.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, + { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, ] [[package]] @@ -709,11 +714,26 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.3.8" +version = "4.12.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } +resolution-markers = [ + "python_full_version < '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/90/a1/d5f9002a70298c64a789779077d8dd90c10aa1f47fe40c86802df874f2a6/platformdirs-4.12.4.tar.gz", hash = "sha256:63743c02414e755de4e31b8f68125c1407495b86c5a006e203c01ff8b9924250", size = 60010, upload-time = "2026-10-07T23:30:32.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, + { url = "https://files.pythonhosted.org/packages/f4/ba/223e00b885e960edd5d4b4d178c88acce019bd5b83786093681b8c393492/platformdirs-4.12.4-py3-none-any.whl", hash = "sha256:78bfb9db2a8471ed7eebe3c3c932da413911042994e699b384fbb4493fa872d7", size = 32596, upload-time = "2026-10-07T23:30:30.825Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.13.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/80/a8/66d45abadff219e36e2a824181b8f6a67e7ed4572934d6252c71c29d5731/platformdirs-4.13.0.tar.gz", hash = "sha256:1aa0b0d3f224c1f07c295121e312a5a24a180d6ae5a8425ea1784b3e3863e9c0", size = 61094, upload-time = "2026-10-11T02:05:24.109Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/15/1633010b26e88e872c93b67c0b6c5e174fb74cb6fb5c1472b4d51d4a8f22/platformdirs-4.13.0-py3-none-any.whl", hash = "sha256:3dbcf4cd708f21cf876c4eaa90e58412bc4f033d87143f41b1493ff77c25b7e1", size = 32724, upload-time = "2026-10-11T02:05:22.776Z" }, ] [[package]] @@ -839,14 +859,14 @@ wheels = [ [[package]] name = "python-discovery" -version = "1.6.0" +version = "1.6.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/96/0f93e27c9f60a650838f2118159aa115fd5732c0716247917b7ba7ede665/python_discovery-1.6.0.tar.gz", hash = "sha256:6393b4eae1be8b2182670635e7baff89ac21cb9f8e86fd1ff40c7b1144febb4c", size = 82849, upload-time = "2026-08-28T17:30:02.366Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/73/54993df8fc57e906dc9b7e01d1d9b0b2d3eb0ce3190639e33dccb12853f7/python_discovery-1.6.2.tar.gz", hash = "sha256:cd1738ca1d37c86ef9d0b654dd46fcee1e41c97c6add12575e8501ced39afdb4", size = 86921, upload-time = "2026-10-10T01:24:27.912Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/5e/21abf578182fb15006a57faf3711a1e659e29d600d19b6e557eae908c81d/python_discovery-1.6.0-py3-none-any.whl", hash = "sha256:d4e244cf17b8b29819ed78003d55fbacf86eda23425b075454fff9271b79377a", size = 38451, upload-time = "2026-08-28T17:30:01.236Z" }, + { url = "https://files.pythonhosted.org/packages/61/3b/50ed32583bfffa737df67d33b9c15d7b25df232c55ab606d059f610ef6ca/python_discovery-1.6.2-py3-none-any.whl", hash = "sha256:f0c697f95a3aaec4174a6e5e58f5885e25768684bafc76f1afde384709ebdcf2", size = 38912, upload-time = "2026-10-10T01:24:26.721Z" }, ] [[package]] @@ -1061,11 +1081,11 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.14.1" +version = "4.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, ] [[package]] @@ -1083,27 +1103,29 @@ wheels = [ [[package]] name = "urllib3" -version = "2.7.0" +version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/05/b17359e1cefb4f909b5e40b1b90a496d987258916dbbf88e842c729f510e/urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63", size = 458972, upload-time = "2026-09-15T19:29:36.253Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, + { url = "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3", size = 135717, upload-time = "2026-09-15T19:29:34.577Z" }, ] [[package]] name = "virtualenv" -version = "21.7.7" +version = "21.14.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, - { name = "platformdirs" }, + { name = "packaging" }, + { name = "platformdirs", version = "4.12.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "platformdirs", version = "4.13.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "python-discovery" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/79/41/c3f34799487924f2a6f43b8a8b7acd345a6c61aac2211d4bced8621ca4f1/virtualenv-21.7.7.tar.gz", hash = "sha256:6874376f99ba6b8d4e3ee8bde67f9285412400c7d5b29ba41ee6daa5e0221bdc", size = 5347022, upload-time = "2026-08-28T18:59:50.093Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/3f/935cf1757643381fb7f7cc98197b4bc119223d9c2cf37dc3b03ad2a4455f/virtualenv-21.14.7.tar.gz", hash = "sha256:5f427d56f39eb7e7447d641dd4b7ab1e9c92793f498f35f26da2e4972c5546ae", size = 5471741, upload-time = "2026-10-12T01:27:31.842Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/f8/dcec8dc767b812193316c7debed1e2b53e586e59c267bfe517688ff90275/virtualenv-21.7.7-py3-none-any.whl", hash = "sha256:67a6a68fef3ad8ca16b8b89f33fd8f97996cc0bf0db31629d07ecf8dec539a2c", size = 5324620, upload-time = "2026-08-28T18:59:48.056Z" }, + { url = "https://files.pythonhosted.org/packages/52/5b/799c3e5b8e04d5fa1c9b61a4c1f5079603e747205c7311b92abd30283df5/virtualenv-21.14.7-py3-none-any.whl", hash = "sha256:3769219a308c5d2f093e7729621ad12a6346b5767a7ec4338414e2a0fb0c526b", size = 5487587, upload-time = "2026-10-12T01:27:29.37Z" }, ] [[package]] From 5ed9b3a710ab09ab84a93d3619229deecf53d32f Mon Sep 17 00:00:00 2001 From: thxCode Date: Mon, 12 Oct 2026 17:50:40 +0800 Subject: [PATCH 2/3] feat: add runtime-release skill Document the release procedure modeled on the runner repo's runner-release skill, cut down to this repository's workflow: final tags publish immediately as latest (no promotion gate), the workflow generates no baseline notes, so curating the GitHub Release notes is the required final step. The canonical skill lives in .agents/skills and is exposed to Claude Code through a tracked .claude/skills symlink; the gitignore un-ignores only that path. AGENTS.md points at the skill. Signed-off-by: thxCode --- .agents/skills/runtime-release/SKILL.md | 98 +++++++++++++++++++++++++ .claude/skills/runtime-release | 1 + .gitignore | 5 +- AGENTS.md | 2 + 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 .agents/skills/runtime-release/SKILL.md create mode 120000 .claude/skills/runtime-release diff --git a/.agents/skills/runtime-release/SKILL.md b/.agents/skills/runtime-release/SKILL.md new file mode 100644 index 0000000..6cce3ae --- /dev/null +++ b/.agents/skills/runtime-release/SKILL.md @@ -0,0 +1,98 @@ +--- +name: runtime-release +description: Cut a gpustack-runtime package release end to end (select and push the tag, monitor the release workflow, curate the GitHub Release notes). +--- + +# Runtime release + +One maintainer duty: cut a package release. Push a version tag; `release.yml` builds and publishes +it. Then write the GitHub Release notes. + +## Cut a package release + +The git tag is the single source of truth: hatch-vcs derives the package version from it at build +time, and there is no version file to bump. Pushing a `v*.*.*` tag runs +`.github/workflows/release.yml`: build the distributions, create the GitHub Release with the +wheel/sdist assets, publish to PyPI, then verify an isolated install. Branch pushes to `main` or +`v*-dev` run the same job against TestPyPI and create no release. + +Two workflow facts shape the procedure: + +- The GitHub Release is a pre-release only when the tag contains `rc`. A final tag goes public and + becomes `latest` immediately. There is no promotion gate. +- The workflow generates no baseline notes. The release body starts empty, so curating the notes is + not polish; it is the entire text the reader gets. + +PyPI is the irreversible step: a version once published there cannot be re-uploaded or edited. + +### Hard rules + +- Tag shapes: `vX.Y.Z` final, `vX.Y.ZrcN` pre-release, `vX.Y.Z.postN` post-release. PEP 440 + canonical spellings only; history contains the non-dotted `v0.2.5postN` — do not repeat it. +- A tag whose PyPI publish succeeded is burned. NEVER delete or move it; fix forward with a new + version. Delete-and-recreate is limited to a tag that never reached PyPI and is interactive-only. +- An `rc` tag stays a pre-release; never mark it latest. +- Release from `origin/main` HEAD by default. A maintenance line (`v*-dev` branch) targets that + branch's HEAD; flag the choice in the summary. +- Interactive mode confirms every mutating step (tag push, note replacement). Auto mode runs + unattended through note curation and reports the release URL. + +### 1. Preflight (read-only) + +```sh +gh auth status +git fetch origin --tags --prune +git status --porcelain # must be empty +git tag -l 'v*' --sort=-v:refname | head -5 +git rev-parse origin/main +``` + +### 2. Version and commit (confirm) + +- Read the range since the previous tag: `git log --no-merges --oneline ..origin/main`. +- Propose the bump from the Conventional Commits in range: any `feat` → minor; fixes, docs, and + chores → patch. Use `.postN` only to re-issue the same version line (packaging metadata or a + docs-only rebuild of unchanged content). +- Confirm the (version, commit) pair before tagging. A final tag publishes immediately, so this + confirmation is the only gate. + +### 3. Draft notes + +Group the range by type: Features / Fixes / Docs / Other; omit empty sections. Keep highlights and +fold noisy `chore`/`ci`/`test` entries. Link PRs from `(#NNN)` subjects. Do not open the body with +a heading that repeats the tag. End with the Full Changelog compare URL +(`https://github.com/gpustack/runtime/compare/...`). + +### 4. Tag and monitor (confirm, then read-only) + +```sh +git tag -a "$VER" "$SHA" -m "Release $VER" +git push origin "$VER" +gh run list --branch "$VER" --limit 5 # the release.yml run for the tag +gh run watch --exit-status # background it; wait for the completion notification +``` + +The job's own verify step installs the package from PyPI in an isolated env, but it is unpinned and +only prints the installed version. A green run proves the upload succeeded, not that PyPI already +serves the new version; read the verify log's `version =` line and confirm it equals `$VER`. On +failure read `gh run view --log-failed`; retry the same run on transient errors. If the +failure is real and PyPI already holds the version, cut the next version instead — never re-tag. + +### 5. Curate notes (confirm) + +```sh +gh release view "$VER" --json body,isPrerelease # the body starts empty +gh release edit "$VER" --notes-file notes.md +``` + +A maintenance-line final keeps `--latest=false` when a newer stable tag exists. Verify the badge +with `gh api repos/gpustack/runtime/releases/latest --jq .tag_name`. An `rc` release stays a +pre-release and needs no further action. + +## Scope + +Package releases and their notes run here. No other repository document changes with a release: +the version comes from the tag, and no README or docs table tracks it. Container image builds are +`make package` (`pack/`) and deployment manifests live in `deploy/`; both are outside this skill. +Docs-only changes never trigger a release: the release workflow ignores docs paths on branch +pushes, so docs updates need no tag. diff --git a/.claude/skills/runtime-release b/.claude/skills/runtime-release new file mode 120000 index 0000000..d3072c2 --- /dev/null +++ b/.claude/skills/runtime-release @@ -0,0 +1 @@ +../../.agents/skills/runtime-release \ No newline at end of file diff --git a/.gitignore b/.gitignore index 787a6fe..06142e3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,10 @@ .vscode/ .DS_Store *.swp -.claude/ +**/.claude/* +!/.claude/skills +/.claude/skills/* +!/.claude/skills/runtime-release # Python-generated files _version.py diff --git a/AGENTS.md b/AGENTS.md index b7da1c4..e160862 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -59,6 +59,8 @@ Setup is `make install` (uv sync plus pre-commit hooks). Day-to-day targets: `gpustack_runtime/_version.py` is generated by hatch-vcs and `_version_appendix.py` by `make prepare`; never hand-edit either. +Cut package releases with the [runtime-release](.agents/skills/runtime-release/SKILL.md) skill. + ### Python conventions - Prefer clarity over cleverness to simplify long-term maintenance. From 0b9f0b1ac1c5d0b80ffbd48c01e1bb99ba18a1a8 Mon Sep 17 00:00:00 2001 From: thxCode Date: Mon, 12 Oct 2026 18:10:25 +0800 Subject: [PATCH 3/3] fixup! feat: add runtime-release skill Signed-off-by: thxCode --- .agents/skills/runtime-release/SKILL.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.agents/skills/runtime-release/SKILL.md b/.agents/skills/runtime-release/SKILL.md index 6cce3ae..426f805 100644 --- a/.agents/skills/runtime-release/SKILL.md +++ b/.agents/skills/runtime-release/SKILL.md @@ -44,12 +44,13 @@ gh auth status git fetch origin --tags --prune git status --porcelain # must be empty git tag -l 'v*' --sort=-v:refname | head -5 -git rev-parse origin/main ``` ### 2. Version and commit (confirm) -- Read the range since the previous tag: `git log --no-merges --oneline ..origin/main`. +- Pick the target ref: `origin/main` by default, or the `v*-dev` branch for a maintenance line. The + steps below call it `$TARGET`; `$SHA` is its HEAD (`git rev-parse "$TARGET"`). +- Read the range since the previous tag: `git log --no-merges --oneline ..$TARGET`. - Propose the bump from the Conventional Commits in range: any `feat` → minor; fixes, docs, and chores → patch. Use `.postN` only to re-issue the same version line (packaging metadata or a docs-only rebuild of unchanged content). @@ -61,7 +62,8 @@ git rev-parse origin/main Group the range by type: Features / Fixes / Docs / Other; omit empty sections. Keep highlights and fold noisy `chore`/`ci`/`test` entries. Link PRs from `(#NNN)` subjects. Do not open the body with a heading that repeats the tag. End with the Full Changelog compare URL -(`https://github.com/gpustack/runtime/compare/...`). +(`https://github.com/gpustack/runtime/compare/...`). Write the draft to `notes.md`; +step 5 publishes that file. ### 4. Tag and monitor (confirm, then read-only)