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

jreleaser / jreleaser / #556

22 Nov 2025 04:17PM UTC coverage: 46.213% (-2.0%) from 48.203%
#556

push

github

aalmiray
feat(jdks): Allow filtering by platform

Closes #2000

Co-authored-by: Ixchel Ruiz <ixchelruiz@yahoo.com>

0 of 42 new or added lines in 5 files covered. (0.0%)

1116 existing lines in 107 files now uncovered.

24939 of 53965 relevant lines covered (46.21%)

0.46 hits per line

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

66.37
/plugins/jreleaser/src/main/java/org/jreleaser/cli/AbstractModelCommand.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.cli;
19

20
import org.jreleaser.config.JReleaserConfigParser;
21
import org.jreleaser.engine.context.ContextCreator;
22
import org.jreleaser.model.JReleaserVersion;
23
import org.jreleaser.model.api.JReleaserCommand;
24
import org.jreleaser.model.api.JReleaserContext.Mode;
25
import org.jreleaser.model.internal.JReleaserContext;
26
import org.jreleaser.model.internal.JReleaserModel;
27
import org.jreleaser.model.internal.environment.Environment;
28
import org.jreleaser.util.Env;
29
import org.jreleaser.util.PlatformUtils;
30
import org.jreleaser.util.StringUtils;
31
import picocli.CommandLine;
32

33
import java.nio.file.Files;
34
import java.nio.file.Path;
35
import java.nio.file.Paths;
36
import java.util.Arrays;
37
import java.util.Collections;
38
import java.util.LinkedHashSet;
39
import java.util.List;
40
import java.util.Optional;
41
import java.util.Properties;
42
import java.util.ServiceLoader;
43
import java.util.Set;
44

45
import static java.util.stream.Collectors.toList;
46
import static org.jreleaser.util.FileUtils.resolveOutputDirectory;
47
import static org.jreleaser.util.StringUtils.isBlank;
48
import static org.jreleaser.util.StringUtils.isNotBlank;
49

50
/**
51
 * @author Andres Almiray
52
 * @since 0.1.0
53
 */
