SONAR-10366 Add pull request object to api/project_branches/list and api/ce/activity SONAR-10365 Analyze pull requests as 1st class citizen SONAR-10366 SONAR-10367 Create WS api/projet_pull_requests/list and delete SONAR-10383 Add Pull Request information when listing CE tasks SONAR-10365 Add key type in PROJECT_BRANCHES (#3063) SONAR-10371 Add pullRequest parameter in the Web API (#3076) * ComponentFinder searches by branch or pull request * Add pullRequest parameter to WS api/issues/* WS * Add pullRequest parameter to api/settings/* WS * Add pullRequest parameter to api/badges/* WS * Add pullRequest parameter to api/components/* WS * Add pullRequest parameter to api/sources/* WS SONAR-10368 Copy issue states from pull request after it's merged SONAR-10373 Send notifications for events on issues of a pull request SONAR-10365 Add pull_request_binary column in project_branches (#3073) SONAR-10433 Store pull request in projects table SONAR-10371 Add pullRequest field in the Web API SONAR-10365 Analyze pull requests as 1st class citizen BRANCH-45 Expose issue resolution for PR decoration BRANCH-49 Basic support of pull request analysis on pull request branch BRANCH-47 Fail when user tries to analyze a pull request and the plugin is not available SONAR-10366 update pull request decorated links to project and issues SONAR-10365 Use pull request id as key instead of branch name SONAR-10454 Update embedded Git 1.4 and SVN 1.7 SONAR-10365 rename sonar.pullrequest.id to sonar.pullrequest.key SONAR-10383 api/navigation/component returns the pull request keytags/7.5
+ 26 // level 1 | + 26 // level 1 | ||||
+ 53 // content of DaoModule | + 53 // content of DaoModule | ||||
+ 3 // content of EsModule | + 3 // content of EsModule | ||||
+ 57 // content of CorePropertyDefinitions | |||||
+ 59 // content of CorePropertyDefinitions | |||||
+ 1 // StopFlagContainer | + 1 // StopFlagContainer | ||||
); | ); | ||||
assertThat( | assertThat( |
"UUID" VARCHAR(50) NOT NULL PRIMARY KEY, | "UUID" VARCHAR(50) NOT NULL PRIMARY KEY, | ||||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | "PROJECT_UUID" VARCHAR(50) NOT NULL, | ||||
"KEE" VARCHAR(255) NOT NULL, | "KEE" VARCHAR(255) NOT NULL, | ||||
"BRANCH_TYPE" VARCHAR(5), | |||||
"KEY_TYPE" VARCHAR(12) NOT NULL, | |||||
"BRANCH_TYPE" VARCHAR(12), | |||||
"MERGE_BRANCH_UUID" VARCHAR(50), | "MERGE_BRANCH_UUID" VARCHAR(50), | ||||
"PULL_REQUEST_BINARY" BLOB, | |||||
"CREATED_AT" BIGINT NOT NULL, | "CREATED_AT" BIGINT NOT NULL, | ||||
"UPDATED_AT" BIGINT NOT NULL | "UPDATED_AT" BIGINT NOT NULL | ||||
); | ); | ||||
CREATE UNIQUE INDEX "PK_PROJECT_BRANCHES" ON "PROJECT_BRANCHES" ("UUID"); | CREATE UNIQUE INDEX "PK_PROJECT_BRANCHES" ON "PROJECT_BRANCHES" ("UUID"); | ||||
CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE" ON "PROJECT_BRANCHES" ("PROJECT_UUID", "KEE"); | |||||
CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE_KEY_TYPE" ON "PROJECT_BRANCHES" ("PROJECT_UUID", "KEE", "KEY_TYPE"); | |||||
CREATE TABLE "ANALYSIS_PROPERTIES" ( | CREATE TABLE "ANALYSIS_PROPERTIES" ( | ||||
"UUID" VARCHAR(40) NOT NULL PRIMARY KEY, | "UUID" VARCHAR(40) NOT NULL PRIMARY KEY, |
public static final String BRANCH_KEY = "branch"; | public static final String BRANCH_KEY = "branch"; | ||||
public static final String BRANCH_TYPE_KEY = "branchType"; | public static final String BRANCH_TYPE_KEY = "branchType"; | ||||
public static final String PULL_REQUEST = "pullRequest"; | |||||
private String uuid; | private String uuid; | ||||
private String taskUuid; | private String taskUuid; |
} | } | ||||
public void insert(DbSession dbSession, BranchDto dto) { | public void insert(DbSession dbSession, BranchDto dto) { | ||||
setKeyType(dto); | |||||
mapper(dbSession).insert(dto, system2.now()); | mapper(dbSession).insert(dto, system2.now()); | ||||
} | } | ||||
public void upsert(DbSession dbSession, BranchDto dto) { | public void upsert(DbSession dbSession, BranchDto dto) { | ||||
BranchMapper mapper = mapper(dbSession); | BranchMapper mapper = mapper(dbSession); | ||||
long now = system2.now(); | long now = system2.now(); | ||||
setKeyType(dto); | |||||
if (mapper.update(dto, now) == 0) { | if (mapper.update(dto, now) == 0) { | ||||
mapper.insert(dto, now); | mapper.insert(dto, now); | ||||
} | } | ||||
} | } | ||||
private static void setKeyType(BranchDto dto) { | |||||
if (dto.getBranchType() == BranchType.PULL_REQUEST) { | |||||
dto.setKeyType(KeyType.PULL_REQUEST); | |||||
} else { | |||||
dto.setKeyType(KeyType.BRANCH); | |||||
} | |||||
} | |||||
public int updateMainBranchName(DbSession dbSession, String projectUuid, String newBranchKey) { | public int updateMainBranchName(DbSession dbSession, String projectUuid, String newBranchKey) { | ||||
long now = system2.now(); | long now = system2.now(); | ||||
return mapper(dbSession).updateMainBranchName(projectUuid, newBranchKey, now); | return mapper(dbSession).updateMainBranchName(projectUuid, newBranchKey, now); | ||||
} | } | ||||
public Optional<BranchDto> selectByKey(DbSession dbSession, String projectUuid, String key) { | |||||
return Optional.ofNullable(mapper(dbSession).selectByKey(projectUuid, key)); | |||||
public Optional<BranchDto> selectByBranchKey(DbSession dbSession, String projectUuid, String key) { | |||||
return selectByKey(dbSession, projectUuid, key, KeyType.BRANCH); | |||||
} | |||||
public Optional<BranchDto> selectByPullRequestKey(DbSession dbSession, String projectUuid, String key) { | |||||
return selectByKey(dbSession, projectUuid, key, KeyType.PULL_REQUEST); | |||||
} | |||||
private static Optional<BranchDto> selectByKey(DbSession dbSession, String projectUuid, String key, KeyType keyType) { | |||||
return Optional.ofNullable(mapper(dbSession).selectByKey(projectUuid, key, keyType)); | |||||
} | } | ||||
public Collection<BranchDto> selectByComponent(DbSession dbSession, ComponentDto component) { | public Collection<BranchDto> selectByComponent(DbSession dbSession, ComponentDto component) { |
*/ | */ | ||||
package org.sonar.db.component; | package org.sonar.db.component; | ||||
import java.io.ByteArrayInputStream; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.IOException; | |||||
import java.util.Objects; | import java.util.Objects; | ||||
import javax.annotation.CheckForNull; | |||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.sonar.db.protobuf.DbProjectBranches; | |||||
import static com.google.common.base.Preconditions.checkArgument; | import static com.google.common.base.Preconditions.checkArgument; | ||||
private String projectUuid; | private String projectUuid; | ||||
/** | /** | ||||
* Name of branch, for example "feature/foo". | |||||
* Key that identifies a branch or a pull request. | |||||
* For keyType=BRANCH, this is the name of the branch, for example "feature/foo". | |||||
* For keyType=PULL_REQUEST, this is the ID of the pull request in some external system, for example 123 in GitHub. | |||||
*/ | */ | ||||
private String kee; | private String kee; | ||||
/** | |||||
* Key type, as provided by {@link KeyType}. | |||||
* Not null. | |||||
*/ | |||||
private KeyType keyType; | |||||
/** | /** | ||||
* Branch type, as provided by {@link BranchType}. | * Branch type, as provided by {@link BranchType}. | ||||
* Not null. | * Not null. | ||||
@Nullable | @Nullable | ||||
private String mergeBranchUuid; | private String mergeBranchUuid; | ||||
/** | |||||
* Pull Request data, such as branch name, title, url, and provider specific attributes | |||||
*/ | |||||
@Nullable | |||||
private byte[] pullRequestBinary; | |||||
public String getUuid() { | public String getUuid() { | ||||
return uuid; | return uuid; | ||||
} | } | ||||
return this; | return this; | ||||
} | } | ||||
BranchDto setKeyType(@Nullable KeyType keyType) { | |||||
this.keyType = keyType; | |||||
return this; | |||||
} | |||||
public BranchType getBranchType() { | public BranchType getBranchType() { | ||||
return branchType; | return branchType; | ||||
} | } | ||||
return this; | return this; | ||||
} | } | ||||
public BranchDto setPullRequestData(DbProjectBranches.PullRequestData pullRequestData) { | |||||
this.pullRequestBinary = encodePullRequestData(pullRequestData); | |||||
return this; | |||||
} | |||||
@CheckForNull | |||||
public DbProjectBranches.PullRequestData getPullRequestData() { | |||||
if (pullRequestBinary == null) { | |||||
return null; | |||||
} | |||||
return decodePullRequestData(pullRequestBinary); | |||||
} | |||||
private static byte[] encodePullRequestData(DbProjectBranches.PullRequestData pullRequestData) { | |||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | |||||
try { | |||||
pullRequestData.writeTo(outputStream); | |||||
return outputStream.toByteArray(); | |||||
} catch (IOException e) { | |||||
throw new IllegalStateException("Fail to serialize pull request data", e); | |||||
} | |||||
} | |||||
private static DbProjectBranches.PullRequestData decodePullRequestData(byte[] pullRequestBinary) { | |||||
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(pullRequestBinary)) { | |||||
return DbProjectBranches.PullRequestData.parseFrom(inputStream); | |||||
} catch (IOException e) { | |||||
throw new IllegalStateException("Fail to deserialize pull request data", e); | |||||
} | |||||
} | |||||
@Override | @Override | ||||
public boolean equals(Object o) { | public boolean equals(Object o) { | ||||
if (this == o) { | if (this == o) { | ||||
sb.append("uuid='").append(uuid).append('\''); | sb.append("uuid='").append(uuid).append('\''); | ||||
sb.append(", projectUuid='").append(projectUuid).append('\''); | sb.append(", projectUuid='").append(projectUuid).append('\''); | ||||
sb.append(", kee='").append(kee).append('\''); | sb.append(", kee='").append(kee).append('\''); | ||||
sb.append(", keyType=").append(keyType); | |||||
sb.append(", branchType=").append(branchType); | sb.append(", branchType=").append(branchType); | ||||
sb.append(", mergeBranchUuid='").append(mergeBranchUuid).append('\''); | sb.append(", mergeBranchUuid='").append(mergeBranchUuid).append('\''); | ||||
sb.append('}'); | sb.append('}'); |
int updateMainBranchName(@Param("projectUuid") String projectUuid, @Param("newBranchName") String newBranchName, @Param("now") long now); | int updateMainBranchName(@Param("projectUuid") String projectUuid, @Param("newBranchName") String newBranchName, @Param("now") long now); | ||||
BranchDto selectByKey(@Param("projectUuid") String projectUuid, @Param("key") String key); | |||||
BranchDto selectByKey(@Param("projectUuid") String projectUuid, @Param("key") String key, @Param("keyType") KeyType keyType); | |||||
BranchDto selectByUuid(@Param("uuid") String uuid); | BranchDto selectByUuid(@Param("uuid") String uuid); | ||||
/** | /** | ||||
* Short-lived branch | * Short-lived branch | ||||
*/ | */ | ||||
SHORT | |||||
SHORT, | |||||
/** | |||||
* Pull request | |||||
*/ | |||||
PULL_REQUEST | |||||
} | } |
import static org.sonar.db.DatabaseUtils.executeLargeUpdates; | import static org.sonar.db.DatabaseUtils.executeLargeUpdates; | ||||
import static org.sonar.db.WildcardPosition.BEFORE_AND_AFTER; | import static org.sonar.db.WildcardPosition.BEFORE_AND_AFTER; | ||||
import static org.sonar.db.component.ComponentDto.generateBranchKey; | import static org.sonar.db.component.ComponentDto.generateBranchKey; | ||||
import static org.sonar.db.component.ComponentDto.generatePullRequestKey; | |||||
public class ComponentDao implements Dao { | public class ComponentDao implements Dao { | ||||
return executeLargeInputs(allKeys, subKeys -> mapper(session).selectByKeysAndBranch(subKeys, branch)); | return executeLargeInputs(allKeys, subKeys -> mapper(session).selectByKeysAndBranch(subKeys, branch)); | ||||
} | } | ||||
public List<ComponentDto> selectByKeysAndPullRequest(DbSession session, Collection<String> keys, String pullRequestId) { | |||||
List<String> dbKeys = keys.stream().map(k -> generatePullRequestKey(k, pullRequestId)).collect(toList()); | |||||
List<String> allKeys = Stream.of(keys, dbKeys).flatMap(Collection::stream).collect(toList()); | |||||
return executeLargeInputs(allKeys, subKeys -> mapper(session).selectByKeysAndBranch(subKeys, pullRequestId)); | |||||
} | |||||
public List<ComponentDto> selectComponentsHavingSameKeyOrderedById(DbSession session, String key) { | public List<ComponentDto> selectComponentsHavingSameKeyOrderedById(DbSession session, String key) { | ||||
return mapper(session).selectComponentsHavingSameKeyOrderedById(key); | return mapper(session).selectComponentsHavingSameKeyOrderedById(key); | ||||
} | } | ||||
} | } | ||||
public java.util.Optional<ComponentDto> selectByKeyAndBranch(DbSession session, String key, String branch) { | public java.util.Optional<ComponentDto> selectByKeyAndBranch(DbSession session, String key, String branch) { | ||||
return java.util.Optional.ofNullable(mapper(session).selectByKeyAndBranch(key, generateBranchKey(key, branch), branch)); | |||||
return java.util.Optional.ofNullable(mapper(session).selectByKeyAndBranchKey(key, generateBranchKey(key, branch), branch)); | |||||
} | |||||
public java.util.Optional<ComponentDto> selectByKeyAndPullRequest(DbSession session, String key, String pullRequestId) { | |||||
return java.util.Optional.ofNullable(mapper(session).selectByKeyAndBranchKey(key, generatePullRequestKey(key, pullRequestId), pullRequestId)); | |||||
} | } | ||||
public List<UuidWithProjectUuidDto> selectAllViewsAndSubViews(DbSession session) { | public List<UuidWithProjectUuidDto> selectAllViewsAndSubViews(DbSession session) { |
import com.google.common.base.Strings; | import com.google.common.base.Strings; | ||||
import java.util.Date; | import java.util.Date; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.regex.Pattern; | |||||
import javax.annotation.CheckForNull; | import javax.annotation.CheckForNull; | ||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.apache.commons.lang.StringUtils; | |||||
import org.apache.commons.lang.builder.ToStringBuilder; | import org.apache.commons.lang.builder.ToStringBuilder; | ||||
import org.sonar.api.resources.Scopes; | import org.sonar.api.resources.Scopes; | ||||
import org.sonar.db.WildcardPosition; | import org.sonar.db.WildcardPosition; | ||||
import static com.google.common.base.Preconditions.checkArgument; | import static com.google.common.base.Preconditions.checkArgument; | ||||
import static java.lang.String.format; | import static java.lang.String.format; | ||||
import static org.apache.commons.lang.StringUtils.substringBeforeLast; | |||||
import static org.sonar.db.DaoDatabaseUtils.buildLikeValue; | import static org.sonar.db.DaoDatabaseUtils.buildLikeValue; | ||||
import static org.sonar.db.component.ComponentValidator.checkComponentKey; | import static org.sonar.db.component.ComponentValidator.checkComponentKey; | ||||
import static org.sonar.db.component.ComponentValidator.checkComponentName; | import static org.sonar.db.component.ComponentValidator.checkComponentName; | ||||
* Separator used to generate the key of the branch | * Separator used to generate the key of the branch | ||||
*/ | */ | ||||
public static final String BRANCH_KEY_SEPARATOR = ":BRANCH:"; | public static final String BRANCH_KEY_SEPARATOR = ":BRANCH:"; | ||||
public static final String PULL_REQUEST_SEPARATOR = ":PULL_REQUEST:"; | |||||
private static final Splitter BRANCH_OR_PULL_REQUEST_SPLITTER = Splitter.on(Pattern.compile(BRANCH_KEY_SEPARATOR + "|" + PULL_REQUEST_SEPARATOR)); | |||||
private static final Splitter BRANCH_KEY_SPLITTER = Splitter.on(BRANCH_KEY_SEPARATOR); | private static final Splitter BRANCH_KEY_SPLITTER = Splitter.on(BRANCH_KEY_SEPARATOR); | ||||
private static final Splitter PULL_REQUEST_SPLITTER = Splitter.on(PULL_REQUEST_SEPARATOR); | |||||
public static final String UUID_PATH_SEPARATOR = "."; | public static final String UUID_PATH_SEPARATOR = "."; | ||||
public static final String UUID_PATH_OF_ROOT = UUID_PATH_SEPARATOR; | public static final String UUID_PATH_OF_ROOT = UUID_PATH_SEPARATOR; | ||||
private String organizationUuid; | private String organizationUuid; | ||||
/** | /** | ||||
* Non-empty and unique functional key | |||||
* Non-empty and unique functional key. Do not rename, used by MyBatis. | |||||
*/ | */ | ||||
private String kee; | private String kee; | ||||
return UUID_PATH_SPLITTER.splitToList(uuidPath); | return UUID_PATH_SPLITTER.splitToList(uuidPath); | ||||
} | } | ||||
/** | |||||
* Used my MyBatis mapper | |||||
*/ | |||||
private String getKee(){ | |||||
return kee; | |||||
} | |||||
/** | |||||
* Used my MyBatis mapper | |||||
*/ | |||||
private void setKee(String kee){ | |||||
this.kee = kee; | |||||
} | |||||
public String getDbKey() { | public String getDbKey() { | ||||
return kee; | return kee; | ||||
} | } | ||||
* The key to be displayed to user, doesn't contain information on branches | * The key to be displayed to user, doesn't contain information on branches | ||||
*/ | */ | ||||
public String getKey() { | public String getKey() { | ||||
List<String> split = BRANCH_KEY_SPLITTER.splitToList(kee); | |||||
List<String> split = BRANCH_OR_PULL_REQUEST_SPLITTER.splitToList(kee); | |||||
return split.size() == 2 ? split.get(0) : kee; | return split.size() == 2 ? split.get(0) : kee; | ||||
} | } | ||||
return split.size() == 2 ? split.get(1) : null; | return split.size() == 2 ? split.get(1) : null; | ||||
} | } | ||||
/** | |||||
* @return the pull request id. It will be null when the component is not on a pull request | |||||
*/ | |||||
@CheckForNull | |||||
public String getPullRequest() { | |||||
List<String> split = PULL_REQUEST_SPLITTER.splitToList(kee); | |||||
return split.size() == 2 ? split.get(1) : null; | |||||
} | |||||
public String scope() { | public String scope() { | ||||
return scope; | return scope; | ||||
} | } | ||||
return format("%s%s%s", componentKey, BRANCH_KEY_SEPARATOR, branch); | return format("%s%s%s", componentKey, BRANCH_KEY_SEPARATOR, branch); | ||||
} | } | ||||
public static String removeBranchFromKey(String componentKey) { | |||||
return StringUtils.substringBeforeLast(componentKey, ComponentDto.BRANCH_KEY_SEPARATOR); | |||||
public static String generatePullRequestKey(String componentKey, String pullRequest) { | |||||
return format("%s%s%s", componentKey, PULL_REQUEST_SEPARATOR, pullRequest); | |||||
} | } | ||||
public static String removeBranchAndPullRequestFromKey(String componentKey) { | |||||
return substringBeforeLast(substringBeforeLast(componentKey, ComponentDto.BRANCH_KEY_SEPARATOR), ComponentDto.PULL_REQUEST_SEPARATOR); | |||||
} | |||||
} | } |
private static String branchBaseKey(String key) { | private static String branchBaseKey(String key) { | ||||
int index = key.lastIndexOf(ComponentDto.BRANCH_KEY_SEPARATOR); | int index = key.lastIndexOf(ComponentDto.BRANCH_KEY_SEPARATOR); | ||||
if (index == -1) { | |||||
return key; | |||||
if (index > -1) { | |||||
return key.substring(0, index); | |||||
} | } | ||||
return key.substring(0, index); | |||||
index = key.lastIndexOf(ComponentDto.PULL_REQUEST_SEPARATOR); | |||||
if (index > -1) { | |||||
return key.substring(0, index); | |||||
} | |||||
return key; | |||||
} | } | ||||
private static void runBatchUpdateForAllResources(Collection<ResourceDto> resources, String oldKey, String newKey, ComponentKeyUpdaterMapper mapper) { | private static void runBatchUpdateForAllResources(Collection<ResourceDto> resources, String oldKey, String newKey, ComponentKeyUpdaterMapper mapper) { |
ComponentDto selectByKey(String key); | ComponentDto selectByKey(String key); | ||||
@CheckForNull | @CheckForNull | ||||
ComponentDto selectByKeyAndBranch(@Param("key") String key, @Param("dbKey") String dbKey, @Param("branch") String branch); | |||||
ComponentDto selectByKeyAndBranchKey(@Param("key") String key, @Param("dbKey") String dbKey, @Param("branch") String branch); | |||||
@CheckForNull | @CheckForNull | ||||
ComponentDto selectById(long id); | ComponentDto selectById(long id); |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.db.component; | |||||
public enum KeyType { | |||||
BRANCH, | |||||
PULL_REQUEST | |||||
} |
/* | |||||
SonarQube, open source software quality management tool. | |||||
Copyright (C) 2008-2016 SonarSource | |||||
mailto:contact AT sonarsource DOT com | |||||
SonarQube 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. | |||||
SonarQube 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. | |||||
*/ | |||||
// Structure of db column PROJECT_BRANCHES.PULL_REQUEST_DATA | |||||
syntax = "proto3"; | |||||
package sonarqube.db.project_branches; | |||||
// The java package can be changed without breaking compatibility. | |||||
// it impacts only the generated Java code. | |||||
option java_package = "org.sonar.db.protobuf"; | |||||
option optimize_for = SPEED; | |||||
message PullRequestData { | |||||
string branch = 1; | |||||
string title = 2; | |||||
string url = 3; | |||||
map<string, string> attributes = 4; | |||||
} |
pb.uuid as uuid, | pb.uuid as uuid, | ||||
pb.project_uuid as projectUuid, | pb.project_uuid as projectUuid, | ||||
pb.kee as kee, | pb.kee as kee, | ||||
pb.key_type as keyType, | |||||
pb.branch_type as branchType, | pb.branch_type as branchType, | ||||
pb.merge_branch_uuid as mergeBranchUuid | |||||
pb.merge_branch_uuid as mergeBranchUuid, | |||||
pb.pull_request_binary as pullRequestBinary | |||||
</sql> | </sql> | ||||
<insert id="insert" parameterType="map" useGeneratedKeys="false"> | <insert id="insert" parameterType="map" useGeneratedKeys="false"> | ||||
uuid, | uuid, | ||||
project_uuid, | project_uuid, | ||||
kee, | kee, | ||||
key_type, | |||||
branch_type, | branch_type, | ||||
merge_branch_uuid, | merge_branch_uuid, | ||||
pull_request_binary, | |||||
created_at, | created_at, | ||||
updated_at | updated_at | ||||
) values ( | ) values ( | ||||
#{dto.uuid, jdbcType=VARCHAR}, | #{dto.uuid, jdbcType=VARCHAR}, | ||||
#{dto.projectUuid, jdbcType=VARCHAR}, | #{dto.projectUuid, jdbcType=VARCHAR}, | ||||
#{dto.kee, jdbcType=VARCHAR}, | #{dto.kee, jdbcType=VARCHAR}, | ||||
#{dto.keyType, jdbcType=VARCHAR}, | |||||
#{dto.branchType, jdbcType=VARCHAR}, | #{dto.branchType, jdbcType=VARCHAR}, | ||||
#{dto.mergeBranchUuid, jdbcType=VARCHAR}, | #{dto.mergeBranchUuid, jdbcType=VARCHAR}, | ||||
#{dto.pullRequestBinary, jdbcType=BINARY}, | |||||
#{now, jdbcType=BIGINT}, | #{now, jdbcType=BIGINT}, | ||||
#{now, jdbcType=BIGINT} | #{now, jdbcType=BIGINT} | ||||
) | ) | ||||
update project_branches | update project_branches | ||||
set | set | ||||
merge_branch_uuid = #{dto.mergeBranchUuid, jdbcType=VARCHAR}, | merge_branch_uuid = #{dto.mergeBranchUuid, jdbcType=VARCHAR}, | ||||
pull_request_binary = #{dto.pullRequestBinary, jdbcType=BINARY}, | |||||
updated_at = #{now, jdbcType=BIGINT} | updated_at = #{now, jdbcType=BIGINT} | ||||
where | where | ||||
uuid = #{dto.uuid, jdbcType=VARCHAR} | uuid = #{dto.uuid, jdbcType=VARCHAR} | ||||
from project_branches pb | from project_branches pb | ||||
where | where | ||||
pb.project_uuid = #{projectUuid, jdbcType=VARCHAR} and | pb.project_uuid = #{projectUuid, jdbcType=VARCHAR} and | ||||
pb.kee = #{key, jdbcType=VARCHAR} | |||||
pb.kee = #{key, jdbcType=VARCHAR} and | |||||
pb.key_type = #{keyType, jdbcType=VARCHAR} | |||||
</select> | </select> | ||||
<select id="selectByProjectUuid" parameterType="string" resultType="org.sonar.db.component.BranchDto"> | <select id="selectByProjectUuid" parameterType="string" resultType="org.sonar.db.component.BranchDto"> |
p.kee=#{key,jdbcType=VARCHAR} | p.kee=#{key,jdbcType=VARCHAR} | ||||
</select> | </select> | ||||
<select id="selectByKeyAndBranch" parameterType="String" resultType="Component"> | |||||
<select id="selectByKeyAndBranchKey" parameterType="String" resultType="Component"> | |||||
SELECT | SELECT | ||||
<include refid="componentColumns"/> | <include refid="componentColumns"/> | ||||
FROM projects p | FROM projects p | ||||
ON p.uuid = i.component_uuid | ON p.uuid = i.component_uuid | ||||
JOIN project_branches b | JOIN project_branches b | ||||
ON i.project_uuid = b.uuid | ON i.project_uuid = b.uuid | ||||
AND b.branch_type = 'SHORT' | |||||
AND (b.branch_type = 'SHORT' OR b.branch_type = 'PULL_REQUEST') | |||||
AND b.merge_branch_uuid = #{mergeBranchUuid,jdbcType=VARCHAR} | AND b.merge_branch_uuid = #{mergeBranchUuid,jdbcType=VARCHAR} | ||||
AND i.status != 'CLOSED' | AND i.status != 'CLOSED' | ||||
</select> | </select> |
import org.sonar.api.utils.internal.TestSystem2; | import org.sonar.api.utils.internal.TestSystem2; | ||||
import org.sonar.db.DbSession; | import org.sonar.db.DbSession; | ||||
import org.sonar.db.DbTester; | import org.sonar.db.DbTester; | ||||
import org.sonar.db.protobuf.DbProjectBranches; | |||||
import static java.util.Arrays.asList; | import static java.util.Arrays.asList; | ||||
import static java.util.Collections.singletonList; | import static java.util.Collections.singletonList; | ||||
private static final long NOW = 1_000L; | private static final long NOW = 1_000L; | ||||
private static final String SELECT_FROM = "select project_uuid as \"projectUuid\", uuid as \"uuid\", branch_type as \"branchType\", " + | private static final String SELECT_FROM = "select project_uuid as \"projectUuid\", uuid as \"uuid\", branch_type as \"branchType\", " + | ||||
"kee as \"kee\", merge_branch_uuid as \"mergeBranchUuid\", created_at as \"createdAt\", updated_at as \"updatedAt\" " + | |||||
"kee as \"kee\", merge_branch_uuid as \"mergeBranchUuid\", pull_request_binary as \"pullRequestBinary\", created_at as \"createdAt\", updated_at as \"updatedAt\" " + | |||||
"from project_branches "; | "from project_branches "; | ||||
private System2 system2 = new TestSystem2().setNow(NOW); | private System2 system2 = new TestSystem2().setNow(NOW); | ||||
entry("branchType", "SHORT"), | entry("branchType", "SHORT"), | ||||
entry("kee", "feature/foo"), | entry("kee", "feature/foo"), | ||||
entry("mergeBranchUuid", null), | entry("mergeBranchUuid", null), | ||||
entry("pullRequestBinary", null), | |||||
entry("createdAt", 1_000L), | entry("createdAt", 1_000L), | ||||
entry("updatedAt", 1_000L)); | entry("updatedAt", 1_000L)); | ||||
} | } | ||||
underTest.insert(dbSession, dto2); | underTest.insert(dbSession, dto2); | ||||
underTest.updateMainBranchName(dbSession, "U1", "master"); | underTest.updateMainBranchName(dbSession, "U1", "master"); | ||||
BranchDto loaded = underTest.selectByKey(dbSession, "U1", "master").get(); | |||||
BranchDto loaded = underTest.selectByBranchKey(dbSession, "U1", "master").get(); | |||||
assertThat(loaded.getMergeBranchUuid()).isNull(); | assertThat(loaded.getMergeBranchUuid()).isNull(); | ||||
assertThat(loaded.getProjectUuid()).isEqualTo("U1"); | assertThat(loaded.getProjectUuid()).isEqualTo("U1"); | ||||
assertThat(loaded.getBranchType()).isEqualTo(BranchType.LONG); | assertThat(loaded.getBranchType()).isEqualTo(BranchType.LONG); | ||||
} | } | ||||
@Test | @Test | ||||
public void upsert() { | |||||
public void insert_pull_request_branch_with_only_non_null_fields() { | |||||
String projectUuid = "U1"; | |||||
String uuid = "U2"; | |||||
BranchType branchType = BranchType.PULL_REQUEST; | |||||
String kee = "123"; | |||||
BranchDto dto = new BranchDto(); | |||||
dto.setProjectUuid(projectUuid); | |||||
dto.setUuid(uuid); | |||||
dto.setBranchType(branchType); | |||||
dto.setKey(kee); | |||||
underTest.insert(dbSession, dto); | |||||
BranchDto loaded = underTest.selectByUuid(dbSession, dto.getUuid()).get(); | |||||
assertThat(loaded.getProjectUuid()).isEqualTo(projectUuid); | |||||
assertThat(loaded.getUuid()).isEqualTo(uuid); | |||||
assertThat(loaded.getBranchType()).isEqualTo(branchType); | |||||
assertThat(loaded.getKey()).isEqualTo(kee); | |||||
assertThat(loaded.getMergeBranchUuid()).isNull(); | |||||
assertThat(loaded.getPullRequestData()).isNull(); | |||||
} | |||||
@Test | |||||
public void insert_pull_request_branch_with_all_fields() { | |||||
String projectUuid = "U1"; | |||||
String uuid = "U2"; | |||||
BranchType branchType = BranchType.PULL_REQUEST; | |||||
String kee = "123"; | |||||
String branch = "feature/pr1"; | |||||
String title = "Dummy Feature Title"; | |||||
String url = "http://example.com/pullRequests/pr1"; | |||||
String tokenAttributeName = "token"; | |||||
String tokenAttributeValue = "dummy token"; | |||||
DbProjectBranches.PullRequestData pullRequestData = DbProjectBranches.PullRequestData.newBuilder() | |||||
.setBranch(branch) | |||||
.setTitle(title) | |||||
.setUrl(url) | |||||
.putAttributes(tokenAttributeName, tokenAttributeValue) | |||||
.build(); | |||||
BranchDto dto = new BranchDto(); | |||||
dto.setProjectUuid(projectUuid); | |||||
dto.setUuid(uuid); | |||||
dto.setBranchType(branchType); | |||||
dto.setKey(kee); | |||||
dto.setPullRequestData(pullRequestData); | |||||
underTest.insert(dbSession, dto); | |||||
BranchDto loaded = underTest.selectByUuid(dbSession, dto.getUuid()).get(); | |||||
assertThat(loaded.getProjectUuid()).isEqualTo(projectUuid); | |||||
assertThat(loaded.getUuid()).isEqualTo(uuid); | |||||
assertThat(loaded.getBranchType()).isEqualTo(branchType); | |||||
assertThat(loaded.getKey()).isEqualTo(kee); | |||||
assertThat(loaded.getMergeBranchUuid()).isNull(); | |||||
DbProjectBranches.PullRequestData loadedPullRequestData = loaded.getPullRequestData(); | |||||
assertThat(loadedPullRequestData).isNotNull(); | |||||
assertThat(loadedPullRequestData.getBranch()).isEqualTo(branch); | |||||
assertThat(loadedPullRequestData.getTitle()).isEqualTo(title); | |||||
assertThat(loadedPullRequestData.getUrl()).isEqualTo(url); | |||||
assertThat(loadedPullRequestData.getAttributesMap().get(tokenAttributeName)).isEqualTo(tokenAttributeValue); | |||||
} | |||||
@Test | |||||
public void upsert_branch() { | |||||
BranchDto dto = new BranchDto(); | BranchDto dto = new BranchDto(); | ||||
dto.setProjectUuid("U1"); | dto.setProjectUuid("U1"); | ||||
dto.setUuid("U2"); | dto.setUuid("U2"); | ||||
dto.setBranchType(BranchType.SHORT); | dto.setBranchType(BranchType.SHORT); | ||||
underTest.upsert(dbSession, dto); | underTest.upsert(dbSession, dto); | ||||
BranchDto loaded = underTest.selectByKey(dbSession, "U1", "foo").get(); | |||||
BranchDto loaded = underTest.selectByBranchKey(dbSession, "U1", "foo").get(); | |||||
assertThat(loaded.getMergeBranchUuid()).isEqualTo("U3"); | assertThat(loaded.getMergeBranchUuid()).isEqualTo("U3"); | ||||
assertThat(loaded.getProjectUuid()).isEqualTo("U1"); | assertThat(loaded.getProjectUuid()).isEqualTo("U1"); | ||||
assertThat(loaded.getBranchType()).isEqualTo(BranchType.LONG); | assertThat(loaded.getBranchType()).isEqualTo(BranchType.LONG); | ||||
} | } | ||||
@Test | @Test | ||||
public void selectByKey() { | |||||
public void upsert_pull_request() { | |||||
BranchDto dto = new BranchDto(); | |||||
dto.setProjectUuid("U1"); | |||||
dto.setUuid("U2"); | |||||
dto.setBranchType(BranchType.PULL_REQUEST); | |||||
dto.setKey("foo"); | |||||
underTest.insert(dbSession, dto); | |||||
// the fields that can be updated | |||||
dto.setMergeBranchUuid("U3"); | |||||
String branch = "feature/pr1"; | |||||
String title = "Dummy Feature Title"; | |||||
String url = "http://example.com/pullRequests/pr1"; | |||||
String tokenAttributeName = "token"; | |||||
String tokenAttributeValue = "dummy token"; | |||||
DbProjectBranches.PullRequestData pullRequestData = DbProjectBranches.PullRequestData.newBuilder() | |||||
.setBranch(branch) | |||||
.setTitle(title) | |||||
.setUrl(url) | |||||
.putAttributes(tokenAttributeName, tokenAttributeValue) | |||||
.build(); | |||||
dto.setPullRequestData(pullRequestData); | |||||
// the fields that can't be updated. New values are ignored. | |||||
dto.setProjectUuid("ignored"); | |||||
dto.setBranchType(BranchType.SHORT); | |||||
underTest.upsert(dbSession, dto); | |||||
BranchDto loaded = underTest.selectByPullRequestKey(dbSession, "U1", "foo").get(); | |||||
assertThat(loaded.getMergeBranchUuid()).isEqualTo("U3"); | |||||
assertThat(loaded.getProjectUuid()).isEqualTo("U1"); | |||||
assertThat(loaded.getBranchType()).isEqualTo(BranchType.PULL_REQUEST); | |||||
DbProjectBranches.PullRequestData loadedPullRequestData = loaded.getPullRequestData(); | |||||
assertThat(loadedPullRequestData).isNotNull(); | |||||
assertThat(loadedPullRequestData.getBranch()).isEqualTo(branch); | |||||
assertThat(loadedPullRequestData.getTitle()).isEqualTo(title); | |||||
assertThat(loadedPullRequestData.getUrl()).isEqualTo(url); | |||||
assertThat(loadedPullRequestData.getAttributesMap().get(tokenAttributeName)).isEqualTo(tokenAttributeValue); | |||||
} | |||||
@Test | |||||
public void update_pull_request_data() { | |||||
BranchDto dto = new BranchDto(); | |||||
dto.setProjectUuid("U1"); | |||||
dto.setUuid("U2"); | |||||
dto.setBranchType(BranchType.PULL_REQUEST); | |||||
dto.setKey("foo"); | |||||
// the fields that can be updated | |||||
String mergeBranchUuid = "U3"; | |||||
dto.setMergeBranchUuid(mergeBranchUuid + "-dummy-suffix"); | |||||
String branch = "feature/pr1"; | |||||
String title = "Dummy Feature Title"; | |||||
String url = "http://example.com/pullRequests/pr1"; | |||||
String tokenAttributeName = "token"; | |||||
String tokenAttributeValue = "dummy token"; | |||||
DbProjectBranches.PullRequestData pullRequestData = DbProjectBranches.PullRequestData.newBuilder() | |||||
.setBranch(branch + "-dummy-suffix") | |||||
.setTitle(title + "-dummy-suffix") | |||||
.setUrl(url + "-dummy-suffix") | |||||
.putAttributes(tokenAttributeName, tokenAttributeValue + "-dummy-suffix") | |||||
.build(); | |||||
dto.setPullRequestData(pullRequestData); | |||||
underTest.insert(dbSession, dto); | |||||
// modify pull request data | |||||
dto.setMergeBranchUuid(mergeBranchUuid); | |||||
pullRequestData = DbProjectBranches.PullRequestData.newBuilder() | |||||
.setBranch(branch) | |||||
.setTitle(title) | |||||
.setUrl(url) | |||||
.putAttributes(tokenAttributeName, tokenAttributeValue) | |||||
.build(); | |||||
dto.setPullRequestData(pullRequestData); | |||||
underTest.upsert(dbSession, dto); | |||||
BranchDto loaded = underTest.selectByPullRequestKey(dbSession, "U1", "foo").get(); | |||||
assertThat(loaded.getMergeBranchUuid()).isEqualTo(mergeBranchUuid); | |||||
assertThat(loaded.getProjectUuid()).isEqualTo("U1"); | |||||
assertThat(loaded.getBranchType()).isEqualTo(BranchType.PULL_REQUEST); | |||||
DbProjectBranches.PullRequestData loadedPullRequestData = loaded.getPullRequestData(); | |||||
assertThat(loadedPullRequestData).isNotNull(); | |||||
assertThat(loadedPullRequestData.getBranch()).isEqualTo(branch); | |||||
assertThat(loadedPullRequestData.getTitle()).isEqualTo(title); | |||||
assertThat(loadedPullRequestData.getUrl()).isEqualTo(url); | |||||
assertThat(loadedPullRequestData.getAttributesMap().get(tokenAttributeName)).isEqualTo(tokenAttributeValue); | |||||
} | |||||
@Test | |||||
public void selectByBranchKey() { | |||||
BranchDto mainBranch = new BranchDto(); | BranchDto mainBranch = new BranchDto(); | ||||
mainBranch.setProjectUuid("U1"); | mainBranch.setProjectUuid("U1"); | ||||
mainBranch.setUuid("U1"); | mainBranch.setUuid("U1"); | ||||
underTest.insert(dbSession, featureBranch); | underTest.insert(dbSession, featureBranch); | ||||
// select the feature branch | // select the feature branch | ||||
BranchDto loaded = underTest.selectByKey(dbSession, "U1", "feature/foo").get(); | |||||
BranchDto loaded = underTest.selectByBranchKey(dbSession, "U1", "feature/foo").get(); | |||||
assertThat(loaded.getUuid()).isEqualTo(featureBranch.getUuid()); | assertThat(loaded.getUuid()).isEqualTo(featureBranch.getUuid()); | ||||
assertThat(loaded.getKey()).isEqualTo(featureBranch.getKey()); | assertThat(loaded.getKey()).isEqualTo(featureBranch.getKey()); | ||||
assertThat(loaded.getProjectUuid()).isEqualTo(featureBranch.getProjectUuid()); | assertThat(loaded.getProjectUuid()).isEqualTo(featureBranch.getProjectUuid()); | ||||
assertThat(loaded.getMergeBranchUuid()).isEqualTo(featureBranch.getMergeBranchUuid()); | assertThat(loaded.getMergeBranchUuid()).isEqualTo(featureBranch.getMergeBranchUuid()); | ||||
// select a branch on another project with same branch name | // select a branch on another project with same branch name | ||||
assertThat(underTest.selectByKey(dbSession, "U3", "feature/foo")).isEmpty(); | |||||
assertThat(underTest.selectByBranchKey(dbSession, "U3", "feature/foo")).isEmpty(); | |||||
} | |||||
@Test | |||||
public void selectByPullRequestKey() { | |||||
BranchDto mainBranch = new BranchDto(); | |||||
mainBranch.setProjectUuid("U1"); | |||||
mainBranch.setUuid("U1"); | |||||
mainBranch.setBranchType(BranchType.LONG); | |||||
mainBranch.setKey("master"); | |||||
underTest.insert(dbSession, mainBranch); | |||||
String pullRequestId = "123"; | |||||
BranchDto pullRequest = new BranchDto(); | |||||
pullRequest.setProjectUuid("U1"); | |||||
pullRequest.setUuid("U2"); | |||||
pullRequest.setBranchType(BranchType.PULL_REQUEST); | |||||
pullRequest.setKey(pullRequestId); | |||||
pullRequest.setMergeBranchUuid("U3"); | |||||
underTest.insert(dbSession, pullRequest); | |||||
// select the feature branch | |||||
BranchDto loaded = underTest.selectByPullRequestKey(dbSession, "U1", pullRequestId).get(); | |||||
assertThat(loaded.getUuid()).isEqualTo(pullRequest.getUuid()); | |||||
assertThat(loaded.getKey()).isEqualTo(pullRequest.getKey()); | |||||
assertThat(loaded.getProjectUuid()).isEqualTo(pullRequest.getProjectUuid()); | |||||
assertThat(loaded.getBranchType()).isEqualTo(pullRequest.getBranchType()); | |||||
assertThat(loaded.getMergeBranchUuid()).isEqualTo(pullRequest.getMergeBranchUuid()); | |||||
// select a branch on another project with same branch name | |||||
assertThat(underTest.selectByPullRequestKey(dbSession, "U3", pullRequestId)).isEmpty(); | |||||
} | } | ||||
@Test | @Test |
*/ | */ | ||||
package org.sonar.db.component; | package org.sonar.db.component; | ||||
import org.junit.Rule; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.junit.rules.ExpectedException; | |||||
import org.sonar.db.protobuf.DbProjectBranches; | |||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
public class BranchDtoTest { | public class BranchDtoTest { | ||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private BranchDto underTest = new BranchDto(); | private BranchDto underTest = new BranchDto(); | ||||
@Test | @Test | ||||
assertThat(underTest.isMain()).isFalse(); | assertThat(underTest.isMain()).isFalse(); | ||||
} | } | ||||
@Test | |||||
public void encode_and_decode_pull_request_data() { | |||||
String branch = "feature/pr1"; | |||||
String title = "Dummy Feature Title"; | |||||
String url = "http://example.com/pullRequests/pr1"; | |||||
DbProjectBranches.PullRequestData pullRequestData = DbProjectBranches.PullRequestData.newBuilder() | |||||
.setBranch(branch) | |||||
.setTitle(title) | |||||
.setUrl(url) | |||||
.build(); | |||||
underTest.setPullRequestData(pullRequestData); | |||||
DbProjectBranches.PullRequestData decoded = underTest.getPullRequestData(); | |||||
assertThat(decoded).isNotNull(); | |||||
assertThat(decoded.getBranch()).isEqualTo(branch); | |||||
assertThat(decoded.getTitle()).isEqualTo(title); | |||||
assertThat(decoded.getUrl()).isEqualTo(url); | |||||
} | |||||
@Test | |||||
public void getPullRequestData_returns_null_when_data_is_null() { | |||||
assertThat(underTest.getPullRequestData()).isNull(); | |||||
} | |||||
} | } |
assertThat(underTest.getKey()).isEqualTo("my_key"); | assertThat(underTest.getKey()).isEqualTo("my_key"); | ||||
assertThat(underTest.getBranch()).isNull(); | assertThat(underTest.getBranch()).isNull(); | ||||
} | } | ||||
@Test | |||||
public void getKey_and_getPullRequest() { | |||||
ComponentDto underTest = new ComponentDto().setDbKey("my_key:PULL_REQUEST:pr-123"); | |||||
assertThat(underTest.getKey()).isEqualTo("my_key"); | |||||
assertThat(underTest.getPullRequest()).isEqualTo("pr-123"); | |||||
underTest = new ComponentDto().setDbKey("my_key"); | |||||
assertThat(underTest.getKey()).isEqualTo("my_key"); | |||||
assertThat(underTest.getPullRequest()).isNull(); | |||||
} | |||||
} | } |
import static com.google.common.collect.Lists.newArrayList; | import static com.google.common.collect.Lists.newArrayList; | ||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.assertj.core.api.Assertions.entry; | import static org.assertj.core.api.Assertions.entry; | ||||
import static org.sonar.db.component.BranchType.PULL_REQUEST; | |||||
import static org.sonar.db.component.ComponentKeyUpdaterDao.computeNewKey; | import static org.sonar.db.component.ComponentKeyUpdaterDao.computeNewKey; | ||||
import static org.sonar.db.component.ComponentTesting.newDirectory; | import static org.sonar.db.component.ComponentTesting.newDirectory; | ||||
import static org.sonar.db.component.ComponentTesting.newFileDto; | import static org.sonar.db.component.ComponentTesting.newFileDto; | ||||
.forEach(map -> map.values().forEach(k -> assertThat(k.toString()).startsWith(newProjectKey))); | .forEach(map -> map.values().forEach(k -> assertThat(k.toString()).startsWith(newProjectKey))); | ||||
} | } | ||||
@Test | |||||
public void updateKey_updates_pull_requests_too() { | |||||
ComponentDto project = db.components().insertMainBranch(); | |||||
ComponentDto pullRequest = db.components().insertProjectBranch(project, b -> b.setBranchType(PULL_REQUEST)); | |||||
db.components().insertComponent(newFileDto(pullRequest)); | |||||
db.components().insertComponent(newFileDto(pullRequest)); | |||||
int branchComponentCount = 3; | |||||
String oldProjectKey = project.getKey(); | |||||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldProjectKey)).hasSize(1); | |||||
String oldBranchKey = pullRequest.getDbKey(); | |||||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldBranchKey)).hasSize(branchComponentCount); | |||||
String newProjectKey = "newKey"; | |||||
String newBranchKey = ComponentDto.generatePullRequestKey(newProjectKey, pullRequest.getPullRequest()); | |||||
underTest.updateKey(dbSession, project.uuid(), newProjectKey); | |||||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldProjectKey)).isEmpty(); | |||||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldBranchKey)).isEmpty(); | |||||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, newProjectKey)).hasSize(1); | |||||
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, newBranchKey)).hasSize(branchComponentCount); | |||||
db.select(dbSession, "select kee from projects") | |||||
.forEach(map -> map.values().forEach(k -> assertThat(k.toString()).startsWith(newProjectKey))); | |||||
} | |||||
@Test | @Test | ||||
public void bulk_updateKey_updates_branches_too() { | public void bulk_updateKey_updates_branches_too() { | ||||
ComponentDto project = db.components().insertMainBranch(); | ComponentDto project = db.components().insertMainBranch(); | ||||
.forEach(map -> map.values().forEach(k -> assertThat(k.toString()).startsWith(newProjectKey))); | .forEach(map -> map.values().forEach(k -> assertThat(k.toString()).startsWith(newProjectKey))); | ||||
} | } | ||||
@Test | |||||
public void bulk_updateKey_updates_pull_requests_too() { | |||||
ComponentDto project = db.components().insertMainBranch(); | |||||
ComponentDto pullRequest = db.components().insertProjectBranch(project, b -> b.setBranchType(PULL_REQUEST)); | |||||
ComponentDto module = db.components().insertComponent(prefixDbKeyWithKey(newModuleDto(pullRequest), project.getKey())); | |||||
db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey())); | |||||
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()); | |||||
underTest.bulkUpdateKey(dbSession, project.uuid(), oldProjectKey, newProjectKey); | |||||
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 projects") | |||||
.forEach(map -> map.values().forEach(k -> assertThat(k.toString()).startsWith(newProjectKey))); | |||||
} | |||||
private ComponentDto prefixDbKeyWithKey(ComponentDto componentDto, String key) { | private ComponentDto prefixDbKeyWithKey(ComponentDto componentDto, String key) { | ||||
return componentDto.setDbKey(key + ":" + componentDto.getDbKey()); | return componentDto.setDbKey(key + ":" + componentDto.getDbKey()); | ||||
} | } |
import static com.google.common.base.Preconditions.checkArgument; | import static com.google.common.base.Preconditions.checkArgument; | ||||
import static com.google.common.base.Preconditions.checkNotNull; | import static com.google.common.base.Preconditions.checkNotNull; | ||||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | ||||
import static org.sonar.db.component.BranchType.PULL_REQUEST; | |||||
import static org.sonar.db.component.ComponentDto.UUID_PATH_SEPARATOR; | import static org.sonar.db.component.ComponentDto.UUID_PATH_SEPARATOR; | ||||
public class ComponentTesting { | public class ComponentTesting { | ||||
private static String generateKey(String key, ComponentDto parentModuleOrProject) { | private static String generateKey(String key, ComponentDto parentModuleOrProject) { | ||||
String branch = parentModuleOrProject.getBranch(); | String branch = parentModuleOrProject.getBranch(); | ||||
return branch == null ? key : ComponentDto.generateBranchKey(key, branch); | |||||
if (branch != null) { | |||||
return ComponentDto.generateBranchKey(key, branch); | |||||
} | |||||
String pullRequest = parentModuleOrProject.getPullRequest(); | |||||
if (pullRequest != null) { | |||||
return ComponentDto.generatePullRequestKey(key, pullRequest); | |||||
} | |||||
return key; | |||||
} | } | ||||
public static ComponentDto newModuleDto(ComponentDto subProjectOrProject) { | public static ComponentDto newModuleDto(ComponentDto subProjectOrProject) { | ||||
checkArgument(project.qualifier().equals(Qualifiers.PROJECT)); | checkArgument(project.qualifier().equals(Qualifiers.PROJECT)); | ||||
checkArgument(project.getMainBranchProjectUuid() == null); | checkArgument(project.getMainBranchProjectUuid() == null); | ||||
String branchName = branchDto.getKey(); | String branchName = branchDto.getKey(); | ||||
String branchSeparator = branchDto.getBranchType() == PULL_REQUEST ? ":PULL_REQUEST:" : ":BRANCH:"; | |||||
String uuid = branchDto.getUuid(); | String uuid = branchDto.getUuid(); | ||||
return new ComponentDto() | return new ComponentDto() | ||||
.setUuid(uuid) | .setUuid(uuid) | ||||
.setModuleUuidPath(UUID_PATH_SEPARATOR + uuid + UUID_PATH_SEPARATOR) | .setModuleUuidPath(UUID_PATH_SEPARATOR + uuid + UUID_PATH_SEPARATOR) | ||||
.setRootUuid(uuid) | .setRootUuid(uuid) | ||||
// name of the branch is not mandatory on the main branch | // name of the branch is not mandatory on the main branch | ||||
.setDbKey(branchName != null ? project.getDbKey() + ":BRANCH:" + branchName : project.getKey()) | |||||
.setDbKey(branchName != null ? project.getDbKey() + branchSeparator + branchName : project.getKey()) | |||||
.setMainBranchProjectUuid(project.uuid()) | .setMainBranchProjectUuid(project.uuid()) | ||||
.setName(project.name()) | .setName(project.name()) | ||||
.setLongName(project.longName()) | .setLongName(project.longName()) |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import org.sonar.db.Database; | |||||
import org.sonar.server.platform.db.migration.def.VarcharColumnDef; | |||||
import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder; | |||||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||||
public class AddKeyTypeInProjectBranches extends DdlChange { | |||||
public static final String TABLE_NAME = "project_branches"; | |||||
public AddKeyTypeInProjectBranches(Database db) { | |||||
super(db); | |||||
} | |||||
@Override | |||||
public void execute(Context context) throws SQLException { | |||||
context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME) | |||||
.addColumn(VarcharColumnDef.newVarcharColumnDefBuilder() | |||||
.setColumnName("key_type") | |||||
.setIsNullable(true) | |||||
.setLimit(12) | |||||
.build()) | |||||
.build()); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import org.sonar.db.Database; | |||||
import org.sonar.server.platform.db.migration.def.BlobColumnDef; | |||||
import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder; | |||||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||||
public class AddPullRequestBinaryInProjectBranches extends DdlChange { | |||||
static final String TABLE_NAME = "project_branches"; | |||||
static final String COLUMN_NAME = "pull_request_binary"; | |||||
public AddPullRequestBinaryInProjectBranches(Database db) { | |||||
super(db); | |||||
} | |||||
@Override | |||||
public void execute(Context context) throws SQLException { | |||||
context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME) | |||||
.addColumn(BlobColumnDef.newBlobColumnDefBuilder() | |||||
.setColumnName(COLUMN_NAME) | |||||
.setIsNullable(true) | |||||
.build()) | |||||
.build()); | |||||
} | |||||
} |
.add(2013, "Create WEBHOOKS Table", CreateWebhooksTable.class) | .add(2013, "Create WEBHOOKS Table", CreateWebhooksTable.class) | ||||
.add(2014, "Migrate webhooks from SETTINGS table to WEBHOOKS table", MigrateWebhooksToWebhooksTable.class) | .add(2014, "Migrate webhooks from SETTINGS table to WEBHOOKS table", MigrateWebhooksToWebhooksTable.class) | ||||
.add(2015, "Add webhook key to WEBHOOK_DELIVERIES table", AddWebhookKeyToWebhookDeliveriesTable.class) | .add(2015, "Add webhook key to WEBHOOK_DELIVERIES table", AddWebhookKeyToWebhookDeliveriesTable.class) | ||||
.add(2016, "Increase branch type size in PROJECT_BRANCHES", IncreaseBranchTypeSizeForPullRequest.class) | |||||
.add(2017, "Add key_type column in PROJECT_BRANCHES", AddKeyTypeInProjectBranches.class) | |||||
.add(2018, "Fill key_type column in PROJECT_BRANCHES", SetKeyTypeToBranchInProjectBranches.class) | |||||
.add(2019, "Make key_type not nullable in PROJECT_BRANCHES", MakeKeyTypeNotNullableInProjectBranches.class) | |||||
.add(2020, "Replace index in PROJECT_BRANCHES", ReplaceIndexInProjectBranches.class) | |||||
.add(2021, "Add pull_request_data in PROJECT_BRANCHES", AddPullRequestBinaryInProjectBranches.class) | |||||
; | ; | ||||
} | } | ||||
} | } |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import org.sonar.db.Database; | |||||
import org.sonar.server.platform.db.migration.sql.AlterColumnsBuilder; | |||||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||||
public class IncreaseBranchTypeSizeForPullRequest extends DdlChange { | |||||
private static final String TABLE_NAME = "project_branches"; | |||||
public IncreaseBranchTypeSizeForPullRequest(Database db) { | |||||
super(db); | |||||
} | |||||
@Override | |||||
public void execute(Context context) throws SQLException { | |||||
context.execute(new AlterColumnsBuilder(getDialect(), TABLE_NAME) | |||||
.updateColumn(newVarcharColumnDefBuilder() | |||||
.setColumnName("branch_type") | |||||
.setLimit(12) | |||||
.build()) | |||||
.build()); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import org.sonar.db.Database; | |||||
import org.sonar.server.platform.db.migration.sql.AlterColumnsBuilder; | |||||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||||
public class MakeKeyTypeNotNullableInProjectBranches extends DdlChange { | |||||
static final String TABLE_NAME = "project_branches"; | |||||
public MakeKeyTypeNotNullableInProjectBranches(Database db) { | |||||
super(db); | |||||
} | |||||
@Override | |||||
public void execute(Context context) throws SQLException { | |||||
context.execute(new AlterColumnsBuilder(getDialect(), TABLE_NAME) | |||||
.updateColumn(newVarcharColumnDefBuilder() | |||||
.setColumnName("key_type") | |||||
.setLimit(12) | |||||
.setIsNullable(false) | |||||
.build()) | |||||
.build()); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import org.sonar.db.Database; | |||||
import org.sonar.server.platform.db.migration.def.VarcharColumnDef; | |||||
import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; | |||||
import org.sonar.server.platform.db.migration.sql.DropIndexBuilder; | |||||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||||
public class ReplaceIndexInProjectBranches extends DdlChange { | |||||
static final String TABLE_NAME = "project_branches"; | |||||
private static final String OLD_INDEX_NAME = "project_branches_kee"; | |||||
static final String NEW_INDEX_NAME = "project_branches_kee_key_type"; | |||||
static final VarcharColumnDef PROJECT_UUID_COLUMN = VarcharColumnDef.newVarcharColumnDefBuilder() | |||||
.setColumnName("project_uuid") | |||||
.setIsNullable(false) | |||||
.setLimit(50) | |||||
.build(); | |||||
static final VarcharColumnDef KEE_COLUMN = VarcharColumnDef.newVarcharColumnDefBuilder() | |||||
.setColumnName("kee") | |||||
.setIsNullable(false) | |||||
.setLimit(255) | |||||
.build(); | |||||
static final VarcharColumnDef KEY_TYPE_COLUMN = VarcharColumnDef.newVarcharColumnDefBuilder() | |||||
.setColumnName("key_type") | |||||
.setIsNullable(false) | |||||
.setLimit(12) | |||||
.build(); | |||||
public ReplaceIndexInProjectBranches(Database db) { | |||||
super(db); | |||||
} | |||||
@Override | |||||
public void execute(Context context) throws SQLException { | |||||
context.execute(new DropIndexBuilder(getDialect()) | |||||
.setTable(TABLE_NAME) | |||||
.setName(OLD_INDEX_NAME) | |||||
.build()); | |||||
context.execute(new CreateIndexBuilder(getDialect()) | |||||
.addColumn(PROJECT_UUID_COLUMN) | |||||
.addColumn(KEE_COLUMN) | |||||
.addColumn(KEY_TYPE_COLUMN) | |||||
.setUnique(true) | |||||
.setTable(TABLE_NAME) | |||||
.setName(NEW_INDEX_NAME) | |||||
.build() | |||||
); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import org.sonar.api.utils.System2; | |||||
import org.sonar.db.Database; | |||||
import org.sonar.server.platform.db.migration.step.DataChange; | |||||
import org.sonar.server.platform.db.migration.step.MassUpdate; | |||||
public class SetKeyTypeToBranchInProjectBranches extends DataChange { | |||||
static final String TABLE_NAME = "project_branches"; | |||||
static final String DEFAULT_KEY_TYPE = "BRANCH"; | |||||
private final System2 system2; | |||||
public SetKeyTypeToBranchInProjectBranches(Database db, System2 system2) { | |||||
super(db); | |||||
this.system2 = system2; | |||||
} | |||||
@Override | |||||
protected void execute(Context context) throws SQLException { | |||||
long now = system2.now(); | |||||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||||
massUpdate.rowPluralName("branches"); | |||||
massUpdate.select("select uuid from " + TABLE_NAME + " where key_type is null"); | |||||
massUpdate.update("update " + TABLE_NAME + " set key_type=?, updated_at=? where uuid = ?"); | |||||
massUpdate.execute((row, update) -> { | |||||
update.setString(1, DEFAULT_KEY_TYPE); | |||||
update.setLong(2, now); | |||||
update.setString(3, row.getString(1)); | |||||
return true; | |||||
}); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import org.sonar.db.CoreDbTester; | |||||
import static java.sql.Types.VARCHAR; | |||||
public class AddKeyTypeInProjectBranchesTest { | |||||
public static final String TABLE_NAME = "project_branches"; | |||||
@Rule | |||||
public final CoreDbTester dbTester = CoreDbTester.createForSchema(AddKeyTypeInProjectBranchesTest.class, TABLE_NAME + ".sql"); | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private AddKeyTypeInProjectBranches underTest = new AddKeyTypeInProjectBranches(dbTester.database()); | |||||
@Test | |||||
public void column_is_added_to_table() throws SQLException { | |||||
underTest.execute(); | |||||
dbTester.assertColumnDefinition(TABLE_NAME, "key_type", VARCHAR, null, true); | |||||
} | |||||
@Test | |||||
public void migration_is_not_reentrant() throws SQLException { | |||||
underTest.execute(); | |||||
expectedException.expect(IllegalStateException.class); | |||||
underTest.execute(); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import org.sonar.db.CoreDbTester; | |||||
import static java.sql.Types.BLOB; | |||||
import static org.sonar.server.platform.db.migration.version.v71.AddPullRequestBinaryInProjectBranches.COLUMN_NAME; | |||||
import static org.sonar.server.platform.db.migration.version.v71.AddPullRequestBinaryInProjectBranches.TABLE_NAME; | |||||
public class AddPullRequestBinaryInProjectBranchesTest { | |||||
@Rule | |||||
public final CoreDbTester dbTester = CoreDbTester.createForSchema(AddPullRequestBinaryInProjectBranchesTest.class, TABLE_NAME + ".sql"); | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private AddPullRequestBinaryInProjectBranches underTest = new AddPullRequestBinaryInProjectBranches(dbTester.database()); | |||||
@Test | |||||
public void column_is_added_to_table() throws SQLException { | |||||
underTest.execute(); | |||||
dbTester.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, BLOB, null, true); | |||||
} | |||||
@Test | |||||
public void migration_is_not_reentrant() throws SQLException { | |||||
underTest.execute(); | |||||
expectedException.expect(IllegalStateException.class); | |||||
underTest.execute(); | |||||
} | |||||
} |
@Test | @Test | ||||
public void verify_migration_count() { | public void verify_migration_count() { | ||||
verifyMigrationCount(underTest, 16); | |||||
verifyMigrationCount(underTest, 22); | |||||
} | } | ||||
} | } |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import java.sql.Types; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import org.sonar.db.CoreDbTester; | |||||
import org.sonar.scanner.protocol.output.ScannerReport; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
public class IncreaseBranchTypeSizeForPullRequestTest { | |||||
private static final String TABLE_NAME = "project_branches"; | |||||
@Rule | |||||
public CoreDbTester db = CoreDbTester.createForSchema(IncreaseBranchTypeSizeForPullRequestTest.class, "project_branches.sql"); | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private IncreaseBranchTypeSizeForPullRequest underTest = new IncreaseBranchTypeSizeForPullRequest(db.database()); | |||||
@Test | |||||
public void cannot_insert_PULL_REQUEST_type_before_migration() { | |||||
expectedException.expect(IllegalStateException.class); | |||||
insertRow(); | |||||
} | |||||
@Test | |||||
public void can_insert_PULL_REQUEST_after_execute() throws SQLException { | |||||
underTest.execute(); | |||||
assertThat(db.countRowsOfTable(TABLE_NAME)).isEqualTo(0); | |||||
insertRow(); | |||||
assertThat(db.countRowsOfTable(TABLE_NAME)).isEqualTo(1); | |||||
} | |||||
private void insertRow() { | |||||
db.executeInsert( | |||||
"PROJECT_BRANCHES", | |||||
"UUID", "dummy_uuid", | |||||
"PROJECT_UUID", "dummy_project_uuid", | |||||
"KEE", "dummy_key", | |||||
"CREATED_AT", 456789, | |||||
"UPDATED_AT", 456789, | |||||
"BRANCH_TYPE", "PULL_REQUEST"); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import java.sql.Types; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import org.sonar.api.rule.RuleScope; | |||||
import org.sonar.db.CoreDbTester; | |||||
import static org.sonar.server.platform.db.migration.version.v71.MakeKeyTypeNotNullableInProjectBranches.TABLE_NAME; | |||||
public class MakeKeyTypeNotNullableInProjectBranchesTest { | |||||
@Rule | |||||
public CoreDbTester db = CoreDbTester.createForSchema(MakeKeyTypeNotNullableInProjectBranchesTest.class, "project_branches.sql"); | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private MakeKeyTypeNotNullableInProjectBranches underTest = new MakeKeyTypeNotNullableInProjectBranches(db.database()); | |||||
@Test | |||||
public void execute_makes_column_not_null() throws SQLException { | |||||
db.assertColumnDefinition(TABLE_NAME, "key_type", Types.VARCHAR, null, true); | |||||
insertRow(); | |||||
underTest.execute(); | |||||
db.assertColumnDefinition(TABLE_NAME, "key_type", Types.VARCHAR, null, false); | |||||
} | |||||
private void insertRow() { | |||||
db.executeInsert( | |||||
"PROJECT_BRANCHES", | |||||
"UUID", "dummy_uuid", | |||||
"PROJECT_UUID", "dummy_project_uuid", | |||||
"KEE", "dummy_key", | |||||
"KEY_TYPE", "BRANCH", | |||||
"CREATED_AT", 456789, | |||||
"UPDATED_AT", 456789, | |||||
"BRANCH_TYPE", "BRANCH"); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import org.sonar.db.CoreDbTester; | |||||
import static org.sonar.server.platform.db.migration.version.v71.ReplaceIndexInProjectBranches.NEW_INDEX_NAME; | |||||
import static org.sonar.server.platform.db.migration.version.v71.ReplaceIndexInProjectBranches.KEE_COLUMN; | |||||
import static org.sonar.server.platform.db.migration.version.v71.ReplaceIndexInProjectBranches.KEY_TYPE_COLUMN; | |||||
import static org.sonar.server.platform.db.migration.version.v71.ReplaceIndexInProjectBranches.PROJECT_UUID_COLUMN; | |||||
import static org.sonar.server.platform.db.migration.version.v71.ReplaceIndexInProjectBranches.TABLE_NAME; | |||||
public class ReplaceIndexInProjectBranchesTest { | |||||
@Rule | |||||
public final CoreDbTester dbTester = CoreDbTester.createForSchema(ReplaceIndexInProjectBranchesTest.class, "project_branches.sql"); | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private ReplaceIndexInProjectBranches underTest = new ReplaceIndexInProjectBranches(dbTester.database()); | |||||
@Test | |||||
public void column_is_part_of_index() throws SQLException { | |||||
underTest.execute(); | |||||
dbTester.assertUniqueIndex(TABLE_NAME, NEW_INDEX_NAME, PROJECT_UUID_COLUMN.getName(), KEE_COLUMN.getName(), KEY_TYPE_COLUMN.getName()); | |||||
} | |||||
@Test | |||||
public void adding_pr_with_same_key_as_existing_branch_fails_before_migration() { | |||||
expectedException.expect(IllegalStateException.class); | |||||
String key = "feature/foo"; | |||||
insertBranch(1, key); | |||||
insertPullRequest(2, key); | |||||
} | |||||
@Test | |||||
public void adding_pr_with_same_key_as_existing_branch_works_after_migration() throws SQLException { | |||||
underTest.execute(); | |||||
String key = "feature/foo"; | |||||
insertBranch(1, key); | |||||
insertPullRequest(2, key); | |||||
} | |||||
private void insertBranch(int id, String name) { | |||||
insertRow(id, "SHORT", name, "BRANCH"); | |||||
} | |||||
private void insertPullRequest(int id, String pullRequestId) { | |||||
insertRow(id, "PULL_REQUEST", pullRequestId, "PULL_REQUEST"); | |||||
} | |||||
private void insertRow(int id, String branchType, String key, String keyType) { | |||||
dbTester.executeInsert( | |||||
"PROJECT_BRANCHES", | |||||
"UUID", "dummy_uuid" + id, | |||||
"PROJECT_UUID", "dummy_project_uuid", | |||||
"KEE", key, | |||||
"KEY_TYPE", keyType, | |||||
"CREATED_AT", 456789 + id, | |||||
"UPDATED_AT", 456789 + id, | |||||
"BRANCH_TYPE", branchType); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.platform.db.migration.version.v71; | |||||
import java.sql.SQLException; | |||||
import javax.annotation.Nullable; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import org.sonar.api.utils.System2; | |||||
import org.sonar.api.utils.internal.TestSystem2; | |||||
import org.sonar.db.CoreDbTester; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
import static org.sonar.server.platform.db.migration.version.v71.SetKeyTypeToBranchInProjectBranches.DEFAULT_KEY_TYPE; | |||||
import static org.sonar.server.platform.db.migration.version.v71.SetKeyTypeToBranchInProjectBranches.TABLE_NAME; | |||||
public class SetKeyTypeToBranchInProjectBranchesTest { | |||||
private static final long PAST = 10_000_000_000L; | |||||
private static final long NOW = 50_000_000_000L; | |||||
private System2 system2 = new TestSystem2().setNow(NOW); | |||||
@Rule | |||||
public final CoreDbTester dbTester = CoreDbTester.createForSchema(SetKeyTypeToBranchInProjectBranchesTest.class, "project_branches.sql"); | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private SetKeyTypeToBranchInProjectBranches underTest = new SetKeyTypeToBranchInProjectBranches(dbTester.database(), system2); | |||||
@Test | |||||
public void has_no_effect_if_table_project_branches_is_empty() throws SQLException { | |||||
underTest.execute(); | |||||
assertThat(dbTester.countRowsOfTable(TABLE_NAME)).isEqualTo(0); | |||||
} | |||||
@Test | |||||
public void updates_rows_to_BRANCH() throws SQLException { | |||||
insertRow(1, "SHORT"); | |||||
insertRow(2, "LONG"); | |||||
insertRow(3, "SHORT"); | |||||
insertRow(4, "LONG"); | |||||
String countUpdatedAtSQL = "select count(uuid) from " + TABLE_NAME + " where updated_at = "; | |||||
assertThat(countRowsWithValue(null)).isEqualTo(4); | |||||
assertThat(countRowsWithValue(DEFAULT_KEY_TYPE)).isEqualTo(0); | |||||
assertThat(dbTester.countSql(countUpdatedAtSQL + PAST)).isEqualTo(4); | |||||
underTest.execute(); | |||||
assertThat(countRowsWithValue(null)).isEqualTo(0); | |||||
assertThat(countRowsWithValue(DEFAULT_KEY_TYPE)).isEqualTo(4); | |||||
assertThat(dbTester.countSql(countUpdatedAtSQL + NOW)).isEqualTo(4); | |||||
} | |||||
@Test | |||||
public void execute_is_reentreant() throws SQLException { | |||||
insertRow(1, "SHORT"); | |||||
insertRow(2, "LONG"); | |||||
insertRow(3, "SHORT"); | |||||
insertRow(4, "LONG"); | |||||
underTest.execute(); | |||||
underTest.execute(); | |||||
assertThat(countRowsWithValue(null)).isEqualTo(0); | |||||
assertThat(countRowsWithValue(DEFAULT_KEY_TYPE)).isEqualTo(4); | |||||
} | |||||
private int countRowsWithValue(@Nullable String value) { | |||||
if (value == null) { | |||||
return dbTester.countSql("select count(1) from " + TABLE_NAME + " where key_type is null"); | |||||
} | |||||
return dbTester.countSql("select count(1) from " + TABLE_NAME + " where key_type = '" + value + "'"); | |||||
} | |||||
private void insertRow(int id, String branchType) { | |||||
dbTester.executeInsert( | |||||
"PROJECT_BRANCHES", | |||||
"UUID", "dummy_uuid" + id, | |||||
"PROJECT_UUID", "dummy_project_uuid" + id, | |||||
"KEE", "dummy_key" + id, | |||||
"CREATED_AT", PAST, | |||||
"UPDATED_AT", PAST, | |||||
"BRANCH_TYPE", branchType); | |||||
} | |||||
} |
CREATE TABLE "PROJECT_BRANCHES" ( | |||||
"UUID" VARCHAR(50) NOT NULL PRIMARY KEY, | |||||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||||
"KEE" VARCHAR(255) NOT NULL, | |||||
"BRANCH_TYPE" VARCHAR(12), | |||||
"MERGE_BRANCH_UUID" VARCHAR(50), | |||||
"CREATED_AT" BIGINT NOT NULL, | |||||
"UPDATED_AT" BIGINT NOT NULL | |||||
); | |||||
CREATE UNIQUE INDEX "PK_PROJECT_BRANCHES" ON "PROJECT_BRANCHES" ("UUID"); | |||||
CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE" ON "PROJECT_BRANCHES" ("PROJECT_UUID", "KEE"); |
CREATE TABLE "PROJECT_BRANCHES" ( | |||||
"UUID" VARCHAR(50) NOT NULL PRIMARY KEY, | |||||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||||
"KEE" VARCHAR(255) NOT NULL, | |||||
"KEY_TYPE" VARCHAR(12) NOT NULL, | |||||
"BRANCH_TYPE" VARCHAR(12), | |||||
"MERGE_BRANCH_UUID" VARCHAR(50), | |||||
"CREATED_AT" BIGINT NOT NULL, | |||||
"UPDATED_AT" BIGINT NOT NULL | |||||
); | |||||
CREATE UNIQUE INDEX "PK_PROJECT_BRANCHES" ON "PROJECT_BRANCHES" ("UUID"); | |||||
CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE" ON "PROJECT_BRANCHES" ("PROJECT_UUID", "KEE", "KEY_TYPE"); |
CREATE TABLE "PROJECT_BRANCHES" ( | |||||
"UUID" VARCHAR(50) NOT NULL PRIMARY KEY, | |||||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||||
"KEE" VARCHAR(255) NOT NULL, | |||||
"BRANCH_TYPE" VARCHAR(5), | |||||
"MERGE_BRANCH_UUID" VARCHAR(50), | |||||
"CREATED_AT" BIGINT NOT NULL, | |||||
"UPDATED_AT" BIGINT NOT NULL | |||||
); | |||||
CREATE UNIQUE INDEX "PK_PROJECT_BRANCHES" ON "PROJECT_BRANCHES" ("UUID"); | |||||
CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE" ON "PROJECT_BRANCHES" ("PROJECT_UUID", "KEE"); |
CREATE TABLE "PROJECT_BRANCHES" ( | |||||
"UUID" VARCHAR(50) NOT NULL PRIMARY KEY, | |||||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||||
"KEE" VARCHAR(255) NOT NULL, | |||||
"KEY_TYPE" VARCHAR(12) NULL, | |||||
"BRANCH_TYPE" VARCHAR(12), | |||||
"MERGE_BRANCH_UUID" VARCHAR(50), | |||||
"CREATED_AT" BIGINT NOT NULL, | |||||
"UPDATED_AT" BIGINT NOT NULL | |||||
); | |||||
CREATE UNIQUE INDEX "PK_PROJECT_BRANCHES" ON "PROJECT_BRANCHES" ("UUID"); | |||||
CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE" ON "PROJECT_BRANCHES" ("PROJECT_UUID", "KEE"); |
CREATE TABLE "PROJECT_BRANCHES" ( | |||||
"UUID" VARCHAR(50) NOT NULL PRIMARY KEY, | |||||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||||
"KEE" VARCHAR(255) NOT NULL, | |||||
"KEY_TYPE" VARCHAR(12) NOT NULL, | |||||
"BRANCH_TYPE" VARCHAR(12), | |||||
"MERGE_BRANCH_UUID" VARCHAR(50), | |||||
"CREATED_AT" BIGINT NOT NULL, | |||||
"UPDATED_AT" BIGINT NOT NULL | |||||
); | |||||
CREATE UNIQUE INDEX "PK_PROJECT_BRANCHES" ON "PROJECT_BRANCHES" ("UUID"); | |||||
CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE" ON "PROJECT_BRANCHES" ("PROJECT_UUID", "KEE"); |
CREATE TABLE "PROJECT_BRANCHES" ( | |||||
"UUID" VARCHAR(50) NOT NULL PRIMARY KEY, | |||||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||||
"KEE" VARCHAR(255) NOT NULL, | |||||
"KEY_TYPE" VARCHAR(12) NULL, | |||||
"BRANCH_TYPE" VARCHAR(12), | |||||
"MERGE_BRANCH_UUID" VARCHAR(50), | |||||
"CREATED_AT" BIGINT NOT NULL, | |||||
"UPDATED_AT" BIGINT NOT NULL | |||||
); | |||||
CREATE UNIQUE INDEX "PK_PROJECT_BRANCHES" ON "PROJECT_BRANCHES" ("UUID"); | |||||
CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE" ON "PROJECT_BRANCHES" ("PROJECT_UUID", "KEE"); |
import org.sonar.api.config.Settings; | import org.sonar.api.config.Settings; | ||||
import org.sonar.api.config.internal.ConfigurationBridge; | import org.sonar.api.config.internal.ConfigurationBridge; | ||||
import org.sonar.db.DbClient; | import org.sonar.db.DbClient; | ||||
import org.sonar.db.component.BranchType; | |||||
import org.sonar.server.computation.task.projectanalysis.analysis.Branch; | import org.sonar.server.computation.task.projectanalysis.analysis.Branch; | ||||
import org.sonar.server.settings.ChildSettings; | import org.sonar.server.settings.ChildSettings; | ||||
import static org.sonar.db.component.ComponentDto.generateBranchKey; | import static org.sonar.db.component.ComponentDto.generateBranchKey; | ||||
import static org.sonar.db.component.ComponentDto.generatePullRequestKey; | |||||
@ComputeEngineSide | @ComputeEngineSide | ||||
public class ProjectConfigurationFactory { | public class ProjectConfigurationFactory { | ||||
public Configuration newProjectConfiguration(String projectKey, Branch branch) { | public Configuration newProjectConfiguration(String projectKey, Branch branch) { | ||||
Settings projectSettings = new ChildSettings(globalSettings); | Settings projectSettings = new ChildSettings(globalSettings); | ||||
addSettings(projectSettings, projectKey); | addSettings(projectSettings, projectKey); | ||||
addSettings(projectSettings, generateBranchKey(projectKey, branch.getName())); | |||||
if (branch.getType() == BranchType.PULL_REQUEST) { | |||||
addSettings(projectSettings, generatePullRequestKey(projectKey, branch.getPullRequestId())); | |||||
} else { | |||||
addSettings(projectSettings, generateBranchKey(projectKey, branch.getName())); | |||||
} | |||||
return new ConfigurationBridge(projectSettings); | return new ConfigurationBridge(projectSettings); | ||||
} | } | ||||
import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY; | import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.TECHNICAL_DEBT_KEY; | import static org.sonar.api.measures.CoreMetrics.TECHNICAL_DEBT_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY; | import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; | |||||
import static org.sonar.api.measures.Metric.Level; | import static org.sonar.api.measures.Metric.Level; | ||||
import static org.sonar.api.measures.Metric.ValueType; | import static org.sonar.api.measures.Metric.ValueType; | ||||
import static org.sonar.api.measures.Metric.Level.ERROR; | import static org.sonar.api.measures.Metric.Level.ERROR; | ||||
import static org.sonar.server.computation.task.projectanalysis.qualitymodel.Rating.valueOf; | import static org.sonar.server.computation.task.projectanalysis.qualitymodel.Rating.valueOf; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | 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.sonarqube.ws.MediaTypes.SVG; | import static org.sonarqube.ws.MediaTypes.SVG; | ||||
public class MeasureAction implements ProjectBadgesWsAction { | public class MeasureAction implements ProjectBadgesWsAction { | ||||
private static final String PARAM_PROJECT = "project"; | private static final String PARAM_PROJECT = "project"; | ||||
private static final String PARAM_BRANCH = "branch"; | private static final String PARAM_BRANCH = "branch"; | ||||
private static final String PARAM_PULL_REQUEST = "pullRequest"; | |||||
private static final String PARAM_METRIC = "metric"; | private static final String PARAM_METRIC = "metric"; | ||||
private static final Map<String, String> METRIC_NAME_BY_KEY = ImmutableMap.<String, String>builder() | private static final Map<String, String> METRIC_NAME_BY_KEY = ImmutableMap.<String, String>builder() | ||||
.createParam(PARAM_BRANCH) | .createParam(PARAM_BRANCH) | ||||
.setDescription("Branch key") | .setDescription("Branch key") | ||||
.setExampleValue(KEY_BRANCH_EXAMPLE_001); | .setExampleValue(KEY_BRANCH_EXAMPLE_001); | ||||
action | |||||
.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001); | |||||
action.createParam(PARAM_METRIC) | action.createParam(PARAM_METRIC) | ||||
.setDescription("Metric key") | .setDescription("Metric key") | ||||
.setRequired(true) | .setRequired(true) | ||||
response.stream().setMediaType(SVG); | response.stream().setMediaType(SVG); | ||||
String projectKey = request.mandatoryParam(PARAM_PROJECT); | String projectKey = request.mandatoryParam(PARAM_PROJECT); | ||||
String branch = request.param(PARAM_BRANCH); | String branch = request.param(PARAM_BRANCH); | ||||
String pullRequest = request.param(PARAM_PULL_REQUEST); | |||||
String metricKey = request.mandatoryParam(PARAM_METRIC); | String metricKey = request.mandatoryParam(PARAM_METRIC); | ||||
try (DbSession dbSession = dbClient.openSession(false)) { | try (DbSession dbSession = dbClient.openSession(false)) { | ||||
ComponentDto project = componentFinder.getByKeyAndOptionalBranch(dbSession, projectKey, branch); | |||||
ComponentDto project = componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, projectKey, branch, pullRequest); | |||||
userSession.checkComponentPermission(USER, project); | userSession.checkComponentPermission(USER, project); | ||||
MetricDto metric = dbClient.metricDao().selectByKey(dbSession, metricKey); | MetricDto metric = dbClient.metricDao().selectByKey(dbSession, metricKey); | ||||
checkState(metric != null && metric.isEnabled(), "Metric '%s' hasn't been found", metricKey); | checkState(metric != null && metric.isEnabled(), "Metric '%s' hasn't been found", metricKey); |
import static org.sonar.api.web.UserRole.USER; | import static org.sonar.api.web.UserRole.USER; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | 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.sonarqube.ws.MediaTypes.SVG; | import static org.sonarqube.ws.MediaTypes.SVG; | ||||
public class QualityGateAction implements ProjectBadgesWsAction { | public class QualityGateAction implements ProjectBadgesWsAction { | ||||
private static final String PARAM_PROJECT = "project"; | private static final String PARAM_PROJECT = "project"; | ||||
private static final String PARAM_BRANCH = "branch"; | private static final String PARAM_BRANCH = "branch"; | ||||
private static final String PARAM_PULL_REQUEST = "pullRequest"; | |||||
private final UserSession userSession; | private final UserSession userSession; | ||||
private final DbClient dbClient; | private final DbClient dbClient; | ||||
.createParam(PARAM_BRANCH) | .createParam(PARAM_BRANCH) | ||||
.setDescription("Branch key") | .setDescription("Branch key") | ||||
.setExampleValue(KEY_BRANCH_EXAMPLE_001); | .setExampleValue(KEY_BRANCH_EXAMPLE_001); | ||||
action | |||||
.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001); | |||||
} | } | ||||
@Override | @Override | ||||
response.stream().setMediaType(SVG); | response.stream().setMediaType(SVG); | ||||
String projectKey = request.mandatoryParam(PARAM_PROJECT); | String projectKey = request.mandatoryParam(PARAM_PROJECT); | ||||
String branch = request.param(PARAM_BRANCH); | String branch = request.param(PARAM_BRANCH); | ||||
String pullRequest = request.param(PARAM_PULL_REQUEST); | |||||
try (DbSession dbSession = dbClient.openSession(false)) { | try (DbSession dbSession = dbClient.openSession(false)) { | ||||
ComponentDto project = componentFinder.getByKeyAndOptionalBranch(dbSession, projectKey, branch); | |||||
ComponentDto project = componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, projectKey, branch, pullRequest); | |||||
userSession.checkComponentPermission(USER, project); | userSession.checkComponentPermission(USER, project); | ||||
Level qualityGateStatus = getQualityGate(dbSession, project); | Level qualityGateStatus = getQualityGate(dbSession, project); | ||||
write(svgGenerator.generateQualityGate(qualityGateStatus), response.stream().output(), UTF_8); | write(svgGenerator.generateQualityGate(qualityGateStatus), response.stream().output(), UTF_8); |
import static org.sonar.core.util.Protobuf.setNullable; | import static org.sonar.core.util.Protobuf.setNullable; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | 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.sonar.server.ws.WsUtils.writeProtobuf; | ||||
public class ProjectAction implements BatchWsAction { | public class ProjectAction implements BatchWsAction { | ||||
private static final String PARAM_PROFILE = "profile"; | private static final String PARAM_PROFILE = "profile"; | ||||
private static final String PARAM_ISSUES_MODE = "issues_mode"; | private static final String PARAM_ISSUES_MODE = "issues_mode"; | ||||
private static final String PARAM_BRANCH = "branch"; | private static final String PARAM_BRANCH = "branch"; | ||||
private static final String PARAM_PULL_REQUEST = "pullRequest"; | |||||
private final ProjectDataLoader projectDataLoader; | private final ProjectDataLoader projectDataLoader; | ||||
.setSince("6.6") | .setSince("6.6") | ||||
.setDescription("Branch key") | .setDescription("Branch key") | ||||
.setExampleValue(KEY_BRANCH_EXAMPLE_001); | .setExampleValue(KEY_BRANCH_EXAMPLE_001); | ||||
action | |||||
.createParam(PARAM_PULL_REQUEST) | |||||
.setSince("7.1") | |||||
.setDescription("Pull request id") | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001); | |||||
} | } | ||||
@Override | @Override | ||||
.setModuleKey(wsRequest.mandatoryParam(PARAM_KEY)) | .setModuleKey(wsRequest.mandatoryParam(PARAM_KEY)) | ||||
.setProfileName(wsRequest.param(PARAM_PROFILE)) | .setProfileName(wsRequest.param(PARAM_PROFILE)) | ||||
.setIssuesMode(wsRequest.mandatoryParamAsBoolean(PARAM_ISSUES_MODE)) | .setIssuesMode(wsRequest.mandatoryParamAsBoolean(PARAM_ISSUES_MODE)) | ||||
.setBranch(wsRequest.param(PARAM_BRANCH))); | |||||
.setBranch(wsRequest.param(PARAM_BRANCH)) | |||||
.setPullRequest(wsRequest.param(PARAM_PULL_REQUEST))); | |||||
WsProjectResponse projectResponse = buildResponse(data); | WsProjectResponse projectResponse = buildResponse(data); | ||||
writeProtobuf(projectResponse, wsRequest, wsResponse); | writeProtobuf(projectResponse, wsRequest, wsResponse); |
ProjectRepositories data = new ProjectRepositories(); | ProjectRepositories data = new ProjectRepositories(); | ||||
String moduleKey = query.getModuleKey(); | String moduleKey = query.getModuleKey(); | ||||
String branch = query.getBranch(); | String branch = query.getBranch(); | ||||
String pullRequest = query.getPullRequest(); | |||||
ComponentDto mainModule = componentFinder.getByKey(session, moduleKey); | ComponentDto mainModule = componentFinder.getByKey(session, moduleKey); | ||||
checkRequest(isProjectOrModule(mainModule), "Key '%s' belongs to a component which is not a Project", moduleKey); | checkRequest(isProjectOrModule(mainModule), "Key '%s' belongs to a component which is not a Project", moduleKey); | ||||
boolean hasScanPerm = userSession.hasComponentPermission(SCAN_EXECUTION, mainModule) || | boolean hasScanPerm = userSession.hasComponentPermission(SCAN_EXECUTION, mainModule) || | ||||
userSession.hasPermission(OrganizationPermission.SCAN, mainModule.getOrganizationUuid()); | userSession.hasPermission(OrganizationPermission.SCAN, mainModule.getOrganizationUuid()); | ||||
boolean hasBrowsePerm = userSession.hasComponentPermission(USER, mainModule); | boolean hasBrowsePerm = userSession.hasComponentPermission(USER, mainModule); | ||||
checkPermission(query.isIssuesMode(), hasScanPerm, hasBrowsePerm); | checkPermission(query.isIssuesMode(), hasScanPerm, hasBrowsePerm); | ||||
ComponentDto branchOrMainModule = branch == null ? mainModule : componentFinder.getByKeyAndBranch(session, moduleKey, branch); | |||||
ComponentDto branchOrMainModule = (branch == null && pullRequest == null) ? mainModule | |||||
: componentFinder.getByKeyAndOptionalBranchOrPullRequest(session, moduleKey, branch, pullRequest); | |||||
ComponentDto project = getProject(branchOrMainModule, session); | ComponentDto project = getProject(branchOrMainModule, session); | ||||
if (!project.getKey().equals(branchOrMainModule.getKey())) { | if (!project.getKey().equals(branchOrMainModule.getKey())) { |
private String profileName; | private String profileName; | ||||
private boolean issuesMode; | private boolean issuesMode; | ||||
private String branch; | private String branch; | ||||
private String pullRequest; | |||||
private ProjectDataQuery() { | private ProjectDataQuery() { | ||||
// No direct call | // No direct call | ||||
return this; | return this; | ||||
} | } | ||||
@CheckForNull | |||||
public String getPullRequest() { | |||||
return pullRequest; | |||||
} | |||||
public ProjectDataQuery setPullRequest(@Nullable String pullRequest) { | |||||
this.pullRequest = pullRequest; | |||||
return this; | |||||
} | |||||
public static ProjectDataQuery create() { | public static ProjectDataQuery create() { | ||||
return new ProjectDataQuery(); | return new ProjectDataQuery(); | ||||
} | } |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.branch.pr.ws; | |||||
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.server.ws.WebService.NewController; | |||||
import org.sonar.api.web.UserRole; | |||||
import org.sonar.db.DbClient; | |||||
import org.sonar.db.DbSession; | |||||
import org.sonar.db.component.BranchDto; | |||||
import org.sonar.db.component.ComponentDto; | |||||
import org.sonar.server.component.ComponentCleanerService; | |||||
import org.sonar.server.component.ComponentFinder; | |||||
import org.sonar.server.exceptions.NotFoundException; | |||||
import org.sonar.server.user.UserSession; | |||||
import static org.sonar.db.component.BranchType.PULL_REQUEST; | |||||
import static org.sonar.server.branch.pr.ws.PullRequestsWs.addProjectParam; | |||||
import static org.sonar.server.branch.pr.ws.PullRequestsWs.addPullRequestParam; | |||||
import static org.sonar.server.branch.pr.ws.PullRequestsWsParameters.PARAM_PROJECT; | |||||
import static org.sonar.server.branch.pr.ws.PullRequestsWsParameters.PARAM_PULL_REQUEST; | |||||
import static org.sonar.server.branch.ws.ProjectBranchesParameters.ACTION_DELETE; | |||||
public class DeleteAction implements PullRequestWsAction { | |||||
private final DbClient dbClient; | |||||
private final UserSession userSession; | |||||
private final ComponentCleanerService componentCleanerService; | |||||
private final ComponentFinder componentFinder; | |||||
public DeleteAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, ComponentCleanerService componentCleanerService) { | |||||
this.dbClient = dbClient; | |||||
this.componentFinder = componentFinder; | |||||
this.userSession = userSession; | |||||
this.componentCleanerService = componentCleanerService; | |||||
} | |||||
@Override | |||||
public void define(NewController context) { | |||||
WebService.NewAction action = context.createAction(ACTION_DELETE) | |||||
.setSince("7.1") | |||||
.setDescription("Delete a pull request.<br/>" + | |||||
"Requires 'Administer' rights on the specified project.") | |||||
.setPost(true) | |||||
.setHandler(this); | |||||
addProjectParam(action); | |||||
addPullRequestParam(action); | |||||
} | |||||
@Override | |||||
public void handle(Request request, Response response) throws Exception { | |||||
userSession.checkLoggedIn(); | |||||
String projectKey = request.mandatoryParam(PARAM_PROJECT); | |||||
String pullRequestId = request.mandatoryParam(PARAM_PULL_REQUEST); | |||||
try (DbSession dbSession = dbClient.openSession(false)) { | |||||
ComponentDto project = componentFinder.getRootComponentByUuidOrKey(dbSession, null, projectKey); | |||||
checkPermission(project); | |||||
BranchDto pullRequest = dbClient.branchDao().selectByPullRequestKey(dbSession, project.uuid(), pullRequestId) | |||||
.filter(branch -> branch.getBranchType() == PULL_REQUEST) | |||||
.orElseThrow(() -> new NotFoundException(String.format("Pull request '%s' is not found for project '%s'", pullRequestId, projectKey))); | |||||
ComponentDto branchComponent = componentFinder.getByKeyAndPullRequest(dbSession, projectKey, pullRequest.getKey()); | |||||
componentCleanerService.deleteBranch(dbSession, branchComponent); | |||||
response.noContent(); | |||||
} | |||||
} | |||||
private void checkPermission(ComponentDto project) { | |||||
userSession.checkComponentPermission(UserRole.ADMIN, project); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.branch.pr.ws; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.Objects; | |||||
import java.util.Optional; | |||||
import java.util.function.Function; | |||||
import javax.annotation.Nullable; | |||||
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.BranchDto; | |||||
import org.sonar.db.component.ComponentDto; | |||||
import org.sonar.db.component.SnapshotDto; | |||||
import org.sonar.db.protobuf.DbProjectBranches; | |||||
import org.sonar.server.component.ComponentFinder; | |||||
import org.sonar.server.issue.index.BranchStatistics; | |||||
import org.sonar.server.issue.index.IssueIndex; | |||||
import org.sonar.server.user.UserSession; | |||||
import org.sonarqube.ws.ProjectPullRequests; | |||||
import static com.google.common.base.Preconditions.checkArgument; | |||||
import static java.util.Objects.requireNonNull; | |||||
import static org.sonar.api.resources.Qualifiers.PROJECT; | |||||
import static org.sonar.api.utils.DateUtils.formatDateTime; | |||||
import static org.sonar.core.util.Protobuf.setNullable; | |||||
import static org.sonar.core.util.stream.MoreCollectors.toList; | |||||
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; | |||||
import static org.sonar.db.component.BranchType.PULL_REQUEST; | |||||
import static org.sonar.server.branch.pr.ws.PullRequestsWs.addProjectParam; | |||||
import static org.sonar.server.branch.pr.ws.PullRequestsWsParameters.PARAM_PROJECT; | |||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||||
public class ListAction implements PullRequestWsAction { | |||||
private final DbClient dbClient; | |||||
private final UserSession userSession; | |||||
private final ComponentFinder componentFinder; | |||||
private final IssueIndex issueIndex; | |||||
public ListAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder, IssueIndex issueIndex) { | |||||
this.dbClient = dbClient; | |||||
this.userSession = userSession; | |||||
this.componentFinder = componentFinder; | |||||
this.issueIndex = issueIndex; | |||||
} | |||||
@Override | |||||
public void define(WebService.NewController context) { | |||||
WebService.NewAction action = context.createAction("list") | |||||
.setSince("7.1") | |||||
.setDescription("List the pull requests of a project.<br/>" + | |||||
"Requires 'Administer' rights on the specified project.") | |||||
.setResponseExample(getClass().getResource("list-example.json")) | |||||
.setHandler(this); | |||||
addProjectParam(action); | |||||
} | |||||
@Override | |||||
public void handle(Request request, Response response) throws Exception { | |||||
String projectKey = request.mandatoryParam(PARAM_PROJECT); | |||||
try (DbSession dbSession = dbClient.openSession(false)) { | |||||
ComponentDto project = componentFinder.getByKey(dbSession, projectKey); | |||||
userSession.checkComponentPermission(UserRole.USER, project); | |||||
checkArgument(project.isEnabled() && PROJECT.equals(project.qualifier()), "Invalid project key"); | |||||
List<BranchDto> pullRequests = dbClient.branchDao().selectByComponent(dbSession, project).stream() | |||||
.filter(b -> b.getBranchType() == PULL_REQUEST) | |||||
.collect(toList()); | |||||
List<String> pullRequestUuids = pullRequests.stream().map(BranchDto::getUuid).collect(toList()); | |||||
Map<String, BranchDto> mergeBranchesByUuid = dbClient.branchDao() | |||||
.selectByUuids(dbSession, pullRequests.stream().map(BranchDto::getMergeBranchUuid).filter(Objects::nonNull).collect(toList())) | |||||
.stream().collect(uniqueIndex(BranchDto::getUuid)); | |||||
Map<String, BranchStatistics> branchStatisticsByBranchUuid = issueIndex.searchBranchStatistics(project.uuid(), pullRequestUuids).stream() | |||||
.collect(uniqueIndex(BranchStatistics::getBranchUuid, Function.identity())); | |||||
Map<String, String> analysisDateByBranchUuid = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, pullRequestUuids).stream() | |||||
.collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> formatDateTime(s.getCreatedAt()))); | |||||
ProjectPullRequests.ListWsResponse.Builder protobufResponse = ProjectPullRequests.ListWsResponse.newBuilder(); | |||||
pullRequests | |||||
.forEach(b -> addPullRequest(protobufResponse, b, mergeBranchesByUuid, branchStatisticsByBranchUuid.get(b.getUuid()), | |||||
analysisDateByBranchUuid.get(b.getUuid()))); | |||||
writeProtobuf(protobufResponse.build(), request, response); | |||||
} | |||||
} | |||||
private static void addPullRequest(ProjectPullRequests.ListWsResponse.Builder response, BranchDto branch, Map<String, BranchDto> mergeBranchesByUuid, | |||||
BranchStatistics branchStatistics, @Nullable String analysisDate) { | |||||
Optional<BranchDto> mergeBranch = Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid())); | |||||
ProjectPullRequests.PullRequest.Builder builder = ProjectPullRequests.PullRequest.newBuilder(); | |||||
builder.setKey(branch.getKey()); | |||||
DbProjectBranches.PullRequestData pullRequestData = requireNonNull(branch.getPullRequestData(), "Pull request data should be available for branch type PULL_REQUEST"); | |||||
builder.setBranch(pullRequestData.getBranch()); | |||||
builder.setUrl(pullRequestData.getUrl()); | |||||
builder.setTitle(pullRequestData.getTitle()); | |||||
if (mergeBranch.isPresent()) { | |||||
String mergeBranchKey = mergeBranch.get().getKey(); | |||||
builder.setBase(mergeBranchKey); | |||||
} else { | |||||
builder.setIsOrphan(true); | |||||
} | |||||
setNullable(analysisDate, builder::setAnalysisDate); | |||||
setBranchStatus(builder, branchStatistics); | |||||
response.addPullRequests(builder); | |||||
} | |||||
private static void setBranchStatus(ProjectPullRequests.PullRequest.Builder builder, @Nullable BranchStatistics branchStatistics) { | |||||
ProjectPullRequests.Status.Builder statusBuilder = ProjectPullRequests.Status.newBuilder(); | |||||
statusBuilder.setBugs(branchStatistics == null ? 0L : branchStatistics.getBugs()); | |||||
statusBuilder.setVulnerabilities(branchStatistics == null ? 0L : branchStatistics.getVulnerabilities()); | |||||
statusBuilder.setCodeSmells(branchStatistics == null ? 0L : branchStatistics.getCodeSmells()); | |||||
builder.setStatus(statusBuilder); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.branch.pr.ws; | |||||
import org.sonar.server.ws.WsAction; | |||||
public interface PullRequestWsAction extends WsAction { | |||||
// marker interface | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.branch.pr.ws; | |||||
import org.sonar.core.platform.Module; | |||||
public class PullRequestWsModule extends Module { | |||||
@Override | |||||
protected void configureModule() { | |||||
add( | |||||
ListAction.class, | |||||
DeleteAction.class, | |||||
PullRequestsWs.class); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.branch.pr.ws; | |||||
import org.sonar.api.server.ws.WebService; | |||||
import static java.util.Arrays.stream; | |||||
import static org.sonar.server.branch.pr.ws.PullRequestsWsParameters.PARAM_PROJECT; | |||||
import static org.sonar.server.branch.pr.ws.PullRequestsWsParameters.PARAM_PULL_REQUEST; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | |||||
public class PullRequestsWs implements WebService { | |||||
private final PullRequestWsAction[] actions; | |||||
public PullRequestsWs(PullRequestWsAction... actions) { | |||||
this.actions = actions; | |||||
} | |||||
@Override | |||||
public void define(Context context) { | |||||
NewController controller = context.createController("api/project_pull_requests") | |||||
.setSince("7.1") | |||||
.setDescription("Manage pull request (only available when the Branch plugin is installed)"); | |||||
stream(actions).forEach(action -> action.define(controller)); | |||||
controller.done(); | |||||
} | |||||
static void addProjectParam(NewAction action) { | |||||
action | |||||
.createParam(PARAM_PROJECT) | |||||
.setDescription("Project key") | |||||
.setExampleValue(KEY_PROJECT_EXAMPLE_001) | |||||
.setRequired(true); | |||||
} | |||||
static void addPullRequestParam(NewAction action) { | |||||
action | |||||
.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setExampleValue("1543") | |||||
.setRequired(true); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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.branch.pr.ws; | |||||
public class PullRequestsWsParameters { | |||||
public static final String PARAM_PROJECT = "project"; | |||||
public static final String PARAM_COMPONENT = "component"; | |||||
public static final String PARAM_PULL_REQUEST = "pullRequest"; | |||||
private PullRequestsWsParameters() { | |||||
// static utility class | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 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. | |||||
*/ | |||||
@ParametersAreNonnullByDefault | |||||
package org.sonar.server.branch.pr.ws; | |||||
import javax.annotation.ParametersAreNonnullByDefault; |
*/ | */ | ||||
package org.sonar.server.branch.ws; | package org.sonar.server.branch.ws; | ||||
import com.google.common.io.Resources; | |||||
import org.sonar.api.server.ws.Request; | import org.sonar.api.server.ws.Request; | ||||
import org.sonar.api.server.ws.Response; | import org.sonar.api.server.ws.Response; | ||||
import org.sonar.api.server.ws.WebService; | import org.sonar.api.server.ws.WebService; | ||||
import static org.sonar.server.branch.ws.BranchesWs.addBranchParam; | import static org.sonar.server.branch.ws.BranchesWs.addBranchParam; | ||||
import static org.sonar.server.branch.ws.BranchesWs.addProjectParam; | import static org.sonar.server.branch.ws.BranchesWs.addProjectParam; | ||||
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional; | |||||
import static org.sonar.server.branch.ws.ProjectBranchesParameters.ACTION_DELETE; | import static org.sonar.server.branch.ws.ProjectBranchesParameters.ACTION_DELETE; | ||||
import static org.sonar.server.branch.ws.ProjectBranchesParameters.PARAM_BRANCH; | import static org.sonar.server.branch.ws.ProjectBranchesParameters.PARAM_BRANCH; | ||||
import static org.sonar.server.branch.ws.ProjectBranchesParameters.PARAM_PROJECT; | import static org.sonar.server.branch.ws.ProjectBranchesParameters.PARAM_PROJECT; | ||||
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional; | |||||
public class DeleteAction implements BranchWsAction { | public class DeleteAction implements BranchWsAction { | ||||
private final DbClient dbClient; | private final DbClient dbClient; | ||||
.setSince("6.6") | .setSince("6.6") | ||||
.setDescription("Delete a non-main branch of a project.<br/>" + | .setDescription("Delete a non-main branch of a project.<br/>" + | ||||
"Requires 'Administer' rights on the specified project.") | "Requires 'Administer' rights on the specified project.") | ||||
.setResponseExample(Resources.getResource(getClass(), "list-example.json")) | |||||
.setPost(true) | .setPost(true) | ||||
.setHandler(this); | .setHandler(this); | ||||
checkPermission(project); | checkPermission(project); | ||||
BranchDto branch = checkFoundWithOptional( | BranchDto branch = checkFoundWithOptional( | ||||
dbClient.branchDao().selectByKey(dbSession, project.uuid(), branchKey), | |||||
dbClient.branchDao().selectByBranchKey(dbSession, project.uuid(), branchKey), | |||||
"Branch '%s' not found for project '%s'", branchKey, projectKey); | "Branch '%s' not found for project '%s'", branchKey, projectKey); | ||||
if (branch.isMain()) { | if (branch.isMain()) { |
import com.google.common.io.Resources; | import com.google.common.io.Resources; | ||||
import java.util.Collection; | import java.util.Collection; | ||||
import java.util.List; | |||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Objects; | import java.util.Objects; | ||||
import java.util.Optional; | import java.util.Optional; | ||||
import java.util.function.Function; | import java.util.function.Function; | ||||
import java.util.stream.Collectors; | |||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.sonar.api.server.ws.Request; | import org.sonar.api.server.ws.Request; | ||||
import org.sonar.api.server.ws.Response; | import org.sonar.api.server.ws.Response; | ||||
import org.sonar.api.server.ws.WebService; | import org.sonar.api.server.ws.WebService; | ||||
import org.sonar.api.web.UserRole; | import org.sonar.api.web.UserRole; | ||||
import org.sonar.core.util.Protobuf; | import org.sonar.core.util.Protobuf; | ||||
import org.sonar.core.util.stream.MoreCollectors; | |||||
import org.sonar.db.DbClient; | import org.sonar.db.DbClient; | ||||
import org.sonar.db.DbSession; | import org.sonar.db.DbSession; | ||||
import org.sonar.db.component.BranchDto; | import org.sonar.db.component.BranchDto; | ||||
checkPermission(project); | checkPermission(project); | ||||
checkArgument(project.isEnabled() && PROJECT.equals(project.qualifier()), "Invalid project key"); | checkArgument(project.isEnabled() && PROJECT.equals(project.qualifier()), "Invalid project key"); | ||||
Collection<BranchDto> branches = dbClient.branchDao().selectByComponent(dbSession, project); | |||||
Collection<BranchDto> branches = dbClient.branchDao().selectByComponent(dbSession, project).stream() | |||||
.filter(b -> b.getBranchType() == SHORT || b.getBranchType() == LONG) | |||||
.collect(MoreCollectors.toList()); | |||||
List<String> branchUuids = branches.stream().map(BranchDto::getUuid).collect(toList()); | |||||
Map<String, BranchDto> mergeBranchesByUuid = dbClient.branchDao() | Map<String, BranchDto> mergeBranchesByUuid = dbClient.branchDao() | ||||
.selectByUuids(dbSession, branches.stream().map(BranchDto::getMergeBranchUuid).filter(Objects::nonNull).collect(toList())) | .selectByUuids(dbSession, branches.stream().map(BranchDto::getMergeBranchUuid).filter(Objects::nonNull).collect(toList())) | ||||
.stream().collect(uniqueIndex(BranchDto::getUuid)); | .stream().collect(uniqueIndex(BranchDto::getUuid)); | ||||
Map<String, LiveMeasureDto> qualityGateMeasuresByComponentUuids = dbClient.liveMeasureDao() | Map<String, LiveMeasureDto> qualityGateMeasuresByComponentUuids = dbClient.liveMeasureDao() | ||||
.selectByComponentUuidsAndMetricKeys(dbSession, branches.stream().map(BranchDto::getUuid).collect(toList()), singletonList(ALERT_STATUS_KEY)) | |||||
.stream().collect(uniqueIndex(LiveMeasureDto::getComponentUuid)); | |||||
.selectByComponentUuidsAndMetricKeys(dbSession, branchUuids, singletonList(ALERT_STATUS_KEY)).stream() | |||||
.collect(uniqueIndex(LiveMeasureDto::getComponentUuid)); | |||||
Map<String, BranchStatistics> branchStatisticsByBranchUuid = issueIndex.searchBranchStatistics(project.uuid(), branches.stream() | Map<String, BranchStatistics> branchStatisticsByBranchUuid = issueIndex.searchBranchStatistics(project.uuid(), branches.stream() | ||||
.filter(b -> b.getBranchType().equals(SHORT)) | .filter(b -> b.getBranchType().equals(SHORT)) | ||||
.map(BranchDto::getUuid).collect(toList())) | |||||
.stream().collect(uniqueIndex(BranchStatistics::getBranchUuid, Function.identity())); | |||||
.map(BranchDto::getUuid).collect(toList())).stream() | |||||
.collect(uniqueIndex(BranchStatistics::getBranchUuid, Function.identity())); | |||||
Map<String, String> analysisDateByBranchUuid = dbClient.snapshotDao() | Map<String, String> analysisDateByBranchUuid = dbClient.snapshotDao() | ||||
.selectLastAnalysesByRootComponentUuids(dbSession, branches.stream().map(BranchDto::getUuid).collect(Collectors.toList())) | |||||
.stream().collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> formatDateTime(s.getCreatedAt()))); | |||||
.selectLastAnalysesByRootComponentUuids(dbSession, branchUuids).stream() | |||||
.collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> formatDateTime(s.getCreatedAt()))); | |||||
ProjectBranches.ListWsResponse.Builder protobufResponse = ProjectBranches.ListWsResponse.newBuilder(); | ProjectBranches.ListWsResponse.Builder protobufResponse = ProjectBranches.ListWsResponse.newBuilder(); | ||||
branches.forEach(b -> addBranch(protobufResponse, b, mergeBranchesByUuid, qualityGateMeasuresByComponentUuids.get(b.getUuid()), branchStatisticsByBranchUuid.get(b.getUuid()), | branches.forEach(b -> addBranch(protobufResponse, b, mergeBranchesByUuid, qualityGateMeasuresByComponentUuids.get(b.getUuid()), branchStatisticsByBranchUuid.get(b.getUuid()), | ||||
analysisDateByBranchUuid.get(b.getUuid()))); | |||||
analysisDateByBranchUuid.get(b.getUuid()))); | |||||
WsUtils.writeProtobuf(protobufResponse.build(), request, response); | WsUtils.writeProtobuf(protobufResponse.build(), request, response); | ||||
} | } | ||||
} | } | ||||
private static void addBranch(ProjectBranches.ListWsResponse.Builder response, BranchDto branch, Map<String, BranchDto> mergeBranchesByUuid, | private static void addBranch(ProjectBranches.ListWsResponse.Builder response, BranchDto branch, Map<String, BranchDto> mergeBranchesByUuid, | ||||
@Nullable LiveMeasureDto qualityGateMeasure, BranchStatistics branchStatistics, @Nullable String analysisDate) { | |||||
@Nullable LiveMeasureDto qualityGateMeasure, BranchStatistics branchStatistics, @Nullable String analysisDate) { | |||||
ProjectBranches.Branch.Builder builder = toBranchBuilder(branch, Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid()))); | ProjectBranches.Branch.Builder builder = toBranchBuilder(branch, Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid()))); | ||||
setBranchStatus(builder, branch, qualityGateMeasure, branchStatistics); | setBranchStatus(builder, branch, qualityGateMeasure, branchStatistics); | ||||
if (analysisDate != null) { | if (analysisDate != null) { | ||||
setNullable(branchKey, builder::setName); | setNullable(branchKey, builder::setName); | ||||
builder.setIsMain(branch.isMain()); | builder.setIsMain(branch.isMain()); | ||||
builder.setType(Common.BranchType.valueOf(branch.getBranchType().name())); | builder.setType(Common.BranchType.valueOf(branch.getBranchType().name())); | ||||
if (branch.getBranchType().equals(SHORT)) { | |||||
if (branch.getBranchType() == SHORT) { | |||||
if (mergeBranch.isPresent()) { | if (mergeBranch.isPresent()) { | ||||
String mergeBranchKey = mergeBranch.get().getKey(); | String mergeBranchKey = mergeBranch.get().getKey(); | ||||
builder.setMergeBranch(mergeBranchKey); | builder.setMergeBranch(mergeBranchKey); | ||||
} | } | ||||
private static void setBranchStatus(ProjectBranches.Branch.Builder builder, BranchDto branch, @Nullable LiveMeasureDto qualityGateMeasure, | private static void setBranchStatus(ProjectBranches.Branch.Builder builder, BranchDto branch, @Nullable LiveMeasureDto qualityGateMeasure, | ||||
@Nullable BranchStatistics branchStatistics) { | |||||
ProjectBranches.Branch.Status.Builder statusBuilder = ProjectBranches.Branch.Status.newBuilder(); | |||||
@Nullable BranchStatistics branchStatistics) { | |||||
ProjectBranches.Status.Builder statusBuilder = ProjectBranches.Status.newBuilder(); | |||||
if (branch.getBranchType() == LONG && qualityGateMeasure != null) { | if (branch.getBranchType() == LONG && qualityGateMeasure != null) { | ||||
Protobuf.setNullable(qualityGateMeasure.getDataAsString(), statusBuilder::setQualityGateStatus); | Protobuf.setNullable(qualityGateMeasure.getDataAsString(), statusBuilder::setQualityGateStatus); | ||||
} | } |
ComponentDto project = componentFinder.getRootComponentByUuidOrKey(dbSession, null, projectKey); | ComponentDto project = componentFinder.getRootComponentByUuidOrKey(dbSession, null, projectKey); | ||||
checkPermission(project); | checkPermission(project); | ||||
Optional<BranchDto> existingBranch = dbClient.branchDao().selectByKey(dbSession, project.uuid(), newBranchName); | |||||
Optional<BranchDto> existingBranch = dbClient.branchDao().selectByBranchKey(dbSession, project.uuid(), newBranchName); | |||||
checkArgument(!existingBranch.filter(b -> !b.isMain()).isPresent(), | checkArgument(!existingBranch.filter(b -> !b.isMain()).isPresent(), | ||||
"Impossible to update branch name: a branch with name \"%s\" already exists in the project.", newBranchName); | "Impossible to update branch name: a branch with name \"%s\" already exists in the project.", newBranchName); | ||||
.setChangelog( | .setChangelog( | ||||
new Change("5.5", "it's no more possible to specify the page parameter."), | new Change("5.5", "it's no more possible to specify the page parameter."), | ||||
new Change("6.1", "field \"logs\" is deprecated and its value is always false"), | new Change("6.1", "field \"logs\" is deprecated and its value is always false"), | ||||
new Change("6.6", "fields \"branch\" and \"branchType\" added")) | |||||
new Change("6.6", "fields \"branch\" and \"branchType\" added"), | |||||
new Change("7.1", "fields \"pullRequest\" and \"pullRequestTitle\" added")) | |||||
.setSince("5.2"); | .setSince("5.2"); | ||||
action.createParam(PARAM_COMPONENT_ID) | action.createParam(PARAM_COMPONENT_ID) |
builder.setSubmittedAt(formatDateTime(new Date(dto.getCreatedAt()))); | builder.setSubmittedAt(formatDateTime(new Date(dto.getCreatedAt()))); | ||||
setNullable(dto.getStartedAt(), builder::setStartedAt, DateUtils::formatDateTime); | setNullable(dto.getStartedAt(), builder::setStartedAt, DateUtils::formatDateTime); | ||||
setNullable(computeExecutionTimeMs(dto), builder::setExecutionTimeMs); | setNullable(computeExecutionTimeMs(dto), builder::setExecutionTimeMs); | ||||
setBranch(builder, dto.getUuid(), componentDtoCache); | |||||
setBranchOrPullRequest(builder, dto.getUuid(), componentDtoCache); | |||||
return builder.build(); | return builder.build(); | ||||
} | } | ||||
builder.setLogs(false); | builder.setLogs(false); | ||||
setNullable(dto.getComponentUuid(), uuid -> setComponent(builder, uuid, componentDtoCache).setComponentId(uuid)); | setNullable(dto.getComponentUuid(), uuid -> setComponent(builder, uuid, componentDtoCache).setComponentId(uuid)); | ||||
String analysisUuid = dto.getAnalysisUuid(); | String analysisUuid = dto.getAnalysisUuid(); | ||||
if (analysisUuid != null) { | |||||
builder.setAnalysisId(analysisUuid); | |||||
} | |||||
setBranch(builder, dto.getUuid(), componentDtoCache); | |||||
setNullable(analysisUuid, builder::setAnalysisId); | |||||
setBranchOrPullRequest(builder, dto.getUuid(), componentDtoCache); | |||||
setNullable(analysisUuid, builder::setAnalysisId); | setNullable(analysisUuid, builder::setAnalysisId); | ||||
setNullable(dto.getSubmitterLogin(), builder::setSubmitterLogin); | setNullable(dto.getSubmitterLogin(), builder::setSubmitterLogin); | ||||
builder.setSubmittedAt(formatDateTime(new Date(dto.getSubmittedAt()))); | builder.setSubmittedAt(formatDateTime(new Date(dto.getSubmittedAt()))); | ||||
return builder; | return builder; | ||||
} | } | ||||
private static Ce.Task.Builder setBranch(Ce.Task.Builder builder, String taskUuid, DtoCache componentDtoCache) { | |||||
componentDtoCache.getBranchName(taskUuid).ifPresent( | |||||
private static Ce.Task.Builder setBranchOrPullRequest(Ce.Task.Builder builder, String taskUuid, DtoCache componentDtoCache) { | |||||
componentDtoCache.getBranchKey(taskUuid).ifPresent( | |||||
b -> { | b -> { | ||||
builder.setBranch(b); | |||||
builder.setBranchType(componentDtoCache.getBranchType(taskUuid) | |||||
.orElseThrow(() -> new IllegalStateException(format("Could not find branch type of task '%s'", taskUuid)))); | |||||
Common.BranchType branchType = componentDtoCache.getBranchType(taskUuid) | |||||
.orElseThrow(() -> new IllegalStateException(format("Could not find branch type of task '%s'", taskUuid))); | |||||
switch (branchType) { | |||||
case LONG: | |||||
case SHORT: | |||||
builder.setBranchType(branchType); | |||||
builder.setBranch(b); | |||||
break; | |||||
default: | |||||
throw new IllegalStateException(String.format("Unknown branch type '%s'", branchType)); | |||||
} | |||||
}); | }); | ||||
componentDtoCache.getPullRequest(taskUuid).ifPresent(builder::setPullRequest); | |||||
return builder; | return builder; | ||||
} | } | ||||
return organizationDto.getKey(); | return organizationDto.getKey(); | ||||
} | } | ||||
Optional<String> getBranchName(String taskUuid) { | |||||
Optional<String> getBranchKey(String taskUuid) { | |||||
return characteristicsByTaskUuid.get(taskUuid).stream() | return characteristicsByTaskUuid.get(taskUuid).stream() | ||||
.filter(c -> c.getKey().equals(CeTaskCharacteristicDto.BRANCH_KEY)) | .filter(c -> c.getKey().equals(CeTaskCharacteristicDto.BRANCH_KEY)) | ||||
.map(CeTaskCharacteristicDto::getValue) | .map(CeTaskCharacteristicDto::getValue) | ||||
.map(c -> Common.BranchType.valueOf(c.getValue())) | .map(c -> Common.BranchType.valueOf(c.getValue())) | ||||
.findAny(); | .findAny(); | ||||
} | } | ||||
Optional<String> getPullRequest(String taskUuid) { | |||||
return characteristicsByTaskUuid.get(taskUuid).stream() | |||||
.filter(c -> c.getKey().equals(CeTaskCharacteristicDto.PULL_REQUEST)) | |||||
.map(CeTaskCharacteristicDto::getValue) | |||||
.findAny(); | |||||
} | |||||
} | } | ||||
/** | /** |
throw new NotFoundException(format("Component '%s' on branch '%s' not found", key, branch)); | throw new NotFoundException(format("Component '%s' on branch '%s' not found", key, branch)); | ||||
} | } | ||||
public ComponentDto getByKeyAndOptionalBranch(DbSession dbSession, String key, @Nullable String branch) { | |||||
return branch == null ? getByKey(dbSession, key) : getByKeyAndBranch(dbSession, key, branch); | |||||
public ComponentDto getByKeyAndPullRequest(DbSession dbSession, String key, String pullRequest) { | |||||
java.util.Optional<ComponentDto> componentDto = dbClient.componentDao().selectByKeyAndPullRequest(dbSession, key, pullRequest); | |||||
if (componentDto.isPresent() && componentDto.get().isEnabled()) { | |||||
return componentDto.get(); | |||||
} | |||||
throw new NotFoundException(format("Component '%s' of pull request '%s' not found", key, pullRequest)); | |||||
} | |||||
public ComponentDto getByKeyAndOptionalBranchOrPullRequest(DbSession dbSession, String key, @Nullable String branch, @Nullable String pullRequest) { | |||||
checkArgument(branch == null || pullRequest == null, "Either branch or pull request can be provided, not both"); | |||||
if (branch != null) { | |||||
return getByKeyAndBranch(dbSession, key, branch); | |||||
} | |||||
if (pullRequest != null) { | |||||
return getByKeyAndPullRequest(dbSession, key, pullRequest); | |||||
} | |||||
return getByKey(dbSession, key); | |||||
} | } | ||||
public enum ParamNames { | public enum ParamNames { | ||||
UUID_AND_KEY("uuid", "key"), | UUID_AND_KEY("uuid", "key"), | ||||
ID_AND_KEY("id", "key"), | ID_AND_KEY("id", "key"), | ||||
COMPONENT_ID_AND_KEY("componentId", "componentKey"), | COMPONENT_ID_AND_KEY("componentId", "componentKey"), | ||||
BASE_COMPONENT_ID_AND_KEY("baseComponentId", "baseComponentKey"), | |||||
BASE_COMPONENT_ID_AND_KEY("baseComponentId", "component"), | |||||
DEVELOPER_ID_AND_KEY("developerId", "developerKey"), | DEVELOPER_ID_AND_KEY("developerId", "developerKey"), | ||||
COMPONENT_ID_AND_COMPONENT("componentId", "component"), | COMPONENT_ID_AND_COMPONENT("componentId", "component"), | ||||
PROJECT_ID_AND_PROJECT("projectId", "project"), | PROJECT_ID_AND_PROJECT("projectId", "project"), |
import static org.sonar.api.measures.CoreMetrics.VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.VIOLATIONS_KEY; | ||||
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; | import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; | ||||
import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_COMPONENT; | import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_COMPONENT; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH; | |||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_PULL_REQUEST; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001; | |||||
public class AppAction implements ComponentsWsAction { | public class AppAction implements ComponentsWsAction { | ||||
.setSince("6.6") | .setSince("6.6") | ||||
.setInternal(true) | .setInternal(true) | ||||
.setExampleValue(KEY_BRANCH_EXAMPLE_001); | .setExampleValue(KEY_BRANCH_EXAMPLE_001); | ||||
action.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setSince("7.1") | |||||
.setInternal(true) | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001); | |||||
} | } | ||||
@Override | @Override | ||||
private ComponentDto loadComponent(DbSession dbSession, Request request) { | private ComponentDto loadComponent(DbSession dbSession, Request request) { | ||||
String componentUuid = request.param(PARAM_COMPONENT_ID); | String componentUuid = request.param(PARAM_COMPONENT_ID); | ||||
String branch = request.param("branch"); | |||||
checkArgument(componentUuid == null || branch == null, "'%s' and '%s' parameters cannot be used at the same time", PARAM_COMPONENT_ID, PARAM_BRANCH); | |||||
if (branch == null) { | |||||
String branch = request.param(PARAM_BRANCH); | |||||
String pullRequest = request.param(PARAM_PULL_REQUEST); | |||||
checkArgument(componentUuid == null || (branch == null && pullRequest == null), "Parameter '%s' cannot be used at the same time as '%s' or '%s'", PARAM_COMPONENT_ID, | |||||
PARAM_BRANCH, PARAM_PULL_REQUEST); | |||||
if (branch == null && pullRequest == null) { | |||||
return componentFinder.getByUuidOrKey(dbSession, componentUuid, request.param(PARAM_COMPONENT), COMPONENT_ID_AND_COMPONENT); | return componentFinder.getByUuidOrKey(dbSession, componentUuid, request.param(PARAM_COMPONENT), COMPONENT_ID_AND_COMPONENT); | ||||
} | } | ||||
return componentFinder.getByKeyAndOptionalBranch(dbSession, request.mandatoryParam(PARAM_COMPONENT), branch); | |||||
return componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, request.mandatoryParam(PARAM_COMPONENT), branch, pullRequest); | |||||
} | } | ||||
private void appendComponent(JsonWriter json, ComponentDto component, UserSession userSession, DbSession session) { | private void appendComponent(JsonWriter json, ComponentDto component, UserSession userSession, DbSession session) { | ||||
if (branch != null) { | if (branch != null) { | ||||
json.prop("branch", branch); | json.prop("branch", branch); | ||||
} | } | ||||
String pullRequest = project.getPullRequest(); | |||||
if (pullRequest != null) { | |||||
json.prop("pullRequest", pullRequest); | |||||
} | |||||
json.prop("fav", isFavourite); | json.prop("fav", isFavourite); | ||||
} | } |
.setName(dto.name()) | .setName(dto.name()) | ||||
.setQualifier(dto.qualifier()); | .setQualifier(dto.qualifier()); | ||||
setNullable(emptyToNull(dto.getBranch()), wsComponent::setBranch); | setNullable(emptyToNull(dto.getBranch()), wsComponent::setBranch); | ||||
setNullable(emptyToNull(dto.getPullRequest()), wsComponent::setPullRequest); | |||||
setNullable(emptyToNull(dto.path()), wsComponent::setPath); | setNullable(emptyToNull(dto.path()), wsComponent::setPath); | ||||
setNullable(emptyToNull(dto.description()), wsComponent::setDescription); | setNullable(emptyToNull(dto.description()), wsComponent::setDescription); | ||||
setNullable(emptyToNull(dto.language()), wsComponent::setLanguage); | setNullable(emptyToNull(dto.language()), wsComponent::setLanguage); |
public static final String DEPRECATED_PARAM_BASE_COMPONENT_KEY = "baseComponentKey"; | public static final String DEPRECATED_PARAM_BASE_COMPONENT_KEY = "baseComponentKey"; | ||||
public static final String PARAM_COMPONENT = "component"; | public static final String PARAM_COMPONENT = "component"; | ||||
public static final String PARAM_BRANCH = "branch"; | public static final String PARAM_BRANCH = "branch"; | ||||
public static final String PARAM_PULL_REQUEST = "pullRequest"; | |||||
public static final String PARAM_STRATEGY = "strategy"; | public static final String PARAM_STRATEGY = "strategy"; | ||||
public static final String PARAM_QUALIFIERS = "qualifiers"; | public static final String PARAM_QUALIFIERS = "qualifiers"; | ||||
public static final String PARAM_METRICS = "metrics"; | public static final String PARAM_METRICS = "metrics"; |
import java.util.List; | import java.util.List; | ||||
import java.util.Optional; | import java.util.Optional; | ||||
import java.util.stream.IntStream; | import java.util.stream.IntStream; | ||||
import javax.annotation.CheckForNull; | |||||
import javax.annotation.Nullable; | |||||
import org.sonar.api.server.ws.Change; | import org.sonar.api.server.ws.Change; | ||||
import org.sonar.api.server.ws.Response; | import org.sonar.api.server.ws.Response; | ||||
import org.sonar.api.server.ws.WebService; | import org.sonar.api.server.ws.WebService; | ||||
import org.sonar.server.user.UserSession; | import org.sonar.server.user.UserSession; | ||||
import org.sonarqube.ws.Components.ShowWsResponse; | import org.sonarqube.ws.Components.ShowWsResponse; | ||||
import javax.annotation.CheckForNull; | |||||
import javax.annotation.Nullable; | |||||
import static com.google.common.base.Preconditions.checkArgument; | import static com.google.common.base.Preconditions.checkArgument; | ||||
import static java.lang.String.format; | import static java.lang.String.format; | ||||
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; | import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; | ||||
import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_COMPONENT; | import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_COMPONENT; | ||||
import static org.sonar.server.component.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; | import static org.sonar.server.component.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH; | |||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_PULL_REQUEST; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | 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.checkRequest; | |||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | import static org.sonar.server.ws.WsUtils.writeProtobuf; | ||||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.ACTION_SHOW; | import static org.sonarqube.ws.client.component.ComponentsWsParameters.ACTION_SHOW; | ||||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_COMPONENT; | import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_COMPONENT; | ||||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_COMPONENT_ID; | import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_COMPONENT_ID; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH; | |||||
public class ShowAction implements ComponentsWsAction { | public class ShowAction implements ComponentsWsAction { | ||||
private final UserSession userSession; | private final UserSession userSession; | ||||
.setExampleValue(KEY_BRANCH_EXAMPLE_001) | .setExampleValue(KEY_BRANCH_EXAMPLE_001) | ||||
.setInternal(true) | .setInternal(true) | ||||
.setSince("6.6"); | .setSince("6.6"); | ||||
action.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001) | |||||
.setInternal(true) | |||||
.setSince("7.1"); | |||||
} | } | ||||
@Override | @Override | ||||
private ShowWsResponse doHandle(Request request) { | private ShowWsResponse doHandle(Request request) { | ||||
try (DbSession dbSession = dbClient.openSession(false)) { | try (DbSession dbSession = dbClient.openSession(false)) { | ||||
ComponentDto component = loadComponent(dbSession, request); | ComponentDto component = loadComponent(dbSession, request); | ||||
userSession.checkComponentPermission(UserRole.USER, component); | |||||
Optional<SnapshotDto> lastAnalysis = dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, component.projectUuid()); | Optional<SnapshotDto> lastAnalysis = dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, component.projectUuid()); | ||||
List<ComponentDto> ancestors = dbClient.componentDao().selectAncestors(dbSession, component); | List<ComponentDto> ancestors = dbClient.componentDao().selectAncestors(dbSession, component); | ||||
OrganizationDto organizationDto = componentFinder.getOrganization(dbSession, component); | OrganizationDto organizationDto = componentFinder.getOrganization(dbSession, component); | ||||
String componentId = request.getId(); | String componentId = request.getId(); | ||||
String componentKey = request.getKey(); | String componentKey = request.getKey(); | ||||
String branch = request.getBranch(); | String branch = request.getBranch(); | ||||
checkArgument(componentId == null || branch == null, "'%s' and '%s' parameters cannot be used at the same time", PARAM_COMPONENT_ID, PARAM_BRANCH); | |||||
ComponentDto component = branch == null | |||||
? componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, COMPONENT_ID_AND_COMPONENT) | |||||
: componentFinder.getByKeyAndBranch(dbSession, componentKey, branch); | |||||
userSession.checkComponentPermission(UserRole.USER, component); | |||||
return component; | |||||
String pullRequest = request.getPullRequest(); | |||||
checkArgument(componentId == null || (branch == null && pullRequest == null), "Parameter '%s' cannot be used at the same time as '%s' or '%s'", PARAM_COMPONENT_ID, | |||||
PARAM_BRANCH, PARAM_PULL_REQUEST); | |||||
if (branch == null && pullRequest == null) { | |||||
return componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, COMPONENT_ID_AND_COMPONENT); | |||||
} | |||||
checkRequest(componentKey!=null, "The '%s' parameter is missing", PARAM_COMPONENT); | |||||
return componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, componentKey, branch, pullRequest); | |||||
} | } | ||||
private static ShowWsResponse buildResponse(ComponentDto component, OrganizationDto organizationDto, List<ComponentDto> orderedAncestors, Optional<SnapshotDto> lastAnalysis) { | private static ShowWsResponse buildResponse(ComponentDto component, OrganizationDto organizationDto, List<ComponentDto> orderedAncestors, Optional<SnapshotDto> lastAnalysis) { | ||||
return new Request() | return new Request() | ||||
.setId(request.param(PARAM_COMPONENT_ID)) | .setId(request.param(PARAM_COMPONENT_ID)) | ||||
.setKey(request.param(PARAM_COMPONENT)) | .setKey(request.param(PARAM_COMPONENT)) | ||||
.setBranch(request.param(PARAM_BRANCH)); | |||||
.setBranch(request.param(PARAM_BRANCH)) | |||||
.setPullRequest(request.param(PARAM_PULL_REQUEST)); | |||||
} | } | ||||
private static class Request { | private static class Request { | ||||
private String id; | private String id; | ||||
private String key; | private String key; | ||||
private String branch; | private String branch; | ||||
private String pullRequest; | |||||
@CheckForNull | @CheckForNull | ||||
public String getId() { | public String getId() { | ||||
this.branch = branch; | this.branch = branch; | ||||
return this; | return this; | ||||
} | } | ||||
@CheckForNull | |||||
public String getPullRequest() { | |||||
return pullRequest; | |||||
} | |||||
public Request setPullRequest(@Nullable String pullRequest) { | |||||
this.pullRequest = pullRequest; | |||||
return this; | |||||
} | |||||
} | } | ||||
} | } |
import static org.sonar.server.component.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; | import static org.sonar.server.component.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | ||||
import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001; | |||||
import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext; | import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext; | ||||
import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter; | |||||
import static org.sonar.server.ws.WsUtils.checkRequest; | |||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | import static org.sonar.server.ws.WsUtils.writeProtobuf; | ||||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.ACTION_TREE; | import static org.sonarqube.ws.client.component.ComponentsWsParameters.ACTION_TREE; | ||||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH; | |||||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_COMPONENT; | import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_COMPONENT; | ||||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_COMPONENT_ID; | import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_COMPONENT_ID; | ||||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_PULL_REQUEST; | |||||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS; | import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS; | ||||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_STRATEGY; | import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_STRATEGY; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH; | |||||
public class TreeAction implements ComponentsWsAction { | public class TreeAction implements ComponentsWsAction { | ||||
.setInternal(true) | .setInternal(true) | ||||
.setSince("6.6"); | .setSince("6.6"); | ||||
action.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001) | |||||
.setInternal(true) | |||||
.setSince("7.1"); | |||||
action.createSortParams(SORTS, NAME_SORT, true) | action.createSortParams(SORTS, NAME_SORT, true) | ||||
.setDescription("Comma-separated list of sort fields") | .setDescription("Comma-separated list of sort fields") | ||||
.setExampleValue(NAME_SORT + ", " + PATH_SORT); | .setExampleValue(NAME_SORT + ", " + PATH_SORT); | ||||
private ComponentDto loadComponent(DbSession dbSession, Request request) { | private ComponentDto loadComponent(DbSession dbSession, Request request) { | ||||
String componentId = request.getBaseComponentId(); | String componentId = request.getBaseComponentId(); | ||||
String componentKey = request.getBaseComponentKey(); | |||||
String componentKey = request.getComponent(); | |||||
String branch = request.getBranch(); | String branch = request.getBranch(); | ||||
checkArgument(componentId == null || branch == null, "'%s' and '%s' parameters cannot be used at the same time", PARAM_COMPONENT_ID, PARAM_BRANCH); | |||||
return branch == null | |||||
? componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, COMPONENT_ID_AND_COMPONENT) | |||||
: componentFinder.getByKeyAndBranch(dbSession, componentKey, branch); | |||||
String pullRequest = request.getPullRequest(); | |||||
checkArgument(componentId == null || (branch == null && pullRequest == null), "Parameter '%s' cannot be used at the same time as '%s' or '%s'", PARAM_COMPONENT_ID, | |||||
PARAM_BRANCH, PARAM_PULL_REQUEST); | |||||
if (branch == null && pullRequest == null) { | |||||
return componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, COMPONENT_ID_AND_COMPONENT); | |||||
} | |||||
checkRequest(componentKey != null, "The '%s' parameter is missing", PARAM_COMPONENT); | |||||
return componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, componentKey, branch, pullRequest); | |||||
} | } | ||||
private Map<String, ComponentDto> searchReferenceComponentsByUuid(DbSession dbSession, List<ComponentDto> components) { | private Map<String, ComponentDto> searchReferenceComponentsByUuid(DbSession dbSession, List<ComponentDto> components) { | ||||
private static Request toTreeWsRequest(org.sonar.api.server.ws.Request request) { | private static Request toTreeWsRequest(org.sonar.api.server.ws.Request request) { | ||||
return new Request() | return new Request() | ||||
.setBaseComponentId(request.param(PARAM_COMPONENT_ID)) | .setBaseComponentId(request.param(PARAM_COMPONENT_ID)) | ||||
.setBaseComponentKey(request.param(PARAM_COMPONENT)) | |||||
.setComponent(request.param(PARAM_COMPONENT)) | |||||
.setBranch(request.param(PARAM_BRANCH)) | .setBranch(request.param(PARAM_BRANCH)) | ||||
.setPullRequest(request.param(PARAM_PULL_REQUEST)) | |||||
.setStrategy(request.mandatoryParam(PARAM_STRATEGY)) | .setStrategy(request.mandatoryParam(PARAM_STRATEGY)) | ||||
.setQuery(request.param(Param.TEXT_QUERY)) | .setQuery(request.param(Param.TEXT_QUERY)) | ||||
.setQualifiers(request.paramAsStrings(PARAM_QUALIFIERS)) | .setQualifiers(request.paramAsStrings(PARAM_QUALIFIERS)) | ||||
private static class Request { | private static class Request { | ||||
private String baseComponentId; | private String baseComponentId; | ||||
private String baseComponentKey; | |||||
private String component; | private String component; | ||||
private String branch; | private String branch; | ||||
private String pullRequest; | |||||
private String strategy; | private String strategy; | ||||
private List<String> qualifiers; | private List<String> qualifiers; | ||||
private String query; | private String query; | ||||
return this; | return this; | ||||
} | } | ||||
/** | |||||
* @deprecated since 6.4, please use {@link #getComponent()} instead | |||||
*/ | |||||
@Deprecated | |||||
@CheckForNull | |||||
private String getBaseComponentKey() { | |||||
return baseComponentKey; | |||||
} | |||||
/** | |||||
* @deprecated since 6.4, please use {@link #setComponent(String)} instead | |||||
*/ | |||||
@Deprecated | |||||
private Request setBaseComponentKey(@Nullable String baseComponentKey) { | |||||
this.baseComponentKey = baseComponentKey; | |||||
return this; | |||||
} | |||||
public Request setComponent(@Nullable String component) { | public Request setComponent(@Nullable String component) { | ||||
this.component = component; | this.component = component; | ||||
return this; | return this; | ||||
return this; | return this; | ||||
} | } | ||||
@CheckForNull | |||||
public String getPullRequest() { | |||||
return pullRequest; | |||||
} | |||||
public Request setPullRequest(@Nullable String pullRequest) { | |||||
this.pullRequest = pullRequest; | |||||
return this; | |||||
} | |||||
@CheckForNull | @CheckForNull | ||||
private String getStrategy() { | private String getStrategy() { | ||||
return strategy; | return strategy; |
*/ | */ | ||||
boolean isLongLivingBranch(); | boolean isLongLivingBranch(); | ||||
/** | |||||
* Convenience method equivalent to do the check using {@link #getBranch()} | |||||
* | |||||
* @throws IllegalStateException if branch has not been set | |||||
*/ | |||||
boolean isPullRequest(); | |||||
/** | /** | ||||
* @throws IllegalStateException if cross project duplication flag has not been set | * @throws IllegalStateException if cross project duplication flag has not been set | ||||
*/ | */ | ||||
*/ | */ | ||||
Branch getBranch(); | Branch getBranch(); | ||||
/** | |||||
* In a pull request analysis, return the ID of the pull request | |||||
* | |||||
* @throws IllegalStateException if current analysis is not a pull request | |||||
*/ | |||||
String getPullRequestId(); | |||||
/** | /** | ||||
* The project as represented by the main branch. It is used to load settings | * The project as represented by the main branch. It is used to load settings | ||||
* like Quality gates, webhooks and configuration. | * like Quality gates, webhooks and configuration. | ||||
* Plugins used during the analysis on scanner side | * Plugins used during the analysis on scanner side | ||||
*/ | */ | ||||
Map<String, ScannerPlugin> getScannerPluginsByKey(); | Map<String, ScannerPlugin> getScannerPluginsByKey(); | ||||
} | } |
private final InitializedProperty<Analysis> baseProjectSnapshot = new InitializedProperty<>(); | private final InitializedProperty<Analysis> baseProjectSnapshot = new InitializedProperty<>(); | ||||
private final InitializedProperty<Boolean> crossProjectDuplicationEnabled = new InitializedProperty<>(); | private final InitializedProperty<Boolean> crossProjectDuplicationEnabled = new InitializedProperty<>(); | ||||
private final InitializedProperty<Branch> branch = new InitializedProperty<>(); | private final InitializedProperty<Branch> branch = new InitializedProperty<>(); | ||||
private final InitializedProperty<String> pullRequestId = new InitializedProperty<>(); | |||||
private final InitializedProperty<Project> project = new InitializedProperty<>(); | private final InitializedProperty<Project> project = new InitializedProperty<>(); | ||||
private final InitializedProperty<Integer> rootComponentRef = new InitializedProperty<>(); | private final InitializedProperty<Integer> rootComponentRef = new InitializedProperty<>(); | ||||
private final InitializedProperty<Map<String, QualityProfile>> qProfilesPerLanguage = new InitializedProperty<>(); | private final InitializedProperty<Map<String, QualityProfile>> qProfilesPerLanguage = new InitializedProperty<>(); | ||||
return branch.getProperty(); | return branch.getProperty(); | ||||
} | } | ||||
@Override | |||||
public MutableAnalysisMetadataHolder setPullRequestId(String pullRequestId) { | |||||
checkState(!this.pullRequestId.isInitialized(), "Pull request id has already been set"); | |||||
this.pullRequestId.setProperty(pullRequestId); | |||||
return this; | |||||
} | |||||
@Override | |||||
public String getPullRequestId() { | |||||
checkState(pullRequestId.isInitialized(), "Pull request id has not been set"); | |||||
return pullRequestId.getProperty(); | |||||
} | |||||
@Override | @Override | ||||
public MutableAnalysisMetadataHolder setProject(Project project) { | public MutableAnalysisMetadataHolder setProject(Project project) { | ||||
checkState(!this.project.isInitialized(), "Project has already been set"); | checkState(!this.project.isInitialized(), "Project has already been set"); | ||||
return pluginsByKey.getProperty(); | return pluginsByKey.getProperty(); | ||||
} | } | ||||
@Override | |||||
public boolean isShortLivingBranch() { | public boolean isShortLivingBranch() { | ||||
checkState(this.branch.isInitialized(), BRANCH_NOT_SET); | checkState(this.branch.isInitialized(), BRANCH_NOT_SET); | ||||
Branch prop = branch.getProperty(); | Branch prop = branch.getProperty(); | ||||
return prop != null && prop.getType() == BranchType.SHORT; | return prop != null && prop.getType() == BranchType.SHORT; | ||||
} | } | ||||
@Override | |||||
public boolean isLongLivingBranch() { | public boolean isLongLivingBranch() { | ||||
checkState(this.branch.isInitialized(), BRANCH_NOT_SET); | checkState(this.branch.isInitialized(), BRANCH_NOT_SET); | ||||
Branch prop = branch.getProperty(); | Branch prop = branch.getProperty(); | ||||
return prop != null && prop.getType() == BranchType.LONG; | return prop != null && prop.getType() == BranchType.LONG; | ||||
} | } | ||||
@Override | |||||
public boolean isPullRequest() { | |||||
checkState(this.branch.isInitialized(), BRANCH_NOT_SET); | |||||
Branch prop = branch.getProperty(); | |||||
return prop != null && prop.getType() == BranchType.PULL_REQUEST; | |||||
} | |||||
} | } |
* or not. | * or not. | ||||
*/ | */ | ||||
boolean supportsCrossProjectCpd(); | boolean supportsCrossProjectCpd(); | ||||
/** | |||||
* @throws IllegalStateException if this branch configuration is not a pull request. | |||||
*/ | |||||
String getPullRequestId(); | |||||
} | } |
*/ | */ | ||||
MutableAnalysisMetadataHolder setBranch(Branch branch); | MutableAnalysisMetadataHolder setBranch(Branch branch); | ||||
/** | |||||
* @throws IllegalStateException if pull request id has already been set | |||||
*/ | |||||
MutableAnalysisMetadataHolder setPullRequestId(String pullRequestId); | |||||
/** | /** | ||||
* @throws IllegalStateException if project has already been set | * @throws IllegalStateException if project has already been set | ||||
*/ | */ |
import static java.util.Optional.ofNullable; | import static java.util.Optional.ofNullable; | ||||
import static org.sonar.api.ce.posttask.CeTask.Status.FAILED; | import static org.sonar.api.ce.posttask.CeTask.Status.FAILED; | ||||
import static org.sonar.api.ce.posttask.CeTask.Status.SUCCESS; | import static org.sonar.api.ce.posttask.CeTask.Status.SUCCESS; | ||||
import static org.sonar.db.component.BranchType.PULL_REQUEST; | |||||
/** | /** | ||||
* Responsible for calling {@link PostProjectAnalysisTask} implementations (if any). | * Responsible for calling {@link PostProjectAnalysisTask} implementations (if any). | ||||
private BranchImpl createBranch() { | private BranchImpl createBranch() { | ||||
org.sonar.server.computation.task.projectanalysis.analysis.Branch analysisBranch = analysisMetadataHolder.getBranch(); | org.sonar.server.computation.task.projectanalysis.analysis.Branch analysisBranch = analysisMetadataHolder.getBranch(); | ||||
if (!analysisBranch.isLegacyFeature()) { | if (!analysisBranch.isLegacyFeature()) { | ||||
return new BranchImpl(analysisBranch.isMain(), analysisBranch.getName(), Branch.Type.valueOf(analysisBranch.getType().name())); | |||||
String branchKey = analysisBranch.getType() == PULL_REQUEST ? analysisBranch.getPullRequestId() : analysisBranch.getName(); | |||||
return new BranchImpl(analysisBranch.isMain(), branchKey, Branch.Type.valueOf(analysisBranch.getType().name())); | |||||
} | } | ||||
return null; | return null; | ||||
} | } |
import org.sonar.db.DbClient; | import org.sonar.db.DbClient; | ||||
import org.sonar.db.DbSession; | import org.sonar.db.DbSession; | ||||
import org.sonar.db.component.BranchDto; | import org.sonar.db.component.BranchDto; | ||||
import org.sonar.db.component.BranchType; | |||||
import org.sonar.db.component.ComponentDto; | import org.sonar.db.component.ComponentDto; | ||||
import org.sonar.db.protobuf.DbProjectBranches; | |||||
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; | import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; | ||||
import org.sonar.server.computation.task.projectanalysis.analysis.Branch; | import org.sonar.server.computation.task.projectanalysis.analysis.Branch; | ||||
if (branch.isMain()) { | if (branch.isMain()) { | ||||
checkState(branchComponentDtoOpt.isPresent(), "Project has been deleted by end-user during analysis"); | checkState(branchComponentDtoOpt.isPresent(), "Project has been deleted by end-user during analysis"); | ||||
branchComponentDto = branchComponentDtoOpt.get(); | branchComponentDto = branchComponentDtoOpt.get(); | ||||
} else { | } else { | ||||
// inserts new row in table projects if it's the first time branch is analyzed | // inserts new row in table projects if it's the first time branch is analyzed | ||||
branchComponentDto = branchComponentDtoOpt.or(() -> insertIntoProjectsTable(dbSession, branchUuid)); | branchComponentDto = branchComponentDtoOpt.or(() -> insertIntoProjectsTable(dbSession, branchUuid)); | ||||
} | } | ||||
// insert or update in table project_branches | // insert or update in table project_branches | ||||
dbClient.branchDao().upsert(dbSession, toBranchDto(branchComponentDto, branch)); | dbClient.branchDao().upsert(dbSession, toBranchDto(branchComponentDto, branch)); | ||||
} | } | ||||
return (first != null) ? first : second; | return (first != null) ? first : second; | ||||
} | } | ||||
private static BranchDto toBranchDto(ComponentDto componentDto, Branch branch) { | |||||
private BranchDto toBranchDto(ComponentDto componentDto, Branch branch) { | |||||
BranchDto dto = new BranchDto(); | BranchDto dto = new BranchDto(); | ||||
dto.setUuid(componentDto.uuid()); | dto.setUuid(componentDto.uuid()); | ||||
// MainBranchProjectUuid will be null if it's a main branch | // MainBranchProjectUuid will be null if it's a main branch | ||||
dto.setProjectUuid(firstNonNull(componentDto.getMainBranchProjectUuid(), componentDto.projectUuid())); | dto.setProjectUuid(firstNonNull(componentDto.getMainBranchProjectUuid(), componentDto.projectUuid())); | ||||
dto.setKey(branch.getName()); | |||||
dto.setBranchType(branch.getType()); | dto.setBranchType(branch.getType()); | ||||
// merge branch is only present if it's a short living branch | // merge branch is only present if it's a short living branch | ||||
dto.setMergeBranchUuid(branch.getMergeBranchUuid().orElse(null)); | dto.setMergeBranchUuid(branch.getMergeBranchUuid().orElse(null)); | ||||
if (branch.getType() == BranchType.PULL_REQUEST) { | |||||
dto.setKey(analysisMetadataHolder.getPullRequestId()); | |||||
DbProjectBranches.PullRequestData pullRequestData = DbProjectBranches.PullRequestData.newBuilder() | |||||
.setBranch(branch.getName()) | |||||
.setTitle(branch.getName()) | |||||
.build(); | |||||
dto.setPullRequestData(pullRequestData); | |||||
} else { | |||||
dto.setKey(branch.getName()); | |||||
} | |||||
return dto; | return dto; | ||||
} | } | ||||
return !isLegacyBranch; | return !isLegacyBranch; | ||||
} | } | ||||
@Override | |||||
public String getPullRequestId() { | |||||
throw new IllegalStateException("Only a branch of type PULL_REQUEST can have a pull request id."); | |||||
} | |||||
@Override | @Override | ||||
public String generateKey(ScannerReport.Component module, @Nullable ScannerReport.Component fileOrDir) { | public String generateKey(ScannerReport.Component module, @Nullable ScannerReport.Component fileOrDir) { | ||||
String moduleWithBranch = module.getKey(); | String moduleWithBranch = module.getKey(); |
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; | import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; | ||||
import static com.google.common.base.Preconditions.checkState; | import static com.google.common.base.Preconditions.checkState; | ||||
import static org.sonar.db.component.ComponentDto.removeBranchFromKey; | |||||
import static org.sonar.db.component.ComponentDto.removeBranchAndPullRequestFromKey; | |||||
/** | /** | ||||
* Cache a map between component keys and uuids in the merge branch | * Cache a map between component keys and uuids in the merge branch | ||||
@CheckForNull | @CheckForNull | ||||
public String getUuid(String dbKey) { | public String getUuid(String dbKey) { | ||||
lazyInit(); | lazyInit(); | ||||
String cleanComponentKey = removeBranchFromKey(dbKey); | |||||
String cleanComponentKey = removeBranchAndPullRequestFromKey(dbKey); | |||||
return uuidsByKey.get(cleanComponentKey); | return uuidsByKey.get(cleanComponentKey); | ||||
} | } | ||||
} | } |
import org.sonar.db.DbSession; | import org.sonar.db.DbSession; | ||||
import org.sonar.db.component.KeyWithUuidDto; | import org.sonar.db.component.KeyWithUuidDto; | ||||
import static org.sonar.db.component.ComponentDto.removeBranchFromKey; | |||||
import static org.sonar.db.component.ComponentDto.removeBranchAndPullRequestFromKey; | |||||
/** | /** | ||||
* Cache a map of component key -> uuid in short branches that have issues with status either RESOLVED or CONFIRMED. | * Cache a map of component key -> uuid in short branches that have issues with status either RESOLVED or CONFIRMED. | ||||
try (DbSession dbSession = dbClient.openSession(false)) { | try (DbSession dbSession = dbClient.openSession(false)) { | ||||
List<KeyWithUuidDto> components = dbClient.componentDao().selectComponentKeysHavingIssuesToMerge(dbSession, uuid); | List<KeyWithUuidDto> components = dbClient.componentDao().selectComponentKeysHavingIssuesToMerge(dbSession, uuid); | ||||
for (KeyWithUuidDto dto : components) { | for (KeyWithUuidDto dto : components) { | ||||
uuidsByKey.computeIfAbsent(removeBranchFromKey(dto.key()), s -> new HashSet<>()).add(dto.uuid()); | |||||
uuidsByKey.computeIfAbsent(removeBranchAndPullRequestFromKey(dto.key()), s -> new HashSet<>()).add(dto.uuid()); | |||||
} | } | ||||
} | } | ||||
} | } |
} | } | ||||
public TrackingResult track(Component component) { | public TrackingResult track(Component component) { | ||||
if (analysisMetadataHolder.isShortLivingBranch()) { | |||||
if (analysisMetadataHolder.isShortLivingBranch() || analysisMetadataHolder.isPullRequest()) { | |||||
return standardResult(shortBranchTracker.track(component)); | return standardResult(shortBranchTracker.track(component)); | ||||
} else if (isFirstAnalysisSecondaryLongLivingBranch()) { | } else if (isFirstAnalysisSecondaryLongLivingBranch()) { | ||||
Tracking<DefaultIssue, DefaultIssue> tracking = mergeBranchTracker.track(component); | Tracking<DefaultIssue, DefaultIssue> tracking = mergeBranchTracker.track(component); |
} | } | ||||
public Collection<ShortBranchIssue> loadCandidateIssuesForMergingInTargetBranch(Component component) { | public Collection<ShortBranchIssue> loadCandidateIssuesForMergingInTargetBranch(Component component) { | ||||
String componentKey = ComponentDto.removeBranchFromKey(component.getKey()); | |||||
String componentKey = ComponentDto.removeBranchAndPullRequestFromKey(component.getKey()); | |||||
Set<String> uuids = shortBranchComponentsWithIssues.getUuids(componentKey); | Set<String> uuids = shortBranchComponentsWithIssues.getUuids(componentKey); | ||||
if (uuids.isEmpty()) { | if (uuids.isEmpty()) { | ||||
return Collections.emptyList(); | return Collections.emptyList(); |
} | } | ||||
private Optional<QualityGate> getShortLivingBranchQualityGate() { | private Optional<QualityGate> getShortLivingBranchQualityGate() { | ||||
if (analysisMetadataHolder.isShortLivingBranch()) { | |||||
if (analysisMetadataHolder.isShortLivingBranch() || analysisMetadataHolder.isPullRequest()) { | |||||
Optional<QualityGate> qualityGate = qualityGateService.findById(ShortLivingBranchQualityGate.ID); | Optional<QualityGate> qualityGate = qualityGateService.findById(ShortLivingBranchQualityGate.ID); | ||||
if (qualityGate.isPresent()) { | if (qualityGate.isPresent()) { | ||||
return qualityGate; | return qualityGate; |
@Override | @Override | ||||
public void execute() { | public void execute() { | ||||
// no notification on short living branch as there is no real Quality Gate on those | |||||
if (analysisMetadataHolder.isShortLivingBranch()) { | |||||
// no notification on short living branch and pull request as there is no real Quality Gate on those | |||||
if (analysisMetadataHolder.isShortLivingBranch() || analysisMetadataHolder.isPullRequest()) { | |||||
return; | return; | ||||
} | } | ||||
new DepthTraversalTypeAwareCrawler( | new DepthTraversalTypeAwareCrawler( |
import java.util.Optional; | import java.util.Optional; | ||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.function.Predicate; | import java.util.function.Predicate; | ||||
import javax.annotation.CheckForNull; | |||||
import org.sonar.api.issue.Issue; | import org.sonar.api.issue.Issue; | ||||
import org.sonar.api.utils.Duration; | import org.sonar.api.utils.Duration; | ||||
import org.sonar.core.issue.DefaultIssue; | import org.sonar.core.issue.DefaultIssue; | ||||
import org.sonar.server.issue.notification.NewIssuesStatistics; | import org.sonar.server.issue.notification.NewIssuesStatistics; | ||||
import org.sonar.server.notification.NotificationService; | import org.sonar.server.notification.NotificationService; | ||||
import static org.sonar.db.component.BranchType.PULL_REQUEST; | |||||
import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER; | import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER; | ||||
/** | /** | ||||
IssueChangeNotification changeNotification = new IssueChangeNotification(); | IssueChangeNotification changeNotification = new IssueChangeNotification(); | ||||
changeNotification.setRuleName(rules.getByKey(issue.ruleKey()).getName()); | changeNotification.setRuleName(rules.getByKey(issue.ruleKey()).getName()); | ||||
changeNotification.setIssue(issue); | changeNotification.setIssue(issue); | ||||
changeNotification.setProject(project.getPublicKey(), project.getName(), getBranchName()); | |||||
changeNotification.setProject(project.getPublicKey(), project.getName(), getBranchName(), getPullRequest()); | |||||
getComponentKey(issue).ifPresent(c -> changeNotification.setComponent(c.getPublicKey(), c.getName())); | getComponentKey(issue).ifPresent(c -> changeNotification.setComponent(c.getPublicKey(), c.getName())); | ||||
service.deliver(changeNotification); | service.deliver(changeNotification); | ||||
} | } | ||||
NewIssuesStatistics.Stats globalStatistics = statistics.globalStatistics(); | NewIssuesStatistics.Stats globalStatistics = statistics.globalStatistics(); | ||||
NewIssuesNotification notification = newIssuesNotificationFactory | NewIssuesNotification notification = newIssuesNotificationFactory | ||||
.newNewIssuesNotication() | .newNewIssuesNotication() | ||||
.setProject(project.getPublicKey(), project.getName(), getBranchName()) | |||||
.setProject(project.getPublicKey(), project.getName(), getBranchName(), getPullRequest()) | |||||
.setProjectVersion(project.getReportAttributes().getVersion()) | .setProjectVersion(project.getReportAttributes().getVersion()) | ||||
.setAnalysisDate(new Date(analysisDate)) | .setAnalysisDate(new Date(analysisDate)) | ||||
.setStatistics(project.getName(), globalStatistics) | .setStatistics(project.getName(), globalStatistics) | ||||
.newMyNewIssuesNotification() | .newMyNewIssuesNotification() | ||||
.setAssignee(assignee); | .setAssignee(assignee); | ||||
myNewIssuesNotification | myNewIssuesNotification | ||||
.setProject(project.getPublicKey(), project.getName(), getBranchName()) | |||||
.setProject(project.getPublicKey(), project.getName(), getBranchName(), getPullRequest()) | |||||
.setProjectVersion(project.getReportAttributes().getVersion()) | .setProjectVersion(project.getReportAttributes().getVersion()) | ||||
.setAnalysisDate(new Date(analysisDate)) | .setAnalysisDate(new Date(analysisDate)) | ||||
.setStatistics(project.getName(), assigneeStatistics) | .setStatistics(project.getName(), assigneeStatistics) | ||||
return "Send issue notifications"; | return "Send issue notifications"; | ||||
} | } | ||||
@CheckForNull | |||||
private String getBranchName() { | private String getBranchName() { | ||||
Branch branch = analysisMetadataHolder.getBranch(); | Branch branch = analysisMetadataHolder.getBranch(); | ||||
return branch.isMain() ? null : branch.getName(); | |||||
return branch.isMain() || branch.getType() == PULL_REQUEST ? null : branch.getName(); | |||||
} | |||||
@CheckForNull | |||||
private String getPullRequest() { | |||||
Branch branch = analysisMetadataHolder.getBranch(); | |||||
return branch.getType() == PULL_REQUEST ? analysisMetadataHolder.getPullRequestId() : null; | |||||
} | } | ||||
} | } |
this.componentDao = componentDao; | this.componentDao = componentDao; | ||||
} | } | ||||
public List<Block> parse(DbSession session, ComponentDto component, @Nullable String branch, @Nullable String duplicationsData) { | |||||
public List<Block> parse(DbSession session, ComponentDto component, @Nullable String branch, @Nullable String pullRequest, @Nullable String duplicationsData) { | |||||
Map<String, ComponentDto> componentsByKey = newHashMap(); | Map<String, ComponentDto> componentsByKey = newHashMap(); | ||||
List<Block> blocks = newArrayList(); | List<Block> blocks = newArrayList(); | ||||
if (duplicationsData != null) { | if (duplicationsData != null) { | ||||
String size = bCursor.getAttrValue("l"); | String size = bCursor.getAttrValue("l"); | ||||
String componentKey = bCursor.getAttrValue("r"); | String componentKey = bCursor.getAttrValue("r"); | ||||
if (from != null && size != null && componentKey != null) { | if (from != null && size != null && componentKey != null) { | ||||
duplications.add(createDuplication(componentsByKey, branch, from, size, componentKey, session)); | |||||
duplications.add(createDuplication(componentsByKey, branch, pullRequest, from, size, componentKey, session)); | |||||
} | } | ||||
} | } | ||||
Collections.sort(duplications, new DuplicationComparator(component.uuid(), component.projectUuid())); | Collections.sort(duplications, new DuplicationComparator(component.uuid(), component.projectUuid())); | ||||
return blocks; | return blocks; | ||||
} | } | ||||
private Duplication createDuplication(Map<String, ComponentDto> componentsByKey, @Nullable String branch, String from, String size, String componentDbKey, DbSession session) { | |||||
private Duplication createDuplication(Map<String, ComponentDto> componentsByKey, @Nullable String branch, @Nullable String pullRequest, String from, String size, | |||||
String componentDbKey, DbSession session) { | |||||
String componentKey = convertToKey(componentDbKey); | String componentKey = convertToKey(componentDbKey); | ||||
ComponentDto component = componentsByKey.get(componentKey); | ComponentDto component = componentsByKey.get(componentKey); | ||||
if (component == null) { | if (component == null) { | ||||
Optional<ComponentDto> componentDtoOptional = branch == null ? componentDao.selectByKey(session, componentKey) | |||||
: Optional.fromNullable(componentDao.selectByKeyAndBranch(session, componentKey, branch).orElseGet(null)); | |||||
Optional<ComponentDto> componentDtoOptional; | |||||
if (branch != null) { | |||||
componentDtoOptional = Optional.fromNullable(componentDao.selectByKeyAndBranch(session, componentKey, branch).orElseGet(null)); | |||||
} else if (pullRequest != null) { | |||||
componentDtoOptional = Optional.fromNullable(componentDao.selectByKeyAndPullRequest(session, componentKey, pullRequest).orElseGet(null)); | |||||
} else { | |||||
componentDtoOptional = componentDao.selectByKey(session, componentKey); | |||||
} | |||||
component = componentDtoOptional.isPresent() ? componentDtoOptional.get() : null; | component = componentDtoOptional.isPresent() ? componentDtoOptional.get() : null; | ||||
componentsByKey.put(componentKey, component); | componentsByKey.put(componentKey, component); | ||||
} | } |
import static com.google.common.base.Preconditions.checkArgument; | import static com.google.common.base.Preconditions.checkArgument; | ||||
import static org.sonar.server.component.ComponentFinder.ParamNames.UUID_AND_KEY; | import static org.sonar.server.component.ComponentFinder.ParamNames.UUID_AND_KEY; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_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.sonar.server.ws.WsUtils.writeProtobuf; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH; | |||||
public class ShowAction implements DuplicationsWsAction { | public class ShowAction implements DuplicationsWsAction { | ||||
private static final String PARAM_KEY = "key"; | |||||
private static final String PARAM_UUID = "uuid"; | |||||
private static final String PARAM_BRANCH = "branch"; | |||||
private static final String PARAM_PULL_REQUEST = "pullRequest"; | |||||
private final DbClient dbClient; | private final DbClient dbClient; | ||||
private final DuplicationsParser parser; | private final DuplicationsParser parser; | ||||
private final ShowResponseBuilder responseBuilder; | private final ShowResponseBuilder responseBuilder; | ||||
new Change("6.5", "The fields 'uuid', 'projectUuid', 'subProjectUuid' are deprecated in the response.")); | new Change("6.5", "The fields 'uuid', 'projectUuid', 'subProjectUuid' are deprecated in the response.")); | ||||
action | action | ||||
.createParam("key") | |||||
.createParam(PARAM_KEY) | |||||
.setDescription("File key") | .setDescription("File key") | ||||
.setExampleValue("my_project:/src/foo/Bar.php"); | .setExampleValue("my_project:/src/foo/Bar.php"); | ||||
action | action | ||||
.createParam("uuid") | |||||
.createParam(PARAM_UUID) | |||||
.setDeprecatedSince("6.5") | .setDeprecatedSince("6.5") | ||||
.setDescription("File ID. If provided, 'key' must not be provided.") | .setDescription("File ID. If provided, 'key' must not be provided.") | ||||
.setExampleValue("584a89f2-8037-4f7b-b82c-8b45d2d63fb2"); | .setExampleValue("584a89f2-8037-4f7b-b82c-8b45d2d63fb2"); | ||||
action | action | ||||
.createParam("branch") | |||||
.createParam(PARAM_BRANCH) | |||||
.setDescription("Branch key") | .setDescription("Branch key") | ||||
.setInternal(true) | .setInternal(true) | ||||
.setExampleValue(KEY_BRANCH_EXAMPLE_001); | .setExampleValue(KEY_BRANCH_EXAMPLE_001); | ||||
action | |||||
.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setInternal(true) | |||||
.setSince("7.1") | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001); | |||||
} | } | ||||
@Override | @Override | ||||
userSession.checkComponentPermission(UserRole.CODEVIEWER, component); | userSession.checkComponentPermission(UserRole.CODEVIEWER, component); | ||||
String duplications = findDataFromComponent(dbSession, component); | String duplications = findDataFromComponent(dbSession, component); | ||||
String branch = component.getBranch(); | String branch = component.getBranch(); | ||||
List<DuplicationsParser.Block> blocks = parser.parse(dbSession, component, branch, duplications); | |||||
writeProtobuf(responseBuilder.build(dbSession, blocks, branch), request, response); | |||||
String pullRequest = component.getPullRequest(); | |||||
List<DuplicationsParser.Block> blocks = parser.parse(dbSession, component, branch, pullRequest, duplications); | |||||
writeProtobuf(responseBuilder.build(dbSession, blocks, branch, pullRequest), request, response); | |||||
} | } | ||||
} | } | ||||
private ComponentDto loadComponent(DbSession dbSession, Request request) { | private ComponentDto loadComponent(DbSession dbSession, Request request) { | ||||
String componentUuid = request.param("uuid"); | |||||
String branch = request.param("branch"); | |||||
checkArgument(componentUuid == null || branch == null, "'%s' and '%s' parameters cannot be used at the same time", "uuid", PARAM_BRANCH); | |||||
if (branch == null) { | |||||
return componentFinder.getByUuidOrKey(dbSession, componentUuid, request.param("key"), UUID_AND_KEY); | |||||
String componentUuid = request.param(PARAM_UUID); | |||||
String branch = request.param(PARAM_BRANCH); | |||||
String pullRequest = request.param(PARAM_PULL_REQUEST); | |||||
checkArgument(componentUuid == null || (branch == null && pullRequest == null), "Parameter '%s' cannot be used at the same time as '%s' or '%s'", PARAM_UUID, | |||||
PARAM_BRANCH, PARAM_PULL_REQUEST); | |||||
if (branch == null && pullRequest == null) { | |||||
return componentFinder.getByUuidOrKey(dbSession, componentUuid, request.param(PARAM_KEY), UUID_AND_KEY); | |||||
} | } | ||||
return componentFinder.getByKeyAndOptionalBranch(dbSession, request.mandatoryParam("key"), branch); | |||||
return componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, request.mandatoryParam(PARAM_KEY), branch, pullRequest); | |||||
} | } | ||||
@CheckForNull | @CheckForNull |
this.componentDao = componentDao; | this.componentDao = componentDao; | ||||
} | } | ||||
ShowResponse build(DbSession session, List<DuplicationsParser.Block> blocks, @Nullable String branch) { | |||||
ShowResponse build(DbSession session, List<DuplicationsParser.Block> blocks, @Nullable String branch, @Nullable String pullRequest) { | |||||
ShowResponse.Builder response = ShowResponse.newBuilder(); | ShowResponse.Builder response = ShowResponse.newBuilder(); | ||||
Map<String, String> refByComponentKey = newHashMap(); | Map<String, String> refByComponentKey = newHashMap(); | ||||
blocks.stream() | blocks.stream() | ||||
.map(block -> toWsDuplication(block, refByComponentKey)) | .map(block -> toWsDuplication(block, refByComponentKey)) | ||||
.forEach(response::addDuplications); | .forEach(response::addDuplications); | ||||
writeFiles(session, response, refByComponentKey, branch); | |||||
writeFiles(session, response, refByComponentKey, branch, pullRequest); | |||||
return response.build(); | return response.build(); | ||||
} | } | ||||
return block; | return block; | ||||
} | } | ||||
private static Duplications.File toWsFile(ComponentDto file, @Nullable ComponentDto project, @Nullable ComponentDto subProject, @Nullable String branch) { | |||||
private static Duplications.File toWsFile(ComponentDto file, @Nullable ComponentDto project, @Nullable ComponentDto subProject, @Nullable String branch, | |||||
@Nullable String pullRequest) { | |||||
Duplications.File.Builder wsFile = Duplications.File.newBuilder(); | Duplications.File.Builder wsFile = Duplications.File.newBuilder(); | ||||
wsFile.setKey(file.getKey()); | wsFile.setKey(file.getKey()); | ||||
wsFile.setUuid(file.uuid()); | wsFile.setUuid(file.uuid()); | ||||
wsFile.setSubProjectUuid(subProject.uuid()); | wsFile.setSubProjectUuid(subProject.uuid()); | ||||
wsFile.setSubProjectName(subProject.longName()); | wsFile.setSubProjectName(subProject.longName()); | ||||
} | } | ||||
if (branch != null) { | |||||
wsFile.setBranch(branch); | |||||
} | |||||
setNullable(branch, wsFile::setBranch); | |||||
setNullable(pullRequest, wsFile::setPullRequest); | |||||
return wsFile; | return wsFile; | ||||
}); | }); | ||||
return wsFile.build(); | return wsFile.build(); | ||||
} | } | ||||
private void writeFiles(DbSession session, ShowResponse.Builder response, Map<String, String> refByComponentKey, @Nullable String branch) { | |||||
private void writeFiles(DbSession session, ShowResponse.Builder response, Map<String, String> refByComponentKey, @Nullable String branch, @Nullable String pullRequest) { | |||||
Map<String, ComponentDto> projectsByUuid = newHashMap(); | Map<String, ComponentDto> projectsByUuid = newHashMap(); | ||||
Map<String, ComponentDto> parentModulesByUuid = newHashMap(); | Map<String, ComponentDto> parentModulesByUuid = newHashMap(); | ||||
Map<String, Duplications.File> filesByRef = response.getMutableFiles(); | Map<String, Duplications.File> filesByRef = response.getMutableFiles(); | ||||
ComponentDto project = getProject(file.projectUuid(), projectsByUuid, session); | ComponentDto project = getProject(file.projectUuid(), projectsByUuid, session); | ||||
ComponentDto parentModule = getParentProject(file.getRootUuid(), parentModulesByUuid, session); | ComponentDto parentModule = getParentProject(file.getRootUuid(), parentModulesByUuid, session); | ||||
filesByRef.put(ref, toWsFile(file, project, parentModule, branch)); | |||||
filesByRef.put(ref, toWsFile(file, project, parentModule, branch, pullRequest)); | |||||
} | } | ||||
} | } | ||||
} | } |
Collection<String> componentRootUuids = request.getComponentRootUuids(); | Collection<String> componentRootUuids = request.getComponentRootUuids(); | ||||
Collection<String> componentRoots = request.getComponentRoots(); | Collection<String> componentRoots = request.getComponentRoots(); | ||||
String branch = request.getBranch(); | String branch = request.getBranch(); | ||||
String pullRequest = request.getPullRequest(); | |||||
boolean effectiveOnComponentOnly = false; | boolean effectiveOnComponentOnly = false; | ||||
if (componentRootUuids != null) { | if (componentRootUuids != null) { | ||||
allComponents.addAll(getComponentsFromUuids(session, componentRootUuids)); | allComponents.addAll(getComponentsFromUuids(session, componentRootUuids)); | ||||
} else if (componentRoots != null) { | } else if (componentRoots != null) { | ||||
allComponents.addAll(getComponentsFromKeys(session, componentRoots, branch)); | |||||
allComponents.addAll(getComponentsFromKeys(session, componentRoots, branch, pullRequest)); | |||||
} else if (components != null) { | } else if (components != null) { | ||||
allComponents.addAll(getComponentsFromKeys(session, components, branch)); | |||||
allComponents.addAll(getComponentsFromKeys(session, components, branch, pullRequest)); | |||||
effectiveOnComponentOnly = true; | effectiveOnComponentOnly = true; | ||||
} else if (componentUuids != null) { | } else if (componentUuids != null) { | ||||
allComponents.addAll(getComponentsFromUuids(session, componentUuids)); | allComponents.addAll(getComponentsFromUuids(session, componentUuids)); | ||||
effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly); | effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly); | ||||
} else if (componentKeys != null) { | } else if (componentKeys != null) { | ||||
allComponents.addAll(getComponentsFromKeys(session, componentKeys, branch)); | |||||
allComponents.addAll(getComponentsFromKeys(session, componentKeys, branch, pullRequest)); | |||||
effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly); | effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly); | ||||
} | } | ||||
.count() <= 1; | .count() <= 1; | ||||
} | } | ||||
private void addComponentParameters(IssueQuery.Builder builder, DbSession session, boolean onComponentOnly, | |||||
List<ComponentDto> components, SearchRequest request) { | |||||
private void addComponentParameters(IssueQuery.Builder builder, DbSession session, boolean onComponentOnly, List<ComponentDto> components, SearchRequest request) { | |||||
builder.onComponentOnly(onComponentOnly); | builder.onComponentOnly(onComponentOnly); | ||||
if (onComponentOnly) { | if (onComponentOnly) { | ||||
builder.componentUuids(components.stream().map(ComponentDto::uuid).collect(toList())); | builder.componentUuids(components.stream().map(ComponentDto::uuid).collect(toList())); | ||||
setBranch(builder, components.get(0), request.getBranch()); | |||||
setBranch(builder, components.get(0), request.getBranch(), request.getPullRequest()); | |||||
return; | return; | ||||
} | } | ||||
if (projectUuids != null) { | if (projectUuids != null) { | ||||
builder.projectUuids(projectUuids); | builder.projectUuids(projectUuids); | ||||
} else if (projectKeys != null) { | } else if (projectKeys != null) { | ||||
List<ComponentDto> projects = getComponentsFromKeys(session, projectKeys, request.getBranch()); | |||||
List<ComponentDto> projects = getComponentsFromKeys(session, projectKeys, request.getBranch(), request.getPullRequest()); | |||||
builder.projectUuids(projects.stream().map(IssueQueryFactory::toProjectUuid).collect(toList())); | builder.projectUuids(projects.stream().map(IssueQueryFactory::toProjectUuid).collect(toList())); | ||||
setBranch(builder, projects.get(0), request.getBranch()); | |||||
setBranch(builder, projects.get(0), request.getBranch(), request.getPullRequest()); | |||||
} | } | ||||
builder.moduleUuids(request.getModuleUuids()); | builder.moduleUuids(request.getModuleUuids()); | ||||
builder.directories(request.getDirectories()); | builder.directories(request.getDirectories()); | ||||
Set<String> qualifiers = components.stream().map(ComponentDto::qualifier).collect(toHashSet()); | Set<String> qualifiers = components.stream().map(ComponentDto::qualifier).collect(toHashSet()); | ||||
checkArgument(qualifiers.size() == 1, "All components must have the same qualifier, found %s", String.join(",", qualifiers)); | checkArgument(qualifiers.size() == 1, "All components must have the same qualifier, found %s", String.join(",", qualifiers)); | ||||
setBranch(builder, components.get(0), request.getBranch()); | |||||
setBranch(builder, components.get(0), request.getBranch(), request.getPullRequest()); | |||||
String qualifier = qualifiers.iterator().next(); | String qualifier = qualifiers.iterator().next(); | ||||
switch (qualifier) { | switch (qualifier) { | ||||
case Qualifiers.VIEW: | case Qualifiers.VIEW: | ||||
builder.directories(directoryPaths); | builder.directories(directoryPaths); | ||||
} | } | ||||
private List<ComponentDto> getComponentsFromKeys(DbSession dbSession, Collection<String> componentKeys, @Nullable String branch) { | |||||
List<ComponentDto> componentDtos = branch == null | |||||
? dbClient.componentDao().selectByKeys(dbSession, componentKeys) | |||||
: dbClient.componentDao().selectByKeysAndBranch(dbSession, componentKeys, branch); | |||||
private List<ComponentDto> getComponentsFromKeys(DbSession dbSession, Collection<String> componentKeys, @Nullable String branch, @Nullable String pullRequest) { | |||||
List<ComponentDto> componentDtos; | |||||
if (branch != null) { | |||||
componentDtos = dbClient.componentDao().selectByKeysAndBranch(dbSession, componentKeys, branch); | |||||
} else if (pullRequest != null) { | |||||
componentDtos = dbClient.componentDao().selectByKeysAndPullRequest(dbSession, componentKeys, pullRequest); | |||||
} else { | |||||
componentDtos = dbClient.componentDao().selectByKeys(dbSession, componentKeys); | |||||
} | |||||
if (!componentKeys.isEmpty() && componentDtos.isEmpty()) { | if (!componentKeys.isEmpty() && componentDtos.isEmpty()) { | ||||
return singletonList(UNKNOWN_COMPONENT); | return singletonList(UNKNOWN_COMPONENT); | ||||
} | } | ||||
return mainBranchProjectUuid == null ? componentDto.projectUuid() : mainBranchProjectUuid; | return mainBranchProjectUuid == null ? componentDto.projectUuid() : mainBranchProjectUuid; | ||||
} | } | ||||
private static void setBranch(IssueQuery.Builder builder, ComponentDto component, @Nullable String branch) { | |||||
builder.branchUuid(branch == null ? null : component.projectUuid()); | |||||
builder.mainBranch(branch == null || component.equals(UNKNOWN_COMPONENT) || !branch.equals(component.getBranch())); | |||||
private static void setBranch(IssueQuery.Builder builder, ComponentDto component, @Nullable String branch, @Nullable String pullRequest) { | |||||
builder.branchUuid(branch == null && pullRequest == null ? null : component.projectUuid()); | |||||
builder.mainBranch(UNKNOWN_COMPONENT.equals(component) | |||||
|| (branch == null && pullRequest == null) | |||||
|| (branch != null && !branch.equals(component.getBranch())) | |||||
|| (pullRequest != null && !pullRequest.equals(component.getPullRequest()))); | |||||
} | } | ||||
} | } |
private List<String> moduleUuids; | private List<String> moduleUuids; | ||||
private Boolean onComponentOnly; | private Boolean onComponentOnly; | ||||
private String branch; | private String branch; | ||||
private String pullRequest; | |||||
private String organization; | private String organization; | ||||
private Integer page; | private Integer page; | ||||
private Integer pageSize; | private Integer pageSize; | ||||
this.branch = branch; | this.branch = branch; | ||||
return this; | return this; | ||||
} | } | ||||
@CheckForNull | |||||
public String getPullRequest() { | |||||
return pullRequest; | |||||
} | |||||
public SearchRequest setPullRequest(@Nullable String pullRequest) { | |||||
this.pullRequest = pullRequest; | |||||
return this; | |||||
} | |||||
} | } |
static final String FIELD_PROJECT_VERSION = "projectVersion"; | static final String FIELD_PROJECT_VERSION = "projectVersion"; | ||||
static final String FIELD_ASSIGNEE = "assignee"; | static final String FIELD_ASSIGNEE = "assignee"; | ||||
static final String FIELD_BRANCH = "branch"; | static final String FIELD_BRANCH = "branch"; | ||||
static final String FIELD_PULL_REQUEST = "pullRequest"; | |||||
protected final EmailSettings settings; | protected final EmailSettings settings; | ||||
protected final I18n i18n; | protected final I18n i18n; | ||||
} | } | ||||
String projectName = checkNotNull(notification.getFieldValue(FIELD_PROJECT_NAME)); | String projectName = checkNotNull(notification.getFieldValue(FIELD_PROJECT_NAME)); | ||||
String branchName = notification.getFieldValue(FIELD_BRANCH); | String branchName = notification.getFieldValue(FIELD_BRANCH); | ||||
String pullRequest = notification.getFieldValue(FIELD_PULL_REQUEST); | |||||
StringBuilder message = new StringBuilder(); | StringBuilder message = new StringBuilder(); | ||||
message.append("Project: ").append(projectName).append(NEW_LINE); | message.append("Project: ").append(projectName).append(NEW_LINE); | ||||
if (branchName != null) { | if (branchName != null) { | ||||
message.append("Branch: ").append(branchName).append(NEW_LINE); | message.append("Branch: ").append(branchName).append(NEW_LINE); | ||||
} | } | ||||
if (pullRequest!= null) { | |||||
message.append("Pull request: ").append(pullRequest).append(NEW_LINE); | |||||
} | |||||
String version = notification.getFieldValue(FIELD_PROJECT_VERSION); | String version = notification.getFieldValue(FIELD_PROJECT_VERSION); | ||||
if (version != null) { | if (version != null) { | ||||
message.append("Version: ").append(version).append(NEW_LINE); | message.append("Version: ").append(version).append(NEW_LINE); | ||||
if (branchName != null) { | if (branchName != null) { | ||||
url += "&branch=" + encode(branchName); | url += "&branch=" + encode(branchName); | ||||
} | } | ||||
String pullRequest = notification.getFieldValue(FIELD_PULL_REQUEST); | |||||
if (pullRequest != null) { | |||||
url += "&pullRequest=" + encode(pullRequest); | |||||
} | |||||
url += "&createdAt=" + encode(DateUtils.formatDateTime(date)); | url += "&createdAt=" + encode(DateUtils.formatDateTime(date)); | ||||
message | message | ||||
.append("More details at: ") | .append("More details at: ") |
import org.sonar.core.issue.FieldDiffs; | import org.sonar.core.issue.FieldDiffs; | ||||
import org.sonar.db.component.ComponentDto; | import org.sonar.db.component.ComponentDto; | ||||
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_BRANCH; | |||||
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_PROJECT_KEY; | |||||
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_PROJECT_NAME; | |||||
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_PULL_REQUEST; | |||||
public class IssueChangeNotification extends Notification { | public class IssueChangeNotification extends Notification { | ||||
public static final String TYPE = "issue-changes"; | public static final String TYPE = "issue-changes"; | ||||
} | } | ||||
public IssueChangeNotification setProject(ComponentDto project) { | public IssueChangeNotification setProject(ComponentDto project) { | ||||
return setProject(project.getKey(), project.name(), project.getBranch()); | |||||
return setProject(project.getKey(), project.name(), project.getBranch(), project.getPullRequest()); | |||||
} | } | ||||
public IssueChangeNotification setProject(String projectKey, String projectName, @Nullable String branch) { | |||||
setFieldValue("projectName", projectName); | |||||
setFieldValue("projectKey", projectKey); | |||||
public IssueChangeNotification setProject(String projectKey, String projectName, @Nullable String branch, @Nullable String pullRequest) { | |||||
setFieldValue(FIELD_PROJECT_NAME, projectName); | |||||
setFieldValue(FIELD_PROJECT_KEY, projectKey); | |||||
if (branch != null) { | if (branch != null) { | ||||
setFieldValue("branch", branch); | |||||
setFieldValue(FIELD_BRANCH, branch); | |||||
} | |||||
if (pullRequest != null) { | |||||
setFieldValue(FIELD_PULL_REQUEST, pullRequest); | |||||
} | } | ||||
return this; | return this; | ||||
} | } |
import org.sonar.plugins.emailnotifications.api.EmailTemplate; | import org.sonar.plugins.emailnotifications.api.EmailTemplate; | ||||
import static java.net.URLEncoder.encode; | import static java.net.URLEncoder.encode; | ||||
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_BRANCH; | |||||
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_PULL_REQUEST; | |||||
/** | /** | ||||
* Creates email message for notification "issue-changes". | * Creates email message for notification "issue-changes". | ||||
private static void appendHeader(Notification notif, StringBuilder sb) { | private static void appendHeader(Notification notif, StringBuilder sb) { | ||||
appendLine(sb, StringUtils.defaultString(notif.getFieldValue("componentName"), notif.getFieldValue("componentKey"))); | appendLine(sb, StringUtils.defaultString(notif.getFieldValue("componentName"), notif.getFieldValue("componentKey"))); | ||||
String branchName = notif.getFieldValue("branch"); | |||||
String branchName = notif.getFieldValue(FIELD_BRANCH); | |||||
if (branchName != null) { | if (branchName != null) { | ||||
appendField(sb, "Branch", null, branchName); | appendField(sb, "Branch", null, branchName); | ||||
} | } | ||||
String pullRequest = notif.getFieldValue(FIELD_PULL_REQUEST); | |||||
if (pullRequest != null) { | |||||
appendField(sb, "Pull request", null, pullRequest); | |||||
} | |||||
appendField(sb, "Rule", null, notif.getFieldValue("ruleName")); | appendField(sb, "Rule", null, notif.getFieldValue("ruleName")); | ||||
appendField(sb, "Message", null, notif.getFieldValue("message")); | appendField(sb, "Message", null, notif.getFieldValue("message")); | ||||
} | } | ||||
.append("/project/issues?id=").append(encode(notification.getFieldValue("projectKey"), "UTF-8")) | .append("/project/issues?id=").append(encode(notification.getFieldValue("projectKey"), "UTF-8")) | ||||
.append("&issues=").append(issueKey) | .append("&issues=").append(issueKey) | ||||
.append("&open=").append(issueKey); | .append("&open=").append(issueKey); | ||||
String branchName = notification.getFieldValue("branch"); | |||||
String branchName = notification.getFieldValue(FIELD_BRANCH); | |||||
if (branchName != null) { | if (branchName != null) { | ||||
sb.append("&branch=").append(branchName); | sb.append("&branch=").append(branchName); | ||||
} | } | ||||
String pullRequest = notification.getFieldValue(FIELD_PULL_REQUEST); | |||||
if (pullRequest != null) { | |||||
sb.append("&pullRequest=").append(pullRequest); | |||||
} | |||||
sb.append(NEW_LINE); | sb.append(NEW_LINE); | ||||
} catch (UnsupportedEncodingException e) { | } catch (UnsupportedEncodingException e) { | ||||
throw new IllegalStateException("Encoding not supported", e); | throw new IllegalStateException("Encoding not supported", e); |
settings.getServerBaseURL(), | settings.getServerBaseURL(), | ||||
encode(projectKey), | encode(projectKey), | ||||
encode(assignee)); | encode(assignee)); | ||||
String branchName = notification.getFieldValue("branch"); | |||||
String branchName = notification.getFieldValue(FIELD_BRANCH); | |||||
if (branchName != null) { | if (branchName != null) { | ||||
url += "&branch=" + encode(branchName); | url += "&branch=" + encode(branchName); | ||||
} | } | ||||
String pullRequest = notification.getFieldValue(FIELD_PULL_REQUEST); | |||||
if (pullRequest != null) { | |||||
url += "&pullRequest=" + encode(pullRequest); | |||||
} | |||||
url += "&createdAt=" + encode(DateUtils.formatDateTime(date)); | url += "&createdAt=" + encode(DateUtils.formatDateTime(date)); | ||||
message | message | ||||
.append("More details at: ") | .append("More details at: ") |
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_BRANCH; | import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_BRANCH; | ||||
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_PROJECT_VERSION; | import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_PROJECT_VERSION; | ||||
import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate.FIELD_PULL_REQUEST; | |||||
import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_DATE; | import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_DATE; | ||||
import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_KEY; | import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_KEY; | ||||
import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_NAME; | import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_NAME; | ||||
return this; | return this; | ||||
} | } | ||||
public NewIssuesNotification setProject(String projectKey, String projectName, @Nullable String branchName) { | |||||
public NewIssuesNotification setProject(String projectKey, String projectName, @Nullable String branchName, @Nullable String pullRequest) { | |||||
setFieldValue(FIELD_PROJECT_NAME, projectName); | setFieldValue(FIELD_PROJECT_NAME, projectName); | ||||
setFieldValue(FIELD_PROJECT_KEY, projectKey); | setFieldValue(FIELD_PROJECT_KEY, projectKey); | ||||
if (branchName != null) { | if (branchName != null) { | ||||
setFieldValue(FIELD_BRANCH, branchName); | setFieldValue(FIELD_BRANCH, branchName); | ||||
} | } | ||||
if (pullRequest != null) { | |||||
setFieldValue(FIELD_PULL_REQUEST, pullRequest); | |||||
} | |||||
return this; | return this; | ||||
} | } | ||||
import static org.sonar.server.es.SearchOptions.MAX_LIMIT; | import static org.sonar.server.es.SearchOptions.MAX_LIMIT; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | 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.sonar.server.ws.WsUtils.writeProtobuf; | ||||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_SEARCH; | import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_SEARCH; | ||||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_FACET_MODE_DEBT; | import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_FACET_MODE_DEBT; | ||||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS; | import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS; | ||||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_KEYS; | import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_KEYS; | ||||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_UUIDS; | import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_UUIDS; | ||||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PULL_REQUEST; | |||||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_REPORTERS; | import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_REPORTERS; | ||||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLUTIONS; | import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLUTIONS; | ||||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLVED; | import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLVED; | ||||
.setInternal(true) | .setInternal(true) | ||||
.setSince("6.6"); | .setSince("6.6"); | ||||
action.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001) | |||||
.setInternal(true) | |||||
.setSince("7.1"); | |||||
action.createParam(PARAM_ORGANIZATION) | action.createParam(PARAM_ORGANIZATION) | ||||
.setDescription("Organization key") | .setDescription("Organization key") | ||||
.setRequired(false) | .setRequired(false) | ||||
.setModuleUuids(request.paramAsStrings(PARAM_MODULE_UUIDS)) | .setModuleUuids(request.paramAsStrings(PARAM_MODULE_UUIDS)) | ||||
.setOnComponentOnly(request.paramAsBoolean(PARAM_ON_COMPONENT_ONLY)) | .setOnComponentOnly(request.paramAsBoolean(PARAM_ON_COMPONENT_ONLY)) | ||||
.setBranch(request.param(PARAM_BRANCH)) | .setBranch(request.param(PARAM_BRANCH)) | ||||
.setPullRequest(request.param(PARAM_PULL_REQUEST)) | |||||
.setOrganization(request.param(PARAM_ORGANIZATION)) | .setOrganization(request.param(PARAM_ORGANIZATION)) | ||||
.setPage(request.mandatoryParamAsInt(Param.PAGE)) | .setPage(request.mandatoryParamAsInt(Param.PAGE)) | ||||
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)) | .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)) |
issueBuilder.setOrganization(data.getOrganizationKey(component.getOrganizationUuid())); | issueBuilder.setOrganization(data.getOrganizationKey(component.getOrganizationUuid())); | ||||
issueBuilder.setComponent(component.getKey()); | issueBuilder.setComponent(component.getKey()); | ||||
setNullable(component.getBranch(), issueBuilder::setBranch); | setNullable(component.getBranch(), issueBuilder::setBranch); | ||||
setNullable(component.getPullRequest(), issueBuilder::setPullRequest); | |||||
ComponentDto project = data.getComponentByUuid(dto.getProjectUuid()); | ComponentDto project = data.getComponentByUuid(dto.getProjectUuid()); | ||||
if (project != null) { | if (project != null) { | ||||
issueBuilder.setProject(project.getKey()); | issueBuilder.setProject(project.getKey()); | ||||
.setLongName(nullToEmpty(dto.longName())) | .setLongName(nullToEmpty(dto.longName())) | ||||
.setEnabled(dto.isEnabled()); | .setEnabled(dto.isEnabled()); | ||||
setNullable(dto.getBranch(), builder::setBranch); | setNullable(dto.getBranch(), builder::setBranch); | ||||
setNullable(dto.getPullRequest(), builder::setPullRequest); | |||||
String path = dto.path(); | String path = dto.path(); | ||||
// path is not applicable to the components that are not files. | // path is not applicable to the components that are not files. | ||||
// Value must not be "" in this case. | // Value must not be "" in this case. |
@Override | @Override | ||||
public QualityGate loadQualityGate(DbSession dbSession, OrganizationDto organization, ComponentDto project, BranchDto branch) { | public QualityGate loadQualityGate(DbSession dbSession, OrganizationDto organization, ComponentDto project, BranchDto branch) { | ||||
if (branch.getBranchType() == BranchType.SHORT) { | |||||
if (branch.getBranchType() == BranchType.SHORT || branch.getBranchType() == BranchType.PULL_REQUEST) { | |||||
return ShortLivingBranchQualityGate.GATE; | return ShortLivingBranchQualityGate.GATE; | ||||
} | } | ||||
import static java.util.Collections.singletonList; | import static java.util.Collections.singletonList; | ||||
import static java.util.Collections.singletonMap; | import static java.util.Collections.singletonMap; | ||||
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; | import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; | ||||
import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_COMPONENT; | |||||
import static org.sonar.server.measure.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createAdditionalFieldsParameter; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createDeveloperParameters; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createMetricKeysParameter; | |||||
import static org.sonar.server.measure.ws.MetricDtoToWsMetric.metricDtoToWsMetric; | |||||
import static org.sonar.server.measure.ws.SnapshotDtoToWsPeriods.snapshotToWsPeriods; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | |||||
import static org.sonar.server.ws.WsUtils.checkRequest; | |||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||||
import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_KEY; | |||||
import static org.sonar.server.component.ws.MeasuresWsParameters.ACTION_COMPONENT; | import static org.sonar.server.component.ws.MeasuresWsParameters.ACTION_COMPONENT; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_METRICS; | import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_METRICS; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_PERIODS; | import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_PERIODS; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_DEVELOPER_ID; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_DEVELOPER_ID; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_DEVELOPER_KEY; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_DEVELOPER_KEY; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_KEYS; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_KEYS; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_PULL_REQUEST; | |||||
import static org.sonar.server.measure.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createAdditionalFieldsParameter; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createDeveloperParameters; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createMetricKeysParameter; | |||||
import static org.sonar.server.measure.ws.MetricDtoToWsMetric.metricDtoToWsMetric; | |||||
import static org.sonar.server.measure.ws.SnapshotDtoToWsPeriods.snapshotToWsPeriods; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | |||||
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.checkRequest; | |||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||||
public class ComponentAction implements MeasuresWsAction { | public class ComponentAction implements MeasuresWsAction { | ||||
private static final Set<String> QUALIFIERS_ELIGIBLE_FOR_BEST_VALUE = ImmutableSortedSet.of(Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE); | private static final Set<String> QUALIFIERS_ELIGIBLE_FOR_BEST_VALUE = ImmutableSortedSet.of(Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE); | ||||
.setInternal(true) | .setInternal(true) | ||||
.setSince("6.6"); | .setSince("6.6"); | ||||
action.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001) | |||||
.setInternal(true) | |||||
.setSince("7.1"); | |||||
createMetricKeysParameter(action); | createMetricKeysParameter(action); | ||||
createAdditionalFieldsParameter(action); | createAdditionalFieldsParameter(action); | ||||
createDeveloperParameters(action); | createDeveloperParameters(action); | ||||
String componentKey = request.getComponent(); | String componentKey = request.getComponent(); | ||||
String componentId = request.getComponentId(); | String componentId = request.getComponentId(); | ||||
String branch = request.getBranch(); | String branch = request.getBranch(); | ||||
checkArgument(componentId == null || branch == null, "'%s' and '%s' parameters cannot be used at the same time", DEPRECATED_PARAM_COMPONENT_ID, PARAM_BRANCH); | |||||
return branch == null | |||||
? componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, COMPONENT_ID_AND_COMPONENT) | |||||
: componentFinder.getByKeyAndBranch(dbSession, componentKey, branch); | |||||
String pullRequest = request.getPullRequest(); | |||||
checkArgument(componentId == null || (branch == null && pullRequest == null), "Parameter '%s' cannot be used at the same time as '%s' or '%s'", | |||||
DEPRECATED_PARAM_COMPONENT_ID, PARAM_BRANCH, PARAM_PULL_REQUEST); | |||||
if (branch == null && pullRequest == null) { | |||||
return componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, COMPONENT_ID_AND_KEY); | |||||
} | |||||
checkRequest(componentKey != null, "The '%s' parameter is missing", PARAM_COMPONENT); | |||||
return componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, componentKey, branch, pullRequest); | |||||
} | } | ||||
private Optional<ComponentDto> getReferenceComponent(DbSession dbSession, ComponentDto component) { | private Optional<ComponentDto> getReferenceComponent(DbSession dbSession, ComponentDto component) { | ||||
.setComponentId(request.param(DEPRECATED_PARAM_COMPONENT_ID)) | .setComponentId(request.param(DEPRECATED_PARAM_COMPONENT_ID)) | ||||
.setComponent(request.param(PARAM_COMPONENT)) | .setComponent(request.param(PARAM_COMPONENT)) | ||||
.setBranch(request.param(PARAM_BRANCH)) | .setBranch(request.param(PARAM_BRANCH)) | ||||
.setPullRequest(request.param(PARAM_PULL_REQUEST)) | |||||
.setAdditionalFields(request.paramAsStrings(PARAM_ADDITIONAL_FIELDS)) | .setAdditionalFields(request.paramAsStrings(PARAM_ADDITIONAL_FIELDS)) | ||||
.setMetricKeys(request.mandatoryParamAsStrings(PARAM_METRIC_KEYS)); | .setMetricKeys(request.mandatoryParamAsStrings(PARAM_METRIC_KEYS)); | ||||
checkRequest(!componentRequest.getMetricKeys().isEmpty(), "At least one metric key must be provided"); | checkRequest(!componentRequest.getMetricKeys().isEmpty(), "At least one metric key must be provided"); | ||||
private String componentId; | private String componentId; | ||||
private String component; | private String component; | ||||
private String branch; | private String branch; | ||||
private String pullRequest; | |||||
private List<String> metricKeys; | private List<String> metricKeys; | ||||
private List<String> additionalFields; | private List<String> additionalFields; | ||||
private String developerId; | private String developerId; | ||||
return this; | return this; | ||||
} | } | ||||
@CheckForNull | |||||
public String getPullRequest() { | |||||
return pullRequest; | |||||
} | |||||
public ComponentRequest setPullRequest(@Nullable String pullRequest) { | |||||
this.pullRequest = pullRequest; | |||||
return this; | |||||
} | |||||
private List<String> getMetricKeys() { | private List<String> getMetricKeys() { | ||||
return metricKeys; | return metricKeys; | ||||
} | } |
.setName(component.name()) | .setName(component.name()) | ||||
.setQualifier(component.qualifier()); | .setQualifier(component.qualifier()); | ||||
Protobuf.setNullable(component.getBranch(), wsComponent::setBranch); | Protobuf.setNullable(component.getBranch(), wsComponent::setBranch); | ||||
Protobuf.setNullable(component.getPullRequest(), wsComponent::setPullRequest); | |||||
Protobuf.setNullable(component.path(), wsComponent::setPath); | Protobuf.setNullable(component.path(), wsComponent::setPath); | ||||
Protobuf.setNullable(component.description(), wsComponent::setDescription); | Protobuf.setNullable(component.description(), wsComponent::setDescription); | ||||
Protobuf.setNullable(component.language(), wsComponent::setLanguage); | Protobuf.setNullable(component.language(), wsComponent::setLanguage); |
import static org.sonar.db.component.ComponentTreeQuery.Strategy.CHILDREN; | import static org.sonar.db.component.ComponentTreeQuery.Strategy.CHILDREN; | ||||
import static org.sonar.db.component.ComponentTreeQuery.Strategy.LEAVES; | import static org.sonar.db.component.ComponentTreeQuery.Strategy.LEAVES; | ||||
import static org.sonar.server.component.ComponentFinder.ParamNames.BASE_COMPONENT_ID_AND_KEY; | import static org.sonar.server.component.ComponentFinder.ParamNames.BASE_COMPONENT_ID_AND_KEY; | ||||
import static org.sonar.server.component.ComponentFinder.ParamNames.DEVELOPER_ID_AND_KEY; | |||||
import static org.sonar.server.measure.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; | |||||
import static org.sonar.server.measure.ws.MeasureDtoToWsMeasure.updateMeasureBuilder; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createAdditionalFieldsParameter; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createDeveloperParameters; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createMetricKeysParameter; | |||||
import static org.sonar.server.measure.ws.MetricDtoToWsMetric.metricDtoToWsMetric; | |||||
import static org.sonar.server.measure.ws.SnapshotDtoToWsPeriods.snapshotToWsPeriods; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | |||||
import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter; | |||||
import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext; | |||||
import static org.sonar.server.ws.WsUtils.checkRequest; | |||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||||
import static org.sonar.server.component.ws.MeasuresWsParameters.ACTION_COMPONENT_TREE; | import static org.sonar.server.component.ws.MeasuresWsParameters.ACTION_COMPONENT_TREE; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_METRICS; | import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_METRICS; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_PERIODS; | import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_PERIODS; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_PERIOD_SORT; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_PERIOD_SORT; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_SORT; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_SORT; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_SORT_FILTER; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_SORT_FILTER; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_PULL_REQUEST; | |||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_QUALIFIERS; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_QUALIFIERS; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_STRATEGY; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_STRATEGY; | ||||
import static org.sonar.server.measure.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; | |||||
import static org.sonar.server.measure.ws.MeasureDtoToWsMeasure.updateMeasureBuilder; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createAdditionalFieldsParameter; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createDeveloperParameters; | |||||
import static org.sonar.server.measure.ws.MeasuresWsParametersBuilder.createMetricKeysParameter; | |||||
import static org.sonar.server.measure.ws.MetricDtoToWsMetric.metricDtoToWsMetric; | |||||
import static org.sonar.server.measure.ws.SnapshotDtoToWsPeriods.snapshotToWsPeriods; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | |||||
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.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext; | |||||
import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter; | |||||
import static org.sonar.server.ws.WsUtils.checkRequest; | |||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||||
/** | /** | ||||
* <p>Navigate through components based on different strategy with specified measures. | * <p>Navigate through components based on different strategy with specified measures. | ||||
.setInternal(true) | .setInternal(true) | ||||
.setSince("6.6"); | .setSince("6.6"); | ||||
action.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001) | |||||
.setInternal(true) | |||||
.setSince("7.1"); | |||||
action.createParam(PARAM_METRIC_SORT) | action.createParam(PARAM_METRIC_SORT) | ||||
.setDescription( | .setDescription( | ||||
format("Metric key to sort by. The '%s' parameter must contain the '%s' or '%s' value. It must be part of the '%s' parameter", Param.SORT, METRIC_SORT, METRIC_PERIOD_SORT, | format("Metric key to sort by. The '%s' parameter must contain the '%s' or '%s' value. It must be part of the '%s' parameter", Param.SORT, METRIC_SORT, METRIC_PERIOD_SORT, | ||||
.setBaseComponentId(request.param(DEPRECATED_PARAM_BASE_COMPONENT_ID)) | .setBaseComponentId(request.param(DEPRECATED_PARAM_BASE_COMPONENT_ID)) | ||||
.setComponent(request.param(PARAM_COMPONENT)) | .setComponent(request.param(PARAM_COMPONENT)) | ||||
.setBranch(request.param(PARAM_BRANCH)) | .setBranch(request.param(PARAM_BRANCH)) | ||||
.setPullRequest(request.param(PARAM_PULL_REQUEST)) | |||||
.setMetricKeys(metricKeys) | .setMetricKeys(metricKeys) | ||||
.setStrategy(request.mandatoryParam(PARAM_STRATEGY)) | .setStrategy(request.mandatoryParam(PARAM_STRATEGY)) | ||||
.setQualifiers(request.paramAsStrings(PARAM_QUALIFIERS)) | .setQualifiers(request.paramAsStrings(PARAM_QUALIFIERS)) | ||||
} | } | ||||
private ComponentDto loadComponent(DbSession dbSession, ComponentTreeRequest request) { | private ComponentDto loadComponent(DbSession dbSession, ComponentTreeRequest request) { | ||||
String componentKey = request.getComponent(); | |||||
String componentId = request.getBaseComponentId(); | String componentId = request.getBaseComponentId(); | ||||
String componentKey = request.getComponent(); | |||||
String branch = request.getBranch(); | String branch = request.getBranch(); | ||||
checkArgument(componentId == null || branch == null, "'%s' and '%s' parameters cannot be used at the same time", DEPRECATED_PARAM_BASE_COMPONENT_ID, PARAM_BRANCH); | |||||
return branch == null | |||||
? componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, BASE_COMPONENT_ID_AND_KEY) | |||||
: componentFinder.getByKeyAndBranch(dbSession, componentKey, branch); | |||||
String pullRequest = request.getPullRequest(); | |||||
checkArgument(componentId == null || (branch == null && pullRequest == null), "Parameter '%s' cannot be used at the same time as '%s' or '%s'", | |||||
DEPRECATED_PARAM_BASE_COMPONENT_ID, PARAM_BRANCH, PARAM_PULL_REQUEST); | |||||
if (branch == null && pullRequest == null) { | |||||
return componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, BASE_COMPONENT_ID_AND_KEY); | |||||
} | |||||
checkRequest(componentKey != null, "The '%s' parameter is missing", PARAM_COMPONENT); | |||||
return componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, componentKey, branch, pullRequest); | |||||
} | } | ||||
private Map<String, ComponentDto> searchReferenceComponentsById(DbSession dbSession, List<ComponentDto> components) { | private Map<String, ComponentDto> searchReferenceComponentsById(DbSession dbSession, List<ComponentDto> components) { |
private String baseComponentId; | private String baseComponentId; | ||||
private String component; | private String component; | ||||
private String branch; | private String branch; | ||||
private String pullRequest; | |||||
private String strategy; | private String strategy; | ||||
private List<String> qualifiers; | private List<String> qualifiers; | ||||
private List<String> additionalFields; | private List<String> additionalFields; | ||||
return this; | return this; | ||||
} | } | ||||
@CheckForNull | |||||
public String getPullRequest() { | |||||
return pullRequest; | |||||
} | |||||
public ComponentTreeRequest setPullRequest(@Nullable String pullRequest) { | |||||
this.pullRequest = pullRequest; | |||||
return this; | |||||
} | |||||
@CheckForNull | @CheckForNull | ||||
public String getStrategy() { | public String getStrategy() { | ||||
return strategy; | return strategy; |
import java.util.Set; | import java.util.Set; | ||||
import java.util.function.Function; | import java.util.function.Function; | ||||
import java.util.stream.Stream; | import java.util.stream.Stream; | ||||
import javax.annotation.CheckForNull; | |||||
import javax.annotation.Nullable; | |||||
import org.sonar.api.server.ws.Request; | import org.sonar.api.server.ws.Request; | ||||
import org.sonar.api.server.ws.Response; | import org.sonar.api.server.ws.Response; | ||||
import org.sonar.api.server.ws.WebService; | import org.sonar.api.server.ws.WebService; | ||||
import org.sonar.server.ws.KeyExamples; | import org.sonar.server.ws.KeyExamples; | ||||
import org.sonarqube.ws.Measures.SearchHistoryResponse; | import org.sonarqube.ws.Measures.SearchHistoryResponse; | ||||
import javax.annotation.CheckForNull; | |||||
import javax.annotation.Nullable; | |||||
import static java.lang.String.format; | import static java.lang.String.format; | ||||
import static org.sonar.api.utils.DateUtils.parseEndingDateOrDateTime; | import static org.sonar.api.utils.DateUtils.parseEndingDateOrDateTime; | ||||
import static org.sonar.api.utils.DateUtils.parseStartingDateOrDateTime; | import static org.sonar.api.utils.DateUtils.parseStartingDateOrDateTime; | ||||
import static org.sonar.core.util.Protobuf.setNullable; | import static org.sonar.core.util.Protobuf.setNullable; | ||||
import static org.sonar.db.component.SnapshotDto.STATUS_PROCESSED; | import static org.sonar.db.component.SnapshotDto.STATUS_PROCESSED; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | |||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||||
import static org.sonar.server.component.ws.MeasuresWsParameters.ACTION_SEARCH_HISTORY; | import static org.sonar.server.component.ws.MeasuresWsParameters.ACTION_SEARCH_HISTORY; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_COMPONENT; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_COMPONENT; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_FROM; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_FROM; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRICS; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRICS; | ||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_PULL_REQUEST; | |||||
import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_TO; | import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_TO; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001; | |||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||||
public class SearchHistoryAction implements MeasuresWsAction { | public class SearchHistoryAction implements MeasuresWsAction { | ||||
this.userSession = userSession; | this.userSession = userSession; | ||||
} | } | ||||
private static SearchHistoryRequest toWsRequest(Request request) { | |||||
return SearchHistoryRequest.builder() | |||||
.setComponent(request.mandatoryParam(PARAM_COMPONENT)) | |||||
.setBranch(request.param(PARAM_BRANCH)) | |||||
.setMetrics(request.mandatoryParamAsStrings(PARAM_METRICS)) | |||||
.setFrom(request.param(PARAM_FROM)) | |||||
.setTo(request.param(PARAM_TO)) | |||||
.setPage(request.mandatoryParamAsInt(Param.PAGE)) | |||||
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)) | |||||
.build(); | |||||
} | |||||
@Override | @Override | ||||
public void define(WebService.NewController context) { | public void define(WebService.NewController context) { | ||||
WebService.NewAction action = context.createAction(ACTION_SEARCH_HISTORY) | WebService.NewAction action = context.createAction(ACTION_SEARCH_HISTORY) | ||||
.setInternal(true) | .setInternal(true) | ||||
.setExampleValue(KEY_BRANCH_EXAMPLE_001); | .setExampleValue(KEY_BRANCH_EXAMPLE_001); | ||||
action.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setSince("7.1") | |||||
.setInternal(true) | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001); | |||||
action.createParam(PARAM_METRICS) | action.createParam(PARAM_METRICS) | ||||
.setDescription("Comma-separated list of metric keys") | .setDescription("Comma-separated list of metric keys") | ||||
.setRequired(true) | .setRequired(true) | ||||
writeProtobuf(searchHistoryResponse, request, response); | writeProtobuf(searchHistoryResponse, request, response); | ||||
} | } | ||||
private static SearchHistoryRequest toWsRequest(Request request) { | |||||
return SearchHistoryRequest.builder() | |||||
.setComponent(request.mandatoryParam(PARAM_COMPONENT)) | |||||
.setBranch(request.param(PARAM_BRANCH)) | |||||
.setPullRequest(request.param(PARAM_PULL_REQUEST)) | |||||
.setMetrics(request.mandatoryParamAsStrings(PARAM_METRICS)) | |||||
.setFrom(request.param(PARAM_FROM)) | |||||
.setTo(request.param(PARAM_TO)) | |||||
.setPage(request.mandatoryParamAsInt(Param.PAGE)) | |||||
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)) | |||||
.build(); | |||||
} | |||||
private Function<SearchHistoryRequest, SearchHistoryResult> search() { | private Function<SearchHistoryRequest, SearchHistoryResult> search() { | ||||
return request -> { | return request -> { | ||||
try (DbSession dbSession = dbClient.openSession(false)) { | try (DbSession dbSession = dbClient.openSession(false)) { | ||||
private ComponentDto loadComponent(DbSession dbSession, SearchHistoryRequest request) { | private ComponentDto loadComponent(DbSession dbSession, SearchHistoryRequest request) { | ||||
String componentKey = request.getComponent(); | String componentKey = request.getComponent(); | ||||
String branch = request.getBranch(); | String branch = request.getBranch(); | ||||
if (branch != null) { | |||||
return componentFinder.getByKeyAndBranch(dbSession, componentKey, branch); | |||||
} | |||||
return componentFinder.getByKey(dbSession, componentKey); | |||||
String pullRequest = request.getPullRequest(); | |||||
return componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, componentKey, branch, pullRequest); | |||||
} | } | ||||
static class SearchHistoryRequest { | static class SearchHistoryRequest { | ||||
private final String component; | private final String component; | ||||
private final String branch; | private final String branch; | ||||
private final String pullRequest; | |||||
private final List<String> metrics; | private final List<String> metrics; | ||||
private final String from; | private final String from; | ||||
private final String to; | private final String to; | ||||
public SearchHistoryRequest(Builder builder) { | public SearchHistoryRequest(Builder builder) { | ||||
this.component = builder.component; | this.component = builder.component; | ||||
this.branch = builder.branch; | this.branch = builder.branch; | ||||
this.pullRequest = builder.pullRequest; | |||||
this.metrics = builder.metrics; | this.metrics = builder.metrics; | ||||
this.from = builder.from; | this.from = builder.from; | ||||
this.to = builder.to; | this.to = builder.to; | ||||
return branch; | return branch; | ||||
} | } | ||||
@CheckForNull | |||||
public String getPullRequest() { | |||||
return pullRequest; | |||||
} | |||||
public List<String> getMetrics() { | public List<String> getMetrics() { | ||||
return metrics; | return metrics; | ||||
} | } | ||||
static class Builder { | static class Builder { | ||||
private String component; | private String component; | ||||
private String branch; | private String branch; | ||||
private String pullRequest; | |||||
private List<String> metrics; | private List<String> metrics; | ||||
private String from; | private String from; | ||||
private String to; | private String to; | ||||
return this; | return this; | ||||
} | } | ||||
public Builder setPullRequest(@Nullable String pullRequest) { | |||||
this.pullRequest = pullRequest; | |||||
return this; | |||||
} | |||||
public Builder setMetrics(List<String> metrics) { | public Builder setMetrics(List<String> metrics) { | ||||
this.metrics = metrics; | this.metrics = metrics; | ||||
return this; | return this; |
import org.sonar.server.badge.ws.ProjectBadgesWsModule; | import org.sonar.server.badge.ws.ProjectBadgesWsModule; | ||||
import org.sonar.server.batch.BatchWsModule; | import org.sonar.server.batch.BatchWsModule; | ||||
import org.sonar.server.branch.BranchFeatureProxyImpl; | import org.sonar.server.branch.BranchFeatureProxyImpl; | ||||
import org.sonar.server.branch.pr.ws.PullRequestWsModule; | |||||
import org.sonar.server.branch.ws.BranchWsModule; | import org.sonar.server.branch.ws.BranchWsModule; | ||||
import org.sonar.server.ce.ws.CeWsModule; | import org.sonar.server.ce.ws.CeWsModule; | ||||
import org.sonar.server.component.ComponentCleanerService; | import org.sonar.server.component.ComponentCleanerService; | ||||
// components | // components | ||||
BranchWsModule.class, | BranchWsModule.class, | ||||
PullRequestWsModule.class, | |||||
ProjectsWsModule.class, | ProjectsWsModule.class, | ||||
ProjectsEsModule.class, | ProjectsEsModule.class, | ||||
ProjectTagsWsModule.class, | ProjectTagsWsModule.class, |
public static final String PARAM_FROM = "from"; | public static final String PARAM_FROM = "from"; | ||||
public static final String PARAM_TO = "to"; | public static final String PARAM_TO = "to"; | ||||
public static final String PARAM_BRANCH = "branch"; | public static final String PARAM_BRANCH = "branch"; | ||||
public static final String PARAM_PULL_REQUEST = "pullRequest"; | |||||
private ProjectAnalysesWsParameters() { | private ProjectAnalysesWsParameters() { | ||||
// static access only | // static access only |
import static org.sonar.core.util.Protobuf.setNullable; | import static org.sonar.core.util.Protobuf.setNullable; | ||||
import static org.sonar.db.component.SnapshotQuery.SORT_FIELD.BY_DATE; | import static org.sonar.db.component.SnapshotQuery.SORT_FIELD.BY_DATE; | ||||
import static org.sonar.db.component.SnapshotQuery.SORT_ORDER.DESC; | import static org.sonar.db.component.SnapshotQuery.SORT_ORDER.DESC; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | |||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||||
import static org.sonar.server.projectanalysis.ws.EventCategory.OTHER; | import static org.sonar.server.projectanalysis.ws.EventCategory.OTHER; | ||||
import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_BRANCH; | import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_BRANCH; | ||||
import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_CATEGORY; | import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_CATEGORY; | ||||
import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_FROM; | import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_FROM; | ||||
import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_PROJECT; | import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_PROJECT; | ||||
import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_PULL_REQUEST; | |||||
import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_TO; | import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_TO; | ||||
import static org.sonar.server.projectanalysis.ws.SearchRequest.DEFAULT_PAGE_SIZE; | import static org.sonar.server.projectanalysis.ws.SearchRequest.DEFAULT_PAGE_SIZE; | ||||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | |||||
import static org.sonar.server.ws.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001; | |||||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||||
public class SearchAction implements ProjectAnalysesWsAction { | public class SearchAction implements ProjectAnalysesWsAction { | ||||
private static final Set<String> ALLOWED_QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.APP, Qualifiers.VIEW); | private static final Set<String> ALLOWED_QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.APP, Qualifiers.VIEW); | ||||
.setInternal(true) | .setInternal(true) | ||||
.setExampleValue(KEY_BRANCH_EXAMPLE_001); | .setExampleValue(KEY_BRANCH_EXAMPLE_001); | ||||
action.createParam(PARAM_PULL_REQUEST) | |||||
.setDescription("Pull request id") | |||||
.setSince("7.1") | |||||
.setInternal(true) | |||||
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001); | |||||
action.createParam(PARAM_CATEGORY) | action.createParam(PARAM_CATEGORY) | ||||
.setDescription("Event category. Filter analyses that have at least one event of the category specified.") | .setDescription("Event category. Filter analyses that have at least one event of the category specified.") | ||||
.setPossibleValues(EnumSet.allOf(EventCategory.class)) | .setPossibleValues(EnumSet.allOf(EventCategory.class)) | ||||
return SearchRequest.builder() | return SearchRequest.builder() | ||||
.setProject(request.mandatoryParam(PARAM_PROJECT)) | .setProject(request.mandatoryParam(PARAM_PROJECT)) | ||||
.setBranch(request.param(PARAM_BRANCH)) | .setBranch(request.param(PARAM_BRANCH)) | ||||
.setPullRequest(request.param(PARAM_PULL_REQUEST)) | |||||
.setCategory(category == null ? null : EventCategory.valueOf(category)) | .setCategory(category == null ? null : EventCategory.valueOf(category)) | ||||
.setPage(request.mandatoryParamAsInt(Param.PAGE)) | .setPage(request.mandatoryParamAsInt(Param.PAGE)) | ||||
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)) | .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)) | ||||
private ComponentDto loadComponent(DbSession dbSession, SearchRequest request) { | private ComponentDto loadComponent(DbSession dbSession, SearchRequest request) { | ||||
String project = request.getProject(); | String project = request.getProject(); | ||||
String branch = request.getBranch(); | String branch = request.getBranch(); | ||||
if (branch != null) { | |||||
return componentFinder.getByKeyAndBranch(dbSession, project, branch); | |||||
} | |||||
return componentFinder.getByKey(dbSession, project); | |||||
String pullRequest = request.getPullRequest(); | |||||
return componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, project, branch, pullRequest); | |||||
} | } | ||||
} | } |