diff --git a/internal/commands/update_stemcell.go b/internal/commands/update_stemcell.go index 88e4505e..77853c1f 100644 --- a/internal/commands/update_stemcell.go +++ b/internal/commands/update_stemcell.go @@ -12,16 +12,16 @@ import ( "github.com/pivotal-cf/kiln/internal/commands/flags" "github.com/pivotal-cf/kiln/internal/component" - "github.com/pivotal-cf/kiln/pkg/cargo" ) type UpdateStemcell struct { Options struct { flags.Standard - Version string `short:"v" long:"version" required:"true" description:"desired version of stemcell"` - ReleasesDir string `short:"rd" long:"releases-directory" default:"releases" description:"path to a directory to download releases into"` - UpdateReleases bool `short:"ur" long:"update-releases" description:"finds latest matching releases for new stemcell version"` + Version string `short:"v" long:"version" required:"true" description:"desired version of stemcell"` + ReleasesDir string `short:"rd" long:"releases-directory" default:"releases" description:"path to a directory to download releases into"` + UpdateReleases bool `short:"ur" long:"update-releases" description:"finds latest matching releases for new stemcell version"` + WithoutDownload bool ` long:"without-download" description:"updates stemcell releases without downloading releases"` } FS billy.Filesystem MultiReleaseSourceProvider MultiReleaseSourceProvider @@ -69,45 +69,46 @@ func (update UpdateStemcell) Execute(args []string) error { releaseSource := update.MultiReleaseSourceProvider(kilnfile, false) for i, rel := range kilnfileLock.Releases { - update.Logger.Printf("Updating release %q with stemcell %s %s...", rel.Name, kilnfileLock.Stemcell.OS, trimmedInputVersion) + update.Logger.Printf("Updating release %s %s with stemcell %s %s...", rel.Name, rel.Version, kilnfileLock.Stemcell.OS, trimmedInputVersion) spec, err := kilnfile.BOSHReleaseTarballSpecification(rel.Name) if err != nil { return err } + spec.StemcellOS = kilnfileLock.Stemcell.OS spec.StemcellVersion = trimmedInputVersion - var remote cargo.BOSHReleaseTarballLock - if update.Options.UpdateReleases { - remote, err = releaseSource.FindReleaseVersion(spec, true) - } else { + if !update.Options.UpdateReleases { spec.Version = rel.Version - remote, err = releaseSource.GetMatchedRelease(spec) } + remote, err := releaseSource.FindReleaseVersion(spec, true) if err != nil { - return fmt.Errorf("while finding release %q, encountered error: %w", rel.Name, err) + return fmt.Errorf("while finding release %s %s, encountered error: %w", rel.Name, rel.Version, err) } + if component.IsErrNotFound(err) { - return fmt.Errorf("couldn't find release %q", rel.Name) + return fmt.Errorf("couldn't find release %s %s", rel.Name, rel.Version) } if remote.RemotePath == rel.RemotePath && remote.RemoteSource == rel.RemoteSource { - update.Logger.Printf("No change for release %q\n", rel.Name) + update.Logger.Printf("No change for release %s %s\n", rel.Name, rel.Version) continue } - lock := &kilnfileLock.Releases[i] + lock := &kilnfileLock.Releases[i] lock.RemotePath = remote.RemotePath lock.RemoteSource = remote.RemoteSource lock.SHA1 = remote.SHA1 - if remote.SHA1 == "" || remote.SHA1 == "not-calculated" { + + if !update.Options.WithoutDownload || lock.SHA1 == "" || lock.SHA1 == "not-calculated" { // release source needs to download. local, err := releaseSource.DownloadRelease(update.Options.ReleasesDir, remote) if err != nil { - return fmt.Errorf("while downloading release %q, encountered error: %w", rel.Name, err) + return fmt.Errorf("while downloading release %s %s, encountered error: %w", rel.Name, rel.Version, err) } + lock.SHA1 = local.Lock.SHA1 } } diff --git a/internal/commands/update_stemcell_test.go b/internal/commands/update_stemcell_test.go index 3c4edf6f..da198221 100644 --- a/internal/commands/update_stemcell_test.go +++ b/internal/commands/update_stemcell_test.go @@ -110,7 +110,8 @@ var _ = Describe("UpdateStemcell", func() { switch requirement.Name { case release1Name: remote := cargo.BOSHReleaseTarballLock{ - Name: release1Name, Version: release1Version, + Name: release1Name, + Version: release1Version, RemotePath: newRelease1RemotePath, RemoteSource: publishableReleaseSourceID, SHA1: "", @@ -118,7 +119,8 @@ var _ = Describe("UpdateStemcell", func() { return remote, nil case release2Name: remote := cargo.BOSHReleaseTarballLock{ - Name: release2Name, Version: release2Version, + Name: release2Name, + Version: release2Version, RemotePath: newRelease2RemotePath, RemoteSource: unpublishableReleaseSourceID, SHA1: "not-calculated", @@ -126,7 +128,8 @@ var _ = Describe("UpdateStemcell", func() { return remote, nil case release3Name: remote := cargo.BOSHReleaseTarballLock{ - Name: release3Name, Version: release3Version, + Name: release3Name, + Version: release3Version, RemotePath: newRelease3RemotePath, RemoteSource: publishableReleaseSourceID, SHA1: newRelease3SHA, @@ -141,7 +144,8 @@ var _ = Describe("UpdateStemcell", func() { switch requirement.Name { case release1Name: remote := cargo.BOSHReleaseTarballLock{ - Name: release1Name, Version: release1Version, + Name: release1Name, + Version: release1Version, RemotePath: newRelease1RemotePath, RemoteSource: publishableReleaseSourceID, SHA1: "", @@ -149,7 +153,8 @@ var _ = Describe("UpdateStemcell", func() { return remote, nil case release2Name: remote := cargo.BOSHReleaseTarballLock{ - Name: release2Name, Version: release2Version, + Name: release2Name, + Version: release2Version, RemotePath: newRelease2RemotePath, RemoteSource: unpublishableReleaseSourceID, SHA1: "not-calculated", @@ -157,7 +162,8 @@ var _ = Describe("UpdateStemcell", func() { return remote, nil case release3Name: remote := cargo.BOSHReleaseTarballLock{ - Name: release3Name, Version: release3Version, + Name: release3Name, + Version: release3Version, RemotePath: newRelease3RemotePath, RemoteSource: publishableReleaseSourceID, SHA1: newRelease3SHA, @@ -172,13 +178,31 @@ var _ = Describe("UpdateStemcell", func() { switch remote.Name { case release1Name: local := component.Local{ - Lock: cargo.BOSHReleaseTarballLock{Name: release1Name, Version: release1Version, SHA1: newRelease1SHA}, + Lock: cargo.BOSHReleaseTarballLock{ + Name: release1Name, + Version: release1Version, + SHA1: newRelease1SHA, + }, LocalPath: "not-used", } return local, nil case release2Name: local := component.Local{ - Lock: cargo.BOSHReleaseTarballLock{Name: release2Name, Version: release2Version, SHA1: newRelease2SHA}, + Lock: cargo.BOSHReleaseTarballLock{ + Name: release2Name, + Version: release2Version, + SHA1: newRelease2SHA, + }, + LocalPath: "not-used", + } + return local, nil + case release3Name: + local := component.Local{ + Lock: cargo.BOSHReleaseTarballLock{ + Name: release3Name, + Version: release3Version, + SHA1: newRelease3SHA, + }, LocalPath: "not-used", } return local, nil @@ -260,28 +284,37 @@ var _ = Describe("UpdateStemcell", func() { }) Expect(err).NotTo(HaveOccurred()) - Expect(releaseSource.GetMatchedReleaseCallCount()).To(Equal(3)) + Expect(releaseSource.FindReleaseVersionCallCount()).To(Equal(3)) - req1 := releaseSource.GetMatchedReleaseArgsForCall(0) + req1, noDL1 := releaseSource.FindReleaseVersionArgsForCall(0) Expect(req1).To(Equal(cargo.BOSHReleaseTarballSpecification{ - Name: release1Name, Version: release1Version, - StemcellOS: newStemcellOS, StemcellVersion: newStemcellVersion, + Name: release1Name, + Version: release1Version, + StemcellOS: newStemcellOS, + StemcellVersion: newStemcellVersion, GitHubRepository: "https://example.com/lemon", })) + Expect(noDL1).To(BeTrue()) - req2 := releaseSource.GetMatchedReleaseArgsForCall(1) + req2, noDL2 := releaseSource.FindReleaseVersionArgsForCall(1) Expect(req2).To(Equal(cargo.BOSHReleaseTarballSpecification{ - Name: release2Name, Version: release2Version, - StemcellOS: newStemcellOS, StemcellVersion: newStemcellVersion, + Name: release2Name, + Version: release2Version, + StemcellOS: newStemcellOS, + StemcellVersion: newStemcellVersion, GitHubRepository: "https://example.com/orange", })) + Expect(noDL2).To(BeTrue()) - req3 := releaseSource.GetMatchedReleaseArgsForCall(2) + req3, noDL3 := releaseSource.FindReleaseVersionArgsForCall(2) Expect(req3).To(Equal(cargo.BOSHReleaseTarballSpecification{ - Name: release3Name, Version: release3Version, - StemcellOS: newStemcellOS, StemcellVersion: newStemcellVersion, + Name: release3Name, + Version: release3Version, + StemcellOS: newStemcellOS, + StemcellVersion: newStemcellVersion, GitHubRepository: "https://example.com/pomelo", })) + Expect(noDL3).To(BeTrue()) }) It("looks up the correct releases with --update-releases", func() { err := update.Execute([]string{ @@ -293,34 +326,41 @@ var _ = Describe("UpdateStemcell", func() { req1, noDownload1 := releaseSource.FindReleaseVersionArgsForCall(0) Expect(req1).To(Equal(cargo.BOSHReleaseTarballSpecification{ - Name: release1Name, Version: "*", - StemcellOS: newStemcellOS, StemcellVersion: newStemcellVersion, + Name: release1Name, + Version: "*", + StemcellOS: newStemcellOS, + StemcellVersion: newStemcellVersion, GitHubRepository: "https://example.com/lemon", })) Expect(noDownload1).To(BeTrue()) req2, noDownload2 := releaseSource.FindReleaseVersionArgsForCall(1) Expect(req2).To(Equal(cargo.BOSHReleaseTarballSpecification{ - Name: release2Name, Version: "*", - StemcellOS: newStemcellOS, StemcellVersion: newStemcellVersion, + Name: release2Name, + Version: "*", + StemcellOS: newStemcellOS, + StemcellVersion: newStemcellVersion, GitHubRepository: "https://example.com/orange", })) Expect(noDownload2).To(BeTrue()) }) - It("downloads 2 of the 3 correct releases, ", func() { + It("downloads all of the releases", func() { err := update.Execute([]string{ - "--kilnfile", kilnfilePath, "--version", newStemcellVersion, "--releases-directory", releasesDirPath, + "--kilnfile", kilnfilePath, + "--version", newStemcellVersion, + "--releases-directory", releasesDirPath, }) Expect(err).NotTo(HaveOccurred()) - Expect(releaseSource.DownloadReleaseCallCount()).To(Equal(2)) + Expect(releaseSource.DownloadReleaseCallCount()).To(Equal(3)) actualDir, remote1 := releaseSource.DownloadReleaseArgsForCall(0) Expect(actualDir).To(Equal(releasesDirPath)) Expect(remote1).To(Equal( cargo.BOSHReleaseTarballLock{ - Name: release1Name, Version: release1Version, + Name: release1Name, + Version: release1Version, RemotePath: newRelease1RemotePath, RemoteSource: publishableReleaseSourceID, SHA1: "", @@ -331,12 +371,111 @@ var _ = Describe("UpdateStemcell", func() { Expect(actualDir).To(Equal(releasesDirPath)) Expect(remote2).To(Equal( cargo.BOSHReleaseTarballLock{ - Name: release2Name, Version: release2Version, + Name: release2Name, + Version: release2Version, RemotePath: newRelease2RemotePath, RemoteSource: unpublishableReleaseSourceID, SHA1: "not-calculated", }, )) + + actualDir, remote3 := releaseSource.DownloadReleaseArgsForCall(2) + Expect(actualDir).To(Equal(releasesDirPath)) + Expect(remote3).To(Equal( + cargo.BOSHReleaseTarballLock{ + Name: release3Name, + Version: release3Version, + RemotePath: newRelease3RemotePath, + RemoteSource: publishableReleaseSourceID, + SHA1: "new-sha1-3", + }, + )) + }) + + When("the remote information for a release doesn't change", func() { + BeforeEach(func() { + kilnfileLock.Releases[1].RemoteSource = unpublishableReleaseSourceID + kilnfileLock.Releases[1].RemotePath = newRelease2RemotePath + }) + + It("still downloads the release", func() { + err := update.Execute([]string{ + "--kilnfile", kilnfilePath, + "--version", newStemcellVersion, + }) + Expect(err).NotTo(HaveOccurred()) + + Expect(releaseSource.DownloadReleaseCallCount()).To(Equal(2)) + + _, remote := releaseSource.DownloadReleaseArgsForCall(0) + Expect(remote.Name).To(Equal(release1Name)) + + _, remote = releaseSource.DownloadReleaseArgsForCall(1) + Expect(remote.Name).To(Equal(release3Name)) + + Expect(string(outputBuffer.Contents())).To(ContainSubstring("No change for release " + release2Name)) + }) + }) + + When("when the --without-download flag is specified", func() { + It("downloads 2 of the 3 correct releases", func() { + err := update.Execute([]string{ + "--kilnfile", kilnfilePath, + "--version", newStemcellVersion, + "--releases-directory", releasesDirPath, + "--without-download", + }) + Expect(err).NotTo(HaveOccurred()) + + Expect(releaseSource.DownloadReleaseCallCount()).To(Equal(2)) + + actualDir, remote1 := releaseSource.DownloadReleaseArgsForCall(0) + Expect(actualDir).To(Equal(releasesDirPath)) + Expect(remote1).To(Equal( + cargo.BOSHReleaseTarballLock{ + Name: release1Name, + Version: release1Version, + RemotePath: newRelease1RemotePath, + RemoteSource: publishableReleaseSourceID, + SHA1: "", + }, + )) + + actualDir, remote2 := releaseSource.DownloadReleaseArgsForCall(1) + Expect(actualDir).To(Equal(releasesDirPath)) + Expect(remote2).To(Equal( + cargo.BOSHReleaseTarballLock{ + Name: release2Name, + Version: release2Version, + RemotePath: newRelease2RemotePath, + RemoteSource: unpublishableReleaseSourceID, + SHA1: "not-calculated", + }, + )) + }) + + When("the remote information for a release doesn't change", func() { + BeforeEach(func() { + kilnfileLock.Releases[1].RemoteSource = unpublishableReleaseSourceID + kilnfileLock.Releases[1].RemotePath = newRelease2RemotePath + }) + + It("doesn't download the release", func() { + err := update.Execute([]string{ + "--kilnfile", kilnfilePath, + "--version", newStemcellVersion, + "--without-download", + }) + Expect(err).NotTo(HaveOccurred()) + + Expect(releaseSource.DownloadReleaseCallCount()).To(Equal(1)) + _, remote := releaseSource.DownloadReleaseArgsForCall(0) + Expect(remote.Name).To(Equal(release1Name)) + + Expect(string(outputBuffer.Contents())).To(ContainSubstring("No change")) + Expect(string(outputBuffer.Contents())).To(ContainSubstring(release2Name)) + }) + }) }) When("the version input is invalid", func() { @@ -470,28 +609,9 @@ var _ = Describe("UpdateStemcell", func() { }) }) - When("the remote information for a release doesn't change", func() { - BeforeEach(func() { - kilnfileLock.Releases[1].RemoteSource = unpublishableReleaseSourceID - kilnfileLock.Releases[1].RemotePath = newRelease2RemotePath - }) - - It("doesn't download the release", func() { - err := update.Execute([]string{"--kilnfile", kilnfilePath, "--version", newStemcellVersion}) - Expect(err).NotTo(HaveOccurred()) - - Expect(releaseSource.DownloadReleaseCallCount()).To(Equal(1)) - _, remote := releaseSource.DownloadReleaseArgsForCall(0) - Expect(remote.Name).To(Equal(release1Name)) - - Expect(string(outputBuffer.Contents())).To(ContainSubstring("No change")) - Expect(string(outputBuffer.Contents())).To(ContainSubstring(release2Name)) - }) - }) - When("the release can't be found", func() { BeforeEach(func() { - releaseSource.GetMatchedReleaseReturns(cargo.BOSHReleaseTarballLock{}, component.ErrNotFound) + releaseSource.FindReleaseVersionReturns(cargo.BOSHReleaseTarballLock{}, component.ErrNotFound) }) It("errors", func() { @@ -506,7 +626,7 @@ var _ = Describe("UpdateStemcell", func() { When("finding the release errors", func() { BeforeEach(func() { - releaseSource.GetMatchedReleaseReturns(cargo.BOSHReleaseTarballLock{}, errors.New("big badda boom")) + releaseSource.FindReleaseVersionReturns(cargo.BOSHReleaseTarballLock{}, errors.New("big badda boom")) }) It("errors", func() { diff --git a/internal/component/artifactory_release_source.go b/internal/component/artifactory_release_source.go index 4d8435b9..d0428c8b 100644 --- a/internal/component/artifactory_release_source.go +++ b/internal/component/artifactory_release_source.go @@ -178,7 +178,7 @@ func (ars *ArtifactoryReleaseSource) GetMatchedRelease(spec cargo.BOSHReleaseTar default: return cargo.BOSHReleaseTarballLock{}, fmt.Errorf("unexpected http status: %s", http.StatusText(response.StatusCode)) } - + matchedRelease := cargo.BOSHReleaseTarballLock{ Name: spec.Name, Version: spec.Version, diff --git a/pkg/cargo/bosh_release.go b/pkg/cargo/bosh_release.go index 9befde7f..8b6ca8fd 100644 --- a/pkg/cargo/bosh_release.go +++ b/pkg/cargo/bosh_release.go @@ -155,7 +155,7 @@ func ReadBOSHReleaseTarball(tarballPath string, r io.Reader) (BOSHReleaseTarball if err != nil { return BOSHReleaseTarball{}, err } - _, err = io.CopyBuffer(io.Discard, r, make([]byte, 1024 * 64)) + _, err = io.CopyBuffer(io.Discard, r, make([]byte, 1024*64)) return BOSHReleaseTarball{ Manifest: m, SHA1: hex.EncodeToString(sum.Sum(nil)),