forked from ChristianKatzmann/http-post-plugin
-
Notifications
You must be signed in to change notification settings - Fork 10
/
HttpPostPublisher.java
188 lines (158 loc) · 5.85 KB
/
HttpPostPublisher.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package jenkins.plugins.httppost;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.model.Run;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Notifier;
import hudson.tasks.Publisher;
import hudson.util.FormValidation;
import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeUnit;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
/**
* Upload all {@link hudson.model.Run.Artifact artifacts} using a multipart HTTP POST call to an
* specific URL.<br> Additional metadata will be included in the request as HTTP headers: {@code
* Job-Name}, {@code Build-Number} and {@code Build-Timestamp} are included automatically by the
* time writing.
*
* @author Christian Becker (christian.becker.1987@gmail.com)
*/
@SuppressWarnings("UnusedDeclaration") // This class will be loaded using its Descriptor.
public class HttpPostPublisher extends Notifier {
@DataBoundConstructor
public HttpPostPublisher() {
}
@SuppressWarnings({"unchecked", "deprecation"})
@Override
public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) {
if (build.getResult().isWorseOrEqualTo(Result.FAILURE)) {
listener.getLogger().println("HTTP POST: Skipping because of FAILURE");
return true;
}
List<Run.Artifact> artifacts = build.getArtifacts();
if (artifacts.isEmpty()) {
listener.getLogger().println("HTTP POST: No artifacts to POST");
return true;
}
Descriptor descriptor = getDescriptor();
String url = descriptor.url;
String headers = descriptor.headers;
if (url == null || url.length() == 0) {
listener.getLogger().println("HTTP POST: No URL specified");
return true;
}
try {
MultipartBuilder multipart = new MultipartBuilder();
multipart.type(MultipartBuilder.FORM);
for (Run.Artifact artifact : artifacts) {
multipart.addFormDataPart(artifact.getFileName(), artifact.getFileName(),
RequestBody.create(null, artifact.getFile()));
}
OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(30, TimeUnit.SECONDS);
client.setReadTimeout(60, TimeUnit.SECONDS);
Request.Builder builder = new Request.Builder();
builder.url(url);
builder.header("Job-Name", build.getProject().getName());
builder.header("Build-Number", String.valueOf(build.getNumber()));
builder.header("Build-Timestamp", String.valueOf(build.getTimeInMillis()));
if (headers != null && headers.length() > 0) {
String[] lines = headers.split("\r?\n");
for (String line : lines) {
int index = line.indexOf(':');
builder.header(line.substring(0, index).trim(), line.substring(index + 1).trim());
}
}
builder.post(multipart.build());
Request request = builder.build();
listener.getLogger().println(String.format("---> POST %s", url));
listener.getLogger().println(request.headers());
long start = System.nanoTime();
Response response = client.newCall(request).execute();
long time = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
listener.getLogger()
.println(String.format("<--- %s %s (%sms)", response.code(), response.message(), time));
listener.getLogger().println(response.body().string());
} catch (Exception e) {
e.printStackTrace(listener.getLogger());
}
return true;
}
@Override
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.NONE;
}
@Override
public Descriptor getDescriptor() {
return (Descriptor) super.getDescriptor();
}
@Extension
public static final class Descriptor extends BuildStepDescriptor<Publisher> {
public String url;
public String headers;
public Descriptor() {
load();
}
@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
}
@Override
public String getDisplayName() {
return "HTTP POST artifacts to an URL";
}
public FormValidation doCheckUrl(@QueryParameter String value) {
if (value.length() == 0) {
return FormValidation.error("URL must not be empty");
}
if (!value.startsWith("http://") && !value.startsWith("https://")) {
return FormValidation.error("URL must start with http:// or https://");
}
try {
new URL(value).toURI();
} catch (Exception e) {
return FormValidation.error(e.getMessage());
}
return FormValidation.ok();
}
public FormValidation doCheckHeaders(@QueryParameter String value) {
if (value.length() > 0) {
Headers.Builder headers = new Headers.Builder();
String[] lines = value.split("\r?\n");
for (String line : lines) {
int index = line.indexOf(':');
if (index == -1) {
return FormValidation.error("Unexpected header: " + line);
}
try {
headers.add(line.substring(0, index).trim(), line.substring(index + 1).trim());
} catch (Exception e) {
return FormValidation.error(e.getMessage());
}
}
}
return FormValidation.ok();
}
@Override
public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
req.bindJSON(this, json.getJSONObject("http-post"));
save();
return true;
}
}
}