Skip to content

Commit cb262ee

Browse files
jetersenbaymac
andauthored
add project name strategy, being able to use GitLab project names (#53)
* add project name strategy, being able to use GitLab project names * some code rearrangements and commenting * add trait to docs * improve other traits docs Co-authored-by: Parichay Barpanda <[email protected]>
1 parent 196e692 commit cb262ee

File tree

12 files changed

+243
-55
lines changed

12 files changed

+243
-55
lines changed

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -449,19 +449,21 @@ These traits can be selected by selecting `Add` in the `Behaviours` section.
449449
450450
* `Tag discovery` - Discover tags in the project. To automatically build tags install `basic-branch-build-plugin`.
451451
452-
* `Discover group/subgroup projects` - Discovers subgroup projects inside a group/subgroup. Only applicable to `GitLab Group` Job type whose owner is a `Group`/`Subgroup` but not `User`.
452+
* `Discover group/subgroup projects` - Discover subgroup projects inside a group/subgroup. Only applicable to `GitLab Group` Job type whose owner is a `Group`/`Subgroup` but not `User`.
453453
454454
* `Log build status as comment on GitLab` - Enable logging build status as comment on GitLab. A comment is logged on the commit or merge request once the build is completed. You can decide if you want to log success builds or not. You can also use sudo user to comment the build status as commment e.g. `jenkinsadmin` or something similar.
455455
456456
* `Trigger build on merge request comment` - Enable trigger a rebuild of a merge request by comment with your desired comment body (default: `jenkins rebuild`). The job can only be triggered by trusted members of the project i.e. users with Developer/Maintainer/Owner accesslevel.
457457
458-
* `Disable GitLab project avatar` - It is not possible to fetch avatars when api has no token authentication or project is private. So as a workaround you may want to disable fetching avatars of GitLab project(s). We will fix this issue in a later release.
458+
* `Disable GitLab project avatar` - Disable avatars of GitLab project(s). It is not possible to fetch avatars when API has no token authentication or project is private. So you may use this option as a workaround. We will fix this issue in a later release.
459459
460-
* `Filter by name (with regex)` - To filter the type of items you want to discover in your project based on the regular expression specified. For example, to discover only `master` branch, `develop` branch and all Merge Requests add `(master|develop|MR-.*)`.
460+
* `Project Naming Strategy` - Choose whether you want `project name` or the `project path (with namespace)` as job names of each project. Users generally prefer the first option but due to legacy reasons we have `project path (with namespace)` as default naming scheme. Note if a job is already created and the naming strategy is changed it will cause projects and build logs to be destroyed.
461461
462-
* `Filter by name (with wildcards)` - To filter the type of items you want to discover in your project based on the wildcards specified. For example, to discover only `master` branch, `develop` branch and all Merge Requests add `development master MR-*`.
462+
* `Filter by name (with regex)` - Filter the type of items you want to discover in your project based on the regular expression specified. For example, to discover only `master` branch, `develop` branch and all Merge Requests add `(master|develop|MR-.*)`.
463463
464-
* `Skip pipeline status notifications` - To disable notifying GitLab server about the pipeline status.
464+
* `Filter by name (with wildcards)` - Filter the type of items you want to discover in your project based on the wildcards specified. For example, to discover only `master` branch, `develop` branch and all Merge Requests add `development master MR-*`.
465+
466+
* `Skip pipeline status notifications` - Disable notifying GitLab server about the pipeline status.
465467
466468
* `Override hook management modes` - Override default hook management mode of web hook and system hook. `ITEM` credentials for webhook is currently not supported.
467469

src/main/java/io/jenkins/plugins/gitlabbranchsource/GitLabSCMNavigator.java

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,20 @@ public void setTraits(@CheckForNull SCMTrait[] traits) {
184184
}
185185
}
186186

