Skip to content

Commit

Permalink
Merge pull request #92 from kcmvp/v013
Browse files Browse the repository at this point in the history
#10: apply cobra template for pretty print
  • Loading branch information
kcmvp authored Apr 13, 2024
2 parents b729dd4 + dc7bfac commit 6fdcf97
Show file tree
Hide file tree
Showing 56 changed files with 1,692 additions and 545 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@
go.work
.idea
gob
*.sql
11.json
target
62 changes: 31 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ flowchart TD
gob.yaml --> plugin2
gob.yaml --> plugin3
```
You just need to tell `gob` 3W(where,when and what)
You just need to tell `gbc` 3W(where,when and what)

1. **Where** : where to download the tool
2. **When** : when to execute to command
Expand All @@ -59,40 +59,40 @@ You just need to tell `gob` 3W(where,when and what)
## Quick Start
1. Install `gob` with below command
```shell
go install github.com/kcmvp/gob
go install github.com/kcmvp/gbc
```
2. Initialize project with below command(in the project home directory)
```shell
gob init
gbc init
```

| Make some changes and comit code | execute `gob deps` |
| Make some changes and comit code | execute `gbc deps` |
|--------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|
| <img src="https://github.com/kcmvp/gob/blob/main/docs/commit_hook.gif" height="245" width="400"> | <img src="https://github.com/kcmvp/gob/blob/main/docs/dependency_tree.png" height="245" width="300"> |
| <img src="https://github.com/kcmvp/gbc/blob/main/docs/commit_hook.gif" height="245" width="400"> | <img src="https://github.com/kcmvp/gbc/blob/main/docs/dependency_tree.png" height="245" width="300"> |


## Commands

Build Commands
- [gob init](#gob-init)
- [gob build](#gob-build)
- [gob clean](#gob-clean)
- [gob test](#gob-test)
- [gob lint](#gob-lint)
- [gob deps](#gob-deps)
- [gbc init](#gbc-init)
- [gbc build](#gbc-build)
- [gbc clean](#gbc-clean)
- [gbc test](#gbc-test)
- [gbc lint](#gbc-lint)
- [gbc deps](#gbc-deps)

Plugin Commands
- [gob plugin install](#gob-plugin-install)
- [gob plugin list](#gob-plugin-list)
- [gbc plugin install](#gbc-plugin-install)
- [gbc plugin list](#gbc-plugin-list)

Setup Commands
- [gob setup version](#gob-setup-version)
- [gbc setup version](#gbc-setup-version)

### gob init
### gbc init
```shell
gob init
gbc init
```
Initialize gob for the project, it will do following initializations
Initialize gbc for the project, it will do following initializations
1. generate file `gob.yaml`
2. generate file `.golangci.yaml`, which is the configuration for [golangci-lint](https://github.com/golangci/golangci-lint)
3. setup `git hooks` if project in the source control.
Expand All @@ -113,49 +113,49 @@ exec:
- test
plugins:
golangci-lint:
alias: lint #When : when issue `gob lint`
alias: lint #When : when issue `gbc lint`
args: run ./... #What: execute `golangci-lint run ./...`
url: github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.2 #Where: where to download the plugin
gotestsum:
alias: test
args: --format testname -- -coverprofile=target/cover.out ./...
url: gotest.tools/gotestsum@v1.11.0
```
in most cases you don't need to edit the configuration manually. you can achieve this by [plugin commands](#gob-plugin-install)
in most cases you don't need to edit the configuration manually. you can achieve this by [plugin commands](#gbc-plugin-install)
### gob build
### gbc build
```shell
gob build
gbc build
```
This command would build all the candidate binaries(main methods in main packages) to the `target` folder.
1. Final binary name is same as go source file name which contains `main method`
2. Would fail if there are same name go main surce file

### gob clean
### gbc clean
```shell
gob clean
gbc clean
```
This command would clean `target` folder

### gob test
### gbc test
```shell
gob test
gbc test
```
This command would run all tests for the project and generate coverage report at `target/cover.html`

### gob lint
### gbc lint
```shell
gob lint
gbc lint
```
Run `golangci-lint` against project based on the configuration, a report named `target/lint.log` will be generated if there are any violations
### gob deps
### gbc deps
```shell
gob deps
gbc deps
```
List project dependencies tree and indicate there are updates for a specific dependency
### gob plugin install
### gbc plugin install
```shell
gob plugin install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.2 lint run ./...
gbc plugin install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.2 lint run ./...
```
It is an advanced version of `go install`, which supports multi-version.(eg:`golangci-lint-v1.55.2`, `golangci-lint-v1.55.1`)
1. Install the versioned tool(just the same as `go install`)
Expand Down
19 changes: 19 additions & 0 deletions application.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# "postgres://username:password@localhost:5432/database_name"
# username:password@protocol(address)/dbname?param=value
datasource:
ds1:
driver: sqlite3
user: usera
password: passwd1
Host: localhost
url: file:test1.db?cache=shared&mode=memory
ds2:
driver: sqlite3
user: userb
password: passwd2
url: file:test2.db?cache=shared&mode=memory
scripts:
- sqlite3-schema.sql



12 changes: 12 additions & 0 deletions application_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# "postgres://username:password@localhost:5432/database_name"
# username:password@protocol(address)/dbname?param=value
datasource:
ds1:
driver: sqlite3
user: abc
password: 123
url: file:test3.db?cache=shared&mode=memory
scripts:
- sqlite3-schema.sql
- sqlite3-init.sql

57 changes: 57 additions & 0 deletions boot/application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package boot

