discussions;
40 |
41 | public GitLabAPIMergeRequestDiscussionExt(GitLabAPI gitLabAPI) {
42 | this.gitLabAPI = gitLabAPI;
43 | }
44 |
45 | //
46 | // /**
47 | // * Gets a list of all discussions for a single merge request.
48 | // *
49 | // * GET /projects/:id/merge_requests/:merge_request_iid/discussions
50 | // *
51 | // * @param projectId (required) - The ID or URL-encoded path of the project
52 | // * @param iid (required) - The IID of a merge request
53 | // * @param pagination (optional) - The ID of a discussion
54 | // * @return Paged object of {@link GitlabDiscussionStatus} instances
55 | // * @throws IOException
56 | // */
57 | public Paged getAllDiscussions(Serializable projectId, Integer iid, Pagination pagination)
58 | throws IOException {
59 | Query query = QueryHelper.getQuery(pagination);
60 | String tailUrl = String.format(BASE_URL + "%s", gitLabAPI.sanitize(projectId), iid, query.build());
61 | return gitLabAPI.retrieve().toPaged(tailUrl, GitlabDiscussionStatus[].class);
62 | }
63 |
64 | public Boolean hasDiscussion(Integer projectId, Integer mergeRequestIid, String fullPath, Integer lineNumber,
65 | String body, String baseSha, String headSha) throws IOException {
66 |
67 | if (discussions == null) {
68 |
69 | LOG.debug("gettting existing Merge Request discussions");
70 |
71 | Paged paged = getAllDiscussions(projectId, mergeRequestIid, null);
72 |
73 | do {
74 | if (paged.getResults() != null) {
75 | if (discussions == null) {
76 | discussions = new ArrayList<>();
77 | }
78 | discussions.addAll(paged.getResults());
79 | }
80 | } while ((paged = paged.nextPage()) != null);
81 |
82 |
83 | if (LOG.isDebugEnabled()) {
84 | LOG.debug("Existing count {}", discussions.size());
85 | discussions.forEach(item -> {
86 | LOG.debug("discussion {} note count {}", item.getId(), item.getNotes().size());
87 | item.getNotes().forEach(note -> {
88 | GitlabPosition position = note.getPosition();
89 | if (position != null) {
90 | LOG.debug("-File: {} {}", position.getNewPath(), position.getNewLine());
91 | LOG.debug("-bSha: {}, hSha {}", position.getBaseSha(), position.getHeadSha());
92 | }
93 | LOG.debug("-Note {}: {}",note.getBody().length(), note.getBody());
94 | });
95 | });
96 |
97 | LOG.debug("Current Issue Comment:");
98 | LOG.debug("Path {} {}", fullPath, lineNumber);
99 | LOG.debug("bSha: {}, hSha {}", baseSha, headSha);
100 | LOG.debug("Note {}: {}",body.length(), body);
101 | }
102 | }
103 |
104 | boolean isExist = discussions.stream().anyMatch(x ->
105 | x.getNotes().stream().anyMatch(n ->
106 | body.equals(n.getBody())
107 | && n.getPosition() != null
108 | && lineNumber.equals(n.getPosition().getNewLine())
109 | && baseSha.equals(n.getPosition().getBaseSha())
110 | && headSha.equals(n.getPosition().getHeadSha())
111 | && fullPath.equals(n.getPosition().getNewPath())
112 | )
113 | );
114 |
115 | if(isExist)
116 | LOG.debug("-------------------Issue Comment already exist on MR----------------------");
117 |
118 | return isExist;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/api/GitlabDiscussionStatus.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.api;
18 |
19 | import com.fasterxml.jackson.annotation.JsonProperty;
20 |
21 | import java.util.List;
22 |
23 | public class GitlabDiscussionStatus {
24 |
25 |
26 | private String id;
27 |
28 | @JsonProperty("individual_note")
29 | private boolean individualNote;
30 |
31 | private List notes;
32 |
33 | public String getId() {
34 | return id;
35 | }
36 |
37 | public void setId(String id) {
38 | this.id = id;
39 | }
40 |
41 | public boolean isIndividualNote() {
42 | return individualNote;
43 | }
44 |
45 | public void setIndividualNote(boolean individualNote) {
46 | this.individualNote = individualNote;
47 | }
48 |
49 | public List getNotes() {
50 | return notes;
51 | }
52 |
53 | public void setNotes(List notes) {
54 | this.notes = notes;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/api/GitlabNote.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.api;
18 |
19 | import com.fasterxml.jackson.annotation.JsonProperty;
20 | import com.talanlabs.gitlab.api.v4.models.users.GitLabUser;
21 |
22 | import java.util.Date;
23 |
24 | public class GitlabNote {
25 |
26 | public static final String URL = "/notes";
27 |
28 | private Integer id;
29 | private String body;
30 | private String attachment;
31 | private GitLabUser author;
32 | private boolean system;
33 | private boolean upvote;
34 | private boolean downvote;
35 |
36 | @JsonProperty("created_at")
37 | private Date createdAt;
38 |
39 | private GitlabPosition position;
40 |
41 | @JsonProperty("noteable_id")
42 | private Integer noteableId;
43 |
44 | @JsonProperty("noteableType")
45 | private String noteable_type;
46 |
47 | private boolean resolvable;
48 | private boolean resolved;
49 |
50 | @JsonProperty("resolved_by")
51 | private GitLabUser resolvedBy;
52 |
53 | @JsonProperty("noteable_iid")
54 | private Integer noteableIid;
55 |
56 | public Integer getId() {
57 | return id;
58 | }
59 |
60 | public void setId(Integer id) {
61 | this.id = id;
62 | }
63 |
64 | public String getBody() {
65 | return body;
66 | }
67 |
68 | public void setBody(String body) {
69 | this.body = body;
70 | }
71 |
72 | public GitLabUser getAuthor() {
73 | return author;
74 | }
75 |
76 | public void setAuthor(GitLabUser author) {
77 | this.author = author;
78 | }
79 |
80 | public Date getCreatedAt() {
81 | return createdAt;
82 | }
83 |
84 | public void setCreatedAt(Date createdAt) {
85 | this.createdAt = createdAt;
86 | }
87 |
88 | public String getAttachment() {
89 | return attachment;
90 | }
91 |
92 | public void setAttachment(String attachment) {
93 | this.attachment = attachment;
94 | }
95 |
96 | public boolean isSystem() {
97 | return system;
98 | }
99 |
100 | public void setSystem(boolean system) {
101 | this.system = system;
102 | }
103 |
104 | public boolean isUpvote() {
105 | return upvote;
106 | }
107 |
108 | public void setUpvote(boolean upvote) {
109 | this.upvote = upvote;
110 | }
111 |
112 | public boolean isDownvote() {
113 | return downvote;
114 | }
115 |
116 | public void setDownvote(boolean downvote) {
117 | this.downvote = downvote;
118 | }
119 |
120 | public GitlabPosition getPosition() {
121 | return position;
122 | }
123 |
124 | public void setPosition(GitlabPosition position) {
125 | this.position = position;
126 | }
127 |
128 | public Integer getNoteableId() {
129 | return noteableId;
130 | }
131 |
132 | public void setNoteableId(Integer noteableId) {
133 | this.noteableId = noteableId;
134 | }
135 |
136 | public String getNoteable_type() {
137 | return noteable_type;
138 | }
139 |
140 | public void setNoteable_type(String noteable_type) {
141 | this.noteable_type = noteable_type;
142 | }
143 |
144 | public boolean isResolvable() {
145 | return resolvable;
146 | }
147 |
148 | public void setResolvable(boolean resolvable) {
149 | this.resolvable = resolvable;
150 | }
151 |
152 | public boolean isResolved() {
153 | return resolved;
154 | }
155 |
156 | public void setResolved(boolean resolved) {
157 | this.resolved = resolved;
158 | }
159 |
160 | public GitLabUser getResolvedBy() {
161 | return resolvedBy;
162 | }
163 |
164 | public void setResolvedBy(GitLabUser resolvedBy) {
165 | this.resolvedBy = resolvedBy;
166 | }
167 |
168 | public Integer getNoteableIid() {
169 | return noteableIid;
170 | }
171 |
172 | public void setNoteableIid(Integer noteableIid) {
173 | this.noteableIid = noteableIid;
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/api/GitlabPosition.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.api;
18 |
19 | import com.fasterxml.jackson.annotation.JsonProperty;
20 |
21 | public class GitlabPosition {
22 |
23 |
24 | @JsonProperty("base_sha")
25 | private String baseSha;
26 |
27 | @JsonProperty("start_sha")
28 | private String startSha;
29 |
30 | @JsonProperty("head_sha")
31 | private String headSha;
32 |
33 | @JsonProperty("position_type")
34 | private String positionType;
35 |
36 | @JsonProperty("new_path")
37 | private String newPath;
38 |
39 | @JsonProperty("new_line")
40 | private Integer newLine;
41 |
42 | @JsonProperty("old_path")
43 | private String oldPath;
44 |
45 | @JsonProperty("old_line")
46 | private Integer oldLine;
47 |
48 | private Integer width;
49 | private Integer height;
50 | private Integer x;
51 | private Integer y;
52 |
53 | public String getBaseSha() {
54 | return baseSha;
55 | }
56 |
57 | public void setBaseSha(String baseSha) {
58 | this.baseSha = baseSha;
59 | }
60 |
61 | public String getStartSha() {
62 | return startSha;
63 | }
64 |
65 | public void setStartSha(String startSha) {
66 | this.startSha = startSha;
67 | }
68 |
69 | public String getHeadSha() {
70 | return headSha;
71 | }
72 |
73 | public void setHeadSha(String headSha) {
74 | this.headSha = headSha;
75 | }
76 |
77 | public String getPositionType() {
78 | return positionType;
79 | }
80 |
81 | public void setPositionType(String positionType) {
82 | this.positionType = positionType;
83 | }
84 |
85 | public String getNewPath() {
86 | return newPath;
87 | }
88 |
89 | public void setNewPath(String newPath) {
90 | this.newPath = newPath;
91 | }
92 |
93 | public Integer getNewLine() {
94 | return newLine;
95 | }
96 |
97 | public void setNewLine(Integer newLine) {
98 | this.newLine = newLine;
99 | }
100 |
101 | public String getOldPath() {
102 | return oldPath;
103 | }
104 |
105 | public void setOldPath(String oldPath) {
106 | this.oldPath = oldPath;
107 | }
108 |
109 | public Integer getOldLine() {
110 | return oldLine;
111 | }
112 |
113 | public void setOldLine(Integer oldLine) {
114 | this.oldLine = oldLine;
115 | }
116 |
117 | public Integer getWidth() {
118 | return width;
119 | }
120 |
121 | public void setWidth(Integer width) {
122 | this.width = width;
123 | }
124 |
125 | public Integer getHeight() {
126 | return height;
127 | }
128 |
129 | public void setHeight(Integer height) {
130 | this.height = height;
131 | }
132 |
133 | public Integer getX() {
134 | return x;
135 | }
136 |
137 | public void setX(Integer x) {
138 | this.x = x;
139 | }
140 |
141 | public Integer getY() {
142 | return y;
143 | }
144 |
145 | public void setY(Integer y) {
146 | this.y = y;
147 | }
148 | }
149 |
150 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/freemarker/AbstractIssuesTemplateMethodModelEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.models.ReportIssue;
20 | import freemarker.template.TemplateBooleanModel;
21 | import freemarker.template.TemplateMethodModelEx;
22 | import freemarker.template.TemplateModelException;
23 | import freemarker.template.TemplateScalarModel;
24 | import org.sonar.api.batch.rule.Severity;
25 |
26 | import java.util.ArrayList;
27 | import java.util.Collections;
28 | import java.util.List;
29 | import java.util.stream.Stream;
30 |
31 | public abstract class AbstractIssuesTemplateMethodModelEx implements TemplateMethodModelEx {
32 |
33 | private final List reportIssues;
34 |
35 | AbstractIssuesTemplateMethodModelEx(List reportIssues) {
36 | super();
37 |
38 | this.reportIssues = Collections.unmodifiableList(new ArrayList<>(reportIssues));
39 | }
40 |
41 | @Override
42 | public Object exec(List arguments) throws TemplateModelException {
43 | if (arguments.isEmpty()) {
44 | return execEmptyArg();
45 | } else if (arguments.size() == 1) {
46 | return execOneArg(arguments.get(0));
47 | } else if (arguments.size() == 2) {
48 | return execTwoArg(arguments.get(0), arguments.get(1));
49 | }
50 | throw new TemplateModelException("Failed call accept 0, 1 or 2 args");
51 | }
52 |
53 | protected abstract Object exec(Stream stream);
54 |
55 | private Object execEmptyArg() {
56 | return exec(reportIssues.stream());
57 | }
58 |
59 | private Object execOneArg(Object arg) throws TemplateModelException {
60 | if (arg instanceof TemplateScalarModel) {
61 | String name = ((TemplateScalarModel) arg).getAsString();
62 | try {
63 | Severity severity = Severity.valueOf(name);
64 | return exec(reportIssues.stream().filter(i -> isSeverityEquals(i, severity)));
65 | } catch (IllegalArgumentException e) {
66 | throw new TemplateModelException("Failed call 1 Severity arg (INFO,MINOR,MAJOR,CRITICAL,BLOCKER)", e);
67 | }
68 | } else if (arg instanceof TemplateBooleanModel) {
69 | boolean r = ((TemplateBooleanModel) arg).getAsBoolean();
70 | return exec(reportIssues.stream().filter(i -> isSameReportedOnDiff(i, r)));
71 | }
72 | throw new TemplateModelException("Failed call accept boolean or Severity");
73 | }
74 |
75 | private Object execTwoArg(Object arg1, Object arg2) throws TemplateModelException {
76 | if (arg1 instanceof TemplateScalarModel && arg2 instanceof TemplateBooleanModel) {
77 | String name = ((TemplateScalarModel) arg1).getAsString();
78 | boolean r = ((TemplateBooleanModel) arg2).getAsBoolean();
79 | try {
80 | Severity severity = Severity.valueOf(name);
81 | return exec(reportIssues.stream().filter(i -> isSeverityEquals(i, severity) && isSameReportedOnDiff(i, r)));
82 | } catch (IllegalArgumentException e) {
83 | throw new TemplateModelException("Failed call Severity arg (INFO,MINOR,MAJOR,CRITICAL,BLOCKER)", e);
84 | }
85 | }
86 | throw new TemplateModelException("Failed call accept 2 args boolean or Severity");
87 | }
88 |
89 | private boolean isSeverityEquals(ReportIssue reportIssue, Severity severity) {
90 | return severity == reportIssue.getIssue().getSeverity();
91 | }
92 |
93 | private boolean isSameReportedOnDiff(ReportIssue reportIssue, boolean r) {
94 | return (r && reportIssue.isReportedOnDiff()) || (!r && !reportIssue.isReportedOnDiff());
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/freemarker/AbstractQualityGateConditionsTemplateMethodModelEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.models.QualityGate;
20 | import freemarker.template.TemplateMethodModelEx;
21 | import freemarker.template.TemplateModelException;
22 | import freemarker.template.TemplateScalarModel;
23 |
24 | import java.util.ArrayList;
25 | import java.util.Collections;
26 | import java.util.List;
27 | import java.util.stream.Stream;
28 |
29 | public abstract class AbstractQualityGateConditionsTemplateMethodModelEx implements TemplateMethodModelEx {
30 |
31 | private final List conditions;
32 |
33 | AbstractQualityGateConditionsTemplateMethodModelEx(List conditions) {
34 | super();
35 |
36 | this.conditions = Collections.unmodifiableList(new ArrayList<>(conditions));
37 | }
38 |
39 | @Override
40 | public Object exec(List arguments) throws TemplateModelException {
41 | if (arguments.isEmpty()) {
42 | return execEmptyArg();
43 | } else if (arguments.size() == 1) {
44 | return execOneArg(arguments.get(0));
45 | }
46 | throw new TemplateModelException("Failed call accept 0 or 1 args");
47 | }
48 |
49 | protected abstract Object exec(Stream stream);
50 |
51 | private Object execEmptyArg() {
52 | return exec(conditions.stream());
53 | }
54 |
55 | private Object execOneArg(Object arg) throws TemplateModelException {
56 | if (arg instanceof TemplateScalarModel) {
57 | String name = ((TemplateScalarModel) arg).getAsString();
58 | try {
59 | QualityGate.Status status = QualityGate.Status.valueOf(name);
60 | return exec(conditions.stream().filter(c -> isStatusEquals(c, status)));
61 | } catch (IllegalArgumentException e) {
62 | throw new TemplateModelException("Failed call 1 Status arg (OK,WARN,ERROR)", e);
63 | }
64 | }
65 | throw new TemplateModelException("Failed call accept Status");
66 | }
67 |
68 | private boolean isStatusEquals(QualityGate.Condition condition, QualityGate.Status status) {
69 | return status == condition.getStatus();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/freemarker/AbstractSeverityTemplateMethodModelEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import freemarker.template.TemplateMethodModelEx;
20 | import freemarker.template.TemplateModelException;
21 | import freemarker.template.TemplateScalarModel;
22 | import org.sonar.api.batch.rule.Severity;
23 |
24 | import java.util.List;
25 |
26 | public abstract class AbstractSeverityTemplateMethodModelEx implements TemplateMethodModelEx {
27 |
28 | AbstractSeverityTemplateMethodModelEx() {
29 | super();
30 | }
31 |
32 | @Override
33 | public Object exec(List arguments) throws TemplateModelException {
34 | if (arguments.size() == 1) {
35 | return execOneArg(arguments.get(0));
36 | }
37 | throw new TemplateModelException("Failed call accept 1 Severity arg (INFO,MINOR,MAJOR,CRITICAL,BLOCKER)");
38 | }
39 |
40 | protected abstract Object exec(Severity severity);
41 |
42 | private Object execOneArg(Object arg) throws TemplateModelException {
43 | if (arg instanceof TemplateScalarModel) {
44 | String name = ((TemplateScalarModel) arg).getAsString();
45 | try {
46 | Severity severity = Severity.valueOf(name);
47 | return exec(severity);
48 | } catch (IllegalArgumentException e) {
49 | throw new TemplateModelException("Failed call 1 Severity arg (INFO,MINOR,MAJOR,CRITICAL,BLOCKER)", e);
50 | }
51 | }
52 | throw new TemplateModelException("Failed call accept 1 Severity arg (INFO,MINOR,MAJOR,CRITICAL,BLOCKER)");
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/freemarker/EmojiSeverityTemplateMethodModelEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.MarkDownUtils;
20 | import org.sonar.api.batch.rule.Severity;
21 |
22 | public class EmojiSeverityTemplateMethodModelEx extends AbstractSeverityTemplateMethodModelEx {
23 |
24 | private final MarkDownUtils markDownUtils;
25 |
26 | public EmojiSeverityTemplateMethodModelEx(MarkDownUtils markDownUtils) {
27 | super();
28 |
29 | this.markDownUtils = markDownUtils;
30 | }
31 |
32 | @Override
33 | protected Object exec(Severity severity) {
34 | return markDownUtils.getEmojiForSeverity(severity);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/freemarker/ImageSeverityTemplateMethodModelEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.MarkDownUtils;
20 | import org.sonar.api.batch.rule.Severity;
21 |
22 | public class ImageSeverityTemplateMethodModelEx extends AbstractSeverityTemplateMethodModelEx {
23 |
24 | private final MarkDownUtils markDownUtils;
25 |
26 | public ImageSeverityTemplateMethodModelEx(MarkDownUtils markDownUtils) {
27 | super();
28 |
29 | this.markDownUtils = markDownUtils;
30 | }
31 |
32 | @Override
33 | protected Object exec(Severity severity) {
34 | return markDownUtils.getImageForSeverity(severity);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/freemarker/IssueCountTemplateMethodModelEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.models.ReportIssue;
20 |
21 | import java.util.List;
22 | import java.util.stream.Stream;
23 |
24 | public class IssueCountTemplateMethodModelEx extends AbstractIssuesTemplateMethodModelEx {
25 |
26 | public IssueCountTemplateMethodModelEx(List reportIssues) {
27 | super(reportIssues);
28 | }
29 |
30 | @Override
31 | protected Object exec(Stream stream) {
32 | return (int) stream.count();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/freemarker/IssuesTemplateMethodModelEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.models.ReportIssue;
20 | import com.talanlabs.sonar.plugins.gitlab.models.Rule;
21 |
22 | import java.util.HashMap;
23 | import java.util.List;
24 | import java.util.Map;
25 | import java.util.stream.Collectors;
26 | import java.util.stream.Stream;
27 |
28 | public class IssuesTemplateMethodModelEx extends AbstractIssuesTemplateMethodModelEx {
29 |
30 | public IssuesTemplateMethodModelEx(List reportIssues) {
31 | super(reportIssues);
32 | }
33 |
34 | @Override
35 | protected Object exec(Stream stream) {
36 | return stream.map(this::convertReportIssue).collect(Collectors.toList());
37 | }
38 |
39 | private Map convertReportIssue(ReportIssue reportIssue) {
40 | Map root = new HashMap<>();
41 | root.put("reportedOnDiff", reportIssue.isReportedOnDiff());
42 | root.put("url", reportIssue.getUrl());
43 | root.put("componentKey", reportIssue.getIssue().getComponentKey());
44 | root.put("severity", reportIssue.getIssue().getSeverity());
45 | root.put("line", reportIssue.getIssue().getLine());
46 | root.put("key", reportIssue.getIssue().getKey());
47 | root.put("message", reportIssue.getIssue().getMessage());
48 | root.put("ruleKey", reportIssue.getIssue().getRuleKey());
49 | root.put("new", reportIssue.getIssue().isNewIssue());
50 | root.put("ruleLink", reportIssue.getRuleLink());
51 | root.put("src", reportIssue.getFile());
52 | root.put("rule", reportIssue.getRule() != null ? convertRule(reportIssue.getRule()) : null);
53 | return root;
54 | }
55 |
56 | private Map convertRule(Rule rule) {
57 | Map root = new HashMap<>();
58 | root.put("key", rule.getKey());
59 | root.put("repo", rule.getRepo());
60 | root.put("name", rule.getName());
61 | root.put("description", rule.getDescription());
62 | root.put("type", rule.getType());
63 | root.put("debtRemFnType", rule.getDebtRemFnType());
64 | root.put("debtRemFnBaseEffort", rule.getDebtRemFnBaseEffort());
65 | return root;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/freemarker/PrintTemplateMethodModelEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.MarkDownUtils;
20 | import freemarker.ext.util.WrapperTemplateModel;
21 | import freemarker.template.TemplateMethodModelEx;
22 | import freemarker.template.TemplateModelException;
23 | import org.sonar.api.batch.rule.Severity;
24 |
25 | import java.util.List;
26 | import java.util.Map;
27 |
28 | public class PrintTemplateMethodModelEx implements TemplateMethodModelEx {
29 |
30 | private final MarkDownUtils markDownUtils;
31 |
32 | public PrintTemplateMethodModelEx(MarkDownUtils markDownUtils) {
33 | super();
34 |
35 | this.markDownUtils = markDownUtils;
36 | }
37 |
38 | @Override
39 | public Object exec(List arguments) throws TemplateModelException {
40 | if (arguments.size() == 1) {
41 | return execOneArg(arguments.get(0));
42 | }
43 | throw new TemplateModelException("Failed call accept 1 issue arg");
44 | }
45 |
46 | private String execOneArg(Object arg) throws TemplateModelException {
47 | if (arg instanceof WrapperTemplateModel && ((WrapperTemplateModel) arg).getWrappedObject() instanceof Map) {
48 | Map map = (Map) ((WrapperTemplateModel) arg).getWrappedObject();
49 | return markDownUtils.printIssue((Severity) (map.get("severity")), (String) map.get("message"), (String) map.get("ruleLink"), (String) map.get("url"), (String) map.get("componentKey"));
50 | }
51 | throw new TemplateModelException("Failed call accept 1 issue arg");
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/freemarker/QualityGateConditionCountTemplateMethodModelEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.models.QualityGate;
20 |
21 | import java.util.List;
22 | import java.util.stream.Stream;
23 |
24 | public class QualityGateConditionCountTemplateMethodModelEx extends AbstractQualityGateConditionsTemplateMethodModelEx {
25 |
26 | public QualityGateConditionCountTemplateMethodModelEx(List conditions) {
27 | super(conditions);
28 | }
29 |
30 | @Override
31 | protected Object exec(Stream stream) {
32 | return (int)stream.count();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/freemarker/QualityGateConditionsTemplateMethodModelEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.models.QualityGate;
20 |
21 | import java.util.HashMap;
22 | import java.util.List;
23 | import java.util.Map;
24 | import java.util.stream.Collectors;
25 | import java.util.stream.Stream;
26 |
27 | public class QualityGateConditionsTemplateMethodModelEx extends AbstractQualityGateConditionsTemplateMethodModelEx {
28 |
29 | public QualityGateConditionsTemplateMethodModelEx(List conditions) {
30 | super(conditions);
31 | }
32 |
33 | @Override
34 | protected Object exec(Stream stream) {
35 | return stream.map(this::convertCondition).collect(Collectors.toList());
36 | }
37 |
38 | private Map convertCondition(QualityGate.Condition condition) {
39 | Map root = new HashMap<>();
40 | root.put("status", condition.getStatus());
41 | root.put("actual", condition.getActual());
42 | root.put("warning", condition.getWarning());
43 | root.put("error", condition.getError());
44 | root.put("metricKey", condition.getMetricKey());
45 | root.put("metricName", condition.getMetricName());
46 | root.put("symbol", condition.getSymbol());
47 | return root;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/freemarker/RuleLinkTemplateMethodModelEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.CommitFacade;
20 | import com.talanlabs.sonar.plugins.gitlab.GitLabPluginConfiguration;
21 | import freemarker.template.TemplateMethodModelEx;
22 | import freemarker.template.TemplateModelException;
23 | import freemarker.template.TemplateScalarModel;
24 |
25 | import java.util.List;
26 |
27 | public class RuleLinkTemplateMethodModelEx implements TemplateMethodModelEx {
28 |
29 | private final String ruleUrlPrefix;
30 |
31 | public RuleLinkTemplateMethodModelEx(GitLabPluginConfiguration gitLabPluginConfiguration) {
32 | super();
33 |
34 | this.ruleUrlPrefix = gitLabPluginConfiguration.baseUrl();
35 | }
36 |
37 | @Override
38 | public Object exec(List arguments) throws TemplateModelException {
39 | if (arguments.size() == 1) {
40 | return execOneArg(arguments.get(0));
41 | }
42 | throw new TemplateModelException("Failed call accept 1 url arg");
43 | }
44 |
45 | private Object execOneArg(Object arg) throws TemplateModelException {
46 | if (arg instanceof TemplateScalarModel) {
47 | String name = ((TemplateScalarModel) arg).getAsString();
48 | return ruleUrlPrefix + "coding_rules#rule_key=" + CommitFacade.encodeForUrl(name);
49 | }
50 | throw new TemplateModelException("Failed call accept 1 url arg");
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/models/Issue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.models;
18 |
19 | import org.sonar.api.batch.rule.Severity;
20 |
21 | import java.io.File;
22 |
23 | public class Issue {
24 |
25 | private String key;
26 | private String ruleKey;
27 | private String componentKey;
28 | private File file;
29 | private Integer line;
30 | private String message;
31 | private Severity severity;
32 | private boolean newIssue;
33 |
34 | private Issue() {
35 | // Nothing
36 | }
37 |
38 | public static Builder newBuilder() {
39 | return new Builder();
40 | }
41 |
42 | public String getKey() {
43 | return key;
44 | }
45 |
46 | public String getRuleKey() {
47 | return ruleKey;
48 | }
49 |
50 | public String getComponentKey() {
51 | return componentKey;
52 | }
53 |
54 | public File getFile() {
55 | return file;
56 | }
57 |
58 | public Integer getLine() {
59 | return line;
60 | }
61 |
62 | public String getMessage() {
63 | return message;
64 | }
65 |
66 | public Severity getSeverity() {
67 | return severity;
68 | }
69 |
70 | public boolean isNewIssue() {
71 | return newIssue;
72 | }
73 |
74 | public static class Builder {
75 |
76 | private final Issue issue;
77 |
78 | private Builder() {
79 | this.issue = new Issue();
80 | }
81 |
82 | public Builder key(String key) {
83 | issue.key = key;
84 | return this;
85 | }
86 |
87 | public Builder ruleKey(String ruleKey) {
88 | issue.ruleKey = ruleKey;
89 | return this;
90 | }
91 |
92 | public Builder componentKey(String componentKey) {
93 | issue.componentKey = componentKey;
94 | return this;
95 | }
96 |
97 | public Builder file(File file) {
98 | issue.file = file;
99 | return this;
100 | }
101 |
102 | public Builder line(Integer line) {
103 | issue.line = line;
104 | return this;
105 | }
106 |
107 | public Builder message(String message) {
108 | issue.message = message;
109 | return this;
110 | }
111 |
112 | public Builder severity(Severity severity) {
113 | issue.severity = severity;
114 | return this;
115 | }
116 |
117 | public Builder newIssue(boolean newIssue) {
118 | issue.newIssue = newIssue;
119 | return this;
120 | }
121 |
122 | public Issue build() {
123 | return issue;
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/models/JsonMode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.models;
18 |
19 | public enum JsonMode {
20 |
21 | NONE, CODECLIMATE, SAST;
22 |
23 | public static JsonMode of(String name) {
24 | for (JsonMode m : values()) {
25 | if (m.name().equals(name)) {
26 | return m;
27 | }
28 | }
29 | return null;
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/models/QualityGate.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.models;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Collections;
21 | import java.util.List;
22 |
23 | public class QualityGate {
24 |
25 | private Status status;
26 | private List conditions;
27 |
28 | private QualityGate() {
29 | // Nothing
30 | }
31 |
32 | public static Builder newBuilder() {
33 | return new Builder();
34 | }
35 |
36 | public Status getStatus() {
37 | return status;
38 | }
39 |
40 | public List getConditions() {
41 | return Collections.unmodifiableList(conditions);
42 | }
43 |
44 | public enum Status {
45 |
46 | OK, WARN, ERROR, NONE;
47 |
48 | public static Status of(String name) {
49 | for (Status m : values()) {
50 | if (m.name().equals(name)) {
51 | return m;
52 | }
53 | }
54 | return null;
55 | }
56 | }
57 |
58 | public static class Builder {
59 |
60 | private final QualityGate qualityGate;
61 |
62 | private Builder() {
63 | this.qualityGate = new QualityGate();
64 | }
65 |
66 | public Builder status(Status status) {
67 | this.qualityGate.status = status;
68 | return this;
69 | }
70 |
71 | public Builder conditions(List conditions) {
72 | this.qualityGate.conditions = new ArrayList<>(conditions);
73 | return this;
74 | }
75 |
76 | public QualityGate build() {
77 | return qualityGate;
78 | }
79 | }
80 |
81 | public static class Condition {
82 |
83 | private Status status;
84 | private String metricKey;
85 | private String metricName;
86 | private String actual;
87 | private String symbol;
88 | private String warning;
89 | private String error;
90 |
91 | private Condition() {
92 | // Nothing
93 | }
94 |
95 | public static Builder newBuilder() {
96 | return new Builder();
97 | }
98 |
99 | public Status getStatus() {
100 | return status;
101 | }
102 |
103 | public String getMetricKey() {
104 | return metricKey;
105 | }
106 |
107 | public String getMetricName() {
108 | return metricName;
109 | }
110 |
111 | public String getActual() {
112 | return actual;
113 | }
114 |
115 | public String getSymbol() {
116 | return symbol;
117 | }
118 |
119 | public String getWarning() {
120 | return warning;
121 | }
122 |
123 | public String getError() {
124 | return error;
125 | }
126 |
127 | public static class Builder {
128 |
129 | private final Condition condition;
130 |
131 | private Builder() {
132 | this.condition = new Condition();
133 | }
134 |
135 | public Builder status(Status status) {
136 | this.condition.status = status;
137 | return this;
138 | }
139 |
140 | public Builder metricKey(String metricKey) {
141 | this.condition.metricKey = metricKey;
142 | return this;
143 | }
144 |
145 | public Builder metricName(String metricName) {
146 | this.condition.metricName = metricName;
147 | return this;
148 | }
149 |
150 | public Builder actual(String actual) {
151 | this.condition.actual = actual;
152 | return this;
153 | }
154 |
155 | public Builder symbol(String symbol) {
156 | this.condition.symbol = symbol;
157 | return this;
158 | }
159 |
160 | public Builder warning(String warning) {
161 | this.condition.warning = warning;
162 | return this;
163 | }
164 |
165 | public Builder error(String error) {
166 | this.condition.error = error;
167 | return this;
168 | }
169 |
170 | public Condition build() {
171 | return condition;
172 | }
173 | }
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/models/QualityGateFailMode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.models;
18 |
19 | public enum QualityGateFailMode {
20 |
21 | ERROR("ERROR"), WARN("WARN"), NONE("NONE");
22 |
23 | private final String meaning;
24 |
25 | QualityGateFailMode(String meaning) {
26 | this.meaning = meaning;
27 | }
28 |
29 | public static QualityGateFailMode of(String meaning) {
30 | for (QualityGateFailMode m : values()) {
31 | if (m.meaning.equalsIgnoreCase(meaning)) {
32 | return m;
33 | }
34 | }
35 | return null;
36 | }
37 |
38 | public String getMeaning() {
39 | return meaning;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/models/ReportIssue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.models;
18 |
19 | public class ReportIssue {
20 |
21 | private Issue issue;
22 | private Rule rule;
23 | private String revision;
24 | private String url;
25 | private String file;
26 | private String ruleLink;
27 | private boolean reportedOnDiff;
28 |
29 | private ReportIssue() {
30 | // Nothing
31 | }
32 |
33 | public static Builder newBuilder() {
34 | return new Builder();
35 | }
36 |
37 | public Issue getIssue() {
38 | return issue;
39 | }
40 |
41 | public String getRevision() {
42 | return revision;
43 | }
44 |
45 | public String getUrl() {
46 | return url;
47 | }
48 |
49 | public String getFile() {
50 | return file;
51 | }
52 |
53 | public String getRuleLink() {
54 | return ruleLink;
55 | }
56 |
57 | public boolean isReportedOnDiff() {
58 | return reportedOnDiff;
59 | }
60 |
61 | public Rule getRule() {
62 | return rule;
63 | }
64 |
65 | public static class Builder {
66 |
67 | private final ReportIssue reportIssue;
68 |
69 | private Builder() {
70 | this.reportIssue = new ReportIssue();
71 | }
72 |
73 | public Builder issue(Issue issue) {
74 | this.reportIssue.issue = issue;
75 | return this;
76 | }
77 |
78 | public Builder rule(Rule rule) {
79 | this.reportIssue.rule = rule;
80 | return this;
81 | }
82 |
83 | public Builder revision(String revision) {
84 | this.reportIssue.revision = revision;
85 | return this;
86 | }
87 |
88 | public Builder url(String url) {
89 | this.reportIssue.url = url;
90 | return this;
91 | }
92 |
93 | public Builder file(String file) {
94 | this.reportIssue.file = file;
95 | return this;
96 | }
97 |
98 | public Builder ruleLink(String ruleLink) {
99 | this.reportIssue.ruleLink = ruleLink;
100 | return this;
101 | }
102 |
103 | public Builder reportedOnDiff(boolean reportedOnDiff) {
104 | this.reportIssue.reportedOnDiff = reportedOnDiff;
105 | return this;
106 | }
107 |
108 | public ReportIssue build() {
109 | return reportIssue;
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/models/Rule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.models;
18 |
19 | public class Rule {
20 |
21 | private String key;
22 | private String repo;
23 | private String name;
24 | private String description;
25 | private String type;
26 | private String debtRemFnType;
27 | private String debtRemFnBaseEffort;
28 |
29 | private Rule() {
30 | // Nothing
31 | }
32 |
33 | public static Builder newBuilder() {
34 | return new Builder();
35 | }
36 |
37 | public String getKey() {
38 | return key;
39 | }
40 |
41 | public String getRepo() {
42 | return repo;
43 | }
44 |
45 | public String getName() {
46 | return name;
47 | }
48 |
49 | public String getDescription() {
50 | return description;
51 | }
52 |
53 | public String getType() {
54 | return type;
55 | }
56 |
57 | public String getDebtRemFnType() {
58 | return debtRemFnType;
59 | }
60 |
61 | public String getDebtRemFnBaseEffort() {
62 | return debtRemFnBaseEffort;
63 | }
64 |
65 | public static class Builder {
66 |
67 | private final Rule rule;
68 |
69 | private Builder() {
70 | this.rule = new Rule();
71 | }
72 |
73 | public Builder key(String key) {
74 | this.rule.key = key;
75 | return this;
76 | }
77 |
78 | public Builder repo(String repo) {
79 | this.rule.repo = repo;
80 | return this;
81 | }
82 |
83 | public Builder name(String name) {
84 | this.rule.name = name;
85 | return this;
86 | }
87 |
88 | public Builder description(String description) {
89 | this.rule.description = description;
90 | return this;
91 | }
92 |
93 | public Builder type(String type) {
94 | this.rule.type = type;
95 | return this;
96 | }
97 |
98 | public Builder debtRemFnType(String debtRemFnType) {
99 | this.rule.debtRemFnType = debtRemFnType;
100 | return this;
101 | }
102 |
103 | public Builder debtRemFnBaseEffort(String debtRemFnBaseEffort) {
104 | this.rule.debtRemFnBaseEffort = debtRemFnBaseEffort;
105 | return this;
106 | }
107 |
108 | public Rule build() {
109 | return rule;
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/com/talanlabs/sonar/plugins/gitlab/models/StatusNotificationsMode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.models;
18 |
19 | public enum StatusNotificationsMode {
20 |
21 | COMMIT_STATUS("commit-status"), EXIT_CODE("exit-code"), NOTHING("nothing");
22 |
23 | private final String meaning;
24 |
25 | StatusNotificationsMode(String meaning) {
26 | this.meaning = meaning;
27 | }
28 |
29 | public static StatusNotificationsMode of(String meaning) {
30 | for (StatusNotificationsMode m : values()) {
31 | if (m.meaning.equals(meaning)) {
32 | return m;
33 | }
34 | }
35 | return null;
36 | }
37 |
38 | public String getMeaning() {
39 | return meaning;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/resources/org/sonar/l10n/gitlab.properties:
--------------------------------------------------------------------------------
1 | property.category.gitlab=GitLab
2 | property.category.gitlab.reporting=Reporting
3 | property.category.gitlab.reporting.description=Set GitLab URL and Token access
--------------------------------------------------------------------------------
/src/test/java/com/talanlabs/sonar/plugins/gitlab/CommitFacadeTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.models.JsonMode;
20 | import org.assertj.core.api.Assertions;
21 | import org.junit.Rule;
22 | import org.junit.Test;
23 | import org.junit.rules.TemporaryFolder;
24 | import org.mockito.Mockito;
25 |
26 | import java.io.File;
27 | import java.io.IOException;
28 | import java.nio.file.Files;
29 | import java.util.Collections;
30 |
31 | import static org.assertj.core.api.Assertions.assertThat;
32 | import static org.mockito.Mockito.mock;
33 | import static org.mockito.Mockito.when;
34 |
35 | public class CommitFacadeTest {
36 |
37 | @Rule
38 | public TemporaryFolder temp = new TemporaryFolder();
39 |
40 | @Test
41 | public void testInitGitBaseDirNotFound() throws Exception {
42 | CommitFacade facade = new CommitFacade(mock(GitLabPluginConfiguration.class));
43 | File projectBaseDir = temp.newFolder();
44 | facade.initGitBaseDir(projectBaseDir);
45 | assertThat(facade.getPath(new File(projectBaseDir, "src/main/java/Foo.java"))).isEqualTo("src/main/java/Foo.java");
46 | }
47 |
48 | @Test
49 | public void testInitGitBaseDir() throws Exception {
50 | CommitFacade facade = new CommitFacade(mock(GitLabPluginConfiguration.class));
51 | File gitBaseDir = temp.newFolder();
52 | Files.createDirectory(gitBaseDir.toPath().resolve(".git"));
53 | File projectBaseDir = new File(gitBaseDir, "myProject");
54 | facade.initGitBaseDir(projectBaseDir);
55 | assertThat(facade.getPath(new File(projectBaseDir, "src/main/java/Foo.java"))).isEqualTo("myProject/src/main/java/Foo.java");
56 | }
57 |
58 | @Test
59 | public void testGetPath() throws IOException {
60 | GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
61 | when(gitLabPluginConfiguration.commitSHA()).thenReturn(Collections.singletonList("1"));
62 | when(gitLabPluginConfiguration.refName()).thenReturn("master");
63 |
64 | CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
65 |
66 | File gitBasedir = temp.newFolder();
67 | facade.setGitBaseDir(gitBasedir);
68 |
69 | Assertions.assertThat(facade.getPath(new File(gitBasedir, "src/main/Foo.java"))).isEqualTo("src/main/Foo.java");
70 |
71 | when(gitLabPluginConfiguration.prefixDirectory()).thenReturn("toto/");
72 |
73 | Assertions.assertThat(facade.getPath(new File(gitBasedir, "src/main/Foo.java"))).isEqualTo("toto/src/main/Foo.java");
74 | }
75 |
76 | @Test
77 | public void testWriteCodeClimateJson() throws IOException {
78 | GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
79 | when(gitLabPluginConfiguration.jsonMode()).thenReturn(JsonMode.CODECLIMATE);
80 | CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
81 | File projectBaseDir = temp.newFolder();
82 | facade.initGitBaseDir(projectBaseDir);
83 |
84 | facade.writeJsonFile("[{\"tool\":\"sonarqube\",\"fingerprint\":\"null\",\"message\":\"Issue\",\"file\":\"file\",\"line\":\"0\",\"priority\":\"INFO\",\"solution\":\"http://myserver\"}]");
85 |
86 | File file = new File(projectBaseDir, "gl-code-quality-report.json");
87 | Assertions.assertThat(file).exists().hasContent("[{\"tool\":\"sonarqube\",\"fingerprint\":\"null\",\"message\":\"Issue\",\"file\":\"file\",\"line\":\"0\",\"priority\":\"INFO\",\"solution\":\"http://myserver\"}]");
88 | }
89 |
90 | @Test
91 | public void testWriteSastJson() throws IOException {
92 | GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
93 | when(gitLabPluginConfiguration.jsonMode()).thenReturn(JsonMode.SAST);
94 | CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
95 | File projectBaseDir = temp.newFolder();
96 | facade.initGitBaseDir(projectBaseDir);
97 |
98 | facade.writeJsonFile("[{\"tool\":\"sonarqube\",\"fingerprint\":\"null\",\"message\":\"Issue\",\"file\":\"file\",\"line\":\"0\",\"priority\":\"INFO\",\"solution\":\"http://myserver\"}]");
99 |
100 | File file = new File(projectBaseDir, "gl-sast-report.json");
101 | Assertions.assertThat(file).exists().hasContent("[{\"tool\":\"sonarqube\",\"fingerprint\":\"null\",\"message\":\"Issue\",\"file\":\"file\",\"line\":\"0\",\"priority\":\"INFO\",\"solution\":\"http://myserver\"}]");
102 | }
103 |
104 | @Test
105 | public void testWriteNoneJson() throws IOException {
106 | GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
107 | when(gitLabPluginConfiguration.jsonMode()).thenReturn(JsonMode.NONE);
108 | CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
109 | File projectBaseDir = temp.newFolder();
110 | facade.initGitBaseDir(projectBaseDir);
111 |
112 | facade.writeJsonFile("[{\"tool\":\"sonarqube\",\"fingerprint\":\"null\",\"message\":\"Issue\",\"file\":\"file\",\"line\":\"0\",\"priority\":\"INFO\",\"solution\":\"http://myserver\"}]");
113 |
114 | File file = new File(projectBaseDir, "gl-code-quality-report.json");
115 | Assertions.assertThat(projectBaseDir.listFiles((p) -> p.getPath().endsWith(".json"))).isEmpty();
116 | }
117 |
118 | @Test
119 | public void testUsernameForRevision() {
120 | GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
121 | CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
122 | IGitLabApiWrapper gitLabApiWrapper = mock(IGitLabApiWrapper.class);
123 | facade.setGitLabWrapper(gitLabApiWrapper);
124 | facade.getUsernameForRevision("123");
125 |
126 | Mockito.verify(gitLabApiWrapper).getUsernameForRevision("123");
127 | }
128 |
129 | @Test
130 | public void testCreateOrUpdateSonarQubeStatus() {
131 | GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
132 | CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
133 | IGitLabApiWrapper gitLabApiWrapper = mock(IGitLabApiWrapper.class);
134 | facade.setGitLabWrapper(gitLabApiWrapper);
135 | facade.createOrUpdateSonarQubeStatus("ok", "hello");
136 |
137 | Mockito.verify(gitLabApiWrapper).createOrUpdateSonarQubeStatus("ok", "hello");
138 | }
139 |
140 | @Test
141 | public void testGetGitLabUrl() throws IOException {
142 | GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
143 | when(gitLabPluginConfiguration.commitSHA()).thenReturn(Collections.singletonList("1"));
144 | when(gitLabPluginConfiguration.refName()).thenReturn("master");
145 |
146 | CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
147 | IGitLabApiWrapper gitLabApiWrapper = mock(IGitLabApiWrapper.class);
148 |
149 | File gitBasedir = temp.newFolder();
150 | facade.setGitBaseDir(gitBasedir);
151 | facade.setGitLabWrapper(gitLabApiWrapper);
152 |
153 | Assertions.assertThat(facade.getGitLabUrl("123", null, null)).isNull();
154 |
155 | when(gitLabApiWrapper.getGitLabUrl("123", "src/main/Foo.java", 1)).thenReturn("response");
156 | Assertions.assertThat(facade.getGitLabUrl("123", new File(gitBasedir, "src/main/Foo.java"), 1)).isEqualTo("response");
157 | }
158 |
159 | @Test
160 | public void testGetSrc() throws IOException {
161 | GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
162 | when(gitLabPluginConfiguration.commitSHA()).thenReturn(Collections.singletonList("1"));
163 | when(gitLabPluginConfiguration.refName()).thenReturn("master");
164 |
165 | CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
166 |
167 | File gitBasedir = temp.newFolder();
168 | facade.setGitBaseDir(gitBasedir);
169 |
170 | Assertions.assertThat(facade.getSrc(null)).isNull();
171 |
172 | Assertions.assertThat(facade.getSrc(new File(gitBasedir, "src/main/Foo.java"))).isEqualTo("src/main/Foo.java");
173 |
174 | when(gitLabPluginConfiguration.prefixDirectory()).thenReturn("toto/");
175 |
176 | Assertions.assertThat(facade.getSrc(new File(gitBasedir, "src/main/Foo.java"))).isEqualTo("toto/src/main/Foo.java");
177 | }
178 |
179 | @Test
180 | public void testCreateOrUpdateReviewComment() throws IOException {
181 | GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
182 | when(gitLabPluginConfiguration.commitSHA()).thenReturn(Collections.singletonList("1"));
183 | when(gitLabPluginConfiguration.refName()).thenReturn("master");
184 |
185 | CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
186 | IGitLabApiWrapper gitLabApiWrapper = mock(IGitLabApiWrapper.class);
187 |
188 | File gitBasedir = temp.newFolder();
189 | facade.setGitBaseDir(gitBasedir);
190 | facade.setGitLabWrapper(gitLabApiWrapper);
191 |
192 | facade.createOrUpdateReviewComment("123", new File(gitBasedir, "src/main/Foo.java"), 5, "toto");
193 |
194 | Mockito.verify(gitLabApiWrapper).createOrUpdateReviewComment("123", "src/main/Foo.java", 5, "toto");
195 | }
196 |
197 | @Test
198 | public void testAddGlobalComment() {
199 | GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
200 | CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
201 | IGitLabApiWrapper gitLabApiWrapper = mock(IGitLabApiWrapper.class);
202 | facade.setGitLabWrapper(gitLabApiWrapper);
203 | facade.addGlobalComment("hello");
204 |
205 | Mockito.verify(gitLabApiWrapper).addGlobalComment("hello");
206 | }
207 |
208 | @Test
209 | public void testGetRuleLink() {
210 | GitLabPluginConfiguration gitLabPluginConfiguration = mock(GitLabPluginConfiguration.class);
211 | when(gitLabPluginConfiguration.baseUrl()).thenReturn("http://test/");
212 |
213 | CommitFacade facade = new CommitFacade(gitLabPluginConfiguration);
214 |
215 | Assertions.assertThat(facade.getRuleLink("hello")).isEqualTo("http://test/coding_rules#rule_key=hello");
216 |
217 | }
218 | }
--------------------------------------------------------------------------------
/src/test/java/com/talanlabs/sonar/plugins/gitlab/GitLabPluginTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab;
18 |
19 | import org.junit.Test;
20 | import org.sonar.api.Plugin;
21 | import org.sonar.api.SonarEdition;
22 | import org.sonar.api.SonarQubeSide;
23 | import org.sonar.api.internal.SonarRuntimeImpl;
24 | import org.sonar.api.utils.Version;
25 |
26 | import static org.assertj.core.api.Assertions.assertThat;
27 |
28 | public class GitLabPluginTest {
29 |
30 | @Test
31 | public void uselessTest() {
32 | final Version version = Version.parse("7.9.1");
33 | Plugin.Context context = new Plugin.Context(SonarRuntimeImpl.forSonarQube(version, SonarQubeSide.SCANNER, SonarEdition.COMMUNITY));
34 | new GitLabPlugin().define(context);
35 | assertThat(context.getExtensions().size()).isGreaterThan(7);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/com/talanlabs/sonar/plugins/gitlab/InlineTemplateTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.models.ReportIssue;
20 | import org.assertj.core.api.Assertions;
21 | import org.junit.Before;
22 | import org.junit.Test;
23 | import org.sonar.api.CoreProperties;
24 | import org.sonar.api.batch.rule.Severity;
25 | import org.sonar.api.config.PropertyDefinition;
26 | import org.sonar.api.config.PropertyDefinitions;
27 | import org.sonar.api.config.internal.MapSettings;
28 | import org.sonar.api.utils.System2;
29 |
30 | import java.util.Collections;
31 | import java.util.List;
32 | import java.util.stream.Collectors;
33 | import java.util.stream.Stream;
34 |
35 | public class InlineTemplateTest {
36 |
37 | private static final String TEMPLATE = "<#list issues() as issue>\n" + "<@p issue=issue/>\n" + "#list>\n" + "<#macro p issue>\n"
38 | + "${emojiSeverity(issue.severity)} ${issue.message} [:blue_book:](${ruleLink(issue.ruleKey)})\n" + "#macro>";
39 |
40 | private MapSettings settings;
41 | private GitLabPluginConfiguration config;
42 |
43 | @Before
44 | public void setUp() {
45 | settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, PropertyDefinition.builder(CoreProperties.SERVER_BASE_URL).name("Server base URL")
46 | .description("HTTP URL of this SonarQube server, such as http://yourhost.yourdomain/sonar. This value is used i.e. to create links in emails.")
47 | .category(CoreProperties.CATEGORY_GENERAL).defaultValue("http://localhost:9000").build()).addComponents(GitLabPlugin.definitions()));
48 |
49 | settings.setProperty(CoreProperties.SERVER_BASE_URL, "http://myserver");
50 | settings.setProperty(GitLabPlugin.GITLAB_COMMIT_SHA, "abc123");
51 |
52 | config = new GitLabPluginConfiguration(settings.asConfig(), new System2());
53 |
54 | settings.setProperty(GitLabPlugin.GITLAB_INLINE_TEMPLATE, TEMPLATE);
55 | }
56 |
57 | @Test
58 | public void testOneIssue() {
59 | ReportIssue r1 =ReportIssue.newBuilder().issue(Utils.newIssue("component", null, 1, Severity.INFO, true, "Issue", "rule")).revision(null).url("lalal").file("file").ruleLink(
60 | "http://myserver/coding_rules#rule_key=repo%3Arule").reportedOnDiff(true).build();
61 |
62 | Assertions.assertThat(new InlineCommentBuilder(config, "123", null, 1, Collections.singletonList(r1), new MarkDownUtils()).buildForMarkdown())
63 | .isEqualTo(":information_source: Issue [:blue_book:](http://myserver/coding_rules#rule_key=repo%3Arule)\n");
64 | }
65 |
66 | @Test
67 | public void testTwoIssue() {
68 | List ris = Stream.iterate(0, i -> i++).limit(2)
69 | .map(i ->ReportIssue.newBuilder().issue(Utils.newIssue("component", null, 1, Severity.INFO, true, "Issue", "rule")).revision(null).url("lalal").file("file").ruleLink(
70 | "http://myserver/coding_rules#rule_key=repo%3Arule").reportedOnDiff(true).build()).collect(Collectors.toList());
71 |
72 | Assertions.assertThat(new InlineCommentBuilder(config, "123", null, 1, ris, new MarkDownUtils()).buildForMarkdown()).isEqualTo(
73 | ":information_source: Issue [:blue_book:](http://myserver/coding_rules#rule_key=repo%3Arule)\n"
74 | + ":information_source: Issue [:blue_book:](http://myserver/coding_rules#rule_key=repo%3Arule)\n");
75 | }
76 |
77 | @Test
78 | public void testUnescapeHTML() {
79 | settings.setProperty(GitLabPlugin.GITLAB_INLINE_TEMPLATE, TEMPLATE + "àâéç");
80 |
81 | ReportIssue r1 =ReportIssue.newBuilder().issue(Utils.newIssue("component", null, 1, Severity.INFO, true, "Issue", "rule")).revision(null).url("lalal").file("file").ruleLink(
82 | "http://myserver/coding_rules#rule_key=repo%3Arule").reportedOnDiff(true).build();
83 |
84 | Assertions.assertThat(new InlineCommentBuilder(config, "123", null, 1, Collections.singletonList(r1), new MarkDownUtils()).buildForMarkdown())
85 | .isEqualTo(":information_source: Issue [:blue_book:](http://myserver/coding_rules#rule_key=repo%3Arule)\nàâéç");
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/test/java/com/talanlabs/sonar/plugins/gitlab/IssueComparatorTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.models.Issue;
20 | import org.assertj.core.api.Assertions;
21 | import org.junit.Before;
22 | import org.junit.Test;
23 | import org.sonar.api.batch.rule.Severity;
24 |
25 | public class IssueComparatorTest {
26 |
27 | private IssueComparator issueComparator;
28 |
29 | @Before
30 | public void before() {
31 | issueComparator = new IssueComparator();
32 | }
33 |
34 | @Test
35 | public void testNull() {
36 | Assertions.assertThat(issueComparator.compare(null, null)).isEqualTo(0);
37 | Assertions.assertThat(issueComparator.compare(Issue.newBuilder().build(), null)).isEqualTo(-1);
38 | Assertions.assertThat(issueComparator.compare(null, Issue.newBuilder().build())).isEqualTo(1);
39 | }
40 |
41 | @Test
42 | public void testSeverity() {
43 | Assertions.assertThat(issueComparator.compare(Issue.newBuilder().severity(Severity.BLOCKER).componentKey("toto").line(1).build(), Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "toto").line(1).build())).isEqualTo(0);
44 | Assertions.assertThat(issueComparator.compare(Issue.newBuilder().severity(Severity.MAJOR).componentKey( "toto").line(1).build(), Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "toto").line(1).build())).isEqualTo(1);
45 | Assertions.assertThat(issueComparator.compare(Issue.newBuilder().severity(Severity.MAJOR).componentKey( "toto").line(1).build(), Issue.newBuilder().severity(Severity.MINOR).componentKey( "toto").line(1).build())).isEqualTo(-1);
46 | }
47 |
48 | @Test
49 | public void testComponentKey() {
50 | Assertions.assertThat(issueComparator.compare(Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line(1).build(), Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "b").line( 1).build())).isEqualTo(-1);
51 | Assertions.assertThat(issueComparator.compare(Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "b").line(1).build(), Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line( 1).build())).isEqualTo(1);
52 | }
53 |
54 | @Test
55 | public void testSimple() {
56 | Assertions.assertThat(issueComparator.compare(Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line(null).build(), Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line( null).build())).isEqualTo(0);
57 | Assertions.assertThat(issueComparator.compare(Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line(1).build(), Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line( 2).build())).isEqualTo(-1);
58 | Assertions.assertThat(issueComparator.compare(Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line(1).build(), Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line( null).build())).isEqualTo(1);
59 | Assertions.assertThat(issueComparator.compare(Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line(10).build(), Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line( 1).build())).isEqualTo(1);
60 | Assertions.assertThat(issueComparator.compare(Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line(null).build(), Issue.newBuilder().severity(Severity.BLOCKER).componentKey( "a").line( 1).build())).isEqualTo(-1);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/test/java/com/talanlabs/sonar/plugins/gitlab/PatchUtilsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab;
18 |
19 | import org.assertj.core.api.Assertions;
20 | import org.junit.Test;
21 |
22 | public class PatchUtilsTest {
23 |
24 | @Test
25 | public void testEmpty() {
26 | Assertions.assertThat(PatchUtils.getPositionsFromPatch("12313")).isEmpty();
27 | }
28 |
29 | @Test
30 | public void testWrong() {
31 | Assertions.assertThatThrownBy(() -> PatchUtils.getPositionsFromPatch("@ wrong")).isInstanceOf(IllegalStateException.class).hasMessage("Unable to parse line:\n" +
32 | "\t@ wrong\n" +
33 | "Full patch: \n" +
34 | "\t@ wrong");
35 | }
36 |
37 | @Test
38 | public void testCorrectUnixEOL() {
39 | Assertions.assertThat(PatchUtils.getPositionsFromPatch("@@ -78,6 +78,27 @@\n" +
40 | "\t\t\t\t\"src/styles.scss\",\n" +
41 | " \"src/cordova-styles.scss\"\n" +
42 | " ]\n" +
43 | " },\n" +
44 | "+ \"prod-cordova\": {\n" +
45 | "+ \"optimization\": true,\n" +
46 | "+ \"outputHashing\": \"all\",\n" +
47 | " \"sourceMap\": false,\n" +
48 | " \"extractCss\": true,\n" +
49 | " \"namedChunks\": false,\n" +
50 | " \"aot\": true,\n" +
51 | " \"extractLicenses\": true,\n" +
52 | " \"vendorChunk\": false,\n" +
53 | " \"buildOptimizer\": true,\n" +
54 | " \"fileReplacements\": [\n" +
55 | " {\n" +
56 | " \"replace\": \"src/environments/environment.ts\",\n" +
57 | " \"with\": \"src/environments/environment.prod-cordova.ts\"\n" +
58 | " }\n" +
59 | " ],\n" +
60 | " \"styles\": [\n" +
61 | " \"src/styles.scss\",\n" +
62 | " \"src/cordova-styles.scss\"\n" +
63 | " ]\n" +
64 | " }\n" +
65 | " }\n" +
66 | " },")).isNotEmpty().hasSize(3).containsExactlyInAnyOrder(
67 | new IGitLabApiWrapper.Line(83, " \"outputHashing\": \"all\","),
68 | new IGitLabApiWrapper.Line(82, " \"optimization\": true,"),
69 | new IGitLabApiWrapper.Line(81, " \"prod-cordova\": {")
70 | );
71 | }
72 |
73 |
74 | @Test
75 | public void testCorrectMacEOL() {
76 | Assertions.assertThat(PatchUtils.getPositionsFromPatch("@@ -78,6 +78,27 @@\r" +
77 | "\t\t\t\t\"src/styles.scss\",\r" +
78 | " \"src/cordova-styles.scss\"\r" +
79 | " ]\r" +
80 | " },\r" +
81 | "+ \"prod-cordova\": {\r" +
82 | "+ \"optimization\": true,\r" +
83 | "+ \"outputHashing\": \"all\",\r" +
84 | " \"sourceMap\": false,\r" +
85 | " \"extractCss\": true,\r" +
86 | " \"namedChunks\": false,\r" +
87 | " \"aot\": true,\r" +
88 | " \"extractLicenses\": true,\r" +
89 | " \"vendorChunk\": false,\r" +
90 | " \"buildOptimizer\": true,\r" +
91 | " \"fileReplacements\": [\r" +
92 | " {\r" +
93 | " \"replace\": \"src/environments/environment.ts\",\r" +
94 | " \"with\": \"src/environments/environment.prod-cordova.ts\"\r" +
95 | " }\r" +
96 | " ],\r" +
97 | " \"styles\": [\r" +
98 | " \"src/styles.scss\",\r" +
99 | " \"src/cordova-styles.scss\"\r" +
100 | " ]\r" +
101 | " }\r" +
102 | " }\r" +
103 | " },")).isNotEmpty().hasSize(3).containsExactlyInAnyOrder(
104 | new IGitLabApiWrapper.Line(83, " \"outputHashing\": \"all\","),
105 | new IGitLabApiWrapper.Line(82, " \"optimization\": true,"),
106 | new IGitLabApiWrapper.Line(81, " \"prod-cordova\": {")
107 | );
108 | }
109 |
110 | @Test
111 | public void testCorrectWindowsEOL() {
112 | Assertions.assertThat(PatchUtils.getPositionsFromPatch("@@ -78,6 +78,27 @@\n" +
113 | "\t\t\t\t\"src/styles.scss\",\r\n" +
114 | " \"src/cordova-styles.scss\"\r\n" +
115 | " ]\r\n" +
116 | " },\r\n" +
117 | "+ \"prod-cordova\": {\r\n" +
118 | "+ \"optimization\": true,\r\n" +
119 | "+ \"outputHashing\": \"all\",\r\n" +
120 | " \"sourceMap\": false,\r\n" +
121 | " \"extractCss\": true,\r\n" +
122 | " \"namedChunks\": false,\r\n" +
123 | " \"aot\": true,\r\n" +
124 | " \"extractLicenses\": true,\r\n" +
125 | " \"vendorChunk\": false,\r\n" +
126 | " \"buildOptimizer\": true,\r\n" +
127 | " \"fileReplacements\": [\r\n" +
128 | " {\r\n" +
129 | " \"replace\": \"src/environments/environment.ts\",\r\n" +
130 | " \"with\": \"src/environments/environment.prod-cordova.ts\"\r\n" +
131 | " }\r\n" +
132 | " ],\r\n" +
133 | " \"styles\": [\rn" +
134 | " \"src/styles.scss\",\r\n" +
135 | " \"src/cordova-styles.scss\"\r\n" +
136 | " ]\r\n" +
137 | " }\r\n" +
138 | " }\r\n" +
139 | " },")).isNotEmpty().hasSize(3).containsExactlyInAnyOrder(
140 | new IGitLabApiWrapper.Line(83, " \"outputHashing\": \"all\","),
141 | new IGitLabApiWrapper.Line(82, " \"optimization\": true,"),
142 | new IGitLabApiWrapper.Line(81, " \"prod-cordova\": {")
143 | );
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/src/test/java/com/talanlabs/sonar/plugins/gitlab/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.models.Issue;
20 | import org.mockito.Mockito;
21 | import org.sonar.api.batch.fs.InputComponent;
22 | import org.sonar.api.batch.fs.InputFile;
23 | import org.sonar.api.batch.rule.Severity;
24 |
25 | import java.io.BufferedWriter;
26 | import java.io.File;
27 | import java.io.IOException;
28 | import java.nio.charset.Charset;
29 | import java.nio.file.Files;
30 |
31 | public class Utils {
32 |
33 | private Utils() {
34 | super();
35 | }
36 |
37 | public static InputComponent newMockedInputComponent(String key) {
38 | InputComponent inputComponent = Mockito.mock(InputComponent.class);
39 | Mockito.when(inputComponent.key()).thenReturn(key);
40 | Mockito.when(inputComponent.isFile()).thenReturn(false);
41 | return inputComponent;
42 | }
43 |
44 | public static InputFile newMockedInputFile(File file) {
45 | InputFile inputFile = Mockito.mock(InputFile.class);
46 | Mockito.when(inputFile.key()).thenReturn(file.getPath());
47 | Mockito.when(inputFile.isFile()).thenReturn(true);
48 | Mockito.when(inputFile.uri()).thenReturn(file.toURI());
49 | return inputFile;
50 | }
51 |
52 | public static Issue newIssue(String componentKey, Severity severity, boolean isNew, String message) {
53 | return newIssue(componentKey, null, null, severity, isNew, message, "rule");
54 | }
55 |
56 | public static Issue newIssue(String componentKey, File file, Integer line, Severity severity, boolean isNew, String message) {
57 | return newIssue(componentKey, file, line, severity, isNew, message, "rule");
58 | }
59 |
60 | public static Issue newIssue(String componentKey, File file, Integer line, Severity severity, boolean isNew, String message, String rule) {
61 | return newIssue(null, componentKey, file, line, severity, isNew, message, rule);
62 | }
63 |
64 | public static Issue newIssue(String key, String componentKey, File file, Integer line, Severity severity, boolean isNew, String message, String rule) {
65 | return Issue.newBuilder().key(key).componentKey(componentKey).file(file).line(line).severity(severity).newIssue(isNew).message(message).ruleKey("repo:" + rule).build();
66 | }
67 |
68 | public static void createFile(File root, String path, String filename, String value) throws IOException {
69 | File dir = new File(root, path);
70 | if (!dir.exists()) {
71 | if (!dir.mkdirs()) {
72 | throw new IOException("Failed to create directories " + dir.toString());
73 | }
74 | }
75 | File file = new File(dir, filename);
76 | if (!file.createNewFile()) {
77 | throw new IOException("Failed to create file " + file.toString());
78 | }
79 | try (BufferedWriter bw = Files.newBufferedWriter(file.toPath(), Charset.defaultCharset())) {
80 | bw.write(value);
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/test/java/com/talanlabs/sonar/plugins/gitlab/freemarker/EmojiSeverityTemplateMethodModelExTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SonarQube :: GitLab Plugin
3 | * Copyright (C) 2016-2025 Talanlabs
4 | * gabriel.allaigre@gmail.com
5 | *
6 | * This program is free software; you can redistribute it and/or
7 | * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the Sonar Source-Available License for more details.
13 | *
14 | * You should have received a copy of the Sonar Source-Available License
15 | * along with this program; if not, see https://sonarsource.com/license/ssal/
16 | */
17 | package com.talanlabs.sonar.plugins.gitlab.freemarker;
18 |
19 | import com.talanlabs.sonar.plugins.gitlab.GitLabPlugin;
20 | import com.talanlabs.sonar.plugins.gitlab.MarkDownUtils;
21 | import freemarker.template.SimpleScalar;
22 | import freemarker.template.TemplateModelException;
23 | import org.assertj.core.api.Assertions;
24 | import org.junit.Before;
25 | import org.junit.Test;
26 | import org.sonar.api.CoreProperties;
27 | import org.sonar.api.batch.rule.Severity;
28 | import org.sonar.api.config.PropertyDefinition;
29 | import org.sonar.api.config.PropertyDefinitions;
30 | import org.sonar.api.config.internal.MapSettings;
31 | import org.sonar.api.utils.System2;
32 |
33 | import java.util.Collections;
34 | import java.util.List;
35 |
36 | public class EmojiSeverityTemplateMethodModelExTest {
37 |
38 | private EmojiSeverityTemplateMethodModelEx emojiSeverityTemplateMethodModelEx;
39 |
40 | @Before
41 | public void setUp() throws Exception {
42 | MapSettings settings = new MapSettings(new PropertyDefinitions(System2.INSTANCE, PropertyDefinition.builder(CoreProperties.SERVER_BASE_URL).name("Server base URL")
43 | .description("HTTP URL of this SonarQube server, such as http://yourhost.yourdomain/sonar. This value is used i.e. to create links in emails.")
44 | .category(CoreProperties.CATEGORY_GENERAL).defaultValue("http://localhost:9000").build()).addComponents(GitLabPlugin.definitions()));
45 |
46 | settings.setProperty(CoreProperties.SERVER_BASE_URL, "http://myserver");
47 |
48 | MarkDownUtils markDownUtils = new MarkDownUtils();
49 |
50 | emojiSeverityTemplateMethodModelEx = new EmojiSeverityTemplateMethodModelEx(markDownUtils);
51 | }
52 |
53 | private String emoji(List