private static void checkNewNameOfAllModules(Set<ResourceDto> modules, String stringToReplace, String replacementString, ComponentKeyUpdaterMapper mapper) { | private static void checkNewNameOfAllModules(Set<ResourceDto> modules, String stringToReplace, String replacementString, ComponentKeyUpdaterMapper mapper) { | ||||
for (ResourceDto module : modules) { | for (ResourceDto module : modules) { | ||||
String newKey = computeNewKey(module.getKey(), stringToReplace, replacementString); | 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) { | if (mapper.countResourceByKey(newKey) > 0) { | ||||
throw new IllegalArgumentException("Impossible to update key: a component with key \"" + newKey + "\" already exists."); | throw new IllegalArgumentException("Impossible to update key: a component with key \"" + newKey + "\" already exists."); | ||||
} | } |
ComponentDto project = db.components().insertPrivateProject(); | ComponentDto project = db.components().insertPrivateProject(); | ||||
thrown.expect(IllegalArgumentException.class); | 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 | @Test | ||||
thrown.expect(IllegalArgumentException.class); | thrown.expect(IllegalArgumentException.class); | ||||
underTest.simulateBulkUpdateKey(dbSession, "A", "project", "project?"); | |||||
underTest.simulateBulkUpdateKey(dbSession, "A", "project", " "); | |||||
} | } | ||||
@Test | @Test |
} | } | ||||
private static void checkProjectOrModuleKeyFormat(String key) { | 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); | |||||
} | } | ||||
} | } |
} | } | ||||
private void checkKeyFormat(String qualifier, String key) { | 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) { | private void checkLegacyBranchFormat(String qualifier, @Nullable String branch) { |
logInAsProjectAdministrator(project); | logInAsProjectAdministrator(project); | ||||
expectedException.expect(BadRequestException.class); | 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, ""); | underTest.updateKey(dbSession, project, ""); | ||||
} | } | ||||
@Test | @Test | ||||
public void fail_if_new_key_is_not_formatted_correctly() { | |||||
public void fail_if_new_key_is_invalid() { | |||||
ComponentDto project = insertSampleRootProject(); | ComponentDto project = insertSampleRootProject(); | ||||
logInAsProjectAdministrator(project); | logInAsProjectAdministrator(project); | ||||
expectedException.expect(BadRequestException.class); | 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 | @Test |
@Test | @Test | ||||
public void fail_when_key_has_bad_format() { | public void fail_when_key_has_bad_format() { | ||||
expectedException.expect(BadRequestException.class); | expectedException.expect(BadRequestException.class); | ||||
expectedException.expectMessage("Malformed key for Project: 1234"); | |||||
expectedException.expectMessage("Malformed key for Project: ' '"); | |||||
underTest.create(db.getSession(), | underTest.create(db.getSession(), | ||||
NewComponent.newComponentBuilder() | NewComponent.newComponentBuilder() | ||||
.setKey("1234") | |||||
.setKey(" ") | |||||
.setName(DEFAULT_PROJECT_NAME) | .setName(DEFAULT_PROJECT_NAME) | ||||
.setOrganizationUuid(db.getDefaultOrganization().getUuid()) | .setOrganizationUuid(db.getDefaultOrganization().getUuid()) | ||||
.build(), | .build(), | ||||
@Test | @Test | ||||
public void properly_fail_when_key_contains_percent_character() { | public void properly_fail_when_key_contains_percent_character() { | ||||
expectedException.expect(BadRequestException.class); | expectedException.expect(BadRequestException.class); | ||||
expectedException.expectMessage("Malformed key for Project: project%Key"); | |||||
expectedException.expectMessage("Malformed key for Project: ' '"); | |||||
underTest.create(db.getSession(), | underTest.create(db.getSession(), | ||||
NewComponent.newComponentBuilder() | NewComponent.newComponentBuilder() | ||||
.setKey("project%Key") | |||||
.setKey(" ") | |||||
.setName(DEFAULT_PROJECT_NAME) | .setName(DEFAULT_PROJECT_NAME) | ||||
.setOrganizationUuid(db.getDefaultOrganization().getUuid()) | .setOrganizationUuid(db.getDefaultOrganization().getUuid()) | ||||
.build(), | .build(), |
insertMyProject(); | insertMyProject(); | ||||
expectedException.expect(IllegalArgumentException.class); | 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 | @Test | ||||
insertMyProject(); | insertMyProject(); | ||||
expectedException.expect(IllegalArgumentException.class); | 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 | @Test |
} | } | ||||
@Test | @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()); | userSession.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization()); | ||||
expectedException.expect(BadRequestException.class); | 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() | call(CreateRequest.builder() | ||||
.setKey("project%Key") | |||||
.setKey("project Key") | |||||
.setName(DEFAULT_PROJECT_NAME) | .setName(DEFAULT_PROJECT_NAME) | ||||
.build()); | .build()); | ||||
} | } |
public static final int MAX_COMPONENT_KEY_LENGTH = 400; | 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}\\-_.:/]*"; | private static final String VALID_PROJECT_KEY_ISSUES_MODE_REGEXP = "[\\p{Alnum}\\-_.:/]*[\\p{Alpha}\\-_.:/]+[\\p{Alnum}\\-_.:/]*"; | ||||
/* | /* | ||||
* Allowed characters are alphanumeric, '-', '_', '.' and '/' | * Allowed characters are alphanumeric, '-', '_', '.' and '/' | ||||
*/ | */ | ||||
} | } | ||||
/** | /** | ||||
* <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 | * @return <code>true</code> if <code>keyCandidate</code> can be used for a project | ||||
*/ | */ | ||||
* @throws IllegalArgumentException if the format is incorrect | * @throws IllegalArgumentException if the format is incorrect | ||||
*/ | */ | ||||
public static void checkProjectKey(String keyCandidate) { | 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) { | public static boolean isValidProjectKeyIssuesMode(String keyCandidate) { | ||||
return keyCandidate.matches(VALID_PROJECT_KEY_ISSUES_MODE_REGEXP); | return keyCandidate.matches(VALID_PROJECT_KEY_ISSUES_MODE_REGEXP); |
} | } | ||||
@Test | @Test | ||||
public void isValidModuleKey() { | |||||
assertThat(ComponentKeys.isValidProjectKey("")).isFalse(); | |||||
public void isValidProjectKey() { | |||||
assertThat(ComponentKeys.isValidProjectKey("abc")).isTrue(); | 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")).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 | @Test | ||||
} | } | ||||
@Test | @Test | ||||
public void checkModuleKey_with_correct_keys() { | |||||
public void checkProjectKey_with_correct_keys() { | |||||
ComponentKeys.checkProjectKey("abc"); | ComponentKeys.checkProjectKey("abc"); | ||||
ComponentKeys.checkProjectKey("a-b_1.:2"); | ComponentKeys.checkProjectKey("a-b_1.:2"); | ||||
} | } | ||||
@Test | @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); | expectedException.expect(IllegalArgumentException.class); | ||||
ComponentKeys.checkProjectKey(""); | ComponentKeys.checkProjectKey(""); | ||||
} | } | ||||
@Test | @Test | ||||
public void checkModuleKey_fail_if_space() { | |||||
public void checkProjectKey_fail_if_space() { | |||||
expectedException.expect(IllegalArgumentException.class); | expectedException.expect(IllegalArgumentException.class); | ||||
ComponentKeys.checkProjectKey("ab 12"); | ComponentKeys.checkProjectKey("ab 12"); | ||||
} | } | ||||
@Test | |||||
public void checkModuleKey_fail_if_special_characters_not_allowed() { | |||||
expectedException.expect(IllegalArgumentException.class); | |||||
ComponentKeys.checkProjectKey("ab/12"); | |||||
} | |||||
} | } |
private static void validateModule(ProjectDefinition moduleDef, List<String> validationMessages) { | private static void validateModule(ProjectDefinition moduleDef, List<String> validationMessages) { | ||||
if (!ComponentKeys.isValidProjectKey(moduleDef.getKey())) { | 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())); | |||||
} | } | ||||
} | } | ||||
public void allow_slash_issues_mode() { | public void allow_slash_issues_mode() { | ||||
when(mode.isIssues()).thenReturn(true); | when(mode.isIssues()).thenReturn(true); | ||||
underTest.validate(createProjectReactor("project/key")); | 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 | @Test | ||||
public void fail_with_invalid_key() { | 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.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); | underTest.validate(reactor); | ||||
} | } | ||||
}; | }; | ||||
} | } | ||||
@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 | @Test | ||||
public void fail_when_branch_name_is_specified_but_branch_plugin_not_present() { | public void fail_when_branch_name_is_specified_but_branch_plugin_not_present() { | ||||
ProjectDefinition def = ProjectDefinition.create().setProperty(CoreProperties.PROJECT_KEY_PROPERTY, "foo"); | ProjectDefinition def = ProjectDefinition.create().setProperty(CoreProperties.PROJECT_KEY_PROPERTY, "foo"); |