Skip to content

Commit

Permalink
feat: Check last dib build using referentiel image from registry
Browse files Browse the repository at this point in the history
  • Loading branch information
julienvey committed Jan 18, 2022
1 parent ce6dc87 commit 7e6329d
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 33 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ lint.fix: ## Lint and fix source code
golangci-lint run --fix -v

test: ## Run tests
IS_TEST="TRUE" bash -c 'go test -v ./... -coverprofile coverage.output'
go test -v ./... -coverprofile coverage.output

fmt: ## Run `go fmt` on all files
find -name '*.go' -exec gofmt -w -s '{}' ';'
19 changes: 17 additions & 2 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
versn "github.com/radiofrance/dib/version"
)

const placeholderNonExistent = "non-existent"

func cmdBuild(cmd *cli.Cmd) {
var opts buildOpts

Expand Down Expand Up @@ -110,9 +112,15 @@ func doBuild(opts buildOpts) (*dag.DAG, error) {
return nil, err
}

previousVersion, diffs, err := versn.GetDiffSinceLastDockerVersionChange(workingDir, shell)
previousVersion, diffs, err := versn.GetDiffSinceLastDockerVersionChange(
workingDir, shell, gcrRegistry, path.Join(opts.buildPath, versn.DockerVersionFilename),
path.Join(opts.registryURL, opts.referentialImage))
if err != nil {
return nil, err
if errors.Is(err, versn.ErrNoPreviousBuild) {
previousVersion = placeholderNonExistent
} else {
return nil, err
}
}

if opts.forceRebuild {
Expand All @@ -137,6 +145,13 @@ func doBuild(opts buildOpts) (*dag.DAG, error) {
return nil, err
}
}

// We retag the referential image to explicit this commit was build using dib
if err := DAG.Tagger.Tag(fmt.Sprintf("%s:%s", path.Join(opts.registryURL, opts.referentialImage), "latest"),
fmt.Sprintf("%s:%s", path.Join(opts.registryURL, opts.referentialImage), currentVersion)); err != nil {
return nil, err
}

logrus.Info("Build process completed")
return DAG, nil
}
Expand Down
4 changes: 0 additions & 4 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ import (
"github.com/sirupsen/logrus"
)

const (
defaultRegistryURL = "eu.gcr.io/my-test-repository"
)

