• 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

0.59
/core/jreleaser-engine/src/main/java/org/jreleaser/packagers/DockerPackagerProcessor.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.packagers;
19

20
import org.jreleaser.bundle.RB;
21
import org.jreleaser.model.internal.JReleaserContext;
22
import org.jreleaser.model.internal.common.AbstractActivatable;
23
import org.jreleaser.model.internal.common.Artifact;
24
import org.jreleaser.model.internal.distributions.Distribution;
25
import org.jreleaser.model.internal.packagers.DockerConfiguration;
26
import org.jreleaser.model.internal.packagers.DockerPackager;
27
import org.jreleaser.model.internal.packagers.DockerSpec;
28
import org.jreleaser.model.spi.packagers.PackagerProcessingException;
29
import org.jreleaser.mustache.TemplateContext;
30
import org.jreleaser.sdk.command.Command;
31
import org.jreleaser.util.FileUtils;
32
import org.jreleaser.util.PlatformUtils;
33

34
import java.io.ByteArrayInputStream;
35
import java.io.File;
36
import java.io.IOException;
37
import java.nio.file.Files;
38
import java.nio.file.Path;
39
import java.util.ArrayList;
40
import java.util.LinkedHashMap;
41
import java.util.LinkedHashSet;
42
import java.util.List;
43
import java.util.Locale;
44
import java.util.Map;
45
import java.util.Set;
46

47
import static java.nio.charset.StandardCharsets.UTF_8;
48
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
49
import static java.util.Collections.singletonList;
50
import static java.util.stream.Collectors.toList;
51
import static java.util.stream.Collectors.toSet;
52
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_JAVA_MAIN_CLASS;
53
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_JAVA_MAIN_MODULE;
54
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_PACKAGE_DIRECTORY;
55
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_PREPARE_DIRECTORY;
56
import static org.jreleaser.model.Constants.KEY_DOCKER_BASE_IMAGE;
57
import static org.jreleaser.model.Constants.KEY_DOCKER_CMD;
58
import static org.jreleaser.model.Constants.KEY_DOCKER_ENTRYPOINT;
59
import static org.jreleaser.model.Constants.KEY_DOCKER_LABELS;
60
import static org.jreleaser.model.Constants.KEY_DOCKER_POST_COMMANDS;
61
import static org.jreleaser.model.Constants.KEY_DOCKER_PRE_COMMANDS;
62
import static org.jreleaser.model.Constants.KEY_DOCKER_SPEC_NAME;
63
import static org.jreleaser.mustache.MustacheUtils.passThrough;
64
import static org.jreleaser.mustache.Templates.resolveTemplate;
65
import static org.jreleaser.templates.TemplateUtils.trimTplExtension;
66
import static org.jreleaser.util.StringUtils.isNotBlank;
67

68
/**
69
 * @author Andres Almiray
70
 * @since 0.1.0
71
 */
