Skip to content

Commit 4e38d4f

Browse files
JadedBlueEyesnik-rev
authored andcommitted
feat: Allow specifying branches in config
1 parent 097e1d4 commit 4e38d4f

File tree

4 files changed

+159
-36
lines changed

4 files changed

+159
-36
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,15 @@ pull-requests = [
6969
"11164",
7070
]
7171

72+
# List of branches from other repositories to merge
73+
# Format: "owner/repo/branch"
74+
branches = [
75+
# Include master branch from another repo
76+
"helix-editor/helix/master",
77+
# Include a specific commit from a branch
78+
"helix-editor/helix/master @ 6049f20",
79+
]
80+
7281
# An optional list of patches to apply, more on them later
7382
patches = ["remove-tab"]
7483
```
@@ -133,6 +142,11 @@ pull-requests = [
133142
"145 @ fccc58957eece10d0818dfa000bf5123e26ee32f",
134143
"88 @ a556aeef3736a3b6b79bb9507d26224f5c0c3449"
135144
]
145+
146+
branches = [
147+
"helix-editor/helix/master @ 6049f20b7e3ca83f832790a0ad84d85a56205d47",
148+
"other-user/fork/feature-branch @ 3a56b1c"
149+
]
136150
```
137151

138152
Where the hashes represent each `sha1` hash of every commit.

example-config.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,30 @@ local-branch = "patchy"
5454

5555
pull-requests = []
5656

57+
# List of branches from other repositories to merge into the repository
58+
# Format: "owner/repo/branch"
59+
#
60+
# Examples
61+
#
62+
# branches = [
63+
# "helix-editor/helix/master",
64+
# "other-user/fork/feature-branch"
65+
# ]
66+
#
67+
# The above always fetch the latest commit for each branch.
68+
#
69+
# To use a specific commit, use the following syntax:
70+
# "<owner/repo/branch> @ <hash-of-commit>"
71+
#
72+
# so for example:
73+
#
74+
# branches = [
75+
# "helix-editor/helix/master",
76+
# "other-user/fork/feature-branch @ a556aeef3736a3b6b79bb9507d26224f5c0c3449"
77+
# ]
78+
79+
branches = []
80+
5781
# Optional: A list of patches to apply
5882
#
5983
# A patch allows you to do specify custom commits and not have to rely on there being a pull request for that change

src/commands/run.rs

Lines changed: 117 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -130,54 +130,135 @@ pub async fn run(yes: bool) -> anyhow::Result<()> {
130130
&info.remote.local_remote_alias,
131131
)?;
132132

