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

jreleaser / jreleaser / #558

08 Dec 2025 02:56PM UTC coverage: 48.239% (+0.02%) from 48.215%
#558

push

github

aalmiray
feat(core): warn when a name template cannot be resolved

Closes #1960

Closes #1961

299 of 573 new or added lines in 133 files covered. (52.18%)

4 existing lines in 4 files now uncovered.

26047 of 53996 relevant lines covered (48.24%)

0.48 hits per line

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

53.63
/core/jreleaser-engine/src/main/java/org/jreleaser/assemblers/JpackageAssemblerProcessor.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.assemblers;
19

20
import org.apache.commons.io.IOUtils;
21
import org.jreleaser.bundle.RB;
22
import org.jreleaser.model.Constants;
23
import org.jreleaser.model.internal.JReleaserContext;
24
import org.jreleaser.model.internal.assemble.JlinkAssembler;
25
import org.jreleaser.model.internal.assemble.JpackageAssembler;
26
import org.jreleaser.model.internal.common.Artifact;
27
import org.jreleaser.model.spi.assemble.AssemblerProcessingException;
28
import org.jreleaser.mustache.TemplateContext;
29
import org.jreleaser.mustache.Templates;
30
import org.jreleaser.sdk.command.Command;
31
import org.jreleaser.templates.TemplateResource;
32
import org.jreleaser.templates.TemplateUtils;
33
import org.jreleaser.util.FileUtils;
34
import org.jreleaser.util.PlatformUtils;
35
import org.jreleaser.version.SemanticVersion;
36

37
import java.io.IOException;
38
import java.nio.file.Files;
39
import java.nio.file.Path;
40
import java.nio.file.Paths;
41
import java.util.Optional;
42
import java.util.stream.Collectors;
43

44
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
45
import static org.jreleaser.assemblers.AssemblerUtils.copyJars;
46
import static org.jreleaser.assemblers.AssemblerUtils.readJavaVersion;
47
import static org.jreleaser.mustache.Templates.resolveTemplate;
48
import static org.jreleaser.util.FileType.JAR;
49
import static org.jreleaser.util.FileUtils.listFilesAndProcess;
50
import static org.jreleaser.util.PlatformUtils.isWindows;
51
import static org.jreleaser.util.StringUtils.isBlank;
52
import static org.jreleaser.util.StringUtils.isNotBlank;
53

54
/**
55
 * @author Andres Almiray
56
 * @since 0.10.0
57
 */
