You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ComponentTagsAction.java 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.server.issue.ws;
  21. import com.google.common.io.Resources;
  22. import java.util.Map;
  23. import java.util.Optional;
  24. import org.sonar.api.server.ws.Request;
  25. import org.sonar.api.server.ws.Response;
  26. import org.sonar.api.server.ws.WebService;
  27. import org.sonar.api.server.ws.WebService.NewAction;
  28. import org.sonar.api.utils.text.JsonWriter;
  29. import org.sonar.db.DbClient;
  30. import org.sonar.db.DbSession;
  31. import org.sonar.db.component.ComponentDto;
  32. import org.sonar.server.issue.SearchRequest;
  33. import org.sonar.server.issue.index.IssueIndex;
  34. import org.sonar.server.issue.index.IssueIndexSyncProgressChecker;
  35. import org.sonar.server.issue.index.IssueQuery;
  36. import org.sonar.server.issue.index.IssueQueryFactory;
  37. import static java.util.Collections.singletonList;
  38. import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
  39. import static org.sonar.server.issue.index.IssueQueryFactory.ISSUE_TYPE_NAMES;
  40. import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_COMPONENT_TAGS;
  41. import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_UUID;
  42. import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AFTER;
  43. /**
  44. * List issue tags matching a given query.
  45. */
  46. public class ComponentTagsAction implements IssuesWsAction {
  47. private final IssueIndex issueIndex;
  48. private final IssueIndexSyncProgressChecker issueIndexSyncProgressChecker;
  49. private final IssueQueryFactory queryService;
  50. private final DbClient dbClient;
  51. public ComponentTagsAction(IssueIndex issueIndex,
  52. IssueIndexSyncProgressChecker issueIndexSyncProgressChecker,
  53. IssueQueryFactory queryService, DbClient dbClient) {
  54. this.issueIndex = issueIndex;
  55. this.issueIndexSyncProgressChecker = issueIndexSyncProgressChecker;
  56. this.queryService = queryService;
  57. this.dbClient = dbClient;
  58. }
  59. @Override
  60. public void define(WebService.NewController controller) {
  61. NewAction action = controller.createAction(ACTION_COMPONENT_TAGS)
  62. .setHandler(this)
  63. .setSince("5.1")
  64. .setInternal(true)
  65. .setDescription("List tags for the issues under a given component (including issues on the descendants of the component)"
  66. + "<br/>When issue indexing is in progress returns 503 service unavailable HTTP code.")
  67. .setResponseExample(Resources.getResource(getClass(), "component-tags-example.json"));
  68. action.createParam(PARAM_COMPONENT_UUID)
  69. .setDescription("A component UUID")
  70. .setRequired(true)
  71. .setExampleValue("7d8749e8-3070-4903-9188-bdd82933bb92");
  72. action.createParam(PARAM_CREATED_AFTER)
  73. .setDescription("To retrieve tags on issues created after the given date (inclusive). <br>" +
  74. "Either a date (server timezone) or datetime can be provided.")
  75. .setExampleValue("2017-10-19 or 2017-10-19T13:00:00+0200");
  76. action.createParam(PAGE_SIZE)
  77. .setDescription("The maximum size of the list to return")
  78. .setExampleValue("25")
  79. .setDefaultValue("10");
  80. }
  81. @Override
  82. public void handle(Request request, Response response) throws Exception {
  83. String componentUuid = request.mandatoryParam(PARAM_COMPONENT_UUID);
  84. checkIfAnyComponentsNeedIssueSync(componentUuid);
  85. SearchRequest searchRequest = new SearchRequest()
  86. .setComponentUuids(singletonList(componentUuid))
  87. .setTypes(ISSUE_TYPE_NAMES)
  88. .setResolved(false)
  89. .setCreatedAfter(request.param(PARAM_CREATED_AFTER));
  90. IssueQuery query = queryService.create(searchRequest);
  91. int pageSize = request.mandatoryParamAsInt(PAGE_SIZE);
  92. try (JsonWriter json = response.newJsonWriter()) {
  93. json.beginObject().name("tags").beginArray();
  94. for (Map.Entry<String, Long> tag : issueIndex.countTags(query, pageSize).entrySet()) {
  95. json.beginObject()
  96. .prop("key", tag.getKey())
  97. .prop("value", tag.getValue())
  98. .endObject();
  99. }
  100. json.endArray().endObject();
  101. }
  102. }
  103. private void checkIfAnyComponentsNeedIssueSync(String componentUuid) {
  104. try (DbSession dbSession = dbClient.openSession(false)) {
  105. Optional<ComponentDto> componentDto = dbClient.componentDao().selectByUuid(dbSession, componentUuid);
  106. if (componentDto.isPresent()) {
  107. issueIndexSyncProgressChecker.checkIfComponentNeedIssueSync(dbSession, componentDto.get().getKey());
  108. } else {
  109. issueIndexSyncProgressChecker.checkIfIssueSyncInProgress(dbSession);
  110. }
  111. }
  112. }
  113. }