• 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

1.1
/core/jreleaser-engine/src/main/java/org/jreleaser/packagers/JibPackagerProcessor.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.JibConfiguration;
25
import org.jreleaser.model.internal.packagers.JibPackager;
26
import org.jreleaser.model.internal.packagers.JibSpec;
27
import org.jreleaser.model.spi.packagers.PackagerProcessingException;
28
import org.jreleaser.mustache.TemplateContext;
29
import org.jreleaser.sdk.command.CommandException;
30
import org.jreleaser.sdk.tool.Jib;
31
import org.jreleaser.sdk.tool.ToolException;
32
import org.jreleaser.util.FileUtils;
33

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.List;
40
import java.util.Set;
41
import java.util.TreeSet;
42

43
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
44
import static java.util.Collections.singletonList;
45
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_JAVA_MAIN_CLASS;
46
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_JAVA_MAIN_MODULE;
47
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_PACKAGE_DIRECTORY;
48
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_PREPARE_DIRECTORY;
49
import static org.jreleaser.model.Constants.KEY_JIB_BASE_IMAGE;
50
import static org.jreleaser.model.Constants.KEY_JIB_CREATION_TIME;
51
import static org.jreleaser.model.Constants.KEY_JIB_ENVIRONMENT;
52
import static org.jreleaser.model.Constants.KEY_JIB_EXPOSED_PORTS;
53
import static org.jreleaser.model.Constants.KEY_JIB_FORMAT;
54
import static org.jreleaser.model.Constants.KEY_JIB_HAS_ENVIRONMENT;
55
import static org.jreleaser.model.Constants.KEY_JIB_HAS_EXPOSED_PORTS;
56
import static org.jreleaser.model.Constants.KEY_JIB_HAS_VOLUMES;
57
import static org.jreleaser.model.Constants.KEY_JIB_LABELS;
58
import static org.jreleaser.model.Constants.KEY_JIB_SPEC_NAME;
59
import static org.jreleaser.model.Constants.KEY_JIB_USER;
60
import static org.jreleaser.model.Constants.KEY_JIB_VOLUMES;
61
import static org.jreleaser.model.Constants.KEY_JIB_WORKING_DIRECTORY;
62
import static org.jreleaser.mustache.MustacheUtils.passThrough;
63
import static org.jreleaser.mustache.Templates.resolveTemplate;
64
import static org.jreleaser.templates.TemplateUtils.trimTplExtension;
65
import static org.jreleaser.util.StringUtils.isNotBlank;
66

67
/**
68
 * @author Andres Almiray
69
 * @since 1.6.0
70
 */
71
public class JibPackagerProcessor extends AbstractRepositoryPackagerProcessor<JibPackager> {
72
    private static final String ROOT = "ROOT";
73

74
    public JibPackagerProcessor(JReleaserContext context) {
75
        super(context);
1✔
76
    }
1✔
77

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

92
        // copy root files
UNCOV
93
        String rootTemplateDirectory = getPackager().getTemplateDirectory() + File.separator + ROOT;
×
UNCOV
94
        super.doPrepareDistribution(distribution, props, distributionName,
×
UNCOV
95
            prepareDirectory.resolve(ROOT),
×
96
            rootTemplateDirectory,
UNCOV
97
            packager.getType(),
×
98
            false);
UNCOV
99
        Files.deleteIfExists(prepareDirectory.resolve(ROOT).resolve("build.yml"));
×
100

UNCOV
101
        for (JibSpec spec : packager.getActiveSpecs()) {
×
UNCOV
102
            prepareSpec(distribution, props, distributionName, prepareDirectory, spec);
×
UNCOV
103
        }
×
UNCOV
104
    }
×
105

106
    private void prepareSpec(Distribution distribution,
107
                             TemplateContext props,
108
                             String distributionName,
109
                             Path prepareDirectory,
110
                             JibSpec spec) throws IOException, PackagerProcessingException {
UNCOV
111
        TemplateContext newProps = fillSpecProps(distribution, props, spec);
×
UNCOV
112
        context.getLogger().debug(RB.$("distributions.action.preparing") + " {} spec", spec.getName());
×
UNCOV
113
        super.doPrepareDistribution(distribution, newProps, distributionName,
×
UNCOV
114
            prepareDirectory.resolve(spec.getName()),
×
UNCOV
115
            spec.getTemplateDirectory(),
×
UNCOV
116
            spec.getName() + "/" + packager.getType(),
×
117
            false);
UNCOV
118
    }
