• 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

81.33
/core/jreleaser-model-impl/src/main/java/org/jreleaser/model/internal/environment/Environment.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.model.internal.environment;
19

20
import com.fasterxml.jackson.annotation.JsonIgnore;
21
import org.jreleaser.bundle.RB;
22
import org.jreleaser.config.JReleaserConfigLoader;
23
import org.jreleaser.config.JReleaserConfigParser;
24
import org.jreleaser.model.internal.JReleaserContext;
25
import org.jreleaser.model.internal.common.AbstractModelObject;
26
import org.jreleaser.model.internal.common.Domain;
27
import org.jreleaser.util.Env;
28

29
import java.io.File;
30
import java.io.IOException;
31
import java.io.InputStream;
32
import java.io.Serializable;
33
import java.nio.file.Files;
34
import java.nio.file.Path;
35
import java.nio.file.Paths;
36
import java.util.LinkedHashMap;
37
import java.util.Map;
38
import java.util.Optional;
39
import java.util.Properties;
40
import java.util.ServiceLoader;
41
import java.util.Set;
42
import java.util.TreeSet;
43

44
import static java.nio.file.Files.newInputStream;
45
import static java.util.Collections.unmodifiableMap;
46
import static org.jreleaser.model.Constants.DEFAULT_GIT_REMOTE;
47
import static org.jreleaser.model.Constants.JRELEASER_USER_HOME;
48
import static org.jreleaser.model.Constants.XDG_CONFIG_HOME;
49
import static org.jreleaser.util.Env.JRELEASER_ENV_PREFIX;
50
import static org.jreleaser.util.Env.JRELEASER_SYS_PREFIX;
51
import static org.jreleaser.util.Env.envKey;
52
import static org.jreleaser.util.StringUtils.getPropertyNameForLowerCaseHyphenSeparatedName;
53
import static org.jreleaser.util.StringUtils.isBlank;
54
import static org.jreleaser.util.StringUtils.isNotBlank;
55

56
/**
57
 * @author Andres Almiray
58
 * @since 0.1.0
59
 */
