Skip to content

Commit 04df02d

Browse files
committed
preserve partial sha when sending to api
1 parent b662ada commit 04df02d

1 file changed

Lines changed: 28 additions & 211 deletions

File tree

src/utils/vcs.rs

Lines changed: 28 additions & 211 deletions
Original file line numberDiff line numberDiff line change
@@ -84,27 +84,17 @@ impl CommitSpec {
8484
}
8585

8686
pub fn reference(&self) -> GitReference<'_> {
87-
// Only treat as a commit OID if it's a full 40-character SHA
88-
if self.rev.len() == 40 && self.rev.chars().all(|c| c.is_ascii_hexdigit()) {
89-
if let Ok(oid) = git2::Oid::from_str(&self.rev) {
90-
GitReference::Commit(oid)
91-
} else {
92-
GitReference::Symbolic(&self.rev)
93-
}
87+
if let Ok(oid) = git2::Oid::from_str(&self.rev) {
88+
GitReference::Commit(oid)
9489
} else {
9590
GitReference::Symbolic(&self.rev)
9691
}
9792
}
9893

9994
pub fn prev_reference(&self) -> Option<GitReference<'_>> {
10095
self.prev_rev.as_ref().map(|rev| {
101-
// Only treat as a commit OID if it's a full 40-character SHA
102-
if rev.len() == 40 && rev.chars().all(|c| c.is_ascii_hexdigit()) {
103-
if let Ok(oid) = git2::Oid::from_str(rev) {
104-
GitReference::Commit(oid)
105-
} else {
106-
GitReference::Symbolic(rev)
107-
}
96+
if let Ok(oid) = git2::Oid::from_str(rev) {
97+
GitReference::Commit(oid)
10898
} else {
10999
GitReference::Symbolic(rev)
110100
}
@@ -449,6 +439,26 @@ fn find_matching_submodule(
449439
Ok(None)
450440
}
451441

442+
/// Helper function to determine which SHA to use for the API
443+
/// Returns the original partial SHA if it looks like a partial SHA that would be padded,
444+
/// otherwise returns the resolved SHA
445+
fn get_api_sha(original: &str, resolved: &str) -> String {
446+
// Check if original looks like a partial SHA (valid hex, 4-39 chars)
447+
let is_partial = original.len() >= 4 && original.len() < 40 && original.chars().all(|c| c.is_ascii_hexdigit());
448+
449+
// Check if this looks like a padded partial SHA
450+
// The resolved SHA should start with the original and be padded with zeros
451+
let is_padded = resolved.len() == 40
452+
&& resolved.starts_with(original)
453+
&& resolved[original.len()..].chars().all(|c| c == '0');
454+
455+
if is_padded && is_partial {
456+
original.to_owned() // Use original partial SHA
457+
} else {
458+
resolved.to_owned() // Use resolved SHA
459+
}
460+
}
461+
452462
fn find_matching_revs(
453463
spec: &CommitSpec,
454464
repos: &[Repo],
@@ -466,21 +476,21 @@ fn find_matching_revs(
466476
)
467477
}
468478

469-
let rev = if let Some(rev) = find_matching_rev(
479+
let rev = if let Some(resolved_sha) = find_matching_rev(
470480
spec.reference(),
471481
spec,
472482
repos,
473483
disable_discovery,
474484
remote_name.clone(),
475485
)? {
476-
rev
486+
get_api_sha(&spec.rev, &resolved_sha)
477487
} else {
478488
return Err(error(spec.reference(), &spec.repo));
479489
};
480490

481491
let prev_rev = if let Some(rev) = spec.prev_reference() {
482-
if let Some(rv) = find_matching_rev(rev, spec, repos, disable_discovery, remote_name)? {
483-
Some(rv)
492+
if let Some(resolved_sha) = find_matching_rev(rev, spec, repos, disable_discovery, remote_name)? {
493+
Some(get_api_sha(spec.prev_rev.as_ref().unwrap(), &resolved_sha))
484494
} else {
485495
return Err(error(rev, &spec.repo));
486496
}
@@ -1311,71 +1321,6 @@ fn test_git_repo_head_ref() {
13111321
);
13121322
}
13131323

1314-
#[test]
1315-
fn test_partial_sha_resolution_with_real_git() {
1316-
let dir = git_initialize_repo();
1317-
1318-
git_create_commit(dir.path(), "test.txt", b"test content", "test commit");
1319-
1320-
// Get the full and short SHA
1321-
let full_sha_output = std::process::Command::new("git")
1322-
.args(["rev-parse", "HEAD"])
1323-
.current_dir(dir.path())
1324-
.output()
1325-
.expect("Failed to get full SHA");
1326-
let full_sha = String::from_utf8(full_sha_output.stdout)
1327-
.expect("Invalid UTF-8")
1328-
.trim()
1329-
.to_owned();
1330-
let short_sha_output = std::process::Command::new("git")
1331-
.args(["rev-parse", "--short", "HEAD"])
1332-
.current_dir(dir.path())
1333-
.output()
1334-
.expect("Failed to get short SHA");
1335-
let short_sha = String::from_utf8(short_sha_output.stdout)
1336-
.expect("Invalid UTF-8")
1337-
.trim()
1338-
.to_owned();
1339-
1340-
let spec = CommitSpec {
1341-
repo: "test-repo".to_owned(),
1342-
path: Some(dir.path().to_path_buf()),
1343-
rev: short_sha.clone(),
1344-
prev_rev: None,
1345-
};
1346-
1347-
match spec.reference() {
1348-
GitReference::Symbolic(s) => {
1349-
assert_eq!(s, short_sha);
1350-
}
1351-
GitReference::Commit(_) => {
1352-
panic!("Partial SHA should be treated as symbolic reference")
1353-
}
1354-
}
1355-
1356-
let reference = spec.reference();
1357-
let repos = [Repo {
1358-
id: String::from("1"),
1359-
name: String::from("test-repo"),
1360-
url: Some(String::from("https://github.com/test/test-repo")),
1361-
provider: RepoProvider {
1362-
id: String::from("integrations:github"),
1363-
name: String::from("GitHub"),
1364-
},
1365-
status: String::from("active"),
1366-
date_created: chrono::Utc::now(),
1367-
}];
1368-
1369-
let resolved_sha = find_matching_rev(reference, &spec, &repos, false, None)
1370-
.expect("Failed to resolve partial SHA")
1371-
.expect("Partial SHA should resolve to a commit");
1372-
1373-
assert_eq!(
1374-
resolved_sha, full_sha,
1375-
"Partial SHA {short_sha} should resolve to full SHA {full_sha}, but got {resolved_sha}"
1376-
);
1377-
}
1378-
13791324
#[cfg(test)]
13801325
mod tests {
13811326
use super::*;
@@ -1396,132 +1341,4 @@ mod tests {
13961341
std::env::remove_var("GITHUB_EVENT_NAME");
13971342
std::env::remove_var("GITHUB_REF");
13981343
}
1399-
1400-
#[test]
1401-
fn test_commit_spec_reference_partial_sha() {
1402-
let spec = CommitSpec {
1403-
repo: "test-repo".to_owned(),
1404-
path: None,
1405-
rev: "f915d32".to_owned(),
1406-
prev_rev: None,
1407-
};
1408-
1409-
match spec.reference() {
1410-
GitReference::Symbolic(s) => assert_eq!(s, "f915d32"),
1411-
GitReference::Commit(_) => {
1412-
panic!("Partial SHA should be treated as symbolic reference")
1413-
}
1414-
}
1415-
}
1416-
1417-
#[test]
1418-
fn test_commit_spec_reference_full_sha() {
1419-
let spec = CommitSpec {
1420-
repo: "test-repo".to_owned(),
1421-
path: None,
1422-
rev: "f915d32000000000000000000000000000000000".to_owned(),
1423-
prev_rev: None,
1424-
};
1425-
1426-
match spec.reference() {
1427-
GitReference::Commit(oid) => {
1428-
assert_eq!(oid.to_string(), "f915d32000000000000000000000000000000000");
1429-
}
1430-
GitReference::Symbolic(_) => panic!("Full SHA should be treated as commit OID"),
1431-
}
1432-
}
1433-
1434-
#[test]
1435-
fn test_commit_spec_reference_symbolic_refs() {
1436-
let test_cases = vec![
1437-
("main", "branch name"),
1438-
("v1.0.0", "tag name"),
1439-
("HEAD~1", "relative reference"),
1440-
("f915d32g", "invalid hex"),
1441-
];
1442-
1443-
for (rev, description) in test_cases {
1444-
let spec = CommitSpec {
1445-
repo: "test-repo".to_owned(),
1446-
path: None,
1447-
rev: rev.to_owned(),
1448-
prev_rev: None,
1449-
};
1450-
1451-
match spec.reference() {
1452-
GitReference::Symbolic(s) => assert_eq!(
1453-
s, rev,
1454-
"Failed for {description}: expected '{rev}', got '{s}'"
1455-
),
1456-
GitReference::Commit(_) => {
1457-
panic!("{description} should be treated as symbolic reference")
1458-
}
1459-
}
1460-
}
1461-
}
1462-
1463-
#[test]
1464-
fn test_commit_spec_prev_reference_partial_sha() {
1465-
let spec = CommitSpec {
1466-
repo: "test-repo".to_owned(),
1467-
path: None,
1468-
rev: "HEAD".to_owned(),
1469-
prev_rev: Some("4ebad56".to_owned()),
1470-
};
1471-
1472-
match spec.prev_reference().unwrap() {
1473-
GitReference::Symbolic(s) => assert_eq!(s, "4ebad56"),
1474-
GitReference::Commit(_) => {
1475-
panic!("Partial SHA in prev_rev should be treated as symbolic reference")
1476-
}
1477-
}
1478-
}
1479-
1480-
#[test]
1481-
fn test_commit_spec_prev_reference_full_sha() {
1482-
let spec = CommitSpec {
1483-
repo: "test-repo".to_owned(),
1484-
path: None,
1485-
rev: "HEAD".to_owned(),
1486-
prev_rev: Some("f915d32000000000000000000000000000000000".to_owned()),
1487-
};
1488-
1489-
match spec.prev_reference().unwrap() {
1490-
GitReference::Commit(oid) => {
1491-
assert_eq!(oid.to_string(), "f915d32000000000000000000000000000000000");
1492-
}
1493-
GitReference::Symbolic(_) => {
1494-
panic!("Full SHA in prev_rev should be treated as commit OID")
1495-
}
1496-
}
1497-
}
1498-
1499-
#[test]
1500-
fn test_commit_spec_prev_reference_symbolic_refs() {
1501-
let test_cases = vec![
1502-
("main", "branch name"),
1503-
("v1.0.0", "tag name"),
1504-
("HEAD~1", "relative reference"),
1505-
("f915d32g", "invalid hex"),
1506-
];
1507-
1508-
for (prev_rev, description) in test_cases {
1509-
let spec = CommitSpec {
1510-
repo: "test-repo".to_owned(),
1511-
path: None,
1512-
rev: "HEAD".to_owned(),
1513-
prev_rev: Some(prev_rev.to_owned()),
1514-
};
1515-
1516-
match spec.prev_reference().unwrap() {
1517-
GitReference::Symbolic(s) => assert_eq!(
1518-
s, prev_rev,
1519-
"Failed for {description}: expected '{prev_rev}', got '{s}'"
1520-
),
1521-
GitReference::Commit(_) => {
1522-
panic!("{description} in prev_rev should be treated as symbolic reference")
1523-
}
1524-
}
1525-
}
1526-
}
15271344
}

0 commit comments

Comments
 (0)