• 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

0.6
/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.Artifact;
23
import org.jreleaser.model.internal.distributions.Distribution;
24
import org.jreleaser.model.internal.packagers.DockerConfiguration;
25
import org.jreleaser.model.internal.packagers.DockerPackager;
26
import org.jreleaser.model.internal.packagers.DockerSpec;
27
import org.jreleaser.model.spi.packagers.PackagerProcessingException;
28
import org.jreleaser.mustache.TemplateContext;
29
import org.jreleaser.sdk.command.Command;
30
import org.jreleaser.util.FileUtils;
31
import org.jreleaser.util.PlatformUtils;
32

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

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

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

72
    public DockerPackagerProcessor(JReleaserContext context) {
73
        super(context);
1✔
74
    }
1✔
75

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

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

96
            return;
×
97
        }
98

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

UNCOV
109
        for (DockerSpec spec : packager.getActiveSpecs()) {
×
UNCOV
110
            prepareSpec(distribution, props, distributionName, prepareDirectory, spec);
×
UNCOV
111
        }
×
UNCOV
112
    }
×
113

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

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

136
    private TemplateContext fillSpecProps(Distribution distribution, TemplateContext props, DockerSpec spec) {
UNCOV
137
        List<Artifact> artifacts = singletonList(spec.getArtifact());
×
UNCOV
138
        TemplateContext newProps = fillProps(distribution, props);
×
UNCOV
139
        newProps.set(KEY_DOCKER_SPEC_NAME, spec.getName());
×
UNCOV
140
        fillDockerProperties(newProps, spec);
×
UNCOV
141
        verifyAndAddArtifacts(newProps, distribution, artifacts);
×
UNCOV
142
        Path prepareDirectory = newProps.get(KEY_DISTRIBUTION_PREPARE_DIRECTORY);
×
UNCOV
143
        newProps.set(KEY_DISTRIBUTION_PREPARE_DIRECTORY, prepareDirectory.resolve(spec.getName()));
×
UNCOV
144
        Path packageDirectory = newProps.get(KEY_DISTRIBUTION_PACKAGE_DIRECTORY);
×
UNCOV
145
        newProps.set(KEY_DISTRIBUTION_PACKAGE_DIRECTORY, packageDirectory.resolve(spec.getName()));
×
UNCOV
146
        return newProps;
×
147
    }
148

149
    @Override
150
    protected boolean verifyAndAddArtifacts(TemplateContext props, Distribution distribution) {
UNCOV
151
        if (packager.getActiveSpecs().isEmpty()) {
×
152
            return super.verifyAndAddArtifacts(props, distribution);
×
153
        }
UNCOV
154
        return true;
×
155
    }
156

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

UNCOV
167
        Path rootPrepareDirectory = getPrepareDirectory(props).resolve(ROOT);
×
UNCOV
168
        Path rootPackageDirectory = getPackageDirectory(props).resolve(ROOT);
×
UNCOV
169
        copyFiles(rootPrepareDirectory, rootPackageDirectory);
×
170

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

179
    protected void packageDocker(Distribution distribution,
180
                                 TemplateContext props,
181
                                 Path packageDirectory,
182
                                 DockerConfiguration docker,
183
                                 List<Artifact> artifacts) throws PackagerProcessingException {
UNCOV
184
        super.doPackageDistribution(distribution, props, packageDirectory);
×
185

186
        try {
187
            // copy files
UNCOV
188
            Path workingDirectory = prepareAssembly(distribution, props, packageDirectory, artifacts);
×
189

UNCOV
190
            Map<String, List<String>> tagNames = resolveTagNames(docker, props);
×
UNCOV
191
            List<String> tags = tagNames.values().stream()
×
UNCOV
192
                .flatMap(List::stream)
×
UNCOV
193
                .collect(toList());
×
194

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

UNCOV
197
            if (docker.getBuildx().isEnabled()) {
×
198
                // create builder if needed
199
                createBuildxBuilder(props, docker);
×
200
                configureAndExecuteBuildCommand(buildxBuildCommand(props, docker), workingDirectory, tags);
×
201
            } else {
UNCOV
202
                configureAndExecuteBuildCommand(buildCommand(props, docker), workingDirectory, tags);
×
203
            }
204
        } catch (IOException e) {
×
205
            throw new PackagerProcessingException(e);
×
UNCOV
206
        }
×
UNCOV
207
    }
