Browse Source

SONAR-9551 WS api/issues/search search by application

tags/6.6-RC1
Teryk Bellahsene 6 years ago
parent
commit
580514b445

+ 52
- 32
server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryFactory.java View File

@@ -25,14 +25,13 @@ import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -59,11 +58,13 @@ import org.sonarqube.ws.client.issue.SearchWsRequest;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static org.sonar.api.utils.DateUtils.longToDate;
import static org.sonar.api.utils.DateUtils.parseDateOrDateTime;
import static org.sonar.api.utils.DateUtils.parseEndingDateOrDateTime;
import static org.sonar.api.utils.DateUtils.parseStartingDateOrDateTime;
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
import static org.sonar.server.ws.WsUtils.checkRequest;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENTS;
@@ -125,12 +126,7 @@ public class IssueQueryFactory {
addComponentParameters(builder, dbSession,
effectiveOnComponentOnly,
allComponentUuids,
request.getProjectUuids(),
request.getProjectKeys(),
request.getModuleUuids(),
request.getDirectories(),
request.getFileUuids(),
request.getAuthors());
request);

builder.createdAfter(buildCreatedAfterFromRequest(dbSession, request, allComponentUuids));

@@ -205,12 +201,12 @@ public class IssueQueryFactory {
}

private boolean mergeDeprecatedComponentParameters(DbSession session, @Nullable Boolean onComponentOnly,
@Nullable Collection<String> components,
@Nullable Collection<String> componentUuids,
@Nullable Collection<String> componentKeys,
@Nullable Collection<String> componentRootUuids,
@Nullable Collection<String> componentRoots,
Set<String> allComponentUuids) {
@Nullable Collection<String> components,
@Nullable Collection<String> componentUuids,
@Nullable Collection<String> componentKeys,
@Nullable Collection<String> componentRootUuids,
@Nullable Collection<String> componentRoots,
Set<String> allComponentUuids) {
boolean effectiveOnComponentOnly = false;

checkArgument(atMostOneNonNullElement(components, componentUuids, componentKeys, componentRootUuids, componentRoots),
@@ -243,13 +239,9 @@ public class IssueQueryFactory {
}

private void addComponentParameters(IssueQuery.Builder builder, DbSession session,
boolean onComponentOnly,
Collection<String> componentUuids,
@Nullable Collection<String> projectUuids, @Nullable Collection<String> projectKeys,
@Nullable Collection<String> moduleUuids,
@Nullable Collection<String> directories,
@Nullable Collection<String> fileUuids,
@Nullable Collection<String> authors) {
boolean onComponentOnly,
Collection<String> componentUuids,
SearchWsRequest request) {

builder.onComponentOnly(onComponentOnly);
if (onComponentOnly) {
@@ -257,46 +249,48 @@ public class IssueQueryFactory {
return;
}

builder.authors(authors);
builder.authors(request.getAuthors());
List<String> projectUuids = request.getProjectUuids();
List<String> projectKeys = request.getProjectKeys();
checkArgument(projectUuids == null || projectKeys == null, "Parameters projects and projectUuids cannot be set simultaneously");
if (projectUuids != null) {
builder.projectUuids(projectUuids);
} else if (projectKeys != null) {
builder.projectUuids(convertComponentKeysToUuids(session, projectKeys));
}
builder.moduleUuids(moduleUuids);
builder.directories(directories);
builder.fileUuids(fileUuids);
builder.moduleUuids(request.getModuleUuids());
builder.directories(request.getDirectories());
builder.fileUuids(request.getFileUuids());

if (!componentUuids.isEmpty()) {
addComponentsBasedOnQualifier(builder, session, componentUuids);
addComponentsBasedOnQualifier(builder, session, componentUuids, request);
}
}

private void addComponentsBasedOnQualifier(IssueQuery.Builder builder, DbSession session, Collection<String> componentUuids) {
private void addComponentsBasedOnQualifier(IssueQuery.Builder builder, DbSession dbSession, Collection<String> componentUuids, SearchWsRequest request) {
if (componentUuids.isEmpty()) {
builder.componentUuids(componentUuids);
return;
}

List<ComponentDto> components = dbClient.componentDao().selectByUuids(session, componentUuids);
List<ComponentDto> components = dbClient.componentDao().selectByUuids(dbSession, componentUuids);
if (components.isEmpty()) {
builder.componentUuids(componentUuids);
return;
}

Set<String> qualifiers = components.stream().map(ComponentDto::qualifier).collect(MoreCollectors.toHashSet());
if (qualifiers.size() > 1) {
throw new IllegalArgumentException("All components must have the same qualifier, found " + Joiner.on(',').join(qualifiers));
}
checkArgument(qualifiers.size() == 1, "All components must have the same qualifier, found %s", String.join(",", qualifiers));

String qualifier = qualifiers.iterator().next();
switch (qualifier) {
case Qualifiers.VIEW:
case Qualifiers.SUBVIEW:
case Qualifiers.APP:
addViewsOrSubViews(builder, componentUuids);
break;
case Qualifiers.APP:
addApplications(builder, dbSession, components, request);
break;
case Qualifiers.PROJECT:
builder.projectUuids(componentUuids);
break;
@@ -326,6 +320,32 @@ public class IssueQueryFactory {
builder.viewUuids(filteredViewUuids);
}

private void addApplications(IssueQuery.Builder builder, DbSession dbSession, List<ComponentDto> applications, SearchWsRequest request) {
Set<String> authorizedApplicationUuids = applications.stream()
.filter(app -> userSession.hasComponentPermission(UserRole.USER, app))
.map(ComponentDto::uuid)
.collect(MoreCollectors.toSet());

builder.viewUuids(authorizedApplicationUuids.isEmpty() ? singleton(UNKNOWN) : authorizedApplicationUuids);
addCreatedAfterByProjects(builder, dbSession, request, authorizedApplicationUuids);
}

private void addCreatedAfterByProjects(IssueQuery.Builder builder, DbSession dbSession, SearchWsRequest request, Set<String> applicationUuids) {
if (request.getSinceLeakPeriod() == null || !request.getSinceLeakPeriod()) {
return;
}

Set<String> projectUuids = applicationUuids.stream()
.flatMap(app -> dbClient.componentDao().selectProjectsFromView(dbSession, app, app).stream())
.collect(MoreCollectors.toSet());

Map<String, Date> leakByProjects = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, projectUuids)
.stream()
.filter(s -> s.getPeriodDate() != null)
.collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> longToDate(s.getPeriodDate())));
builder.createdAfterByProjectUuids(leakByProjects);
}

private static void addDirectories(IssueQuery.Builder builder, List<ComponentDto> directories) {
Collection<String> directoryModuleUuids = new HashSet<>();
Collection<String> directoryPaths = new HashSet<>();

+ 43
- 0
server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryFactoryTest.java View File

@@ -30,6 +30,7 @@ import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.tester.UserSessionRule;
@@ -37,10 +38,14 @@ import org.sonarqube.ws.client.issue.SearchWsRequest;

import static com.google.common.collect.Lists.newArrayList;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.guava.api.Assertions.entry;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.api.utils.DateUtils.addDays;
import static org.sonar.db.component.ComponentTesting.newProjectCopy;

public class IssueQueryFactoryTest {

@@ -199,6 +204,44 @@ public class IssueQueryFactoryTest {
assertThat(query.onComponentOnly()).isFalse();
}

@Test
public void application_search_project_issues() {
ComponentDto project1 = db.components().insertPublicProject();
ComponentDto project2 = db.components().insertPublicProject();
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization());
db.components().insertComponents(newProjectCopy("PC1", project1, application));
db.components().insertComponents(newProjectCopy("PC2", project2, application));
userSession.registerComponents(application, project1, project2);

IssueQuery result = underTest.create(new SearchWsRequest().setComponentUuids(singletonList(application.uuid())));

assertThat(result.viewUuids()).containsExactlyInAnyOrder(application.uuid());
}

@Test
public void application_search_project_issues_on_leak() {
Date now = new Date();
ComponentDto project1 = db.components().insertPublicProject();
SnapshotDto analysis1 = db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
ComponentDto project2 = db.components().insertPublicProject();
SnapshotDto analysis2 = db.components().insertSnapshot(project2, s -> s.setPeriodDate(null));
ComponentDto project3 = db.components().insertPublicProject();
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization());
db.components().insertComponents(newProjectCopy("PC1", project1, application));
db.components().insertComponents(newProjectCopy("PC2", project2, application));
db.components().insertComponents(newProjectCopy("PC3", project3, application));
userSession.registerComponents(application, project1, project2, project3);

IssueQuery result = underTest.create(new SearchWsRequest()
.setComponentUuids(singletonList(application.uuid()))
.setSinceLeakPeriod(true)
);

assertThat(result.createdAfterByProjectUuids()).containsOnly(
entry(project1.uuid(), new Date(analysis1.getPeriodDate())));
assertThat(result.viewUuids()).containsExactlyInAnyOrder(application.uuid());
}

@Test
public void return_empty_results_if_not_allowed_to_search_for_subview() {
ComponentDto view = db.components().insertView();

+ 4
- 0
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java View File

@@ -67,6 +67,10 @@ import static org.sonar.db.component.SnapshotTesting.newAnalysis;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_SEARCH;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.CONTROLLER_ISSUES;

/**
* @deprecated use {@link SearchActionComponentsTest} instead
*/
@Deprecated
public class SearchActionComponentsMediumTest {

@ClassRule

+ 260
- 0
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsTest.java View File

@@ -0,0 +1,260 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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.issue.ws;

import java.util.Date;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.resources.Languages;
import org.sonar.api.utils.Durations;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.issue.IssueDto;
import org.sonar.server.es.EsTester;
import org.sonar.server.issue.IssueQueryFactory;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.issue.index.IssueIndexDefinition;
import org.sonar.server.issue.index.IssueIndexer;
import org.sonar.server.issue.index.IssueIteratorFactory;
import org.sonar.server.permission.index.AuthorizationTypeSupport;
import org.sonar.server.permission.index.PermissionIndexerTester;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.view.index.ViewIndexDefinition;
import org.sonar.server.view.index.ViewIndexer;
import org.sonar.server.ws.WsActionTester;
import org.sonar.server.ws.WsResponseCommonFormat;
import org.sonarqube.ws.Issues.Issue;
import org.sonarqube.ws.Issues.SearchWsResponse;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.utils.DateUtils.addDays;
import static org.sonar.db.component.ComponentTesting.newProjectCopy;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_KEYS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD;

public class SearchActionComponentsTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public DbTester db = DbTester.create();
@Rule
public EsTester es = new EsTester(
new IssueIndexDefinition(new MapSettings().asConfig()),
new ViewIndexDefinition(new MapSettings().asConfig()));

private IssueIndex index = new IssueIndex(es.client(), System2.INSTANCE, userSession, new AuthorizationTypeSupport(userSession));
private IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient()));
private ViewIndexer viewIndexer = new ViewIndexer(db.getDbClient(), es.client());
private PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer);
private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(db.getDbClient(), System2.INSTANCE, userSession);
private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, db.getDbClient(), null, null);
private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), new WsResponseCommonFormat(new Languages()), new Languages(),
new AvatarResolverImpl());