×
119

120
    private TemplateContext fillSpecProps(Distribution distribution, TemplateContext props, JibSpec spec) {
UNCOV
121
        List<Artifact> artifacts = singletonList(spec.getArtifact());
×
UNCOV
122
        TemplateContext newProps = fillProps(distribution, props);
×
UNCOV
123
        newProps.set(KEY_JIB_SPEC_NAME, spec.getName());
×
UNCOV
124
        fillJibProperties(newProps, spec);
×
UNCOV
125
        verifyAndAddArtifacts(newProps, distribution, artifacts);
×
UNCOV
126
        Path prepareDirectory = newProps.get(KEY_DISTRIBUTION_PREPARE_DIRECTORY);
×
UNCOV
127
        newProps.set(KEY_DISTRIBUTION_PREPARE_DIRECTORY, prepareDirectory.resolve(spec.getName()));
×
UNCOV
128
        Path packageDirectory = newProps.get(KEY_DISTRIBUTION_PACKAGE_DIRECTORY);
×
UNCOV
129
        newProps.set(KEY_DISTRIBUTION_PACKAGE_DIRECTORY, packageDirectory.resolve(spec.getName()));
×
UNCOV
130
        return newProps;
×
131
    }
132

133
    @Override
134
    protected boolean verifyAndAddArtifacts(TemplateContext props, Distribution distribution) {
UNCOV
135
        if (packager.getActiveSpecs().isEmpty()) {
×
136
            return super.verifyAndAddArtifacts(props, distribution);
×
137
        }
UNCOV
138
        return true;
×
139
    }
140

141
    @Override
142
    protected void doPackageDistribution(Distribution distribution,
143
                                         TemplateContext props,
144
                                         Path packageDirectory) throws PackagerProcessingException {
UNCOV
145
        if (packager.getActiveSpecs().isEmpty()) {
×
146
            List<Artifact> artifacts = packager.resolveArtifacts(context, distribution);
×
147
            packageJib(distribution, props, packageDirectory, artifacts);
×
148
            return;
×
149
        }
150

UNCOV
151
        Path rootPrepareDirectory = getPrepareDirectory(props).resolve(ROOT);
×
UNCOV
152
        Path rootPackageDirectory = getPackageDirectory(props).resolve(ROOT);
×
UNCOV
153
        copyFiles(rootPrepareDirectory, rootPackageDirectory);
×
154

UNCOV
155
        for (JibSpec spec : packager.getActiveSpecs()) {
×
UNCOV
156
            context.getLogger().debug(RB.$("distributions.action.packaging") + " {} spec", spec.getName());
×
UNCOV
157
            TemplateContext newProps = fillSpecProps(distribution, props, spec);
×
UNCOV
158
            packageJib(distribution, newProps, packageDirectory.resolve(spec.getName()), singletonList(spec.getArtifact()));
×
UNCOV
159
        }
×
UNCOV
160
    }
×
161

162
    protected void packageJib(Distribution distribution,
163
                              TemplateContext props,
164
                              Path packageDirectory,
165
                              List<Artifact> artifacts) throws PackagerProcessingException {
UNCOV
166
        super.doPackageDistribution(distribution, props, packageDirectory);
×
167

168
        try {
UNCOV
169
            copyPreparedFiles(props);
×
UNCOV
170
            Path assemblyDirectory = packageDirectory.resolve("assembly");
×
171

UNCOV
172
            Files.createDirectories(assemblyDirectory);
×
173

UNCOV
174
            for (Artifact artifact : artifacts) {
×
UNCOV
175
                Path artifactPath = artifact.getEffectivePath(context, distribution);
×
UNCOV
176
                if (distribution.getType() == org.jreleaser.model.Distribution.DistributionType.FLAT_BINARY) {
×
177
                    Files.copy(artifactPath, assemblyDirectory.resolve(artifactPath.getFileName()), REPLACE_EXISTING);
×
178
                } else {
UNCOV
179
                    FileUtils.unpackArchive(artifactPath, assemblyDirectory);
×
180
                }
UNCOV
181
            }
×
182
        } catch (IOException e) {
×
183
            throw new PackagerProcessingException(e);
×
UNCOV
184
        }
×
UNCOV
185
    }
×
186

187
    @Override
188
    public void publishDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
189
        if (packager.getActiveSpecs().isEmpty()) {
×
190
            publishToRepository(distribution, props);
×
191
            super.publishDistribution(distribution, props);
×
192
            return;
×
193
        }