72
public class DockerPackagerProcessor extends AbstractRepositoryPackagerProcessor<DockerPackager> {
73
    private static final String ROOT = "ROOT";
74

75
    public DockerPackagerProcessor(JReleaserContext context) {
76
        super(context);
1✔
77
    }
1✔
78

79
    @Override
80
    protected void doPrepareDistribution(Distribution distribution,
81
                                         TemplateContext props,
82
                                         String distributionName,
83
                                         Path prepareDirectory,
84
                                         String templateDirectory,
85
                                         String packagerName,
86
                                         boolean copyLicense) throws IOException, PackagerProcessingException {
UNCOV
87
        if (packager.getActiveSpecs().isEmpty()) {
×
88
            super.doPrepareDistribution(distribution, props, distributionName,
×
89
                prepareDirectory, templateDirectory, packagerName, true);
90

91
            if (!packager.isUseLocalArtifact()) {
×
92
                Files.move(prepareDirectory.resolve("Dockerfile-remote"),
×
93
                    prepareDirectory.resolve("Dockerfile"),
×
94
                    REPLACE_EXISTING);
95
            } else {
96
                Files.deleteIfExists(prepareDirectory.resolve("Dockerfile-remote"));
×
97
            }
98

99
            return;
×
100
        }
101

102
        // copy root files
UNCOV
103
        String rootTemplateDirectory = getPackager().getTemplateDirectory() + File.separator + ROOT;
×
UNCOV
104
        super.doPrepareDistribution(distribution, props, distributionName,
×
UNCOV
105
            prepareDirectory.resolve(ROOT),
×
106
            rootTemplateDirectory,
UNCOV
107
            packager.getType(),
×
108
            false);
UNCOV
109
        Files.deleteIfExists(prepareDirectory.resolve(ROOT).resolve("Dockerfile"));
×
UNCOV
110
        Files.deleteIfExists(prepareDirectory.resolve(ROOT).resolve("Dockerfile-remote"));
×
111

UNCOV
112
        for (DockerSpec spec : packager.getActiveSpecs()) {
×
UNCOV
113
            prepareSpec(distribution, props, distributionName, prepareDirectory, spec);
×
UNCOV
114
        }
×
UNCOV
115
    }
×
116

117
    private void prepareSpec(Distribution distribution,
118
                             TemplateContext props,
119
                             String distributionName,
120
                             Path prepareDirectory,
121
                             DockerSpec spec) throws IOException, PackagerProcessingException {
UNCOV
122
        TemplateContext newProps = fillSpecProps(distribution, props, spec);
×
UNCOV
123
        context.getLogger().debug(RB.$("distributions.action.preparing") + " {} spec", spec.getName());
×
UNCOV
124
        super.doPrepareDistribution(distribution, newProps, distributionName,
×
UNCOV
125
            prepareDirectory.resolve(spec.getName()),
×
UNCOV
126
            spec.getTemplateDirectory(),
×
UNCOV
127
            spec.getName() + "/" + packager.getType(),
×
128
            false);
129

UNCOV
130
        if (!spec.isUseLocalArtifact()) {
×
131
            Files.move(prepareDirectory.resolve(spec.getName()).resolve("Dockerfile-remote"),
×
132
                prepareDirectory.resolve(spec.getName()).resolve("Dockerfile"),
×
133
                REPLACE_EXISTING);
134
        } else {
UNCOV
135
            Files.deleteIfExists(prepareDirectory.resolve(spec.getName()).resolve("Dockerfile-remote"));
×
136
        }
UNCOV
137
    }
×
138

139
    private TemplateContext fillSpecProps(Distribution distribution, TemplateContext props, DockerSpec spec) {
UNCOV
140
        List<Artifact> artifacts = singletonList(spec.getArtifact());
×
UNCOV
141
        TemplateContext newProps = fillProps(distribution, props);
×
UNCOV
142
        newProps.set(KEY_DOCKER_SPEC_NAME, spec.getName());
×
UNCOV
143
        fillDockerProperties(newProps, spec);
×
UNCOV
144
        verifyAndAddArtifacts(newProps, distribution, artifacts);
×
UNCOV
145
        newProps.set(KEY_DOCKER_ENTRYPOINT, passThrough(resolveTemplate(spec.getEntrypoint(), newProps)));
×
UNCOV
146
        newProps.set(KEY_DOCKER_CMD, passThrough(resolveTemplate(spec.getCmd(), newProps)));
×
UNCOV
147
        Path prepareDirectory = newProps.get(KEY_DISTRIBUTION_PREPARE_DIRECTORY);
×
UNCOV
148
        newProps.set(KEY_DISTRIBUTION_PREPARE_DIRECTORY, prepareDirectory.resolve(spec.getName()));
×
UNCOV
149
        Path packageDirectory = newProps.get(KEY_DISTRIBUTION_PACKAGE_DIRECTORY);
×
UNCOV
150
        newProps.set(KEY_DISTRIBUTION_PACKAGE_DIRECTORY, packageDirectory.resolve(spec.getName()));
×
UNCOV
151
        return newProps;
×
152
    }
153

154
    @Override
155
    protected boolean verifyAndAddArtifacts(TemplateContext props, Distribution distribution) {
UNCOV
156
        if (packager.getActiveSpecs().isEmpty()) {
×
157
            return super.verifyAndAddArtifacts(props, distribution);
×
158
        }
UNCOV
159
        return true;
×
160
    }
161

162
    @Override
163
    protected void doPackageDistribution(Distribution distribution,
164
                                         TemplateContext props,
165
                                         Path packageDirectory) throws PackagerProcessingException {
UNCOV
166
        if (packager.getActiveSpecs().isEmpty()) {
×
167
            List<Artifact> artifacts = packager.resolveArtifacts(context, distribution);
×
168
            packageDocker(distribution, props, packageDirectory, getPackager(), artifacts);
×
169
            return;
×
170
        }
171

UNCOV
172
        Path rootPrepareDirectory = getPrepareDirectory(props).resolve(ROOT);
×
UNCOV
173
        Path rootPackageDirectory = getPackageDirectory(props).resolve(ROOT);
×
UNCOV
174
        copyFiles(rootPrepareDirectory, rootPackageDirectory);
×
175

UNCOV
176
        for (DockerSpec spec : packager.getActiveSpecs()) {
×
UNCOV
177
            context.getLogger().debug(RB.$("distributions.action.packaging") + " {} spec", spec.getName());
×
UNCOV
178
            TemplateContext newProps = fillSpecProps(distribution, props, spec);
×
UNCOV
179
            packageDocker(distribution, newProps, packageDirectory.resolve(spec.getName()),
×
UNCOV
180
                spec, singletonList(spec.getArtifact()));
×
UNCOV
181
        }
×
UNCOV
182
    }
×
183

184
    protected void packageDocker(Distribution distribution,
185
                                 TemplateContext props,
186
                                 Path packageDirectory,
187
                                 DockerConfiguration docker,
188
                                 List<Artifact> artifacts) throws PackagerProcessingException {
UNCOV
189
        super.doPackageDistribution(distribution, props, packageDirectory);
×
190

191
        try {
192
            // copy files
UNCOV
193
            Path workingDirectory = prepareAssembly(distribution, props, packageDirectory, artifacts);
×
194

UNCOV
195
            Map<String, List<String>> tagNames = resolveTagNames(docker, props);
×
UNCOV
196
            List<String> tags = tagNames.values().stream()
×
UNCOV
197
                .flatMap(List::stream)
×
UNCOV
198
                .collect(toList());
×
199

UNCOV
200
            tags.forEach(tag -> context.getLogger().info(" - {}", tag));
×
201

UNCOV
202
            if (docker.getBuildx().isEnabled()) {
×
203
                // create builder if needed
204
                createBuildxBuilder(props, docker);
×
205
                configureAndExecuteBuildCommand(buildxBuildCommand(props, docker), workingDirectory, tags);
×
206
            } else {
UNCOV
207
                configureAndExecuteBuildCommand(buildCommand(props, docker), workingDirectory, tags);
×
208
            }
209
        } catch (IOException e) {
×
210
            throw new PackagerProcessingException(e);
×
UNCOV
211
        }
×
UNCOV
212
    }
×
213

214
    private void configureAndExecuteBuildCommand(Command cmd, Path workingDirectory, List<String> tags) throws PackagerProcessingException {
UNCOV
215
        if (!cmd.hasArg("-q") && !cmd.hasArg("--quiet")) {
×
UNCOV
216
            cmd.arg("--quiet");
×
217
        }
UNCOV
218
        cmd.arg("--file");
×
UNCOV
219
        cmd.arg(workingDirectory.resolve("Dockerfile").toAbsolutePath().toString());
×
UNCOV
220
        for (String tag : tags) {
×
UNCOV
221
            cmd.arg("--tag");
×
UNCOV
222
            cmd.arg(tag);
×
UNCOV
223
        }
×
UNCOV
224
        cmd.arg(workingDirectory.toAbsolutePath().toString());
×
UNCOV
225
        context.getLogger().debug(String.join(" ", cmd.getArgs()));
×
226

227
        // execute
UNCOV
228
        executeCommand(cmd);
×
UNCOV
229
    }
×
230

231
    private void createBuildxBuilder(TemplateContext props, DockerConfiguration docker) throws PackagerProcessingException {
232
        if (!docker.getBuildx().isCreateBuilder()) return;
×
233

234
        Command cmd = new Command("docker" + (PlatformUtils.isWindows() ? ".exe" : ""))
×
235
            .arg("buildx")
×
236
            .arg("ls");
×
237
        Command.Result result = executeCommand(cmd);
×
238
        if (result.getOut().contains("jreleaser")) return;
×
239

240
        cmd = buildxCreateCommand(props, docker);
×
241
        context.getLogger().debug(String.join(" ", cmd.getArgs()));
×
242
        executeCommand(cmd);
×
243
    }
×
244

245
    private Path prepareAssembly(Distribution distribution,
246
                                 TemplateContext props,
247
                                 Path packageDirectory,
248
                                 List<Artifact> artifacts) throws IOException, PackagerProcessingException {
UNCOV
249
        copyPreparedFiles(props);
×
UNCOV
250
        Path assemblyDirectory = packageDirectory.resolve("assembly");
×
251

UNCOV
252
        Files.createDirectories(assemblyDirectory);
×
253

UNCOV
254
        for (Artifact artifact : artifacts) {
×
UNCOV
255
            Path artifactPath = artifact.getEffectivePath(context, distribution);
×
UNCOV
256
            if (distribution.getType() == org.jreleaser.model.Distribution.DistributionType.BINARY) {
×
257
                if (artifactPath.toString().endsWith(".zip")) {
×
258
                    FileUtils.unpackArchive(artifactPath, assemblyDirectory);
×
259
                } else {
260
                    Files.copy(artifactPath, assemblyDirectory.resolve(artifactPath.getFileName()), REPLACE_EXISTING);
×
261
                }
262
            } else {
UNCOV
263
                Files.copy(artifactPath, assemblyDirectory.resolve(artifactPath.getFileName()), REPLACE_EXISTING);
×
264
            }
UNCOV
265
        }
×
266

UNCOV
267
        return packageDirectory;
×
268
    }
269

270
    private Command buildCommand(TemplateContext props, DockerConfiguration docker) {
UNCOV
271
        Command cmd = createCommand(docker, "build");
×
UNCOV
272
        for (int i = 0; i < docker.getBuildArgs().size(); i++) {
×
273
            String arg = docker.getBuildArgs().get(i);
×
274
            if (arg.contains("{{")) {
×
275
                cmd.arg(resolveTemplate(arg, props).trim());
×
276
            } else {
277
                cmd.arg(arg.trim());
×
278
            }
279
        }
UNCOV
280
        return cmd;
×
281
    }
282

283
    private Command buildxBuildCommand(TemplateContext props, DockerConfiguration docker) {
284
        Command cmd = createCommand(docker, "buildx");
×
285
        cmd.arg("build");
×
286

287
        List<String> platforms = new ArrayList<>();
×
288
        for (int i = 0; i < docker.getBuildx().getPlatforms().size(); i++) {
×
289
            String arg = docker.getBuildx().getPlatforms().get(i);
×
290
            if (arg.contains("{{")) {
×
291
                platforms.add(resolveTemplate(arg, props).trim());
×
292
            } else {
293
                platforms.add(arg.trim());
×
294
            }
295
        }
296
        cmd.arg("--platform")
×
297
            .arg(String.join(",", platforms));
×
298

299
        for (int i = 0; i < docker.getBuildArgs().size(); i++) {
×
300
            String arg = docker.getBuildArgs().get(i);
×
301
            if (arg.contains("{{")) {
×
302
                cmd.arg(resolveTemplate(arg, props).trim());
×
303
            } else {
304
                cmd.arg(arg.trim());
×
305
            }
306
        }
307
        return cmd;
×
308
    }
309

310
    private Command buildxCreateCommand(TemplateContext props, DockerConfiguration docker) {
311
        Command cmd = createCommand(docker, "buildx");
×
312
        cmd.arg("create");
×
313
        for (int i = 0; i < docker.getBuildx().getCreateBuilderFlags().size(); i++) {
×
314
            String arg = docker.getBuildx().getCreateBuilderFlags().get(i);
×
315
            if (arg.contains("{{")) {
×
316
                cmd.arg(resolveTemplate(arg, props).trim());
×
317
            } else {
318
                cmd.arg(arg.trim());
×
319
            }
320
        }
321
        return cmd;
×
322
    }
323

324
    private Command createCommand(DockerConfiguration docker, String name) {
UNCOV
325
        return new Command(docker.getCommand().formatted() + (PlatformUtils.isWindows() ? ".exe" : ""))
×
UNCOV
326
            .arg("--log-level")
×
UNCOV
327
            .arg("error")
×
UNCOV
328
            .arg(name);
×
329
    }
330

331
    @Override
332
    public void publishDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
333
        if (packager.getActiveSpecs().isEmpty()) {
×
334
            publishToRepository(distribution, props);
×
335
            super.publishDistribution(distribution, props);
×
336
            cleanupBuilder(props, getPackager());
×
337
            return;
×
338
        }
339

340
        publishToRepository(distribution, props);
×
341
        for (DockerSpec spec : packager.getActiveSpecs()) {
×
342
            context.getLogger().info(RB.$("distributions.action.publishing") + " {} spec", spec.getName());
×
343
            TemplateContext newProps = fillSpecProps(distribution, props, spec);
×
344
            publishDocker(newProps, spec);
×
345
        }
×
346
        cleanupBuilder(props, packager.getActiveSpecs());
×
347
    }
