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

jreleaser / jreleaser / #524

01 Aug 2025 02:16PM UTC coverage: 48.454% (-0.9%) from 49.315%
#524

push

github

aalmiray
fix(hooks): Inherit matrix and environment from named groups

Relates to #1947

56 of 125 new or added lines in 5 files covered. (44.8%)

450 existing lines in 37 files now uncovered.

25680 of 52999 relevant lines covered (48.45%)

0.48 hits per line

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

49.41
/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 = -3217813295313251223L;
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 String getEntrypoint() {
138
            return DockerPackager.this.getEntrypoint();
×
139
        }
140

141
        @Override
142
        public String getCmd() {
143
            return DockerPackager.this.getCmd();
×
144
        }
145

146
        @Override
147
        public Map<String, String> getLabels() {
148
            return unmodifiableMap(DockerPackager.this.getLabels());
×
149
        }
150

151
        @Override
152
        public Set<String> getImageNames() {
153
            return unmodifiableSet(DockerPackager.this.getImageNames());
×
154
        }
155

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

161
        @Override
162
        public List<String> getPreCommands() {
163
            return unmodifiableList(DockerPackager.this.getPreCommands());
×
164
        }
165

166
        @Override
167
        public List<String> getPostCommands() {
168
            return unmodifiableList(DockerPackager.this.getPostCommands());
×
169
        }
170

171
        @Override
172
        public Set<? extends org.jreleaser.model.api.packagers.DockerConfiguration.Registry> getRegistries() {
173
            if (null == registries) {
×
174
                registries = DockerPackager.this.getRegistries().stream()
×
175
                    .map(DockerConfiguration.Registry::asImmutable)
×
176
                    .collect(toSet());
×
177
            }
178
            return registries;
×
179
        }
180

181
        @Override
182
        public boolean isUseLocalArtifact() {
183
            return DockerPackager.this.isUseLocalArtifact();
×
184
        }
185

186
        @Override
187
        public org.jreleaser.model.api.packagers.PackagerRepository getPackagerRepository() {
188
            return getRepository();
×
189
        }
190

191
        @Override
192
        public String getType() {
193
            return TYPE;
×
194
        }
195

196
        @Override
197
        public String getDownloadUrl() {
198
            return downloadUrl;
×
199
        }
200

201
        @Override
202
        public boolean supportsPlatform(String platform) {
203
            return DockerPackager.this.supportsPlatform(platform);
×
204
        }
205

206
        @Override
207
        public boolean supportsDistribution(org.jreleaser.model.Distribution.DistributionType distributionType) {
208
            return DockerPackager.this.supportsDistribution(distributionType);
×
209
        }
210

211
        @Override
212
        public Set<String> getSupportedFileExtensions(org.jreleaser.model.Distribution.DistributionType distributionType) {
213
            return DockerPackager.this.getSupportedFileExtensions(distributionType);
×
214
        }
215

216
        @Override
217
        public Set<Stereotype> getSupportedStereotypes() {
218
            return DockerPackager.this.getSupportedStereotypes();
×
219
        }
220

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

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

231
        @Override
232
        public Active getActive() {
233
            return DockerPackager.this.getActive();
×
234
        }
235

236
        @Override
237
        public boolean isEnabled() {
238
            return DockerPackager.this.isEnabled();
×
239
        }
240

241
        @Override
242
        public Map<String, Object> asMap(boolean full) {
243
            return unmodifiableMap(DockerPackager.this.asMap(full));
×
244
        }
245

246
        @Override
247
        public String getPrefix() {
248
            return DockerPackager.this.prefix();
×
249
        }
250

251
        @Override
252
        public Buildx getBuildx() {
253
            return DockerPackager.this.getBuildx().asImmutable();
×
254
        }
255

256
        @Override
257
        public Map<String, Object> getExtraProperties() {
258
            return unmodifiableMap(DockerPackager.this.getExtraProperties());
×
259
        }
260
    };
261

262
    @JsonIgnore
263
    private boolean failed;
264

265
    @Override
266
    public org.jreleaser.model.api.packagers.DockerPackager asImmutable() {
UNCOV
267
        return immutable;
×
268
    }
269

270
    @Override
271
    public void merge(DockerPackager source) {
272
        super.merge(source);
1✔
273
        this.continueOnError = merge(this.continueOnError, source.continueOnError);
1✔
274
        this.downloadUrl = merge(this.downloadUrl, source.downloadUrl);
1✔
275
        this.failed = source.failed;
1✔
276
        setSpecs(mergeModel(this.specs, source.specs));
1✔
277
        setCommitAuthor(source.commitAuthor);
1✔
278
        setRepository(source.repository);
1✔
279
    }
