dfreilich / gophercon-cli

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

gophercon-cli

If you encounter any issues through this tutorial, you can see the add-joker branch for an implementation

1. Create initial functionality

  1. Initialize go.mod: go mod init github.com/dfreilich/gophercon-cli
  2. Create a cmd directory: mkdir -p cmd/
  3. Get cobra: go get github.com/spf13/cobra
  4. Create a file in the cmd/ directory with the contents:
func NewJokerCmd() *cobra.Command {
	return &cobra.Command{
		Use:     "joker",
		Aliases: []string{"joke"},
		Short:   "This returns GPT3 Dad jokes!",
		Version: "0.0.1",
		RunE: func(cmd *cobra.Command, args []string) error {
			fmt.Println("Hello Gophercon!")
			return nil
		},
	}
}
  1. Initialize the main.go file to run the command:
func main() {
	root := cmd.NewJokerCmd()
	if err := root.Execute(); err != nil {
		_, _ = fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
  1. Create a Makefile with the contents:
GOCMD?=go
NAME?=joker

build:
	$(GOCMD) build -o $(NAME)

test:
	$(GOCMD) test ./... -v

run:
	$(GOCMD) run ./...

.PHONY: build test run
  1. Write initial test in root_test.go:
func TestNewJokerCmd(t *testing.T) {
	cmd := NewJokerCmd()
	buf := &bytes.Buffer{}
	cmd.SetOut(buf)
	err := cmd.Execute()
	require.NoError(t, err)
	require.NotEmpty(t, buf.String())
}

2. Sprinkle Some AI

  1. Get library for GPT3: go get github.com/sashabaranov/go-gpt3
  2. Make API Key here and set it as an environment variable export OPEN_AI_KEY=MY_KEY
  3. Use GPT3 in root.go:
// Note: For this, you need to make an API KEY at https://beta.openai.com/account/api-keys
c := gogpt.NewClient(os.Getenv("OPEN_AI_KEY"))
ctx := context.Background()

req := gogpt.CompletionRequest{
    Model:            gogpt.GPT3TextDavinci003,
    MaxTokens:        maxTokens,
    Temperature:      1,
    Prompt:           "Tell me a corny dad joke",
    TopP:             1,
    FrequencyPenalty: 1,
    PresencePenalty:  1,
}
resp, err := c.CreateCompletion(ctx, req)
if err != nil {
    return err
}

3. Add Some Style

  1. Get a nice rendering library: go get github.com/charmbracelet/lipgloss
  2. Make the output fabulous :
style := lipgloss.NewStyle().
    Bold(true).
    BorderStyle(lipgloss.RoundedBorder()).
    BorderForeground(lipgloss.Color("12")). // Light Blue
    Foreground(lipgloss.Color("5")) // Magenta

fmt.Println(style.Render(strings.TrimSpace(resp.Choices[0].Text)))

4. Add Mocking/Interface

  1. Go get assertion library: go get github.com/stretchr/testify/require
  2. Install mockgen : go install github.com/golang/mock/mockgen@v1.6.0 and go get github.com/golang/mock/mockgen/model
  3. Create the interface and annotations:
//go:generate mockgen -package mocks -destination ../test/mocks/mock_asker.go github.com/dfreilich/gophercon-cli/cmd Asker
type Asker interface {
	CreateCompletion(ctx context.Context, request gogpt.CompletionRequest) (response gogpt.CompletionResponse, err error)
}
  1. Change the Command to use it:
func NewJokerCmd(asker Asker) *cobra.Command {
...
    resp, err := asker.CreateCompletion(ctx, req)
  1. Change the main to se it:
	c := gogpt.NewClient(os.Getenv("OPEN_AI_KEY"))
	root := cmd.NewJokerCmd(c)
  1. Change the test to use it:
func TestNewJokerCmd(t *testing.T) {
	ctrl := gomock.NewController(t)
	testActor := mocks.NewMockAsker(ctrl)
	cmd := NewJokerCmd(testActor)
	testActor.EXPECT().CreateCompletion(gomock.Any(), gomock.Any()).Return(gogpt.CompletionResponse{
		Choices: []gogpt.CompletionChoice{{Text: "Some funny joke!"}},
	}, nil)
	buf := &bytes.Buffer{}
	cmd.SetOut(buf)
	err := cmd.Execute()
	require.NoError(t, err)
	require.NotEmpty(t, buf.String())
	require.Contains(t, buf.String(), "Some funny joke!")
}

5. Run

asciicast

6. Next Steps

For more, check out the Cobra documentation here, and look at how some major CLIs are using it.

One project you can check out is the Cloud Native Buildpacks pack CLI. You can see how they generate the Root Command here, define subcommands here, and create an interface of their client here

About


Languages

Language:Makefile 100.0%