×
348

349
    private void publishToRepository(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
350
        super.doPublishDistribution(distribution, fillProps(distribution, props));
×
351
    }
×
352

353
    @Override
354
    protected void doPublishDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
355
        context.getLogger().info(RB.$("distributions.action.publishing") + " {}", distribution.getName());
×
356
        publishDocker(props, getPackager());
×
357
    }
×
358

359
    protected void publishDocker(TemplateContext props, DockerConfiguration docker) throws PackagerProcessingException {
360
        Map<String, List<String>> tagNames = resolveTagNames(docker, props);
×
361

362
        if (context.isDryrun()) {
×
363
            Set<String> uniqueImageNames = new LinkedHashSet<>();
×
364
            tagNames.values().forEach(uniqueImageNames::addAll);
×
365
            for (String imageName : uniqueImageNames) {
×
366
                context.getLogger().info(" - {}", imageName);
×
367
            }
×
368
            return;
×
369
        }
370

371
        for (DockerConfiguration.Registry registry : docker.getRegistries()) {
×
372
            if (registry.isEnabled()) {
×
373
                login(docker, registry);
×
374
            } else {
375
                context.getLogger().info(RB.$("docker.publish.disabled"), registry.getServerName(), registry.getRepositoryName());
×
376
            }
377
        }
×
378

379
        boolean activeRegistries = docker.getRegistries().stream().anyMatch(AbstractActivatable::isEnabled);
×
380

381
        if (activeRegistries) {
×
382
            if (docker.getBuildx().isEnabled()) {
×
383
                Path workingDirectory = props.get(KEY_DISTRIBUTION_PACKAGE_DIRECTORY);
×
384
                List<String> tags = tagNames.values().stream()
×
385
                    .flatMap(List::stream)
×
386
                    .collect(toList());
×
387

388
                // command line
389
                Command cmd = buildxBuildCommand(props, docker);
×
390
                if (!cmd.hasArg("-q") && !cmd.hasArg("--quiet")) {
×
391
                    cmd.arg("--quiet");
×
392
                }
393
                cmd.arg("--file");
×
394
                cmd.arg(workingDirectory.resolve("Dockerfile").toAbsolutePath().toString());
×
395
                for (String tag : tags) {
×
396
                    cmd.arg("--tag");
×
397
                    cmd.arg(tag);
×
398
                }
×
399
                cmd.arg("--push");
×
400
                cmd.arg(workingDirectory.toAbsolutePath().toString());
×
401
                context.getLogger().debug(String.join(" ", cmd.getArgs()));
×
402

403
                // execute
404
                executeCommand(cmd);
×
405
            } else {
×
406
                for (Map.Entry<String, List<String>> e : tagNames.entrySet()) {
×
407
                    Set<String> uniqueImageNames = e.getValue().stream()
×
408
                        .map(tag -> tag.split(":")[0])
×
409
                        .collect(toSet());
×
410
                    for (String imageName : uniqueImageNames) {
×
411
                        push(docker, e.getKey(), imageName);
×
412
                    }
×
413
                }
×
414
            }
415
        }
416

417
        for (DockerConfiguration.Registry registry : docker.getRegistries()) {
×
418
            if (registry.isEnabled()) logout(docker, registry);
×
419
        }
×
420
    }
