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

jreleaser / jreleaser / #558

08 Dec 2025 02:56PM UTC coverage: 48.239% (+0.02%) from 48.215%
#558

push

github

aalmiray
feat(core): warn when a name template cannot be resolved

Closes #1960

Closes #1961

299 of 573 new or added lines in 133 files covered. (52.18%)

4 existing lines in 4 files now uncovered.

26047 of 53996 relevant lines covered (48.24%)

0.48 hits per line

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

32.35
/sdks/jreleaser-http-java-sdk/src/main/java/org/jreleaser/sdk/http/HttpAnnouncer.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.sdk.http;
19

20
import feign.form.FormData;
21
import org.jreleaser.bundle.RB;
22
import org.jreleaser.extensions.api.workflow.WorkflowListenerException;
23
import org.jreleaser.model.Http;
24
import org.jreleaser.model.api.JReleaserCommand;
25
import org.jreleaser.model.api.announce.HttpAnnouncers;
26
import org.jreleaser.model.api.hooks.ExecutionEvent;
27
import org.jreleaser.model.internal.JReleaserContext;
28
import org.jreleaser.model.spi.announce.AnnounceException;
29
import org.jreleaser.model.spi.announce.Announcer;
30
import org.jreleaser.model.spi.upload.UploadException;
31
import org.jreleaser.mustache.TemplateContext;
32
import org.jreleaser.sdk.commons.ClientUtils;
33

34
import java.util.Base64;
35
import java.util.LinkedHashMap;
36
import java.util.Map;
37

38
import static java.nio.charset.StandardCharsets.UTF_8;
39
import static org.jreleaser.mustache.Templates.resolveTemplate;
40
import static org.jreleaser.util.StringUtils.isNotBlank;
41

42
/**
43
 * @author Andres Almiray
44
 * @since 1.3.0
45
 */
46
@org.jreleaser.infra.nativeimage.annotations.NativeImage
47
public class HttpAnnouncer implements Announcer<org.jreleaser.model.api.announce.HttpAnnouncers> {
48
    private final JReleaserContext context;
49
    private final org.jreleaser.model.internal.announce.HttpAnnouncers https;
50

51
    public HttpAnnouncer(JReleaserContext context) {
1✔
52
        this.context = context;
1✔
53
        this.https = context.getModel().getAnnounce().getConfiguredHttp();
1✔
54
    }
1✔
55

56
    @Override
57
    public HttpAnnouncers getAnnouncer() {
58
        return https.asImmutable();
1✔
59
    }
60

61
    @Override
62
    public String getName() {
63
        return org.jreleaser.model.api.announce.HttpAnnouncers.TYPE;
1✔
64
    }
65

66
    @Override
67
    public boolean isEnabled() {
68
        return https.isEnabled();
1✔
69
    }
70

71
    @Override
72
    public void announce() throws AnnounceException {
73
        Map<String, org.jreleaser.model.internal.announce.HttpAnnouncer> http = https.getHttp();
1✔
74

75
        for (Map.Entry<String, org.jreleaser.model.internal.announce.HttpAnnouncer> e : http.entrySet()) {
1✔
76
            if (e.getValue().isEnabled()) {
1✔
77
                context.getLogger().setPrefix("http." + e.getKey());
1✔
78
                try {
79
                    announce(e.getValue());
1✔
80
                } catch (AnnounceException x) {
×
81
                    context.getLogger().warn(x.getMessage().trim());
×
82
                } finally {
83
                    context.getLogger().restorePrefix();
1✔
84
                }
85
            }
86
        }
1✔
87
    }
1✔
88

89
    public void announce(org.jreleaser.model.internal.announce.HttpAnnouncer announcer) throws AnnounceException {
90
        String payload = "";
1✔
91
        if (isNotBlank(announcer.getPayload())) {
1✔
92
            payload = announcer.getResolvedPayload(context);
1✔
93
        } else {
94
            TemplateContext props = context.props();
×
NEW
95
            context.getModel().getRelease().getReleaser().fillProps(props, context);
×
96
            payload = announcer.getResolvedPayloadTemplate(context, props);
×
97
        }
98

99
        String resolvedUrl = announcer.getResolvedUrl(context);
1✔
100
        context.getLogger().info("url: {}", resolvedUrl);
1✔
101
        context.getLogger().debug("payload: {}", payload);
1✔
102

103
        if (context.isDryrun()) return;
1✔
104

105
        fireAnnouncerEvent(ExecutionEvent.before(JReleaserCommand.ANNOUNCE.toStep()), announcer);
×
106

107
        String username = announcer.getUsername();
×
108
        String password = announcer.getPassword();
×
109

110
        try {
111
            Map<String, String> headers = new LinkedHashMap<>();
×
112
            switch (announcer.resolveAuthorization()) {
×
113
                case NONE:
114
                    break;
×
115
                case BASIC:
116
                    String auth = username + ":" + password;
×
117
                    byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(UTF_8));
×
118
                    auth = new String(encodedAuth, UTF_8);
×
119
                    headers.put("Authorization", "Basic " + auth);
×
120
                    break;
×
121
                case BEARER:
122
                    headers.put("Authorization", announcer.getBearerKeyword() + " " + password);
×
123
                    break;
124
            }
125

126
            resolveHeaders(announcer, headers);
×
127

128
            FormData data = ClientUtils.toFormData(
×
129
                "payload",
130
                headers.computeIfAbsent("Content-Type", k -> "text/plain"),
×
131
                payload);
132

133
            if (announcer.getMethod() == Http.Method.POST) {
×
134
                ClientUtils.postFile(context.getLogger(),
×
135
                    resolvedUrl,
136
                    announcer.getConnectTimeout(),
×
137
                    announcer.getReadTimeout(),
×
138
                    data,
139
                    headers);
140
            } else {
141
                ClientUtils.putFile(context.getLogger(),
×
142
                    resolvedUrl,
143
                    announcer.getConnectTimeout(),
×
144
                    announcer.getReadTimeout(),
×
145
                    data,
146
                    headers);
147
            }
148

149
            fireAnnouncerEvent(ExecutionEvent.success(JReleaserCommand.ANNOUNCE.toStep()), announcer);
×
150
        } catch (UploadException e) {
×
151
            fireAnnouncerEvent(ExecutionEvent.failure(JReleaserCommand.ANNOUNCE.toStep(), e), announcer);
×
152

153
            context.getLogger().trace(e);
×
154
            throw new AnnounceException(e.getMessage(), e);
×
155
        }
×
156
    }
×
157

158
    private void resolveHeaders(org.jreleaser.model.internal.announce.HttpAnnouncer announcer, Map<String, String> headers) {
159
        TemplateContext props = context.props();
×
160
        announcer.getHeaders().forEach((k, v) -> {
×
NEW
161
            String value = resolveTemplate(context.getLogger(), v, props);
×
162
            if (isNotBlank(value)) headers.put(k, value);
×
163
        });
×
164
    }
×
165

166
    private void fireAnnouncerEvent(ExecutionEvent event, org.jreleaser.model.internal.announce.HttpAnnouncer http) {
167
        try {
168
            context.fireAnnounceStepEvent(event, http.asImmutable());
×
169
        } catch (WorkflowListenerException e) {
×
170
            context.getLogger().error(RB.$("listener.failure", e.getListener().getClass().getName()));
×
171
            context.getLogger().trace(e);
×
172
        }
×
173
    }
×
174
}
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