Skip to content

Commit 52439c2

Browse files
committed
interactive: add pr github action
1 parent 5110b8c commit 52439c2

File tree

4 files changed

+99
-24
lines changed

4 files changed

+99
-24
lines changed

src/commands/interactive/command.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use ratatui::{
1414
};
1515

1616
use super::{
17-
Action, EventSource, Focus, StatusMessage, WorktreeEntry,
17+
Action, EventSource, Focus, Selection, StatusMessage, WorktreeEntry,
1818
dialog::{CreateDialog, CreateDialogFocus, Dialog},
1919
view::{DetailData, DialogView, Snapshot},
2020
};
@@ -72,7 +72,7 @@ where
7272
}
7373
}
7474

75-
pub fn run<F, G>(mut self, mut on_remove: F, mut on_create: G) -> Result<Option<String>>
75+
pub fn run<F, G>(mut self, mut on_remove: F, mut on_create: G) -> Result<Option<Selection>>
7676
where
7777
F: FnMut(&str) -> Result<()>,
7878
G: FnMut(&str, Option<&str>) -> Result<()>,
@@ -90,7 +90,11 @@ where
9090
result
9191
}
9292

93-
fn event_loop<F, G>(&mut self, on_remove: &mut F, on_create: &mut G) -> Result<Option<String>>
93+
fn event_loop<F, G>(
94+
&mut self,
95+
on_remove: &mut F,
96+
on_create: &mut G,
97+
) -> Result<Option<Selection>>
9498
where
9599
F: FnMut(&str) -> Result<()>,
96100
G: FnMut(&str, Option<&str>) -> Result<()>,
@@ -203,7 +207,9 @@ where
203207
Focus::Worktrees => {
204208
if let Some(index) = self.selected {
205209
return Ok(LoopControl::Exit(
206-
self.worktrees.get(index).map(|entry| entry.name.clone()),
210+
self.worktrees
211+
.get(index)
212+
.map(|entry| Selection::Worktree(entry.name.clone())),
207213
));
208214
}
209215
}
@@ -212,7 +218,9 @@ where
212218
match action {
213219
Action::Open => {
214220
if let Some(entry) = self.current_entry() {
215-
return Ok(LoopControl::Exit(Some(entry.name.clone())));
221+
return Ok(LoopControl::Exit(Some(Selection::Worktree(
222+
entry.name.clone(),
223+
))));
216224
}
217225
self.status = Some(StatusMessage::info("No worktree selected."));
218226
}
@@ -224,6 +232,14 @@ where
224232
Some(StatusMessage::info("No worktree selected to remove."));
225233
}
226234
}
235+
Action::PrGithub => {
236+
if let Some(entry) = self.current_entry() {
237+
return Ok(LoopControl::Exit(Some(Selection::PrGithub(
238+
entry.name.clone(),
239+
))));
240+
}
241+
self.status = Some(StatusMessage::info("No worktree selected."));
242+
}
227243
}
228244
}
229245
Focus::GlobalActions => match self.global_action_selected {
@@ -233,9 +249,7 @@ where
233249
self.dialog = Some(Dialog::Create(dialog));
234250
}
235251
1 => {
236-
return Ok(LoopControl::Exit(Some(
237-
super::REPO_ROOT_SELECTION.to_string(),
238-
)));
252+
return Ok(LoopControl::Exit(Some(Selection::RepoRoot)));
239253
}
240254
_ => {}
241255
},
@@ -641,7 +655,7 @@ where
641655

642656
enum LoopControl {
643657
Continue,
644-
Exit(Option<String>),
658+
Exit(Option<Selection>),
645659
}
646660

647661
fn build_detail_data(entry: &WorktreeEntry) -> DetailData {

src/commands/interactive/mod.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,26 +55,34 @@ impl Focus {
5555
}
5656

5757
pub(crate) const GLOBAL_ACTIONS: [&str; 2] = ["Create worktree", "Cd to root dir"];
58-
pub(crate) const REPO_ROOT_SELECTION: &str = "__RSWORKTREE_REPO_ROOT__";
58+
59+
#[derive(Clone, Debug, PartialEq, Eq)]
60+
pub(crate) enum Selection {
61+
Worktree(String),
62+
PrGithub(String),
63+
RepoRoot,
64+
}
5965

6066
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6167
pub(crate) enum Action {
6268
Open,
6369
Remove,
70+
PrGithub,
6471
}
6572

6673
impl Action {
67-
pub(crate) const ALL: [Action; 2] = [Action::Open, Action::Remove];
74+
pub(crate) const ALL: [Action; 3] = [Action::Open, Action::Remove, Action::PrGithub];
6875

6976
pub(crate) fn label(self) -> &'static str {
7077
match self {
7178
Action::Open => "Open",
7279
Action::Remove => "Remove",
80+
Action::PrGithub => "PR (GitHub)",
7381
}
7482
}
7583

7684
pub(crate) fn requires_selection(self) -> bool {
77-
matches!(self, Action::Open | Action::Remove)
85+
matches!(self, Action::Open | Action::Remove | Action::PrGithub)
7886
}
7987

8088
pub(crate) fn from_index(index: usize) -> Self {

src/commands/interactive/runtime.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ use crate::{
1414
cd::{CdCommand, shell_command},
1515
create::{CreateCommand, CreateOutcome},
1616
list::{find_worktrees, format_worktree},
17+
pr_github::{PrGithubCommand, PrGithubOptions},
1718
rm::RemoveCommand,
1819
},
1920
};
2021

21-
use super::{EventSource, REPO_ROOT_SELECTION, WorktreeEntry, command::InteractiveCommand};
22+
use super::{EventSource, Selection, WorktreeEntry, command::InteractiveCommand};
2223

2324
pub struct CrosstermEvents;
2425

@@ -91,12 +92,29 @@ pub fn run(repo: &Repo) -> Result<()> {
9192
}
9293
};
9394

