Skip to content

Commit

Permalink
Fix error message for invalid subcommands (#227)
Browse files Browse the repository at this point in the history
  • Loading branch information
vigoo authored Jul 16, 2023
1 parent ded6f16 commit bc0dd10
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
31 changes: 29 additions & 2 deletions zio-cli/shared/src/main/scala/zio/cli/Command.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package zio.cli
import zio.cli.HelpDoc.h1
import zio.cli.ValidationErrorType.CommandMismatch
import zio.cli.oauth2.OAuth2PlatformSpecific
import zio.{IO, ZIO}
import zio.{Chunk, IO, ZIO}

/**
* A `Command` represents a command in a command-line application. Every command-line application will have at least one
Expand Down Expand Up @@ -35,6 +35,8 @@ sealed trait Command[+A] extends Parameter with Named { self =>
subcommands.copy(parent = subcommands.parent.withHelp(help)).asInstanceOf[Command[A]]
}

def getSubcommands: Map[String, Command[_]]

def helpDoc: HelpDoc

final def map[B](f: A => B): Command[B] = Command.Map(self, f)
Expand Down Expand Up @@ -158,6 +160,8 @@ object Command {
UsageSynopsis.Named(List(self.name), None) + self.options.synopsis + self.args.synopsis

def pipeline = ("", List(options, args))

def getSubcommands: Predef.Map[String, Command[_]] = Predef.Map(self.name -> self)
}

final case class Map[A, B](command: Command[A], f: A => B) extends Command[B] with Pipeline with Wrap { self =>
Expand All @@ -178,6 +182,8 @@ object Command {
override def wrapped: Command[A] = self.command

def pipeline = ("", List(command))

def getSubcommands: Predef.Map[String, Command[_]] = self.command.getSubcommands
}

final case class OrElse[A](left: Command[A], right: Command[A]) extends Command[A] with Alternatives { self =>
Expand All @@ -195,6 +201,7 @@ object Command {

override val alternatives = List(left, right)

def getSubcommands: Predef.Map[String, Command[_]] = self.left.getSubcommands ++ self.right.getSubcommands
}

final case class Subcommands[A, B](parent: Command[A], child: Command[B]) extends Command[(A, B)] with Pipeline {
Expand Down Expand Up @@ -282,14 +289,32 @@ object Command {

self.parent
.parse(args, conf)
.debug("Subcommand parent parse")
.flatMap {
case CommandDirective.BuiltIn(BuiltInOption.ShowHelp(_, _)) =>
helpDirectiveForChild orElse helpDirectiveForParent
case CommandDirective.BuiltIn(BuiltInOption.ShowWizard(_)) =>
wizardDirectiveForChild orElse wizardDirectiveForParent
case builtIn @ CommandDirective.BuiltIn(_) => ZIO.succeed(builtIn)
case CommandDirective.UserDefined(leftover, a) if leftover.nonEmpty =>
self.child.parse(leftover, conf).map(_.map((a, _)))
self.child
.parse(leftover, conf)
.mapBoth(
{
case ValidationError(CommandMismatch, _) =>
val parentName = self.names.headOption.getOrElse("")
val subCommandNames = Chunk.fromIterable(self.getSubcommands.keys).map(n => s"'$n'")
val oneOf = if (subCommandNames.size == 1) "" else " one of"
ValidationError(
CommandMismatch,
HelpDoc.p(
s"Invalid subcommand for ${parentName}. Use$oneOf ${subCommandNames.mkString(", ")}"
)
)
case other: ValidationError => other
},
_.map((a, _))
)
case _ =>
helpDirectiveForParent
}
Expand All @@ -302,6 +327,8 @@ object Command {
lazy val synopsis: UsageSynopsis = self.parent.synopsis + self.child.synopsis

def pipeline = ("", List(parent, child))

def getSubcommands: Predef.Map[String, Command[_]] = self.child.getSubcommands
}

/**
Expand Down
14 changes: 14 additions & 0 deletions zio-cli/shared/src/test/scala/zio/cli/CommandSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ object CommandSpec extends ZIOSpecDefault {
assertZIO(git.parse(List("git", "log"), CliConfig.default))(
equalTo(CommandDirective.UserDefined(Nil, ()))
)
},
test("test unknown sub command error message") {
assertZIO(git.parse(List("git", "abc"), CliConfig.default).flip.map { e =>
e.error
})(
equalTo(HelpDoc.p("Invalid subcommand for git. Use one of 'remote', 'log'"))
)
}
)
}: _*),
Expand Down Expand Up @@ -149,6 +156,13 @@ object CommandSpec extends ZIOSpecDefault {
equalTo(ValidationErrorType.CommandMismatch)
)
},
test("test unknown sub command error message") {
assertZIO(git.parse(List("git", "abc"), CliConfig.default).flip.map { e =>
e.error
})(
equalTo(HelpDoc.p("Invalid subcommand for git. Use 'rebase'"))
)
},
test("test without sub command") {
git.parse(List("git"), CliConfig.default).map { result =>
assertTrue {
Expand Down

0 comments on commit bc0dd10

Please sign in to comment.