private WsActionTester ws = new WsActionTester(new SearchAction(userSession, index, issueQueryFactory, searchResponseLoader, searchResponseFormat));

@Test
public void search_by_application_key() throws Exception {
ComponentDto project1 = db.components().insertPublicProject();
ComponentDto project2 = db.components().insertPublicProject();
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization());
db.components().insertComponents(newProjectCopy("PC1", project1, application));
db.components().insertComponents(newProjectCopy("PC2", project2, application));
IssueDto issue1 = db.issues().insertIssue(i -> i.setProject(project1));
IssueDto issue2 = db.issues().insertIssue(i -> i.setProject(project2));
userSession.registerComponents(application, project1, project2);
permissionIndexer.allowOnlyAnyone(project1);
permissionIndexer.allowOnlyAnyone(project2);
indexIssuesAndViews();

SearchWsResponse result = ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, application.getKey())
.executeProtobuf(SearchWsResponse.class);

assertThat(result.getIssuesList()).extracting(Issue::getKey)
.containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey());
}

@Test
public void ignore_application_without_browse_permission() {
ComponentDto project = db.components().insertPublicProject();
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization());
db.components().insertComponents(newProjectCopy("PC1", project, application));
db.issues().insertIssue(i -> i.setProject(project));
userSession.registerComponents(project);
permissionIndexer.allowOnlyAnyone(project);
indexIssuesAndViews();

