Skip to content

Commit

Permalink
move update logic from main file to internal package
Browse files Browse the repository at this point in the history
  • Loading branch information
choffmeister committed Nov 12, 2021
1 parent 8822ae1 commit f839f9b
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 174 deletions.
176 changes: 2 additions & 174 deletions cmd/git-ops-update/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,134 +2,12 @@ package main

import (
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"

"github.com/choffmeister/git-ops-update/internal"
"gopkg.in/yaml.v3"
)

// UpdateVersionsOptions ...
type UpdateVersionsOptions struct {
Dry bool
Config string
}

// Run ...
func Run(dir string, opts UpdateVersionsOptions) error {
configFile := opts.Config
if !filepath.IsAbs(configFile) {
configFile = filepath.Join(dir, configFile)
}
configRaw, err := ioutil.ReadFile(configFile)
if err != nil {
return err
}
config, registries, policies, err := internal.LoadGitOpsUpdaterConfig(configRaw)
if err != nil {
return err
}

files, err := fileList(dir, config.Files.Includes, config.Files.Excludes)
if err != nil {
return err
}

for _, file := range *files {
log.Printf("Updating file %s\n", file)

fileBytes, err := ioutil.ReadFile(file)
if err != nil {
return err
}

fileDoc := yaml.Node{}
err = yaml.Unmarshal(fileBytes, &fileDoc)
if err != nil {
return err
}

err = internal.VisitAnnotations(&fileDoc, "git-ops-update", func(keyNode *yaml.Node, valueNode *yaml.Node, parentNodes []*yaml.Node, annotation string) error {
segments := strings.Split(annotation, ":")

registryName := segments[0]
if len(segments) < 2 {
return fmt.Errorf("line %d column %d: annotation is missing the resource", valueNode.Line, valueNode.Column)
}
registry, ok := (*registries)[registryName]
if !ok {
return fmt.Errorf("line %d column %d: annotation references unknown registry %s", valueNode.Line, valueNode.Column, registryName)
}

resourceName := segments[1]
if len(segments) < 3 {
return fmt.Errorf("line %d column %d: annotation is missing the policy", valueNode.Line, valueNode.Column)
}

policyName := segments[2]
policy, ok := (*policies)[policyName]
if !ok {
return fmt.Errorf("line %d column %d: annotation references unknown policy %s", valueNode.Line, valueNode.Column, policyName)
}

formatName := "plain"
if len(segments) >= 4 {
formatName = segments[3]
}
format, err := internal.GetFormat(formatName)
if err != nil {
return err
}

availableVersions, err := registry.FetchVersions(resourceName)
if err != nil {
return err
}
currentValue := valueNode.Value
currentVersion, err := (*format).ExtractVersion(currentValue)
if err != nil {
return err
}
nextVersion, err := policy.FindNext(*currentVersion, *availableVersions)
if err != nil {
return err
}

if *currentVersion != *nextVersion {
log.Printf("%s/%s: %s -> %s\n", registryName, resourceName, *currentVersion, *nextVersion)
nextValue, err := (*format).ReplaceVersion(currentValue, *nextVersion)
if err != nil {
return err
}
valueNode.Value = *nextValue
}

return nil
})
if err != nil {
return err
}

if !opts.Dry {
fileBytesOut, err := yaml.Marshal(&fileDoc)
if err != nil {
return err
}

err = ioutil.WriteFile(file, fileBytesOut, 0644)
if err != nil {
return err
}
}
}

return nil
}

func main() {
dry := flag.Bool("dry", false, "Dry run")
config := flag.String("config", ".git-ops-update.yaml", "Config file")
Expand All @@ -139,62 +17,12 @@ func main() {
if err != nil {
log.Fatalf("unable to determine current directory: %v\n", err)
}
opts := UpdateVersionsOptions{
opts := internal.UpdateVersionsOptions{
Dry: *dry,
Config: *config,
}
err = Run(dir, opts)
err = internal.UpdateVersions(dir, opts)
if err != nil {
log.Fatalf("unable to update versions: %v\n", err)
}
}

func fileList(dir string, includes []string, excludes []string) (*[]string, error) {
temp := []string{}
for _, exclude := range excludes {
fs, err := fileGlob(dir, exclude)
if err != nil {
return nil, err
}
temp = append(temp, *fs...)
}
files := []string{}
for _, include := range includes {
fs, err := fileGlob(dir, include)
if err != nil {
return nil, err
}
for _, f := range *fs {
excluded := false
for _, f2 := range temp {
if f == f2 {
excluded = true
break
}
}
if !excluded {
files = append(files, f)
}
}
}
return &files, nil
}

func fileGlob(dir string, pattern string) (*[]string, error) {
files := []string{}
err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
_, file := filepath.Split(path)
matched, err := filepath.Match(pattern, file)
if err != nil {
return err
}
if matched {
files = append(files, path)
}
return nil
})
return &files, err
}
1 change: 1 addition & 0 deletions internal/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func (f TagFormat) ReplaceVersion(str string, version string) (*string, error) {
return &result, nil
}