58
public class JpackageAssemblerProcessor extends AbstractAssemblerProcessor<org.jreleaser.model.api.assemble.JpackageAssembler, JpackageAssembler> {
59
    private static final String FILES_DIRECTORY = "files";
60

61
    public JpackageAssemblerProcessor(JReleaserContext context) {
62
        super(context);
1✔
63
    }
1✔
64

65
    @Override
66
    protected void doAssemble(TemplateContext props) throws AssemblerProcessingException {
67
        JpackageAssembler.PlatformPackager packager = assembler.getResolvedPlatformPackager();
1✔
68

69
        if (!packager.getJdk().isActiveAndSelected()) return;
1✔
70

71
        // verify jdk
72
        Path jdkPath = packager.getJdk().getEffectivePath(context, assembler);
1✔
73
        SemanticVersion jdkVersion = SemanticVersion.of(readJavaVersion(jdkPath));
1✔
74
        context.getLogger().debug(RB.$("assembler.jpackage.jdk"), jdkVersion, jdkPath.toAbsolutePath().toString());
1✔
75
        if (jdkVersion.getMajor() < 16) {
1✔
76
            throw new AssemblerProcessingException(RB.$("ERROR_jpackage_minimum_jdk_required", jdkVersion.toString()));
×
77
        }
78

79
        String platform = packager.getJdk().getPlatform();
1✔
80
        String platformReplaced = assembler.getPlatform().applyReplacements(platform);
1✔
81

82
        Path assembleDirectory = props.get(Constants.KEY_DISTRIBUTION_ASSEMBLE_DIRECTORY);
1✔
83
        Path workDirectory = assembleDirectory.resolve(WORK_DIRECTORY + "-" + platformReplaced);
1✔
84
        Path inputsDirectory = workDirectory.resolve(INPUTS_DIRECTORY);
1✔
85
        Path filesDirectory = inputsDirectory.resolve(FILES_DIRECTORY);
1✔
86

87
        // copy files to inputs
88
        copyTemplates(context, props, filesDirectory);
1✔
89
        copyArtifacts(context, filesDirectory, platform, true);
1✔
90
        copyFiles(context, filesDirectory);
1✔
91
        copyFileSets(context, filesDirectory);
1✔
92

93
        // copy jars to inputs
94
        context.getLogger().debug(RB.$("assembler.copy.jars"), context.relativizeToBasedir(filesDirectory));
1✔
95
        if (isBlank(assembler.getJava().getMainModule())) {
1✔
96
            if (isNotBlank(assembler.getJlink())) {
1✔
97
                JlinkAssembler jlink = context.getModel().getAssemble().findJlink(assembler.getJlink());
1✔
98
                if (jlink.getJavaArchive().isSet()) {
1✔
99
                    String configuredPath = jlink.getJavaArchive().getPath();
×
NEW
100
                    String archiveFile = resolveTemplate(context.getLogger(), configuredPath, props);
×
101
                    Path archivePath = context.getBasedir().resolve(Paths.get(archiveFile));
×
102
                    if (!Files.exists(archivePath)) {
×
103
                        throw new AssemblerProcessingException(RB.$("ERROR_path_does_not_exist_2", configuredPath, archivePath));
×
104
                    }
105

106
                    Path archiveDirectory = inputsDirectory.resolve(ARCHIVE_DIRECTORY);
×
107
                    try {
108
                        FileUtils.unpackArchive(archivePath, archiveDirectory, true);
×
109
                    } catch (IOException e) {
×
110
                        throw new AssemblerProcessingException(RB.$("ERROR_unexpected_error"), e);
×
111
                    }
×
112

NEW
113
                    String libDirectoryName = resolveTemplate(context.getLogger(), jlink.getJavaArchive().getLibDirectoryName(), props);
×
114
                    Path libPath = inputsDirectory.resolve(ARCHIVE_DIRECTORY).resolve(libDirectoryName);
×
115
                    try {
116
                        FileUtils.copyFiles(context.getLogger(), libPath, filesDirectory);
×
117
                    } catch (IOException e) {
×
118
                        throw new AssemblerProcessingException(RB.$("ERROR_unexpected_error"), e);
×
119
                    }
×
120
                }
121
            }
122

123
            copyJars(context, assembler, filesDirectory, "");
1✔
124
            copyJars(context, assembler, filesDirectory, platform);
1✔
125
        }
126

127
        // copy icon to inputs
128
        copyIcon(context, assembler, packager, inputsDirectory, platform, props);
1✔
129

130
        // adjust runtime image
131
        if (isNotBlank(assembler.getJlink())) {
1✔
132
            adjustRuntimeImage(context, assembler, workDirectory, platform);
1✔
133
        }
134

135
        for (String type : packager.getTypes()) {
1✔
136
            context.getLogger().info("- " + RB.$("assembler.jpackage.type"), type);
1✔
137
            jpackage(context, type, workDirectory, props);
1✔
138
        }
1✔
139
    }
1✔
140

141
    private void copyIcon(JReleaserContext context, JpackageAssembler assembler,
142
                          JpackageAssembler.PlatformPackager packager, Path inputsDirectory,
143
                          String platform, TemplateContext props) throws AssemblerProcessingException {
144
        String p = "linux";
1✔
145
        String ext = ".png";
1✔
146

147
        if (isWindows(platform)) {
1✔
148
            p = "windows";
×
149
            ext = ".ico";
×
150
        } else if (PlatformUtils.isMac(platform)) {
1✔
151
            p = "osx";
1✔
152
            ext = ".icns";
1✔
153
        }
154

155
        String icon = resolveTemplate(context.getLogger(), packager.getIcon(), props);
1✔
156
        try {
157
            if (isNotBlank(icon) && Files.exists(context.getBasedir().resolve(icon)) && icon.endsWith(ext)) {
1✔
158
                Path iconPath = context.getBasedir().resolve(icon);
1✔
159
                Files.copy(iconPath, inputsDirectory.resolve(assembler.getName() + ext), REPLACE_EXISTING);
1✔
160
            } else {
1✔
161
                String iconResource = "META-INF/jreleaser/icons/" + p + "/duke" + ext;
×
162
                try (TemplateResource templateResource = TemplateUtils.resolveResource(context.getLogger(), iconResource)) {
×
163
                    writeFile(IOUtils.toByteArray(templateResource.getInputStream()), inputsDirectory.resolve(assembler.getName() + ext));
×
164
                }
165
            }
166
        } catch (Exception e) {
×
167
            throw new AssemblerProcessingException(RB.$("ERROR_unexpected_error"), e);
×
168
        }
1✔
169
    }
1✔
170

171
    @SuppressWarnings("UnnecessaryParentheses")
172
    private void adjustRuntimeImage(JReleaserContext context, JpackageAssembler assembler, Path workDirectory, String platform) throws AssemblerProcessingException {
173
        Optional<Artifact> runtimeImageByPlatform = assembler.findRuntimeImageByPlatform(platform);
1✔
174
        if (!runtimeImageByPlatform.isPresent()) {
1✔
175
            throw new AssemblerProcessingException(RB.$("ERROR_jpackage_runtime_image_not_found", platform));
×
176
        }
177

178
        Path originalImage = runtimeImageByPlatform.get().getEffectivePath(context, assembler);
1✔
179
        Path adjustedImage = workDirectory.resolve("runtime-image");
1✔
180

181
        try {
182
            if (!FileUtils.copyFilesRecursive(context.getLogger(), originalImage, adjustedImage, path -> {
1✔
183
                String fileName = path.getFileName().toString();
1✔
184
                boolean pathIsJar = fileName.endsWith(JAR.extension()) && path.getParent().getFileName().toString().equals(JARS_DIRECTORY);
1✔
185
                boolean pathIsExecutable = fileName.equals(context.getModel().getAssemble().findJlink(assembler.getJlink()).getExecutable());
1✔
186
                return pathIsJar || pathIsExecutable;
1✔
187
            })) {
188
                throw new IOException(RB.$("ERROR_assembler_adjusting_image", adjustedImage));
×
189
            }
190
        } catch (IOException e) {
×
191
            throw new AssemblerProcessingException(RB.$("ERROR_unexpected_error"), e);
×
192
        }
1✔
193

194
        runtimeImageByPlatform.get().setPath(adjustedImage.toAbsolutePath().toString());
1✔
195
    }
1✔
196

197
    private void jpackage(JReleaserContext context, String type, Path workDirectory, TemplateContext props) throws AssemblerProcessingException {
198
        JpackageAssembler.PlatformPackager packager = assembler.getResolvedPlatformPackager();
1✔
199
        Path jdkPath = packager.getJdk().getEffectivePath(context, assembler);
1✔
200
        String platform = packager.getJdk().getPlatform();
1✔
201
        String platformReplaced = assembler.getPlatform().applyReplacements(platform);
1✔
202

203
        Path assembleDirectory = workDirectory.getParent();
1✔
204
        Path packagerDirectory = workDirectory.resolve(type).toAbsolutePath();
1✔
205
        try {
206
            FileUtils.deleteFiles(packagerDirectory);
1✔
207
        } catch (IOException e) {
×
208
            throw new AssemblerProcessingException(RB.$("ERROR_assembler_delete_dir",
×
209
                context.relativizeToBasedir(packagerDirectory)), e);
×
210
        }
1✔
211

212
        Path inputsDirectory = workDirectory.resolve(INPUTS_DIRECTORY);
1✔
213

214
        Optional<Artifact> runtimeImageByPlatform = assembler.findRuntimeImageByPlatform(platform);
1✔
215
        if (!runtimeImageByPlatform.isPresent()) {
1✔
216
            throw new AssemblerProcessingException(RB.$("ERROR_jpackage_runtime_image_not_found", platform));
×
217
        }
218

219
        String moduleName = resolveTemplate(context.getLogger(), assembler.getJava().getMainModule(), props);
1✔
220
        String mainClass = resolveTemplate(context.getLogger(), assembler.getJava().getMainClass(), props);
1✔
221
        String appName = packager.getResolvedAppName(context, assembler);
1✔
222
        String appVersion = assembler.getApplicationPackage().getResolvedAppVersion(context, assembler);
1✔
223
        String vendor = resolveTemplate(context.getLogger(), assembler.getApplicationPackage().getVendor(), props);
1✔
224
        String copyright = resolveTemplate(context.getLogger(), assembler.getApplicationPackage().getCopyright(), props);
1✔
225

226
        Path jpackageExecutable = jdkPath
1✔
227
            .resolve(BIN_DIRECTORY)
1✔
228
            .resolve(isWindows() ? "jpackage.exe" : "jpackage")
1✔
229
            .toAbsolutePath();
1✔
230

231
        Command cmd = new Command(jpackageExecutable.toAbsolutePath().toString(), true)
1✔
232
            .arg("--type")
1✔
233
            .arg(type)
1✔
234
            .arg("--dest")
1✔
235
            .arg(assembleDirectory.toAbsolutePath().toString())
1✔
236
            .arg("--input")
1✔
237
            .arg(inputsDirectory.resolve(FILES_DIRECTORY).toAbsolutePath().toString())
1✔
238
            .arg("--name")
1✔
239
            .arg(maybeQuote(appName))
1✔
240
            .arg("--runtime-image")
1✔
241
            .arg(maybeQuote(runtimeImageByPlatform.get().getEffectivePath(context, assembler).toAbsolutePath().toString()))
1✔
242
            .arg("--app-version")
1✔
243
            .arg(appVersion)
1✔
244
            .arg("--vendor")
1✔
245
            .arg(maybeQuote(vendor))
1✔
246
            .arg("--copyright")
1✔
247
            .arg(maybeQuote(copyright))
1✔
248
            .arg("--description")
1✔
249
            .arg(maybeQuote(context.getModel().getProject().getDescription()));
1✔
250

251
        if (assembler.isVerbose()) {
1✔
252
            cmd.arg("--verbose");
×
253
        }
254

255
        if (isNotBlank(moduleName)) {
1✔
256
            cmd.arg("--module")
×
257
                .arg(moduleName + "/" + mainClass);
×
258
        } else {
259
            String mainJarPath = "";
1✔
260

261
            if (isNotBlank(assembler.getMainJar().getPath())) {
1✔
262
                mainJarPath = assembler.getMainJar().getResolvedPath().getFileName().toString();
1✔
263
            }
264

265
            if (isNotBlank(assembler.getJlink())) {
1✔
266
                JlinkAssembler jlink = context.getModel().getAssemble().findJlink(assembler.getJlink());
1✔
267
                if (jlink.getJavaArchive().isSet()) {
1✔
NEW
268
                    String mainJarName = resolveTemplate(context.getLogger(), jlink.getJavaArchive().getMainJarName(), props);
×
269
                    Path filesDirectory = inputsDirectory.resolve(FILES_DIRECTORY);
×
270
                    mainJarPath = filesDirectory.resolve(mainJarName).getFileName().toString();
×
271
                }
272
            }
273

274
            cmd.arg("--main-class")
1✔
275
                .arg(mainClass)
1✔
276
                .arg("--main-jar")
1✔
277
                .arg(maybeQuote(mainJarPath));
1✔
278
        }
279

280
        // Launcher
281
        for (String argument : assembler.getLauncher().getArguments()) {
1✔
282
            cmd.arg("--arguments")
×
NEW
283
                .arg(maybeQuote(resolveTemplate(context.getLogger(), argument, props)));
×
284
        }
×
285
        for (String javaOption : assembler.getLauncher().getJavaOptions()) {
1✔
286
            cmd.arg("--java-options")
×
NEW
287
                .arg(maybeQuote(resolveTemplate(context.getLogger(), javaOption, props)));
×
288
        }
×
289
        for (String launcher : assembler.getLauncher().getLaunchers()) {
1✔
290
            cmd.arg("--add-launcher")
×
NEW
291
                .arg(maybeQuote(resolveTemplate(context.getLogger(), launcher, props)));
×
292
        }
×
293

294
        // ApplicationPackage
295
        String licenseFile = resolveTemplate(context.getLogger(), assembler.getApplicationPackage().getLicenseFile(), props);
1✔
296
        if (isNotBlank(licenseFile)) {
1✔
297
            Path licenseFilePath = context.getBasedir().resolve(licenseFile);
×
298
            if (Files.exists(licenseFilePath)) {
×
299
                cmd.arg("--license-file")
×
300
                    .arg(maybeQuote(licenseFilePath.toAbsolutePath().toString()));
×
301
            }
302
        }
303

304
        if (!assembler.getApplicationPackage().getFileAssociations().isEmpty()) {
1✔
305
            for (String filename : assembler.getApplicationPackage().getFileAssociations()) {
×
NEW
306
                Path path = context.getBasedir().resolve(resolveTemplate(context.getLogger(), filename, props));
×
307
                if (Files.exists(path)) {
×
308
                    cmd.arg("--file-associations")
×
309
                        .arg(maybeQuote(path.toAbsolutePath().toString()));
×
310
                }
311
            }
×
312
        }
313

314
        customize(type, packager, inputsDirectory, cmd, props);
1✔
315

316
        context.getLogger().debug(String.join(" ", cmd.getArgs()));
1✔
317
        Command.Result result = executeCommand(cmd);
1✔
318
        if (assembler.isVerbose()) {
1✔
319
            context.getLogger().debug(result.getOut());
×
320
        }
321

322
        // replace only if not linux
323
        if (!PlatformUtils.isLinux(platform) && assembler.isAttachPlatform()) {
1✔
324
            try {
325
                Optional<Path> artifact = listFilesAndProcess(assembleDirectory, files ->
1✔
326
                    files.filter(path -> path.getFileName().toString().endsWith(type))
1✔
327
                        .findFirst().orElse(null));
1✔
328

329
                if (artifact.isPresent()) {
1✔
330
                    String dest = artifact.get().getFileName().toString()
1✔
331
                        .replace("." + type, "-" + platformReplaced + "." + type);
1✔
332
                    Files.move(
1✔
333
                        assembleDirectory.resolve(artifact.get().getFileName()),
1✔
334
                        assembleDirectory.resolve(dest), REPLACE_EXISTING);
1✔
335
                }
336
            } catch (IOException e) {
×
337
                throw new AssemblerProcessingException(RB.$("ERROR_unexpected_error"), e);
×
338
            }
1✔
339
        }
340
    }
1✔
341

342
    private void customize(String type, JpackageAssembler.PlatformPackager packager, Path inputsDirectory, Command cmd, TemplateContext props) {
343
        String installDir = resolveTemplate(context.getLogger(), packager.getInstallDir(), props);
1✔
344
        if (isNotBlank(installDir)) {
1✔
345
            cmd.arg("--install-dir")
×
346
                .arg(maybeQuote(installDir));
×
347
        }
348

349
        String resourceDir = resolveTemplate(context.getLogger(), packager.getResourceDir(), props);
1✔
350
        if (isNotBlank(resourceDir)) {
1✔
351
            Path resourceDirPath = context.getBasedir().resolve(resourceDir);
1✔
352
            if (Files.exists(resourceDirPath)) {
1✔
353
                cmd.arg("--resource-dir")
×
354
                    .arg(maybeQuote(resourceDirPath.toAbsolutePath().toString()));
×
355
            }
356
        }
357

358
        if (packager instanceof JpackageAssembler.Osx) {
1✔
359
            customizeOsx((JpackageAssembler.Osx) packager, inputsDirectory, cmd, props);
1✔
360
        } else if (packager instanceof JpackageAssembler.Linux) {
×
361
            customizeLinux(type, (JpackageAssembler.Linux) packager, inputsDirectory, cmd, props);
×
362
        } else if (packager instanceof JpackageAssembler.Windows) {
×
363
            customizeWindows((JpackageAssembler.Windows) packager, inputsDirectory, cmd, props);
×
364
        }
365
    }
1✔
366

367
    private void customizeOsx(JpackageAssembler.Osx packager, Path inputsDirectory, Command cmd, TemplateContext props) {
368
        if (isNotBlank(packager.getPackageName())) {
1✔
369
            cmd.arg("--mac-package-name")
1✔
370
                .arg(resolveTemplate(context.getLogger(), packager.getPackageName(), props));
1✔
371
        }
372
        if (isNotBlank(packager.getPackageIdentifier())) {
1✔
373
            cmd.arg("--mac-package-identifier")
1✔
374
                .arg(resolveTemplate(context.getLogger(), packager.getPackageIdentifier(), props));
1✔
375
        }
376
        if (isNotBlank(packager.getPackageSigningPrefix())) {
1✔
377
            cmd.arg("--mac-package-signing-prefix")
×
NEW
378
                .arg(resolveTemplate(context.getLogger(), packager.getPackageSigningPrefix(), props));
×
379
        }
380
        if (packager.isSign()) {
1✔
381
            cmd.arg("--mac-sign");
×
382
        }
383

384
        String signingKeychain = resolveTemplate(context.getLogger(), packager.getSigningKeychain(), props);
1✔
385
        if (isNotBlank(signingKeychain)) {
1✔
NEW
386
            Path path = context.getBasedir().resolve(resolveTemplate(context.getLogger(), signingKeychain, props));
×
387
            if (Files.exists(path)) {
×
388
                cmd.arg("--mac-signing-keychain")
×
389
                    .arg(path.toAbsolutePath().toString());
×
390
            }
391
        }
392
        if (isNotBlank(packager.getSigningKeyUsername())) {
1✔
393
            cmd.arg("--mac-signing-key-user-name")
×
NEW
394
                .arg(resolveTemplate(context.getLogger(), packager.getSigningKeyUsername(), props));
×
395
        }
396

397
        cmd.arg("--icon")
1✔
398
            .arg(inputsDirectory.resolve(assembler.getName() + ".icns").toAbsolutePath().toString());
1✔
399
    }
1✔
400

401
    private void customizeLinux(String type, JpackageAssembler.Linux packager, Path inputsDirectory, Command cmd, TemplateContext props) {
402
        if (isNotBlank(packager.getPackageName())) {
×
403
            cmd.arg("--linux-package-name")
×
NEW
404
                .arg(resolveTemplate(context.getLogger(), packager.getPackageName(), props));
×
405
        }
406
        if (isNotBlank(packager.getMenuGroup())) {
×
407
            cmd.arg("--linux-menu-group")
×
NEW
408
                .arg(resolveTemplate(context.getLogger(), packager.getMenuGroup(), props));
×
409
        }
410
        if (isNotBlank(packager.getAppRelease())) {
×
411
            cmd.arg("--linux-app-release")
×
NEW
412
                .arg(resolveTemplate(context.getLogger(), packager.getAppRelease(), props));
×
413
        }
414
        if (isNotBlank(packager.getAppCategory())) {
×
415
            cmd.arg("--linux-app-category")
×
NEW
416
                .arg(resolveTemplate(context.getLogger(), packager.getAppCategory(), props));
×
417
        }
418
        if (packager.isShortcut()) {
×
419
            cmd.arg("--linux-shortcut");
×
420
        }
421
        if (!packager.getPackageDeps().isEmpty()) {
×
422
            cmd.arg("--linux-package-deps")
×
423
                .arg(packager.getPackageDeps().stream()
×
NEW
424
                    .map(arg -> Templates.resolveTemplate(context.getLogger(), arg, props))
×
425
                    .collect(Collectors.joining(",")));
×
426
        }
427

428
        if ("deb".equals(type)) {
×
429
            if (isNotBlank(packager.getMaintainer())) {
×
430
                cmd.arg("--linux-deb-maintainer")
×
NEW
431
                    .arg(resolveTemplate(context.getLogger(), packager.getMaintainer(), props));
×
432
            }
433
        } else if ("rpm".equals(type)) {
×
434
            if (isNotBlank(packager.getLicense())) {
×
435
                cmd.arg("--linux-rpm-license-type")
×
NEW
436
                    .arg(resolveTemplate(context.getLogger(), packager.getLicense(), props));
×
437
            }
438
        }
439

440
        cmd.arg("--icon")
×
441
            .arg(inputsDirectory.resolve(assembler.getName() + ".png").toAbsolutePath().toString());
×
442
    }
×
443

444
    private void customizeWindows(JpackageAssembler.Windows packager, Path inputsDirectory, Command cmd, TemplateContext props) {
445
        if (packager.isConsole()) {
×
446
            cmd.arg("--win-console");
×
447
        }
448
        if (packager.isDirChooser()) {
×
449
            cmd.arg("--win-dir-chooser");
×
450
        }
451
        if (packager.isMenu()) {
×
452
            cmd.arg("--win-menu");
×
453
        }
454
        if (packager.isPerUserInstall()) {
×
455
            cmd.arg("--win-per-user-install");
×
456
        }
457
        if (packager.isShortcut()) {
×
458
            cmd.arg("--win-shortcut");
×
459
        }
460
        if (packager.isShortcutPrompt()) {
×
461
            cmd.arg("--win-shortcut-prompt");
×
462
        }
463
        if (isNotBlank(packager.getMenuGroup())) {
×
464
            cmd.arg("--win-menu-group")
×
NEW
465
                .arg(maybeQuote(resolveTemplate(context.getLogger(), packager.getMenuGroup(), props)));
×
466
        }
467
        if (isNotBlank(packager.getUpgradeUuid())) {
×
468
            cmd.arg("--win-upgrade-uuid")
×
NEW
469
                .arg(resolveTemplate(context.getLogger(), packager.getUpgradeUuid(), props));
×
470
        }
471
        if (isNotBlank(packager.getHelpUrl())) {
×
472
            cmd.arg("--win-help-url")
×
NEW
473
                .arg(resolveTemplate(context.getLogger(), packager.getHelpUrl(), props));
×
474
        }
475
        if (isNotBlank(packager.getUpdateUrl())) {
×
476
            cmd.arg("--win-update-url")
×
NEW
477
                .arg(resolveTemplate(context.getLogger(), packager.getUpdateUrl(), props));
×
478
        }
479

480
        cmd.arg("--icon")
×
481
            .arg(maybeQuote(inputsDirectory.resolve(assembler.getName() + ".ico").toAbsolutePath().toString()));
×
482
    }
×
483
}
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