Repository: probe-rs/probe-rs
Pull request #3463 (2025-07-11 14:25:00)

Release script fixes.
- **Fix missing quote in release script.**
- **Include PR number and user in changelog even if the commit has been cherry-picked.**
- **Allow doing `xtask release` from point release branches.**



Patch:
diff --git a/.github/workflows/release_crates.yml b/.github/workflows/release_crates.yml
index 5c8e2417..cec4e428 100644
--- a/.github/workflows/release_crates.yml
+++ b/.github/workflows/release_crates.yml
@@ -68,7 +68,15 @@ jobs:
         # The tag prefix is set to an empty string, so that the tag is just the version number, and doesn't contain the crate name.
       - name: release to crates.io
         run: |
-          git checkout master
+          # Checkout appropriate branch based on trigger type
+          if [ "${{ github.event_name }}" = "pull_request" ]; then
+            # For PR merge, checkout the PR's target branch
+            echo "Checking out PR target branch: ${{ github.event.pull_request.base.ref }}"
+            git checkout ${{ github.event.pull_request.base.ref }}
+          else
+            # For workflow_dispatch, stay on current branch (let user choose)
+            echo "Running on current branch: $(git branch --show-current)"
+          fi
 
           echo "::group::Setup auth for crates.io"
           cargo login ${{ secrets.CARGO_REGISTRY_TOKEN }}
diff --git a/.github/workflows/start-release.yml b/.github/workflows/start-release.yml
index f640cf44..fa12feb9 100644
--- a/.github/workflows/start-release.yml
+++ b/.github/workflows/start-release.yml
@@ -103,6 +103,6 @@ jobs:
           - target-gen
           - probe-rs-tools
           - probe-rs-mi
-          - probe-rs-debug
+          - probe-rs-debug"
         env:
           GH_TOKEN: ${{ secrets.GH_PAT }}