60
public final class Environment extends AbstractModelObject<Environment> implements Domain {
1✔
61
    private static final long serialVersionUID = 4554098923129885325L;
62

63
    private final Map<String, Object> properties = new LinkedHashMap<>();
1✔
64
    @JsonIgnore
1✔
65
    private final Map<String, Object> sourcedProperties = new LinkedHashMap<>();
66
    @JsonIgnore
67
    private PropertiesSource propertiesSource;
68
    private String variables;
69
    @JsonIgnore
70
    private Properties vars;
71
    @JsonIgnore
72
    private Path propertiesFile;
73

74
    @JsonIgnore
1✔
75
    private final org.jreleaser.model.api.environment.Environment immutable = new org.jreleaser.model.api.environment.Environment() {
1✔
76
        private static final long serialVersionUID = -7287090119869371299L;
77

78
        @Override
79
        public Properties getVars() {
80
            return vars;
1✔
81
        }
82

83
        @Override
84
        public String getVariables() {
85
            return variables;
×
86
        }
87

88
        @Override
89
        public Map<String, Object> getProperties() {
90
            return unmodifiableMap(properties);
×
91
        }
92

93
        @Override
94
        public Map<String, Object> asMap(boolean full) {
95
            return unmodifiableMap(Environment.this.asMap(full));
×
96
        }
97
    };
98

99
    public org.jreleaser.model.api.environment.Environment asImmutable() {
100
        return immutable;
1✔
101
    }
102

103
    @Override
104
    public void merge(Environment source) {
105
        this.variables = merge(this.variables, source.variables);
1✔
106
        setProperties(merge(this.properties, source.properties));
1✔
107
        setPropertiesSource(merge(this.propertiesSource, source.propertiesSource));
1✔
108
    }
1✔
109

110
    public String resolve(String key) {
111
        return env(key, Env.sys(key, ""));
1✔
112
    }
113

114
    public String resolve(String key, String value) {
115
        return env(key, Env.sys(key, value));
1✔
116
    }
117

118
    public String resolveOrDefault(String key, String value, String defaultValue) {
119
        String result = env(key, Env.sys(key, value));
1✔
120
        return isNotBlank(result) ? result : defaultValue;
1✔
121
    }
122

123
    private String env(String key, String value) {
124
        if (isNotBlank(value)) {
1✔
125
            return value;
×
126
        }
127
        return getVariable(envKey(key));
1✔
128
    }
129

130
    public Properties getVars() {
131
        return vars;
1✔
132
    }
133

134
    public String getVariable(String key) {
135
        return vars.getProperty(Env.envKey(key));
1✔
136
    }
137

138
    public boolean isSet() {
139
        return isNotBlank(variables) ||
1✔
140
            !properties.isEmpty();
1✔
141
    }
142

143
    public PropertiesSource getPropertiesSource() {
144
        return propertiesSource;
×
145
    }
146

147
    public void setPropertiesSource(PropertiesSource propertiesSource) {
148
        this.propertiesSource = propertiesSource;
1✔
149
        if (null != this.propertiesSource) {
1✔
150
            sourcedProperties.putAll(propertiesSource.getProperties());
1✔
151
        }
152
    }
1✔
153

154
    public String getVariables() {
155
        return variables;
×
156
    }
157

158
    public void setVariables(String variables) {
159
        this.variables = variables;
×
160
    }
×
161

162
    public Map<String, Object> getProperties() {
163
        return properties;
1✔
164
    }
165

166
    public void setProperties(Map<String, Object> properties) {
167
        this.properties.putAll(properties);
1✔
168
    }
1✔
169

170
    public Map<String, Object> getSourcedProperties() {
171
        return sourcedProperties;
1✔
172
    }
173

174
    public Path getPropertiesFile() {
175
        return propertiesFile;
1✔
176
    }
177

178
    @Override
179
    public Map<String, Object> asMap(boolean full) {
180
        Map<String, Object> map = new LinkedHashMap<>();
1✔
181
        map.put("variables", variables);
1✔
182
        map.put("properties", properties);
1✔
183

184
        return map;
1✔
185
    }
186

187
    public void initProps(JReleaserContext context) {
188
        if (null == vars) {
1✔
189
            vars = new Properties();
1✔
190

191
            Path settings = context.getSettings();
1✔
192

193
            if (null != settings) {
1✔
194
                if (!Files.isDirectory(settings)) {
1✔
195
                    loadVariables(context, settings);
×
196
                } else {
197
                    context.getLogger().warn(RB.$("environment.load.variables.dir", settings.toAbsolutePath()));
1✔
198
                    loadSettings(context);
1✔
199
                }
200
            } else {
201
                loadSettings(context);
1✔
202
            }
203

204
            if (isNotBlank(variables)) {
1✔
205
                loadVariables(context, context.getBasedir().resolve(variables.trim()));
×
206
            }
207

208
            Path envFilePath = context.getBasedir().resolve(".env");
1✔
209
            if (Files.exists(envFilePath)) {
1✔
210
                loadVariables(context, envFilePath);
×
211
            }
212

213
            // env vars
214
            Set<String> keyNames = new TreeSet<>();
1✔
215
            Properties envVars = new Properties();
1✔
216
            System.getenv().forEach((k, v) -> {
1✔
217
                if (k.startsWith(JRELEASER_ENV_PREFIX) && isNotBlank(v)) {
1✔
218
                    keyNames.add(k);
1✔
219
                    envVars.put(k, v);
1✔
220
                }
221
            });
1✔
222
            if (System.getenv().containsKey(envKey(DEFAULT_GIT_REMOTE))) {
1✔
223
                keyNames.add(envKey(DEFAULT_GIT_REMOTE));
×
224
            }
225
            if (!keyNames.isEmpty()) {
1✔
226
                context.getLogger().debug(RB.$("environment.variables.env"));
1✔
227
                keyNames.forEach(message -> context.getLogger().debug("  " + message));
1✔
228
            }
229

230
            // system props
231
            keyNames.clear();
1✔
232
            System.getProperties().stringPropertyNames().forEach(k -> {
1✔
233
                if (k.startsWith(JRELEASER_SYS_PREFIX)) keyNames.add(k);
1✔
234
            });
1✔
235
            if (!keyNames.isEmpty()) {
1✔
UNCOV
236
                context.getLogger().debug(RB.$("environment.system.properties"));
×
UNCOV
237
                keyNames.forEach(message -> context.getLogger().debug("  " + message));
×
238
            }
239

240
            // merge keyNames
241
            Properties merged = new Properties();
1✔
242
            merged.putAll(envVars);
1✔
243
            merged.putAll(this.vars);
1✔
244
            this.vars.clear();
1✔
245
            this.vars.putAll(merged);
1✔
246

247
            if (null != propertiesSource) {
1✔
248
                sourcedProperties.putAll(propertiesSource.getProperties());
1✔
249
            }
250
        }
251
    }
1✔
252

253
    private void loadSettings(JReleaserContext context) {
254
        Path configDirectory = null;
1✔
255

256
        String home = System.getenv(XDG_CONFIG_HOME);
1✔
257
        if (isNotBlank(home) && Files.exists(Paths.get(home).resolve("jreleaser"))) {
1✔
258
            configDirectory = Paths.get(home).resolve("jreleaser");
×
259
        }
260

261
        if (null == configDirectory) {
1✔
262
            home = System.getenv(JRELEASER_USER_HOME);
1✔
263
            if (isBlank(home)) {
1✔
264
                home = System.getProperty("user.home") + File.separator + ".jreleaser";
×
265
            }
266
            configDirectory = Paths.get(home);
1✔
267
        }
268

269
        loadVariables(context, resolveConfigFileAt(configDirectory)
1✔
270
            .orElse(configDirectory.resolve("config.properties")));
1✔
271
    }
1✔
272

273
    private void loadVariables(JReleaserContext context, Path file) {
274
        propertiesFile = file;
1✔
275
        context.getLogger().info(RB.$("environment.load.variables"), file.toAbsolutePath());
1✔
276
        if (Files.exists(file)) {
1✔
277
            try {
278
                Properties p = new Properties();
1✔
279
                if (file.getFileName().toString().endsWith(".properties") ||
1✔
280
                    file.getFileName().toString().equals(".env")) {
1✔
281
                    try (InputStream in = newInputStream(file)) {
×
282
                        p.load(in);
×
283
                    }
284
                } else {
285
                    p.putAll(JReleaserConfigLoader.loadProperties(file));
1✔
286
                }
287
                vars.putAll(p);
1✔
288

289
                Set<String> keyNames = new TreeSet<>();
1✔
290
                p.stringPropertyNames().stream()
1✔
291
                    .filter(k -> k.startsWith(JRELEASER_ENV_PREFIX)).
1✔
292
                    forEach(keyNames::add);
1✔
293

294
                if (!keyNames.isEmpty()) {
1✔
295
                    context.getLogger().debug(RB.$("environment.variables.file", file.getFileName().toString()));
1✔
296
                    keyNames.forEach(message -> context.getLogger().debug("  " + message));
1✔
297
                }
298
            } catch (IOException e) {
×
299
                context.getLogger().debug(RB.$("environment.variables.load.error"), file.toAbsolutePath(), e);
×
300
            }
1✔
301
        } else {
302
            context.getLogger().warn(RB.$("environment.variables.source.missing"), file.toAbsolutePath());
×
303
        }
304
    }
1✔
305

306
    private Optional<Path> resolveConfigFileAt(Path directory) {
307
        ServiceLoader<JReleaserConfigParser> parsers = ServiceLoader.load(JReleaserConfigParser.class,
1✔
308
            JReleaserConfigParser.class.getClassLoader());
1✔
309

310
        for (JReleaserConfigParser parser : parsers) {
1✔
311
            Path file = directory.resolve("config." + parser.getPreferredFileExtension());
1✔
312
            if (Files.exists(file)) {
1✔
313
                return Optional.of(file);
1✔
314
            }
315
        }
1✔
316

317
        return Optional.empty();
×
318
    }
319

320
    public boolean getBooleanProperty(String key) {
321
        boolean keyInProperties = properties.containsKey(key) && Boolean.parseBoolean(String.valueOf(properties.get(key)));
1✔
322
        boolean keyInSourcedProperties = sourcedProperties.containsKey(key) && Boolean.parseBoolean(String.valueOf(sourcedProperties.get(key)));
1✔
323
        return keyInProperties || keyInSourcedProperties;
1✔
324
    }
325

326
    public interface PropertiesSource extends Serializable {
327
        Map<String, String> getProperties();
328
    }
329

330
    public abstract static class AbstractPropertiesSource implements PropertiesSource {
1✔
331
        private static final long serialVersionUID = 9102569253517657171L;
332

333
        @Override
334
        public Map<String, String> getProperties() {
335
            Map<String, String> props = doGetProperties();
1✔
336
            Map<String, String> map = new LinkedHashMap<>();
1✔
337

338
            props.forEach((key, value) -> {
1✔
339
                if (key.startsWith("JRELEASER_")) return;
1✔
340
                String k = key.replace(".", "-");
1✔
341
                k = getPropertyNameForLowerCaseHyphenSeparatedName(k);
1✔
342
                map.put(k, value);
1✔
343
            });
1✔
344

345
            return map;
1✔
346
        }
347

348
        protected abstract Map<String, String> doGetProperties();
349
    }
350

351
    public static class PropertiesPropertiesSource extends AbstractPropertiesSource {
352
        private static final long serialVersionUID = 7747477120107034027L;
353

354
        private final Properties properties;
355

356
        public PropertiesPropertiesSource(Properties properties) {
1✔
357
            this.properties = properties;
1✔
358
        }
1✔
359

360
        @Override
361
        protected Map<String, String> doGetProperties() {
362
            Map<String, String> map = new LinkedHashMap<>();
1✔
363
            properties.forEach((k, v) -> map.put(String.valueOf(k), String.valueOf(v)));
1✔
364
            return map;
1✔
365
        }
366
    }
367

368
    public static class MapPropertiesSource extends AbstractPropertiesSource {
369
        private static final long serialVersionUID = 6643212572356054605L;
370

371
        private final Map<String, ?> properties;
372

373
        public MapPropertiesSource(Map<String, ?> properties) {
×
374
            this.properties = properties;
×
375
        }
×
376

377
        @Override
378
        protected Map<String, String> doGetProperties() {
379
            Map<String, String> map = new LinkedHashMap<>();
×
380
            properties.forEach((k, v) -> map.put(k, String.valueOf(v)));
×
381
            return map;
×
382
        }
383
    }
384
}
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