94-
if let Some(name) = selection {
95-
if name == REPO_ROOT_SELECTION {
96-
cd_repo_root(repo)?;
97-
} else {
98-
let command = CdCommand::new(name, false);
99-
command.execute(repo)?;
95+
if let Some(selection) = selection {
96+
match selection {
97+
Selection::RepoRoot => {
98+
cd_repo_root(repo)?;
99+
}
100+
Selection::Worktree(name) => {
101+
let command = CdCommand::new(name, false);
102+
command.execute(repo)?;
103+
}
104+
Selection::PrGithub(name) => {
105+
let options = PrGithubOptions {
106+
name,
107+
push: true,
108+
draft: false,
109+
fill: false,
110+
web: false,
111+
remote: String::from("origin"),
112+
reviewers: Vec::new(),
113+
extra_args: Vec::new(),
114+
};
115+
let mut command = PrGithubCommand::new(options);
116+
command.execute(repo)?;
117+
}
100118
}
101119
}
102120

src/commands/interactive/tests.rs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ fn returns_first_worktree_when_enter_pressed_immediately() -> Result<()> {
5858
let selection = command
5959
.run(|_| Ok(()), |_, _| panic!("create should not be called"))?
6060
.expect("expected selection");
61-
assert_eq!(selection, "alpha");
61+
assert_eq!(selection, Selection::Worktree(String::from("alpha")));
6262

6363
Ok(())
6464
}
@@ -81,7 +81,42 @@ fn navigates_down_before_selecting() -> Result<()> {
8181
let selection = command
8282
.run(|_| Ok(()), |_, _| panic!("create should not be called"))?
8383
.expect("expected selection");
84-
assert_eq!(selection, "beta");
84+
assert_eq!(selection, Selection::Worktree(String::from("beta")));
85+
86+
Ok(())
87+
}
88+
89+
#[test]
90+
fn selecting_pr_github_action_exits_with_pr_variant() -> Result<()> {
91+
let backend = TestBackend::new(40, 12);
92+
let terminal = Terminal::new(backend)?;
93+
let events = StubEvents::new(vec![
94+
key(KeyCode::Tab),
95+
key(KeyCode::Down),
96+
key(KeyCode::Down),
97+
key(KeyCode::Enter),
98+
]);
99+
let worktrees = entries(&["alpha", "beta"]);
100+
let command = InteractiveCommand::new(
101+
terminal,
102+
events,
103+
PathBuf::from("/tmp/worktrees"),
104+
worktrees,
105+
vec![String::from("main")],
106+
Some(String::from("main")),
107+
);
108+
109+
let mut removed = Vec::new();
110+
let result = command.run(
111+
|name| {
112+
removed.push(name.to_owned());
113+
Ok(())
114+
},
115+
|_, _| panic!("create should not be called"),
116+
)?;
117+
118+
assert!(removed.is_empty(), "remove should not be triggered");
119+
assert_eq!(result, Some(Selection::PrGithub(String::from("alpha"))));
85120

86121
Ok(())
87122
}
@@ -199,7 +234,7 @@ fn create_action_adds_new_worktree() -> Result<()> {
199234
},
200235
)?;
201236

202-
assert_eq!(result, Some(String::from("new")));
237+
assert_eq!(result, Some(Selection::Worktree(String::from("new"))));
203238
assert_eq!(
204239
created,
205240
vec![(String::from("new"), Some(String::from("main")))]
@@ -260,7 +295,7 @@ fn cd_to_root_global_action_exits() -> Result<()> {
260295

261296
let result = command.run(|_| Ok(()), |_, _| Ok(()))?;
262297

263-
assert_eq!(result, Some(String::from(super::REPO_ROOT_SELECTION)));
298+
assert_eq!(result, Some(Selection::RepoRoot));
264299

265300
Ok(())
266301
}
@@ -287,7 +322,7 @@ fn up_from_top_moves_to_global_actions() -> Result<()> {
287322

288323
let result = command.run(|_| Ok(()), |_, _| Ok(()))?;
289324

290-
assert_eq!(result, Some(String::from(super::REPO_ROOT_SELECTION)));
325+
assert_eq!(result, Some(Selection::RepoRoot));
291326

292327
Ok(())
293328
}

0 commit comments

Comments
 (0)