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

jreleaser / jreleaser / #486

23 May 2025 05:11PM UTC coverage: 48.584% (-0.09%) from 48.67%
#486

push

github

aalmiray
feat(core): Add a flag to skip non-configured sections. The yolo flag.

Closes #1840

160 of 217 new or added lines in 57 files covered. (73.73%)

438 existing lines in 34 files now uncovered.

25292 of 52058 relevant lines covered (48.58%)

0.49 hits per line

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

50.0
/core/jreleaser-model-impl/src/main/java/org/jreleaser/model/internal/packagers/DockerPackager.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.packagers;
19

20
import com.fasterxml.jackson.annotation.JsonIgnore;
21
import org.jreleaser.model.Active;
22
import org.jreleaser.model.Stereotype;
23
import org.jreleaser.model.internal.JReleaserContext;
24
import org.jreleaser.model.internal.common.Artifact;
25
import org.jreleaser.model.internal.common.CommitAuthor;
26
import org.jreleaser.model.internal.common.CommitAuthorAware;
27
import org.jreleaser.model.internal.common.Domain;
28
import org.jreleaser.model.internal.distributions.Distribution;
29
import org.jreleaser.model.internal.project.Project;
30
import org.jreleaser.util.FileType;
31
import org.jreleaser.util.PlatformUtils;
32

33
import java.util.ArrayList;
34
import java.util.Collections;
35
import java.util.EnumSet;
36
import java.util.LinkedHashMap;
37
import java.util.List;
38
import java.util.Map;
39
import java.util.Set;
40
import java.util.stream.Collectors;
41

42
import static java.util.Collections.emptySet;
43
import static java.util.Collections.unmodifiableList;
44
import static java.util.Collections.unmodifiableMap;
45
import static java.util.Collections.unmodifiableSet;
46
import static java.util.Comparator.naturalOrder;
47
import static java.util.function.Function.identity;
48
import static java.util.stream.Collectors.toList;
49
import static java.util.stream.Collectors.toMap;
50
import static java.util.stream.Collectors.toSet;
51
import static org.jreleaser.model.Distribution.DistributionType.BINARY;
52
import static org.jreleaser.model.Distribution.DistributionType.FLAT_BINARY;
53
import static org.jreleaser.model.Distribution.DistributionType.JAVA_BINARY;
54
import static org.jreleaser.model.Distribution.DistributionType.JLINK;
55
import static org.jreleaser.model.Distribution.DistributionType.NATIVE_IMAGE;
56
import static org.jreleaser.model.Distribution.DistributionType.SINGLE_JAR;
57
import static org.jreleaser.model.api.packagers.DockerPackager.SKIP_DOCKER;
58
import static org.jreleaser.util.CollectionUtils.setOf;
59
import static org.jreleaser.util.FileType.JAR;
60
import static org.jreleaser.util.FileType.ZIP;
61
import static org.jreleaser.util.StringUtils.isBlank;
62
import static org.jreleaser.util.StringUtils.isFalse;
63

64
/**
65
 * @author Andres Almiray
66
 * @since 0.1.0
67
 */
