diff --git a/internal/commands/glaze.go b/internal/commands/glaze.go index fdebe9384..14dd2cbfd 100644 --- a/internal/commands/glaze.go +++ b/internal/commands/glaze.go @@ -5,46 +5,28 @@ import ( "github.com/pivotal-cf/kiln/pkg/cargo" ) -type ( - glazeCommandOptions struct { +type Glaze struct { + Options struct { Kilnfile string `short:"kf" long:"kilnfile" default:"Kilnfile" description:"path to Kilnfile"` + Undo bool ` long:"undo" description:"loosens bosh release constraints post-GA based on 'maintenance_version_bump_policy' and 'float_always'"` } - Glaze struct { - Options glazeCommandOptions - } - DeGlaze struct { - Options glazeCommandOptions - } -) - -func (cmd *Glaze) Execute(args []string) error { - return glazeCommandExecute(cmd.Options, args, (*cargo.Kilnfile).Glaze) -} - -func (cmd *Glaze) Usage() jhanda.Usage { - return jhanda.Usage{ - Description: "This command locks all the components.", - ShortDescription: "Pin versions in Kilnfile to match lock.", - } -} -func (cmd *DeGlaze) Execute(args []string) error { - return glazeCommandExecute(cmd.Options, args, (*cargo.Kilnfile).DeGlaze) + glaze, deGlaze func(kf *cargo.Kilnfile, kl cargo.KilnfileLock) error } -func (cmd *DeGlaze) Usage() jhanda.Usage { - return jhanda.Usage{ - Description: "This command unlocks all the components.", - ShortDescription: "Unpin version constraints in Kilnfile based on de_glaze_behavior.", +func NewGlaze() *Glaze { + return &Glaze{ + glaze: (*cargo.Kilnfile).Glaze, + deGlaze: (*cargo.Kilnfile).DeGlaze, } } -func glazeCommandExecute(options glazeCommandOptions, args []string, fn func(kilnfile *cargo.Kilnfile, lock cargo.KilnfileLock) error) error { - _, err := jhanda.Parse(&options, args) +func (cmd *Glaze) Execute(args []string) error { + _, err := jhanda.Parse(&cmd.Options, args) if err != nil { return err } - kfPath, err := cargo.ResolveKilnfilePath(options.Kilnfile) + kfPath, err := cargo.ResolveKilnfilePath(cmd.Options.Kilnfile) if err != nil { return err } @@ -52,8 +34,20 @@ func glazeCommandExecute(options glazeCommandOptions, args []string, fn func(kil if err != nil { return err } - if err := fn(&kilnfile, kilnfileLock); err != nil { + if cmd.Options.Undo { + err = cmd.deGlaze(&kilnfile, kilnfileLock) + } else { + err = cmd.glaze(&kilnfile, kilnfileLock) + } + if err != nil { return err } return cargo.WriteKilnfile(kfPath, kilnfile) } + +func (cmd *Glaze) Usage() jhanda.Usage { + return jhanda.Usage{ + Description: "This command locks all the components.", + ShortDescription: "Pin versions in Kilnfile to match lock.", + } +} diff --git a/internal/commands/glaze_test.go b/internal/commands/glaze_test.go index 044b05a25..166a1826a 100644 --- a/internal/commands/glaze_test.go +++ b/internal/commands/glaze_test.go @@ -1,27 +1,45 @@ package commands import ( + "fmt" "os" "path/filepath" "testing" . "github.com/onsi/gomega" - "github.com/pivotal-cf/jhanda" "github.com/pivotal-cf/kiln/pkg/cargo" "gopkg.in/yaml.v2" ) const invalidYAML = `}` -func TestGlaze_Execute(t *testing.T) { - testGlazeCommand(t, &Glaze{}) +type glazeWithFakeImplementation struct { + Glaze + GlazeFuncCalled, DeGlazeFuncCalled bool + glazeFuncError, deGlazeFuncError error +} + +func (fake *glazeWithFakeImplementation) glaze(*cargo.Kilnfile, cargo.KilnfileLock) error { + fake.GlazeFuncCalled = true + return fake.glazeFuncError +} + +func (fake *glazeWithFakeImplementation) deGlaze(*cargo.Kilnfile, cargo.KilnfileLock) error { + fake.DeGlazeFuncCalled = true + return fake.deGlazeFuncError } -func TestDeGlaze_Execute(t *testing.T) { - testGlazeCommand(t, &DeGlaze{}) +func newGlazeWithFake(glazeFuncError, deGlazeFuncError error) *glazeWithFakeImplementation { + result := &glazeWithFakeImplementation{ + glazeFuncError: glazeFuncError, + deGlazeFuncError: deGlazeFuncError, + } + result.Glaze.glaze = result.glaze + result.Glaze.deGlaze = result.deGlaze + return result } -func testGlazeCommand(t *testing.T, cmd jhanda.Command) { +func TestGlaze_Execute(t *testing.T) { t.Run("Kilnfile passed in as argument", func(t *testing.T) { tmp := t.TempDir() kfp := filepath.Join(tmp, "Kilnfile") @@ -30,7 +48,7 @@ func testGlazeCommand(t *testing.T, cmd jhanda.Command) { klp := filepath.Join(tmp, "Kilnfile.lock") writeYAML(t, klp, cargo.KilnfileLock{}) - err := cmd.Execute([]string{"--kilnfile", kfp}) + err := newGlazeWithFake(nil, nil).Execute([]string{"--kilnfile", kfp}) g := NewWithT(t) g.Expect(err).ToNot(HaveOccurred()) @@ -38,7 +56,7 @@ func testGlazeCommand(t *testing.T, cmd jhanda.Command) { t.Run("Kilnfile is missing", func(t *testing.T) { tmp := t.TempDir() - err := cmd.Execute([]string{"--kilnfile", tmp}) + err := newGlazeWithFake(nil, nil).Execute([]string{"--kilnfile", tmp}) g := NewWithT(t) g.Expect(err).To(MatchError(ContainSubstring("Kilnfile"))) @@ -52,7 +70,7 @@ func testGlazeCommand(t *testing.T, cmd jhanda.Command) { klp := filepath.Join(tmp, "Kilnfile.lock") writeYAML(t, klp, cargo.KilnfileLock{}) - err := cmd.Execute([]string{"--kilnfile", tmp}) + err := newGlazeWithFake(nil, nil).Execute([]string{"--kilnfile", tmp}) g := NewWithT(t) g.Expect(err).NotTo(HaveOccurred()) @@ -63,51 +81,14 @@ func testGlazeCommand(t *testing.T, cmd jhanda.Command) { kfp := filepath.Join(tmp, "Kilnfile") writeYAML(t, kfp, cargo.Kilnfile{}) - err := cmd.Execute([]string{"--kilnfile", kfp}) + err := newGlazeWithFake(nil, nil).Execute([]string{"--kilnfile", kfp}) g := NewWithT(t) g.Expect(err).To(MatchError(ContainSubstring("Kilnfile.lock"))) }) - t.Run("Kilnfile has a release not in Kilnfile.lock", func(t *testing.T) { - tmp := t.TempDir() - kfp := filepath.Join(tmp, "Kilnfile") - writeYAML(t, kfp, cargo.Kilnfile{ - Releases: []cargo.ComponentSpec{ - {Name: "banana"}, - }, - }) - klp := filepath.Join(tmp, "Kilnfile.lock") - writeYAML(t, klp, cargo.KilnfileLock{ - Releases: []cargo.ComponentLock{}, - }) - err := cmd.Execute([]string{"--kilnfile", kfp}) - - g := NewWithT(t) - g.Expect(err).To(MatchError(ContainSubstring(`"banana" not found in Kilnfile.lock`))) - }) - - t.Run("Kilnfile has a release not in Kilnfile.lock", func(t *testing.T) { - tmp := t.TempDir() - - kfp := filepath.Join(tmp, "Kilnfile") - writeYAML(t, kfp, cargo.Kilnfile{ - Releases: []cargo.ComponentSpec{ - {Name: "banana"}, - }, - }) - klp := filepath.Join(tmp, "Kilnfile.lock") - writeYAML(t, klp, cargo.KilnfileLock{ - Releases: []cargo.ComponentLock{}, - }) - err := cmd.Execute([]string{"--kilnfile", kfp}) - - g := NewWithT(t) - g.Expect(err).To(MatchError(ContainSubstring(`"banana" not found in Kilnfile.lock`))) - }) - t.Run("bad flag passed", func(t *testing.T) { - err := cmd.Execute([]string{"--unknown-flag"}) + err := newGlazeWithFake(nil, nil).Execute([]string{"--unknown-flag"}) g := NewWithT(t) g.Expect(err).To(MatchError(ContainSubstring(`flag provided but not defined`))) @@ -118,7 +99,7 @@ func testGlazeCommand(t *testing.T, cmd jhanda.Command) { tmp := t.TempDir() kfp := filepath.Join(tmp, "Kilnfile") _ = os.WriteFile(kfp, []byte(invalidYAML), 0o777) - err := cmd.Execute([]string{"--kilnfile", kfp}) + err := newGlazeWithFake(nil, nil).Execute([]string{"--kilnfile", kfp}) g := NewWithT(t) g.Expect(err).To(MatchError(And( ContainSubstring(`Kilnfile`), @@ -131,7 +112,7 @@ func testGlazeCommand(t *testing.T, cmd jhanda.Command) { _ = os.WriteFile(kfp, []byte(`{}`), 0o777) klp := filepath.Join(tmp, "Kilnfile.lock") _ = os.WriteFile(klp, []byte(invalidYAML), 0o777) - err := cmd.Execute([]string{"--kilnfile", kfp}) + err := newGlazeWithFake(nil, nil).Execute([]string{"--kilnfile", kfp}) g := NewWithT(t) g.Expect(err).To(MatchError(And( ContainSubstring(`Kilnfile.lock`), @@ -139,6 +120,68 @@ func testGlazeCommand(t *testing.T, cmd jhanda.Command) { ))) }) }) + + t.Run("when undo is passed", func(t *testing.T) { + tmp := t.TempDir() + kfp := filepath.Join(tmp, "Kilnfile") + writeYAML(t, kfp, cargo.Kilnfile{}) + + klp := filepath.Join(tmp, "Kilnfile.lock") + writeYAML(t, klp, cargo.KilnfileLock{}) + + cmd := newGlazeWithFake(nil, nil) + err := cmd.Execute([]string{"--undo", "--kilnfile", kfp}) + + g := NewWithT(t) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(cmd.DeGlazeFuncCalled).To(BeTrue(), "it calls deGlaze") + }) + + t.Run("when de-glaze fails", func(t *testing.T) { + tmp := t.TempDir() + kfp := filepath.Join(tmp, "Kilnfile") + writeYAML(t, kfp, cargo.Kilnfile{}) + + klp := filepath.Join(tmp, "Kilnfile.lock") + writeYAML(t, klp, cargo.KilnfileLock{}) + + cmd := newGlazeWithFake(nil, fmt.Errorf("banana")) + err := cmd.Execute([]string{"--undo"}) + + g := NewWithT(t) + g.Expect(err).To(HaveOccurred()) + }) + + t.Run("when undo is not passed", func(t *testing.T) { + tmp := t.TempDir() + kfp := filepath.Join(tmp, "Kilnfile") + writeYAML(t, kfp, cargo.Kilnfile{}) + + klp := filepath.Join(tmp, "Kilnfile.lock") + writeYAML(t, klp, cargo.KilnfileLock{}) + + cmd := newGlazeWithFake(nil, nil) + err := cmd.Execute([]string{"--kilnfile", kfp}) + + g := NewWithT(t) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(cmd.GlazeFuncCalled).To(BeTrue(), "it calls glaze") + }) + + t.Run("when glaze fails", func(t *testing.T) { + tmp := t.TempDir() + kfp := filepath.Join(tmp, "Kilnfile") + writeYAML(t, kfp, cargo.Kilnfile{}) + + klp := filepath.Join(tmp, "Kilnfile.lock") + writeYAML(t, klp, cargo.KilnfileLock{}) + + cmd := newGlazeWithFake(nil, fmt.Errorf("banana")) + err := cmd.Execute([]string{}) + + g := NewWithT(t) + g.Expect(err).To(HaveOccurred()) + }) } func writeYAML(t *testing.T, path string, data interface{}) { diff --git a/main.go b/main.go index e75b0f3b6..91c55cb52 100644 --- a/main.go +++ b/main.go @@ -108,8 +108,7 @@ func main() { } // commandSet["fetch"] = commands.NewFetch(outLogger, mrsProvider, localReleaseDirectory) - commandSet["glaze"] = new(commands.Glaze) - commandSet["de-glaze"] = new(commands.DeGlaze) + commandSet["glaze"] = commands.NewGlaze() commandSet["generate-osm-manifest"] = commands.NewOSM(outLogger, nil)