diff --git a/docs/docs/commands/doctor.md b/docs/docs/commands/doctor.md index c05bfae0..9fdd42ed 100644 --- a/docs/docs/commands/doctor.md +++ b/docs/docs/commands/doctor.md @@ -36,6 +36,7 @@ Options: -o, --only When set, only the checks listed will run -f, --fix When set, if a fix is specified it will also run [default: true] [possible values: true, false] -n, --no-cache When set cache will be disabled, forcing all file based checks to run + --yolo Automatically approve all fix prompts without asking (excluded default args) ``` diff --git a/scope/src/doctor/commands/run.rs b/scope/src/doctor/commands/run.rs index 10507097..7fc75fd1 100644 --- a/scope/src/doctor/commands/run.rs +++ b/scope/src/doctor/commands/run.rs @@ -33,6 +33,9 @@ pub struct DoctorRunArgs { /// Do not ask, create report on failure #[arg(long, default_value = "false", env = "SCOPE_DOCTOR_AUTO_PUBLISH")] pub auto_publish_report: bool, + /// Automatically approve all fix prompts without asking + #[arg(long, short = 'y', default_value = "false")] + pub yolo: bool, } fn get_cache(args: &DoctorRunArgs) -> Arc { @@ -101,6 +104,7 @@ pub async fn doctor_run(found_config: &FoundConfig, args: &DoctorRunArgs) -> Res let run_groups = RunGroups { group_actions: transform.groups, all_paths, + yolo: args.yolo, }; let result = run_groups.execute().await?; diff --git a/scope/src/doctor/runner.rs b/scope/src/doctor/runner.rs index bd950a90..9c82d709 100644 --- a/scope/src/doctor/runner.rs +++ b/scope/src/doctor/runner.rs @@ -180,6 +180,7 @@ where { pub(crate) group_actions: BTreeMap>, pub(crate) all_paths: Vec, + pub(crate) yolo: bool, } impl RunGroups @@ -293,8 +294,9 @@ where )); action_span.pb_set_style(&progress_bar_without_pos()); + let prompt_fn = if self.yolo { auto_approve } else { prompt_user }; let action_result = action - .run_action(prompt_user) + .run_action(prompt_fn) .instrument(action_span.clone()) .await?; @@ -362,6 +364,14 @@ fn prompt_user(prompt_text: &str, maybe_help_text: &Option) -> bool { }) } +fn auto_approve(prompt_text: &str, maybe_help_text: &Option) -> bool { + println!("{} Yes (auto-approved)", prompt_text); + if let Some(help_text) = maybe_help_text { + println!("[{}]", help_text); + } + true +} + async fn report_action_output( group_name: &str, action: &T, @@ -753,6 +763,7 @@ mod tests { "group_2".to_string(), "group_3".to_string(), ], + yolo: false, }; let exit_code = run_groups.execute().await?; @@ -784,6 +795,7 @@ mod tests { "skipped_1".to_string(), "skipped_2".to_string(), ], + yolo: false, }; let exit_code = run_groups.execute().await?; @@ -821,6 +833,7 @@ mod tests { "user_denies".to_string(), "skipped".to_string(), ], + yolo: false, }; let exit_code = run_groups.execute().await?; @@ -868,6 +881,7 @@ mod tests { "user_denies".to_string(), "succeeds_2".to_string(), ], + yolo: false, }; let exit_code = run_groups.execute().await?; @@ -911,6 +925,7 @@ mod tests { "fails".to_string(), "succeeds_2".to_string(), ], + yolo: false, }; let exit_code = run_groups.execute().await?; @@ -1019,6 +1034,7 @@ mod tests { let run_groups = RunGroups { group_actions: BTreeMap::new(), all_paths: Vec::new(), + yolo: false, }; let group_span = info_span!("test_group", "indicatif.pb_show" = true); @@ -1072,6 +1088,7 @@ mod tests { let run_groups = RunGroups { group_actions: BTreeMap::new(), all_paths: Vec::new(), + yolo: false, }; let group_span = info_span!("test_group", "indicatif.pb_show" = true); diff --git a/scope/tests/scope_doctor.rs b/scope/tests/scope_doctor.rs index e985f9a2..ad0386c0 100644 --- a/scope/tests/scope_doctor.rs +++ b/scope/tests/scope_doctor.rs @@ -270,3 +270,23 @@ fn test_group_skip_subsequent_groups_run() { test_helper.clean_work_dir(); } + +#[test] +fn test_yolo_flag_auto_approves_fix_prompts() { + let test_helper = ScopeTestHelper::new( + "test_yolo_flag_auto_approves_fix_prompts", + "fix-with-prompt", + ); + + // Without --yolo, the fix would be skipped because user can't confirm in non-interactive mode. + // With --yolo, the fix should run automatically and succeed. + let result = test_helper.doctor_run(Some(&["--yolo"])); + + result + .success() + .stdout(predicate::str::contains( + "Check initially failed, fix was successful, group: \"prompt-test\", name: \"needs-approval\"", + )); + + test_helper.clean_work_dir(); +} diff --git a/scope/tests/test-cases/fix-with-prompt/.scope/group.yaml b/scope/tests/test-cases/fix-with-prompt/.scope/group.yaml new file mode 100644 index 00000000..e05c053d --- /dev/null +++ b/scope/tests/test-cases/fix-with-prompt/.scope/group.yaml @@ -0,0 +1,18 @@ +apiVersion: scope.github.com/v1alpha +kind: ScopeDoctorGroup +metadata: + name: prompt-test + description: Test fix that requires user confirmation +spec: + actions: + - name: needs-approval + description: A fix that needs user approval before running + check: + commands: + - test -f {{ working_dir }}/approved-file.txt + fix: + prompt: + text: "Do you want to create the file?" + extraContext: "This will create approved-file.txt" + commands: + - touch {{ working_dir }}/approved-file.txt