• 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

73.98
/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_SHA_256;
78
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_SIZE;
79
import static org.jreleaser.model.Constants.KEY_DISTRIBUTION_URL;
80
import static org.jreleaser.model.Constants.KEY_REVERSE_REPO_HOST;
81
import static org.jreleaser.mustache.MustacheUtils.applyTemplates;
82
import static org.jreleaser.util.FileUtils.resolveRootEntryName;
83
import static org.jreleaser.util.StringUtils.capitalize;
84
import static org.jreleaser.util.StringUtils.getFilename;
85
import static org.jreleaser.util.StringUtils.isBlank;
86
import static org.jreleaser.util.StringUtils.isNotBlank;
87

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

452
        return count > 0;
1✔
453
    }
454

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

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

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

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

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

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

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

483
    protected void safePut(TemplateContext dest, String key, Object value) {
484
        if (value instanceof CharSequence && isNotBlank(String.valueOf(value)) || null != value) {
1✔
485
            dest.set(key, value);
1✔
486
        }
487
    }
1✔
488

489
    protected Optional<Stereotype> resolveStereotype(String fileName) {
490
        for (Stereotype stereotype : packager.getSupportedStereotypes()) {
1✔
491
            if (fileName.startsWith(stereotype.formatted() + "-")) {
1✔
492
                return Optional.of(stereotype);
1✔
493
            }
494
        }
1✔
495

496
        return Optional.empty();
1✔
497
    }
498
}
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