mod branch;
mod ci;
mod failed_run;
mod git;
mod github;
mod interrupt;
mod issue;
mod plugin;
mod poll;
mod preflight;
mod progress;
mod prompt;
#[cfg(test)]
mod prompts_page;
mod run;
mod session;
mod update;
mod worktree;
use std::process::ExitCode;
use issue::IssueUrl;
use run::Goal;
const HELP: &str = "\
thirdshift turns a GitHub issue into a ready-for-review pull request, or a merged one, unattended.
usage: thirdshift <Issue URL> Run the factory on the issue, from the clone on the Base branch
thirdshift merge <Issue URL> Run the factory on the issue, then merge its pull request
thirdshift update Update thirdshift to the latest release
thirdshift version Print thirdshift's version
thirdshift help Print this help
";
fn main() -> ExitCode {
let args: Vec<String> = std::env::args().skip(1).collect();
let (goal, rest) = match args.first().map(String::as_str) {
Some("help" | "--help" | "-h") => {
print!("{HELP}");
return ExitCode::SUCCESS;
}
Some("version" | "--version" | "-V") => {
println!("thirdshift {}", env!("CARGO_PKG_VERSION"));
return ExitCode::SUCCESS;
}
Some("update") => {
return match update::update() {
Ok(outcome) => {
progress::step(outcome);
ExitCode::SUCCESS
}
Err(error) => {
progress::step(format_args!("{error:#}"));
ExitCode::FAILURE
}
};
}
Some("merge" | "--merge") => (Goal::Merged, &args[1..]),
_ => (Goal::ReadyForReview, &args[..]),
};
let Some((url, after)) = rest.split_first() else {
return argument_error(format_args!("missing Issue URL"));
};
let issue = match IssueUrl::parse(url) {
Ok(issue) => issue,
Err(error) => return argument_error(format_args!("{error:#}")),
};
if let Some(extra) = after.first() {
return argument_error(format_args!(
"unexpected argument after the Issue URL: {extra}"
));
}
if let Err(error) = interrupt::install() {
progress::step(format_args!("{error:#}"));
return ExitCode::FAILURE;
}
match run::run(&issue, goal) {
Ok(pr_url) => {
progress::step(format_args!("PR {pr_url} {}", goal.outcome()));
println!("{pr_url}");
ExitCode::SUCCESS
}
Err(failed) => {
progress::step(format_args!("{:#}", failed.error));
if let Some(log) = failed.log {
progress::step(format_args!("session log: {}", log.display()));
}
if let Some(pr_url) = failed.pr_url {
println!("{pr_url}");
}
ExitCode::FAILURE
}
}
}
fn argument_error(error: std::fmt::Arguments) -> ExitCode {
progress::step(error);
eprint!("\n{HELP}");
ExitCode::from(2)
}