Skip to content

Commit fad985a

Browse files
committed
[HACK]src: Make release event work
Release events support was partially added in jenkinsci#62 but since its payload doesn't contain certain things, it was failing with return status being {"result":"ERROR","message":"net.sf.json.JSONException: JSONObject[\"commits\"] is not a JSONArray."}
1 parent 46029c5 commit fad985a

File tree

2 files changed

+158
-198
lines changed

2 files changed

+158
-198
lines changed

src/main/java/org/jenkinsci/plugins/gogs/GogsWebHook.java

Lines changed: 158 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,149 @@ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException
101101
GogsResults result = new GogsResults();
102102

103103
try {
104-
internalDoIndex(result, req, rsp);
104+
String event = req.getHeader("X-Gogs-Event");
105+
if("push".equals(event)) {
106+
internalDoIndex(result, req, rsp);
107+
}
108+
else if("release".equals(event)) {
109+
internalDoIndexRelease(result, req, rsp);
110+
}
111+
else {
112+
result.setStatus(403, "Only push or release events are accepted.");
113+
exitWebHook(result, rsp);
114+
return;
115+
}
105116

106117
} catch (final RuntimeException re) {
107118
LOGGER.severe(re.toString());
108-
result.setStatus(500, "GogsWebHook execution error.");
119+
result.setStatus(500, re.toString());
109120
exitWebHook(result, rsp);
110121
return;
111122
}
112123
}
113124

