CLI¶
Aside from what you can with the spokfile syntax itself, there's also a bunch of stuff you can do from the CLI.
Usage¶
Let's start by showing the help:
$ spok --help
It's a build system Jim, but not as we know it!
Spok is a lightweight build system and command runner, inspired by things like
make, just etc.
However, spok offers a number of additional features such as:
- Cleaner, more developer-friendly syntax
- Full cross compatibility
- No dependency on any form of shell
- Load .env files by default
- Incremental runs based on file hashing and sum checks
USAGE:
spok [tasks]... [flags]
FLAGS:
-c, --clean Remove all build artifacts.
-d, --debug Show verbose logging output.
--fmt Format the spokfile.
-f, --force Bypass file hash checks and force running.
-h, --help help for spok
--init Initialise a new spokfile in $CWD.
-j, --json Output task results as JSON.
-q, --quiet Silence all CLI output.
-s, --show Show all tasks defined in the spokfile.
--spokfile string The path to the spokfile (defaults to '$CWD/spokfile').
-V, --vars Show all defined variables in spokfile.
--version version for spok
Some of this stuff we've already talked about, but let's look at some stuff we haven't touched on yet.
--fmt
¶
The --fmt
flag is used to format the spokfile. Spok comes equipped with an (albeit basic) formatter that parses the spokfile
and then dumps it back in place with the desired formatting, simple really!
Warning
Because the spokfile has to be parsed before formatting, it's not possible to format a spokfile that contains syntax errors.
--force
¶
If you've read the user guide you'll know that Spok calculates the state of the task dependency graph by hashing the contents of all the declared files in your task definition. This avoids unnecessary work by only running tasks who's dependencies have changed.
However, sometimes you want to force a task to run regardless of whether it's dependencies have changed or not. This is where the --force
flag comes in.
$ spok test
- Task "test" skipped as none of it's dependencies have changed
// Okay fine, let's force it to run
$ spok test --force
ok github.com/FollowTheProcess/spok/ast (cached)
ok github.com/FollowTheProcess/spok/builtins (cached)
ok github.com/FollowTheProcess/spok/cache (cached)
? github.com/FollowTheProcess/spok/cli/app [no test files]
? github.com/FollowTheProcess/spok/cli/cmd [no test files]
ok github.com/FollowTheProcess/spok/cmd/spok (cached)
ok github.com/FollowTheProcess/spok/file (cached)
ok github.com/FollowTheProcess/spok/graph (cached)
ok github.com/FollowTheProcess/spok/hash (cached)
? github.com/FollowTheProcess/spok/iostream [no test files]
ok github.com/FollowTheProcess/spok/lexer (cached)
? github.com/FollowTheProcess/spok/logger [no test files]
ok github.com/FollowTheProcess/spok/parser (cached)
ok github.com/FollowTheProcess/spok/shell (cached)
ok github.com/FollowTheProcess/spok/task (cached)
ok github.com/FollowTheProcess/spok/token (cached)
✅ Task "test" completed successfully
--json
¶
By default, spok outputs the results of the running tasks in their original format straight to the terminal. This is great for humans, but not so great for machines.
If you want to programmatically access the results of a spok run, you can use the --json
flag to output the results as JSON, which can then be queried
by external programs e.g. jq.
For example, let's run a sample task and pipe the output to jq
:
Here's the spokfile:
# Do some things with JSON
task echo() {
echo "I succeeded"
}
Running spok echo --json
will get you:
$ spok echo --json | jq
[
{
"task": "echo",
"command_results": [
{
"cmd": "echo I succeeded",
"stdout": "I succeeded\n",
"stderr": "",
"status": 0
}
],
"skipped": false
}
]
Spok's output JSON is a list of objects, each object representing a task. Each task object contains the following fields:
task
: The name of the taskcommand_results
: A list of objects, each object representing a command run by the task. Each command object contains the following fields:cmd
: The command that was runstdout
: The stdout of the commandstderr
: The stderr of the commandstatus
: The exit status of the command
You can imagine how this could be useful for things like CI/CD pipelines where tasks are more complicated and you may need to query or parse the results of a task or a whole run.
--quiet
¶
The --quiet
flag does exactly what it says on the tin, shuts Spok up!
When using the --quiet
flag, Spok will not show any of the task results or any other output at all, simply exit with a zero status
code if the run was successful or a non-zero status code if it wasn't.
I'd include an example here, but by definition it would be empty! 🤓
--show
¶
The --show
flag simply displays all the tasks and their docstrings if present. By default, Spok will do this when it
is invoked with no arguments, unless you have declared a task called default
, see the user guide for more info on that!
To show you what this looks like, consider a simple spokfile:
# Run the unit tests
task test() {
go test ./...
}
# Format the source code
task fmt() {
go fmt ./...
}
# Run the linter
task lint() {
golangci-lint run --fix
}
Running spok
with no arguments, or spok --show
will get you:
$ spok --show
Tasks defined in /Users/you/yourproject/spokfile:
Name Description
fmt Run go fmt on all project files
lint Lint the project and auto-fix errors if possible
test Run all project tests
Tip
--show
comes in handy when you've reassigned the default task to do something else 🧠
--spokfile
¶
The --spokfile
flag is used to specify the path to the spokfile. By default, Spok will look for a spokfile in the current working directory.
Note
The path doesn't have to be absolute, if you use a relative path, Spok will assume you meant relative to the current working directory.
--vars
¶
The --vars
flag tells Spok simply to print all the global variables in the spokfile and exit, this is useful for checking whether
the outputs of spok's builtin functions are what you expect.
For example:
TAG := exec("git describe --tags --abbrev=0")
COMMIT := exec("git rev-parse HEAD")
Will get you:
$ spok --vars
Variables defined in /Users/you/yourproject/spokfile:
Name Value
TAG 0.3.0
COMMIT 3f2a1c2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f
--debug
¶
If you're ever curious what's going on under the hood, you can use the --debug
flag to get a more detailed output of what Spok is doing during
any other CLI operation:
$ spok test --debug
2022-11-27T10:10:26.441Z DEBUG Looking in /Users/tomfleet/Development/spok for spokfile
2022-11-27T10:10:26.442Z DEBUG Found spokfile at /Users/tomfleet/Development/spok/spokfile
2022-11-27T10:10:26.442Z DEBUG Looking for .env file
2022-11-27T10:10:26.442Z DEBUG No .env file found
2022-11-27T10:10:26.442Z DEBUG Parsing spokfile at /Users/tomfleet/Development/spok/spokfile
2022-11-27T10:10:26.459Z DEBUG Running requested tasks: [test]
2022-11-27T10:10:26.760Z DEBUG Building dependency graph for requested tasks: [test]
2022-11-27T10:10:26.760Z DEBUG Calculating topological sort of dependency graph
2022-11-27T10:10:26.761Z DEBUG Task test glob dependency pattern "**/*.go" expanded to 34 files
2022-11-27T10:10:26.761Z DEBUG Task test depends on 34 files
2022-11-27T10:10:26.765Z DEBUG Task test current checksum: 670d2ef1c36f6e1 cached checksum: 670d2ef1c36f6e1
- Task "test" skipped as none of its dependencies have changed