Skip to content

Commit

Permalink
feat: use environment vars when config file is absent
Browse files Browse the repository at this point in the history
  • Loading branch information
katerina20 committed May 3, 2024
1 parent de67290 commit 383fea5
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 10 deletions.
24 changes: 14 additions & 10 deletions src/main/java/com/crowdin/cli/properties/BaseProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -52,6 +43,19 @@ public void populateWithValues(BaseProperties props, Map<String, Object> 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/com/crowdin/cli/properties/PropertiesBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,26 @@ public abstract class PropertiesBuilder<T extends Properties, P extends Params>

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";
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -223,6 +234,13 @@ static void setEnvOrPropertyIfExists(Consumer<String> setter, Map<String, Object
}
}

static void setEnvIfExists(Consumer<String> setter, String envKey) {
String param = getDotenv().get(envKey);
if (param != null) {
setter.accept(param);
}
}

private static Dotenv getDotenv() {
if (dotenv == null) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ interface PropertiesConfigurator<P extends Properties> {

void populateWithDefaultValues(P props);

void populateWithEnvValues(P props);

PropertiesBuilder.Messages checkProperties(P props, CheckType checkType);

enum CheckType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
36 changes: 36 additions & 0 deletions website/docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

| <div style={{width:170 + 'px'}}>Option</div> | 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.
Expand Down

0 comments on commit 383fea5

Please sign in to comment.