From 9994bdcd065625efc55330cf9db3019789c5386d Mon Sep 17 00:00:00 2001 From: Kateryna Oblakevych Date: Thu, 2 May 2024 19:39:28 +0300 Subject: [PATCH] feat: use environment vars when config file is absent --- .../cli/properties/BaseProperties.java | 24 +++++++------ .../cli/properties/BasePropertiesBuilder.java | 8 +++++ .../cli/properties/ProjectProperties.java | 9 +++++ .../properties/ProjectPropertiesBuilder.java | 9 +++++ .../cli/properties/PropertiesBuilder.java | 18 ++++++++++ .../properties/PropertiesBuilderChecker.java | 13 +++++++ .../properties/PropertiesConfigurator.java | 2 ++ .../cli/properties/PropertiesWithFiles.java | 5 +++ .../PropertiesWithFilesBuilder.java | 10 ++++++ website/docs/intro.md | 36 +++++++++++++++++++ 10 files changed, 124 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/crowdin/cli/properties/BaseProperties.java b/src/main/java/com/crowdin/cli/properties/BaseProperties.java index c9ea42406..6e1383d98 100644 --- a/src/main/java/com/crowdin/cli/properties/BaseProperties.java +++ b/src/main/java/com/crowdin/cli/properties/BaseProperties.java @@ -14,16 +14,7 @@ import java.util.Map; import static com.crowdin.cli.BaseCli.RESOURCE_BUNDLE; -import static com.crowdin.cli.properties.PropertiesBuilder.API_TOKEN; -import static com.crowdin.cli.properties.PropertiesBuilder.API_TOKEN_ENV; -import static com.crowdin.cli.properties.PropertiesBuilder.BASE_PATH; -import static com.crowdin.cli.properties.PropertiesBuilder.BASE_PATH_ENV; -import static com.crowdin.cli.properties.PropertiesBuilder.BASE_URL; -import static com.crowdin.cli.properties.PropertiesBuilder.BASE_URL_ENV; -import static com.crowdin.cli.properties.PropertiesBuilder.CONFIG_FILE_PATH; -import static com.crowdin.cli.properties.PropertiesBuilder.SETTINGS; -import static com.crowdin.cli.properties.PropertiesBuilder.checkBasePathExists; -import static com.crowdin.cli.properties.PropertiesBuilder.checkBasePathIsDir; +import static com.crowdin.cli.properties.PropertiesBuilder.*; @Data public class BaseProperties implements Properties { @@ -52,6 +43,19 @@ public void populateWithValues(BaseProperties props, Map map) { props.setSettings(SettingsBean.CONFIGURATOR.buildFromMap(PropertiesBuilder.getMap(map, SETTINGS))); } + @Override + public void populateWithEnvValues(BaseProperties props) { + if (props.getApiToken() == null) { + PropertiesBuilder.setEnvIfExists(props::setApiToken, CROWDIN_PERSONAL_TOKEN); + } + if (props.getBasePath() == null) { + PropertiesBuilder.setEnvIfExists(props::setBasePath, CROWDIN_BASE_PATH); + } + if (props.getBaseUrl() == null) { + PropertiesBuilder.setEnvIfExists(props::setBaseUrl, CROWDIN_BASE_URL); + } + } + @Override public void populateWithDefaultValues(BaseProperties props) { if (props == null) { diff --git a/src/main/java/com/crowdin/cli/properties/BasePropertiesBuilder.java b/src/main/java/com/crowdin/cli/properties/BasePropertiesBuilder.java index 44f702e69..f588df4b3 100644 --- a/src/main/java/com/crowdin/cli/properties/BasePropertiesBuilder.java +++ b/src/main/java/com/crowdin/cli/properties/BasePropertiesBuilder.java @@ -64,6 +64,14 @@ protected void populateWithArgParams(BaseProperties props, @NonNull BaseParams p } } + @Override + protected void populateWithEnvValues(BaseProperties props) { + if (props == null) { + return; + } + BaseProperties.CONFIGURATOR.populateWithEnvValues(props); + } + @Override protected void populateWithDefaultValues(BaseProperties props) { if (props == null) { diff --git a/src/main/java/com/crowdin/cli/properties/ProjectProperties.java b/src/main/java/com/crowdin/cli/properties/ProjectProperties.java index 6eb7a0706..f38a09969 100644 --- a/src/main/java/com/crowdin/cli/properties/ProjectProperties.java +++ b/src/main/java/com/crowdin/cli/properties/ProjectProperties.java @@ -9,6 +9,7 @@ import static com.crowdin.cli.BaseCli.RESOURCE_BUNDLE; import static com.crowdin.cli.properties.PropertiesBuilder.PROJECT_ID; import static com.crowdin.cli.properties.PropertiesBuilder.PROJECT_ID_ENV; +import static com.crowdin.cli.properties.PropertiesBuilder.CROWDIN_PROJECT_ID; @EqualsAndHashCode(callSuper = true) @Data @@ -34,6 +35,14 @@ public void populateWithDefaultValues(ProjectProperties props) { // do nothing } + @Override + public void populateWithEnvValues(ProjectProperties props) { + if (props == null) { + return; + } + PropertiesBuilder.setEnvIfExists(props::setProjectId, CROWDIN_PROJECT_ID); + } + @Override public PropertiesBuilder.Messages checkProperties(ProjectProperties props, CheckType checkType) { PropertiesBuilder.Messages messages = new PropertiesBuilder.Messages(); diff --git a/src/main/java/com/crowdin/cli/properties/ProjectPropertiesBuilder.java b/src/main/java/com/crowdin/cli/properties/ProjectPropertiesBuilder.java index 6f5080541..018dff447 100644 --- a/src/main/java/com/crowdin/cli/properties/ProjectPropertiesBuilder.java +++ b/src/main/java/com/crowdin/cli/properties/ProjectPropertiesBuilder.java @@ -69,6 +69,15 @@ protected void populateWithArgParams(ProjectProperties props, @NonNull ProjectPa } } + @Override + protected void populateWithEnvValues(ProjectProperties props) { + if (props == null) { + return; + } + BaseProperties.CONFIGURATOR.populateWithEnvValues(props); + ProjectProperties.CONFIGURATOR.populateWithEnvValues(props); + } + @Override protected void populateWithDefaultValues(ProjectProperties props) { if (props == null) { diff --git a/src/main/java/com/crowdin/cli/properties/PropertiesBuilder.java b/src/main/java/com/crowdin/cli/properties/PropertiesBuilder.java index 7404fbbbc..68eb09c8b 100644 --- a/src/main/java/com/crowdin/cli/properties/PropertiesBuilder.java +++ b/src/main/java/com/crowdin/cli/properties/PropertiesBuilder.java @@ -32,18 +32,26 @@ public abstract class PropertiesBuilder public static final String PROJECT_ID_ENV = "project_id_env"; + public static final String CROWDIN_PROJECT_ID = "crowdin_project_id"; + public static final String API_TOKEN = "api_token"; public static final String API_TOKEN_ENV = "api_token_env"; + public static final String CROWDIN_PERSONAL_TOKEN = "crowdin_personal_token"; + public static final String BASE_PATH = "base_path"; public static final String BASE_PATH_ENV = "base_path_env"; + public static final String CROWDIN_BASE_PATH = "crowdin_base_path"; + public static final String BASE_URL = "base_url"; public static final String BASE_URL_ENV = "base_url_env"; + public static final String CROWDIN_BASE_URL = "crowdin_base_url"; + public static final String PRESERVE_HIERARCHY = "preserve_hierarchy"; public static final String FILES = "files"; @@ -160,6 +168,7 @@ public T build() { this.throwErrorIfNeeded(this.checkArgParams(params), RESOURCE_BUNDLE.getString("error.params_are_invalid")); this.populateWithArgParams(props, params); } + this.populateWithEnvValues(props); this.populateWithDefaultValues(props); String errorTitle = (configFileParams == null && identityFileParams == null) ? RESOURCE_BUNDLE.getString("error.configuration_is_invalid") @@ -190,6 +199,8 @@ private void throwErrorIfNeeded(Messages messages, String text) { protected abstract void populateWithArgParams(T props, @NonNull P params); + protected abstract void populateWithEnvValues(T props); + protected abstract void populateWithDefaultValues(T props); protected abstract Messages checkProperties(T props); @@ -223,6 +234,13 @@ static void setEnvOrPropertyIfExists(Consumer setter, Map setter, String envKey) { + String param = System.getenv(envKey); + if (param != null) { + setter.accept(param); + } + } + private static Dotenv getDotenv() { if (dotenv == null) { try { diff --git a/src/main/java/com/crowdin/cli/properties/PropertiesBuilderChecker.java b/src/main/java/com/crowdin/cli/properties/PropertiesBuilderChecker.java index a6425f329..958c3d38d 100644 --- a/src/main/java/com/crowdin/cli/properties/PropertiesBuilderChecker.java +++ b/src/main/java/com/crowdin/cli/properties/PropertiesBuilderChecker.java @@ -47,6 +47,19 @@ protected void populateWithArgParams(AllProperties props, @NonNull NoParams para } + @Override + protected void populateWithEnvValues(AllProperties props) { + if (props == null) { + return; + } + BaseProperties.CONFIGURATOR.populateWithEnvValues(props.getProjectProperties()); + ProjectProperties.CONFIGURATOR.populateWithEnvValues(props.getProjectProperties()); + + BaseProperties.CONFIGURATOR.populateWithEnvValues(props.getPropertiesWithFiles()); + ProjectProperties.CONFIGURATOR.populateWithEnvValues(props.getPropertiesWithFiles()); + PropertiesWithFiles.CONFIGURATOR.populateWithEnvValues(props.getPropertiesWithFiles()); + } + @Override protected void populateWithDefaultValues(AllProperties props) { if (props == null) { diff --git a/src/main/java/com/crowdin/cli/properties/PropertiesConfigurator.java b/src/main/java/com/crowdin/cli/properties/PropertiesConfigurator.java index 33c5ff745..60dca6658 100644 --- a/src/main/java/com/crowdin/cli/properties/PropertiesConfigurator.java +++ b/src/main/java/com/crowdin/cli/properties/PropertiesConfigurator.java @@ -8,6 +8,8 @@ interface PropertiesConfigurator

{ void populateWithDefaultValues(P props); + void populateWithEnvValues(P props); + PropertiesBuilder.Messages checkProperties(P props, CheckType checkType); enum CheckType { diff --git a/src/main/java/com/crowdin/cli/properties/PropertiesWithFiles.java b/src/main/java/com/crowdin/cli/properties/PropertiesWithFiles.java index 3cd1cb4b8..62f64fd47 100644 --- a/src/main/java/com/crowdin/cli/properties/PropertiesWithFiles.java +++ b/src/main/java/com/crowdin/cli/properties/PropertiesWithFiles.java @@ -61,6 +61,11 @@ public void populateWithDefaultValues(PropertiesWithFiles props) { } } + @Override + public void populateWithEnvValues(PropertiesWithFiles props) { +// do nothing + } + @Override public PropertiesBuilder.Messages checkProperties(PropertiesWithFiles props, CheckType checkType) { PropertiesBuilder.Messages messages = new PropertiesBuilder.Messages(); diff --git a/src/main/java/com/crowdin/cli/properties/PropertiesWithFilesBuilder.java b/src/main/java/com/crowdin/cli/properties/PropertiesWithFilesBuilder.java index 794d69c4e..a04678dbf 100644 --- a/src/main/java/com/crowdin/cli/properties/PropertiesWithFilesBuilder.java +++ b/src/main/java/com/crowdin/cli/properties/PropertiesWithFilesBuilder.java @@ -151,6 +151,16 @@ protected void populateWithArgParams(@NonNull PropertiesWithFiles props, @NonNul } } + @Override + protected void populateWithEnvValues(PropertiesWithFiles props) { + if (props == null) { + return; + } + BaseProperties.CONFIGURATOR.populateWithEnvValues(props); + ProjectProperties.CONFIGURATOR.populateWithEnvValues(props); + PropertiesWithFiles.CONFIGURATOR.populateWithEnvValues(props); + } + @Override protected void populateWithDefaultValues(PropertiesWithFiles props) { if (props == null) { diff --git a/website/docs/intro.md b/website/docs/intro.md index 97e7e951c..c40accc6d 100644 --- a/website/docs/intro.md +++ b/website/docs/intro.md @@ -81,6 +81,42 @@ Here are the common config options for all CLI commands: Some commands have their own config options. +## Environment Variables + +Configuration can be specified using Environment Variables. They have the lowest priority and are used in case any of the parameters are missed. + +Here are Environment Variables that can be used: + +|

Option
| Description | +|----------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| CROWDIN_PERSONAL_TOKEN | Personal Access Token required for authentication | +| CROWDIN_BASE_URL | Base URL of Crowdin server for API requests execution (`https://api.crowdin.com` for crowdin.com, `https://{organization-name}.api.crowdin.com` for Crowdin Enterprise) | +| CROWDIN_BASE_PATH | Path to your project directory on a local machine (default: `.`) | +| CROWDIN_PROJECT_ID | Numerical ID of the Crowdin project | + + +You can also map the Environment Variable in the configuration file, for example: + +```ini +"project_id_env": "CROWDIN_PROJECT_ID" +"api_token_env": "CROWDIN_PERSONAL_TOKEN" +"base_path_env": "CROWDIN_BASE_PATH" +"base_url_env": "CROWDIN_BASE_URL" +``` + +If mixed, api_token and project_id are prioritized: + +```ini +"project_id_env": "CROWDIN_PROJECT_ID" # Low priority +"api_token_env": "CROWDIN_PERSONAL_TOKEN" # Low priority +"base_path_env": "CROWDIN_BASE_PATH" # Low priority +"base_url_env": "CROWDIN_BASE_PATH" # Low priority +"project_id": "projectId" # High priority +"api_token": "personal-access-token" # High priority +"base_path": "/project-base-path" # High priority +"base_url": "https://api.crowdin.com" # High priority +``` + ## Bash completion script The bash completion script provided by Crowdin CLI is a utility that provides auto-completion suggestions for Crowdin CLI commands and options within the bash terminal. This script can significantly improve the productivity of users who frequently work with Crowdin CLI by reducing the need to manually type commands and options.