]> source.dussan.org Git - sonarqube.git/blob
de7a2a6fc8ba0845195cf9ee9cdebc5ee1c3426f
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2021 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.almintegration.ws.azure;
21
22 import com.google.common.annotations.VisibleForTesting;
23
24 import java.util.Optional;
25
26 import org.sonar.alm.client.azure.AzureDevOpsHttpClient;
27 import org.sonar.alm.client.azure.GsonAzureRepo;
28 import org.sonar.api.server.ws.Request;
29 import org.sonar.api.server.ws.Response;
30 import org.sonar.api.server.ws.WebService;
31 import org.sonar.db.DbClient;
32 import org.sonar.db.DbSession;
33 import org.sonar.db.alm.pat.AlmPatDto;
34 import org.sonar.db.alm.setting.AlmSettingDto;
35 import org.sonar.db.alm.setting.ProjectAlmSettingDto;
36 import org.sonar.db.component.ComponentDto;
37 import org.sonar.server.almintegration.ws.AlmIntegrationsWsAction;
38 import org.sonar.server.almintegration.ws.ImportHelper;
39 import org.sonar.server.component.ComponentUpdater;
40 import org.sonar.server.project.ProjectDefaultVisibility;
41 import org.sonar.server.user.UserSession;
42 import org.sonarqube.ws.Projects.CreateWsResponse;
43
44 import static java.util.Objects.requireNonNull;
45 import static org.sonar.api.resources.Qualifiers.PROJECT;
46 import static org.sonar.server.almintegration.ws.ImportHelper.PARAM_ALM_SETTING;
47 import static org.sonar.server.almintegration.ws.ImportHelper.toCreateResponse;
48 import static org.sonar.server.component.NewComponent.newComponentBuilder;
49 import static org.sonar.server.ws.WsUtils.writeProtobuf;
50
51 public class ImportAzureProjectAction implements AlmIntegrationsWsAction {
52
53   private static final String PARAM_REPOSITORY_NAME = "repositoryName";
54   private static final String PARAM_PROJECT_NAME = "projectName";
55
56   private final DbClient dbClient;
57   private final UserSession userSession;
58   private final AzureDevOpsHttpClient azureDevOpsHttpClient;
59   private final ProjectDefaultVisibility projectDefaultVisibility;
60   private final ComponentUpdater componentUpdater;
61   private final ImportHelper importHelper;
62
63   public ImportAzureProjectAction(DbClient dbClient, UserSession userSession, AzureDevOpsHttpClient azureDevOpsHttpClient,
64     ProjectDefaultVisibility projectDefaultVisibility, ComponentUpdater componentUpdater,
65     ImportHelper importHelper) {
66     this.dbClient = dbClient;
67     this.userSession = userSession;
68     this.azureDevOpsHttpClient = azureDevOpsHttpClient;
69     this.projectDefaultVisibility = projectDefaultVisibility;
70     this.componentUpdater = componentUpdater;
71     this.importHelper = importHelper;
72   }
73
74   @Override
75   public void define(WebService.NewController context) {
76     WebService.NewAction action = context.createAction("import_azure_project")
77       .setDescription("Create a SonarQube project with the information from the provided Azure DevOps project.<br/>" +
78         "Autoconfigure pull request decoration mechanism.<br/>" +
79         "Requires the 'Create Projects' permission")
80       .setPost(true)
81       .setInternal(true)
82       .setSince("8.6")
83       .setHandler(this);
84
85     action.createParam(PARAM_ALM_SETTING)
86       .setRequired(true)
87       .setMaximumLength(200)
88       .setDescription("ALM setting key");
89
90     action.createParam(PARAM_PROJECT_NAME)
91       .setRequired(true)
92       .setMaximumLength(200)
93       .setDescription("Azure project name");
94
95     action.createParam(PARAM_REPOSITORY_NAME)
96       .setRequired(true)
97       .setMaximumLength(200)
98       .setDescription("Azure repository name");
99   }
100
101   @Override
102   public void handle(Request request, Response response) {
103     CreateWsResponse createResponse = doHandle(request);
104     writeProtobuf(createResponse, request, response);
105   }
106
107   private CreateWsResponse doHandle(Request request) {
108     importHelper.checkProvisionProjectPermission();
109     AlmSettingDto almSettingDto = importHelper.getAlmSetting(request);
110     String userUuid = importHelper.getUserUuid();
111     try (DbSession dbSession = dbClient.openSession(false)) {
112
113       Optional<AlmPatDto> almPatDto = dbClient.almPatDao().selectByUserAndAlmSetting(dbSession, userUuid, almSettingDto);
114       String pat = almPatDto.map(AlmPatDto::getPersonalAccessToken)
115         .orElseThrow(() -> new IllegalArgumentException(String.format("personal access token for '%s' is missing", almSettingDto.getKey())));
116
117       String projectName = request.mandatoryParam(PARAM_PROJECT_NAME);
118       String repositoryName = request.mandatoryParam(PARAM_REPOSITORY_NAME);
119
120       String url = requireNonNull(almSettingDto.getUrl(), "ALM url cannot be null");
121       GsonAzureRepo repo = azureDevOpsHttpClient.getRepo(url, pat, projectName, repositoryName);
122
123       ComponentDto componentDto = createProject(dbSession, repo);
124       populatePRSetting(dbSession, repo, componentDto, almSettingDto);
125
126       return toCreateResponse(componentDto);
127     }
128   }
129
130   private ComponentDto createProject(DbSession dbSession, GsonAzureRepo repo) {
131     boolean visibility = projectDefaultVisibility.get(dbSession).isPrivate();
132     return componentUpdater.create(dbSession, newComponentBuilder()
133       .setKey(generateProjectKey(repo.getProject().getName(), repo.getName()))
134       .setName(repo.getName())
135       .setPrivate(visibility)
136       .setQualifier(PROJECT)
137       .build(),
138       userSession.isLoggedIn() ? userSession.getUuid() : null);
139   }
140
141   private void populatePRSetting(DbSession dbSession, GsonAzureRepo repo, ComponentDto componentDto, AlmSettingDto almSettingDto) {
142     ProjectAlmSettingDto projectAlmSettingDto = new ProjectAlmSettingDto()
143       .setAlmSettingUuid(almSettingDto.getUuid())
144       .setAlmRepo(repo.getName())
145       .setAlmSlug(repo.getProject().getName())
146       .setProjectUuid(componentDto.uuid())
147       .setMonorepo(false);
148     dbClient.projectAlmSettingDao().insertOrUpdate(dbSession, projectAlmSettingDto);
149     dbSession.commit();
150   }
151
152   @VisibleForTesting
153   String generateProjectKey(String projectName, String repoName) {
154     String sqProjectKey = projectName + "_" + repoName;
155
156     if (sqProjectKey.length() > 250) {
157       sqProjectKey = sqProjectKey.substring(sqProjectKey.length() - 250);
158     }
159
160     return sqProjectKey.replace(" ", "_");
161   }
162
163 }