54
public abstract class AbstractModelCommand<C extends IO> extends AbstractLoggingCommand<C> {
1✔
55
    @CommandLine.Option(names = {"-c", "--config-file"}, paramLabel = "<file>")
56
    Path configFile;
57

58
    @CommandLine.Option(names = {"--settings-file"}, paramLabel = "<file>")
59
    Path settingsFile;
60

61
    @CommandLine.Option(names = {"-grs", "--git-root-search"})
62
    Boolean gitRootSearch;
63

64
    @CommandLine.Option(names = {"--yolo"})
65
    Boolean yolo;
66

67
    @CommandLine.Option(names = {"--strict"})
68
    Boolean strict;
69

70
    @CommandLine.Option(names = {"-P", "--set-property"},
71
        paramLabel = "<key=value>")
72
    String[] properties;
73

74
    Path actualConfigFile;
75
    Path actualBasedir;
76

77
    @Override
78
    protected void collectCandidateDeprecatedArgs(Set<AbstractCommand.DeprecatedArg> args) {
79
        super.collectCandidateDeprecatedArgs(args);
1✔
80
        args.add(new DeprecatedArg("-grs", "--git-root-search", "1.5.0"));
1✔
81
    }
1✔
82

83
    @Override
84
    protected void execute() {
85
        resolveConfigFile();
1✔
86
        resolveBasedir();
1✔
87
        initLogger();
1✔
88
        PlatformUtils.resolveCurrentPlatform(logger);
1✔
89
        logger.info("JReleaser {}", JReleaserVersion.getPlainVersion());
1✔
90
        JReleaserVersion.banner(logger.getTracer());
1✔
91
        logger.info($("TEXT_config_file"), actualConfigFile);
1✔
92
        logger.increaseIndent();
1✔
93
        logger.info($("TEXT_basedir_set"), actualBasedir.toAbsolutePath());
1✔
94
        Path settings = resolveSettings();
1✔
95
        if (null != settings) {
1✔
96
            logger.info($("TEXT_settings_set"), settings.toAbsolutePath());
×
97
        }
98
        logger.info($("TEXT_outputdir_set"), getOutputDirectory().toAbsolutePath());
1✔
99
        logger.decreaseIndent();
1✔
UNCOV
100
        doExecute(createContext());
×
UNCOV
101
    }
×
102

103
    private void resolveConfigFile() {
104
        if (null != configFile) {
1✔
105
            actualConfigFile = configFile.normalize();
×
106
        } else {
107
            Path directory = Paths.get(".").normalize();
1✔
108
            Optional<Path> file = resolveConfigFileAt(directory);
1✔
109
            if (!file.isPresent() && null != basedir) {
1✔
110
                file = resolveConfigFileAt(basedir);
×
111
            }
112
            actualConfigFile = file.orElse(null);
1✔
113
        }
114

115
        if (null == actualConfigFile || !Files.exists(actualConfigFile)) {
1✔
116
            spec.commandLine().getErr()
×
117
                .println(spec.commandLine()
×
118
                    .getColorScheme()
×
119
                    .errorText($("ERROR_missing_config_file",
×
120
                        String.join("|", getSupportedConfigFormats())
×
121
                    )));
122
            spec.commandLine().usage(parent().getOut());
×
123
            throw new HaltExecutionException();
×
124
        }
125
    }
1✔
126

127
    private Optional<Path> resolveConfigFileAt(Path directory) {
128
        ServiceLoader<JReleaserConfigParser> parsers = ServiceLoader.load(JReleaserConfigParser.class,
1✔
129
            JReleaserConfigParser.class.getClassLoader());
1✔
130

131
        for (JReleaserConfigParser parser : parsers) {
1✔
132
            Path file = directory.resolve("jreleaser." + parser.getPreferredFileExtension()).normalize();
1✔
133
            if (Files.exists(file)) {
1✔
134
                return Optional.of(file);
1✔
135
            }
136
        }
1✔
137

138
        return Optional.empty();
×
139
    }
140

141
    private void resolveBasedir() {
142
        String resolvedBasedir = Env.resolve(org.jreleaser.model.api.JReleaserContext.BASEDIR, null != basedir ? basedir.toString() : "");
1✔
143
        actualBasedir = (isNotBlank(resolvedBasedir) ? Paths.get(resolvedBasedir) : actualConfigFile.toAbsolutePath().getParent()).normalize();
1✔
144
        if (!Files.exists(actualBasedir)) {
1✔
145
            spec.commandLine().getErr()
×
146
                .println(spec.commandLine().getColorScheme().errorText(
×
147
                    $("ERROR_missing_required_option", "--basedir=<basedir>")));
×
148
            spec.commandLine().usage(parent().getOut());
×
149
            throw new HaltExecutionException();
×
150
        }
151
    }
1✔
152

153
    private Path resolveSettings() {
154
        if (null != settingsFile) {
1✔
155
            return actualBasedir.resolve(settingsFile).normalize();
×
156
        }
157

158
        return null;
1✔
159
    }
160

161
    protected abstract void doExecute(JReleaserContext context);
162

163
    protected JReleaserContext createContext() {
164
        JReleaserModel model = ContextCreator.resolveModel(logger, actualConfigFile);
1✔
165
        Environment.PropertiesSource propertiesSource = new Environment.PropertiesPropertiesSource(collectProperties());
1✔
166
        model.getEnvironment().setPropertiesSource(propertiesSource);
1✔
167

168
        return ContextCreator.create(
1✔
169
            logger,
170
            resolveConfigurer(actualConfigFile),
1✔
171
            getMode(),
1✔
172
            getCommand(),
1✔
173
            model,
174
            actualBasedir,
175
            resolveSettings(),
1✔
176
            getOutputDirectory(),
1✔
177
            resolveBoolean(org.jreleaser.model.api.JReleaserContext.YOLO, yolo()),
1✔
178
            resolveBoolean(org.jreleaser.model.api.JReleaserContext.DRY_RUN, dryrun()),
1✔
179
            resolveBoolean(org.jreleaser.model.api.JReleaserContext.GIT_ROOT_SEARCH, gitRootSearch()),
1✔
180
            resolveBoolean(org.jreleaser.model.api.JReleaserContext.STRICT, strict()),
1✔
181
            collectSelectedPlatforms(),
1✔
182
            collectRejectedPlatforms());
1✔
183
    }
184

185
    protected boolean resolveBoolean(String key, Boolean value) {
186
        if (null != value) return value;
1✔
187
        String resolvedValue = Env.resolve(key, "");
1✔
188
        return isNotBlank(resolvedValue) && Boolean.parseBoolean(resolvedValue);
1✔
189
    }
190

191
    protected List<String> resolveCollection(String key, List<String> values) {
192
        if (!values.isEmpty()) return values;
1✔
193
        String resolvedValue = Env.resolve(key, "");
1✔
194
        if (isBlank(resolvedValue)) return Collections.emptyList();
1✔
195
        return Arrays.stream(resolvedValue.trim().split(","))
×
196
            .map(String::trim)
×
197
            .filter(StringUtils::isNotBlank)
×
198
            .collect(toList());
×
199
    }
200

201
    protected JReleaserContext.Configurer resolveConfigurer(Path configFile) {
202
        switch (StringUtils.getFilenameExtension(configFile.getFileName().toString())) {
1✔
203
            case "yml":
204
            case "yaml":
205
                return JReleaserContext.Configurer.CLI_YAML;
1✔
206
            case "toml":
207
                return JReleaserContext.Configurer.CLI_TOML;
×
208
            case "json":
209
                return JReleaserContext.Configurer.CLI_JSON;
×
210
            default:
211
                // should not happen!
212
                throw new IllegalArgumentException($("ERROR_invalid_config_format", configFile.getFileName()));
×
213
        }
214
    }
215

216
    @Override
217
    protected Path getOutputDirectory() {
218
        return resolveOutputDirectory(actualBasedir, outputdir, "out");
1✔
219
    }
220

221
    protected Boolean dryrun() {
222
        return false;
1✔
223
    }
224

225
    protected Boolean yolo() {
226
        return yolo;
1✔
227
    }
228

229
    protected Boolean strict() {
230
        return strict;
1✔
231
    }
232

233
    protected Boolean gitRootSearch() {
234
        return gitRootSearch;
1✔
235
    }
236

237
    private Set<String> getSupportedConfigFormats() {
238
        Set<String> extensions = new LinkedHashSet<>();
×
239

240
        ServiceLoader<JReleaserConfigParser> parsers = ServiceLoader.load(JReleaserConfigParser.class,
×
241
            JReleaserConfigParser.class.getClassLoader());
×
242

243
        for (JReleaserConfigParser parser : parsers) {
×
244
            extensions.add("." + parser.getPreferredFileExtension());
×
245
        }
×
246

247
        return extensions;
×
248
    }
249

250
    protected Mode getMode() {
UNCOV
251
        return Mode.FULL;
×
252
    }
253

254
    protected abstract JReleaserCommand getCommand();
255

256
    protected List<String> collectSelectedPlatforms() {
UNCOV
257
        return Collections.emptyList();
×
258
    }
259

260
    protected List<String> collectRejectedPlatforms() {
UNCOV
261
        return Collections.emptyList();
×
262
    }
263

264
    protected Properties collectProperties() {
265
        Properties props = new Properties();
1✔
266

267
        if (null != properties && properties.length > 0) {
1✔
268
            for (String property : properties) {
1✔
269
                if (property.contains("=")) {
1✔
270
                    int d = property.indexOf('=');
1✔
271
                    if (d == 0 || d == properties.length - 1) {
1✔
272
                        throw new IllegalArgumentException($("ERROR_invalid_property", property));
×
273
                    }
274
                    props.put(property.substring(0, d),
1✔
275
                        property.substring(d + 1));
1✔
276
                } else {
1✔
277
                    props.put(property, Boolean.TRUE);
×
278
                }
279
            }
280
        }
281

282
        return props;
1✔
283
    }
284
}
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