194

195
        publishToRepository(distribution, props);
×
196
        for (JibSpec spec : packager.getActiveSpecs()) {
×
197
            context.getLogger().debug(RB.$("distributions.action.publishing") + " {} spec", spec.getName());
×
198
            TemplateContext newProps = fillSpecProps(distribution, props, spec);
×
199
            publishJib(newProps, spec);
×
200
        }
×
201
    }
×
202

203
    private void publishToRepository(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
204
        super.doPublishDistribution(distribution, fillProps(distribution, props));
×
205
    }
×
206

207
    @Override
208
    protected void doPublishDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
209
        publishJib(props, getPackager());
×
210
    }
×
211

212
    protected void publishJib(TemplateContext props, JibConfiguration jibc) throws PackagerProcessingException {
213
        if (context.isDryrun()) {
×
214
            for (JibConfiguration.Registry registry : jibc.getRegistries()) {
×
215
                for (String imageName : jibc.getImageNames()) {
×
216
                    imageName = registry.getServer() + "/" + resolveTemplate(imageName, props);
×
217
                    context.getLogger().info(" - {}", imageName);
×
218
                }
×
219
            }
×
220
            return;
×
221
        }
222

223
        Jib jib = new Jib(context.asImmutable(), packager.getVersion());
×
224
        try {
225
            if (!jib.setup()) {
×
226
                throw new PackagerProcessingException(RB.$("tool_unavailable", "jib"));
×
227
            }
228
        } catch (ToolException e) {
×
229
            throw new PackagerProcessingException(RB.$("tool_unavailable", "jib"));
×
230
        }
×
231

232
        Path packageDirectory = getPackageDirectory(props);
×
233

234
        for (JibConfiguration.Registry registry : jibc.getRegistries()) {
×
235
            List<String> args = new ArrayList<>();
×
236
            args.add("build");
×
237
            args.add("--console");
×
238
            args.add("plain");
×
239
            args.add("--verbosity");
×
240
            args.add("error");
×
241
            args.add("-c");
×
242
            args.add(packageDirectory.toAbsolutePath().toString());
×
243
            args.add("-b");
×
244
            args.add(packageDirectory.resolve("build.yml").toAbsolutePath().toString());
×
245

246
            if (isNotBlank(registry.getUsername())) {
×
247
                args.add("--username=" + registry.getUsername());
×
248
            }
249
            if (isNotBlank(registry.getFromUsername())) {
×
250
                args.add("--from-username=" + registry.getFromUsername());
×
251
            }
252
            if (isNotBlank(registry.getToUsername())) {
×
253
                args.add("--to-username=" + registry.getToUsername());
×
254
            }
255

256
            if (isNotBlank(registry.getPassword())) {
×
257
                args.add("--password=" + registry.getPassword());
×
258
            }
259
            if (isNotBlank(registry.getFromPassword())) {
×
260
                args.add("--from-password=" + registry.getFromPassword());
×
261
            }
262
            if (isNotBlank(registry.getToPassword())) {
×
263
                args.add("--to-password=" + registry.getToPassword());
×
264
            }
265

266
            for (String imageName : jibc.getImageNames()) {
×
267
                imageName = registry.getServer() + "/" + resolveTemplate(imageName, props);
×
268
                List<String> argsCopy = new ArrayList<>(args);
×
269
                argsCopy.add("-t");
×
270
                argsCopy.add(imageName);
×
271

272
                try {
273
                    context.getLogger().info(" - {}", imageName);
×
274
                    jib.invoke(context.getBasedir(), argsCopy);
×
275
                } catch (CommandException e) {
×
276
                    throw new PackagerProcessingException(RB.$("ERROR_unexpected_error"), e);
×
277
                }
×
278
            }
×
279
        }
×
280
    }
×
281

282
    @Override
283
    protected void fillPackagerProperties(TemplateContext props, Distribution distribution) {
UNCOV
284
        props.set(KEY_DISTRIBUTION_JAVA_MAIN_CLASS, distribution.getJava().getMainClass());
×
UNCOV
285
        props.set(KEY_DISTRIBUTION_JAVA_MAIN_MODULE, distribution.getJava().getMainModule());
×
UNCOV
286
        fillJibProperties(props, getPackager());
×
UNCOV
287
    }
×
288

