Skip to content

Commit

Permalink
Merge pull request #17 from BESTSELLER/lets-fix-docker
Browse files Browse the repository at this point in the history
Lets fix docker
  • Loading branch information
Gaardsholt authored Oct 26, 2020
2 parents 0fd911b + 9af85aa commit 8fb4662
Show file tree
Hide file tree
Showing 12 changed files with 829 additions and 67 deletions.
6 changes: 6 additions & 0 deletions .test_cases/1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2.1
jobs:
build:
docker:
- image: quay.io/jetstack/cert-manager-controller:v0.16.1
command: [--smallfiles]
6 changes: 5 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/",
"env": {},
"env": {
"DEPENDABOT_ORG": "BESTSELLER",
"DEPENDABOT_CONFIG": "/Users/lasse.gaardsholt/dev/dependabot-circleci/config.json",
"DEPENDABOT_DDADDRESS": "asd:443"
},
"args": []
}
]
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# dependabot-circleci
>!Disclaimer, it is early days, prepare for breaking changes.
>⚠️Disclaimer⚠️ it's early days, prepare for breaking changes!
<br/>

Expand Down Expand Up @@ -60,4 +60,4 @@ You must store this file in the .github directory of your repository.
<br/>

## Contributing
We are open for issues, pull requests etc.
We are open for issues, pull requests etc.
140 changes: 118 additions & 22 deletions circleci/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,46 @@ package circleci

import (
"fmt"
"regexp"
"sort"
"strings"

"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/hashicorp/go-version"
"github.com/rs/zerolog/log"
"gopkg.in/yaml.v3"
)

