refactor(xtask): use the git binary to perform git operations

This commit is contained in:
Amaan Qureshi 2025-09-02 14:28:32 -04:00 committed by Amaan Qureshi
parent 5263cd0706
commit 5cd6e747a0
6 changed files with 155 additions and 207 deletions

157
Cargo.lock generated
View file

@ -105,11 +105,11 @@ checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
[[package]]
name = "bindgen"
version = "0.72.0"
version = "0.72.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f"
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
dependencies = [
"bitflags 2.9.3",
"bitflags 2.9.4",
"cexpr",
"clang-sys",
"itertools 0.13.0",
@ -131,9 +131,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.9.3"
version = "2.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d"
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
[[package]]
name = "bstr"
@ -169,12 +169,11 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cc"
version = "1.2.34"
version = "1.2.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc"
checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3"
dependencies = [
"jobserver",
"libc",
"find-msvc-tools",
"shlex",
]
@ -224,9 +223,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.46"
version = "4.5.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57"
checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931"
dependencies = [
"clap_builder",
"clap_derive",
@ -234,9 +233,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.46"
version = "4.5.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41"
checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6"
dependencies = [
"anstream",
"anstyle",
@ -265,9 +264,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.45"
version = "4.5.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6"
checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
dependencies = [
"heck",
"proc-macro2",
@ -624,6 +623,12 @@ dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650"
[[package]]
name = "foldhash"
version = "0.1.5"
@ -701,21 +706,6 @@ dependencies = [
"stable_deref_trait",
]
[[package]]
name = "git2"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110"
dependencies = [
"bitflags 2.9.3",
"libc",
"libgit2-sys",
"log",
"openssl-probe",
"openssl-sys",
"url",
]
[[package]]
name = "glob"
version = "0.3.3"
@ -892,7 +882,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
dependencies = [
"bitflags 2.9.3",
"bitflags 2.9.4",
"inotify-sys",
"libc",
]
@ -958,16 +948,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "jobserver"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [
"getrandom 0.3.3",
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.77"
@ -1010,20 +990,6 @@ version = "0.2.175"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]]
name = "libgit2-sys"
version = "0.18.2+1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222"
dependencies = [
"cc",
"libc",
"libssh2-sys",
"libz-sys",
"openssl-sys",
"pkg-config",
]
[[package]]
name = "libloading"
version = "0.8.8"
@ -1046,37 +1012,11 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
dependencies = [
"bitflags 2.9.3",
"bitflags 2.9.4",
"libc",
"redox_syscall",
]
[[package]]
name = "libssh2-sys"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9"
dependencies = [
"cc",
"libc",
"libz-sys",
"openssl-sys",
"pkg-config",
"vcpkg",
]
[[package]]
name = "libz-sys"
version = "1.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.15"
@ -1118,11 +1058,11 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "memfd"
version = "0.6.4"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64"
checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227"
dependencies = [
"rustix 0.38.44",
"rustix 1.0.8",
]
[[package]]
@ -1155,7 +1095,7 @@ version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [
"bitflags 2.9.3",
"bitflags 2.9.4",
"cfg-if",
"cfg_aliases",
"libc",
@ -1177,7 +1117,7 @@ version = "8.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
dependencies = [
"bitflags 2.9.3",
"bitflags 2.9.4",
"fsevent-sys",
"inotify",
"kqueue",
@ -1229,7 +1169,7 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
dependencies = [
"bitflags 2.9.3",
"bitflags 2.9.4",
"objc2",
]
@ -1257,24 +1197,6 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "openssl-probe"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-sys"
version = "0.9.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "path-slash"
version = "0.2.1"
@ -1293,12 +1215,6 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pkg-config"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "postcard"
version = "1.1.3"
@ -1429,7 +1345,7 @@ version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
dependencies = [
"bitflags 2.9.3",
"bitflags 2.9.4",
]
[[package]]
@ -1496,7 +1412,7 @@ version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags 2.9.3",
"bitflags 2.9.4",
"errno",
"libc",
"linux-raw-sys 0.4.15",
@ -1509,7 +1425,7 @@ version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
dependencies = [
"bitflags 2.9.3",
"bitflags 2.9.4",
"errno",
"libc",
"linux-raw-sys 0.9.4",
@ -1993,12 +1909,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "walkdir"
version = "2.5.0"
@ -2097,7 +2007,7 @@ version = "0.229.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc3b1f053f5d41aa55640a1fa9b6d1b8a9e4418d118ce308d20e24ff3575a8c"
dependencies = [
"bitflags 2.9.3",
"bitflags 2.9.4",
"hashbrown",
"indexmap",
"semver",
@ -2123,7 +2033,7 @@ checksum = "57373e1d8699662fb791270ac5dfac9da5c14f618ecf940cdb29dc3ad9472a3c"
dependencies = [
"addr2line",
"anyhow",
"bitflags 2.9.3",
"bitflags 2.9.4",
"bumpalo",
"cc",
"cfg-if",
@ -2617,7 +2527,6 @@ dependencies = [
"bindgen",
"cc",
"clap",
"git2",
"indoc",
"notify",
"notify-debouncer-full",

View file

@ -123,7 +123,6 @@ dialoguer = { version = "0.11.0", features = ["fuzzy-select"] }
etcetera = "0.10.0"
filetime = "0.2.26"
fs4 = "0.12.0"
git2 = "0.20.2"
glob = "0.3.3"
heck = "0.5.0"
html-escape = "0.2.13"

View file

@ -20,7 +20,6 @@ anyhow.workspace = true
bindgen = { version = "0.72.0" }
cc.workspace = true
clap.workspace = true
git2.workspace = true
indoc.workspace = true
regex.workspace = true
semver.workspace = true

View file

@ -1,18 +1,25 @@
use std::cmp::Ordering;
use std::{cmp::Ordering, path::Path};
use anyhow::{anyhow, Result};
use git2::{DiffOptions, Repository};
use anyhow::{anyhow, Context, Result};
use indoc::indoc;
use semver::{BuildMetadata, Prerelease, Version};
use crate::{create_commit, BumpVersion};
pub fn get_latest_tag(repo: &Repository) -> Result<String> {
let mut tags = repo
.tag_names(None)?
.into_iter()
.filter_map(|tag| tag.map(String::from))
.filter_map(|tag| Version::parse(tag.strip_prefix('v').unwrap_or(&tag)).ok())
pub fn get_latest_tag() -> Result<String> {
let output = std::process::Command::new("git")
.args(["tag", "-l"])
.output()?;
if !output.status.success() {
anyhow::bail!(
"Failed to list tags: {}",
String::from_utf8_lossy(&output.stderr)
);
}
let mut tags = String::from_utf8(output.stdout)?
.lines()
.filter_map(|tag| Version::parse(tag.strip_prefix('v').unwrap_or(tag)).ok())
.collect::<Vec<Version>>();
tags.sort_by(
@ -29,10 +36,19 @@ pub fn get_latest_tag(repo: &Repository) -> Result<String> {
}
pub fn run(args: BumpVersion) -> Result<()> {
let repo = Repository::open(".")?;
let latest_tag = get_latest_tag(&repo)?;
let latest_tag = get_latest_tag()?;
let current_version = Version::parse(&latest_tag)?;
let latest_tag_sha = repo.revparse_single(&format!("v{latest_tag}"))?.id();
let output = std::process::Command::new("git")
.args(["rev-parse", &format!("v{latest_tag}")])
.output()?;
if !output.status.success() {
anyhow::bail!(
"Failed to get tag SHA: {}",
String::from_utf8_lossy(&output.stderr)
);
}
let latest_tag_sha = String::from_utf8(output.stdout)?.trim().to_string();
let workspace_toml_version = Version::parse(&fetch_workspace_version()?)?;
@ -49,43 +65,57 @@ pub fn run(args: BumpVersion) -> Result<()> {
return Ok(());
}
let mut revwalk = repo.revwalk()?;
revwalk.push_range(format!("{latest_tag_sha}..HEAD").as_str())?;
let mut diff_options = DiffOptions::new();
let output = std::process::Command::new("git")
.args(["rev-list", &format!("{latest_tag_sha}..HEAD")])
.output()?;
if !output.status.success() {
anyhow::bail!(
"Failed to get commits: {}",
String::from_utf8_lossy(&output.stderr)
);
}
let commits = String::from_utf8(output.stdout)?
.lines()
.map(|s| s.to_string())
.collect::<Vec<_>>();
let mut should_increment_patch = false;
let mut should_increment_minor = false;
for oid in revwalk {
let oid = oid?;
let commit = repo.find_commit(oid)?;
let message = commit.message().unwrap();
let message = message.trim();
for commit_sha in commits {
let output = std::process::Command::new("git")
.args(["log", "-1", "--format=%s", &commit_sha])
.output()?;
if !output.status.success() {
continue;
}
let message = String::from_utf8(output.stdout)?.trim().to_string();
let diff = {
let parent = commit.parent(0).unwrap();
let parent_tree = parent.tree().unwrap();
let commit_tree = commit.tree().unwrap();
repo.diff_tree_to_tree(
Some(&parent_tree),
Some(&commit_tree),
Some(&mut diff_options),
)?
};
let output = std::process::Command::new("git")
.args([
"diff-tree",
"--no-commit-id",
"--name-only",
"-r",
&commit_sha,
])
.output()?;
if !output.status.success() {
continue;
}
let mut source_code_changed = false;
diff.foreach(
&mut |delta, _| {
let path = delta.new_file().path().unwrap().to_str().unwrap();
if path.ends_with("rs") || path.ends_with("js") || path.ends_with('c') {
source_code_changed = true;
}
true
},
None,
None,
None,
)?;
for path in String::from_utf8(output.stdout)?.lines() {
let path = Path::new(path);
if path.extension().is_some_and(|ext| {
ext.eq_ignore_ascii_case("rs")
|| ext.eq_ignore_ascii_case("js")
|| ext.eq_ignore_ascii_case("c")
}) {
source_code_changed = true;
break;
}
}
if source_code_changed {
should_increment_patch = true;
@ -138,16 +168,13 @@ pub fn run(args: BumpVersion) -> Result<()> {
update_cmake(&next_version)?;
update_npm(&next_version)?;
update_zig(&next_version)?;
tag_next_version(&repo, &next_version)?;
tag_next_version(&next_version)?;
Ok(())
}
fn tag_next_version(repo: &Repository, next_version: &Version) -> Result<()> {
let signature = repo.signature()?;
let commit_id = create_commit(
repo,
fn tag_next_version(next_version: &Version) -> Result<()> {
let commit_sha = create_commit(
&format!("{next_version}"),
&[
"Cargo.lock",
@ -166,15 +193,25 @@ fn tag_next_version(repo: &Repository, next_version: &Version) -> Result<()> {
],
)?;
let tag = repo.tag(
&format!("v{next_version}"),
&repo.find_object(commit_id, None)?,
&signature,
&format!("v{next_version}"),
false,
)?;
// Create tag
let output = std::process::Command::new("git")
.args([
"tag",
"-a",
&format!("v{next_version}"),
"-m",
&format!("v{next_version}"),
&commit_sha,
])
.output()?;
if !output.status.success() {
anyhow::bail!(
"Failed to create tag: {}",
String::from_utf8_lossy(&output.stderr)
);
}
println!("Tagged commit {commit_id} with tag {tag}");
println!("Tagged commit {commit_sha} with tag v{next_version}");
Ok(())
}
@ -256,8 +293,9 @@ fn update_npm(next_version: &Version) -> Result<()> {
"lib/binding_web/package.json",
"crates/cli/npm/package.json",
] {
let package_json =
serde_json::from_str::<serde_json::Value>(&std::fs::read_to_string(path)?)?;
let package_json = serde_json::from_str::<serde_json::Value>(
&std::fs::read_to_string(path).with_context(|| format!("Failed to read {path}"))?,
)?;
let mut package_json = package_json
.as_object()

View file

@ -9,12 +9,11 @@ mod generate;
mod test;
mod upgrade_wasmtime;
use std::path::Path;
use std::{path::Path, process::Command};
use anstyle::{AnsiColor, Color, Style};
use anyhow::Result;
use clap::{crate_authors, Args, Command, FromArgMatches as _, Subcommand};
use git2::{Oid, Repository};
use clap::{crate_authors, Args, FromArgMatches as _, Subcommand};
use semver::Version;
#[derive(Subcommand)]
@ -205,7 +204,7 @@ fn run() -> Result<()> {
);
let version: &'static str = Box::leak(version.into_boxed_str());
let cli = Command::new("xtask")
let cli = clap::Command::new("xtask")
.help_template(
"\
{before-help}{name} {version}
@ -296,27 +295,34 @@ const fn get_styles() -> clap::builder::Styles {
.placeholder(Style::new().fg_color(Some(Color::Ansi(AnsiColor::White))))
}
pub fn create_commit(repo: &Repository, msg: &str, paths: &[&str]) -> Result<Oid> {
let mut index = repo.index()?;
pub fn create_commit(msg: &str, paths: &[&str]) -> Result<String> {
for path in paths {
index.add_path(Path::new(path))?;
let output = Command::new("git").args(["add", path]).output()?;
if !output.status.success() {
anyhow::bail!(
"Failed to add {path}: {}",
String::from_utf8_lossy(&output.stderr)
);
}
}
index.write()?;
let output = Command::new("git").args(["commit", "-m", msg]).output()?;
if !output.status.success() {
anyhow::bail!(
"Failed to commit: {}",
String::from_utf8_lossy(&output.stderr)
);
}
let tree_id = index.write_tree()?;
let tree = repo.find_tree(tree_id)?;
let signature = repo.signature()?;
let parent_commit = repo.revparse_single("HEAD")?.peel_to_commit()?;
let output = Command::new("git").args(["rev-parse", "HEAD"]).output()?;
if !output.status.success() {
anyhow::bail!(
"Failed to get commit SHA: {}",
String::from_utf8_lossy(&output.stderr)
);
}
Ok(repo.commit(
Some("HEAD"),
&signature,
&signature,
msg,
&tree,
&[&parent_commit],
)?)
Ok(String::from_utf8(output.stdout)?.trim().to_string())
}
#[macro_export]

View file

@ -1,7 +1,6 @@
use std::process::Command;
use anyhow::{Context, Result};
use git2::Repository;
use semver::Version;
use crate::{create_commit, UpgradeWasmtime};
@ -93,9 +92,7 @@ pub fn run(args: &UpgradeWasmtime) -> Result<()> {
println!("Upgrading wasmtime for Zig");
update_zig(&args.version)?;
let repo = Repository::open(".")?;
create_commit(
&repo,
&format!("build(deps): bump wasmtime-c-api to v{}", args.version),
&["lib/Cargo.toml", "Cargo.lock", "build.zig.zon"],
)?;