Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .mockery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,11 @@ packages:
config:
all: true
interfaces:
github.com/codesphere-cloud/oms/internal/version:
config:
all: true
interfaces:
github.com/codesphere-cloud/oms/cli/cmd:
config:
all: true
interfaces:
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ endif
generate: install-build-deps
mockery
go generate ./...

VERSION ?= "0.0.0"
release-local:
rm -rf dist
/bin/bash -c "goreleaser --skip=validate,announce,publish -f <(sed s/{{.Version}}/$(VERSION)/g < .goreleaser.yaml)"
36 changes: 15 additions & 21 deletions cli/cmd/download_package.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,27 +61,21 @@ func AddDownloadPackageCmd(download *cobra.Command, opts GlobalOptions) {
pkg.cmd.RunE = pkg.RunE
}

func (c *DownloadPackageCmd) DownloadBuild(p portal.Portal, build portal.CodesphereBuild, filename string) error {
for _, art := range build.Artifacts {
if art.Filename == filename {
fullFilename := build.Version + "-" + art.Filename
out, err := c.FileWriter.Create(fullFilename)
if err != nil {
return fmt.Errorf("failed to create file %s: %w", fullFilename, err)
}
defer func() { _ = out.Close() }()

buildWithArtifact := build
buildWithArtifact.Artifacts = []portal.Artifact{art}

err = p.DownloadBuildArtifact(buildWithArtifact, out)
if err != nil {
return fmt.Errorf("failed to download build: %w", err)
}
return nil
}

func (c *DownloadPackageCmd) DownloadBuild(p portal.Portal, build portal.Build, filename string) error {
download, err := build.GetBuildForDownload(filename)
if err != nil {
return fmt.Errorf("failed to find artifact in package: %w", err)
}
fullFilename := build.Version + "-" + filename
out, err := c.FileWriter.Create(fullFilename)
if err != nil {
return fmt.Errorf("failed to create file %s: %w", fullFilename, err)
}
defer func() { _ = out.Close() }()

return fmt.Errorf("can't find artifact %s in version %s", filename, build.Version)
err = p.DownloadBuildArtifact("codesphere", download, out)
if err != nil {
return fmt.Errorf("failed to download build: %w", err)
}
return nil
}
10 changes: 5 additions & 5 deletions cli/cmd/download_package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var _ = Describe("ListPackages", func() {
c cmd.DownloadPackageCmd
filename string
version string
build portal.CodesphereBuild
build portal.Build
mockPortal *portal.MockPortal
mockFileWriter *util.MockFileWriter
)
Expand All @@ -36,7 +36,7 @@ var _ = Describe("ListPackages", func() {
},
FileWriter: mockFileWriter,
}
build = portal.CodesphereBuild{
build = portal.Build{
Version: version,
Artifacts: []portal.Artifact{
{Filename: filename},
Expand All @@ -51,7 +51,7 @@ var _ = Describe("ListPackages", func() {

Context("File exists", func() {
It("Downloads the correct artifact to the correct output file", func() {
expectedBuildToDownload := portal.CodesphereBuild{
expectedBuildToDownload := portal.Build{
Version: version,
Artifacts: []portal.Artifact{
{Filename: filename},
Expand All @@ -60,7 +60,7 @@ var _ = Describe("ListPackages", func() {

fakeFile := os.NewFile(uintptr(0), filename)
mockFileWriter.EXPECT().Create(version+"-"+filename).Return(fakeFile, nil)
mockPortal.EXPECT().DownloadBuildArtifact(expectedBuildToDownload, mock.Anything).Return(nil)
mockPortal.EXPECT().DownloadBuildArtifact(portal.CodesphereProduct, expectedBuildToDownload, mock.Anything).Return(nil)
err := c.DownloadBuild(mockPortal, build, filename)
Expect(err).NotTo(HaveOccurred())
})
Expand All @@ -69,7 +69,7 @@ var _ = Describe("ListPackages", func() {
Context("File doesn't exist in build", func() {
It("Returns an error", func() {
err := c.DownloadBuild(mockPortal, build, "installer-lite.tar.gz")
Expect(err).To(MatchError("can't find artifact installer-lite.tar.gz in version " + version))
Expect(err).To(MatchError("failed to find artifact in package: artifact not found: installer-lite.tar.gz"))
})
})
})
4 changes: 2 additions & 2 deletions cli/cmd/list_packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type ListBuildsOpts struct {

func (c *ListBuildsCmd) RunE(_ *cobra.Command, args []string) error {
p := portal.NewPortalClient()
packages, err := p.ListCodesphereBuilds()
packages, err := p.ListBuilds(portal.CodesphereProduct)
if err != nil {
return fmt.Errorf("failed to list codesphere packages: %w", err)
}
Expand All @@ -51,7 +51,7 @@ func AddListPackagesCmd(list *cobra.Command, opts GlobalOptions) {
list.AddCommand(builds.cmd)
}

func (c *ListBuildsCmd) PrintPackagesTable(packages portal.CodesphereBuilds) {
func (c *ListBuildsCmd) PrintPackagesTable(packages portal.Builds) {
c.TableWriter.AppendHeader(table.Row{"Int", "Version", "Build Date", "Hash", "Artifacts"})

for _, build := range packages.Builds {
Expand Down
8 changes: 4 additions & 4 deletions cli/cmd/list_packages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ var _ = Describe("ListPackages", func() {
table.Row{"", "1.42", buildDate, "externalBuild", "installer.tar, installer2.tar"},
)
c.PrintPackagesTable(
portal.CodesphereBuilds{
Builds: []portal.CodesphereBuild{
portal.Builds{
Builds: []portal.Build{
{
Hash: "externalBuild",
Version: "1.42",
Expand Down Expand Up @@ -76,8 +76,8 @@ var _ = Describe("ListPackages", func() {
table.Row{"*", "master", buildDate, "internalBuild", "installer.tar, installer2.tar"},
)
c.PrintPackagesTable(
portal.CodesphereBuilds{
Builds: []portal.CodesphereBuild{
portal.Builds{
Builds: []portal.Build{
{
Hash: "externalBuild",
Version: "1.42",
Expand Down
82 changes: 82 additions & 0 deletions cli/cmd/mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func Execute() {
like downloading new versions.`),
}
AddVersionCmd(rootCmd)
AddUpdateCmd(rootCmd)
AddListCmd(rootCmd, opts)
AddDownloadCmd(rootCmd, opts)

Expand Down
Binary file added cli/cmd/testdata/testcli.tar.gz
Binary file not shown.
111 changes: 111 additions & 0 deletions cli/cmd/update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package cmd

import (
"fmt"
"golang.org/x/sync/errgroup"
"io"
"strings"

"github.com/blang/semver"
"github.com/inconshreveable/go-update"
"github.com/spf13/cobra"

"github.com/codesphere-cloud/oms/internal/portal"
"github.com/codesphere-cloud/oms/internal/util"
"github.com/codesphere-cloud/oms/internal/version"
)

type UpdateCmd struct {
cmd *cobra.Command
Version version.Version
Updater Updater
}

func (c *UpdateCmd) RunE(_ *cobra.Command, args []string) error {

p := portal.NewPortalClient()

return c.SelfUpdate(p)
}

func AddUpdateCmd(rootCmd *cobra.Command) {
update := UpdateCmd{
cmd: &cobra.Command{
Use: "update",
Short: "Update Codesphere OMS",
Long: `Updates the OMS to the latest release from OMS Portal.`,
},
Version: &version.Build{},
Updater: &SelfUpdater{},
}
rootCmd.AddCommand(update.cmd)
update.cmd.RunE = update.RunE
}

func (c *UpdateCmd) SelfUpdate(p portal.Portal) error {
currentVersion := semver.MustParse(c.Version.Version())

latest, err := p.GetLatestBuild(portal.OmsProduct)
if err != nil {
return fmt.Errorf("failed to OMS Portal for latest version: %w", err)
}
latestVersion := semver.MustParse(strings.TrimPrefix(latest.Version, "oms-v"))

fmt.Printf("current version: %v\n", currentVersion)
fmt.Printf("latest version: %v\n", latestVersion)
if latestVersion.Equals(currentVersion) {
fmt.Println("Current OMS CLI is already the latest version", c.Version.Version())
return nil
}

// Need a build with a single artifact to download it
download, err := latest.GetBuildForDownload(fmt.Sprintf("%s_%s.tar.gz", c.Version.Os(), c.Version.Arch()))
if err != nil {
return fmt.Errorf("failed to find OMS CLI in package: %w", err)
}

// Use a pipe to unzip the file while downloading without storing on the filesystem
reader, writer := io.Pipe()
defer func() { _ = reader.Close() }()

eg := errgroup.Group{}
eg.Go(func() error {
defer func() { _ = writer.Close() }()
err = p.DownloadBuildArtifact(portal.OmsProduct, download, writer)
if err != nil {
return fmt.Errorf("failed to download latest OMS package: %w", err)
}
return nil
})

cliReader, err := util.StreamFileFromGzip(reader, "oms-cli")
if err != nil {
return fmt.Errorf("failed to extract binary from archive: %w", err)
}

err = c.Updater.Apply(cliReader)
if err != nil {
return fmt.Errorf("failed to apply update: %w", err)
}

_, _ = io.Copy(io.Discard, reader)

// Wait for download to finish and handle any error from the go routine
err = eg.Wait()
if err != nil {
return err
}

fmt.Println("Update finished successfully.")
return nil
}

type Updater interface {
Apply(update io.Reader) error
}

type SelfUpdater struct{}

func (s *SelfUpdater) Apply(r io.Reader) error {
return update.Apply(r, update.Options{})
}
Loading