import (
"fmt"
"os"
"path/filepath"
"sync"

"github.com/kcmvp/gob/internal"
"github.com/kcmvp/gob/utils"

"github.com/samber/do/v2"
"github.com/spf13/viper"
)

const (
DefaultCfg = "application"
)

var (
cfg *viper.Viper
once sync.Once
)

func RootDir() string {
return internal.RootDir
}

func Container() *do.RootScope {
return internal.Container
}

func InitApp() {
InitAppWith(DefaultCfg)
}

func InitAppWith(cfgName string) {
if cfg == nil {
once.Do(func() {
cfg = viper.New()
cfg.SetConfigName(cfgName) // name of cfg file (without extension)
cfg.SetConfigType("yaml") // REQUIRED if the cfg file does not have the extension in the name
cfg.AddConfigPath(internal.RootDir) // optionally look for cfg in the working directory
if err := cfg.ReadInConfig(); err != nil { // Find and read the cfg file
panic(fmt.Errorf("fatal error cfg file: %w", err))
}
if test, _ := utils.TestCaller(); test {
if testCfg, err := os.Open(filepath.Join(internal.RootDir, fmt.Sprintf("%s_test.yaml", cfgName))); err == nil {
if err = cfg.MergeConfig(testCfg); err != nil {
panic(fmt.Errorf("failed to merge test configuration file: %w", err))
}
}
}
setupDb()
})
}
}
86 changes: 86 additions & 0 deletions boot/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package boot

import (
"database/sql"
"fmt"
"os"
"path/filepath"
"strings"

"github.com/kcmvp/gob/internal"

//"github.com/kcmvp/gob/internal"

"github.com/samber/do/v2"
typetostring "github.com/samber/go-type-to-string"
"github.com/samber/lo"
)

const (
DSKey = "datasource"
UserKey = "${user}"
PasswordKey = "${password}"
HostKey = "${host}"
DefaultDS = "DefaultDS"
)

type dataSource struct {
Driver string `mapstructure:"driver"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
Host string `mapstructure:"host"`
URL string `mapstructure:"url"`
Scripts []string `mapstructure:"scripts"`
}

func (ds dataSource) DSN() string {
dsn := strings.ReplaceAll(ds.URL, UserKey, ds.User)
dsn = strings.ReplaceAll(dsn, PasswordKey, ds.Password)
return strings.ReplaceAll(dsn, HostKey, ds.Host)
}

func dsMap() map[string]dataSource {
// single data source
if v := cfg.Get(fmt.Sprintf("%s.%s", DSKey, "driver")); v != nil {
var ds dataSource
if err := cfg.UnmarshalKey(DSKey, &ds); err != nil {
panic(fmt.Errorf("failed parse datasource: %w", err))
}
return map[string]dataSource{DefaultDS: ds}
// multiple data sources
} else if v = cfg.Get(DSKey); v != nil {
dss := v.(map[string]any)
return lo.MapValues(dss, func(_ any, key string) dataSource {
var ds dataSource
key = fmt.Sprintf("%s.%s", DSKey, key)
if err := cfg.UnmarshalKey(key, &ds); err != nil {
panic(fmt.Errorf("failed parse datasource: %w", err))
}
return ds
})
}
return map[string]dataSource{}
}

func setupDb() {
for name, ds := range dsMap() {
if db, err := sql.Open(ds.Driver, ds.DSN()); err == nil {
if err = db.Ping(); err != nil {
_ = db.Close()
panic(fmt.Errorf("failed to initialize %s: %w", name, err))
}
lo.ForEach(ds.Scripts, func(script string, _ int) {
if data, err := os.ReadFile(filepath.Join(internal.RootDir, script)); err == nil {
if _, err = db.Exec(string(data)); err != nil {
panic(fmt.Errorf("failed to execute %s: %w", script, err))
}
} else {
panic(fmt.Errorf("failed to read %s: %w", script, err))
}
})
do.ProvideNamedValue[*sql.DB](internal.Container, fmt.Sprintf("%s_%s", name, typetostring.GetType[*sql.DB]()), db)
} else {
panic(fmt.Errorf("failed to connect to datasource %s: %w", name, err))
}
}
}
42 changes: 42 additions & 0 deletions boot/db_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package boot

import (
"database/sql"
"fmt"
"github.com/kcmvp/gob/internal"
_ "github.com/mattn/go-sqlite3"
"github.com/samber/do/v2"
typetostring "github.com/samber/go-type-to-string"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"testing"
)

type DBTestSuite struct {
suite.Suite
}

func TestDBTestSuite(t *testing.T) {
suite.Run(t, &DBTestSuite{})
}

func (dbs *DBTestSuite) SetupSuite() {
InitApp()
}

func (dbs *DBTestSuite) TestMultipleDB() {
ds := dsMap()
assert.Equal(dbs.T(), 2, len(ds))
db := do.MustInvokeNamed[*sql.DB](internal.Container, fmt.Sprintf("%s_%s", "ds1", typetostring.GetType[*sql.DB]()))
assert.NotNil(dbs.T(), db)
rs, err := db.Exec("select * from Product")
assert.NoError(dbs.T(), err)
cnt, _ := rs.RowsAffected()
assert.Equal(dbs.T(), int64(2), cnt)
db = do.MustInvokeNamed[*sql.DB](internal.Container, fmt.Sprintf("%s_%s", "ds2", typetostring.GetType[*sql.DB]()))
assert.NotNil(dbs.T(), db)
rs, err = db.Exec("select * from Product")
assert.NoError(dbs.T(), err)
cnt, _ = rs.RowsAffected()
assert.Equal(dbs.T(), int64(0), cnt)
}
Loading

0 comments on commit 6fdcf97

Please sign in to comment.