func main() {
app := cli.App("dib", "Docker Image Builder helps building a complex image dependency graph")

Expand Down
25 changes: 17 additions & 8 deletions cmd/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@ import (
cli "github.com/jawher/mow.cli"
)

const (
defaultRegistryURL = "eu.gcr.io/my-test-repository"
defaultReferentialImage = "dib-referential"
)

type buildOpts struct {
dryRun bool
forceRebuild bool
runTests bool
retagLatest bool
generateGraph bool
localOnly bool
buildPath string
registryURL string
dryRun bool
forceRebuild bool
runTests bool
retagLatest bool
generateGraph bool
localOnly bool
buildPath string
registryURL string
referentialImage string
}

func defaultOpts(opts *buildOpts, cmd *cli.Cmd) {
Expand All @@ -27,4 +33,7 @@ be considered as the root directory for the hash generation and comparison`

cmd.StringArgPtr(&opts.buildPath, "BUILD_PATH", "docker", desc)
cmd.StringOptPtr(&opts.registryURL, "registry-url", defaultRegistryURL, "Docker registry URL where images are stored.")
cmd.StringOptPtr(&opts.referentialImage, "referential-image", defaultReferentialImage, "Name of an image on "+
"the registry. This image will serve as a reference for checking build completion of previous dib runs. Tags will be"+
"added to this image but it has no other purpose.")
}
11 changes: 11 additions & 0 deletions init/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This Dockerfile is only used to init your dib managed repository
#
# Within this repository, run the following commands
#
# $ docker build -t <your_registry_url>/dib-referential .
# $ docker push <your_registry_url>/dib-referential
#
# If you choose to use another name than `dib-referential`, you will need
# to set it in your command-line, with `--referential-image`
FROM scratch
LABEL name="dib-referential"
64 changes: 46 additions & 18 deletions version/git.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
package version

import (
"errors"
"fmt"
"path"
"strings"

"github.com/go-git/go-git/v5/plumbing/object"

"github.com/radiofrance/dib/types"

"github.com/go-git/go-git/v5/plumbing"

"github.com/go-git/go-git/v5"
"github.com/radiofrance/dib/exec"
)

var ErrNoPreviousBuild = errors.New("no previous build was found in git history")

// GetDiffSinceLastDockerVersionChange computes the diff since last version.
// The last version is the git revision hash of the .docker-version file.
// It returns the hash of the compared revision, and the list of modified files.
func GetDiffSinceLastDockerVersionChange(repositoryPath string, exec exec.Executor) (string, []string, error) {
func GetDiffSinceLastDockerVersionChange(repositoryPath string, exec exec.Executor,
registry types.DockerRegistry, dockerVersionFile, referentialImage string) (string, []string, error) {
repo, err := git.PlainOpen(repositoryPath)
if err != nil {
return "", nil, err
}

lastChangedDockerVersionHash, err := getLastChangedDockerVersion(repo)
lastChangedDockerVersionHash, err := getLastChangedDockerVersion(repo, registry, dockerVersionFile, referentialImage)
if err != nil {
return "", nil, err
}
Expand All @@ -30,6 +38,11 @@ func GetDiffSinceLastDockerVersionChange(repositoryPath string, exec exec.Execut
return "", nil, err
}

if lastChangedDockerVersionHash == plumbing.ZeroHash {
// No previous build was found
return "", nil, nil
}

versions := fmt.Sprintf("%s..%s", head.Hash().String(), lastChangedDockerVersionHash.String())
out, err := exec.Execute("git", "diff", versions, "--name-only")
if err != nil {
Expand All @@ -43,16 +56,17 @@ func GetDiffSinceLastDockerVersionChange(repositoryPath string, exec exec.Execut
fullPathDiffs = append(fullPathDiffs, path.Join(repositoryPath, filename))
}

dockerVersionContent, err := getDockerVersionContentForHash(repo, lastChangedDockerVersionHash)
dockerVersionContent, err := getDockerVersionContentForHash(repo, lastChangedDockerVersionHash, dockerVersionFile)
if err != nil {
return "", nil, fmt.Errorf("failed to get %s content for hash %s",
DockerVersionFilename, lastChangedDockerVersionHash.String())
dockerVersionFile, lastChangedDockerVersionHash.String())
}

return strings.TrimSuffix(dockerVersionContent, "\n"), fullPathDiffs, nil
}

func getDockerVersionContentForHash(repo *git.Repository, lastChangedDockerVersionHash plumbing.Hash) (string, error) {
func getDockerVersionContentForHash(repo *git.Repository, lastChangedDockerVersionHash plumbing.Hash,
dockerVersionFile string) (string, error) {
commitObject, err := repo.CommitObject(lastChangedDockerVersionHash)
if err != nil {
return "", err
Expand All @@ -61,7 +75,7 @@ func getDockerVersionContentForHash(repo *git.Repository, lastChangedDockerVersi
if err != nil {
return "", err
}
file, err := tree.File(DockerVersionFilename)
file, err := tree.File(dockerVersionFile)
if err != nil {
return "", err
}
Expand All @@ -72,23 +86,37 @@ func getDockerVersionContentForHash(repo *git.Repository, lastChangedDockerVersi
return content, nil
}

func getLastChangedDockerVersion(repository *git.Repository) (plumbing.Hash, error) {
filename := DockerVersionFilename
func getLastChangedDockerVersion(repository *git.Repository, registry types.DockerRegistry,
dockerVersionFile, referentialImage string) (plumbing.Hash, error) {
commitLog, err := repository.Log(&git.LogOptions{
FileName: &filename,
PathFilter: func(p string) bool {
return p == dockerVersionFile
},
})
if err != nil {
return plumbing.Hash{}, err
}

_, err = commitLog.Next() // We skip Next, which is the commit where it was last modified. We want the one before
if err != nil {
return plumbing.Hash{}, err
for {
commit, err := commitLog.Next()
if err != nil {
return plumbing.Hash{}, err
}
commitID := commit.ID()
dockerVersionContent, err := getDockerVersionContentForHash(repository, commitID, dockerVersionFile)
if err != nil {
if errors.Is(err, object.ErrFileNotFound) {
// We consider we went as far as we could to find a matching commit that was already built
return plumbing.Hash{}, ErrNoPreviousBuild
}
return plumbing.Hash{}, fmt.Errorf("failed to get %s content for hash %s", dockerVersionFile, commitID)
}
refExists, err := registry.RefExists(fmt.Sprintf("%s:%s", referentialImage, dockerVersionContent))
if err != nil {
return plumbing.Hash{}, err
}
if refExists {
return commitID, nil
}
}
commit, err := commitLog.Next()
if err != nil {
return plumbing.Hash{}, err
}

return commit.ID(), nil
}

0 comments on commit 7e6329d

Please sign in to comment.