• 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

84.0
/core/jreleaser-model-impl/src/main/java/org/jreleaser/model/spi/deploy/maven/Deployable.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.spi.deploy.maven;
19

20
import org.jreleaser.bundle.RB;
21
import org.jreleaser.mustache.TemplateContext;
22

23
import java.nio.file.Path;
24
import java.nio.file.Paths;
25
import java.util.Objects;
26
import java.util.Set;
27

28
import static org.jreleaser.util.CollectionUtils.setOf;
29
import static org.jreleaser.util.StringUtils.isNotBlank;
30

31
/**
32
 * @author Andres Almiray
33
 * @since 1.4.0
34
 */
35
public class Deployable implements Comparable<Deployable> {
36
    public static final String PACKAGING_AAR = "aar";
37
    public static final String PACKAGING_JAR = "jar";
38
    public static final String PACKAGING_WAR = "war";
39
    public static final String PACKAGING_POM = "pom";
40
    public static final String PACKAGING_NBM = "nbm";
41
    public static final String PACKAGING_ZIP = "zip";
42
    public static final String PACKAGING_MAVEN_ARCHETYPE = "maven-archetype";
43
    public static final String MAVEN_METADATA_XML = "maven-metadata.xml";
44
    public static final String EXT_JAR = ".jar";
45
    public static final String EXT_WAR = ".war";
46
    public static final String EXT_POM = ".pom";
47
    public static final String EXT_ASC = ".asc";
48
    public static final String EXT_MODULE = ".module";
49
    public static final String EXT_XML = ".xml";
50
    public static final String EXT_JSON = ".json";
51

52
    private static final String[] EXT_CHECKSUMS = {".md5", ".sha1", ".sha256", ".sha512"};
1✔
53

54
    private static final Set<String> JAR_EXCLUSIONS = setOf(
1✔
55
        PACKAGING_POM,
56
        PACKAGING_AAR,
57
        PACKAGING_WAR,
58
        PACKAGING_ZIP
59
    );
60

61
    private static final Set<String> SOURCE_EXCLUSIONS = setOf(
1✔
62
        PACKAGING_POM,
63
        PACKAGING_NBM,
64
        PACKAGING_AAR
65
    );
66

67
    private static final Set<String> JAVADOC_EXCLUSIONS = setOf(
1✔
68
        PACKAGING_POM,
69
        PACKAGING_NBM,
70
        PACKAGING_MAVEN_ARCHETYPE,
71
        PACKAGING_AAR
72
    );
73

74
    private final String stagingRepository;
75
    private final String path;
76
    private final String filename;
77
    private final String groupId;
78
    private final String artifactId;
79
    private final String version;
80
    private final String classifier;
81
    private final String extension;
82
    private final String packaging;
83
    private final boolean relocated;
84
    private final boolean snapshot;
85

86
    public Deployable(boolean snapshot, String stagingRepository, String path, String packaging, String filename, boolean relocated) {
1✔
87
        this.snapshot = snapshot;
1✔
88
        this.stagingRepository = stagingRepository;
1✔
89
        this.path = path;
1✔
90
        this.filename = filename;
1✔
91
        this.packaging = packaging;
1✔
92
        this.relocated = relocated;
1✔
93

94
        if (!filename.startsWith(MAVEN_METADATA_XML)) {
1✔
95
            Path p = Paths.get(path);
1✔
96
            this.version = p.getFileName().toString();
1✔
97
            p = p.getParent();
1✔
98
            this.artifactId = p.getFileName().toString();
1✔
99
            p = p.getParent();
1✔
100
            String gid = p.toString()
1✔
101
                .replace("/", ".")
1✔
102
                .replace("\\", ".");
1✔
103
            if (gid.startsWith(".")) {
1✔
104
                gid = gid.substring(1);
1✔
105
            }
106
            this.groupId = gid;
1✔
107

108
            String v = version;
1✔
109
            int l = version.length();
1✔
110
            if (snapshot) {
1✔
111
                // Maven requires snapshot versions to contain the literal "-SNAPSHOT" suffix
112
                if (!version.contains("SNAPSHOT")) {
1✔
113
                    throw new IllegalArgumentException(RB.$("ERROR_snapshot_version_missing_suffix", version));
1✔
114
                }
115
                // SNAPSHOT replaced with YYYYMMDD.HHmmSS-#
116
                v = version.substring(0, version.length() - "SNAPSHOT".length());
1✔
117
                l = v.length() + 17;
1✔
118
            }
119

120
            if (filename.contains(v)) {
1✔
121
                String str = filename.substring(filename.indexOf(v) + l + 1);
1✔
122
                if (filename.charAt(filename.indexOf(v) + l) == '-') {
1✔
123
                    this.classifier = str.substring(0, str.indexOf('.'));
1✔
124
                } else {
125
                    this.classifier = "";
1✔
126
                }
127
            } else {
1✔
128
                this.classifier = "";
×
129
            }
130

131
            int ll = artifactId.length() + 1 + l;
1✔
132
            if (isNotBlank(classifier)) ll += classifier.length() + 1;
1✔
133
            if (filename.length() > ll+1) {
1✔
134
                this.extension = filename.substring(ll+1);
1✔
135
            } else {
136
                this.extension = "";
×
137
            }
138
        } else {
1✔
139
            this.version = "";
×
140
            this.artifactId = "";
×
141
            this.groupId = "";
×
142
            this.classifier = "";
×
143
            this.extension = "";
×
144
        }
145
    }
1✔
146

147
    public TemplateContext props() {
148
        TemplateContext props = new TemplateContext();
1✔
149
        props.set("groupId", groupId);
1✔
150
        props.set("artifactId", artifactId);
1✔
151
        props.set("version", version);
1✔
152
        props.set("filename", filename);
1✔
153
        props.set("path", getDeployPath());
1✔
154
        return props;
1✔
155
    }
156

157
    public boolean requiresJar() {
158
        return isNotBlank(packaging) && !JAR_EXCLUSIONS.contains(packaging);
1✔
159
    }
160

161
    public boolean requiresWar() {
162
        return isNotBlank(packaging) && PACKAGING_WAR.equalsIgnoreCase(packaging);
1✔
163
    }
164

165
    public boolean requiresSourcesJar() {
166
        return isNotBlank(packaging) && !SOURCE_EXCLUSIONS.contains(packaging);
1✔
167
    }
168

169
    public boolean requiresJavadocJar() {
170
        return isNotBlank(packaging) && !JAVADOC_EXCLUSIONS.contains(packaging);
1✔
171
    }
172

173
    public String getGav() {
174
        return groupId + ":" + artifactId + ":" + version;
×
175
    }
176

177
    public String getStagingRepository() {
178
        return stagingRepository;
1✔
179
    }
180

181
    public String getPath() {
182
        return path;
1✔
183
    }
184

185
    public String getFullDeployPath() {
186
        return getDeployPath() + "/" + getFilename();
1✔
187
    }
188

189
    public String getDeployPath() {
190
        return path.replace("\\", "/").substring(1);
1✔
191
    }
192

193
    public String getFilename() {
194
        return filename;
1✔
195
    }
196

197
    public String getGroupId() {
198
        return groupId;
1✔
199
    }
200

201
    public String getArtifactId() {
202
        return artifactId;
1✔
203
    }
204

205
    public String getVersion() {
206
        return version;
1✔
207
    }
208

209
    public String getClassifier() {
210
        return classifier;
×
211
    }
212

213
    public String getExtension() {
214
        return extension;
×
215
    }
216

217
    public Path getLocalPath() {
218
        return Paths.get(stagingRepository, path, filename);
1✔
219
    }
220

221
    public boolean isRelocated() {
222
        return relocated;
1✔
223
    }
224

225
    public Deployable deriveByFilename(String filename) {
226
        return new Deployable(snapshot, stagingRepository, path, packaging, filename, false);
1✔
227
    }
228

229
    public Deployable deriveByFilename(String packaging, String filename) {
230
        return new Deployable(snapshot, stagingRepository, path, packaging, filename, false);
1✔
231
    }
232

233
    @Override
234
    public boolean equals(Object o) {
UNCOV
235
        if (this == o) return true;
×
UNCOV
236
        if (null == o || getClass() != o.getClass()) return false;
×
UNCOV
237
        Deployable that = (Deployable) o;
×
UNCOV
238
        return stagingRepository.equals(that.stagingRepository) &&
×
UNCOV
239
            path.equals(that.path) &&
×
UNCOV
240
            filename.equals(that.filename);
×
241
    }
242

243
    @Override
244
    public int hashCode() {
245
        return Objects.hash(stagingRepository, path, filename);
1✔
246
    }
247

248
    @Override
249
    public int compareTo(Deployable o) {
250
        if (null == o) return -1;
1✔
251
        return getFullDeployPath().compareTo(o.getFullDeployPath());
1✔
252
    }
253

254
    public boolean isArtifact() {
255
        return !isPom() &&
1✔
256
            !isSignature() &&
1✔
257
            !isChecksum() &&
1✔
258
            !isJson() &&
1✔
259
            !isXml() &&
1✔
260
            !isGradleMetadata() &&
1✔
261
            !isMavenMetadata();
1✔
262
    }
263

264
    public boolean isPom() {
265
        return filename.endsWith(EXT_POM);
1✔
266
    }
267

268
    public boolean isSignature() {
269
        return filename.endsWith(EXT_ASC);
1✔
270
    }
271

272
    public boolean isChecksum() {
273
        for (String ext : EXT_CHECKSUMS) {
1✔
274
            if (filename.endsWith(ext)) return true;
1✔
275
        }
276
        return false;
1✔
277
    }
278

279
    public boolean isJson() {
280
        return filename.endsWith(EXT_JSON);
1✔
281
    }
282

283
    public boolean isXml() {
284
        return filename.endsWith(EXT_XML);
1✔
285
    }
286

287
    public boolean isGradleMetadata() {
288
        return filename.endsWith(EXT_MODULE);
1✔
289
    }
290

291
    public boolean isMavenMetadata() {
292
        return filename.endsWith(MAVEN_METADATA_XML);
1✔
293
    }
294
}
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