×
421

422
    private void cleanupBuilder(TemplateContext props, DockerConfiguration docker) throws PackagerProcessingException {
423
        if (docker.getBuildx().isEnabled() && docker.getBuildx().isCreateBuilder()) {
×
424
            int i = docker.getBuildx().getCreateBuilderFlags().indexOf("--name");
×
425
            String builderName = docker.getBuildx().getCreateBuilderFlags().get(i + 1);
×
426
            Command cmd = createCommand(docker, "buildx")
×
427
                .arg("rm")
×
428
                .arg(resolveTemplate(builderName, props).trim());
×
429

430
            executeCommand(cmd);
×
431
        }
432
    }
×
433

434
    private void cleanupBuilder(TemplateContext props, List<DockerSpec> specs) throws PackagerProcessingException {
435
        Set<String> builderNames = new LinkedHashSet<>();
×
436
        for (DockerSpec spec : specs) {
×
437
            if (spec.getBuildx().isEnabled() && spec.getBuildx().isCreateBuilder()) {
×
438
                int i = spec.getBuildx().getCreateBuilderFlags().indexOf("--name");
×
439
                builderNames.add(spec.getBuildx().getCreateBuilderFlags().get(i + 1));
×
440
            }
441
        }
×
442

443
        for (String builderName : builderNames) {
×
444
            Command cmd = createCommand(packager, "buildx")
×
445
                .arg("rm")
×
446
                .arg(resolveTemplate(builderName, props).trim());
×
447

448
            executeCommand(cmd);
×
449
        }
×
450
    }