diff --git a/Cargo.lock b/Cargo.lock
index c33c12c3..6f08d02f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -522,13 +522,13 @@ dependencies = [
 
 [[package]]
 name = "cargo-config2"
-version = "0.1.34"
+version = "0.1.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a82de3b1a1dd72252c6d456247864ffe52110d109da949f579eeb16349e0eb5d"
+checksum = "2f307d010782c2a4066cc5125ba8c6b68db926b3a1bb82bd6d0b38950c6d4815"
 dependencies = [
  "serde",
  "serde_derive",
- "toml_edit",
+ "toml 0.9.2",
  "windows-sys 0.60.2",
 ]
 
@@ -543,25 +543,25 @@ dependencies = [
 
 [[package]]
 name = "cargo-util-schemas"
-version = "0.2.0"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e63d2780ac94487eb9f1fea7b0d56300abc9eb488800854ca217f102f5caccca"
+checksum = "7dc1a6f7b5651af85774ae5a34b4e8be397d9cf4bc063b7e6dbd99a841837830"
 dependencies = [
  "semver",
  "serde",
  "serde-untagged",
  "serde-value",
- "thiserror 1.0.69",
- "toml",
+ "thiserror 2.0.12",
+ "toml 0.8.23",
  "unicode-xid",
  "url",
 ]
 
 [[package]]
 name = "cargo_metadata"
-version = "0.20.0"
+version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f7835cfc6135093070e95eb2b53e5d9b5c403dc3a6be6040ee026270aa82502"
+checksum = "5cfca2aaa699835ba88faf58a06342a314a950d2b9686165e038286c30316868"
 dependencies = [
  "camino",
  "cargo-platform",
@@ -644,9 +644,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.40"
+version = "4.5.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
+checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -654,9 +654,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.40"
+version = "4.5.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
+checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
 dependencies = [
  "anstream",
  "anstyle",
@@ -666,18 +666,18 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.54"
+version = "4.5.55"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677"
+checksum = "a5abde44486daf70c5be8b8f8f1b66c49f86236edf6fa2abadb4d961c4c6229a"
 dependencies = [
  "clap",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.5.40"
+version = "4.5.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
+checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -1304,9 +1304,9 @@ dependencies = [
 
 [[package]]
 name = "espflash"
-version = "4.0.0"
+version = "4.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4779db2705a005a81a0c536d8ef49fbb0f0739c060bfd9a8eac8bc29f8f862b4"
+checksum = "cae69927fa129d5bf119dc39fe984de95851f7ef918d06d14df95f8a74c59cda"
 dependencies = [
  "base64 0.22.1",
  "bitflags 2.9.1",
@@ -1379,7 +1379,7 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_yaml",
- "toml",
+ "toml 0.8.23",
  "uncased",
  "version_check",
 ]
@@ -2976,9 +2976,9 @@ dependencies = [
 
 [[package]]
 name = "postcard-rpc"
-version = "0.11.9"
+version = "0.11.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6af390b4b4c1a3a187293bfef773157c75a06f935eeae147c981ee1d958652ea"
+checksum = "c741980fc5a15ac8301bf3e69385eb0da54fccd69f03301286c3176f0d6e40d7"
 dependencies = [
  "heapless 0.8.0",
  "maitake-sync",
@@ -3580,9 +3580,9 @@ dependencies = [
 
 [[package]]
 name = "rustls"
-version = "0.23.28"
+version = "0.23.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643"
+checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1"
 dependencies = [
  "once_cell",
  "ring",
@@ -3606,18 +3606,19 @@ dependencies = [
 
 [[package]]
 name = "rustls-pki-types"
-version = "1.11.0"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
+checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
 dependencies = [
  "web-time",
+ "zeroize",
 ]
 
 [[package]]
 name = "rustls-webpki"
-version = "0.103.3"
+version = "0.103.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
+checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
 dependencies = [
  "ring",
  "rustls-pki-types",
@@ -3883,6 +3884,15 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "serde_spanned"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "serde_urlencoded"
 version = "0.7.1"
@@ -4050,7 +4060,7 @@ dependencies = [
  "probe-rs",
  "serde",
  "thiserror 2.0.12",
- "toml",
+ "toml 0.9.2",
 ]
 
 [[package]]
@@ -4536,11 +4546,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
 dependencies = [
  "serde",
- "serde_spanned",
- "toml_datetime",
+ "serde_spanned 0.6.9",
+ "toml_datetime 0.6.11",
  "toml_edit",
 ]
 
+[[package]]
+name = "toml"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned 1.0.0",
+ "toml_datetime 0.7.0",
+ "toml_parser",
+ "toml_writer",
+ "winnow",
+]
+
 [[package]]
 name = "toml_datetime"
 version = "0.6.11"
@@ -4550,6 +4575,15 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "toml_datetime"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "toml_edit"
 version = "0.22.27"
@@ -4558,18 +4592,33 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
 dependencies = [
  "indexmap",
  "serde",
- "serde_spanned",
- "toml_datetime",
+ "serde_spanned 0.6.9",
+ "toml_datetime 0.6.11",
  "toml_write",
  "winnow",
 ]
 
+[[package]]
+name = "toml_parser"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30"
+dependencies = [
+ "winnow",
+]
+
 [[package]]
 name = "toml_write"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
 
+[[package]]
+name = "toml_writer"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
+
 [[package]]
 name = "tower"
 version = "0.5.2"
@@ -5491,6 +5540,7 @@ version = "0.29.0"
 dependencies = [
  "anyhow",
  "clap",
+ "regex",
  "serde",
  "serde_json",
  "xshell",
@@ -5597,9 +5647,9 @@ dependencies = [
 
 [[package]]
 name = "zip"
-version = "4.2.0"
+version = "4.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95ab361742de920c5535880f89bbd611ee62002bf11341d16a5f057bb8ba6899"
+checksum = "9aed4ac33e8eb078c89e6cbb1d5c4c7703ec6d299fc3e7c3695af8f8b423468b"
 dependencies = [
  "arbitrary",
  "crc32fast",
diff --git a/dist-workspace.toml b/dist-workspace.toml
index 494fecc9..10f3757d 100644
--- a/dist-workspace.toml
+++ b/dist-workspace.toml
@@ -40,6 +40,9 @@ aarch64-unknown-linux-musl = "buildjet-2vcpu-ubuntu-2204-arm"
 # taken from <https://github.com/axodotdev/cargo-dist/issues/1760#issuecomment-2769218034>
 runner = "ubuntu-latest"
 
+[dist.github-custom-runners.x86_64-pc-windows-msvc]
+runner = "windows-2022"
+
 [dist.dependencies.apt]
 libudev-dev = '*'
 libudev1 = { stage = ["run"] }
diff --git a/probe-rs-tools/Cargo.toml b/probe-rs-tools/Cargo.toml
index 2fe13394..ecfcbed5 100644
--- a/probe-rs-tools/Cargo.toml
+++ b/probe-rs-tools/Cargo.toml
@@ -47,7 +47,7 @@ itertools = "0.14"
 addr2line = "0.25"
 bytesize = "2"
 capstone = "0.13"
-cargo_metadata = "0.20"
+cargo_metadata = "0.21"
 clap = { version = "4", features = ["derive", "env"] }
 colored = "3"
 defmt-decoder = "1.0"
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index 3b33972f..075406d9 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -11,6 +11,7 @@ clap = { version = "4", features = ["derive"] }
 anyhow.workspace = true
 serde_json = "1"
 serde = { version = "1", features = ["derive"] }
+regex = "1.11.1"
 
 [lints]
 workspace = true
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 515ad930..c4f3e650 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -5,8 +5,10 @@ use std::{
     path::{Path, PathBuf},
 };
 
-use anyhow::{Context, ensure};
+use anyhow::{Context, bail, ensure};
 use clap::Parser;
+use regex::Regex;
+use serde_json::Value;
 use xshell::{Shell, cmd};
 
 use anyhow::Result;
@@ -87,10 +89,22 @@ fn fetch_prs() -> Result<()> {
 fn create_release_pr(version: String) -> Result<()> {
     let sh = Shell::new()?;
 
-    // Make sure we are on the master branch and we have the latest state pulled from our source of truth, GH.
+    // Make sure we are on the right branch and we have the latest state pulled from our source of truth, GH.
+
+    let branch = cmd!(sh, "git branch --show-current")
+        .read()?
+        .trim()
+        .to_string();
+
+    if branch != "master" && !branch.starts_with("release/") {
+        bail!(
+            "Invalid current branch '{branch}'. Make sure you're either on `master` or `release/x.y`."
+        )
+    }
+
     cmd!(
         sh,
-        "gh workflow run 'Open a release PR' --ref master -f version={version}"
+        "gh workflow run 'Open a release PR' --ref {branch} -f version={version}"
     )
     .run()?;
 
@@ -209,6 +223,8 @@ fn check_local_changelog_fragments(list: &mut FragmentList, fragments_dir: &Path
     let fragment_files = std::fs::read_dir(fragments_dir)
         .with_context(|| format!("Unable to read fragments from {}", fragments_dir.display()))?;
 
+    let pr_number_regex = Regex::new(" \\(#(\\d+)\\)\n").unwrap();
+
     for file in fragment_files {
         let file = file?;
         let path = file.path();
@@ -244,13 +260,30 @@ fn check_local_changelog_fragments(list: &mut FragmentList, fragments_dir: &Path
         let sha = sha.split(' ').next().unwrap();
         println!("fetching PR info for sha: {sha}");
 
-        let response = cmd!(sh, "gh api -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' https://api.github.com/repos/probe-rs/probe-rs/commits/{sha}/pulls").read()?;
+        let commit_message = cmd!(
+            sh,
+            "git rev-list --max-count=1 --no-commit-header --format=%B {sha}"
+        )
+        .read()?;
+
+        let mut pull = if let Some(m) = pr_number_regex.captures(&commit_message) {
+            let pull = m.get(1).unwrap().as_str();
+            let response = cmd!(sh, "gh api -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' https://api.github.com/repos/probe-rs/probe-rs/pulls/{pull}").read()?;
+            serde_json::from_str::<serde_json::Value>(&response).unwrap()
+        } else {
+            let response = cmd!(sh, "gh api -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' https://api.github.com/repos/probe-rs/probe-rs/commits/{sha}/pulls").read()?;
+            let json = serde_json::from_str::<serde_json::Value>(&response).unwrap();
 
-        let json = serde_json::from_str::<serde_json::Value>(&response).unwrap();
+            json.get(0).cloned().unwrap_or(Value::Null)
+        };
+
+        if pull["user"]["login"].as_str() == Some("probe-rs-bot") {
+            pull = Value::Null
+        }
 
         fragments.push(Fragment {
-            pr_number: json[0]["number"].as_i64().map(|n| n.to_string()),
-            author: json[0]["user"]["login"].as_str().map(|s| s.to_string()),
+            pr_number: pull["number"].as_i64().map(|n| n.to_string()),
+            author: pull["user"]["login"].as_str().map(|s| s.to_string()),
             path,
         });
     }


Test patch:
diff --git a/.github/workflows/smoketest.yml b/.github/workflows/smoketest.yml
index cdac3061..a9570303 100644
--- a/.github/workflows/smoketest.yml
+++ b/.github/workflows/smoketest.yml
@@ -30,7 +30,7 @@ jobs:
         run: rustup target add aarch64-unknown-linux-gnu
 
       - name: Install cross
-        uses: taiki-e/install-action@v2.56.7
+        uses: taiki-e/install-action@v2.56.13
         with:
           tool: cross
 
diff --git a/smoke-tester/Cargo.toml b/smoke-tester/Cargo.toml
index a97698fc..371a27fe 100644
--- a/smoke-tester/Cargo.toml
+++ b/smoke-tester/Cargo.toml
@@ -13,7 +13,7 @@ publish = false
 anyhow = { version = "1.0" }
 serde = { version = "1", features = ["derive"] }
 probe-rs = { workspace = true }
-toml = "0.8.12"
+toml = "0.9.0"
 env_logger = "0.11.0"
 log = "0.4.21"
 clap = { version = "4.5", features = ["derive"] }