feat(sesamy): add config

This commit is contained in:
Kevin Franklin Kim 2025-03-20 16:08:13 +01:00
parent 985b52a785
commit dd2e795045
No known key found for this signature in database
5 changed files with 181 additions and 44 deletions

View File

@ -28,6 +28,15 @@ func New(l log.Logger) (plugin.Plugin, error) {
}
```
### Config
```yaml
sesamy:
default:
- path/to/sesamy.base.yaml
- path/to/sesamy.base.override.yaml
```
### Ownbrew
To install binary locally, add:

View File

@ -3,40 +3,80 @@ package sesamy
import (
"bytes"
"context"
"path"
"sort"
"github.com/foomo/posh-providers/onepassword"
"github.com/foomo/posh/pkg/cache"
"github.com/foomo/posh/pkg/command/tree"
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/prompt/goprompt"
"github.com/foomo/posh/pkg/readline"
"github.com/foomo/posh/pkg/shell"
"github.com/foomo/posh/pkg/util/files"
"github.com/foomo/posh/pkg/util/suggests"
"github.com/knadh/koanf/parsers/yaml"
"github.com/knadh/koanf/providers/file"
"github.com/knadh/koanf/v2"
"github.com/pkg/errors"
"github.com/pterm/pterm"
"github.com/samber/lo"
"github.com/spf13/viper"
)
type Command struct {
type (
Command struct {
l log.Logger
name string
op *onepassword.OnePassword
cache cache.Namespace
config Config
configKey string
commandTree tree.Root
}
CommandOption func(*Command)
)
// ------------------------------------------------------------------------------------------------
// ~ Options
// ------------------------------------------------------------------------------------------------
func CommandWithName(v string) CommandOption {
return func(o *Command) {
o.name = v
}
}
func CommandWithConfigKey(v string) CommandOption {
return func(o *Command) {
o.configKey = v
}
}
// ------------------------------------------------------------------------------------------------
// ~ Constructor
// ------------------------------------------------------------------------------------------------
func NewCommand(l log.Logger, op *onepassword.OnePassword, cache cache.Cache) *Command {
func NewCommand(l log.Logger, op *onepassword.OnePassword, opts ...CommandOption) (*Command, error) {
inst := &Command{
l: l.Named("sesamy"),
op: op,
cache: cache.Get("sesamy"),
name: "sesamy",
configKey: "sesamy",
}
for _, opt := range opts {
if opt != nil {
opt(inst)
}
}
if err := viper.UnmarshalKey(inst.configKey, &inst.config); err != nil {
return nil, err
}
// if err := os.Setenv("SESAMY_SCOPE", inst.name); err != nil {
// return nil, err
// }
configArg := &tree.Arg{
Name: "path",
Name: "config",
Optional: true,
Suggest: inst.completePaths,
}
@ -46,14 +86,14 @@ func NewCommand(l log.Logger, op *onepassword.OnePassword, cache cache.Cache) *C
}
inst.commandTree = tree.New(&tree.Node{
Name: "sesamy",
Name: inst.name,
Description: "Run sesamy",
Nodes: tree.Nodes{
{
Name: "config",
Description: "Dump config",
Args: tree.Args{configArg},
Execute: inst.config,
Execute: inst.conf,
},
{
Name: "tags",
@ -73,6 +113,16 @@ func NewCommand(l log.Logger, op *onepassword.OnePassword, cache cache.Cache) *C
Name: "provision",
Description: "Provision Google Tag Manager",
Nodes: tree.Nodes{
{
Name: "all",
Description: "Provision Web & Server Container",
Args: tree.Args{configArg},
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
fs.Default().StringSlice("tags", nil, "list of tags to run")
return flags(ctx, r, fs)
},
Execute: inst.provisionAll,
},
{
Name: "web",
Description: "Provision Web Container",
@ -109,6 +159,7 @@ func NewCommand(l log.Logger, op *onepassword.OnePassword, cache cache.Cache) *C
Suggest: func(ctx context.Context, t tree.Root, r *readline.Readline) []goprompt.Suggest {
return []goprompt.Suggest{
{Text: "built-in-variables"},
{Text: "environments"},
{Text: "folders"},
{Text: "gtag-config"},
{Text: "status"},
@ -118,6 +169,7 @@ func NewCommand(l log.Logger, op *onepassword.OnePassword, cache cache.Cache) *C
{Text: "transformations"},
{Text: "triggers"},
{Text: "variables"},
{Text: "workspaces"},
{Text: "zones"},
}
},
@ -136,6 +188,7 @@ func NewCommand(l log.Logger, op *onepassword.OnePassword, cache cache.Cache) *C
Suggest: func(ctx context.Context, t tree.Root, r *readline.Readline) []goprompt.Suggest {
return []goprompt.Suggest{
{Text: "built-in-variables"},
{Text: "environments"},
{Text: "clients"},
{Text: "folders"},
{Text: "gtag-config"},
@ -146,6 +199,7 @@ func NewCommand(l log.Logger, op *onepassword.OnePassword, cache cache.Cache) *C
{Text: "transformations"},
{Text: "triggers"},
{Text: "variables"},
{Text: "workspaces"},
{Text: "zones"},
}
},
@ -159,7 +213,7 @@ func NewCommand(l log.Logger, op *onepassword.OnePassword, cache cache.Cache) *C
},
})
return inst
return inst, nil
}
// ------------------------------------------------------------------------------------------------
@ -190,7 +244,27 @@ func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
// ~ Private methods
// ------------------------------------------------------------------------------------------------
func (c *Command) config(ctx context.Context, r *readline.Readline) error {
func (c *Command) merge(ctx context.Context, path string) ([]byte, error) {
filenames, ok := c.config[path]
if !ok {
return nil, errors.New("invalid config key: " + path)
}
var conf = koanf.Conf{
Delim: "/",
}
var k = koanf.NewWithConf(conf)
for _, filename := range filenames {
if err := k.Load(file.Provider(filename), yaml.Parser()); err != nil {
return nil, errors.Wrap(err, "error loading config file: "+filename)
}
}
return k.Marshal(yaml.Parser())
}
func (c *Command) conf(ctx context.Context, r *readline.Readline) error {
var paths []string
if r.Args().HasIndex(1) {
paths = []string{r.Args().At(1)}
@ -202,9 +276,15 @@ func (c *Command) config(ctx context.Context, r *readline.Readline) error {
for _, value := range paths {
c.l.Info("└ " + value)
out, err := c.op.RenderFile(ctx, value)
b, err := c.merge(ctx, value)
if err != nil {
return err
return errors.Wrap(err, "failed to merge config")
}
out, err := c.op.Render(ctx, string(b))
if err != nil {
pterm.Error.Println(string(b))
return errors.Wrap(err, "failed to render secrets")
}
if err := shell.New(ctx, c.l, "sesamy", "config").
@ -212,7 +292,6 @@ func (c *Command) config(ctx context.Context, r *readline.Readline) error {
Args("--config", "-").
Args(r.AdditionalArgs()...).
Stdin(bytes.NewReader(out)).
Dir(path.Dir(value)).
Run(); err != nil {
return err
}
@ -232,9 +311,15 @@ func (c *Command) tags(ctx context.Context, r *readline.Readline) error {
for _, value := range paths {
c.l.Info("└ " + value)
out, err := c.op.RenderFile(ctx, value)
b, err := c.merge(ctx, value)
if err != nil {
return err
return errors.Wrap(err, "failed to merge config")
}
out, err := c.op.Render(ctx, string(b))
if err != nil {
pterm.Error.Println(string(b))
return errors.Wrap(err, "failed to render secrets")
}
if err := shell.New(ctx, c.l, "sesamy", "tags").
@ -242,7 +327,6 @@ func (c *Command) tags(ctx context.Context, r *readline.Readline) error {
Args("--config", "-").
Args(r.AdditionalArgs()...).
Stdin(bytes.NewReader(out)).
Dir(path.Dir(value)).
Run(); err != nil {
return err
}
@ -262,9 +346,15 @@ func (c *Command) typescript(ctx context.Context, r *readline.Readline) error {
for _, value := range paths {
c.l.Info("└ " + value)
out, err := c.op.RenderFile(ctx, value)
b, err := c.merge(ctx, value)
if err != nil {
return err
return errors.Wrap(err, "failed to merge config")
}
out, err := c.op.Render(ctx, string(b))
if err != nil {
pterm.Error.Println(string(b))
return errors.Wrap(err, "failed to render secrets")
}
if err := shell.New(ctx, c.l, "sesamy", "typescript").
@ -272,7 +362,6 @@ func (c *Command) typescript(ctx context.Context, r *readline.Readline) error {
Args("--config", "-").
Args(r.AdditionalArgs()...).
Stdin(bytes.NewReader(out)).
Dir(path.Dir(value)).
Run(); err != nil {
return err
}
@ -292,9 +381,15 @@ func (c *Command) provision(ctx context.Context, r *readline.Readline, cmd strin
for _, value := range paths {
c.l.Info("└ " + value)
out, err := c.op.RenderFile(ctx, value)
b, err := c.merge(ctx, value)
if err != nil {
return err
return errors.Wrap(err, "failed to merge config")
}
out, err := c.op.Render(ctx, string(b))
if err != nil {
pterm.Error.Println(string(b))
return errors.Wrap(err, "failed to render secrets")
}
if err := shell.New(ctx, c.l, "sesamy", "provision", cmd).
@ -302,7 +397,6 @@ func (c *Command) provision(ctx context.Context, r *readline.Readline, cmd strin
Args("--config", "-").
Args(r.AdditionalArgs()...).
Stdin(bytes.NewReader(out)).
Dir(path.Dir(value)).
Run(); err != nil {
return err
}
@ -310,6 +404,16 @@ func (c *Command) provision(ctx context.Context, r *readline.Readline, cmd strin
return nil
}
func (c *Command) provisionAll(ctx context.Context, r *readline.Readline) error {
if err := c.provision(ctx, r, "web"); err != nil {
return err
}
if err := c.provision(ctx, r, "server"); err != nil {
return err
}
return nil
}
func (c *Command) provisionWeb(ctx context.Context, r *readline.Readline) error {
return c.provision(ctx, r, "web")
}
@ -340,9 +444,15 @@ func (c *Command) list(ctx context.Context, r *readline.Readline, cmd string) er
for _, value := range paths {
c.l.Info("└ " + value)
out, err := c.op.RenderFile(ctx, value)
b, err := c.merge(ctx, value)
if err != nil {
return err
return errors.Wrap(err, "failed to merge config")
}
out, err := c.op.Render(ctx, string(b))
if err != nil {
pterm.Error.Println(string(b))
return errors.Wrap(err, "failed to render secrets")
}
if err := shell.New(ctx, c.l, "sesamy", "list", cmd, resource).
@ -350,7 +460,6 @@ func (c *Command) list(ctx context.Context, r *readline.Readline, cmd string) er
Args("--config", "-").
Args(r.AdditionalArgs()...).
Stdin(bytes.NewReader(out)).
Dir(path.Dir(value)).
Run(); err != nil {
return err
}
@ -364,12 +473,7 @@ func (c *Command) completePaths(ctx context.Context, t tree.Root, r *readline.Re
//nolint:forcetypeassert
func (c *Command) paths(ctx context.Context) []string {
return c.cache.Get("paths", func() any {
if value, err := files.Find(ctx, ".", "sesamy*.yml"); err != nil {
c.l.Debug("failed to walk files", err.Error())
return nil
} else {
return value
}
}).([]string)
keys := lo.Keys(c.config)
sort.Strings(keys)
return keys
}

3
foomo/sesamy/config.go Normal file
View File

@ -0,0 +1,3 @@
package sesamy
type Config map[string][]string

9
go.mod
View File

@ -10,11 +10,14 @@ require (
github.com/c-bata/go-prompt v0.2.6
github.com/cloudrecipes/packagejson v1.0.0
github.com/digitalocean/godo v1.139.0
github.com/foomo/posh v0.10.0
github.com/foomo/posh v0.10.1
github.com/goccy/go-json v0.10.5
github.com/golang-migrate/migrate/v4 v4.18.2
github.com/google/go-github/v47 v47.1.0
github.com/joho/godotenv v1.5.1
github.com/knadh/koanf/parsers/yaml v0.1.0
github.com/knadh/koanf/providers/file v1.1.2
github.com/knadh/koanf/v2 v2.1.2
github.com/mitchellh/mapstructure v1.5.0
github.com/muesli/go-app-paths v0.2.2
github.com/pkg/errors v0.9.1
@ -41,6 +44,7 @@ require (
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-test/deep v1.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/gookit/color v1.5.4 // indirect
@ -50,6 +54,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/knadh/koanf/maps v0.1.1 // indirect
github.com/lithammer/fuzzysearch v1.1.8 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.9 // indirect
@ -57,7 +62,9 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-tty v0.0.7 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/neilotoole/slogt v1.1.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect

18
go.sum
View File

@ -42,8 +42,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/foomo/posh v0.10.0 h1:iMCHgsUBZTMIeeCF0pnrT8vsWYguxtPXC4ndGrNpaMo=
github.com/foomo/posh v0.10.0/go.mod h1:iXdJ4j07pWlzrmINk7sn0hsl9b9cC90c6LcF4O96vMQ=
github.com/foomo/posh v0.10.1 h1:sIjCyEcFdKOHuyc/gcRPchHlHL8+qIkLvGfMkYy8cf0=
github.com/foomo/posh v0.10.1/go.mod h1:mHj/4ktsbdHOQTj6VDCsw/1lOA8qPeEsbJlKOMaZSmk=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/franklinkim/go-prompt v0.2.7-0.20210427061716-a8f4995d7aa5 h1:kXNtle4AoQnngdm+gwt4ku6Llbzw3EFHgZYpL618JaI=
@ -55,6 +55,8 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang-migrate/migrate/v4 v4.18.2 h1:2VSCMz7x7mjyTXx3m2zPokOY82LTRgxK1yQYKo6wWQ8=
@ -97,6 +99,14 @@ github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuOb
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
github.com/knadh/koanf/parsers/yaml v0.1.0 h1:ZZ8/iGfRLvKSaMEECEBPM1HQslrZADk8fP1XFUxVI5w=
github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY=
github.com/knadh/koanf/providers/file v1.1.2 h1:aCC36YGOgV5lTtAFz2qkgtWdeQsgfxUkxDOe+2nQY3w=
github.com/knadh/koanf/providers/file v1.1.2/go.mod h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI=
github.com/knadh/koanf/v2 v2.1.2 h1:I2rtLRqXRy1p01m/utEtpZSSA6dcJbgGVuE27kW2PzQ=
github.com/knadh/koanf/v2 v2.1.2/go.mod h1:Gphfaen0q1Fc1HTgJgSTC4oRX9R2R5ErYMZJy8fLJBo=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -128,10 +138,14 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
github.com/mattn/go-tty v0.0.7 h1:KJ486B6qI8+wBO7kQxYgmmEFDaFEE96JMBQ7h400N8Q=
github.com/mattn/go-tty v0.0.7/go.mod h1:f2i5ZOvXBU/tCABmLmOfzLz9azMo5wdAaElRNnJKr+k=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/muesli/go-app-paths v0.2.2 h1:NqG4EEZwNIhBq/pREgfBmgDmt3h1Smr1MjZiXbpZUnI=
github.com/muesli/go-app-paths v0.2.2/go.mod h1:SxS3Umca63pcFcLtbjVb+J0oD7cl4ixQWoBKhGEtEho=
github.com/neilotoole/slogt v1.1.0 h1:c7qE92sq+V0yvCuaxph+RQ2jOKL61c4hqS1Bv9W7FZE=