Skip to content

Commit 355adaa

Browse files
Adds a backup command to help teams transition from the cloud service to self-hosted.
1 parent 32a47d5 commit 355adaa

File tree

3 files changed

+126
-1
lines changed

3 files changed

+126
-1
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
structurizrVersion=5.0.1
1+
structurizrVersion=5.0.2
22
version=1.0.0
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package com.structurizr.cli;
2+
3+
import com.structurizr.api.AdminApiClient;
4+
import com.structurizr.api.WorkspaceApiClient;
5+
import com.structurizr.api.WorkspaceMetadata;
6+
import com.structurizr.util.StringUtils;
7+
import org.apache.commons.cli.*;
8+
import org.apache.commons.logging.Log;
9+
import org.apache.commons.logging.LogFactory;
10+
11+
import java.io.File;
12+
import java.io.FileWriter;
13+
import java.nio.file.Files;
14+
import java.util.List;
15+
import java.util.Properties;
16+
17+
class BackupCommand extends AbstractCommand {
18+
19+
private static final Log log = LogFactory.getLog(BackupCommand.class);
20+
21+
BackupCommand() {
22+
}
23+
24+
public void run(String... args) throws Exception {
25+
Options options = new Options();
26+
27+
Option option = new Option("url", "structurizrApiUrl", true, "Structurizr API URL (default: https://api.structurizr.com)");
28+
option.setRequired(false);
29+
options.addOption(option);
30+
31+
option = new Option("key", "apiKey", true, "API key");
32+
option.setRequired(true);
33+
options.addOption(option);
34+
35+
option = new Option("user", "username", true, "Username (only required for cloud service)");
36+
option.setRequired(false);
37+
options.addOption(option);
38+
39+
option = new Option("o", "output", true, "Path to an output directory");
40+
option.setRequired(false);
41+
options.addOption(option);
42+
43+
option = new Option("debug", "debug", false, "Enable debug logging");
44+
option.setRequired(false);
45+
options.addOption(option);
46+
47+
CommandLineParser commandLineParser = new DefaultParser();
48+
HelpFormatter formatter = new HelpFormatter();
49+
50+
String apiUrl = "";
51+
String username = "";
52+
String apiKey = "";
53+
boolean debug = false;
54+
String outputPath = null;
55+
56+
try {
57+
CommandLine cmd = commandLineParser.parse(options, args);
58+
59+
apiUrl = cmd.getOptionValue("structurizrApiUrl", "https://api.structurizr.com");
60+
apiKey = cmd.getOptionValue("apiKey");
61+
username = cmd.getOptionValue("username");
62+
outputPath = cmd.getOptionValue("output");
63+
debug = cmd.hasOption("debug");
64+
} catch (ParseException e) {
65+
log.error(e.getMessage());
66+
formatter.printHelp("backup", options);
67+
68+
System.exit(1);
69+
}
70+
71+
if (debug) {
72+
configureDebugLogging();
73+
}
74+
75+
File outputDir = new File(outputPath);
76+
if (outputDir.exists()) {
77+
throw new RuntimeException("Output directory already exists: " + outputDir.getAbsolutePath());
78+
}
79+
80+
AdminApiClient adminApiClient = new AdminApiClient(apiUrl, username, apiKey);
81+
List<WorkspaceMetadata> workspaces = adminApiClient.getWorkspaces();
82+
83+
if (!workspaces.isEmpty()) {
84+
outputDir.mkdirs();
85+
86+
File structurizrPropertiesFile = new File(outputDir, "structurizr.properties");
87+
Files.writeString(structurizrPropertiesFile.toPath(), "structurizr.workspaces=*");
88+
log.info(" - " + structurizrPropertiesFile.getCanonicalPath());
89+
90+
for (WorkspaceMetadata workspaceMetadata : workspaces) {
91+
File workspaceDirectory = new File(outputDir, "" + workspaceMetadata.getId());
92+
workspaceDirectory.mkdirs();
93+
94+
WorkspaceApiClient client = new WorkspaceApiClient(apiUrl, workspaceMetadata.getApiKey(), workspaceMetadata.getApiSecret());
95+
client.setAgent(getAgent());
96+
97+
String json = client.getWorkspaceAsJson(workspaceMetadata.getId());
98+
File workspaceJsonFile = new File(workspaceDirectory, "workspace.json");
99+
Files.writeString(workspaceJsonFile.toPath(), json);
100+
log.info(" - " + workspaceJsonFile.getCanonicalPath());
101+
102+
Properties properties = new Properties();
103+
properties.setProperty("name", workspaceMetadata.getName() != null ? workspaceMetadata.getName() : "");
104+
properties.setProperty("description", workspaceMetadata.getDescription() != null ? workspaceMetadata.getDescription() : "");
105+
properties.setProperty("apiKey", workspaceMetadata.getApiKey());
106+
properties.setProperty("apiSecret", workspaceMetadata.getApiSecret());
107+
properties.setProperty("public", "" + !StringUtils.isNullOrEmpty(workspaceMetadata.getPublicUrl()));
108+
if (!StringUtils.isNullOrEmpty(workspaceMetadata.getShareableUrl())) {
109+
properties.setProperty("sharingToken", workspaceMetadata.getShareableUrl().substring(workspaceMetadata.getShareableUrl().lastIndexOf("/") + 1));
110+
}
111+
properties.setProperty("clientSideEncrypted", "" + (json.contains("\"encryptionStrategy\"") && json.contains("\"ciphertext\"")));
112+
113+
File workspacePropertiesFile = new File(workspaceDirectory, "workspace.properties");
114+
FileWriter fileWriter = new FileWriter(workspacePropertiesFile);
115+
properties.store(fileWriter, null);
116+
fileWriter.flush();
117+
fileWriter.close();
118+
log.info(" - " + workspacePropertiesFile.getCanonicalPath());
119+
}
120+
}
121+
}
122+
123+
}

src/main/java/com/structurizr/cli/StructurizrCliApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class StructurizrCliApplication {
1919

2020
private static final String PUSH_COMMAND = "push";
2121
private static final String PULL_COMMAND = "pull";
22+
private static final String BACKUP_COMMAND = "backup";
2223
private static final String LOCK_COMMAND = "lock";
2324
private static final String UNLOCK_COMMAND = "unlock";
2425
private static final String EXPORT_COMMAND = "export";
@@ -60,6 +61,7 @@ public class StructurizrCliApplication {
6061

6162
COMMANDS.put(PUSH_COMMAND, new PushCommand());
6263
COMMANDS.put(PULL_COMMAND, new PullCommand());
64+
COMMANDS.put(BACKUP_COMMAND, new BackupCommand());
6365
COMMANDS.put(LOCK_COMMAND, new LockCommand());
6466
COMMANDS.put(UNLOCK_COMMAND, new UnlockCommand());
6567
COMMANDS.put(EXPORT_COMMAND, new ExportCommand());

0 commit comments

Comments
 (0)