187+
private GitLabOwner getGitlabOwner() {
188+
if (gitlabOwner == null) {
189+
getGitlabOwner(apiBuilder(serverName));
190+
}
191+
return gitlabOwner;
192+
}
193+
194+
private GitLabOwner getGitlabOwner(GitLabApi gitLabApi) {
195+
if (gitlabOwner == null) {
196+
gitlabOwner = GitLabOwner.fetchOwner(gitLabApi, projectOwner);
197+
}
198+
return gitlabOwner;
199+
}
200+
187201
/**
188202
* Sets the behavioural traits that are applied to this navigator and any {@link
189203
* GitLabSCMSource} instances it discovers. The new traits will take affect on the next
@@ -212,9 +226,7 @@ public void visitSources(@NonNull final SCMSourceObserver observer)
212226
.withTraits(traits)
213227
.newRequest(this, observer)) {
214228
GitLabApi gitLabApi = apiBuilder(serverName);
215-
if (gitlabOwner == null) {
216-
gitlabOwner = GitLabOwner.fetchOwner(gitLabApi, projectOwner);
217-
}
229+
getGitlabOwner(gitLabApi);
218230
List<Project> projects;
219231
if (gitlabOwner instanceof GitLabUser) {
220232
// Even returns the group projects owned by the user
@@ -241,6 +253,8 @@ public void visitSources(@NonNull final SCMSourceObserver observer)
241253
for (Project p : projects) {
242254
count++;
243255
String projectPathWithNamespace = p.getPathWithNamespace();
256+
String projectOwner = getProjectOwnerFromNamespace(projectPathWithNamespace);
257+
String projectName = getProjectName(request.withProjectNamingStrategy(), p);
244258
getNavigatorProjects().add(projectPathWithNamespace);
245259
if (StringUtils.isEmpty(p.getDefaultBranch())) {
246260
observer.getListener().getLogger()
@@ -249,7 +263,7 @@ public void visitSources(@NonNull final SCMSourceObserver observer)
249263
continue;
250264
}
251265
observer.getListener().getLogger().format("%nChecking project %s%n",
252-
HyperlinkNote.encodeTo(p.getWebUrl(), p.getName()));
266+
HyperlinkNote.encodeTo(p.getWebUrl(), projectName));
253267
try {
254268
if (webhookGitLabApi != null && webHookUrl != null) {
255269
observer.getListener().getLogger().format("Web hook %s%n", GitLabHookCreator
@@ -260,22 +274,22 @@ public void visitSources(@NonNull final SCMSourceObserver observer)
260274
observer.getListener().getLogger()
261275
.format("Cannot set web hook: %s%n", e.getReason());
262276
}
263-
String projectOwner = getProjectOwnerFromNamespace(projectPathWithNamespace);
264-
if (request.process(projectPathWithNamespace,
265-
projectPath -> new GitLabSCMSourceBuilder(
266-
getId() + "::" + projectPath,
277+
if (request.process(projectName,
278+
name -> new GitLabSCMSourceBuilder(
279+
getId() + "::" + projectPathWithNamespace,
267280
serverName,
268281
credentialsId,
269282
projectOwner,
270-
projectPath
283+
projectPathWithNamespace,
284+
name
271285
).withTraits(traits).build(),
272286
null,
273-
(Witness) (projectPath, isMatch) -> {
287+
(Witness) (name, isMatch) -> {
274288
if (isMatch) {
275289
observer.getListener().getLogger()
276-
.format("Proposing %s%n", projectPath);
290+
.format("Proposing %s%n", name);
277291
} else {
278-
observer.getListener().getLogger().format("Ignoring %s%n", projectPath);
292+
observer.getListener().getLogger().format("Ignoring %s%n", name);
279293
}
280294
})) {
281295
observer.getListener().getLogger()
@@ -290,6 +304,23 @@ public void visitSources(@NonNull final SCMSourceObserver observer)
290304
}
291305
}
292306

307+
@NonNull
308+
private String getProjectName(int projectNamingStrategy, Project project) {
309+
String projectName;
310+
switch (projectNamingStrategy) {
311+
default:
312+
// for legacy reasons default naming strategy is set to full path
313+
case 1:
314+
projectName = project.getPathWithNamespace();
315+
break;
316+
case 2:
317+
projectName = project.getNameWithNamespace()
318+
.replace(String.format("%s / ", getGitlabOwner().getFullName()), "");
319+
break;
320+
}
321+
return projectName;
322+
}
323+
293324
private PersonalAccessToken getWebHookCredentials(SCMSourceOwner owner) {
294325
PersonalAccessToken credentials = null;
295326
GitLabServer server = GitLabServers.get().findServer(getServerName());
@@ -331,10 +362,7 @@ protected List<Action> retrieveActions(@NonNull SCMNavigatorOwner owner,
331362
SCMNavigatorEvent event,
332363
@NonNull TaskListener listener) throws IOException, InterruptedException {
333364
LOGGER.info("retrieving actions..");
334-
if (gitlabOwner == null) {
335-
GitLabApi gitLabApi = apiBuilder(serverName);
336-
gitlabOwner = GitLabOwner.fetchOwner(gitLabApi, projectOwner);
337-
}
365+
getGitlabOwner();
338366
String fullName = gitlabOwner.getFullName();
339367
String webUrl = gitlabOwner.getWebUrl();
340368
String avatarUrl = gitlabOwner.getAvatarUrl();

src/main/java/io/jenkins/plugins/gitlabbranchsource/GitLabSCMNavigatorContext.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ public class GitLabSCMNavigatorContext extends
1010

1111
private boolean wantSubgroupProjects;
1212

13+
private int projectNamingStrategy = 1;
14+
1315
@NonNull
1416
@Override
1517
public GitLabSCMNavigatorRequest newRequest(@NonNull SCMNavigator navigator,
@@ -28,4 +30,18 @@ public GitLabSCMNavigatorContext wantSubgroupProjects(boolean include) {
2830
this.wantSubgroupProjects = include;
2931
return this;
3032
}
33+
34+
/**
35+
* Returns the project naming strategy id.
36+
*
37+
* @return the project naming strategy id.
38+
*/
39+
public int withProjectNamingStrategy() {
40+
return projectNamingStrategy;
41+
}
42+
43+
public GitLabSCMNavigatorContext withProjectNamingStrategy(int strategyId) {
44+
this.projectNamingStrategy = strategyId;
45+
return this;
46+
}
3147
}