1✔
280

281
    @Override
282
    public boolean resolveEnabled(Project project, Distribution distribution) {
283
        resolveEnabled(project);
×
284
        if (!supportsDistribution(distribution.getType())) {
×
285
            disable();
×
286
        }
287
        return isEnabled();
×
288
    }
289

290
    @Override
291
    public void fail() {
292
        this.failed = true;
×
293
    }
×
294

295
    @Override
296
    public boolean isFailed() {
UNCOV
297
        return failed;
×
298
    }
299

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

305
    @Override
306
    public void setContinueOnError(Boolean continueOnError) {
307
        this.continueOnError = continueOnError;
1✔
308
    }
1✔
309

310
    @Override
311
    public boolean isContinueOnErrorSet() {
312
        return null != continueOnError;
1✔
313
    }
314

315
    @Override
316
    public String getDownloadUrl() {
317
        return downloadUrl;
1✔
318
    }
319

320
    @Override
321
    public void setDownloadUrl(String downloadUrl) {
322
        this.downloadUrl = downloadUrl;
1✔
323
    }
1✔
324

325
    @Override
326
    public boolean supportsPlatform(String platform) {
327
        return isBlank(platform) || PlatformUtils.isUnix(platform);
1✔
328
    }
329

330
    @Override
331
    public boolean supportsDistribution(org.jreleaser.model.Distribution.DistributionType distributionType) {
332
        return SUPPORTED.containsKey(distributionType);
×
333
    }
334

335
    @Override
336
    public Set<String> getSupportedFileExtensions(org.jreleaser.model.Distribution.DistributionType distributionType) {
337
        return unmodifiableSet(SUPPORTED.getOrDefault(distributionType, emptySet()));
1✔
338
    }
339

340
    @Override
341
    public Set<Stereotype> getSupportedStereotypes() {
342
        return EnumSet.allOf(Stereotype.class);
×
343
    }
344

345
    @Override
346
    public List<Artifact> resolveCandidateArtifacts(JReleaserContext context, Distribution distribution) {
347
        if (distribution.getType() == FLAT_BINARY && supportsDistribution(distribution.getType())) {
1✔
348
            return distribution.getArtifacts().stream()
×
349
                .filter(Artifact::isActiveAndSelected)
×
350
                .filter(artifact -> supportsPlatform(artifact.getPlatform()))
×
351
                .filter(this::isNotSkipped)
×
352
                .sorted(Artifact.comparatorByPlatform())
×
353
                .collect(toList());
×
354
        }
355

356
        List<String> fileExtensions = new ArrayList<>(getSupportedFileExtensions(distribution.getType()));
1✔
357
        fileExtensions.sort(naturalOrder());
1✔
358

359
        return distribution.getArtifacts().stream()
1✔
360
            .filter(Artifact::isActiveAndSelected)
1✔
361
            .filter(artifact -> fileExtensions.stream().anyMatch(ext -> artifact.getResolvedPath(context, distribution).toString().endsWith(ext)))
1✔
362
            .filter(artifact -> supportsPlatform(artifact.getPlatform()))
1✔
363
            .filter(this::isNotSkipped)
1✔
364
            .sorted(Artifact.comparatorByPlatform().thenComparingInt(artifact -> {
1✔
365
                String ext = FileType.getExtension(artifact.getResolvedPath(context, distribution));
×
366
                return fileExtensions.indexOf(ext);
×
367
            }))
368
            .collect(toList());
1✔
369
    }
370

371
    @Override
372
    public List<Artifact> resolveArtifacts(JReleaserContext context, Distribution distribution) {
373
        return resolveCandidateArtifacts(context, distribution).stream()
×
374
            .filter(Artifact::resolvedPathExists)
×
375
            .collect(toList());
×
376
    }
377

378
    private boolean isNotSkipped(Artifact artifact) {
379
        return isFalse(artifact.getExtraProperties().get(SKIP_DOCKER));
1✔
380
    }
381

382
    @Override
383
    public boolean isSnapshotSupported() {
384
        return true;
×
385
    }
386

387
    @Override
388
    public String getType() {
389
        return TYPE;
1✔
390
    }
391

392
    @Override
393
    public CommitAuthor getCommitAuthor() {
394
        return commitAuthor;
1✔
395
    }
396

397
    @Override
398
    public void setCommitAuthor(CommitAuthor commitAuthor) {
399
        this.commitAuthor.merge(commitAuthor);
1✔
400
    }
1✔
401

402
    public List<DockerSpec> getActiveSpecs() {
UNCOV
403
        return specs.values().stream()
×
UNCOV
404
            .filter(DockerSpec::isEnabled)
×
UNCOV
405
            .collect(Collectors.toList());
×
406
    }
