Automating your routine with Golang and a CLI
Tags: go, automation, cli
Published: 2020-11-30 15:09:27

I had this idea after reading the article of @[Chris Bongers](@dailydevtips) about  [automating morning routine](https://h.daily-dev-tips.com/ive-automated-my-morning-routine)  

I read that article and loved the idea to automate some tasks that we do everyday.

So i decided to take a step further and create a CLI who is gonna be my "assistant" to make all kind of small tasks.

In this tutorial, we are going to make a CLI in Golang to do two things : 

- Open tabs on my browser (like Chris Bongers did with a script but we are gonna do it with Golang)
- Create and saves txt notes from the CLI.

## Requirements

You must have a little knowledge about Golang to follow this tutorial.

To create the CLI, we are going to use  [Cobra](https://github.com/spf13/cobra) 

Cobra is a library for creating CLI in golang.

## Create the project

Now we can start.

We are going to create a new project on our computer


```
mkdir mycli
cd mycli
go mod init mycli
go get -u github.com/spf13/cobra/cobra
``` 

## init the CLI

Now that we have cobra installed, we can start creating our cli

The pkg-name here is important because it's going to be the name you invoke when calling your CLI. I'm gonna call mine Homer 
```
cobra init --pkg-name homer
``` 

After executing that command , you can see that your project-folder looks like this


```
▾ mycli/
  ▾ cmd/
     root.go
   main.go
``` 

## Create our first command

Now let's add our first command to our cli 


```
cobra add <commandName>
``` 

Our first command is to open tabs in the morning, so i am gonna type

```
cobra add morning
``` 

If you look at your files structure, a new file called morning.go has been created.
Every time you are gonna add a command, a new file with the name of your command is gonna be created in the cmd folder.

```
▾ mycli/
  ▾ cmd/
     root.go
     morning.go
   main.go
``` 

## Implement the morning command

Now, open the file called morning.go


```
package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// morningCmd represents the morning command
var morningCmd = &cobra.Command{
	Use:   "morning",
	Short: "A brief description of your command",
	Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. 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.`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("morning called")
	},
}

func init() {
	rootCmd.AddCommand(morningCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// morningCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// morningCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

``` 

We are going to work inside the `var morningCmd` that represents our command.

First, complete the use and the descriptions (long and short) of your command.

Then, inside the Run , we are going to implement the actual code that we want to run when we are going to call the command : `homer morning`


```
package cmd

import (
	"bufio"
    "fmt"
	"os"
	
	"github.com/spf13/cobra"
	"github.com/pkg/browser"
)

// morningCmd represents the morning command
var morningCmd = &cobra.Command{
	Use:   "morning",
	Short: "Open a list of urls",
	Long: `Url opens a list of urls defined in a txt file`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("Good morning ! Homer is opening your tabs")
		// Open the file.
		f, _ := os.Open("/path/to/your/tabs.txt")
		// Create a new Scanner for the file.
		scanner := bufio.NewScanner(f)
		// Loop over all lines in the file and print them.
		for scanner.Scan() {
		  line := scanner.Text()
          // use browser to Open the url
		  browser.OpenURL(line)
		}
	},
}
``` 

Great ! 
Now let's build our app 

`go install homer`

And try our command

```
homer morning
Good morning ! Homer is opening your tabs
``` 

Tadaaaaaam ! 

## Let's add another command

Well, now let's go further and add another command.

Let's add a command to take quick notes.

`cobra add notes`

A new file called notes.go is now available.

Let's implement the code 


```
package cmd

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/spf13/cobra"
)

// notesCmd represents the notes command
var notesCmd = &cobra.Command{
	Use:   "notes",
	Short: "A command to take quick notes",
	Long: `This command helps you take quick notes by opening a file .txt`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("Homer is opening a new note")
		// create a folder for the notes if doesn't exists
		_ = os.Mkdir("./notes", 0755)
		// open the editor of your choice => nano for me
		// the name of the file will be your argument
		// homer notes myfile will open a file called myfile.txt 
		editorCmd := exec.Command("nano", fmt.Sprintf("./notes/%v.txt", args[0]))
		editorCmd.Stdin = os.Stdin
		editorCmd.Stdout = os.Stdout
		editorCmd.Stderr = os.Stderr
    
		err := editorCmd.Run()
		if (err != nil) {
			fmt.Println(err)
		}
	},
}

func init() {
	rootCmd.AddCommand(notesCmd)
}
``` 

Now, build the app : `go install homer`

And run the command 

`homer notes mynote`


![Capture d'écran 2020-11-29 13:21:46.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1606652530171/Iz4mVyJxx.png)


Just write your note and save it.

All your notes will be saved inside the folder notes.  
I chose to put it inside the project (./notes) but you can choose to create it wherever you want on your computer.

## And now ?

Now you have a new assistant called homer that can do multiple tasks for you.  
So just think about a new task you want to automate, and make a new command with cobra.  

For example, you can add subcommands to list all your notes, to find a particular note, to delete a note ...

Have fun with your new assistant :)