Skip to content

Commit 0bbcde4

Browse files
committed
Add CLI Stacktrace & purge endpoint
1 parent ce3eb73 commit 0bbcde4

File tree

11 files changed

+193
-49
lines changed

11 files changed

+193
-49
lines changed

src/main/java/io/simplelocalize/cli/SimplelocalizeCliCommand.java

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public class SimplelocalizeCliCommand implements Runnable
4343
@Option(names = {"--debug"}, description = "Debug mode", defaultValue = "false")
4444
boolean debug;
4545

46+
private Configuration configuration;
47+
4648
public static void main(String[] args)
4749
{
4850
int exitCode = new CommandLine(new SimplelocalizeCliCommand()).execute(args);
@@ -85,13 +87,13 @@ public void extract(
8587
}
8688
ConfigurationValidator configurationValidator = new ConfigurationValidator();
8789
configurationValidator.validateExtractConfiguration(configuration);
90+
this.configuration = configuration;
8891
SimpleLocalizeClient client = SimpleLocalizeClient.create(configuration.getBaseUrl(), configuration.getApiKey());
8992
ExtractCommand extractCommand = new ExtractCommand(client, configuration);
9093
extractCommand.invoke();
9194
} catch (Exception e)
9295
{
93-
printDebug(e);
94-
System.exit(CommandLine.ExitCode.USAGE);
96+
handleException(e);
9597
}
9698
}
9799

@@ -196,14 +198,13 @@ public void upload(
196198

197199
ConfigurationValidator configurationValidator = new ConfigurationValidator();
198200
configurationValidator.validateUploadConfiguration(configuration);
199-
201+
this.configuration = configuration;
200202
SimpleLocalizeClient client = SimpleLocalizeClient.create(configuration.getBaseUrl(), configuration.getApiKey());
201203
UploadCommand uploadCommand = new UploadCommand(client, configuration);
202204
uploadCommand.invoke();
203205
} catch (Exception e)
204206
{
205-
printDebug(e);
206-
System.exit(CommandLine.ExitCode.USAGE);
207+
handleException(e);
207208
}
208209
}
209210

@@ -264,13 +265,13 @@ public void download(
264265

265266
ConfigurationValidator configurationValidator = new ConfigurationValidator();
266267
configurationValidator.validateDownloadConfiguration(configuration);
268+
this.configuration = configuration;
267269
SimpleLocalizeClient client = SimpleLocalizeClient.create(configuration.getBaseUrl(), configuration.getApiKey());
268270
DownloadCommand downloadCommand = new DownloadCommand(client, configuration);
269271
downloadCommand.invoke();
270272
} catch (Exception e)
271273
{
272-
printDebug(e);
273-
System.exit(CommandLine.ExitCode.USAGE);
274+
handleException(e);
274275
}
275276
}
276277

@@ -316,13 +317,13 @@ public void pull(
316317

317318
ConfigurationValidator configurationValidator = new ConfigurationValidator();
318319
configurationValidator.validateHostingPullConfiguration(configuration);
320+
this.configuration = configuration;
319321
SimpleLocalizeClient client = SimpleLocalizeClient.create(configuration.getBaseUrl(), configuration.getApiKey());
320322
PullHostingCommand command = new PullHostingCommand(client, configuration);
321323
command.invoke();
322324
} catch (Exception e)
323325
{
324-
printDebug(e);
325-
System.exit(CommandLine.ExitCode.USAGE);
326+
handleException(e);
326327
}
327328
}
328329

@@ -358,13 +359,13 @@ public void startAutoTranslation(
358359

359360
ConfigurationValidator configurationValidator = new ConfigurationValidator();
360361
configurationValidator.validateAutoTranslationConfiguration(configuration);
362+
this.configuration = configuration;
361363
SimpleLocalizeClient client = SimpleLocalizeClient.create(configuration.getBaseUrl(), configuration.getApiKey());
362364
AutoTranslationCommand command = new AutoTranslationCommand(client, configuration);
363365
command.invoke();
364366
} catch (Exception e)
365367
{
366-
printDebug(e);
367-
System.exit(CommandLine.ExitCode.USAGE);
368+
handleException(e);
368369
}
369370
}
370371