×
208

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

222
        // execute
UNCOV
223
        executeCommand(cmd);
×
UNCOV
224
    }
×
225

226
    private void createBuildxBuilder(TemplateContext props, DockerConfiguration docker) throws PackagerProcessingException {
227
        if (!docker.getBuildx().isCreateBuilder()) return;
×
228

229
        Command cmd = new Command("docker" + (PlatformUtils.isWindows() ? ".exe" : ""))
×
230
            .arg("buildx")
×
231
            .arg("ls");
×
232
        Command.Result result = executeCommand(cmd);
×
233
        if (result.getOut().contains("jreleaser")) return;
×
234

235
        cmd = buildxCreateCommand(props, docker);
×
236
        context.getLogger().debug(String.join(" ", cmd.getArgs()));
×
237
        executeCommand(cmd);
×
238
    }
×
239

240
    private Path prepareAssembly(Distribution distribution,
241
                                 TemplateContext props,
242
                                 Path packageDirectory,
243
                                 List<Artifact> artifacts) throws IOException, PackagerProcessingException {
UNCOV
244
        copyPreparedFiles(props);
×
UNCOV
245
        Path assemblyDirectory = packageDirectory.resolve("assembly");
×
246

UNCOV
247
        Files.createDirectories(assemblyDirectory);
×
248

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

UNCOV
262
        return packageDirectory;
×
263
    }
264

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

278
    private Command buildxBuildCommand(TemplateContext props, DockerConfiguration docker) {
279
        Command cmd = createCommand(docker, "buildx");
×
280
        cmd.arg("build");
×
281

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

294
        for (int i = 0; i < docker.getBuildArgs().size(); i++) {
×
295
            String arg = docker.getBuildArgs().get(i);
×
296
            if (arg.contains("{{")) {
×
297
                cmd.arg(resolveTemplate(arg, props).trim());
×
298
            } else {
299
                cmd.arg(arg.trim());
×
300
            }
301
        }
302
        return cmd;
×
303
    }
304

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

319
    private Command createCommand(DockerConfiguration docker, String name) {
UNCOV
320
        return new Command(docker.getCommand().formatted() + (PlatformUtils.isWindows() ? ".exe" : ""))
×
UNCOV
321
            .arg("--log-level")
×
UNCOV
322
            .arg("error")
×
UNCOV
323
            .arg(name);
×
324
    }
325

326
    @Override
327
    public void publishDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
UNCOV
328
        if (packager.getActiveSpecs().isEmpty()) {
×
329
            publishToRepository(distribution, props);
×
330
            super.publishDistribution(distribution, props);
×
331
            cleanupBuilder(props, getPackager());
×
332
            return;
×
333
        }
334

UNCOV
335
        publishToRepository(distribution, props);
×
UNCOV
336
        for (DockerSpec spec : packager.getActiveSpecs()) {
×
UNCOV
337
            context.getLogger().debug(RB.$("distributions.action.publishing") + " {} spec", spec.getName());
×
UNCOV
338
            TemplateContext newProps = fillSpecProps(distribution, props, spec);
×
UNCOV
339
            publishDocker(newProps, spec);
×
UNCOV
340
        }
×
UNCOV
341
        cleanupBuilder(props, packager.getActiveSpecs());
×
UNCOV
342
    }
×
343

344
    private void publishToRepository(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
UNCOV
345
        super.doPublishDistribution(distribution, fillProps(distribution, props));
×
UNCOV
346
    }
×
347

348
    @Override
349
    protected void doPublishDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
350
        publishDocker(props, getPackager());
×
351
    }
×
352

