Skip to content

Commit

Permalink
Add max-in-flight flag to copy-src command
Browse files Browse the repository at this point in the history
Signed-off-by: João Pereira <joaod@vmware.com>
  • Loading branch information
joaopapereira committed Aug 7, 2024
1 parent e9d877f commit e03a8f9
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 48 deletions.
16 changes: 13 additions & 3 deletions command/v7/copy_source_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type CopySourceCommand struct {
RequiredArgs flag.CopySourceArgs `positional-args:"yes"`
usage interface{} `usage:"CF_NAME copy-source SOURCE_APP DESTINATION_APP [-s TARGET_SPACE [-o TARGET_ORG]] [--no-restart] [--strategy STRATEGY] [--no-wait]"`
Strategy flag.DeploymentStrategy `long:"strategy" description:"Deployment strategy can be canary, rolling or null"`
MaxInFlight int `long:"max-in-flight" default:"-1" description:"Defines the maximum number of instances that will be actively being started. Only applies when --strategy flag is specified."`
NoWait bool `long:"no-wait" description:"Exit when the first instance of the web process is healthy"`
NoRestart bool `long:"no-restart" description:"Do not restage the destination application"`
Organization string `short:"o" long:"organization" description:"Org that contains the destination application"`
Expand Down Expand Up @@ -48,6 +49,14 @@ func (cmd *CopySourceCommand) ValidateFlags() error {
}
}

if cmd.Strategy.Name == constant.DeploymentStrategyDefault && cmd.MaxInFlight > 0 {
return translatableerror.RequiredFlagsError{Arg1: "--max-in-flight", Arg2: "--strategy"}
}

if cmd.Strategy.Name != constant.DeploymentStrategyDefault && cmd.MaxInFlight < 1 {
return translatableerror.IncorrectUsageError{Message: "--max-in-flight must be greater than or equal to 1"}
}

return nil
}

Expand Down Expand Up @@ -160,9 +169,10 @@ func (cmd CopySourceCommand) Execute(args []string) error {
cmd.UI.DisplayNewline()

opts := shared.AppStartOpts{
Strategy: cmd.Strategy.Name,
NoWait: cmd.NoWait,
AppAction: constant.ApplicationRestarting,
AppAction: constant.ApplicationRestarting,
MaxInFlight: cmd.MaxInFlight,
NoWait: cmd.NoWait,
Strategy: cmd.Strategy.Name,
}
err = cmd.Stager.StageAndStart(targetApp, targetSpace, targetOrg, pkg.GUID, opts)
if err != nil {
Expand Down
110 changes: 65 additions & 45 deletions command/v7/copy_source_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,49 +125,6 @@ var _ = Describe("copy-source Command", func() {
})
})

When("the target organization is specified but the targeted space isn't", func() {
BeforeEach(func() {
cmd.Organization = "some-other-organization"
})

It("returns an error", func() {
Expect(executeErr).To(MatchError(translatableerror.RequiredFlagsError{
Arg1: "--organization, -o",
Arg2: "--space, -s",
}))
})
})

When("the no restart and strategy flags are both provided", func() {
BeforeEach(func() {
cmd.NoRestart = true
cmd.Strategy = flag.DeploymentStrategy{Name: constant.DeploymentStrategyRolling}
})

It("returns an error", func() {
Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
Args: []string{
"--no-restart", "--strategy",
},
}))
})
})

When("the no restart and no wait flags are both provided", func() {
BeforeEach(func() {
cmd.NoRestart = true
cmd.NoWait = true
})

It("returns an error", func() {
Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
Args: []string{
"--no-restart", "--no-wait",
},
}))
})
})