@@ -379,8 +380,7 @@ public void init()
379380
initCommand.invoke();
380381
} catch (Exception e)
381382
{
382-
printDebug(e);
383-
System.exit(CommandLine.ExitCode.USAGE);
383+
handleException(e);
384384
}
385385
}
386386

@@ -408,13 +408,13 @@ public void status(
408408

409409
ConfigurationValidator configurationValidator = new ConfigurationValidator();
410410
configurationValidator.validateGetStatusConfiguration(configuration);
411+
this.configuration = configuration;
411412
SimpleLocalizeClient client = SimpleLocalizeClient.create(configuration.getBaseUrl(), configuration.getApiKey());
412413
StatusCommand command = new StatusCommand(client);
413414
command.invoke();
414415
} catch (Exception e)
415416
{
416-
printDebug(e);
417-
System.exit(CommandLine.ExitCode.USAGE);
417+
handleException(e);
418418
}
419419
}
420420

@@ -447,13 +447,13 @@ public void publish(
447447

448448
ConfigurationValidator configurationValidator = new ConfigurationValidator();
449449
configurationValidator.validateHostingPublishConfiguration(configuration);
450+
this.configuration = configuration;
450451
SimpleLocalizeClient client = SimpleLocalizeClient.create(configuration.getBaseUrl(), configuration.getApiKey());
451452
PublishHostingCommand command = new PublishHostingCommand(client, configuration);
452453
command.invoke();
453454
} catch (Exception e)
454455
{
455-
printDebug(e);
456-
System.exit(CommandLine.ExitCode.USAGE);
456+
handleException(e);
457457
}
458458
}
459459

@@ -482,24 +482,32 @@ public void purge(
482482

483483
ConfigurationValidator configurationValidator = new ConfigurationValidator();
484484
configurationValidator.validateGetPurgeConfiguration(configuration);
485+
this.configuration = configuration;
485486
SimpleLocalizeClient client = SimpleLocalizeClient.create(configuration.getBaseUrl(), configuration.getApiKey());
486487
PurgeCommand command = new PurgeCommand(client, force);
487488
command.invoke();
488489
} catch (Exception e)
489490
{
490-
printDebug(e);
491-
System.exit(CommandLine.ExitCode.USAGE);
491+
handleException(e);
492492
}
493493
}
494494

495-
private void printDebug(Exception e)
495+
private void handleException(Exception e)
496+
{
497+
log.error("Command failed.", e);
498+
trySendException(e);
499+
System.exit(CommandLine.ExitCode.USAGE);
500+
}
501+
502+
private void trySendException(Exception exception)
496503
{
497-
if (debug)
504+
try
498505
{
499-
log.error("Command failed.", e);
500-
} else
506+
SimpleLocalizeClient client = SimpleLocalizeClient.create(configuration.getBaseUrl(), configuration.getApiKey());
507+
client.sendException(configuration, exception);
508+
} catch (Exception ex)
501509
{
502-
log.error("Command failed. Use '--debug' parameter before the command name to see stacktrace.");
510+
log.error("Unable to send exception to SimpleLocalize, please contact us at [email protected]", ex);
503511
}
504512
}
505513

src/main/java/io/simplelocalize/cli/client/ClientBodyBuilders.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,20 @@
11
package io.simplelocalize.cli.client;
22

33
import com.fasterxml.jackson.core.JsonProcessingException;
4-
import com.fasterxml.jackson.databind.ObjectMapper;
5-
import io.simplelocalize.cli.client.dto.proxy.ImportForm;
6-
import io.simplelocalize.cli.client.dto.proxy.ImportKey;
7-
import io.simplelocalize.cli.client.dto.proxy.StartAutoTranslationRequest;
4+
import io.simplelocalize.cli.client.dto.proxy.*;
5+
import io.simplelocalize.cli.util.StackTraceUtils;
86

97
import java.io.IOException;
108
import java.net.http.HttpRequest;
119
import java.nio.charset.StandardCharsets;
1210
import java.nio.file.Files;
1311
import java.nio.file.Path;
14-
import java.util.ArrayList;
15-
import java.util.Collection;
16-
import java.util.Map;
17-
import java.util.Set;
12+
import java.util.*;
1813
import java.util.stream.Collectors;
1914

