Skip to content

Commit

Permalink
add check for latest available version
Browse files Browse the repository at this point in the history
Signed-off-by: Sid Kattoju <[email protected]>
  • Loading branch information
skattoju committed Jan 17, 2024
1 parent 19d5b5e commit 465434a
Show file tree
Hide file tree
Showing 7 changed files with 250 additions and 28 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ image-push:
.PHONY: test
test:
go test -v $$(go list ./... | grep -v e2e) \
-ldflags "-X github.com/redhat-openshift-ecosystem/openshift-preflight/version.commit=bar -X github.com/redhat-openshift-ecosystem/openshift-preflight/version.version=foo"
-ldflags "-X github.com/redhat-openshift-ecosystem/openshift-preflight/version.commit=foobar -X github.com/redhat-openshift-ecosystem/openshift-preflight/version.version=0.0.1"

.PHONY: cover
cover:
go test -v \
-ldflags "-X github.com/redhat-openshift-ecosystem/openshift-preflight/version.commit=bar -X github.com/redhat-openshift-ecosystem/openshift-preflight/version.version=foo" \
-ldflags "-X github.com/redhat-openshift-ecosystem/openshift-preflight/version.commit=foobar -X github.com/redhat-openshift-ecosystem/openshift-preflight/version.version=0.0.1" \
$$(go list ./... | grep -v e2e) \
-race \
-cover -coverprofile=coverage.out
Expand Down
65 changes: 55 additions & 10 deletions cmd/preflight/cmd/check_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@ import (
"context"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
rt "runtime"
"strings"
"time"

"github.com/go-logr/logr"
"github.com/google/go-containerregistry/pkg/crane"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/google/go-github/v57/github"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/redhat-openshift-ecosystem/openshift-preflight/artifacts"
"github.com/redhat-openshift-ecosystem/openshift-preflight/certification"
Expand All @@ -23,13 +33,6 @@ import (
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/runtime"
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/viper"
"github.com/redhat-openshift-ecosystem/openshift-preflight/version"

"github.com/go-logr/logr"
"github.com/google/go-containerregistry/pkg/crane"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

var submit bool
Expand All @@ -45,7 +48,7 @@ func checkContainerCmd(runpreflight runPreflight) *cobra.Command {
Args: checkContainerPositionalArgs,
// this fmt.Sprintf is in place to keep spacing consistent with cobras two spaces that's used in: Usage, Flags, etc
Example: fmt.Sprintf(" %s", "preflight check container quay.io/repo-name/container-name:version"),
PreRunE: validateCertificationProjectID,
PreRunE: validateConditions,
RunE: func(cmd *cobra.Command, args []string) error {
return checkContainerRunE(cmd, args, runpreflight)
},
Expand Down Expand Up @@ -88,6 +91,9 @@ func checkContainerCmd(runpreflight runPreflight) *cobra.Command {
flags.String("platform", rt.GOARCH, "Architecture of image to pull. Defaults to runtime platform.")
_ = viper.BindPFlag("platform", flags.Lookup("platform"))

flags.String("gh-auth-token", "", "A Github auth token can be specified to work around rate limits")
_ = viper.BindPFlag("gh-auth-token", flags.Lookup("gh-auth-token"))

return checkContainerCmd
}

Expand Down Expand Up @@ -198,7 +204,7 @@ func checkContainerRunE(cmd *cobra.Command, args []string, runpreflight runPrefl

func checkContainerPositionalArgs(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("a container image positional argument is required")
return fmt.Errorf("a container image positional argument is required, found %v", args)
}

cmd.Flags().VisitAll(func(f *pflag.Flag) {
Expand Down Expand Up @@ -237,9 +243,16 @@ func checkContainerPositionalArgs(cmd *cobra.Command, args []string) error {
return nil
}

// validateConditions run all pre-run functions
func validateConditions(cmd *cobra.Command, args []string) error {
err := validateCertificationProjectID()
checkForNewerReleaseVersion(cmd)
return err
}

// validateCertificationProjectID validates that the certification project id is in the proper format
// and throws an error if the value provided is in a legacy format that is not usable to query pyxis
func validateCertificationProjectID(cmd *cobra.Command, args []string) error {
func validateCertificationProjectID() error {
viper := viper.Instance()
certificationProjectID := viper.GetString("certification_project_id")
// splitting the certification project id into parts. if there are more than 2 elements in the array,
Expand All @@ -257,6 +270,38 @@ func validateCertificationProjectID(cmd *cobra.Command, args []string) error {
return nil
}

// checkForNewerReleaseVersion checks if there is a newer release available
func checkForNewerReleaseVersion(cmd *cobra.Command) {
logger, err := logr.FromContext(cmd.Context())
if err != nil {
fmt.Println("Unable to get logger from context skipping check for newer release version", err)
return
}

// use an authenticated client if a token is provided
var client *github.Client
ghToken, err := cmd.Flags().GetString("gh-auth-token")
if err == nil && len(ghToken) > 0 {
client = github.NewClient(&http.Client{
// Timeout in 1s in case Github is slow to respond
Timeout: time.Second * 1,
}).WithAuthToken(ghToken)
} else {
client = github.NewClient(&http.Client{
// timeout in 1s in case Github is slow to respond
Timeout: time.Second * 1,
})
}
// check if a newer release is available
latestRelease, err := version.Version.LatestReleasedVersion(cmd, client.Repositories)
if err != nil {
logger.Error(err, "Unable to determine if running the latest release")
}
if latestRelease != nil {
logger.Info("Found newer release", "New version", *latestRelease.TagName, "available at", *latestRelease.HTMLURL)
}
}

// generateContainerCheckOptions returns appropriate container.Options based on cfg.
func generateContainerCheckOptions(cfg *runtime.Config) []container.Option {
o := []container.Option{
Expand Down
24 changes: 12 additions & 12 deletions cmd/preflight/cmd/check_container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,6 @@ import (
"path/filepath"
"runtime"

"github.com/redhat-openshift-ecosystem/openshift-preflight/artifacts"
"github.com/redhat-openshift-ecosystem/openshift-preflight/certification"
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/check"
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/cli"
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/formatters"
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/lib"
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/viper"

"github.com/go-logr/logr"
"github.com/google/go-containerregistry/pkg/crane"
"github.com/google/go-containerregistry/pkg/name"
Expand All @@ -33,6 +25,14 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/types"

"github.com/redhat-openshift-ecosystem/openshift-preflight/artifacts"
"github.com/redhat-openshift-ecosystem/openshift-preflight/certification"
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/check"
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/cli"
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/formatters"
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/lib"
"github.com/redhat-openshift-ecosystem/openshift-preflight/internal/viper"
)

func createPlatformImage(arch string, addlLayers int) cranev1.Image {
Expand Down Expand Up @@ -225,7 +225,7 @@ certification_project_id: mycertid`
DeferCleanup(viper.Instance().Set, "certification_project_id", "")
})
It("should not change the flag value", func() {
err := validateCertificationProjectID(checkContainerCmd(mockRunPreflightReturnNil), []string{"foo"})
err := validateCertificationProjectID()
Expect(err).ToNot(HaveOccurred())
Expect(viper.Instance().GetString("certification_project_id")).To(Equal("123456789"))
})
Expand All @@ -236,7 +236,7 @@ certification_project_id: mycertid`
DeferCleanup(viper.Instance().Set, "certification_project_id", "")
})
It("should strip ospid- from the flag value", func() {
err := validateCertificationProjectID(checkContainerCmd(mockRunPreflightReturnNil), []string{"foo"})
err := validateCertificationProjectID()
Expect(err).ToNot(HaveOccurred())
Expect(viper.Instance().GetString("certification_project_id")).To(Equal("123456789"))
})
Expand All @@ -247,7 +247,7 @@ certification_project_id: mycertid`
DeferCleanup(viper.Instance().Set, "certification_project_id", "")
})
It("should throw an error", func() {
err := validateCertificationProjectID(checkContainerCmd(mockRunPreflightReturnNil), []string{"foo"})
err := validateCertificationProjectID()
Expect(err).To(HaveOccurred())
})
})
Expand All @@ -257,7 +257,7 @@ certification_project_id: mycertid`
DeferCleanup(viper.Instance().Set, "certification_project_id", "")
})
It("should throw an error", func() {
err := validateCertificationProjectID(checkContainerCmd(mockRunPreflightReturnNil), []string{"foo"})
err := validateCertificationProjectID()
Expect(err).To(HaveOccurred())
})
})
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ require (
github.com/glebarez/go-sqlite v1.22.0
github.com/go-logr/logr v1.4.1
github.com/google/go-containerregistry v0.17.0
github.com/google/go-github/v57 v57.0.0
github.com/hashicorp/go-version v1.2.1
github.com/knqyf263/go-rpmdb v0.0.0-20230517124904-b97c85e63254
github.com/onsi/ginkgo/v2 v2.13.2
github.com/onsi/gomega v1.30.0
Expand Down Expand Up @@ -59,6 +61,7 @@ require (
github.com/google/cel-go v0.16.1 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 // indirect
github.com/google/uuid v1.5.0 // indirect
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,18 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.17.0 h1:5p+zYs/R4VGHkhyvgWurWrpJ2hW4Vv9fQI+GzdcwXLk=
github.com/google/go-containerregistry v0.17.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
github.com/google/go-github/v57 v57.0.0 h1:L+Y3UPTY8ALM8x+TV0lg+IEBI+upibemtBD8Q9u7zHs=
github.com/google/go-github/v57 v57.0.0/go.mod h1:s0omdnye0hvK/ecLvpsGfJMiRt85PimQh4oygmLIxHw=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand All @@ -206,6 +211,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
Expand Down
49 changes: 47 additions & 2 deletions version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,20 @@
// describing the preflight project.
package version

import "fmt"
import (
"context"
"fmt"
"strings"

"github.com/go-logr/logr"
"github.com/google/go-github/v57/github"
semvc "github.com/hashicorp/go-version"
"github.com/spf13/cobra"
)

var (
projectName = "github.com/redhat-openshift-ecosystem/openshift-preflight"
version = "unknown"
version = "0.0.1"
commit = "unknown"
)

Expand All @@ -16,6 +25,10 @@ var Version = VersionContext{
Commit: commit,
}

type VersionClient interface {
GetLatestRelease(ctx context.Context, owner string, repo string) (*github.RepositoryRelease, *github.Response, error)
}

type VersionContext struct {
Name string `json:"name"`
Version string `json:"version"`
Expand All @@ -25,3 +38,35 @@ type VersionContext struct {
func (vc *VersionContext) String() string {
return fmt.Sprintf("%s <commit: %s>", vc.Version, vc.Commit)
}

func (vc *VersionContext) LatestReleasedVersion(cmd *cobra.Command, svc VersionClient) (*github.RepositoryRelease, error) {
ctx := cmd.Context()
logger, err := logr.FromContext(ctx)
if err != nil {
fmt.Println("Unable to create logger from context", err)
return nil, err
}
projectTokens := strings.Split(vc.Name, "/")
owner := projectTokens[1]
repo := projectTokens[2]
// Fetch latest release from Github
latestRelease, resp, err := svc.GetLatestRelease(ctx, owner, repo)
if err != nil {
return nil, err
}
logger.Info("Github responded with", "rate limit", resp.Rate.String())
currentVersion, err := semvc.NewVersion(vc.Version)
if err != nil {
logger.Error(err, "Unable to determine current semver")
return nil, err
}
latestVersion, err := semvc.NewVersion(*latestRelease.TagName)
if err != nil {
logger.Error(err, "Unable to determine latest semver")
return nil, err
}
if !currentVersion.Equal(latestVersion) {
return latestRelease, nil
}
return nil, nil
}
Loading

0 comments on commit 465434a

Please sign in to comment.