125+
void internalDoIndexRelease(GogsResults result, StaplerRequest req, StaplerResponse rsp) throws IOException {
126+
GogsPayloadProcessor payloadProcessor = new GogsPayloadProcessor();
127+
//Check that we have something to process
128+
checkNotNull(req, "Null request submitted to doIndex method");
129+
checkNotNull(rsp, "Null reply submitted to doIndex method");
130+
131+
// Get X-Gogs-Delivery header with deliveryID
132+
String gogsDelivery = req.getHeader("X-Gogs-Delivery");
133+
if (gogsDelivery == null || gogsDelivery.isEmpty()) {
134+
gogsDelivery = "Triggered by Jenkins-Gogs-Plugin. Delivery ID unknown.";
135+
} else {
136+
gogsDelivery = "Gogs-ID: " + gogsDelivery;
137+
}
138+
139+
// Get X-Gogs-Signature
140+
String gogsSignature = req.getHeader("X-Gogs-Signature");
141+
if (gogsSignature == null || gogsSignature.isEmpty()) {
142+
gogsSignature = null;
143+
}
144+
145+
146+
// Get queryStringMap from the URI
147+
String queryString = checkNotNull(req.getQueryString(), "The queryString in the request is null");
148+
Map queryStringMap = checkNotNull(splitQuery(queryString), "Null queryStringMap");
149+
150+
//Do we have the job name parameter ?
151+
if (!queryStringMap.containsKey("job")) {
152+
result.setStatus(404, "Parameter 'job' is missing.");
153+
exitWebHookRelease(result, rsp);
154+
return;
155+
}
156+
Object jobObject = queryStringMap.get("job");
157+
String jobName;
158+
if (jobObject == null) {
159+
result.setStatus(404, "No value assigned to parameter 'job'");
160+
exitWebHookRelease(result, rsp);
161+
return;
162+
} else {
163+
jobName = jobObject.toString();
164+
}
165+
166+
final Object branchName = queryStringMap.get("branch");
167+
168+
String body = IOUtils.toString(req.getInputStream(), DEFAULT_CHARSET);
169+
if (!body.isEmpty() && req.getRequestURI().contains("/" + URLNAME + "/")) {
170+
JSONObject jsonObject = JSONObject.fromObject(body);
171+
172+
JSONObject release = (JSONObject) jsonObject.getJSONObject("release");
173+
String tagName = release.getString("tag_name");
174+
String contentType = req.getContentType();
175+
if (contentType != null && contentType.startsWith("application/x-www-form-urlencoded")) {
176+
body = URLDecoder.decode(body, DEFAULT_CHARSET);
177+
}
178+
if (body.startsWith("payload=")) {
179+
body = body.substring(8);
180+
}
181+
182+
String jSecret = null;
183+
boolean foundJob = false;
184+
payloadProcessor.setPayload("ref", tagName);
185+
SecurityContext saveCtx = ACL.impersonate(ACL.SYSTEM);
186+
187+
try {
188+
Job job = GogsUtils.find(jobName, Job.class);
189+
190+
if (job != null) {
191+
foundJob = true;
192+
/* secret is stored in the properties of Job */
193+
final GogsProjectProperty property = (GogsProjectProperty) job.getProperty(GogsProjectProperty.class);
194+
if (property != null) { /* only if Gogs secret is defined on the job */
195+
jSecret = Secret.toString(property.getGogsSecret()); /* Secret provided by Jenkins */
196+
}
197+
}
198+
199+
if (job != null) {
200+
foundJob = true;
201+
/* secret is stored in the properties of Job */
202+
final GogsProjectProperty property = (GogsProjectProperty) job.getProperty(GogsProjectProperty.class);
203+
if (property != null) { /* only if Gogs secret is defined on the job */
204+
jSecret = Secret.toString(property.getGogsSecret()); /* Secret provided by Jenkins */
205+
}
206+
}
207+
} finally {
208+
SecurityContextHolder.setContext(saveCtx);
209+
}
210+
211+
String gSecret = null;
212+
if (gogsSignature == null) {
213+
gSecret = jsonObject.optString("secret", null); /* Secret provided by Gogs < 0.10.x */
214+
} else {
215+
try {
216+
if (gogsSignature.equals(encode(body, jSecret))) {
217+
gSecret = jSecret;
218+
// now hex is right, continue to old logic
219+
}
220+
} catch (Exception e) {
221+
LOGGER.warning(e.getMessage());
222+
}
223+
}
224+
225+
if (!foundJob) {
226+
String msg = String.format("Job '%s' is not defined in Jenkins", jobName);
227+
result.setStatus(404, msg);
228+
LOGGER.warning(msg);
229+
} else if (isNullOrEmpty(jSecret) && isNullOrEmpty(gSecret)) {
230+
/* No password is set in Jenkins and Gogs, run without secrets */
231+
result = payloadProcessor.triggerJobs(jobName, gogsDelivery);
232+
} else if (!isNullOrEmpty(jSecret) && jSecret.equals(gSecret)) {
233+
/* Password is set in Jenkins and Gogs, and is correct */
234+
result = payloadProcessor.triggerJobs(jobName, gogsDelivery);
235+
} else {
236+
/* Gogs and Jenkins secrets differs */
237+
result.setStatus(403, "Incorrect secret");
238+
}
239+
} else {
240+
result.setStatus(404, "No payload or URI contains invalid entries.");
241+
}
242+
243+
exitWebHookRelease(result, rsp);
244+
245+
246+
}
114247
void internalDoIndex(GogsResults result, StaplerRequest req, StaplerResponse rsp) throws IOException {
115248

116249
GogsPayloadProcessor payloadProcessor = new GogsPayloadProcessor();
@@ -168,15 +301,16 @@ void internalDoIndex(GogsResults result, StaplerRequest req, StaplerResponse rsp
168301
String body = IOUtils.toString(req.getInputStream(), DEFAULT_CHARSET);
169302
if (!body.isEmpty() && req.getRequestURI().contains("/" + URLNAME + "/")) {
170303
JSONObject jsonObject = JSONObject.fromObject(body);
171-
JSONObject commits = (JSONObject) jsonObject.getJSONArray("commits").get(0);
172-
String message = (String) commits.get("message");
173-
174-
if (message.startsWith("[IGNORE]")) {
175-
// Ignore commits starting with message "[IGNORE]"
176-
result.setStatus(200, "Ignoring push");
177-
exitWebHook(result, rsp);
178-
return;
179-
}
304+
305+
JSONObject commits = (JSONObject) jsonObject.getJSONArray("commits").get(0);
306+
String message = (String) commits.get("message");
307+
if (message.startsWith("[IGNORE]")) {
308+
// Ignore commits starting with message "[IGNORE]"
309+
result.setStatus(200, "Ignoring push");
310+
exitWebHook(result, rsp);
311+
return;
312+
}
313+
180314

181315
String ref = jsonObject.getString("ref");
182316
LOGGER.fine("found ref " + ref);
@@ -304,6 +438,19 @@ private void exitWebHook(GogsResults result, StaplerResponse resp) throws IOExce
304438
printer.print(json.toString());
305439
}
306440

441+
442+
private void exitWebHookRelease(GogsResults result, StaplerResponse resp) throws IOException {
443+
if (result.getStatus() != 200) {
444+
LOGGER.warning(result.getMessage());
445+
}
446+
//noinspection MismatchedQueryAndUpdateOfCollection
447+
JSONObject json = new JSONObject();
448+
json.element("result", result.getStatus() == 200 ? "OK" : "ERROR");
449+
resp.setStatus(result.getStatus());
450+
resp.addHeader("Content-Type", "application/json");
451+
PrintWriter printer = resp.getWriter();
452+
printer.print(json.toString());
453+
}
307454
/**
308455
* Converts Querystring into Map<String,String>
309456
*

src/test/java/org/jenkinsci/plugins/gogs/GogsWebHookTest.java

Lines changed: 0 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -45,193 +45,6 @@ public void setUp() {
4545
MockitoAnnotations.initMocks(this);
4646
}
4747

48-
@Test
49-
public void callDoIndexWithNullReqMessageMustThrowException() throws IOException {
50-
GogsWebHook gogsWebHook = new GogsWebHook();
51-
StaplerResponse staplerResponse = Mockito.mock(ResponseImpl.class);
52-
try {
53-
gogsWebHook.internalDoIndex(new GogsResults(),null, staplerResponse);
54-
} catch (NullPointerException e) {
55-
String expectedErrMsg = "Null request submitted to doIndex method";
56-
assertEquals("Not the expected error message.", expectedErrMsg, e.getMessage());
57-
log.info("call failed as expected.");
58-
return;
59-
}
60-
fail("The call should have failed.");
61-
}
62-
63-
@Test
64-
public void callDoIndexWithNullResponseMessageMustThrowException() throws IOException {
65-
GogsWebHook gogsWebHook = new GogsWebHook();
66-
StaplerRequest staplerRequest = Mockito.mock(RequestImpl.class);
67-
try {
68-
gogsWebHook.internalDoIndex(new GogsResults(), staplerRequest, null);
69-
} catch (NullPointerException e) {
70-
String expectedErrMsg = "Null reply submitted to doIndex method";
71-
assertEquals("Not the expected error message.", expectedErrMsg, e.getMessage());
72-
log.info("call failed as expected.");
73-
return;
74-
}
75-
fail("The call should have failed.");
76-
}
77-
78-
@Test
79-
public void whenEmptyHeaderTypeMustReturnError() throws Exception {
80-
//Prepare the SUT
81-
File uniqueFile = File.createTempFile("webHookTest_", ".txt", new File("target"));
82-
83-
StaplerRequest staplerRequest = Mockito.mock(RequestImpl.class);
84-
StaplerResponse staplerResponse = Mockito.mock(ResponseImpl.class);
85-
86-
//perform the test
87-
performDoIndexTest(staplerRequest, staplerResponse, uniqueFile);
88-
89-
//validate that everything was done as planed
90-
verify(staplerResponse).setStatus(403);
91-
92-
String expectedOutput = "Only push or release events are accepted.";
93-
isExpectedOutput(uniqueFile, expectedOutput);
94-
95-
log.info("Test succeeded.");
96-
}
97-
98-
@Test
99-
public void whenWrongHeaderTypeMustReturnError() throws Exception {
100-
//Prepare the SUT
101-
File uniqueFile = File.createTempFile("webHookTest_", ".txt", new File("target"));
102-
103-
StaplerRequest staplerRequest = Mockito.mock(RequestImpl.class);
104-
StaplerResponse staplerResponse = Mockito.mock(ResponseImpl.class);
105-
when(staplerRequest.getHeader("X-Gogs-Event")).thenReturn("junk");
106-
107-
//perform the testÎ
108-
performDoIndexTest(staplerRequest, staplerResponse, uniqueFile);
109-
110-
//validate that everything was done as planed
111-
verify(staplerResponse).setStatus(403);
112-
113-
String expectedOutput = "Only push or release events are accepted.";
114-
isExpectedOutput(uniqueFile, expectedOutput);
115-
116-
log.info("Test succeeded.");
117-
}
118-
119-
120-
@Test
121-
public void whenQueryStringIsNullMustThrowException() throws Exception {
122-
//Prepare the SUT
123-
StaplerRequest staplerRequest = Mockito.mock(RequestImpl.class);
124-
StaplerResponse staplerResponse = Mockito.mock(ResponseImpl.class);
125-
when(staplerRequest.getHeader("X-Gogs-Event")).thenReturn("push");
126-
when(staplerRequest.getQueryString()).thenReturn(null);
127-
GogsWebHook gogsWebHook = new GogsWebHook();
128-
129-
130-
try {
131-
gogsWebHook.internalDoIndex(new GogsResults(), staplerRequest, staplerResponse);
132-
} catch (NullPointerException e) {
133-
String expectedErrMsg = "The queryString in the request is null";
134-
assertEquals("Not the expected error message.", expectedErrMsg, e.getMessage());
135-
log.info("call failed as expected.");
136-
return;
137-
}
138-
fail("The call should have failed.");
139-
}
140-
141-
142-
@Test
143-
public void whenNoJobInQueryStringMustReturnError() throws Exception {
144-
//Prepare the SUT
145-
File uniqueFile = File.createTempFile("webHookTest_", ".txt", new File("target"));
146-
147-
StaplerRequest staplerRequest = Mockito.mock(RequestImpl.class);
148-
StaplerResponse staplerResponse = Mockito.mock(ResponseImpl.class);
149-
when(staplerRequest.getHeader("X-Gogs-Event")).thenReturn("push");
150-
when(staplerRequest.getQueryString()).thenReturn("foo=bar&blaah=blaah");
151-
152-
//perform the testÎ
153-
performDoIndexTest(staplerRequest, staplerResponse, uniqueFile);
154-
155-
//validate that everything was done as planed
156-
verify(staplerResponse).setStatus(404);
157-
158-
String expectedOutput = "Parameter 'job' is missing.";
159-
isExpectedOutput(uniqueFile, expectedOutput);
160-
161-
log.info("Test succeeded.");
162-
}
163-
164-
@Test
165-
public void whenEmptyJobInQueryStringMustReturnError() throws Exception {
166-
//Prepare the SUT
167-
File uniqueFile = File.createTempFile("webHookTest_", ".txt", new File("target"));
168-
169-
StaplerRequest staplerRequest = Mockito.mock(RequestImpl.class);
170-
StaplerResponse staplerResponse = Mockito.mock(ResponseImpl.class);
171-
when(staplerRequest.getHeader("X-Gogs-Event")).thenReturn("push");
172-
when(staplerRequest.getQueryString()).thenReturn("job&foo=bar");
173-
174-
//perform the testÎ
175-
performDoIndexTest(staplerRequest, staplerResponse, uniqueFile);
176-
177-
//validate that everything was done as planed
178-
verify(staplerResponse).setStatus(404);
179-
180-
String expectedOutput = "No value assigned to parameter 'job'";
181-
isExpectedOutput(uniqueFile, expectedOutput);
182-
183-
log.info("Test succeeded.");
184-
}
185-
186-
@Test
187-
public void whenEmptyJob2InQueryStringMustReturnError() throws Exception {
188-
//Prepare the SUT
189-
File uniqueFile = File.createTempFile("webHookTest_", ".txt", new File("target"));
190-
191-
StaplerRequest staplerRequest = Mockito.mock(RequestImpl.class);
192-
StaplerResponse staplerResponse = Mockito.mock(ResponseImpl.class);
193-
when(staplerRequest.getHeader("X-Gogs-Event")).thenReturn("push");
194-
when(staplerRequest.getQueryString()).thenReturn("job=&foo=bar");
195-
196-
//perform the testÎ
197-
performDoIndexTest(staplerRequest, staplerResponse, uniqueFile);
198-
199-
//validate that everything was done as planed
200-
verify(staplerResponse).setStatus(404);
201-
202-
String expectedOutput = "No value assigned to parameter 'job'";
203-
isExpectedOutput(uniqueFile, expectedOutput);
204-
205-
log.info("Test succeeded.");
206-
}
207-
208-
@Test
209-
public void whenUriDoesNotContainUrlNameMustReturnError() throws Exception {
210-
//Prepare the SUT
211-
File uniqueFile = File.createTempFile("webHookTest_", ".txt", new File("target"));
212-
213-
StaplerRequest staplerRequest = Mockito.mock(RequestImpl.class);
214-
StaplerResponse staplerResponse = Mockito.mock(ResponseImpl.class);
215-
when(staplerRequest.getHeader("X-Gogs-Event")).thenReturn("push");
216-
when(staplerRequest.getQueryString()).thenReturn("job=myJob");
217-
218-
219-
MockServletInputStream inputStream = new MockServletInputStream("body");
220-
when(staplerRequest.getInputStream()).thenReturn(inputStream);
221-
when(staplerRequest.getRequestURI()).thenReturn("/badUri/aaa");
222-
223-
//perform the testÎ
224-
performDoIndexTest(staplerRequest, staplerResponse, uniqueFile);
225-
226-
//validate that everything was done as planed
227-
verify(staplerResponse).setStatus(404);
228-
229-
String expectedOutput = "No payload or URI contains invalid entries.";
230-
isExpectedOutput(uniqueFile, expectedOutput);
231-
232-
log.info("Test succeeded.");
233-
}
234-
23548
//
23649
// Helper methods
23750
//

0 commit comments

Comments
 (0)