Skip to content

Commit

Permalink
Merge pull request #27 from jakedeichert/error-when-no-script-and-mis…
Browse files Browse the repository at this point in the history
…sing-subcommand

Error when command has no script and missing subcommand
  • Loading branch information
jacobdeichert authored Jul 29, 2019
2 parents a524e31 + 1225e30 commit 12b600e
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 16 deletions.
20 changes: 12 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ use std::env;
use std::path::Path;

use clap::{
crate_authors, crate_description, crate_name, crate_version, App, Arg, ArgMatches, SubCommand,
crate_authors, crate_description, crate_name, crate_version, App, AppSettings, Arg, ArgMatches,
SubCommand,
};
use colored::*;

use mask::command::Command;
use mask::executor::execute_command;

fn main() {
let cli_app = App::new(crate_name!())
.setting(AppSettings::VersionlessSubcommands)
.setting(AppSettings::SubcommandRequired)
.version(crate_version!())
.author(crate_authors!())
.about(crate_description!())
Expand All @@ -24,14 +28,10 @@ fn main() {

let root_command = mask::parser::build_command_structure(maskfile.unwrap());
let matches = build_subcommands(cli_app, &root_command.subcommands).get_matches();
let chosen_cmd = find_command(&matches, &root_command.subcommands);
if chosen_cmd.is_none() {
// Exit with an error
eprintln!("{} missing subcommand", "ERROR:".red());
std::process::exit(1);
}
let chosen_cmd = find_command(&matches, &root_command.subcommands)
.expect("SubcommandRequired failed to work");

match mask::executor::execute_command(chosen_cmd.unwrap(), maskfile_path) {
match execute_command(chosen_cmd, maskfile_path) {
Ok(status) => match status.code() {
Some(code) => std::process::exit(code),
None => return,
Expand Down Expand Up @@ -92,6 +92,10 @@ fn build_subcommands<'a, 'b>(
let mut subcmd = SubCommand::with_name(&c.name).about(c.desc.as_ref());
if !c.subcommands.is_empty() {
subcmd = build_subcommands(subcmd, &c.subcommands);
// If this parent command has no script source, require a subcommand.
if c.source == "" {
subcmd = subcmd.setting(AppSettings::SubcommandRequired);
}
}

// Add all required arguments
Expand Down
34 changes: 33 additions & 1 deletion tests/arguments_and_flags_test.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use assert_cmd::prelude::*;
use clap::{crate_name, crate_version};
use predicates::str::contains;

mod common;

use common::MaskCommandExt;

#[test]
Expand Down Expand Up @@ -84,3 +84,35 @@ fi
.stdout(contains("Starting an http server on PORT: 1234"))
.success();
}

mod version_flag {
use super::*;

#[test]
fn shows_the_correct_version_for_the_root_command() {
let (_temp, maskfile_path) = common::maskfile("## foo");

common::run_mask(&maskfile_path)
.command("--version")
.assert()
.stdout(contains(format!("{} {}", crate_name!(), crate_version!())))
.success();
}

#[test]
fn exits_with_error_when_subcommand_has_version_flag() {
let (_temp, maskfile_path) = common::maskfile("## foo");

// The setting "VersionlessSubcommands" removes the version flags (-V, --version)
// from subcommands. Only the root command has a version flag.

common::run_mask(&maskfile_path)
.command("foo")
.arg("--version")
.assert()
.stderr(contains(
"error: Found argument '--version' which wasn't expected, or isn't valid in this context",
))
.failure();
}
}
6 changes: 3 additions & 3 deletions tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ mod when_no_maskfile_found_in_current_directory {
use super::*;

#[test]
fn logs_warning_about_missing_maskfile_when_its_not_custom() {
fn logs_warning_about_missing_maskfile() {
common::run_mask(&PathBuf::from("./maskfile.md"))
.current_dir(".github")
.command("-V")
.assert()
.stdout(contains(format!(
"{} no maskfile.md found",
"WARNING:".yellow()
)))
.success();
)));
}

#[test]
Expand Down
53 changes: 49 additions & 4 deletions tests/subcommands_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use assert_cmd::prelude::*;
use colored::*;
use predicates::str::contains;
use predicates::str::{contains, is_empty};

mod common;

Expand Down Expand Up @@ -41,7 +40,7 @@ echo "Stopping service $service_name"
}

#[test]
fn exits_with_error_when_missing_subcommnad() {
fn exits_with_error_when_missing_subcommand() {
let (_temp, maskfile_path) = common::maskfile(
r#"
## foo
Expand All @@ -50,6 +49,52 @@ fn exits_with_error_when_missing_subcommnad() {

common::run_mask(&maskfile_path)
.assert()
.stderr(contains(format!("{} missing subcommand", "ERROR:".red())))
.stderr(contains(
"error: 'mask' requires a subcommand, but one was not provided",
))
.failure();
}

mod when_command_has_no_source {
use super::*;

#[test]
fn exits_gracefully_when_it_has_no_subcommands() {
let (_temp, maskfile_path) = common::maskfile(
r#"
## system
"#,
);

// NOTE: Right now we exit without an error. Perhaps there should at least
// be a warning logged to the console?
common::run_mask(&maskfile_path)
.command("system")
.assert()
.stdout(is_empty())
.success();
}

#[test]
fn exits_with_error_when_it_has_subcommands() {
let (_temp, maskfile_path) = common::maskfile(
r#"
## system
### start
~~~sh
echo "system, online"
~~~
"#,
);

common::run_mask(&maskfile_path)
.command("system")
.assert()
.stderr(contains(
"error: 'mask system' requires a subcommand, but one was not provided",
))
.failure();
}
}

0 comments on commit 12b600e

Please sign in to comment.