68
public final class DockerPackager extends AbstractDockerConfiguration<DockerPackager> implements RepositoryPackager<org.jreleaser.model.api.packagers.DockerPackager>, CommitAuthorAware {
1✔
69
    private static final Map<org.jreleaser.model.Distribution.DistributionType, Set<String>> SUPPORTED = new LinkedHashMap<>();
1✔
70
    private static final long serialVersionUID = -8293471753814007950L;
71

72
    static {
73
        Set<String> extensions = setOf(ZIP.extension());
1✔
74
        SUPPORTED.put(NATIVE_IMAGE, extensions);
1✔
75
        SUPPORTED.put(BINARY, extensions);
1✔
76
        SUPPORTED.put(JAVA_BINARY, extensions);
1✔
77
        SUPPORTED.put(JLINK, extensions);
1✔
78
        SUPPORTED.put(SINGLE_JAR, setOf(JAR.extension()));
1✔
79
        SUPPORTED.put(FLAT_BINARY, emptySet());
1✔
80
    }
1✔
81

82
    private final Map<String, DockerSpec> specs = new LinkedHashMap<>();
1✔
83
    private final CommitAuthor commitAuthor = new CommitAuthor();
1✔
84
    private final DockerRepository repository = new DockerRepository();
1✔
85

86
    private Boolean continueOnError;
87
    private String downloadUrl;
88

89
    @JsonIgnore
1✔
90
    private final org.jreleaser.model.api.packagers.DockerPackager immutable = new org.jreleaser.model.api.packagers.DockerPackager() {
1✔
91
        private static final long serialVersionUID = 8086673555899372436L;
92

93
        private Set<? extends org.jreleaser.model.api.packagers.DockerConfiguration.Registry> registries;
94
        private Map<String, ? extends org.jreleaser.model.api.packagers.DockerSpec> specs;
95

96
        @Override
97
        public Map<String, ? extends org.jreleaser.model.api.packagers.DockerSpec> getSpecs() {
98
            if (null == specs) {
×
99
                specs = DockerPackager.this.specs.values().stream()
×
100
                    .map(DockerSpec::asImmutable)
×
101
                    .collect(toMap(org.jreleaser.model.api.packagers.DockerSpec::getName, identity()));
×
102
            }
103
            return specs;
×
104
        }
105

106
        @Override
107
        public DockerRepository getRepository() {
108
            return repository.asImmutable();
×
109
        }
110

111
        @Override
112
        public DockerCommand getCommand() {
113
            return DockerPackager.this.getCommand();
×
114
        }
115

116
        @Override
117
        public org.jreleaser.model.api.common.CommitAuthor getCommitAuthor() {
118
            return commitAuthor.asImmutable();
×
119
        }
120

121
        @Override
122
        public String getTemplateDirectory() {
123
            return DockerPackager.this.getTemplateDirectory();
×
124
        }
125

126
        @Override
127
        public List<String> getSkipTemplates() {
128
            return unmodifiableList(DockerPackager.this.getSkipTemplates());
×
129
        }
130

131
        @Override
132
        public String getBaseImage() {
133
            return DockerPackager.this.getBaseImage();
×
134
        }
135

136
        @Override
137
        public Map<String, String> getLabels() {
138
            return unmodifiableMap(DockerPackager.this.getLabels());
×
139
        }
140

141
        @Override
142
        public Set<String> getImageNames() {
143
            return unmodifiableSet(DockerPackager.this.getImageNames());
×
144
        }
145

146
        @Override
147
        public List<String> getBuildArgs() {
148
            return unmodifiableList(DockerPackager.this.getBuildArgs());
×
149
        }
150

151
        @Override
152
        public List<String> getPreCommands() {
153
            return unmodifiableList(DockerPackager.this.getPreCommands());
×
154
        }
155

156
        @Override
157
        public List<String> getPostCommands() {
158
            return unmodifiableList(DockerPackager.this.getPostCommands());
×
159
        }
160

161
        @Override
162
        public Set<? extends org.jreleaser.model.api.packagers.DockerConfiguration.Registry> getRegistries() {
163
            if (null == registries) {
×
164
                registries = DockerPackager.this.getRegistries().stream()
×
165
                    .map(DockerConfiguration.Registry::asImmutable)
×
166
                    .collect(toSet());
×
167
            }
168
            return registries;
×
169
        }
170

171
        @Override
172
        public boolean isUseLocalArtifact() {
173
            return DockerPackager.this.isUseLocalArtifact();
×
174
        }
175

176
        @Override
177
        public org.jreleaser.model.api.packagers.PackagerRepository getPackagerRepository() {
178
            return getRepository();
×
179
        }
180

181
        @Override
182
        public String getType() {
183
            return TYPE;
×
184
        }
185

186
        @Override
187
        public String getDownloadUrl() {
188
            return downloadUrl;
×
189
        }
190

191
        @Override
192
        public boolean supportsPlatform(String platform) {
193
            return DockerPackager.this.supportsPlatform(platform);
×
194
        }
195

196
        @Override
197
        public boolean supportsDistribution(org.jreleaser.model.Distribution.DistributionType distributionType) {
198
            return DockerPackager.this.supportsDistribution(distributionType);
×
199
        }
200

201
        @Override
202
        public Set<String> getSupportedFileExtensions(org.jreleaser.model.Distribution.DistributionType distributionType) {
203
            return DockerPackager.this.getSupportedFileExtensions(distributionType);
×
204
        }
205

206
        @Override
207
        public Set<Stereotype> getSupportedStereotypes() {
208
            return DockerPackager.this.getSupportedStereotypes();
×
209
        }
210

211
        @Override
212
        public boolean isSnapshotSupported() {
213
            return DockerPackager.this.isSnapshotSupported();
×
214
        }
215

216
        @Override
217
        public boolean isContinueOnError() {
218
            return DockerPackager.this.isContinueOnError();
×
219
        }
220

221
        @Override
222
        public Active getActive() {
223
            return DockerPackager.this.getActive();
×
224
        }
225

226
        @Override
227
        public boolean isEnabled() {
228
            return DockerPackager.this.isEnabled();
×
229
        }
230

231
        @Override
232
        public Map<String, Object> asMap(boolean full) {
233
            return unmodifiableMap(DockerPackager.this.asMap(full));
×
234
        }
235

236
        @Override
237
        public String getPrefix() {
238
            return DockerPackager.this.prefix();
×
239
        }
240

241
        @Override
242
        public Buildx getBuildx() {
243
            return DockerPackager.this.getBuildx().asImmutable();
×
244
        }
245

246
        @Override
247
        public Map<String, Object> getExtraProperties() {
248
            return unmodifiableMap(DockerPackager.this.getExtraProperties());
×
249
        }
250
    };
251

252
    @JsonIgnore
253
    private boolean failed;
254

255
    @Override
256
    public org.jreleaser.model.api.packagers.DockerPackager asImmutable() {
UNCOV
257
        return immutable;
×
258
    }
259

260
    @Override
261
    public void merge(DockerPackager source) {
262
        super.merge(source);
1✔
263
        this.continueOnError = merge(this.continueOnError, source.continueOnError);
1✔
264
        this.downloadUrl = merge(this.downloadUrl, source.downloadUrl);
1✔
265
        this.failed = source.failed;
1✔
266
        setSpecs(mergeModel(this.specs, source.specs));
1✔
267
        setCommitAuthor(source.commitAuthor);
1✔
268
        setRepository(source.repository);
1✔
269
    }
1✔
270

271
    @Override
272
    public boolean resolveEnabled(Project project, Distribution distribution) {
273
        resolveEnabled(project);
×
274
        if (!supportsDistribution(distribution.getType())) {
×
275
            disable();
×
276
        }
277
        return isEnabled();
×
278
    }
279

280
    @Override
281
    public void fail() {
282
        this.failed = true;
×
283
    }
×
284

285
    @Override
286
    public boolean isFailed() {
UNCOV
287
        return failed;
×
288
    }
289

290
    @Override
291
    public boolean isContinueOnError() {
292
        return null != continueOnError && continueOnError;
1✔
293
    }
294

295
    @Override
296
    public void setContinueOnError(Boolean continueOnError) {
297
        this.continueOnError = continueOnError;
1✔
298
    }
1✔
299

300
    @Override
301
    public boolean isContinueOnErrorSet() {
302
        return null != continueOnError;
1✔
303
    }
304

305
    @Override
306
    public String getDownloadUrl() {
307
        return downloadUrl;
1✔
308
    }
309

310
    @Override
311
    public void setDownloadUrl(String downloadUrl) {
312
        this.downloadUrl = downloadUrl;
1✔
313
    }
1✔
314

315
    @Override
316
    public boolean supportsPlatform(String platform) {
317
        return isBlank(platform) || PlatformUtils.isUnix(platform);
1✔
318
    }
319

320
    @Override
321
    public boolean supportsDistribution(org.jreleaser.model.Distribution.DistributionType distributionType) {
322
        return SUPPORTED.containsKey(distributionType);
×
323
    }
324

325
    @Override
326
    public Set<String> getSupportedFileExtensions(org.jreleaser.model.Distribution.DistributionType distributionType) {
327
        return unmodifiableSet(SUPPORTED.getOrDefault(distributionType, emptySet()));
1✔
328
    }
329

330
    @Override
331
    public Set<Stereotype> getSupportedStereotypes() {
332
        return EnumSet.allOf(Stereotype.class);
×
333
    }
334

335
    @Override
336
    public List<Artifact> resolveCandidateArtifacts(JReleaserContext context, Distribution distribution) {
337
        if (distribution.getType() == FLAT_BINARY && supportsDistribution(distribution.getType())) {
1✔
338
            return distribution.getArtifacts().stream()
×
339
                .filter(Artifact::isActiveAndSelected)
×
340
                .filter(artifact -> supportsPlatform(artifact.getPlatform()))
×
341
                .filter(this::isNotSkipped)
×
342
                .sorted(Artifact.comparatorByPlatform())
×
343
                .collect(toList());
×
344
        }
345

346
        List<String> fileExtensions = new ArrayList<>(getSupportedFileExtensions(distribution.getType()));
1✔
347
        fileExtensions.sort(naturalOrder());
1✔
348

349
        return distribution.getArtifacts().stream()
1✔
350
            .filter(Artifact::isActiveAndSelected)
1✔
351
            .filter(artifact -> fileExtensions.stream().anyMatch(ext -> artifact.getResolvedPath(context, distribution).toString().endsWith(ext)))
1✔
352
            .filter(artifact -> supportsPlatform(artifact.getPlatform()))
1✔
353
            .filter(this::isNotSkipped)
1✔
354
            .sorted(Artifact.comparatorByPlatform().thenComparingInt(artifact -> {
1✔
355
                String ext = FileType.getExtension(artifact.getResolvedPath(context, distribution));
×
356
                return fileExtensions.indexOf(ext);
×
357
            }))
358
            .collect(toList());
1✔
359
    }
360

361
    @Override
362
    public List<Artifact> resolveArtifacts(JReleaserContext context, Distribution distribution) {
363
        return resolveCandidateArtifacts(context, distribution).stream()
×
364
            .filter(Artifact::resolvedPathExists)
×
365
            .collect(toList());
×
366
    }
367

368
    private boolean isNotSkipped(Artifact artifact) {
369
        return isFalse(artifact.getExtraProperties().get(SKIP_DOCKER));
1✔
370
    }
371

372
    @Override
373
    public boolean isSnapshotSupported() {
374
        return true;
×
375
    }
376

377
    @Override
378
    public String getType() {
379
        return TYPE;
1✔
380
    }
381

382
    @Override
383
    public CommitAuthor getCommitAuthor() {
384
        return commitAuthor;
1✔
385
    }
386

387
    @Override
388
    public void setCommitAuthor(CommitAuthor commitAuthor) {
389
        this.commitAuthor.merge(commitAuthor);
1✔
390
    }
1✔
391

392
    public List<DockerSpec> getActiveSpecs() {
UNCOV
393
        return specs.values().stream()
×
UNCOV
394
            .filter(DockerSpec::isEnabled)
×
UNCOV
395
            .collect(Collectors.toList());
×
396
    }
397

398
    public Map<String, DockerSpec> getSpecs() {
399
        return specs;
1✔
400
    }
401

402
    public void setSpecs(Map<String, DockerSpec> specs) {
403
        this.specs.clear();
1✔
404
        this.specs.putAll(specs);
1✔
405
    }
1✔
406

407
    public void addSpecs(Map<String, DockerSpec> specs) {
408
        this.specs.putAll(specs);
×
409
    }
×
410

411
    public void addSpec(DockerSpec spec) {
412
        this.specs.put(spec.getName(), spec);
×
413
    }
×
414

415
    @Override
416
    public Map<String, Object> asMap(boolean full) {
417
        if (!full && !isEnabled()) return Collections.emptyMap();
1✔
418

419
        Map<String, Object> map = new LinkedHashMap<>();
1✔
420
        map.put(getType(), super.asMap(full));
1✔
421
        return map;
1✔
422
    }
423

424
    @Override
425
    protected void asMap(boolean full, Map<String, Object> props) {
426
        props.put("commitAuthor", commitAuthor.asMap(full));
1✔
427
        props.put("repository", repository.asMap(full));
1✔
428
        props.put("downloadUrl", downloadUrl);
1✔
429
        props.put("continueOnError", isContinueOnError());
1✔
430
        List<Map<String, Object>> specs = this.specs.values()
1✔
431
            .stream()
1✔
432
            .filter(d -> full || d.isEnabled())
1✔
433
            .map(d -> d.asMap(full))
1✔
434
            .collect(Collectors.toList());
1✔
435
        if (!specs.isEmpty()) props.put("specs", specs);
1✔
436
    }
1✔
437

438
    public void setRepository(DockerRepository repository) {
439
        this.repository.merge(repository);
1✔
440
    }
1✔
441

442
    @Override
443
    public RepositoryTap getRepositoryTap() {
444
        return getPackagerRepository();
1✔
445
    }
446

447
    public DockerRepository getPackagerRepository() {
448
        return repository;
1✔
449
    }
450

451
    public static final class DockerRepository extends AbstractRepositoryTap<DockerRepository> implements Domain {
452
        private static final long serialVersionUID = 6677470182457638257L;
453

454
        private Boolean versionedSubfolders;
455

456
        @JsonIgnore
1✔
457
        private final org.jreleaser.model.api.packagers.DockerPackager.DockerRepository immutable = new org.jreleaser.model.api.packagers.DockerPackager.DockerRepository() {
1✔
458
            private static final long serialVersionUID = 1452104357672519L;
459

460
            @Override
461
            public boolean isVersionedSubfolders() {
462
                return DockerRepository.this.isVersionedSubfolders();
×
463
            }
464

465
            @Override
466
            public String getBasename() {
467
                return DockerRepository.this.getBasename();
×
468
            }
469

470
            @Override
471
            public String getCanonicalRepoName() {
472
                return DockerRepository.this.getCanonicalRepoName();
×
473
            }
474

475
            @Override
476
            public String getName() {
477
                return DockerRepository.this.getName();
×
478
            }
479

480
            @Override
481
            public String getTagName() {
482
                return DockerRepository.this.getTagName();
×
483
            }
484

485
            @Override
486
            public String getBranch() {
487
                return DockerRepository.this.getBranch();
×
488
            }
489

490
            @Override
491
            public String getBranchPush() {
492
                return DockerRepository.this.getBranchPush();
×
493
            }
494

495
            @Override
496
            public String getUsername() {
497
                return DockerRepository.this.getUsername();
×
498
            }
499

500
            @Override
501
            public String getToken() {
502
                return DockerRepository.this.getToken();
×
503
            }
504

505
            @Override
506
            public String getCommitMessage() {
507
                return DockerRepository.this.getCommitMessage();
×
508
            }
509

510
            @Override
511
            public Active getActive() {
512
                return DockerRepository.this.getActive();
×
513
            }
514

515
            @Override
516
            public boolean isEnabled() {
517
                return DockerRepository.this.isEnabled();
×
518
            }
519

520
            @Override
521
            public Map<String, Object> asMap(boolean full) {
522
                return unmodifiableMap(DockerRepository.this.asMap(full));
×
523
            }
524

525
            @Override
526
            public String getOwner() {
527
                return DockerRepository.this.getOwner();
×
528
            }
529

530
            @Override
531
            public String getPrefix() {
532
                return DockerRepository.this.prefix();
×
533
            }
534

535
            @Override
536
            public Map<String, Object> getExtraProperties() {
537
                return unmodifiableMap(DockerRepository.this.getExtraProperties());
×
538
            }
539
        };
540

541
        public DockerRepository() {
542
            super("docker", "docker");
1✔
543
        }
1✔
544

545
        public org.jreleaser.model.api.packagers.DockerPackager.DockerRepository asImmutable() {
546
            return immutable;
×
547
        }
548

549
        @Override
550
        public void merge(DockerRepository source) {
551
            super.merge(source);
1✔
552
            this.versionedSubfolders = this.merge(this.versionedSubfolders, source.versionedSubfolders);
1✔
553
        }
1✔
554

555
        @Override
556
        public String prefix() {
557
            return "repository";
×
558
        }
559

560
        public boolean isVersionedSubfolders() {
561
            return null != versionedSubfolders && versionedSubfolders;
1✔
562
        }
563

564
        public void setVersionedSubfolders(Boolean versionedSubfolders) {
565
            this.versionedSubfolders = versionedSubfolders;
1✔
566
        }
1✔
567

568
        public boolean isVersionedSubfoldersSet() {
569
            return null != versionedSubfolders;
1✔
570
        }
571

572
        @Override
573
        public Map<String, Object> asMap(boolean full) {
574
            Map<String, Object> map = super.asMap(full);
1✔
575
            map.put("versionedSubfolders", isVersionedSubfolders());
1✔
576
            return map;
1✔
577
        }
578
    }
579
}
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