This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to branch feature/SLING-8337 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-committer-cli.git
commit 6ef8c7286e12f78b0e2c0203b274b89796432457 Author: Robert Munteanu <[email protected]> AuthorDate: Wed Apr 24 13:48:00 2019 +0300 SLING-8337 - Create sub-command to manage the Jira update when promoting a release Implement VersionClient.findUnresolvedIssues --- .../apache/sling/cli/impl/jira/VersionClient.java | 49 ++++++++++++++++---- ...GetRelatedIssueCountsForVersionsJiraAction.java | 19 ++------ .../cli/impl/jira/IssuesSearchJiraAction.java | 53 ++++++++++++++++++++++ .../org/apache/sling/cli/impl/jira/JiraAction.java | 16 +++++++ .../cli/impl/jira/ListVersionsJiraAction.java | 11 +---- .../org/apache/sling/cli/impl/jira/MockJira.java | 4 +- .../sling/cli/impl/jira/VersionClientTest.java | 9 ++++ src/test/resources/README.md | 1 + .../search/unresolved-committer-cli-1.0.0.json | 26 +++++++++++ 9 files changed, 153 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/apache/sling/cli/impl/jira/VersionClient.java b/src/main/java/org/apache/sling/cli/impl/jira/VersionClient.java index 829a4da..0cf8eea 100644 --- a/src/main/java/org/apache/sling/cli/impl/jira/VersionClient.java +++ b/src/main/java/org/apache/sling/cli/impl/jira/VersionClient.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringWriter; import java.lang.reflect.Type; +import java.net.URISyntaxException; import java.util.List; import java.util.Optional; import java.util.function.Predicate; @@ -28,6 +29,7 @@ import java.util.function.Predicate; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.sling.cli.impl.ComponentContextHelper; @@ -154,8 +156,36 @@ public class VersionClient { } } } + + public List<Issue> findUnresolvedIssues(Release release) throws IOException { + + try { + HttpGet get = newGet("search"); + URIBuilder builder = new URIBuilder(get.getURI()); + builder.addParameter("jql", "project = "+ PROJECT_KEY+" AND resolution = Unresolved AND fixVersion = \"" + release.getName() + "\""); + builder.addParameter("fields", "summary"); + get.setURI(builder.build()); + + try ( CloseableHttpClient client = httpClientFactory.newClient() ) { + try (CloseableHttpResponse response = client.execute(get)) { + try (InputStream content = response.getEntity().getContent(); + InputStreamReader reader = new InputStreamReader(content)) { + + if (response.getStatusLine().getStatusCode() != 200) { + throw newException(response, reader); + } + + Gson gson = new Gson(); + return gson.fromJson(reader, IssueResponse.class).getIssues(); + } + } + } + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e); + } + } - private IOException newException(CloseableHttpResponse response, InputStreamReader reader) throws IOException { + private IOException newException(CloseableHttpResponse response, InputStreamReader reader) { StringBuilder message = new StringBuilder(); message.append("Status line : " + response.getStatusLine()); @@ -163,14 +193,15 @@ public class VersionClient { try { Gson gson = new Gson(); ErrorResponse errors = gson.fromJson(reader, ErrorResponse.class); - if ( !errors.getErrorMessages().isEmpty() ) - message.append(". Error messages: ") - .append(errors.getErrorMessages()); - - if ( !errors.getErrors().isEmpty() ) - errors.getErrors().entrySet().stream() - .forEach( e -> message.append(". Error for " + e.getKey() + " : " + e.getValue())); - + if ( errors != null ) { + if ( !errors.getErrorMessages().isEmpty() ) + message.append(". Error messages: ") + .append(errors.getErrorMessages()); + + if ( !errors.getErrors().isEmpty() ) + errors.getErrors().entrySet().stream() + .forEach( e -> message.append(". Error for " + e.getKey() + " : " + e.getValue())); + } } catch ( JsonIOException | JsonSyntaxException e) { message.append(". Failed parsing response as JSON ( ") .append(e.getMessage()) diff --git a/src/test/java/org/apache/sling/cli/impl/jira/GetRelatedIssueCountsForVersionsJiraAction.java b/src/test/java/org/apache/sling/cli/impl/jira/GetRelatedIssueCountsForVersionsJiraAction.java index aa9616f..fd134e8 100644 --- a/src/test/java/org/apache/sling/cli/impl/jira/GetRelatedIssueCountsForVersionsJiraAction.java +++ b/src/test/java/org/apache/sling/cli/impl/jira/GetRelatedIssueCountsForVersionsJiraAction.java @@ -17,13 +17,9 @@ package org.apache.sling.cli.impl.jira; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.io.IOUtils; - import com.sun.net.httpserver.HttpExchange; public class GetRelatedIssueCountsForVersionsJiraAction implements JiraAction { @@ -40,17 +36,10 @@ public class GetRelatedIssueCountsForVersionsJiraAction implements JiraAction { return false; int version = Integer.parseInt(matcher.group(1)); - InputStream in = getClass().getResourceAsStream("/jira/relatedIssueCounts/" + version + ".json"); - if ( in == null ) { - ex.sendResponseHeaders(404, -1); - } else { - ex.sendResponseHeaders(200, 0); - try ( OutputStream out = ex.getResponseBody() ) { - IOUtils.copy(in, out); - } - } - - return false; + + serveFileFromClasspath(ex, "/jira/relatedIssueCounts/" + version + ".json"); + + return true; } } diff --git a/src/test/java/org/apache/sling/cli/impl/jira/IssuesSearchJiraAction.java b/src/test/java/org/apache/sling/cli/impl/jira/IssuesSearchJiraAction.java new file mode 100644 index 0000000..96df4c7 --- /dev/null +++ b/src/test/java/org/apache/sling/cli/impl/jira/IssuesSearchJiraAction.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sling.cli.impl.jira; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.io.Charsets; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; + +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; + +public class IssuesSearchJiraAction implements JiraAction { + + static final String KNOWN_JQL_QUERY = "project = SLING AND resolution = Unresolved AND fixVersion = \"Committer CLI 1.0.0\""; + + @Override + public boolean tryHandle(HttpExchange ex) throws IOException { + if ( !ex.getRequestMethod().equals("GET") || + !ex.getRequestURI().getPath().equals("/jira/rest/api/2/search") ) { + return false; + } + + List<NameValuePair> parsed = URLEncodedUtils.parse(ex.getRequestURI(), Charsets.UTF_8); + + for ( NameValuePair pair : parsed ) { + if ( "jql".equals(pair.getName()) && KNOWN_JQL_QUERY.equals(pair.getValue()) ) { + serveFileFromClasspath(ex, "/jira/search/unresolved-committer-cli-1.0.0.json"); + return true; + } + } + error(ex, new Gson(), er -> er.getErrorMessages().add("Unable to run unknown JQL query, only available one is [" + KNOWN_JQL_QUERY +"]")); + + return true; + } + +} diff --git a/src/test/java/org/apache/sling/cli/impl/jira/JiraAction.java b/src/test/java/org/apache/sling/cli/impl/jira/JiraAction.java index 6cbc1b9..8d84a3a 100644 --- a/src/test/java/org/apache/sling/cli/impl/jira/JiraAction.java +++ b/src/test/java/org/apache/sling/cli/impl/jira/JiraAction.java @@ -17,9 +17,12 @@ package org.apache.sling.cli.impl.jira; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.function.Consumer; +import org.apache.commons.io.IOUtils; import org.apache.sling.cli.impl.jira.ErrorResponse; import com.google.gson.Gson; @@ -36,5 +39,18 @@ public interface JiraAction { } } + default void serveFileFromClasspath(HttpExchange ex, String classpathLocation) throws IOException { + InputStream in = getClass().getResourceAsStream(classpathLocation); + if ( in == null ) { + ex.sendResponseHeaders(404, -1); + return; + } + + ex.sendResponseHeaders(200, 0); + try ( OutputStream out = ex.getResponseBody() ) { + IOUtils.copy(in, out); + } + } + boolean tryHandle(HttpExchange ex) throws IOException; } diff --git a/src/test/java/org/apache/sling/cli/impl/jira/ListVersionsJiraAction.java b/src/test/java/org/apache/sling/cli/impl/jira/ListVersionsJiraAction.java index 30ce879..acce035 100644 --- a/src/test/java/org/apache/sling/cli/impl/jira/ListVersionsJiraAction.java +++ b/src/test/java/org/apache/sling/cli/impl/jira/ListVersionsJiraAction.java @@ -1,10 +1,6 @@ package org.apache.sling.cli.impl.jira; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.apache.commons.io.IOUtils; import com.sun.net.httpserver.HttpExchange; @@ -18,12 +14,7 @@ public class ListVersionsJiraAction implements JiraAction { return false; } - ex.sendResponseHeaders(200, 0); - try ( InputStream in = getClass().getResourceAsStream("/jira/versions.json"); - OutputStream out = ex.getResponseBody() ) { - IOUtils.copy(in, out); - } - + serveFileFromClasspath(ex, "/jira/versions.json"); return true; } } diff --git a/src/test/java/org/apache/sling/cli/impl/jira/MockJira.java b/src/test/java/org/apache/sling/cli/impl/jira/MockJira.java index e26dd87..9dcffcd 100644 --- a/src/test/java/org/apache/sling/cli/impl/jira/MockJira.java +++ b/src/test/java/org/apache/sling/cli/impl/jira/MockJira.java @@ -57,8 +57,9 @@ public class MockJira extends ExternalResource { @Override public Result authenticate(HttpExchange t) { + // get requests are never authenticated if ( t.getRequestMethod().contentEquals("GET") ) - return new Authenticator.Success(new HttpPrincipal("anonymous", getClass().getSimpleName())); + return new Authenticator.Success(new HttpPrincipal("anonymous", getClass().getSimpleName())); return super.authenticate(t); } }); @@ -67,6 +68,7 @@ public class MockJira extends ExternalResource { actions.add(new ListVersionsJiraAction()); actions.add(new GetRelatedIssueCountsForVersionsJiraAction()); actions.add(new CreateVersionJiraAction()); + actions.add(new IssuesSearchJiraAction()); // fallback, always executed actions.add(new JiraAction() { diff --git a/src/test/java/org/apache/sling/cli/impl/jira/VersionClientTest.java b/src/test/java/org/apache/sling/cli/impl/jira/VersionClientTest.java index 2951b3b..d279a43 100644 --- a/src/test/java/org/apache/sling/cli/impl/jira/VersionClientTest.java +++ b/src/test/java/org/apache/sling/cli/impl/jira/VersionClientTest.java @@ -17,12 +17,14 @@ package org.apache.sling.cli.impl.jira; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.sling.cli.impl.CredentialsService; @@ -103,4 +105,11 @@ public class VersionClientTest { public void illegalVersionFails() throws IOException { versionClient.create(""); } + + @Test + public void findUnresolvedIssuesForVersion() throws IOException { + List<Issue> issues = versionClient.findUnresolvedIssues(Release.fromString("Committer CLI 1.0.0").get(0)); + + assertThat(issues, hasSize(2)); + } } diff --git a/src/test/resources/README.md b/src/test/resources/README.md index 3158b2f..76be9cb 100644 --- a/src/test/resources/README.md +++ b/src/test/resources/README.md @@ -8,4 +8,5 @@ These resources are downloaded from remote servers and maybe slightly tweaked to http https://issues.apache.org/jira/rest/api/2/project/SLING/versions | jq '.[0:199]' > src/test/resources/jira/versions.json http https://issues.apache.org/jira/rest/api/2/version/12329667/relatedIssueCounts | jq '.' > src/test/resources/jira/relatedIssueCounts/12329667.json http https://issues.apache.org/jira/rest/api/2/version/12329844/relatedIssueCounts | jq '.' > src/test/resources/jira/relatedIssueCounts/12329844.json +http https://issues.apache.org/jira/rest/api/2/search 'jql==project = SLING AND resolution = Unresolved AND fixVersion = "Committer CLI 1.0.0"' 'fields==summary' | jq '.' > src/test/resources/jira/search/unresolved-committer-cli-1.0.0.json ``` \ No newline at end of file diff --git a/src/test/resources/jira/search/unresolved-committer-cli-1.0.0.json b/src/test/resources/jira/search/unresolved-committer-cli-1.0.0.json new file mode 100644 index 0000000..6a01267 --- /dev/null +++ b/src/test/resources/jira/search/unresolved-committer-cli-1.0.0.json @@ -0,0 +1,26 @@ +{ + "expand": "schema,names", + "startAt": 0, + "maxResults": 50, + "total": 2, + "issues": [ + { + "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", + "id": "13225243", + "self": "https://issues.apache.org/jira/rest/api/2/issue/13225243", + "key": "SLING-8338", + "fields": { + "summary": "Create sub-command to manage the Nexus stage repository release when promoting a release" + } + }, + { + "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", + "id": "13224868", + "self": "https://issues.apache.org/jira/rest/api/2/issue/13224868", + "key": "SLING-8337", + "fields": { + "summary": "Create sub-command to manage the Jira update when promoting a release" + } + } + ] +}
