From bf7776ff7da0661c5a966a869e7dae1760fce038 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Beno=C3=AEt=20Gianinetti?= Date: Thu, 16 May 2019 14:18:42 +0200 Subject: [PATCH] SONARCLOUD-628 Allow UTF-8 characters in project key --- .../db/component/ComponentKeyUpdaterDao.java | 2 +- .../component/ComponentKeyUpdaterDaoTest.java | 6 ++-- .../server/component/ComponentService.java | 2 +- .../server/component/ComponentUpdater.java | 3 +- .../ComponentServiceUpdateKeyTest.java | 8 ++--- .../component/ComponentUpdaterTest.java | 8 ++--- .../project/ws/BulkUpdateKeyActionTest.java | 8 ++--- .../server/project/ws/CreateActionTest.java | 6 ++-- .../sonar/core/component/ComponentKeys.java | 36 ++++++++++--------- .../core/component/ComponentKeysTest.java | 35 +++++++----------- .../scanner/scan/ProjectReactorValidator.java | 3 +- .../scan/ProjectReactorValidatorTest.java | 28 ++------------- 12 files changed, 55 insertions(+), 90 deletions(-) diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java index 84d686173c9..3b2802be577 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java @@ -233,7 +233,7 @@ public class ComponentKeyUpdaterDao implements Dao { private static void checkNewNameOfAllModules(Set modules, String stringToReplace, String replacementString, ComponentKeyUpdaterMapper mapper) { for (ResourceDto module : modules) { String newKey = computeNewKey(module.getKey(), stringToReplace, replacementString); - checkArgument(isValidProjectKey(newKey), "Malformed key for '%s'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.", newKey); + checkProjectKey(newKey); if (mapper.countResourceByKey(newKey) > 0) { throw new IllegalArgumentException("Impossible to update key: a component with key \"" + newKey + "\" already exists."); } diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java index d41c321949e..faf276cf947 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java @@ -314,9 +314,9 @@ public class ComponentKeyUpdaterDaoTest { ComponentDto project = db.components().insertPrivateProject(); thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("Malformed key for 'my?project?key'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); + thrown.expectMessage("Malformed key for ' '. Project key cannot be empty nor contain whitespaces."); - underTest.bulkUpdateKey(dbSession, project.uuid(), project.getDbKey(), "my?project?key", doNotReturnAnyRekeyedResource()); + underTest.bulkUpdateKey(dbSession, project.uuid(), project.getDbKey(), " ", doNotReturnAnyRekeyedResource()); } @Test @@ -377,7 +377,7 @@ public class ComponentKeyUpdaterDaoTest { thrown.expect(IllegalArgumentException.class); - underTest.simulateBulkUpdateKey(dbSession, "A", "project", "project?"); + underTest.simulateBulkUpdateKey(dbSession, "A", "project", " "); } @Test diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java index f72e0c6803c..2b25909072c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java @@ -102,7 +102,7 @@ public class ComponentService { } private static void checkProjectOrModuleKeyFormat(String key) { - checkRequest(isValidProjectKey(key), "Malformed key for '%s'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.", key); + checkRequest(isValidProjectKey(key), "Malformed key for '%s'. It cannot be empty nor contain whitespaces.", key); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentUpdater.java index 974e4c9aafa..9a8db67b0a7 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentUpdater.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentUpdater.java @@ -163,8 +163,7 @@ public class ComponentUpdater { } private void checkKeyFormat(String qualifier, String key) { - checkRequest(isValidProjectKey(key), - "Malformed key for %s: %s. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.", getQualifierToDisplay(qualifier), key); + checkRequest(isValidProjectKey(key), "Malformed key for %s: '%s'. It cannot be empty nor contain whitespaces.", getQualifierToDisplay(qualifier), key); } private void checkLegacyBranchFormat(String qualifier, @Nullable String branch) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java index 706996052ab..66583ddfbf2 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java @@ -153,20 +153,20 @@ public class ComponentServiceUpdateKeyTest { logInAsProjectAdministrator(project); expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Malformed key for ''. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); + expectedException.expectMessage("Malformed key for ''. It cannot be empty nor contain whitespaces."); underTest.updateKey(dbSession, project, ""); } @Test - public void fail_if_new_key_is_not_formatted_correctly() { + public void fail_if_new_key_is_invalid() { ComponentDto project = insertSampleRootProject(); logInAsProjectAdministrator(project); expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Malformed key for 'sample?root'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); + expectedException.expectMessage("Malformed key for 'sample root'. It cannot be empty nor contain whitespaces."); - underTest.updateKey(dbSession, project, "sample?root"); + underTest.updateKey(dbSession, project, "sample root"); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java index 6581277f23f..9739cfae408 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java @@ -304,11 +304,11 @@ public class ComponentUpdaterTest { @Test public void fail_when_key_has_bad_format() { expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Malformed key for Project: 1234"); + expectedException.expectMessage("Malformed key for Project: ' '"); underTest.create(db.getSession(), NewComponent.newComponentBuilder() - .setKey("1234") + .setKey(" ") .setName(DEFAULT_PROJECT_NAME) .setOrganizationUuid(db.getDefaultOrganization().getUuid()) .build(), @@ -318,11 +318,11 @@ public class ComponentUpdaterTest { @Test public void properly_fail_when_key_contains_percent_character() { expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Malformed key for Project: project%Key"); + expectedException.expectMessage("Malformed key for Project: ' '"); underTest.create(db.getSession(), NewComponent.newComponentBuilder() - .setKey("project%Key") + .setKey(" ") .setName(DEFAULT_PROJECT_NAME) .setOrganizationUuid(db.getDefaultOrganization().getUuid()) .build(), diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkUpdateKeyActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkUpdateKeyActionTest.java index 726d87dbc73..aa3e20bf131 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkUpdateKeyActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkUpdateKeyActionTest.java @@ -183,9 +183,9 @@ public class BulkUpdateKeyActionTest { insertMyProject(); expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Malformed key for 'my?project'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); + expectedException.expectMessage("Malformed key for 'my aproject'. Project key cannot be empty nor contain whitespaces."); - callByKey(MY_PROJECT_KEY, FROM, "my?"); + callByKey(MY_PROJECT_KEY, FROM, "my a"); } @Test @@ -193,9 +193,9 @@ public class BulkUpdateKeyActionTest { insertMyProject(); expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Malformed key for 'my?project'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); + expectedException.expectMessage("Malformed key for 'my aproject'. Project key cannot be empty nor contain whitespaces."); - callDryRunByKey(MY_PROJECT_KEY, FROM, "my?"); + callDryRunByKey(MY_PROJECT_KEY, FROM, "my a"); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java index 5be7889c667..ebae2a8d207 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java @@ -305,14 +305,14 @@ public class CreateActionTest { } @Test - public void properly_fail_when_project_key_contains_percent_character() { + public void properly_fail_when_invalid_project_key() { userSession.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization()); expectedException.expect(BadRequestException.class); - expectedException.expectMessage("Malformed key for Project: project%Key. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); + expectedException.expectMessage("Malformed key for Project: 'project Key'. It cannot be empty nor contain whitespaces."); call(CreateRequest.builder() - .setKey("project%Key") + .setKey("project Key") .setName(DEFAULT_PROJECT_NAME) .build()); } diff --git a/sonar-core/src/main/java/org/sonar/core/component/ComponentKeys.java b/sonar-core/src/main/java/org/sonar/core/component/ComponentKeys.java index a3bb4fb1453..e4d59ea1dd8 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/ComponentKeys.java +++ b/sonar-core/src/main/java/org/sonar/core/component/ComponentKeys.java @@ -30,11 +30,12 @@ public final class ComponentKeys { public static final int MAX_COMPONENT_KEY_LENGTH = 400; /* - * Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit + * Must not be blank or empty */ - private static final String VALID_PROJECT_KEY_REGEXP = "[\\p{Alnum}\\-_.:]*[\\p{Alpha}\\-_.:]+[\\p{Alnum}\\-_.:]*"; + private static final String VALID_PROJECT_KEY_REGEXP = "[^\\p{javaWhitespace}]+"; private static final String VALID_PROJECT_KEY_ISSUES_MODE_REGEXP = "[\\p{Alnum}\\-_.:/]*[\\p{Alpha}\\-_.:/]+[\\p{Alnum}\\-_.:/]*"; + /* * Allowed characters are alphanumeric, '-', '_', '.' and '/' */ @@ -60,18 +61,7 @@ public final class ComponentKeys { } /** - *

Test if given parameter is valid for a project. Valid format is:

- * + * Test if given parameter is valid for a project. A key is valid if it doesn't contain whitespaces. * * @return true if keyCandidate can be used for a project */ @@ -85,12 +75,24 @@ public final class ComponentKeys { * @throws IllegalArgumentException if the format is incorrect */ public static void checkProjectKey(String keyCandidate) { - checkArgument(isValidProjectKey(keyCandidate), "Malformed key for '%s'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.", - keyCandidate); + checkArgument(isValidProjectKey(keyCandidate), "Malformed key for '%s'. %s", keyCandidate, "Project key cannot be empty nor contain whitespaces."); } /** - * Same as {@link #isValidProjectKey(String)}, but allows additionally '/'. + *

Test if given parameter is valid for a project. Valid format is:

+ * + * + * @return true if keyCandidate can be used for a project in issues mode */ public static boolean isValidProjectKeyIssuesMode(String keyCandidate) { return keyCandidate.matches(VALID_PROJECT_KEY_ISSUES_MODE_REGEXP); diff --git a/sonar-core/src/test/java/org/sonar/core/component/ComponentKeysTest.java b/sonar-core/src/test/java/org/sonar/core/component/ComponentKeysTest.java index a328a0c586b..7f555664e29 100644 --- a/sonar-core/src/test/java/org/sonar/core/component/ComponentKeysTest.java +++ b/sonar-core/src/test/java/org/sonar/core/component/ComponentKeysTest.java @@ -47,13 +47,17 @@ public class ComponentKeysTest { } @Test - public void isValidModuleKey() { - assertThat(ComponentKeys.isValidProjectKey("")).isFalse(); + public void isValidProjectKey() { assertThat(ComponentKeys.isValidProjectKey("abc")).isTrue(); - assertThat(ComponentKeys.isValidProjectKey("0123")).isFalse(); - assertThat(ComponentKeys.isValidProjectKey("ab 12")).isFalse(); + assertThat(ComponentKeys.isValidProjectKey("0123")).isTrue(); assertThat(ComponentKeys.isValidProjectKey("ab_12")).isTrue(); - assertThat(ComponentKeys.isValidProjectKey("ab/12")).isFalse(); + assertThat(ComponentKeys.isValidProjectKey("ab/12")).isTrue(); + assertThat(ComponentKeys.isValidProjectKey("코드품질")).isTrue(); + assertThat(ComponentKeys.isValidProjectKey("")).isFalse(); + assertThat(ComponentKeys.isValidProjectKey(" ")).isFalse(); + assertThat(ComponentKeys.isValidProjectKey("ab 12")).isFalse(); + assertThat(ComponentKeys.isValidProjectKey(" ab")).isFalse(); + assertThat(ComponentKeys.isValidProjectKey("ab ")).isFalse(); } @Test @@ -79,37 +83,22 @@ public class ComponentKeysTest { } @Test - public void checkModuleKey_with_correct_keys() { + public void checkProjectKey_with_correct_keys() { ComponentKeys.checkProjectKey("abc"); ComponentKeys.checkProjectKey("a-b_1.:2"); } @Test - public void checkModuleKey_fail_if_only_digit() { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Malformed key for '0123'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); - - ComponentKeys.checkProjectKey("0123"); - } - - @Test - public void checkModuleKey_fail_if_key_is_empty() { + public void checkProjectKey_fail_if_key_is_empty() { expectedException.expect(IllegalArgumentException.class); ComponentKeys.checkProjectKey(""); } @Test - public void checkModuleKey_fail_if_space() { + public void checkProjectKey_fail_if_space() { expectedException.expect(IllegalArgumentException.class); ComponentKeys.checkProjectKey("ab 12"); } - - @Test - public void checkModuleKey_fail_if_special_characters_not_allowed() { - expectedException.expect(IllegalArgumentException.class); - - ComponentKeys.checkProjectKey("ab/12"); - } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java index c49d685c9c3..d16261393e9 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java @@ -117,8 +117,7 @@ public class ProjectReactorValidator { private static void validateModule(ProjectDefinition moduleDef, List validationMessages) { if (!ComponentKeys.isValidProjectKey(moduleDef.getKey())) { - validationMessages.add(format("\"%s\" is not a valid project or module key. " - + "Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.", moduleDef.getKey())); + validationMessages.add(format("\"%s\" is not a valid project or module key. It cannot be empty nor contain whitespaces.", moduleDef.getKey())); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java index 90ec4d316d3..cfda303ff0d 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java @@ -91,28 +91,14 @@ public class ProjectReactorValidatorTest { public void allow_slash_issues_mode() { when(mode.isIssues()).thenReturn(true); underTest.validate(createProjectReactor("project/key")); - - when(mode.isIssues()).thenReturn(false); - thrown.expect(MessageException.class); - thrown.expectMessage("is not a valid project or module key"); - underTest.validate(createProjectReactor("project/key")); } @Test public void fail_with_invalid_key() { - ProjectReactor reactor = createProjectReactor("foo$bar"); - - thrown.expect(MessageException.class); - thrown.expectMessage("\"foo$bar\" is not a valid project or module key"); - underTest.validate(reactor); - } - - @Test - public void fail_with_backslash_in_key() { - ProjectReactor reactor = createProjectReactor("foo\\bar"); + ProjectReactor reactor = createProjectReactor(" "); thrown.expect(MessageException.class); - thrown.expectMessage("\"foo\\bar\" is not a valid project or module key"); + thrown.expectMessage("\" \" is not a valid project or module key"); underTest.validate(reactor); } @@ -155,16 +141,6 @@ public class ProjectReactorValidatorTest { }; } - @Test - public void fail_with_only_digits() { - ProjectReactor reactor = createProjectReactor("12345"); - - thrown.expect(MessageException.class); - thrown.expectMessage("\"12345\" is not a valid project or module key"); - - underTest.validate(reactor); - } - @Test public void fail_when_branch_name_is_specified_but_branch_plugin_not_present() { ProjectDefinition def = ProjectDefinition.create().setProperty(CoreProperties.PROJECT_KEY_PROPERTY, "foo"); -- 2.39.5