func extractImages(orbs []*yaml.Node) {
for i := 0; i < len(orbs); i++ {
orb := orbs[i]
if orb.Value == "image" {
orb = orbs[i+1]
func extractImages(images []*yaml.Node) map[string]*yaml.Node {
updates := map[string]*yaml.Node{}
for i := 0; i < len(images); i++ {
image := images[i]
if image.Value == "image" {
image = images[i+1]

orb.Value = findNewestDockerVersion(orb.Value)
imageVersion := findNewestDockerVersion(image.Value)
log.Debug().Msg(fmt.Sprintf("new: %s", imageVersion))

if image.Value != imageVersion {
oldVersion := image.Value
image.Value = imageVersion
updates[oldVersion] = image
}
}
baah := extractImages(image.Content)
for k, v := range baah {
updates[k] = v
}
extractImages(orb.Content)
}
return updates
}

func findNewestDockerVersion(currentVersion string) string {

fmt.Println(currentVersion)
log.Debug().Msg(fmt.Sprintf("old: %s", currentVersion))

current := strings.Split(currentVersion, ":")

fmt.Println(current)
fmt.Println(len(current))

// check if image has no version tag
if len(current) == 1 {
return currentVersion
Expand All @@ -38,19 +52,101 @@ func findNewestDockerVersion(currentVersion string) string {
return currentVersion
}

// define registry
registry := "registry.hub.docker.com"
registryImage := strings.Split(current[0], "/")
// fix this shit
tags, err := getTags(currentVersion)
if err != nil {
log.Debug().Err(err)
return currentVersion
}

versionParts := splitVersion(current[1])
if len(versionParts) == 0 {
return currentVersion
}

var newTagsList []string
for _, tag := range tags {
aa := splitVersion(tag)

if len(registryImage) > 2 {
registry = fmt.Sprintf("%s", registryImage[0])
if aa["version"] != "" && aa["prefix"] == versionParts["prefix"] && aa["suffix"] == versionParts["suffix"] {
newTagsList = append(newTagsList, tag)
}

}

errorList := []string{}
versions := []*version.Version{}
for _, raw := range newTagsList {
v, err := version.NewVersion(raw)
if err != nil {
errorList = append(errorList, fmt.Sprintf("%s", err))
continue
}

versions = append(versions, v)
}

if len(errorList) > 0 {
log.Debug().Err(fmt.Errorf("You have the following errors: %s", errorList))
}

fmt.Println(registry)
sort.Sort(version.Collection(versions))

// query that damn registry for newer versions
newest := versions[len(versions)-1]

currentv, _ := version.NewVersion(versionParts["version"])
if currentv.GreaterThan(newest) {
return currentVersion
}

return fmt.Sprintf("%s:%s", current[0], newest.Original())
}

func getTags(circleciTag string) ([]string, error) {
dig, err := name.NewTag(circleciTag, name.WeakValidation)
if err != nil {
return nil, err
}

registryName := dig.Registry.RegistryStr()
repoName := dig.Repository.RepositoryStr()

newName, err := name.NewRepository(fmt.Sprintf("%s/%s", registryName, repoName), name.WeakValidation)
if err != nil {
return nil, err
}
tags, err := remote.List(newName)
if err != nil {
return nil, err
}

return tags, nil
}

func splitVersion(version string) map[string]string {
result := make(map[string]string)
// Regex stolen with love from dependabot-core
// https://github.com/dependabot/dependabot-core/blob/v0.123.0/docker/lib/dependabot/docker/update_checker.rb#L15-L27
versionRegex := `v?(?P<version>([0-9]+)\.([0-9]+)\.([0-9]+)?(?:\+[0-9A-Za-z-]+)?)`
versionWithSFX := versionRegex + `(?P<suffix>-[a-z0-9.\-]+)?$`
versionWithPFX := `(?P<prefix>[a-z0-9.\-]+-)?` + versionRegex + `$`
versionWithPFXSFX := `(?P<prefix>[a-z\-]+-)?` + versionRegex + `(?P<suffix>-[a-z\-]+)?$`

nameWithVersion := versionWithPFX + `|` + versionWithSFX + `|` + versionWithPFXSFX

var myExp = regexp.MustCompile(nameWithVersion)
match := myExp.FindStringSubmatch(version)

if match == nil {
return result
}

matches := myExp.SubexpNames()
for i, name := range matches {
if i != 0 && name != "" && match[i] != "" {
result[name] = match[i]
}
}

return "latest"
// This one is a bit tricky actually! Watchtower seems to do this by utilising a docker client, but then we need
// Docker in docker i guess ? Maybe there is a smart api endpoint, all registries should use the same to communicate with docker i guess ?
return result
}
55 changes: 35 additions & 20 deletions circleci/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,52 @@ import (
"gopkg.in/yaml.v3"
)

// GetUpdates returns a list of updated yaml nodes
func GetUpdates(node *yaml.Node) map[string]*yaml.Node {
orbUpdates := map[string]*yaml.Node{}
func getDockerUpdates(node *yaml.Node) map[string]*yaml.Node {
updates := map[string]*yaml.Node{}

for i, nextHole := range node.Content {
if nextHole.Value == "executors" || nextHole.Value == "jobs" {
dockers := node.Content[i+1]
updates := extractImages(dockers.Content)
for k, v := range updates {
updates[k] = v
}
return updates
}

next := getDockerUpdates(nextHole)
for k, v := range next {
updates[k] = v
}
}

return updates
}
func getOrbUpdates(node *yaml.Node) map[string]*yaml.Node {
updates := map[string]*yaml.Node{}

for i, nextHole := range node.Content {
if nextHole.Value == "orbs" {
orbs := node.Content[i+1]
orbUpdates := extractOrbs(orbs.Content)
for k, v := range orbUpdates {
orbUpdates[k] = v
updates := extractOrbs(orbs.Content)
for k, v := range updates {
updates[k] = v
}
return orbUpdates
return updates
}

// *** ready for docker image check ***
// if nextHole.Value == "executors" {
// orbs := node.Content[i+1]
// extractImages(orbs.Content)
// }
// if nextHole.Value == "jobs" {
// orbs := node.Content[i+1]
// extractImages(orbs.Content)
// }

next := GetUpdates(nextHole)
next := getOrbUpdates(nextHole)
for k, v := range next {
orbUpdates[k] = v
updates[k] = v
}
}

return orbUpdates
return updates
}

// GetUpdates returns a list of updated yaml nodes
func GetUpdates(node *yaml.Node) (map[string]*yaml.Node, map[string]*yaml.Node) {
return getOrbUpdates(node), getDockerUpdates(node)
}

// ReplaceVersion replaces a specific line in the yaml
Expand Down
52 changes: 52 additions & 0 deletions circleci/update_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package circleci

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

"github.com/rs/zerolog/log"
"gopkg.in/yaml.v3"
)

func getTestCases() map[string]*yaml.Node {
path := "../.test_cases"
files, err := ioutil.ReadDir(path)
if err != nil {
log.Fatal().Err(err)
}
result := make(map[string]*yaml.Node, len(files))
for _, f := range files {
fileName := f.Name()
ext := strings.ToLower(filepath.Ext(fileName))
if ext != ".yml" && ext != ".yaml" {
continue
}
filePath := filepath.Join(path, fileName)
fmt.Println(f.Name())

content, _ := ioutil.ReadFile(filePath)
var cciconfig yaml.Node
err = yaml.Unmarshal(content, &cciconfig)
if err != nil {
continue
}
result[fileName] = &cciconfig
}

return result
}
func TestGetUpdates(t *testing.T) {
tests := getTestCases()

for k, v := range tests {
t.Run(k, func(t *testing.T) {
GetUpdates(v)
// if got := GetUpdates(v); !reflect.DeepEqual(got, tt.want) {
// t.Errorf("GetUpdates() = %v, want %v", got, tt.want)
// }
})
}
}
2 changes: 1 addition & 1 deletion config/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type EnvConfig struct {
Org string `required:"true"`
Config string `required:"true"`
LogLevel string `required:"false"`
DDAddress string `required:"true"`
DDAddress string `required:"false"`
}

// EnvVars stores the Global Configuration.
Expand Down
Loading

0 comments on commit 8fb4662

Please sign in to comment.