Skip to content

Commit a1e4760

Browse files
feat: allow include and exclude by target tag
1 parent f2871d1 commit a1e4760

3 files changed

Lines changed: 77 additions & 19 deletions

File tree

pkg/cmd/release/deploy/deploy.go

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ const (
8181
FlagAliasExcludeTarget = "exclude-target"
8282
FlagAliasExcludeMachines = "excludeMachines" // octo wants a comma separated list. We prefer specifying --exclude-target multiple times, but CSV also works because pflag does it for free
8383

84+
FlagSpecificTargetTagName = "specific-target-tag"
85+
FlagExcludedTargetTagName = "excluded-target-tag"
86+
8487
FlagVariable = "variable"
8588

8689
FlagUpdateVariables = "update-variables"
@@ -110,6 +113,8 @@ type DeployFlags struct {
110113
ForcePackageDownload *flag.Flag[bool]
111114
DeploymentTargets *flag.Flag[[]string]
112115
ExcludeTargets *flag.Flag[[]string]
116+
SpecificTargetTagNames *flag.Flag[[]string]
117+
ExcludedTargetTagNames *flag.Flag[[]string]
113118
DeploymentFreezeNames *flag.Flag[[]string]
114119
DeploymentFreezeOverrideReason *flag.Flag[string]
115120
}
@@ -130,6 +135,8 @@ func NewDeployFlags() *DeployFlags {
130135
ForcePackageDownload: flag.New[bool](FlagForcePackageDownload, false),
131136
DeploymentTargets: flag.New[[]string](FlagDeploymentTarget, false),
132137
ExcludeTargets: flag.New[[]string](FlagExcludeDeploymentTarget, false),
138+
SpecificTargetTagNames: flag.New[[]string](FlagSpecificTargetTagName, false),
139+
ExcludedTargetTagNames: flag.New[[]string](FlagExcludedTargetTagName, false),
133140
DeploymentFreezeNames: flag.New[[]string](FlagDeploymentFreezeName, false),
134141
DeploymentFreezeOverrideReason: flag.New[string](FlagDeploymentFreezeOverrideReason, false),
135142
}
@@ -172,6 +179,8 @@ func NewCmdDeploy(f factory.Factory) *cobra.Command {
172179
flags.BoolVarP(&deployFlags.ForcePackageDownload.Value, deployFlags.ForcePackageDownload.Name, "", false, "Force re-download of packages")
173180
flags.StringArrayVarP(&deployFlags.DeploymentTargets.Value, deployFlags.DeploymentTargets.Name, "", nil, "Deploy to this target (can be specified multiple times)")
174181
flags.StringArrayVarP(&deployFlags.ExcludeTargets.Value, deployFlags.ExcludeTargets.Name, "", nil, "Deploy to targets except for this (can be specified multiple times)")
182+
flags.StringArrayVarP(&deployFlags.SpecificTargetTagNames.Value, deployFlags.SpecificTargetTagNames.Name, "", nil, "Deploy to targets matching this tag (can be specified multiple times)")
183+
flags.StringArrayVarP(&deployFlags.ExcludedTargetTagNames.Value, deployFlags.ExcludedTargetTagNames.Name, "", nil, "Deploy to targets except for those matching this tag (can be specified multiple times)")
175184
flags.StringArrayVarP(&deployFlags.DeploymentFreezeNames.Value, deployFlags.DeploymentFreezeNames.Name, "", nil, "Override this deployment freeze (can be specified multiple times)")
176185
flags.StringVarP(&deployFlags.DeploymentFreezeOverrideReason.Value, deployFlags.DeploymentFreezeOverrideReason.Name, "", "", "Reason for overriding a deployment freeze")
177186

@@ -226,6 +235,8 @@ func deployRun(cmd *cobra.Command, f factory.Factory, flags *DeployFlags) error
226235
ForcePackageDownload: flags.ForcePackageDownload.Value,
227236
DeploymentTargets: flags.DeploymentTargets.Value,
228237
ExcludeTargets: flags.ExcludeTargets.Value,
238+
SpecificTargetTagNames: flags.SpecificTargetTagNames.Value,
239+
ExcludedTargetTagNames: flags.ExcludedTargetTagNames.Value,
229240
DeploymentFreezeNames: flags.DeploymentFreezeNames.Value,
230241
DeploymentFreezeOverrideReason: flags.DeploymentFreezeOverrideReason.Value,
231242
Variables: parsedVariables,
@@ -264,6 +275,8 @@ func deployRun(cmd *cobra.Command, f factory.Factory, flags *DeployFlags) error
264275
resolvedFlags.GuidedFailureMode.Value = options.GuidedFailureMode
265276
resolvedFlags.DeploymentTargets.Value = options.DeploymentTargets
266277
resolvedFlags.ExcludeTargets.Value = options.ExcludeTargets
278+
resolvedFlags.SpecificTargetTagNames.Value = options.SpecificTargetTagNames
279+
resolvedFlags.ExcludedTargetTagNames.Value = options.ExcludedTargetTagNames
267280
resolvedFlags.DeploymentFreezeNames.Value = options.DeploymentFreezeNames
268281
resolvedFlags.DeploymentFreezeOverrideReason.Value = options.DeploymentFreezeOverrideReason
269282

@@ -296,6 +309,8 @@ func deployRun(cmd *cobra.Command, f factory.Factory, flags *DeployFlags) error
296309
resolvedFlags.ForcePackageDownload,
297310
resolvedFlags.DeploymentTargets,
298311
resolvedFlags.ExcludeTargets,
312+
resolvedFlags.SpecificTargetTagNames,
313+
resolvedFlags.ExcludedTargetTagNames,
299314
resolvedFlags.Variables,
300315
resolvedFlags.DeploymentFreezeNames,
301316
resolvedFlags.DeploymentFreezeOverrideReason,
@@ -619,6 +634,8 @@ func AskQuestions(octopus *octopusApiClient.Client, stdout io.Writer, asker ques
619634
return err
620635
}
621636
}
637+
638+
// TODO: Add support for isDeploymentTargetTagsSpecified
622639
}
623640
// DONE
624641
return nil
@@ -1065,14 +1082,43 @@ func PrintAdvancedSummary(stdout io.Writer, options *executor.TaskOptionsDeployR
10651082
depTargetsStr = sb.String()
10661083
}
10671084

