• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jreleaser / jreleaser / #558

08 Dec 2025 02:56PM UTC coverage: 48.239% (+0.02%) from 48.215%
#558

push

github

aalmiray
feat(core): warn when a name template cannot be resolved

Closes #1960

Closes #1961

299 of 573 new or added lines in 133 files covered. (52.18%)

4 existing lines in 4 files now uncovered.

26047 of 53996 relevant lines covered (48.24%)

0.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/sdks/jreleaser-gitlab-java-sdk/src/main/java/org/jreleaser/sdk/gitlab/GitlabReleaser.java
1
/*
2
 * SPDX-License-Identifier: Apache-2.0
3
 *
4
 * Copyright 2020-2025 The JReleaser authors.
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     https://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
package org.jreleaser.sdk.gitlab;
19

20
import org.jreleaser.bundle.RB;
21
import org.jreleaser.model.UpdateSection;
22
import org.jreleaser.model.api.common.Apply;
23
import org.jreleaser.model.internal.JReleaserContext;
24
import org.jreleaser.model.internal.common.Artifact;
25
import org.jreleaser.model.internal.common.ExtraProperties;
26
import org.jreleaser.model.internal.distributions.Distribution;
27
import org.jreleaser.model.internal.upload.Uploader;
28
import org.jreleaser.model.internal.util.Artifacts;
29
import org.jreleaser.model.internal.util.VersionUtils;
30
import org.jreleaser.model.spi.release.Asset;
31
import org.jreleaser.model.spi.release.Release;
32
import org.jreleaser.model.spi.release.ReleaseException;
33
import org.jreleaser.model.spi.release.Repository;
34
import org.jreleaser.model.spi.release.User;
35
import org.jreleaser.mustache.TemplateContext;
36
import org.jreleaser.sdk.commons.RestAPIException;
37
import org.jreleaser.sdk.git.ChangelogProvider;
38
import org.jreleaser.sdk.git.GitSdk;
39
import org.jreleaser.sdk.git.release.AbstractReleaser;
40
import org.jreleaser.sdk.gitlab.api.GlFileUpload;
41
import org.jreleaser.sdk.gitlab.api.GlIssue;
42
import org.jreleaser.sdk.gitlab.api.GlLabel;
43
import org.jreleaser.sdk.gitlab.api.GlLink;
44
import org.jreleaser.sdk.gitlab.api.GlLinkRequest;
45
import org.jreleaser.sdk.gitlab.api.GlMilestone;
46
import org.jreleaser.sdk.gitlab.api.GlProject;
47
import org.jreleaser.sdk.gitlab.api.GlRelease;
48

49
import java.io.IOException;
50
import java.nio.file.Files;
51
import java.nio.file.Path;
52
import java.util.ArrayList;
53
import java.util.Collection;
54
import java.util.LinkedHashMap;
55
import java.util.List;
56
import java.util.Map;
57
import java.util.Optional;
58
import java.util.Set;
59
import java.util.TreeSet;
60
import java.util.regex.Pattern;
61

62
import static org.jreleaser.model.Constants.KEY_PLATFORM_REPLACED;
63
import static org.jreleaser.model.api.signing.Signing.KEY_SKIP_SIGNING;
64
import static org.jreleaser.mustache.Templates.resolveTemplate;
65
import static org.jreleaser.util.StringUtils.isNotBlank;
66
import static org.jreleaser.util.StringUtils.uncapitalize;
67

68
/**
69
 * @author Andres Almiray
70
 * @since 0.1.0
71
 */
