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

jreleaser / jreleaser / #539

25 Sep 2025 06:51PM UTC coverage: 48.269% (+0.7%) from 47.589%
#539

push

github

web-flow
feat(release): Add support for github immutable releases

Closes #1978

2 of 14 new or added lines in 4 files covered. (14.29%)

10 existing lines in 5 files now uncovered.

25820 of 53492 relevant lines covered (48.27%)

0.48 hits per line

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

38.02
/core/jreleaser-model-impl/src/main/java/org/jreleaser/model/internal/release/GithubReleaser.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.internal.common.AbstractModelObject;
23
import org.jreleaser.model.internal.common.Domain;
24
import org.jreleaser.model.internal.common.EnabledAware;
25

26
import java.util.LinkedHashMap;
27
import java.util.Map;
28

29
import static java.util.Collections.unmodifiableMap;
30

31
/**
32
 * @author Andres Almiray
33
 * @since 0.1.0
34
 */
35
public final class GithubReleaser extends BaseReleaser<org.jreleaser.model.api.release.GithubReleaser, GithubReleaser> {
36
    private static final long serialVersionUID = 8444833889157237176L;
37

38
    private final ReleaseNotes releaseNotes = new ReleaseNotes();
1✔
39

40
    private Boolean draft;
41
    private Boolean immutableRelease;
42
    private String discussionCategoryName;
43
    private org.jreleaser.model.api.release.GithubReleaser.MakeLatest makeLatest;
44

45
    @JsonIgnore
1✔
46
    private final org.jreleaser.model.api.release.GithubReleaser immutable = new org.jreleaser.model.api.release.GithubReleaser() {
1✔
47
        private static final long serialVersionUID = -9123016069637288447L;
48

49
        @Override
50
        public boolean isPrerelease() {
51
            return GithubReleaser.this.isPrerelease();
×
52
        }
53

54
        @Override
55
        public boolean isDraft() {
56
            return GithubReleaser.this.isDraft();
×
57
        }
58

59
        @Override
60
        public boolean isImmutableRelease() {
NEW
61
            return GithubReleaser.this.isImmutableRelease();
×
62
        }
63

64
        @Override
65
        public MakeLatest getMakeLatest() {
66
            return makeLatest;
×
67
        }
68

69
        @Override
70
        public String getDiscussionCategoryName() {
71
            return discussionCategoryName;
×
72
        }
73

74
        @Override
75
        public ReleaseNotes getReleaseNotes() {
76
            return releaseNotes.asImmutable();
×
77
        }
78

79
        @Override
80
        public String getServiceName() {
81
            return GithubReleaser.this.getServiceName();
×
82
        }
83

84
        @Override
85
        public boolean isReleaseSupported() {
86
            return GithubReleaser.this.isReleaseSupported();
×
87
        }
88

89
        @Override
90
        public String getCanonicalRepoName() {
91
            return GithubReleaser.this.getCanonicalRepoName();
×
92
        }
93

94
        @Override
95
        public String getReverseRepoHost() {
96
            return GithubReleaser.this.getReverseRepoHost();
×
97
        }
98

99
        @Override
100
        public boolean isMatch() {
101
            return GithubReleaser.this.isMatch();
×
102
        }
103

104
        @Override
105
        public String getHost() {
106
            return GithubReleaser.this.getHost();
×
107
        }
108

109
        @Override
110
        public String getName() {
111
            return GithubReleaser.this.getName();
×
112
        }
113

114
        @Override
115
        public String getRepoUrl() {
116
            return GithubReleaser.this.getRepoUrl();
×
117
        }
118

119
        @Override
120
        public String getRepoCloneUrl() {
121
            return GithubReleaser.this.getRepoCloneUrl();
×
122
        }
123

124
        @Override
125
        public String getCommitUrl() {
126
            return GithubReleaser.this.getCommitUrl();
×
127
        }
128

129
        @Override
130
        public String getSrcUrl() {
131
            return GithubReleaser.this.getSrcUrl();
×
132
        }
133

134
        @Override
135
        public String getDownloadUrl() {
136
            return GithubReleaser.this.getDownloadUrl();
×
137
        }
138

139
        @Override
140
        public String getReleaseNotesUrl() {
141
            return GithubReleaser.this.getReleaseNotesUrl();
×
142
        }
143

144
        @Override
145
        public String getLatestReleaseUrl() {
146
            return GithubReleaser.this.getLatestReleaseUrl();
×
147
        }
148

149
        @Override
150
        public String getIssueTrackerUrl() {
151
            return GithubReleaser.this.getIssueTrackerUrl();
×
152
        }
153

154
        @Override
155
        public String getUsername() {
156
            return GithubReleaser.this.getUsername();
×
157
        }
158

159
        @Override
160
        public String getToken() {
161
            return GithubReleaser.this.getToken();
×
162
        }
163

164
        @Override
165
        public String getTagName() {
166
            return GithubReleaser.this.getTagName();
×
167
        }
168

169
        @Override
170
        public String getPreviousTagName() {
171
            return GithubReleaser.this.getPreviousTagName();
×
172
        }
173

174
        @Override
175
        public String getReleaseName() {
176
            return GithubReleaser.this.getReleaseName();
×
177
        }
178

179
        @Override
180
        public String getBranch() {
181
            return GithubReleaser.this.getBranch();
×
182
        }
183

184
        @Override
185
        public String getBranchPush() {
186
            return GithubReleaser.this.getBranchPush();
×
187
        }
188

189
        @Override
190
        public Prerelease getPrerelease() {
191
            return GithubReleaser.this.getPrerelease().asImmutable();
×
192
        }
193

194
        @Override
195
        public boolean isSign() {
196
            return GithubReleaser.this.isSign();
×
197
        }
198

199
        @Override
200
        public org.jreleaser.model.api.release.Changelog getChangelog() {
201
            return GithubReleaser.this.getChangelog().asImmutable();
×
202
        }
203

204
        @Override
205
        public Milestone getMilestone() {
206
            return GithubReleaser.this.getMilestone().asImmutable();
×
207
        }
208

209
        @Override
210
        public Issues getIssues() {
211
            return GithubReleaser.this.getIssues().asImmutable();
×
212
        }
213

214
        @Override
215
        public boolean isSkipTag() {
216
            return GithubReleaser.this.isSkipTag();
×
217
        }
218

219
        @Override
220
        public boolean isSkipRelease() {
221
            return GithubReleaser.this.isSkipRelease();
×
222
        }
223

224
        @Override
225
        public boolean isOverwrite() {
226
            return GithubReleaser.this.isOverwrite();
×
227
        }
228

229
        @Override
230
        public Update getUpdate() {
231
            return GithubReleaser.this.getUpdate().asImmutable();
×
232
        }
233

234
        @Override
235
        public String getApiEndpoint() {
236
            return GithubReleaser.this.getApiEndpoint();
×
237
        }
238

239
        @Override
240
        public boolean isArtifacts() {
241
            return GithubReleaser.this.isArtifacts();
×
242
        }
243

244
        @Override
245
        public boolean isFiles() {
246
            return GithubReleaser.this.isFiles();
×
247
        }
248

249
        @Override
250
        public boolean isChecksums() {
251
            return GithubReleaser.this.isChecksums();
×
252
        }
253

254
        @Override
255
        public boolean isCatalogs() {
256
            return GithubReleaser.this.isCatalogs();
×
257
        }
258

259
        @Override
260
        public boolean isSignatures() {
261
            return GithubReleaser.this.isSignatures();
×
262
        }
263

264
        @Override
265
        public Active getUploadAssets() {
266
            return GithubReleaser.this.getUploadAssets();
×
267
        }
268

269
        @Override
270
        public org.jreleaser.model.api.common.CommitAuthor getCommitAuthor() {
271
            return GithubReleaser.this.getCommitAuthor().asImmutable();
×
272
        }
273

274
        @Override
275
        public Map<String, Object> asMap(boolean full) {
276
            return unmodifiableMap(GithubReleaser.this.asMap(full));
×
277
        }
278

279
        @Override
280
        public boolean isEnabled() {
281
            return GithubReleaser.this.isEnabled();
×
282
        }
283

284
        @Override
285
        public String getOwner() {
286
            return GithubReleaser.this.getOwner();
×
287
        }
288

289
        @Override
290
        public Integer getConnectTimeout() {
291
            return GithubReleaser.this.getConnectTimeout();
×
292
        }
293

294
        @Override
295
        public Integer getReadTimeout() {
296
            return GithubReleaser.this.getReadTimeout();
×
297
        }
298
    };
299

300
    public GithubReleaser() {
301
        super(org.jreleaser.model.api.release.GithubReleaser.TYPE, true);
1✔
302
        setHost("github.com");
1✔
303
        setApiEndpoint("https://api.github.com");
1✔
304
        setRepoUrl("https://{{repoHost}}/{{repoOwner}}/{{repoName}}");
1✔
305
        setRepoCloneUrl("https://{{repoHost}}/{{repoOwner}}/{{repoName}}.git");
1✔
306
        setCommitUrl("https://{{repoHost}}/{{repoOwner}}/{{repoName}}/commits");
1✔
307
        setSrcUrl("https://{{repoHost}}/{{repoOwner}}/{{repoName}}/blob/{{repoBranch}}");
1✔
308
        setDownloadUrl("https://{{repoHost}}/{{repoOwner}}/{{repoName}}/releases/download/{{tagName}}/{{artifactFile}}");
1✔
309
        setReleaseNotesUrl("https://{{repoHost}}/{{repoOwner}}/{{repoName}}/releases/tag/{{tagName}}");
1✔
310
        setLatestReleaseUrl("https://{{repoHost}}/{{repoOwner}}/{{repoName}}/releases/latest");
1✔
311
        setIssueTrackerUrl("https://{{repoHost}}/{{repoOwner}}/{{repoName}}/issues");
1✔
312
    }
1✔
313

314
    @Override
315
    public org.jreleaser.model.api.release.GithubReleaser asImmutable() {
316
        return immutable;
1✔
317
    }
318

319
    @Override
320
    public void merge(GithubReleaser source) {
321
        super.merge(source);
×
322
        this.draft = merge(this.draft, source.draft);
×
323
        this.makeLatest = merge(this.makeLatest, source.makeLatest);
×
324
        this.discussionCategoryName = merge(this.discussionCategoryName, source.discussionCategoryName);
×
325
        setReleaseNotes(source.releaseNotes);
×
326
    }
×
327

328
    public org.jreleaser.model.api.release.GithubReleaser.MakeLatest getMakeLatest() {
329
        return makeLatest;
1✔
330
    }
331

332
    public void setMakeLatest(org.jreleaser.model.api.release.GithubReleaser.MakeLatest makeLatest) {
333
        this.makeLatest = makeLatest;
1✔
334
    }
1✔
335

336
    public void setMakeLatest(String makeLatest) {
337
        if (null != makeLatest) {
1✔
338
            setMakeLatest(org.jreleaser.model.api.release.GithubReleaser.MakeLatest.of(makeLatest.trim()));
1✔
339
        }
340
    }
1✔
341

342
    public boolean isDraft() {
343
        return null != draft && draft;
1✔
344
    }
345

346
    public void setDraft(Boolean draft) {
347
        this.draft = draft;
1✔
348
    }
1✔
349

350
    public boolean isDraftSet() {
351
        return null != draft;
1✔
352
    }
353

354
    public boolean isImmutableRelease() {
355
        return null != immutableRelease && immutableRelease;
1✔
356
    }
357

358
    public void setImmutableRelease(Boolean immutableRelease) {
NEW
359
        this.immutableRelease = immutableRelease;
×
NEW
360
    }
×
361

362
    public boolean isImmutableReleaseSet() {
NEW
363
        return null != immutableRelease;
×
364
    }
365

366
    public String getDiscussionCategoryName() {
367
        return discussionCategoryName;
×
368
    }
369

370
    public void setDiscussionCategoryName(String discussionCategoryName) {
371
        this.discussionCategoryName = discussionCategoryName;
1✔
372
    }
1✔
373

374
    public ReleaseNotes getReleaseNotes() {
375
        return releaseNotes;
1✔
376
    }
377

378
    public void setReleaseNotes(ReleaseNotes releaseNotes) {
379
        this.releaseNotes.merge(releaseNotes);
×
380
    }
×
381

382
    @Override
383
    public String getReverseRepoHost() {
384
        return "com.github";
1✔
385
    }
386

387
    @Override
388
    public Map<String, Object> asMap(boolean full) {
389
        Map<String, Object> map = super.asMap(full);
1✔
390
        map.put("draft", isDraft());
1✔
391
        map.put("immutableRelease", isImmutableRelease());
1✔
392
        map.put("discussionCategoryName", discussionCategoryName);
1✔
393
        map.put("releaseNotes", releaseNotes.asMap(full));
1✔
394
        map.put("makeLatest", null != makeLatest ? makeLatest.formatted() : null);
1✔
395
        return map;
1✔
396
    }
397

398
    public static final class ReleaseNotes extends AbstractModelObject<ReleaseNotes> implements Domain, EnabledAware {
1✔
399
        private static final long serialVersionUID = -1029998017479730113L;
400

401
        private Boolean enabled;
402
        private String configurationFile;
403

404
        @JsonIgnore
1✔
405
        private final org.jreleaser.model.api.release.GithubReleaser.ReleaseNotes immutable = new org.jreleaser.model.api.release.GithubReleaser.ReleaseNotes() {
1✔
406
            private static final long serialVersionUID = -301461478911447433L;
407

408
            @Override
409
            public String getConfigurationFile() {
410
                return configurationFile;
×
411
            }
412

413
            @Override
414
            public Map<String, Object> asMap(boolean full) {
415
                return unmodifiableMap(ReleaseNotes.this.asMap(full));
×
416
            }
417

418
            @Override
419
            public boolean isEnabled() {
420
                return ReleaseNotes.this.isEnabled();
×
421
            }
422
        };
423

424
        public org.jreleaser.model.api.release.GithubReleaser.ReleaseNotes asImmutable() {
425
            return immutable;
×
426
        }
427

428
        @Override
429
        public void merge(ReleaseNotes source) {
430
            this.enabled = merge(this.enabled, source.enabled);
×
431
            this.configurationFile = merge(this.configurationFile, source.configurationFile);
×
432
        }
×
433

434
        @Override
435
        public boolean isEnabled() {
436
            return null != enabled && enabled;
1✔
437
        }
438

439
        @Override
440
        public void setEnabled(Boolean enabled) {
441
            this.enabled = enabled;
×
442
        }
×
443

444
        @Override
445
        public boolean isEnabledSet() {
446
            return null != enabled;
×
447
        }
448

449
        public String getConfigurationFile() {
450
            return configurationFile;
×
451
        }
452

453
        public void setConfigurationFile(String configurationFile) {
454
            this.configurationFile = configurationFile;
×
455
        }
×
456

457
        @Override
458
        public Map<String, Object> asMap(boolean full) {
459
            Map<String, Object> map = new LinkedHashMap<>();
1✔
460
            map.put("enabled", isEnabled());
1✔
461
            map.put("configurationFile", configurationFile);
1✔
462
            return map;
1✔
463
        }
464
    }
465
}
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