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 ff616fd463a3820fd2e454b0d417890c90c52de5 Author: Robert Munteanu <[email protected]> AuthorDate: Wed Apr 24 13:29:59 2019 +0300 SLING-8337 - Create sub-command to manage the Jira update when promoting a release Simplify MockJira --- .../java/org/apache/sling/cli/impl/jira/Issue.java | 45 ++++++ .../apache/sling/cli/impl/jira/IssueResponse.java | 28 ++++ .../cli/impl/jira/CreateVersionJiraAction.java | 126 ++++++++++++++++ ...GetRelatedIssueCountsForVersionsJiraAction.java | 56 +++++++ .../org/apache/sling/cli/impl/jira/JiraAction.java | 40 +++++ .../cli/impl/jira/ListVersionsJiraAction.java | 29 ++++ .../org/apache/sling/cli/impl/jira/MockJira.java | 166 +++------------------ 7 files changed, 344 insertions(+), 146 deletions(-) diff --git a/src/main/java/org/apache/sling/cli/impl/jira/Issue.java b/src/main/java/org/apache/sling/cli/impl/jira/Issue.java new file mode 100644 index 0000000..425f5e3 --- /dev/null +++ b/src/main/java/org/apache/sling/cli/impl/jira/Issue.java @@ -0,0 +1,45 @@ +/* + * 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; + +public class Issue { + + private int id; + private String key; + private Fields fields; + + public int getId() { + return id; + } + + public String getKey() { + return key; + } + + public String getSummary() { + return fields.summary; + } + + static class Fields { + private String summary; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + key + " : " + getSummary() + " ]"; + } +} diff --git a/src/main/java/org/apache/sling/cli/impl/jira/IssueResponse.java b/src/main/java/org/apache/sling/cli/impl/jira/IssueResponse.java new file mode 100644 index 0000000..0cf5697 --- /dev/null +++ b/src/main/java/org/apache/sling/cli/impl/jira/IssueResponse.java @@ -0,0 +1,28 @@ +/* + * 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.util.List; + +public class IssueResponse { + + private List<Issue> issues; + + public List<Issue> getIssues() { + return issues; + } +} diff --git a/src/test/java/org/apache/sling/cli/impl/jira/CreateVersionJiraAction.java b/src/test/java/org/apache/sling/cli/impl/jira/CreateVersionJiraAction.java new file mode 100644 index 0000000..09837bf --- /dev/null +++ b/src/test/java/org/apache/sling/cli/impl/jira/CreateVersionJiraAction.java @@ -0,0 +1,126 @@ +/* + * 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.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.concurrent.ThreadLocalRandom; + +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; + +public class CreateVersionJiraAction implements JiraAction { + + @Override + public boolean tryHandle(HttpExchange ex) throws IOException { + if ( !ex.getRequestMethod().equals("POST") || + !ex.getRequestURI().getPath().equals("/jira/rest/api/2/version") ) { + return false; + } + + Gson gson = new Gson(); + try ( InputStreamReader reader = new InputStreamReader(ex.getRequestBody())) { + VersionToCreate version = gson.fromJson(reader, VersionToCreate.class); + if ( version.getName() == null || version.getName().isEmpty() ) { + error(ex, gson, + er -> er.getErrors().put("name", "You must specify a valid version name")); + return true; + } + + if ( !"SLING".equals(version.getProject()) ) { + error(ex, gson, + er -> er.getErrorMessages().add("Project must be specified to create a version.")); + return true; + } + + // note not all fields are sent, projectId and self are missing + CreatedVersion createdVersion = new CreatedVersion(); + createdVersion.archived = false; + createdVersion.id = ThreadLocalRandom.current().nextInt(); + createdVersion.released = false; + createdVersion.name = version.getName(); + + try ( OutputStreamWriter out = new OutputStreamWriter(ex.getResponseBody()) ) { + ex.sendResponseHeaders(201, 0); + gson.toJson(createdVersion, out); + } + } + + return true; + } + + static class VersionToCreate { + private String name; + private String project; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getProject() { + return project; + } + + public void setProject(String project) { + this.project = project; + } + } + + static class CreatedVersion { + private String name; + private int id; + private boolean archived; + private boolean released; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public boolean isArchived() { + return archived; + } + + public void setArchived(boolean archived) { + this.archived = archived; + } + + public boolean isReleased() { + return released; + } + + public void setReleased(boolean released) { + this.released = released; + } + } +} 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 new file mode 100644 index 0000000..aa9616f --- /dev/null +++ b/src/test/java/org/apache/sling/cli/impl/jira/GetRelatedIssueCountsForVersionsJiraAction.java @@ -0,0 +1,56 @@ +/* + * 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.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 { + + private static final Pattern VERSION_RELATED_ISSUES = Pattern.compile("^/jira/rest/api/2/version/(\\d+)/relatedIssueCounts$"); + + @Override + public boolean tryHandle(HttpExchange ex) throws IOException { + if ( !ex.getRequestMethod().equals("GET") ) + return false; + + Matcher matcher = VERSION_RELATED_ISSUES.matcher(ex.getRequestURI().getPath()); + if ( !matcher.matches() ) + 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; + } + +} 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 new file mode 100644 index 0000000..6cbc1b9 --- /dev/null +++ b/src/test/java/org/apache/sling/cli/impl/jira/JiraAction.java @@ -0,0 +1,40 @@ +/* + * 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.io.OutputStreamWriter; +import java.util.function.Consumer; + +import org.apache.sling.cli.impl.jira.ErrorResponse; + +import com.google.gson.Gson; +import com.sun.net.httpserver.HttpExchange; + +public interface JiraAction { + + default void error(HttpExchange httpExchange, Gson gson, Consumer<ErrorResponse> c) throws IOException { + try ( OutputStreamWriter out = new OutputStreamWriter(httpExchange.getResponseBody()) ) { + httpExchange.sendResponseHeaders(400, 0); + ErrorResponse er = new ErrorResponse(); + c.accept(er); + gson.toJson(er, 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 new file mode 100644 index 0000000..30ce879 --- /dev/null +++ b/src/test/java/org/apache/sling/cli/impl/jira/ListVersionsJiraAction.java @@ -0,0 +1,29 @@ +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; + +public class ListVersionsJiraAction implements JiraAction { + + @Override + public boolean tryHandle(HttpExchange ex) throws IOException { + + if ( !ex.getRequestMethod().equals("GET") || + !ex.getRequestURI().getPath().equals("/jira/rest/api/2/project/SLING/versions")) { + return false; + } + + ex.sendResponseHeaders(200, 0); + try ( InputStream in = getClass().getResourceAsStream("/jira/versions.json"); + OutputStream out = ex.getResponseBody() ) { + IOUtils.copy(in, out); + } + + 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 3df51ca..e26dd87 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 @@ -17,20 +17,12 @@ package org.apache.sling.cli.impl.jira; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.net.InetSocketAddress; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.Consumer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.ArrayList; +import java.util.List; -import org.apache.commons.io.IOUtils; import org.junit.rules.ExternalResource; -import com.google.gson.Gson; import com.sun.net.httpserver.Authenticator; import com.sun.net.httpserver.BasicAuthenticator; import com.sun.net.httpserver.HttpContext; @@ -40,8 +32,6 @@ import com.sun.net.httpserver.HttpServer; public class MockJira extends ExternalResource { - private static final Pattern VERSION_RELATED_ISSUES = Pattern.compile("^/jira/rest/api/2/version/(\\d+)/relatedIssueCounts$"); - static final String AUTH_USER = "jira-user"; static final String AUTH_PWD = "jira-password"; @@ -72,89 +62,33 @@ public class MockJira extends ExternalResource { return super.authenticate(t); } }); + + List<JiraAction> actions = new ArrayList<>(); + actions.add(new ListVersionsJiraAction()); + actions.add(new GetRelatedIssueCountsForVersionsJiraAction()); + actions.add(new CreateVersionJiraAction()); + + // fallback, always executed + actions.add(new JiraAction() { + @Override + public boolean tryHandle(HttpExchange ex) throws IOException { + ex.sendResponseHeaders(400, -1); + return true; + } + }); + rootContext.setHandler(httpExchange -> { - switch ( httpExchange.getRequestMethod() ) { - case "GET": - if ( httpExchange.getRequestURI().getPath().equals("/jira/rest/api/2/project/SLING/versions") ) { - httpExchange.sendResponseHeaders(200, 0); - try ( InputStream in = getClass().getResourceAsStream("/jira/versions.json"); - OutputStream out = httpExchange.getResponseBody() ) { - IOUtils.copy(in, out); - } - } else { - Matcher matcher = VERSION_RELATED_ISSUES.matcher(httpExchange.getRequestURI().getPath()); - if ( matcher.matches() ) { - int version = Integer.parseInt(matcher.group(1)); - InputStream in = getClass().getResourceAsStream("/jira/relatedIssueCounts/" + version + ".json"); - if ( in == null ) { - httpExchange.sendResponseHeaders(404, -1); - } else { - httpExchange.sendResponseHeaders(200, 0); - try ( OutputStream out = httpExchange.getResponseBody() ) { - IOUtils.copy(in, out); - } - } - } else { - httpExchange.sendResponseHeaders(400, -1); - } + for ( JiraAction action : actions ) { + if ( action.tryHandle(httpExchange) ) { + break; } - break; - case "POST": - if ( httpExchange.getRequestURI().getPath().equals("/jira/rest/api/2/version") ) { - handleCreateVersion(httpExchange); - return; - } - httpExchange.sendResponseHeaders(400, -1); - break; - default: - httpExchange.sendResponseHeaders(400, -1); } - }); server.start(); } - private void handleCreateVersion(HttpExchange httpExchange) throws IOException { - Gson gson = new Gson(); - try ( InputStreamReader reader = new InputStreamReader(httpExchange.getRequestBody())) { - VersionToCreate version = gson.fromJson(reader, VersionToCreate.class); - if ( version.getName() == null || version.getName().isEmpty() ) { - error(httpExchange, gson, - er -> er.getErrors().put("name", "You must specify a valid version name")); - return; - } - - if ( !"SLING".equals(version.getProject()) ) { - error(httpExchange, gson, - er -> er.getErrorMessages().add("Project must be specified to create a version.")); - return; - } - - // note not all fields are sent, projectId and self are missing - CreatedVersion createdVersion = new CreatedVersion(); - createdVersion.archived = false; - createdVersion.id = ThreadLocalRandom.current().nextInt(); - createdVersion.released = false; - createdVersion.name = version.getName(); - - try ( OutputStreamWriter out = new OutputStreamWriter(httpExchange.getResponseBody()) ) { - httpExchange.sendResponseHeaders(201, 0); - gson.toJson(createdVersion, out); - } - } - } - - private void error(HttpExchange httpExchange, Gson gson, Consumer<ErrorResponse> c) throws IOException { - try ( OutputStreamWriter out = new OutputStreamWriter(httpExchange.getResponseBody()) ) { - httpExchange.sendResponseHeaders(400, 0); - ErrorResponse er = new ErrorResponse(); - c.accept(er); - gson.toJson(er, out); - } - } - @Override protected void after() { @@ -165,64 +99,4 @@ public class MockJira extends ExternalResource { return server.getAddress().getPort(); } - - static class VersionToCreate { - private String name; - private String project; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getProject() { - return project; - } - - public void setProject(String project) { - this.project = project; - } - } - - static class CreatedVersion { - private String name; - private int id; - private boolean archived; - private boolean released; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public boolean isArchived() { - return archived; - } - - public void setArchived(boolean archived) { - this.archived = archived; - } - - public boolean isReleased() { - return released; - } - - public void setReleased(boolean released) { - this.released = released; - } - } }
