From aa071059e2a56c601f278de68247cdca0804018e Mon Sep 17 00:00:00 2001 From: Paul Johnston Date: Thu, 4 Jun 2026 10:28:01 +1000 Subject: [PATCH] Ticket #1843 - Fix stapler request double completion Fix issue with status pngs throwing java.lang.IllegalStateException: COMMITTED Stapler calls getDynamic, and will keep calling getDynamic on each part of the url, eventualy it hits the end of the parts of the url and thingks the response has not been handled Stapler sees it as 'not handled' and so eventually trys to complete the response itself, resulting in the double commit error Instead we can use doDynamic which means we will fill out the response in all cases, and stapler does not call the rest of the chain https://github.com/jenkinsci/stapler/blob/master/docs/reference.adoc "The doDynamic action method is the final consumer of the request." --- .../gitlabjenkins/webhook/ActionResolver.java | 3 +- .../gitlabjenkins/webhook/GitLabWebHook.java | 6 +- .../webhook/ActionResolverTest.java | 60 +++++++++---------- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/dabsquared/gitlabjenkins/webhook/ActionResolver.java b/src/main/java/com/dabsquared/gitlabjenkins/webhook/ActionResolver.java index 4d4135cf6..f0c5da381 100644 --- a/src/main/java/com/dabsquared/gitlabjenkins/webhook/ActionResolver.java +++ b/src/main/java/com/dabsquared/gitlabjenkins/webhook/ActionResolver.java @@ -44,10 +44,11 @@ public class ActionResolver { private static final Pattern COMMIT_STATUS_PATTERN = Pattern.compile("^(refs/[^/]+/)?(commits|builds)/(?[0-9a-fA-F]+)(?/status.json)?$"); - public WebHookAction resolve(final String projectName, StaplerRequest2 request) { + public WebHookAction resolve(StaplerRequest2 request) { Iterator restOfPathParts = Arrays.stream(request.getRestOfPath().split("/")) .filter(s -> !s.isEmpty()) .iterator(); + String projectName = restOfPathParts.hasNext() ? restOfPathParts.next() : ""; Item project = resolveProject(projectName, restOfPathParts); if (project == null) { throw HttpResponses.notFound(); diff --git a/src/main/java/com/dabsquared/gitlabjenkins/webhook/GitLabWebHook.java b/src/main/java/com/dabsquared/gitlabjenkins/webhook/GitLabWebHook.java index d7486397a..58fdccaf4 100644 --- a/src/main/java/com/dabsquared/gitlabjenkins/webhook/GitLabWebHook.java +++ b/src/main/java/com/dabsquared/gitlabjenkins/webhook/GitLabWebHook.java @@ -37,9 +37,9 @@ public String getUrlName() { return WEBHOOK_URL; } - public void getDynamic(final String projectName, final StaplerRequest2 request, StaplerResponse2 response) { - LOGGER.log(Level.INFO, "WebHook called with url: {0}", request.getRequestURIWithQueryString()); - actionResolver.resolve(projectName, request).execute(response); + public void doDynamic(final StaplerRequest2 request, StaplerResponse2 response) { + LOGGER.log(Level.FINE, "WebHook called with url: {0}", request.getRequestURIWithQueryString()); + actionResolver.resolve(request).execute(response); } @Extension diff --git a/src/test/java/com/dabsquared/gitlabjenkins/webhook/ActionResolverTest.java b/src/test/java/com/dabsquared/gitlabjenkins/webhook/ActionResolverTest.java index 0a6453f5e..9a28bdeab 100644 --- a/src/test/java/com/dabsquared/gitlabjenkins/webhook/ActionResolverTest.java +++ b/src/test/java/com/dabsquared/gitlabjenkins/webhook/ActionResolverTest.java @@ -50,11 +50,11 @@ static void setUp(JenkinsRule rule) { void getBranchBuildPageRedirect() throws Exception { String projectName = "getBranchBuildPageRedirect"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn(""); + when(request.getRestOfPath()).thenReturn(projectName); when(request.hasParameter("ref")).thenReturn(true); when(request.getMethod()).thenReturn("GET"); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(BranchBuildPageRedirectAction.class)); } @@ -63,10 +63,10 @@ void getBranchBuildPageRedirect() throws Exception { void getCommitStatus() throws Exception { String projectName = "getCommitStatus"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn("builds/1234abcd/status.json"); + when(request.getRestOfPath()).thenReturn(projectName + "/builds/1234abcd/status.json"); when(request.getMethod()).thenReturn("GET"); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(StatusJsonAction.class)); } @@ -75,10 +75,10 @@ void getCommitStatus() throws Exception { void getCommitBuildPageRedirect_builds() throws Exception { String projectName = "getCommitBuildPageRedirect_builds"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn("builds/1234abcd"); + when(request.getRestOfPath()).thenReturn(projectName + "/builds/1234abcd"); when(request.getMethod()).thenReturn("GET"); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(CommitBuildPageRedirectAction.class)); } @@ -87,10 +87,10 @@ void getCommitBuildPageRedirect_builds() throws Exception { void getCommitBuildPageRedirect_commits() throws Exception { String projectName = "getCommitBuildPageRedirect_commits"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn("commits/7890efab"); + when(request.getRestOfPath()).thenReturn(projectName + "/commits/7890efab"); when(request.getMethod()).thenReturn("GET"); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(CommitBuildPageRedirectAction.class)); } @@ -99,11 +99,11 @@ void getCommitBuildPageRedirect_commits() throws Exception { void getBranchStatusPng() throws Exception { String projectName = "getBranchStatusPng"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn("builds/status.png"); + when(request.getRestOfPath()).thenReturn(projectName + "/builds/status.png"); when(request.hasParameter("ref")).thenReturn(true); when(request.getMethod()).thenReturn("GET"); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(BranchStatusPngAction.class)); } @@ -112,11 +112,11 @@ void getBranchStatusPng() throws Exception { void getCommitStatusPng() throws Exception { String projectName = "getCommitStatusPng"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn("builds/status.png"); + when(request.getRestOfPath()).thenReturn(projectName + "/builds/status.png"); when(request.hasParameter("ref")).thenReturn(false); when(request.getMethod()).thenReturn("GET"); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(CommitStatusPngAction.class)); } @@ -125,13 +125,13 @@ void getCommitStatusPng() throws Exception { void postMergeRequest() throws Exception { String projectName = "postMergeRequest"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn(""); + when(request.getRestOfPath()).thenReturn(projectName); when(request.getMethod()).thenReturn("POST"); when(request.getHeader("X-Gitlab-Event")).thenReturn("Merge Request Hook"); when(request.getInputStream()) .thenReturn(new ResourceServletInputStream("ActionResolverTest_postMergeRequest.json")); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(MergeRequestBuildAction.class)); } @@ -140,13 +140,13 @@ void postMergeRequest() throws Exception { void postSystemHookMergeRequest() throws Exception { String projectName = "postSystemHookMergeRequest"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn(""); + when(request.getRestOfPath()).thenReturn(projectName); when(request.getMethod()).thenReturn("POST"); when(request.getHeader("X-Gitlab-Event")).thenReturn("System Hook"); when(request.getInputStream()) .thenReturn(new ResourceServletInputStream("ActionResolverTest_postSystemHook_MergeRequest.json")); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(MergeRequestBuildAction.class)); } @@ -155,13 +155,13 @@ void postSystemHookMergeRequest() throws Exception { void postSystemHookPush() throws Exception { String projectName = "postSystemHookPush"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn(""); + when(request.getRestOfPath()).thenReturn(projectName); when(request.getMethod()).thenReturn("POST"); when(request.getHeader("X-Gitlab-Event")).thenReturn("System Hook"); when(request.getInputStream()) .thenReturn(new ResourceServletInputStream("ActionResolverTest_postSystemHook_Push.json")); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(PushBuildAction.class)); } @@ -170,13 +170,13 @@ void postSystemHookPush() throws Exception { void postSystemHookPushTag() throws Exception { String projectName = "postSystemHookPushTag"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn(""); + when(request.getRestOfPath()).thenReturn(projectName); when(request.getMethod()).thenReturn("POST"); when(request.getHeader("X-Gitlab-Event")).thenReturn("System Hook"); when(request.getInputStream()) .thenReturn(new ResourceServletInputStream("ActionResolverTest_postSystemHook_PushTag.json")); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(PushBuildAction.class)); } @@ -185,12 +185,12 @@ void postSystemHookPushTag() throws Exception { void postNote() throws Exception { String projectName = "postNote"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn(""); + when(request.getRestOfPath()).thenReturn(projectName); when(request.getMethod()).thenReturn("POST"); when(request.getHeader("X-Gitlab-Event")).thenReturn("Note Hook"); when(request.getInputStream()).thenReturn(new ResourceServletInputStream("ActionResolverTest_postNote.json")); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(NoteBuildAction.class)); } @@ -199,12 +199,12 @@ void postNote() throws Exception { void postPush() throws Exception { String projectName = "postPush"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn(""); + when(request.getRestOfPath()).thenReturn(projectName); when(request.getMethod()).thenReturn("POST"); when(request.getHeader("X-Gitlab-Event")).thenReturn("Push Hook"); when(request.getInputStream()).thenReturn(new ResourceServletInputStream("ActionResolverTest_postPush.json")); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(PushBuildAction.class)); } @@ -213,13 +213,13 @@ void postPush() throws Exception { void postPushTag() throws Exception { String projectName = "postPushTag"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn(""); + when(request.getRestOfPath()).thenReturn(projectName); when(request.getMethod()).thenReturn("POST"); when(request.getHeader("X-Gitlab-Event")).thenReturn("Tag Push Hook"); when(request.getInputStream()) .thenReturn(new ResourceServletInputStream("ActionResolverTest_postPushTag.json")); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(PushBuildAction.class)); } @@ -228,12 +228,12 @@ void postPushTag() throws Exception { void postPushMissingEventHeader() throws Exception { String projectName = "postPushMissingEventHeader"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn(""); + when(request.getRestOfPath()).thenReturn(projectName); when(request.getMethod()).thenReturn("POST"); when(request.getHeader("X-Gitlab-Event")).thenReturn(null); when(request.getInputStream()).thenReturn(new ResourceServletInputStream("ActionResolverTest_postPush.json")); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(NoopAction.class)); } @@ -242,12 +242,12 @@ void postPushMissingEventHeader() throws Exception { void postPushUnsupportedEventHeader() throws Exception { String projectName = "postPushUnsupportedEventHeader"; jenkins.createFreeStyleProject(projectName); - when(request.getRestOfPath()).thenReturn(""); + when(request.getRestOfPath()).thenReturn(projectName); when(request.getMethod()).thenReturn("POST"); when(request.getHeader("X-Gitlab-Event")).thenReturn("__Not Supported Header__"); when(request.getInputStream()).thenReturn(new ResourceServletInputStream("ActionResolverTest_postPush.json")); - WebHookAction resolvedAction = new ActionResolver().resolve(projectName, request); + WebHookAction resolvedAction = new ActionResolver().resolve(request); assertThat(resolvedAction, instanceOf(NoopAction.class)); }