133-
if config.pull_requests.is_empty() {
133+
let has_pull_requests = !config.pull_requests.is_empty();
134+
let has_branches = !config.branches.is_empty();
135+
136+
if !has_pull_requests && !has_branches {
134137
log::info!(
135-
"You haven't specified any pull requests to fetch in your config, {}",
138+
"You haven't specified any pull requests or branches to fetch in your config, {}",
136139
display_link(
137140
"see the instructions on how to configure patchy.",
138141
"https://github.com/nik-rev/patchy?tab=readme-ov-file#config"
139142
)
140143
);
141144
} else {
142-
// TODO: make this concurrent, see https://users.rust-lang.org/t/processing-subprocesses-concurrently/79638/3
143-
// Git cannot handle multiple threads executing commands in the same repository,
144-
// so we can't use threads, but we can run processes in the background
145-
for pull_request in &config.pull_requests {
146-
let pull_request = ignore_octothorpe(pull_request);
147-
let (pull_request, commit_hash) = parse_if_maybe_hash(&pull_request, " @ ");
148-
// TODO: refactor this to not use such deep nesting
149-
match git::fetch_pull_request(&config.repo, &pull_request, None, commit_hash.as_ref())
145+
// Process pull requests
146+
if has_pull_requests {
147+
// TODO: make this concurrent, see https://users.rust-lang.org/t/processing-subprocesses-concurrently/79638/3
148+
// Git cannot handle multiple threads executing commands in the same repository,
149+
// so we can't use threads, but we can run processes in the background
150+
for pull_request in &config.pull_requests {
151+
let pull_request = ignore_octothorpe(pull_request);
152+
let (pull_request, commit_hash) = parse_if_maybe_hash(&pull_request, " @ ");
153+
// TODO: refactor this to not use such deep nesting
154+
match git::fetch_pull_request(
155+
&config.repo,
156+
&pull_request,
157+
None,
158+
commit_hash.as_ref(),
159+
)
150160
.await
151-
{
152-
Ok((response, info)) => {
153-
match git::merge_pull_request(
154-
&info,
155-
&pull_request,
156-
&response.title,
157-
&response.html_url,
158-
) {
159-
Ok(()) => {
160-
success!(
161-
"Merged pull request {}",
162-
display_link(
163-
&format!(
164-
"{}{}{}{}",
165-
"#".bright_blue(),
166-
pull_request.bright_blue(),
167-
" ".bright_blue(),
168-
&response.title.bright_blue().italic()
161+
{
162+
Ok((response, info)) => {
163+
match git::merge_pull_request(
164+
&info,
165+
&pull_request,
166+
&response.title,
167+
&response.html_url,
168+
) {
169+
Ok(()) => {
170+
success!(
171+
"Merged pull request {}",
172+
display_link(
173+
&format!(
174+
"{}{}{}{}",
175+
"#".bright_blue(),
176+
pull_request.bright_blue(),
177+
" ".bright_blue(),
178+
&response.title.bright_blue().italic()
179+
),
180+
&response.html_url
169181
),
170-
&response.html_url
171-
),
172-
);
173-
}
174-
Err(err) => {
175-
fail!("{err}");
182+
);
183+
}
184+
Err(err) => {
185+
fail!("{err}");
186+
}
176187
}
177188
}
189+
Err(err) => {
190+
fail!("Could not fetch branch from remote\n{err}");
191+
}
178192
}
179-
Err(err) => {
180-
fail!("Could not fetch branch from remote\n{err}");
193+
}
194+
}
195+
196+
// Process branches
197+
if has_branches {
198+
for branch_entry in &config.branches {
199+
let (branch_path, commit_hash) = parse_if_maybe_hash(branch_entry, " @ ");
200+
201+
// Parse the branch path into owner/repo/branch format
202+
let parts: Vec<&str> = branch_path.split('/').collect();
203+
if parts.len() < 3 {
204+
fail!(
205+
"Invalid branch format: {}. Expected format: owner/repo/branch",
206+
branch_path
207+
);
208+
continue;
209+
}
210+
211+
let owner = parts[0];
212+
let repo = parts[1];
213+
let branch_name = parts[2..].join("/");
214+
215+
let remote = crate::cli::Remote {
216+
owner: owner.to_string(),
217+
repo: repo.to_string(),
218+
branch: branch_name.clone(),
219+
};
220+
221+
match git::fetch_branch(&remote, commit_hash.as_ref()).await {
222+
Ok((_, info)) => {
223+
match git::merge_into_main(
224+
&info.branch.local_branch_name,
225+
&info.branch.upstream_branch_name,
226+
) {
227+
Ok(_) => {
228+
success!(
229+
"Merged branch {}/{}/{} {}",
230+
owner.bright_blue(),
231+
repo.bright_blue(),
232+
branch_name.bright_blue(),
233+
commit_hash
234+
.map(|hash| format!(
235+
"at commit {}",
236+
hash.as_ref().bright_yellow()
237+
))
238+
.unwrap_or_default()
239+
);
240+
241+
// Clean up the remote branch
242+
if let Err(err) = git::delete_remote_and_branch(
243+
&info.remote.local_remote_alias,
244+
&info.branch.local_branch_name,
245+
) {
246+
fail!("Failed to clean up branch: {err}");
247+
}
248+
}
249+
Err(err) => {
250+
fail!("{err}");
251+
}
252+
}
253+
}
254+
Err(err) => {
255+
fail!(
256+
"Could not fetch branch {}/{}/{}: {err}",
257+
owner,
258+
repo,
259+
branch_name
260+
);
261+
}
181262
}
182263
}
183264
}

src/types.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ use serde::{Deserialize, Serialize};
66
#[serde(rename_all = "kebab-case")]
77
pub struct Configuration {
88
pub local_branch: String,
9+
#[serde(default)]
910
pub patches: IndexSet<String>,
11+
#[serde(default)]
1012
pub pull_requests: Vec<String>,
13+
#[serde(default)]
14+
pub branches: Vec<String>,
1115
pub remote_branch: String,
1216
pub repo: String,
1317
}

0 commit comments

Comments
 (0)