Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Mikusa <dan@mikusa.com>
  • Loading branch information
dmikusa committed Nov 9, 2024
1 parent ab88dd7 commit b609918
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 13 deletions.
16 changes: 16 additions & 0 deletions carton/buildmodule_dependency.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (

"github.com/paketo-buildpacks/libpak/v2/log"
"github.com/paketo-buildpacks/libpak/v2/utils"

"github.com/paketo-buildpacks/libpak-tools/internal"
)

const (
Expand All @@ -47,6 +49,7 @@ type BuildModuleDependency struct {
PURLPattern string
Source string
SourceSHA256 string
EolID string
}

func (b BuildModuleDependency) Update(options ...Option) {
Expand All @@ -68,6 +71,7 @@ func (b BuildModuleDependency) Update(options ...Option) {
logger.Headerf("SHA256: %s", b.SHA256)
logger.Headerf("Source: %s", b.Source)
logger.Headerf("SourceSHA256: %s", b.SourceSHA256)
logger.Headerf("EOL ID: %s", b.EolID)

versionExp, err := regexp.Compile(b.VersionPattern)
if err != nil {
Expand Down Expand Up @@ -208,6 +212,18 @@ func (b BuildModuleDependency) Update(options ...Option) {
}
}
}

if b.EolID != "" {
eolDate, err := internal.GetEolDate(b.EolID, b.Version)
if err != nil {
config.exitHandler.Error(fmt.Errorf("unable to fetch deprecation_date"))
return
}

if eolDate != "" {
dep["deprecation_date"] = eolDate
}
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions commands/dependency_update_build_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func DependencyUpdateBuildModuleCommand() *cobra.Command {
dependencyUpdateBuildModuleCmd.Flags().StringVar(&b.CPEPattern, "cpe-pattern", "", "the cpe version pattern of the dependency, if not set defaults to version-pattern")
dependencyUpdateBuildModuleCmd.Flags().StringVar(&b.Source, "source", "", "the new uri of the dependency source")
dependencyUpdateBuildModuleCmd.Flags().StringVar(&b.SourceSHA256, "source-sha256", "", "the new sha256 of the dependency source")
dependencyUpdateBuildModuleCmd.Flags().StringVar(&b.EolID, "eol-id", "", "id of the dependency for looking up the EOL date on the https://endoflife.date/")

return dependencyUpdateBuildModuleCmd
}
11 changes: 6 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,28 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/text v0.20.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

require (
dario.cat/mergo v1.0.1 // indirect
github.com/BurntSushi/toml v1.4.0
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/Masterminds/semver/v3 v3.3.0
github.com/buildpacks/libcnb/v2 v2.0.0
github.com/creack/pty v1.1.24 // indirect
github.com/heroku/color v0.0.6
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jarcoal/httpmock v1.3.1
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
github.com/onsi/gomega v1.35.1
github.com/sclevine/spec v1.4.0
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/sys v0.27.0 // indirect
)
20 changes: 12 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ github.com/heroku/color v0.0.6 h1:UTFFMrmMLFcL3OweqP1lAdp8i1y/9oHqkeHjQ/b/Ny0=
github.com/heroku/color v0.0.6/go.mod h1:ZBvOcx7cTF2QKOv4LbmoBtNl5uB17qWxGuzZrsi1wLU=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
Expand All @@ -36,6 +38,8 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo=
Expand All @@ -46,8 +50,8 @@ github.com/paketo-buildpacks/libpak/v2 v2.0.0-alpha.3.0.20241030145014-4e3b6fe37
github.com/paketo-buildpacks/libpak/v2 v2.0.0-alpha.3.0.20241030145014-4e3b6fe37213/go.mod h1:TJnhn128zE4lKVV/UGtpgYoEk4wQyAApcNwB4toRPDM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
Expand All @@ -59,15 +63,15 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
Expand Down
110 changes: 110 additions & 0 deletions internal/eol.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package internal

import (
"encoding/json"
"fmt"
"net/http"
"time"

"github.com/Masterminds/semver/v3"
)

const eolBaseURL = "https://endoflife.date/api"

func GetEolDate(eolID, version string) (string, error) {
cycleList, err := getProjectCycleList(eolID)
if err != nil {
return "", fmt.Errorf("could not fetch cycle list: %w", err)
}

cycle, err := selectCycle(version, cycleList)
if err != nil {
return "", fmt.Errorf("could not find a release cycle: %w", err)
}

if cycle.EOL == "" {
return "", nil
}

eol, err := time.Parse(time.DateOnly, cycle.EOL)
if err != nil {
return "", fmt.Errorf("could not parse eol %q: %w", cycle.EOL, err)
}

return eol.Format(time.RFC3339), nil
}

func selectCycle(version string, cycles cycleList) (*cycle, error) {
versionParsed, err := semver.NewVersion(version)
if err != nil {
return nil, err
}

for _, v := range []string{fmt.Sprintf("%d.%d", versionParsed.Major(), versionParsed.Minor()), fmt.Sprintf("%d", versionParsed.Major())} {
for _, c := range cycles {
if c.Cycle == v {
return c, nil
}
}
}

return nil, fmt.Errorf("no release cycle found for the version %s", version)
}

func getProjectCycleList(id string) (cycleList, error) {
res, err := http.Get(fmt.Sprintf("%s/%s.json", eolBaseURL, id))
if err != nil {
return nil, err
}
defer res.Body.Close()

if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to fetch release cycles, status: %d", res.StatusCode)
}

cycles := cycleList{}
if err := json.NewDecoder(res.Body).Decode(&cycles); err != nil {
return nil, err
}

return cycles, nil
}

type cycleList []*cycle

type cycle struct {
Cycle string
EOL string
}

func (c *cycle) UnmarshalJSON(data []byte) error {
var i map[string]interface{}

if err := json.Unmarshal(data, &i); err != nil {
return err
}

if val, ok := i["cycle"]; ok {
switch t := val.(type) {
case string:
c.Cycle = t
case int, float64:
c.Cycle = fmt.Sprintf("%d", t)
default:
return fmt.Errorf("invalid type of the \"cycle\" field: %T", t)
}
}

if val, ok := i["eol"]; ok {
switch t := val.(type) {
case string:
c.EOL = t
case bool:
c.EOL = ""
default:
return fmt.Errorf("invalid type of the \"eol\" field: %T", t)
}
}

return nil
}
85 changes: 85 additions & 0 deletions internal/eol_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package internal_test

import (
"net/http"
"testing"

"github.com/buildpacks/libcnb/v2/mocks"
"github.com/jarcoal/httpmock"
. "github.com/onsi/gomega"
"github.com/sclevine/spec"
"github.com/stretchr/testify/mock"

"github.com/paketo-buildpacks/libpak-tools/internal"
)

func testGetEolDate(t *testing.T, context spec.G, it spec.S) {
var (
Expect = NewWithT(t).Expect

exitHandler *mocks.ExitHandler
)

it.Before(func() {
httpmock.Activate()
exitHandler = &mocks.ExitHandler{}
exitHandler.On("Error", mock.Anything)
})

it.After(func() {
httpmock.DeactivateAndReset()
})

context("finds release cycle by major.minor version", func() {
it.Before(func() {
httpmock.RegisterResponder(http.MethodGet, "https://endoflife.date/api/foo.json", httpmock.NewBytesResponder(200, []byte(`
[
{
"cycle": "10.1",
"releaseDate": "2022-09-23",
"eol": false,
"minJavaVersion": 11,
"latest": "10.1.24",
"latestReleaseDate": "2024-05-09",
"lts": false
},
{
"cycle": "10.0",
"releaseDate": "2020-12-03",
"eol": "2026-12-31",
"minJavaVersion": 8,
"latest": "10.0.27",
"latestReleaseDate": "2025-10-03",
"lts": false
},
{
"cycle": "9",
"releaseDate": "2017-09-27",
"eol": "2023-12-31",
"minJavaVersion": 8,
"latest": "9.0.89",
"latestReleaseDate": "2021-05-03",
"lts": false
}
]`)))
})

it("finds release cycle by major and minor version", func() {
eolDate, err := internal.GetEolDate("foo", "10.0.1")
Expect(err).NotTo(HaveOccurred())
Expect(eolDate).To(Equal("2026-12-31T00:00:00Z"))
})

it("finds release cycle by major version", func() {
eolDate, err := internal.GetEolDate("foo", "9.5.4")
Expect(err).NotTo(HaveOccurred())
Expect(eolDate).To(Equal("2023-12-31T00:00:00Z"))
})

it("returns empty eol date if eol is a bool", func() {
eolDate, err := internal.GetEolDate("foo", "10.1.0")
Expect(err).NotTo(HaveOccurred())
Expect(eolDate).To(Equal(""))
})
})
}
29 changes: 29 additions & 0 deletions internal/init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2018-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package internal_test

import (
"testing"

"github.com/sclevine/spec"
"github.com/sclevine/spec/report"
)

func TestUnit(t *testing.T) {
suite := spec.New("libpak-tools/internal", spec.Report(report.Terminal{}))
suite("EOL", testGetEolDate)
suite.Run(t)
}

0 comments on commit b609918

Please sign in to comment.