diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b7b9b6e..b5cf6aa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +# [3.19.0](https://github.com/crowdin/crowdin-cli/compare/3.18.0...3.19.0) (2024-03-19) + + +### Bug Fixes + +* double asterisks in paths ([#733](https://github.com/crowdin/crowdin-cli/issues/733)) ([aa99d5e](https://github.com/crowdin/crowdin-cli/commit/aa99d5e55d1150bb91003b165b812ef7bc5eae7d)) +* label descriptions ([#723](https://github.com/crowdin/crowdin-cli/issues/723)) ([04a76c8](https://github.com/crowdin/crowdin-cli/commit/04a76c8e033aa9f7235ef67c2655ef2dfc906ffe)) +* message for strings based project when download ([#729](https://github.com/crowdin/crowdin-cli/issues/729)) ([c280608](https://github.com/crowdin/crowdin-cli/commit/c280608b0b7e8605b3107102b19200b377b29cbe)) +* preserve hierarchy output ([#738](https://github.com/crowdin/crowdin-cli/issues/738)) ([976f01d](https://github.com/crowdin/crowdin-cli/commit/976f01dff43cd4f5b9e66852665914da4d6d3940)) + + +### Features + +* label option for screenshot upload command ([#721](https://github.com/crowdin/crowdin-cli/issues/721)) ([bb57d11](https://github.com/crowdin/crowdin-cli/commit/bb57d1164f7bf7d72848d27065dfea286ac6bee5)) +* label option for string list command ([#722](https://github.com/crowdin/crowdin-cli/issues/722)) ([369ef8d](https://github.com/crowdin/crowdin-cli/commit/369ef8d5fdff14da2bf82b2eafdd9a07030b43b6)) +* multilingual option ([#725](https://github.com/crowdin/crowdin-cli/issues/725)) ([31e2053](https://github.com/crowdin/crowdin-cli/commit/31e20536da54562b9dbfc68d28ba887051e6968c)) +* plural strings ([#731](https://github.com/crowdin/crowdin-cli/issues/731)) ([503a974](https://github.com/crowdin/crowdin-cli/commit/503a974bc037521a9f34f0d25f465535f36e7fc6)) +* set http timeout ([#734](https://github.com/crowdin/crowdin-cli/issues/734)) ([690cb22](https://github.com/crowdin/crowdin-cli/commit/690cb22b59460154278cf59fd5c595b70b2c0107)) + # [3.18.0](https://github.com/crowdin/crowdin-cli/compare/3.17.0...3.18.0) (2024-02-07) diff --git a/build.gradle b/build.gradle index ea501e21..1b8de128 100755 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ plugins { } group 'com.crowdin' -version '3.18.0' +version '3.19.0' sourceCompatibility = 1.8 diff --git a/package-lock.json b/package-lock.json index fe51f27d..31dcc28d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@crowdin/cli", - "version": "3.18.0", + "version": "3.19.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@crowdin/cli", - "version": "3.18.0", + "version": "3.19.0", "license": "MIT", "dependencies": { "command-exists-promise": "^2.0.2", diff --git a/package.json b/package.json index 12591a69..c3950b12 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "type": "git", "url": "https://github.com/crowdin/crowdin-cli.git" }, - "version": "3.18.0", + "version": "3.19.0", "bin": { "crowdin": "jdeploy-bundle/jdeploy.js" }, diff --git a/packages/aur/pkgbuild/PKGBUILD b/packages/aur/pkgbuild/PKGBUILD index 4d8b38a4..b982e43b 100644 --- a/packages/aur/pkgbuild/PKGBUILD +++ b/packages/aur/pkgbuild/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: Senya pkgname=crowdin-cli -pkgver=3.18.0 +pkgver=3.19.0 pkgrel=1 pkgdesc="Command line tool that allows you to manage and synchronize localization resources with your Crowdin project" url="https://support.crowdin.com/cli-tool/" diff --git a/packages/chocolatey/crowdin-cli.nuspec b/packages/chocolatey/crowdin-cli.nuspec index 21196cc3..272883ac 100644 --- a/packages/chocolatey/crowdin-cli.nuspec +++ b/packages/chocolatey/crowdin-cli.nuspec @@ -2,7 +2,7 @@ crowdin-cli - 3.18.0 + 3.19.0 https://github.com/crowdin/crowdin-cli/tree/main/packages/chocolatey crowdin Crowdin CLI (Portable) diff --git a/packages/chocolatey/tools/chocolateyinstall.ps1 b/packages/chocolatey/tools/chocolateyinstall.ps1 index 049f6cf3..357ed681 100644 --- a/packages/chocolatey/tools/chocolateyinstall.ps1 +++ b/packages/chocolatey/tools/chocolateyinstall.ps1 @@ -7,7 +7,7 @@ $packageArgs = @{ packageName = $packageName unzipLocation = $toolsDir url = 'https://github.com/crowdin/crowdin-cli/releases/latest/download/crowdin-cli.zip' - checksum = 'a8e57a5ca8342864194ea97feaeeab58cc234dc6da7e43eabfba649d4aef3185' + checksum = '13c239c96384199c22337a07866661be9a6e08058b0c5c7b5fb0d57e8dbd5be5' checksumType = 'sha256' } Install-ChocolateyZipPackage @packageArgs diff --git a/src/main/java/com/crowdin/cli/client/Clients.java b/src/main/java/com/crowdin/cli/client/Clients.java index 73595db0..2073ee95 100644 --- a/src/main/java/com/crowdin/cli/client/Clients.java +++ b/src/main/java/com/crowdin/cli/client/Clients.java @@ -11,6 +11,8 @@ public final class Clients { + private static final int TIMEOUT = 30 * 60 * 1000; //30 minĖš + private Clients() {} public static NoClient noClient() { @@ -65,7 +67,7 @@ public static ProjectClient getProjectClient(String apiToken, String baseUrl, lo return new CrowdinProjectClient(client, projectId); } - public static com.crowdin.client.Client prepareClient(String apiToken, String baseUrl) { + private static com.crowdin.client.Client prepareClient(String apiToken, String baseUrl) { boolean isTesting = PropertiesBeanUtils.isUrlForTesting(baseUrl); String organization = PropertiesBeanUtils.getOrganization(baseUrl); Credentials credentials = (isTesting) @@ -74,6 +76,7 @@ public static com.crowdin.client.Client prepareClient(String apiToken, String ba ClientConfig clientConfig = ClientConfig.builder() .jsonTransformer(new JacksonJsonTransformer()) .userAgent(Utils.buildUserAgent()) + .httpTimeoutMs(TIMEOUT) .build(); Utils.proxyHost() .map(pair -> new ClientConfig.Host(pair.getKey(), pair.getValue())) diff --git a/src/main/java/com/crowdin/cli/commands/actions/DownloadSourcesAction.java b/src/main/java/com/crowdin/cli/commands/actions/DownloadSourcesAction.java index 95fb2f9a..cc254df3 100644 --- a/src/main/java/com/crowdin/cli/commands/actions/DownloadSourcesAction.java +++ b/src/main/java/com/crowdin/cli/commands/actions/DownloadSourcesAction.java @@ -88,6 +88,10 @@ public void act(Outputter out, PropertiesWithFiles properties, ProjectClient cli return; } + if (!plainView && !properties.getPreserveHierarchy()) { + out.println(WARNING.withIcon(RESOURCE_BUNDLE.getString("message.download_sources.preserve_hierarchy_warning"))); + } + CrowdinProjectFull project = ConsoleSpinner .execute(out, "message.spinner.fetching_project_info", "error.collect_project_info", this.noProgress, this.plainView, () -> client.downloadFullProject(this.branchName)); @@ -96,10 +100,6 @@ public void act(Outputter out, PropertiesWithFiles properties, ProjectClient cli throw new RuntimeException(RESOURCE_BUNDLE.getString("message.no_file_string_project")); } - if (!plainView && !properties.getPreserveHierarchy()) { - out.println(WARNING.withIcon(RESOURCE_BUNDLE.getString("message.download_sources.preserve_hierarchy_warning"))); - } - Long branchId = Optional.ofNullable(project.getBranch()) .map(Branch::getId) .orElse(null); diff --git a/src/main/java/com/crowdin/cli/utils/PlaceholderUtil.java b/src/main/java/com/crowdin/cli/utils/PlaceholderUtil.java index 9257f9d5..e5cdabb8 100644 --- a/src/main/java/com/crowdin/cli/utils/PlaceholderUtil.java +++ b/src/main/java/com/crowdin/cli/utils/PlaceholderUtil.java @@ -64,7 +64,7 @@ public class PlaceholderUtil { private static final String ESCAPE_ASTERISK = isWindows() ? "^*" : "\\*"; private static final String ESCAPE_ASTERISK_REGEX = "\\*"; private static final String ESCAPE_ASTERISK_PLACEHOLDER = "{ESCAPE_ASTERISK}"; - private static final String ESCAPE_ASTERISK_REPLACEMENT_FROM = ".+" + Utils.PATH_SEPARATOR; + private static final String ESCAPE_ASTERISK_REPLACEMENT_FROM = ".+" + Utils.PATH_SEPARATOR_REGEX; private static final String ESCAPE_ASTERISK_REPLACEMENT_TO = "(.+" + Utils.PATH_SEPARATOR_REGEX + ")?"; private List supportedLanguages; @@ -193,10 +193,12 @@ public String replaceFileDependentPlaceholders(String toFormat, File file) { toFormat = toFormat.replace("/", File.separator); if (toFormat.contains("**")) { - String prefix = StringUtils.substringBefore(toFormat, "**"); - prefix = prefix.length() > 1 && file.getPath().contains(prefix) ? StringUtils.substringBefore(fileParent, Utils.noSepAtStart(prefix)) : ""; + String prefixFormat = StringUtils.substringBefore(toFormat, "**"); + String postfix = Utils.getParentDirectory(StringUtils.substringAfter(toFormat, "**")); + String prefix = prefixFormat.length() > 1 && file.getPath().contains(prefixFormat) ? StringUtils.substringBefore(fileParent, Utils.noSepAtStart(prefixFormat)) : ""; String doubleAsterisks = - StringUtils.removeStart(Utils.noSepAtStart(StringUtils.removeStart(fileParent, prefix)), Utils.noSepAtEnd(Utils.noSepAtStart(StringUtils.substringBefore(toFormat, "**")))); + StringUtils.removeStart(Utils.noSepAtStart(StringUtils.removeStart(fileParent, prefix)), Utils.noSepAtEnd(Utils.noSepAtStart(prefixFormat))); + doubleAsterisks = postfix.length() > 1 ? StringUtils.removeEnd(doubleAsterisks, Utils.noSepAtEnd(postfix)) : doubleAsterisks; toFormat = toFormat.replace("**", doubleAsterisks); } diff --git a/src/main/resources/crowdin.properties b/src/main/resources/crowdin.properties index 95ca9757..360f0535 100755 --- a/src/main/resources/crowdin.properties +++ b/src/main/resources/crowdin.properties @@ -1,4 +1,4 @@ application.name=crowdin-cli -application.version=3.18.0 +application.version=3.19.0 application.base_url=https://api.crowdin.com application.version_file_url=https://github.com/crowdin/crowdin-cli/releases/latest/download/version.txt diff --git a/src/test/java/com/crowdin/cli/commands/actions/DownloadSourcesActionTest.java b/src/test/java/com/crowdin/cli/commands/actions/DownloadSourcesActionTest.java index a37d0ed4..3958af3e 100644 --- a/src/test/java/com/crowdin/cli/commands/actions/DownloadSourcesActionTest.java +++ b/src/test/java/com/crowdin/cli/commands/actions/DownloadSourcesActionTest.java @@ -83,6 +83,42 @@ public void testDest() throws IOException { verifyNoMoreInteractions(files); } + @Test + public void testDest_doubleAsterisks() throws IOException { + PropertiesWithFiles pb = NewPropertiesWithFilesUtilBuilder + .minimalBuiltPropertiesBean( + Utils.normalizePath("/values/**/res/strings.xml"), Utils.normalizePath("/values/**/%two_letters_code%/%original_file_name%"), + null, Utils.normalizePath("/common/**/%original_file_name%")) + .setBasePath(project.getBasePath()) + .setPreserveHierarchy(true) + .build(); + + ProjectClient client = mock(ProjectClient.class); + when(client.downloadFullProject(null)) + .thenReturn(ProjectBuilder.emptyProject(Long.parseLong(pb.getProjectId())) + .addDirectory("common", 201L, null, null) + .addDirectory("values", 202L, 201L, null) + .addDirectory("first", 203L, 202L, null) + .addDirectory("second", 204L, 203L, null) + .addFile("strings.xml", "gettext", 101L, 204L, null, Utils.normalizePath("/values/first/second/%two_letters_code%/%original_file_name%")).build()); + URL urlMock = MockitoUtils.getMockUrl(getClass()); + when(client.downloadFile(eq(101L))) + .thenReturn(urlMock); + + FilesInterface files = mock(FilesInterface.class); + + NewAction action = + new DownloadSourcesAction(files, false, false, null, true, false, false); + action.act(Outputter.getDefault(), pb, client); + + verify(client).downloadFullProject(null); + verify(client).downloadFile(eq(101L)); + verifyNoMoreInteractions(client); + + verify(files).writeToFile(eq(Utils.joinPaths(project.getBasePath(), "values/first/second/res/strings.xml")), any()); + verifyNoMoreInteractions(files); + } + @Test public void testDestAndUnaryAsterisk() throws IOException { PropertiesWithFiles pb = NewPropertiesWithFilesUtilBuilder diff --git a/src/test/java/com/crowdin/cli/utils/PlaceholderUtilTest.java b/src/test/java/com/crowdin/cli/utils/PlaceholderUtilTest.java index 164eb3c2..400b985f 100644 --- a/src/test/java/com/crowdin/cli/utils/PlaceholderUtilTest.java +++ b/src/test/java/com/crowdin/cli/utils/PlaceholderUtilTest.java @@ -66,6 +66,13 @@ static Stream testMainFunctionality() { new File[] {new File("resources/messages.xml")}, Utils.normalizePath("/**/%two_letters_code%_%original_file_name%"), new String[] {Utils.normalizePath("resources/en_messages.xml")} + ), + arguments(// How to treat double asterisks in the middle + new Language[] {LanguageBuilder.ENG.build()}, + new Language[] {LanguageBuilder.ENG.build()}, + new File[] {new File("resources/main/settings/default/messages.xml")}, + Utils.normalizePath("app/**/default/%two_letters_code%_%original_file_name%"), + new String[] {Utils.normalizePath("app/resources/main/settings/default/en_messages.xml")} ) ); } diff --git a/versions.properties b/versions.properties index ec0b3de4..f73b3db9 100644 --- a/versions.properties +++ b/versions.properties @@ -43,7 +43,7 @@ version.commons-io..commons-io=2.14.0 version.commons-cli..commons-cli=1.5.0 -version.com.github.crowdin..crowdin-api-client-java=1.15.0 +version.com.github.crowdin..crowdin-api-client-java=1.15.1 plugin.org.asciidoctor.jvm.convert=3.3.2 diff --git a/website/package-lock.json b/website/package-lock.json index 1f1e9e20..66bdc86f 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -6513,9 +6513,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -17729,9 +17729,9 @@ } }, "follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==" + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" }, "fork-ts-checker-webpack-plugin": { "version": "6.5.3",