Skip to content

Commit 6227b3f

Browse files
committed
add include Flags option to match export CLI
1 parent 00cf697 commit 6227b3f

File tree

2 files changed

+204
-10
lines changed

2 files changed

+204
-10
lines changed

rd-cli-tool/src/main/java/org/rundeck/client/tool/commands/projects/Archives.java

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,54 @@ public static class ArchiveImportOpts extends BaseOptions{
122122
description = "Set options for enabled components, in the form name.key=value")
123123
Map<String, String> componentOptions;
124124

125+
@CommandLine.Option(
126+
names = {"--include", "-i"},
127+
description =
128+
"List of archive contents to import. [executions,config,acl,scm,webhooks,nodeSources]. Default: " +
129+
"executions. (webhooks: requires API v34. nodeSources: requires API v38).")
130+
Set<ImportFlags> includeFlags;
131+
132+
boolean isIncludeFlags() {
133+
return includeFlags != null && !includeFlags.isEmpty();
134+
}
135+
136+
Set<ImportFlags> calculateFlags(){
137+
if(isIncludeFlags()){
138+
return includeFlags;
139+
}
140+
Set<ImportFlags> importFlags = new HashSet<>();
141+
//determine via boolean options
142+
if(!isNoExecutions()){
143+
importFlags.add(ImportFlags.executions);
144+
}
145+
if(isIncludeConfig()){
146+
importFlags.add(ImportFlags.config);
147+
}
148+
if(isIncludeAcl()){
149+
importFlags.add(ImportFlags.acl);
150+
}
151+
if(isIncludeScm()){
152+
importFlags.add(ImportFlags.scm);
153+
}
154+
if(isIncludeWebhooks()){
155+
importFlags.add(ImportFlags.webhooks);
156+
}
157+
if(isIncludeNodeSources()){
158+
importFlags.add(ImportFlags.nodeSources);
159+
}
160+
161+
return importFlags;
162+
}
163+
164+
}
165+
166+
enum ImportFlags {
167+
executions,
168+
config,
169+
acl,
170+
scm,
171+
webhooks,
172+
nodeSources,
125173
}
126174