×
451

452
    private void login(DockerConfiguration docker, DockerConfiguration.Registry registry) throws PackagerProcessingException {
453
        if (registry.isExternalLogin()) return;
×
454

455
        Command cmd = createCommand(docker, "login");
×
456
        if (isNotBlank(registry.getServer())) {
×
457
            cmd.arg(registry.getServer());
×
458
        }
459
        cmd.arg("-u");
×
460
        cmd.arg(registry.getUsername());
×
461
        cmd.arg("-p");
×
462
        cmd.arg(registry.getPassword());
×
463

464
        ByteArrayInputStream in = new ByteArrayInputStream((registry.getPassword() + System.lineSeparator()).getBytes(UTF_8));
×
465

466
        context.getLogger().debug(RB.$("docker.login"),
×
467
            registry.getServerName(),
×
468
            isNotBlank(registry.getServer()) ? " (" + registry.getServer() + ")" : "");
×
469
        if (!context.isDryrun()) executeCommand(cmd, in);
×
470
    }
×
471

472
    private Map<String, List<String>> resolveTagNames(DockerConfiguration docker, TemplateContext props) {
UNCOV
473
        Map<String, List<String>> tags = new LinkedHashMap<>();
×
474

UNCOV
475
        for (DockerConfiguration.Registry registry : docker.getRegistries()) {
×
UNCOV
476
            for (String imageName : docker.getImageNames()) {
×
UNCOV
477
                imageName = resolveTemplate(imageName, props).toLowerCase(Locale.ENGLISH);
×
478

UNCOV
479
                String tag = imageName;
×
UNCOV
480
                String serverName = registry.getServerName();
×
UNCOV
481
                String server = registry.getServer();
×
UNCOV
482
                String repositoryName = registry.getRepositoryName();
×
483

484
                // if serverName == DEFAULT
485
                //   tag: docker.io/repositoryName/imageName
486
                // else
487
                //   tag: server/repositoryName/imageName
488

UNCOV
489
                if (DockerConfiguration.Registry.DEFAULT_NAME.equals(serverName)) {
×
UNCOV
490
                    if (!tag.startsWith(repositoryName)) {
×
UNCOV
491
                        int pos = tag.indexOf("/");
×
UNCOV
492
                        if (pos < 0) {
×
493
                            tag = server + "/" + repositoryName + "/" + tag;
×
494
                        } else {
UNCOV
495
                            tag = server + "/" + repositoryName + tag.substring(pos);
×
496
                        }
UNCOV
497
                    }
×
498
                } else {
499
                    if (!tag.startsWith(server)) {
×
500
                        int pos = tag.indexOf("/");
×
501
                        if (pos < 0) {
×
502
                            tag = server + "/" + repositoryName + "/" + tag;
×
503
                        } else {
504
                            tag = server + "/" + repositoryName + tag.substring(pos);
×
505
                        }
506
                    }
507
                }
508

UNCOV
509
                tags.computeIfAbsent(server, k -> new ArrayList<>()).add(tag);
×
UNCOV
510
            }
×
UNCOV
511
        }
×
512

UNCOV
513
        return tags;
×
514
    }
