From b5cac1d8ab70f31affba191f27172b63e921ebf4 Mon Sep 17 00:00:00 2001 From: Kateryna Oblakevych Date: Thu, 19 Oct 2023 15:04:27 +0300 Subject: [PATCH 1/5] feat: config params for generate command --- .../com/crowdin/cli/commands/Actions.java | 3 +- .../cli/commands/actions/CliActions.java | 6 +- .../cli/commands/actions/GenerateAction.java | 120 +++++++++++------- .../commands/picocli/GenerateSubcommand.java | 30 ++++- .../cli/commands/actions/CliActionsTest.java | 2 +- .../commands/actions/GenerateActionTest.java | 28 ++-- .../picocli/GenerateSubcommandTest.java | 2 +- .../commands/picocli/PicocliTestUtils.java | 2 +- 8 files changed, 128 insertions(+), 65 deletions(-) diff --git a/src/main/java/com/crowdin/cli/commands/Actions.java b/src/main/java/com/crowdin/cli/commands/Actions.java index db446dfa9..a5c45ef77 100644 --- a/src/main/java/com/crowdin/cli/commands/Actions.java +++ b/src/main/java/com/crowdin/cli/commands/Actions.java @@ -28,7 +28,8 @@ NewAction download( boolean ignoreMatch, boolean isVerbose, boolean plainView, boolean userServerSources, boolean keepArchive ); - NewAction generate(FilesInterface files, Path destinationPath, boolean skipGenerateDescription); + NewAction generate(FilesInterface files, String token, String baseUrl, String basePath, + String projectId, String source, String translation, String dest, Boolean preserveHierarchy, Path configDestPath, boolean skipGenerateDescription); NewAction listBranches(boolean noProgress, boolean plainView); diff --git a/src/main/java/com/crowdin/cli/commands/actions/CliActions.java b/src/main/java/com/crowdin/cli/commands/actions/CliActions.java index eef1b3a87..e99f5442f 100644 --- a/src/main/java/com/crowdin/cli/commands/actions/CliActions.java +++ b/src/main/java/com/crowdin/cli/commands/actions/CliActions.java @@ -34,8 +34,10 @@ public NewAction download( } @Override - public NewAction generate(FilesInterface files, Path destinationPath, boolean skipGenerateDescription) { - return new GenerateAction(files, destinationPath, skipGenerateDescription); + public NewAction generate(FilesInterface files, String token, String baseUrl, String basePath, + String projectId, String source, String translation, String dest, Boolean preserveHierarchy, Path configDestPath, boolean skipGenerateDescription + ) { + return new GenerateAction(files, token, baseUrl, basePath, projectId, source, translation, dest, preserveHierarchy, configDestPath, skipGenerateDescription); } @Override diff --git a/src/main/java/com/crowdin/cli/commands/actions/GenerateAction.java b/src/main/java/com/crowdin/cli/commands/actions/GenerateAction.java index a8479e6c7..77cf79631 100644 --- a/src/main/java/com/crowdin/cli/commands/actions/GenerateAction.java +++ b/src/main/java/com/crowdin/cli/commands/actions/GenerateAction.java @@ -12,6 +12,7 @@ import com.crowdin.cli.utils.console.ConsoleSpinner; import com.crowdin.cli.utils.console.ExecutionStatus; import com.crowdin.cli.utils.http.OAuthUtil; +import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import java.io.ByteArrayInputStream; @@ -19,21 +20,19 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Scanner; +import java.util.*; import static com.crowdin.cli.BaseCli.OAUTH_CLIENT_ID; import static com.crowdin.cli.BaseCli.RESOURCE_BUNDLE; -import static com.crowdin.cli.properties.PropertiesBuilder.API_TOKEN; -import static com.crowdin.cli.properties.PropertiesBuilder.BASE_PATH; -import static com.crowdin.cli.properties.PropertiesBuilder.BASE_URL; -import static com.crowdin.cli.properties.PropertiesBuilder.PROJECT_ID; +import static com.crowdin.cli.properties.PropertiesBuilder.*; import static com.crowdin.cli.utils.console.ExecutionStatus.ERROR; import static com.crowdin.cli.utils.console.ExecutionStatus.OK; import static com.crowdin.cli.utils.console.ExecutionStatus.WARNING; +import static java.lang.Boolean.TRUE; +import static java.util.Objects.isNull; +import static java.util.Objects.nonNull; +@RequiredArgsConstructor class GenerateAction implements NewAction { public static final String BASE_PATH_DEFAULT = "."; @@ -46,15 +45,17 @@ class GenerateAction implements NewAction { public static final String LINK = "https://support.crowdin.com/configuration-file/"; public static final String ENTERPRISE_LINK = "https://support.crowdin.com/enterprise/configuration-file/"; - private FilesInterface files; - private Path destinationPath; - private boolean skipGenerateDescription; - - public GenerateAction(FilesInterface files, Path destinationPath, boolean skipGenerateDescription) { - this.files = files; - this.destinationPath = destinationPath; - this.skipGenerateDescription = skipGenerateDescription; - } + private final FilesInterface files; + private final String token; + private final String baseUrl; + private final String basePath; + private final String projectId; + private final String source; + private final String translation; + private final String dest; + private final Boolean preserveHierarchy; + private final Path configDestPath; + private final boolean skipGenerateDescription; @Override public void act(Outputter out, NoProperties noProperties, NoClient noClient) { @@ -63,10 +64,10 @@ public void act(Outputter out, NoProperties noProperties, NoClient noClient) { try { out.println(String.format( RESOURCE_BUNDLE.getString("message.command_generate_description"), - destinationPath.toAbsolutePath())); - if (Files.exists(destinationPath)) { + configDestPath.toAbsolutePath())); + if (Files.exists(configDestPath)) { out.println(ExecutionStatus.SKIPPED.getIcon() + String.format( - RESOURCE_BUNDLE.getString("message.already_exists"), destinationPath.toAbsolutePath())); + RESOURCE_BUNDLE.getString("message.already_exists"), configDestPath.toAbsolutePath())); return; } @@ -75,7 +76,7 @@ public void act(Outputter out, NoProperties noProperties, NoClient noClient) { this.updateWithUserInputs(out, asking, fileLines); } files.writeToFile( - destinationPath.toString(), new ByteArrayInputStream(StringUtils.join(fileLines, "\n").getBytes(StandardCharsets.UTF_8))); + configDestPath.toString(), new ByteArrayInputStream(StringUtils.join(fileLines, "\n").getBytes(StandardCharsets.UTF_8))); out.println(String.format( RESOURCE_BUNDLE.getString("message.generate_successful"), this.isEnterprise ? ENTERPRISE_LINK : LINK)); @@ -87,8 +88,9 @@ public void act(Outputter out, NoProperties noProperties, NoClient noClient) { private void updateWithUserInputs(Outputter out, Asking asking, List fileLines) { Map values = new HashMap<>(); + setGivenParams(values); - withBrowser = !StringUtils.startsWithAny(asking.ask( + withBrowser = isNull(token) && !StringUtils.startsWithAny(asking.ask( RESOURCE_BUNDLE.getString("message.ask_auth_via_browser") + ": (Y/n) "), "n", "N", "-"); if (withBrowser) { String token; @@ -108,38 +110,45 @@ private void updateWithUserInputs(Outputter out, Asking asking, List fil values.put(BASE_URL, BASE_URL_DEFAULT); } } else { - this.isEnterprise = StringUtils.startsWithAny(asking.ask( + if (isNull(baseUrl)) { + this.isEnterprise = StringUtils.startsWithAny(asking.ask( RESOURCE_BUNDLE.getString("message.ask_is_enterprise") + ": (N/y) "), "y", "Y", "+"); - if (this.isEnterprise) { - String organizationName = asking.ask(RESOURCE_BUNDLE.getString("message.ask_organization_name") + ": "); - if (StringUtils.isNotEmpty(organizationName)) { - if (PropertiesBeanUtils.isUrlValid(organizationName)) { - String realOrganizationName = PropertiesBeanUtils.getOrganization(organizationName); - System.out.println(String.format(RESOURCE_BUNDLE.getString("message.extracted_organization_name"), realOrganizationName)); - values.put(BASE_URL, String.format(BASE_ENTERPRISE_URL_DEFAULT, realOrganizationName)); + if (this.isEnterprise) { + String organizationName = asking.ask(RESOURCE_BUNDLE.getString("message.ask_organization_name") + ": "); + if (StringUtils.isNotEmpty(organizationName)) { + if (PropertiesBeanUtils.isUrlValid(organizationName)) { + String realOrganizationName = PropertiesBeanUtils.getOrganization(organizationName); + System.out.println(String.format(RESOURCE_BUNDLE.getString("message.extracted_organization_name"), realOrganizationName)); + values.put(BASE_URL, String.format(BASE_ENTERPRISE_URL_DEFAULT, realOrganizationName)); + } else { + values.put(BASE_URL, String.format(BASE_ENTERPRISE_URL_DEFAULT, PropertiesBeanUtils.getOrganization(organizationName))); + } } else { - values.put(BASE_URL, String.format(BASE_ENTERPRISE_URL_DEFAULT, PropertiesBeanUtils.getOrganization(organizationName))); + this.isEnterprise = false; + values.put(BASE_URL, BASE_URL_DEFAULT); } } else { - this.isEnterprise = false; values.put(BASE_URL, BASE_URL_DEFAULT); } - } else { - values.put(BASE_URL, BASE_URL_DEFAULT); } - String apiToken = asking.askParam(API_TOKEN); - if (!apiToken.isEmpty()) { - values.put(API_TOKEN, apiToken); + if (isNull(token)) { + String apiToken = asking.askParam(API_TOKEN); + if (!apiToken.isEmpty()) { + values.put(API_TOKEN, apiToken); + } } } + boolean projectIdSpecified = nonNull(projectId); while (true) { - String projectId = asking.askParam(PROJECT_ID); - if (projectId.isEmpty()) { + String projectIdToSet = projectIdSpecified ? projectId : asking.askParam(PROJECT_ID); + if (projectIdToSet.isEmpty()) { break; - } else if (StringUtils.isNumeric(projectId)) { - values.put(PROJECT_ID, projectId); + } else if (StringUtils.isNumeric(projectIdToSet)) { + values.put(PROJECT_ID, projectIdToSet); break; } else { + projectIdSpecified = false; + values.remove(PROJECT_ID); System.out.println(String.format(RESOURCE_BUNDLE.getString("error.init.project_id_is_not_number"), projectId)); } } @@ -148,23 +157,42 @@ private void updateWithUserInputs(Outputter out, Asking asking, List fil } else { System.out.println(WARNING.withIcon(RESOURCE_BUNDLE.getString("error.init.skip_project_validation"))); } - String basePath = asking.askWithDefault(RESOURCE_BUNDLE.getString("message.ask_project_directory"), BASE_PATH_DEFAULT); - java.io.File basePathFile = Paths.get(basePath).normalize().toAbsolutePath().toFile(); + String basePathToSet = nonNull(basePath) ? basePath : asking.askWithDefault(RESOURCE_BUNDLE.getString("message.ask_project_directory"), BASE_PATH_DEFAULT); + java.io.File basePathFile = Paths.get(basePathToSet).normalize().toAbsolutePath().toFile(); if (!basePathFile.exists()) { System.out.println(WARNING.withIcon(String.format(RESOURCE_BUNDLE.getString("error.init.path_not_exist"), basePathFile))); } - values.put(BASE_PATH, basePath); + values.put(BASE_PATH, basePathToSet); for (Map.Entry entry : values.entrySet()) { for (int i = 0; i < fileLines.size(); i++) { - if (fileLines.get(i).contains(entry.getKey())) { - fileLines.set(i, fileLines.get(i).replaceFirst(": \"*\"", String.format(": \"%s\"", Utils.regexPath(entry.getValue())))); + String keyToSearch = String.format("\"%s\"", entry.getKey()); + if (fileLines.get(i).contains(keyToSearch)) { + String updatedLine; + if (PRESERVE_HIERARCHY.equals(entry.getKey())) { + updatedLine = fileLines.get(i).replace(String.valueOf(TRUE), entry.getValue()); + } else { + updatedLine = fileLines.get(i).replaceFirst(": \"*\"", String.format(": \"%s\"", Utils.regexPath(entry.getValue()))); + } + updatedLine = updatedLine.replace(" #", ""); + fileLines.set(i, updatedLine); break; } } } } + private void setGivenParams(Map values) { + Optional.ofNullable(token).ifPresent(v -> values.put(API_TOKEN, token)); + Optional.ofNullable(baseUrl).ifPresent(v -> values.put(BASE_URL, baseUrl)); + Optional.ofNullable(basePath).ifPresent(v -> values.put(BASE_PATH, basePath)); + Optional.ofNullable(projectId).ifPresent(v -> values.put(PROJECT_ID, projectId)); + Optional.ofNullable(source).ifPresent(v -> values.put(SOURCE, source)); + Optional.ofNullable(translation).ifPresent(v -> values.put(TRANSLATION, translation)); + Optional.ofNullable(dest).ifPresent(v -> values.put(DEST, dest)); + Optional.ofNullable(preserveHierarchy).ifPresent(v -> values.put(PRESERVE_HIERARCHY, String.valueOf(preserveHierarchy))); + } + public static class Asking { private Outputter out; diff --git a/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java b/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java index 81286889e..9a07fcd1a 100644 --- a/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java +++ b/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java @@ -17,14 +17,38 @@ aliases = CommandNames.ALIAS_GENERATE) public class GenerateSubcommand extends GenericActCommand { - @CommandLine.Option(names = {"-d", "--destination"}, paramLabel = "...", defaultValue = "crowdin.yml") - private Path destinationPath; + @CommandLine.Option(names = {"-T", "--token"}, paramLabel = "...", descriptionKey = "params.token") + private String token; + + @CommandLine.Option(names = {"--base-url"}, paramLabel = "...", descriptionKey = "params.base-url") + private String baseUrl; + + @CommandLine.Option(names = {"--base-path"}, paramLabel = "...", descriptionKey = "params.base-path") + private String basePath; + + @CommandLine.Option(names = {"-i", "--project-id"}, paramLabel = "...", descriptionKey = "params.project-id") + private String projectId; + + @CommandLine.Option(names = {"-s", "--source"}, paramLabel = "...", descriptionKey = "params.source") + private String source; + + @CommandLine.Option(names = {"-t", "--translation"}, paramLabel = "...", descriptionKey = "params.translation") + private String translation; + + @CommandLine.Option(names = {"--dest"}, paramLabel = "...", descriptionKey = "params.dest") + private String dest; + + @CommandLine.Option(names = {"--preserve-hierarchy"}, negatable = true, paramLabel = "...", descriptionKey = "params.preserve-hierarchy") + private Boolean preserveHierarchy; + + @CommandLine.Option(names = {"-d", "--config-dest"}, paramLabel = "...", defaultValue = "crowdin.yml") + private Path configDestPath; @CommandLine.Option(names = "--skip-generate-description", hidden = true) private boolean skipGenerateDescription; protected NewAction getAction(Actions actions) { - return actions.generate(new FsFiles(), destinationPath, skipGenerateDescription); + return actions.generate(new FsFiles(), token, baseUrl, basePath, projectId, source, translation, dest, preserveHierarchy, configDestPath, skipGenerateDescription); } protected NoProperties getProperties(PropertiesBuilders propertiesBuilders, Outputter out) { diff --git a/src/test/java/com/crowdin/cli/commands/actions/CliActionsTest.java b/src/test/java/com/crowdin/cli/commands/actions/CliActionsTest.java index bdf61204f..f88c334b0 100644 --- a/src/test/java/com/crowdin/cli/commands/actions/CliActionsTest.java +++ b/src/test/java/com/crowdin/cli/commands/actions/CliActionsTest.java @@ -19,7 +19,7 @@ public void testDownload() { @Test public void testGenerate() { - assertNotNull(actions.generate(new FsFiles(), null, false)); + assertNotNull(actions.generate(new FsFiles(), null, null, null, null, null, null, null, null, null, false)); } @Test diff --git a/src/test/java/com/crowdin/cli/commands/actions/GenerateActionTest.java b/src/test/java/com/crowdin/cli/commands/actions/GenerateActionTest.java index 271e1011a..35eb02a27 100644 --- a/src/test/java/com/crowdin/cli/commands/actions/GenerateActionTest.java +++ b/src/test/java/com/crowdin/cli/commands/actions/GenerateActionTest.java @@ -20,10 +20,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.*; public class GenerateActionTest { @@ -47,7 +44,18 @@ public void simpleTest() throws IOException { InputStream responsesIS = setResponses(false, false, "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class)); + + verify(files).writeToFile(anyString(), any()); + verifyNoMoreInteractions(files); + } + + @Test + public void userInputTest() throws IOException { + FilesInterface files = mock(FilesInterface.class); + + action = new GenerateAction(files, "token", "", ".", "42", "file.json", "translation.json", "dest", true, Paths.get(project.getBasePath() + "/crowdin.yml"), false); action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class)); verify(files).writeToFile(anyString(), any()); @@ -61,7 +69,7 @@ public void writeToFileThrowsTest() throws IOException { InputStream responsesIS = setResponses(false, false, "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); assertThrows(RuntimeException.class, () -> action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class))); verify(files).writeToFile(anyString(), any()); @@ -75,7 +83,7 @@ public void enterprisetest() throws IOException { InputStream responsesIS = setResponses(false, true, "undefined", "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); assertThrows(RuntimeException.class, () -> action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class))); verify(files).writeToFile(anyString(), any()); @@ -89,7 +97,7 @@ public void enterpriseUrlTest() throws IOException { InputStream responsesIS = setResponses(false, true, "https://undefined.crowdin.com", "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); assertThrows(RuntimeException.class, () -> action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class))); verify(files).writeToFile(anyString(), any()); @@ -103,7 +111,7 @@ public void enterpriseNoNametest() throws IOException { InputStream responsesIS = setResponses(false, true, "", "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); assertThrows(RuntimeException.class, () -> action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class))); verify(files).writeToFile(anyString(), any()); @@ -118,7 +126,7 @@ public void fileExists() throws IOException { InputStream responsesIS = setResponses(false, true, "https://undefined.crowdin.com", "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class)); verifyNoMoreInteractions(files); diff --git a/src/test/java/com/crowdin/cli/commands/picocli/GenerateSubcommandTest.java b/src/test/java/com/crowdin/cli/commands/picocli/GenerateSubcommandTest.java index b3557eb41..7944dd351 100644 --- a/src/test/java/com/crowdin/cli/commands/picocli/GenerateSubcommandTest.java +++ b/src/test/java/com/crowdin/cli/commands/picocli/GenerateSubcommandTest.java @@ -12,7 +12,7 @@ public class GenerateSubcommandTest extends PicocliTestUtils { public void testGenerate() { this.execute(CommandNames.GENERATE); verify(actionsMock) - .generate(any(), any(), anyBoolean()); + .generate(any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), anyBoolean()); this.check(false); } } diff --git a/src/test/java/com/crowdin/cli/commands/picocli/PicocliTestUtils.java b/src/test/java/com/crowdin/cli/commands/picocli/PicocliTestUtils.java index ff6d60b38..d774eea4e 100644 --- a/src/test/java/com/crowdin/cli/commands/picocli/PicocliTestUtils.java +++ b/src/test/java/com/crowdin/cli/commands/picocli/PicocliTestUtils.java @@ -60,7 +60,7 @@ void mockActions() { when(actionsMock.download(any(), anyBoolean(), any(), any(), anyBoolean(), any(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean())) .thenReturn(actionMock); - when(actionsMock.generate(any(), any(), anyBoolean())) + when(actionsMock.generate(any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), anyBoolean())) .thenReturn(actionMock); when(actionsMock.listBranches(anyBoolean(), anyBoolean())) .thenReturn(actionMock); From b970a3c65a7b55ede1a005e28d38850409ae4042 Mon Sep 17 00:00:00 2001 From: Kateryna Oblakevych Date: Thu, 19 Oct 2023 16:36:28 +0300 Subject: [PATCH 2/5] return old destination and remove dest param --- .../com/crowdin/cli/commands/Actions.java | 2 +- .../cli/commands/actions/CliActions.java | 4 +-- .../cli/commands/actions/GenerateAction.java | 22 ++++++---------- .../commands/picocli/GenerateSubcommand.java | 25 ++++++++----------- .../cli/commands/actions/CliActionsTest.java | 2 +- .../commands/actions/GenerateActionTest.java | 14 +++++------ .../picocli/GenerateSubcommandTest.java | 2 +- .../commands/picocli/PicocliTestUtils.java | 2 +- 8 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/crowdin/cli/commands/Actions.java b/src/main/java/com/crowdin/cli/commands/Actions.java index a5c45ef77..09640cbd4 100644 --- a/src/main/java/com/crowdin/cli/commands/Actions.java +++ b/src/main/java/com/crowdin/cli/commands/Actions.java @@ -29,7 +29,7 @@ NewAction download( ); NewAction generate(FilesInterface files, String token, String baseUrl, String basePath, - String projectId, String source, String translation, String dest, Boolean preserveHierarchy, Path configDestPath, boolean skipGenerateDescription); + String projectId, String source, String translation, Boolean preserveHierarchy, Path destinationPath, boolean skipGenerateDescription); NewAction listBranches(boolean noProgress, boolean plainView); diff --git a/src/main/java/com/crowdin/cli/commands/actions/CliActions.java b/src/main/java/com/crowdin/cli/commands/actions/CliActions.java index e99f5442f..20f1ee80b 100644 --- a/src/main/java/com/crowdin/cli/commands/actions/CliActions.java +++ b/src/main/java/com/crowdin/cli/commands/actions/CliActions.java @@ -35,9 +35,9 @@ public NewAction download( @Override public NewAction generate(FilesInterface files, String token, String baseUrl, String basePath, - String projectId, String source, String translation, String dest, Boolean preserveHierarchy, Path configDestPath, boolean skipGenerateDescription + String projectId, String source, String translation, Boolean preserveHierarchy, Path destinationPath, boolean skipGenerateDescription ) { - return new GenerateAction(files, token, baseUrl, basePath, projectId, source, translation, dest, preserveHierarchy, configDestPath, skipGenerateDescription); + return new GenerateAction(files, token, baseUrl, basePath, projectId, source, translation, preserveHierarchy, destinationPath, skipGenerateDescription); } @Override diff --git a/src/main/java/com/crowdin/cli/commands/actions/GenerateAction.java b/src/main/java/com/crowdin/cli/commands/actions/GenerateAction.java index 77cf79631..aa0d5ee3e 100644 --- a/src/main/java/com/crowdin/cli/commands/actions/GenerateAction.java +++ b/src/main/java/com/crowdin/cli/commands/actions/GenerateAction.java @@ -52,9 +52,8 @@ class GenerateAction implements NewAction { private final String projectId; private final String source; private final String translation; - private final String dest; private final Boolean preserveHierarchy; - private final Path configDestPath; + private final Path destinationPath; private final boolean skipGenerateDescription; @Override @@ -64,10 +63,10 @@ public void act(Outputter out, NoProperties noProperties, NoClient noClient) { try { out.println(String.format( RESOURCE_BUNDLE.getString("message.command_generate_description"), - configDestPath.toAbsolutePath())); - if (Files.exists(configDestPath)) { + destinationPath.toAbsolutePath())); + if (Files.exists(destinationPath)) { out.println(ExecutionStatus.SKIPPED.getIcon() + String.format( - RESOURCE_BUNDLE.getString("message.already_exists"), configDestPath.toAbsolutePath())); + RESOURCE_BUNDLE.getString("message.already_exists"), destinationPath.toAbsolutePath())); return; } @@ -76,7 +75,7 @@ public void act(Outputter out, NoProperties noProperties, NoClient noClient) { this.updateWithUserInputs(out, asking, fileLines); } files.writeToFile( - configDestPath.toString(), new ByteArrayInputStream(StringUtils.join(fileLines, "\n").getBytes(StandardCharsets.UTF_8))); + destinationPath.toString(), new ByteArrayInputStream(StringUtils.join(fileLines, "\n").getBytes(StandardCharsets.UTF_8))); out.println(String.format( RESOURCE_BUNDLE.getString("message.generate_successful"), this.isEnterprise ? ENTERPRISE_LINK : LINK)); @@ -168,13 +167,9 @@ private void updateWithUserInputs(Outputter out, Asking asking, List fil for (int i = 0; i < fileLines.size(); i++) { String keyToSearch = String.format("\"%s\"", entry.getKey()); if (fileLines.get(i).contains(keyToSearch)) { - String updatedLine; - if (PRESERVE_HIERARCHY.equals(entry.getKey())) { - updatedLine = fileLines.get(i).replace(String.valueOf(TRUE), entry.getValue()); - } else { - updatedLine = fileLines.get(i).replaceFirst(": \"*\"", String.format(": \"%s\"", Utils.regexPath(entry.getValue()))); - } - updatedLine = updatedLine.replace(" #", ""); + String updatedLine = PRESERVE_HIERARCHY.equals(entry.getKey()) ? + fileLines.get(i).replace(String.valueOf(TRUE), entry.getValue()) + : fileLines.get(i).replaceFirst(": \"*\"", String.format(": \"%s\"", Utils.regexPath(entry.getValue()))); fileLines.set(i, updatedLine); break; } @@ -189,7 +184,6 @@ private void setGivenParams(Map values) { Optional.ofNullable(projectId).ifPresent(v -> values.put(PROJECT_ID, projectId)); Optional.ofNullable(source).ifPresent(v -> values.put(SOURCE, source)); Optional.ofNullable(translation).ifPresent(v -> values.put(TRANSLATION, translation)); - Optional.ofNullable(dest).ifPresent(v -> values.put(DEST, dest)); Optional.ofNullable(preserveHierarchy).ifPresent(v -> values.put(PRESERVE_HIERARCHY, String.valueOf(preserveHierarchy))); } diff --git a/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java b/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java index 9a07fcd1a..910678cb8 100644 --- a/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java +++ b/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java @@ -17,38 +17,35 @@ aliases = CommandNames.ALIAS_GENERATE) public class GenerateSubcommand extends GenericActCommand { - @CommandLine.Option(names = {"-T", "--token"}, paramLabel = "...", descriptionKey = "params.token") + @CommandLine.Option(names = {"-T", "--token"}, paramLabel = "...", descriptionKey = "params.token", order = -2) private String token; - @CommandLine.Option(names = {"--base-url"}, paramLabel = "...", descriptionKey = "params.base-url") + @CommandLine.Option(names = {"--base-url"}, paramLabel = "...", descriptionKey = "params.base-url", order = -2) private String baseUrl; - @CommandLine.Option(names = {"--base-path"}, paramLabel = "...", descriptionKey = "params.base-path") + @CommandLine.Option(names = {"--base-path"}, paramLabel = "...", descriptionKey = "params.base-path", order = -2) private String basePath; - @CommandLine.Option(names = {"-i", "--project-id"}, paramLabel = "...", descriptionKey = "params.project-id") + @CommandLine.Option(names = {"-i", "--project-id"}, paramLabel = "...", descriptionKey = "params.project-id", order = -2) private String projectId; - @CommandLine.Option(names = {"-s", "--source"}, paramLabel = "...", descriptionKey = "params.source") + @CommandLine.Option(names = {"-s", "--source"}, paramLabel = "...", descriptionKey = "params.source", order = -2) private String source; - @CommandLine.Option(names = {"-t", "--translation"}, paramLabel = "...", descriptionKey = "params.translation") + @CommandLine.Option(names = {"-t", "--translation"}, paramLabel = "...", descriptionKey = "params.translation", order = -2) private String translation; - @CommandLine.Option(names = {"--dest"}, paramLabel = "...", descriptionKey = "params.dest") - private String dest; - - @CommandLine.Option(names = {"--preserve-hierarchy"}, negatable = true, paramLabel = "...", descriptionKey = "params.preserve-hierarchy") + @CommandLine.Option(names = {"--preserve-hierarchy"}, negatable = true, paramLabel = "...", descriptionKey = "params.preserve-hierarchy", order = -2) private Boolean preserveHierarchy; - @CommandLine.Option(names = {"-d", "--config-dest"}, paramLabel = "...", defaultValue = "crowdin.yml") - private Path configDestPath; + @CommandLine.Option(names = {"-d", "--destination"}, paramLabel = "...", descriptionKey = "crowdin.generate.destination", defaultValue = "crowdin.yml", order = -2) + private Path destinationPath; - @CommandLine.Option(names = "--skip-generate-description", hidden = true) + @CommandLine.Option(names = "--skip-generate-description", hidden = true, order = -2) private boolean skipGenerateDescription; protected NewAction getAction(Actions actions) { - return actions.generate(new FsFiles(), token, baseUrl, basePath, projectId, source, translation, dest, preserveHierarchy, configDestPath, skipGenerateDescription); + return actions.generate(new FsFiles(), token, baseUrl, basePath, projectId, source, translation, preserveHierarchy, destinationPath, skipGenerateDescription); } protected NoProperties getProperties(PropertiesBuilders propertiesBuilders, Outputter out) { diff --git a/src/test/java/com/crowdin/cli/commands/actions/CliActionsTest.java b/src/test/java/com/crowdin/cli/commands/actions/CliActionsTest.java index f88c334b0..f513e67ee 100644 --- a/src/test/java/com/crowdin/cli/commands/actions/CliActionsTest.java +++ b/src/test/java/com/crowdin/cli/commands/actions/CliActionsTest.java @@ -19,7 +19,7 @@ public void testDownload() { @Test public void testGenerate() { - assertNotNull(actions.generate(new FsFiles(), null, null, null, null, null, null, null, null, null, false)); + assertNotNull(actions.generate(new FsFiles(), null, null, null, null, null, null, null, null, false)); } @Test diff --git a/src/test/java/com/crowdin/cli/commands/actions/GenerateActionTest.java b/src/test/java/com/crowdin/cli/commands/actions/GenerateActionTest.java index 35eb02a27..bd8bcbad2 100644 --- a/src/test/java/com/crowdin/cli/commands/actions/GenerateActionTest.java +++ b/src/test/java/com/crowdin/cli/commands/actions/GenerateActionTest.java @@ -44,7 +44,7 @@ public void simpleTest() throws IOException { InputStream responsesIS = setResponses(false, false, "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class)); verify(files).writeToFile(anyString(), any()); @@ -55,7 +55,7 @@ public void simpleTest() throws IOException { public void userInputTest() throws IOException { FilesInterface files = mock(FilesInterface.class); - action = new GenerateAction(files, "token", "", ".", "42", "file.json", "translation.json", "dest", true, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, "token", "", ".", "42", "file.json", "translation.json", true, Paths.get(project.getBasePath() + "/crowdin.yml"), false); action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class)); verify(files).writeToFile(anyString(), any()); @@ -69,7 +69,7 @@ public void writeToFileThrowsTest() throws IOException { InputStream responsesIS = setResponses(false, false, "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); assertThrows(RuntimeException.class, () -> action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class))); verify(files).writeToFile(anyString(), any()); @@ -83,7 +83,7 @@ public void enterprisetest() throws IOException { InputStream responsesIS = setResponses(false, true, "undefined", "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); assertThrows(RuntimeException.class, () -> action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class))); verify(files).writeToFile(anyString(), any()); @@ -97,7 +97,7 @@ public void enterpriseUrlTest() throws IOException { InputStream responsesIS = setResponses(false, true, "https://undefined.crowdin.com", "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); assertThrows(RuntimeException.class, () -> action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class))); verify(files).writeToFile(anyString(), any()); @@ -111,7 +111,7 @@ public void enterpriseNoNametest() throws IOException { InputStream responsesIS = setResponses(false, true, "", "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); assertThrows(RuntimeException.class, () -> action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class))); verify(files).writeToFile(anyString(), any()); @@ -126,7 +126,7 @@ public void fileExists() throws IOException { InputStream responsesIS = setResponses(false, true, "https://undefined.crowdin.com", "apiToken", "42", "."); System.setIn(responsesIS); - action = new GenerateAction(files, null, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); + action = new GenerateAction(files, null, null, null, null, null, null, null, Paths.get(project.getBasePath() + "/crowdin.yml"), false); action.act(Outputter.getDefault(), new NoProperties(), mock(NoClient.class)); verifyNoMoreInteractions(files); diff --git a/src/test/java/com/crowdin/cli/commands/picocli/GenerateSubcommandTest.java b/src/test/java/com/crowdin/cli/commands/picocli/GenerateSubcommandTest.java index 7944dd351..93a60a168 100644 --- a/src/test/java/com/crowdin/cli/commands/picocli/GenerateSubcommandTest.java +++ b/src/test/java/com/crowdin/cli/commands/picocli/GenerateSubcommandTest.java @@ -12,7 +12,7 @@ public class GenerateSubcommandTest extends PicocliTestUtils { public void testGenerate() { this.execute(CommandNames.GENERATE); verify(actionsMock) - .generate(any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), anyBoolean()); + .generate(any(), any(), any(), any(), any(), any(), any(), any(), any(), anyBoolean()); this.check(false); } } diff --git a/src/test/java/com/crowdin/cli/commands/picocli/PicocliTestUtils.java b/src/test/java/com/crowdin/cli/commands/picocli/PicocliTestUtils.java index d774eea4e..7ff5b45b2 100644 --- a/src/test/java/com/crowdin/cli/commands/picocli/PicocliTestUtils.java +++ b/src/test/java/com/crowdin/cli/commands/picocli/PicocliTestUtils.java @@ -60,7 +60,7 @@ void mockActions() { when(actionsMock.download(any(), anyBoolean(), any(), any(), anyBoolean(), any(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean())) .thenReturn(actionMock); - when(actionsMock.generate(any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), anyBoolean())) + when(actionsMock.generate(any(), any(), any(), any(), any(), any(), any(), any(), any(), anyBoolean())) .thenReturn(actionMock); when(actionsMock.listBranches(anyBoolean(), anyBoolean())) .thenReturn(actionMock); From e1b3871aff1b847a710427d3a9a1240b28547d5f Mon Sep 17 00:00:00 2001 From: Andrii Bodnar Date: Fri, 20 Oct 2023 12:06:59 +0300 Subject: [PATCH 3/5] docs: add example for the init command --- website/mantemplates/crowdin-generate.adoc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/website/mantemplates/crowdin-generate.adoc b/website/mantemplates/crowdin-generate.adoc index b83bdbebb..4ce9b0d26 100644 --- a/website/mantemplates/crowdin-generate.adoc +++ b/website/mantemplates/crowdin-generate.adoc @@ -15,6 +15,23 @@ include::{includedir}/{command}.adoc[tag=picocli-generated-man-section-options] include::{includedir}/{command}.adoc[tag=picocli-generated-man-section-footer] +=== Examples + +Instead of interactive mode, you can also pass the parameters directly to the command: + +---- +crowdin init \ + --base-path "." \ + --base-url "https://api.crowdin.com" \ + -i "1" \ + -T "personal-access-token" \ + -s "/locales/**/*" \ + -t "/%two_letters_code%/%original_file_name%" \ + --preserve-hierarchy +---- + +As a result, the configuration file will be filled with the passed parameters. + === Notes *Warning*: The browser authorization token you receive has an expiration period of 30 days. This means that after 30 days, the token will expire and you need to generate a new token to continue using CLI. From d8c4d18ce94b17a04b8f82a9457220938e97fe77 Mon Sep 17 00:00:00 2001 From: Kateryna Oblakevych Date: Mon, 30 Oct 2023 04:23:17 +0200 Subject: [PATCH 4/5] file input test --- .../commands/picocli/GenerateSubcommand.java | 2 +- .../commands/actions/GenerateActionTest.java | 36 ++++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java b/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java index 910678cb8..532ea016e 100644 --- a/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java +++ b/src/main/java/com/crowdin/cli/commands/picocli/GenerateSubcommand.java @@ -41,7 +41,7 @@ public class GenerateSubcommand extends GenericActCommand