When("a target org and space is provided", func() {
BeforeEach(func() {
cmd.Organization = "destination-org"
Expand Down Expand Up @@ -329,6 +286,7 @@ var _ = Describe("copy-source Command", func() {
cmd.Strategy = flag.DeploymentStrategy{
Name: constant.DeploymentStrategyRolling,
}
cmd.MaxInFlight = 5
})

It("stages and starts the app with the appropriate strategy", func() {
Expand All @@ -338,9 +296,10 @@ var _ = Describe("copy-source Command", func() {
Expect(spaceForApp).To(Equal(configv3.Space{Name: "some-space", GUID: "some-space-guid"}))
Expect(orgForApp).To(Equal(configv3.Organization{Name: "some-org"}))
Expect(pkgGUID).To(Equal("target-package-guid"))
Expect(opts.Strategy).To(Equal(constant.DeploymentStrategyRolling))
Expect(opts.NoWait).To(Equal(false))
Expect(opts.AppAction).To(Equal(constant.ApplicationRestarting))
Expect(opts.MaxInFlight).To(Equal(5))
Expect(opts.NoWait).To(Equal(false))
Expect(opts.Strategy).To(Equal(constant.DeploymentStrategyRolling))
})
})

Expand All @@ -349,6 +308,7 @@ var _ = Describe("copy-source Command", func() {
cmd.Strategy = flag.DeploymentStrategy{
Name: constant.DeploymentStrategyCanary,
}
cmd.MaxInFlight = 1
})

It("stages and starts the app with the appropriate strategy", func() {
Expand Down Expand Up @@ -417,4 +377,64 @@ var _ = Describe("copy-source Command", func() {
It("succeeds", func() {
Expect(executeErr).To(Not(HaveOccurred()))
})

DescribeTable("ValidateFlags returns an error",
func(setup func(), expectedErr error) {
setup()
err := cmd.ValidateFlags()
if expectedErr == nil {
Expect(err).To(BeNil())
} else {
Expect(err).To(MatchError(expectedErr))
}
},
Entry("the target organization is specified but the targeted space isn't",
func() {
cmd.Organization = "some-other-organization"
},
translatableerror.RequiredFlagsError{
Arg1: "--organization, -o",
Arg2: "--space, -s",
}),

Entry("the no restart and strategy flags are both provided",
func() {
cmd.NoRestart = true
cmd.Strategy = flag.DeploymentStrategy{Name: constant.DeploymentStrategyRolling}
},
translatableerror.ArgumentCombinationError{
Args: []string{
"--no-restart", "--strategy",
},
}),

Entry("the no restart and no wait flags are both provided",
func() {
cmd.NoRestart = true
cmd.NoWait = true
},
translatableerror.ArgumentCombinationError{
Args: []string{
"--no-restart", "--no-wait",
},
}),

Entry("max-in-flight is passed without strategy",
func() {
cmd.MaxInFlight = 10
},
translatableerror.RequiredFlagsError{
Arg1: "--max-in-flight",
Arg2: "--strategy",
}),

Entry("max-in-flight is smaller than 1",
func() {
cmd.Strategy = flag.DeploymentStrategy{Name: constant.DeploymentStrategyRolling}
cmd.MaxInFlight = 0
},
translatableerror.IncorrectUsageError{
Message: "--max-in-flight must be greater than or equal to 1",
}),
)
})
1 change: 1 addition & 0 deletions integration/v7/isolated/copy_source_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ func helpText(session *Session) {
Eventually(session).Should(Say(`cf copy-source SOURCE_APP DESTINATION_APP \[-s TARGET_SPACE \[-o TARGET_ORG\]\] \[--no-restart\] \[--strategy STRATEGY\] \[--no-wait\]`))
Eventually(session).Should(Say("OPTIONS:"))
Eventually(session).Should(Say(`--strategy\s+Deployment strategy can be canary, rolling or null`))
Eventually(session).Should(Say(`--max-in-flight\s+Defines the maximum number of instances`))
Eventually(session).Should(Say(`--no-wait\s+ Exit when the first instance of the web process is healthy`))
Eventually(session).Should(Say(`--no-restart\s+Do not restage the destination application`))
Eventually(session).Should(Say(`--organization, -o\s+Org that contains the destination application`))
Expand Down

0 comments on commit e03a8f9

Please sign in to comment.