]> source.dussan.org Git - sonarqube.git/blob
a615c9a50beba861c0e83a4b498cf8a38394b18a
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2023 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.bitbucketserver;
21
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.Optional;
26 import org.junit.Before;
27 import org.junit.BeforeClass;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.sonar.alm.client.bitbucketserver.BitbucketServerRestClient;
31 import org.sonar.alm.client.bitbucketserver.Branch;
32 import org.sonar.alm.client.bitbucketserver.BranchesList;
33 import org.sonar.alm.client.bitbucketserver.Project;
34 import org.sonar.alm.client.bitbucketserver.Repository;
35 import org.sonar.api.server.ws.WebService;
36 import org.sonar.api.utils.System2;
37 import org.sonar.core.platform.EditionProvider;
38 import org.sonar.core.platform.PlatformEditionProvider;
39 import org.sonar.core.util.SequenceUuidFactory;
40 import org.sonar.db.DbTester;
41 import org.sonar.db.alm.pat.AlmPatDto;
42 import org.sonar.db.alm.setting.AlmSettingDto;
43 import org.sonar.db.component.BranchDto;
44 import org.sonar.db.newcodeperiod.NewCodePeriodDto;
45 import org.sonar.db.project.ProjectDto;
46 import org.sonar.db.user.UserDto;
47 import org.sonar.server.almintegration.ws.ImportHelper;
48 import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
49 import org.sonar.server.component.ComponentUpdater;
50 import org.sonar.server.es.TestIndexers;
51 import org.sonar.server.exceptions.BadRequestException;
52 import org.sonar.server.exceptions.ForbiddenException;
53 import org.sonar.server.exceptions.NotFoundException;
54 import org.sonar.server.exceptions.UnauthorizedException;
55 import org.sonar.server.favorite.FavoriteUpdater;
56 import org.sonar.server.l18n.I18nRule;
57 import org.sonar.server.newcodeperiod.NewCodeDefinitionResolver;
58 import org.sonar.server.permission.PermissionTemplateService;
59 import org.sonar.server.project.DefaultBranchNameResolver;
60 import org.sonar.server.project.ProjectDefaultVisibility;
61 import org.sonar.server.project.Visibility;
62 import org.sonar.server.tester.UserSessionRule;
63 import org.sonar.server.ws.WsActionTester;
64 import org.sonarqube.ws.Projects;
65
66 import static java.util.Objects.requireNonNull;
67 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
68 import static org.apache.commons.lang.math.JVMRandom.nextLong;
69 import static org.assertj.core.api.Assertions.assertThat;
70 import static org.assertj.core.api.Assertions.assertThatThrownBy;
71 import static org.assertj.core.api.Assertions.tuple;
72 import static org.mockito.ArgumentMatchers.any;
73 import static org.mockito.Mockito.mock;
74 import static org.mockito.Mockito.verify;
75 import static org.mockito.Mockito.when;
76 import static org.sonar.db.alm.integration.pat.AlmPatsTesting.newAlmPatDto;
77 import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME;
78 import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
79 import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
80 import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
81 import static org.sonar.db.permission.GlobalPermission.SCAN;
82 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_TYPE;
83 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NEW_CODE_DEFINITION_VALUE;
84
85 public class ImportBitbucketServerProjectActionIT {
86   private static final String GENERATED_PROJECT_KEY = "TEST_PROJECT_KEY";
87
88   @Rule
89   public UserSessionRule userSession = UserSessionRule.standalone();
90   @Rule
91   public DbTester db = DbTester.create();
92   @Rule
93   public final I18nRule i18n = new I18nRule();
94
95   private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class);
96   private final BitbucketServerRestClient bitbucketServerRestClient = mock(BitbucketServerRestClient.class);
97   private final DefaultBranchNameResolver defaultBranchNameResolver = mock(DefaultBranchNameResolver.class);
98   private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
99   private NewCodeDefinitionResolver newCodeDefinitionResolver = new NewCodeDefinitionResolver(db.getDbClient(), editionProvider);
100
101   private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE,
102     mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestIndexers(), new SequenceUuidFactory(),
103     defaultBranchNameResolver, true);
104
105   private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession);
106   private final ProjectKeyGenerator projectKeyGenerator = mock(ProjectKeyGenerator.class);
107   private final WsActionTester ws = new WsActionTester(new ImportBitbucketServerProjectAction(db.getDbClient(), userSession,
108     bitbucketServerRestClient, projectDefaultVisibility, componentUpdater, importHelper, projectKeyGenerator, newCodeDefinitionResolver, defaultBranchNameResolver));
109
110   private static BranchesList defaultBranchesList;
111
112   @BeforeClass
113   public static void beforeAll() {
114     Branch defaultBranch = new Branch("default", true);
115     defaultBranchesList = new BranchesList(Collections.singletonList(defaultBranch));
116   }
117
118   @Before
119   public void before() {
120     when(projectDefaultVisibility.get(any())).thenReturn(Visibility.PRIVATE);
121     when(projectKeyGenerator.generateUniqueProjectKey(any(), any())).thenReturn(GENERATED_PROJECT_KEY);
122     when(defaultBranchNameResolver.getEffectiveMainBranchName()).thenReturn(DEFAULT_MAIN_BRANCH_NAME);
123   }
124
125   @Test
126   public void import_project() {
127     UserDto user = db.users().insertUser();
128     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
129     AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting();
130     db.almPats().insert(dto -> {
131       dto.setAlmSettingUuid(almSetting.getUuid());
132       dto.setUserUuid(user.getUuid());
133     });
134     Project project = getGsonBBSProject();
135     Repository repo = getGsonBBSRepo(project);
136     when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo);
137     when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(defaultBranchesList);
138
139     Projects.CreateWsResponse response = ws.newRequest()
140       .setParam("almSetting", almSetting.getKey())
141       .setParam("projectKey", "projectKey")
142       .setParam("repositorySlug", "repo-slug")
143       .executeProtobuf(Projects.CreateWsResponse.class);
144
145     Projects.CreateWsResponse.Project result = response.getProject();
146     assertThat(result.getKey()).isEqualTo(GENERATED_PROJECT_KEY);
147     assertThat(result.getName()).isEqualTo(repo.getName());
148
149     Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
150     assertThat(projectDto).isPresent();
151     assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get())).isPresent();
152     verify(projectKeyGenerator).generateUniqueProjectKey(requireNonNull(project.getKey()), repo.getSlug());
153   }
154
155   @Test
156   public void import_project_with_NCD_developer_edition_sets_project_NCD() {
157     when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER));
158
159     UserDto user = db.users().insertUser();
160     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
161     AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting();
162     db.almPats().insert(dto -> {
163       dto.setAlmSettingUuid(almSetting.getUuid());
164       dto.setUserUuid(user.getUuid());
165     });
166     Project project = getGsonBBSProject();
167     Repository repo = getGsonBBSRepo(project);
168     when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo);
169     when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(defaultBranchesList);
170
171     Projects.CreateWsResponse response = ws.newRequest()
172       .setParam("almSetting", almSetting.getKey())
173       .setParam("projectKey", "projectKey")
174       .setParam("repositorySlug", "repo-slug")
175       .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "NUMBER_OF_DAYS")
176       .setParam(PARAM_NEW_CODE_DEFINITION_VALUE, "30")
177       .executeProtobuf(Projects.CreateWsResponse.class);
178
179     Projects.CreateWsResponse.Project result = response.getProject();
180     assertThat(result.getKey()).isEqualTo(GENERATED_PROJECT_KEY);
181     assertThat(result.getName()).isEqualTo(repo.getName());
182
183     Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
184     assertThat(projectDto).isPresent();
185     assertThat(db.getDbClient().projectAlmSettingDao().selectByProject(db.getSession(), projectDto.get())).isPresent();
186     verify(projectKeyGenerator).generateUniqueProjectKey(requireNonNull(project.getKey()), repo.getSlug());
187
188     assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(),  projectDto.get().getUuid()))
189       .isPresent()
190       .get()
191       .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue, NewCodePeriodDto::getBranchUuid)
192       .containsExactly(NUMBER_OF_DAYS, "30", null);
193   }
194
195   @Test
196   public void import_project_with_NCD_community_edition_sets_branch_NCD() {
197     when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY));
198
199     UserDto user = db.users().insertUser();
200     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
201     AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting();
202     db.almPats().insert(dto -> {
203       dto.setAlmSettingUuid(almSetting.getUuid());
204       dto.setUserUuid(user.getUuid());
205     });
206     Project project = getGsonBBSProject();
207     Repository repo = getGsonBBSRepo(project);
208     when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo);
209     when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(defaultBranchesList);
210
211     Projects.CreateWsResponse response = ws.newRequest()
212       .setParam("almSetting", almSetting.getKey())
213       .setParam("projectKey", "projectKey")
214       .setParam("repositorySlug", "repo-slug")
215       .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "NUMBER_OF_DAYS")
216       .setParam(PARAM_NEW_CODE_DEFINITION_VALUE, "30")
217       .executeProtobuf(Projects.CreateWsResponse.class);
218
219     Projects.CreateWsResponse.Project result = response.getProject();
220
221     Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
222     assertThat(projectDto).isPresent();
223     BranchDto branchDto = db.getDbClient().branchDao().selectMainBranchByProjectUuid(db.getSession(), projectDto.get().getUuid()).orElseThrow();
224
225
226     String projectUuid = projectDto.get().getUuid();
227     assertThat(db.getDbClient().newCodePeriodDao().selectByBranch(db.getSession(), projectUuid, branchDto.getUuid()))
228       .isPresent()
229       .get()
230       .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue, NewCodePeriodDto::getBranchUuid)
231       .containsExactly(NUMBER_OF_DAYS, "30", branchDto.getUuid());
232   }
233
234   @Test
235   public void import_project_reference_branch_ncd_no_default_branch() {
236     when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER));
237     when(defaultBranchNameResolver.getEffectiveMainBranchName()).thenReturn("default-branch");
238
239     UserDto user = db.users().insertUser();
240     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
241     AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting();
242     db.almPats().insert(dto -> {
243       dto.setAlmSettingUuid(almSetting.getUuid());
244       dto.setUserUuid(user.getUuid());
245     });
246     Project project = getGsonBBSProject();
247     Repository repo = getGsonBBSRepo(project);
248     when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo);
249     when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(new BranchesList());
250
251     Projects.CreateWsResponse response = ws.newRequest()
252       .setParam("almSetting", almSetting.getKey())
253       .setParam("projectKey", "projectKey")
254       .setParam("repositorySlug", "repo-slug")
255       .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "REFERENCE_BRANCH")
256       .executeProtobuf(Projects.CreateWsResponse.class);
257
258     Projects.CreateWsResponse.Project result = response.getProject();
259
260     Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
261     assertThat(projectDto).isPresent();
262
263
264     String projectUuid = projectDto.get().getUuid();
265     assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectUuid))
266       .isPresent()
267       .get()
268       .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue)
269       .containsExactly(REFERENCE_BRANCH, "default-branch");
270   }
271
272   @Test
273   public void import_project_reference_branch_ncd() {
274     when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER));
275
276     UserDto user = db.users().insertUser();
277     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
278     AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting();
279     db.almPats().insert(dto -> {
280       dto.setAlmSettingUuid(almSetting.getUuid());
281       dto.setUserUuid(user.getUuid());
282     });
283     Project project = getGsonBBSProject();
284     Repository repo = getGsonBBSRepo(project);
285     when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo);
286     when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(defaultBranchesList);
287
288     Projects.CreateWsResponse response = ws.newRequest()
289       .setParam("almSetting", almSetting.getKey())
290       .setParam("projectKey", "projectKey")
291       .setParam("repositorySlug", "repo-slug")
292       .setParam(PARAM_NEW_CODE_DEFINITION_TYPE, "REFERENCE_BRANCH")
293       .executeProtobuf(Projects.CreateWsResponse.class);
294
295     Projects.CreateWsResponse.Project result = response.getProject();
296
297     Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
298     assertThat(projectDto).isPresent();
299
300     String projectUuid = projectDto.get().getUuid();
301     assertThat(db.getDbClient().newCodePeriodDao().selectByProject(db.getSession(), projectUuid))
302       .isPresent()
303       .get()
304       .extracting(NewCodePeriodDto::getType, NewCodePeriodDto::getValue)
305       .containsExactly(REFERENCE_BRANCH, "default");
306   }
307
308   @Test
309   public void fail_project_already_exist() {
310     UserDto user = db.users().insertUser();
311     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
312     AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting();
313     db.almPats().insert(dto -> {
314       dto.setAlmSettingUuid(almSetting.getUuid());
315       dto.setUserUuid(user.getUuid());
316     });
317     Project project = getGsonBBSProject();
318     Repository repo = getGsonBBSRepo(project);
319     db.components().insertPublicProject(p -> p.setKey(GENERATED_PROJECT_KEY)).getMainBranchComponent();
320
321     assertThatThrownBy(() -> {
322       when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo);
323       when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(defaultBranchesList);
324
325       ws.newRequest()
326         .setParam("almSetting", almSetting.getKey())
327         .setParam("projectKey", "projectKey")
328         .setParam("repositorySlug", "repo-slug")
329         .execute();
330     })
331       .isInstanceOf(BadRequestException.class)
332       .hasMessage("Could not create Project with key: \"%s\". A similar key already exists: \"%s\"", GENERATED_PROJECT_KEY, GENERATED_PROJECT_KEY);
333   }
334
335   @Test
336   public void fail_when_not_logged_in() {
337     assertThatThrownBy(() -> {
338       ws.newRequest()
339         .setParam("almSetting", "sdgfdshfjztutz")
340         .setParam("projectKey", "projectKey")
341         .setParam("repositorySlug", "repo-slug")
342         .execute();
343     })
344       .isInstanceOf(UnauthorizedException.class);
345   }
346
347   @Test
348   public void fail_when_missing_project_creator_permission() {
349     UserDto user = db.users().insertUser();
350     userSession.logIn(user).addPermission(SCAN);
351
352     assertThatThrownBy(() -> {
353       ws.newRequest()
354         .setParam("almSetting", "sdgfdshfjztutz")
355         .setParam("projectKey", "projectKey")
356         .setParam("repositorySlug", "repo-slug")
357         .execute();
358     })
359       .isInstanceOf(ForbiddenException.class)
360       .hasMessage("Insufficient privileges");
361   }
362
363   @Test
364   public void check_pat_is_missing() {
365     UserDto user = db.users().insertUser();
366     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
367     AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting();
368
369     assertThatThrownBy(() -> {
370       ws.newRequest()
371         .setParam("almSetting", almSetting.getKey())
372         .execute();
373     })
374       .isInstanceOf(IllegalArgumentException.class)
375       .hasMessage("personal access token for '" + almSetting.getKey() + "' is missing");
376   }
377
378   @Test
379   public void fail_check_alm_setting_not_found() {
380     UserDto user = db.users().insertUser();
381     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
382     AlmPatDto almPatDto = newAlmPatDto();
383     db.getDbClient().almPatDao().insert(db.getSession(), almPatDto, user.getLogin(), null);
384
385     assertThatThrownBy(() -> {
386       ws.newRequest()
387         .setParam("almSetting", "testKey")
388         .execute();
389     })
390       .isInstanceOf(NotFoundException.class)
391       .hasMessage("DevOps Platform Setting 'testKey' not found");
392   }
393
394   @Test
395   public void fail_when_no_creation_project_permission() {
396     UserDto user = db.users().insertUser();
397     userSession.logIn(user);
398
399     assertThatThrownBy(() -> {
400       ws.newRequest()
401         .setParam("almSetting", "anyvalue")
402         .execute();
403     })
404       .isInstanceOf(ForbiddenException.class)
405       .hasMessage("Insufficient privileges");
406   }
407
408   @Test
409   public void handle_givenNoDefaultBranchFound_doNotUpdateDefaultBranchName() {
410     BranchesList branchesList = new BranchesList();
411     Branch branch = new Branch("not_a_master", false);
412     branchesList.addBranch(branch);
413
414     UserDto user = db.users().insertUser();
415     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
416     AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting();
417     db.almPats().insert(dto -> {
418       dto.setAlmSettingUuid(almSetting.getUuid());
419       dto.setUserUuid(user.getUuid());
420     });
421     Project project = getGsonBBSProject();
422     Repository repo = getGsonBBSRepo(project);
423     when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo);
424     when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(branchesList);
425
426     Projects.CreateWsResponse response = ws.newRequest()
427       .setParam("almSetting", almSetting.getKey())
428       .setParam("projectKey", "projectKey")
429       .setParam("repositorySlug", "repo-slug")
430       .executeProtobuf(Projects.CreateWsResponse.class);
431
432     Projects.CreateWsResponse.Project result = response.getProject();
433
434     Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
435
436     Collection<BranchDto> branchDtos = db.getDbClient().branchDao().selectByProject(db.getSession(), projectDto.get());
437     List<BranchDto> collect = branchDtos.stream().filter(BranchDto::isMain).toList();
438     String mainBranchName = collect.iterator().next().getKey();
439     assertThat(mainBranchName).isEqualTo(DEFAULT_MAIN_BRANCH_NAME);
440   }
441
442   @Test
443   public void handle_givenDefaultBranchNamedDefault_updateDefaultBranchNameToDefault() {
444     BranchesList branchesList = new BranchesList();
445     Branch branch = new Branch("default", true);
446     branchesList.addBranch(branch);
447
448     UserDto user = db.users().insertUser();
449     userSession.logIn(user).addPermission(PROVISION_PROJECTS);
450     AlmSettingDto almSetting = db.almSettings().insertGitHubAlmSetting();
451     db.almPats().insert(dto -> {
452       dto.setAlmSettingUuid(almSetting.getUuid());
453       dto.setUserUuid(user.getUuid());
454     });
455     Project project = getGsonBBSProject();
456     Repository repo = getGsonBBSRepo(project);
457     when(bitbucketServerRestClient.getRepo(any(), any(), any(), any())).thenReturn(repo);
458     when(bitbucketServerRestClient.getBranches(any(), any(), any(), any())).thenReturn(branchesList);
459
460     Projects.CreateWsResponse response = ws.newRequest()
461       .setParam("almSetting", almSetting.getKey())
462       .setParam("projectKey", "projectKey")
463       .setParam("repositorySlug", "repo-slug")
464       .executeProtobuf(Projects.CreateWsResponse.class);
465
466     Projects.CreateWsResponse.Project result = response.getProject();
467
468     Optional<ProjectDto> projectDto = db.getDbClient().projectDao().selectProjectByKey(db.getSession(), result.getKey());
469
470     Collection<BranchDto> branchDtos = db.getDbClient().branchDao().selectByProject(db.getSession(), projectDto.get());
471     List<BranchDto> collect = branchDtos.stream().filter(BranchDto::isMain).toList();
472     String mainBranchName = collect.iterator().next().getKey();
473     assertThat(mainBranchName).isEqualTo("default");
474   }
475
476   @Test
477   public void definition() {
478     WebService.Action def = ws.getDef();
479
480     assertThat(def.since()).isEqualTo("8.2");
481     assertThat(def.isPost()).isTrue();
482     assertThat(def.params())
483       .extracting(WebService.Param::key, WebService.Param::isRequired)
484       .containsExactlyInAnyOrder(
485         tuple("almSetting", true),
486         tuple("repositorySlug", true),
487         tuple("projectKey", true),
488         tuple(PARAM_NEW_CODE_DEFINITION_TYPE, false),
489         tuple(PARAM_NEW_CODE_DEFINITION_VALUE, false));
490   }
491
492   private Repository getGsonBBSRepo(Project project) {
493     Repository bbsResult = new Repository();
494     bbsResult.setProject(project);
495     bbsResult.setSlug(randomAlphanumeric(5));
496     bbsResult.setName(randomAlphanumeric(5));
497     bbsResult.setId(nextLong(100));
498     return bbsResult;
499   }
500
501   private Project getGsonBBSProject() {
502     return new Project()
503       .setKey(randomAlphanumeric(5))
504       .setId(nextLong(100))
505       .setName(randomAlphanumeric(5));
506   }
507
508 }