353
    protected void publishDocker(TemplateContext props, DockerConfiguration docker) throws PackagerProcessingException {
UNCOV
354
        Map<String, List<String>> tagNames = resolveTagNames(docker, props);
×
355

UNCOV
356
        if (context.isDryrun()) {
×
UNCOV
357
            for (Map.Entry<String, List<String>> e : tagNames.entrySet()) {
×
UNCOV
358
                Set<String> uniqueImageNames = e.getValue().stream()
×
UNCOV
359
                    .map(tag -> tag.split(":")[0])
×
UNCOV
360
                    .collect(toSet());
×
UNCOV
361
                for (String imageName : uniqueImageNames) {
×
UNCOV
362
                    context.getLogger().info(" - {}", imageName);
×
UNCOV
363
                }
×
UNCOV
364
            }
×
UNCOV
365
            return;
×
366
        }
367

368
        for (DockerConfiguration.Registry registry : docker.getRegistries()) {
×
369
            login(docker, registry);
×
370
        }
×
371

372
        if (docker.getBuildx().isEnabled()) {
×
373
            Path workingDirectory = props.get(KEY_DISTRIBUTION_PACKAGE_DIRECTORY);
×
374
            List<String> tags = tagNames.values().stream()
×
375
                .flatMap(List::stream)
×
376
                .collect(toList());
×
377

378
            // command line
379
            Command cmd = buildxBuildCommand(props, docker);
×
380
            if (!cmd.hasArg("-q") && !cmd.hasArg("--quiet")) {
×
381
                cmd.arg("--quiet");
×
382
            }
383
            cmd.arg("--file");
×
384
            cmd.arg(workingDirectory.resolve("Dockerfile").toAbsolutePath().toString());
×
385
            for (String tag : tags) {
×
386
                cmd.arg("--tag");
×
387
                cmd.arg(tag);
×
388
            }
×
389
            cmd.arg("--push");
×
390
            cmd.arg(workingDirectory.toAbsolutePath().toString());
×
391
            context.getLogger().debug(String.join(" ", cmd.getArgs()));
×
392

393
            // execute
394
            executeCommand(cmd);
×
395
        } else {
×
396
            for (Map.Entry<String, List<String>> e : tagNames.entrySet()) {
×
397
                Set<String> uniqueImageNames = e.getValue().stream()
×
398
                    .map(tag -> tag.split(":")[0])
×
399
                    .collect(toSet());
×
400
                for (String imageName : uniqueImageNames) {
×
401
                    push(docker, e.getKey(), imageName);
×
402
                }
×
403
            }
×
404
        }
405

406
        for (DockerConfiguration.Registry registry : docker.getRegistries()) {
×
407
            logout(docker, registry);
×
408
        }
×
409
    }
×
410

411
    private void cleanupBuilder(TemplateContext props, DockerConfiguration docker) throws PackagerProcessingException {
412
        if (docker.getBuildx().isEnabled() && docker.getBuildx().isCreateBuilder()) {
×
413
            int i = docker.getBuildx().getCreateBuilderFlags().indexOf("--name");
×
414
            String builderName = docker.getBuildx().getCreateBuilderFlags().get(i + 1);
×
415
            Command cmd = createCommand(docker, "buildx")
×
416
                .arg("rm")
×
417
                .arg(resolveTemplate(builderName, props).trim());
×
418

419
            executeCommand(cmd);
×
420
        }
421
    }
×
422

423
    private void cleanupBuilder(TemplateContext props, List<DockerSpec> specs) throws PackagerProcessingException {
UNCOV
424
        Set<String> builderNames = new LinkedHashSet<>();
×
UNCOV
425
        for (DockerSpec spec : specs) {
×
UNCOV
426
            if (spec.getBuildx().isEnabled() && spec.getBuildx().isCreateBuilder()) {
×
427
                int i = spec.getBuildx().getCreateBuilderFlags().indexOf("--name");
×
428
                builderNames.add(spec.getBuildx().getCreateBuilderFlags().get(i + 1));
×
429
            }
UNCOV
430
        }
×
431

UNCOV
432
        for (String builderName : builderNames) {
×
433
            Command cmd = createCommand(packager, "buildx")
×
434
                .arg("rm")
×
435
                .arg(resolveTemplate(builderName, props).trim());
×
436

437
            executeCommand(cmd);
×
438
        }
×
UNCOV
439
    }
×
440

