From d9c345617500a830d748dbd2f74bf106c5f040d3 Mon Sep 17 00:00:00 2001 From: Lucien Cartier-Tilet Date: Sun, 8 Mar 2026 15:44:26 +0100 Subject: [PATCH] chore(build): preparing for CI --- .tarpaulin.ci.toml | 2 +- Cargo.toml | 7 +++ nix/package.nix | 12 ++++- nix/shell.nix | 18 +------ src/jj/lib_executor.rs | 111 +++++++++++++++++++++++++---------------- src/lib.rs | 5 +- 6 files changed, 90 insertions(+), 65 deletions(-) diff --git a/.tarpaulin.ci.toml b/.tarpaulin.ci.toml index 610e47e..f72d618 100644 --- a/.tarpaulin.ci.toml +++ b/.tarpaulin.ci.toml @@ -3,4 +3,4 @@ out = ["Xml"] target-dir = "coverage" output-dir = "coverage" fail-under = 60 -exclude-files = ["target/*"] +exclude-files = ["target/*", "private/*"] diff --git a/Cargo.toml b/Cargo.toml index a7be1f1..d76de0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,3 +37,10 @@ predicates = "3.1.3" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] } + +[profile.release] +opt-level = "z" +lto = true +codegen-units = 1 +panic = "abort" +strip = true diff --git a/nix/package.nix b/nix/package.nix index 9afe7d0..7b0a480 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -1,4 +1,5 @@ { + pkgs, rustPlatform, ... }: let @@ -8,8 +9,17 @@ rustBuild = rustPlatform.buildRustPackage { pname = name; inherit version; - src = ../.; + src = pkgs.lib.cleanSource ../.; cargoLock.lockFile = ../Cargo.lock; + buildInputs = [ pkgs.upx ]; + useNextest = true; + meta = { + description = "Conventional commits for Jujutsu"; + homepage = "https://labs.phundrak.com/phundrak/jj-cz"; + }; + postBuild = '' + ${pkgs.upx}/bin/upx target/*/release/${name} + ''; }; in { default = rustBuild; diff --git a/nix/shell.nix b/nix/shell.nix index 86ce32e..1dee101 100644 --- a/nix/shell.nix +++ b/nix/shell.nix @@ -19,26 +19,10 @@ inputs.devenv.lib.mkShell { }) bacon cargo-deny + cargo-nextest cargo-tarpaulin just ]; - - # processes.run.exec = "cargo watch -x run"; - - # enterShell = '' - # echo "" - # echo "Rust development environment loaded!" - # echo "Rust version: $(rustc --version)" - # echo "Cargo version: $(cargo --version)" - # echo "" - # echo "Available tools:" - # echo " - rust-analyzer (LSP)" - # echo " - clippy (linter)" - # echo " - rustfmt (formatter)" - # echo " - bacon (continuous testing/linting)" - # echo " - cargo-deny (dependency checker)" - # echo " - cargo-tarpaulin (code coverage)" - # ''; } ]; } diff --git a/src/jj/lib_executor.rs b/src/jj/lib_executor.rs index 9dc2e69..af8fd5a 100644 --- a/src/jj/lib_executor.rs +++ b/src/jj/lib_executor.rs @@ -127,44 +127,51 @@ impl JjExecutor for JjLib { #[cfg(test)] mod tests { use super::*; - use std::process::Command; - /// Initialize a jj repository in the given directory using `jj git init` - fn init_jj_repo(dir: &Path) -> std::io::Result<()> { - let output = Command::new("jj") - .args(["git", "init"]) - .current_dir(dir) - .output()?; - - if !output.status.success() { - return Err(std::io::Error::other(format!( - "jj git init failed: {}", - String::from_utf8_lossy(&output.stderr) - ))); - } - Ok(()) + /// Initialize a jj repository in the given directory using jj-lib directly + async fn init_jj_repo(dir: &Path) -> Result<(), String> { + let settings = JjLib::load_settings().map_err(|e| e.to_string())?; + Workspace::init_internal_git(&settings, dir) + .await + .map(|_| ()) + .map_err(|e| format!("Failed to init jj repo: {e}")) } - /// Get the current commit description from a jj repository - fn get_commit_description(dir: &Path) -> std::io::Result { - let output = Command::new("jj") - .args(["log", "-r", "@", "--no-graph", "-T", "description"]) - .current_dir(dir) - .output()?; + /// Get the current commit description from a jj repository using jj-lib + async fn get_commit_description(dir: &Path) -> Result { + let settings = JjLib::load_settings().map_err(|e| e.to_string())?; + let store_factories = StoreFactories::default(); + let wc_factories = default_working_copy_factories(); - if !output.status.success() { - return Err(std::io::Error::other(format!( - "jj log failed: {}", - String::from_utf8_lossy(&output.stderr) - ))); - } - Ok(String::from_utf8_lossy(&output.stdout).trim().to_string()) + let workspace = Workspace::load(&settings, dir, &store_factories, &wc_factories) + .map_err(|e| format!("Failed to load workspace: {e}"))?; + + let repo = workspace + .repo_loader() + .load_at_head() + .await + .map_err(|e| format!("Failed to load repo: {e}"))?; + + let wc_commit_id = repo + .view() + .get_wc_commit_id(WorkspaceName::DEFAULT) + .ok_or_else(|| "No working copy commit found".to_string())? + .clone(); + + let wc_commit = repo + .store() + .get_commit(&wc_commit_id) + .map_err(|e| format!("Failed to get commit: {e}"))?; + + Ok(wc_commit.description().trim_end().to_string()) } #[tokio::test] async fn is_repository_returns_true_inside_jj_repo() { let temp_dir = assert_fs::TempDir::new().unwrap(); - init_jj_repo(temp_dir.path()).expect("Failed to init jj repo"); + init_jj_repo(temp_dir.path()) + .await + .expect("Failed to init jj repo"); let executor = JjLib::with_working_dir(temp_dir.path()); let result = executor.is_repository().await; @@ -187,7 +194,9 @@ mod tests { #[tokio::test] async fn describe_updates_commit_description() { let temp_dir = assert_fs::TempDir::new().unwrap(); - init_jj_repo(temp_dir.path()).expect("Failed to init jj repo"); + init_jj_repo(temp_dir.path()) + .await + .expect("Failed to init jj repo"); let test_message = "test: initial commit"; let executor = JjLib::with_working_dir(temp_dir.path()); @@ -195,14 +204,18 @@ mod tests { let result = executor.describe(test_message).await; assert!(result.is_ok(), "describe failed: {result:?}"); - let actual = get_commit_description(temp_dir.path()).expect("Failed to get description"); + let actual = get_commit_description(temp_dir.path()) + .await + .expect("Failed to get description"); assert_eq!(actual, test_message); } #[tokio::test] async fn describe_handles_special_characters() { let temp_dir = assert_fs::TempDir::new().unwrap(); - init_jj_repo(temp_dir.path()).expect("Failed to init jj repo"); + init_jj_repo(temp_dir.path()) + .await + .expect("Failed to init jj repo"); let test_message = "feat: add feature with special chars !@#$%^&*()"; let executor = JjLib::with_working_dir(temp_dir.path()); @@ -210,14 +223,18 @@ mod tests { let result = executor.describe(test_message).await; assert!(result.is_ok()); - let actual = get_commit_description(temp_dir.path()).expect("Failed to get description"); + let actual = get_commit_description(temp_dir.path()) + .await + .expect("Failed to get description"); assert_eq!(actual, test_message); } #[tokio::test] async fn describe_handles_unicode() { let temp_dir = assert_fs::TempDir::new().unwrap(); - init_jj_repo(temp_dir.path()).expect("Failed to init jj repo"); + init_jj_repo(temp_dir.path()) + .await + .expect("Failed to init jj repo"); let test_message = "docs: add unicode support 🎉 🚀"; let executor = JjLib::with_working_dir(temp_dir.path()); @@ -225,14 +242,18 @@ mod tests { let result = executor.describe(test_message).await; assert!(result.is_ok()); - let actual = get_commit_description(temp_dir.path()).expect("Failed to get description"); + let actual = get_commit_description(temp_dir.path()) + .await + .expect("Failed to get description"); assert_eq!(actual, test_message); } #[tokio::test] async fn describe_handles_multiline_message() { let temp_dir = assert_fs::TempDir::new().unwrap(); - init_jj_repo(temp_dir.path()).expect("Failed to init jj repo"); + init_jj_repo(temp_dir.path()) + .await + .expect("Failed to init jj repo"); let test_message = "feat: add feature\n\nThis is a multiline\ndescription"; let executor = JjLib::with_working_dir(temp_dir.path()); @@ -240,7 +261,9 @@ mod tests { let result = executor.describe(test_message).await; assert!(result.is_ok()); - let actual = get_commit_description(temp_dir.path()).expect("Failed to get description"); + let actual = get_commit_description(temp_dir.path()) + .await + .expect("Failed to get description"); assert_eq!(actual, test_message); } @@ -258,7 +281,9 @@ mod tests { #[tokio::test] async fn describe_can_be_called_multiple_times() { let temp_dir = assert_fs::TempDir::new().unwrap(); - init_jj_repo(temp_dir.path()).expect("Failed to init jj repo"); + init_jj_repo(temp_dir.path()) + .await + .expect("Failed to init jj repo"); let executor = JjLib::with_working_dir(temp_dir.path()); @@ -266,16 +291,18 @@ mod tests { .describe("feat: first commit") .await .expect("First describe failed"); - let desc1 = - get_commit_description(temp_dir.path()).expect("Failed to get first description"); + let desc1 = get_commit_description(temp_dir.path()) + .await + .expect("Failed to get first description"); assert_eq!(desc1, "feat: first commit"); executor .describe("feat: updated commit") .await .expect("Second describe failed"); - let desc2 = - get_commit_description(temp_dir.path()).expect("Failed to get second description"); + let desc2 = get_commit_description(temp_dir.path()) + .await + .expect("Failed to get second description"); assert_eq!(desc2, "feat: updated commit"); } diff --git a/src/lib.rs b/src/lib.rs index 2055f33..d54ae18 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,4 @@ pub use crate::{ /// /// Enable with `--features test-utils` (e.g. `cargo test --features test-utils`). #[cfg(feature = "test-utils")] -pub use crate::{ - jj::mock::MockJjExecutor, - prompts::mock::MockPrompts, -}; +pub use crate::{jj::mock::MockJjExecutor, prompts::mock::MockPrompts};