SearchWsResponse result = ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, application.getKey())
.executeProtobuf(SearchWsResponse.class);

assertThat(result.getIssuesList()).isEmpty();
}

@Test
public void search_application_without_projects() {
ComponentDto project = db.components().insertPublicProject();
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization());
db.issues().insertIssue(i -> i.setProject(project));
userSession.registerComponents(application, project);
permissionIndexer.allowOnlyAnyone(project);
indexIssuesAndViews();

SearchWsResponse result = ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, application.getKey())
.executeProtobuf(SearchWsResponse.class);

assertThat(result.getIssuesList()).isEmpty();
}

@Test
public void search_by_application_and_by_leak() throws Exception {
Date now = new Date();
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization());
// Project 1
ComponentDto project1 = db.components().insertPublicProject();
db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
db.components().insertComponents(newProjectCopy("PC1", project1, application));
IssueDto project1Issue1 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -10)));
IssueDto project1Issue2 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -20)));
// Project 2
ComponentDto project2 = db.components().insertPublicProject();
db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime()));
db.components().insertComponents(newProjectCopy("PC2", project2, application));
IssueDto project2Issue1 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -15)));
IssueDto project2Issue2 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -30)));
// Permissions and index
userSession.registerComponents(application, project1, project2);
permissionIndexer.allowOnlyAnyone(project1);
permissionIndexer.allowOnlyAnyone(project2);
indexIssuesAndViews();