289
    protected void fillJibProperties(TemplateContext props, JibConfiguration jib) {
UNCOV
290
        props.set(KEY_JIB_BASE_IMAGE, jib.getBaseImage());
×
UNCOV
291
        props.set(KEY_JIB_CREATION_TIME, jib.getCreationTime());
×
UNCOV
292
        props.set(KEY_JIB_FORMAT, jib.getFormat().formatted());
×
UNCOV
293
        props.set(KEY_JIB_USER, jib.getUser());
×
UNCOV
294
        props.set(KEY_JIB_WORKING_DIRECTORY, jib.getWorkingDirectory());
×
UNCOV
295
        props.set(KEY_JIB_HAS_VOLUMES, !jib.getVolumes().isEmpty());
×
UNCOV
296
        props.set(KEY_JIB_VOLUMES, jib.getVolumes());
×
UNCOV
297
        props.set(KEY_JIB_HAS_EXPOSED_PORTS, !jib.getExposedPorts().isEmpty());
×
UNCOV
298
        props.set(KEY_JIB_EXPOSED_PORTS, jib.getExposedPorts());
×
UNCOV
299
        props.set(KEY_JIB_HAS_ENVIRONMENT, !jib.getEnvironment().isEmpty());
×
300

UNCOV
301
        Set<String> env = new TreeSet<>();
×
UNCOV
302
        jib.getEnvironment().forEach((key, value) -> env.add(passThrough("\"" + key + "\": \"" +
×
303
            resolveTemplate(value, props) + "\"")));
×
UNCOV
304
        props.set(KEY_JIB_ENVIRONMENT, env);
×
305

UNCOV
306
        Set<String> labels = new TreeSet<>();
×
UNCOV
307
        jib.getLabels().forEach((key, value) -> labels.add(passThrough("\"" + key + "\": \"" +
×
UNCOV
308
            resolveTemplate(value, props) + "\"")));
×
UNCOV
309
        props.set(KEY_JIB_LABELS, labels);
×
UNCOV
310
    }
×
311

312
    @Override
313
    protected void writeFile(Distribution distribution,
314
                             String content,
315
                             TemplateContext props,
316
                             Path outputDirectory,
317
                             String fileName) throws PackagerProcessingException {
UNCOV
318
        fileName = trimTplExtension(fileName);
×
319

UNCOV
320
        Path outputFile = "executable".equals(fileName) ?
×
321
            outputDirectory.resolve("assembly").resolve(distribution.getExecutable().getName()) :
×
UNCOV
322
            outputDirectory.resolve(fileName);
×
323

UNCOV
324
        writeFile(content, outputFile);
×
UNCOV
325
    }
×
326

327
    @Override
328
    protected void prepareWorkingCopy(TemplateContext props, Path directory, Distribution distribution) throws IOException {
329
        Path packageDirectory = props.get(KEY_DISTRIBUTION_PACKAGE_DIRECTORY);
×
330

331
        List<JibSpec> activeSpecs = packager.getActiveSpecs();
×
332

333
        if (activeSpecs.isEmpty()) {
×
334
            for (String imageName : packager.getImageNames()) {
×
335
                copyJibfiles(packageDirectory, resolveTemplate(imageName, props), directory, false);
×
336
            }
×
337
        } else {
338
            // copy files that do not belong to specs
339
            prepareWorkingCopy(packageDirectory.resolve(ROOT), directory);
×
340

341
            for (JibSpec spec : activeSpecs) {
×
342
                TemplateContext newProps = fillSpecProps(distribution, props, spec);
×
343
                for (String imageName : spec.getImageNames()) {
×
344
                    copyJibfiles(packageDirectory.resolve(spec.getName()), resolveTemplate(imageName, newProps), directory, true);
×
345
                }
×
346
            }
×
347
        }
348
    }
×
349

350
    private void copyJibfiles(Path source, String imageName, Path directory, boolean isSpec) throws IOException {
351
        Path destination = directory;
×
352

353
        String[] parts = imageName.split("/");
×
354
        parts = parts[parts.length - 1].split(":");
×
355
        if (isSpec) {
×
356
            destination = directory.resolve(parts[0]);
×
357
        }
358

359
        if (packager.getPackagerRepository().isVersionedSubfolders()) {
×
360
            destination = directory.resolve(parts[1]);
×
361
        }
362

363
        Path assembly = destination.resolve("assembly");
×
364
        FileUtils.deleteFiles(assembly);
×
365

366
        Files.createDirectories(destination);
×
367
        prepareWorkingCopy(source, destination, path -> "assembly".equals(path.getFileName().toString()));
×
368
    }
×
369
}
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