Skip to content

jneo8/mermaid

Repository files navigation

Mermaid

testing codecov Go Report Card GoDoc Release TODOs

Mermaid is a tool helping user use Cobra, Viper and dig together.

What Mermaid do?

Mermaid bind flags from cobra to viper as settings. And provide all settings to dig container automatically. Make it easy to setup and write testing.

Basic args

  • config: config file path or filename.yaml

  • config_name: if config field is blank, mermaid will find config yaml file in ., /, $HOME, ./config. Default name is config.

  • log_level: Set logger's log level. Default is info level.

Example

Basic use

cmd/example/main.go

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/jneo8/mermaid"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"go.uber.org/dig"
	"os"
)

type Service interface {
	Run() error
}

type HttpService struct {
	Engine   *gin.Engine
	Username string
}

func (s *HttpService) Run() error {
	s.Engine.GET("ping", func(c *gin.Context) {
		c.JSON(200, gin.H{"message": "pong"})
	})

	s.Engine.GET("user", func(c *gin.Context) {
		c.JSON(200, gin.H{"message": s.Username})
	})
	return s.Engine.Run()
}

type ServiceOptions struct {
	dig.In
	Username string `name:"username"`
}

func NewHttpService(opts ServiceOptions) Service {
	log.Infof("New HpptService %v", opts)
	return &HttpService{
		Engine:   gin.Default(),
		Username: opts.Username,
	}
}

var cmd = &cobra.Command{
	Use:   "exmaple",
	Short: "exmaple",
	RunE: func(cmd *cobra.Command, args []string) error {

		initializers := []interface{}{
			NewHttpService,
		}
		runable := func(service Service, logger *log.Logger, config *viper.Viper) error {
			logger.Infof("Config: %v", config.AllSettings())
			if err := service.Run(); err != nil {
				logger.Error(err)
			}
			return nil
		}
		return mermaid.Run(cmd, runable, initializers...)
	},
}

func init() {
	cmd.Flags().String("username", "userA", "username")
}

func main() {
	if err := cmd.Execute(); err != nil {
		log.Error(err)
		os.Exit(1)
	}
}

cmd/example/main_test.go

package main

import (
	"encoding/json"
	"github.com/stretchr/testify/assert"
	"net/http"
	"sync"
	"testing"
	"time"
)

func TestRootCMD(t *testing.T) {
	wg := sync.WaitGroup{}

	wg.Add(1)
	go func() {
		defer wg.Done()
		// Overwrite config using args.
		rootCMD.SetArgs(
			[]string{"--username", "userB"},
		)
		if err := rootCMD.Execute(); err != nil {
			t.Error(err)
		}
	}()

	time.Sleep(1 * time.Second) // Waiting for gin engineer setup.
	resp, err := http.Get("http://127.0.0.1:8080/user")
	if err != nil {
		t.Error(err)
	}
	defer resp.Body.Close()

	var result map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&result)

	assert.Equal(t, result["message"], "userB")
}

Use customized logger

cmd/customized_mermaid/main.go

package main

import (
	"github.com/jneo8/mermaid"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func main() {
	worker, err := mermaid.NewMermaid(
		&cobra.Command{},
		viper.New(),
		log.New(),
		"",
	)
	if err != nil {
		log.Fatal(err)
	}

	runable := func(logger *log.Logger) error {
		logger.Info("Customized mermaid worker")
		return nil
	}
	initializers := []interface{}{}
	if err := worker.Execute(runable, initializers...); err != nil {
		log.Fatal(err)
	}
}

Thanks

The basic idea isn't from me. Is from here 結構化的 Go 專案設計模式與風格 — 4 - getamis - Medium.

About

Mermaid is a tool helping user to use dependency injection more easily. By using dig, cobra and viper together.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published