2015
final class ClientBodyBuilders
2116
{
2217

23-
private static final ObjectMapper objectMapper = new ObjectMapper();
2418

2519
private ClientBodyBuilders()
2620
{
@@ -35,14 +29,24 @@ static HttpRequest.BodyPublisher ofKeysBody(Collection<String> keys) throws Json
3529

3630
ImportForm importForm = new ImportForm(importContent);
3731

38-
String jsonString = objectMapper.writeValueAsString(importForm);
32+
String jsonString = ObjectMapperSingleton.getInstance().writeValueAsString(importForm);
3933
return HttpRequest.BodyPublishers.ofString(jsonString);
4034
}
4135

4236
static HttpRequest.BodyPublisher ofStartAutoTranslation(Collection<String> languageKeys) throws JsonProcessingException
4337
{
4438
StartAutoTranslationRequest request = new StartAutoTranslationRequest(languageKeys, "CLI");
45-
String jsonString = objectMapper.writeValueAsString(request);
39+
String jsonString = ObjectMapperSingleton.getInstance().writeValueAsString(request);
40+
return HttpRequest.BodyPublishers.ofString(jsonString);
41+
}
42+
43+
static HttpRequest.BodyPublisher ofException(Configuration configuration, Exception exception) throws JsonProcessingException
44+
{
45+
String configurationString = Optional.ofNullable(configuration).map(Configuration::toString).orElse("");
46+
String message = Optional.ofNullable(exception).map(Throwable::getMessage).orElse("");
47+
String stackTrace = StackTraceUtils.getStackTrace(exception);
48+
ExceptionRequest request = new ExceptionRequest(configurationString, message, stackTrace);
49+
String jsonString = ObjectMapperSingleton.getInstance().writeValueAsString(request);
4650
return HttpRequest.BodyPublishers.ofString(jsonString);
4751
}
4852

@@ -54,9 +58,8 @@ static HttpRequest.BodyPublisher ofMimeMultipartData(Map<Object, Object> data, S
5458
{
5559
byteArrays.add(separator);
5660

57-
if (entry.getValue() instanceof Path)
61+
if (entry.getValue() instanceof Path path)
5862
{
59-
var path = (Path) entry.getValue();
6063
String mimeType = Files.probeContentType(path);
6164
byteArrays.add(("\"" + entry.getKey() + "\"; filename=\"" + path.getFileName() + "\"\r\nContent-Type: " + mimeType + "\r\n\r\n").getBytes(StandardCharsets.UTF_8));
6265
byteArrays.add(Files.readAllBytes(path));
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.simplelocalize.cli.client;
2+
3+
import com.fasterxml.jackson.databind.DeserializationFeature;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
6+
public class ObjectMapperSingleton
7+
{
8+
9+
private static ObjectMapper INSTANCE = null;
10+
11+
private ObjectMapperSingleton()
12+
{
13+
}
14+
15+
public static synchronized ObjectMapper getInstance()
16+
{
17+
if (INSTANCE == null)
18+
{
19+
INSTANCE = new ObjectMapper();
20+
INSTANCE.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
21+
return INSTANCE;
22+
}
23+
return INSTANCE;
24+
}
25+
}

src/main/java/io/simplelocalize/cli/client/SimpleLocalizeClient.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.jayway.jsonpath.Option;
66
import io.simplelocalize.cli.client.dto.DownloadRequest;
77
import io.simplelocalize.cli.client.dto.UploadRequest;
8+
import io.simplelocalize.cli.client.dto.proxy.Configuration;
89
import io.simplelocalize.cli.client.dto.proxy.DownloadableFile;
910
import io.simplelocalize.cli.client.dto.proxy.ExportResponse;
1011
import io.simplelocalize.cli.exception.ApiRequestException;
@@ -45,7 +46,7 @@ public SimpleLocalizeClient(String baseUrl, String apiKey)
4546
Objects.requireNonNull(apiKey);
4647
this.uriFactory = new SimpleLocalizeUriFactory(baseUrl);
4748
this.httpRequestFactory = new SimpleLocalizeHttpRequestFactory(apiKey);
48-
this.objectMapper = new ObjectMapper();
49+
this.objectMapper = ObjectMapperSingleton.getInstance();
4950
this.httpClient = HttpClientFactory.createHttpClient();
5051
}
5152

@@ -151,6 +152,14 @@ public void purgeTranslations() throws IOException, InterruptedException
151152
}
152153

153154

155+
public void sendException(Configuration configuration, Exception exception) throws IOException, InterruptedException
156+
{
157+
URI uri = uriFactory.buildStacktraceUri();
158+
HttpRequest httpRequest = httpRequestFactory.createBaseRequest(uri).POST(ClientBodyBuilders.ofException(configuration, exception)).build();
159+
HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
160+
throwOnError(httpResponse);
161+
}
162+
154163
private void throwOnError(HttpResponse<?> httpResponse)
155164
{
156165
if (httpResponse.statusCode() != 200)

src/main/java/io/simplelocalize/cli/client/SimpleLocalizeUriFactory.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ URI buildUploadUri(UploadRequest uploadRequest)
8585

8686
URI buildGetProjectUri()
8787
{
88-
return URI.create(baseUrl + "/api/v1/project");
88+
return URI.create(baseUrl + "/api/v2/project");
8989
}
9090

9191
public URI buildPublishUri(String environment)
@@ -98,6 +98,11 @@ public URI buildPurgeTranslations()
9898
return URI.create(baseUrl + "/api/v1/translations/purge?source=CLI");
9999
}
100100

101+
public URI buildStacktraceUri()
102+
{
103+
return URI.create(baseUrl + "/cli/v1/stacktrace");
104+
}
105+
101106
URI buildGetRunningAutoTranslationJobsUri()
102107
{
103108
return URI.create(baseUrl + "/api/v2/jobs?status=RUNNING&type=AUTO_TRANSLATION");

src/main/java/io/simplelocalize/cli/client/dto/proxy/Configuration.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import java.util.ArrayList;
77
import java.util.List;
8+
import java.util.StringJoiner;
89

910
@NativeProxy
1011
public class Configuration
@@ -275,4 +276,34 @@ public Configuration setDownloadSort(String downloadSort)
275276
this.downloadSort = downloadSort;
276277
return this;
277278
}
279+
280+
@Override
281+
public String toString()
282+
{
283+
return new StringJoiner(", ", Configuration.class.getSimpleName() + "[", "]")
284+
.add("baseUrl='" + baseUrl + "'")
285+
.add("apiKey='***'")
286+
.add("projectType='" + projectType + "'")
287+
.add("searchDir='" + searchDir + "'")
288+
.add("ignoreKeys=" + ignoreKeys)
289+
.add("uploadPath='" + uploadPath + "'")
290+
.add("uploadFormat='" + uploadFormat + "'")
291+
.add("uploadOptions=" + uploadOptions)
292+
.add("uploadFilesExclude=" + uploadFilesExclude)
293+
.add("uploadFilesInclude=" + uploadFilesInclude)
294+
.add("dryRun=" + dryRun)
295+
.add("downloadPath='" + downloadPath + "'")
296+
.add("downloadFormat='" + downloadFormat + "'")
297+
.add("downloadSort='" + downloadSort + "'")
298+
.add("downloadOptions=" + downloadOptions)
299+
.add("downloadFilesExclude=" + downloadFilesExclude)
300+
.add("downloadFilesInclude=" + downloadFilesInclude)
301+
.add("customerId='" + customerId + "'")
302+
.add("languageKey='" + languageKey + "'")
303+
.add("autoTranslation=" + autoTranslation)
304+
.add("environment='" + environment + "'")
305+
.add("pullPath='" + pullPath + "'")
306+
.add("filterRegex='" + filterRegex + "'")
307+
.toString();
308+
}
278309
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.simplelocalize.cli.client.dto.proxy;
2+
3+
4+
import io.simplelocalize.cli.NativeProxy;
5+
6+
@NativeProxy
7+
public record ExceptionRequest(String configuration, String message, String stacktrace)
8+
{
9+
}

0 commit comments

Comments
 (0)