Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion crates/but-gerrit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ rust-version.workspace = true

[lib]
doctest = false
test = false

[dependencies]
but-core.workspace = true
Expand All @@ -24,3 +23,11 @@ bstr.workspace = true
chrono.workspace = true
serde.workspace = true
gix = { workspace = true }

[dev-dependencies]

but-testsupport.workspace = true

gix = { workspace = true, features = ["revision"] }

tempfile = "3"
27 changes: 27 additions & 0 deletions crates/but-gerrit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ fn mappings(
push_output: PushOutput,
) -> anyhow::Result<Vec<ChangeIdMapping>> {
let mut mappings = vec![];
let host = gerrit_host(repo);
for id in candidate_ids {
let commit = repo.find_commit(id)?;
let msg = commit.message_bstr().to_string();
Expand All @@ -217,20 +218,46 @@ fn mappings(
.change_id()
.map(|change_id| (change_id, c.url.clone()))
});

if let Some((change_id, review_url)) = change_id_review_url {
mappings.push(ChangeIdMapping {
commit_id: id,
change_id,
review_url,
});
} else if let (Some(change_id), Some(host)) = (commit.change_id(), host.as_ref()) {
// Fallback: generate review URL if we have a change ID and a host
if let Ok(uuid) = uuid::Uuid::parse_str(&change_id) {
let gerrit_change_id = GerritChangeId::from(uuid);
let review_url = format!("https://{}/q/{}", host, gerrit_change_id);
mappings.push(ChangeIdMapping {
commit_id: id,
change_id,
review_url,
});
}
}
}
Ok(mappings)
}

fn gerrit_host(repo: &gix::Repository) -> Option<String> {
let name = repo.remote_default_name(gix::remote::Direction::Push);
let name = name
.as_ref()
.map(|n| n.as_ref())
.unwrap_or(b"origin".as_bstr());
let remote = repo.find_remote(name).ok()?;
let url = remote
.url(gix::remote::Direction::Push)
.or_else(|| remote.url(gix::remote::Direction::Fetch))?;
url.host().map(|h| h.to_string())
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn output_is_41_characters_long() {
let uuid = Uuid::new_v4();
Expand Down
70 changes: 70 additions & 0 deletions crates/but-gerrit/tests/integration_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use but_ctx::Context;
use but_gerrit::{GerritChangeId, parse::PushOutput, record_push_metadata};
use but_testsupport::CommandExt;

#[test]
fn test_record_push_metadata_fallback_url() {
let temp_dir = tempfile::tempdir().unwrap();
let gix_repo = gix::init(temp_dir.path()).unwrap();
let mut ctx = Context::from_repo(gix_repo.clone()).unwrap();

// 1. Create a commit with GitButler headers
let change_uuid = uuid::Uuid::new_v4();

let tree_id = gix_repo
.write_object(gix::objs::Tree::empty())
.unwrap()
.detach();
let author = gix::actor::Signature {
name: "Author".into(),
email: "author@example.com".into(),
time: gix::date::Time::now_local_or_utc(),
};
let committer = author.clone();

let commit_obj = gix::objs::Commit {
tree: tree_id,
parents: Default::default(),
author,
committer,
encoding: None,
message: "Test commit".into(),
extra_headers: vec![
(b"gitbutler-headers-version".into(), b"2".into()),
(
b"gitbutler-change-id".into(),
change_uuid.to_string().into(),
),
],
};
let commit_id = gix_repo.write_object(&commit_obj).unwrap().detach();

// 2. Set up a remote so we can derive the host
but_testsupport::git(&gix_repo)
.args(["remote", "add", "origin", "https://gerrithost/project"])
.run();

let gix_repo = gix::open(gix_repo.path()).unwrap();
let candidate_ids = vec![commit_id];
let push_output = PushOutput {
success: true,
warnings: vec![],
changes: vec![], // Empty changes to trigger fallback
processing_info: None,
};

record_push_metadata(&mut ctx, &gix_repo, candidate_ids, push_output).unwrap();

let mut db = ctx.db.get_mut().unwrap();
let mut db = db.gerrit_metadata();
let meta = db
.get(&change_uuid.to_string())
.unwrap()
.expect("Metadata should be recorded");

let gerrit_change_id = GerritChangeId::from(change_uuid);
assert_eq!(
meta.review_url,
format!("https://gerrithost/q/{}", gerrit_change_id)
);
}
Loading