]> source.dussan.org Git - sonarqube.git/commitdiff
SONARCLOUD-628 Allow UTF-8 characters in project key
authorBenoît Gianinetti <benoit.gianinetti@sonarsource.com>
Thu, 16 May 2019 12:18:42 +0000 (14:18 +0200)
committerSonarTech <sonartech@sonarsource.com>
Mon, 20 May 2019 18:21:07 +0000 (20:21 +0200)
12 files changed:
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentKeyUpdaterDaoTest.java
server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java
server/sonar-server/src/main/java/org/sonar/server/component/ComponentUpdater.java
server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceUpdateKeyTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java
server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkUpdateKeyActionTest.java
server/sonar-server/src/test/java/org/sonar/server/project/ws/CreateActionTest.java
sonar-core/src/main/java/org/sonar/core/component/ComponentKeys.java
sonar-core/src/test/java/org/sonar/core/component/ComponentKeysTest.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java

index 84d686173c9580e78fd6c37dc77d30d690a57af9..3b2802be57732136975cfd592ca5ea908d0cf6cb 100644 (file)
@@ -233,7 +233,7 @@ public class ComponentKeyUpdaterDao implements Dao {
   private static void checkNewNameOfAllModules(Set<ResourceDto> 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.");
       }
index d41c321949e445aab315895be6e10f220b415149..faf276cf9476b3c121a72ddd8b7cdf73bdc228bc 100644 (file)
@@ -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
index f72e0c6803c8d2d154632ea867ccdb719aa1af1b..2b25909072cece28f09df2fbc5bae576a7e1c7b5 100644 (file)
@@ -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);
   }
 
 }
index 974e4c9aafa639ebe62491d7808de6c4785f80c5..9a8db67b0a7e89b3791ccc74396f6fd8a97169aa 100644 (file)
@@ -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) {
index 706996052ab4fe6446b41ffa2734065bd1944368..66583ddfbf26fc73d8865f1441726d56f4e34c42 100644 (file)
@@ -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
index 6581277f23f9768882f357b3501255f0bf3c6bca..9739cfae408ee6b72bf1eb6d0b2104552d11b10d 100644 (file)
@@ -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(),
index 726d87dbc73feead002856083c8504adbfabac30..aa3e20bf13197397c83c31906e95d75b95fe915a 100644 (file)
@@ -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
index 5be7889c66724f73acdc08c42d520b1a42645df3..ebae2a8d2078fb81f58a2912e1faa377eef8dad4 100644 (file)
@@ -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());
   }
index a3bb4fb14533e9dd65d408cda1add490e040f0cd..e4d59ea1dd82921e5bca72fcc84808f5ccb5ea70 100644 (file)
@@ -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 {
   }
 
   /**
-   * <p>Test if given parameter is valid for a project. Valid format is:</p>
-   * <ul>
-   * <li>Allowed characters:
-   * <ul>
-   * <li>Uppercase ASCII letters A-Z</li>
-   * <li>Lowercase ASCII letters a-z</li>
-   * <li>ASCII digits 0-9</li>
-   * <li>Punctuation signs dash '-', underscore '_', period '.' and colon ':'</li>
-   * </ul>
-   * </li>
-   * <li>At least one non-digit</li>
-   * </ul>
+   * Test if given parameter is valid for a project. A key is valid if it doesn't contain whitespaces.
    *
    * @return <code>true</code> if <code>keyCandidate</code> 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 '/'.
+   * <p>Test if given parameter is valid for a project. Valid format is:</p>
+   * <ul>
+   * <li>Allowed characters:
+   * <ul>
+   * <li>Uppercase ASCII letters A-Z</li>
+   * <li>Lowercase ASCII letters a-z</li>
+   * <li>ASCII digits 0-9</li>
+   * <li>Punctuation signs dash '-', underscore '_', period '.', colon ':' and slash '/'</li>
+   * </ul>
+   * </li>
+   * <li>At least one non-digit</li>
+   * </ul>
+   *
+   * @return <code>true</code> if <code>keyCandidate</code> can be used for a project in issues mode
    */
   public static boolean isValidProjectKeyIssuesMode(String keyCandidate) {
     return keyCandidate.matches(VALID_PROJECT_KEY_ISSUES_MODE_REGEXP);
index a328a0c586b8bb7ee697d9484c93ebe2d8c9da25..7f555664e298ddf57f3dacd99f5f9de3506377f0 100644 (file)
@@ -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");
-  }
 }
index c49d685c9c31918115b0b3e19d29c18d395bc728..d16261393e91c4c382983055506cf022e68390c1 100644 (file)
@@ -117,8 +117,7 @@ public class ProjectReactorValidator {
 
   private static void validateModule(ProjectDefinition moduleDef, List<String> 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()));
     }
   }
 
index 90ec4d316d3ba357fa284ae4a6cdcff149c8bb6b..cfda303ff0d91db53f0ca0607fef8581d855b6db 100644 (file)
@@ -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");