441
    private void login(DockerConfiguration docker, DockerConfiguration.Registry registry) throws PackagerProcessingException {
442
        if (registry.isExternalLogin()) return;
×
443

444
        Command cmd = createCommand(docker, "login");
×
445
        if (isNotBlank(registry.getServer())) {
×
446
            cmd.arg(registry.getServer());
×
447
        }
448
        cmd.arg("-u");
×
449
        cmd.arg(registry.getUsername());
×
450
        cmd.arg("-p");
×
451
        cmd.arg(registry.getPassword());
×
452

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

455
        context.getLogger().debug(RB.$("docker.login"),
×
456
            registry.getServerName(),
×
457
            isNotBlank(registry.getServer()) ? " (" + registry.getServer() + ")" : "");
×
458
        if (!context.isDryrun()) executeCommand(cmd, in);
×
459
    }
×
460

461
    private Map<String, List<String>> resolveTagNames(DockerConfiguration docker, TemplateContext props) {
UNCOV
462
        Map<String, List<String>> tags = new LinkedHashMap<>();
×
463

UNCOV
464
        for (DockerConfiguration.Registry registry : docker.getRegistries()) {
×
UNCOV
465
            for (String imageName : docker.getImageNames()) {
×
UNCOV
466
                imageName = resolveTemplate(imageName, props).toLowerCase(Locale.ENGLISH);
×
467

UNCOV
468
                String tag = imageName;
×
UNCOV
469
                String serverName = registry.getServerName();
×
UNCOV
470
                String server = registry.getServer();
×
UNCOV
471
                String repositoryName = registry.getRepositoryName();
×
472

473
                // if serverName == DEFAULT
474
                //   tag: docker.io/repositoryName/imageName
475
                // else
476
                //   tag: server/repositoryName/imageName
477

UNCOV
478
                if (DockerConfiguration.Registry.DEFAULT_NAME.equals(serverName)) {
×
UNCOV
479
                    if (!tag.startsWith(repositoryName)) {
×
UNCOV
480
                        int pos = tag.indexOf("/");
×
UNCOV
481
                        if (pos < 0) {
×
482
                            tag = server + "/" + repositoryName + "/" + tag;
×
483
                        } else {
UNCOV
484
                            tag = server + "/" + repositoryName + tag.substring(pos);
×
485
                        }
UNCOV
486
                    }
×
487
                } else {
488
                    if (!tag.startsWith(server)) {
×
489
                        int pos = tag.indexOf("/");
×
490
                        if (pos < 0) {
×
491
                            tag = server + "/" + repositoryName + "/" + tag;
×
492
                        } else {
493
                            tag = server + "/" + repositoryName + tag.substring(pos);
×
494
                        }
495
                    }
496
                }
497

UNCOV
498
                tags.computeIfAbsent(server, k -> new ArrayList<>()).add(tag);
×
UNCOV
499
            }
×
UNCOV
500
        }
×
501

UNCOV
502
        return tags;
×
503
    }
504

505
    private void push(DockerConfiguration docker, String server, String imageName) throws PackagerProcessingException {
506
        Command cmd = createCommand(docker, "push")
×
507
            .arg("--quiet")
×
508
            .arg("--all-tags")
×
509
            .arg(imageName);
×
510

511
        context.getLogger().info(" - {}", imageName);
×
512
        context.getLogger().debug(RB.$("docker.push", imageName, server));
×
513
        context.getLogger().debug(String.join(" ", cmd.getArgs()));
×
514
        if (!context.isDryrun()) executeCommand(cmd);
×
515
    }
×
516

517
    private void logout(DockerConfiguration docker, DockerConfiguration.Registry registry) throws PackagerProcessingException {
518
        if (registry.isExternalLogin()) return;
×
519

520
        Command cmd = createCommand(docker, "logout");
×
521
        if (isNotBlank(registry.getServer())) {
×
522
            cmd.arg(registry.getServerName());
×
523
        }
524

525
        context.getLogger().debug(RB.$("docker.logout"),
×
526
            registry.getServerName(),
×
527
            isNotBlank(registry.getServer()) ? " (" + registry.getServer() + ")" : "");
×
528
        if (!context.isDryrun()) executeCommand(cmd);
×
529
    }
×
530

531
    @Override