515

516
    private void push(DockerConfiguration docker, String server, String imageName) throws PackagerProcessingException {
517
        Command cmd = createCommand(docker, "push")
×
518
            .arg("--quiet")
×
519
            .arg("--all-tags")
×
520
            .arg(imageName);
×
521

522
        context.getLogger().info(" - {}", imageName);
×
523
        context.getLogger().debug(RB.$("docker.push", imageName, server));
×
524
        context.getLogger().debug(String.join(" ", cmd.getArgs()));
×
525
        if (!context.isDryrun()) executeCommand(cmd);
×
526
    }
×
527

528
    private void logout(DockerConfiguration docker, DockerConfiguration.Registry registry) throws PackagerProcessingException {
529
        if (registry.isExternalLogin()) return;
×
530

531
        Command cmd = createCommand(docker, "logout");
×
532
        if (isNotBlank(registry.getServer())) {
×
533
            cmd.arg(registry.getServerName());
×
534
        }
535

536
        context.getLogger().debug(RB.$("docker.logout"),
×
537
            registry.getServerName(),
×
538
            isNotBlank(registry.getServer()) ? " (" + registry.getServer() + ")" : "");
×
539
        if (!context.isDryrun()) executeCommand(cmd);
×
540
    }
×
541

542
    @Override
