Skip to content

Commit

Permalink
Parse lifecycle version as semver
Browse files Browse the repository at this point in the history
* this allows for versions in either x.x.x or vx.x.x format
* allows for version comparisons

Signed-off-by: Danny Joyce <[email protected]>
Signed-off-by: Emily Casey <[email protected]>
  • Loading branch information
Danny Joyce authored and ekcasey committed May 14, 2019
1 parent eea7a39 commit 32b3c05
Show file tree
Hide file tree
Showing 27 changed files with 1,467 additions and 35 deletions.
1 change: 1 addition & 0 deletions acceptance/acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,7 @@ func isCommandRunning(cmd *exec.Cmd) bool {
return true
}

// FIXME : buf needs a mutex
func terminateAtStep(t *testing.T, cmd *exec.Cmd, buf *bytes.Buffer, pattern string) {
t.Helper()
var interruptSignal os.Signal
Expand Down
2 changes: 2 additions & 0 deletions acceptance/testdata/mock_buildpacks/builder.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@
build-image = "pack-test/build"
run-image = "pack-test/run"

[lifecycle]
version = "v0.1.0"
# run-image-mirror and lifecycle are appended by accpetance tests
10 changes: 7 additions & 3 deletions build/lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"sync"
"time"

"github.com/Masterminds/semver"
"github.com/docker/docker/client"
"github.com/google/go-containerregistry/pkg/name"
"github.com/pkg/errors"
Expand Down Expand Up @@ -75,10 +76,10 @@ func (l *Lifecycle) Execute(ctx context.Context, opts LifecycleOptions) error {
l.logger.Verbose("Build cache %s cleared", style.Symbol(buildCache.Name()))
}

if lifecycleVersion := l.builder.GetLifecycleVersion(); lifecycleVersion == "" {
if lifecycleVersion := l.builder.GetLifecycleVersion(); lifecycleVersion == nil {
l.logger.Verbose("Warning: lifecycle version unknown")
} else {
l.logger.Verbose("Executing lifecycle version %s", style.Symbol(lifecycleVersion))
l.logger.Verbose("Executing lifecycle version %s", style.Symbol(lifecycleVersion.String()))
}

l.logger.Verbose(style.Step("DETECTING"))
Expand Down Expand Up @@ -154,5 +155,8 @@ func randString(n int) string {
}

func (l *Lifecycle) supportsVolumeCache() bool {
return l.builder.GetLifecycleVersion() >= "0.2.0"
if l.builder.GetLifecycleVersion() == nil {
return false
}
return l.builder.GetLifecycleVersion().Compare(semver.MustParse("0.2.0")) >= 0
}
3 changes: 2 additions & 1 deletion builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

"github.com/BurntSushi/toml"
"github.com/Masterminds/semver"
"github.com/buildpack/imgutil"
"github.com/pkg/errors"

Expand Down Expand Up @@ -82,7 +83,7 @@ func (b *Builder) Description() string {
return b.metadata.Description
}

func (b *Builder) GetLifecycleVersion() string {
func (b *Builder) GetLifecycleVersion() *semver.Version {
return b.metadata.Lifecycle.Version
}

Expand Down
20 changes: 17 additions & 3 deletions builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path/filepath"
"testing"

"github.com/Masterminds/semver"
"github.com/buildpack/imgutil/fakes"
"github.com/fatih/color"
"github.com/sclevine/spec"
Expand Down Expand Up @@ -193,15 +194,15 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) {
when("#SetLifecycle", func() {
it.Before(func() {
h.AssertNil(t, subject.SetLifecycle(lifecycle.Metadata{
Version: "1.2.3",
Version: semver.MustParse("1.2.3"),
Dir: filepath.Join("testdata", "lifecycle"),
}))
h.AssertNil(t, subject.Save())
h.AssertEq(t, baseImage.IsSaved(), true)
})

it("should set the lifecycle version successfully", func() {
h.AssertEq(t, subject.GetLifecycleVersion(), "1.2.3")
h.AssertEq(t, subject.GetLifecycleVersion().String(), "1.2.3")
})

it("should add the lifecycle binaries as an image layer", func() {
Expand Down Expand Up @@ -244,6 +245,15 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) {
h.HasFileMode(0755),
)
})

it("sets the lifecycle version on the metadata", func() {
label, err := baseImage.Label("io.buildpacks.builder.metadata")
h.AssertNil(t, err)

var metadata builder.Metadata
h.AssertNil(t, json.Unmarshal([]byte(label), &metadata))
h.AssertEq(t, metadata.Lifecycle.Version.String(), "1.2.3")
})
})

when("#AddBuildpack", func() {
Expand Down Expand Up @@ -348,7 +358,10 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) {

when("base image already has metadata", func() {
it.Before(func() {
h.AssertNil(t, baseImage.SetLabel("io.buildpacks.builder.metadata", `{"buildpacks": [{"id": "prev.id"}], "groups": [{"buildpacks": [{"id": "prev.id"}]}], "stack": {"runImage": {"image": "prev/run", "mirrors": ["prev/mirror"]}}}`))
h.AssertNil(t, baseImage.SetLabel(
"io.buildpacks.builder.metadata",
`{"buildpacks": [{"id": "prev.id"}], "groups": [{"buildpacks": [{"id": "prev.id"}]}], "stack": {"runImage": {"image": "prev/run", "mirrors": ["prev/mirror"]}}, "lifecycle": {"version": "6.6.6"}}`,
))

var err error
subject, err = builder.New(baseImage, "some/builder")
Expand Down Expand Up @@ -377,6 +390,7 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) {
h.AssertEq(t, metadata.Groups[0].Buildpacks[0].ID, "prev.id")
h.AssertEq(t, metadata.Stack.RunImage.Image, "prev/run")
h.AssertEq(t, metadata.Stack.RunImage.Mirrors[0], "prev/mirror")
h.AssertEq(t, subject.GetLifecycleVersion().String(), "6.6.6")

// adds new buildpack
h.AssertEq(t, metadata.Buildpacks[1].ID, "some-buildpack-id")
Expand Down
19 changes: 18 additions & 1 deletion create_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"

"github.com/Masterminds/semver"
"github.com/buildpack/imgutil"
"github.com/pkg/errors"

Expand All @@ -24,6 +25,11 @@ func (c *Client) CreateBuilder(ctx context.Context, opts CreateBuilderOptions) e
return errors.Wrap(err, "invalid builder config")
}

lifecycleVersion, err := processLifecycleVersion(opts.BuilderConfig.Lifecycle.Version)
if err != nil {
return errors.Wrap(err, "invalid builder config")
}

if err := c.validateRunImageConfig(ctx, opts); err != nil {
return err
}
Expand Down Expand Up @@ -70,7 +76,7 @@ func (c *Client) CreateBuilder(ctx context.Context, opts CreateBuilderOptions) e

builderImage.SetStackInfo(opts.BuilderConfig.Stack)

lifecycleMd, err := c.lifecycleFetcher.Fetch(opts.BuilderConfig.Lifecycle.Version, opts.BuilderConfig.Lifecycle.URI)
lifecycleMd, err := c.lifecycleFetcher.Fetch(lifecycleVersion, opts.BuilderConfig.Lifecycle.URI)
if err != nil {
return errors.Wrap(err, "fetching lifecycle")
}
Expand All @@ -82,6 +88,17 @@ func (c *Client) CreateBuilder(ctx context.Context, opts CreateBuilderOptions) e
return builderImage.Save()
}

func processLifecycleVersion(version string) (*semver.Version, error) {
if version == "" {
return nil, nil
}
v, err := semver.NewVersion(version)
if err != nil {
return nil, errors.Wrap(err, "lifecycle.version must be a valid semver")
}
return v, nil
}

func validateBuilderConfig(conf builder.Config) error {
if conf.Stack.ID == "" {
return errors.New("stack.id is required")
Expand Down
15 changes: 13 additions & 2 deletions create_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"runtime"
"testing"

"github.com/Masterminds/semver"
"github.com/buildpack/imgutil/fakes"
"github.com/fatih/color"
"github.com/golang/mock/gomock"
Expand Down Expand Up @@ -82,7 +83,11 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) {

mockBPFetcher.EXPECT().FetchBuildpack(gomock.Any()).Return(bp, nil).AnyTimes()

mockLifecycleFetcher.EXPECT().Fetch(gomock.Any(), gomock.Any()).Return(lifecycle.Metadata{Dir: filepath.Join("testdata", "lifecycle"), Version: "3.4.5"}, nil).AnyTimes()
mockLifecycleFetcher.EXPECT().Fetch(gomock.Any(), gomock.Any()).
Return(lifecycle.Metadata{
Dir: filepath.Join("testdata", "lifecycle"),
Version: semver.MustParse("3.4.5"),
}, nil).AnyTimes()

logOut, logErr = &bytes.Buffer{}, &bytes.Buffer{}

Expand Down Expand Up @@ -150,6 +155,12 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) {
err := subject.CreateBuilder(context.TODO(), opts)
h.AssertError(t, err, "stack.run-image is required")
})

it("should fail when lifecycle version is not a semver", func() {
opts.BuilderConfig.Lifecycle.Version = "not-semver"
err := subject.CreateBuilder(context.TODO(), opts)
h.AssertError(t, err, "lifecycle.version must be a valid semver")
})
})

when("validating the run image config", func() {
Expand Down Expand Up @@ -201,7 +212,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) {
Optional: false,
}},
}})
h.AssertEq(t, builderImage.GetLifecycleVersion(), "3.4.5")
h.AssertEq(t, builderImage.GetLifecycleVersion().String(), "3.4.5")

layerTar, err := fakeBuildImage.FindLayerWithPath("/lifecycle")
h.AssertNil(t, err)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module github.com/buildpack/pack

require (
github.com/BurntSushi/toml v0.3.1
github.com/Masterminds/semver v1.4.2
github.com/buildpack/imgutil v0.0.0-20190509214933-76de939dfb34
github.com/buildpack/lifecycle v0.1.1-0.20190510142604-8612386b1cea
github.com/dgodd/dockerdial v1.0.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7O
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc=
Expand Down
7 changes: 6 additions & 1 deletion inspect_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ func (c *Client) InspectBuilder(name string, daemon bool) (*BuilderInfo, error)
localMirrors = runImageConfig.Mirrors
}

var lifecycleVersion string
if ver := bldr.GetLifecycleVersion(); ver != nil {
lifecycleVersion = ver.String()
}

return &BuilderInfo{
Description: bldr.Description(),
Stack: bldr.StackID,
Expand All @@ -56,6 +61,6 @@ func (c *Client) InspectBuilder(name string, daemon bool) (*BuilderInfo, error)
LocalRunImageMirrors: localMirrors,
Buildpacks: bldr.GetBuildpacks(),
Groups: bldr.GetOrder(),
LifecycleVersion: bldr.GetLifecycleVersion(),
LifecycleVersion: lifecycleVersion,
}, nil
}
4 changes: 2 additions & 2 deletions inspect_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func testInspectBuilder(t *testing.T, when spec.G, it spec.S) {
]
}
],
"lifecycle": {"version": "some-lifecycle-version"}
"lifecycle": {"version": "1.2.3"}
}`))
})

Expand Down Expand Up @@ -159,7 +159,7 @@ func testInspectBuilder(t *testing.T, when spec.G, it spec.S) {
it("sets the lifecycle version", func() {
builderInfo, err := client.InspectBuilder("some/builder", useDaemon)
h.AssertNil(t, err)
h.AssertEq(t, builderInfo.LifecycleVersion, "some-lifecycle-version")
h.AssertEq(t, builderInfo.LifecycleVersion, "1.2.3")
})
})
})
Expand Down
3 changes: 2 additions & 1 deletion interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package pack
import (
"context"

"github.com/Masterminds/semver"
"github.com/buildpack/imgutil"

"github.com/buildpack/pack/buildpack"
Expand All @@ -24,5 +25,5 @@ type BuildpackFetcher interface {
//go:generate mockgen -package mocks -destination mocks/lifecycle_fetcher.go github.com/buildpack/pack LifecycleFetcher

type LifecycleFetcher interface {
Fetch(version, uri string) (lifecycle.Metadata, error)
Fetch(version *semver.Version, uri string) (lifecycle.Metadata, error)
}
11 changes: 6 additions & 5 deletions lifecycle/fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import (
"io/ioutil"
"path/filepath"

"github.com/Masterminds/semver"
"github.com/pkg/errors"

"github.com/buildpack/pack/style"
)

const (
DefaultLifecycleVersion = "0.1.0"
DefaultLifecycleVersion = "0.2.0"
)

//go:generate mockgen -package mocks -destination mocks/downloader.go github.com/buildpack/pack/lifecycle Downloader
Expand All @@ -28,13 +29,13 @@ func NewFetcher(downloader Downloader) *Fetcher {
return &Fetcher{downloader: downloader}
}

func (f *Fetcher) Fetch(version, uri string) (Metadata, error) {
if version == "" && uri == "" {
version = DefaultLifecycleVersion
func (f *Fetcher) Fetch(version *semver.Version, uri string) (Metadata, error) {
if version == nil && uri == "" {
version = semver.MustParse(DefaultLifecycleVersion)
}

if uri == "" {
uri = fmt.Sprintf("https://github.com/buildpack/lifecycle/releases/download/v%s/lifecycle-v%s+linux.x86-64.tgz", version, version)
uri = fmt.Sprintf("https://github.com/buildpack/lifecycle/releases/download/v%s/lifecycle-v%s+linux.x86-64.tgz", version.String(), version.String())
}

downloadDir, err := f.downloader.Download(uri)
Expand Down
Loading

0 comments on commit 32b3c05

Please sign in to comment.