Skip to content

Commit e2306a7

Browse files
committed
Support checking out the previous MR by using - instead of an MR number.
1 parent 520e5ce commit e2306a7

2 files changed

Lines changed: 77 additions & 21 deletions

File tree

src/git.rs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use anyhow::{anyhow, Result};
2-
use std::collections::HashSet;
2+
use logchop::OptionLogger;
33
use std::path::Path;
44
use std::str;
5+
use std::{collections::HashSet, convert::TryInto};
56

67
use duct::cmd;
78
use git2::{Config, Repository};
@@ -138,13 +139,50 @@ pub fn guess_default_remote_name() -> Result<String> {
138139
}
139140
}
140141

142+
/// Get the ID of the previous MR that had been checked out using git-req
143+
pub fn get_previous_mr_id() -> Result<i64> {
144+
let repo = Repository::open_from_env().expect("Couldn't find repository");
145+
let testco = repo.find_reference("git-req/previous")?;
146+
let content = testco.peel_to_blob()?;
147+
let binary = content.content();
148+
let reqnum = i64::from_le_bytes(binary.try_into()?);
149+
debug!("Loaded previous reference MR number: {}", reqnum);
150+
Ok(reqnum)
151+
}
152+
153+
/// Push a new `current` history ref, moving the existing `current` to `previous`
154+
pub fn push_current_ref(new_req_number: i64) -> Result<i64> {
155+
trace!("Storing refs for MR {}", new_req_number);
156+
let repo = Repository::open_from_env().expect("Couldn't find repository");
157+
let old_oid = match repo.find_reference("git-req/current") {
158+
Ok(current_ref) => current_ref
159+
.target()
160+
.debug_none("Could not peel current ref"),
161+
Err(_) => None,
162+
};
163+
let data = new_req_number.to_le_bytes();
164+
let new_oid = repo.blob(&data).unwrap();
165+
if let Some(oid) = old_oid {
166+
repo.reference("git-req/previous", oid, true, "").unwrap();
167+
debug!("Wrote old OID '{}' to git_req/previous", oid);
168+
};
169+
repo.reference("git-req/current", new_oid, true, "")?;
170+
Ok(new_req_number)
171+
}
172+
173+
#[derive(Debug)]
174+
pub enum CheckoutResult {
175+
BranchChanged,
176+
BranchUnchanged,
177+
}
178+
141179
/// Check out a branch by name
142180
pub fn checkout_branch(
143181
remote_name: &str,
144182
remote_branch_name: &str,
145183
local_branch_name: &str,
146184
is_virtual_remote_branch: bool,
147-
) -> Result<()> {
185+
) -> Result<CheckoutResult> {
148186
let repo = Repository::open_from_env().expect("Couldn't find repository");
149187
let local_branch_name = match get_project_config("defaultremote") {
150188
Some(default_remote_name) => {
@@ -166,8 +204,16 @@ pub fn checkout_branch(
166204
match local_branch_exists {
167205
Ok(_) => {
168206
debug!("Checking out branch: {}", local_branch_name);
207+
let head = repo.head()?;
208+
trace!("On head: {:?}", head.name());
209+
if head.is_branch()
210+
&& head.name().unwrap() == format!("refs/heads/{}", &local_branch_name)
211+
{
212+
// return Err(anyhow!("Already on {}", &local_branch_name));
213+
return Ok(CheckoutResult::BranchUnchanged);
214+
}
169215
match cmd!("git", "checkout", &local_branch_name).run() {
170-
Ok(_) => Ok(()),
216+
Ok(_) => Ok(CheckoutResult::BranchChanged),
171217
Err(err) => Err(anyhow!("Could not check out local branch: {}", err)),
172218
}
173219
}
@@ -203,7 +249,7 @@ pub fn checkout_branch(
203249
);
204250
};
205251
match cmd("git", checkout_args).run() {
206-
Ok(_) => Ok(()),
252+
Ok(_) => Ok(CheckoutResult::BranchChanged),
207253
Err(err) => Err(anyhow!("Could not check out local branch: {}", err)),
208254
}
209255
}

src/main.rs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use colored::*;
88
use git2::ErrorCode;
99
use lazy_static::lazy_static;
1010
use log::{debug, error, info, trace};
11-
use logchop::*;
1211
use std::io::{self, stdin, stdout, Cursor, Write};
1312
use std::{env, include_str, process};
1413
use tabwriter::TabWriter;
@@ -58,20 +57,27 @@ fn checkout_mr(remote_name: &str, mr_id: i64) {
5857
abort(&message);
5958
});
6059
debug!("Got remote branch name: {}", remote_branch_name);
61-
git::checkout_branch(
60+
match git::checkout_branch(
6261
remote_name,
6362
&remote_branch_name,
6463
&remote.get_local_req_branch(mr_id).unwrap(),
6564
remote.has_virtual_remote_branch_names(),
6665
)
67-
.info_ok("Done")
6866
.unwrap_or_else(|err| {
69-
eprintln!(
70-
"{}",
71-
format!("There was an error checking out the branch: {}", err).red()
72-
);
73-
process::exit(1)
74-
});
67+
let message = format!("There was an error checking out the branch: {}", err);
68+
abort(&message);
69+
}) {
70+
git::CheckoutResult::BranchChanged => {
71+
if git::push_current_ref(mr_id).is_err() {
72+
trace!("Couldn't update the current ref");
73+
eprintln!("{}", "failed to update some git-req metadata".yellow());
74+
}
75+
}
76+
_ => {
77+
eprintln!("Already on branch");
78+
}
79+
};
80+
trace!("Done");
7581
}
7682

7783
/// Clear the API key for the current domain
@@ -229,14 +235,18 @@ fn main() {
229235
app = build_cli();
230236
generate_completion(&mut app, &shell_name);
231237
} else {
232-
match matches.value_of("REQUEST_ID").unwrap().parse() {
233-
Ok(mr_id) => {
234-
checkout_mr(&get_remote_name(&matches), mr_id);
235-
}
236-
Err(_) => {
237-
eprintln!("{}", "Invalid request ID provided".red());
238-
process::exit(1);
239-
}
238+
let request_id = matches.value_of("REQUEST_ID").unwrap();
239+
let mr_id = if request_id == "-" {
240+
trace!("Received request for previous MR");
241+
git::get_previous_mr_id().unwrap_or_else(|_| {
242+
abort("Could not find previous request");
243+
})
244+
} else {
245+
trace!("Received request for numbered MR: {}", request_id);
246+
request_id.parse::<i64>().unwrap_or_else(|_| {
247+
abort("Invalid request ID provided");
248+
})
240249
};
250+
checkout_mr(&get_remote_name(&matches), mr_id);
241251
}
242252
}

0 commit comments

Comments
 (0)