CodingChallenges in GO - initial setup
Published: 2024-02-17 22:04:32

Hello world! 

Procrastination is real and I've been putting off starting a "blog" for far too long. Why not use this opportunity and go over the fairly new [codingchallenges.fyi](https://codingchallenges.fyi/). 

In this series, I will be using Go and Test-Driven-Development while walking through the challenges and explaining my thoughts process. So without further ado, let's get going. 

## 1. Tools 
1. **go** - I will be coding in golang, so https://go.dev/doc/install is essential. 
2. **[cobra-cli](https://github.com/spf13/cobra)** I will also be using cobra go package as most of the challenges are cli oriented. Cobra provides a CLI tool that can help you produce boilerplate code to save you some time.
3. [OPTIONAL] **[gotestsum](https://github.com/gotestyourself/gotestsum)** - this is an excellent go testing tool that has many features over the standard `go test` command. I hihgly recommend!
4. [OPTIONAL] **Unix environment** - this is not a requirement, but a nice to have. Most of the tools we will be creating are only available in unix, so having a system that runs unix or WSL for windows will be handy when you need to do a parity check.

## 2. Repository Setup
To get started, I have created an empty git repository on github and cloned it to my computer.

Now we need to initialize our go module, I will `cd` into the newly cloned directory and run the following command:
```
go mod init github.com/berkeli/coding-challenges
```

I have given my module the path to my git repository, as that makes it easy to import & reference things. 

## 3. Creating hello world
Now we will initialize our CLI application and write simple `Hello World!` to the terminal. 

I will run `cobra-cli init .` which creates the basic boilerplate for our application. Once done, you should be able to run the application and it will display the description for our `root` command
```
go run .                                                                                                                                                                                                                                              
A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.
```

Let's update the handler function for the `rootCmd` (located in `cmd/root.go`) so we have our hello world:

from:
```
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
```
to: 
```
// Uncomment the following line if your bare application
// has an action associated with it:
Run: func(cmd *cobra.Command, args []string) {
	fmt.Println("hello world!")
},
```
and voila! we have our hello world:
```
go run .                                                                                                                                                                                                                                                   
hello world!
```

But we won't be attaching a handler to the `rootCmd`, so we can undo our change and the cleanup comments and descriptions so it matches what we are trying to do.

### A few notes on project structure
For this project I will be following the follwowing structure
```
├── cmd <-- most of our work will live here
│   ├── go-wc <-- subdirectory for each command/challenge, e.g. wc command
│   │   ├── main.go <-- logic for wc command
│   │   ├── main_test.go <-- tests for wc command
│   │   └── test.txt <-- any additional fixtures needed for testing
│   └── root.go <-- our root command, this will only register child commands
├── go.mod
├── go.sum
└── main.go 
```

`cobra-cli` has a useful command for adding new commands `cobra-cli add <new-command>`, but I won't be using that much as it won't be following the folder structure I've chosen. It creates files directly in `cmd` folder without subdirectories which could get very busy in this series.

## Tests & CI
Of course, you can't have TDD without proper CI (continuous integration) setup. So let's get that out of the way and introduce a github action that will test our code. 

We can create a YAML file in `.github/workflows/` directory, I named mine `go-test.yaml` and place the following inside of it:
```
name: Go Test

on: [push]

jobs:
  example:
    name: run tests
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version-file: ./go.mod
        id: go
      - name: Run Go tests
        run: go run gotest.tools/gotestsum@latest --junitfile unit-tests.xml
      - name: Test Summary
        uses: test-summary/action@v2
        with:
          paths: "unit-tests.xml"
        if: always()

```

The action about has 3 steps:
1. Checkout the repository (get the latest commit)
2. Install gotestsum
3. Run go tests with gotestsum
4. Create a summary from the output of gotestsum

That's it for the setup, let's go implement `wc` command next!

The code for this series is available at https://github.com/berkeli/coding-challenges 
The code for this post is on this [Pull Request](https://github.com/berkeli/coding-challenges/pull/1)

## **UPDATE** [18/02/24] - I realized that this series will contain other types of applications that CLI, so I have made a small re-org of the repo to make it a GO monorepo.

The new structure is as follows:
```
.
├── cmd
│   └── cli <-- these will be individual applications
│       └── main.go
├── go.mod
├── go.sum
└── pkg <-- this will contain individual challenges as importable packages
    └── wc <-- wc package, which is the next challenge
        ├── main.go
        ├── main_test.go
        └── test.txt
```

So from the example above, we will have a cli package which is our `gocc` (go coding challenges) app that will register subcommands like wc, ls, etc. 

These changes are recording in [2nd Pull request](https://github.com/berkeli/coding-challenges/pull/2)

To run our cli tool, we will now be running `go run ./cmd/cli`