I've built many CLIs with Cobra and haven't found it all that intense. I've built incredibly simple, single function CLIs up to some incredibly advanced CLIs that the entire company relies on daily.
I like Cobra because it gives you a great place to start, with tons of stuff "for free". Things like spellcheck on commands like if you type "mycli statr", you might get a response "mycli statr command not found. Did you mean mycli start?". This is out of the box. I don't do a single thing to create this functionality. Really nice help pages, automatic --help flags with autodocumentation all comes for free, by just running a simple init script to start the project. It speeds up my ability to make a reliable CLI because I don't need to worry about alot of the little things, I basically just create the command I want, choose the flags, and then start writing the actual code that performs the task and don't have to write very much code to manage the tool.
I usually organize my project so all the Cobra stuff is in the main module. Then I write my own custom module that contains the application code that I am building. It builds great seperation between the two. The main module just has cobra setup, flags, configuration, documentation, etc.. Then for each command, all I do is call a function from my module, where all the logic resides.
This makes it easy for me to switch between a "Cobra" context and my "Application" context depending on the module. It also makes it portable. If i want to use a different CLI framework or make this into a backend job, I can pull my module into a different project and then call the functions from that other project that reside in my module. The module is unaware of Cobra entirely, but it performs all my logic. The cobra module (the main module) contains only Cobra stuff and then offloads all the logic to my application module.
Cobra has all the power you could want from even the most advanced CLIs (I think github's CLI and Kubectl, kubernetes cli are both built on it for example). But you don't need to use any of the advanced stuff if you don't want. It means there is a lot of confidence to build a project in cobra and if it grows you won't be limited, but it also abstracts the complexity away when the project is simple.
I don't have a dog in this fight, just a fan. It is a tool I really appreciate. I will check out subcommands though, it looks like a good project. Reminds me of "click" for python.
hmm I recently just finish making a CLT with cobra and it wasn't too bad. Granted it's extremely basic but I like it for my use case (cloning all the repos in an org):
What did you find complicated about it? What I struggle with is creating man pages automatically, although I did just find where in the repo this is explained.
subcommands does look neat tho, I'll likely use it for another tool I have in mind.
One thing I did not realize is that cobra and charmbracelet/bubbletea are not compatible. It may be my inexperience in making CLTs vs TUIs but I was disappointed I could use say the loading spinner from bubbles easily in my tool (opted for briandowns/spinner instead).
- https://github.com/golangci/golangci-lint - meta-linter
- https://goreleaser.com - automate release workflows
- https://magefile.org - build tool that can version your tools
- https://godoc.org/github.com/ory/dockertest/v3 - run containers for e2e testing
- https://github.com/ecordell/optgen - generate functional options
- https://golang.org/x/tools/cmd/stringer - generate String()
- https://mvdan.cc/gofumpt - stricter gofmt
- https://github.com/stretchr/testify - test assertion library
- https://github.com/rs/zerolog - logging
- https://github.com/spf13/cobra - CLI framework
FWIW, I just lifted all the tools we use for https://github.com/authzed/spicedb
We've also written some custom linters that might be useful for other folks: https://github.com/authzed/spicedb/tree/main/tools/analyzers