Using Swift Argument Parser to build CLI tools

May 9, 2021 · 3 minutes read

When it comes to writing CLI tools or simple scripts, bash is a pretty good solution. If you follow a few simple rules and make sure to check & document all your dependencies, you can create tools that work on a wide variety of systems and platforms (even Windows). However, where bash starts to fall down is when you need to create much more complex tooling. Not impossible, but it just gets harder and harder to maintain (and also lacks a few basic features of modern languages).

Enter Swift (my favorite language) and Apple’s Swift Argument Parser project. It’s an Open Source project actively maintained by Apple, that allows you to use Swift to create complex CLI tooling within a few minutes.

It literally takes you less than 3 minutes to set up the basic project and have the first CLI command ready (given that you already know Swift).

Have a look at this project for a simple CLI with two commands and a bunch of options/flags I created for a small project of mine.
The project is pretty self explanatory and Apple’s documentation is pretty good, too.

Essentially, you write “Commands” like this:

import ArgumentParser

struct Something: ParsableCommand {
    @Flag(help: "Include flag.")
    var include = false

    @Option(name: .shortAndLong, help: "Some option.")
    var option: Int?

    @Argument(help: "A mandatory argument.")
    var argument: String

		func validate() throws {
		  // Validation logic
		}

    func run() throws {
	    // do something
    }
}

Something.main()

And then you can compile it and run the tool like this:

$ something --help
USAGE: something [--option <option>] [--include] <argument>

ARGUMENTS:
  <argument>              A mandatory argument.

OPTIONS:
  --include               Include flag.
  -o, --option <option>   Some Option.
  -h, --help              Show help for this command.

Of course you can have more complex tools with multiple commands and different options per command.
So you can easily build a tool like this:

$ changelog-generator
OVERVIEW: A Swift command-line tool to generate changelogs for configured projects

USAGE: changelog-generator [--config-file <config-file>] <subcommand>

OPTIONS:
  -c, --config-file <config-file>
  -h, --help              Show help information.

SUBCOMMANDS:
  generate                Generate Changelogs for a project
  generate-all            Generate Changelogs for all projects

  See 'changelog-generator help <subcommand>' for detailed help.

$ changelog-generator help generate
OVERVIEW: Generate Changelogs for a project

USAGE: changelog-generator generate <release> [--push] [--create-mr] [--no-delete] [--access-token <access-token>] [--base-branch <base-branch>] [--git-url <git-url>] [--local-path <local-path>]

ARGUMENTS:
  <release>               The name of the release, e.g. 8.0-IT-32 

OPTIONS:
  -c, --config-file <config-file>
  --push                  Push 
  -m, --create-mr         Create merge request 
  --no-delete             Don't delete git project when finished 
  -t, --access-token <access-token>
                          Personal access token (needed for merge request operations) 
  -b, --base-branch <base-branch>
                          Base branch (default: master)
  -g, --git-url <git-url> Git Url 
  -l, --local-path <local-path>
                          Path to local git repo 
  -h, --help              Show help information.