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

jreleaser / jreleaser / #537

25 Sep 2025 02:50PM UTC coverage: 48.299% (-0.7%) from 48.959%
#537

push

github

web-flow
fix: check snapshot version for '-SNAPSHOT' tag

Fixe #1971

2 of 2 new or added lines in 1 file covered. (100.0%)

362 existing lines in 31 files now uncovered.

25821 of 53461 relevant lines covered (48.3%)

0.48 hits per line

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

74.09
/core/jreleaser-engine/src/main/java/org/jreleaser/packagers/AbstractPackagerProcessor.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.Stereotype;
22
import org.jreleaser.model.internal.JReleaserContext;
23
import org.jreleaser.model.internal.common.Artifact;
24
import org.jreleaser.model.internal.distributions.Distribution;
25
import org.jreleaser.model.internal.packagers.Packager;
26
import org.jreleaser.model.internal.util.Artifacts;
27
import org.jreleaser.model.spi.packagers.PackagerProcessingException;
28
import org.jreleaser.model.spi.packagers.PackagerProcessor;
29
import org.jreleaser.mustache.TemplateContext;
30
import org.jreleaser.sdk.command.Command;
31
import org.jreleaser.sdk.command.CommandException;
32
import org.jreleaser.sdk.command.CommandExecutor;
33
import org.jreleaser.util.Algorithm;
34
import org.jreleaser.util.FileType;
35
import org.jreleaser.util.FileUtils;
36
import org.jreleaser.util.IoUtils;
37

38
import java.io.ByteArrayOutputStream;
39
import java.io.IOException;
40
import java.io.InputStream;
41
import java.nio.file.Files;
42
import java.nio.file.Path;
43
import java.util.Arrays;
44
import java.util.List;
45
import java.util.Map;
46
import java.util.Optional;
47
import java.util.function.Consumer;
48

49
import static java.util.stream.Collectors.toList;
50
import static org.jreleaser.model.Constants.KEY_ARTIFACT_ARCH;
51
import static org.jreleaser.model.Constants.KEY_ARTIFACT_FILE;
52
import static org.jreleaser.model.Constants.KEY_ARTIFACT_FILE_EXTENSION;
53
import static org.jreleaser.model.Constants.KEY_ARTIFACT_FILE_FORMAT;
54
import static org.jreleaser.model.Constants.KEY_ARTIFACT_FILE_NAME;
55
import static org.jreleaser.model.Constants.KEY_ARTIFACT_NAME;
56
import static org.jreleaser.model.Constants.KEY_ARTIFACT_OS;
57
import static org.jreleaser.model.Constants.KEY_ARTIFACT_PLATFORM;
58
import static org.jreleaser.model.Constants.KEY_ARTIFACT_PLATFORM_REPLACED;
59
import static org.jreleaser.model.Constants.KEY_ARTIFACT_ROOT_ENTRY_NAME;
60
import static org.jreleaser.model.Constants.KEY_ARTIFACT_SIZE;
61
import static org.jreleaser.model.Constants.KEY_ARTIFACT_VERSION;
62
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT;
63
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_ARCH;
64
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_FILE;
65
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_FILE_EXTENSION;
66
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_FILE_FORMAT;
67
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_FILE_NAME;
68
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_NAME;
69
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_OS;
70
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_PLATFORM;
71
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_PLATFORM_REPLACED;
72
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_ROOT_ENTRY_NAME;
73
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_SIZE;
74
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_ARTIFACT_VERSION;
75
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_PACKAGE_DIRECTORY;
76
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_PREPARE_DIRECTORY;
77
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_PUBLISH_DIRECTORY;
78
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_SHA_256;
79
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_SIZE;
80
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_URL;
81
import static org.jreleaser.model.Constants.KEY_REVERSE_REPO_HOST;
82
import static org.jreleaser.mustache.MustacheUtils.applyTemplates;
83
import static org.jreleaser.util.FileUtils.resolveRootEntryName;
84
import static org.jreleaser.util.StringUtils.capitalize;
85
import static org.jreleaser.util.StringUtils.getFilename;
86
import static org.jreleaser.util.StringUtils.isBlank;
87
import static org.jreleaser.util.StringUtils.isNotBlank;
88

89
/**
90
 * @author Andres Almiray
91
 * @since 0.1.0
92
 */
