use crate::common::{TestRepo, make_snapshot_cmd, repo, setup_snapshot_settings};
use insta_cmd::assert_cmd_snapshot;
use rstest::rstest;
use std::io::Write;
use std::process::Stdio;
#[rstest]
fn test_step_alias_from_project_config(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
hello = "echo Hello from {{ branch }}"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["hello", "--yes"],
Some(&feature_path),
));
}
#[rstest]
fn test_step_alias_dry_run(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
hello = "echo Hello from {{ branch }}"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["hello", "--dry-run"],
Some(&feature_path),
));
}
#[rstest]
fn test_step_alias_unknown_with_available(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
hello = "echo Hello"
deploy = "make deploy"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["nonexistent"],
Some(&feature_path),
));
}
#[rstest]
fn test_step_alias_did_you_mean(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
deploy = "make deploy"
hello = "echo Hello"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["deplyo"],
Some(&feature_path),
));
}
#[rstest]
fn test_step_alias_unknown_no_aliases(mut repo: TestRepo) {
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["deploy"],
Some(&feature_path),
));
}
#[rstest]
fn test_step_alias_with_var(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
greet = "echo Hello {{ name }} from {{ branch }}"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["greet", "--dry-run", "--var", "name=World", "--yes"],
Some(&feature_path),
));
}
#[rstest]
fn test_step_alias_exit_code(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
fail = "exit 42"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["fail", "--yes"],
Some(&feature_path),
));
}
#[rstest]
fn test_step_alias_from_user_config(mut repo: TestRepo) {
let feature_path = repo.add_worktree("feature");
repo.write_test_config(
r#"
[aliases]
greet = "echo Greetings from {{ branch }}"
"#,
);
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["greet"],
Some(&feature_path),
));
}
#[rstest]
fn test_step_alias_shadows_builtin(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
commit = "echo custom-commit"
hello = "echo hello"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["nonexistent"],
Some(&feature_path),
));
}
#[rstest]
fn test_step_alias_shadows_builtin_plural(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
commit = "echo custom-commit"
rebase = "echo custom-rebase"
hello = "echo hello"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["nonexistent"],
Some(&feature_path),
));
}
#[rstest]
fn test_step_alias_merge_user_and_project(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
project-cmd = "echo from-project"
shared = "echo project-version"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
repo.write_test_config(
r#"
[aliases]
user-cmd = "echo from-user"
shared = "echo user-version"
"#,
);
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(
"user_alias",
make_snapshot_cmd(
&repo,
"step",
&["user-cmd", "--dry-run"],
Some(&feature_path),
)
);
assert_cmd_snapshot!(
"project_alias",
make_snapshot_cmd(
&repo,
"step",
&["project-cmd", "--dry-run", "--yes"],
Some(&feature_path),
)
);
assert_cmd_snapshot!(
"user_and_project_append",
make_snapshot_cmd(&repo, "step", &["shared", "--dry-run"], Some(&feature_path),)
);
}
#[rstest]
fn test_alias_append_executes_both(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
greet = "echo PROJECT"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
repo.write_test_config(
r#"
[aliases]
greet = "echo USER"
"#,
);
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["greet", "--yes"],
Some(&feature_path),
));
}
fn snapshot_alias_approval(
test_name: &str,
repo: &TestRepo,
alias_args: &[&str],
approve: bool,
cwd: Option<&std::path::Path>,
) {
let mut cmd = make_snapshot_cmd(repo, "step", alias_args, cwd);
cmd.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let mut child = cmd.spawn().unwrap();
{
let stdin = child.stdin.as_mut().unwrap();
let response = if approve { b"y\n" } else { b"n\n" };
stdin.write_all(response).unwrap();
}
let output = child.wait_with_output().unwrap();
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let combined = format!(
"exit_code: {}\n----- stdout -----\n{}\n----- stderr -----\n{}",
output.status.code().unwrap_or(-1),
stdout,
stderr
);
insta::assert_snapshot!(test_name, combined);
}
#[rstest]
fn test_alias_approval_project_config_prompts(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
deploy = "echo deploying {{ branch }}"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["deploy"],
Some(&feature_path),
));
}
#[rstest]
fn test_alias_approval_already_approved(mut repo: TestRepo) {
repo.run_git(&["remote", "remove", "origin"]);
repo.write_project_config(
r#"
[aliases]
deploy = "echo deploying {{ branch }}"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
repo.write_test_approvals(&format!(
r#"[projects.'{}']
approved-commands = ["echo deploying {{{{ branch }}}}"]
"#,
repo.project_id()
));
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["deploy"],
Some(&feature_path),
));
}
#[rstest]
fn test_alias_approval_user_config_skips(mut repo: TestRepo) {
let feature_path = repo.add_worktree("feature");
repo.write_test_config(
r#"
[aliases]
deploy = "echo deploying from user config"
"#,
);
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["deploy"],
Some(&feature_path),
));
}
#[rstest]
fn test_alias_approval_user_and_project_both_need_approval(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
deploy = "echo project deploy"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
repo.write_test_config(
r#"
[aliases]
deploy = "echo user deploy"
"#,
);
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(make_snapshot_cmd(
&repo,
"step",
&["deploy", "--yes"],
Some(&feature_path),
));
}
#[rstest]
fn test_alias_approval_yes_bypasses(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
deploy = "echo deploying"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
assert_cmd_snapshot!(
"alias_approval_yes_first_run",
make_snapshot_cmd(&repo, "step", &["deploy", "--yes"], Some(&feature_path),)
);
assert_cmd_snapshot!(
"alias_approval_yes_second_run_prompts",
make_snapshot_cmd(&repo, "step", &["deploy"], Some(&feature_path),)
);
}
#[rstest]
fn test_alias_approval_decline(mut repo: TestRepo) {
repo.write_project_config(
r#"
[aliases]
deploy = "echo deploying"
"#,
);
repo.commit("Add alias config");
let feature_path = repo.add_worktree("feature");
let settings = setup_snapshot_settings(&repo);
let _guard = settings.bind_to_scope();
snapshot_alias_approval(
"alias_approval_decline",
&repo,
&["deploy"],
false,
Some(&feature_path),
);
}