Merge pull request #69 from foomo/pretty

feat: pretty logs
This commit is contained in:
Kevin Franklin Kim 2024-09-25 17:35:45 +02:00 committed by GitHub
commit b79b8cfe6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 239 additions and 129 deletions

View File

@ -22,12 +22,12 @@ var buildCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
sq := squadron.New(cwd, "", flagFiles)
if err := sq.MergeConfigFiles(); err != nil {
if err := sq.MergeConfigFiles(cmd.Context()); err != nil {
return errors.Wrap(err, "failed to merge config files")
}
squadronName, unitNames := parseSquadronAndUnitNames(args)
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
if err := sq.FilterConfig(cmd.Context(), squadronName, unitNames, flagTags); err != nil {
return errors.Wrap(err, "failed to filter config")
}

View File

@ -22,12 +22,12 @@ var configCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
sq := squadron.New(cwd, "", flagFiles)
if err := sq.MergeConfigFiles(); err != nil {
if err := sq.MergeConfigFiles(cmd.Context()); err != nil {
return errors.Wrap(err, "failed to merge config files")
}
squadronName, unitNames := parseSquadronAndUnitNames(args)
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
if err := sq.FilterConfig(cmd.Context(), squadronName, unitNames, flagTags); err != nil {
return errors.Wrap(err, "failed to filter config")
}

View File

@ -19,14 +19,14 @@ var diffCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
sq := squadron.New(cwd, flagNamespace, flagFiles)
if err := sq.MergeConfigFiles(); err != nil {
if err := sq.MergeConfigFiles(cmd.Context()); err != nil {
return errors.Wrap(err, "failed to merge config files")
}
args, helmArgs := parseExtraArgs(args)
squadronName, unitNames := parseSquadronAndUnitNames(args)
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
if err := sq.FilterConfig(cmd.Context(), squadronName, unitNames, flagTags); err != nil {
return errors.Wrap(err, "failed to filter config")
}

View File

@ -21,14 +21,14 @@ var downCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
sq := squadron.New(cwd, flagNamespace, flagFiles)
if err := sq.MergeConfigFiles(); err != nil {
if err := sq.MergeConfigFiles(cmd.Context()); err != nil {
return errors.Wrap(err, "failed to merge config files")
}
args, helmArgs := parseExtraArgs(args)
squadronName, unitNames := parseSquadronAndUnitNames(args)
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
if err := sq.FilterConfig(cmd.Context(), squadronName, unitNames, flagTags); err != nil {
return errors.Wrap(err, "failed to filter config")
}

View File

@ -1,6 +1,8 @@
package actions
import (
"context"
"github.com/foomo/squadron"
"github.com/foomo/squadron/internal/config"
"github.com/pkg/errors"
@ -30,21 +32,21 @@ var listCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
sq := squadron.New(cwd, "", flagFiles)
if err := sq.MergeConfigFiles(); err != nil {
if err := sq.MergeConfigFiles(cmd.Context()); err != nil {
return errors.Wrap(err, "failed to merge config files")
}
squadronName, unitNames := parseSquadronAndUnitNames(args)
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
if err := sq.FilterConfig(cmd.Context(), squadronName, unitNames, flagTags); err != nil {
return errors.Wrap(err, "failed to filter config")
}
var list pterm.LeveledList
// List squadrons
_ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
_ = sq.Config().Squadrons.Iterate(cmd.Context(), func(ctx context.Context, key string, value config.Map[*config.Unit]) error {
list = append(list, pterm.LeveledListItem{Level: 0, Text: key})
return value.Iterate(func(k string, v *config.Unit) error {
return value.Iterate(ctx, func(ctx context.Context, k string, v *config.Unit) error {
list = append(list, pterm.LeveledListItem{Level: 1, Text: k})
if flagWithTags && len(v.Tags) > 0 {
list = append(list, pterm.LeveledListItem{Level: 2, Text: "🔖: " + v.Tags.SortedString()})

View File

@ -22,12 +22,12 @@ var pushCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
sq := squadron.New(cwd, flagNamespace, flagFiles)
if err := sq.MergeConfigFiles(); err != nil {
if err := sq.MergeConfigFiles(cmd.Context()); err != nil {
return errors.Wrap(err, "failed to merge config files")
}
squadronName, unitNames := parseSquadronAndUnitNames(args)
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
if err := sq.FilterConfig(cmd.Context(), squadronName, unitNames, flagTags); err != nil {
return errors.Wrap(err, "failed to filter config")
}

View File

@ -21,14 +21,14 @@ var rollbackCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
sq := squadron.New(cwd, flagNamespace, flagFiles)
if err := sq.MergeConfigFiles(); err != nil {
if err := sq.MergeConfigFiles(cmd.Context()); err != nil {
return errors.Wrap(err, "failed to merge config files")
}
args, helmArgs := parseExtraArgs(args)
squadronName, unitNames := parseSquadronAndUnitNames(args)
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
if err := sq.FilterConfig(cmd.Context(), squadronName, unitNames, flagTags); err != nil {
return errors.Wrap(err, "failed to filter config")
}

View File

@ -58,9 +58,12 @@ func init() {
rootCmd.AddCommand(upCmd, diffCmd, downCmd, buildCmd, pushCmd, listCmd, rollbackCmd, statusCmd, configCmd, versionCmd, completionCmd, templateCmd, postRendererCmd)
pterm.Info = *pterm.Info.WithPrefix(pterm.Prefix{Text: "INFO", Style: pterm.Info.Prefix.Style})
pterm.Error = *pterm.Info.WithPrefix(pterm.Prefix{Text: "ERROR", Style: pterm.Error.Prefix.Style})
pterm.Warning = *pterm.Info.WithPrefix(pterm.Prefix{Text: "WARNING", Style: pterm.Warning.Prefix.Style})
pterm.Info = *pterm.Info.WithPrefix(pterm.Prefix{Text: "⎈", Style: pterm.Info.Prefix.Style})
pterm.Debug = *pterm.Debug.WithPrefix(pterm.Prefix{Text: "⚒︎", Style: pterm.Debug.Prefix.Style})
pterm.Fatal = *pterm.Fatal.WithPrefix(pterm.Prefix{Text: "💀", Style: pterm.Fatal.Prefix.Style})
pterm.Error = *pterm.Error.WithPrefix(pterm.Prefix{Text: "⛌", Style: pterm.Error.Prefix.Style})
pterm.Warning = *pterm.Info.WithPrefix(pterm.Prefix{Text: "⚠", Style: pterm.Warning.Prefix.Style})
pterm.Success = *pterm.Success.WithPrefix(pterm.Prefix{Text: "✓", Style: pterm.Success.Prefix.Style})
}
func Execute() {

View File

@ -20,14 +20,14 @@ var statusCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
sq := squadron.New(cwd, flagNamespace, flagFiles)
if err := sq.MergeConfigFiles(); err != nil {
if err := sq.MergeConfigFiles(cmd.Context()); err != nil {
return errors.Wrap(err, "failed to merge config files")
}
args, helmArgs := parseExtraArgs(args)
squadronName, unitNames := parseSquadronAndUnitNames(args)
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
if err := sq.FilterConfig(cmd.Context(), squadronName, unitNames, flagTags); err != nil {
return errors.Wrap(err, "failed to filter config")
}

View File

@ -23,14 +23,14 @@ var templateCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
sq := squadron.New(cwd, flagNamespace, flagFiles)
if err := sq.MergeConfigFiles(); err != nil {
if err := sq.MergeConfigFiles(cmd.Context()); err != nil {
return errors.Wrap(err, "failed to merge config files")
}
args, helmArgs := parseExtraArgs(args)
squadronName, unitNames := parseSquadronAndUnitNames(args)
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
if err := sq.FilterConfig(cmd.Context(), squadronName, unitNames, flagTags); err != nil {
return errors.Wrap(err, "failed to filter config")
}

View File

@ -27,14 +27,14 @@ var upCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
sq := squadron.New(cwd, flagNamespace, flagFiles)
if err := sq.MergeConfigFiles(); err != nil {
if err := sq.MergeConfigFiles(cmd.Context()); err != nil {
return errors.Wrap(err, "failed to merge config files")
}
args, helmArgs := parseExtraArgs(args)
squadronName, unitNames := parseSquadronAndUnitNames(args)
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
if err := sq.FilterConfig(cmd.Context(), squadronName, unitNames, flagTags); err != nil {
return errors.Wrap(err, "failed to filter config")
}

View File

@ -1,6 +1,7 @@
package config
import (
"context"
"fmt"
"github.com/pkg/errors"
@ -21,10 +22,10 @@ type Config struct {
}
// BuildDependencies returns a map of requested build dependencies
func (c *Config) BuildDependencies() map[string]Build {
func (c *Config) BuildDependencies(ctx context.Context) map[string]Build {
ret := map[string]Build{}
_ = c.Squadrons.Iterate(func(key string, value Map[*Unit]) error {
return value.Iterate(func(k string, v *Unit) error {
_ = c.Squadrons.Iterate(ctx, func(ctx context.Context, key string, value Map[*Unit]) error {
return value.Iterate(ctx, func(ctx context.Context, k string, v *Unit) error {
for _, build := range v.Builds {
for _, dependency := range build.Dependencies {
b, ok := c.Builds[dependency]
@ -44,8 +45,8 @@ func (c *Config) BuildDependencies() map[string]Build {
}
// Trim delete empty squadron recursively
func (c *Config) Trim() {
_ = c.Squadrons.Iterate(func(key string, value Map[*Unit]) error {
func (c *Config) Trim(ctx context.Context) {
_ = c.Squadrons.Iterate(ctx, func(ctx context.Context, key string, value Map[*Unit]) error {
value.Trim()
return nil
})

View File

@ -1,6 +1,7 @@
package config
import (
"context"
"reflect"
"slices"
"sort"
@ -89,12 +90,15 @@ func (m Map[T]) FilterFn(handler func(key string, value T) bool) error {
return nil
}
func (m Map[T]) Iterate(handler func(key string, value T) error) error {
func (m Map[T]) Iterate(ctx context.Context, handler func(ctx context.Context, key string, value T) error) error {
if len(m) == 0 {
return nil
}
for _, key := range m.Keys() {
if err := handler(key, m[key]); err != nil {
if err := ctx.Err(); err != nil {
return err
}
if err := handler(ctx, key, m[key]); err != nil {
return err
}
}

View File

@ -5,12 +5,12 @@ import (
"context"
"fmt"
"path"
"sort"
"strings"
"github.com/foomo/squadron/internal/helm"
"github.com/foomo/squadron/internal/util"
"github.com/pkg/errors"
"github.com/pterm/pterm"
yamlv2 "gopkg.in/yaml.v2"
)
@ -44,34 +44,13 @@ func (u *Unit) ValuesYAML(global, vars map[string]any) ([]byte, error) {
return yamlv2.Marshal(values)
}
func (u *Unit) Build(ctx context.Context, squadron, unit string, args []string) (string, error) {
var i int
for _, build := range u.Builds {
i++
pterm.Info.Printfln("[%d/%d] Building %s/%s", i, len(u.Builds), squadron, unit)
pterm.FgGray.Printfln("└ %s:%s", build.Image, build.Tag)
if out, err := build.Build(ctx, args); err != nil {
pterm.Error.Printfln("[%d/%d] Failed to build squadron unit %s/%s", i, len(u.Builds), squadron, unit)
pterm.FgGray.Printfln("└ %s:%s", build.Image, build.Tag)
return out, err
}
func (u *Unit) BuildNames() []string {
ret := make([]string, 0, len(u.Builds))
for name := range u.Builds {
ret = append(ret, name)
}
return "", nil
}
func (u *Unit) Push(ctx context.Context, squadron, unit string, args []string) (string, error) {
var i int
for _, build := range u.Builds {
i++
pterm.Info.Printfln("[%d/%d] Pushing %s/%s", i, len(u.Builds), squadron, unit)
pterm.FgGray.Printfln("└ %s:%s", build.Image, build.Tag)
if out, err := build.Push(ctx, args); err != nil {
pterm.Error.Printfln("[%d/%d] Failed to push %s/%s", i, len(u.Builds), squadron, unit)
pterm.FgGray.Printfln("└ %s:%s", build.Image, build.Tag)
return out, err
}
}
return "", nil
sort.Strings(ret)
return ret
}
func (u *Unit) Template(ctx context.Context, name, squadron, unit, namespace string, global, vars map[string]any, helmArgs []string) ([]byte, error) {

View File

@ -1,9 +1,30 @@
package template
import (
"fmt"
"strings"
)
func quote(str ...any) string {
out := make([]string, 0, len(str))
for _, s := range str {
if s != nil {
out = append(out, fmt.Sprintf("%v", s))
}
}
return "'" + strings.Join(out, " ") + "'"
}
func quoteAll(str ...any) string {
out := make([]string, 0, len(str))
for _, s := range str {
if s != nil {
out = append(out, fmt.Sprintf("'%v'", s))
}
}
return strings.Join(out, " ")
}
func indent(spaces int, v string) string {
pad := strings.Repeat(" ", spaces)
return strings.ReplaceAll(v, "\n", "\n"+pad)

View File

@ -14,6 +14,8 @@ func ExecuteFileTemplate(ctx context.Context, text string, templateVars any, err
delete(funcMap, "expandenv")
funcMap["env"] = env
funcMap["quote"] = quote
funcMap["quoteAll"] = quoteAll
funcMap["envDefault"] = envDefault
// deprecated

View File

@ -2,6 +2,7 @@ package util
import (
"bytes"
"fmt"
"github.com/alecthomas/chroma"
"github.com/alecthomas/chroma/formatters"
@ -11,7 +12,10 @@ import (
)
func Highlight(source string) string {
var out bytes.Buffer
out := &numberWriter{
w: bytes.NewBufferString(""),
currentLine: 1,
}
// Determine lexer.
l := lexers.Get("yaml")
if l == nil {
@ -38,10 +42,57 @@ func Highlight(source string) string {
if err != nil {
pterm.Error.Println(err.Error())
}
err = f.Format(&out, s, it)
if err != nil {
if err = f.Format(out, s, it); err != nil {
pterm.Error.Println(err.Error())
}
return out.String()
return out.w.String()
}
type numberWriter struct {
w *bytes.Buffer
currentLine uint64
buf []byte
}
func (w *numberWriter) Write(p []byte) (int, error) {
// Early return.
// Can't calculate the line numbers until the line breaks are made, so store them all in a buffer.
if !bytes.Contains(p, []byte{'\n'}) {
w.buf = append(w.buf, p...)
return len(p), nil
}
var (
original = p
tokenLen uint
)
for i, c := range original {
tokenLen++
if c != '\n' {
continue
}
token := p[:tokenLen]
p = original[i+1:]
tokenLen = 0
format := "%4d |\t%s%s"
if w.currentLine > 9999 {
format = "%d |\t%s%s"
}
format = "\033[34m" + format + "\033[0m"
if _, err := fmt.Fprintf(w.w, format, w.currentLine, string(w.buf), string(token)); err != nil {
return i + 1, err
}
w.buf = w.buf[:0]
w.currentLine++
}
if len(p) > 0 {
w.buf = append(w.buf, p...)
}
return len(original), nil
}

View File

@ -11,6 +11,7 @@ import (
"slices"
"strings"
"sync"
"time"
"github.com/foomo/squadron/internal/config"
templatex "github.com/foomo/squadron/internal/template"
@ -68,7 +69,7 @@ func (sq *Squadron) ConfigYAML() string {
// ~ Public methods
// ------------------------------------------------------------------------------------------------
func (sq *Squadron) MergeConfigFiles() error {
func (sq *Squadron) MergeConfigFiles(ctx context.Context) error {
pterm.Debug.Println("merging config files")
pterm.Debug.Println(strings.Join(append([]string{"using files"}, sq.files...), "\n└ "))
@ -87,7 +88,7 @@ func (sq *Squadron) MergeConfigFiles() error {
return errors.New("Please upgrade your YAML definition to 2.0")
}
sq.c.Trim()
sq.c.Trim(ctx)
value, err := yamlv2.Marshal(sq.c)
if err != nil {
@ -99,7 +100,7 @@ func (sq *Squadron) MergeConfigFiles() error {
return nil
}
func (sq *Squadron) FilterConfig(squadron string, units, tags []string) error {
func (sq *Squadron) FilterConfig(ctx context.Context, squadron string, units, tags []string) error {
if len(squadron) > 0 {
if err := sq.Config().Squadrons.Filter(squadron); err != nil {
return err
@ -113,7 +114,7 @@ func (sq *Squadron) FilterConfig(squadron string, units, tags []string) error {
}
if len(tags) > 0 {
if err := sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
if err := sq.Config().Squadrons.Iterate(ctx, func(ctx context.Context, key string, value config.Map[*config.Unit]) error {
return value.FilterFn(func(k string, v *config.Unit) bool {
for _, tag := range tags {
if strings.HasPrefix(tag, "-") {
@ -131,7 +132,7 @@ func (sq *Squadron) FilterConfig(squadron string, units, tags []string) error {
}
}
sq.c.Trim()
sq.c.Trim(ctx)
value, err := yamlv2.Marshal(sq.c)
if err != nil {
@ -169,22 +170,22 @@ func (sq *Squadron) RenderConfig(ctx context.Context) error {
// execute without errors to get existing values
pterm.Debug.Println("executing file template")
// pterm.Debug.Println(sq.config)
out, err := templatex.ExecuteFileTemplate(ctx, sq.config, tv, false)
out1, err := templatex.ExecuteFileTemplate(ctx, sq.config, tv, false)
if err != nil {
return errors.Wrapf(err, "failed to execute initial file template\n%s", util.Highlight(sq.config))
}
// re-execute for rendering copied values
pterm.Debug.Println("re-executing file template")
// pterm.Debug.Println(string(out))
out, err = templatex.ExecuteFileTemplate(ctx, string(out), tv, false)
out2, err := templatex.ExecuteFileTemplate(ctx, string(out1), tv, false)
if err != nil {
fmt.Print(util.Highlight(string(out1)))
return errors.Wrap(err, "failed to re-execute initial file template")
}
pterm.Debug.Println("unmarshalling vars")
if err := yaml.Unmarshal(out, &vars); err != nil {
pterm.Error.Println(string(out))
if err := yaml.Unmarshal(out2, &vars); err != nil {
fmt.Print(util.Highlight(string(out2)))
return errors.Wrap(err, "failed to unmarshal vars")
}
@ -204,34 +205,47 @@ func (sq *Squadron) RenderConfig(ctx context.Context) error {
}
pterm.Debug.Println("executing file template")
out, err = templatex.ExecuteFileTemplate(ctx, sq.config, tv, true)
out3, err := templatex.ExecuteFileTemplate(ctx, sq.config, tv, true)
if err != nil {
fmt.Print(util.Highlight(sq.config))
return errors.Wrap(err, "failed to execute second file template")
}
pterm.Debug.Println("unmarshalling vars")
if err := yaml.Unmarshal(out, &sq.c); err != nil {
pterm.Error.Println(string(out))
if err := yaml.Unmarshal(out3, &sq.c); err != nil {
fmt.Print(util.Highlight(string(out3)))
return errors.Wrap(err, "failed to unmarshal vars")
}
sq.config = string(out)
sq.config = string(out3)
return nil
}
func (sq *Squadron) Push(ctx context.Context, pushArgs []string, parallel int) error {
wg, gctx := errgroup.WithContext(ctx)
wg, ctx := errgroup.WithContext(ctx)
wg.SetLimit(parallel)
_ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
return value.Iterate(func(k string, v *config.Unit) error {
wg.Go(func() error {
if out, err := v.Push(gctx, key, k, pushArgs); err != nil {
return errors.Wrap(err, out)
}
return nil
})
_ = sq.Config().Squadrons.Iterate(ctx, func(ctx context.Context, key string, value config.Map[*config.Unit]) error {
return value.Iterate(ctx, func(ctx context.Context, k string, v *config.Unit) error {
for _, name := range v.BuildNames() {
build := v.Builds[name]
id := fmt.Sprintf("%s/%s.%s", key, k, name)
wg.Go(func() error {
if err := ctx.Err(); err != nil {
return err
}
start := time.Now()
pterm.Info.Printfln("Push | %s [%s:%s]", id, build.Image, build.Tag)
if out, err := build.Push(ctx, pushArgs); err != nil {
pterm.Error.Printfln("Push | %s [%s:%s] ⏱ %s", id, build.Image, build.Tag, time.Since(start).Round(time.Millisecond))
return errors.Wrap(err, out)
}
pterm.Success.Printfln("Push | %s [%s:%s] ⏱ %s", id, build.Image, build.Tag, time.Since(start).Round(time.Millisecond))
return nil
})
}
return nil
})
})
@ -240,21 +254,23 @@ func (sq *Squadron) Push(ctx context.Context, pushArgs []string, parallel int) e
}
func (sq *Squadron) BuildDependencies(ctx context.Context, buildArgs []string, parallel int) error {
wg, gctx := errgroup.WithContext(ctx)
wg, ctx := errgroup.WithContext(ctx)
wg.SetLimit(parallel)
var i int
dependencies := sq.c.BuildDependencies()
for name, dependency := range dependencies {
i := i + 1
dependencies := sq.c.BuildDependencies(ctx)
for name, build := range dependencies {
wg.Go(func() error {
pterm.Info.Printfln("[%d/%d] Building dependency `%s`", i, len(dependencies), name)
pterm.FgGray.Printfln("└ %s:%s", dependency.Image, dependency.Tag)
if out, err := dependency.Build(gctx, buildArgs); err != nil {
pterm.Error.Printfln("[%d/%d] Failed to build dependency `%s`", i, len(dependencies), name)
pterm.FgGray.Printfln("└ %s:%s", dependency.Image, dependency.Tag)
if err := ctx.Err(); err != nil {
return err
}
start := time.Now()
pterm.Info.Printfln("Build | %s [%s:%s]", name, build.Image, build.Tag)
if out, err := build.Build(ctx, buildArgs); err != nil {
pterm.Error.Printfln("Build | %s [%s:%s] ⏱ %s", name, build.Image, build.Tag, time.Since(start).Round(time.Millisecond))
return errors.Wrap(err, out)
}
pterm.Success.Printfln("Build | %s [%s:%s] ⏱ %s", name, build.Image, build.Tag, time.Since(start).Round(time.Millisecond))
return nil
})
}
@ -267,17 +283,29 @@ func (sq *Squadron) Build(ctx context.Context, buildArgs []string, parallel int)
return err
}
wg, gctx := errgroup.WithContext(ctx)
wg, ctx := errgroup.WithContext(ctx)
wg.SetLimit(parallel)
_ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
return value.Iterate(func(k string, v *config.Unit) error {
wg.Go(func() error {
if out, err := v.Build(gctx, key, k, buildArgs); err != nil {
return errors.Wrap(err, out)
}
return nil
})
_ = sq.Config().Squadrons.Iterate(ctx, func(ctx context.Context, key string, value config.Map[*config.Unit]) error {
return value.Iterate(ctx, func(ctx context.Context, k string, v *config.Unit) error {
for _, name := range v.BuildNames() {
build := v.Builds[name]
id := fmt.Sprintf("%s/%s.%s", key, k, name)
wg.Go(func() error {
if err := ctx.Err(); err != nil {
return err
}
start := time.Now()
pterm.Info.Printfln("Build | %s [%s:%s]", id, build.Image, build.Tag)
if out, err := build.Build(ctx, buildArgs); err != nil {
pterm.Error.Printfln("Build | %s [%s:%s] ⏱ %s", id, build.Image, build.Tag, time.Since(start).Round(time.Millisecond))
return errors.Wrap(err, out)
}
pterm.Success.Printfln("Build | %s [%s:%s] ⏱ %s", id, build.Image, build.Tag, time.Since(start).Round(time.Millisecond))
return nil
})
}
return nil
})
})
@ -289,9 +317,14 @@ func (sq *Squadron) Down(ctx context.Context, helmArgs []string, parallel int) e
wg, ctx := errgroup.WithContext(ctx)
wg.SetLimit(parallel)
_ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
return value.Iterate(func(k string, v *config.Unit) error {
_ = sq.Config().Squadrons.Iterate(ctx, func(ctx context.Context, key string, value config.Map[*config.Unit]) error {
return value.Iterate(ctx, func(ctx context.Context, k string, v *config.Unit) error {
wg.Go(func() error {
if err := ctx.Err(); err != nil {
return err
}
start := time.Now()
name := fmt.Sprintf("%s-%s", key, k)
namespace, err := sq.Namespace(ctx, key, k)
if err != nil {
@ -299,7 +332,7 @@ func (sq *Squadron) Down(ctx context.Context, helmArgs []string, parallel int) e
}
stdErr := bytes.NewBuffer([]byte{})
pterm.Debug.Printfln("running helm uninstall for: %s", name)
pterm.Info.Printfln("Down | %s/%s", key, k)
if out, err := util.NewHelmCommand().Args("uninstall", name).
Stderr(stdErr).
Stdout(os.Stdout).
@ -307,8 +340,10 @@ func (sq *Squadron) Down(ctx context.Context, helmArgs []string, parallel int) e
Args(helmArgs...).
Run(ctx); err != nil &&
string(bytes.TrimSpace(stdErr.Bytes())) != fmt.Sprintf("Error: uninstall: Release not loaded: %s: release: not found", name) {
pterm.Error.Printfln("Down | %s/%s] ⏱ %s", key, k, time.Since(start).Round(time.Millisecond))
return errors.Wrap(err, out)
}
pterm.Success.Printfln("Down | %s/%s] ⏱ %s", key, k, time.Since(start).Round(time.Millisecond))
return nil
})
return nil
@ -330,9 +365,13 @@ func (sq *Squadron) Diff(ctx context.Context, helmArgs []string, parallel int) e
wg, ctx := errgroup.WithContext(ctx)
wg.SetLimit(parallel)
_ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
return value.Iterate(func(k string, v *config.Unit) error {
_ = sq.Config().Squadrons.Iterate(ctx, func(ctx context.Context, key string, value config.Map[*config.Unit]) error {
return value.Iterate(ctx, func(ctx context.Context, k string, v *config.Unit) error {
wg.Go(func() error {
if err := ctx.Err(); err != nil {
return err
}
name := fmt.Sprintf("%s-%s", key, k)
namespace, err := sq.Namespace(ctx, key, k)
if err != nil {
@ -422,8 +461,8 @@ func (sq *Squadron) Status(ctx context.Context, helmArgs []string, parallel int)
wg, ctx := errgroup.WithContext(ctx)
wg.SetLimit(parallel)
_ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
return value.Iterate(func(k string, v *config.Unit) error {
_ = sq.Config().Squadrons.Iterate(ctx, func(ctx context.Context, key string, value config.Map[*config.Unit]) error {
return value.Iterate(ctx, func(ctx context.Context, k string, v *config.Unit) error {
var status statusType
name := fmt.Sprintf("%s-%s", key, k)
namespace, err := sq.Namespace(ctx, key, k)
@ -486,8 +525,8 @@ func (sq *Squadron) Rollback(ctx context.Context, revision string, helmArgs []st
wg, ctx := errgroup.WithContext(ctx)
wg.SetLimit(parallel)
_ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
return value.Iterate(func(k string, v *config.Unit) error {
_ = sq.Config().Squadrons.Iterate(ctx, func(ctx context.Context, key string, value config.Map[*config.Unit]) error {
return value.Iterate(ctx, func(ctx context.Context, k string, v *config.Unit) error {
name := fmt.Sprintf("%s-%s", key, k)
namespace, err := sq.Namespace(ctx, key, k)
if err != nil {
@ -518,8 +557,8 @@ func (sq *Squadron) Rollback(ctx context.Context, revision string, helmArgs []st
func (sq *Squadron) UpdateLocalDependencies(ctx context.Context, parallel int) error {
// collect unique entrie
repositories := map[string]struct{}{}
err := sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
return value.Iterate(func(k string, v *config.Unit) error {
err := sq.Config().Squadrons.Iterate(ctx, func(ctx context.Context, key string, value config.Map[*config.Unit]) error {
return value.Iterate(ctx, func(ctx context.Context, k string, v *config.Unit) error {
if strings.HasPrefix(v.Chart.Repository, "file:///") {
repositories[v.Chart.Repository] = struct{}{}
}
@ -530,7 +569,7 @@ func (sq *Squadron) UpdateLocalDependencies(ctx context.Context, parallel int) e
return err
}
wg, gctx := errgroup.WithContext(ctx)
wg, ctx := errgroup.WithContext(ctx)
wg.SetLimit(parallel)
for repository := range repositories {
@ -539,7 +578,7 @@ func (sq *Squadron) UpdateLocalDependencies(ctx context.Context, parallel int) e
if out, err := util.NewHelmCommand().
Cwd(path.Clean(strings.TrimPrefix(repository, "file://"))).
Args("dependency", "update", "--skip-refresh", "--debug").
Run(gctx); err != nil {
Run(ctx); err != nil {
return errors.Wrap(err, out)
} else {
pterm.Debug.Println(out)
@ -554,12 +593,16 @@ func (sq *Squadron) UpdateLocalDependencies(ctx context.Context, parallel int) e
func (sq *Squadron) Up(ctx context.Context, helmArgs []string, username, version, commit, branch string, parallel int) error {
description := fmt.Sprintf("\nDeployed-By: %s\nManaged-By: Squadron %s\nGit-Commit: %s\nGit-Branch: %s", username, version, commit, branch)
wg, gctx := errgroup.WithContext(ctx)
wg, ctx := errgroup.WithContext(ctx)
wg.SetLimit(parallel)
_ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
return value.Iterate(func(k string, v *config.Unit) error {
_ = sq.Config().Squadrons.Iterate(ctx, func(ctx context.Context, key string, value config.Map[*config.Unit]) error {
return value.Iterate(ctx, func(ctx context.Context, k string, v *config.Unit) error {
wg.Go(func() error {
if err := ctx.Err(); err != nil {
return err
}
name := fmt.Sprintf("%s-%s", key, k)
namespace, err := sq.Namespace(ctx, key, k)
if err != nil {
@ -597,7 +640,7 @@ func (sq *Squadron) Up(ctx context.Context, helmArgs []string, username, version
}
}
if out, err := cmd.Run(gctx); err != nil {
if out, err := cmd.Run(ctx); err != nil {
return errors.Wrap(err, out)
}
@ -620,12 +663,16 @@ func (sq *Squadron) Template(ctx context.Context, helmArgs []string, parallel in
return err
}
wg, gctx := errgroup.WithContext(ctx)
wg, ctx := errgroup.WithContext(ctx)
wg.SetLimit(parallel)
_ = sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
return value.Iterate(func(k string, v *config.Unit) error {
_ = sq.Config().Squadrons.Iterate(ctx, func(ctx context.Context, key string, value config.Map[*config.Unit]) error {
return value.Iterate(ctx, func(ctx context.Context, k string, v *config.Unit) error {
wg.Go(func() error {
if err := ctx.Err(); err != nil {
return err
}
name := fmt.Sprintf("%s-%s", key, k)
namespace, err := sq.Namespace(ctx, key, k)
if err != nil {
@ -633,7 +680,7 @@ func (sq *Squadron) Template(ctx context.Context, helmArgs []string, parallel in
}
pterm.Debug.Printfln("running helm template for chart: %s", name)
out, err := v.Template(gctx, name, key, k, namespace, sq.c.Global, sq.c.Vars, helmArgs)
out, err := v.Template(ctx, name, key, k, namespace, sq.c.Global, sq.c.Vars, helmArgs)
if err != nil {
return err
}

View File

@ -73,11 +73,11 @@ func config(t *testing.T, name string, files []string, squadronName string, unit
sq := squadron.New(cwd, "default", files)
{
require.NoError(t, sq.MergeConfigFiles(), "failed to merge files")
require.NoError(t, sq.MergeConfigFiles(ctx), "failed to merge files")
}
{
require.NoError(t, sq.FilterConfig(squadronName, unitNames, tags), "failed to filter config")
require.NoError(t, sq.FilterConfig(ctx, squadronName, unitNames, tags), "failed to filter config")
testutils.Snapshot(t, path.Join("testdata", name, "snapshop-config-norender.yaml"), sq.ConfigYAML())
}