93
public abstract class AbstractPackagerProcessor<T extends Packager<?>> implements PackagerProcessor<T> {
94
    private static final String ARTIFACT = "artifact";
95
    private static final String DISTRIBUTION = "distribution";
96
    private static final String NAME = "Name";
97
    private static final String VERSION = "Version";
98
    private static final String OS = "Os";
99
    private static final String ARCH = "Arch";
100
    private static final String FILE = "File";
101
    private static final String SIZE = "Size";
102
    private static final String FILE_NAME = "FileName";
103
    private static final String ROOT_ENTRY_NAME = "RootEntryName";
104
    private static final String FILE_EXTENSION = "FileExtension";
105
    private static final String FILE_FORMAT = "FileFormat";
106
    private static final String CHECKSUM = "Checksum";
107
    private static final String URL = "Url";
108

109
    protected final JReleaserContext context;
110
    protected T packager;
111

112
    protected AbstractPackagerProcessor(JReleaserContext context) {
1✔
113
        this.context = context;
1✔
114
    }
1✔
115

116
    @Override
117
    public T getPackager() {
118
        return packager;
1✔
119
    }
120

121
    @Override
122
    public void setPackager(T packager) {
123
        this.packager = packager;
1✔
124
    }
1✔
125

126
    @Override
127
    public String getPackagerName() {
128
        return packager.getType();
1✔
129
    }
130

131
    @Override
132
    public boolean supportsDistribution(Distribution distribution) {
133
        return true;
1✔
134
    }
135

136
    @Override
137
    public void prepareDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
138
        try {
139
            String distributionName = distribution.getName();
1✔
140
            context.getLogger().debug(RB.$("packager.create.properties"), distributionName, getPackagerName());
1✔
141
            TemplateContext newProps = fillProps(distribution, props);
1✔
142
            if (newProps.isEmpty()) {
1✔
143
                context.getLogger().warn(RB.$("packager.skip.distribution"), distributionName);
×
144
                return;
×
145
            }
146

147
            doPrepareDistribution(distribution, newProps);
1✔
148
        } catch (RuntimeException e) {
×
149
            throw new PackagerProcessingException(e);
×
150
        }
1✔
151
    }
1✔
152

153
    protected abstract void doPrepareDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException;
154

155
    @Override
156
    public void packageDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
157
        try {
158
            String distributionName = distribution.getName();
1✔
159
            context.getLogger().debug(RB.$("packager.create.properties"), distributionName, getPackagerName());
1✔
160
            TemplateContext newProps = fillProps(distribution, props);
1✔
161
            if (newProps.isEmpty()) {
1✔
162
                context.getLogger().warn(RB.$("packager.skip.distribution"), distributionName);
×
163
                return;
×
164
            }
165

166
            doPackageDistribution(distribution, newProps);
1✔
167
        } catch (IllegalArgumentException e) {
×
168
            throw new PackagerProcessingException(e);
×
169
        }
1✔
170
    }
1✔
171

172
    @Override
173
    public void publishDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException {
174
        if (context.getModel().getProject().isSnapshot() && !packager.isSnapshotSupported()) {
1✔
175
            context.getLogger().info(RB.$("packager.publish.snapshot.not.supported"));
×
176
            return;
×
177
        }
178

179
        try {
180
            String distributionName = distribution.getName();
1✔
181
            context.getLogger().debug(RB.$("packager.create.properties"), distributionName, getPackagerName());
1✔
182
            TemplateContext newProps = fillProps(distribution, props);
1✔
183
            if (newProps.isEmpty()) {
1✔
184
                context.getLogger().warn(RB.$("packager.skip.distribution"), distributionName);
×
185
                return;
×
186
            }
187

188
            doPublishDistribution(distribution, newProps);
1✔
189
        } catch (RuntimeException e) {
×
190
            throw new PackagerProcessingException(e);
×
191
        }
1✔
192
    }
1✔
193

194
    protected abstract void doPackageDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException;
195

196
    protected abstract void doPublishDistribution(Distribution distribution, TemplateContext props) throws PackagerProcessingException;
197

