Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUN-1348: Add component options to project archives import #482

Merged
merged 1 commit into from
Dec 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,29 @@ Call<ResponseBody> exportProjectDownload(
);

/**
* Export project archive (&lt;=v18)
* Import project archive (&lt;=v18)
*
* @param project project
*
* @return archive response
*/
@Headers("Accept: application/json")
@PUT("project/{project}/import")
Call<ProjectImportStatus> importProjectArchive(
@Path("project") String project,
@Query("jobUuidOption") String jobUuidOption,
@Query("importExecutions") Boolean importExecutions,
@Query("importConfig") Boolean importConfig,
@Query("importACL") Boolean importACL,
@Query("importScm") Boolean importScm,
@Query("importWebhooks") Boolean importWebhooks,
@Query("whkRegenAuthTokens") Boolean whkRegenAuthTokens,
@Query("importNodesSources") Boolean importNodesSources,
@Body RequestBody body
);

/**
* Import project archive (&lt;=v18)
*
* @param project project
*
Expand All @@ -406,6 +428,7 @@ Call<ProjectImportStatus> importProjectArchive(
@Query("importWebhooks") Boolean importWebhooks,
@Query("whkRegenAuthTokens") Boolean whkRegenAuthTokens,
@Query("importNodesSources") Boolean importNodesSources,
@QueryMap Map<String,String> params,
@Body RequestBody body
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.function.BooleanSupplier;

/**
Expand All @@ -51,7 +49,7 @@
public class Archives extends BaseCommand {

@Getter @Setter static class BaseOptions extends ProjectRequiredNameOptions{
@CommandLine.Option(names = {"-f", "--file"}, description = "Output file path", required = true)
@CommandLine.Option(names = {"-f", "--file"}, description = "Output/Import file path", required = true)
@Getter
private File file;
}
Expand Down Expand Up @@ -100,6 +98,19 @@ static class ArchiveImportOpts extends BaseOptions{
"import errors are treated as failures.")
boolean strict;


@CommandLine.Option(
names = {"--component", "-I"},
arity = "0..*",
description = "Enable named import components, such as project-tours (enterprise)")
Set<String> components;

@CommandLine.Option(
names = {"--options", "-O"},
arity = "0..*",
description = "Set options for enabled components, in the form name.key=value")
Map<String, String> componentOptions;

}

@CommandLine.Command(description = "Import a project archive", name = "import")
Expand All @@ -116,6 +127,17 @@ public boolean importArchive(@CommandLine.Mixin ArchiveImportOpts opts) throws I
}
RequestBody body = RequestBody.create(input, Client.MEDIA_TYPE_ZIP);

Map<String, String> extraCompOpts = new HashMap<>();
if (opts.components != null && opts.components.size() > 0) {
for (String component : opts.components) {
extraCompOpts.put("importComponents." + component, "true");
}
}
if (opts.componentOptions != null && opts.componentOptions.size() > 0) {
for (Map.Entry<String, String> stringStringEntry : opts.componentOptions.entrySet()) {
extraCompOpts.put("importOpts." + stringStringEntry.getKey(), stringStringEntry.getValue());
}
}
String project = validate(opts);
ProjectImportStatus status = apiCall(api -> api.importProjectArchive(
project,
Expand All @@ -127,6 +149,7 @@ public boolean importArchive(@CommandLine.Mixin ArchiveImportOpts opts) throws I
opts.isIncludeWebhooks(),
opts.isWhkRegenAuthTokens(),
opts.isIncludeNodeSources(),
extraCompOpts,
body
));
boolean anyerror = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.rundeck.client.tool.commands.projects

import groovy.transform.CompileStatic
import okhttp3.ResponseBody
import org.rundeck.client.api.RundeckApi
import org.rundeck.client.api.model.ProjectImportStatus
import org.rundeck.client.tool.CommandOutput
import org.rundeck.client.tool.RdApp
import org.rundeck.client.tool.commands.RdToolImpl
import org.rundeck.client.tool.options.ProjectRequiredNameOptions
import org.rundeck.client.util.Client
import org.rundeck.client.util.RdClientConfig
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.jackson.JacksonConverterFactory
import retrofit2.mock.Calls
import spock.lang.Specification

class ArchivesSpec extends Specification {
File tempFile

def setup() {
tempFile = File.createTempFile('ArchivesSpec-test', 'zip')
}

def cleanup() {
if (tempFile.exists()) {
tempFile.delete()
}
}

def "import component options set in url"() {

def api = Mock(RundeckApi)

def retrofit = new Retrofit.Builder()
.addConverterFactory(JacksonConverterFactory.create())
.baseUrl('http://example.com/fake/').build()
def out = Mock(CommandOutput)
def client = new Client(api, retrofit, null, null, 18, true, null)

def rdapp = Mock(RdApp) {
getClient() >> client
getAppConfig() >> Mock(RdClientConfig)
}
def rdTool = new RdToolImpl(rdapp)

def sut = new Archives()
sut.rdOutput = out
sut.rdTool = rdTool
def opts = new Archives.ArchiveImportOpts()
opts.components = ['test-comp'].toSet()
opts.componentOptions = ['test-comp.key': 'value']
opts.file = tempFile
opts.project = 'Aproj'


when:
def result = sut.importArchive(opts)

then:
1 * api.importProjectArchive(
'Aproj',
_,
_,
_,
_,
_,
_,
_,
_,
[
'importComponents.test-comp': 'true',
'importOpts.test-comp.key' : 'value',
],
_
) >> Calls.response(new ProjectImportStatus())
0 * api._(*_)
}
}