127175
@CommandLine.Command(description = "Get the status of an ongoing asynchronous import process.", name = "async-import-status")
@@ -142,13 +190,14 @@ public int importArchive(@CommandLine.Mixin ArchiveImportOpts opts) throws Input
142190
if (!input.canRead() || !input.isFile()) {
143191
throw new InputError(String.format("File is not readable or does not exist: %s", input));
144192
}
145-
if ((opts.isIncludeWebhooks() || opts.isWhkRegenAuthTokens()) && getRdTool().getClient().getApiVersion() < 34) {
193+
Set<ImportFlags> importFlags = opts.calculateFlags();
194+
if ((importFlags.contains(ImportFlags.webhooks) || opts.isWhkRegenAuthTokens()) && getRdTool().getClient().getApiVersion() < 34) {
146195
throw new InputError(String.format("Cannot use --include-webhooks or --regenerate-tokens with API < 34 (currently: %s)", getRdTool().getClient().getApiVersion()));
147196
}
148-
if ((opts.isIncludeWebhooks() || opts.isWhkRegenUuid()) && getRdTool().getClient().getApiVersion() < 47) {
149-
throw new InputError(String.format("Cannot use --include-webhooks or --remove-webhooks-uuids with API < 47 (currently: %s)", getRdTool().getClient().getApiVersion()));
197+
if ((importFlags.contains(ImportFlags.webhooks) && opts.isWhkRegenUuid()) && getRdTool().getClient().getApiVersion() < 47) {
198+
throw new InputError(String.format("Cannot use --include-webhooks with --remove-webhooks-uuids with API < 47 (currently: %s)", getRdTool().getClient().getApiVersion()));
150199
}
151-
if ((opts.isIncludeNodeSources()) && getRdTool().getClient().getApiVersion() < 38) {
200+
if ((importFlags.contains(ImportFlags.nodeSources)) && getRdTool().getClient().getApiVersion() < 38) {
152201
throw new InputError(String.format("Cannot use --include-node-sources with API < 38 (currently: %s)", getRdTool().getClient().getApiVersion()));
153202
}
154203
RequestBody body = RequestBody.create(input, Client.MEDIA_TYPE_ZIP);
@@ -168,14 +217,14 @@ public int importArchive(@CommandLine.Mixin ArchiveImportOpts opts) throws Input
168217
ProjectImportStatus status = apiCall(api -> api.importProjectArchive(
169218
project,
170219
opts.isRemove() ? "remove" : "preserve",
171-
!opts.isNoExecutions(),
172-
opts.isIncludeConfig(),
173-
opts.isIncludeAcl(),
174-
opts.isIncludeScm(),
175-
opts.isIncludeWebhooks(),
220+
importFlags.contains(ImportFlags.executions),
221+
importFlags.contains(ImportFlags.config),
222+
importFlags.contains(ImportFlags.acl),
223+
importFlags.contains(ImportFlags.scm),
224+
importFlags.contains(ImportFlags.webhooks),
176225
opts.isWhkRegenAuthTokens(),
177226
opts.isWhkRegenUuid(),
178-
opts.isIncludeNodeSources(),
227+
importFlags.contains(ImportFlags.nodeSources),
179228
opts.isAsyncImportEnabled(),
180229
extraCompOpts,
181230
body

rd-cli-tool/src/test/groovy/org/rundeck/client/tool/commands/projects/ArchivesSpec.groovy

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,151 @@ class ArchivesSpec extends Specification {
8282
0 * api._(*_)
8383
result == 0
8484
}
85+
def "import include via direct flags"() {
86+
87+
def api = Mock(RundeckApi)
88+
89+
def retrofit = new Retrofit.Builder()
90+
.addConverterFactory(JacksonConverterFactory.create())
91+
.baseUrl('http://example.com/fake/').build()
92+
def out = Mock(CommandOutput)
93+
def client = new Client(api, retrofit, null, null, 38, true, null)
94+
95+
def rdapp = Mock(RdApp) {
96+
getClient() >> client
97+
getAppConfig() >> Mock(RdClientConfig)
98+
}
99+
def rdTool = new RdToolImpl(rdapp)
100+
101+
def sut = new Archives()
102+
sut.rdOutput = out
103+
sut.rdTool = rdTool
104+
def opts = new Archives.ArchiveImportOpts()
105+
opts.components = ['test-comp'].toSet()
106+
opts.componentOptions = ['test-comp.key': 'value']
107+
opts.file = tempFile
108+
opts.project = 'Aproj'
109+
110+
opts.noExecutions = !execs
111+
opts.includeConfig = configs
112+
opts.includeAcl = acls
113+
opts.includeScm = scm
114+
opts.includeWebhooks = webhooks
115+
opts.includeNodeSources = nodes
116+
117+
118+
when:
119+
def result = sut.importArchive(opts)
120+
121+
then:
122+
1 * api.importProjectArchive(
123+
'Aproj',
124+
_,
125+
execs,
126+
configs,
127+
acls,
128+
scm,
129+
webhooks,
130+
_,
131+
_,
132+
nodes,
133+
_,
134+
_,
135+
_
136+
) >> Calls.response(new ProjectImportStatus(successful: true))
137+
0 * api._(*_)
138+
result == 0
139+
where:
140+
execs | configs | acls | scm | webhooks | nodes
141+
false | false | false | false | false | false
142+
false | false | false | false | false | true
143+
false | false | false | false | true | false
144+
false | false | false | true | false | false
145+
false | false | true | false | false | false
146+
false | true | false | false | false | false
147+
true | false | false | false | false | false
148+
true | true | true | true | true | true
149+
}
150+
151+
def "import include via include includeFlags option"() {
152+
153+
def api = Mock(RundeckApi)
154+
155+
def retrofit = new Retrofit.Builder()
156+
.addConverterFactory(JacksonConverterFactory.create())
157+
.baseUrl('http://example.com/fake/').build()
158+
def out = Mock(CommandOutput)
159+
def client = new Client(api, retrofit, null, null, 38, true, null)
160+
161+
def rdapp = Mock(RdApp) {
162+
getClient() >> client
163+
getAppConfig() >> Mock(RdClientConfig)
164+
}
165+
def rdTool = new RdToolImpl(rdapp)
166+
167+
def sut = new Archives()
168+
sut.rdOutput = out
169+
sut.rdTool = rdTool
170+
def opts = new Archives.ArchiveImportOpts()
171+
opts.components = ['test-comp'].toSet()
172+
opts.componentOptions = ['test-comp.key': 'value']
173+
opts.file = tempFile
174+
opts.project = 'Aproj'
175+
176+
Set<Archives.ImportFlags> importFlags = new HashSet<>()
177+
if (execs) {
178+
importFlags.add(Archives.ImportFlags.executions)
179+
}
180+
if (configs) {
181+
importFlags.add(Archives.ImportFlags.config)
182+
}
183+
if (acls) {
184+
importFlags.add(Archives.ImportFlags.acl)
185+
}
186+
if (scm) {
187+
importFlags.add(Archives.ImportFlags.scm)
188+
}
189+
if (webhooks) {
190+
importFlags.add(Archives.ImportFlags.webhooks)
191+
}
192+
if (nodes) {
193+
importFlags.add(Archives.ImportFlags.nodeSources)
194+
}
195+
opts.setIncludeFlags(importFlags)
196+
197+
198+
when:
199+
def result = sut.importArchive(opts)
200+
201+
then:
202+
1 * api.importProjectArchive(
203+
'Aproj',
204+
_,
205+
expectExecs,
206+
configs,
207+
acls,
208+
scm,
209+
webhooks,
210+
_,
211+
_,
212+
nodes,
213+
_,
214+
_,
215+
_
216+
) >> Calls.response(new ProjectImportStatus(successful: true))
217+
0 * api._(*_)
218+
result == 0
219+
where: "include flags determine request params, lack of any params still includes executions"
220+
execs | expectExecs | configs | acls | scm | webhooks | nodes
221+
false | true | false | false | false | false | false
222+
false | false | false | false | false | false | true
223+
false | false | false | false | false | true | false
224+
false | false | false | false | true | false | false
225+
false | false | false | true | false | false | false
226+
false | false | true | false | false | false | false
227+
true | true | false | false | false | false | false
228+
true | true | true | true | true | true | true
229+
}
85230

86231
def "successful with async import enabled"() {
87232

0 commit comments

Comments
 (0)