198
    protected TemplateContext fillProps(Distribution distribution, TemplateContext props) {
199
        TemplateContext newProps = new TemplateContext(props);
1✔
200
        context.getLogger().debug(RB.$("packager.fill.distribution.properties"));
1✔
201
        fillDistributionProperties(newProps, distribution);
1✔
202
        context.getLogger().debug(RB.$("packager.fill.git.properties"));
1✔
203
        context.getModel().getRelease().getReleaser().fillProps(newProps, context.getModel());
1✔
204
        context.getLogger().debug(RB.$("packager.fill.artifact.properties"));
1✔
205
        if (!verifyAndAddArtifacts(newProps, distribution)) {
1✔
206
            // we can't continue with this packager
207
            return TemplateContext.empty();
×
208
        }
209
        context.getLogger().debug(RB.$("packager.fill.packager.properties"));
1✔
210
        fillPackagerProperties(newProps, distribution);
1✔
211
        applyTemplates(newProps, packager.resolvedExtraProperties());
1✔
212
        if (isBlank(context.getModel().getRelease().getReleaser().getReverseRepoHost())) {
1✔
213
            newProps.set(KEY_REVERSE_REPO_HOST,
×
214
                packager.getExtraProperties().get(KEY_REVERSE_REPO_HOST));
×
215
        }
216
        applyTemplates(newProps, newProps);
1✔
217
        return newProps;
1✔
218
    }
219

220
    protected void fillDistributionProperties(TemplateContext props, Distribution distribution) {
221
        props.setAll(distribution.props());
1✔
222
    }
1✔
223

224
    protected abstract void fillPackagerProperties(TemplateContext props, Distribution distribution);
225

226
    protected Command.Result executeCommand(Path directory, Command command) throws PackagerProcessingException {
227
        try {
228
            Command.Result result = new CommandExecutor(context.getLogger())
×
229
                .executeCommand(directory, command);
×
230
            if (result.getExitValue() != 0) {
×
231
                throw new CommandException(RB.$("ERROR_command_execution_exit_value", result.getExitValue()));
×
232
            }
233
            return result;
×
234
        } catch (CommandException e) {
×
235
            throw new PackagerProcessingException(RB.$("ERROR_unexpected_error"), e);
×
236
        }
237
    }
238

239
    protected Command.Result executeCommand(Command command) throws PackagerProcessingException {
240
        try {
UNCOV
241
            Command.Result result = new CommandExecutor(context.getLogger())
×
UNCOV
242
                .executeCommand(command);
×
UNCOV
243
            if (result.getExitValue() != 0) {
×
UNCOV
244
                throw new CommandException(RB.$("ERROR_command_execution_exit_value", result.getExitValue()));
×
245
            }
246
            return result;
×
UNCOV
247
        } catch (CommandException e) {
×
UNCOV
248
            throw new PackagerProcessingException(RB.$("ERROR_unexpected_error"), e);
×
249
        }
250
    }
251

252
    protected Command.Result executeCommand(Command command, InputStream in) throws PackagerProcessingException {
253
        try {
254
            Command.Result result = new CommandExecutor(context.getLogger())
×
255
                .executeCommand(command, in);
×
256
            if (result.getExitValue() != 0) {
×
257
                throw new CommandException(RB.$("ERROR_command_execution_exit_value", result.getExitValue()));
×
258
            }
259
            return result;
×
260
        } catch (CommandException e) {
×
261
            throw new PackagerProcessingException(RB.$("ERROR_unexpected_error"), e);
×
262
        }
263
    }
264

265
    protected void copyPreparedFiles(TemplateContext props) throws PackagerProcessingException {
266
        Path prepareDirectory = getPrepareDirectory(props);
1✔
267
        Path packageDirectory = getPackageDirectory(props);
1✔
268
        copyFiles(prepareDirectory, packageDirectory);
1✔
269
    }
1✔
270

271
    protected void copyFiles(Path src, Path dest) throws PackagerProcessingException {
272
        try {
273
            if (!Files.exists(dest)) {
1✔
UNCOV
274
                Files.createDirectories(dest);
×
275
            }
276

277
            if (!FileUtils.copyFilesRecursive(context.getLogger(), src, dest)) {
1✔
278
                throw new PackagerProcessingException(RB.$("ERROR_copy_files_from_to",
×
279
                    context.relativizeToBasedir(src),
×
280
                    context.relativizeToBasedir(dest)));
×
281
            }
282
        } catch (IOException e) {
×
283
            throw new PackagerProcessingException(RB.$("ERROR_unexpected_copy_files_from_to",
×
284
                context.relativizeToBasedir(src),
×
285
                context.relativizeToBasedir(dest)), e);
×
286
        }
1✔
287
    }
1✔
288