72
@org.jreleaser.infra.nativeimage.annotations.NativeImage
73
public class GitlabReleaser extends AbstractReleaser<org.jreleaser.model.api.release.GitlabReleaser> {
74
    private static final long serialVersionUID = 1079387159817891884L;
75

76
    private final org.jreleaser.model.internal.release.GitlabReleaser gitlab;
77

78
    public GitlabReleaser(JReleaserContext context, Set<Asset> assets) {
79
        super(context, assets);
×
80
        gitlab = context.getModel().getRelease().getGitlab();
×
81
    }
×
82

83
    @Override
84
    public org.jreleaser.model.api.release.GitlabReleaser getReleaser() {
85
        return gitlab.asImmutable();
×
86
    }
87

88
    @Override
89
    protected void createRelease() throws ReleaseException {
90
        String pullBranch = gitlab.getBranch();
×
NEW
91
        String pushBranch = gitlab.getResolvedBranchPush(context);
×
92
        boolean mustCheckoutBranch = !pushBranch.equals(pullBranch);
×
NEW
93
        context.getLogger().info(RB.$("git.releaser.releasing"), gitlab.getResolvedRepoUrl(context), pushBranch);
×
NEW
94
        String tagName = gitlab.getEffectiveTagName(context);
×
95

96
        try {
97
            Gitlab api = new Gitlab(context.asImmutable(),
×
98
                gitlab.getApiEndpoint(),
×
99
                gitlab.getToken(),
×
100
                gitlab.getConnectTimeout(),
×
101
                gitlab.getReadTimeout());
×
102

103
            if (!context.isDryrun()) {
×
104
                List<String> branchNames = api.listBranches(gitlab.getOwner(), gitlab.getName(), gitlab.getProjectIdentifier());
×
105
                GitSdk.of(context).checkoutBranch(gitlab, pushBranch, mustCheckoutBranch, !branchNames.contains(pushBranch));
×
106
            }
107

108
            String changelog = context.getChangelog().getResolvedChangelog();
×
109

110
            context.getLogger().debug(RB.$("git.releaser.release.lookup"), tagName, gitlab.getCanonicalRepoName());
×
111
            GlRelease release = findReleaseByTag(api, tagName);
×
112
            boolean snapshot = context.getModel().getProject().isSnapshot();
×
113
            if (null != release) {
×
114
                context.getLogger().debug(RB.$("git.releaser.release.exists"), tagName);
×
115
                if (gitlab.isOverwrite() || snapshot) {
×
116
                    context.getLogger().debug(RB.$("git.releaser.release.delete"), tagName);
×
117
                    if (!context.isDryrun()) {
×
118
                        api.deleteRelease(gitlab.getOwner(), gitlab.getName(), gitlab.getProjectIdentifier(), tagName);
×
119
                    }
120
                    context.getLogger().debug(RB.$("git.releaser.release.create"), tagName);
×
121
                    createRelease(api, tagName, changelog, snapshot && gitlab.isMatch());
×
122
                } else if (gitlab.getUpdate().isEnabled()) {
×
123
                    context.getLogger().debug(RB.$("git.releaser.release.update"), tagName);
×
124
                    if (!context.isDryrun()) {
×
125
                        boolean update = false;
×
126
                        GlRelease updater = new GlRelease();
×
127
                        if (gitlab.getUpdate().getSections().contains(UpdateSection.TITLE)) {
×
128
                            update = true;
×
129
                            context.getLogger().info(RB.$("git.releaser.release.update.title"), gitlab.getEffectiveReleaseName());
×
130
                            updater.setName(gitlab.getEffectiveReleaseName());
×
131
                        }
132
                        if (gitlab.getUpdate().getSections().contains(UpdateSection.BODY)) {
×
133
                            update = true;
×
134
                            context.getLogger().info(RB.$("git.releaser.release.update.body"));
×
135
                            updater.setDescription(changelog);
×
136
                        }
137
                        if (update) {
×
138
                            api.updateRelease(gitlab.getOwner(), gitlab.getName(), gitlab.getProjectIdentifier(), updater);
×
139
                        }
140

141
                        if (gitlab.getUpdate().getSections().contains(UpdateSection.ASSETS)) {
×
142
                            updateAssets(api, release);
×
143
                        }
144
                        updateIssues(gitlab, api);
×
145
                    }
×
146
                } else {
147
                    if (context.isDryrun()) {
×
148
                        context.getLogger().debug(RB.$("git.releaser.release.create"), tagName);
×
149
                        createRelease(api, tagName, changelog, false);
×
150
                        return;
×
151
                    }
152

153
                    throw new IllegalStateException(RB.$("ERROR_git_releaser_cannot_release",
×
154
                        "GitLab", tagName));
155
                }
156
            } else {
157
                context.getLogger().debug(RB.$("git.releaser.release.not.found"), tagName);
×
158
                context.getLogger().debug(RB.$("git.releaser.release.create"), tagName);
×
159
                createRelease(api, tagName, changelog, snapshot && gitlab.isMatch());
×
160
            }
161
        } catch (RestAPIException | IOException | IllegalStateException e) {
×
162
            context.getLogger().trace(e);
×
163
            throw new ReleaseException(e);
×
164
        }
×
165
    }
×
166

167
    private GlRelease findReleaseByTag(Gitlab api, String tagName) {
168
        if (context.isDryrun()) return null;
×
169
        return api.findReleaseByTag(gitlab.getOwner(), gitlab.getName(), gitlab.getProjectIdentifier(), tagName);
×
170
    }
171

172
    @Override
173
    public Repository maybeCreateRepository(String owner, String repo, String password, org.jreleaser.model.api.common.ExtraProperties extraProperties) throws IOException {
174
        context.getLogger().debug(RB.$("git.repository.lookup"), owner, repo);
×
175

176
        Gitlab api = new Gitlab(context.asImmutable(),
×
177
            gitlab.getApiEndpoint(),
×
178
            password,
179
            gitlab.getConnectTimeout(),
×
180
            gitlab.getReadTimeout());
×
181
        GlProject project = null;
×
182

183
        try {
184
            String projectIdentifier = extraProperties.getExtraProperty("projectIdentifier");
×
185
            if (isNotBlank(projectIdentifier)) {
×
186
                project = api.findProject(repo, projectIdentifier);
×
187
            }
188
        } catch (RestAPIException e) {
×
189
            if (!e.isNotFound()) {
×
190
                throw e;
×
191
            }
192
        }
×
193

194
        if (null == project) {
×
195
            project = api.createProject(owner, repo);
×
196
        }
197

198
        return new Repository(
×
199
            Repository.Kind.GITLAB,
200
            owner,
201
            repo,
202
            project.getWebUrl(),
×
203
            project.getHttpUrlToRepo());
×
204
    }
205

206
    @Override
207
    public Optional<User> findUser(String email, String name) {
208
        try {
209
            return new Gitlab(context.asImmutable(),
×
210
                gitlab.getApiEndpoint(),
×
211
                gitlab.getToken(),
×
212
                gitlab.getConnectTimeout(),
×
213
                gitlab.getReadTimeout())
×
214
                .findUser(email, name);
×
215
        } catch (RestAPIException e) {
×
216
            context.getLogger().trace(e);
×
217
            context.getLogger().debug(RB.$("git.releaser.user.not.found"), email);
×
218
        }
219

220
        return Optional.empty();
×
221
    }
222

223
    @Override
224
    public List<Release> listReleases(String owner, String repo) throws IOException {
225
        Gitlab api = new Gitlab(context.asImmutable(),
×
226
            gitlab.getApiEndpoint(),
×
227
            gitlab.getToken(),
×
228
            gitlab.getConnectTimeout(),
×
229
            gitlab.getReadTimeout());
×
230

231
        List<Release> releases = api.listReleases(owner, repo, gitlab.getProjectIdentifier());
×
232

233
        VersionUtils.clearUnparseableTags();
×
234
        Pattern versionPattern = VersionUtils.resolveVersionPattern(context);
×
235
        for (Release release : releases) {
×
236
            release.setVersion(VersionUtils.version(context, release.getTagName(), versionPattern));
×
237
        }
×
238

239
        releases.sort((r1, r2) -> r2.getVersion().compareTo(r1.getVersion()));
×
240

241
        return releases;
×
242
    }
243

244
    private void createRelease(Gitlab api, String tagName, String changelog, boolean deleteTags) throws IOException {
245
        Collection<GlLinkRequest> links = collectUploadLinks(gitlab);
×
246

247
        if (context.isDryrun()) {
×
248
            if (!assets.isEmpty()) {
×
249
                for (Asset asset : assets) {
×
250
                    if (0 == Files.size(asset.getPath()) || !Files.exists(asset.getPath())) {
×
251
                        // do not upload empty or non existent files
252
                        continue;
×
253
                    }
254

255
                    context.getLogger().info(" " + RB.$("git.upload.asset"), asset.getFilename());
×
256
                }
×
257
            }
258
            if (!links.isEmpty()) {
×
259
                for (GlLinkRequest link : links) {
×
260
                    context.getLogger().info(" " + RB.$("git.upload.asset"), link.getName());
×
261
                }
×
262
            }
263
            updateIssues(gitlab, api);
×
264

265
            return;
×
266
        }
267

268
        Integer projectIdentifier = api.findProject(gitlab.getName(), gitlab.getProjectIdentifier()).getId();
×
269

270
        if (deleteTags) {
×
271
            deleteTags(api, gitlab.getOwner(), gitlab.getName(), projectIdentifier, tagName);
×
272
        }
273

274
        // local tag
275
        if (deleteTags || !gitlab.isSkipTag()) {
×
276
            context.getLogger().debug(RB.$("git.releaser.repository.tag"), tagName, context.getModel().getCommit().getShortHash());
×
277
            GitSdk.of(context).tag(tagName, true, context);
×
278
        }
279

280
        GlRelease release = new GlRelease();
×
281
        release.setName(gitlab.getEffectiveReleaseName());
×
282
        release.setTagName(tagName);
×
NEW
283
        release.setRef(gitlab.getResolvedBranchPush(context));
×
284
        release.setDescription(changelog);
×
285

286
        Optional<GlMilestone> milestone = api.findMilestoneByName(
×
287
            gitlab.getOwner(),
×
288
            gitlab.getName(),
×
289
            projectIdentifier,
290
            gitlab.getMilestone().getEffectiveName());
×
291
        milestone.ifPresent(glMilestone -> {
×
292
            List<String> milestones = new ArrayList<>();
×
293
            milestones.add(glMilestone.getTitle());
×
294
            release.setMilestones(milestones);
×
295
        });
×
296

297
        // remote tag/release
298
        api.createRelease(gitlab.getOwner(), gitlab.getName(), projectIdentifier, release);
×
299

300
        if (!assets.isEmpty()) {
×
301
            Collection<GlFileUpload> uploads = api.uploadAssets(gitlab.getOwner(), gitlab.getName(), projectIdentifier, assets);
×
302
            api.linkReleaseAssets(gitlab.getOwner(), gitlab.getName(), release, projectIdentifier, uploads);
×
303
        }
304
        if (!links.isEmpty()) {
×
305
            api.linkAssets(gitlab.getOwner(), gitlab.getName(), release, projectIdentifier, links);
×
306
        }
307

308
        if (gitlab.getMilestone().isClose() && !context.getModel().getProject().isSnapshot()) {
×
309
            milestone.ifPresent(glMilestone -> api.closeMilestone(gitlab.getOwner(),
×
310
                gitlab.getName(),
×
311
                projectIdentifier,
312
                glMilestone));
313
        }
314
        updateIssues(gitlab, api);
×
315
    }
×
316

317
    private void updateAssets(Gitlab api, GlRelease release) throws IOException {
318
        Set<Asset> assetsToBeUpdated = new TreeSet<>();
×
319
        Set<Asset> assetsToBeUploaded = new TreeSet<>();
×
320

321
        Integer projectIdentifier = api.findProject(gitlab.getName(), gitlab.getProjectIdentifier()).getId();
×
NEW
322
        String tagName = gitlab.getEffectiveTagName(context);
×
323
        Map<String, GlLink> existingAssets = api.listLinks(projectIdentifier, tagName);
×
324

325
        Map<String, Asset> assetsToBePublished = new LinkedHashMap<>();
×
326
        assets.forEach(asset -> assetsToBePublished.put(asset.getFilename(), asset));
×
327

328
        assetsToBePublished.keySet().forEach(name -> {
×
329
            if (existingAssets.containsKey(name)) {
×
330
                assetsToBeUpdated.add(assetsToBePublished.get(name));
×
331
            } else {
332
                assetsToBeUploaded.add(assetsToBePublished.get(name));
×
333
            }
334
        });
×
335

336
        updateAssets(api, release, assetsToBeUpdated, projectIdentifier, tagName, existingAssets);
×
337
        uploadAssets(api, release, assetsToBeUploaded, projectIdentifier);
×
338
        if (!gitlab.getUploadLinks().isEmpty()) {
×
339
            Collection<GlLinkRequest> links = collectUploadLinks(gitlab);
×
340
            api.linkAssets(gitlab.getOwner(), gitlab.getName(), release, projectIdentifier, links);
×
341
        }
342
    }
×
343

344
    private void updateAssets(Gitlab api, GlRelease release, Set<Asset> assetsToBeUpdated, Integer projectIdentifier, String tagName, Map<String, GlLink> existingLinks) throws IOException {
345
        if (!assetsToBeUpdated.isEmpty()) {
×
346
            for (Asset asset : assetsToBeUpdated) {
×
347
                GlLink existingLink = existingLinks.get(asset.getFilename());
×
348
                api.deleteLinkedAsset(gitlab.getToken(), projectIdentifier, tagName, existingLink);
×
349
            }
×
350

351
            Collection<GlFileUpload> uploads = api.uploadAssets(gitlab.getOwner(), gitlab.getName(), projectIdentifier, assetsToBeUpdated);
×
352
            api.linkReleaseAssets(gitlab.getOwner(), gitlab.getName(), release, projectIdentifier, uploads);
×
353
        }
354
    }
×
355

356
    private void uploadAssets(Gitlab api, GlRelease release, Set<Asset> assetsToBeUploaded, Integer projectIdentifier) throws IOException {
357
        if (!assetsToBeUploaded.isEmpty()) {
×
358
            Collection<GlFileUpload> uploads = api.uploadAssets(gitlab.getOwner(), gitlab.getName(), projectIdentifier, assetsToBeUploaded);
×
359
            api.linkReleaseAssets(gitlab.getOwner(), gitlab.getName(), release, projectIdentifier, uploads);
×
360
        }
361
    }
×
362

363
    private void updateIssues(org.jreleaser.model.internal.release.GitlabReleaser gitlab, Gitlab api) throws IOException {
364
        if (!gitlab.getIssues().isEnabled()) return;
×
365

366
        List<String> issueNumbers = ChangelogProvider.getIssues(context);
×
367

368
        if (!issueNumbers.isEmpty()) {
×
369
            context.getLogger().info(RB.$("git.issue.release.mark", issueNumbers.size()));
×
370
        }
371

372
        if (context.isDryrun()) {
×
373
            for (String issueNumber : issueNumbers) {
×
374
                context.getLogger().debug(RB.$("git.issue.release", issueNumber));
×
375
            }
×
376
            return;
×
377
        }
378

379
        Integer projectIdentifier = api.findProject(gitlab.getName(), gitlab.getProjectIdentifier()).getId();
×
NEW
380
        String tagName = gitlab.getEffectiveTagName(context);
×
381
        String labelName = gitlab.getIssues().getLabel().getName();
×
382
        String labelColor = gitlab.getIssues().getLabel().getColor();
×
NEW
383
        TemplateContext props = gitlab.props(context);
×
NEW
384
        gitlab.fillProps(props, context);
×
NEW
385
        String comment = resolveTemplate(context.getLogger(), gitlab.getIssues().getComment(), props);
×
386

387
        if (!labelColor.startsWith("#")) {
×
388
            try {
389
                Integer.parseInt(labelColor, 16);
×
390
                labelColor = "#" + labelColor;
×
391
            } catch (NumberFormatException ok) {
×
392
                // ignored
393
            }
×
394
        }
395

396
        GlLabel glLabel = null;
×
397

398
        try {
399
            glLabel = api.getOrCreateLabel(
×
400
                projectIdentifier,
401
                labelName,
402
                labelColor,
403
                gitlab.getIssues().getLabel().getDescription());
×
404
        } catch (IOException e) {
×
405
            throw new IllegalStateException(RB.$("ERROR_git_releaser_fetch_label", tagName, labelName), e);
×
406
        }
×
407

408
        Optional<GlMilestone> milestone = Optional.empty();
×
409
        Apply applyMilestone = gitlab.getIssues().getApplyMilestone();
×
410
        if (gitlab.getMilestone().isClose() && !context.getModel().getProject().isSnapshot()) {
×
411
            milestone = api.findMilestoneByName(
×
412
                gitlab.getOwner(),
×
413
                gitlab.getName(),
×
414
                projectIdentifier,
415
                gitlab.getMilestone().getEffectiveName());
×
416

417
            if (!milestone.isPresent()) {
×
418
                milestone = api.findClosedMilestoneByName(
×
419
                    gitlab.getOwner(),
×
420
                    gitlab.getName(),
×
421
                    projectIdentifier,
422
                    gitlab.getMilestone().getEffectiveName());
×
423
            }
424
        }
425

426
        List<GlIssue> issues = api.listIssues(projectIdentifier);
×
427

428
        for (String issueNumber : issueNumbers) {
×
429
            Integer in = Integer.parseInt(issueNumber);
×
430
            Optional<GlIssue> op = issues.stream().filter(i -> i.getIid().equals(in)).findFirst();
×
431
            if (!op.isPresent()) continue;
×
432

433
            GlIssue glIssue = op.get();
×
434
            if ("closed".equals(glIssue.getState()) && glIssue.getLabels().stream().noneMatch(l -> l.equals(labelName))) {
×
435
                context.getLogger().debug(RB.$("git.issue.release", issueNumber));
×
436

437
                try {
438
                    api.addLabelToIssue(projectIdentifier, glIssue, glLabel);
×
439
                    api.commentOnIssue(projectIdentifier, glIssue, comment);
×
440

441
                    milestone.ifPresent(glMilestone -> applyMilestone(api, projectIdentifier, issueNumber, glIssue, applyMilestone, glMilestone));
×
442
                } catch (RestAPIException e) {
×
443
                    if (e.isForbidden()) {
×
444
                        context.getLogger().warn(e.getMessage());
×
445
                    } else {
446
                        throw e;
×
447
                    }
448
                }
×
449
            }
450
        }
×
451
    }
×
452

453
    private void applyMilestone(Gitlab api, Integer projectIdentifier,
454
                                String issueNumber, GlIssue glIssue, Apply applyMilestone, GlMilestone targetMilestone) {
455
        GlMilestone issueMilestone = glIssue.getMilestone();
×
456
        String targetMilestoneTitle = targetMilestone.getTitle();
×
457

458
        if (null == issueMilestone) {
×
459
            context.getLogger().debug(RB.$("git.issue.milestone.apply", targetMilestoneTitle, issueNumber));
×
460
            api.setMilestoneOnIssue(projectIdentifier, glIssue, targetMilestone);
×
461
        } else {
462
            String milestoneTitle = issueMilestone.getTitle();
×
463

464
            if (applyMilestone == Apply.ALWAYS) {
×
465
                context.getLogger().debug(uncapitalize(RB.$("git.issue.milestone.warn", issueNumber, milestoneTitle)));
×
466
            } else if (applyMilestone == Apply.WARN) {
×
467
                if (!milestoneTitle.equals(targetMilestoneTitle)) {
×
468
                    context.getLogger().warn(RB.$("git.issue.milestone.warn", issueNumber, milestoneTitle));
×
469
                }
470
            } else if (applyMilestone == Apply.FORCE) {
×
471
                if (!milestoneTitle.equals(targetMilestoneTitle)) {
×
472
                    context.getLogger().warn(RB.$("git.issue.milestone.force", targetMilestoneTitle, issueNumber, milestoneTitle));
×
473
                    api.setMilestoneOnIssue(projectIdentifier, glIssue, targetMilestone);
×
474
                } else {
475
                    context.getLogger().debug(uncapitalize(RB.$("git.issue.milestone.warn", issueNumber, milestoneTitle)));
×
476
                }
477
            }
478
        }
479
    }
×
480

481
    private Collection<GlLinkRequest> collectUploadLinks(org.jreleaser.model.internal.release.GitlabReleaser gitlab) {
482
        List<GlLinkRequest> links = new ArrayList<>();
×
483

484
        for (Map.Entry<String, String> e : gitlab.getUploadLinks().entrySet()) {
×
485
            Optional<? extends Uploader> uploader = context.getModel().getUpload().getActiveUploader(e.getKey(), e.getValue());
×
486
            if (uploader.isPresent()) {
×
487
                collectUploadLinks(uploader.get(), links);
×
488
            }
489
        }
×
490

491
        return links;
×
492
    }
493

494
    private void collectUploadLinks(Uploader<?> uploader, List<GlLinkRequest> links) {
495
        List<String> keys = uploader.resolveSkipKeys();
×
496
        keys.add(org.jreleaser.model.api.release.GitlabReleaser.SKIP_GITLAB_LINKS);
×
497

498
        List<Artifact> artifacts = new ArrayList<>();
×
499

500
        if (uploader.isFiles()) {
×
501
            for (Artifact artifact : Artifacts.resolveFiles(context)) {
×
502
                if (!artifact.isActiveAndSelected()) continue;
×
503
                Path path = artifact.getEffectivePath(context);
×
504
                if (isSkip(artifact, keys)) continue;
×
505
                if (Files.exists(path) && 0 != path.toFile().length()) {
×
506
                    artifacts.add(artifact);
×
507
                }
508
            }
×
509
        }
510

511
        if (uploader.isArtifacts()) {
×
512
            for (Distribution distribution : context.getModel().getActiveDistributions()) {
×
513
                if (isSkip(distribution, keys)) continue;
×
514
                for (Artifact artifact : distribution.getArtifacts()) {
×
515
                    if (!artifact.isActiveAndSelected()) continue;
×
516
                    Path path = artifact.getEffectivePath(context, distribution);
×
517
                    if (isSkip(artifact, keys)) continue;
×
518
                    if (Files.exists(path) && 0 != path.toFile().length()) {
×
519
                        String platform = artifact.getPlatform();
×
520
                        String platformReplaced = distribution.getPlatform().applyReplacements(platform);
×
521
                        if (isNotBlank(platformReplaced)) {
×
522
                            artifact.getExtraProperties().put(KEY_PLATFORM_REPLACED, platformReplaced);
×
523
                        }
524
                        artifacts.add(artifact);
×
525
                    }
526
                }
×
527
            }
×
528
        }
529

530
        if (uploader.isSignatures() && context.getModel().getSigning().isEnabled()) {
×
531
            String extension = context.getModel().getSigning().isArmored() ? ".asc" : ".sig";
×
532

533
            List<Artifact> signatures = new ArrayList<>();
×
534
            for (Artifact artifact : artifacts) {
×
535
                if (artifact.extraPropertyIsTrue(KEY_SKIP_SIGNING)) continue;
×
536
                Path signaturePath = context.getSignaturesDirectory()
×
537
                    .resolve(artifact.getEffectivePath(context).getFileName() + extension);
×
538
                if (Files.exists(signaturePath) && 0 != signaturePath.toFile().length()) {
×
539
                    signatures.add(Artifact.of(signaturePath));
×
540
                }
541
            }
×
542

543
            artifacts.addAll(signatures);
×
544
        }
545

546
        for (Artifact artifact : artifacts) {
×
547
            links.add(toLinkRequest(artifact.getEffectivePath(), uploader.getResolvedDownloadUrl(context, artifact)));
×
548
        }
×
549
    }
×
550

551
    private boolean isSkip(ExtraProperties props, List<String> keys) {
552
        for (String key : keys) {
×
553
            if (props.extraPropertyIsTrue(key)) {
×
554
                return true;
×
555
            }
556
        }
×
557
        return false;
×
558
    }
559

560
    private void deleteTags(Gitlab api, String owner, String repo, Integer projectIdentifier, String tagName) {
561
        // delete remote tag
562
        try {
563
            api.deleteTag(owner, repo, projectIdentifier, tagName);
×
564
        } catch (RestAPIException ignored) {
×
565
            //noop
566
        }
×
567
    }
×
568

569
    private static GlLinkRequest toLinkRequest(Path path, String url) {
570
        GlLinkRequest link = new GlLinkRequest();
×
571
        link.setName(path.getFileName().toString());
×
572
        link.setUrl(url);
×
573
        link.setFilepath("/" + link.getName());
×
574
        return link;
×
575
    }
576
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc