Skip to content

Commit

Permalink
Fill in pre-commit env vars
Browse files Browse the repository at this point in the history
  • Loading branch information
j178 committed Nov 4, 2024
1 parent 736aca6 commit 6151cb3
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 40 deletions.
55 changes: 31 additions & 24 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,30 +204,7 @@ pub(crate) enum HookType {
}

#[derive(Debug, Clone, Args)]
pub(crate) struct RunArgs {
/// The hook ID to run.
#[arg(value_name = "HOOK")]
pub(crate) hook_id: Option<String>,
/// Run on all files in the repo.
#[arg(short, long, conflicts_with_all = ["files", "from_ref", "to_ref"])]
pub(crate) all_files: bool,
/// Specific filenames to run hooks on.
#[arg(long, conflicts_with_all = ["all_files", "from_ref", "to_ref"])]
pub(crate) files: Vec<PathBuf>,
/// The original ref in a `from_ref...to_ref` diff expression.
/// Files changed in this diff will be run through the hooks.
#[arg(short = 's', long, alias = "source", requires = "to_ref")]
pub(crate) from_ref: Option<String>,
/// The destination ref in a `from_ref...to_ref` diff expression.
/// Files changed in this diff will be run through the hooks.
#[arg(short = 'o', long, alias = "origin", requires = "from_ref")]
pub(crate) to_ref: Option<String>,
/// The stage during which the hook is fired.
#[arg(long)]
pub(crate) hook_stage: Option<Stage>,
/// When hooks fail, run `git diff` directly afterward.
#[arg(long)]
pub(crate) show_diff_on_failure: bool,
pub(crate) struct RunMiscArgs {
#[arg(long, hide = true)]
pub(crate) remote_branch: Option<String>,
#[arg(long, hide = true)]
Expand All @@ -254,6 +231,36 @@ pub(crate) struct RunArgs {
pub(crate) rewrite_command: Option<String>,
}

#[derive(Debug, Clone, Args)]
pub(crate) struct RunArgs {
/// The hook ID to run.
#[arg(value_name = "HOOK")]
pub(crate) hook_id: Option<String>,
/// Run on all files in the repo.
#[arg(short, long, conflicts_with_all = ["files", "from_ref", "to_ref"])]
pub(crate) all_files: bool,
/// Specific filenames to run hooks on.
#[arg(long, conflicts_with_all = ["all_files", "from_ref", "to_ref"])]
pub(crate) files: Vec<PathBuf>,
/// The original ref in a `from_ref...to_ref` diff expression.
/// Files changed in this diff will be run through the hooks.
#[arg(short = 's', long, alias = "source", requires = "to_ref")]
pub(crate) from_ref: Option<String>,
/// The destination ref in a `from_ref...to_ref` diff expression.
/// Files changed in this diff will be run through the hooks.
#[arg(short = 'o', long, alias = "origin", requires = "from_ref")]
pub(crate) to_ref: Option<String>,
/// The stage during which the hook is fired.
#[arg(long)]
pub(crate) hook_stage: Option<Stage>,
/// When hooks fail, run `git diff` directly afterward.
#[arg(long)]
pub(crate) show_diff_on_failure: bool,

#[command(flatten)]
pub(crate) misc: RunMiscArgs,
}

#[derive(Debug, Args)]
pub(crate) struct AutoUpdateArgs {
#[arg(long, default_value_t = true)]
Expand Down
75 changes: 61 additions & 14 deletions src/cli/run.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::fmt::Write;
use std::path::{Path, PathBuf};

Expand All @@ -10,7 +11,7 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator};
use tokio::process::Command;
use tracing::{debug, trace};

use crate::cli::ExitStatus;
use crate::cli::{ExitStatus, RunMiscArgs};
use crate::config::Stage;
use crate::fs::{normalize_path, Simplified};
use crate::git::{get_all_files, get_changed_files, get_staged_files, has_unmerged_paths, GIT};
Expand All @@ -29,7 +30,7 @@ pub(crate) async fn run(
all_files: bool,
files: Vec<PathBuf>,
show_diff_on_failure: bool,
commit_msg_filename: Option<PathBuf>,
misc_args: RunMiscArgs,
verbose: bool,
printer: Printer,
) -> Result<ExitStatus> {
Expand All @@ -54,23 +55,15 @@ pub(crate) async fn run(
return Ok(ExitStatus::Failure);
}

if matches!(hook_stage, Some(Stage::PrepareCommitMsg | Stage::CommitMsg))
&& commit_msg_filename.is_none()
{
writeln!(
printer.stderr(),
"`--commit-msg-filename` is required for stage `{}`",
hook_stage.unwrap().cyan()
)?;
return Ok(ExitStatus::Failure);
}
// Prevent recursive post-checkout hooks.
if matches!(hook_stage, Some(Stage::PostCheckout))
&& std::env::var_os("_PRE_COMMIT_SKIP_POST_CHECKOUT").is_some()
{
return Ok(ExitStatus::Success);
}

let env_vars = fill_envs(from_ref.as_ref(), to_ref.as_ref(), &misc_args);

let mut project = Project::new(config_file)?;
let store = Store::from_settings()?.init()?;

Expand Down Expand Up @@ -136,7 +129,7 @@ pub(crate) async fn run(
to_ref,
all_files,
files,
commit_msg_filename,
misc_args.commit_msg_filename.as_ref(),
)
.await?;
for filename in &mut filenames {
Expand Down Expand Up @@ -164,6 +157,7 @@ pub(crate) async fn run(
&hooks,
&skips,
filenames,
env_vars,
project.config().fail_fast.unwrap_or(false),
show_diff_on_failure,
verbose,
Expand All @@ -186,6 +180,59 @@ async fn config_not_staged(config: &Path) -> Result<bool> {
Ok(!output.success())
}

fn fill_envs(
from_ref: Option<&String>,
to_ref: Option<&String>,
args: &RunMiscArgs,
) -> HashMap<&'static str, String> {
let mut env = HashMap::new();
env.insert("PRE_COMMIT", "1".into());

if let Some(ref source) = args.prepare_commit_message_source {
env.insert("PRE_COMMIT_COMMIT_MSG_SOURCE", source.clone());
}
if let Some(ref object) = args.commit_object_name {
env.insert("PRE_COMMIT_COMMIT_OBJECT_NAME", object.clone());
}
if let Some(from_ref) = from_ref {
env.insert("PRE_COMMIT_ORIGIN", from_ref.clone());
env.insert("PRE_COMMIT_FROM_REF", from_ref.clone());
}
if let Some(to_ref) = to_ref {
env.insert("PRE_COMMIT_SOURCE", to_ref.clone());
env.insert("PRE_COMMIT_TO_REF", to_ref.clone());
}
if let Some(ref upstream) = args.pre_rebase_upstream {
env.insert("PRE_COMMIT_PRE_REBASE_UPSTREAM", upstream.clone());
}
if let Some(ref branch) = args.pre_rebase_branch {
env.insert("PRE_COMMIT_PRE_REBASE_BRANCH", branch.clone());
}
if let Some(ref branch) = args.local_branch {
env.insert("PRE_COMMIT_LOCAL_BRANCH", branch.clone());
}
if let Some(ref branch) = args.remote_branch {
env.insert("PRE_COMMIT_REMOTE_BRANCH", branch.clone());
}
if let Some(ref name) = args.remote_name {
env.insert("PRE_COMMIT_REMOTE_NAME", name.clone());
}
if let Some(ref url) = args.remote_url {
env.insert("PRE_COMMIT_REMOTE_URL", url.clone());
}
if let Some(ref checkout) = args.checkout_type {
env.insert("PRE_COMMIT_CHECKOUT_TYPE", checkout.clone());
}
if args.is_squash_merge {
env.insert("PRE_COMMIT_SQUASH_MERGE", "1".into());
}
if let Some(ref command) = args.rewrite_command {
env.insert("PRE_COMMIT_REWRITE_COMMAND", command.clone());
}

env
}

fn get_skips() -> Vec<String> {
match std::env::var_os("SKIP") {
Some(s) if !s.is_empty() => s
Expand All @@ -206,7 +253,7 @@ async fn all_filenames(
to_ref: Option<String>,
all_files: bool,
files: Vec<PathBuf>,
commit_msg_filename: Option<PathBuf>,
commit_msg_filename: Option<&PathBuf>,
) -> Result<Vec<String>> {
if hook_stage.is_some_and(|stage| !stage.operate_on_files()) {
return Ok(vec![]);
Expand Down
5 changes: 3 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ fn adjust_relative_paths(mut cli: Cli, new_cwd: &Path) -> Result<Cli> {
.iter()
.map(|path| fs::relative_to(std::path::absolute(path)?, new_cwd))
.collect::<Result<Vec<PathBuf>, std::io::Error>>()?;
args.commit_msg_filename = args
args.misc.commit_msg_filename = args
.misc
.commit_msg_filename
.as_ref()
.map(|path| fs::relative_to(std::path::absolute(path)?, new_cwd))
Expand Down Expand Up @@ -178,7 +179,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.all_files,
args.files,
args.show_diff_on_failure,
args.commit_msg_filename,
args.misc,
cli.globals.verbose > 0,
printer,
)
Expand Down
3 changes: 3 additions & 0 deletions src/run.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::cmp::max;
use std::collections::HashMap;
use std::fmt::Write as _;
use std::future::Future;
use std::io::Write as _;
Expand Down Expand Up @@ -120,6 +121,8 @@ pub async fn run_hooks(
hooks: &[Hook],
skips: &[String],
filenames: Vec<String>,
// TODO: pass down env vars
_env_vars: HashMap<&'static str, String>,
fail_fast: bool,
show_diff_on_failure: bool,
verbose: bool,
Expand Down

0 comments on commit 6151cb3

Please sign in to comment.