Skip to content

Commit 7d7f416

Browse files
committed
Stack Entry: Carry associated review information
Stack entries also know the associtated forge review ID.
1 parent 7ad4653 commit 7d7f416

File tree

4 files changed

+33
-8
lines changed

4 files changed

+33
-8
lines changed

crates/but-api/src/legacy/virtual_branches.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,16 @@ pub fn create_virtual_branch(ctx: &mut Context, branch: BranchCreateRequest) ->
5959
.context("BUG: didn't find a stack that was just created")?;
6060
let stack = &new_ws.stacks[stack_idx];
6161
let tip = stack.segments[segment_idx].tip().unwrap_or(repo.object_hash().null());
62+
let review_id = stack.segments[segment_idx]
63+
.metadata
64+
.as_ref()
65+
.and_then(|meta| meta.review.pull_request);
6266

6367
let out = StackEntryNoOpt {
6468
id: stack.id.context("BUG: all new stacks are created with an ID")?,
6569
heads: vec![StackHeadInfo {
6670
name: new_ref.shorten().into(),
71+
review_id,
6772
tip,
6873
is_checked_out: false,
6974
}],

crates/but-workspace/src/legacy/stacks.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ fn id_from_name_v2_to_v3_opt(
5252
}))
5353
}
5454

55+
/// Get the associated forge review information out of the metadata, if any.
56+
fn review_id_from_meta(
57+
name: &gix::refs::FullNameRef,
58+
meta: &VirtualBranchesTomlMetadata,
59+
) -> anyhow::Result<Option<usize>> {
60+
let ref_meta = meta.branch(name)?;
61+
Ok(ref_meta.review.pull_request)
62+
}
63+
5564
/// Returns the list of branch information for the branches in a stack.
5665
pub fn stack_heads_info(stack: &Stack, repo: &gix::Repository) -> anyhow::Result<Vec<StackHeadInfo>> {
5766
let branches = stack
@@ -62,6 +71,7 @@ pub fn stack_heads_info(stack: &Stack, repo: &gix::Repository) -> anyhow::Result
6271
let tip = branch.head_oid(repo).ok()?;
6372
Some(StackHeadInfo {
6473
name: branch.name().to_owned().into(),
74+
review_id: branch.pr_number,
6575
tip,
6676
is_checked_out: false,
6777
})
@@ -84,6 +94,7 @@ fn try_from_stack_v3(
8494
.segments
8595
.into_iter()
8696
.map(|segment| -> anyhow::Result<_> {
97+
let review_id = segment.metadata.and_then(|meta| meta.review.pull_request);
8798
let ref_name = segment
8899
.ref_info
89100
.context("This type can't represent this state and it shouldn't have to")?
@@ -95,6 +106,7 @@ fn try_from_stack_v3(
95106
.and_then(|r| r.try_id())
96107
.map(|id| id.detach())
97108
.unwrap_or(repo.object_hash().null()),
109+
review_id,
98110
name: ref_name.shorten().into(),
99111
is_checked_out: segment.is_entrypoint,
100112
})
@@ -160,6 +172,7 @@ pub fn stacks_v3(
160172
heads: vec![StackHeadInfo {
161173
name: ref_name.shorten().into(),
162174
tip,
175+
review_id: review_id_from_meta(ref_name.as_ref(), meta)?,
163176
is_checked_out: false,
164177
}],
165178
tip,

crates/but-workspace/src/legacy/ui.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ pub struct StackHeadInfo {
1818
#[serde(with = "but_serde::object_id")]
1919
#[cfg_attr(feature = "export-ts", ts(type = "string"))]
2020
pub tip: gix::ObjectId,
21+
/// The associated forge review with this branch, e.g. GitHub PRs or GitLab MRs
22+
pub review_id: Option<usize>,
2123
/// If `true`, then this head is checked directly so `HEAD` points to it, and this is only ever `true` for a single head.
2224
/// This is `false` if the worktree is checked out.
2325
pub is_checked_out: bool,

crates/but/src/command/legacy/forge/review.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub async fn create_pr(
8686
Some(get_branch_names(&ctx.legacy_project, &branch_id)?)
8787
} else {
8888
// Find branches without PRs
89-
let branches_without_prs = get_branches_without_prs(&review_map, &applied_stacks);
89+
let branches_without_prs = get_branches_without_prs(&review_map, &applied_stacks)?;
9090

9191
if branches_without_prs.is_empty() {
9292
if let Some(out) = out.for_human() {
@@ -169,19 +169,25 @@ async fn ensure_forge_authentication(ctx: &mut Context) -> Result<(), anyhow::Er
169169
fn get_branches_without_prs(
170170
review_map: &std::collections::HashMap<String, Vec<but_forge::ForgeReview>>,
171171
applied_stacks: &[but_workspace::legacy::ui::StackEntry],
172-
) -> Vec<String> {
172+
) -> anyhow::Result<Vec<String>> {
173173
let mut branches_without_prs = Vec::new();
174174
for stack_entry in applied_stacks {
175175
for head in &stack_entry.heads {
176-
let branch_name = head.name.to_string();
177-
if !review_map.contains_key(&branch_name)
178-
|| review_map.get(&branch_name).map(|v| v.is_empty()).unwrap_or(true)
176+
let branch_name = &head.name.to_string();
177+
if !review_map.contains_key(branch_name)
178+
|| review_map.get(branch_name).map(|v| v.is_empty()).unwrap_or(true)
179179
{
180-
branches_without_prs.push(branch_name);
180+
// This means that there are no associated reviews that are open, but that doesn't mean that there are
181+
// no associated reviews.
182+
// Check whether there's an associated forge review.
183+
if head.review_id.is_none() {
184+
// If there's no associated review, the append the branch
185+
branches_without_prs.push(branch_name.to_owned());
186+
}
181187
}
182188
}
183189
}
184-
branches_without_prs
190+
Ok(branches_without_prs)
185191
}
186192

187193
fn get_branch_names(project: &Project, branch_id: &str) -> anyhow::Result<Vec<String>> {
@@ -776,7 +782,6 @@ pub fn get_review_map(
776782
cache_config: Option<but_forge::CacheConfig>,
777783
) -> anyhow::Result<std::collections::HashMap<String, Vec<but_forge::ForgeReview>>> {
778784
let reviews = but_api::legacy::forge::list_reviews(ctx, cache_config).unwrap_or_default();
779-
780785
let branch_review_map = reviews
781786
.into_iter()
782787
.fold(std::collections::HashMap::new(), |mut acc, r| {

0 commit comments

Comments
 (0)