1085+
targetTagsStr := "All included"
1086+
if len(options.SpecificTargetTagNames) != 0 || len(options.ExcludedTargetTagNames) != 0 {
1087+
sb := strings.Builder{}
1088+
if len(options.SpecificTargetTagNames) > 0 {
1089+
sb.WriteString("Include ")
1090+
for idx, name := range options.SpecificTargetTagNames {
1091+
if idx > 0 {
1092+
sb.WriteString(",")
1093+
}
1094+
sb.WriteString(name)
1095+
}
1096+
}
1097+
if len(options.ExcludedTargetTagNames) > 0 {
1098+
if sb.Len() > 0 {
1099+
sb.WriteString("; ")
1100+
}
1101+
1102+
sb.WriteString("Exclude ")
1103+
for idx, name := range options.ExcludedTargetTagNames {
1104+
if idx > 0 {
1105+
sb.WriteString(",")
1106+
}
1107+
sb.WriteString(name)
1108+
}
1109+
}
1110+
targetTagsStr = sb.String()
1111+
}
1112+
10681113
_, _ = fmt.Fprintf(stdout, output.FormatDoc(heredoc.Doc(`
10691114
bold(Additional Options):
10701115
Deploy Time: cyan(%s)
10711116
Skipped Steps: cyan(%s)
10721117
Guided Failure Mode: cyan(%s)
10731118
Package Download: cyan(%s)
10741119
Deployment Targets: cyan(%s)
1075-
`)), deployAtStr, skipStepsStr, gfmStr, pkgDownloadStr, depTargetsStr)
1120+
Target Tags: cyan(%s)
1121+
`)), deployAtStr, skipStepsStr, gfmStr, pkgDownloadStr, depTargetsStr, targetTagsStr)
10761122
}
10771123

10781124
func selectRelease(octopus *octopusApiClient.Client, ask question.Asker, questionText string, space *spaces.Space, project *projects.Project, channel *channels.Channel) (*releases.Release, error) {

pkg/cmd/release/deploy/deploy_test.go

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,6 +1880,8 @@ func TestDeployCreate_AutomationMode(t *testing.T) {
18801880
"--update-variables",
18811881
"--target", "firstMachine", "--target", "secondMachine",
18821882
"--exclude-target", "thirdMachine",
1883+
"--specific-target-tag", "Role/AppServer", "--specific-target-tag", "Region/US-West",
1884+
"--excluded-target-tag", "Maintenance/True",
18831885
"--deployment-freeze-name", "freeze 1", "--deployment-freeze-name", "freeze 2",
18841886
"--deployment-freeze-override-reason", "Testing",
18851887
"--variable", "Approver:John", "--variable", "Signoff:Jane",
@@ -1904,15 +1906,17 @@ func TestDeployCreate_AutomationMode(t *testing.T) {
19041906
ForcePackageRedeployment: true,
19051907
UpdateVariableSnapshot: true,
19061908
CreateExecutionAbstractCommandV1: deployments.CreateExecutionAbstractCommandV1{
1907-
SpaceID: "Spaces-1",
1908-
ProjectIDOrName: fireProject.Name,
1909-
ForcePackageDownload: true,
1910-
SpecificMachineNames: []string{"firstMachine", "secondMachine"},
1911-
ExcludedMachineNames: []string{"thirdMachine"},
1912-
SkipStepNames: []string{"Install", "Cleanup"},
1913-
UseGuidedFailure: &trueVal,
1914-
RunAt: "2022-09-10 13:32:03 +10:00",
1915-
NoRunAfter: "2022-09-10 13:37:03 +10:00",
1909+
SpaceID: "Spaces-1",
1910+
ProjectIDOrName: fireProject.Name,
1911+
ForcePackageDownload: true,
1912+
SpecificMachineNames: []string{"firstMachine", "secondMachine"},
1913+
ExcludedMachineNames: []string{"thirdMachine"},
1914+
SpecificTargetTagNames: []string{"Role/AppServer", "Region/US-West"},
1915+
ExcludedTargetTagNames: []string{"Maintenance/True"},
1916+
SkipStepNames: []string{"Install", "Cleanup"},
1917+
UseGuidedFailure: &trueVal,
1918+
RunAt: "2022-09-10 13:32:03 +10:00",
1919+
NoRunAfter: "2022-09-10 13:37:03 +10:00",
19161920
Variables: map[string]string{
19171921
"Approver": "John",
19181922
"Signoff": "Jane",
@@ -1954,6 +1958,8 @@ func TestDeployCreate_AutomationMode(t *testing.T) {
19541958
"--update-variables",
19551959
"--target", "firstMachine", "--target", "secondMachine",
19561960
"--exclude-target", "thirdMachine",
1961+
"--specific-target-tag", "Role/WebServer", "--specific-target-tag", "Environment/Production",
1962+
"--excluded-target-tag", "Role/Database",
19571963
"--deployment-freeze-name", "freeze 1",
19581964
"--deployment-freeze-override-reason", "Testing",
19591965
"--variable", "Approver:John", "--variable", "Signoff:Jane",
@@ -1979,15 +1985,17 @@ func TestDeployCreate_AutomationMode(t *testing.T) {
19791985
Tenants: []string{"Coke", "Pepsi"},
19801986
TenantTags: []string{"Region/us-east"},
19811987
CreateExecutionAbstractCommandV1: deployments.CreateExecutionAbstractCommandV1{
1982-
SpaceID: "Spaces-1",
1983-
ProjectIDOrName: fireProject.Name,
1984-
ForcePackageDownload: true,
1985-
SpecificMachineNames: []string{"firstMachine", "secondMachine"},
1986-
ExcludedMachineNames: []string{"thirdMachine"},
1987-
SkipStepNames: []string{"Install", "Cleanup"},
1988-
UseGuidedFailure: &trueVal,
1989-
RunAt: "2022-09-10 13:32:03 +10:00",
1990-
NoRunAfter: "2022-09-10 13:37:03 +10:00",
1988+
SpaceID: "Spaces-1",
1989+
ProjectIDOrName: fireProject.Name,
1990+
ForcePackageDownload: true,
1991+
SpecificMachineNames: []string{"firstMachine", "secondMachine"},
1992+
ExcludedMachineNames: []string{"thirdMachine"},
1993+
SpecificTargetTagNames: []string{"Role/WebServer", "Environment/Production"},
1994+
ExcludedTargetTagNames: []string{"Role/Database"},
1995+
SkipStepNames: []string{"Install", "Cleanup"},
1996+
UseGuidedFailure: &trueVal,
1997+
RunAt: "2022-09-10 13:32:03 +10:00",
1998+
NoRunAfter: "2022-09-10 13:37:03 +10:00",
19911999
Variables: map[string]string{
19922000
"Approver": "John",
19932001
"Signoff": "Jane",

pkg/executor/release.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ type TaskOptionsDeployRelease struct {
104104
ForcePackageDownload bool
105105
DeploymentTargets []string
106106
ExcludeTargets []string
107+
SpecificTargetTagNames []string
108+
ExcludedTargetTagNames []string
107109
Variables map[string]string
108110
UpdateVariables bool
109111
DeploymentFreezeNames []string
@@ -153,6 +155,8 @@ func releaseDeploy(octopus *client.Client, space *spaces.Space, input any) error
153155
ForcePackageDownload: params.ForcePackageDownload,
154156
SpecificMachineNames: params.DeploymentTargets,
155157
ExcludedMachineNames: params.ExcludeTargets,
158+
SpecificTargetTagNames: params.SpecificTargetTagNames,
159+
ExcludedTargetTagNames: params.ExcludedTargetTagNames,
156160
SkipStepNames: params.ExcludedSteps,
157161
RunAt: params.ScheduledStartTime,
158162
NoRunAfter: params.ScheduledExpiryTime,

0 commit comments

Comments
 (0)