src/main/java/io/jenkins/plugins/gitlabbranchsource/GitLabSCMNavigatorRequest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ public class GitLabSCMNavigatorRequest extends SCMNavigatorRequest {
99

1010
private boolean wantSubgroupProjects;
1111

12+
private int projectNamingStrategy;
13+
1214
protected GitLabSCMNavigatorRequest(@NonNull SCMNavigator source,
1315
@NonNull GitLabSCMNavigatorContext context,
1416
@NonNull SCMSourceObserver observer) {
1517
super(source, context, observer);
1618
wantSubgroupProjects = context.wantSubgroupProjects();
19+
projectNamingStrategy = context.withProjectNamingStrategy();
1720
}
1821

1922
/**
@@ -22,4 +25,13 @@ protected GitLabSCMNavigatorRequest(@NonNull SCMNavigator source,
2225
public boolean wantSubgroupProjects() {
2326
return wantSubgroupProjects;
2427
}
28+
29+
/**
30+
* Returns the project naming strategy id.
31+
*
32+
* @return the project naming strategy id.
33+
*/
34+
public int withProjectNamingStrategy() {
35+
return projectNamingStrategy;
36+
}
2537
}

src/main/java/io/jenkins/plugins/gitlabbranchsource/GitLabSCMSource.java

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ public class GitLabSCMSource extends AbstractGitSCMSource {
107107
private final String serverName;
108108
private final String projectOwner;
109109
private final String projectPath;
110+
private String projectName;
110111
private String credentialsId;
111112
private List<SCMSourceTrait> traits = new ArrayList<>();
112113
private transient String sshRemote;
@@ -160,6 +161,18 @@ public void setSshRemote(String sshRemote) {
160161
this.sshRemote = sshRemote;
161162
}
162163

164+
public String getProjectName() {
165+
return projectName;
166+
}
167+
168+
/**
169+
* Only used for saving project name for {@link GitLabSCMNavigator}
170+
* @param projectName the name of the project
171+
*/
172+
public void setProjectName(String projectName) {
173+
this.projectName = projectName;
174+
}
175+
163176
@Override
164177
public String getCredentialsId() {
165178
return credentialsId;
@@ -179,6 +192,24 @@ public String getRemote() {
179192
.expand();
180193
}
181194

195+
protected Project getGitlabProject() {
196+
if (gitlabProject == null) {
197+
getGitlabProject(apiBuilder(serverName));
198+
}
199+
return gitlabProject;
200+
}
201+
202+
protected Project getGitlabProject(GitLabApi gitLabApi) {
203+
if (gitlabProject == null) {
204+
try {
205+
gitlabProject = gitLabApi.getProjectApi().getProject(projectPath);
206+
} catch (GitLabApiException e) {
207+
throw new IllegalStateException("Failed to retrieve project " + projectPath, e);
208+
}
209+
}
210+
return gitlabProject;
211+
}
212+
182213
// This method always returns the latest list of members of the project
183214
public HashMap<String, AccessLevel> getMembers() {
184215
HashMap<String, AccessLevel> members = new HashMap<>();
@@ -218,9 +249,7 @@ protected SCMRevision retrieve(@NonNull SCMHead head, @NonNull TaskListener list
218249
throws IOException, InterruptedException {
219250
try {
220251
GitLabApi gitLabApi = apiBuilder(serverName);
221-
if (gitlabProject == null) {
222-
gitlabProject = gitLabApi.getProjectApi().getProject(projectPath);
223-
}
252+
getGitlabProject(gitLabApi);
224253
LOGGER.info(String.format("h, l..%s", Thread.currentThread().getName()));
225254
if (head instanceof BranchSCMHead) {
226255
listener.getLogger()
@@ -280,9 +309,7 @@ protected void retrieve(SCMSourceCriteria criteria, @NonNull SCMHeadObserver obs
280309
@NonNull TaskListener listener) throws IOException, InterruptedException {
281310
try {
282311
GitLabApi gitLabApi = apiBuilder(serverName);
283-
if (gitlabProject == null) {
284-
gitlabProject = gitLabApi.getProjectApi().getProject(projectPath);
285-
}
312+
getGitlabProject(gitLabApi);
286313
setProjectId(gitlabProject.getId());
287314
LOGGER.info(String.format("c, o, e, l..%s", Thread.currentThread().getName()));
288315
sshRemote = gitlabProject.getSshUrlToRepo();
@@ -537,18 +564,11 @@ protected Set<String> retrieveRevisions(@NonNull TaskListener listener)
537564
@Override
538565
protected List<Action> retrieveActions(SCMSourceEvent event, @NonNull TaskListener listener) {
539566
List<Action> result = new ArrayList<>();
540-
if (gitlabProject == null) {
541-
try {
542-
GitLabApi gitLabApi = apiBuilder(serverName);
543-
listener.getLogger().format("Looking up project %s%n", projectPath);
544-
gitlabProject = gitLabApi.getProjectApi().getProject(projectPath);
545-
} catch (GitLabApiException e) {
546-
throw new IllegalStateException("Failed to retrieve project", e);
547-
}
548-
}
567+
getGitlabProject();
549568
GitLabSCMSourceContext ctx = new GitLabSCMSourceContext(null, SCMHeadObserver.none()).withTraits(traits);
550569
String projectUrl = gitlabProject.getWebUrl();
551-
result.add(new ObjectMetadataAction(gitlabProject.getNameWithNamespace(),
570+
String name = StringUtils.isBlank(projectName) ? gitlabProject.getNameWithNamespace() : projectName;
571+
result.add(new ObjectMetadataAction(name,
552572
gitlabProject.getDescription(),
553573
projectUrl));
554574
String avatarUrl = gitlabProject.getAvatarUrl();
@@ -564,15 +584,7 @@ protected List<Action> retrieveActions(SCMSourceEvent event, @NonNull TaskListen
564584
protected List<Action> retrieveActions(@NonNull SCMHead head, SCMHeadEvent event,
565585
@NonNull TaskListener listener) {
566586
LOGGER.info(String.format("h, e, l..%s", Thread.currentThread().getName()));
567-
if (gitlabProject == null) {
568-
try {
569-
GitLabApi gitLabApi = apiBuilder(serverName);
570-
listener.getLogger().format("Looking up project %s%n", projectPath);
571-
gitlabProject = gitLabApi.getProjectApi().getProject(projectPath);
572-
} catch (GitLabApiException e) {
573-
e.printStackTrace();
574-
}
575-
}
587+
getGitlabProject();
576588
List<Action> result = new ArrayList<>();
577589
if (head instanceof BranchSCMHead) {
578590
String branchUrl = branchUriTemplate(serverName)
@@ -687,9 +699,7 @@ protected SCMProbe createProbe(@NonNull final SCMHead head, SCMRevision revision
687699
throw new AssertionError();
688700
}
689701
GitLabApi gitLabApi = apiBuilder(serverName);
690-
if (gitlabProject == null) {
691-
gitlabProject = gitLabApi.getProjectApi().getProject(projectPath);
692-
}
702+
getGitlabProject(gitLabApi);
693703
LOGGER.info("Creating a probe: " + head.getName());
694704
final SCMFileSystem fs = builder.build(head, revision, gitLabApi, gitlabProject);
695705
return new SCMProbe() {
@@ -728,7 +738,7 @@ public SCMFile getRoot() {
728738
return fs != null ? fs.getRoot() : null;
729739
}
730740
};
731-
} catch (InterruptedException | GitLabApiException e) {
741+
} catch (InterruptedException e) {
732742
throw new IOException(e);
733743
}
734744
}

src/main/java/io/jenkins/plugins/gitlabbranchsource/GitLabSCMSourceBuilder.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,19 @@ public class GitLabSCMSourceBuilder extends
1717
private final String projectOwner;
1818
@NonNull
1919
private final String projectPath;
20+
@NonNull
21+
private final String projectName;
2022

2123
public GitLabSCMSourceBuilder(@CheckForNull String id, @CheckForNull String serverName,
2224
@CheckForNull String credentialsId, @NonNull String projectOwner,
23-
@NonNull String projectPath) {
24-
super(GitLabSCMSource.class, projectPath);
25-
this.projectPath = projectPath;
25+
@NonNull String projectPath, @NonNull String projectName) {
26+
super(GitLabSCMSource.class, projectName);
2627
this.id = id;
2728
this.serverName = serverName;
28-
this.projectOwner = projectOwner;
2929
this.credentialsId = credentialsId;
30+
this.projectOwner = projectOwner;
31+
this.projectPath = projectPath;
32+
this.projectName = projectName;
3033
}
3134

3235
@CheckForNull
@@ -47,6 +50,7 @@ public GitLabSCMSource build() {
4750
result.setId(id);
4851
result.setCredentialsId(credentialsId);
4952
result.setTraits(traits());
53+
result.setProjectName(projectName);
5054
return result;
5155
}
5256
}

0 commit comments

Comments
 (0)