]> source.dussan.org Git - sonarqube.git/blob
db6c6062ada6c61b5518e1dbde08950ee0c37d4d
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2019 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.projectanalysis.ws;
21
22 import com.google.protobuf.Empty;
23 import javax.annotation.Nullable;
24 import org.sonar.api.server.ws.Request;
25 import org.sonar.api.server.ws.Response;
26 import org.sonar.api.server.ws.WebService;
27 import org.sonar.api.web.UserRole;
28 import org.sonar.core.util.Uuids;
29 import org.sonar.db.DbClient;
30 import org.sonar.db.DbSession;
31 import org.sonar.db.component.BranchDto;
32 import org.sonar.db.component.BranchType;
33 import org.sonar.db.component.ComponentDto;
34 import org.sonar.db.component.SnapshotDto;
35 import org.sonar.db.newcodeperiod.NewCodePeriodDto;
36 import org.sonar.db.newcodeperiod.NewCodePeriodType;
37 import org.sonar.server.component.ComponentFinder;
38 import org.sonar.server.exceptions.NotFoundException;
39 import org.sonar.server.user.UserSession;
40
41 import static com.google.common.base.Preconditions.checkArgument;
42 import static java.lang.String.format;
43 import static org.apache.commons.lang.StringUtils.trimToNull;
44 import static org.sonar.server.component.ComponentFinder.ParamNames.PROJECT_ID_AND_KEY;
45 import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_ANALYSIS;
46 import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_BRANCH;
47 import static org.sonar.server.projectanalysis.ws.ProjectAnalysesWsParameters.PARAM_PROJECT;
48 import static org.sonar.server.ws.WsUtils.writeProtobuf;
49
50 public class SetBaselineAction implements ProjectAnalysesWsAction {
51   private final DbClient dbClient;
52   private final UserSession userSession;
53   private final ComponentFinder componentFinder;
54
55   public SetBaselineAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder) {
56     this.dbClient = dbClient;
57     this.userSession = userSession;
58     this.componentFinder = componentFinder;
59   }
60
61   @Override
62   public void define(WebService.NewController context) {
63     WebService.NewAction action = context.createAction("set_baseline")
64       .setDescription("Set an analysis as the baseline of the New Code Period on a project or a long-lived branch.<br/>" +
65         "This manually set baseline overrides the `sonar.leak.period` setting.<br/>" +
66         "Requires one of the following permissions:" +
67         "<ul>" +
68         "  <li>'Administer System'</li>" +
69         "  <li>'Administer' rights on the specified project</li>" +
70         "</ul>")
71       .setSince("7.7")
72       .setDeprecatedSince("8.0")
73       .setPost(true)
74       .setHandler(this);
75
76     action.createParam(PARAM_PROJECT)
77       .setDescription("Project key")
78       .setRequired(true);
79
80     action.createParam(PARAM_BRANCH)
81       .setDescription("Branch key");
82
83     action.createParam(PARAM_ANALYSIS)
84       .setDescription("Analysis key")
85       .setExampleValue(Uuids.UUID_EXAMPLE_01)
86       .setRequired(true);
87   }
88
89   @Override
90   public void handle(Request httpRequest, Response httpResponse) throws Exception {
91     doHandle(httpRequest);
92
93     writeProtobuf(Empty.newBuilder().build(), httpRequest, httpResponse);
94   }
95
96   private void doHandle(Request request) {
97     String projectKey = request.mandatoryParam(PARAM_PROJECT);
98     String branchKey = trimToNull(request.param(PARAM_BRANCH));
99     String analysisUuid = request.mandatoryParam(PARAM_ANALYSIS);
100
101     try (DbSession dbSession = dbClient.openSession(false)) {
102       ComponentDto projectBranch = getProjectBranch(dbSession, projectKey, branchKey);
103       SnapshotDto analysis = getAnalysis(dbSession, analysisUuid);
104       checkRequest(dbSession, projectBranch, branchKey, analysis);
105
106       dbClient.newCodePeriodDao().upsert(dbSession, new NewCodePeriodDto()
107         .setProjectUuid(projectBranch.getMainBranchProjectUuid() != null ? projectBranch.getMainBranchProjectUuid() : projectBranch.uuid())
108         .setBranchUuid(branchKey != null ? projectBranch.uuid() : null)
109         .setType(NewCodePeriodType.SPECIFIC_ANALYSIS)
110         .setValue(analysisUuid)
111       );
112       dbSession.commit();
113     }
114   }
115
116   private ComponentDto getProjectBranch(DbSession dbSession, String projectKey, @Nullable String branchKey) {
117     if (branchKey == null) {
118       return componentFinder.getByUuidOrKey(dbSession, null, projectKey, PROJECT_ID_AND_KEY);
119     }
120     ComponentDto project = componentFinder.getByKeyAndBranch(dbSession, projectKey, branchKey);
121
122     BranchDto branchDto = dbClient.branchDao().selectByUuid(dbSession, project.uuid())
123       .orElseThrow(() -> new NotFoundException(format("Branch '%s' is not found", branchKey)));
124
125     checkArgument(branchDto.getBranchType() == BranchType.LONG,
126       "Not a long-living branch: '%s'", branchKey);
127
128     return project;
129   }
130
131   private SnapshotDto getAnalysis(DbSession dbSession, String analysisUuid) {
132     return dbClient.snapshotDao().selectByUuid(dbSession, analysisUuid)
133       .orElseThrow(() -> new NotFoundException(format("Analysis '%s' is not found", analysisUuid)));
134   }
135
136   private void checkRequest(DbSession dbSession, ComponentDto projectBranch, @Nullable String branchKey, SnapshotDto analysis) {
137     userSession.checkComponentPermission(UserRole.ADMIN, projectBranch);
138     ComponentDto project = dbClient.componentDao().selectByUuid(dbSession, analysis.getComponentUuid()).orElse(null);
139
140     boolean analysisMatchesProjectBranch = project != null && projectBranch.uuid().equals(project.uuid());
141     if (branchKey != null) {
142       checkArgument(analysisMatchesProjectBranch,
143         "Analysis '%s' does not belong to branch '%s' of project '%s'",
144         analysis.getUuid(), branchKey, projectBranch.getKey());
145     } else {
146       checkArgument(analysisMatchesProjectBranch,
147         "Analysis '%s' does not belong to project '%s'",
148         analysis.getUuid(), projectBranch.getKey());
149     }
150   }
151 }