532
    protected void fillPackagerProperties(TemplateContext props, Distribution distribution) {
UNCOV
533
        props.set(KEY_DISTRIBUTION_JAVA_MAIN_CLASS, distribution.getJava().getMainClass());
×
UNCOV
534
        props.set(KEY_DISTRIBUTION_JAVA_MAIN_MODULE, distribution.getJava().getMainModule());
×
UNCOV
535
        fillDockerProperties(props, getPackager());
×
UNCOV
536
    }
×
537

538
    protected void fillDockerProperties(TemplateContext props, DockerConfiguration docker) {
UNCOV
539
        props.set(KEY_DOCKER_BASE_IMAGE,
×
UNCOV
540
            resolveTemplate(docker.getBaseImage(), props));
×
541

UNCOV
542
        List<String> labels = new ArrayList<>();
×
UNCOV
543
        docker.getLabels().forEach((label, value) -> labels.add(passThrough("\"" + label + "\"=\"" +
×
UNCOV
544
            resolveTemplate(value, props) + "\"")));
×
UNCOV
545
        props.set(KEY_DOCKER_LABELS, labels);
×
UNCOV
546
        props.set(KEY_DOCKER_PRE_COMMANDS, docker.getPreCommands().stream()
×
UNCOV
547
            .map(c -> passThrough(resolveTemplate(c, props)))
×
UNCOV
548
            .collect(toList()));
×
UNCOV
549
        props.set(KEY_DOCKER_POST_COMMANDS, docker.getPostCommands().stream()
×
UNCOV
550
            .map(c -> passThrough(resolveTemplate(c, props)))
×
UNCOV
551
            .collect(toList()));
×
UNCOV
552
    }
×
553

554
    @Override
555
    protected void writeFile(Distribution distribution,
556
                             String content,
557
                             TemplateContext props,
558
                             Path outputDirectory,
559
                             String fileName) throws PackagerProcessingException {
UNCOV
560
        fileName = trimTplExtension(fileName);
×
561

UNCOV
562
        Path outputFile = "executable".equals(fileName) ?
×
563
            outputDirectory.resolve("assembly").resolve(distribution.getExecutable().getName()) :
×
UNCOV
564
            outputDirectory.resolve(fileName);
×
565

UNCOV
566
        writeFile(content, outputFile);
×
UNCOV
567
    }
×
568

569
    @Override
570
    protected void prepareWorkingCopy(TemplateContext props, Path directory, Distribution distribution) throws IOException {
571
        Path packageDirectory = props.get(KEY_DISTRIBUTION_PACKAGE_DIRECTORY);
×
572

573
        List<DockerSpec> activeSpecs = packager.getActiveSpecs();
×
574

575
        if (activeSpecs.isEmpty()) {
×
576
            for (String imageName : packager.getImageNames()) {
×
577
                copyDockerfiles(packageDirectory, resolveTemplate(imageName, props), directory, packager, false);
×
578
            }
×
579
        } else {
580
            // copy files that do not belong to specs
581
            prepareWorkingCopy(packageDirectory.resolve(ROOT), directory);
×
582

583
            for (DockerSpec spec : activeSpecs) {
×
584
                TemplateContext newProps = fillSpecProps(distribution, props, spec);
×
585
                for (String imageName : spec.getImageNames()) {
×
586
                    copyDockerfiles(packageDirectory.resolve(spec.getName()), resolveTemplate(imageName, newProps), directory, spec, true);
×
587
                }
×
588
            }
×
589
        }
590
    }
×
591

592
    private void copyDockerfiles(Path source, String imageName, Path directory, DockerConfiguration docker, boolean isSpec) throws IOException {
593
        Path destination = directory;
×
594

595
        String[] parts = imageName.split("/");
×
596
        parts = parts[parts.length - 1].split(":");
×
597
        if (isSpec) {
×
598
            destination = directory.resolve(parts[0]);
×
599
        }
600

601
        if (packager.getPackagerRepository().isVersionedSubfolders()) {
×
602
            destination = directory.resolve(parts[1]);
×
603
        }
604

605
        Path assembly = destination.resolve("assembly");
×
606
        FileUtils.deleteFiles(assembly);
×
607

608
        Files.createDirectories(destination);
×
609
        prepareWorkingCopy(source, destination,
×
610
            path -> !docker.isUseLocalArtifact() &&
×
611
                "assembly".equals(path.getFileName().toString()));
×
612
    }
×
613
}
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