Co-authored-by: Lukasz Jarocki <lukasz.jarocki@sonarsource.com> Co-authored-by: Philippe Perrin <philippe.perrin@sonarsource.com> Co-authored-by: MikeBirnstiehl <michael.birnstiehl@sonarsource.com>tags/9.1.0.47736
@@ -20,18 +20,10 @@ | |||
package org.sonar.db.component; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import com.google.common.collect.Lists; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.Set; | |||
import java.util.function.BiConsumer; | |||
import java.util.function.Function; | |||
import java.util.function.Predicate; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.resources.Qualifiers; | |||
@@ -41,7 +33,6 @@ import org.sonar.db.DbSession; | |||
import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.ComponentKeyNewValue; | |||
import static org.sonar.core.component.ComponentKeys.checkProjectKey; | |||
import static org.sonar.db.component.ComponentDto.BRANCH_KEY_SEPARATOR; | |||
import static org.sonar.db.component.ComponentDto.generateBranchKey; | |||
@@ -108,87 +99,11 @@ public class ComponentKeyUpdaterDao implements Dao { | |||
} | |||
} | |||
/** | |||
* | |||
* @return a map with currentKey/newKey is a bulk update was executed | |||
*/ | |||
public Map<String, String> simulateBulkUpdateKey(DbSession dbSession, String projectUuid, String stringToReplace, String replacementString) { | |||
return collectAllModules(projectUuid, stringToReplace, mapper(dbSession), false) | |||
.stream() | |||
.collect(Collectors.toMap( | |||
ResourceDto::getKey, | |||
component -> { | |||
String newKey = computeNewKey(component.getKey(), stringToReplace, replacementString); | |||
checkProjectKey(newKey); | |||
return newKey; | |||
})); | |||
} | |||
/** | |||
* @return a map with the component key as key, and boolean as true if key already exists in db | |||
*/ | |||
public Map<String, Boolean> checkComponentKeys(DbSession dbSession, List<String> newComponentKeys) { | |||
return newComponentKeys.stream().collect(Collectors.toMap(Function.identity(), key -> mapper(dbSession).countResourceByKey(key) > 0)); | |||
} | |||
@VisibleForTesting | |||
static String computeNewKey(String key, String stringToReplace, String replacementString) { | |||
return key.replace(stringToReplace, replacementString); | |||
} | |||
public Set<RekeyedResource> bulkUpdateKey(DbSession session, String projectUuid, String stringToReplace, String replacementString, | |||
Predicate<RekeyedResource> rekeyedResourceFilter) { | |||
ComponentKeyUpdaterMapper mapper = session.getMapper(ComponentKeyUpdaterMapper.class); | |||
// must SELECT first everything | |||
Set<ResourceDto> modules = collectAllModules(projectUuid, stringToReplace, mapper, true); | |||
checkNewNameOfAllModules(modules, stringToReplace, replacementString, mapper); | |||
// add branches (no check should be done as branch keys cannot be changed by the user) | |||
Map<String, String> branchBaseKeys = new HashMap<>(); | |||
session.getMapper(BranchMapper.class).selectByProjectUuid(projectUuid).stream() | |||
.filter(branch -> !projectUuid.equals(branch.getUuid())) | |||
.forEach(branch -> { | |||
Set<ResourceDto> branchModules = collectAllModules(branch.getUuid(), stringToReplace, mapper, true); | |||
modules.addAll(branchModules); | |||
branchModules.forEach(module -> branchBaseKeys.put(module.getKey(), branchBaseKey(module.getKey()))); | |||
}); | |||
Map<ResourceDto, List<ResourceDto>> allResourcesByModuleMap = new HashMap<>(); | |||
for (ResourceDto module : modules) { | |||
allResourcesByModuleMap.put(module, mapper.selectProjectResources(module.getUuid())); | |||
} | |||
Set<RekeyedResource> rekeyedResources = new HashSet<>(); | |||
// and then proceed with the batch UPDATE at once | |||
for (ResourceDto module : modules) { | |||
String oldModuleKey = module.getKey(); | |||
oldModuleKey = branchBaseKeys.getOrDefault(oldModuleKey, oldModuleKey); | |||
String newModuleKey = computeNewKey(oldModuleKey, stringToReplace, replacementString); | |||
Collection<ResourceDto> resources = Lists.newArrayList(module); | |||
resources.addAll(allResourcesByModuleMap.get(module)); | |||
runBatchUpdateForAllResources(resources, oldModuleKey, newModuleKey, mapper, | |||
(resource, oldKey) -> { | |||
RekeyedResource rekeyedResource = new RekeyedResource(resource, oldKey); | |||
if (rekeyedResourceFilter.test(rekeyedResource)) { | |||
rekeyedResources.add(rekeyedResource); | |||
} | |||
}, session); | |||
} | |||
return rekeyedResources; | |||
} | |||
private static String branchBaseKey(String key) { | |||
int index = key.lastIndexOf(ComponentDto.BRANCH_KEY_SEPARATOR); | |||
if (index > -1) { | |||
return key.substring(0, index); | |||
} | |||
index = key.lastIndexOf(ComponentDto.PULL_REQUEST_SEPARATOR); | |||
if (index > -1) { | |||
return key.substring(0, index); | |||
} | |||
return key; | |||
} | |||
private void runBatchUpdateForAllResources(Collection<ResourceDto> resources, String oldKey, String newKey, ComponentKeyUpdaterMapper mapper, | |||
@Nullable BiConsumer<ResourceDto, String> consumer, DbSession dbSession) { | |||
for (ResourceDto resource : resources) { | |||
@@ -250,26 +165,6 @@ public class ComponentKeyUpdaterDao implements Dao { | |||
} | |||
} | |||
private static Set<ResourceDto> collectAllModules(String projectUuid, String stringToReplace, ComponentKeyUpdaterMapper mapper, boolean includeDisabled) { | |||
ResourceDto project = mapper.selectProjectByUuid(projectUuid); | |||
Set<ResourceDto> modules = new HashSet<>(); | |||
if (project.getKey().contains(stringToReplace) && (project.isEnabled() || includeDisabled)) { | |||
modules.add(project); | |||
} | |||
for (ResourceDto submodule : mapper.selectDescendantProjects(projectUuid)) { | |||
modules.addAll(collectAllModules(submodule.getUuid(), stringToReplace, mapper, includeDisabled)); | |||
} | |||
return modules; | |||
} | |||
private static void checkNewNameOfAllModules(Set<ResourceDto> modules, String stringToReplace, String replacementString, ComponentKeyUpdaterMapper mapper) { | |||
for (ResourceDto module : modules) { | |||
String newKey = computeNewKey(module.getKey(), stringToReplace, replacementString); | |||
checkProjectKey(newKey); | |||
checkExistentKey(mapper, newKey); | |||
} | |||
} | |||
private static ComponentKeyUpdaterMapper mapper(DbSession dbSession) { | |||
return dbSession.getMapper(ComponentKeyUpdaterMapper.class); | |||
} |
@@ -20,7 +20,6 @@ | |||
package org.sonar.db.source; | |||
import com.google.common.base.Splitter; | |||
import java.io.Reader; | |||
import java.sql.Connection; | |||
import java.sql.PreparedStatement; | |||
import java.sql.ResultSet; | |||
@@ -28,9 +27,7 @@ import java.sql.SQLException; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.function.Consumer; | |||
import javax.annotation.CheckForNull; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.ibatis.session.ResultHandler; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DatabaseUtils; | |||
@@ -89,31 +86,6 @@ public class FileSourceDao implements Dao { | |||
} | |||
} | |||
public void readLineHashesStream(DbSession dbSession, String fileUuid, Consumer<Reader> consumer) { | |||
Connection connection = dbSession.getConnection(); | |||
PreparedStatement pstmt = null; | |||
ResultSet rs = null; | |||
Reader reader = null; | |||
try { | |||
pstmt = connection.prepareStatement("SELECT line_hashes FROM file_sources WHERE file_uuid=?"); | |||
pstmt.setString(1, fileUuid); | |||
rs = pstmt.executeQuery(); | |||
if (rs.next()) { | |||
reader = rs.getCharacterStream(1); | |||
if (reader != null) { | |||
consumer.accept(reader); | |||
} | |||
} | |||
} catch (SQLException e) { | |||
throw new IllegalStateException("Fail to read FILE_SOURCES.LINE_HASHES of file " + fileUuid, e); | |||
} finally { | |||
IOUtils.closeQuietly(reader); | |||
DatabaseUtils.closeQuietly(rs); | |||
DatabaseUtils.closeQuietly(pstmt); | |||
DatabaseUtils.closeQuietly(connection); | |||
} | |||
} | |||
public void insert(DbSession session, FileSourceDto dto) { | |||
mapper(session).insert(dto); | |||
} |
@@ -22,7 +22,6 @@ package org.sonar.db.component; | |||
import com.google.common.base.Strings; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.function.Predicate; | |||
import org.assertj.core.groups.Tuple; | |||
import org.junit.Rule; | |||
@@ -37,9 +36,7 @@ import org.sonar.db.audit.AuditPersister; | |||
import org.sonar.db.audit.model.ComponentKeyNewValue; | |||
import org.sonar.db.component.ComponentKeyUpdaterDao.RekeyedResource; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.entry; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.anyString; | |||
import static org.mockito.Mockito.mock; | |||
@@ -217,94 +214,6 @@ public class ComponentKeyUpdaterDaoTest { | |||
.forEach(map -> map.values().forEach(k -> assertThat(k.toString()).startsWith(newProjectKey))); | |||
} | |||
@Test | |||
public void bulk_updateKey_updates_branches_too() { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
ComponentDto module = db.components().insertComponent(prefixDbKeyWithKey(newModuleDto(branch), project.getKey())); | |||
ComponentDto file1 = db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey())); | |||
ComponentDto file2 = db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey())); | |||
int branchComponentCount = 4; | |||
String oldProjectKey = project.getKey(); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldProjectKey)).hasSize(1); | |||
String oldBranchKey = branch.getDbKey(); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldBranchKey)).hasSize(branchComponentCount); | |||
String newProjectKey = "newKey"; | |||
Set<RekeyedResource> rekeyedResources = underTest.bulkUpdateKey(dbSession, project.uuid(), oldProjectKey, newProjectKey, a -> true); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldProjectKey)).isEmpty(); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldBranchKey)).isEmpty(); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, newProjectKey)).hasSize(1); | |||
String newBranchKey = ComponentDto.generateBranchKey(newProjectKey, branch.getBranch()); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, newBranchKey)).hasSize(branchComponentCount); | |||
db.select(dbSession, "select kee from components") | |||
.forEach(map -> map.values().forEach(k -> assertThat(k.toString()).startsWith(newProjectKey))); | |||
assertThat(rekeyedResources) | |||
.extracting(t -> t.getResource().getUuid()) | |||
.containsOnly(project.uuid(), branch.uuid(), module.uuid(), file1.uuid(), file2.uuid()); | |||
assertThat(rekeyedResources) | |||
.extracting(t -> t.getResource().getKey()) | |||
.allMatch(t -> t.startsWith(newProjectKey)); | |||
assertThat(rekeyedResources) | |||
.extracting(RekeyedResource::getOldKey) | |||
.allMatch(t -> t.startsWith(oldProjectKey)); | |||
} | |||
@Test | |||
public void bulk_updateKey_on_branch_containing_slash() { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch/with/slash")); | |||
String newKey = "newKey"; | |||
underTest.bulkUpdateKey(dbSession, project.uuid(), project.getKey(), newKey, t -> true); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, newKey)).hasSize(1); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, ComponentDto.generateBranchKey(newKey, branch.getBranch()))).hasSize(1); | |||
} | |||
@Test | |||
public void bulk_updateKey_updates_pull_requests_too() { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
ComponentDto pullRequest = db.components().insertProjectBranch(project, b -> b.setBranchType(PULL_REQUEST)); | |||
ComponentDto module = db.components().insertComponent(prefixDbKeyWithKey(newModuleDto(pullRequest), project.getKey())); | |||
ComponentDto file1 = db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey())); | |||
ComponentDto file2 = db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey())); | |||
int branchComponentCount = 4; | |||
String oldProjectKey = project.getKey(); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldProjectKey)).hasSize(1); | |||
String oldPullRequestKey = pullRequest.getDbKey(); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldPullRequestKey)).hasSize(branchComponentCount); | |||
String newProjectKey = "newKey"; | |||
String newPullRequestKey = ComponentDto.generatePullRequestKey(newProjectKey, pullRequest.getPullRequest()); | |||
Set<RekeyedResource> rekeyedResources = underTest.bulkUpdateKey(dbSession, project.uuid(), oldProjectKey, newProjectKey, t -> true); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldProjectKey)).isEmpty(); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldPullRequestKey)).isEmpty(); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, newProjectKey)).hasSize(1); | |||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, newPullRequestKey)).hasSize(branchComponentCount); | |||
db.select(dbSession, "select kee from components") | |||
.forEach(map -> map.values().forEach(k -> assertThat(k.toString()).startsWith(newProjectKey))); | |||
assertThat(rekeyedResources) | |||
.extracting(t -> t.getResource().getUuid()) | |||
.containsOnly(project.uuid(), pullRequest.uuid(), module.uuid(), file1.uuid(), file2.uuid()); | |||
assertThat(rekeyedResources) | |||
.extracting(t -> t.getResource().getKey()) | |||
.allMatch(t -> t.startsWith(newProjectKey)); | |||
assertThat(rekeyedResources) | |||
.extracting(RekeyedResource::getOldKey) | |||
.allMatch(t -> t.startsWith(oldProjectKey)); | |||
} | |||
private ComponentDto prefixDbKeyWithKey(ComponentDto componentDto, String key) { | |||
return componentDto.setDbKey(key + ":" + componentDto.getDbKey()); | |||
} | |||
@@ -319,99 +228,6 @@ public class ComponentKeyUpdaterDaoTest { | |||
underTest.updateKey(dbSession, "B", "org.struts:struts-ui"); | |||
} | |||
@Test | |||
public void bulk_update_key_updates_disabled_components() { | |||
ComponentDto project = db.components().insertComponent(newPrivateProjectDto("A").setDbKey("my_project")); | |||
db.components().insertComponent(newModuleDto(project).setDbKey("my_project:module")); | |||
db.components().insertComponent(newModuleDto(project).setDbKey("my_project:inactive_module").setEnabled(false)); | |||
Set<RekeyedResource> rekeyedResources = underTestWithAuditPersister.bulkUpdateKey(dbSession, "A", "my_", "your_", doNotReturnAnyRekeyedResource()); | |||
List<ComponentDto> result = dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, "your_project"); | |||
assertThat(result) | |||
.hasSize(3) | |||
.extracting(ComponentDto::getDbKey) | |||
.containsOnlyOnce("your_project", "your_project:module", "your_project:inactive_module"); | |||
} | |||
@Test | |||
public void shouldBulkUpdateKey() { | |||
populateSomeData(); | |||
underTest.bulkUpdateKey(dbSession, "A", "org.struts", "org.apache.struts", doNotReturnAnyRekeyedResource()); | |||
dbSession.commit(); | |||
assertThat(db.select("select uuid as \"UUID\", kee as \"KEE\" from components")) | |||
.extracting(t -> t.get("UUID"), t -> t.get("KEE")) | |||
.containsOnly( | |||
Tuple.tuple("A", "org.apache.struts:struts"), | |||
Tuple.tuple("B", "org.apache.struts:struts-core"), | |||
Tuple.tuple("C", "org.apache.struts:struts-core:/src/org/struts"), | |||
Tuple.tuple("D", "org.apache.struts:struts-core:/src/org/struts/RequestContext.java"), | |||
Tuple.tuple("E", "org.apache.struts:struts-ui"), | |||
Tuple.tuple("F", "org.apache.struts:struts-ui:/src/org/struts"), | |||
Tuple.tuple("G", "org.apache.struts:struts-ui:/src/org/struts/RequestContext.java"), | |||
Tuple.tuple("H", "foo:struts-core")); | |||
} | |||
@Test | |||
public void shouldBulkUpdateKeyOnOnlyOneSubmodule() { | |||
populateSomeData(); | |||
underTest.bulkUpdateKey(dbSession, "A", "struts-ui", "struts-web", doNotReturnAnyRekeyedResource()); | |||
dbSession.commit(); | |||
assertThat(db.select("select uuid as \"UUID\", kee as \"KEE\" from components")) | |||
.extracting(t -> t.get("UUID"), t -> t.get("KEE")) | |||
.containsOnly( | |||
Tuple.tuple("A", "org.struts:struts"), | |||
Tuple.tuple("B", "org.struts:struts-core"), | |||
Tuple.tuple("C", "org.struts:struts-core:/src/org/struts"), | |||
Tuple.tuple("D", "org.struts:struts-core:/src/org/struts/RequestContext.java"), | |||
Tuple.tuple("E", "org.struts:struts-web"), | |||
Tuple.tuple("F", "org.struts:struts-web:/src/org/struts"), | |||
Tuple.tuple("G", "org.struts:struts-web:/src/org/struts/RequestContext.java"), | |||
Tuple.tuple("H", "foo:struts-core")); | |||
} | |||
@Test | |||
public void shouldFailBulkUpdateKeyIfKeyAlreadyExist() { | |||
populateSomeData(); | |||
thrown.expect(IllegalArgumentException.class); | |||
thrown.expectMessage("Impossible to update key: a component with key \"foo:struts-core\" already exists."); | |||
underTest.bulkUpdateKey(dbSession, "A", "org.struts", "foo", doNotReturnAnyRekeyedResource()); | |||
dbSession.commit(); | |||
} | |||
@Test | |||
public void shouldNotUpdateAllSubmodules() { | |||
ComponentDto project1 = db.components().insertPrivateProject(t1 -> t1.setDbKey("org.struts:struts").setUuid("A")); | |||
ComponentDto module1 = db.components().insertComponent(newModuleDto(project1).setDbKey("org.struts:struts-core").setUuid("B")); | |||
ComponentDto directory1 = db.components().insertComponent(newDirectory(module1, "/src/org/struts").setUuid("C")); | |||
db.components().insertComponent(ComponentTesting.newFileDto(module1, directory1).setDbKey("org.struts:struts-core:/src/org/struts/RequestContext.java").setUuid("D")); | |||
ComponentDto module2 = db.components().insertComponent(newModuleDto(project1).setDbKey("foo:struts-ui").setUuid("E")); | |||
ComponentDto directory2 = db.components().insertComponent(newDirectory(module2, "/src/org/struts").setUuid("F")); | |||
db.components().insertComponent(ComponentTesting.newFileDto(module2, directory2).setDbKey("foo:struts-ui:/src/org/struts/RequestContext.java").setUuid("G")); | |||
ComponentDto project2 = db.components().insertPublicProject(t1 -> t1.setDbKey("foo:struts-core").setUuid("H")); | |||
underTest.bulkUpdateKey(dbSession, "A", "org.struts", "org.apache.struts", doNotReturnAnyRekeyedResource()); | |||
dbSession.commit(); | |||
assertThat(db.select("select uuid as \"UUID\", kee as \"KEE\" from components")) | |||
.extracting(t -> t.get("UUID"), t -> t.get("KEE")) | |||
.containsOnly( | |||
Tuple.tuple("A", "org.apache.struts:struts"), | |||
Tuple.tuple("B", "org.apache.struts:struts-core"), | |||
Tuple.tuple("C", "org.apache.struts:struts-core:/src/org/struts"), | |||
Tuple.tuple("D", "org.apache.struts:struts-core:/src/org/struts/RequestContext.java"), | |||
Tuple.tuple("E", "foo:struts-ui"), | |||
Tuple.tuple("F", "foo:struts-ui:/src/org/struts"), | |||
Tuple.tuple("G", "foo:struts-ui:/src/org/struts/RequestContext.java"), | |||
Tuple.tuple("H", "foo:struts-core")); | |||
} | |||
@Test | |||
public void updateKey_throws_IAE_when_sub_component_key_is_too_long() { | |||
ComponentDto project = newPrivateProjectDto("project-uuid").setDbKey("old-project-key"); | |||
@@ -424,75 +240,6 @@ public class ComponentKeyUpdaterDaoTest { | |||
underTest.updateKey(dbSession, project.uuid(), newLongProjectKey); | |||
} | |||
@Test | |||
public void fail_when_new_key_is_invalid() { | |||
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."); | |||
underTest.bulkUpdateKey(dbSession, project.uuid(), project.getDbKey(), "my?project?key", doNotReturnAnyRekeyedResource()); | |||
} | |||
@Test | |||
public void check_component_keys() { | |||
populateSomeData(); | |||
Map<String, Boolean> result = underTest.checkComponentKeys(dbSession, newArrayList("foo:struts", "foo:struts-core", "foo:struts-ui")); | |||
assertThat(result) | |||
.hasSize(3) | |||
.containsOnly(entry("foo:struts", false), entry("foo:struts-core", true), entry("foo:struts-ui", false)); | |||
} | |||
@Test | |||
public void check_component_keys_checks_inactive_components() { | |||
db.components().insertComponent(ComponentTesting.newPrivateProjectDto().setDbKey("my-project")); | |||
db.components().insertComponent(ComponentTesting.newPrivateProjectDto().setDbKey("your-project").setEnabled(false)); | |||
Map<String, Boolean> result = underTest.checkComponentKeys(dbSession, newArrayList("my-project", "your-project", "new-project")); | |||
assertThat(result) | |||
.hasSize(3) | |||
.containsOnly(entry("my-project", true), entry("your-project", true), entry("new-project", false)); | |||
} | |||
@Test | |||
public void simulate_bulk_update_key() { | |||
populateSomeData(); | |||
Map<String, String> result = underTest.simulateBulkUpdateKey(dbSession, "A", "org.struts", "foo"); | |||
assertThat(result) | |||
.hasSize(3) | |||
.containsOnly(entry("org.struts:struts", "foo:struts"), entry("org.struts:struts-core", "foo:struts-core"), entry("org.struts:struts-ui", "foo:struts-ui")); | |||
} | |||
@Test | |||
public void simulate_bulk_update_key_does_not_return_disable_components() { | |||
ComponentDto project = db.components().insertComponent(newPrivateProjectDto("A").setDbKey("project")); | |||
db.components().insertComponent(newModuleDto(project).setDbKey("project:enabled-module")); | |||
db.components().insertComponent(newModuleDto(project).setDbKey("project:disabled-module").setEnabled(false)); | |||
db.components().insertComponent(newPrivateProjectDto("D").setDbKey("other-project")); | |||
Map<String, String> result = underTest.simulateBulkUpdateKey(dbSession, "A", "project", "new-project"); | |||
assertThat(result).containsOnly( | |||
entry("project", "new-project"), | |||
entry("project:enabled-module", "new-project:enabled-module")); | |||
} | |||
@Test | |||
public void simulate_bulk_update_key_fails_if_invalid_componentKey() { | |||
ComponentDto project = db.components().insertComponent(newPrivateProjectDto("A").setDbKey("project")); | |||
db.components().insertComponent(newModuleDto(project).setDbKey("project:enabled-module")); | |||
db.components().insertComponent(newModuleDto(project).setDbKey("project:disabled-module").setEnabled(false)); | |||
thrown.expect(IllegalArgumentException.class); | |||
underTest.simulateBulkUpdateKey(dbSession, "A", "project", "project?"); | |||
} | |||
@Test | |||
public void compute_new_key() { | |||
assertThat(computeNewKey("my_project", "my_", "your_")).isEqualTo("your_project"); | |||
@@ -509,19 +256,6 @@ public class ComponentKeyUpdaterDaoTest { | |||
.componentKeyUpdate(any(DbSession.class), any(ComponentKeyNewValue.class), anyString()); | |||
} | |||
@Test | |||
public void bulkUpdate_callsAuditPersister() { | |||
ComponentDto project = db.components().insertComponent(newPrivateProjectDto("A").setDbKey("project")); | |||
db.components().insertComponent(newModuleDto(project).setDbKey("project:enabled-module")); | |||
db.components().insertComponent(newModuleDto(project).setDbKey("project:disabled-module").setEnabled(false)); | |||
thrown.expect(IllegalArgumentException.class); | |||
underTest.simulateBulkUpdateKey(dbSession, "A", "project", "project?"); | |||
verify(auditPersister, times(1)) | |||
.componentKeyUpdate(any(DbSession.class), any(ComponentKeyNewValue.class), anyString()); | |||
} | |||
private Predicate<RekeyedResource> doNotReturnAnyRekeyedResource() { | |||
return a -> false; |
@@ -21,17 +21,12 @@ package org.sonar.db.source; | |||
import com.google.common.collect.ImmutableList; | |||
import com.google.common.collect.ImmutableSet; | |||
import java.io.IOException; | |||
import java.io.Reader; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import java.util.Random; | |||
import java.util.function.Consumer; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.IntStream; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.ibatis.session.ResultContext; | |||
import org.apache.ibatis.session.ResultHandler; | |||
import org.junit.Rule; | |||
@@ -78,30 +73,6 @@ public class FileSourceDaoTest { | |||
assertThat(fileSourceDto.getLineHashes()).isEqualTo(expected.getLineHashes()); | |||
} | |||
@Test | |||
public void select_line_hashes() { | |||
ComponentDto project = dbTester.components().insertPrivateProject(); | |||
ComponentDto file = dbTester.components().insertComponent(newFileDto(project)); | |||
FileSourceDto expected = dbTester.fileSources().insertFileSource(file); | |||
ReaderToStringConsumer fn = new ReaderToStringConsumer(); | |||
underTest.readLineHashesStream(dbSession, expected.getFileUuid(), fn); | |||
assertThat(fn.result).isEqualTo(expected.getLineHashes().isEmpty() ? null : String.join("\n", expected.getLineHashes())); | |||
} | |||
@Test | |||
public void no_line_hashes_on_unknown_file() { | |||
ComponentDto project = dbTester.components().insertPrivateProject(); | |||
ComponentDto file = dbTester.components().insertComponent(newFileDto(project)); | |||
dbTester.fileSources().insertFileSource(file); | |||
ReaderToStringConsumer fn = new ReaderToStringConsumer(); | |||
underTest.readLineHashesStream(dbSession, "unknown", fn); | |||
assertThat(fn.result).isNull(); | |||
} | |||
@Test | |||
public void insert() { | |||
FileSourceDto expected = new FileSourceDto() | |||
@@ -217,31 +188,6 @@ public class FileSourceDaoTest { | |||
assertThat(underTest.selectLineHashesVersion(dbSession, "FILE2_UUID")).isEqualTo(LineHashVersion.WITH_SIGNIFICANT_CODE); | |||
} | |||
@Test | |||
public void readLineHashesStream_does_not_fail_when_lineshashes_is_null() { | |||
underTest.insert(dbSession, new FileSourceDto() | |||
.setUuid(Uuids.createFast()) | |||
.setProjectUuid("PRJ_UUID") | |||
.setFileUuid("FILE2_UUID") | |||
.setBinaryData("FILE2_BINARY_DATA".getBytes()) | |||
.setDataHash("FILE2_DATA_HASH") | |||
.setSrcHash("FILE2_HASH") | |||
.setCreatedAt(1500000000000L) | |||
.setUpdatedAt(1500000000001L) | |||
.setRevision("123456789")); | |||
dbSession.commit(); | |||
boolean[] flag = {false}; | |||
underTest.readLineHashesStream(dbSession, "FILE2_UUID", new Consumer<Reader>() { | |||
@Override | |||
public void accept(@Nullable Reader input) { | |||
fail("function must never been called since there is no data to read"); | |||
flag[0] = true; | |||
} | |||
}); | |||
assertThat(flag[0]).isFalse(); | |||
} | |||
@Test | |||
public void scrollLineHashes_has_no_effect_if_no_uuids() { | |||
underTest.scrollLineHashes(dbSession, emptySet(), resultContext -> fail("handler should not be called")); | |||
@@ -391,18 +337,4 @@ public class FileSourceDaoTest { | |||
assertThat(res.getLineHashes()).isEmpty(); | |||
assertThat(res.getLineCount()).isEqualTo(1); | |||
} | |||
private static class ReaderToStringConsumer implements Consumer<Reader> { | |||
String result = null; | |||
@Override | |||
public void accept(Reader input) { | |||
try { | |||
result = IOUtils.toString(input); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
} | |||
} |
@@ -65,7 +65,6 @@ If the **Force user authentication** property is set to false, the following API | |||
| * api/system/status | |||
| * api/system/upgrades | |||
| * api/users/search | |||
| * api/views/run | |||
| * api/webservices/list | |||
| * api/webservices/response_example | |||
@@ -5,7 +5,10 @@ url: /setup/upgrade-notes/ | |||
## Release 9.1 Upgrade Notes | |||
**Custom measures feature has been dropped** | |||
The custom measures feature, which was previously deprecated, has been removed. ([SONAR-10762)[https://jira.sonarsource.com/browse/SONAR-10762]). | |||
The custom measures feature, which was previously deprecated, has been removed. ([SONAR-10762](https://jira.sonarsource.com/browse/SONAR-10762)). | |||
**Deprecated WebAPI endpoints and parameters removal** | |||
The WebAPI endpoints and parameters deprecated during the 7.X release cycle have been removed. For a complete list of removed endpoints and parameters see [SONAR-15313](https://jira.sonarsource.com/browse/SONAR-15313). | |||
## Release 9.0 Upgrade Notes | |||
**Scanners require Java 11** |
@@ -46,7 +46,6 @@ public class SearchRequest { | |||
private List<String> issues; | |||
private Set<String> scopes; | |||
private List<String> languages; | |||
private List<String> moduleUuids; | |||
private Boolean onComponentOnly; | |||
private String branch; | |||
private String pullRequest; | |||
@@ -252,16 +251,6 @@ public class SearchRequest { | |||
return this; | |||
} | |||
@CheckForNull | |||
public List<String> getModuleUuids() { | |||
return moduleUuids; | |||
} | |||
public SearchRequest setModuleUuids(@Nullable List<String> moduleUuids) { | |||
this.moduleUuids = moduleUuids; | |||
return this; | |||
} | |||
@CheckForNull | |||
public Boolean getOnComponentOnly() { | |||
return onComponentOnly; |
@@ -36,7 +36,6 @@ public class SearchRequestTest { | |||
.setResolutions(singletonList("FALSE-POSITIVE")) | |||
.setResolved(true) | |||
.setProjects(singletonList("project-a")) | |||
.setModuleUuids(singletonList("module-a")) | |||
.setDirectories(singletonList("aDirPath")) | |||
.setFiles(asList("file-a", "file-b")) | |||
.setAssigneesUuid(asList("user-a", "user-b")) | |||
@@ -56,7 +55,6 @@ public class SearchRequestTest { | |||
assertThat(underTest.getResolutions()).containsExactly("FALSE-POSITIVE"); | |||
assertThat(underTest.getResolved()).isTrue(); | |||
assertThat(underTest.getProjects()).containsExactly("project-a"); | |||
assertThat(underTest.getModuleUuids()).containsExactly("module-a"); | |||
assertThat(underTest.getDirectories()).containsExactly("aDirPath"); | |||
assertThat(underTest.getFiles()).containsExactly("file-a", "file-b"); | |||
assertThat(underTest.getAssigneeUuids()).containsExactly("user-a", "user-b"); |
@@ -25,13 +25,12 @@ import { IssueResponse, RawIssuesResponse } from '../types/issues'; | |||
type FacetName = | |||
| 'assigned_to_me' | |||
| 'assignees' | |||
| 'authors' | |||
| 'author' | |||
| 'createdAt' | |||
| 'cwe' | |||
| 'directories' | |||
| 'files' | |||
| 'languages' | |||
| 'modules' | |||
| 'owaspTop10' | |||
| 'projects' | |||
| 'reporters' |
@@ -68,7 +68,6 @@ import { | |||
areMyIssuesSelected, | |||
areQueriesEqual, | |||
getOpen, | |||
mapFacet, | |||
parseFacets, | |||
parseQuery, | |||
Query, | |||
@@ -408,7 +407,6 @@ export default class App extends React.PureComponent<Props, State> { | |||
const facets = requestFacets | |||
? Object.keys(openFacets) | |||
.filter(facet => facet !== STANDARDS) | |||
.map(mapFacet) | |||
.join(',') | |||
: undefined; | |||
@@ -590,7 +588,7 @@ export default class App extends React.PureComponent<Props, State> { | |||
}; | |||
fetchFacet = (facet: string) => { | |||
return this.fetchIssues({ ps: 1, facets: mapFacet(facet) }, false).then( | |||
return this.fetchIssues({ ps: 1, facets: facet }, false).then( | |||
({ facets, ...other }) => { | |||
if (this.mounted) { | |||
this.setState(state => ({ | |||
@@ -689,7 +687,7 @@ export default class App extends React.PureComponent<Props, State> { | |||
const parameters = { | |||
...getBranchLikeQuery(this.props.branchLike), | |||
componentKeys: component && component.key, | |||
facets: mapFacet(property), | |||
facets: property, | |||
s: 'FILE_LINE', | |||
...serializeQuery({ ...query, ...changes }), | |||
ps: 1 |
@@ -78,11 +78,6 @@ export default class ListItem extends React.PureComponent<Props> { | |||
case 'project': | |||
onFilterChange({ ...issuesReset, projects: [issue.projectKey] }); | |||
break; | |||
case 'module': | |||
if (issue.subProjectUuid) { | |||
onFilterChange({ ...issuesReset, modules: [issue.subProjectUuid] }); | |||
} | |||
break; | |||
case 'file': | |||
onFilterChange({ ...issuesReset, files: [issue.componentUuid] }); | |||
} |
@@ -35,7 +35,7 @@ interface Props { | |||
open: boolean; | |||
query: Query; | |||
stats: T.Dict<number> | undefined; | |||
authors: string[]; | |||
author: string[]; | |||
} | |||
const SEARCH_SIZE = 100; | |||
@@ -56,8 +56,8 @@ export default class AuthorFacet extends React.PureComponent<Props> { | |||
}).then(authors => ({ maxResults: authors.length === SEARCH_SIZE, results: authors })); | |||
}; | |||
loadSearchResultCount = (authors: string[]) => { | |||
return this.props.loadSearchResultCount('authors', { authors }); | |||
loadSearchResultCount = (author: string[]) => { | |||
return this.props.loadSearchResultCount('author', { author }); | |||
}; | |||
renderSearchResult = (author: string, term: string) => { | |||
@@ -77,13 +77,13 @@ export default class AuthorFacet extends React.PureComponent<Props> { | |||
onSearch={this.handleSearch} | |||
onToggle={this.props.onToggle} | |||
open={this.props.open} | |||
property="authors" | |||
query={omit(this.props.query, 'authors')} | |||
property="author" | |||
query={omit(this.props.query, 'author')} | |||
renderFacetItem={this.identity} | |||
renderSearchResult={this.renderSearchResult} | |||
searchPlaceholder={translate('search.search_for_authors')} | |||
stats={this.props.stats} | |||
values={this.props.authors} | |||
values={this.props.author} | |||
/> | |||
); | |||
} |
@@ -256,15 +256,15 @@ export class Sidebar extends React.PureComponent<Props> { | |||
)} | |||
{displayAuthorFacet && !this.props.disableDeveloperAggregatedInfo && ( | |||
<AuthorFacet | |||
authors={query.authors} | |||
author={query.author} | |||
component={component} | |||
fetching={this.props.loadingFacets.authors === true} | |||
fetching={this.props.loadingFacets.author === true} | |||
loadSearchResultCount={this.props.loadSearchResultCount} | |||
onChange={this.props.onFilterChange} | |||
onToggle={this.props.onFacetToggle} | |||
open={!!openFacets.authors} | |||
open={!!openFacets.author} | |||
query={query} | |||
stats={facets.authors} | |||
stats={facets.author} | |||
/> | |||
)} | |||
</> |
@@ -0,0 +1,58 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import ListStyleFacet from '../../../../components/facet/ListStyleFacet'; | |||
import { mockComponent } from '../../../../helpers/testMocks'; | |||
import { Query } from '../../utils'; | |||
import AuthorFacet from '../AuthorFacet'; | |||
it('should render correctly', () => { | |||
const wrapper = shallowRender(); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('should notify of search result count correctly', () => { | |||
const loadSearchResultCount = jest.fn(); | |||
const wrapper = shallowRender({ loadSearchResultCount }); | |||
wrapper.find(ListStyleFacet).props().loadSearchResultCount!(['1', '2']); | |||
expect(loadSearchResultCount).toHaveBeenCalled(); | |||
}); | |||
function shallowRender(props: Partial<AuthorFacet['props']> = {}) { | |||
return shallow<AuthorFacet>( | |||
<AuthorFacet | |||
component={mockComponent()} | |||
fetching={false} | |||
loadSearchResultCount={jest.fn()} | |||
onChange={jest.fn()} | |||
onToggle={jest.fn()} | |||
open={true} | |||
query={{} as Query} | |||
stats={{}} | |||
author={[]} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,26 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<ListStyleFacet | |||
facetHeader="issues.facet.authors" | |||
fetching={false} | |||
getFacetItemText={[Function]} | |||
getSearchResultKey={[Function]} | |||
getSearchResultText={[Function]} | |||
loadSearchResultCount={[Function]} | |||
maxInitialItems={15} | |||
maxItems={100} | |||
minSearchLength={2} | |||
onChange={[MockFunction]} | |||
onSearch={[Function]} | |||
onToggle={[MockFunction]} | |||
open={true} | |||
property="author" | |||
query={Object {}} | |||
renderFacetItem={[Function]} | |||
renderSearchResult={[Function]} | |||
searchPlaceholder="search.search_for_authors" | |||
stats={Object {}} | |||
values={Array []} | |||
/> | |||
`; |
@@ -17,6 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { isArray } from 'lodash'; | |||
import { searchUsers } from '../../api/users'; | |||
import { formatMeasure } from '../../helpers/measures'; | |||
import { | |||
@@ -32,13 +33,14 @@ import { | |||
} from '../../helpers/query'; | |||
import { scrollToElement } from '../../helpers/scrolling'; | |||
import { get, save } from '../../helpers/storage'; | |||
import { isDefined } from '../../helpers/types'; | |||
import { Facet, RawFacet } from '../../types/issues'; | |||
import { SecurityStandard, StandardType } from '../../types/security'; | |||
export interface Query { | |||
assigned: boolean; | |||
assignees: string[]; | |||
authors: string[]; | |||
author: string[]; | |||
createdAfter: Date | undefined; | |||
createdAt: string; | |||
createdBefore: Date | undefined; | |||
@@ -48,7 +50,6 @@ export interface Query { | |||
files: string[]; | |||
issues: string[]; | |||
languages: string[]; | |||
modules: string[]; | |||
owaspTop10: string[]; | |||
projects: string[]; | |||
resolutions: string[]; | |||
@@ -81,7 +82,7 @@ export function parseQuery(query: T.RawQuery): Query { | |||
return { | |||
assigned: parseAsBoolean(query.assigned), | |||
assignees: parseAsArray(query.assignees, parseAsString), | |||
authors: parseAsArray(query.authors, parseAsString), | |||
author: isArray(query.author) ? query.author : [query.author].filter(isDefined), | |||
createdAfter: parseAsDate(query.createdAfter), | |||
createdAt: parseAsString(query.createdAt), | |||
createdBefore: parseAsDate(query.createdBefore), | |||
@@ -91,7 +92,6 @@ export function parseQuery(query: T.RawQuery): Query { | |||
files: parseAsArray(query.files, parseAsString), | |||
issues: parseAsArray(query.issues, parseAsString), | |||
languages: parseAsArray(query.languages, parseAsString), | |||
modules: parseAsArray(query.moduleUuids, parseAsString), | |||
owaspTop10: parseAsArray(query.owaspTop10, parseAsString), | |||
projects: parseAsArray(query.projects, parseAsString), | |||
resolutions: parseAsArray(query.resolutions, parseAsString), | |||
@@ -119,7 +119,7 @@ export function serializeQuery(query: Query): T.RawQuery { | |||
const filter = { | |||
assigned: query.assigned ? undefined : 'false', | |||
assignees: serializeStringArray(query.assignees), | |||
authors: serializeStringArray(query.authors), | |||
author: query.author, | |||
createdAfter: serializeDateShort(query.createdAfter), | |||
createdAt: serializeString(query.createdAt), | |||
createdBefore: serializeDateShort(query.createdBefore), | |||
@@ -129,7 +129,6 @@ export function serializeQuery(query: Query): T.RawQuery { | |||
files: serializeStringArray(query.files), | |||
issues: serializeStringArray(query.issues), | |||
languages: serializeStringArray(query.languages), | |||
moduleUuids: serializeStringArray(query.modules), | |||
owaspTop10: serializeStringArray(query.owaspTop10), | |||
projects: serializeStringArray(query.projects), | |||
resolutions: serializeStringArray(query.resolutions), | |||
@@ -145,37 +144,25 @@ export function serializeQuery(query: Query): T.RawQuery { | |||
tags: serializeStringArray(query.tags), | |||
types: serializeStringArray(query.types) | |||
}; | |||
return cleanQuery(filter); | |||
} | |||
export const areQueriesEqual = (a: T.RawQuery, b: T.RawQuery) => | |||
queriesEqual(parseQuery(a), parseQuery(b)); | |||
export function mapFacet(facet: string) { | |||
const propertyMapping: T.Dict<string> = { | |||
modules: 'moduleUuids' | |||
}; | |||
return propertyMapping[facet] || facet; | |||
} | |||
export function parseFacets(facets: RawFacet[]): T.Dict<Facet> { | |||
if (!facets) { | |||
return {}; | |||
} | |||
// for readability purpose | |||
const propertyMapping: T.Dict<string> = { | |||
moduleUuids: 'modules' | |||
}; | |||
const result: T.Dict<Facet> = {}; | |||
facets.forEach(facet => { | |||
const values: Facet = {}; | |||
facet.values.forEach(value => { | |||
values[value.val] = value.count; | |||
}); | |||
const finalProperty = propertyMapping[facet.property] || facet.property; | |||
result[finalProperty] = values; | |||
result[facet.property] = values; | |||
}); | |||
return result; | |||
} |
@@ -360,7 +360,6 @@ declare namespace T { | |||
status: string; | |||
subProject?: string; | |||
subProjectName?: string; | |||
subProjectUuid?: string; | |||
tags?: string[]; | |||
textRange?: TextRange; | |||
transitions: string[]; |
@@ -115,7 +115,6 @@ import static org.sonar.server.es.searchrequest.TopAggregationHelper.NO_OTHER_SU | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.ASSIGNED_TO_ME; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.ASSIGNEES; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.AUTHOR; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.AUTHORS; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.CREATED_AT; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.CWE; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.DIRECTORIES; | |||
@@ -171,7 +170,6 @@ import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_INSECURE_I | |||
import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_POROUS_DEFENSES; | |||
import static org.sonar.server.security.SecurityStandards.SANS_TOP_25_RISKY_RESOURCE; | |||
import static org.sonar.server.view.index.ViewIndexDefinition.TYPE_VIEW; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_PARAM_AUTHORS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_EFFORT; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNEES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_AUTHOR; | |||
@@ -180,7 +178,6 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CWE; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_LANGUAGES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_MODULE_UUIDS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_OWASP_TOP_10; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLUTIONS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES; | |||
@@ -200,6 +197,7 @@ public class IssueIndex { | |||
public static final String FACET_PROJECTS = "projects"; | |||
public static final String FACET_ASSIGNED_TO_ME = "assigned_to_me"; | |||
public static final String FACET_MODULES = "moduleUuids"; | |||
private static final int DEFAULT_FACET_SIZE = 15; | |||
private static final int MAX_FACET_SIZE = 100; | |||
@@ -238,10 +236,9 @@ public class IssueIndex { | |||
LANGUAGES(PARAM_LANGUAGES, FIELD_ISSUE_LANGUAGE, STICKY, MAX_FACET_SIZE), | |||
RULES(PARAM_RULES, FIELD_ISSUE_RULE_UUID, STICKY, MAX_FACET_SIZE), | |||
TAGS(PARAM_TAGS, FIELD_ISSUE_TAGS, STICKY, MAX_FACET_SIZE), | |||
AUTHORS(DEPRECATED_PARAM_AUTHORS, FIELD_ISSUE_AUTHOR_LOGIN, STICKY, MAX_FACET_SIZE), | |||
AUTHOR(PARAM_AUTHOR, FIELD_ISSUE_AUTHOR_LOGIN, STICKY, MAX_FACET_SIZE), | |||
PROJECT_UUIDS(FACET_PROJECTS, FIELD_ISSUE_PROJECT_UUID, STICKY, MAX_FACET_SIZE), | |||
MODULE_UUIDS(PARAM_MODULE_UUIDS, FIELD_ISSUE_MODULE_UUID, STICKY, MAX_FACET_SIZE), | |||
MODULE_UUIDS(FACET_MODULES, FIELD_ISSUE_MODULE_UUID, STICKY, MAX_FACET_SIZE), | |||
FILES(PARAM_FILES, FIELD_ISSUE_FILE_PATH, STICKY, MAX_FACET_SIZE), | |||
DIRECTORIES(PARAM_DIRECTORIES, FIELD_ISSUE_DIRECTORY_PATH, STICKY, MAX_FACET_SIZE), | |||
ASSIGNEES(PARAM_ASSIGNEES, FIELD_ISSUE_ASSIGNEE_UUID, STICKY, MAX_FACET_SIZE), | |||
@@ -674,7 +671,6 @@ public class IssueIndex { | |||
addFacetIfNeeded(options, aggregationHelper, esRequest, SCOPES, query.scopes().toArray()); | |||
addFacetIfNeeded(options, aggregationHelper, esRequest, LANGUAGES, query.languages().toArray()); | |||
addFacetIfNeeded(options, aggregationHelper, esRequest, RULES, query.ruleUuids().toArray()); | |||
addFacetIfNeeded(options, aggregationHelper, esRequest, AUTHORS, query.authors().toArray()); | |||
addFacetIfNeeded(options, aggregationHelper, esRequest, AUTHOR, query.authors().toArray()); | |||
addFacetIfNeeded(options, aggregationHelper, esRequest, TAGS, query.tags().toArray()); | |||
addFacetIfNeeded(options, aggregationHelper, esRequest, TYPES, query.types().toArray()); |
@@ -246,7 +246,6 @@ public class IssueQueryFactory { | |||
builder.projectUuids(projects.stream().map(IssueQueryFactory::toProjectUuid).collect(toList())); | |||
setBranch(builder, projects.get(0), request.getBranch(), request.getPullRequest()); | |||
} | |||
builder.moduleUuids(request.getModuleUuids()); | |||
builder.directories(request.getDirectories()); | |||
builder.files(request.getFiles()); | |||
@@ -201,7 +201,7 @@ public class IssueIndexDebtTest { | |||
} | |||
@Test | |||
public void facets_on_authors() { | |||
public void facets_on_author() { | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(); | |||
ComponentDto file = ComponentTesting.newFileDto(project, null); | |||
@@ -211,9 +211,9 @@ public class IssueIndexDebtTest { | |||
IssueDocTesting.newDoc("I3", file).setAuthorLogin("simon").setEffort(10L), | |||
IssueDocTesting.newDoc("I4", file).setAuthorLogin(null).setEffort(10L)); | |||
Facets facets = new Facets(underTest.search(newQueryBuilder().build(), new SearchOptions().addFacets(singletonList("authors"))), system2.getDefaultTimeZone().toZoneId()); | |||
assertThat(facets.getNames()).containsOnly("authors", FACET_MODE_EFFORT); | |||
assertThat(facets.get("authors")).containsOnly(entry("steph", 10L), entry("simon", 20L)); | |||
Facets facets = new Facets(underTest.search(newQueryBuilder().build(), new SearchOptions().addFacets(singletonList("author"))), system2.getDefaultTimeZone().toZoneId()); | |||
assertThat(facets.getNames()).containsOnly("author", FACET_MODE_EFFORT); | |||
assertThat(facets.get("author")).containsOnly(entry("steph", 10L), entry("simon", 20L)); | |||
assertThat(facets.get(FACET_MODE_EFFORT)).containsOnly(entry("total", 40L)); | |||
} | |||
@@ -400,20 +400,6 @@ public class IssueIndexFacetsTest { | |||
assertThatFacetHasOnly(IssueQuery.builder(), "author", entry("steph", 1L), entry("marcel", 2L)); | |||
} | |||
@Test | |||
public void facets_on_deprecated_authors() { | |||
ComponentDto project = newPrivateProjectDto(); | |||
ComponentDto file = newFileDto(project, null); | |||
indexIssues( | |||
newDoc("I1", file).setAuthorLogin("steph"), | |||
newDoc("I2", file).setAuthorLogin("marcel"), | |||
newDoc("I3", file).setAuthorLogin("marcel"), | |||
newDoc("I4", file).setAuthorLogin(null)); | |||
assertThatFacetHasOnly(IssueQuery.builder(), "authors", entry("steph", 1L), entry("marcel", 2L)); | |||
} | |||
@Test | |||
public void facets_on_authors_return_100_entries_plus_selected_values() { | |||
ComponentDto project = newPrivateProjectDto(); | |||
@@ -422,8 +408,8 @@ public class IssueIndexFacetsTest { | |||
IssueDoc issue2 = newDoc(newFileDto(project, null)).setAuthorLogin("user2"); | |||
indexIssues(issue1, issue2); | |||
assertThatFacetHasSize(IssueQuery.builder().build(), "authors", 100); | |||
assertThatFacetHasSize(IssueQuery.builder().authors(asList(issue1.authorLogin(), issue2.authorLogin())).build(), "authors", 102); | |||
assertThatFacetHasSize(IssueQuery.builder().build(), "author", 100); | |||
assertThatFacetHasSize(IssueQuery.builder().authors(asList(issue1.authorLogin(), issue2.authorLogin())).build(), "author", 102); | |||
} | |||
@Test |
@@ -91,7 +91,6 @@ public class IssueQueryFactoryTest { | |||
.setResolutions(asList("FALSE-POSITIVE")) | |||
.setResolved(true) | |||
.setProjects(asList(project.getDbKey())) | |||
.setModuleUuids(asList(module.uuid())) | |||
.setDirectories(asList("aDirPath")) | |||
.setFiles(asList(file.uuid())) | |||
.setAssigneesUuid(asList(user.getUuid())) | |||
@@ -113,7 +112,6 @@ public class IssueQueryFactoryTest { | |||
assertThat(query.resolutions()).containsOnly("FALSE-POSITIVE"); | |||
assertThat(query.resolved()).isTrue(); | |||
assertThat(query.projectUuids()).containsOnly(project.uuid()); | |||
assertThat(query.moduleUuids()).containsOnly(module.uuid()); | |||
assertThat(query.files()).containsOnly(file.uuid()); | |||
assertThat(query.assignees()).containsOnly(user.getUuid()); | |||
assertThat(query.scopes()).containsOnly("TEST", "MAIN"); |
@@ -30,7 +30,6 @@ import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.server.issue.index.IssueQuery.PeriodStart; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static org.apache.commons.lang.math.RandomUtils.nextInt; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.entry; | |||
@@ -19,17 +19,10 @@ | |||
*/ | |||
package org.sonar.server.component; | |||
import java.util.Set; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.resources.Scopes; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.core.util.stream.MoreCollectors; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentKeyUpdaterDao; | |||
import org.sonar.db.component.ResourceDto; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.es.ProjectIndexer; | |||
import org.sonar.server.es.ProjectIndexers; | |||
@@ -38,7 +31,6 @@ import org.sonar.server.project.ProjectLifeCycleListeners; | |||
import org.sonar.server.project.RekeyedProject; | |||
import org.sonar.server.user.UserSession; | |||
import static java.util.Collections.emptyList; | |||
import static java.util.Collections.singleton; | |||
import static java.util.Collections.singletonList; | |||
import static org.sonar.core.component.ComponentKeys.checkProjectKey; | |||
@@ -66,31 +58,4 @@ public class ComponentService { | |||
projectLifeCycleListeners.onProjectsRekeyed(singleton(new RekeyedProject(newProject, project.getKey()))); | |||
} | |||
public void bulkUpdateKey(DbSession dbSession, ProjectDto project, String stringToReplace, String replacementString) { | |||
Set<ComponentKeyUpdaterDao.RekeyedResource> rekeyedProjects = dbClient.componentKeyUpdaterDao().bulkUpdateKey( | |||
dbSession, project.getUuid(), stringToReplace, replacementString, | |||
ComponentService::isMainProject); | |||
projectIndexers.commitAndIndexProjects(dbSession, singletonList(project), ProjectIndexer.Cause.PROJECT_KEY_UPDATE); | |||
if (!rekeyedProjects.isEmpty()) { | |||
projectLifeCycleListeners.onProjectsRekeyed(rekeyedProjects.stream() | |||
.map(ComponentService::toRekeyedProject) | |||
.collect(MoreCollectors.toSet(rekeyedProjects.size()))); | |||
} | |||
} | |||
private static boolean isMainProject(ComponentKeyUpdaterDao.RekeyedResource rekeyedResource) { | |||
ResourceDto resource = rekeyedResource.getResource(); | |||
String resourceKey = resource.getKey(); | |||
return Scopes.PROJECT.equals(resource.getScope()) | |||
&& Qualifiers.PROJECT.equals(resource.getQualifier()) | |||
&& !resourceKey.contains(ComponentDto.BRANCH_KEY_SEPARATOR) | |||
&& !resourceKey.contains(ComponentDto.PULL_REQUEST_SEPARATOR); | |||
} | |||
private static RekeyedProject toRekeyedProject(ComponentKeyUpdaterDao.RekeyedResource rekeyedResource) { | |||
ResourceDto resource = rekeyedResource.getResource(); | |||
Project project = new Project(resource.getUuid(), resource.getKey(), resource.getName(), resource.getDescription(), emptyList()); | |||
return new RekeyedProject(project, rekeyedResource.getOldKey()); | |||
} | |||
} |
@@ -78,6 +78,7 @@ import static org.sonar.api.utils.Paging.forPageIndex; | |||
import static org.sonar.core.util.stream.MoreCollectors.toSet; | |||
import static org.sonar.server.es.SearchOptions.MAX_PAGE_SIZE; | |||
import static org.sonar.server.issue.index.IssueIndex.FACET_ASSIGNED_TO_ME; | |||
import static org.sonar.server.issue.index.IssueIndex.FACET_MODULES; | |||
import static org.sonar.server.issue.index.IssueIndex.FACET_PROJECTS; | |||
import static org.sonar.server.issue.index.IssueQuery.SORT_BY_ASSIGNEE; | |||
import static org.sonar.server.issue.index.IssueQueryFactory.ISSUE_STATUSES; | |||
@@ -91,10 +92,6 @@ import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | |||
import static org.sonar.server.ws.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_SEARCH; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_PARAM_AUTHORS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_COUNT; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_EFFORT; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ADDITIONAL_FIELDS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASC; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNED; | |||
@@ -111,7 +108,6 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ISSUES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_LANGUAGES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_MODULE_UUIDS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ON_COMPONENT_ONLY; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_OWASP_TOP_10; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS; | |||
@@ -136,7 +132,7 @@ public class SearchAction implements IssuesWsAction { | |||
static final List<String> SUPPORTED_FACETS = List.of( | |||
FACET_PROJECTS, | |||
PARAM_MODULE_UUIDS, | |||
FACET_MODULES, | |||
PARAM_FILES, | |||
FACET_ASSIGNED_TO_ME, | |||
PARAM_SEVERITIES, | |||
@@ -144,7 +140,6 @@ public class SearchAction implements IssuesWsAction { | |||
PARAM_RESOLUTIONS, | |||
PARAM_RULES, | |||
PARAM_ASSIGNEES, | |||
DEPRECATED_PARAM_AUTHORS, | |||
PARAM_AUTHOR, | |||
PARAM_DIRECTORIES, | |||
PARAM_SCOPES, | |||
@@ -159,7 +154,7 @@ public class SearchAction implements IssuesWsAction { | |||
); | |||
private static final String INTERNAL_PARAMETER_DISCLAIMER = "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. "; | |||
private static final Set<String> FACETS_REQUIRING_PROJECT = newHashSet(PARAM_MODULE_UUIDS, PARAM_FILES, PARAM_DIRECTORIES); | |||
private static final Set<String> FACETS_REQUIRING_PROJECT = newHashSet(FACET_MODULES, PARAM_FILES, PARAM_DIRECTORIES); | |||
private final UserSession userSession; | |||
private final IssueIndex issueIndex; | |||
@@ -191,6 +186,7 @@ public class SearchAction implements IssuesWsAction { | |||
+ "<br/>When issue indexation is in progress returns 503 service unavailable HTTP code.") | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("9.1", "Deprecated parameters 'authors', 'facetMode' and 'moduleUuids' were dropped"), | |||
new Change("8.6", "Parameter 'timeZone' added"), | |||
new Change("8.5", "Facet 'fileUuids' is dropped in favour of the new facet 'files'" + | |||
"Note that they are not strictly identical, the latter returns the file paths."), | |||
@@ -202,11 +198,11 @@ public class SearchAction implements IssuesWsAction { | |||
new Change("8.2", "Status 'IN_REVIEW' for Security Hotspots has been deprecated"), | |||
new Change("7.8", format("added new Security Hotspots statuses : %s, %s and %s", STATUS_TO_REVIEW, STATUS_IN_REVIEW, STATUS_REVIEWED)), | |||
new Change("7.8", "Security hotspots are returned by default"), | |||
new Change("7.7", format("Value '%s' in parameter '%s' is deprecated, please use '%s' instead", DEPRECATED_PARAM_AUTHORS, FACETS, PARAM_AUTHOR)), | |||
new Change("7.7", format("Value 'authors' in parameter '%s' is deprecated, please use '%s' instead", FACETS, PARAM_AUTHOR)), | |||
new Change("7.6", format("The use of module keys in parameter '%s' is deprecated", PARAM_COMPONENT_KEYS)), | |||
new Change("7.4", "The facet 'projectUuids' is dropped in favour of the new facet 'projects'. " + | |||
"Note that they are not strictly identical, the latter returns the project keys."), | |||
new Change("7.4", format("Parameter '%s' does not accept anymore deprecated value 'debt'", FACET_MODE)), | |||
new Change("7.4", "Parameter 'facetMode' does not accept anymore deprecated value 'debt'"), | |||
new Change("7.3", "response field 'fromHotspot' added to issues that are security hotspots"), | |||
new Change("7.3", "added facets 'sansTop25', 'owaspTop10' and 'cwe'"), | |||
new Change("7.2", "response field 'externalRuleEngine' added to issues that have been imported from an external rule engine"), | |||
@@ -222,11 +218,6 @@ public class SearchAction implements IssuesWsAction { | |||
action.createParam(FACETS) | |||
.setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.") | |||
.setPossibleValues(SUPPORTED_FACETS); | |||
action.createParam(FACET_MODE) | |||
.setDefaultValue(FACET_MODE_COUNT) | |||
.setDeprecatedSince("7.9") | |||
.setDescription("Choose the returned value for facet items, either count of issues or sum of remediation effort.") | |||
.setPossibleValues(FACET_MODE_COUNT, FACET_MODE_EFFORT); | |||
action.addSortParams(IssueQuery.SORTS, null, true); | |||
action.createParam(PARAM_ADDITIONAL_FIELDS) | |||
.setSince("5.2") | |||
@@ -278,10 +269,6 @@ public class SearchAction implements IssuesWsAction { | |||
" with any category") | |||
.setSince("7.8") | |||
.setPossibleValues(Arrays.stream(SQCategory.values()).map(SQCategory::getKey).collect(Collectors.toList())); | |||
action.createParam(DEPRECATED_PARAM_AUTHORS) | |||
.setDeprecatedSince("7.7") | |||
.setDescription("This parameter is deprecated, please use '%s' instead", PARAM_AUTHOR) | |||
.setExampleValue("torvalds@linux-foundation.org"); | |||
action.createParam(PARAM_AUTHOR) | |||
.setDescription("SCM accounts. To set several values, the parameter must be called once for each value.") | |||
.setExampleValue("author=torvalds@linux-foundation.org&author=linux@fondation.org"); | |||
@@ -347,13 +334,6 @@ public class SearchAction implements IssuesWsAction { | |||
.setInternal(true) | |||
.setExampleValue(KEY_PROJECT_EXAMPLE_001); | |||
action.createParam(PARAM_MODULE_UUIDS) | |||
.setDescription("To retrieve issues associated to a specific list of modules (comma-separated list of module IDs). " + | |||
INTERNAL_PARAMETER_DISCLAIMER) | |||
.setInternal(true) | |||
.setDeprecatedSince("7.6") | |||
.setExampleValue("7d8749e8-3070-4903-9188-bdd82933bb92"); | |||
action.createParam(PARAM_DIRECTORIES) | |||
.setDescription("To retrieve issues associated to a specific list of directories (comma-separated list of directory paths). " + | |||
"This parameter is only meaningful when a module is selected. " + | |||
@@ -448,7 +428,7 @@ public class SearchAction implements IssuesWsAction { | |||
addMandatoryValuesToFacet(facets, PARAM_STATUSES, ISSUE_STATUSES); | |||
addMandatoryValuesToFacet(facets, PARAM_RESOLUTIONS, concat(singletonList(""), RESOLUTIONS)); | |||
addMandatoryValuesToFacet(facets, FACET_PROJECTS, query.projectUuids()); | |||
addMandatoryValuesToFacet(facets, PARAM_MODULE_UUIDS, query.moduleUuids()); | |||
addMandatoryValuesToFacet(facets, FACET_MODULES, query.moduleUuids()); | |||
addMandatoryValuesToFacet(facets, PARAM_FILES, query.files()); | |||
List<String> assignees = Lists.newArrayList(""); | |||
@@ -499,13 +479,11 @@ public class SearchAction implements IssuesWsAction { | |||
private static void collectFacets(SearchResponseLoader.Collector collector, Facets facets) { | |||
collector.addProjectUuids(facets.getBucketKeys(FACET_PROJECTS)); | |||
collector.addComponentUuids(facets.getBucketKeys(PARAM_MODULE_UUIDS)); | |||
collector.addRuleIds(facets.getBucketKeys(PARAM_RULES)); | |||
collector.addUserUuids(facets.getBucketKeys(PARAM_ASSIGNEES)); | |||
} | |||
private static void collectRequestParams(SearchResponseLoader.Collector collector, SearchRequest request) { | |||
collector.addComponentUuids(request.getModuleUuids()); | |||
collector.addUserUuids(request.getAssigneeUuids()); | |||
} | |||
@@ -515,20 +493,18 @@ public class SearchAction implements IssuesWsAction { | |||
.setAsc(request.mandatoryParamAsBoolean(PARAM_ASC)) | |||
.setAssigned(request.paramAsBoolean(PARAM_ASSIGNED)) | |||
.setAssigneesUuid(getLogins(dbSession, request.paramAsStrings(PARAM_ASSIGNEES))) | |||
.setAuthors(request.hasParam(PARAM_AUTHOR) ? request.multiParam(PARAM_AUTHOR) : request.paramAsStrings(DEPRECATED_PARAM_AUTHORS)) | |||
.setAuthors(request.multiParam(PARAM_AUTHOR)) | |||
.setComponents(request.paramAsStrings(PARAM_COMPONENT_KEYS)) | |||
.setCreatedAfter(request.param(PARAM_CREATED_AFTER)) | |||
.setCreatedAt(request.param(PARAM_CREATED_AT)) | |||
.setCreatedBefore(request.param(PARAM_CREATED_BEFORE)) | |||
.setCreatedInLast(request.param(PARAM_CREATED_IN_LAST)) | |||
.setDirectories(request.paramAsStrings(PARAM_DIRECTORIES)) | |||
.setFacetMode(request.mandatoryParam(FACET_MODE)) | |||
.setFacets(request.paramAsStrings(FACETS)) | |||
.setFiles(request.paramAsStrings(PARAM_FILES)) | |||
.setIssues(request.paramAsStrings(PARAM_ISSUES)) | |||
.setScopes(request.paramAsStrings(PARAM_SCOPES)) | |||
.setLanguages(request.paramAsStrings(PARAM_LANGUAGES)) | |||
.setModuleUuids(request.paramAsStrings(PARAM_MODULE_UUIDS)) | |||
.setOnComponentOnly(request.paramAsBoolean(PARAM_ON_COMPONENT_ONLY)) | |||
.setBranch(request.param(PARAM_BRANCH)) | |||
.setPullRequest(request.param(PARAM_PULL_REQUEST)) |
@@ -50,7 +50,6 @@ public class PermissionsWsModule extends Module { | |||
RemoveUserAction.class, | |||
UsersAction.class, | |||
GroupsAction.class, | |||
SearchGlobalPermissionsAction.class, | |||
RemoveUserFromTemplateAction.class, | |||
AddUserToTemplateAction.class, | |||
AddGroupToTemplateAction.class, |
@@ -1,123 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.permission.ws; | |||
import java.util.Locale; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.core.i18n.I18n; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.permission.GlobalPermission; | |||
import org.sonar.db.permission.PermissionQuery; | |||
import org.sonar.server.permission.PermissionService; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonarqube.ws.Permissions.Permission; | |||
import org.sonarqube.ws.Permissions.WsSearchGlobalPermissionsResponse; | |||
import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdmin; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.Permissions.Permission.newBuilder; | |||
public class SearchGlobalPermissionsAction implements PermissionsWsAction { | |||
public static final String ACTION = "search_global_permissions"; | |||
private static final String PROPERTY_PREFIX = "global_permissions."; | |||
private static final String DESCRIPTION_SUFFIX = ".desc"; | |||
private final DbClient dbClient; | |||
private final UserSession userSession; | |||
private final I18n i18n; | |||
private final PermissionService permissionService; | |||
public SearchGlobalPermissionsAction(DbClient dbClient, UserSession userSession, I18n i18n, PermissionService permissionService) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.i18n = i18n; | |||
this.permissionService = permissionService; | |||
} | |||
@Override | |||
public void define(WebService.NewController context) { | |||
context.createAction(ACTION) | |||
.setDescription("List global permissions. <br />" + | |||
"Requires the following permission: 'Administer System'") | |||
.setResponseExample(getClass().getResource("search_global_permissions-example.json")) | |||
.setSince("5.2") | |||
.setDeprecatedSince("6.5") | |||
.setHandler(this); | |||
} | |||
@Override | |||
public void handle(Request wsRequest, Response wsResponse) throws Exception { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
checkGlobalAdmin(userSession); | |||
WsSearchGlobalPermissionsResponse response = buildResponse(dbSession); | |||
writeProtobuf(response, wsRequest, wsResponse); | |||
} | |||
} | |||
private WsSearchGlobalPermissionsResponse buildResponse(DbSession dbSession) { | |||
WsSearchGlobalPermissionsResponse.Builder response = WsSearchGlobalPermissionsResponse.newBuilder(); | |||
Permission.Builder permission = newBuilder(); | |||
permissionService.getGlobalPermissions().stream() | |||
.map(GlobalPermission::getKey) | |||
.forEach(permissionKey -> { | |||
PermissionQuery query = permissionQuery(permissionKey); | |||
response.addPermissions( | |||
permission | |||
.clear() | |||
.setKey(permissionKey) | |||
.setName(i18nName(permissionKey)) | |||
.setDescription(i18nDescriptionMessage(permissionKey)) | |||
.setUsersCount(countUsers(dbSession, query)) | |||
.setGroupsCount(countGroups(dbSession, permissionKey))); | |||
}); | |||
return response.build(); | |||
} | |||
private String i18nDescriptionMessage(String permissionKey) { | |||
return i18n.message(Locale.ENGLISH, PROPERTY_PREFIX + permissionKey + DESCRIPTION_SUFFIX, ""); | |||
} | |||
private String i18nName(String permissionKey) { | |||
return i18n.message(Locale.ENGLISH, PROPERTY_PREFIX + permissionKey, permissionKey); | |||
} | |||
private int countGroups(DbSession dbSession, String permission) { | |||
PermissionQuery query = PermissionQuery.builder().setPermission(permission).build(); | |||
return dbClient.groupPermissionDao().countGroupsByQuery(dbSession, query); | |||
} | |||
private int countUsers(DbSession dbSession, PermissionQuery permissionQuery) { | |||
return dbClient.userPermissionDao().countUsersByQuery(dbSession, permissionQuery); | |||
} | |||
private static PermissionQuery permissionQuery(String permissionKey) { | |||
return PermissionQuery.builder() | |||
.setPermission(permissionKey) | |||
.withAtLeastOnePermission() | |||
.build(); | |||
} | |||
} |
@@ -1,115 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.permission.ws; | |||
import com.google.common.collect.FluentIterable; | |||
import com.google.common.collect.Iterables; | |||
import com.google.common.collect.Ordering; | |||
import com.google.common.collect.Table; | |||
import java.util.List; | |||
import java.util.Set; | |||
import org.sonar.api.utils.Paging; | |||
import org.sonar.db.component.ComponentDto; | |||
import static com.google.common.base.MoreObjects.firstNonNull; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static com.google.common.collect.ImmutableList.copyOf; | |||
import static com.google.common.collect.ImmutableTable.copyOf; | |||
class SearchProjectPermissionsData { | |||
private final List<ComponentDto> rootComponents; | |||
private final Paging paging; | |||
private final Table<String, String, Integer> userCountByProjectUuidAndPermission; | |||
private final Table<String, String, Integer> groupCountByProjectUuidAndPermission; | |||
private SearchProjectPermissionsData(Builder builder) { | |||
this.rootComponents = copyOf(builder.projects); | |||
this.paging = builder.paging; | |||
this.userCountByProjectUuidAndPermission = copyOf(builder.userCountByProjectUuidAndPermission); | |||
this.groupCountByProjectUuidAndPermission = copyOf(builder.groupCountByProjectUuidAndPermission); | |||
} | |||
static Builder newBuilder() { | |||
return new Builder(); | |||
} | |||
List<ComponentDto> rootComponents() { | |||
return rootComponents; | |||
} | |||
Paging paging() { | |||
return paging; | |||
} | |||
int userCount(String rootComponentUuid, String permission) { | |||
return firstNonNull(userCountByProjectUuidAndPermission.get(rootComponentUuid, permission), 0); | |||
} | |||
int groupCount(String rootComponentUuid, String permission) { | |||
return firstNonNull(groupCountByProjectUuidAndPermission.get(rootComponentUuid, permission), 0); | |||
} | |||
Set<String> permissions(String rootComponentUuid) { | |||
return FluentIterable.from( | |||
Iterables.concat( | |||
userCountByProjectUuidAndPermission.row(rootComponentUuid).keySet(), | |||
groupCountByProjectUuidAndPermission.row(rootComponentUuid).keySet())) | |||
.toSortedSet(Ordering.natural()); | |||
} | |||
static class Builder { | |||
private List<ComponentDto> projects; | |||
private Paging paging; | |||
private Table<String, String, Integer> userCountByProjectUuidAndPermission; | |||
private Table<String, String, Integer> groupCountByProjectUuidAndPermission; | |||
private Builder() { | |||
// prevents instantiation outside main class | |||
} | |||
SearchProjectPermissionsData build() { | |||
checkState(projects != null); | |||
checkState(userCountByProjectUuidAndPermission != null); | |||
checkState(groupCountByProjectUuidAndPermission != null); | |||
return new SearchProjectPermissionsData(this); | |||
} | |||
Builder rootComponents(List<ComponentDto> projects) { | |||
this.projects = projects; | |||
return this; | |||
} | |||
Builder paging(Paging paging) { | |||
this.paging = paging; | |||
return this; | |||
} | |||
Builder userCountByProjectIdAndPermission(Table<String, String, Integer> userCountByProjectIdAndPermission) { | |||
this.userCountByProjectUuidAndPermission = userCountByProjectIdAndPermission; | |||
return this; | |||
} | |||
Builder groupCountByProjectIdAndPermission(Table<String, String, Integer> groupCountByProjectIdAndPermission) { | |||
this.groupCountByProjectUuidAndPermission = groupCountByProjectIdAndPermission; | |||
return this; | |||
} | |||
} | |||
} |
@@ -1,241 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.project.ws; | |||
import com.google.common.collect.ImmutableList; | |||
import java.util.Map; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentKeyUpdaterDao; | |||
import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.component.ComponentFinder; | |||
import org.sonar.server.component.ComponentService; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonarqube.ws.Projects.BulkUpdateKeyWsResponse; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static org.sonar.server.exceptions.BadRequestException.checkRequest; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_BULK_UPDATE_KEY; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_DRY_RUN; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_FROM; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_TO; | |||
public class BulkUpdateKeyAction implements ProjectsWsAction { | |||
private final DbClient dbClient; | |||
private final ComponentFinder componentFinder; | |||
private final ComponentKeyUpdaterDao componentKeyUpdater; | |||
private final ComponentService componentService; | |||
private final UserSession userSession; | |||
public BulkUpdateKeyAction(DbClient dbClient, ComponentFinder componentFinder, ComponentService componentService, UserSession userSession) { | |||
this.dbClient = dbClient; | |||
this.componentKeyUpdater = dbClient.componentKeyUpdaterDao(); | |||
this.componentFinder = componentFinder; | |||
this.componentService = componentService; | |||
this.userSession = userSession; | |||
} | |||
@Override | |||
public void define(WebService.NewController context) { | |||
doDefine(context); | |||
} | |||
public WebService.NewAction doDefine(WebService.NewController context) { | |||
WebService.NewAction action = context.createAction(ACTION_BULK_UPDATE_KEY) | |||
.setDescription("Bulk update a project key and all its sub-components keys. " + | |||
"The bulk update allows to replace a part of the current key by another string on the current project.<br>" + | |||
"It's possible to simulate the bulk update by setting the parameter '%s' at true. No key is updated with a dry run.<br>" + | |||
"Ex: to rename a project with key 'my_project' to 'my_new_project' and all its sub-components keys, call the WS with parameters:" + | |||
"<ul>" + | |||
" <li>%s: my_project</li>" + | |||
" <li>%s: my_</li>" + | |||
" <li>%s: my_new_</li>" + | |||
"</ul>" + | |||
"Requires one of the following permissions: " + | |||
"<ul>" + | |||
"<li>'Administer System'</li>" + | |||
"<li>'Administer' rights on the specified project</li>" + | |||
"</ul>", | |||
PARAM_DRY_RUN, | |||
PARAM_PROJECT, PARAM_FROM, PARAM_TO) | |||
.setDeprecatedSince("7.6") | |||
.setSince("6.1") | |||
.setPost(true) | |||
.setResponseExample(getClass().getResource("bulk_update_key-example.json")) | |||
.setHandler(this); | |||
action.createParam(PARAM_PROJECT) | |||
.setDescription("Project key") | |||
.setRequired(true) | |||
.setExampleValue("my_old_project"); | |||
action.createParam(PARAM_FROM) | |||
.setDescription("String to match in components keys") | |||
.setRequired(true) | |||
.setExampleValue("_old"); | |||
action.createParam(PARAM_TO) | |||
.setDescription("String replacement in components keys") | |||
.setRequired(true) | |||
.setExampleValue("_new"); | |||
action.createParam(PARAM_DRY_RUN) | |||
.setDescription("Simulate bulk update. No component key is updated.") | |||
.setBooleanPossibleValues() | |||
.setDefaultValue(false); | |||
return action; | |||
} | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
writeProtobuf(doHandle(toWsRequest(request)), request, response); | |||
} | |||
private BulkUpdateKeyWsResponse doHandle(BulkUpdateKeyRequest request) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
ProjectDto project = componentFinder.getProjectByKey(dbSession, request.getProjectKey()); | |||
userSession.checkProjectPermission(UserRole.ADMIN, project); | |||
Map<String, String> newKeysByOldKeys = componentKeyUpdater.simulateBulkUpdateKey(dbSession, project.getUuid(), request.getFrom(), request.getTo()); | |||
Map<String, Boolean> newKeysWithDuplicateMap = componentKeyUpdater.checkComponentKeys(dbSession, ImmutableList.copyOf(newKeysByOldKeys.values())); | |||
if (!request.isDryRun()) { | |||
checkNoDuplicate(newKeysWithDuplicateMap); | |||
bulkUpdateKey(dbSession, request, project); | |||
} | |||
return buildResponse(newKeysByOldKeys, newKeysWithDuplicateMap); | |||
} | |||
} | |||
private static void checkNoDuplicate(Map<String, Boolean> newKeysWithDuplicateMap) { | |||
newKeysWithDuplicateMap.forEach((key, value) -> checkRequest(!value, "Impossible to update key: a component with key \"%s\" already exists.", key)); | |||
} | |||
private void bulkUpdateKey(DbSession dbSession, BulkUpdateKeyRequest request, ProjectDto project) { | |||
componentService.bulkUpdateKey(dbSession, project, request.getFrom(), request.getTo()); | |||
} | |||
private static BulkUpdateKeyWsResponse buildResponse(Map<String, String> newKeysByOldKeys, Map<String, Boolean> newKeysWithDuplicateMap) { | |||
BulkUpdateKeyWsResponse.Builder response = BulkUpdateKeyWsResponse.newBuilder(); | |||
newKeysByOldKeys.entrySet().stream() | |||
// sort by old key | |||
.sorted(Map.Entry.comparingByKey()) | |||
.forEach( | |||
entry -> { | |||
String newKey = entry.getValue(); | |||
response.addKeysBuilder() | |||
.setKey(entry.getKey()) | |||
.setNewKey(newKey) | |||
.setDuplicate(newKeysWithDuplicateMap.getOrDefault(newKey, false)); | |||
}); | |||
return response.build(); | |||
} | |||
private static BulkUpdateKeyRequest toWsRequest(Request request) { | |||
return BulkUpdateKeyRequest.builder() | |||
.setProjectKey(request.mandatoryParam(PARAM_PROJECT)) | |||
.setFrom(request.mandatoryParam(PARAM_FROM)) | |||
.setTo(request.mandatoryParam(PARAM_TO)) | |||
.setDryRun(request.mandatoryParamAsBoolean(PARAM_DRY_RUN)) | |||
.build(); | |||
} | |||
private static class BulkUpdateKeyRequest { | |||
private final String projectKey; | |||
private final String from; | |||
private final String to; | |||
private final boolean dryRun; | |||
public BulkUpdateKeyRequest(Builder builder) { | |||
this.projectKey = builder.projectKey; | |||
this.from = builder.from; | |||
this.to = builder.to; | |||
this.dryRun = builder.dryRun; | |||
} | |||
public String getProjectKey() { | |||
return projectKey; | |||
} | |||
public String getFrom() { | |||
return from; | |||
} | |||
public String getTo() { | |||
return to; | |||
} | |||
public boolean isDryRun() { | |||
return dryRun; | |||
} | |||
public static Builder builder() { | |||
return new Builder(); | |||
} | |||
} | |||
public static class Builder { | |||
private String projectKey; | |||
private String from; | |||
private String to; | |||
private boolean dryRun; | |||
private Builder() { | |||
// enforce method constructor | |||
} | |||
public Builder setProjectKey(String projectKey) { | |||
this.projectKey = projectKey; | |||
return this; | |||
} | |||
public Builder setFrom(String from) { | |||
this.from = from; | |||
return this; | |||
} | |||
public Builder setTo(String to) { | |||
this.to = to; | |||
return this; | |||
} | |||
public Builder setDryRun(boolean dryRun) { | |||
this.dryRun = dryRun; | |||
return this; | |||
} | |||
public BulkUpdateKeyRequest build() { | |||
checkArgument(projectKey != null && !projectKey.isEmpty(), "The key must not be empty"); | |||
checkArgument(from != null && !from.isEmpty(), "The string to match must not be empty"); | |||
checkArgument(to != null && !to.isEmpty(), "The string replacement must not be empty"); | |||
return new BulkUpdateKeyRequest(this); | |||
} | |||
} | |||
} |
@@ -39,7 +39,6 @@ public class ProjectsWsModule extends Module { | |||
BulkDeleteAction.class, | |||
DeleteAction.class, | |||
UpdateKeyAction.class, | |||
BulkUpdateKeyAction.class, | |||
SearchMyProjectsAction.class, | |||
SearchAction.class, | |||
UpdateVisibilityAction.class, |
@@ -22,12 +22,8 @@ package org.sonar.server.qualitygate.ws; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.Stream; | |||
import org.sonar.api.server.ws.Change; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.qualitygate.Condition; | |||
import org.sonar.server.ws.RemovedWebServiceHandler; | |||
import static org.sonar.server.qualitygate.QualityGateConditionsUpdater.INVALID_METRIC_KEYS; | |||
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.CONTROLLER_QUALITY_GATES; | |||
@@ -54,17 +50,6 @@ public class QualityGatesWs implements WebService { | |||
action.define(controller); | |||
} | |||
// unset_default is no more authorized | |||
controller.createAction("unset_default") | |||
.setDescription("This webservice is no more available : a default quality gate is mandatory.") | |||
.setSince("4.3") | |||
.setDeprecatedSince("7.0") | |||
.setPost(true) | |||
.setHandler(RemovedWebServiceHandler.INSTANCE) | |||
.setResponseExample(RemovedWebServiceHandler.INSTANCE.getResponseExample()) | |||
.setChangelog( | |||
new Change("7.0", "Unset a quality gate is no more authorized")); | |||
controller.done(); | |||
} | |||
@@ -106,14 +91,6 @@ public class QualityGatesWs implements WebService { | |||
.collect(Collectors.joining()); | |||
} | |||
static Long parseId(Request request, String paramName) { | |||
try { | |||
return Long.valueOf(request.mandatoryParam(paramName)); | |||
} catch (NumberFormatException badFormat) { | |||
throw BadRequestException.create(paramName + " must be a valid long value"); | |||
} | |||
} | |||
private static Set<String> getPossibleOperators() { | |||
return Stream.of(Condition.Operator.values()) | |||
.map(Condition.Operator::getDbValue) |
@@ -1,114 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.source.ws; | |||
import com.google.common.io.CharStreams; | |||
import com.google.common.io.Resources; | |||
import java.io.IOException; | |||
import java.io.OutputStreamWriter; | |||
import java.io.Reader; | |||
import java.nio.charset.StandardCharsets; | |||
import java.util.function.Consumer; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.component.ComponentFinder; | |||
import org.sonar.server.user.UserSession; | |||
import static org.sonar.server.ws.KeyExamples.KEY_FILE_EXAMPLE_001; | |||
public class HashAction implements SourcesWsAction { | |||
private final DbClient dbClient; | |||
private final UserSession userSession; | |||
private final ComponentFinder componentFinder; | |||
public HashAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
this.componentFinder = componentFinder; | |||
} | |||
@Override | |||
public void define(WebService.NewController controller) { | |||
WebService.NewAction action = controller.createAction("hash") | |||
.setDescription("Show line line hashes for a given file. Require See Source Code permission on file's project<br/>") | |||
.setSince("5.0") | |||
.setInternal(true) | |||
.setDeprecatedSince("7.7") | |||
.setResponseExample(Resources.getResource(getClass(), "example-hash.txt")) | |||
.setHandler(this); | |||
action | |||
.createParam("key") | |||
.setRequired(true) | |||
.setDescription("File key") | |||
.setExampleValue(KEY_FILE_EXAMPLE_001); | |||
} | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
try (DbSession session = dbClient.openSession(false)) { | |||
String componentKey = request.mandatoryParam("key"); | |||
ComponentDto component = componentFinder.getByKey(session, componentKey); | |||
userSession.checkComponentPermission(UserRole.USER, component); | |||
response.stream().setMediaType("text/plain"); | |||
try (OutputStreamWriter writer = new OutputStreamWriter(response.stream().output(), StandardCharsets.UTF_8)) { | |||
HashConsumer hashFunction = new HashConsumer(writer, componentKey); | |||
dbClient.fileSourceDao().readLineHashesStream(session, component.uuid(), hashFunction); | |||
if (!hashFunction.hasData()) { | |||
response.noContent(); | |||
} | |||
} | |||
} | |||
} | |||
private static class HashConsumer implements Consumer<Reader> { | |||
private final OutputStreamWriter writer; | |||
private final String componentKey; | |||
private boolean hasData = false; | |||
public HashConsumer(OutputStreamWriter writer, String componentKey) { | |||
this.writer = writer; | |||
this.componentKey = componentKey; | |||
} | |||
@Override | |||
public void accept(Reader input) { | |||
try { | |||
hasData = true; | |||
CharStreams.copy(input, writer); | |||
} catch (IOException e) { | |||
throw new IllegalStateException(String.format("Can't read line hashes of file '%s'", componentKey), e); | |||
} | |||
} | |||
public boolean hasData() { | |||
return hasData; | |||
} | |||
} | |||
} |
@@ -34,7 +34,6 @@ public class SourceWsModule extends Module { | |||
ShowAction.class, | |||
IssueSnippetsAction.class, | |||
LinesAction.class, | |||
HashAction.class, | |||
RawAction.class, | |||
IndexAction.class, | |||
ScmAction.class |
@@ -1,19 +0,0 @@ | |||
{ | |||
"keys": [ | |||
{ | |||
"key": "my_project", | |||
"newKey": "my_new_project", | |||
"duplicate": false | |||
}, | |||
{ | |||
"key": "my_project:module_1", | |||
"newKey": "my_new_project:module_1", | |||
"duplicate": true | |||
}, | |||
{ | |||
"key": "my_project:module_2", | |||
"newKey": "my_new_project:module_2", | |||
"duplicate": false | |||
} | |||
] | |||
} |
@@ -1,76 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.component; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.es.TestProjectIndexers; | |||
import org.sonar.server.project.ProjectLifeCycleListeners; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
public class ComponentServiceTest { | |||
@Rule | |||
public final UserSessionRule userSession = UserSessionRule.standalone(); | |||
@Rule | |||
public final DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
private final ComponentDbTester componentDb = new ComponentDbTester(dbTester); | |||
private final DbClient dbClient = dbTester.getDbClient(); | |||
private final DbSession dbSession = dbTester.getSession(); | |||
private final TestProjectIndexers projectIndexers = new TestProjectIndexers(); | |||
private final ProjectLifeCycleListeners projectLifeCycleListeners = mock(ProjectLifeCycleListeners.class); | |||
private final ComponentService underTest = new ComponentService(dbClient, userSession, projectIndexers, projectLifeCycleListeners); | |||
@Test | |||
public void bulk_update() { | |||
ComponentDto project = componentDb.insertPublicProject(c -> c.setDbKey("my_project")); | |||
ComponentDto module = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:module")); | |||
ComponentDto inactiveModule = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:inactive_module").setEnabled(false)); | |||
ComponentDto file = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/File.xoo")); | |||
ComponentDto inactiveFile = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/InactiveFile.xoo").setEnabled(false)); | |||
underTest.bulkUpdateKey(dbSession, componentDb.getProjectDto(project), "my_", "your_"); | |||
assertComponentKeyUpdated(project.getDbKey(), "your_project"); | |||
assertComponentKeyUpdated(module.getDbKey(), "your_project:root:module"); | |||
assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo"); | |||
assertComponentKeyUpdated(inactiveModule.getDbKey(), "your_project:root:inactive_module"); | |||
assertComponentKeyUpdated(inactiveFile.getDbKey(), "your_project:root:module:src/InactiveFile.xoo"); | |||
} | |||
private void assertComponentKeyUpdated(String oldKey, String newKey) { | |||
assertThat(dbClient.componentDao().selectByKey(dbSession, oldKey)).isEmpty(); | |||
assertThat(dbClient.componentDao().selectByKey(dbSession, newKey)).isPresent(); | |||
} | |||
} |
@@ -19,7 +19,6 @@ | |||
*/ | |||
package org.sonar.server.component; | |||
import com.google.common.collect.ImmutableSet; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.System2; | |||
@@ -34,18 +33,12 @@ import org.sonar.db.project.ProjectDto; | |||
import org.sonar.server.es.ProjectIndexer; | |||
import org.sonar.server.es.TestProjectIndexers; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.project.Project; | |||
import org.sonar.server.project.ProjectLifeCycleListeners; | |||
import org.sonar.server.project.RekeyedProject; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import static java.util.Collections.emptyList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
public class ComponentServiceUpdateKeyTest { | |||
@@ -149,46 +142,6 @@ public class ComponentServiceUpdateKeyTest { | |||
.hasMessage("Malformed key for 'sample?root'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); | |||
} | |||
@Test | |||
public void bulk_update_key() { | |||
ComponentDto project = componentDb.insertPublicProject(c -> c.setDbKey("my_project")); | |||
ComponentDto module = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:module")); | |||
ComponentDto inactiveModule = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:inactive_module").setEnabled(false)); | |||
ComponentDto file = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/File.xoo")); | |||
ComponentDto inactiveFile = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/InactiveFile.xoo").setEnabled(false)); | |||
underTest.bulkUpdateKey(dbSession, componentDb.getProjectDto(project), "my_", "your_"); | |||
assertComponentKeyUpdated(project.getDbKey(), "your_project"); | |||
assertComponentKeyUpdated(module.getDbKey(), "your_project:root:module"); | |||
assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo"); | |||
assertComponentKeyUpdated(inactiveModule.getDbKey(), "your_project:root:inactive_module"); | |||
assertComponentKeyUpdated(inactiveFile.getDbKey(), "your_project:root:module:src/InactiveFile.xoo"); | |||
verify(projectLifeCycleListeners).onProjectsRekeyed(ImmutableSet.of( | |||
new RekeyedProject(new Project(project.uuid(), "your_project", project.name(), project.uuid(), emptyList()), "my_project"))); | |||
} | |||
@Test | |||
public void bulk_update_key_with_branch_and_pr() { | |||
ComponentDto project = componentDb.insertPublicProject(c -> c.setDbKey("my_project")); | |||
ComponentDto branch = componentDb.insertProjectBranch(project); | |||
ComponentDto module = componentDb.insertComponent(newModuleDto(branch).setDbKey("my_project:root:module")); | |||
ComponentDto file = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/File.xoo")); | |||
underTest.bulkUpdateKey(dbSession, componentDb.getProjectDto(project), "my_", "your_"); | |||
assertComponentKeyUpdated(project.getDbKey(), "your_project"); | |||
assertComponentKeyUpdated(module.getDbKey(), "your_project:root:module"); | |||
assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo"); | |||
verify(projectLifeCycleListeners).onProjectsRekeyed(ImmutableSet.of( | |||
new RekeyedProject(new Project(project.uuid(), "your_project", project.name(), project.uuid(), emptyList()), "my_project"))); | |||
} | |||
private void assertComponentKeyUpdated(String oldKey, String newKey) { | |||
assertThat(dbClient.componentDao().selectByKey(dbSession, oldKey)).isEmpty(); | |||
assertThat(dbClient.componentDao().selectByKey(dbSession, newKey)).isPresent(); | |||
} | |||
private ComponentDto insertSampleProject() { | |||
return insertProject("sample:root"); | |||
} |
@@ -72,13 +72,10 @@ import static org.sonar.db.component.ComponentTesting.newDirectory; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.db.component.ComponentTesting.newProjectCopy; | |||
import static org.sonar.db.component.ComponentTesting.newSubPortfolio; | |||
import static org.sonar.db.component.ComponentTesting.newPortfolio; | |||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_MODULE_UUIDS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PULL_REQUEST; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD; | |||
@@ -169,11 +166,6 @@ public class SearchActionComponentsTest { | |||
.setParam(PARAM_COMPONENT_KEYS, module1.getKey()) | |||
.executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey) | |||
.containsExactlyInAnyOrder(issue1.getKey()); | |||
assertThat(ws.newRequest() | |||
.setParam(PARAM_MODULE_UUIDS, module1.uuid()) | |||
.executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey) | |||
.containsExactlyInAnyOrder(issue1.getKey()); | |||
} | |||
@Test | |||
@@ -343,18 +335,6 @@ public class SearchActionComponentsTest { | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
ws.newRequest() | |||
.setParam(PARAM_MODULE_UUIDS, module1.uuid()) | |||
.setParam(PARAM_DIRECTORIES, "src/main/java/dir") | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_directory_uuid.json"); | |||
ws.newRequest() | |||
.setParam(PARAM_MODULE_UUIDS, module2.uuid()) | |||
.setParam(PARAM_DIRECTORIES, "src/main/java/dir") | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
ws.newRequest() | |||
.setParam(PARAM_DIRECTORIES, "src/main/java/dir") | |||
.execute() |
@@ -63,11 +63,8 @@ import static org.sonar.db.component.ComponentTesting.newDirectory; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.server.tester.UserSessionRule.standalone; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_EFFORT; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_UUIDS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_MODULE_UUIDS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS; | |||
public class SearchActionFacetsTest { | |||
@@ -135,43 +132,6 @@ public class SearchActionFacetsTest { | |||
tuple("assignees", of("", 0L, user.getLogin(), 1L))); | |||
} | |||
@Test | |||
public void display_facets_in_effort_mode() { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
RuleDefinitionDto rule = db.rules().insertIssueRule(); | |||
db.issues().insertIssue(rule, project, file, i -> i | |||
.setSeverity("MAJOR") | |||
.setStatus("OPEN") | |||
.setType(RuleType.CODE_SMELL) | |||
.setEffort(10L) | |||
.setAssigneeUuid(null)); | |||
indexPermissions(); | |||
indexIssues(); | |||
SearchWsResponse response = ws.newRequest() | |||
.setParam(PARAM_COMPONENT_KEYS, project.getKey()) | |||
.setParam(FACETS, "severities,statuses,resolutions,rules,types,languages,projects,files,assignees") | |||
.setParam("facetMode", FACET_MODE_EFFORT) | |||
.executeProtobuf(SearchWsResponse.class); | |||
Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 10L).put("CONFIRMED", 0L) | |||
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).build(); | |||
assertThat(response.getFacets().getFacetsList()) | |||
.extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount))) | |||
.containsExactlyInAnyOrder( | |||
tuple("severities", of("INFO", 0L, "MINOR", 0L, "MAJOR", 10L, "CRITICAL", 0L, "BLOCKER", 0L)), | |||
tuple("statuses", expectedStatuses), | |||
tuple("resolutions", of("", 10L, "FALSE-POSITIVE", 0L, "FIXED", 0L, "REMOVED", 0L, "WONTFIX", 0L)), | |||
tuple("rules", of(rule.getKey().toString(), 10L)), | |||
tuple("types", of("CODE_SMELL", 10L, "BUG", 0L, "VULNERABILITY", 0L)), | |||
tuple("languages", of(rule.getLanguage(), 10L)), | |||
tuple("projects", of(project.getKey(), 10L)), | |||
tuple("files", of(file.path(), 10L)), | |||
tuple("assignees", of("", 10L))); | |||
} | |||
@Test | |||
public void display_projects_facet() { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
@@ -216,52 +176,6 @@ public class SearchActionFacetsTest { | |||
.containsExactlyInAnyOrder(tuple("projects", of(project1.getKey(), 1L, project2.getKey(), 1L, project3.getKey(), 1L))); | |||
} | |||
@Test | |||
public void display_moduleUuids_facet_using_project() { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||
ComponentDto subModule1 = db.components().insertComponent(newModuleDto(module)); | |||
ComponentDto subModule2 = db.components().insertComponent(newModuleDto(module)); | |||
ComponentDto subModule3 = db.components().insertComponent(newModuleDto(module)); | |||
ComponentDto file1 = db.components().insertComponent(newFileDto(subModule1)); | |||
ComponentDto file2 = db.components().insertComponent(newFileDto(subModule2)); | |||
RuleDefinitionDto rule = db.rules().insertIssueRule(); | |||
db.issues().insertIssue(rule, project, file1); | |||
db.issues().insertIssue(rule, project, file2); | |||
indexPermissions(); | |||
indexIssues(); | |||
SearchWsResponse response = ws.newRequest() | |||
.setParam(PARAM_PROJECTS, project.getKey()) | |||
.setParam(PARAM_COMPONENT_UUIDS, module.uuid()) | |||
.setParam(PARAM_MODULE_UUIDS, subModule1.uuid()) | |||
.setParam(WebService.Param.FACETS, "moduleUuids") | |||
.executeProtobuf(SearchWsResponse.class); | |||
assertThat(response.getFacets().getFacetsList()) | |||
.extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount))) | |||
.containsExactlyInAnyOrder(tuple("moduleUuids", of(subModule1.uuid(), 1L, subModule2.uuid(), 1L))); | |||
} | |||
@Test | |||
public void fail_to_display_module_facet_when_no_project_is_set() { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||
ComponentDto file = db.components().insertComponent(newFileDto(module, null)); | |||
RuleDefinitionDto rule = db.rules().insertIssueRule(); | |||
db.issues().insertIssue(rule, project, file); | |||
indexPermissions(); | |||
indexIssues(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Facet(s) 'moduleUuids' require to also filter by project"); | |||
ws.newRequest() | |||
.setParam(PARAM_COMPONENT_UUIDS, module.uuid()) | |||
.setParam(WebService.Param.FACETS, "moduleUuids") | |||
.execute(); | |||
} | |||
@Test | |||
public void display_directory_facet_using_project() { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
@@ -439,7 +353,6 @@ public class SearchActionFacetsTest { | |||
SearchWsResponse response = ws.newRequest() | |||
.setParam(PARAM_PROJECTS, project1.getKey() + "," + project2.getKey()) | |||
.setParam(PARAM_MODULE_UUIDS, module1.uuid() + "," + module2.uuid()) | |||
.setParam(PARAM_FILES, file1.path() + "," + file2.path()) | |||
.setParam("rules", rule1.getKey().toString() + "," + rule2.getKey().toString()) | |||
.setParam("severities", "MAJOR,MINOR") | |||
@@ -461,7 +374,7 @@ public class SearchActionFacetsTest { | |||
tuple("types", of("CODE_SMELL", 1L, "BUG", 0L, "VULNERABILITY", 0L)), | |||
tuple("languages", of(rule1.getLanguage(), 1L, rule2.getLanguage(), 0L)), | |||
tuple("projects", of(project1.getKey(), 1L, project2.getKey(), 0L)), | |||
tuple("moduleUuids", of(module1.uuid(), 1L, module2.uuid(), 0L)), | |||
tuple("moduleUuids", of(module1.uuid(), 1L)), | |||
tuple("files", of(file1.path(), 1L, file2.path(), 0L)), | |||
tuple("assignees", of("", 0L, user1.getLogin(), 1L, user2.getLogin(), 0L))); | |||
} |
@@ -911,39 +911,6 @@ public class SearchActionTest { | |||
.assertJson(this.getClass(), "filter_by_main_scope_2.json"); | |||
} | |||
@Test | |||
public void search_by_deprecated_authors_parameter() { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project, null)); | |||
RuleDefinitionDto rule = db.rules().insertIssueRule(); | |||
IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i.setAuthorLogin("leia")); | |||
IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i.setAuthorLogin("luke")); | |||
indexPermissions(); | |||
indexIssues(); | |||
SearchWsResponse response = ws.newRequest() | |||
.setParam("authors", "leia") | |||
.setParam(FACETS, "authors") | |||
.executeProtobuf(SearchWsResponse.class); | |||
assertThat(response.getIssuesList()).extracting(Issue::getKey).containsExactlyInAnyOrder(issue1.getKey()); | |||
Common.Facet facet = response.getFacets().getFacetsList().get(0); | |||
assertThat(facet.getProperty()).isEqualTo("authors"); | |||
assertThat(facet.getValuesList()) | |||
.extracting(Common.FacetValue::getVal, Common.FacetValue::getCount) | |||
.containsExactlyInAnyOrder( | |||
tuple("leia", 1L), | |||
tuple("luke", 1L)); | |||
// Deprecated parameter 'authors' will be ignored if new parameter 'author' is set | |||
assertThat(ws.newRequest() | |||
.setMultiParam("author", singletonList("luke")) | |||
// This parameter will be ignored | |||
.setParam("authors", "leia") | |||
.executeProtobuf(SearchWsResponse.class).getIssuesList()) | |||
.extracting(Issue::getKey) | |||
.containsExactlyInAnyOrder(issue2.getKey()); | |||
} | |||
@Test | |||
public void sort_by_updated_at() { | |||
RuleDto rule = newIssueRule(); | |||
@@ -1350,8 +1317,8 @@ public class SearchActionTest { | |||
assertThat(def.responseExampleAsString()).isNotEmpty(); | |||
assertThat(def.params()).extracting("key").containsExactlyInAnyOrder( | |||
"additionalFields", "asc", "assigned", "assignees", "authors", "author", "componentKeys", "branch", "pullRequest", "createdAfter", "createdAt", | |||
"createdBefore", "createdInLast", "directories", "facetMode", "facets", "files", "issues", "scopes", "languages", "moduleUuids", "onComponentOnly", | |||
"additionalFields", "asc", "assigned", "assignees", "author", "componentKeys", "branch", "pullRequest", "createdAfter", "createdAt", | |||
"createdBefore", "createdInLast", "directories", "facets", "files", "issues", "scopes", "languages", "onComponentOnly", | |||
"p", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod", "statuses", "tags", "types", "owaspTop10", "sansTop25", | |||
"cwe", "sonarsourceSecurity", "timeZone"); | |||
@@ -30,6 +30,6 @@ public class PermissionsWsModuleTest { | |||
public void verify_count_of_added_components() { | |||
ComponentContainer container = new ComponentContainer(); | |||
new PermissionsWsModule().configure(container); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 27); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 26); | |||
} | |||
} |
@@ -1,119 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.permission.ws; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.resources.ResourceTypes; | |||
import org.sonar.core.permission.GlobalPermissions; | |||
import org.sonar.db.component.ResourceTypesRule; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.UnauthorizedException; | |||
import org.sonar.server.l18n.I18nRule; | |||
import org.sonar.server.permission.PermissionService; | |||
import org.sonar.server.permission.PermissionServiceImpl; | |||
import org.sonarqube.ws.Permissions; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION; | |||
import static org.sonar.db.permission.GlobalPermission.SCAN; | |||
public class SearchGlobalPermissionsActionTest extends BasePermissionWsTest<SearchGlobalPermissionsAction> { | |||
private I18nRule i18n = new I18nRule(); | |||
private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT); | |||
private PermissionService permissionService = new PermissionServiceImpl(resourceTypes); | |||
@Override | |||
protected SearchGlobalPermissionsAction buildWsAction() { | |||
return new SearchGlobalPermissionsAction(db.getDbClient(), userSession, i18n, permissionService); | |||
} | |||
@Before | |||
public void setUp() { | |||
initI18nMessages(); | |||
} | |||
@Test | |||
public void search() { | |||
loginAsAdmin(); | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertPermissionOnUser(user, SCAN); | |||
Permissions.WsSearchGlobalPermissionsResponse result = newRequest() | |||
.executeProtobuf(Permissions.WsSearchGlobalPermissionsResponse.class); | |||
assertThat(result.getPermissionsCount()).isEqualTo(GlobalPermissions.ALL.size()); | |||
for (Permissions.Permission permission : result.getPermissionsList()) { | |||
if (permission.getKey().equals(SCAN_EXECUTION)) { | |||
assertThat(permission.getUsersCount()).isEqualTo(1); | |||
} else { | |||
assertThat(permission.getUsersCount()).isZero(); | |||
} | |||
} | |||
} | |||
@Test | |||
public void supports_protobuf_response() { | |||
loginAsAdmin(); | |||
Permissions.WsSearchGlobalPermissionsResponse result = newRequest() | |||
.executeProtobuf(Permissions.WsSearchGlobalPermissionsResponse.class); | |||
assertThat(result).isNotNull(); | |||
} | |||
@Test | |||
public void fail_if_not_admin() { | |||
userSession.logIn(); | |||
expectedException.expect(ForbiddenException.class); | |||
newRequest() | |||
.execute(); | |||
} | |||
@Test | |||
public void fail_if_not_logged_in() { | |||
userSession.anonymous(); | |||
expectedException.expect(UnauthorizedException.class); | |||
newRequest().execute(); | |||
} | |||
private void initI18nMessages() { | |||
i18n.put("global_permissions.admin", "Administer System"); | |||
i18n.put("global_permissions.admin.desc", "Ability to perform all administration functions for the instance: " + | |||
"global configuration and personalization of default dashboards."); | |||
i18n.put("global_permissions.profileadmin", "Administer Quality Profiles"); | |||
i18n.put("global_permissions.profileadmin.desc", "Ability to perform any action on the quality profiles."); | |||
i18n.put("global_permissions.gateadmin", "Administer Quality Gates"); | |||
i18n.put("global_permissions.gateadmin.desc", "Ability to perform any action on the quality gates."); | |||
i18n.put("global_permissions.scan", "Execute Analysis"); | |||
i18n.put("global_permissions.scan.desc", "Ability to execute analyses, and to get all settings required to perform the analysis, " + | |||
"even the secured ones like the scm account password, the jira account password, and so on."); | |||
i18n.put("global_permissions.provisioning", "Create Projects"); | |||
i18n.put("global_permissions.provisioning.desc", "Ability to initialize project structure before first analysis."); | |||
} | |||
} |
@@ -1,61 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.permission.ws; | |||
import com.google.common.collect.HashBasedTable; | |||
import java.util.Collections; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
public class SearchProjectPermissionsDataTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Test | |||
public void fail_if_no_projects() { | |||
expectedException.expect(IllegalStateException.class); | |||
SearchProjectPermissionsData.newBuilder() | |||
.groupCountByProjectIdAndPermission(HashBasedTable.create()) | |||
.userCountByProjectIdAndPermission(HashBasedTable.create()) | |||
.build(); | |||
} | |||
@Test | |||
public void fail_if_no_group_count() { | |||
expectedException.expect(IllegalStateException.class); | |||
SearchProjectPermissionsData.newBuilder() | |||
.rootComponents(Collections.emptyList()) | |||
.userCountByProjectIdAndPermission(HashBasedTable.create()) | |||
.build(); | |||
} | |||
@Test | |||
public void fail_if_no_user_count() { | |||
expectedException.expect(IllegalStateException.class); | |||
SearchProjectPermissionsData.newBuilder() | |||
.rootComponents(Collections.emptyList()) | |||
.groupCountByProjectIdAndPermission(HashBasedTable.create()) | |||
.build(); | |||
} | |||
} |
@@ -1,294 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.project.ws; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.server.component.ComponentFinder; | |||
import org.sonar.server.component.ComponentService; | |||
import org.sonar.server.component.TestComponentFinder; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.TestRequest; | |||
import org.sonar.server.ws.WsActionTester; | |||
import org.sonarqube.ws.Projects.BulkUpdateKeyWsResponse; | |||
import org.sonarqube.ws.Projects.BulkUpdateKeyWsResponse.Key; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_DRY_RUN; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_FROM; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT; | |||
import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_TO; | |||
public class BulkUpdateKeyActionTest { | |||
private static final String MY_PROJECT_KEY = "my_project"; | |||
private static final String FROM = "my_"; | |||
private static final String TO = "your_"; | |||
private System2 system2 = System2.INSTANCE; | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone().logIn().setRoot(); | |||
@Rule | |||
public EsTester es = EsTester.create(); | |||
@Rule | |||
public DbTester db = DbTester.create(system2); | |||
private ComponentDbTester componentDb = new ComponentDbTester(db); | |||
private DbClient dbClient = db.getDbClient(); | |||
private ComponentFinder componentFinder = TestComponentFinder.from(db); | |||
private ComponentService componentService = mock(ComponentService.class); | |||
private WsActionTester ws = new WsActionTester( | |||
new BulkUpdateKeyAction(dbClient, componentFinder, componentService, userSession)); | |||
@Test | |||
public void json_example() { | |||
ComponentDto project = componentDb.insertPrivateProject(c -> c.setDbKey("my_project")); | |||
componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:module_1")); | |||
ComponentDto anotherProject = componentDb.insertPrivateProject(c -> c.setDbKey("another_project")); | |||
componentDb.insertComponent(newModuleDto(anotherProject).setDbKey("my_new_project:module_1")); | |||
ComponentDto module2 = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:module_2")); | |||
componentDb.insertComponent(newFileDto(module2, null)); | |||
String result = ws.newRequest() | |||
.setParam(PARAM_PROJECT, "my_project") | |||
.setParam(PARAM_FROM, "my_") | |||
.setParam(PARAM_TO, "my_new_") | |||
.setParam(PARAM_DRY_RUN, String.valueOf(true)) | |||
.execute().getInput(); | |||
assertJson(result).withStrictArrayOrder().isSimilarTo(getClass().getResource("bulk_update_key-example.json")); | |||
} | |||
@Test | |||
public void dry_run_by_key() { | |||
insertMyProject(); | |||
BulkUpdateKeyWsResponse result = callDryRunByKey(MY_PROJECT_KEY, FROM, TO); | |||
assertThat(result.getKeysCount()).isEqualTo(1); | |||
assertThat(result.getKeys(0).getNewKey()).isEqualTo("your_project"); | |||
} | |||
@Test | |||
public void bulk_update_project_key() { | |||
ComponentDto project = insertMyProject(); | |||
ComponentDto module = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:module")); | |||
ComponentDto inactiveModule = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:inactive_module").setEnabled(false)); | |||
ComponentDto file = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/File.xoo")); | |||
ComponentDto inactiveFile = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/InactiveFile.xoo").setEnabled(false)); | |||
BulkUpdateKeyWsResponse result = callByKey(project.getDbKey(), FROM, TO); | |||
assertThat(result.getKeysCount()).isEqualTo(2); | |||
assertThat(result.getKeysList()).extracting(Key::getKey, Key::getNewKey, Key::getDuplicate) | |||
.containsExactly( | |||
tuple(project.getDbKey(), "your_project", false), | |||
tuple(module.getDbKey(), "your_project:root:module", false)); | |||
verify(componentService).bulkUpdateKey(any(DbSession.class), eq(componentDb.getProjectDto(project)), eq(FROM), eq(TO)); | |||
} | |||
@Test | |||
public void bulk_update_provisioned_project_key() { | |||
String newKey = "provisionedProject2"; | |||
ComponentDto provisionedProject = componentDb.insertPrivateProject(); | |||
callByKey(provisionedProject.getDbKey(), provisionedProject.getDbKey(), newKey); | |||
verify(componentService).bulkUpdateKey(any(DbSession.class), eq(componentDb.getProjectDto(provisionedProject)), eq(provisionedProject.getDbKey()), eq(newKey)); | |||
} | |||
@Test | |||
public void fail_to_bulk_update_key_using_branch_db_key() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage(String.format("Project '%s' not found", branch.getDbKey())); | |||
callByKey(branch.getDbKey(), FROM, TO); | |||
} | |||
@Test | |||
public void fail_to_bulk_if_a_component_already_exists_with_the_same_key() { | |||
componentDb.insertPrivateProject(c -> c.setDbKey("my_project")); | |||
componentDb.insertPrivateProject(c -> c.setDbKey("your_project")); | |||
expectedException.expect(BadRequestException.class); | |||
expectedException.expectMessage("Impossible to update key: a component with key \"your_project\" already exists."); | |||
callByKey("my_project", "my_", "your_"); | |||
} | |||
@Test | |||
public void fail_to_bulk_update_with_invalid_new_key() { | |||
insertMyProject(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Malformed key for 'my?project'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); | |||
callByKey(MY_PROJECT_KEY, FROM, "my?"); | |||
} | |||
@Test | |||
public void fail_to_dry_bulk_update_with_invalid_new_key() { | |||
insertMyProject(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Malformed key for 'my?project'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit."); | |||
callDryRunByKey(MY_PROJECT_KEY, FROM, "my?"); | |||
} | |||
@Test | |||
public void fail_to_bulk_update_if_not_project_or_module() { | |||
ComponentDto project = insertMyProject(); | |||
ComponentDto file = componentDb.insertComponent(newFileDto(project, null)); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage(String.format("Project '%s' not found", file.getDbKey())); | |||
callByKey(file.getDbKey(), FROM, TO); | |||
} | |||
@Test | |||
public void fail_if_from_string_is_not_provided() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
ComponentDto project = insertMyProject(); | |||
callDryRunByKey(project.getDbKey(), null, TO); | |||
} | |||
@Test | |||
public void fail_if_to_string_is_not_provided() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
ComponentDto project = insertMyProject(); | |||
callDryRunByKey(project.getDbKey(), FROM, null); | |||
} | |||
@Test | |||
public void fail_if_key_not_provided() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
call(null, FROM, TO, false); | |||
} | |||
@Test | |||
public void fail_if_project_does_not_exist() { | |||
expectedException.expect(NotFoundException.class); | |||
callDryRunByKey("UNKNOWN_KEY", FROM, TO); | |||
} | |||
@Test | |||
public void throw_ForbiddenException_if_not_project_administrator() { | |||
userSession.logIn(); | |||
ComponentDto project = insertMyProject(); | |||
expectedException.expect(ForbiddenException.class); | |||
callDryRunByKey(project.getDbKey(), FROM, TO); | |||
} | |||
@Test | |||
public void fail_when_using_branch_db_key() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
userSession.logIn().addProjectPermission(UserRole.USER, project); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage(String.format("Project '%s' not found", branch.getDbKey())); | |||
callByKey(branch.getDbKey(), FROM, TO); | |||
} | |||
@Test | |||
public void api_definition() { | |||
WebService.Action definition = ws.getDef(); | |||
assertThat(definition.isPost()).isTrue(); | |||
assertThat(definition.since()).isEqualTo("6.1"); | |||
assertThat(definition.key()).isEqualTo("bulk_update_key"); | |||
assertThat(definition.params()) | |||
.hasSize(4) | |||
.extracting(WebService.Param::key) | |||
.containsOnlyOnce("project", "from", "to", "dryRun"); | |||
} | |||
private ComponentDto insertMyProject() { | |||
return componentDb.insertPublicProject(c -> c.setDbKey(MY_PROJECT_KEY)); | |||
} | |||
private BulkUpdateKeyWsResponse callDryRunByKey(@Nullable String key, @Nullable String from, @Nullable String to) { | |||
return call(key, from, to, true); | |||
} | |||
private BulkUpdateKeyWsResponse callByKey(@Nullable String key, @Nullable String from, @Nullable String to) { | |||
return call(key, from, to, false); | |||
} | |||
private BulkUpdateKeyWsResponse call(@Nullable String key, @Nullable String from, @Nullable String to, @Nullable Boolean dryRun) { | |||
TestRequest request = ws.newRequest(); | |||
if (key != null) { | |||
request.setParam(PARAM_PROJECT, key); | |||
} | |||
if (from != null) { | |||
request.setParam(PARAM_FROM, from); | |||
} | |||
if (to != null) { | |||
request.setParam(PARAM_TO, to); | |||
} | |||
if (dryRun != null) { | |||
request.setParam(PARAM_DRY_RUN, String.valueOf(dryRun)); | |||
} | |||
return request.executeProtobuf(BulkUpdateKeyWsResponse.class); | |||
} | |||
} |
@@ -31,7 +31,7 @@ public class ProjectsWsModuleTest { | |||
public void verify_count_of_added_components_on_SonarQube() { | |||
ComponentContainer container = new ComponentContainer(); | |||
new ProjectsWsModule().configure(container); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 12); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 11); | |||
} | |||
} |
@@ -1,110 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.source.ws; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.source.FileSourceDto; | |||
import org.sonar.server.component.TestComponentFinder; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.TestRequest; | |||
import org.sonar.server.ws.WsActionTester; | |||
import static java.lang.String.format; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.api.web.UserRole.USER; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
public class HashActionTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
@Rule | |||
public UserSessionRule userSessionRule = UserSessionRule.standalone(); | |||
private final WsActionTester tester = new WsActionTester(new HashAction(db.getDbClient(), userSessionRule, TestComponentFinder.from(db))); | |||
@Test | |||
public void show_hashes() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
FileSourceDto fileSource = db.fileSources().insertFileSource(file, f -> f.setLineHashes(singletonList("ABC"))); | |||
loginAsProjectViewer(project); | |||
TestRequest request = tester.newRequest().setParam("key", file.getDbKey()); | |||
assertThat(request.execute().getInput()).isEqualTo("ABC"); | |||
} | |||
@Test | |||
public void hashes_empty_if_no_source() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
loginAsProjectViewer(project); | |||
TestRequest request = tester.newRequest().setParam("key", file.getKey()); | |||
assertThat(request.execute().getStatus()).isEqualTo(204); | |||
} | |||
@Test | |||
public void fail_to_show_hashes_if_file_does_not_exist() { | |||
expectedException.expect(NotFoundException.class); | |||
tester.newRequest().setParam("key", "unknown").execute(); | |||
} | |||
@Test | |||
public void fail_when_using_branch_db_key() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
loginAsProjectViewer(project); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey())); | |||
tester.newRequest().setParam("key", branch.getDbKey()).execute(); | |||
} | |||
@Test | |||
public void fail_on_missing_permission() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
FileSourceDto fileSource = db.fileSources().insertFileSource(file); | |||
userSessionRule.logIn(db.users().insertUser()); | |||
expectedException.expect(ForbiddenException.class); | |||
tester.newRequest().setParam("key", file.getKey()).execute(); | |||
} | |||
private void loginAsProjectViewer(ComponentDto project) { | |||
userSessionRule.logIn(db.users().insertUser()).addProjectPermission(USER, project); | |||
} | |||
} |
@@ -32,7 +32,7 @@ public class SourceWsModuleTest { | |||
public void verify_count_of_actions() { | |||
ComponentContainer container = new ComponentContainer(); | |||
underTest.configure(container); | |||
assertThat(container.getPicoContainer().getComponentAdapters(WsAction.class)).hasSize(7); | |||
assertThat(container.getPicoContainer().getComponentAdapters(WsAction.class)).hasSize(6); | |||
} | |||
} |
@@ -72,16 +72,6 @@ public class WebServiceReroutingFilterTest { | |||
assertRedirection("/api/projects/update_key", "POST"); | |||
} | |||
@Test | |||
public void redirect_components_bulk_update_key() { | |||
when(request.getServletPath()).thenReturn("/api/components/bulk_update_key"); | |||
when(request.getMethod()).thenReturn("POST"); | |||
underTest.doFilter(request, response, chain); | |||
assertRedirection("/api/projects/bulk_update_key", "POST"); | |||
} | |||
private void assertRedirection(String path, String method) { | |||
verify(webServiceEngine).execute(servletRequestCaptor.capture(), any(ServletResponse.class)); | |||
assertThat(servletRequestCaptor.getValue().getPath()).isEqualTo(path); |
@@ -3940,89 +3940,6 @@ | |||
} | |||
] | |||
}, | |||
{ | |||
"key": "search_global_permissions", | |||
"description": "List global permissions. <br />Requires the following permission: 'Administer System'", | |||
"since": "5.2", | |||
"deprecatedSince": "6.5", | |||
"internal": false, | |||
"post": false, | |||
"hasResponseExample": true, | |||
"changelog": [], | |||
"params": [ | |||
{ | |||
"key": "organization", | |||
"description": "Key of organization, used when group name is set", | |||
"since": "6.2", | |||
"required": false, | |||
"internal": true, | |||
"exampleValue": "my-org" | |||
} | |||
] | |||
}, | |||
{ | |||
"key": "search_project_permissions", | |||
"description": "List project permissions. A project can be a technical project, a view or a developer.<br />Requires one of the following permissions:<ul><li>'Administer System'</li><li>'Administer' rights on the specified project</li></ul>", | |||
"since": "5.2", | |||
"deprecatedSince": "6.5", | |||
"internal": false, | |||
"post": false, | |||
"hasResponseExample": true, | |||
"changelog": [], | |||
"params": [ | |||
{ | |||
"key": "p", | |||
"description": "1-based page number", | |||
"required": false, | |||
"internal": false, | |||
"defaultValue": "1", | |||
"exampleValue": "42", | |||
"deprecatedKey": "pageIndex", | |||
"deprecatedKeySince": "5.2" | |||
}, | |||
{ | |||
"key": "projectId", | |||
"description": "Project id", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "ce4c03d6-430f-40a9-b777-ad877c00aa4d" | |||
}, | |||
{ | |||
"key": "projectKey", | |||
"description": "Project key", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "my_project" | |||
}, | |||
{ | |||
"key": "ps", | |||
"description": "Page size. Must be greater than 0.", | |||
"required": false, | |||
"internal": false, | |||
"defaultValue": "25", | |||
"exampleValue": "20", | |||
"deprecatedKey": "pageSize", | |||
"deprecatedKeySince": "5.2" | |||
}, | |||
{ | |||
"key": "q", | |||
"description": "Limit search to: <ul><li>project names that contain the supplied string</li><li>project keys that are exactly the same as the supplied string</li></ul>", | |||
"required": false, | |||
"internal": false, | |||
"exampleValue": "apac" | |||
}, | |||
{ | |||
"key": "qualifier", | |||
"description": "Project qualifier. Filter the results with the specified qualifier. Possible values are:<ul><li>TRK - Projects</li></ul>", | |||
"since": "5.3", | |||
"required": false, | |||
"internal": false, | |||
"possibleValues": [ | |||
"TRK" | |||
] | |||
} | |||
] | |||
}, | |||
{ | |||
"key": "search_templates", | |||
"description": "List permission templates.<br />Requires the following permission: 'Administer System'.", | |||
@@ -6068,24 +5985,6 @@ | |||
} | |||
] | |||
}, | |||
{ | |||
"key": "unset_default", | |||
"description": "Unset a quality gate as the default quality gate.<br>Requires the 'Administer Quality Gates' permission.", | |||
"since": "4.3", | |||
"internal": false, | |||
"post": true, | |||
"hasResponseExample": false, | |||
"changelog": [], | |||
"params": [ | |||
{ | |||
"key": "id", | |||
"description": "ID of the quality gate to unset as default", | |||
"required": true, | |||
"internal": false, | |||
"exampleValue": "1" | |||
} | |||
] | |||
}, | |||
{ | |||
"key": "update_condition", | |||
"description": "Update a condition attached to a quality gate.<br>Requires the 'Administer Quality Gates' permission.", |
@@ -55,7 +55,6 @@ public class IssuesWsParameters { | |||
public static final String PARAM_RESOLVED = "resolved"; | |||
public static final String PARAM_COMPONENT_KEYS = "componentKeys"; | |||
public static final String PARAM_COMPONENT_UUIDS = "componentUuids"; | |||
public static final String PARAM_MODULE_UUIDS = "moduleUuids"; | |||
public static final String PARAM_PROJECTS = "projects"; | |||
public static final String PARAM_DIRECTORIES = "directories"; | |||
public static final String PARAM_FILES = "files"; | |||
@@ -72,11 +71,6 @@ public class IssuesWsParameters { | |||
public static final String PARAM_SEND_NOTIFICATIONS = "sendNotifications"; | |||
public static final String PARAM_ASSIGNEES = "assignees"; | |||
/** | |||
* @deprecated since 7.7, please use 'author' instead | |||
*/ | |||
@Deprecated | |||
public static final String DEPRECATED_PARAM_AUTHORS = "authors"; | |||
public static final String PARAM_AUTHOR = "author"; | |||
public static final String PARAM_SCOPES = "scopes"; | |||
@@ -96,18 +90,10 @@ public class IssuesWsParameters { | |||
public static final String PARAM_CREATED_BEFORE = "createdBefore"; | |||
public static final String PARAM_CREATED_IN_LAST = "createdInLast"; | |||
public static final String PARAM_SINCE_LEAK_PERIOD = "sinceLeakPeriod"; | |||
public static final String PARAM_PAGE_SIZE = "pageSize"; | |||
public static final String PARAM_PAGE_INDEX = "pageIndex"; | |||
public static final String PARAM_ASC = "asc"; | |||
public static final String PARAM_ADDITIONAL_FIELDS = "additionalFields"; | |||
public static final String PARAM_TIMEZONE = "timeZone"; | |||
/** | |||
* @deprecated since 7.9 | |||
*/ | |||
@Deprecated | |||
public static final String FACET_MODE = "facetMode"; | |||
public static final String FACET_MODE_COUNT = "count"; | |||
public static final String FACET_MODE_EFFORT = "effort"; | |||
private IssuesWsParameters() { |
@@ -206,7 +206,6 @@ public class IssuesService extends BaseService { | |||
.setParam("assigned", request.getAssigned()) | |||
.setParam("assignees", request.getAssignees() == null ? null : request.getAssignees().stream().collect(Collectors.joining(","))) | |||
.setParam("author", request.getAuthor()) | |||
.setParam("authors", request.getAuthors() == null ? null : request.getAuthors().stream().collect(Collectors.joining(","))) | |||
.setParam("branch", request.getBranch()) | |||
.setParam("componentKeys", request.getComponentKeys() == null ? null : request.getComponentKeys().stream().collect(Collectors.joining(","))) | |||
.setParam("componentUuids", request.getComponentUuids() == null ? null : request.getComponentUuids().stream().collect(Collectors.joining(","))) | |||
@@ -216,12 +215,10 @@ public class IssuesService extends BaseService { | |||
.setParam("createdInLast", request.getCreatedInLast()) | |||
.setParam("cwe", request.getCwe() == null ? null : request.getCwe().stream().collect(Collectors.joining(","))) | |||
.setParam("directories", request.getDirectories() == null ? null : request.getDirectories().stream().collect(Collectors.joining(","))) | |||
.setParam("facetMode", request.getFacetMode()) | |||
.setParam("facets", request.getFacets() == null ? null : request.getFacets().stream().collect(Collectors.joining(","))) | |||
.setParam("fileUuids", request.getFileUuids() == null ? null : request.getFileUuids().stream().collect(Collectors.joining(","))) | |||
.setParam("issues", request.getIssues() == null ? null : request.getIssues().stream().collect(Collectors.joining(","))) | |||
.setParam("languages", request.getLanguages() == null ? null : request.getLanguages().stream().collect(Collectors.joining(","))) | |||
.setParam("moduleUuids", request.getModuleUuids() == null ? null : request.getModuleUuids().stream().collect(Collectors.joining(","))) | |||
.setParam("onComponentOnly", request.getOnComponentOnly()) | |||
.setParam("owaspTop10", request.getOwaspTop10() == null ? null : request.getOwaspTop10().stream().collect(Collectors.joining(","))) | |||
.setParam("p", request.getP()) |
@@ -36,7 +36,6 @@ public class SearchRequest { | |||
private String assigned; | |||
private List<String> assignees; | |||
private List<String> author; | |||
private List<String> authors; | |||
private String branch; | |||
private List<String> componentKeys; | |||
private List<String> componentUuids; | |||
@@ -51,7 +50,6 @@ public class SearchRequest { | |||
private List<String> fileUuids; | |||
private List<String> issues; | |||
private List<String> languages; | |||
private List<String> moduleUuids; | |||
private String onComponentOnly; | |||
private List<String> owaspTop10; | |||
private String p; | |||
@@ -152,20 +150,6 @@ public class SearchRequest { | |||
return author; | |||
} | |||
/** | |||
* Example value: "torvalds@linux-foundation.org" | |||
* @deprecated since 7.7 | |||
*/ | |||
@Deprecated | |||
public SearchRequest setAuthors(List<String> authors) { | |||
this.authors = authors; | |||
return this; | |||
} | |||
public List<String> getAuthors() { | |||
return authors; | |||
} | |||
/** | |||
* This is part of the internal API. | |||
* Example value: "feature/my_branch" | |||
@@ -278,22 +262,6 @@ public class SearchRequest { | |||
return directories; | |||
} | |||
/** | |||
* Possible values: | |||
* <ul> | |||
* <li>"count"</li> | |||
* <li>"effort"</li> | |||
* </ul> | |||
*/ | |||
public SearchRequest setFacetMode(String facetMode) { | |||
this.facetMode = facetMode; | |||
return this; | |||
} | |||
public String getFacetMode() { | |||
return facetMode; | |||
} | |||
/** | |||
* Possible values: | |||
* <ul> | |||
@@ -367,21 +335,6 @@ public class SearchRequest { | |||
return languages; | |||
} | |||
/** | |||
* This is part of the internal API. | |||
* Example value: "7d8749e8-3070-4903-9188-bdd82933bb92" | |||
* @deprecated since 7.6 | |||
*/ | |||
@Deprecated | |||
public SearchRequest setModuleUuids(List<String> moduleUuids) { | |||
this.moduleUuids = moduleUuids; | |||
return this; | |||
} | |||
public List<String> getModuleUuids() { | |||
return moduleUuids; | |||
} | |||
/** | |||
* Possible values: | |||
* <ul> |
@@ -22,18 +22,16 @@ package org.sonarqube.ws.client.permissions; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.Generated; | |||
import org.sonarqube.ws.MediaTypes; | |||
import org.sonarqube.ws.client.BaseService; | |||
import org.sonarqube.ws.client.GetRequest; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.WsConnector; | |||
import org.sonarqube.ws.Permissions.CreateTemplateWsResponse; | |||
import org.sonarqube.ws.Permissions.WsGroupsResponse; | |||
import org.sonarqube.ws.Permissions.WsSearchGlobalPermissionsResponse; | |||
import org.sonarqube.ws.Permissions.SearchProjectPermissionsWsResponse; | |||
import org.sonarqube.ws.Permissions.SearchTemplatesWsResponse; | |||
import org.sonarqube.ws.Permissions.WsTemplateGroupsResponse; | |||
import org.sonarqube.ws.Permissions.UpdateTemplateWsResponse; | |||
import org.sonarqube.ws.Permissions.UsersWsResponse; | |||
import org.sonarqube.ws.Permissions.WsGroupsResponse; | |||
import org.sonarqube.ws.Permissions.WsTemplateGroupsResponse; | |||
import org.sonarqube.ws.client.BaseService; | |||
import org.sonarqube.ws.client.GetRequest; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.WsConnector; | |||
/** | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/permissions">Further information about this web service online</a> | |||
@@ -318,42 +316,6 @@ public class PermissionsService extends BaseService { | |||
).content(); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. | |||
* This is a GET request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/permissions/search_global_permissions">Further information about this action online (including a response example)</a> | |||
* @since 5.2 | |||
* @deprecated since 6.5 | |||
*/ | |||
@Deprecated | |||
public WsSearchGlobalPermissionsResponse searchGlobalPermissions(SearchGlobalPermissionsRequest request) { | |||
return call( | |||
new GetRequest(path("search_global_permissions")), | |||
WsSearchGlobalPermissionsResponse.parser()); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. | |||
* This is a GET request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/permissions/search_project_permissions">Further information about this action online (including a response example)</a> | |||
* @since 5.2 | |||
* @deprecated since 6.5 | |||
*/ | |||
@Deprecated | |||
public SearchProjectPermissionsWsResponse searchProjectPermissions(SearchProjectPermissionsRequest request) { | |||
return call( | |||
new GetRequest(path("search_project_permissions")) | |||
.setParam("p", request.getP()) | |||
.setParam("projectId", request.getProjectId()) | |||
.setParam("projectKey", request.getProjectKey()) | |||
.setParam("ps", request.getPs()) | |||
.setParam("q", request.getQ()) | |||
.setParam("qualifier", request.getQualifier()), | |||
SearchProjectPermissionsWsResponse.parser()); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. |
@@ -1,33 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.client.permissions; | |||
import javax.annotation.Generated; | |||
/** | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/permissions/search_global_permissions">Further information about this action online (including a response example)</a> | |||
* @since 5.2 | |||
*/ | |||
@Generated("sonar-ws-generator") | |||
public class SearchGlobalPermissionsRequest { | |||
} |
@@ -26,10 +26,8 @@ public class ProjectsWsParameters { | |||
public static final String CONTROLLER = "api/projects"; | |||
public static final String ACTION_CREATE = "create"; | |||
public static final String ACTION_INDEX = "index"; | |||
public static final String ACTION_SEARCH = "search"; | |||
public static final String ACTION_UPDATE_KEY = "update_key"; | |||
public static final String ACTION_BULK_UPDATE_KEY = "bulk_update_key"; | |||
public static final String ACTION_UPDATE_VISIBILITY = "update_visibility"; | |||
public static final String PARAM_PROJECT = "project"; |
@@ -1,94 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.client.projects; | |||
import javax.annotation.Generated; | |||
/** | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/projects/bulk_update_key">Further information about this action online (including a response example)</a> | |||
* @since 6.1 | |||
*/ | |||
@Generated("sonar-ws-generator") | |||
public class BulkUpdateKeyRequest { | |||
private String dryRun; | |||
private String from; | |||
private String project; | |||
private String to; | |||
/** | |||
* Possible values: | |||
* <ul> | |||
* <li>"true"</li> | |||
* <li>"false"</li> | |||
* <li>"yes"</li> | |||
* <li>"no"</li> | |||
* </ul> | |||
*/ | |||
public BulkUpdateKeyRequest setDryRun(String dryRun) { | |||
this.dryRun = dryRun; | |||
return this; | |||
} | |||
public String getDryRun() { | |||
return dryRun; | |||
} | |||
/** | |||
* This is a mandatory parameter. | |||
* Example value: "_old" | |||
*/ | |||
public BulkUpdateKeyRequest setFrom(String from) { | |||
this.from = from; | |||
return this; | |||
} | |||
public String getFrom() { | |||
return from; | |||
} | |||
/** | |||
* This is a mandatory parameter. | |||
* Example value: "my_old_project" | |||
*/ | |||
public BulkUpdateKeyRequest setProject(String project) { | |||
this.project = project; | |||
return this; | |||
} | |||
public String getProject() { | |||
return project; | |||
} | |||
/** | |||
* This is a mandatory parameter. | |||
* Example value: "_new" | |||
*/ | |||
public BulkUpdateKeyRequest setTo(String to) { | |||
this.to = to; | |||
return this; | |||
} | |||
public String getTo() { | |||
return to; | |||
} | |||
} |
@@ -22,7 +22,6 @@ package org.sonarqube.ws.client.projects; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.Generated; | |||
import org.sonarqube.ws.MediaTypes; | |||
import org.sonarqube.ws.Projects.BulkUpdateKeyWsResponse; | |||
import org.sonarqube.ws.Projects.CreateWsResponse; | |||
import org.sonarqube.ws.Projects.SearchMyProjectsWsResponse; | |||
import org.sonarqube.ws.Projects.SearchWsResponse; | |||
@@ -61,23 +60,6 @@ public class ProjectsService extends BaseService { | |||
).content(); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/projects/bulk_update_key">Further information about this action online (including a response example)</a> | |||
* @since 6.1 | |||
*/ | |||
public BulkUpdateKeyWsResponse bulkUpdateKey(BulkUpdateKeyRequest request) { | |||
return call( | |||
new PostRequest(path("bulk_update_key")) | |||
.setParam("dryRun", request.getDryRun()) | |||
.setParam("from", request.getFrom()) | |||
.setParam("project", request.getProject()) | |||
.setParam("to", request.getTo()), | |||
BulkUpdateKeyWsResponse.parser()); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. |
@@ -266,21 +266,6 @@ public class QualitygatesService extends BaseService { | |||
ShowWsResponse.parser()); | |||
} | |||
/** | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/qualitygates/unset_default">Further information about this action online (including a response example)</a> | |||
* @since 4.3 | |||
* @deprecated since 7.0 | |||
*/ | |||
@Deprecated | |||
public String unsetDefault() { | |||
return call( | |||
new PostRequest(path("unset_default")) | |||
.setMediaType(MediaTypes.JSON)).content(); | |||
} | |||
/** | |||
* This is part of the internal API. | |||
* This is a POST request. |
@@ -1,47 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.client.qualitygates; | |||
import javax.annotation.Generated; | |||
/** | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/qualitygates/unset_default">Further information about this action online (including a response example)</a> | |||
* @since 4.3 | |||
*/ | |||
@Generated("sonar-ws-generator") | |||
public class UnsetDefaultRequest { | |||
private String id; | |||
/** | |||
* This is a mandatory parameter. | |||
* Example value: "1" | |||
*/ | |||
public UnsetDefaultRequest setId(String id) { | |||
this.id = id; | |||
return this; | |||
} | |||
public String getId() { | |||
return id; | |||
} | |||
} |
@@ -35,21 +35,6 @@ public class SourcesService extends BaseService { | |||
super(wsConnector, "api/sources"); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. | |||
* This is a GET request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/sources/hash">Further information about this action online (including a response example)</a> | |||
* @since 5.0 | |||
*/ | |||
public String hash(HashRequest request) { | |||
return call( | |||
new GetRequest(path("hash")) | |||
.setParam("key", request.getKey()) | |||
.setMediaType(MediaTypes.JSON) | |||
).content(); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. |
@@ -33,7 +33,6 @@ public class CreateRequest { | |||
private String description; | |||
private String key; | |||
private String name; | |||
private String qualifier; | |||
private String visibility; | |||
/** | |||
@@ -70,24 +69,6 @@ public class CreateRequest { | |||
return name; | |||
} | |||
/** | |||
* Possible values: | |||
* <ul> | |||
* <li>"VW"</li> | |||
* <li>"APP"</li> | |||
* </ul> | |||
* @deprecated since 7.3 | |||
*/ | |||
@Deprecated | |||
public CreateRequest setQualifier(String qualifier) { | |||
this.qualifier = qualifier; | |||
return this; | |||
} | |||
public String getQualifier() { | |||
return qualifier; | |||
} | |||
/** | |||
* Possible values: | |||
* <ul> |
@@ -1,102 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.client.views; | |||
import javax.annotation.Generated; | |||
/** | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/views/mode">Further information about this action online (including a response example)</a> | |||
* @since 2.6 | |||
*/ | |||
@Generated("sonar-ws-generator") | |||
public class ModeRequest { | |||
private String key; | |||
private String measure; | |||
private String regexp; | |||
private String selectionMode; | |||
private String value; | |||
/** | |||
* This is a mandatory parameter. | |||
*/ | |||
public ModeRequest setKey(String key) { | |||
this.key = key; | |||
return this; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
/** | |||
*/ | |||
public ModeRequest setMeasure(String measure) { | |||
this.measure = measure; | |||
return this; | |||
} | |||
public String getMeasure() { | |||
return measure; | |||
} | |||
/** | |||
*/ | |||
public ModeRequest setRegexp(String regexp) { | |||
this.regexp = regexp; | |||
return this; | |||
} | |||
public String getRegexp() { | |||
return regexp; | |||
} | |||
/** | |||
* This is a mandatory parameter. | |||
* Possible values: | |||
* <ul> | |||
* <li>"MANUAL"</li> | |||
* <li>"REGEXP"</li> | |||
* <li>"MANUAL_MEASURE"</li> | |||
* <li>"REST"</li> | |||
* </ul> | |||
*/ | |||
public ModeRequest setSelectionMode(String selectionMode) { | |||
this.selectionMode = selectionMode; | |||
return this; | |||
} | |||
public String getSelectionMode() { | |||
return selectionMode; | |||
} | |||
/** | |||
*/ | |||
public ModeRequest setValue(String value) { | |||
this.value = value; | |||
return this; | |||
} | |||
public String getValue() { | |||
return value; | |||
} | |||
} |
@@ -1,59 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.client.views; | |||
import javax.annotation.Generated; | |||
/** | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/views/regexp">Further information about this action online (including a response example)</a> | |||
* @since 1.0 | |||
*/ | |||
@Generated("sonar-ws-generator") | |||
public class RegexpRequest { | |||
private String key; | |||
private String regexp; | |||
/** | |||
* This is a mandatory parameter. | |||
*/ | |||
public RegexpRequest setKey(String key) { | |||
this.key = key; | |||
return this; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
/** | |||
* This is a mandatory parameter. | |||
*/ | |||
public RegexpRequest setRegexp(String regexp) { | |||
this.regexp = regexp; | |||
return this; | |||
} | |||
public String getRegexp() { | |||
return regexp; | |||
} | |||
} |
@@ -17,31 +17,31 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonarqube.ws.client.sources; | |||
package org.sonarqube.ws.client.views; | |||
import javax.annotation.Generated; | |||
/** | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/sources/hash">Further information about this action online (including a response example)</a> | |||
* @since 5.0 | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/views/set_none_mode">Further information about this action online (including a response example)</a> | |||
* @since 9.1 | |||
*/ | |||
@Generated("sonar-ws-generator") | |||
public class HashRequest { | |||
public class SetNoneModeRequest { | |||
private String key; | |||
private String portfolio; | |||
/** | |||
* This is a mandatory parameter. | |||
* Example value: "my_project:/src/foo/Bar.php" | |||
*/ | |||
public HashRequest setKey(String key) { | |||
this.key = key; | |||
public SetNoneModeRequest setPortfolio(String portfolio) { | |||
this.portfolio = portfolio; | |||
return this; | |||
} | |||
public String getKey() { | |||
return key; | |||
public String getPortfolio() { | |||
return portfolio; | |||
} | |||
} |
@@ -114,7 +114,6 @@ public class ViewsService extends BaseService { | |||
.setParam("description", request.getDescription()) | |||
.setParam("key", request.getKey()) | |||
.setParam("name", request.getName()) | |||
.setParam("qualifier", request.getQualifier()) | |||
.setParam("visibility", request.getVisibility()) | |||
.setMediaType(MediaTypes.JSON) | |||
).content(); | |||
@@ -193,26 +192,6 @@ public class ViewsService extends BaseService { | |||
).content(); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/views/mode">Further information about this action online (including a response example)</a> | |||
* @since 2.6 | |||
* @deprecated since 7.4 | |||
*/ | |||
public void mode(ModeRequest request) { | |||
call( | |||
new PostRequest(path("mode")) | |||
.setParam("key", request.getKey()) | |||
.setParam("measure", request.getMeasure()) | |||
.setParam("regexp", request.getRegexp()) | |||
.setParam("selectionMode", request.getSelectionMode()) | |||
.setParam("value", request.getValue()) | |||
.setMediaType(MediaTypes.JSON) | |||
).content(); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. | |||
@@ -278,23 +257,6 @@ public class ViewsService extends BaseService { | |||
).content(); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/views/regexp">Further information about this action online (including a response example)</a> | |||
* @since 1.0 | |||
* @deprecated since 7.4 | |||
*/ | |||
public void regexp(RegexpRequest request) { | |||
call( | |||
new PostRequest(path("regexp")) | |||
.setParam("key", request.getKey()) | |||
.setParam("regexp", request.getRegexp()) | |||
.setMediaType(MediaTypes.JSON) | |||
).content(); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. | |||
@@ -361,6 +323,21 @@ public class ViewsService extends BaseService { | |||
).content(); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/views/set_none_mode">Further information about this action online (including a response example)</a> | |||
* @since 9.1 | |||
*/ | |||
public void setNoneMode(SetNoneModeRequest request) { | |||
call( | |||
new PostRequest(path("set_none_mode")) | |||
.setParam("portfolio", request.getPortfolio()) | |||
.setMediaType(MediaTypes.JSON) | |||
).content(); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. |
@@ -73,14 +73,3 @@ message SearchWsResponse { | |||
optional string revision = 8; | |||
} | |||
} | |||
// WS api/projects/prepare_bulk_update_key | |||
message BulkUpdateKeyWsResponse { | |||
repeated Key keys = 1; | |||
message Key { | |||
optional string key = 1; | |||
optional string newKey = 2; | |||
optional bool duplicate = 3; | |||
} | |||
} |