289
    protected boolean verifyAndAddArtifacts(TemplateContext props,
290
                                            Distribution distribution) {
291
        return verifyAndAddArtifacts(props, distribution, collectArtifacts(distribution));
1✔
292
    }
293

294
    protected boolean verifyAndAddArtifacts(TemplateContext props,
295
                                            Distribution distribution,
296
                                            List<Artifact> artifacts) {
297
        List<Artifact> activeArtifacts = artifacts.stream()
1✔
298
            .filter(Artifact::isActiveAndSelected)
1✔
299
            .collect(toList());
1✔
300

301
        if (activeArtifacts.isEmpty()) {
1✔
302
            // we can't proceed
303
            context.getLogger().warn(RB.$("packager.no.matching.artifacts"),
×
304
                distribution.getName(), capitalize(packager.getType()));
×
305
            return false;
×
306
        }
307

308
        int count = 0;
1✔
309
        for (Artifact artifact : activeArtifacts) {
1✔
310
            String artifactUrl = Artifacts.resolveDownloadUrl(context, packager.getType(), distribution, artifact);
1✔
311
            if (isBlank(artifactUrl)) continue;
1✔
312
            count++;
1✔
313

314
            String platform = artifact.getPlatform();
1✔
315
            String artifactPlatform = isNotBlank(platform) ? capitalize(platform) : "";
1✔
316
            String platformReplaced = distribution.getPlatform().applyReplacements(platform);
1✔
317
            String artifactPlatformReplaced = isNotBlank(platformReplaced) ? capitalize(platformReplaced) : "";
1✔
318
            // add extra properties without clobbering existing keys
319
            Map<String, Object> artifactProps = artifact.resolvedExtraProperties(ARTIFACT + artifactPlatform);
1✔
320
            artifactProps.keySet().stream()
1✔
321
                .filter(k -> !props.contains(k))
1✔
322
                .forEach(k -> props.set(k, artifactProps.get(k)));
1✔
323

324
            Path artifactPath = artifact.getEffectivePath(context, distribution);
1✔
325

326
            long artifactSize = 0;
1✔
327
            try {
328
                artifactSize = Files.size(artifactPath);
1✔
329
            } catch (IOException ignored) {
×
330
                // this would be strange
331
                context.getLogger().trace(ignored);
×
332
            }
1✔
333

334
            String artifactFile = artifact.getEffectivePath().getFileName().toString();
1✔
335
            String artifactFileName = getFilename(artifactFile, FileType.getSupportedExtensions());
1✔
336
            String artifactRootEntryName = resolveRootEntryName(artifact.getEffectivePath());
1✔
337
            String artifactFileExtension = "";
1✔
338
            String artifactFileFormat = "";
1✔
339

340
            if (!artifactFile.equals(artifactFileName)) {
1✔
341
                artifactFileExtension = artifactFile.substring(artifactFileName.length());
1✔
342
                artifactFileFormat = artifactFileExtension.substring(1);
1✔
343
            }
344

345
            String artifactName = "";
1✔
346
            String artifactVersion = "";
1✔
347
            String projectVersion = context.getModel().getProject().getEffectiveVersion();
1✔
348
            if (isNotBlank(projectVersion) && artifactFileName.contains(projectVersion)) {
1✔
349
                artifactName = artifactFileName.substring(0, artifactFileName.indexOf(projectVersion));
1✔
350
                if (artifactName.endsWith("-")) {
1✔
351
                    artifactName = artifactName.substring(0, artifactName.length() - 1);
1✔
352
                }
353
                artifactVersion = projectVersion;
1✔
354
            }
355
            projectVersion = context.getModel().getProject().getVersion();
1✔
356
            if (isBlank(artifactName) && isNotBlank(projectVersion) && artifactFileName.contains(projectVersion)) {
1✔
357
                artifactName = artifactFileName.substring(0, artifactFileName.indexOf(projectVersion));
×
358
                if (artifactName.endsWith("-")) {
×
359
                    artifactName = artifactName.substring(0, artifactName.length() - 1);
×
360
                }
361
                artifactVersion = projectVersion;
×
362
            }
363

364
            String artifactOs = "";
1✔
365
            String artifactArch = "";
1✔
366
            if (isNotBlank(platform) && platform.contains("-")) {
1✔
367
                String[] parts = platform.split("-");
1✔
368
                artifactOs = parts[0];
1✔
369
                artifactArch = parts[1];
1✔
370
            }
371

372
            safePut(props, ARTIFACT + artifactPlatform + NAME, artifactName);
1✔
373
            safePut(props, ARTIFACT + artifactPlatform + VERSION, artifactVersion);
1✔
374
            safePut(props, ARTIFACT + artifactPlatform + OS, artifactOs);
1✔
375
            safePut(props, ARTIFACT + artifactPlatform + ARCH, artifactArch);
1✔
376
            safePut(props, ARTIFACT + artifactPlatform + FILE, artifactFile);
1✔
377
            safePut(props, ARTIFACT + artifactPlatform + SIZE, artifactSize);
1✔
378
            safePut(props, ARTIFACT + artifactPlatform + FILE_NAME, artifactFileName);
1✔
379
            safePut(props, ARTIFACT + artifactPlatform + ROOT_ENTRY_NAME, artifactRootEntryName);
1✔
380
            safePut(props, ARTIFACT + artifactPlatform + FILE_EXTENSION, artifactFileExtension);
1✔
381
            safePut(props, ARTIFACT + artifactPlatform + FILE_FORMAT, artifactFileFormat);
1✔
382

383
            safePut(props, ARTIFACT + artifactPlatformReplaced + NAME, artifactName);
1✔
384
            safePut(props, ARTIFACT + artifactPlatformReplaced + VERSION, artifactVersion);
1✔
385
            safePut(props, ARTIFACT + artifactPlatformReplaced + OS, artifactOs);
1✔
386
            safePut(props, ARTIFACT + artifactPlatformReplaced + ARCH, artifactArch);
1✔
387
            safePut(props, ARTIFACT + artifactPlatformReplaced + FILE, artifactFile);
1✔
388
            safePut(props, ARTIFACT + artifactPlatformReplaced + SIZE, artifactSize);
1✔
389
            safePut(props, ARTIFACT + artifactPlatformReplaced + FILE_NAME, artifactFileName);
1✔
390
            safePut(props, ARTIFACT + artifactPlatformReplaced + ROOT_ENTRY_NAME, artifactRootEntryName);
1✔
391
            safePut(props, ARTIFACT + artifactPlatformReplaced + FILE_EXTENSION, artifactFileExtension);
1✔
392
            safePut(props, ARTIFACT + artifactPlatformReplaced + FILE_FORMAT, artifactFileFormat);
1✔
393

394
            for (Algorithm algorithm : context.getModel().getChecksum().getAlgorithms()) {
1✔
395
                safePut(props, ARTIFACT + artifactPlatform + CHECKSUM + capitalize(algorithm.formatted()), artifact.getHash(algorithm));
1✔
396
                safePut(props, ARTIFACT + artifactPlatformReplaced + CHECKSUM + capitalize(algorithm.formatted()), artifact.getHash(algorithm));
1✔
397
            }
1✔
398

399
            safePut(props, ARTIFACT + artifactPlatform + URL, artifactUrl);
1✔
400
            safePut(props, ARTIFACT + artifactPlatformReplaced + URL, artifactUrl);
1✔
401
            props.setAll(context.getModel().getUpload()
1✔
402
                .resolveDownloadUrls(context, distribution, artifact, ARTIFACT + artifactPlatform));
1✔
403
            props.setAll(context.getModel().getUpload()
1✔
404
                .resolveDownloadUrls(context, distribution, artifact, ARTIFACT + artifactPlatformReplaced));
1✔
405

406
            if (count == 1) {
1✔
407
                props.setAll(context.getModel().getUpload()
1✔
408
                    .resolveDownloadUrls(context, distribution, artifact, DISTRIBUTION));
1✔
409
                safePut(props, KEY_DISTRIBUTION_ARTIFACT, artifact);
1✔
410
                safePut(props, KEY_DISTRIBUTION_URL, artifactUrl);
1✔
411
                safePut(props, KEY_DISTRIBUTION_SIZE, artifactSize);
1✔
412
                safePut(props, KEY_DISTRIBUTION_SHA_256, artifact.getHash(Algorithm.SHA_256));
1✔
413
                for (Algorithm algorithm : context.getModel().getChecksum().getAlgorithms()) {
1✔
414
                    safePut(props, DISTRIBUTION + CHECKSUM + capitalize(algorithm.formatted()), artifact.getHash(algorithm));
1✔
415
                }
1✔
416

417
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_PLATFORM, platform);
1✔
418
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_PLATFORM_REPLACED, platformReplaced);
1✔
419
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_NAME, artifactName);
1✔
420
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_VERSION, artifactVersion);
1✔
421
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_OS, artifactOs);
1✔
422
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_ARCH, artifactArch);
1✔
423
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_SIZE, artifactSize);
1✔
424
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_FILE, artifactFile);
1✔
425
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_FILE_NAME, artifactFileName);
1✔
426
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_ROOT_ENTRY_NAME, artifactRootEntryName);
1✔
427
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_FILE_EXTENSION, artifactFileExtension);
1✔
428
                safePut(props, KEY_DISTRIBUTION_ARTIFACT_FILE_FORMAT, artifactFileFormat);
