diff --git a/src/main/java/com/cloudogu/scmmanager/ScmV2Notifier.java b/src/main/java/com/cloudogu/scmmanager/ScmV2Notifier.java index 6d93323..3243931 100644 --- a/src/main/java/com/cloudogu/scmmanager/ScmV2Notifier.java +++ b/src/main/java/com/cloudogu/scmmanager/ScmV2Notifier.java @@ -27,17 +27,19 @@ public class ScmV2Notifier implements Notifier { private final NamespaceAndName namespaceAndName; private final HttpAuthentication httpAuthentication; private final boolean pullRequest; + private final String sourceBranch; private AsyncHttpClient client; private Consumer completionListener = response -> { }; - ScmV2Notifier(URL instance, NamespaceAndName namespaceAndName, HttpAuthentication httpAuthentication, boolean pullRequest) { + ScmV2Notifier(URL instance, NamespaceAndName namespaceAndName, HttpAuthentication httpAuthentication, boolean pullRequest, String sourceBranch) { this.instance = instance; this.namespaceAndName = namespaceAndName; this.httpAuthentication = httpAuthentication; this.pullRequest = pullRequest; + this.sourceBranch = sourceBranch; } @VisibleForTesting @@ -55,6 +57,10 @@ HttpAuthentication getHttpAuthentication() { return httpAuthentication; } + public String getSourceBranch() { + return sourceBranch; + } + @VisibleForTesting void setClient(AsyncHttpClient client) { this.client = client; @@ -104,9 +110,22 @@ public Object onCompleted(Response response) { private byte[] createRequestBody(BuildStatus buildStatus) { JSONObject jsonObject = JSONObject.fromObject(buildStatus); + if (pullRequest && sourceBranch != null) { + setReplacedBuild(buildStatus, jsonObject); + } return jsonObject.toString().getBytes(StandardCharsets.UTF_8); } + private void setReplacedBuild(BuildStatus buildStatus, JSONObject jsonObject) { + try { + String[] path = buildStatus.getName().split("/"); + path[path.length - 1] = URLEncoder.encode(sourceBranch, "UTF-8"); + jsonObject.put("replaces", String.join("/", path)); + } catch (Exception e) { + LOG.warn("Failed to compute replaced branch '{}' with path '{}'", sourceBranch, buildStatus.getName(), e); + } + } + private String createUrl(String revision, BuildStatus buildStatus) throws UnsupportedEncodingException { return String.format(getUrl(), instance.toExternalForm(), diff --git a/src/main/java/com/cloudogu/scmmanager/ScmV2NotifierProvider.java b/src/main/java/com/cloudogu/scmmanager/ScmV2NotifierProvider.java index c1de82d..cb7fdfc 100644 --- a/src/main/java/com/cloudogu/scmmanager/ScmV2NotifierProvider.java +++ b/src/main/java/com/cloudogu/scmmanager/ScmV2NotifierProvider.java @@ -42,7 +42,7 @@ private ScmV2Notifier createNotifier(Run run, JobInformation information, NamespaceAndName namespaceAndName = createNamespaceAndName(matcher); HttpAuthentication httpAuthentication = authenticationFactory.createHttp(run, information.getCredentialsId()); - return new ScmV2Notifier(instance, namespaceAndName, httpAuthentication, information.isPullRequest()); + return new ScmV2Notifier(instance, namespaceAndName, httpAuthentication, information.isPullRequest(), information.getSourceBranch()); } private NamespaceAndName createNamespaceAndName(Matcher matcher) { diff --git a/src/main/java/com/cloudogu/scmmanager/info/JobInformation.java b/src/main/java/com/cloudogu/scmmanager/info/JobInformation.java index 018127f..5f77bb2 100644 --- a/src/main/java/com/cloudogu/scmmanager/info/JobInformation.java +++ b/src/main/java/com/cloudogu/scmmanager/info/JobInformation.java @@ -7,13 +7,19 @@ public class JobInformation { private final String revision; private final String credentialsId; private final boolean pullRequest; + private final String sourceBranch; public JobInformation(String type, String url, String revision, String credentialsId, boolean pullRequest) { + this(type, url, revision, credentialsId, pullRequest, null); + } + + public JobInformation(String type, String url, String revision, String credentialsId, boolean pullRequest, String sourceBranch) { this.type = type; this.url = url; this.revision = revision; this.credentialsId = credentialsId; this.pullRequest = pullRequest; + this.sourceBranch = sourceBranch; } public String getType() { @@ -35,4 +41,8 @@ public String getCredentialsId() { public boolean isPullRequest() { return pullRequest; } + + public String getSourceBranch() { + return sourceBranch; + } } diff --git a/src/main/java/com/cloudogu/scmmanager/info/PullRequestJobInformationResolver.java b/src/main/java/com/cloudogu/scmmanager/info/PullRequestJobInformationResolver.java index 58c7b39..a9c4cf6 100644 --- a/src/main/java/com/cloudogu/scmmanager/info/PullRequestJobInformationResolver.java +++ b/src/main/java/com/cloudogu/scmmanager/info/PullRequestJobInformationResolver.java @@ -63,7 +63,8 @@ private Collection resolve(BranchJobProperty branchJobProperty) ((ScmManagerPullRequestHead) scmHead).getCloneInformation().getUrl(), ((ScmManagerPullRequestHead) scmHead).getId(), urc.getCredentialsId(), - true + true, + ((ScmManagerPullRequestHead) scmHead).getSource().getName() )).collect(toList()); } } diff --git a/src/test/java/com/cloudogu/scmmanager/ScmV2NotifierProviderTest.java b/src/test/java/com/cloudogu/scmmanager/ScmV2NotifierProviderTest.java index 6914dba..874b7b3 100644 --- a/src/test/java/com/cloudogu/scmmanager/ScmV2NotifierProviderTest.java +++ b/src/test/java/com/cloudogu/scmmanager/ScmV2NotifierProviderTest.java @@ -94,6 +94,16 @@ public void testGetWithPort() throws MalformedURLException { assertEquals("http://localhost:8080/scm", notifier.getInstance().toExternalForm()); } + @Test + public void testGetWithSourceBranch() throws MalformedURLException { + applyAuthentication(); + + JobInformation information = new JobInformation("sample", "https://scm.scm-manager.org/repo/ns/one", "pr-1", "one", true, "simple/branch"); + ScmV2Notifier notifier = provider.get(run, information).get(); + + assertEquals("simple/branch", notifier.getSourceBranch()); + } + private JobInformation createInformation(String s) { return new JobInformation("sample", s, "abc", "one", false); } @@ -101,5 +111,4 @@ private JobInformation createInformation(String s) { private void applyAuthentication() { when(authenticationFactory.createHttp(run, "one")).thenReturn(AuthenticationFactory.NOOP_HTTP_AUTHENTICATION); } - } diff --git a/src/test/java/com/cloudogu/scmmanager/ScmV2NotifierTest.java b/src/test/java/com/cloudogu/scmmanager/ScmV2NotifierTest.java index 2192441..56a15af 100644 --- a/src/test/java/com/cloudogu/scmmanager/ScmV2NotifierTest.java +++ b/src/test/java/com/cloudogu/scmmanager/ScmV2NotifierTest.java @@ -20,15 +20,54 @@ public class ScmV2NotifierTest { @Test public void testNotifyForChangesets() throws IOException, InterruptedException { - testNotify(false, "/scm/api/v2/ci/ns/one/changesets/abc/jenkins/hitchhiker%2Fheart-of-gold"); + testNotify("/scm/api/v2/ci/ns/one/changesets/abc/jenkins/hitchhiker%2Fheart-of-gold", "hitchhiker/heart-of-gold", null); + + verify( + putRequestedFor(urlMatching("/scm/api/v2/ci/ns/one/changesets/abc/jenkins/hitchhiker%2Fheart-of-gold")) + .withHeader("Authenticated", equalTo("yes; awesome")) + .withHeader("Content-Type", equalTo("application/vnd.scmm-cistatus+json;v=2")) + .withRequestBody( + matchingJsonPath("$.type", equalTo("jenkins")) + ) + .withRequestBody( + matchingJsonPath("$.name", equalTo("hitchhiker/heart-of-gold")) + ) + .withRequestBody( + matchingJsonPath("$.url", equalTo("https://hitchhiker.com")) + ) + .withRequestBody( + matchingJsonPath("$.status", equalTo("SUCCESS")) + ) + ); } @Test public void testNotifyForPullRequests() throws IOException, InterruptedException { - testNotify(true, "/scm/api/v2/ci/ns/one/pullrequest/abc/jenkins/hitchhiker%2Fheart-of-gold"); + testNotify("/scm/api/v2/ci/ns/one/pullrequest/abc/jenkins/hitchhiker%2Fpr-1", "hitchhiker/heart-of-gold", "hitchhiker/pr-1"); + + verify( + putRequestedFor(urlMatching("/scm/api/v2/ci/ns/one/pullrequest/abc/jenkins/hitchhiker%2Fpr-1")) + .withHeader("Authenticated", equalTo("yes; awesome")) + .withHeader("Content-Type", equalTo("application/vnd.scmm-cistatus+json;v=2")) + .withRequestBody( + matchingJsonPath("$.type", equalTo("jenkins")) + ) + .withRequestBody( + matchingJsonPath("$.name", equalTo("hitchhiker/pr-1")) + ) + .withRequestBody( + matchingJsonPath("$.url", equalTo("https://hitchhiker.com")) + ) + .withRequestBody( + matchingJsonPath("$.status", equalTo("SUCCESS")) + ) + .withRequestBody( + matchingJsonPath("$.replaces", equalTo("hitchhiker/hitchhiker%2Fheart-of-gold")) + ) + ); } - private void testNotify(boolean pullRequest, String notificationUrl) throws IOException, InterruptedException { + private void testNotify(String notificationUrl, String branch, String pullRequest) throws IOException, InterruptedException { stubFor( put(notificationUrl) .willReturn( @@ -44,7 +83,8 @@ private void testNotify(boolean pullRequest, String notificationUrl) throws IOEx new ScmV2Notifier( instanceURL, namespaceAndName, req -> req.setHeader("Authenticated", "yes; awesome"), - pullRequest); + pullRequest != null, + pullRequest == null ? null : branch); CountDownLatch cdl = new CountDownLatch(1); try (AsyncHttpClient client = new AsyncHttpClient()) { @@ -52,7 +92,7 @@ private void testNotify(boolean pullRequest, String notificationUrl) throws IOEx notifier.setCompletionListener((response -> cdl.countDown())); BuildStatus status = BuildStatus.success( - "hitchhiker/heart-of-gold", + pullRequest != null ? pullRequest : branch, "hitchhiker >> heart-of-gold", "https://hitchhiker.com" ); @@ -61,25 +101,6 @@ private void testNotify(boolean pullRequest, String notificationUrl) throws IOEx cdl.await(30, TimeUnit.SECONDS); } - - verify( - putRequestedFor(urlMatching(notificationUrl)) - .withHeader("Authenticated", equalTo("yes; awesome")) - .withHeader("Content-Type", equalTo("application/vnd.scmm-cistatus+json;v=2")) - .withRequestBody( - matchingJsonPath("$.type", equalTo("jenkins")) - ) - .withRequestBody( - matchingJsonPath("$.name", equalTo("hitchhiker/heart-of-gold")) - ) - .withRequestBody( - matchingJsonPath("$.url", equalTo("https://hitchhiker.com")) - ) - .withRequestBody( - matchingJsonPath("$.status", equalTo("SUCCESS")) - ) - ); - } private URL createInstanceURL() throws MalformedURLException {