diff --git a/cmd/build.go b/cmd/build.go index ee335870..3de085f9 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -3,7 +3,8 @@ package main import ( "path" - "github.com/radiofrance/dib/builder/docker" + "github.com/radiofrance/dib/docker" + "github.com/radiofrance/dib/registry" "github.com/radiofrance/dib/types" @@ -54,18 +55,25 @@ func doBuild(opts buildOpts) (*dag.DAG, error) { } var err error - reg, err := registry.NewRegistry(opts.registryURL, opts.dryRun) + gcrRegistry, err := registry.NewRegistry(opts.registryURL, opts.dryRun) if err != nil { return nil, err } + dockerBuilderTagger := docker.NewImageBuilderTagger(shell, opts.dryRun) DAG := &dag.DAG{ - Registry: reg, - Builder: docker.NewImageBuilder(shell, opts.dryRun), + Registry: gcrRegistry, + Builder: dockerBuilderTagger, TestRunners: []types.TestRunner{ dgoss.TestRunner{}, }, } + if opts.localOnly { + DAG.Tagger = dockerBuilderTagger + } else { + DAG.Tagger = gcrRegistry + } + buildPath := path.Join(opts.inputDir, opts.buildDir) logrus.Infof("Building images in directory \"%s\"", buildPath) @@ -90,11 +98,9 @@ func doBuild(opts buildOpts) (*dag.DAG, error) { DAG.CheckForDiff(diffs) } - if !opts.localOnly { - err = DAG.Retag(currentVersion, previousVersion) - if err != nil { - return nil, err - } + err = DAG.Retag(currentVersion, previousVersion) + if err != nil { + return nil, err } if err := DAG.Rebuild(currentVersion, opts.forceRebuild, opts.runTests, opts.localOnly); err != nil { diff --git a/dag/dag.go b/dag/dag.go index c69ffdc6..94d60d24 100644 --- a/dag/dag.go +++ b/dag/dag.go @@ -16,6 +16,7 @@ type DAG struct { Images []*Image Registry types.DockerRegistry Builder types.ImageBuilder + Tagger types.ImageTagger TestRunners []types.TestRunner } @@ -49,6 +50,7 @@ func (dag *DAG) GenerateDAG(buildPath string, registryPrefix string) { Builder: dag.Builder, Registry: dag.Registry, TestRunners: dag.TestRunners, + Tagger: dag.Tagger, } allParents[img.Name] = dockerfile.From diff --git a/dag/image.go b/dag/image.go index c5972b6d..ae50a660 100644 --- a/dag/image.go +++ b/dag/image.go @@ -33,6 +33,7 @@ type Image struct { RebuildCond *sync.Cond Registry types.DockerRegistry Builder types.ImageBuilder + Tagger types.ImageTagger TestRunners []types.TestRunner } @@ -186,7 +187,7 @@ func (img *Image) runTests(ref, path string) error { func (img *Image) retagLatest(tag string) error { if !img.RetagLatestDone { logrus.Debugf("Retag latest tag for image %s with version %s", img.Name, tag) - if err := img.Registry.Retag(img.dockerRef(tag), img.dockerRef(latest)); err != nil { + if err := img.Tagger.Tag(img.dockerRef(tag), img.dockerRef(latest)); err != nil { return err } img.RetagLatestDone = true @@ -236,7 +237,7 @@ func (img *Image) doRetag(newTag, oldTag string) error { logrus.Debugf("Current tag for \"%s:%s\", already exists, nothing to do", img.Name, newTag) } else { if previousTagExists { - return img.retagRemote(oldTag, newTag) + return img.Tagger.Tag(img.dockerRef(oldTag), img.dockerRef(newTag)) } else { logrus.Warnf("Previous tag \"%s:%s\" missing, image will be rebuilt", img.Name, oldTag) img.tagForRebuild() @@ -245,13 +246,6 @@ func (img *Image) doRetag(newTag, oldTag string) error { return nil } -func (img *Image) retagRemote(oldTag string, newTag string) error { - logrus.Infof("Retagging image \"%s:%s\" with tag \"%s\"", img.Name, oldTag, newTag) - err := img.Registry.Retag(img.dockerRef(oldTag), img.dockerRef(newTag)) - img.RetagDone = true - return err -} - func (img *Image) dockerRef(version string) string { return fmt.Sprintf("%s:%s", img.Name, version) } diff --git a/builder/docker/builder.go b/docker/builder.go similarity index 61% rename from builder/docker/builder.go rename to docker/builder.go index 55eeb50c..bcdb0613 100644 --- a/builder/docker/builder.go +++ b/docker/builder.go @@ -9,20 +9,20 @@ import ( "github.com/sirupsen/logrus" ) -// ImageBuilder builds an image using the docker command-line executable. -type ImageBuilder struct { +// ImageBuilderTagger builds an image using the docker command-line executable. +type ImageBuilderTagger struct { exec exec.Executor dryRun bool } -// NewImageBuilder creates a new instance of an ImageBuilder. -func NewImageBuilder(executor exec.Executor, dryRun bool) *ImageBuilder { - return &ImageBuilder{executor, dryRun} +// NewImageBuilderTagger creates a new instance of an ImageBuilder. +func NewImageBuilderTagger(executor exec.Executor, dryRun bool) *ImageBuilderTagger { + return &ImageBuilderTagger{executor, dryRun} } // Build the image using the docker executable. // If the image is built successfully, the image will be pushed to the registry. -func (b ImageBuilder) Build(opts types.ImageBuilderOpts) error { +func (b ImageBuilderTagger) Build(opts types.ImageBuilderOpts) error { if b.dryRun { logrus.Infof("[DRY-RUN] docker build --no-cache -t %s %s", opts.Tag, opts.Context) @@ -69,3 +69,18 @@ func (b ImageBuilder) Build(opts types.ImageBuilderOpts) error { return nil } + +// Tag runs a `docker tag`command to retag the source tag with the destination tag. +func (b ImageBuilderTagger) Tag(src, dest string) error { + if b.dryRun { + logrus.Infof("[DRY-RUN] docker pull %s", src) + logrus.Infof("[DRY-RUN] docker tag %s %s", src, dest) + return nil + } + logrus.Debugf("Running `docker pull %s`", src) + if err := b.exec.ExecuteStdout("docker", "pull", src); err != nil { + return err + } + logrus.Debugf("Running `docker tag %s %s`", src, dest) + return b.exec.ExecuteStdout("docker", "tag", src, dest) +} diff --git a/mock/registry.go b/mock/registry.go index ca40cee4..36e7ff05 100644 --- a/mock/registry.go +++ b/mock/registry.go @@ -9,8 +9,3 @@ func (r *Registry) RefExists(_ string) (bool, error) { r.RefExistsCallCount++ return true, nil } - -func (r *Registry) Retag(_, _ string) error { - r.RetagCallCount++ - return nil -} diff --git a/registry/registry.go b/registry/registry.go index 0f110bc1..4bbc6176 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -26,11 +26,12 @@ func (r Registry) RefExists(imageRef string) (bool, error) { return r.gcr.RefExists(imageRef) } -// Retag creates a new tag from an existing one. -func (r Registry) Retag(existingRef, toCreateRef string) error { +// Tag creates a new tag from an existing one. +func (r Registry) Tag(existingRef, toCreateRef string) error { if r.dryRun { logrus.Infof("[DRY-RUN] Retagging image from \"%s\" to \"%s\"", existingRef, toCreateRef) return nil } + logrus.Debugf("Retaging image on gcr, source %s, dest %s`", existingRef, toCreateRef) return r.gcr.Retag(existingRef, toCreateRef) } diff --git a/types/types.go b/types/types.go index dd92e37d..0684498c 100644 --- a/types/types.go +++ b/types/types.go @@ -25,6 +25,11 @@ type ImageBuilderOpts struct { LocalOnly bool } +// ImageTagger is an abstraction for tagging docker images. +type ImageTagger interface { + Tag(from, to string) error +} + // TestRunner is an interface for dealing with docker tests, such as dgoss, trivy. type TestRunner interface { RunTest(ref, path string) error @@ -33,5 +38,4 @@ type TestRunner interface { // DockerRegistry is an interface for dealing with docker registries. type DockerRegistry interface { RefExists(imageRef string) (bool, error) - Retag(existingRef, toCreateRef string) error }