• 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

72.82
/core/jreleaser-model-impl/src/main/java/org/jreleaser/model/internal/release/BaseReleaser.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.model.internal.release;
19

20
import com.fasterxml.jackson.annotation.JsonIgnore;
21
import org.jreleaser.model.Active;
22
import org.jreleaser.model.Constants;
23
import org.jreleaser.model.UpdateSection;
24
import org.jreleaser.model.api.common.Apply;
25
import org.jreleaser.model.internal.JReleaserContext;
26
import org.jreleaser.model.internal.common.AbstractModelObject;
27
import org.jreleaser.model.internal.common.CommitAuthor;
28
import org.jreleaser.model.internal.common.Domain;
29
import org.jreleaser.model.internal.common.EnabledAware;
30
import org.jreleaser.model.internal.project.Project;
31
import org.jreleaser.mustache.MustacheUtils;
32
import org.jreleaser.mustache.TemplateContext;
33
import org.jreleaser.util.Env;
34
import org.jreleaser.util.PlatformUtils;
35

36
import java.util.LinkedHashMap;
37
import java.util.LinkedHashSet;
38
import java.util.Map;
39
import java.util.Set;
40

41
import static java.util.Collections.unmodifiableMap;
42
import static java.util.Collections.unmodifiableSet;
43
import static org.jreleaser.mustache.MustacheUtils.applyTemplates;
44
import static org.jreleaser.mustache.Templates.resolveTemplate;
45
import static org.jreleaser.util.StringUtils.getCapitalizedName;
46
import static org.jreleaser.util.StringUtils.isBlank;
47
import static org.jreleaser.util.StringUtils.isNotBlank;
48

49
/**
50
 * @author Andres Almiray
51
 * @since 0.1.0
52
 */
