Skip to content

Commit

Permalink
collect errors and improve logging (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
choffmeister committed Dec 10, 2021
1 parent 634f7a7 commit ed4fa88
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 93 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ MAIN := .
TEST := ./internal

run:
go run $(MAIN) --dir=example --dry
go run $(MAIN) --dir=example --dry --verbose

test:
go test -v $(TEST)
Expand Down
42 changes: 31 additions & 11 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package cmd
import (
"fmt"
"io/ioutil"
"os"
"runtime/debug"

"github.com/airfocusio/git-ops-update/internal"
"github.com/fatih/color"
"github.com/spf13/cobra"
)

Expand All @@ -14,6 +16,7 @@ type rootCmd struct {
directory string
dry bool
verbose bool
noColor bool
}

func newRootCmd(version FullVersion) *rootCmd {
Expand All @@ -23,33 +26,50 @@ func newRootCmd(version FullVersion) *rootCmd {
Use: "git-ops-update",
Short: "An updater for docker images and helm charts in your infrastructure-as-code repository",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
Run: func(cmd *cobra.Command, args []string) {
internal.SetLogVerbosity(result.verbose)
if result.noColor {
color.NoColor = true
}
dir := result.directory
fileBytes, err := ioutil.ReadFile(internal.FileResolvePath(dir, ".git-ops-update.yaml"))
if err != nil {
return fmt.Errorf("unable to initialize: %w", err)
internal.LogError("Unable to initialize: %v", err)
os.Exit(1)
}
config, err := internal.LoadConfig(fileBytes)
if err != nil {
return fmt.Errorf("unable to load configuration: %w", err)
internal.LogError("Unable to load configuration: %v", err)
os.Exit(1)
}
cacheFile := internal.FileResolvePath(dir, ".git-ops-update.cache.yaml")
cacheProvider := internal.FileCacheProvider{File: cacheFile}
err = internal.ApplyUpdates(dir, *config, cacheProvider, internal.UpdateVersionsOptions{
Dry: result.dry,
Verbose: result.verbose,
})
if err != nil {
return fmt.Errorf("unable to update versions: %w", err)
result := internal.ApplyUpdates(dir, *config, cacheProvider, result.dry)

errorCount := 0
for _, r := range result {
if r.Error != nil {
errorCount += 1
internal.LogError("%v", r.Error)
} else if r.Skipped && r.Change != nil {
internal.LogDebug("At %s:%s the version could have been updated from %s to %s but as skipped", r.Change.File, r.Change.Trace.ToString(), r.Change.OldVersion, r.Change.NewVersion)
} else if !r.Done && r.Change != nil {
internal.LogInfo("At %s:%s the version can be updated from %s to %s", r.Change.File, r.Change.Trace.ToString(), r.Change.OldVersion, r.Change.NewVersion)
} else if r.Change != nil {
internal.LogInfo("At %s:%s the version was updated from %s to %s", r.Change.File, r.Change.Trace.ToString(), r.Change.OldVersion, r.Change.NewVersion)
}
}

if errorCount > 0 {
os.Exit(1)
}
return nil
},
}

cmd.PersistentFlags().StringVar(&result.directory, "dir", ".", "dir")
cmd.Flags().BoolVar(&result.dry, "dry", false, "dry")
cmd.Flags().BoolVar(&result.verbose, "verbose", false, "verbose")

cmd.Flags().BoolVar(&result.noColor, "no-color", false, "no-color")
result.cmd = cmd
return result
}
Expand Down
1 change: 1 addition & 0 deletions example/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ metadata:
name: nginx
labels:
app: nginx
fail: fail # git-ops-update {"will":"fail1"}
spec:
selector:
matchLabels:
Expand Down
1 change: 1 addition & 0 deletions example/helm-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: nginx-ingress
fail: fail # git-ops-update {"will":"fail2"}
spec:
chart:
spec:
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ require (
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)

require github.com/fatih/color v1.13.0

require (
github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3 // indirect
Expand All @@ -35,6 +37,8 @@ require (
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
Expand Down Expand Up @@ -287,7 +289,12 @@ github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
Expand Down Expand Up @@ -545,6 +552,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
4 changes: 2 additions & 2 deletions internal/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type Action func(dir string, changes Changes) (bool, error)
var branchPrefix = "git-ops-update"

func (p LocalGitProvider) Push(dir string, changes Changes) (bool, error) {
fmt.Printf("Local git provider does not support push mode. Will apply changes to worktree\n")
LogWarning("Local git provider does not support push mode. Will apply changes to worktree")
err := changes.Push(dir)
if err != nil {
return false, err
Expand All @@ -52,7 +52,7 @@ func (p LocalGitProvider) Push(dir string, changes Changes) (bool, error) {
}

func (p LocalGitProvider) Request(dir string, changes Changes) (bool, error) {
fmt.Printf("Local git provider does not support request mode. Will apply changes to worktree\n")
LogWarning("Local git provider does not support request mode. Will apply changes to worktree")
return p.Push(dir, changes)
}

Expand Down
36 changes: 36 additions & 0 deletions internal/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package internal

import (
"fmt"

"github.com/fatih/color"
)

var verbose = false

func SetLogVerbosity(value bool) {
verbose = value
}

var debugC = color.New(color.FgBlue).SprintFunc()("debug")
var infoC = color.New(color.FgGreen).SprintFunc()("info ")
var warningC = color.New(color.FgYellow).SprintFunc()("warn ")
var errorC = color.New(color.FgRed).SprintFunc()("error")

func LogDebug(msg string, args ...interface{}) {
if verbose {
fmt.Printf("[%s] %s\n", debugC, fmt.Sprintf(msg, args...))
}
}

func LogInfo(msg string, args ...interface{}) {
fmt.Printf("[%s] %s\n", infoC, fmt.Sprintf(msg, args...))
}

func LogWarning(msg string, args ...interface{}) {
fmt.Printf("[%s] %s\n", warningC, fmt.Sprintf(msg, args...))
}

func LogError(msg string, args ...interface{}) {
fmt.Printf("[%s] %s\n", errorC, fmt.Sprintf(msg, args...))
}
81 changes: 37 additions & 44 deletions internal/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,75 +11,67 @@ import (
"gopkg.in/yaml.v3"
)

type UpdateVersionsOptions struct {
Dry bool
Verbose bool
type UpdateVersionResult struct {
Error error
Change *Change
Done bool
Skipped bool
}

func ApplyUpdates(dir string, config Config, cacheProvider CacheProvider, opts UpdateVersionsOptions) error {
changes, err := DetectUpdates(dir, config, cacheProvider, opts.Verbose)
if err != nil {
return err
}
func ApplyUpdates(dir string, config Config, cacheProvider CacheProvider, dry bool) []UpdateVersionResult {
result := DetectUpdates(dir, config, cacheProvider)

for _, c := range *changes {
if !opts.Dry {
done, err := c.Action(dir, Changes{c})
if err != nil {
return err
if !dry {
for i := range result {
result := result[i]
if result.Error == nil && result.Change != nil {
done, err := result.Change.Action(dir, Changes{*result.Change})
result.Done = done
result.Error = err
}
if done {
fmt.Printf("%s\n", c.Message())
}
} else {
fmt.Printf("%s\n", c.Message())
}
}

if len(*changes) == 0 {
fmt.Printf("No updates available\n")
}

return nil
return result
}

func DetectUpdates(dir string, config Config, cacheProvider CacheProvider, verbose bool) (*Changes, error) {
func DetectUpdates(dir string, config Config, cacheProvider CacheProvider) []UpdateVersionResult {
cache, err := cacheProvider.Load()
if err != nil {
fmt.Printf("Unable to read cache: %v\n", err)
LogWarning("Unable to read cache: %v", err)
cache = &Cache{}
}

files, err := FileList(dir, config.Files.Includes, config.Files.Excludes)
if err != nil {
return nil, err
return []UpdateVersionResult{{Error: err}}
}

changes := Changes{}
result := []UpdateVersionResult{}
for _, file := range *files {
fileRel, err := filepath.Rel(dir, file)
if err != nil {
return nil, err
}
if verbose {
fmt.Printf("Scanning file %s\n", fileRel)
result = append(result, UpdateVersionResult{Error: err})
continue
}
LogDebug("Scanning file %s", fileRel)

fileDoc := &yaml.Node{}
err = fileReadYaml(file, fileDoc)
if err != nil {
return nil, err
result = append(result, UpdateVersionResult{Error: fmt.Errorf("%s: %w", fileRel, err)})
continue
}

err = VisitYaml(fileDoc, func(trace yamlTrace, yamlNode *yaml.Node) error {
errs := VisitYaml(fileDoc, func(trace yamlTrace, yamlNode *yaml.Node) error {
lineComment := strings.TrimPrefix(yamlNode.LineComment, "#")
if lineComment == "" {
return nil
}

annotation, err := parseAnnotation(*yamlNode, lineComment, config)
if err != nil {
return err
return fmt.Errorf("%s:%s: %w", fileRel, trace.ToString(), err)
}
if annotation == nil {
return nil
Expand All @@ -90,7 +82,7 @@ func DetectUpdates(dir string, config Config, cacheProvider CacheProvider, verbo
if cachedResource == nil || cachedResource.Timestamp.Add(time.Duration((*annotation.Registry).GetInterval())).Before(time.Now()) {
versions, err := (*annotation.Registry).FetchVersions(annotation.ResourceName)
if err != nil {
return err
return fmt.Errorf("%s:%s: %w", fileRel, trace.ToString(), err)
}
availableVersions = *versions
nextCache := cache.UpdateResource(CacheResource{
Expand All @@ -102,7 +94,7 @@ func DetectUpdates(dir string, config Config, cacheProvider CacheProvider, verbo
cache = &nextCache
err = cacheProvider.Save(*cache)
if err != nil {
return err
return fmt.Errorf("%s:%s: %w", fileRel, trace.ToString(), err)
}
} else {
availableVersions = cachedResource.Versions
Expand All @@ -111,11 +103,11 @@ func DetectUpdates(dir string, config Config, cacheProvider CacheProvider, verbo
currentValue := yamlNode.Value
currentVersion, err := (*annotation.Format).ExtractVersion(currentValue)
if err != nil {
return err
return fmt.Errorf("%s:%s: %w", fileRel, trace.ToString(), err)
}
nextVersion, err := annotation.Policy.FindNext(*currentVersion, availableVersions, annotation.Prefix, annotation.Suffix)
if err != nil {
return err
return fmt.Errorf("%s:%s: %w", fileRel, trace.ToString(), err)
}

if *currentVersion != *nextVersion {
Expand All @@ -128,9 +120,9 @@ func DetectUpdates(dir string, config Config, cacheProvider CacheProvider, verbo
}
nextValue, err := (*annotation.Format).ReplaceVersion(currentValue, *nextVersion)
if err != nil {
return err
return fmt.Errorf("%s:%s: %w", fileRel, trace.ToString(), err)
}
changes = append(changes, Change{
change := Change{
RegistryName: annotation.RegistryName,
ResourceName: annotation.ResourceName,
OldVersion: *currentVersion,
Expand All @@ -140,17 +132,18 @@ func DetectUpdates(dir string, config Config, cacheProvider CacheProvider, verbo
OldValue: currentValue,
NewValue: *nextValue,
Action: *annotation.Action,
})
}
result = append(result, UpdateVersionResult{Change: &change})
}

return nil
})
if err != nil {
return nil, err
for _, err := range errs {
result = append(result, UpdateVersionResult{Error: err})
}
}

return &changes, nil
return result
}

type annotation struct {
Expand Down
Loading

0 comments on commit ed4fa88

Please sign in to comment.