use clap::{Parser, Subcommand};
use clap_complete::Shell;
use crate::runner::{Runner, Stage};
#[derive(Parser, Debug)]
#[command(
name = "jj-hooks",
about = "Run pre-commit / lefthook / hk hooks against jj bookmark pushes",
version,
propagate_version = true
)]
pub struct Cli {
#[arg(long, value_enum, global = true, env = "JJ_HOOKS_RUNNER")]
pub runner: Option<RunnerArg>,
#[arg(long, global = true, env = "JJ_HOOKS_LOG", default_value = "warn")]
pub log_level: String,
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand, Debug)]
pub enum Command {
Push {
#[arg(long)]
advance_bookmarks: bool,
#[arg(long, value_enum, default_value = "pre-push")]
stage: StageArg,
#[command(flatten)]
push: PushArgs,
#[arg(long)]
dry_run: bool,
#[arg(long)]
no_retry_after_fixup: bool,
},
Run {
#[arg(long, value_enum, default_value = "pre-commit")]
stage: StageArg,
#[arg(default_value = "@")]
revset: String,
#[arg(long)]
no_retry_after_fixup: bool,
#[arg(long)]
all_files: bool,
},
PushTags {
tags: Vec<String>,
#[arg(long, conflicts_with = "tags")]
all: bool,
#[arg(short = 'f', long)]
force: bool,
#[arg(short = 'n', long)]
dry_run: bool,
#[arg(long, default_value = "origin")]
remote: String,
},
Init,
Completions {
#[arg(value_enum)]
shell: Shell,
},
}
#[derive(clap::Args, Debug, Clone, Default)]
pub struct PushArgs {
#[arg(
short = 'b',
long,
action = clap::ArgAction::Append,
add = clap_complete::ArgValueCompleter::new(crate::completions::bookmark_value_completer),
)]
pub bookmark: Vec<String>,
#[arg(short = 'r', long, action = clap::ArgAction::Append)]
pub revision: Vec<String>,
#[arg(short = 'c', long, action = clap::ArgAction::Append)]
pub change: Vec<String>,
#[arg(
long,
add = clap_complete::ArgValueCompleter::new(crate::completions::remote_value_completer),
)]
pub remote: Option<String>,
#[arg(long)]
pub all: bool,
#[arg(long)]
pub tracked: bool,
#[arg(long)]
pub deleted: bool,
#[arg(long)]
pub allow_new: bool,
#[arg(last = true)]
pub passthrough: Vec<String>,
}
pub fn push_argv(args: &PushArgs, dry_run: bool) -> Vec<String> {
let mut out = Vec::new();
for b in &args.bookmark {
out.push("-b".into());
out.push(b.clone());
}
for r in &args.revision {
out.push("-r".into());
out.push(r.clone());
}
for c in &args.change {
out.push("-c".into());
out.push(c.clone());
}
if let Some(remote) = &args.remote {
out.push("--remote".into());
out.push(remote.clone());
}
if args.all {
out.push("--all".into());
}
if args.tracked {
out.push("--tracked".into());
}
if args.deleted {
out.push("--deleted".into());
}
if args.allow_new {
out.push("--allow-new".into());
}
if dry_run {
out.push("--dry-run".into());
}
out.extend(args.passthrough.iter().cloned());
out
}
#[derive(clap::ValueEnum, Debug, Clone, Copy)]
pub enum RunnerArg {
PreCommit,
Prek,
Lefthook,
Hk,
}
impl From<RunnerArg> for Runner {
fn from(value: RunnerArg) -> Self {
match value {
RunnerArg::PreCommit => Runner::PreCommit,
RunnerArg::Prek => Runner::Prek,
RunnerArg::Lefthook => Runner::Lefthook,
RunnerArg::Hk => Runner::Hk,
}
}
}
#[derive(clap::ValueEnum, Debug, Clone, Copy)]
pub enum StageArg {
PreCommit,
PrePush,
}
impl From<StageArg> for Stage {
fn from(value: StageArg) -> Self {
match value {
StageArg::PreCommit => Stage::PreCommit,
StageArg::PrePush => Stage::PrePush,
}
}
}