53
public abstract class BaseReleaser<A extends org.jreleaser.model.api.release.Releaser, S extends BaseReleaser<A, S>> extends AbstractModelObject<S> implements Releaser<A> {
54
    private static final long serialVersionUID = 4910061043685377223L;
55

56
    @JsonIgnore
57
    private final String serviceName;
58
    private final Changelog changelog = new Changelog();
1✔
59
    private final Milestone milestone = new Milestone();
1✔
60
    private final Issues issues = new Issues();
1✔
61
    private final CommitAuthor commitAuthor = new CommitAuthor();
1✔
62
    private final Update update = new Update();
1✔
63
    private final Prerelease prerelease = new Prerelease();
1✔
64
    @JsonIgnore
65
    private final boolean releaseSupported;
66
    @JsonIgnore
1✔
67
    private boolean match = true;
68
    private Boolean enabled;
69
    private String host;
70
    private String owner;
71
    private String name;
72
    private String repoUrl;
73
    private String repoCloneUrl;
74
    private String commitUrl;
75
    private String srcUrl;
76
    private String downloadUrl;
77
    private String releaseNotesUrl;
78
    private String latestReleaseUrl;
79
    private String issueTrackerUrl;
80
    private String username;
81
    private String token;
82
    private String tagName;
83
    private String previousTagName;
84
    private String releaseName;
85
    private String branch;
86
    private String branchPush;
87
    protected Boolean sign;
88
    protected Boolean skipTag;
89
    protected Boolean skipRelease;
90
    protected Boolean overwrite;
91
    private String apiEndpoint;
92
    private int connectTimeout;
93
    private int readTimeout;
94
    protected Boolean artifacts;
95
    protected Boolean files;
96
    protected Boolean checksums;
97
    protected Boolean signatures;
98
    protected Boolean catalogs;
99
    private Active uploadAssets;
100
    protected Boolean uploadAssetsEnabled;
101
    @JsonIgnore
102
    private String cachedBranchPush;
103
    @JsonIgnore
104
    private String cachedTagName;
105
    @JsonIgnore
106
    private String cachedPreviousTagName;
107
    @JsonIgnore
108
    private String cachedReleaseName;
109

110
    protected BaseReleaser(String serviceName, boolean releaseSupported) {
1✔
111
        this.serviceName = serviceName;
1✔
112
        this.releaseSupported = releaseSupported;
1✔
113
    }
1✔
114

115
    @Override
116
    public boolean isReleaseSupported() {
117
        return releaseSupported;
1✔
118
    }
119

120
    @Override
121
    public String getServiceName() {
122
        return serviceName;
1✔
123
    }
124

125
    @Override
126
    public void merge(S source) {
127
        this.match = source.isMatch();
×
128
        this.enabled = merge(this.enabled, source.isEnabled());
×
129
        this.host = merge(this.host, source.getHost());
×
130
        this.owner = merge(this.owner, source.getOwner());
×
131
        this.name = merge(this.name, source.getName());
×
132
        this.repoUrl = merge(this.repoUrl, source.getRepoUrl());
×
133
        this.repoCloneUrl = merge(this.repoCloneUrl, source.getRepoCloneUrl());
×
134
        this.commitUrl = merge(this.commitUrl, source.getCommitUrl());
×
135
        this.srcUrl = merge(this.srcUrl, source.getSrcUrl());
×
136
        this.downloadUrl = merge(this.downloadUrl, source.getDownloadUrl());
×
137
        this.releaseNotesUrl = merge(this.releaseNotesUrl, source.getReleaseNotesUrl());
×
138
        this.latestReleaseUrl = merge(this.latestReleaseUrl, source.getLatestReleaseUrl());
×
139
        this.issueTrackerUrl = merge(this.issueTrackerUrl, source.getIssueTrackerUrl());
×
140
        this.username = merge(this.username, source.getUsername());
×
141
        this.token = merge(this.token, source.getToken());
×
142
        this.tagName = merge(this.tagName, source.getTagName());
×
143
        this.previousTagName = merge(this.previousTagName, source.getPreviousTagName());
×
144
        this.releaseName = merge(this.releaseName, source.getReleaseName());
×
145
        this.branch = merge(this.branch, source.getBranch());
×
146
        this.branchPush = merge(this.branchPush, source.getBranchPush());
×
147
        this.sign = merge(this.sign, source.sign);
×
148
        this.skipTag = merge(this.skipTag, source.skipTag);
×
149
        this.skipRelease = merge(this.skipRelease, source.skipRelease);
×
150
        this.overwrite = merge(this.overwrite, source.overwrite);
×
151
        this.apiEndpoint = merge(this.apiEndpoint, source.getApiEndpoint());
×
152
        this.connectTimeout = merge(this.getConnectTimeout(), source.getConnectTimeout());
×
153
        this.readTimeout = merge(this.getReadTimeout(), source.getReadTimeout());
×
154
        this.artifacts = merge(this.artifacts, source.artifacts);
×
155
        this.files = merge(this.files, source.files);
×
156
        this.checksums = merge(this.checksums, source.checksums);
×
157
        this.signatures = merge(this.signatures, source.signatures);
×
158
        this.catalogs = merge(this.catalogs, source.catalogs);
×
159
        this.uploadAssets = merge(this.uploadAssets, source.getUploadAssets());
×
160
        this.uploadAssetsEnabled = merge(this.uploadAssetsEnabled, source.uploadAssetsEnabled);
×
161
        setCommitAuthor(source.getCommitAuthor());
×
162
        setUpdate(source.getUpdate());
×
163
        setPrerelease(source.getPrerelease());
×
164
        setChangelog(source.getChangelog());
×
165
        setMilestone(source.getMilestone());
×
166
        setIssues(source.getIssues());
×
167
    }
×
168

169
    protected Boolean getUploadAssetsEnabled() {
170
        return uploadAssetsEnabled;
×
171
    }
172

173
    public abstract String getReverseRepoHost();
174

175
    @Override
176
    public boolean isPrerelease() {
177
        return getPrerelease().isEnabled();
×
178
    }
179

180
    public String getCanonicalRepoName() {
181
        if (isNotBlank(owner)) {
1✔
182
            return owner + "/" + name;
1✔
183
        }
184
        return name;
×
185
    }
186

187
    public String getResolvedBranchPush(JReleaserContext context) {
188
        if (isBlank(cachedBranchPush)) {
1✔
189
            cachedBranchPush = resolveTemplate(context.getLogger(), branchPush, props(context));
1✔
190
        }
191
        if (isNotBlank(cachedBranchPush) && cachedBranchPush.contains("{{")) {
1✔
NEW
192
            cachedBranchPush = resolveTemplate(context.getLogger(), cachedBranchPush, props(context));
×
193
        }
194

195
        return cachedBranchPush;
1✔
196
    }
197

198
    public String getResolvedPreviousTagName(JReleaserContext context) {
199
        if (isBlank(cachedPreviousTagName) && isNotBlank(previousTagName)) {
1✔
NEW
200
            cachedPreviousTagName = resolveTemplate(context.getLogger(), previousTagName, props(context));
×
201
        }
202
        if (isNotBlank(cachedPreviousTagName) && cachedPreviousTagName.contains("{{")) {
1✔
NEW
203
            cachedPreviousTagName = resolveTemplate(context.getLogger(), cachedPreviousTagName, props(context));
×
204
        }
205

206
        return cachedPreviousTagName;
1✔
207
    }
208

209
    public String getResolvedTagName(JReleaserContext context) {
210
        if (isBlank(cachedTagName)) {
1✔
211
            cachedTagName = resolveTemplate(context.getLogger(), tagName, props(context));
1✔
212
        }
213
        if (isNotBlank(cachedTagName) && cachedTagName.contains("{{")) {
1✔
NEW
214
            cachedTagName = resolveTemplate(context.getLogger(), cachedTagName, props(context));
×
215
        }
216

217
        return cachedTagName;
1✔
218
    }
219

220
    public String getEffectiveTagName(JReleaserContext context) {
221
        if (context.getModel().getProject().isSnapshot()) {
1✔
NEW
222
            return context.getModel().getProject().getSnapshot().getResolvedLabel(context);
×
223
        }
224
        return cachedTagName;
1✔
225
    }
226

227
    public String getResolvedReleaseName(JReleaserContext context) {
228
        if (isBlank(cachedReleaseName)) {
1✔
229
            cachedReleaseName = resolveTemplate(context.getLogger(), releaseName, props(context));
1✔
230
        }
231
        if (isNotBlank(cachedReleaseName) && cachedReleaseName.contains("{{")) {
1✔
NEW
232
            cachedReleaseName = resolveTemplate(context.getLogger(), cachedReleaseName, props(context));
×
233
        }
234

235
        return cachedReleaseName;
1✔
236
    }
237

238
    public String getEffectiveReleaseName() {
239
        return cachedReleaseName;
1✔
240
    }
241

242
    public String getResolvedRepoUrl(JReleaserContext context) {
243
        if (!releaseSupported) return "";
1✔
244
        return resolveTemplate(context.getLogger(), repoUrl, props(context));
1✔
245
    }
246

247
    public String getResolvedRepoCloneUrl(JReleaserContext context) {
248
        if (!releaseSupported) return "";
1✔
249
        return resolveTemplate(context.getLogger(), repoCloneUrl, props(context));
1✔
250
    }
251

252
    public String getResolvedRepoUrl(JReleaserContext context, String repoOwner, String repoName) {
253
        if (!releaseSupported) return "";
1✔
254
        TemplateContext props = props(context);
1✔
255
        props.set(Constants.KEY_REPO_OWNER, repoOwner);
1✔
256
        props.set(Constants.KEY_REPO_NAME, repoName);
1✔
257
        return resolveTemplate(context.getLogger(), repoUrl, props);
1✔
258
    }
259

260
    public String getResolvedRepoCloneUrl(JReleaserContext context, String repoOwner, String repoName) {
261
        if (!releaseSupported) return "";
1✔
262
        TemplateContext props = props(context);
1✔
263
        props.set(Constants.KEY_REPO_OWNER, repoOwner);
1✔
264
        props.set(Constants.KEY_REPO_NAME, repoName);
1✔
265
        return resolveTemplate(context.getLogger(), repoCloneUrl, props);
1✔
266
    }
267

268
    public String getResolvedCommitUrl(JReleaserContext context) {
269
        if (!releaseSupported) return "";
1✔
270
        return resolveTemplate(context.getLogger(), commitUrl, props(context));
1✔
271
    }
272

273
    public String getResolvedSrcUrl(JReleaserContext context) {
274
        if (!releaseSupported) return "";
1✔
275
        return resolveTemplate(context.getLogger(), srcUrl, props(context));
1✔
276
    }
277

278
    public String getResolvedDownloadUrl(JReleaserContext context) {
279
        if (!releaseSupported) return "";
×
NEW
280
        return resolveTemplate(context.getLogger(), downloadUrl, props(context));
×
281
    }
282

283
    public String getResolvedReleaseNotesUrl(JReleaserContext context) {
284
        if (!releaseSupported) return "";
1✔
285
        return resolveTemplate(context.getLogger(), releaseNotesUrl, props(context));
1✔
286
    }
287

288
    public String getResolvedLatestReleaseUrl(JReleaserContext context) {
289
        if (!releaseSupported) return "";
1✔
290
        return resolveTemplate(context.getLogger(), latestReleaseUrl, props(context));
1✔
291
    }
292

293
    public String getResolvedIssueTrackerUrl(JReleaserContext context, boolean appendSlash) {
294
        if (!releaseSupported) return "";
1✔
295
        String issueTracker = resolveTemplate(context.getLogger(), issueTrackerUrl, props(context));
1✔
296
        if (appendSlash && isNotBlank(issueTracker) && !issueTracker.endsWith("/")) {
1✔
297
            issueTracker += "/";
1✔
298
        }
299
        return issueTracker;
1✔
300
    }
301

302
    public boolean resolveUploadAssetsEnabled(Project project) {
303
        if (null == uploadAssets) {
1✔
304
            uploadAssets = Active.ALWAYS;
1✔
305
        }
306
        uploadAssetsEnabled = uploadAssets.check(project, this);
1✔
307
        return uploadAssetsEnabled;
1✔
308
    }
309

310
    public boolean isMatch() {
311
        return match;
×
312
    }
313

314
    public void setMatch(boolean match) {
315
        this.match = match;
×
316
    }
×
317

318
    @Override
319
    public boolean isEnabled() {
320
        return null != enabled && enabled;
1✔
321
    }
322

323
    @Override
324
    public void setEnabled(Boolean enabled) {
325
        this.enabled = enabled;
1✔
326
    }
1✔
327

328
    @Override
329
    public boolean isEnabledSet() {
330
        return null != enabled;
1✔
331
    }
332

333
    public String getHost() {
334
        return host;
1✔
335
    }
336

337
    public void setHost(String host) {
338
        this.host = host;
1✔
339
    }
1✔
340

341
    @Override
342
    public String getOwner() {
343
        return owner;
1✔
344
    }
345

346
    @Override
347
    public void setOwner(String owner) {
348
        this.owner = owner;
1✔
349
    }
1✔
350

351
    public String getName() {
352
        return name;
1✔
353
    }
354

355
    public void setName(String name) {
356
        this.name = name;
1✔
357
    }
1✔
358

359
    public String getRepoUrl() {
360
        return repoUrl;
1✔
361
    }
362

363
    public void setRepoUrl(String repoUrl) {
364
        this.repoUrl = repoUrl;
1✔
365
    }
1✔
366

367
    public String getRepoCloneUrl() {
368
        return repoCloneUrl;
×
369
    }
370

371
    public void setRepoCloneUrl(String repoCloneUrl) {
372
        this.repoCloneUrl = repoCloneUrl;
1✔
373
    }
1✔
374

375
    public String getCommitUrl() {
376
        return commitUrl;
×
377
    }
378

379
    public void setCommitUrl(String commitUrl) {
380
        this.commitUrl = commitUrl;
1✔
381
    }
1✔
382

383
    public String getSrcUrl() {
384
        return srcUrl;
×
385
    }
386

387
    public void setSrcUrl(String srcUrl) {
388
        this.srcUrl = srcUrl;
1✔
389
    }
1✔
390

391
    public String getDownloadUrl() {
392
        return downloadUrl;
1✔
393
    }
394

395
    public void setDownloadUrl(String downloadUrl) {
396
        this.downloadUrl = downloadUrl;
1✔
397
    }
1✔
398

399
    public String getReleaseNotesUrl() {
400
        return releaseNotesUrl;
1✔
401
    }
402

403
    public void setReleaseNotesUrl(String releaseNotesUrl) {
404
        this.releaseNotesUrl = releaseNotesUrl;
1✔
405
    }
1✔
406

407
    public String getLatestReleaseUrl() {
408
        return latestReleaseUrl;
1✔
409
    }
410

411
    public void setLatestReleaseUrl(String latestReleaseUrl) {
412
        this.latestReleaseUrl = latestReleaseUrl;
1✔
413
    }
1✔
414

415
    public String getIssueTrackerUrl() {
416
        return issueTrackerUrl;
1✔
417
    }
418

419
    public void setIssueTrackerUrl(String issueTrackerUrl) {
420
        this.issueTrackerUrl = issueTrackerUrl;
1✔
421
    }
1✔
422

423
    public String getUsername() {
424
        return username;
1✔
425
    }
426

427
    public void setUsername(String username) {
428
        this.username = username;
1✔
429
    }
1✔
430

431
    public String getToken() {
432
        return token;
1✔
433
    }
434

435
    public void setToken(String token) {
436
        this.token = token;
1✔
437
    }
1✔
438

439
    public String getTagName() {
440
        return tagName;
1✔
441
    }
442

443
    public void setTagName(String tagName) {
444
        this.cachedTagName = null;
1✔
445
        this.tagName = tagName;
1✔
446
    }
1✔
447

448
    public String getPreviousTagName() {
449
        return previousTagName;
1✔
450
    }
451

452
    public void setPreviousTagName(String previousTagName) {
453
        this.cachedPreviousTagName = null;
1✔
454
        this.previousTagName = previousTagName;
1✔
455
    }
1✔
456

457
    public String getReleaseName() {
458
        return releaseName;
1✔
459
    }
460

461
    public void setReleaseName(String releaseName) {
462
        this.cachedReleaseName = null;
1✔
463
        this.releaseName = releaseName;
1✔
464
    }
1✔
465

466
    public String getBranch() {
467
        return branch;
1✔
468
    }
469

470
    public void setBranch(String branch) {
471
        this.branch = branch;
1✔
472
    }
1✔
473

474
    public String getBranchPush() {
475
        return branchPush;
1✔
476
    }
477

478
    public void setBranchPush(String branchPush) {
479
        this.branchPush = branchPush;
1✔
480
    }
1✔
481

482
    @Override
483
    public CommitAuthor getCommitAuthor() {
484
        return commitAuthor;
1✔
485
    }
486

487
    @Override
488
    public void setCommitAuthor(CommitAuthor commitAuthor) {
489
        this.commitAuthor.merge(commitAuthor);
×
490
    }
×
491

492
    public Prerelease getPrerelease() {
493
        return prerelease;
1✔
494
    }
495

496
    public void setPrerelease(Prerelease prerelease) {
497
        this.prerelease.merge(prerelease);
×
498
    }
×
499

500
    public boolean isSign() {
501
        return null != sign && sign;
1✔
502
    }
503

504
    public void setSign(Boolean sign) {
505
        this.sign = sign;
1✔
506
    }
1✔
507

508
    public Changelog getChangelog() {
509
        return changelog;
1✔
510
    }
511

512
    public void setChangelog(Changelog changelog) {
513
        this.changelog.merge(changelog);
1✔
514
    }
1✔
515

516
    public Milestone getMilestone() {
517
        return milestone;
1✔
518
    }
519

520
    public void setMilestone(Milestone milestone) {
521
        this.milestone.merge(milestone);
×
522
    }
×
523

524
    public Issues getIssues() {
525
        return issues;
1✔
526
    }
527

528
    public void setIssues(Issues issues) {
529
        this.issues.merge(issues);
1✔
530
    }
1✔
531

532
    public boolean isSkipTag() {
533
        return null != skipTag && skipTag;
1✔
534
    }
535

536
    public void setSkipTag(Boolean skipTag) {
537
        this.skipTag = skipTag;
1✔
538
    }
1✔
539

540
    public boolean isSkipTagSet() {
541
        return null != skipTag;
1✔
542
    }
543

544
    public boolean isSkipRelease() {
545
        return null != skipRelease && skipRelease;
1✔
546
    }
547

548
    public void setSkipRelease(Boolean skipRelease) {
549
        this.skipRelease = skipRelease;
1✔
550
    }
1✔
551

552
    public boolean isSkipReleaseSet() {
553
        return null != skipRelease;
1✔
554
    }
555

556
    public boolean isOverwrite() {
557
        return null != overwrite && overwrite;
1✔
558
    }
559

560
    public void setOverwrite(Boolean overwrite) {
561
        this.overwrite = overwrite;
1✔
562
    }
1✔
563

564
    public boolean isOverwriteSet() {
565
        return null != overwrite;
1✔
566
    }
567

568
    public Update getUpdate() {
569
        return update;
1✔
570
    }
571

572
    public void setUpdate(Update update) {
573
        this.update.merge(update);
×
574
    }
×
575

576
    public String getApiEndpoint() {
577
        return apiEndpoint;
1✔
578
    }
579

580
    public void setApiEndpoint(String apiEndpoint) {
581
        this.apiEndpoint = apiEndpoint;
1✔
582
    }
1✔
583

584
    @Override
585
    public Integer getConnectTimeout() {
586
        return connectTimeout;
1✔
587
    }
588

589
    @Override
590
    public void setConnectTimeout(Integer connectTimeout) {
591
        this.connectTimeout = connectTimeout;
1✔
592
    }
1✔
593

594
    @Override
595
    public Integer getReadTimeout() {
596
        return readTimeout;
1✔
597
    }
598

599
    @Override
600
    public void setReadTimeout(Integer readTimeout) {
601
        this.readTimeout = readTimeout;
1✔
602
    }
1✔
603

604
    public boolean isArtifactsSet() {
605
        return null != artifacts;
×
606
    }
607

608
    public boolean isArtifacts() {
609
        return null == artifacts || artifacts;
1✔
610
    }
611

612
    public void setArtifacts(Boolean artifacts) {
613
        this.artifacts = artifacts;
×
614
    }
×
615

616
    public boolean isFiles() {
617
        return null == files || files;
1✔
618
    }
619

620
    public void setFiles(Boolean files) {
621
        this.files = files;
×
622
    }
×
623

624
    public boolean isFilesSet() {
625
        return null != files;
×
626
    }
627

628
    public boolean isChecksumsSet() {
629
        return null != checksums;
×
630
    }
631

632
    public boolean isChecksums() {
633
        return null == checksums || checksums;
1✔
634
    }
635

636
    public void setChecksums(Boolean checksums) {
637
        this.checksums = checksums;
×
638
    }
×
639

640
    public boolean isCatalogsSet() {
641
        return null != catalogs;
×
642
    }
643

644
    public boolean isCatalogs() {
645
        return null == catalogs || catalogs;
1✔
646
    }
647

648
    public void setCatalogs(Boolean catalogs) {
649
        this.catalogs = catalogs;
×
650
    }
×
651

652
    public boolean isSignaturesSet() {
653
        return null != signatures;
×
654
    }
655

656
    public boolean isSignatures() {
657
        return null == signatures || signatures;
1✔
658
    }
659

660
    public void setSignatures(Boolean signatures) {
661
        this.signatures = signatures;
×
662
    }
×
663

664
    public Active getUploadAssets() {
665
        return uploadAssets;
×
666
    }
667

668
    public void setUploadAssets(Active uploadAssets) {
669
        this.uploadAssets = uploadAssets;
×
670
    }
×
671

672
    public void setUploadAssets(String str) {
673
        setUploadAssets(Active.of(str));
×
674
    }
×
675

676
    public boolean isUploadAssetsSet() {
677
        return null != uploadAssets;
×
678
    }
679

680
    @Override
681
    public Map<String, Object> asMap(boolean full) {
682
        Map<String, Object> map = new LinkedHashMap<>();
1✔
683
        map.put("enabled", isEnabled());
1✔
684
        map.put("host", host);
1✔
685
        map.put("owner", owner);
1✔
686
        map.put("name", name);
1✔
687
        map.put("username", username);
1✔
688
        map.put("token", isNotBlank(token) ? Constants.HIDE : Constants.UNSET);
1✔
689
        if (releaseSupported) {
1✔
690
            map.put("uploadAssets", uploadAssets);
1✔
691
            map.put("artifacts", isArtifacts());
1✔
692
            map.put("files", isFiles());
1✔
693
            map.put("checksums", isChecksums());
1✔
694
            map.put("catalogs", isCatalogs());
1✔
695
            map.put("signatures", isSignatures());
1✔
696
            map.put("repoUrl", repoUrl);
1✔
697
            map.put("repoCloneUrl", repoCloneUrl);
1✔
698
            map.put("commitUrl", commitUrl);
1✔
699
            map.put("srcUrl", srcUrl);
1✔
700
            map.put("downloadUrl", downloadUrl);
1✔
701
            map.put("releaseNotesUrl", releaseNotesUrl);
1✔
702
            map.put("latestReleaseUrl", latestReleaseUrl);
1✔
703
            map.put("issueTrackerUrl", issueTrackerUrl);
1✔
704
        }
705
        map.put("tagName", tagName);
1✔
706
        map.put("previousTagName", previousTagName);
1✔
707
        if (releaseSupported) {
1✔
708
            map.put("releaseName", releaseName);
1✔
709
        }
710
        map.put("branch", branch);
1✔
711
        map.put("branchPush", branchPush);
1✔
712
        map.put("commitAuthor", commitAuthor.asMap(full));
1✔
713
        map.put("sign", isSign());
1✔
714
        map.put("skipTag", isSkipTag());
1✔
715
        map.put("skipRelease", isSkipRelease());
1✔
716
        map.put("overwrite", isOverwrite());
1✔
717
        if (releaseSupported) {
1✔
718
            map.put("update", update.asMap(full));
1✔
719
            map.put("apiEndpoint", apiEndpoint);
1✔
720
            map.put("connectTimeout", connectTimeout);
1✔
721
            map.put("readTimeout", readTimeout);
1✔
722
        }
723
        map.put("changelog", changelog.asMap(full));
1✔
724
        if (releaseSupported) {
1✔
725
            map.put("milestone", milestone.asMap(full));
1✔
726
            map.put("issues", issues.asMap(full));
1✔
727
        }
728
        map.put("prerelease", prerelease.asMap(full));
1✔
729
        return map;
1✔
730
    }
731

732
    public TemplateContext props(JReleaserContext context) {
733
        // duplicate from JReleaserModel to avoid endless recursion
734
        TemplateContext props = new TemplateContext();
1✔
735
        Project project = context.getModel().getProject();
1✔
736
        props.setAll(context.getModel().getEnvironment().getProperties());
1✔
737
        props.setAll(context.getModel().getEnvironment().getSourcedProperties());
1✔
738
        props.set(Constants.KEY_PROJECT_NAME, project.getName());
1✔
739
        props.set(Constants.KEY_PROJECT_NAME_CAPITALIZED, getCapitalizedName(project.getName()));
1✔
740
        props.set(Constants.KEY_PROJECT_VERSION, project.getVersion());
1✔
741
        props.set(Constants.KEY_PROJECT_STEREOTYPE, project.getStereotype());
1✔
742
        props.set(Constants.KEY_PROJECT_EFFECTIVE_VERSION, project.getEffectiveVersion());
1✔
743
        props.set(Constants.KEY_PROJECT_SNAPSHOT, String.valueOf(project.isSnapshot()));
1✔
744
        if (isNotBlank(project.getDescription())) {
1✔
745
            props.set(Constants.KEY_PROJECT_DESCRIPTION, MustacheUtils.passThrough(project.getDescription()));
1✔
746
        }
747
        if (isNotBlank(project.getLongDescription())) {
1✔
748
            props.set(Constants.KEY_PROJECT_LONG_DESCRIPTION, MustacheUtils.passThrough(project.getLongDescription()));
1✔
749
        }
750
        if (isNotBlank(project.getLicense())) {
1✔
751
            props.set(Constants.KEY_PROJECT_LICENSE, project.getLicense());
1✔
752
        }
753
        if (null != project.getInceptionYear()) {
1✔
754
            props.set(Constants.KEY_PROJECT_INCEPTION_YEAR, project.getInceptionYear());
1✔
755
        }
756
        if (isNotBlank(project.getCopyright())) {
1✔
757
            props.set(Constants.KEY_PROJECT_COPYRIGHT, project.getCopyright());
1✔
758
        }
759
        if (isNotBlank(project.getVendor())) {
1✔
760
            props.set(Constants.KEY_PROJECT_VENDOR, project.getVendor());
1✔
761
        }
762
        project.getLinks().fillProps(props);
1✔
763

764
        project.getLanguages().fillProperties(props);
1✔
765

766
        project.parseVersion();
1✔
767
        props.setAll(project.resolvedExtraProperties());
1✔
768

769
        String osName = PlatformUtils.getDetectedOs();
1✔
770
        String osArch = PlatformUtils.getDetectedArch();
1✔
771
        props.set(Constants.KEY_OS_NAME, osName);
1✔
772
        props.set(Constants.KEY_OS_ARCH, osArch);
1✔
773
        props.set(Constants.KEY_OS_VERSION, PlatformUtils.getDetectedVersion());
1✔
774
        props.set(Constants.KEY_OS_PLATFORM, PlatformUtils.getCurrentFull());
1✔
775
        props.set(Constants.KEY_OS_PLATFORM_REPLACED, context.getModel().getPlatform().applyReplacements(PlatformUtils.getCurrentFull()));
1✔
776

777
        props.set(Constants.KEY_REPO_HOST, host);
1✔
778
        props.set(Constants.KEY_REPO_OWNER, owner);
1✔
779
        props.set(Constants.KEY_REPO_NAME, name);
1✔
780
        props.set(Constants.KEY_REPO_BRANCH, branch);
1✔
781
        props.set(Constants.KEY_REPO_BRANCH_PUSH, cachedBranchPush);
1✔
782
        props.set(Constants.KEY_REVERSE_REPO_HOST, getReverseRepoHost());
1✔
783
        props.set(Constants.KEY_CANONICAL_REPO_NAME, getCanonicalRepoName());
1✔
784
        props.set(Constants.KEY_TAG_NAME, project.isSnapshot() ? project.getSnapshot().getResolvedLabel(context) : cachedTagName);
1✔
785
        props.set(Constants.KEY_PREVIOUS_TAG_NAME, cachedPreviousTagName);
1✔
786
        props.set(Constants.KEY_RELEASE_NAME, cachedReleaseName);
1✔
787
        props.set(Constants.KEY_MILESTONE_NAME, milestone.getEffectiveName());
1✔
788

789
        applyTemplates(context.getLogger(), props, project.resolvedExtraProperties());
1✔
790
        props.set(Constants.KEY_ZONED_DATE_TIME_NOW, context.getModel().getNow());
1✔
791

792
        return props;
1✔
793
    }
794

795
    public void fillProps(TemplateContext props, JReleaserContext context) {
796
        props.set(Constants.KEY_REPO_HOST, host);
1✔
797
        props.set(Constants.KEY_REPO_OWNER, owner);
1✔
798
        props.set(Constants.KEY_REPO_NAME, name);
1✔
799
        props.set(Constants.KEY_REPO_BRANCH, branch);
1✔
800
        props.set(Constants.KEY_REPO_BRANCH_PUSH, getResolvedBranchPush(context));
1✔
801
        props.set(Constants.KEY_REVERSE_REPO_HOST, getReverseRepoHost());
1✔
802
        props.set(Constants.KEY_CANONICAL_REPO_NAME, getCanonicalRepoName());
1✔
803
        props.set(Constants.KEY_TAG_NAME, getEffectiveTagName(context));
1✔
804
        props.set(Constants.KEY_PREVIOUS_TAG_NAME, getResolvedPreviousTagName(context));
1✔
805
        props.set(Constants.KEY_RELEASE_NAME, getEffectiveReleaseName());
1✔
806
        props.set(Constants.KEY_MILESTONE_NAME, milestone.getEffectiveName());
1✔
807
        props.set(Constants.KEY_REPO_URL, getResolvedRepoUrl(context));
1✔
808
        props.set(Constants.KEY_REPO_CLONE_URL, getResolvedRepoCloneUrl(context));
1✔
809
        props.set(Constants.KEY_COMMIT_URL, getResolvedCommitUrl(context));
1✔
810
        props.set(Constants.KEY_SRC_URL, getResolvedSrcUrl(context));
1✔
811
        props.set(Constants.KEY_RELEASE_NOTES_URL, getResolvedReleaseNotesUrl(context));
1✔
812
        props.set(Constants.KEY_LATEST_RELEASE_URL, getResolvedLatestReleaseUrl(context));
1✔
813
        props.set(Constants.KEY_ISSUE_TRACKER_URL, getResolvedIssueTrackerUrl(context, false));
1✔
814
    }
1✔
815

816
    public static final class Update extends AbstractModelObject<Update> implements Domain, EnabledAware {
1✔
817
        private static final long serialVersionUID = -3809529510256990035L;
818

819
        private final Set<UpdateSection> sections = new LinkedHashSet<>();
1✔
820
        private Boolean enabled;
821

822
        @JsonIgnore
1✔
823
        private final org.jreleaser.model.api.release.Releaser.Update immutable = new org.jreleaser.model.api.release.Releaser.Update() {
1✔
824
            private static final long serialVersionUID = -7253526159752557224L;
825

826
            @Override
827
            public Set<UpdateSection> getSections() {
828
                return unmodifiableSet(sections);
×
829
            }
830

831
            @Override
832
            public Map<String, Object> asMap(boolean full) {
833
                return unmodifiableMap(Update.this.asMap(full));
×
834
            }
835

836
            @Override
837
            public boolean isEnabled() {
838
                return Update.this.isEnabled();
×
839
            }
840
        };
841

842
        public org.jreleaser.model.api.release.Releaser.Update asImmutable() {
843
            return immutable;
×
844
        }
845

846
        @Override
847
        public void merge(Update source) {
848
            this.enabled = merge(this.enabled, source.enabled);
×
849
            setSections(merge(this.sections, source.sections));
×
850
        }
×
851

852
        @Override
853
        public boolean isEnabled() {
854
            return null != enabled && enabled;
1✔
855
        }
856

857
        @Override
858
        public void setEnabled(Boolean enabled) {
859
            this.enabled = enabled;
1✔
860
        }
1✔
861

862
        @Override
863
        public boolean isEnabledSet() {
864
            return null != enabled;
1✔
865
        }
866

867
        public Set<UpdateSection> getSections() {
868
            return sections;
×
869
        }
870

871
        public void setSections(Set<UpdateSection> sections) {
872
            this.sections.clear();
×
873
            this.sections.addAll(sections);
×
874
        }
×
875

876
        @Override
877
        public Map<String, Object> asMap(boolean full) {
878
            Map<String, Object> map = new LinkedHashMap<>();
1✔
879
            map.put("enabled", isEnabled());
1✔
880
            map.put("sections", sections);
1✔
881
            return map;
1✔
882
        }
883
    }
884

885
    public static final class Prerelease extends AbstractModelObject<Prerelease> implements Domain, EnabledAware {
1✔
886
        private static final long serialVersionUID = -7358833182369685133L;
887

888
        private Boolean enabled;
889
        private String pattern;
890

891
        @JsonIgnore
1✔
892
        private final org.jreleaser.model.api.release.Releaser.Prerelease immutable = new org.jreleaser.model.api.release.Releaser.Prerelease() {
1✔
893
            private static final long serialVersionUID = -862797136353472181L;
894

895
            @Override
896
            public boolean isPrerelease(String version) {
897
                return Prerelease.this.isPrerelease(version);
×
898
            }
899

900
            @Override
901
            public String getPattern() {
902
                return pattern;
×
903
            }
904

905
            @Override
906
            public Map<String, Object> asMap(boolean full) {
907
                return unmodifiableMap(Prerelease.this.asMap(full));
×
908
            }
909

910
            @Override
911
            public boolean isEnabled() {
912
                return Prerelease.this.isEnabled();
×
913
            }
914
        };
915

916
        public org.jreleaser.model.api.release.Releaser.Prerelease asImmutable() {
917
            return immutable;
×
918
        }
919

920
        @Override
921
        public void merge(Prerelease source) {
922
            this.enabled = merge(this.enabled, source.enabled);
×
923
            this.pattern = merge(this.pattern, source.pattern);
×
924
        }
×
925

926
        public void disable() {
927
            enabled = false;
×
928
        }
×
929

930
        @Override
931
        public boolean isEnabled() {
932
            return null != enabled && enabled;
1✔
933
        }
934

935
        @Override
936
        public void setEnabled(Boolean enabled) {
937
            this.enabled = enabled;
1✔
938
        }
1✔
939

940
        @Override
941
        public boolean isEnabledSet() {
942
            return null != enabled;
1✔
943
        }
944

945
        public boolean isPrerelease(String version) {
946
            if (null == enabled) {
1✔
947
                String configuredPattern = getConfiguredPattern();
1✔
948
                if (isNotBlank(configuredPattern)) {
1✔
949
                    enabled = version.matches(configuredPattern);
×
950
                } else {
951
                    enabled = false;
1✔
952
                }
953
            }
954

955
            return enabled;
1✔
956
        }
957

958
        public String getConfiguredPattern() {
959
            return Env.env(org.jreleaser.model.api.release.Releaser.PRERELEASE_PATTERN, pattern);
1✔
960
        }
961

962
        public String getPattern() {
963
            return pattern;
1✔
964
        }
965

966
        public void setPattern(String pattern) {
967
            this.pattern = pattern;
1✔
968
        }
1✔
969

970
        @Override
971
        public Map<String, Object> asMap(boolean full) {
972
            Map<String, Object> map = new LinkedHashMap<>();
1✔
973
            map.put("enabled", isEnabled());
1✔
974
            map.put("pattern", getConfiguredPattern());
1✔
975
            return map;
1✔
976
        }
977
    }
978

979
    public static final class Milestone extends AbstractModelObject<Milestone> implements Domain {
1✔
980
        private static final long serialVersionUID = 5385291379888571159L;
981

982
        private Boolean close;
983
        private String name;
984

985
        @JsonIgnore
1✔
986
        private final org.jreleaser.model.api.release.Releaser.Milestone immutable = new org.jreleaser.model.api.release.Releaser.Milestone() {
1✔
987
            private static final long serialVersionUID = 2957887352276816797L;
988

989
            @Override
990
            public boolean isClose() {
991
                return Milestone.this.isClose();
×
992
            }
993

994
            @Override
995
            public String getName() {
996
                return name;
×
997
            }
998

999
            @Override
1000
            public Map<String, Object> asMap(boolean full) {
1001
                return unmodifiableMap(Milestone.this.asMap(full));
×
1002
            }
1003
        };
1004

1005
        @JsonIgnore
1006
        private String cachedName;
1007

1008
        public org.jreleaser.model.api.release.Releaser.Milestone asImmutable() {
1009
            return immutable;
×
1010
        }
1011

1012
        @Override
1013
        public void merge(Milestone source) {
1014
            this.close = merge(this.close, source.close);
×
1015
            this.name = merge(this.name, source.name);
×
1016
        }
×
1017

1018
        public String getConfiguredName() {
1019
            return Env.env(org.jreleaser.model.api.release.Releaser.MILESTONE_NAME, cachedName);
1✔
1020
        }
1021

1022
        public String getResolvedName(JReleaserContext context, TemplateContext props) {
1023
            if (isBlank(cachedName)) {
1✔
1024
                cachedName = getConfiguredName();
1✔
1025
            }
1026

1027
            if (isBlank(cachedName)) {
1✔
1028
                cachedName = resolveTemplate(context.getLogger(), name, props);
1✔
1029
            } else if (cachedName.contains("{{")) {
1✔
NEW
1030
                cachedName = resolveTemplate(context.getLogger(), cachedName, props);
×
1031
            }
1032

1033
            return cachedName;
1✔
1034
        }
1035

1036
        public String getEffectiveName() {
1037
            return cachedName;
1✔
1038
        }
1039

1040
        public boolean isClose() {
1041
            return null == close || close;
1✔
1042
        }
1043

1044
        public void setClose(Boolean close) {
1045
            this.close = close;
×
1046
        }
×
1047

1048
        public boolean isCloseSet() {
1049
            return null != close;
×
1050
        }
1051

1052
        public String getName() {
1053
            return name;
1✔
1054
        }
1055

1056
        public void setName(String name) {
1057
            this.name = name;
1✔
1058
        }
1✔
1059

1060
        @Override
1061
        public Map<String, Object> asMap(boolean full) {
1062
            Map<String, Object> map = new LinkedHashMap<>();
1✔
1063
            map.put("name", name);
1✔
1064
            map.put("close", isClose());
1✔
1065
            return map;
1✔
1066
        }
1067
    }
1068

1069
    public static final class Issues extends AbstractModelObject<Issues> implements Domain, EnabledAware {
1✔
1070
        private static final long serialVersionUID = -8544658826532962076L;
1071

1072
        private final Label label = new Label();
1✔
1073
        private Apply applyMilestone;
1074
        private String comment;
1075
        private Boolean enabled;
1076

1077
        @JsonIgnore
1✔
1078
        private final org.jreleaser.model.api.release.Releaser.Issues immutable = new org.jreleaser.model.api.release.Releaser.Issues() {
1✔
1079
            private static final long serialVersionUID = 7857893617001154950L;
1080

1081
            @Override
1082
            public String getComment() {
1083
                return comment;
×
1084
            }
1085

1086
            @Override
1087
            public Apply getApplyMilestone() {
1088
                return applyMilestone;
×
1089
            }
1090

1091
            @Override
1092
            public Label getLabel() {
1093
                return label.asImmutable();
×
1094
            }
1095

1096
            @Override
1097
            public Map<String, Object> asMap(boolean full) {
1098
                return unmodifiableMap(Issues.this.asMap(full));
×
1099
            }
1100

1101
            @Override
1102
            public boolean isEnabled() {
1103
                return Issues.this.isEnabled();
×
1104
            }
1105
        };
1106

1107
        public org.jreleaser.model.api.release.Releaser.Issues asImmutable() {
1108
            return immutable;
×
1109
        }
1110

1111
        @Override
1112
        public void merge(Issues source) {
1113
            this.comment = merge(this.comment, source.comment);
1✔
1114
            this.enabled = merge(this.enabled, source.enabled);
1✔
1115
            this.applyMilestone = merge(this.applyMilestone, source.applyMilestone);
1✔
1116
            setLabel(source.label);
1✔
1117
        }
1✔
1118

1119
        @Override
1120
        public boolean isEnabled() {
1121
            return null != enabled && enabled;
1✔
1122
        }
1123

1124
        @Override
1125
        public void setEnabled(Boolean enabled) {
1126
            this.enabled = enabled;
1✔
1127
        }
1✔
1128

1129
        @Override
1130
        public boolean isEnabledSet() {
1131
            return null != enabled;
×
1132
        }
1133

1134
        public String getComment() {
1135
            return comment;
1✔
1136
        }
1137

1138
        public void setComment(String comment) {
1139
            this.comment = comment;
1✔
1140
        }
1✔
1141

1142
        public Label getLabel() {
1143
            return label;
1✔
1144
        }
1145

1146
        public void setLabel(Label label) {
1147
            this.label.merge(label);
1✔
1148
        }
1✔
1149

1150
        public Apply getApplyMilestone() {
1151
            return applyMilestone;
×
1152
        }
1153

1154
        public void setApplyMilestone(Apply applyMilestone) {
1155
            this.applyMilestone = applyMilestone;
×
1156
        }
×
1157

1158
        public void setApplyMilestone(String str) {
1159
            setApplyMilestone(Apply.of(str));
×
1160
        }
×
1161

1162
        @Override
1163
        public Map<String, Object> asMap(boolean full) {
1164
            Map<String, Object> map = new LinkedHashMap<>();
1✔
1165
            map.put("enabled", isEnabled());
1✔
1166
            map.put("comment", comment);
1✔
1167
            map.put("label", label.asMap(full));
1✔
1168
            map.put("applyMilestone", applyMilestone);
1✔
1169
            return map;
1✔
1170
        }
1171

1172
        public static final class Label extends AbstractModelObject<Label> implements Domain {
1✔
1173
            private static final long serialVersionUID = 6951467063217168128L;
1174

1175
            private String name;
1176
            private String color;
1177
            private String description;
1178

1179
            @JsonIgnore
1✔
1180
            private final org.jreleaser.model.api.release.Releaser.Issues.Label immutable = new org.jreleaser.model.api.release.Releaser.Issues.Label() {
1✔
1181
                private static final long serialVersionUID = 8642359487826561699L;
1182

1183
                @Override
1184
                public String getName() {
1185
                    return name;
×
1186
                }
1187

1188
                @Override
1189
                public String getColor() {
1190
                    return color;
×
1191
                }
1192

1193
                @Override
1194
                public String getDescription() {
1195
                    return description;
×
1196
                }
1197

1198
                @Override
1199
                public Map<String, Object> asMap(boolean full) {
1200
                    return unmodifiableMap(Label.this.asMap(full));
×
1201
                }
1202
            };
1203

1204
            public org.jreleaser.model.api.release.Releaser.Issues.Label asImmutable() {
1205
                return immutable;
×
1206
            }
1207

1208
            @Override
1209
            public void merge(Label source) {
1210
                this.name = merge(this.name, source.name);
1✔
1211
                this.color = merge(this.color, source.color);
1✔
1212
                this.description = merge(this.description, source.description);
1✔
1213
            }
1✔
1214

1215
            public String getName() {
1216
                return name;
1✔
1217
            }
1218

1219
            public void setName(String name) {
1220
                this.name = name;
1✔
1221
            }
1✔
1222

1223
            public String getColor() {
1224
                return color;
1✔
1225
            }
1226

1227
            public void setColor(String color) {
1228
                this.color = color;
1✔
1229
            }
1✔
1230

1231
            public String getDescription() {
1232
                return description;
1✔
1233
            }
1234

1235
            public void setDescription(String description) {
1236
                this.description = description;
1✔
1237
            }
1✔
1238

1239
            @Override
1240
            public Map<String, Object> asMap(boolean full) {
1241
                Map<String, Object> map = new LinkedHashMap<>();
1✔
1242
                map.put("name", name);
1✔
1243
                map.put("color", color);
1✔
1244
                map.put("description", description);
1✔
1245
                return map;
1✔
1246
            }
1247
        }
1248
    }
1249
}
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