Go CLI - Project Structure
In this post, we will create a proper structure for our CLI created with Cobra in Go.
Introduction
Structuring a Go CLI project can vary depending on the complexity and requirements of your project. However, in this article, we will be using a common approach to structuring a Go CLI project followed by different large projects.
In the previous article, we wrote a very basic CLI application using Cargo. However, we didn’t structure it very well. All the code was dumped into the main function which is not sustainable as our application grows. Also, the code is not at all testable, and we cannot write a single unit test for it. Let’s change that now!
In case you prefer following along a video, you can checkout the following video on my YouTube channel.
root
, and greet
command in their own packages. However, both approaches are correct. You may pick one as per your use case.The Structure
If you have been following along, you must have a flat file structure as shown below:
|
|
The Go community, as a standard practice, groups all the code files building a CLI under the <project-directory>/cmd/<binary-name>
path. It will be clearer as we make changes for our application. In your current directory create a subdirectory as cmd
. Under cmd
create another subdirectory named after the binary you are building. For instance, in our case we want our binary to be called greeter
so the directory structure for us will be:
|
|
In case we wanted to name our binary as xyz
then the directory structure would be:
|
|
The Code
Now that we have the right directories in place, let’s create a few files and move the code to its rightful place.
Under the cmd/greeter
subdirectory, create two new files named after the two commands we have - root
and greet
. So, the files to be created are root.go
and greet.go
. Once done, you must have the following file structure:
|
|
It is time we move root
and greet
commands from main.go
to their respective files. Here is how the root.go
and greet.go
would look after the code has been moved:
|
|
Notice that we now have functions that return the commands. It is essential because we also want to write some unit tests for these commands. And, in order to achieve that we need to have these commands exported.
Next, we move the main.go
file from root of the directory to cmd
. Once moved, you must have the following file structure:
|
|
Now, we need to update the main
function in main.go
to use the commands exported by greeter package. Here is how we can do that:
|
|
Build & Run
We are almost there; however, before we can build our CLI we need to inform Go that we have updated the package/project structure. We can easily do so by executing the following command from the terminal while in the root directory of our project:
|
|
And with that, we are all set to finally build our CLI using the command below:
|
|
Congratulations!! You are now all set to add more commands and features to your CLI.
Conclusion
It’s essential to keep your code modular, maintainable, and easy to understand. However, remember that this is a general structure, and you can modify it based on your specific project requirements. In the next article, we will write unit tests for each command.