543
    protected void fillPackagerProperties(TemplateContext props, Distribution distribution) {
UNCOV
544
        props.set(KEY_DISTRIBUTION_JAVA_MAIN_CLASS, distribution.getJava().getMainClass());
×
UNCOV
545
        props.set(KEY_DISTRIBUTION_JAVA_MAIN_MODULE, distribution.getJava().getMainModule());
×
UNCOV
546
        fillDockerProperties(props, getPackager());
×
UNCOV
547
    }
×
548

549
    protected void fillDockerProperties(TemplateContext props, DockerConfiguration docker) {
UNCOV
550
        props.set(KEY_DOCKER_BASE_IMAGE,
×
UNCOV
551
            resolveTemplate(docker.getBaseImage(), props));
×
UNCOV
552
        props.set(KEY_DOCKER_ENTRYPOINT, passThrough(resolveTemplate(docker.getEntrypoint(), props)));
×
UNCOV
553
        props.set(KEY_DOCKER_CMD, passThrough(resolveTemplate(docker.getCmd(), props)));
×
554

UNCOV
555
        List<String> labels = new ArrayList<>();
×
UNCOV
556
        docker.getLabels().forEach((label, value) -> labels.add(passThrough("\"" + label + "\"=\"" +
×
UNCOV
557
            resolveTemplate(value, props) + "\"")));
×
UNCOV
558
        props.set(KEY_DOCKER_LABELS, labels);
×
UNCOV
559
        props.set(KEY_DOCKER_PRE_COMMANDS, docker.getPreCommands().stream()
×
UNCOV
560
            .map(c -> passThrough(resolveTemplate(c, props)))
×
UNCOV
561
            .collect(toList()));
×
UNCOV
562
        props.set(KEY_DOCKER_POST_COMMANDS, docker.getPostCommands().stream()
×
UNCOV
563
            .map(c -> passThrough(resolveTemplate(c, props)))
×
UNCOV
564
            .collect(toList()));
×
UNCOV
565
    }
