Skip to content

Commit

Permalink
fix: improved error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
yevheniyJ committed Feb 21, 2024
1 parent 5b2768a commit 4482cbd
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 31 deletions.
17 changes: 8 additions & 9 deletions src/main/java/com/crowdin/client/Crowdin.java
Original file line number Diff line number Diff line change
Expand Up @@ -407,17 +407,16 @@ private <T> T executeRequest(Supplier<T> exec) {
try {
return exec.get();
} catch (HttpException e) {
HttpException ex = (HttpException) e;
String code = (ex.getError() != null && ex.getError().getCode() != null) ? ex.getError().getCode() : "<empty_code>";
String message = (ex.getError() != null && ex.getError().getMessage() != null) ? ex.getError().getMessage() : "<empty_message>";
String code = (e.getError() != null && e.getError().getCode() != null) ? e.getError().getCode() : "empty_code";
String message = (e.getError() != null && e.getError().getMessage() != null) ? e.getError().getMessage() : "empty_message";
String errorMessage = ("401".equals(code))
? MESSAGES_BUNDLE.getString("errors.authorize")
: String.format("Error from server: <Code: %s, Message: %s>", code, message);
: String.format("Error from server: Code: %s, Message: %s", code, message);
throw new RuntimeException(errorMessage, e);
} catch (HttpBadRequestException e) {
String errorMessage;
if (e.getErrors() == null) {
errorMessage = "Wrong parameters: <Key: <empty_key>, Code: <empty_code>, Message: <empty_message>";
errorMessage = "Wrong parameters: Key: empty_key, Code: empty_code, Message: empty_message";
} else {
errorMessage = "Wrong parameters: \n" + e.getErrors()
.stream()
Expand All @@ -426,10 +425,10 @@ private <T> T executeRequest(Supplier<T> exec) {
.stream()
.filter(Objects::nonNull)
.map(error ->
String.format("<Key: %s, Code: %s, Message: %s>",
(holder.getKey() != null) ? holder.getKey() : "<empty_key>",
(error.getCode() != null) ? error.getCode() : "<empty_code>",
(error.getMessage() != null) ? error.getMessage() : "<empty_message>")))
String.format("Key: %s, Code: %s, Message: %s",
(holder.getKey() != null) ? holder.getKey() : "empty_key",
(error.getCode() != null) ? error.getCode() : "empty_code",
(error.getMessage() != null) ? error.getMessage() : "empty_message")))
.collect(Collectors.joining("\n"));
}
throw new RuntimeException(errorMessage, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public static Map<String, Object> load(Project project) {
}
try (InputStream in = crowdinPropertyFile.getInputStream()) {
return YAML.load(in);
} catch (ClassCastException e) {
throw new RuntimeException(MESSAGES_BUNDLE.getString("errors.config.has_errors") + "The Yaml file is not in the correct format");
} catch (IOException e) {
throw new RuntimeException(MESSAGES_BUNDLE.getString("errors.config.has_errors") + e.getMessage());
}
Expand Down
112 changes: 91 additions & 21 deletions src/main/java/com/crowdin/client/config/CrowdinPropertiesLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.crowdin.Constants.CONFIG_FILE;
import static com.crowdin.Constants.MESSAGES_BUNDLE;
Expand Down Expand Up @@ -59,7 +60,7 @@ protected static CrowdinConfig load(Map<String, Object> properties, CrowdingSett
try {

Object propProjectId = properties.get(PROJECT_ID);
String propProjectIdEnv = (String) properties.get(PROJECT_ID_ENV);
String propProjectIdEnv = getStringProperty(properties, PROJECT_ID_ENV);

if (propProjectId != null) {
try {
Expand Down Expand Up @@ -88,8 +89,8 @@ protected static CrowdinConfig load(Map<String, Object> properties, CrowdingSett
errors.add(String.format(MESSAGES_BUNDLE.getString("errors.config.missing_property"), PROJECT_ID));
}

String propApiToken = (String) properties.get(API_TOKEN);
String propApiTokenEnv = (String) properties.get(API_TOKEN_ENV);
String propApiToken = getStringProperty(properties, API_TOKEN);
String propApiTokenEnv = getStringProperty(properties, API_TOKEN_ENV);
if (!StringUtils.isEmpty(propApiToken)) {
crowdinProperties.setApiToken(propApiToken);
} else if (!StringUtils.isEmpty(propApiTokenEnv)) {
Expand All @@ -105,8 +106,8 @@ protected static CrowdinConfig load(Map<String, Object> properties, CrowdingSett
errors.add(String.format(MESSAGES_BUNDLE.getString("errors.config.missing_property"), API_TOKEN));
}

String propBaseUrl = (String) properties.get(BASE_URL);
String propBaseUrlEnv = (String) properties.get(BASE_URL_ENV);
String propBaseUrl = getStringProperty(properties, BASE_URL);
String propBaseUrlEnv = getStringProperty(properties, BASE_URL_ENV);
if (!StringUtils.isEmpty(propBaseUrl)) {
if (isBaseUrlValid(propBaseUrl)) {
crowdinProperties.setBaseUrl(propBaseUrl);
Expand Down Expand Up @@ -144,22 +145,22 @@ protected static CrowdinConfig load(Map<String, Object> properties, CrowdingSett
crowdinProperties.setAutocompletionEnabled(settings.enableCompletion);

crowdinProperties.setUseGitBranch(settings.useGitBranch);
Boolean preserveHierarchy = (Boolean) properties.get(PROPERTY_PRESERVE_HIERARCHY);
Boolean preserveHierarchy = getBooleanProperty(properties, PROPERTY_PRESERVE_HIERARCHY);
crowdinProperties.setPreserveHierarchy(preserveHierarchy);
Boolean debug = (Boolean) properties.get(PROPERTY_DEBUG);
Boolean debug = getBooleanProperty(properties, PROPERTY_DEBUG);
crowdinProperties.setDebug(debug);
Boolean importEqSuggestions = (Boolean) properties.get(PROPERTY_IMPORT_EQ_SUGGESTIONS);
Boolean importEqSuggestions = getBooleanProperty(properties, PROPERTY_IMPORT_EQ_SUGGESTIONS);
crowdinProperties.setImportEqSuggestions(importEqSuggestions);
Boolean autoApproveImported = (Boolean) properties.get(PROPERTY_AUTO_APPROVE_IMPORTED);
Boolean autoApproveImported = getBooleanProperty(properties, PROPERTY_AUTO_APPROVE_IMPORTED);
crowdinProperties.setAutoApproveImported(autoApproveImported);
Boolean translateHidden = (Boolean) properties.get(PROPERTY_TRANSLATE_HIDDEN);
Boolean translateHidden = getBooleanProperty(properties, PROPERTY_TRANSLATE_HIDDEN);
crowdinProperties.setTranslateHidden(translateHidden);
String branch = (String) properties.get(PROPERTY_BRANCH);
String branch = getStringProperty(properties, PROPERTY_BRANCH);
crowdinProperties.setBranch(branch);

} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(MESSAGES_BUNDLE.getString("errors.config.has_errors") + e.getMessage());
throw new RuntimeException(MESSAGES_BUNDLE.getString("errors.config.has_errors") + " " + e.getMessage());
}
}

Expand All @@ -173,16 +174,16 @@ protected static CrowdinConfig load(Map<String, Object> properties, CrowdingSett
private static List<FileBean> getSourcesWithTranslations(Map<String, Object> properties, List<String> errors) {
List<FileBean> fileBeans = new ArrayList<>();

List<Map<String, Object>> files = (List<Map<String, Object>>) properties.get(PROPERTY_FILES);
List<Map<String, Object>> files = getListOfObjectsProperty(properties, PROPERTY_FILES);

if (files != null) {
files.forEach(file -> {
String source = (String) file.get(PROPERTY_FILES_SOURCE);
String translation = (String) file.get(PROPERTY_FILES_TRANSLATION);
Boolean updateStrings = (Boolean) file.get(PROPERTY_FILES_UPDATE_STRINGS);
Boolean cleanupMode = (Boolean) file.get(PROPERTY_FILES_CLEANUP_MODE);
List<String> labels = (List<String>) file.get(PROPERTY_LABELS);
List<String> excludedTargetLanguages = (List<String>) file.get(PROPERTY_EXCLUDED_TARGET_LANGUAGES);
String source = getStringProperty(file, PROPERTY_FILES_SOURCE);
String translation = getStringProperty(file, PROPERTY_FILES_TRANSLATION);
Boolean updateStrings = getBooleanProperty(file, PROPERTY_FILES_UPDATE_STRINGS);
Boolean cleanupMode = getBooleanProperty(file, PROPERTY_FILES_CLEANUP_MODE);
List<String> labels = getListStringsProperty(file, PROPERTY_LABELS);
List<String> excludedTargetLanguages = getListStringsProperty(file, PROPERTY_EXCLUDED_TARGET_LANGUAGES);

if (!StringUtils.isEmpty(source) && !StringUtils.isEmpty(translation)) {
FileBean fb = new FileBean();
Expand All @@ -193,9 +194,9 @@ private static List<FileBean> getSourcesWithTranslations(Map<String, Object> pro
fb.setUpdateStrings(updateStrings);
fb.setCleanupMode(cleanupMode);
fileBeans.add(fb);
} else if (StringUtils.isEmpty(translation)) {
errors.add(String.format(MESSAGES_BUNDLE.getString("errors.config.missing_property"), PROPERTY_FILES_SOURCE));
} else if (StringUtils.isEmpty(source)) {
errors.add(String.format(MESSAGES_BUNDLE.getString("errors.config.missing_property"), PROPERTY_FILES_SOURCE));
} else if (StringUtils.isEmpty(translation)) {
errors.add(String.format(MESSAGES_BUNDLE.getString("errors.config.missing_property"), PROPERTY_FILES_TRANSLATION));
}
});
Expand All @@ -204,6 +205,75 @@ private static List<FileBean> getSourcesWithTranslations(Map<String, Object> pro
return fileBeans;
}

private static String getStringProperty(Map<String, Object> map, String property) {
return getProperty(map, property, String.class);
}

private static List<String> getListStringsProperty(Map<String, Object> map, String property) {
List list = getProperty(map, property, List.class);
if (list == null) {
return null;
}
List<String> res = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
Object el = list.get(i);
try {
res.add(String.class.cast(el));
} catch (ClassCastException e) {
throw new RuntimeException(String.format(MESSAGES_BUNDLE.getString("errors.config.invalid_format"), String.format("%s[%s]", property, i)));
}
}
return res;
}

private static List<Map<String, Object>> getListOfObjectsProperty(Map<String, Object> map, String property) {
List list = getProperty(map, property, List.class);
if (list == null) {
return null;
}
List<Map<String, Object>> res = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
Object el = list.get(i);
try {
Map<Object, Object> object = Map.class.cast(el);

int finalI = i;
Map<String, Object> castedObject = object
.entrySet()
.stream()
.peek(entry -> {
if (entry.getKey() == null || entry.getValue() == null) {
throw new RuntimeException(String.format(MESSAGES_BUNDLE.getString("errors.config.invalid_format"), String.format("%s[%s]", property, finalI)));
}
})
.collect(Collectors.toMap(
field -> String.class.cast(field.getKey()),
Map.Entry::getValue
));
res.add(castedObject);
} catch (ClassCastException e) {
throw new RuntimeException(String.format(MESSAGES_BUNDLE.getString("errors.config.invalid_format"), String.format("%s[%s]", property, i)));
}
}
return res;
}

private static Boolean getBooleanProperty(Map<String, Object> map, String property) {
return getProperty(map, property, Boolean.class);
}

private static <T> T getProperty(Map<String, Object> map, String property, Class<T> clazz) {
try {
Object value = map.get(property);
if (value != null) {
return clazz.cast(value);
}
return null;
} catch (ClassCastException e) {
throw new RuntimeException(String.format(MESSAGES_BUNDLE.getString("errors.config.invalid_format"), property));
}
}

protected static boolean isBaseUrlValid(String baseUrl) {
return BASE_URL_PATTERN.matcher(baseUrl).matches();
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/messages/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ labels.loading_text.download_source_file_from_context=Downloading Source File '%
errors.config.project_id_format=Project Id '%s' should be a number
errors.config.sysenv_not_exist.single=Environment variables do not contain <b>'%s'</b> key
errors.config.sysenv_not_exist.plural=Environment variables do not contain %s keys
errors.settings.api_token_missing=API Token is not defined for this workspace
errors.config.invalid_format=Property '%s' has wrong format
errors.config.has_errors=Errors in the configuration file:
errors.config.missing_config_file=File <b>'%s'</b> with Crowdin plugin configuration doesn't exist in the project root directory
errors.config.missing_property=Required property <b>'%s'</b> is missing in the configuration file
Expand Down

0 comments on commit 4482cbd

Please sign in to comment.