SearchWsResponse result = ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, application.getKey())
.setParam(PARAM_SINCE_LEAK_PERIOD, "true")
.executeProtobuf(SearchWsResponse.class);

assertThat(result.getIssuesList()).extracting(Issue::getKey)
.containsExactlyInAnyOrder(project1Issue1.getKey(), project2Issue1.getKey())
.doesNotContain(project1Issue2.getKey(), project2Issue2.getKey());
}

@Test
public void search_by_application_and_project() throws Exception {
ComponentDto project1 = db.components().insertPublicProject();
ComponentDto project2 = db.components().insertPublicProject();
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization());
db.components().insertComponents(newProjectCopy("PC1", project1, application));
db.components().insertComponents(newProjectCopy("PC2", project2, application));
IssueDto issue1 = db.issues().insertIssue(i -> i.setProject(project1));
IssueDto issue2 = db.issues().insertIssue(i -> i.setProject(project2));
userSession.registerComponents(application, project1, project2);
permissionIndexer.allowOnlyAnyone(project1);
permissionIndexer.allowOnlyAnyone(project2);
indexIssuesAndViews();

SearchWsResponse result = ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, application.getKey())
.setParam(PARAM_PROJECT_KEYS, project1.getKey())
.executeProtobuf(SearchWsResponse.class);

assertThat(result.getIssuesList()).extracting(Issue::getKey)
.containsExactlyInAnyOrder(issue1.getKey())
.doesNotContain(issue2.getKey());
}

@Test
public void search_by_application_and_project_and_leak() throws Exception {
Date now = new Date();
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization());
// Project 1
ComponentDto project1 = db.components().insertPublicProject();
db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
db.components().insertComponents(newProjectCopy("PC1", project1, application));
IssueDto project1Issue1 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -10)));
IssueDto project1Issue2 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -20)));
// Project 2
ComponentDto project2 = db.components().insertPublicProject();
db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime()));
db.components().insertComponents(newProjectCopy("PC2", project2, application));
IssueDto project2Issue1 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -15)));
IssueDto project2Issue2 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -30)));
// Permissions and index
userSession.registerComponents(application, project1, project2);
permissionIndexer.allowOnlyAnyone(project1);
permissionIndexer.allowOnlyAnyone(project2);
indexIssuesAndViews();

SearchWsResponse result = ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, application.getKey())
.setParam(PARAM_PROJECT_KEYS, project1.getKey())
.setParam(PARAM_SINCE_LEAK_PERIOD, "true")
.executeProtobuf(SearchWsResponse.class);

assertThat(result.getIssuesList()).extracting(Issue::getKey)
.containsExactlyInAnyOrder(project1Issue1.getKey())
.doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
}

@Test
public void search_by_application_and_by_leak_when_one_project_has_no_leak() throws Exception {
Date now = new Date();
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization());
// Project 1
ComponentDto project1 = db.components().insertPublicProject();
db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime()));
db.components().insertComponents(newProjectCopy("PC1", project1, application));
IssueDto project1Issue1 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -10)));
IssueDto project1Issue2 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -20)));
// Project 2, without leak => no issue form it should be returned
ComponentDto project2 = db.components().insertPublicProject();
db.components().insertSnapshot(project2, s -> s.setPeriodDate(null));
db.components().insertComponents(newProjectCopy("PC2", project2, application));
IssueDto project2Issue1 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -15)));
IssueDto project2Issue2 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -30)));
// Permissions and index
userSession.registerComponents(application, project1, project2);
permissionIndexer.allowOnlyAnyone(project1);
permissionIndexer.allowOnlyAnyone(project2);
indexIssuesAndViews();

SearchWsResponse result = ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, application.getKey())
.setParam(PARAM_SINCE_LEAK_PERIOD, "true")
.executeProtobuf(SearchWsResponse.class);

assertThat(result.getIssuesList()).extracting(Issue::getKey)
.containsExactlyInAnyOrder(project1Issue1.getKey())
.doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey());
}

private void indexIssuesAndViews() {
issueIndexer.indexOnStartup(null);
viewIndexer.indexOnStartup(null);
}
}

Loading…
Cancel
Save