407

408
    public Map<String, DockerSpec> getSpecs() {
409
        return specs;
1✔
410
    }
411

412
    public void setSpecs(Map<String, DockerSpec> specs) {
413
        this.specs.clear();
1✔
414
        this.specs.putAll(specs);
1✔
415
    }
1✔
416

417
    public void addSpecs(Map<String, DockerSpec> specs) {
418
        this.specs.putAll(specs);
×
419
    }
×
420

421
    public void addSpec(DockerSpec spec) {
422
        this.specs.put(spec.getName(), spec);
×
423
    }
×
424

425
    @Override
426
    public Map<String, Object> asMap(boolean full) {
427
        if (!full && !isEnabled()) return Collections.emptyMap();
1✔
428

429
        Map<String, Object> map = new LinkedHashMap<>();
1✔
430
        map.put(getType(), super.asMap(full));
1✔
431
        return map;
1✔
432
    }
433

434
    @Override
435
    protected void asMap(boolean full, Map<String, Object> props) {
436
        props.put("commitAuthor", commitAuthor.asMap(full));
1✔
437
        props.put("repository", repository.asMap(full));
1✔
438
        props.put("downloadUrl", downloadUrl);
1✔
439
        props.put("continueOnError", isContinueOnError());
1✔
440
        List<Map<String, Object>> specs = this.specs.values()
1✔
441
            .stream()
1✔
442
            .filter(d -> full || d.isEnabled())
1✔
443
            .map(d -> d.asMap(full))
1✔
444
            .collect(Collectors.toList());
1✔
445
        if (!specs.isEmpty()) props.put("specs", specs);
1✔
446
    }
1✔
447

448
    public void setRepository(DockerRepository repository) {
449
        this.repository.merge(repository);
1✔
450
    }
1✔
451

452
    @Override
453
    public RepositoryTap getRepositoryTap() {
454
        return getPackagerRepository();
1✔
455
    }
456

457
    public DockerRepository getPackagerRepository() {
458
        return repository;
1✔
459
    }
460

461
    public static final class DockerRepository extends AbstractRepositoryTap<DockerRepository> implements Domain {
462
        private static final long serialVersionUID = 6677470182457638257L;
463

464
        private Boolean versionedSubfolders;
465

466
        @JsonIgnore
1✔
467
        private final org.jreleaser.model.api.packagers.DockerPackager.DockerRepository immutable = new org.jreleaser.model.api.packagers.DockerPackager.DockerRepository() {
1✔
468
            private static final long serialVersionUID = 1452104357672519L;
469

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

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

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

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

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

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

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

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

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

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

520
            @Override
521
            public Active getActive() {
522
                return DockerRepository.this.getActive();
×
523
            }
524

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

530
            @Override
531
            public Map<String, Object> asMap(boolean full) {
532
                return unmodifiableMap(DockerRepository.this.asMap(full));
×
533
            }
534

535
            @Override
536
            public String getOwner() {
537
                return DockerRepository.this.getOwner();
×
538
            }
539

540
            @Override
541
            public String getPrefix() {
542
                return DockerRepository.this.prefix();
×
543
            }
544

545
            @Override
546
            public Map<String, Object> getExtraProperties() {
547
                return unmodifiableMap(DockerRepository.this.getExtraProperties());
×
548
            }
549
        };
550

551
        public DockerRepository() {
552
            super("docker", "docker");
1✔
553
        }
1✔
554

555
        public org.jreleaser.model.api.packagers.DockerPackager.DockerRepository asImmutable() {
UNCOV
556
            return immutable;
×
557
        }
558

559
        @Override
560
        public void merge(DockerRepository source) {
561
            super.merge(source);
1✔
562
            this.versionedSubfolders = this.merge(this.versionedSubfolders, source.versionedSubfolders);
1✔
563
        }
1✔
564

565
        @Override
566
        public String prefix() {
567
            return "repository";
×
568
        }
569

570
        public boolean isVersionedSubfolders() {
571
            return null != versionedSubfolders && versionedSubfolders;
1✔
572
        }
573

574
        public void setVersionedSubfolders(Boolean versionedSubfolders) {
575
            this.versionedSubfolders = versionedSubfolders;
1✔
576
        }
1✔
577

578
        public boolean isVersionedSubfoldersSet() {
579
            return null != versionedSubfolders;
1✔
580
        }
581

582
        @Override
583
        public Map<String, Object> asMap(boolean full) {
584
            Map<String, Object> map = super.asMap(full);
1✔
585
            map.put("versionedSubfolders", isVersionedSubfolders());
1✔
586
            return map;
1✔
587
        }
588
    }
589
}
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