1✔
429

430
                safePut(props, KEY_ARTIFACT_PLATFORM, platform);
1✔
431
                safePut(props, KEY_ARTIFACT_PLATFORM_REPLACED, platformReplaced);
1✔
432
                safePut(props, KEY_ARTIFACT_NAME, artifactName);
1✔
433
                safePut(props, KEY_ARTIFACT_VERSION, artifactVersion);
1✔
434
                safePut(props, KEY_ARTIFACT_OS, artifactOs);
1✔
435
                safePut(props, KEY_ARTIFACT_ARCH, artifactArch);
1✔
436
                safePut(props, KEY_ARTIFACT_SIZE, artifactSize);
1✔
437
                safePut(props, KEY_ARTIFACT_FILE, artifactFile);
1✔
438
                safePut(props, KEY_ARTIFACT_FILE_NAME, artifactFileName);
1✔
439
                safePut(props, KEY_ARTIFACT_ROOT_ENTRY_NAME, artifactRootEntryName);
1✔
440
                safePut(props, KEY_ARTIFACT_FILE_EXTENSION, artifactFileExtension);
1✔
441
                safePut(props, KEY_ARTIFACT_FILE_FORMAT, artifactFileFormat);
1✔
442

443
                // add extra properties without clobbering existing keys
444
                Map<String, Object> aprops = artifact.resolvedExtraProperties();