// GetFormat ...
func GetFormat(formatName string) (*Format, error) {
switch formatName {
case "plain":
Expand Down
128 changes: 128 additions & 0 deletions internal/update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package internal

import (
"fmt"
"io/ioutil"
"log"
"path/filepath"
"strings"

"gopkg.in/yaml.v3"
)

// UpdateVersionsOptions ...
type UpdateVersionsOptions struct {
Dry bool
Config string
}

// UpdateVersions ...
func UpdateVersions(dir string, opts UpdateVersionsOptions) error {
configFile := opts.Config
if !filepath.IsAbs(configFile) {
configFile = filepath.Join(dir, configFile)
}
configRaw, err := ioutil.ReadFile(configFile)
if err != nil {
return err
}
config, registries, policies, err := LoadGitOpsUpdaterConfig(configRaw)
if err != nil {
return err
}

files, err := fileList(dir, config.Files.Includes, config.Files.Excludes)
if err != nil {
return err
}

for _, file := range *files {
log.Printf("Updating file %s\n", file)

fileBytes, err := ioutil.ReadFile(file)
if err != nil {
return err
}

fileDoc := yaml.Node{}
err = yaml.Unmarshal(fileBytes, &fileDoc)
if err != nil {
return err
}

err = VisitAnnotations(&fileDoc, "git-ops-update", func(keyNode *yaml.Node, valueNode *yaml.Node, parentNodes []*yaml.Node, annotation string) error {
segments := strings.Split(annotation, ":")

registryName := segments[0]
if len(segments) < 2 {
return fmt.Errorf("line %d column %d: annotation is missing the resource", valueNode.Line, valueNode.Column)
}
registry, ok := (*registries)[registryName]
if !ok {
return fmt.Errorf("line %d column %d: annotation references unknown registry %s", valueNode.Line, valueNode.Column, registryName)
}

resourceName := segments[1]
if len(segments) < 3 {
return fmt.Errorf("line %d column %d: annotation is missing the policy", valueNode.Line, valueNode.Column)
}

policyName := segments[2]
policy, ok := (*policies)[policyName]
if !ok {
return fmt.Errorf("line %d column %d: annotation references unknown policy %s", valueNode.Line, valueNode.Column, policyName)
}

formatName := "plain"
if len(segments) >= 4 {
formatName = segments[3]
}
format, err := GetFormat(formatName)
if err != nil {
return err
}

availableVersions, err := registry.FetchVersions(resourceName)
if err != nil {
return err
}
currentValue := valueNode.Value
currentVersion, err := (*format).ExtractVersion(currentValue)
if err != nil {
return err
}
nextVersion, err := policy.FindNext(*currentVersion, *availableVersions)
if err != nil {
return err
}

if *currentVersion != *nextVersion {
log.Printf("%s/%s: %s -> %s\n", registryName, resourceName, *currentVersion, *nextVersion)
nextValue, err := (*format).ReplaceVersion(currentValue, *nextVersion)
if err != nil {
return err
}
valueNode.Value = *nextValue
}

return nil
})
if err != nil {
return err
}

if !opts.Dry {
fileBytesOut, err := yaml.Marshal(&fileDoc)
if err != nil {
return err
}

err = ioutil.WriteFile(file, fileBytesOut, 0644)
if err != nil {
return err
}
}
}

return nil
}
56 changes: 56 additions & 0 deletions internal/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package internal

import (
"os"
"path/filepath"
)

func fileList(dir string, includes []string, excludes []string) (*[]string, error) {
temp := []string{}
for _, exclude := range excludes {
fs, err := fileGlob(dir, exclude)
if err != nil {
return nil, err
}
temp = append(temp, *fs...)
}
files := []string{}
for _, include := range includes {
fs, err := fileGlob(dir, include)
if err != nil {
return nil, err
}
for _, f := range *fs {
excluded := false
for _, f2 := range temp {
if f == f2 {
excluded = true
break
}
}
if !excluded {
files = append(files, f)
}
}
}
return &files, nil
}

func fileGlob(dir string, pattern string) (*[]string, error) {
files := []string{}
err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
_, file := filepath.Split(path)
matched, err := filepath.Match(pattern, file)
if err != nil {
return err
}
if matched {
files = append(files, path)
}
return nil
})
return &files, err
}

0 comments on commit f839f9b

Please sign in to comment.