Skip to content

Commit

Permalink
Add support for pre-release apis and experimental features
Browse files Browse the repository at this point in the history
- Refactors cmd package to move platform logic to platform or platform/launch

Signed-off-by: Natalie Arellano <[email protected]>
  • Loading branch information
natalieparellano committed Jun 2, 2022
1 parent b5f8bad commit 8166edc
Show file tree
Hide file tree
Showing 84 changed files with 1,314 additions and 945 deletions.
4 changes: 2 additions & 2 deletions acceptance/acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/sclevine/spec"
"github.com/sclevine/spec/report"

"github.com/buildpacks/lifecycle/api"
"github.com/buildpacks/lifecycle/platform"
h "github.com/buildpacks/lifecycle/testhelpers"
)

Expand All @@ -22,7 +22,7 @@ const (
)

var (
latestPlatformAPI = api.Platform.Latest().String()
latestPlatformAPI = platform.APIs.Latest().String()
buildDir string
)

Expand Down
2 changes: 1 addition & 1 deletion acceptance/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestAnalyzer(t *testing.T) {
analyzeDaemonFixtures = analyzeTest.targetDaemon.fixtures
analyzeRegFixtures = analyzeTest.targetRegistry.fixtures

for _, platformAPI := range api.Platform.Supported {
for _, platformAPI := range platform.APIs.Supported {
spec.Run(t, "acceptance-analyzer/"+platformAPI.String(), testAnalyzerFunc(platformAPI.String()), spec.Parallel(), spec.Report(report.Terminal{}))
}
}
Expand Down
3 changes: 1 addition & 2 deletions acceptance/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/sclevine/spec"
"github.com/sclevine/spec/report"

"github.com/buildpacks/lifecycle/api"
"github.com/buildpacks/lifecycle/platform"
h "github.com/buildpacks/lifecycle/testhelpers"
)
Expand Down Expand Up @@ -50,7 +49,7 @@ func TestBuilder(t *testing.T) {
h.DockerBuild(t,
builderImage,
builderDockerContext,
h.WithArgs("--build-arg", fmt.Sprintf("cnb_platform_api=%s", api.Platform.Latest())),
h.WithArgs("--build-arg", fmt.Sprintf("cnb_platform_api=%s", platform.APIs.Latest())),
h.WithFlags(
"-f", filepath.Join(builderDockerContext, dockerfileName),
),
Expand Down
3 changes: 2 additions & 1 deletion acceptance/creator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/sclevine/spec/report"

"github.com/buildpacks/lifecycle/api"
"github.com/buildpacks/lifecycle/platform"
h "github.com/buildpacks/lifecycle/testhelpers"
)

Expand Down Expand Up @@ -48,7 +49,7 @@ func TestCreator(t *testing.T) {
createDaemonFixtures = createTest.targetDaemon.fixtures
createRegFixtures = createTest.targetRegistry.fixtures

for _, platformAPI := range api.Platform.Supported {
for _, platformAPI := range platform.APIs.Supported {
spec.Run(t, "acceptance-creator/"+platformAPI.String(), testCreatorFunc(platformAPI.String()), spec.Parallel(), spec.Report(report.Terminal{}))
}
}
Expand Down
3 changes: 1 addition & 2 deletions acceptance/detector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/sclevine/spec"
"github.com/sclevine/spec/report"

"github.com/buildpacks/lifecycle/api"
"github.com/buildpacks/lifecycle/buildpack"
"github.com/buildpacks/lifecycle/platform"
h "github.com/buildpacks/lifecycle/testhelpers"
Expand All @@ -41,7 +40,7 @@ func TestDetector(t *testing.T) {
h.DockerBuild(t,
detectImage,
detectDockerContext,
h.WithArgs("--build-arg", fmt.Sprintf("cnb_platform_api=%s", api.Platform.Latest())),
h.WithArgs("--build-arg", fmt.Sprintf("cnb_platform_api=%s", platform.APIs.Latest())),
)
defer h.DockerImageRemove(t, detectImage)

Expand Down
2 changes: 1 addition & 1 deletion acceptance/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func TestExporter(t *testing.T) {

rand.Seed(time.Now().UTC().UnixNano())

for _, platformAPI := range api.Platform.Supported {
for _, platformAPI := range platform.APIs.Supported {
spec.Run(t, "acceptance-exporter/"+platformAPI.String(), testExporterFunc(platformAPI.String()), spec.Parallel(), spec.Report(report.Terminal{}))
}
}
Expand Down
3 changes: 2 additions & 1 deletion acceptance/restorer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/sclevine/spec/report"

"github.com/buildpacks/lifecycle/api"
"github.com/buildpacks/lifecycle/platform"
h "github.com/buildpacks/lifecycle/testhelpers"
)

Expand All @@ -36,7 +37,7 @@ func TestRestorer(t *testing.T) {
h.DockerBuild(t, restorerImage, restoreDockerContext)
defer h.DockerImageRemove(t, restorerImage)

for _, platformAPI := range api.Platform.Supported {
for _, platformAPI := range platform.APIs.Supported {
spec.Run(t, "acceptance-restorer/"+platformAPI.String(), testRestorerFunc(platformAPI.String()), spec.Parallel(), spec.Report(report.Terminal{}))
}
}
Expand Down
7 changes: 4 additions & 3 deletions analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/buildpacks/lifecycle/cache"
"github.com/buildpacks/lifecycle/image"
"github.com/buildpacks/lifecycle/internal/layer"
"github.com/buildpacks/lifecycle/log"
"github.com/buildpacks/lifecycle/platform"
)

Expand Down Expand Up @@ -37,7 +38,7 @@ func NewAnalyzerFactory(platformAPI *api.Version, cacheHandler CacheHandler, con
type Analyzer struct {
PreviousImage imgutil.Image
RunImage imgutil.Image
Logger Logger
Logger log.Logger
SBOMRestorer layer.SBOMRestorer

// Platform API < 0.7
Expand All @@ -59,7 +60,7 @@ func (f *AnalyzerFactory) NewAnalyzer(
previousImageRef string,
runImageRef string,
skipLayers bool,
logger Logger,
logger log.Logger,
) (*Analyzer, error) {
analyzer := &Analyzer{
LayerMetadataRestorer: &layer.NopMetadataRestorer{},
Expand Down Expand Up @@ -246,7 +247,7 @@ func bomSHA(appMeta platform.LayersMetadata) string {
return appMeta.BOM.SHA
}

func retrieveCacheMetadata(fromCache Cache, logger Logger) (platform.CacheMetadata, error) {
func retrieveCacheMetadata(fromCache Cache, logger log.Logger) (platform.CacheMetadata, error) {
// Create empty cache metadata in case a usable cache is not provided.
var cacheMeta platform.CacheMetadata
if fromCache != nil {
Expand Down
12 changes: 6 additions & 6 deletions analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
)

func TestAnalyzer(t *testing.T) {
for _, api := range api.Platform.Supported {
for _, api := range platform.APIs.Supported {
spec.Run(t, "unit-analyzer/"+api.String(), testAnalyzer(api.String()), spec.Parallel(), spec.Report(report.Terminal{}))
}
spec.Run(t, "unit-new-analyzer", testAnalyzerFactory, spec.Parallel(), spec.Report(report.Terminal{}))
Expand Down Expand Up @@ -67,7 +67,7 @@ func testAnalyzerFactory(t *testing.T, when spec.G, it spec.S) {
when("platform api >= 0.8", func() {
it.Before(func() {
analyzerFactory = lifecycle.NewAnalyzerFactory(
api.Platform.Latest(),
platform.APIs.Latest(),
fakeCacheHandler,
fakeConfigHandler,
fakeImageHandler,
Expand Down Expand Up @@ -376,9 +376,9 @@ func testAnalyzer(platformAPI string) func(t *testing.T, when spec.G, it spec.S)
Logger: &discardLogger,
SBOMRestorer: sbomRestorer,
Buildpacks: []buildpack.GroupBuildpack{
{ID: "metadata.buildpack", API: api.Buildpack.Latest().String()},
{ID: "no.cache.buildpack", API: api.Buildpack.Latest().String()},
{ID: "no.metadata.buildpack", API: api.Buildpack.Latest().String()},
{ID: "metadata.buildpack", API: buildpack.APIs.Latest().String()},
{ID: "no.cache.buildpack", API: buildpack.APIs.Latest().String()},
{ID: "no.metadata.buildpack", API: buildpack.APIs.Latest().String()},
},
Cache: testCache,
LayerMetadataRestorer: metadataRestorer,
Expand Down Expand Up @@ -444,7 +444,7 @@ func testAnalyzer(platformAPI string) func(t *testing.T, when spec.G, it spec.S)
h.AssertNil(t, testCache.SetMetadata(expectedCacheMetadata))
h.AssertNil(t, testCache.Commit())

analyzer.Buildpacks = append(analyzer.Buildpacks, buildpack.GroupBuildpack{ID: "escaped/buildpack/id", API: api.Buildpack.Latest().String()})
analyzer.Buildpacks = append(analyzer.Buildpacks, buildpack.GroupBuildpack{ID: "escaped/buildpack/id", API: buildpack.APIs.Latest().String()})
expectRestoresLayerMetadataIfSupported()
})

Expand Down
14 changes: 7 additions & 7 deletions api/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ import (
"github.com/pkg/errors"
)

var (
Platform = newApisMustParse([]string{"0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9"}, nil)
Buildpack = newApisMustParse([]string{"0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8"}, nil)
)

type APIs struct {
Supported List
Deprecated List
Expand All @@ -27,8 +22,8 @@ func (l List) String() string {
return "[" + strings.Join(els, ", ") + "]"
}

// newApisMustParse calls NewApis and panics on error
func newApisMustParse(supported []string, deprecated []string) APIs {
// NewAPIsMustParse calls NewApis and panics on error
func NewAPIsMustParse(supported []string, deprecated []string) APIs {
apis, err := NewAPIs(supported, deprecated)
if err != nil {
panic(err)
Expand Down Expand Up @@ -88,6 +83,11 @@ func (a APIs) IsDeprecated(target *Version) bool {
return false
}

// IsExperimental returns true or false depending on whether the target API is experimental
func (a APIs) IsExperimental(target *Version) bool {
return target.Prerelease != ""
}

// Latest returns the latest API that is supported
func (a APIs) Latest() *Version {
latest := a.Supported[0]
Expand Down
45 changes: 33 additions & 12 deletions api/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import (
"github.com/pkg/errors"
)

var regex = regexp.MustCompile(`^v?(\d+)\.?(\d*)$`)
var regex = regexp.MustCompile(`^v?(\d+)\.?(\d*)(-[a-zA-Z0-9-]+)?$`)

type Version struct {
Major,
Minor uint64
Major uint64
Minor uint64
Prerelease string
}

func MustParse(v string) *Version {
Expand All @@ -32,9 +33,10 @@ func NewVersion(v string) (*Version, error) {

var (
major, minor uint64
prerelease string
err error
)
if len(matches[0]) == 3 {
if len(matches[0]) == 4 {
major, err = strconv.ParseUint(matches[0][1], 10, 64)
if err != nil {
return nil, errors.Wrapf(err, "parsing Major '%s'", matches[0][1])
Expand All @@ -48,14 +50,19 @@ func NewVersion(v string) (*Version, error) {
return nil, errors.Wrapf(err, "parsing Minor '%s'", matches[0][2])
}
}

prerelease = matches[0][3]
} else {
return nil, errors.Errorf("could not parse version '%s'", v)
}

return &Version{Major: major, Minor: minor}, nil
return &Version{Major: major, Minor: minor, Prerelease: prerelease}, nil
}

func (v *Version) String() string {
if v.Prerelease != "" {
return fmt.Sprintf("%d.%d-%s", v.Major, v.Minor, v.Prerelease)
}
return fmt.Sprintf("%d.%d", v.Major, v.Minor)
}

Expand Down Expand Up @@ -89,21 +96,35 @@ func (v *Version) Equal(o *Version) bool {
// 1 is greater than *Version o
func (v *Version) Compare(o *Version) int {
if v.Major != o.Major {
if v.Major < o.Major {
switch {
case v.Major < o.Major:
return -1
}

if v.Major > o.Major {
default:
// v.Major > o.Major
return 1
}
}

if v.Minor != o.Minor {
if v.Minor < o.Minor {
switch {
case v.Minor < o.Minor:
return -1
default:
// v.Minor > o.Minor
return 1
}
}

if v.Minor > o.Minor {
if v.Prerelease != o.Prerelease {
switch {
case o.Prerelease == "":
return -1
case v.Prerelease == "":
return 1
case v.Prerelease < o.Prerelease:
return -1
default:
// v.Prerelease > o.Prerelease
return 1
}
}
Expand All @@ -113,7 +134,7 @@ func (v *Version) Compare(o *Version) int {

func (v *Version) IsSupersetOf(o *Version) bool {
if v.Major == 0 {
return v.Equal(o)
return v.Major == o.Major && v.Minor == o.Minor
}
return v.Major == o.Major && v.Minor >= o.Minor
}
Expand Down
34 changes: 28 additions & 6 deletions api/version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ func testAPIVersion(t *testing.T, when spec.G, it spec.S) {
it("is equal to comparison", func() {
subject := api.MustParse("0.2")
comparison := api.MustParse("0.2")
h.AssertEq(t, subject.Equal(comparison), true)

subject = api.MustParse("0.2-alpha-1")
comparison = api.MustParse("0.2-alpha-1")
h.AssertEq(t, subject.Equal(comparison), true)
})

it("is not equal to comparison", func() {
subject := api.MustParse("0.2")
comparison := api.MustParse("0.3")
h.AssertEq(t, subject.Equal(comparison), false)

subject = api.MustParse("0.2-alpha-1")
comparison = api.MustParse("0.2")
h.AssertEq(t, subject.Equal(comparison), false)
})
})
Expand All @@ -53,6 +59,13 @@ func testAPIVersion(t *testing.T, when spec.G, it spec.S) {

h.AssertEq(t, v.IsSupersetOf(target), false)
})

it("Prerelease", func() {
v := api.MustParse("0.2")
target := api.MustParse("0.2-alpha-2")

h.AssertEq(t, v.IsSupersetOf(target), true)
})
})

when("1.x", func() {
Expand Down Expand Up @@ -90,15 +103,23 @@ func testAPIVersion(t *testing.T, when spec.G, it spec.S) {

h.AssertEq(t, v.IsSupersetOf(target), false)
})

it("Prerelease", func() {
v := api.MustParse("2.0")
target := api.MustParse("2.0-alpha-2")

h.AssertEq(t, v.IsSupersetOf(target), true)
})
})
})

when("#LessThan", func() {
var subject = api.MustParse("0.3")
var toTest = map[string]bool{
"0.2": false,
"0.3": false,
"0.4": true,
"0.2": false,
"0.3": false,
"0.4": true,
"0.3-alpha-1": false,
}
it("returns the expected value", func() {
for comparison, expected := range toTest {
Expand All @@ -110,9 +131,10 @@ func testAPIVersion(t *testing.T, when spec.G, it spec.S) {
when("#AtLeast", func() {
var subject = api.MustParse("0.3")
var toTest = map[string]bool{
"0.2": true,
"0.3": true,
"0.4": false,
"0.2": true,
"0.3": true,
"0.4": false,
"0.3-alpha-1": true,
}
it("returns the expected value", func() {
for comparison, expected := range toTest {
Expand Down
Loading

0 comments on commit 8166edc

Please sign in to comment.