1✔
445
                TemplateContext bprops = new TemplateContext(aprops);
1✔
446
                applyTemplates(aprops, bprops);
1✔
447
                aprops.keySet().stream()
1✔
448
                    .filter(k -> !props.contains(k))
1✔
449
                    .forEach(k -> props.set(k, aprops.get(k)));
1✔
450
            }
451
        }
1✔
452

453
        return count > 0;
1✔
454
    }
455

456
    protected List<Artifact> collectArtifacts(Distribution distribution) {
457
        return packager.resolveArtifacts(context, distribution);
1✔
458
    }
459

460
    protected void info(ByteArrayOutputStream out) {
461
        log(out, context.getLogger()::info);
×
462
    }
×
463

464
    protected void error(ByteArrayOutputStream err) {
465
        log(err, context.getLogger()::error);
×
466
    }
×
467

468
    private void log(ByteArrayOutputStream stream, Consumer<? super String> consumer) {
469
        String str = IoUtils.toString(stream);
×
470
        if (isBlank(str)) return;
×
471

472
        Arrays.stream(str.split(System.lineSeparator()))
×
473
            .forEach(consumer);
×
474
    }
×
475

476
    protected Path getPrepareDirectory(TemplateContext props) {
477
        return props.get(KEY_DISTRIBUTION_PREPARE_DIRECTORY);
1✔
478
    }
479

480
    protected Path getPackageDirectory(TemplateContext props) {
481
        return props.get(KEY_DISTRIBUTION_PACKAGE_DIRECTORY);
1✔
482
    }
483

484
    protected Path getPublishDirectory(TemplateContext props) {
485
        return props.get(KEY_DISTRIBUTION_PUBLISH_DIRECTORY);
1✔
486
    }
487

488
    protected void safePut(TemplateContext dest, String key, Object value) {
489
        if (value instanceof CharSequence && isNotBlank(String.valueOf(value)) || null != value) {
1✔
490
            dest.set(key, value);
1✔
491
        }
492
    }
1✔
493

494
    protected Optional<Stereotype> resolveStereotype(String fileName) {
495
        for (Stereotype stereotype : packager.getSupportedStereotypes()) {
1✔
496
            if (fileName.startsWith(stereotype.formatted() + "-")) {
1✔
497
                return Optional.of(stereotype);
1✔
498
            }
499
        }
1✔
500

501
        return Optional.empty();
1✔
502
    }
503
}
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