upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/test_utils/src/lib.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-03-05 21:25:50 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-03-05 22:12:07 +0000
commitf6d1e03dc99b3ea48cb6e4bd1d3371dd924a567a (patch)
tree19fb789e83bd8d4ccc25f735a80cf41c0eccad17 /test_utils/src/lib.rs
parent83b0886b97e2e90e328f91fcfaeb59726c93308f (diff)
fix(pr-checkout): require --force on diverged proposal branch
checkout_patch() previously re-applied the patch chain whenever the local branch tip didn't match the published tip, silently overwriting local amendments and rebased revisions without warning. Now detects the relationship between local and published tips: - up to date: check out as-is - behind (local is ancestor of published): fast-forward, no flag needed - local commits on top (published is ancestor of local): check out as-is - diverged (neither ancestor): bail with guidance, --force to overwrite - published tip not found locally and branch exists: same as diverged Also adds --force flag to `ngit pr checkout` to explicitly opt in to overwriting a diverged branch, covering both local amendments and author force-pushes. Bug discovered during test implementation in tests/ngit_pr_checkout.rs.
Diffstat (limited to 'test_utils/src/lib.rs')
-rw-r--r--test_utils/src/lib.rs87
1 files changed, 87 insertions, 0 deletions
diff --git a/test_utils/src/lib.rs b/test_utils/src/lib.rs
index ae0fa66..ccd9d80 100644
--- a/test_utils/src/lib.rs
+++ b/test_utils/src/lib.rs
@@ -1532,6 +1532,93 @@ pub fn use_ngit_list_to_download_and_checkout_proposal_branch(
1532 Ok(()) 1532 Ok(())
1533} 1533}
1534 1534
1535/// Fetch proposals into the local cache and checkout the one matching
1536/// `branch_name_in_event` using `ngit pr checkout <id>`.
1537/// Requires relays to already be running.
1538pub fn use_ngit_pr_checkout(
1539 test_repo: &GitTestRepo,
1540 branch_name_in_event: &str,
1541) -> Result<()> {
1542 // populate the local cache
1543 let mut p = CliTester::new_from_dir(
1544 &test_repo.dir,
1545 [
1546 "--nsec",
1547 TEST_KEY_1_NSEC,
1548 "--password",
1549 TEST_PASSWORD,
1550 "--disable-cli-spinners",
1551 "pr",
1552 "list",
1553 ],
1554 );
1555 p.expect_end_eventually()?;
1556
1557 // resolve the event id offline from the now-populated cache
1558 let output = std::process::Command::new(assert_cmd::cargo::cargo_bin("ngit"))
1559 .env("NGITTEST", "TRUE")
1560 .current_dir(&test_repo.dir)
1561 .args([
1562 "--nsec",
1563 TEST_KEY_1_NSEC,
1564 "--password",
1565 TEST_PASSWORD,
1566 "--disable-cli-spinners",
1567 "pr",
1568 "list",
1569 "--json",
1570 "--offline",
1571 ])
1572 .output()?;
1573 let stdout = String::from_utf8(output.stdout)?;
1574 let proposals: Vec<serde_json::Value> = serde_json::from_str(&stdout)
1575 .map_err(|e| anyhow::anyhow!("failed to parse pr list json: {e}\nstdout: {stdout}"))?;
1576 let entry = proposals
1577 .iter()
1578 .find(|p| {
1579 p["branch"]
1580 .as_str()
1581 .map(|b| b.starts_with(&format!("pr/{branch_name_in_event}(")))
1582 .unwrap_or(false)
1583 })
1584 .ok_or_else(|| {
1585 anyhow::anyhow!(
1586 "no proposal found for branch {branch_name_in_event} in: {stdout}"
1587 )
1588 })?;
1589 let proposal_id = entry["id"].as_str().unwrap_or_default().to_string();
1590
1591 let status = std::process::Command::new(assert_cmd::cargo::cargo_bin("ngit"))
1592 .env("NGITTEST", "TRUE")
1593 .current_dir(&test_repo.dir)
1594 .args([
1595 "--nsec",
1596 TEST_KEY_1_NSEC,
1597 "--password",
1598 TEST_PASSWORD,
1599 "--disable-cli-spinners",
1600 "pr",
1601 "checkout",
1602 "--offline",
1603 &proposal_id,
1604 ])
1605 .status()?;
1606 anyhow::ensure!(status.success(), "ngit pr checkout exited with {status}");
1607 Ok(())
1608}
1609
1610/// Returns (originating_repo, test_repo) with proposal branch checked out.
1611/// Uses `ngit pr checkout` instead of the old interactive `ngit list`.
1612pub fn create_proposals_and_repo_with_proposal_branch_checked_out(
1613 branch_name_in_event: &str,
1614) -> Result<(GitTestRepo, GitTestRepo)> {
1615 let originating_repo = cli_tester_create_proposals()?;
1616 let test_repo = GitTestRepo::default();
1617 test_repo.populate()?;
1618 use_ngit_pr_checkout(&test_repo, branch_name_in_event)?;
1619 Ok((originating_repo, test_repo))
1620}
1621
1535pub fn remove_latest_commit_so_proposal_branch_is_behind_and_checkout_main( 1622pub fn remove_latest_commit_so_proposal_branch_is_behind_and_checkout_main(
1536 test_repo: &GitTestRepo, 1623 test_repo: &GitTestRepo,
1537) -> Result<String> { 1624) -> Result<String> {