×
566

567
    @Override
568
    protected void writeFile(Distribution distribution,
569
                             String content,
570
                             TemplateContext props,
571
                             Path outputDirectory,
572
                             String fileName) throws PackagerProcessingException {
UNCOV
573
        fileName = trimTplExtension(fileName);
×
574

UNCOV
575
        Path outputFile = "executable".equals(fileName) ?
×
576
            outputDirectory.resolve("assembly").resolve(distribution.getExecutable().getName()) :
×
UNCOV
577
            outputDirectory.resolve(fileName);
×
578

UNCOV
579
        writeFile(content, outputFile);
×
UNCOV
580
    }
×
581

582
    @Override
583
    protected void prepareWorkingCopy(TemplateContext props, Path directory, Distribution distribution) throws IOException {
UNCOV
584
        Path packageDirectory = props.get(KEY_DISTRIBUTION_PACKAGE_DIRECTORY);
×
585

UNCOV
586
        List<DockerSpec> activeSpecs = packager.getActiveSpecs();
×
587

UNCOV
588
        if (activeSpecs.isEmpty()) {
×
589
            for (String imageName : packager.getImageNames()) {
×
590
                copyDockerfiles(packageDirectory, resolveTemplate(imageName, props), directory, packager, false);
×
591
            }
×
592
        } else {
593
            // copy files that do not belong to specs
UNCOV
594
            prepareWorkingCopy(packageDirectory.resolve(ROOT), directory);
×
595

UNCOV
596
            for (DockerSpec spec : activeSpecs) {
×
UNCOV
597
                TemplateContext newProps = fillSpecProps(distribution, props, spec);
×
UNCOV
598
                for (String imageName : spec.getImageNames()) {
×
599
                    copyDockerfiles(packageDirectory.resolve(spec.getName()), resolveTemplate(imageName, newProps), directory, spec, true);
×
600
                }
×
601
            }
×
602
        }
603
    }
×
604

605
    private void copyDockerfiles(Path source, String imageName, Path directory, DockerConfiguration docker, boolean isSpec) throws IOException {
UNCOV
606
        Path destination = directory;
×
607

UNCOV
608
        String[] parts = imageName.split("/");
×
UNCOV
609
        parts = parts[parts.length - 1].split(":");
×
UNCOV
610
        if (isSpec) {
×
UNCOV
611
            destination = directory.resolve(((DockerSpec) docker).getName());
×
612
        }
613

UNCOV
614
        if (packager.getPackagerRepository().isVersionedSubfolders()) {
×
615
            destination = directory.resolve(parts[1]);
×
616
        }
617

UNCOV
618
        Path assembly = destination.resolve("assembly");
×
UNCOV
619
        FileUtils.deleteFiles(assembly);
×
620

UNCOV
621
        Files.createDirectories(destination);
×
622
        prepareWorkingCopy(source, destination,
×
UNCOV
623
            path -> !docker.isUseLocalArtifact() &&
×
UNCOV
624
                "assembly".equals(path.getFileName().toString()));
×
625
    }
×
626
}
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