From 8317bd0e0c28450cd6c4f86903a496192fe6939f Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Thu, 1 Nov 2018 10:55:26 +0200 Subject: [PATCH 01/46] Initial commit --- pom.xml | 5 + wsmaster/che-core-api-devfile/pom.xml | 130 ++++++++++++++++++ .../api/devfile/server/DevFileService.java | 47 +++++++ .../src/test/resources/logback-test.xml | 37 +++++ wsmaster/pom.xml | 1 + 5 files changed, 220 insertions(+) create mode 100644 wsmaster/che-core-api-devfile/pom.xml create mode 100644 wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java create mode 100644 wsmaster/che-core-api-devfile/src/test/resources/logback-test.xml diff --git a/pom.xml b/pom.xml index e5265a401d0..604a5ed89d9 100644 --- a/pom.xml +++ b/pom.xml @@ -276,6 +276,11 @@ che-core-api-account ${che.version} + + org.eclipse.che.core + che-core-api-devfile + ${che.version} + org.eclipse.che.core che-core-api-account diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml new file mode 100644 index 00000000000..01c74f82d4a --- /dev/null +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -0,0 +1,130 @@ + + + + 4.0.0 + + che-master-parent + org.eclipse.che.core + 6.14.0-SNAPSHOT + + che-core-api-devfile + jar + Che Core :: API :: Devfile + + + org.eclipse.che.core + che-core-api-core + + + org.eclipse.che.core + che-core-commons-annotations + + + org.eclipse.che.core + che-core-commons-json + + + org.eclipse.che.core + che-core-commons-lang + + + org.everrest + everrest-core + + + org.slf4j + slf4j-api + + + javax.servlet + javax.servlet-api + provided + + + javax.ws.rs + javax.ws.rs-api + provided + + + + ch.qos.logback + logback-classic + test + + + com.jayway.restassured + rest-assured + test + + + org.eclipse.che.core + che-core-commons-test + test + + + org.eclipse.jetty + jetty-server + test + + + org.everrest + everrest-assured + test + + + org.everrest + everrest-test + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-testng + test + + + org.slf4j + jcl-over-slf4j + test + + + org.testng + testng + test + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + analyze + + + org.everrest:everrest-core + + + + + + + + diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java new file mode 100644 index 00000000000..85ddf1eed2c --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -0,0 +1,47 @@ +package org.eclipse.che.api.devfile.server; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Response; +import org.eclipse.che.api.core.rest.Service; + +@Path("/devfile") +public class DevFileService extends Service { + +// //Creates a workspace by providing the url to the repository +// @POST +// @Produces(APPLICATION_JSON) +// public Response create(@QueryParam("repo_url") String repo_url){ +// } +// +// +// // Generates a workspace by sending a devfile to a rest API +// // Initially this method will return empty workspace configuration. +// // And will start che-devfile-broker on a background to clone sources and get devfile. +// @POST +// @Consumes("text/yml") +// @Produces(APPLICATION_JSON) +// public Response createFromYaml(DevFile defFile){ +// } +// + + + // Generates the devfile based on an existing workspace + // key = workspace12345678 + // key = namespace/workspace_name + // key = namespace_part_1/namespace_part_2/workspace_name + // See get workspace by id aka key. + @GET + @Path("/{key:.*}") + @Produces("text/yml") + public Response createFromWorkspace(@PathParam("key") String key){ + } + +} diff --git a/wsmaster/che-core-api-devfile/src/test/resources/logback-test.xml b/wsmaster/che-core-api-devfile/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..a38570dd2a6 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/test/resources/logback-test.xml @@ -0,0 +1,37 @@ + + + + + + + %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n + + + + + target/log/codenvy-factory-commons.log + + %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n + + + + + + + + + + + diff --git a/wsmaster/pom.xml b/wsmaster/pom.xml index 1aaedfb10e6..1a4f39691a6 100644 --- a/wsmaster/pom.xml +++ b/wsmaster/pom.xml @@ -29,6 +29,7 @@ che-core-api-installer che-core-api-auth-shared che-core-api-auth + che-core-api-devfile che-core-api-project-templates-shared che-core-api-project-templates che-core-api-workspace-shared From 76a381faa49a6e672ef0032c2f3d77a96f82c685 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 2 Nov 2018 14:12:58 +0200 Subject: [PATCH 02/46] Initial implementation --- pom.xml | 5 + .../eclipse/che/api/devfile/model/Action.java | 51 +++++++++ .../che/api/devfile/model/ChePlugin.java | 51 +++++++++ .../che/api/devfile/model/Command.java | 65 +++++++++++ .../che/api/devfile/model/Definition.java | 51 +++++++++ .../che/api/devfile/model/DevFile.java | 104 ++++++++++++++++++ .../eclipse/che/api/devfile/model/Exec.java | 64 +++++++++++ .../che/api/devfile/model/Project.java | 64 +++++++++++ .../eclipse/che/api/devfile/model/Source.java | 64 +++++++++++ .../eclipse/che/api/devfile/model/Tool.java | 64 +++++++++++ .../che/api/devfile/model/ToolsCommand.java | 64 +++++++++++ wsmaster/che-core-api-devfile/pom.xml | 8 ++ .../api/devfile/server/DevFileService.java | 98 ++++++++++++++--- wsmaster/pom.xml | 1 + 14 files changed, 737 insertions(+), 17 deletions(-) create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java diff --git a/pom.xml b/pom.xml index 604a5ed89d9..d180c3a5e14 100644 --- a/pom.xml +++ b/pom.xml @@ -281,6 +281,11 @@ che-core-api-devfile ${che.version} + + org.eclipse.che.core + che-core-api-devfile-shared + ${che.version} + org.eclipse.che.core che-core-api-account diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java new file mode 100644 index 00000000000..456375efb19 --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"exec"}) +public class Action { + + @JsonProperty("exec") + private Exec exec; + + @JsonIgnore private Map additionalProperties = new HashMap<>(); + + @JsonProperty("exec") + public Exec getExec() { + return exec; + } + + @JsonProperty("exec") + public void setExec(Exec exec) { + this.exec = exec; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java new file mode 100644 index 00000000000..ddd049980a1 --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"name"}) +public class ChePlugin { + + @JsonProperty("name") + private String name; + + @JsonIgnore private Map additionalProperties = new HashMap<>(); + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java new file mode 100644 index 00000000000..35ecbf98c5c --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"name", "toolsCommands"}) +public class Command { + + @JsonProperty("name") + private String name; + + @JsonProperty("toolsCommands") + private List toolsCommands = null; + + @JsonIgnore private Map additionalProperties = new HashMap<>(); + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + @JsonProperty("toolsCommands") + public List getToolsCommands() { + return toolsCommands; + } + + @JsonProperty("toolsCommands") + public void setToolsCommands(List toolsCommands) { + this.toolsCommands = toolsCommands; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java new file mode 100644 index 00000000000..1906c242909 --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"chePlugin"}) +public class Definition { + + @JsonProperty("chePlugin") + private ChePlugin chePlugin; + + @JsonIgnore private Map additionalProperties = new HashMap<>(); + + @JsonProperty("chePlugin") + public ChePlugin getChePlugin() { + return chePlugin; + } + + @JsonProperty("chePlugin") + public void setChePlugin(ChePlugin chePlugin) { + this.chePlugin = chePlugin; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java new file mode 100644 index 00000000000..063426fb06f --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"specVersion", "name", "projects", "tools", "commands"}) +public class DevFile { + + @JsonProperty("specVersion") + private String specVersion; + + @JsonProperty("name") + private String name; + + @JsonProperty("projects") + private List projects = null; + + @JsonProperty("tools") + private List tools = null; + + @JsonProperty("commands") + private List commands = null; + + @JsonIgnore private Map additionalProperties = new HashMap<>(); + + @JsonProperty("specVersion") + public String getSpecVersion() { + return specVersion; + } + + @JsonProperty("specVersion") + public void setSpecVersion(String specVersion) { + this.specVersion = specVersion; + } + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + @JsonProperty("projects") + public List getProjects() { + return projects; + } + + @JsonProperty("projects") + public void setProjects(List projects) { + this.projects = projects; + } + + @JsonProperty("tools") + public List getTools() { + return tools; + } + + @JsonProperty("tools") + public void setTools(List tools) { + this.tools = tools; + } + + @JsonProperty("commands") + public List getCommands() { + return commands; + } + + @JsonProperty("commands") + public void setCommands(List commands) { + this.commands = commands; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java new file mode 100644 index 00000000000..851e5c88c54 --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"command", "workdir"}) +public class Exec { + + @JsonProperty("command") + private String command; + + @JsonProperty("workdir") + private String workdir; + + @JsonIgnore private Map additionalProperties = new HashMap<>(); + + @JsonProperty("command") + public String getCommand() { + return command; + } + + @JsonProperty("command") + public void setCommand(String command) { + this.command = command; + } + + @JsonProperty("workdir") + public String getWorkdir() { + return workdir; + } + + @JsonProperty("workdir") + public void setWorkdir(String workdir) { + this.workdir = workdir; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java new file mode 100644 index 00000000000..ec0c67ee987 --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"name", "source"}) +public class Project { + + @JsonProperty("name") + private String name; + + @JsonProperty("source") + private Source source; + + @JsonIgnore private Map additionalProperties = new HashMap<>(); + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + @JsonProperty("source") + public Source getSource() { + return source; + } + + @JsonProperty("source") + public void setSource(Source source) { + this.source = source; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java new file mode 100644 index 00000000000..3fbe89cf985 --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"type", "location"}) +public class Source { + + @JsonProperty("type") + private String type; + + @JsonProperty("location") + private String location; + + @JsonIgnore private Map additionalProperties = new HashMap<>(); + + @JsonProperty("type") + public String getType() { + return type; + } + + @JsonProperty("type") + public void setType(String type) { + this.type = type; + } + + @JsonProperty("location") + public String getLocation() { + return location; + } + + @JsonProperty("location") + public void setLocation(String location) { + this.location = location; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java new file mode 100644 index 00000000000..f3a75d712cb --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"name", "definition"}) +public class Tool { + + @JsonProperty("name") + private String name; + + @JsonProperty("definition") + private Definition definition; + + @JsonIgnore private Map additionalProperties = new HashMap<>(); + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + @JsonProperty("definition") + public Definition getDefinition() { + return definition; + } + + @JsonProperty("definition") + public void setDefinition(Definition definition) { + this.definition = definition; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java new file mode 100644 index 00000000000..58e8e052838 --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"tool", "action"}) +public class ToolsCommand { + + @JsonProperty("tool") + private String tool; + + @JsonProperty("action") + private Action action; + + @JsonIgnore private Map additionalProperties = new HashMap<>(); + + @JsonProperty("tool") + public String getTool() { + return tool; + } + + @JsonProperty("tool") + public void setTool(String tool) { + this.tool = tool; + } + + @JsonProperty("action") + public Action getAction() { + return action; + } + + @JsonProperty("action") + public void setAction(Action action) { + this.action = action; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index 01c74f82d4a..b6019930d27 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -27,6 +27,14 @@ org.eclipse.che.core che-core-api-core + + org.eclipse.che.core + che-core-api-workspace + + + org.eclipse.che.core + che-core-api-devfile-shared + org.eclipse.che.core che-core-commons-annotations diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index 85ddf1eed2c..1bd532ed762 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -2,6 +2,9 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import java.util.ArrayList; +import java.util.List; +import javax.inject.Inject; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -10,27 +13,46 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Response; +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.rest.Service; +import org.eclipse.che.api.devfile.model.Command; +import org.eclipse.che.api.devfile.model.DevFile; +import org.eclipse.che.api.devfile.model.Project; +import org.eclipse.che.api.devfile.model.Source; +import org.eclipse.che.api.workspace.server.WorkspaceManager; +import org.eclipse.che.api.workspace.server.model.impl.CommandImpl; +import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; + @Path("/devfile") public class DevFileService extends Service { -// //Creates a workspace by providing the url to the repository -// @POST -// @Produces(APPLICATION_JSON) -// public Response create(@QueryParam("repo_url") String repo_url){ -// } -// -// -// // Generates a workspace by sending a devfile to a rest API -// // Initially this method will return empty workspace configuration. -// // And will start che-devfile-broker on a background to clone sources and get devfile. -// @POST -// @Consumes("text/yml") -// @Produces(APPLICATION_JSON) -// public Response createFromYaml(DevFile defFile){ -// } -// + private static final String SPEC_VERSION = "0.0.1"; + private WorkspaceManager workspaceManager; + + @Inject + public DevFileService(WorkspaceManager workspaceManager) { + this.workspaceManager = workspaceManager; + } + + //Creates a workspace by providing the url to the repository + @POST + @Produces(APPLICATION_JSON) + public Response create(@QueryParam("repo_url") String repo_url){ + } + + + // Generates a workspace by sending a devfile to a rest API + // Initially this method will return empty workspace configuration. + // And will start che-devfile-broker on a background to clone sources and get devfile. + @POST + @Consumes("text/yml") + @Produces(APPLICATION_JSON) + public Response createFromYaml(DevFile defFile){ + } + // Generates the devfile based on an existing workspace @@ -41,7 +63,49 @@ public class DevFileService extends Service { @GET @Path("/{key:.*}") @Produces("text/yml") - public Response createFromWorkspace(@PathParam("key") String key){ + public Response createFromWorkspace(@PathParam("key") String key) + throws NotFoundException, ServerException { + //TODO: validate key + WorkspaceImpl workspace = workspaceManager.getWorkspace(key); + DevFile workspaceDevFile = workspaceToDevFile(workspace); + } + + + private DevFile workspaceToDevFile(WorkspaceImpl workspace) { + DevFile devFile = new DevFile(); + devFile.setSpecVersion(SPEC_VERSION); + devFile.setName("???"); + + // Manage projects + List projects = new ArrayList<>(); + for (ProjectConfigImpl project : workspace.getConfig().getProjects()) { + Project devProject = new Project(); + devProject.setName(project.getName()); + Source source = new Source(); + source.setType(project.getSource().getType()); + source.setLocation(project.getSource().getLocation()); + devProject.setSource(source); + projects.add(devProject); + } + devFile.setProjects(projects); + + + // Manage commands + List commands = new ArrayList<>(); + for (CommandImpl command : workspace.getConfig().getCommands()) { + Command devCommand = new Command(); + devCommand.setName(command.getName()); + + devCommand.setToolsCommands(); + commands.add(devCommand); + } + devFile.setCommands(commands); + + + + + + devFile.setTools(); } } diff --git a/wsmaster/pom.xml b/wsmaster/pom.xml index 1a4f39691a6..5e879442430 100644 --- a/wsmaster/pom.xml +++ b/wsmaster/pom.xml @@ -30,6 +30,7 @@ che-core-api-auth-shared che-core-api-auth che-core-api-devfile + che-core-api-devfile-shared che-core-api-project-templates-shared che-core-api-project-templates che-core-api-workspace-shared From 94754e214b5cd183f6dcb17d2a434d9f2a9d82c8 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 2 Nov 2018 19:09:27 +0200 Subject: [PATCH 03/46] fixup --- assembly/assembly-wsmaster-war/pom.xml | 4 + .../che/api/deploy/WsMasterModule.java | 2 + pom.xml | 20 ++-- wsmaster/che-core-api-devfile/pom.xml | 77 ++---------- .../api/devfile/server/DevFileService.java | 113 +++++++++++++----- 5 files changed, 109 insertions(+), 107 deletions(-) diff --git a/assembly/assembly-wsmaster-war/pom.xml b/assembly/assembly-wsmaster-war/pom.xml index d25957bff1d..6c09ecd93ed 100644 --- a/assembly/assembly-wsmaster-war/pom.xml +++ b/assembly/assembly-wsmaster-war/pom.xml @@ -145,6 +145,10 @@ org.eclipse.che.core che-core-api-core + + org.eclipse.che.core + che-core-api-devfile + org.eclipse.che.core che-core-api-factory diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index 76ea8b1c4b3..a6e29f383c6 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -152,6 +152,8 @@ protected void configure() { bind(org.eclipse.che.api.user.server.PreferencesService.class); bind(org.eclipse.che.security.oauth.OAuthAuthenticationService.class); + bind(org.eclipse.che.api.devfile.server.DevFileService.class); + MapBinder stacks = MapBinder.newMapBinder( binder(), String.class, String.class, Names.named(StackLoader.CHE_PREDEFINED_STACKS)); diff --git a/pom.xml b/pom.xml index d180c3a5e14..e6e87c06e3d 100644 --- a/pom.xml +++ b/pom.xml @@ -276,16 +276,6 @@ che-core-api-account ${che.version} - - org.eclipse.che.core - che-core-api-devfile - ${che.version} - - - org.eclipse.che.core - che-core-api-devfile-shared - ${che.version} - org.eclipse.che.core che-core-api-account @@ -335,6 +325,16 @@ ${che.version} sources + + org.eclipse.che.core + che-core-api-devfile + ${che.version} + + + org.eclipse.che.core + che-core-api-devfile-shared + ${che.version} + org.eclipse.che.core che-core-api-dto diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index b6019930d27..cd2db745187 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -24,37 +24,37 @@ Che Core :: API :: Devfile - org.eclipse.che.core - che-core-api-core + com.fasterxml.jackson.core + jackson-core - org.eclipse.che.core - che-core-api-workspace + com.fasterxml.jackson.core + jackson-databind - org.eclipse.che.core - che-core-api-devfile-shared + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + javax.inject + javax.inject org.eclipse.che.core - che-core-commons-annotations + che-core-api-core org.eclipse.che.core - che-core-commons-json + che-core-api-devfile-shared org.eclipse.che.core - che-core-commons-lang + che-core-api-workspace org.everrest everrest-core - - org.slf4j - slf4j-api - javax.servlet javax.servlet-api @@ -65,57 +65,6 @@ javax.ws.rs-api provided - - - ch.qos.logback - logback-classic - test - - - com.jayway.restassured - rest-assured - test - - - org.eclipse.che.core - che-core-commons-test - test - - - org.eclipse.jetty - jetty-server - test - - - org.everrest - everrest-assured - test - - - org.everrest - everrest-test - test - - - org.mockito - mockito-core - test - - - org.mockito - mockito-testng - test - - - org.slf4j - jcl-over-slf4j - test - - - org.testng - testng - test - diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index 1bd532ed762..7c357e69958 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -1,59 +1,74 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ package org.eclipse.che.api.devfile.server; -import static javax.ws.rs.core.MediaType.APPLICATION_JSON; - +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import javax.inject.Inject; -import javax.ws.rs.Consumes; import javax.ws.rs.GET; -import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; import javax.ws.rs.core.Response; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.rest.Service; +import org.eclipse.che.api.devfile.model.Action; +import org.eclipse.che.api.devfile.model.ChePlugin; import org.eclipse.che.api.devfile.model.Command; +import org.eclipse.che.api.devfile.model.Definition; import org.eclipse.che.api.devfile.model.DevFile; +import org.eclipse.che.api.devfile.model.Exec; import org.eclipse.che.api.devfile.model.Project; import org.eclipse.che.api.devfile.model.Source; +import org.eclipse.che.api.devfile.model.Tool; +import org.eclipse.che.api.devfile.model.ToolsCommand; import org.eclipse.che.api.workspace.server.WorkspaceManager; import org.eclipse.che.api.workspace.server.model.impl.CommandImpl; import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; - @Path("/devfile") public class DevFileService extends Service { private static final String SPEC_VERSION = "0.0.1"; private WorkspaceManager workspaceManager; + private ObjectMapper objectMapper; @Inject public DevFileService(WorkspaceManager workspaceManager) { this.workspaceManager = workspaceManager; + this.objectMapper = new ObjectMapper(new YAMLFactory()); } - //Creates a workspace by providing the url to the repository - @POST - @Produces(APPLICATION_JSON) - public Response create(@QueryParam("repo_url") String repo_url){ - } - - - // Generates a workspace by sending a devfile to a rest API - // Initially this method will return empty workspace configuration. - // And will start che-devfile-broker on a background to clone sources and get devfile. - @POST - @Consumes("text/yml") - @Produces(APPLICATION_JSON) - public Response createFromYaml(DevFile defFile){ - } - - + // //Creates a workspace by providing the url to the repository + // @POST + // @Produces(APPLICATION_JSON) + // public Response create(@QueryParam("repo_url") String repo_url){ + // } + // + // + // // Generates a workspace by sending a devfile to a rest API + // // Initially this method will return empty workspace configuration. + // // And will start che-devfile-broker on a background to clone sources and get devfile. + // @POST + // @Consumes("text/yml") + // @Produces(APPLICATION_JSON) + // public Response createFromYaml(DevFile defFile){ + // } // Generates the devfile based on an existing workspace // key = workspace12345678 @@ -65,14 +80,19 @@ public Response createFromYaml(DevFile defFile){ @Produces("text/yml") public Response createFromWorkspace(@PathParam("key") String key) throws NotFoundException, ServerException { - //TODO: validate key + // TODO: validate key WorkspaceImpl workspace = workspaceManager.getWorkspace(key); DevFile workspaceDevFile = workspaceToDevFile(workspace); + // Write object as YAML + try { + return Response.ok().entity(objectMapper.writeValueAsString(workspaceDevFile)).build(); + } catch (JsonProcessingException e) { + throw new ServerException(e.getMessage(), e); + } } - private DevFile workspaceToDevFile(WorkspaceImpl workspace) { - DevFile devFile = new DevFile(); + DevFile devFile = new DevFile(); devFile.setSpecVersion(SPEC_VERSION); devFile.setName("???"); @@ -89,23 +109,50 @@ private DevFile workspaceToDevFile(WorkspaceImpl workspace) { } devFile.setProjects(projects); - // Manage commands List commands = new ArrayList<>(); for (CommandImpl command : workspace.getConfig().getCommands()) { Command devCommand = new Command(); devCommand.setName(command.getName()); - - devCommand.setToolsCommands(); + ToolsCommand toolsCommand = new ToolsCommand(); + toolsCommand.setTool("???"); + Action action = new Action(); + Exec exec = new Exec(); + exec.setCommand(command.getCommandLine()); + exec.setWorkdir("???"); + action.setExec(exec); + toolsCommand.setAction(action); + devCommand.setToolsCommands(Collections.singletonList(toolsCommand)); commands.add(devCommand); } devFile.setCommands(commands); + List tools = new ArrayList<>(); + if (workspace.getConfig().getAttributes().containsKey("editor")) { + Tool editorTool = new Tool(); + editorTool.setName("editor"); + Definition definition = new Definition(); + ChePlugin chePlugin = new ChePlugin(); + chePlugin.setName(workspace.getConfig().getAttributes().get("editor")); + definition.setChePlugin(chePlugin); + editorTool.setDefinition(definition); + tools.add(editorTool); + } + if (workspace.getConfig().getAttributes().containsKey("plugins")) { + for (String plugin : workspace.getConfig().getAttributes().get("plugins").split(",")) { + Tool pluginTool = new Tool(); + pluginTool.setName(plugin.substring(0, plugin.indexOf(":"))); + Definition definition = new Definition(); + ChePlugin chePlugin = new ChePlugin(); + chePlugin.setName(plugin); + definition.setChePlugin(chePlugin); + pluginTool.setDefinition(definition); + tools.add(pluginTool); + } + } - - - devFile.setTools(); + devFile.setTools(tools); + return devFile; } - } From e9f8e95f4f2d06b17f2a3c9a413764a9a7755487 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Tue, 6 Nov 2018 15:58:56 +0200 Subject: [PATCH 04/46] Added create workspace from yaml method --- wsmaster/che-core-api-devfile-shared/pom.xml | 53 ++++++ .../eclipse/che/api/devfile/Constants.java | 17 ++ .../eclipse/che/api/devfile/model/Action.java | 6 +- .../che/api/devfile/model/ChePlugin.java | 6 +- .../che/api/devfile/model/Command.java | 6 +- .../che/api/devfile/model/Definition.java | 6 +- .../che/api/devfile/model/DevFile.java | 6 +- .../eclipse/che/api/devfile/model/Exec.java | 6 +- .../che/api/devfile/model/Project.java | 6 +- .../eclipse/che/api/devfile/model/Source.java | 6 +- .../eclipse/che/api/devfile/model/Tool.java | 6 +- .../che/api/devfile/model/ToolsCommand.java | 6 +- wsmaster/che-core-api-devfile/pom.xml | 8 + .../api/devfile/server/DevFileConverter.java | 173 ++++++++++++++++++ .../server/DevFileFormatException.java | 21 +++ .../api/devfile/server/DevFileService.java | 153 ++++++---------- 16 files changed, 359 insertions(+), 126 deletions(-) create mode 100644 wsmaster/che-core-api-devfile-shared/pom.xml create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/Constants.java create mode 100644 wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java create mode 100644 wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java diff --git a/wsmaster/che-core-api-devfile-shared/pom.xml b/wsmaster/che-core-api-devfile-shared/pom.xml new file mode 100644 index 00000000000..83dcd53f03f --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/pom.xml @@ -0,0 +1,53 @@ + + + + 4.0.0 + + che-master-parent + org.eclipse.che.core + 6.14.0-SNAPSHOT + + che-core-api-devfile-shared + jar + Che Core :: API :: Devfile Shared + + + com.fasterxml.jackson.core + jackson-annotations + + + org.everrest + everrest-core + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + analyze + + + org.everrest:everrest-core + + + + + + + + diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/Constants.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/Constants.java new file mode 100644 index 00000000000..bd86976e18b --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/Constants.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile; + +public class Constants { + + public static final String SPEC_VERSION = "0.0.1"; +} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java index 456375efb19..04cd8f5397c 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java @@ -27,7 +27,7 @@ public class Action { @JsonProperty("exec") private Exec exec; - @JsonIgnore private Map additionalProperties = new HashMap<>(); + @JsonIgnore private Map additionalProperties = new HashMap<>(); @JsonProperty("exec") public Exec getExec() { @@ -40,12 +40,12 @@ public void setExec(Exec exec) { } @JsonAnyGetter - public Map getAdditionalProperties() { + public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter - public void setAdditionalProperty(String name, Object value) { + public void setAdditionalProperty(String name, String value) { this.additionalProperties.put(name, value); } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java index ddd049980a1..e34d69eaeb7 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java @@ -27,7 +27,7 @@ public class ChePlugin { @JsonProperty("name") private String name; - @JsonIgnore private Map additionalProperties = new HashMap<>(); + @JsonIgnore private Map additionalProperties = new HashMap<>(); @JsonProperty("name") public String getName() { @@ -40,12 +40,12 @@ public void setName(String name) { } @JsonAnyGetter - public Map getAdditionalProperties() { + public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter - public void setAdditionalProperty(String name, Object value) { + public void setAdditionalProperty(String name, String value) { this.additionalProperties.put(name, value); } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java index 35ecbf98c5c..5fe7dcda0ad 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java @@ -31,7 +31,7 @@ public class Command { @JsonProperty("toolsCommands") private List toolsCommands = null; - @JsonIgnore private Map additionalProperties = new HashMap<>(); + @JsonIgnore private Map additionalProperties = new HashMap<>(); @JsonProperty("name") public String getName() { @@ -54,12 +54,12 @@ public void setToolsCommands(List toolsCommands) { } @JsonAnyGetter - public Map getAdditionalProperties() { + public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter - public void setAdditionalProperty(String name, Object value) { + public void setAdditionalProperty(String name, String value) { this.additionalProperties.put(name, value); } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java index 1906c242909..3c4f88f5e4a 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java @@ -27,7 +27,7 @@ public class Definition { @JsonProperty("chePlugin") private ChePlugin chePlugin; - @JsonIgnore private Map additionalProperties = new HashMap<>(); + @JsonIgnore private Map additionalProperties = new HashMap<>(); @JsonProperty("chePlugin") public ChePlugin getChePlugin() { @@ -40,12 +40,12 @@ public void setChePlugin(ChePlugin chePlugin) { } @JsonAnyGetter - public Map getAdditionalProperties() { + public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter - public void setAdditionalProperty(String name, Object value) { + public void setAdditionalProperty(String name, String value) { this.additionalProperties.put(name, value); } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java index 063426fb06f..9dbee86eecd 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java @@ -40,7 +40,7 @@ public class DevFile { @JsonProperty("commands") private List commands = null; - @JsonIgnore private Map additionalProperties = new HashMap<>(); + @JsonIgnore private Map additionalProperties = new HashMap<>(); @JsonProperty("specVersion") public String getSpecVersion() { @@ -93,12 +93,12 @@ public void setCommands(List commands) { } @JsonAnyGetter - public Map getAdditionalProperties() { + public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter - public void setAdditionalProperty(String name, Object value) { + public void setAdditionalProperty(String name, String value) { this.additionalProperties.put(name, value); } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java index 851e5c88c54..f8de5178f17 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java @@ -30,7 +30,7 @@ public class Exec { @JsonProperty("workdir") private String workdir; - @JsonIgnore private Map additionalProperties = new HashMap<>(); + @JsonIgnore private Map additionalProperties = new HashMap<>(); @JsonProperty("command") public String getCommand() { @@ -53,12 +53,12 @@ public void setWorkdir(String workdir) { } @JsonAnyGetter - public Map getAdditionalProperties() { + public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter - public void setAdditionalProperty(String name, Object value) { + public void setAdditionalProperty(String name, String value) { this.additionalProperties.put(name, value); } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java index ec0c67ee987..15b82ce4a8e 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java @@ -30,7 +30,7 @@ public class Project { @JsonProperty("source") private Source source; - @JsonIgnore private Map additionalProperties = new HashMap<>(); + @JsonIgnore private Map additionalProperties = new HashMap<>(); @JsonProperty("name") public String getName() { @@ -53,12 +53,12 @@ public void setSource(Source source) { } @JsonAnyGetter - public Map getAdditionalProperties() { + public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter - public void setAdditionalProperty(String name, Object value) { + public void setAdditionalProperty(String name, String value) { this.additionalProperties.put(name, value); } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java index 3fbe89cf985..3cfbd508304 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java @@ -30,7 +30,7 @@ public class Source { @JsonProperty("location") private String location; - @JsonIgnore private Map additionalProperties = new HashMap<>(); + @JsonIgnore private Map additionalProperties = new HashMap<>(); @JsonProperty("type") public String getType() { @@ -53,12 +53,12 @@ public void setLocation(String location) { } @JsonAnyGetter - public Map getAdditionalProperties() { + public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter - public void setAdditionalProperty(String name, Object value) { + public void setAdditionalProperty(String name, String value) { this.additionalProperties.put(name, value); } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java index f3a75d712cb..9e1ea7af332 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java @@ -30,7 +30,7 @@ public class Tool { @JsonProperty("definition") private Definition definition; - @JsonIgnore private Map additionalProperties = new HashMap<>(); + @JsonIgnore private Map additionalProperties = new HashMap<>(); @JsonProperty("name") public String getName() { @@ -53,12 +53,12 @@ public void setDefinition(Definition definition) { } @JsonAnyGetter - public Map getAdditionalProperties() { + public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter - public void setAdditionalProperty(String name, Object value) { + public void setAdditionalProperty(String name, String value) { this.additionalProperties.put(name, value); } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java index 58e8e052838..eb18890f242 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java @@ -30,7 +30,7 @@ public class ToolsCommand { @JsonProperty("action") private Action action; - @JsonIgnore private Map additionalProperties = new HashMap<>(); + @JsonIgnore private Map additionalProperties = new HashMap<>(); @JsonProperty("tool") public String getTool() { @@ -53,12 +53,12 @@ public void setAction(Action action) { } @JsonAnyGetter - public Map getAdditionalProperties() { + public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter - public void setAdditionalProperty(String name, Object value) { + public void setAdditionalProperty(String name, String value) { this.additionalProperties.put(name, value); } } diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index cd2db745187..f94b1369730 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -47,10 +47,18 @@ org.eclipse.che.core che-core-api-devfile-shared + + org.eclipse.che.core + che-core-api-model + org.eclipse.che.core che-core-api-workspace + + org.eclipse.che.core + che-core-api-workspace-shared + org.everrest everrest-core diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java new file mode 100644 index 00000000000..6b14b6dd479 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.server; + +import static java.lang.String.format; +import static java.util.Collections.singletonMap; +import static org.eclipse.che.api.devfile.Constants.SPEC_VERSION; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.eclipse.che.api.devfile.model.Action; +import org.eclipse.che.api.devfile.model.ChePlugin; +import org.eclipse.che.api.devfile.model.Command; +import org.eclipse.che.api.devfile.model.Definition; +import org.eclipse.che.api.devfile.model.DevFile; +import org.eclipse.che.api.devfile.model.Exec; +import org.eclipse.che.api.devfile.model.Project; +import org.eclipse.che.api.devfile.model.Source; +import org.eclipse.che.api.devfile.model.Tool; +import org.eclipse.che.api.devfile.model.ToolsCommand; +import org.eclipse.che.api.workspace.server.model.impl.CommandImpl; +import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl; +import org.eclipse.che.api.workspace.server.model.impl.MachineConfigImpl; +import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl; +import org.eclipse.che.api.workspace.server.model.impl.RecipeImpl; +import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; + +public class DevFileConverter { + + static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { + DevFile devFile = new DevFile(); + devFile.setSpecVersion(SPEC_VERSION); + devFile.setName(wsConfig.getName()); + + // Manage projects + List projects = new ArrayList<>(); + for (ProjectConfigImpl project : wsConfig.getProjects()) { + Project devProject = new Project(); + devProject.setName(project.getName()); + Source source = new Source(); + source.setType(project.getSource().getType()); + source.setLocation(project.getSource().getLocation()); + for (Map.Entry entry : project.getSource().getParameters().entrySet()) { + source.setAdditionalProperty(entry.getKey(), entry.getValue()); + } + devProject.setSource(source); + projects.add(devProject); + } + devFile.setProjects(projects); + + // Manage commands + List commands = new ArrayList<>(); + for (CommandImpl command : wsConfig.getCommands()) { + Command devCommand = new Command(); + devCommand.setName(command.getName()); + ToolsCommand toolsCommand = new ToolsCommand(); + toolsCommand.setTool("???"); + Action action = new Action(); + Exec exec = new Exec(); + exec.setCommand(command.getCommandLine()); + exec.setWorkdir("???"); + action.setExec(exec); + toolsCommand.setAction(action); + devCommand.setToolsCommands(Collections.singletonList(toolsCommand)); + commands.add(devCommand); + } + devFile.setCommands(commands); + + // Manage tools + List tools = new ArrayList<>(); + if (wsConfig.getAttributes().containsKey("editor")) { + Tool editorTool = new Tool(); + editorTool.setName("editor"); + Definition definition = new Definition(); + ChePlugin chePlugin = new ChePlugin(); + chePlugin.setName(wsConfig.getAttributes().get("editor")); + definition.setChePlugin(chePlugin); + editorTool.setDefinition(definition); + tools.add(editorTool); + } + + if (wsConfig.getAttributes().containsKey("plugins")) { + for (String plugin : wsConfig.getAttributes().get("plugins").split(",")) { + Tool pluginTool = new Tool(); + pluginTool.setName(plugin.substring(0, plugin.indexOf(":"))); + Definition definition = new Definition(); + ChePlugin chePlugin = new ChePlugin(); + chePlugin.setName(plugin); + definition.setChePlugin(chePlugin); + pluginTool.setDefinition(definition); + tools.add(pluginTool); + } + } + + devFile.setTools(tools); + return devFile; + } + + static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) + throws DevFileFormatException { + validateDevFile(devFile); + WorkspaceConfigImpl config = new WorkspaceConfigImpl(); + + config.setName(devFile.getName()); + + // Manage projects + List projects = new ArrayList<>(); + for (Project devProject : devFile.getProjects()) { + ProjectConfigImpl projectConfig = new ProjectConfigImpl(); + projectConfig.setName(devProject.getName()); + projectConfig.setPath("/" + projectConfig.getName()); + SourceStorageImpl sourceStorage = new SourceStorageImpl(); + sourceStorage.setType(devProject.getSource().getType()); + sourceStorage.setLocation(devProject.getSource().getLocation()); + sourceStorage.setParameters(devProject.getAdditionalProperties()); + projectConfig.setSource(sourceStorage); + projects.add(projectConfig); + } + config.setProjects(projects); + + // Manage commands + List commands = new ArrayList<>(); + for (Command devCommand : devFile.getCommands()) { + CommandImpl command = new CommandImpl(); + command.setName(devCommand.getName()); + // TODO: convert rest + commands.add(command); + } + + config.setCommands(commands); + + // Manage tools + Map attributes = new HashMap<>(); + + for (Tool tool : devFile.getTools()) { + attributes.put(tool.getName(), tool.getDefinition().getChePlugin().getName()); + } + config.setAttributes(attributes); + + // TODO: Add default environment. Remove when it will be possible + config.setDefaultEnv("default"); + EnvironmentImpl environment = new EnvironmentImpl(); + RecipeImpl recipe = new RecipeImpl(); + recipe.setType("dockerimage"); + recipe.setContent("eclipse/ubuntu_jdk8"); + environment.setRecipe(recipe); + MachineConfigImpl machine = new MachineConfigImpl(); + machine.setAttributes(singletonMap("memoryLimitBytes", "2147483648")); + environment.setMachines(singletonMap("dev-machine", machine)); + config.setEnvironments(singletonMap("default", environment)); + return config; + } + + private static void validateDevFile(DevFile devFile) throws DevFileFormatException { + if (!SPEC_VERSION.equals(devFile.getSpecVersion())) { + throw new DevFileFormatException( + format("Provided devfile has unsupported version %s", devFile.getSpecVersion())); + } + } +} diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java new file mode 100644 index 00000000000..c4a0a8963e6 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.server; + +import org.eclipse.che.api.core.ApiException; + +public class DevFileFormatException extends ApiException { + + public DevFileFormatException(String serviceError) { + super(serviceError); + } +} diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index 7c357e69958..cfd1d0c311c 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -11,70 +11,96 @@ */ package org.eclipse.che.api.devfile.server; +import static java.util.Collections.emptyMap; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.eclipse.che.api.devfile.server.DevFileConverter.devFileToWorkspaceConfig; +import static org.eclipse.che.api.devfile.server.DevFileConverter.workspaceToDevFile; +import static org.eclipse.che.api.workspace.server.DtoConverter.asDto; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.io.IOException; import javax.inject.Inject; +import javax.ws.rs.Consumes; import javax.ws.rs.GET; +import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Response; +import org.eclipse.che.api.core.BadRequestException; +import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.core.ValidationException; +import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; import org.eclipse.che.api.core.rest.Service; -import org.eclipse.che.api.devfile.model.Action; -import org.eclipse.che.api.devfile.model.ChePlugin; -import org.eclipse.che.api.devfile.model.Command; -import org.eclipse.che.api.devfile.model.Definition; import org.eclipse.che.api.devfile.model.DevFile; -import org.eclipse.che.api.devfile.model.Exec; -import org.eclipse.che.api.devfile.model.Project; -import org.eclipse.che.api.devfile.model.Source; -import org.eclipse.che.api.devfile.model.Tool; -import org.eclipse.che.api.devfile.model.ToolsCommand; +import org.eclipse.che.api.workspace.server.WorkspaceLinksGenerator; import org.eclipse.che.api.workspace.server.WorkspaceManager; -import org.eclipse.che.api.workspace.server.model.impl.CommandImpl; -import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; +import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; +import org.eclipse.che.commons.env.EnvironmentContext; @Path("/devfile") public class DevFileService extends Service { - private static final String SPEC_VERSION = "0.0.1"; + private final WorkspaceLinksGenerator linksGenerator; private WorkspaceManager workspaceManager; private ObjectMapper objectMapper; @Inject - public DevFileService(WorkspaceManager workspaceManager) { + public DevFileService(WorkspaceLinksGenerator linksGenerator, WorkspaceManager workspaceManager) { + this.linksGenerator = linksGenerator; this.workspaceManager = workspaceManager; this.objectMapper = new ObjectMapper(new YAMLFactory()); } - // //Creates a workspace by providing the url to the repository + // Creates a workspace by providing the url to the repository + // Initially this method will return + // empty workspace configuration. And will start che-devfile-broker on a background to clone + // sources and get devfile. // @POST // @Produces(APPLICATION_JSON) // public Response create(@QueryParam("repo_url") String repo_url){ // } // // - // // Generates a workspace by sending a devfile to a rest API - // // Initially this method will return empty workspace configuration. - // // And will start che-devfile-broker on a background to clone sources and get devfile. - // @POST - // @Consumes("text/yml") - // @Produces(APPLICATION_JSON) - // public Response createFromYaml(DevFile defFile){ - // } - // Generates the devfile based on an existing workspace - // key = workspace12345678 - // key = namespace/workspace_name - // key = namespace_part_1/namespace_part_2/workspace_name - // See get workspace by id aka key. + /** Generates a workspace from provided devfile to a rest API */ + @POST + @Consumes({"text/yaml", "text/x-yaml", "application/yaml"}) + @Produces(APPLICATION_JSON) + public WorkspaceDto createFromYaml(String data) + throws ServerException, ConflictException, NotFoundException, ValidationException, + BadRequestException { + + DevFile devFile; + WorkspaceConfig workspaceConfig; + try { + devFile = objectMapper.readValue(data, DevFile.class); + workspaceConfig = devFileToWorkspaceConfig(devFile); + } catch (IOException e) { + throw new ServerException(e.getMessage()); + } catch (DevFileFormatException e) { + throw new BadRequestException(e.getMessage()); + } + + final String namespace = EnvironmentContext.getCurrent().getSubject().getUserName(); + WorkspaceImpl workspace = + workspaceManager.createWorkspace(workspaceConfig, namespace, emptyMap()); + WorkspaceDto workspaceDto = + asDto(workspace).withLinks(linksGenerator.genLinks(workspace, getServiceContext())); + return workspaceDto; + } + + /** + * Generates the devfile based on an existing workspace. Key is workspace id or + * namespace/workspace_name + * + * @see WorkspaceManager#getByKey(String) + */ @GET @Path("/{key:.*}") @Produces("text/yml") @@ -82,7 +108,7 @@ public Response createFromWorkspace(@PathParam("key") String key) throws NotFoundException, ServerException { // TODO: validate key WorkspaceImpl workspace = workspaceManager.getWorkspace(key); - DevFile workspaceDevFile = workspaceToDevFile(workspace); + DevFile workspaceDevFile = workspaceToDevFile(workspace.getConfig()); // Write object as YAML try { return Response.ok().entity(objectMapper.writeValueAsString(workspaceDevFile)).build(); @@ -90,69 +116,4 @@ public Response createFromWorkspace(@PathParam("key") String key) throw new ServerException(e.getMessage(), e); } } - - private DevFile workspaceToDevFile(WorkspaceImpl workspace) { - DevFile devFile = new DevFile(); - devFile.setSpecVersion(SPEC_VERSION); - devFile.setName("???"); - - // Manage projects - List projects = new ArrayList<>(); - for (ProjectConfigImpl project : workspace.getConfig().getProjects()) { - Project devProject = new Project(); - devProject.setName(project.getName()); - Source source = new Source(); - source.setType(project.getSource().getType()); - source.setLocation(project.getSource().getLocation()); - devProject.setSource(source); - projects.add(devProject); - } - devFile.setProjects(projects); - - // Manage commands - List commands = new ArrayList<>(); - for (CommandImpl command : workspace.getConfig().getCommands()) { - Command devCommand = new Command(); - devCommand.setName(command.getName()); - ToolsCommand toolsCommand = new ToolsCommand(); - toolsCommand.setTool("???"); - Action action = new Action(); - Exec exec = new Exec(); - exec.setCommand(command.getCommandLine()); - exec.setWorkdir("???"); - action.setExec(exec); - toolsCommand.setAction(action); - devCommand.setToolsCommands(Collections.singletonList(toolsCommand)); - commands.add(devCommand); - } - devFile.setCommands(commands); - - List tools = new ArrayList<>(); - if (workspace.getConfig().getAttributes().containsKey("editor")) { - Tool editorTool = new Tool(); - editorTool.setName("editor"); - Definition definition = new Definition(); - ChePlugin chePlugin = new ChePlugin(); - chePlugin.setName(workspace.getConfig().getAttributes().get("editor")); - definition.setChePlugin(chePlugin); - editorTool.setDefinition(definition); - tools.add(editorTool); - } - - if (workspace.getConfig().getAttributes().containsKey("plugins")) { - for (String plugin : workspace.getConfig().getAttributes().get("plugins").split(",")) { - Tool pluginTool = new Tool(); - pluginTool.setName(plugin.substring(0, plugin.indexOf(":"))); - Definition definition = new Definition(); - ChePlugin chePlugin = new ChePlugin(); - chePlugin.setName(plugin); - definition.setChePlugin(chePlugin); - pluginTool.setDefinition(definition); - tools.add(pluginTool); - } - } - - devFile.setTools(tools); - return devFile; - } } From 05c26ec2a197ba52474bbeab0df2364b5638fb75 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Thu, 8 Nov 2018 16:57:47 +0200 Subject: [PATCH 05/46] Apply devfile schema refacorings; --- .../eclipse/che/api/devfile/Constants.java | 2 +- .../che/api/devfile/model/CheEditor.java | 51 +++++++++++++++++++ .../che/api/devfile/model/ChePlugin.java | 18 +++---- .../che/api/devfile/model/Command.java | 8 +-- .../che/api/devfile/model/Definition.java | 13 +++++ wsmaster/che-core-api-devfile/pom.xml | 4 ++ .../api/devfile/server/DevFileConverter.java | 46 +++++++++++------ 7 files changed, 113 insertions(+), 29 deletions(-) create mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/CheEditor.java diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/Constants.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/Constants.java index bd86976e18b..27c389d3a19 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/Constants.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/Constants.java @@ -13,5 +13,5 @@ public class Constants { - public static final String SPEC_VERSION = "0.0.1"; + public static final String CURRENT_SPEC_VERSION = "0.0.1"; } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/CheEditor.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/CheEditor.java new file mode 100644 index 00000000000..6ceda872940 --- /dev/null +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/CheEditor.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.model; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.HashMap; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"id"}) +public class CheEditor { + + @JsonProperty("id") + private String id; + + @JsonIgnore private Map additionalProperties = new HashMap<>(); + + @JsonProperty("id") + public String getId() { + return id; + } + + @JsonProperty("id") + public void setName(String id) { + this.id = id; + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, String value) { + this.additionalProperties.put(name, value); + } +} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java index e34d69eaeb7..2bcdccbaa66 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java @@ -21,22 +21,22 @@ import java.util.Map; @JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"name"}) +@JsonPropertyOrder({"id"}) public class ChePlugin { - @JsonProperty("name") - private String name; + @JsonProperty("id") + private String id; @JsonIgnore private Map additionalProperties = new HashMap<>(); - @JsonProperty("name") - public String getName() { - return name; + @JsonProperty("id") + public String getId() { + return id; } - @JsonProperty("name") - public void setName(String name) { - this.name = name; + @JsonProperty("id") + public void setId(String id) { + this.id = id; } @JsonAnyGetter diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java index 5fe7dcda0ad..7bfcc5b68fc 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java @@ -22,13 +22,13 @@ import java.util.Map; @JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"name", "toolsCommands"}) +@JsonPropertyOrder({"name", "tools"}) public class Command { @JsonProperty("name") private String name; - @JsonProperty("toolsCommands") + @JsonProperty("tools") private List toolsCommands = null; @JsonIgnore private Map additionalProperties = new HashMap<>(); @@ -43,12 +43,12 @@ public void setName(String name) { this.name = name; } - @JsonProperty("toolsCommands") + @JsonProperty("tools") public List getToolsCommands() { return toolsCommands; } - @JsonProperty("toolsCommands") + @JsonProperty("tools") public void setToolsCommands(List toolsCommands) { this.toolsCommands = toolsCommands; } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java index 3c4f88f5e4a..51fdf5d8f0e 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java @@ -27,6 +27,9 @@ public class Definition { @JsonProperty("chePlugin") private ChePlugin chePlugin; + @JsonProperty("cheEditor") + private CheEditor cheEditor; + @JsonIgnore private Map additionalProperties = new HashMap<>(); @JsonProperty("chePlugin") @@ -39,6 +42,16 @@ public void setChePlugin(ChePlugin chePlugin) { this.chePlugin = chePlugin; } + @JsonProperty("cheEditor") + public CheEditor getCheEditor() { + return cheEditor; + } + + @JsonProperty("cheEditor") + public void setCheEditor(CheEditor cheEditor) { + this.cheEditor = cheEditor; + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index f94b1369730..b79bf330fa2 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -35,6 +35,10 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml + + com.google.guava + guava + javax.inject javax.inject diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index 6b14b6dd479..2e5535a2871 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -11,16 +11,19 @@ */ package org.eclipse.che.api.devfile.server; +import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; import static java.util.Collections.singletonMap; -import static org.eclipse.che.api.devfile.Constants.SPEC_VERSION; +import static org.eclipse.che.api.devfile.Constants.CURRENT_SPEC_VERSION; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.StringJoiner; import org.eclipse.che.api.devfile.model.Action; +import org.eclipse.che.api.devfile.model.CheEditor; import org.eclipse.che.api.devfile.model.ChePlugin; import org.eclipse.che.api.devfile.model.Command; import org.eclipse.che.api.devfile.model.Definition; @@ -42,7 +45,7 @@ public class DevFileConverter { static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { DevFile devFile = new DevFile(); - devFile.setSpecVersion(SPEC_VERSION); + devFile.setSpecVersion(CURRENT_SPEC_VERSION); devFile.setName(wsConfig.getName()); // Manage projects @@ -67,11 +70,15 @@ static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { Command devCommand = new Command(); devCommand.setName(command.getName()); ToolsCommand toolsCommand = new ToolsCommand(); - toolsCommand.setTool("???"); + if (!isNullOrEmpty(command.getAttributes().get("machineName"))) { + toolsCommand.setTool(command.getAttributes().get("machineName")); + } Action action = new Action(); Exec exec = new Exec(); exec.setCommand(command.getCommandLine()); - exec.setWorkdir("???"); + if (!isNullOrEmpty(command.getAttributes().get("machineName"))) { + exec.setWorkdir(command.getAttributes().get("workingDir")); + } action.setExec(exec); toolsCommand.setAction(action); devCommand.setToolsCommands(Collections.singletonList(toolsCommand)); @@ -85,9 +92,9 @@ static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { Tool editorTool = new Tool(); editorTool.setName("editor"); Definition definition = new Definition(); - ChePlugin chePlugin = new ChePlugin(); - chePlugin.setName(wsConfig.getAttributes().get("editor")); - definition.setChePlugin(chePlugin); + CheEditor cheEditor = new CheEditor(); + cheEditor.setName(wsConfig.getAttributes().get("editor")); + definition.setCheEditor(cheEditor); editorTool.setDefinition(definition); tools.add(editorTool); } @@ -98,7 +105,7 @@ static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { pluginTool.setName(plugin.substring(0, plugin.indexOf(":"))); Definition definition = new Definition(); ChePlugin chePlugin = new ChePlugin(); - chePlugin.setName(plugin); + chePlugin.setId(plugin); definition.setChePlugin(chePlugin); pluginTool.setDefinition(definition); tools.add(pluginTool); @@ -134,20 +141,29 @@ static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) // Manage commands List commands = new ArrayList<>(); for (Command devCommand : devFile.getCommands()) { - CommandImpl command = new CommandImpl(); - command.setName(devCommand.getName()); - // TODO: convert rest - commands.add(command); + for (ToolsCommand toolCommand : devCommand.getToolsCommands()) { + CommandImpl command = new CommandImpl(); + command.setName(devCommand.getName() + ":" + toolCommand.getTool()); + command.setCommandLine(toolCommand.getAction().getExec().getCommand()); + command.getAttributes().put("machineName", toolCommand.getTool()); + command.getAttributes().put("workingDir", toolCommand.getAction().getExec().getWorkdir()); + commands.add(command); + } } config.setCommands(commands); // Manage tools Map attributes = new HashMap<>(); - + StringJoiner pluginsStringJoiner = new StringJoiner(","); for (Tool tool : devFile.getTools()) { - attributes.put(tool.getName(), tool.getDefinition().getChePlugin().getName()); + if (tool.getDefinition().getCheEditor() != null) { + attributes.put("editor", tool.getDefinition().getCheEditor().getId()); + } else { + pluginsStringJoiner.add(tool.getDefinition().getChePlugin().getId()); + } } + attributes.put("plugins", pluginsStringJoiner.toString()); config.setAttributes(attributes); // TODO: Add default environment. Remove when it will be possible @@ -165,7 +181,7 @@ static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) } private static void validateDevFile(DevFile devFile) throws DevFileFormatException { - if (!SPEC_VERSION.equals(devFile.getSpecVersion())) { + if (!CURRENT_SPEC_VERSION.equals(devFile.getSpecVersion())) { throw new DevFileFormatException( format("Provided devfile has unsupported version %s", devFile.getSpecVersion())); } From c3ace6a3b87bf797e03ccbd4c5b6f5f976d45273 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 9 Nov 2018 17:24:28 +0200 Subject: [PATCH 06/46] Apply new schema --- .../eclipse/che/api/devfile/model/Action.java | 57 ++++++++++-- .../che/api/devfile/model/CheEditor.java | 51 ----------- .../che/api/devfile/model/ChePlugin.java | 51 ----------- .../che/api/devfile/model/Command.java | 18 ++-- .../che/api/devfile/model/Definition.java | 64 -------------- .../eclipse/che/api/devfile/model/Exec.java | 64 -------------- .../eclipse/che/api/devfile/model/Tool.java | 31 +++++-- .../che/api/devfile/model/ToolsCommand.java | 64 -------------- .../api/devfile/server/DevFileConverter.java | 86 ++++++++----------- 9 files changed, 117 insertions(+), 369 deletions(-) delete mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/CheEditor.java delete mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java delete mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java delete mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java delete mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java index 04cd8f5397c..cb1cce13485 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java @@ -21,22 +21,61 @@ import java.util.Map; @JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"exec"}) +@JsonPropertyOrder({"type", "tool", "command", "workdir"}) public class Action { - @JsonProperty("exec") - private Exec exec; + @JsonProperty("tool") + private String tool; + + @JsonProperty("type") + private String type; + + @JsonProperty("command") + private String command; + + @JsonProperty("workdir") + private String workdir; @JsonIgnore private Map additionalProperties = new HashMap<>(); - @JsonProperty("exec") - public Exec getExec() { - return exec; + @JsonProperty("command") + public String getCommand() { + return command; + } + + @JsonProperty("command") + public void setCommand(String command) { + this.command = command; + } + + @JsonProperty("workdir") + public String getWorkdir() { + return workdir; + } + + @JsonProperty("workdir") + public void setWorkdir(String workdir) { + this.workdir = workdir; + } + + @JsonProperty("type") + public String getType() { + return type; + } + + @JsonProperty("type") + public void setType(String type) { + this.type = type; + } + + @JsonProperty("tool") + public String getTool() { + return tool; } - @JsonProperty("exec") - public void setExec(Exec exec) { - this.exec = exec; + @JsonProperty("tool") + public void setTool(String tool) { + this.tool = tool; } @JsonAnyGetter diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/CheEditor.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/CheEditor.java deleted file mode 100644 index 6ceda872940..00000000000 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/CheEditor.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.model; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"id"}) -public class CheEditor { - - @JsonProperty("id") - private String id; - - @JsonIgnore private Map additionalProperties = new HashMap<>(); - - @JsonProperty("id") - public String getId() { - return id; - } - - @JsonProperty("id") - public void setName(String id) { - this.id = id; - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @JsonAnySetter - public void setAdditionalProperty(String name, String value) { - this.additionalProperties.put(name, value); - } -} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java deleted file mode 100644 index 2bcdccbaa66..00000000000 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ChePlugin.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.model; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"id"}) -public class ChePlugin { - - @JsonProperty("id") - private String id; - - @JsonIgnore private Map additionalProperties = new HashMap<>(); - - @JsonProperty("id") - public String getId() { - return id; - } - - @JsonProperty("id") - public void setId(String id) { - this.id = id; - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @JsonAnySetter - public void setAdditionalProperty(String name, String value) { - this.additionalProperties.put(name, value); - } -} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java index 7bfcc5b68fc..6c4d6884169 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java @@ -22,14 +22,14 @@ import java.util.Map; @JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"name", "tools"}) +@JsonPropertyOrder({"name", "actions"}) public class Command { @JsonProperty("name") private String name; - @JsonProperty("tools") - private List toolsCommands = null; + @JsonProperty("actions") + private List actions = null; @JsonIgnore private Map additionalProperties = new HashMap<>(); @@ -43,14 +43,14 @@ public void setName(String name) { this.name = name; } - @JsonProperty("tools") - public List getToolsCommands() { - return toolsCommands; + @JsonProperty("actions") + public List getActions() { + return actions; } - @JsonProperty("tools") - public void setToolsCommands(List toolsCommands) { - this.toolsCommands = toolsCommands; + @JsonProperty("actions") + public void setActions(List actions) { + this.actions = actions; } @JsonAnyGetter diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java deleted file mode 100644 index 51fdf5d8f0e..00000000000 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Definition.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.model; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"chePlugin"}) -public class Definition { - - @JsonProperty("chePlugin") - private ChePlugin chePlugin; - - @JsonProperty("cheEditor") - private CheEditor cheEditor; - - @JsonIgnore private Map additionalProperties = new HashMap<>(); - - @JsonProperty("chePlugin") - public ChePlugin getChePlugin() { - return chePlugin; - } - - @JsonProperty("chePlugin") - public void setChePlugin(ChePlugin chePlugin) { - this.chePlugin = chePlugin; - } - - @JsonProperty("cheEditor") - public CheEditor getCheEditor() { - return cheEditor; - } - - @JsonProperty("cheEditor") - public void setCheEditor(CheEditor cheEditor) { - this.cheEditor = cheEditor; - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @JsonAnySetter - public void setAdditionalProperty(String name, String value) { - this.additionalProperties.put(name, value); - } -} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java deleted file mode 100644 index f8de5178f17..00000000000 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Exec.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.model; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"command", "workdir"}) -public class Exec { - - @JsonProperty("command") - private String command; - - @JsonProperty("workdir") - private String workdir; - - @JsonIgnore private Map additionalProperties = new HashMap<>(); - - @JsonProperty("command") - public String getCommand() { - return command; - } - - @JsonProperty("command") - public void setCommand(String command) { - this.command = command; - } - - @JsonProperty("workdir") - public String getWorkdir() { - return workdir; - } - - @JsonProperty("workdir") - public void setWorkdir(String workdir) { - this.workdir = workdir; - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @JsonAnySetter - public void setAdditionalProperty(String name, String value) { - this.additionalProperties.put(name, value); - } -} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java index 9e1ea7af332..4e9371dd135 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java @@ -21,14 +21,17 @@ import java.util.Map; @JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"name", "definition"}) +@JsonPropertyOrder({"name", "type", "id"}) public class Tool { @JsonProperty("name") private String name; - @JsonProperty("definition") - private Definition definition; + @JsonProperty("id") + private String id; + + @JsonProperty("type") + private String type; @JsonIgnore private Map additionalProperties = new HashMap<>(); @@ -42,14 +45,24 @@ public void setName(String name) { this.name = name; } - @JsonProperty("definition") - public Definition getDefinition() { - return definition; + @JsonProperty("type") + public String getType() { + return type; + } + + @JsonProperty("type") + public void setType(String type) { + this.type = type; + } + + @JsonProperty("id") + public String getId() { + return id; } - @JsonProperty("definition") - public void setDefinition(Definition definition) { - this.definition = definition; + @JsonProperty("id") + public void setId(String id) { + this.id = id; } @JsonAnyGetter diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java deleted file mode 100644 index eb18890f242..00000000000 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/ToolsCommand.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.model; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.HashMap; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"tool", "action"}) -public class ToolsCommand { - - @JsonProperty("tool") - private String tool; - - @JsonProperty("action") - private Action action; - - @JsonIgnore private Map additionalProperties = new HashMap<>(); - - @JsonProperty("tool") - public String getTool() { - return tool; - } - - @JsonProperty("tool") - public void setTool(String tool) { - this.tool = tool; - } - - @JsonProperty("action") - public Action getAction() { - return action; - } - - @JsonProperty("action") - public void setAction(Action action) { - this.action = action; - } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @JsonAnySetter - public void setAdditionalProperty(String name, String value) { - this.additionalProperties.put(name, value); - } -} diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index 2e5535a2871..c99b6e4032e 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -17,22 +17,17 @@ import static org.eclipse.che.api.devfile.Constants.CURRENT_SPEC_VERSION; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.StringJoiner; import org.eclipse.che.api.devfile.model.Action; -import org.eclipse.che.api.devfile.model.CheEditor; -import org.eclipse.che.api.devfile.model.ChePlugin; import org.eclipse.che.api.devfile.model.Command; -import org.eclipse.che.api.devfile.model.Definition; import org.eclipse.che.api.devfile.model.DevFile; -import org.eclipse.che.api.devfile.model.Exec; import org.eclipse.che.api.devfile.model.Project; import org.eclipse.che.api.devfile.model.Source; import org.eclipse.che.api.devfile.model.Tool; -import org.eclipse.che.api.devfile.model.ToolsCommand; import org.eclipse.che.api.workspace.server.model.impl.CommandImpl; import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl; import org.eclipse.che.api.workspace.server.model.impl.MachineConfigImpl; @@ -69,19 +64,11 @@ static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { for (CommandImpl command : wsConfig.getCommands()) { Command devCommand = new Command(); devCommand.setName(command.getName()); - ToolsCommand toolsCommand = new ToolsCommand(); - if (!isNullOrEmpty(command.getAttributes().get("machineName"))) { - toolsCommand.setTool(command.getAttributes().get("machineName")); - } Action action = new Action(); - Exec exec = new Exec(); - exec.setCommand(command.getCommandLine()); - if (!isNullOrEmpty(command.getAttributes().get("machineName"))) { - exec.setWorkdir(command.getAttributes().get("workingDir")); + action.setCommand(command.getCommandLine()); + if (!isNullOrEmpty(command.getAttributes().get("workingDir"))) { + action.setWorkdir(command.getAttributes().get("workingDir")); } - action.setExec(exec); - toolsCommand.setAction(action); - devCommand.setToolsCommands(Collections.singletonList(toolsCommand)); commands.add(devCommand); } devFile.setCommands(commands); @@ -90,24 +77,19 @@ static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { List tools = new ArrayList<>(); if (wsConfig.getAttributes().containsKey("editor")) { Tool editorTool = new Tool(); - editorTool.setName("editor"); - Definition definition = new Definition(); - CheEditor cheEditor = new CheEditor(); - cheEditor.setName(wsConfig.getAttributes().get("editor")); - definition.setCheEditor(cheEditor); - editorTool.setDefinition(definition); + editorTool.setType("cheEditor"); + String editorId = wsConfig.getAttributes().get("editor"); + editorTool.setId(editorId); + editorTool.setName(editorId.substring(0, editorId.indexOf(":"))); tools.add(editorTool); } if (wsConfig.getAttributes().containsKey("plugins")) { - for (String plugin : wsConfig.getAttributes().get("plugins").split(",")) { + for (String pluginId : wsConfig.getAttributes().get("plugins").split(",")) { Tool pluginTool = new Tool(); - pluginTool.setName(plugin.substring(0, plugin.indexOf(":"))); - Definition definition = new Definition(); - ChePlugin chePlugin = new ChePlugin(); - chePlugin.setId(plugin); - definition.setChePlugin(chePlugin); - pluginTool.setDefinition(definition); + pluginTool.setName(pluginId.substring(0, pluginId.indexOf(":"))); + pluginTool.setId(pluginId); + pluginTool.setType("chePlugin"); tools.add(pluginTool); } } @@ -138,34 +120,42 @@ static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) } config.setProjects(projects); - // Manage commands - List commands = new ArrayList<>(); - for (Command devCommand : devFile.getCommands()) { - for (ToolsCommand toolCommand : devCommand.getToolsCommands()) { - CommandImpl command = new CommandImpl(); - command.setName(devCommand.getName() + ":" + toolCommand.getTool()); - command.setCommandLine(toolCommand.getAction().getExec().getCommand()); - command.getAttributes().put("machineName", toolCommand.getTool()); - command.getAttributes().put("workingDir", toolCommand.getAction().getExec().getWorkdir()); - commands.add(command); - } - } - - config.setCommands(commands); - // Manage tools Map attributes = new HashMap<>(); StringJoiner pluginsStringJoiner = new StringJoiner(","); for (Tool tool : devFile.getTools()) { - if (tool.getDefinition().getCheEditor() != null) { - attributes.put("editor", tool.getDefinition().getCheEditor().getId()); + if (tool.getType().equals("cheEditor")) { + attributes.put("editor", tool.getId()); } else { - pluginsStringJoiner.add(tool.getDefinition().getChePlugin().getId()); + pluginsStringJoiner.add(tool.getId()); } } attributes.put("plugins", pluginsStringJoiner.toString()); config.setAttributes(attributes); + // Manage commands + List commands = new ArrayList<>(); + for (Command devCommand : devFile.getCommands()) { + for (Action devAction : devCommand.getActions()) { + CommandImpl command = new CommandImpl(); + command.setName(devCommand.getName() + ":" + devAction.getTool()); + command.setCommandLine(devAction.getCommand()); + command.getAttributes().put("workingDir", devAction.getWorkdir()); + Optional toolOfCommand = + devFile + .getTools() + .stream() + .filter(tool -> tool.getName().equals(devAction.getTool())) + .findFirst(); + if (toolOfCommand.isPresent()) { + command.getAttributes().put("pluginId", toolOfCommand.get().getId()); + } + commands.add(command); + } + } + + config.setCommands(commands); + // TODO: Add default environment. Remove when it will be possible config.setDefaultEnv("default"); EnvironmentImpl environment = new EnvironmentImpl(); From 137c52b9c36ee1025fbd2aca9f7c290b486ff43a Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Tue, 13 Nov 2018 17:22:33 +0200 Subject: [PATCH 07/46] Add tests --- .../eclipse/che/api/devfile/model/Action.java | 18 +-- .../che/api/devfile/model/Command.java | 12 +- .../che/api/devfile/model/DevFile.java | 35 ++--- .../che/api/devfile/model/Project.java | 16 --- .../eclipse/che/api/devfile/model/Source.java | 17 --- .../eclipse/che/api/devfile/model/Tool.java | 17 --- wsmaster/che-core-api-devfile/pom.xml | 9 ++ .../api/devfile/server/DevFileConverter.java | 57 +++++---- .../devfile/server/DevFileConverterTest.java | 120 ++++++++++++++++++ .../src/test/resources/devfile.yaml | 50 ++++++++ .../src/test/resources/workspace_impl.json | 69 ++++++++++ 11 files changed, 295 insertions(+), 125 deletions(-) create mode 100644 wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java create mode 100644 wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml create mode 100644 wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java index cb1cce13485..a88bf913cd9 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java @@ -11,14 +11,9 @@ */ package org.eclipse.che.api.devfile.model; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.HashMap; -import java.util.Map; @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({"type", "tool", "command", "workdir"}) @@ -36,8 +31,6 @@ public class Action { @JsonProperty("workdir") private String workdir; - @JsonIgnore private Map additionalProperties = new HashMap<>(); - @JsonProperty("command") public String getCommand() { return command; @@ -68,6 +61,7 @@ public void setType(String type) { this.type = type; } + @JsonProperty("tool") public String getTool() { return tool; @@ -77,14 +71,4 @@ public String getTool() { public void setTool(String tool) { this.tool = tool; } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @JsonAnySetter - public void setAdditionalProperty(String name, String value) { - this.additionalProperties.put(name, value); - } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java index 6c4d6884169..bddd1496e64 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java @@ -13,7 +13,6 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; @@ -31,7 +30,8 @@ public class Command { @JsonProperty("actions") private List actions = null; - @JsonIgnore private Map additionalProperties = new HashMap<>(); + @JsonProperty("attributes") + private Map attributes = new HashMap<>(); @JsonProperty("name") public String getName() { @@ -54,12 +54,12 @@ public void setActions(List actions) { } @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; + public Map getAttributes() { + return this.attributes; } @JsonAnySetter - public void setAdditionalProperty(String name, String value) { - this.additionalProperties.put(name, value); + public void getAttribute(String name, String value) { + this.attributes.put(name, value); } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java index 9dbee86eecd..20eaed55a67 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java @@ -11,22 +11,17 @@ */ package org.eclipse.che.api.devfile.model; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.HashMap; import java.util.List; -import java.util.Map; @JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"specVersion", "name", "projects", "tools", "commands"}) +@JsonPropertyOrder({"version", "name", "projects", "tools", "commands"}) public class DevFile { - @JsonProperty("specVersion") - private String specVersion; + @JsonProperty("version") + private String version; @JsonProperty("name") private String name; @@ -40,16 +35,14 @@ public class DevFile { @JsonProperty("commands") private List commands = null; - @JsonIgnore private Map additionalProperties = new HashMap<>(); - - @JsonProperty("specVersion") - public String getSpecVersion() { - return specVersion; + @JsonProperty("version") + public String getVersion() { + return version; } - @JsonProperty("specVersion") - public void setSpecVersion(String specVersion) { - this.specVersion = specVersion; + @JsonProperty("version") + public void setVersion(String version) { + this.version = version; } @JsonProperty("name") @@ -91,14 +84,4 @@ public List getCommands() { public void setCommands(List commands) { this.commands = commands; } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @JsonAnySetter - public void setAdditionalProperty(String name, String value) { - this.additionalProperties.put(name, value); - } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java index 15b82ce4a8e..1a670ed6857 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java @@ -11,14 +11,9 @@ */ package org.eclipse.che.api.devfile.model; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.HashMap; -import java.util.Map; @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({"name", "source"}) @@ -30,8 +25,6 @@ public class Project { @JsonProperty("source") private Source source; - @JsonIgnore private Map additionalProperties = new HashMap<>(); - @JsonProperty("name") public String getName() { return name; @@ -52,13 +45,4 @@ public void setSource(Source source) { this.source = source; } - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @JsonAnySetter - public void setAdditionalProperty(String name, String value) { - this.additionalProperties.put(name, value); - } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java index 3cfbd508304..5b634de7e3c 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java @@ -11,14 +11,9 @@ */ package org.eclipse.che.api.devfile.model; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.HashMap; -import java.util.Map; @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({"type", "location"}) @@ -30,8 +25,6 @@ public class Source { @JsonProperty("location") private String location; - @JsonIgnore private Map additionalProperties = new HashMap<>(); - @JsonProperty("type") public String getType() { return type; @@ -51,14 +44,4 @@ public String getLocation() { public void setLocation(String location) { this.location = location; } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @JsonAnySetter - public void setAdditionalProperty(String name, String value) { - this.additionalProperties.put(name, value); - } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java index 4e9371dd135..3cff92df814 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java @@ -11,14 +11,9 @@ */ package org.eclipse.che.api.devfile.model; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.HashMap; -import java.util.Map; @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({"name", "type", "id"}) @@ -33,8 +28,6 @@ public class Tool { @JsonProperty("type") private String type; - @JsonIgnore private Map additionalProperties = new HashMap<>(); - @JsonProperty("name") public String getName() { return name; @@ -64,14 +57,4 @@ public String getId() { public void setId(String id) { this.id = id; } - - @JsonAnyGetter - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - @JsonAnySetter - public void setAdditionalProperty(String name, String value) { - this.additionalProperties.put(name, value); - } } diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index b79bf330fa2..e9fc3b5be5e 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -63,6 +63,10 @@ org.eclipse.che.core che-core-api-workspace-shared + + org.eclipse.che.core + che-core-commons-json + org.everrest everrest-core @@ -77,6 +81,11 @@ javax.ws.rs-api provided + + org.testng + testng + test + diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index c99b6e4032e..d7a59c97fd1 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -40,7 +40,7 @@ public class DevFileConverter { static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { DevFile devFile = new DevFile(); - devFile.setSpecVersion(CURRENT_SPEC_VERSION); + devFile.setVersion(CURRENT_SPEC_VERSION); devFile.setName(wsConfig.getName()); // Manage projects @@ -51,9 +51,6 @@ static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { Source source = new Source(); source.setType(project.getSource().getType()); source.setLocation(project.getSource().getLocation()); - for (Map.Entry entry : project.getSource().getParameters().entrySet()) { - source.setAdditionalProperty(entry.getKey(), entry.getValue()); - } devProject.setSource(source); projects.add(devProject); } @@ -69,28 +66,33 @@ static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { if (!isNullOrEmpty(command.getAttributes().get("workingDir"))) { action.setWorkdir(command.getAttributes().get("workingDir")); } + // Remove internal attributes + command.getAttributes().remove("workingDir"); + command.getAttributes().remove("pluginId"); + // Put others + devCommand.getAttributes().putAll(command.getAttributes()); commands.add(devCommand); } devFile.setCommands(commands); // Manage tools List tools = new ArrayList<>(); - if (wsConfig.getAttributes().containsKey("editor")) { - Tool editorTool = new Tool(); - editorTool.setType("cheEditor"); - String editorId = wsConfig.getAttributes().get("editor"); - editorTool.setId(editorId); - editorTool.setName(editorId.substring(0, editorId.indexOf(":"))); - tools.add(editorTool); - } - - if (wsConfig.getAttributes().containsKey("plugins")) { - for (String pluginId : wsConfig.getAttributes().get("plugins").split(",")) { - Tool pluginTool = new Tool(); - pluginTool.setName(pluginId.substring(0, pluginId.indexOf(":"))); - pluginTool.setId(pluginId); - pluginTool.setType("chePlugin"); - tools.add(pluginTool); + for (Map.Entry entry : wsConfig.getAttributes().entrySet()) { + if (entry.getKey().equals("editor")) { + Tool editorTool = new Tool(); + editorTool.setType("cheEditor"); + String editorId = wsConfig.getAttributes().get("editor"); + editorTool.setId(editorId); + editorTool.setName(wsConfig.getAttributes().get(editorId)); + tools.add(editorTool); + } else if (entry.getKey().equals("plugins")) { + for (String pluginId : wsConfig.getAttributes().get("plugins").split(",")) { + Tool pluginTool = new Tool(); + pluginTool.setId(pluginId); + pluginTool.setType("chePlugin"); + pluginTool.setName(wsConfig.getAttributes().get(pluginId)); + tools.add(pluginTool); + } } } @@ -114,7 +116,6 @@ static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) SourceStorageImpl sourceStorage = new SourceStorageImpl(); sourceStorage.setType(devProject.getSource().getType()); sourceStorage.setLocation(devProject.getSource().getLocation()); - sourceStorage.setParameters(devProject.getAdditionalProperties()); projectConfig.setSource(sourceStorage); projects.add(projectConfig); } @@ -126,9 +127,10 @@ static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) for (Tool tool : devFile.getTools()) { if (tool.getType().equals("cheEditor")) { attributes.put("editor", tool.getId()); - } else { + } else if (tool.getType().equals("chePlugin")) { pluginsStringJoiner.add(tool.getId()); } + attributes.put(tool.getId(), tool.getName()); } attributes.put("plugins", pluginsStringJoiner.toString()); config.setAttributes(attributes); @@ -140,16 +142,19 @@ static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) CommandImpl command = new CommandImpl(); command.setName(devCommand.getName() + ":" + devAction.getTool()); command.setCommandLine(devAction.getCommand()); - command.getAttributes().put("workingDir", devAction.getWorkdir()); + if (devAction.getWorkdir() != null) { + command.getAttributes().put("workingDir", devAction.getWorkdir()); + } Optional toolOfCommand = devFile .getTools() .stream() .filter(tool -> tool.getName().equals(devAction.getTool())) .findFirst(); - if (toolOfCommand.isPresent()) { + if (toolOfCommand.isPresent() && !isNullOrEmpty(toolOfCommand.get().getId())) { command.getAttributes().put("pluginId", toolOfCommand.get().getId()); } + command.getAttributes().putAll(devCommand.getAttributes()); commands.add(command); } } @@ -171,9 +176,9 @@ static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) } private static void validateDevFile(DevFile devFile) throws DevFileFormatException { - if (!CURRENT_SPEC_VERSION.equals(devFile.getSpecVersion())) { + if (!CURRENT_SPEC_VERSION.equals(devFile.getVersion())) { throw new DevFileFormatException( - format("Provided devfile has unsupported version %s", devFile.getSpecVersion())); + format("Provided devfile has unsupported version %s", devFile.getVersion())); } } } diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java new file mode 100644 index 00000000000..1b118f65b56 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.server; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import org.eclipse.che.api.devfile.model.Action; +import org.eclipse.che.api.devfile.model.Command; +import org.eclipse.che.api.devfile.model.DevFile; +import org.eclipse.che.api.devfile.model.Project; +import org.eclipse.che.api.devfile.model.Tool; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; +import org.eclipse.che.commons.json.JsonHelper; +import org.testng.annotations.Test; +import org.testng.reporters.Files; + +public class DevFileConverterTest { + + private ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); + + @Test + public void shouldBuildWorkspaceConfigFromYamlDevFile() throws Exception { + + String yamlContent = + Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); + + DevFile devFile = objectMapper.readValue(yamlContent, DevFile.class); + + WorkspaceConfigImpl wsConfigImpl = DevFileConverter.devFileToWorkspaceConfig(devFile); + + String jsonContent = + Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_impl.json")); + + assertEquals(wsConfigImpl, JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null)); + } + + @Test + public void shouldBuildYamlDevFileFromWorkspaceConfig() throws Exception { + + String jsonContent = + Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_impl.json")); + WorkspaceConfigImpl workspaceConfig = + JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null); + DevFile devFile = DevFileConverter.workspaceToDevFile(workspaceConfig); + + String yamlContent = + Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); + + DevFile expectedDevFile = objectMapper.readValue(yamlContent, DevFile.class); + + // Recursively compare + assertEquals(devFile.getVersion(), expectedDevFile.getVersion()); + assertEquals(devFile.getName(), expectedDevFile.getName()); + assertEquals(devFile.getProjects().size(), expectedDevFile.getProjects().size()); + for (Project project : devFile.getProjects()) { + Project expectedProject = + expectedDevFile + .getProjects() + .stream() + .filter(project1 -> project1.getName().equals(project.getName())) + .findFirst() + .get(); + assertEquals(project.getSource().getType(), expectedProject.getSource().getType()); + assertEquals(project.getSource().getLocation(), expectedProject.getSource().getLocation()); + } + + assertEquals(devFile.getCommands().size(), expectedDevFile.getCommands().size()); + for (Command command : devFile.getCommands()) { + Command expectedCommand = + expectedDevFile + .getCommands() + .stream() + .filter(command1 -> command1.getName().equals(command.getName().split(":")[0])) + .findFirst() + .get(); + for (Action action : expectedCommand.getActions()) { + Action expectedAction = + expectedCommand + .getActions() + .stream() + .filter(action1 -> action1.getTool().equals(action.getTool())) + .findFirst() + .get(); + assertEquals(action.getCommand(), expectedAction.getCommand()); + assertEquals(action.getType(), expectedAction.getType()); + assertEquals(action.getWorkdir(), expectedAction.getWorkdir()); + } + assertTrue( + command + .getAttributes() + .entrySet() + .containsAll(expectedCommand.getAttributes().entrySet())); + } + + assertEquals(devFile.getTools().size(), expectedDevFile.getTools().size()); + for (Tool tool : devFile.getTools()) { + Tool expectedTool = + expectedDevFile + .getTools() + .stream() + .filter(tool1 -> tool1.getName().equals(tool.getName())) + .findFirst() + .get(); + assertEquals(tool.getId(), expectedTool.getId()); + assertEquals(tool.getType(), expectedTool.getType()); + } + } +} diff --git a/wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml b/wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml new file mode 100644 index 00000000000..e0a107825c9 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml @@ -0,0 +1,50 @@ +# +# Copyright (c) 2012-2018 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Red Hat, Inc. - initial API and implementation +# + +--- +version: 0.0.1 +name: petclinic-dev-environment +projects: + - name: petclinic + source: + type: git + location: 'git@github.com:spring-projects/spring-petclinic.git' +tools: + - name: mvn-stack + type: chePlugin + id: eclipse/maven-jdk8:1.0.0 + - name: theia-ide + type: cheEditor + id: eclipse/theia:0.0.3 + - name: jdt.ls + type: chePlugin + id: eclipse/theia-jdtls:0.0.3 +commands: + - name: build + actions: + - type: exec + tool: mvn-stack + command: mvn package + workdir: /projects/spring-petclinic + - name: run + attributes: + runType: sequential + actions: + - type: exec + tool: mvn-stack + command: mvn spring-boot:run + workdir: /projects/spring-petclinic + - name: other + actions: + - type: exec + tool: jdt.ls + command: run.sh \ No newline at end of file diff --git a/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json b/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json new file mode 100644 index 00000000000..5bfafb20447 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json @@ -0,0 +1,69 @@ +{ + "projects": [ + { + "source": { + "location": "git@github.com:spring-projects/spring-petclinic.git", + "type": "git", + "parameters": {} + }, + "mixins": [], + "name": "petclinic", + "path": "/petclinic", + "attributes": {} + } + ], + "commands": [ + { + "commandLine": "mvn package", + "name": "build:mvn-stack", + "attributes": { + "pluginId": "eclipse/maven-jdk8:1.0.0", + "workingDir": "/projects/spring-petclinic" + } + }, + { + "commandLine": "mvn spring-boot:run", + "name": "run:mvn-stack", + "attributes": { + "pluginId": "eclipse/maven-jdk8:1.0.0", + "runType": "sequential", + "workingDir": "/projects/spring-petclinic" + } + }, + { + "commandLine": "run.sh", + "name": "other:jdt.ls", + "attributes": { + "pluginId": "eclipse/theia-jdtls:0.0.3" + } + } + ], + "defaultEnv": "default", + "environments": { + "default": { + "recipe": { + "type": "dockerimage", + "content": "eclipse/ubuntu_jdk8" + }, + "machines": { + "dev-machine": { + "installers": [], + "servers": {}, + "env": {}, + "volumes": {}, + "attributes": { + "memoryLimitBytes": "2147483648" + } + } + } + } + }, + "name": "petclinic-dev-environment", + "attributes": { + "eclipse/maven-jdk8:1.0.0": "mvn-stack", + "editor": "eclipse/theia:0.0.3", + "eclipse/theia-jdtls:0.0.3": "jdt.ls", + "plugins": "eclipse/maven-jdk8:1.0.0,eclipse/theia-jdtls:0.0.3", + "eclipse/theia:0.0.3": "theia-ide" + } +} \ No newline at end of file From 96ba661c086677e0db8133857e52a33ea8e785a6 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Thu, 15 Nov 2018 10:45:54 +0200 Subject: [PATCH 08/46] Add tests & model fixups --- .../eclipse/che/api/devfile/model/Action.java | 19 ++ .../che/api/devfile/model/Command.java | 15 ++ .../che/api/devfile/model/DevFile.java | 25 +++ .../che/api/devfile/model/Project.java | 9 + .../eclipse/che/api/devfile/model/Source.java | 10 + .../eclipse/che/api/devfile/model/Tool.java | 15 ++ .../api/devfile/server/DevFileConverter.java | 42 ++-- .../src/main/resources/devfile_schema.json | 211 ++++++++++++++++++ .../devfile/server/DevFileConverterTest.java | 1 + .../src/test/resources/workspace_impl.json | 5 +- 10 files changed, 330 insertions(+), 22 deletions(-) create mode 100644 wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java index a88bf913cd9..123e94fe9dc 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java @@ -41,6 +41,11 @@ public void setCommand(String command) { this.command = command; } + public Action withCommand(String command) { + this.command = command; + return this; + } + @JsonProperty("workdir") public String getWorkdir() { return workdir; @@ -51,6 +56,11 @@ public void setWorkdir(String workdir) { this.workdir = workdir; } + public Action withWorkdir(String workdir) { + this.workdir = workdir; + return this; + } + @JsonProperty("type") public String getType() { return type; @@ -61,6 +71,10 @@ public void setType(String type) { this.type = type; } + public Action withType(String type) { + this.type = type; + return this; + } @JsonProperty("tool") public String getTool() { @@ -71,4 +85,9 @@ public String getTool() { public void setTool(String tool) { this.tool = tool; } + + public Action withTool(String tool) { + this.tool = tool; + return this; + } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java index bddd1496e64..aebd3a1db17 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java @@ -43,6 +43,11 @@ public void setName(String name) { this.name = name; } + public Command withName(String name) { + this.name = name; + return this; + } + @JsonProperty("actions") public List getActions() { return actions; @@ -53,6 +58,11 @@ public void setActions(List actions) { this.actions = actions; } + public Command withActions(List actions) { + this.actions = actions; + return this; + } + @JsonAnyGetter public Map getAttributes() { return this.attributes; @@ -62,4 +72,9 @@ public Map getAttributes() { public void getAttribute(String name, String value) { this.attributes.put(name, value); } + + public Command withAttributes(Map attributes) { + this.attributes = attributes; + return this; + } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java index 20eaed55a67..4cc10676c80 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java @@ -45,6 +45,11 @@ public void setVersion(String version) { this.version = version; } + public DevFile withVersion(String version) { + this.version = version; + return this; + } + @JsonProperty("name") public String getName() { return name; @@ -55,6 +60,11 @@ public void setName(String name) { this.name = name; } + public DevFile withName(String name) { + this.name = name; + return this; + } + @JsonProperty("projects") public List getProjects() { return projects; @@ -65,6 +75,11 @@ public void setProjects(List projects) { this.projects = projects; } + public DevFile withProjects(List projects) { + this.projects = projects; + return this; + } + @JsonProperty("tools") public List getTools() { return tools; @@ -75,6 +90,11 @@ public void setTools(List tools) { this.tools = tools; } + public DevFile withTools(List tools) { + this.tools = tools; + return this; + } + @JsonProperty("commands") public List getCommands() { return commands; @@ -84,4 +104,9 @@ public List getCommands() { public void setCommands(List commands) { this.commands = commands; } + + public DevFile withCommands(List commands) { + this.commands = commands; + return this; + } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java index 1a670ed6857..a3e26b17ea0 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java @@ -35,6 +35,11 @@ public void setName(String name) { this.name = name; } + public Project withName(String name) { + this.name = name; + return this; + } + @JsonProperty("source") public Source getSource() { return source; @@ -45,4 +50,8 @@ public void setSource(Source source) { this.source = source; } + public Project withSource(Source source) { + this.source = source; + return this; + } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java index 5b634de7e3c..3b5e5cf3c5f 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java @@ -35,6 +35,11 @@ public void setType(String type) { this.type = type; } + public Source withType(String type) { + this.type = type; + return this; + } + @JsonProperty("location") public String getLocation() { return location; @@ -44,4 +49,9 @@ public String getLocation() { public void setLocation(String location) { this.location = location; } + + public Source withLocation(String location) { + this.location = location; + return this; + } } diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java index 3cff92df814..185c4f1ac24 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java +++ b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java @@ -38,6 +38,11 @@ public void setName(String name) { this.name = name; } + public Tool withName(String name) { + this.name = name; + return this; + } + @JsonProperty("type") public String getType() { return type; @@ -48,6 +53,11 @@ public void setType(String type) { this.type = type; } + public Tool withType(String type) { + this.type = type; + return this; + } + @JsonProperty("id") public String getId() { return id; @@ -57,4 +67,9 @@ public String getId() { public void setId(String id) { this.id = id; } + + public Tool withId(String id) { + this.id = id; + return this; + } } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index d7a59c97fd1..73bd9e9313d 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -39,19 +39,17 @@ public class DevFileConverter { static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { - DevFile devFile = new DevFile(); - devFile.setVersion(CURRENT_SPEC_VERSION); - devFile.setName(wsConfig.getName()); + + DevFile devFile = new DevFile().withVersion(CURRENT_SPEC_VERSION).withName(wsConfig.getName()); // Manage projects List projects = new ArrayList<>(); for (ProjectConfigImpl project : wsConfig.getProjects()) { - Project devProject = new Project(); - devProject.setName(project.getName()); - Source source = new Source(); - source.setType(project.getSource().getType()); - source.setLocation(project.getSource().getLocation()); - devProject.setSource(source); + Source source = + new Source() + .withType(project.getSource().getType()) + .withLocation(project.getSource().getLocation()); + Project devProject = new Project().withName(project.getName()).withSource(source); projects.add(devProject); } devFile.setProjects(projects); @@ -59,10 +57,9 @@ static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { // Manage commands List commands = new ArrayList<>(); for (CommandImpl command : wsConfig.getCommands()) { - Command devCommand = new Command(); - devCommand.setName(command.getName()); - Action action = new Action(); - action.setCommand(command.getCommandLine()); + Command devCommand = new Command().withName(command.getName()); + Action action = + new Action().withCommand(command.getCommandLine()).withType(command.getType()); if (!isNullOrEmpty(command.getAttributes().get("workingDir"))) { action.setWorkdir(command.getAttributes().get("workingDir")); } @@ -79,18 +76,20 @@ static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { List tools = new ArrayList<>(); for (Map.Entry entry : wsConfig.getAttributes().entrySet()) { if (entry.getKey().equals("editor")) { - Tool editorTool = new Tool(); - editorTool.setType("cheEditor"); String editorId = wsConfig.getAttributes().get("editor"); - editorTool.setId(editorId); - editorTool.setName(wsConfig.getAttributes().get(editorId)); + Tool editorTool = + new Tool() + .withType("cheEditor") + .withId(editorId) + .withName(wsConfig.getAttributes().get(editorId)); tools.add(editorTool); } else if (entry.getKey().equals("plugins")) { for (String pluginId : wsConfig.getAttributes().get("plugins").split(",")) { - Tool pluginTool = new Tool(); - pluginTool.setId(pluginId); - pluginTool.setType("chePlugin"); - pluginTool.setName(wsConfig.getAttributes().get(pluginId)); + Tool pluginTool = + new Tool() + .withId(pluginId) + .withType("chePlugin") + .withName(wsConfig.getAttributes().get(pluginId)); tools.add(pluginTool); } } @@ -141,6 +140,7 @@ static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) for (Action devAction : devCommand.getActions()) { CommandImpl command = new CommandImpl(); command.setName(devCommand.getName() + ":" + devAction.getTool()); + command.setType(devAction.getType()); command.setCommandLine(devAction.getCommand()); if (devAction.getWorkdir() != null) { command.getAttributes().put("workingDir", devAction.getWorkdir()); diff --git a/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json b/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json new file mode 100644 index 00000000000..7aefba2f960 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json @@ -0,0 +1,211 @@ +{ + "definitions": {}, + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://example.com/root.json", + "type": "object", + "title": "The Root Schema of DevFile object", + "required": [ + "version", + "name", + "projects", + "tools", + "commands" + ], + "properties": { + "version": { + "$id": "#/properties/version", + "type": "string", + "title": "The Version Schema", + "default": "", + "examples": [ + "0.0.1" + ] + }, + "name": { + "$id": "#/properties/name", + "type": "string", + "title": "The Name Schema", + "default": "", + "examples": [ + "petclinic-dev-environment" + ] + }, + "projects": { + "$id": "#/properties/projects", + "type": "array", + "title": "The Projects Schema", + "items": { + "$id": "#/properties/projects/items", + "type": "object", + "title": "The Project Items Schema", + "required": [ + "name", + "source" + ], + "properties": { + "name": { + "$id": "#/properties/projects/items/properties/name", + "type": "string", + "title": "The Project Name Schema", + "default": "", + "examples": [ + "petclinic" + ] + }, + "source": { + "$id": "#/properties/projects/items/properties/source", + "type": "object", + "title": "The Project Source Schema", + "required": [ + "type", + "location" + ], + "properties": { + "type": { + "$id": "#/properties/projects/items/properties/source/properties/type", + "type": "string", + "title": "The Project Source Type Schema", + "default": "", + "examples": [ + "git" + ] + }, + "location": { + "$id": "#/properties/projects/items/properties/source/properties/location", + "type": "string", + "title": "The Project Source Location Schema", + "default": "", + "examples": [ + "git@github.com:spring-projects/spring-petclinic.git" + ] + } + } + } + } + } + }, + "tools": { + "$id": "#/properties/tools", + "type": "array", + "title": "The Tools Schema", + "items": { + "$id": "#/properties/tools/items", + "type": "object", + "title": "The Items Schema", + "required": [ + "name", + "type", + "id" + ], + "properties": { + "name": { + "$id": "#/properties/tools/items/properties/name", + "type": "string", + "title": "The Tool Name Schema", + "default": "", + "examples": [ + "mvn-stack" + ] + }, + "type": { + "$id": "#/properties/tools/items/properties/type", + "type": "string", + "title": "The Tool Type Schema", + "default": "", + "examples": [ + "chePlugin" + ] + }, + "id": { + "$id": "#/properties/tools/items/properties/id", + "type": "string", + "title": "The Tool Id Schema", + "default": "", + "examples": [ + "eclipse/maven-jdk8:1.0.0" + ] + } + } + } + }, + "commands": { + "$id": "#/properties/commands", + "type": "array", + "title": "The Commands Schema", + "items": { + "$id": "#/properties/commands/items", + "type": "object", + "title": "The Items Schema", + "required": [ + "name", + "actions" + ], + "properties": { + "name": { + "$id": "#/properties/commands/items/properties/name", + "type": "string", + "title": "The Command Name Schema", + "default": "", + "examples": [ + "build" + ] + }, + "actions": { + "$id": "#/properties/commands/items/properties/actions", + "type": "array", + "title": "The Command Actions Schema", + "items": { + "$id": "#/properties/commands/items/properties/actions/items", + "type": "object", + "title": "The Command Items Schema", + "required": [ + "type", + "tool", + "command", + "workdir" + ], + "properties": { + "type": { + "$id": "#/properties/commands/items/properties/actions/items/properties/type", + "type": "string", + "title": "The Action Type Schema", + "default": "", + "examples": [ + "exec" + ] + }, + "tool": { + "$id": "#/properties/commands/items/properties/actions/items/properties/tool", + "type": "string", + "title": "The Action Tool Schema", + "default": "", + "examples": [ + "mvn-stack" + ] + }, + "command": { + "$id": "#/properties/commands/items/properties/actions/items/properties/command", + "type": "string", + "title": "The Action Command Schema", + "default": "", + "examples": [ + "mvn package" + ] + }, + "workdir": { + "$id": "#/properties/commands/items/properties/actions/items/properties/workdir", + "type": "string", + "title": "The Action Workdir Schema", + "default": "", + "examples": [ + "/projects/spring-petclinic" + ] + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java index 1b118f65b56..bda7878ea3f 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java @@ -42,6 +42,7 @@ public void shouldBuildWorkspaceConfigFromYamlDevFile() throws Exception { String jsonContent = Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_impl.json")); + System.out.println(JsonHelper.toJson(wsConfigImpl)); assertEquals(wsConfigImpl, JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null)); } diff --git a/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json b/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json index 5bfafb20447..c5e1a52b2c1 100644 --- a/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json +++ b/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json @@ -16,6 +16,7 @@ { "commandLine": "mvn package", "name": "build:mvn-stack", + "type": "exec", "attributes": { "pluginId": "eclipse/maven-jdk8:1.0.0", "workingDir": "/projects/spring-petclinic" @@ -24,6 +25,7 @@ { "commandLine": "mvn spring-boot:run", "name": "run:mvn-stack", + "type": "exec", "attributes": { "pluginId": "eclipse/maven-jdk8:1.0.0", "runType": "sequential", @@ -33,12 +35,12 @@ { "commandLine": "run.sh", "name": "other:jdt.ls", + "type": "exec", "attributes": { "pluginId": "eclipse/theia-jdtls:0.0.3" } } ], - "defaultEnv": "default", "environments": { "default": { "recipe": { @@ -58,6 +60,7 @@ } } }, + "defaultEnv": "default", "name": "petclinic-dev-environment", "attributes": { "eclipse/maven-jdk8:1.0.0": "mvn-stack", From 8e35675b6934d5b03e7b722149b63fc4d80d3d51 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Thu, 15 Nov 2018 10:55:34 +0200 Subject: [PATCH 09/46] fixup! Add tests & model fixups --- wsmaster/che-core-api-devfile-shared/pom.xml | 22 -------------------- 1 file changed, 22 deletions(-) diff --git a/wsmaster/che-core-api-devfile-shared/pom.xml b/wsmaster/che-core-api-devfile-shared/pom.xml index 83dcd53f03f..cce98873dd6 100644 --- a/wsmaster/che-core-api-devfile-shared/pom.xml +++ b/wsmaster/che-core-api-devfile-shared/pom.xml @@ -27,27 +27,5 @@ com.fasterxml.jackson.core jackson-annotations - - org.everrest - everrest-core - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - analyze - - - org.everrest:everrest-core - - - - - - - From 989e70cc54d21b445fb22b7609deb7194bff9e3d Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Thu, 15 Nov 2018 11:11:14 +0200 Subject: [PATCH 10/46] Add n\l; --- .../che-core-api-devfile/src/main/resources/devfile_schema.json | 2 +- wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml | 2 +- .../che-core-api-devfile/src/test/resources/workspace_impl.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json b/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json index 7aefba2f960..c14fc90a069 100644 --- a/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json +++ b/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json @@ -208,4 +208,4 @@ } } } -} \ No newline at end of file +} diff --git a/wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml b/wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml index e0a107825c9..d3794ebaf78 100644 --- a/wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml +++ b/wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml @@ -47,4 +47,4 @@ commands: actions: - type: exec tool: jdt.ls - command: run.sh \ No newline at end of file + command: run.sh diff --git a/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json b/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json index c5e1a52b2c1..ac6f36be144 100644 --- a/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json +++ b/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json @@ -69,4 +69,4 @@ "plugins": "eclipse/maven-jdk8:1.0.0,eclipse/theia-jdtls:0.0.3", "eclipse/theia:0.0.3": "theia-ide" } -} \ No newline at end of file +} From 0014ef64d981efc63415f65cef35c401355dd09e Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 19 Nov 2018 11:29:12 +0200 Subject: [PATCH 11/46] Add schema & validation --- wsmaster/che-core-api-devfile/pom.xml | 5 +++ .../src/main/resources/devfile_schema.json | 3 +- .../api/devfile/server/DevFileSchemaTest.java | 43 +++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index e9fc3b5be5e..96aafc4f59d 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -71,6 +71,11 @@ org.everrest everrest-core + + com.github.java-json-tools + json-schema-validator + 2.2.10 + javax.servlet javax.servlet-api diff --git a/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json b/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json index c14fc90a069..da479a204fd 100644 --- a/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json +++ b/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json @@ -161,8 +161,7 @@ "required": [ "type", "tool", - "command", - "workdir" + "command" ], "properties": { "type": { diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java new file mode 100644 index 00000000000..4c50244d0e0 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java @@ -0,0 +1,43 @@ +package org.eclipse.che.api.devfile.server; + +import static org.testng.Assert.assertTrue; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.github.fge.jackson.JsonLoader; +import com.github.fge.jsonschema.core.report.ProcessingReport; +import com.github.fge.jsonschema.main.JsonSchemaFactory; +import com.github.fge.jsonschema.main.JsonValidator; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.testng.reporters.Files; + +public class DevFileSchemaTest { + + private JsonValidator validator; + private ObjectMapper yamlReader; + + @BeforeClass + public void setUp() { + final JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); + validator = factory.getValidator(); + yamlReader = new ObjectMapper(new YAMLFactory()); + } + + @Test + public void shouldValidateSchema() throws Exception { + + String devFileYamlContent = Files + .readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); + String devFileSchemaContent = Files + .readFile(getClass().getClassLoader().getResourceAsStream("devfile_schema.json")); + + final JsonNode data = yamlReader.readTree(devFileYamlContent); + final JsonNode schema = JsonLoader.fromString(devFileSchemaContent); + // when + ProcessingReport report = validator.validate(schema, data); + // then + assertTrue(report.isSuccess()); + } +} From 984f96454ef433a1d83065bf9fb3b3666ae0fb50 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 19 Nov 2018 17:42:26 +0200 Subject: [PATCH 12/46] Add pojo gen from schema --- wsmaster/che-core-api-devfile/pom.xml | 54 +++++++++++++++---- .../che/api/devfile/server}/Constants.java | 2 +- .../api/devfile/server/DevFileConverter.java | 23 +++++--- .../api/devfile/server/DevFileService.java | 8 +-- .../devfile.json} | 24 ++++----- .../devfile/server/DevFileConverterTest.java | 20 +++---- .../api/devfile/server/DevFileSchemaTest.java | 19 +++++-- wsmaster/pom.xml | 2 +- 8 files changed, 102 insertions(+), 50 deletions(-) rename wsmaster/{che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile => che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server}/Constants.java (90%) rename wsmaster/che-core-api-devfile/src/main/resources/{devfile_schema.json => schema/devfile.json} (93%) diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index 96aafc4f59d..ac35586cad5 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -35,6 +35,11 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml + + com.github.java-json-tools + json-schema-validator + 2.2.10 + com.google.guava guava @@ -47,10 +52,6 @@ org.eclipse.che.core che-core-api-core - - org.eclipse.che.core - che-core-api-devfile-shared - org.eclipse.che.core che-core-api-model @@ -71,11 +72,6 @@ org.everrest everrest-core - - com.github.java-json-tools - json-schema-validator - 2.2.10 - javax.servlet javax.servlet-api @@ -94,6 +90,46 @@ + + org.codehaus.mojo + build-helper-maven-plugin + 1.4 + + + test + generate-sources + + add-source + + + + ${basedir}/target/java-gen + + + + + + + org.jsonschema2pojo + jsonschema2pojo-maven-plugin + 0.5.1 + + + + generate + + + + + ${basedir}/src/main/resources/schema + org.eclipse.che.api.devfile.model + false + false + false + true + true + + org.apache.maven.plugins maven-dependency-plugin diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/Constants.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java similarity index 90% rename from wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/Constants.java rename to wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java index 27c389d3a19..63e8103f69b 100644 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/Constants.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java @@ -9,7 +9,7 @@ * Contributors: * Red Hat, Inc. - initial API and implementation */ -package org.eclipse.che.api.devfile; +package org.eclipse.che.api.devfile.server; public class Constants { diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index 73bd9e9313d..73ef3e65753 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -14,7 +14,7 @@ import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; import static java.util.Collections.singletonMap; -import static org.eclipse.che.api.devfile.Constants.CURRENT_SPEC_VERSION; +import static org.eclipse.che.api.devfile.server.Constants.CURRENT_SPEC_VERSION; import java.util.ArrayList; import java.util.HashMap; @@ -24,7 +24,7 @@ import java.util.StringJoiner; import org.eclipse.che.api.devfile.model.Action; import org.eclipse.che.api.devfile.model.Command; -import org.eclipse.che.api.devfile.model.DevFile; +import org.eclipse.che.api.devfile.model.Devfile; import org.eclipse.che.api.devfile.model.Project; import org.eclipse.che.api.devfile.model.Source; import org.eclipse.che.api.devfile.model.Tool; @@ -38,9 +38,9 @@ public class DevFileConverter { - static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { + static Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { - DevFile devFile = new DevFile().withVersion(CURRENT_SPEC_VERSION).withName(wsConfig.getName()); + Devfile devFile = new Devfile().withVersion(CURRENT_SPEC_VERSION).withName(wsConfig.getName()); // Manage projects List projects = new ArrayList<>(); @@ -67,7 +67,12 @@ static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { command.getAttributes().remove("workingDir"); command.getAttributes().remove("pluginId"); // Put others - devCommand.getAttributes().putAll(command.getAttributes()); + if (devCommand.getAttributes() == null) { + devCommand.withAttributes(command.getAttributes()); + } else { + devCommand.getAttributes().putAll(command.getAttributes()); + } + commands.add(devCommand); } devFile.setCommands(commands); @@ -99,7 +104,7 @@ static DevFile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { return devFile; } - static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) + static WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) throws DevFileFormatException { validateDevFile(devFile); WorkspaceConfigImpl config = new WorkspaceConfigImpl(); @@ -154,7 +159,9 @@ static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) if (toolOfCommand.isPresent() && !isNullOrEmpty(toolOfCommand.get().getId())) { command.getAttributes().put("pluginId", toolOfCommand.get().getId()); } - command.getAttributes().putAll(devCommand.getAttributes()); + if (devCommand.getAttributes() != null) { + command.getAttributes().putAll(devCommand.getAttributes()); + } commands.add(command); } } @@ -175,7 +182,7 @@ static WorkspaceConfigImpl devFileToWorkspaceConfig(DevFile devFile) return config; } - private static void validateDevFile(DevFile devFile) throws DevFileFormatException { + private static void validateDevFile(Devfile devFile) throws DevFileFormatException { if (!CURRENT_SPEC_VERSION.equals(devFile.getVersion())) { throw new DevFileFormatException( format("Provided devfile has unsupported version %s", devFile.getVersion())); diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index cfd1d0c311c..4ade9a9e3c1 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -36,7 +36,7 @@ import org.eclipse.che.api.core.ValidationException; import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; import org.eclipse.che.api.core.rest.Service; -import org.eclipse.che.api.devfile.model.DevFile; +import org.eclipse.che.api.devfile.model.Devfile; import org.eclipse.che.api.workspace.server.WorkspaceLinksGenerator; import org.eclipse.che.api.workspace.server.WorkspaceManager; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; @@ -76,10 +76,10 @@ public WorkspaceDto createFromYaml(String data) throws ServerException, ConflictException, NotFoundException, ValidationException, BadRequestException { - DevFile devFile; + Devfile devFile; WorkspaceConfig workspaceConfig; try { - devFile = objectMapper.readValue(data, DevFile.class); + devFile = objectMapper.readValue(data, Devfile.class); workspaceConfig = devFileToWorkspaceConfig(devFile); } catch (IOException e) { throw new ServerException(e.getMessage()); @@ -108,7 +108,7 @@ public Response createFromWorkspace(@PathParam("key") String key) throws NotFoundException, ServerException { // TODO: validate key WorkspaceImpl workspace = workspaceManager.getWorkspace(key); - DevFile workspaceDevFile = workspaceToDevFile(workspace.getConfig()); + Devfile workspaceDevFile = workspaceToDevFile(workspace.getConfig()); // Write object as YAML try { return Response.ok().entity(objectMapper.writeValueAsString(workspaceDevFile)).build(); diff --git a/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json b/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json similarity index 93% rename from wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json rename to wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json index da479a204fd..258f16bb135 100644 --- a/wsmaster/che-core-api-devfile/src/main/resources/devfile_schema.json +++ b/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json @@ -1,5 +1,11 @@ { - "definitions": {}, + "definitions": { + "attributes" : { + "id": "propertyList", + "type": "object", + "javaType": "java.util.Map" + } + }, "$schema": "http://json-schema.org/draft-07/schema#", "$id": "http://example.com/root.json", "type": "object", @@ -16,7 +22,6 @@ "$id": "#/properties/version", "type": "string", "title": "The Version Schema", - "default": "", "examples": [ "0.0.1" ] @@ -25,7 +30,6 @@ "$id": "#/properties/name", "type": "string", "title": "The Name Schema", - "default": "", "examples": [ "petclinic-dev-environment" ] @@ -47,7 +51,6 @@ "$id": "#/properties/projects/items/properties/name", "type": "string", "title": "The Project Name Schema", - "default": "", "examples": [ "petclinic" ] @@ -65,7 +68,6 @@ "$id": "#/properties/projects/items/properties/source/properties/type", "type": "string", "title": "The Project Source Type Schema", - "default": "", "examples": [ "git" ] @@ -74,7 +76,6 @@ "$id": "#/properties/projects/items/properties/source/properties/location", "type": "string", "title": "The Project Source Location Schema", - "default": "", "examples": [ "git@github.com:spring-projects/spring-petclinic.git" ] @@ -102,7 +103,6 @@ "$id": "#/properties/tools/items/properties/name", "type": "string", "title": "The Tool Name Schema", - "default": "", "examples": [ "mvn-stack" ] @@ -111,7 +111,6 @@ "$id": "#/properties/tools/items/properties/type", "type": "string", "title": "The Tool Type Schema", - "default": "", "examples": [ "chePlugin" ] @@ -120,7 +119,6 @@ "$id": "#/properties/tools/items/properties/id", "type": "string", "title": "The Tool Id Schema", - "default": "", "examples": [ "eclipse/maven-jdk8:1.0.0" ] @@ -145,11 +143,13 @@ "$id": "#/properties/commands/items/properties/name", "type": "string", "title": "The Command Name Schema", - "default": "", "examples": [ "build" ] }, + "attributes": { + "$ref": "#/definitions/attributes" + }, "actions": { "$id": "#/properties/commands/items/properties/actions", "type": "array", @@ -168,7 +168,6 @@ "$id": "#/properties/commands/items/properties/actions/items/properties/type", "type": "string", "title": "The Action Type Schema", - "default": "", "examples": [ "exec" ] @@ -177,7 +176,6 @@ "$id": "#/properties/commands/items/properties/actions/items/properties/tool", "type": "string", "title": "The Action Tool Schema", - "default": "", "examples": [ "mvn-stack" ] @@ -186,7 +184,6 @@ "$id": "#/properties/commands/items/properties/actions/items/properties/command", "type": "string", "title": "The Action Command Schema", - "default": "", "examples": [ "mvn package" ] @@ -195,7 +192,6 @@ "$id": "#/properties/commands/items/properties/actions/items/properties/workdir", "type": "string", "title": "The Action Workdir Schema", - "default": "", "examples": [ "/projects/spring-petclinic" ] diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java index bda7878ea3f..0699d5fa03e 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java @@ -18,7 +18,7 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import org.eclipse.che.api.devfile.model.Action; import org.eclipse.che.api.devfile.model.Command; -import org.eclipse.che.api.devfile.model.DevFile; +import org.eclipse.che.api.devfile.model.Devfile; import org.eclipse.che.api.devfile.model.Project; import org.eclipse.che.api.devfile.model.Tool; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; @@ -36,7 +36,7 @@ public void shouldBuildWorkspaceConfigFromYamlDevFile() throws Exception { String yamlContent = Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); - DevFile devFile = objectMapper.readValue(yamlContent, DevFile.class); + Devfile devFile = objectMapper.readValue(yamlContent, Devfile.class); WorkspaceConfigImpl wsConfigImpl = DevFileConverter.devFileToWorkspaceConfig(devFile); @@ -54,12 +54,12 @@ public void shouldBuildYamlDevFileFromWorkspaceConfig() throws Exception { Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_impl.json")); WorkspaceConfigImpl workspaceConfig = JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null); - DevFile devFile = DevFileConverter.workspaceToDevFile(workspaceConfig); + Devfile devFile = DevFileConverter.workspaceToDevFile(workspaceConfig); String yamlContent = Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); - DevFile expectedDevFile = objectMapper.readValue(yamlContent, DevFile.class); + Devfile expectedDevFile = objectMapper.readValue(yamlContent, Devfile.class); // Recursively compare assertEquals(devFile.getVersion(), expectedDevFile.getVersion()); @@ -98,11 +98,13 @@ public void shouldBuildYamlDevFileFromWorkspaceConfig() throws Exception { assertEquals(action.getType(), expectedAction.getType()); assertEquals(action.getWorkdir(), expectedAction.getWorkdir()); } - assertTrue( - command - .getAttributes() - .entrySet() - .containsAll(expectedCommand.getAttributes().entrySet())); + if (command.getAttributes() != null && expectedCommand.getAttributes() != null) { + assertTrue( + command + .getAttributes() + .entrySet() + .containsAll(expectedCommand.getAttributes().entrySet())); + } } assertEquals(devFile.getTools().size(), expectedDevFile.getTools().size()); diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java index 4c50244d0e0..ab29cdd91ed 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java @@ -1,3 +1,14 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ package org.eclipse.che.api.devfile.server; import static org.testng.Assert.assertTrue; @@ -28,10 +39,10 @@ public void setUp() { @Test public void shouldValidateSchema() throws Exception { - String devFileYamlContent = Files - .readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); - String devFileSchemaContent = Files - .readFile(getClass().getClassLoader().getResourceAsStream("devfile_schema.json")); + String devFileYamlContent = + Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); + String devFileSchemaContent = + Files.readFile(getClass().getClassLoader().getResourceAsStream("schema/devfile.json")); final JsonNode data = yamlReader.readTree(devFileYamlContent); final JsonNode schema = JsonLoader.fromString(devFileSchemaContent); diff --git a/wsmaster/pom.xml b/wsmaster/pom.xml index c0dbdcd2a95..fbd9d17199f 100644 --- a/wsmaster/pom.xml +++ b/wsmaster/pom.xml @@ -30,7 +30,7 @@ che-core-api-auth-shared che-core-api-auth che-core-api-devfile - che-core-api-devfile-shared + che-core-api-project-templates-shared che-core-api-project-templates che-core-api-workspace-shared From b53b51603075d90ba47c653b53df2017e2b64f81 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Tue, 20 Nov 2018 12:46:04 +0200 Subject: [PATCH 13/46] Add schema generation --- .../che/api/deploy/WsMasterModule.java | 1 + pom.xml | 5 - wsmaster/che-core-api-devfile-shared/pom.xml | 31 ----- .../eclipse/che/api/devfile/model/Action.java | 93 --------------- .../che/api/devfile/model/Command.java | 80 ------------- .../che/api/devfile/model/DevFile.java | 112 ------------------ .../che/api/devfile/model/Project.java | 57 --------- .../eclipse/che/api/devfile/model/Source.java | 57 --------- .../eclipse/che/api/devfile/model/Tool.java | 75 ------------ wsmaster/che-core-api-devfile/pom.xml | 2 +- .../api/devfile/server/DevFileConverter.java | 4 +- .../server/DevFileSchemaValidator.java | 64 ++++++++++ .../api/devfile/server/DevFileService.java | 10 +- .../api/devfile/server/DevFileSchemaTest.java | 54 --------- .../server/DevFileSchemaValidatorTest.java | 45 +++++++ .../src/test/resources/devfile_bad.yaml | 30 +++++ wsmaster/pom.xml | 1 - 17 files changed, 151 insertions(+), 570 deletions(-) delete mode 100644 wsmaster/che-core-api-devfile-shared/pom.xml delete mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java delete mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java delete mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java delete mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java delete mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java delete mode 100644 wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java create mode 100644 wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java delete mode 100644 wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java create mode 100644 wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java create mode 100644 wsmaster/che-core-api-devfile/src/test/resources/devfile_bad.yaml diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index 6aa70264745..f1347c42a31 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -152,6 +152,7 @@ protected void configure() { bind(org.eclipse.che.api.user.server.PreferencesService.class); bind(org.eclipse.che.security.oauth.OAuthAuthenticationService.class); + bind(org.eclipse.che.api.devfile.server.DevFileSchemaValidator.class); bind(org.eclipse.che.api.devfile.server.DevFileService.class); MapBinder stacks = diff --git a/pom.xml b/pom.xml index eea4ecff813..2b75f94d236 100644 --- a/pom.xml +++ b/pom.xml @@ -330,11 +330,6 @@ che-core-api-devfile ${che.version} - - org.eclipse.che.core - che-core-api-devfile-shared - ${che.version} - org.eclipse.che.core che-core-api-dto diff --git a/wsmaster/che-core-api-devfile-shared/pom.xml b/wsmaster/che-core-api-devfile-shared/pom.xml deleted file mode 100644 index cce98873dd6..00000000000 --- a/wsmaster/che-core-api-devfile-shared/pom.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - 4.0.0 - - che-master-parent - org.eclipse.che.core - 6.14.0-SNAPSHOT - - che-core-api-devfile-shared - jar - Che Core :: API :: Devfile Shared - - - com.fasterxml.jackson.core - jackson-annotations - - - diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java deleted file mode 100644 index 123e94fe9dc..00000000000 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Action.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"type", "tool", "command", "workdir"}) -public class Action { - - @JsonProperty("tool") - private String tool; - - @JsonProperty("type") - private String type; - - @JsonProperty("command") - private String command; - - @JsonProperty("workdir") - private String workdir; - - @JsonProperty("command") - public String getCommand() { - return command; - } - - @JsonProperty("command") - public void setCommand(String command) { - this.command = command; - } - - public Action withCommand(String command) { - this.command = command; - return this; - } - - @JsonProperty("workdir") - public String getWorkdir() { - return workdir; - } - - @JsonProperty("workdir") - public void setWorkdir(String workdir) { - this.workdir = workdir; - } - - public Action withWorkdir(String workdir) { - this.workdir = workdir; - return this; - } - - @JsonProperty("type") - public String getType() { - return type; - } - - @JsonProperty("type") - public void setType(String type) { - this.type = type; - } - - public Action withType(String type) { - this.type = type; - return this; - } - - @JsonProperty("tool") - public String getTool() { - return tool; - } - - @JsonProperty("tool") - public void setTool(String tool) { - this.tool = tool; - } - - public Action withTool(String tool) { - this.tool = tool; - return this; - } -} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java deleted file mode 100644 index aebd3a1db17..00000000000 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Command.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.model; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"name", "actions"}) -public class Command { - - @JsonProperty("name") - private String name; - - @JsonProperty("actions") - private List actions = null; - - @JsonProperty("attributes") - private Map attributes = new HashMap<>(); - - @JsonProperty("name") - public String getName() { - return name; - } - - @JsonProperty("name") - public void setName(String name) { - this.name = name; - } - - public Command withName(String name) { - this.name = name; - return this; - } - - @JsonProperty("actions") - public List getActions() { - return actions; - } - - @JsonProperty("actions") - public void setActions(List actions) { - this.actions = actions; - } - - public Command withActions(List actions) { - this.actions = actions; - return this; - } - - @JsonAnyGetter - public Map getAttributes() { - return this.attributes; - } - - @JsonAnySetter - public void getAttribute(String name, String value) { - this.attributes.put(name, value); - } - - public Command withAttributes(Map attributes) { - this.attributes = attributes; - return this; - } -} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java deleted file mode 100644 index 4cc10676c80..00000000000 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/DevFile.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.util.List; - -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"version", "name", "projects", "tools", "commands"}) -public class DevFile { - - @JsonProperty("version") - private String version; - - @JsonProperty("name") - private String name; - - @JsonProperty("projects") - private List projects = null; - - @JsonProperty("tools") - private List tools = null; - - @JsonProperty("commands") - private List commands = null; - - @JsonProperty("version") - public String getVersion() { - return version; - } - - @JsonProperty("version") - public void setVersion(String version) { - this.version = version; - } - - public DevFile withVersion(String version) { - this.version = version; - return this; - } - - @JsonProperty("name") - public String getName() { - return name; - } - - @JsonProperty("name") - public void setName(String name) { - this.name = name; - } - - public DevFile withName(String name) { - this.name = name; - return this; - } - - @JsonProperty("projects") - public List getProjects() { - return projects; - } - - @JsonProperty("projects") - public void setProjects(List projects) { - this.projects = projects; - } - - public DevFile withProjects(List projects) { - this.projects = projects; - return this; - } - - @JsonProperty("tools") - public List getTools() { - return tools; - } - - @JsonProperty("tools") - public void setTools(List tools) { - this.tools = tools; - } - - public DevFile withTools(List tools) { - this.tools = tools; - return this; - } - - @JsonProperty("commands") - public List getCommands() { - return commands; - } - - @JsonProperty("commands") - public void setCommands(List commands) { - this.commands = commands; - } - - public DevFile withCommands(List commands) { - this.commands = commands; - return this; - } -} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java deleted file mode 100644 index a3e26b17ea0..00000000000 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Project.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"name", "source"}) -public class Project { - - @JsonProperty("name") - private String name; - - @JsonProperty("source") - private Source source; - - @JsonProperty("name") - public String getName() { - return name; - } - - @JsonProperty("name") - public void setName(String name) { - this.name = name; - } - - public Project withName(String name) { - this.name = name; - return this; - } - - @JsonProperty("source") - public Source getSource() { - return source; - } - - @JsonProperty("source") - public void setSource(Source source) { - this.source = source; - } - - public Project withSource(Source source) { - this.source = source; - return this; - } -} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java deleted file mode 100644 index 3b5e5cf3c5f..00000000000 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Source.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"type", "location"}) -public class Source { - - @JsonProperty("type") - private String type; - - @JsonProperty("location") - private String location; - - @JsonProperty("type") - public String getType() { - return type; - } - - @JsonProperty("type") - public void setType(String type) { - this.type = type; - } - - public Source withType(String type) { - this.type = type; - return this; - } - - @JsonProperty("location") - public String getLocation() { - return location; - } - - @JsonProperty("location") - public void setLocation(String location) { - this.location = location; - } - - public Source withLocation(String location) { - this.location = location; - return this; - } -} diff --git a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java b/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java deleted file mode 100644 index 185c4f1ac24..00000000000 --- a/wsmaster/che-core-api-devfile-shared/src/main/java/org/eclipse/che/api/devfile/model/Tool.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; - -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"name", "type", "id"}) -public class Tool { - - @JsonProperty("name") - private String name; - - @JsonProperty("id") - private String id; - - @JsonProperty("type") - private String type; - - @JsonProperty("name") - public String getName() { - return name; - } - - @JsonProperty("name") - public void setName(String name) { - this.name = name; - } - - public Tool withName(String name) { - this.name = name; - return this; - } - - @JsonProperty("type") - public String getType() { - return type; - } - - @JsonProperty("type") - public void setType(String type) { - this.type = type; - } - - public Tool withType(String type) { - this.type = type; - return this; - } - - @JsonProperty("id") - public String getId() { - return id; - } - - @JsonProperty("id") - public void setId(String id) { - this.id = id; - } - - public Tool withId(String id) { - this.id = id; - return this; - } -} diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index ac35586cad5..5b5de8d367f 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -17,7 +17,7 @@ che-master-parent org.eclipse.che.core - 6.14.0-SNAPSHOT + 6.15.0-SNAPSHOT che-core-api-devfile jar diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index 73ef3e65753..e95b59c8c69 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -106,7 +106,7 @@ static Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { static WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) throws DevFileFormatException { - validateDevFile(devFile); + validateCurrentVersion(devFile); WorkspaceConfigImpl config = new WorkspaceConfigImpl(); config.setName(devFile.getName()); @@ -182,7 +182,7 @@ static WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) return config; } - private static void validateDevFile(Devfile devFile) throws DevFileFormatException { + private static void validateCurrentVersion(Devfile devFile) throws DevFileFormatException { if (!CURRENT_SPEC_VERSION.equals(devFile.getVersion())) { throw new DevFileFormatException( format("Provided devfile has unsupported version %s", devFile.getVersion())); diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java new file mode 100644 index 00000000000..3a2c020e3f6 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.server; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.github.fge.jackson.JsonLoader; +import com.github.fge.jsonschema.core.exceptions.ProcessingException; +import com.github.fge.jsonschema.core.report.LogLevel; +import com.github.fge.jsonschema.core.report.ProcessingReport; +import com.github.fge.jsonschema.main.JsonSchemaFactory; +import com.github.fge.jsonschema.main.JsonValidator; +import java.io.IOException; +import java.net.URL; +import javax.inject.Singleton; + +@Singleton +public class DevFileSchemaValidator { + + private JsonValidator validator; + private JsonNode schema; + private ObjectMapper yamlReader; + + public DevFileSchemaValidator() throws IOException { + final JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); + URL schemaURL = getClass().getClassLoader().getResource("schema/devfile.json"); + this.schema = JsonLoader.fromURL(schemaURL); + this.validator = factory.getValidator(); + this.yamlReader = new ObjectMapper(new YAMLFactory()); + } + + public void validateBySchema(String content) throws DevFileFormatException { + ProcessingReport report; + try { + final JsonNode data = yamlReader.readTree(content); + report = validator.validate(schema, data); + } catch (IOException | ProcessingException e) { + throw new DevFileFormatException( + String.format("Unable to validate devfile. Error: %s" + e.getMessage())); + } + if (!report.isSuccess()) { + StringBuilder sb = new StringBuilder(); + report.forEach( + jsonError -> { + if (jsonError.getLogLevel() == LogLevel.ERROR + || jsonError.getLogLevel() == LogLevel.FATAL) { + sb.append(String.format("[%s] ", jsonError.getMessage())); + } + }); + throw new DevFileFormatException( + String.format("Devfile schema validation failed. Errors: %s", sb.toString())); + } + } +} diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index 4ade9a9e3c1..862ff88442a 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -46,13 +46,18 @@ @Path("/devfile") public class DevFileService extends Service { - private final WorkspaceLinksGenerator linksGenerator; + private WorkspaceLinksGenerator linksGenerator; + private DevFileSchemaValidator schemaValidator; private WorkspaceManager workspaceManager; private ObjectMapper objectMapper; @Inject - public DevFileService(WorkspaceLinksGenerator linksGenerator, WorkspaceManager workspaceManager) { + public DevFileService( + WorkspaceLinksGenerator linksGenerator, + DevFileSchemaValidator schemaValidator, + WorkspaceManager workspaceManager) { this.linksGenerator = linksGenerator; + this.schemaValidator = schemaValidator; this.workspaceManager = workspaceManager; this.objectMapper = new ObjectMapper(new YAMLFactory()); } @@ -79,6 +84,7 @@ public WorkspaceDto createFromYaml(String data) Devfile devFile; WorkspaceConfig workspaceConfig; try { + schemaValidator.validateBySchema(data); devFile = objectMapper.readValue(data, Devfile.class); workspaceConfig = devFileToWorkspaceConfig(devFile); } catch (IOException e) { diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java deleted file mode 100644 index ab29cdd91ed..00000000000 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.server; - -import static org.testng.Assert.assertTrue; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.github.fge.jackson.JsonLoader; -import com.github.fge.jsonschema.core.report.ProcessingReport; -import com.github.fge.jsonschema.main.JsonSchemaFactory; -import com.github.fge.jsonschema.main.JsonValidator; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import org.testng.reporters.Files; - -public class DevFileSchemaTest { - - private JsonValidator validator; - private ObjectMapper yamlReader; - - @BeforeClass - public void setUp() { - final JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); - validator = factory.getValidator(); - yamlReader = new ObjectMapper(new YAMLFactory()); - } - - @Test - public void shouldValidateSchema() throws Exception { - - String devFileYamlContent = - Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); - String devFileSchemaContent = - Files.readFile(getClass().getClassLoader().getResourceAsStream("schema/devfile.json")); - - final JsonNode data = yamlReader.readTree(devFileYamlContent); - final JsonNode schema = JsonLoader.fromString(devFileSchemaContent); - // when - ProcessingReport report = validator.validate(schema, data); - // then - assertTrue(report.isSuccess()); - } -} diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java new file mode 100644 index 00000000000..e9604608f0c --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.server; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.testng.reporters.Files; + +public class DevFileSchemaValidatorTest { + + private DevFileSchemaValidator schemaValidator; + + @BeforeClass + public void setUp() throws Exception { + schemaValidator = new DevFileSchemaValidator(); + } + + @Test + public void shouldValidateCorrectYamlBySchema() throws Exception { + String devFileYamlContent = + Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); + // when + schemaValidator.validateBySchema(devFileYamlContent); + } + + @Test( + expectedExceptions = DevFileFormatException.class, + expectedExceptionsMessageRegExp = + "Devfile schema validation failed. Errors: \\[object has missing required properties \\(\\[.+\\]\\)\\] $") + public void shouldValidateIncorrectYamlBySchema() throws Exception { + String devFileYamlContent = + Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile_bad.yaml")); + // when + schemaValidator.validateBySchema(devFileYamlContent); + } +} diff --git a/wsmaster/che-core-api-devfile/src/test/resources/devfile_bad.yaml b/wsmaster/che-core-api-devfile/src/test/resources/devfile_bad.yaml new file mode 100644 index 00000000000..e5805fa1756 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/test/resources/devfile_bad.yaml @@ -0,0 +1,30 @@ +# +# Copyright (c) 2012-2018 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Red Hat, Inc. - initial API and implementation +# + +--- +version: 0.0.1 +name: petclinic-dev-environment +projects: + - name: petclinic + source: + type: git + location: 'git@github.com:spring-projects/spring-petclinic.git' +tools: + - type: chePlugin + id: eclipse/maven-jdk8:1.0.0 +commands: + - name: build + actions: + - type: exec + tool: mvn-stack + command: mvn package + workdir: /projects/spring-petclinic diff --git a/wsmaster/pom.xml b/wsmaster/pom.xml index fbd9d17199f..c3708ac3306 100644 --- a/wsmaster/pom.xml +++ b/wsmaster/pom.xml @@ -30,7 +30,6 @@ che-core-api-auth-shared che-core-api-auth che-core-api-devfile - che-core-api-project-templates-shared che-core-api-project-templates che-core-api-workspace-shared From 0a91ba7cd533cdd7941bbe84aeb5163cb9766ffe Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Wed, 21 Nov 2018 12:22:41 +0200 Subject: [PATCH 14/46] Review fix --- .../eclipse/che/api/devfile/server/DevFileConverter.java | 4 ++-- .../eclipse/che/api/devfile/server/DevFileService.java | 8 ++++---- .../che/api/devfile/server/DevFileConverterTest.java | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index e95b59c8c69..5dbe2b0dd8d 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -38,7 +38,7 @@ public class DevFileConverter { - static Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { + public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { Devfile devFile = new Devfile().withVersion(CURRENT_SPEC_VERSION).withName(wsConfig.getName()); @@ -104,7 +104,7 @@ static Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { return devFile; } - static WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) + public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) throws DevFileFormatException { validateCurrentVersion(devFile); WorkspaceConfigImpl config = new WorkspaceConfigImpl(); diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index 862ff88442a..0174c90a90c 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -13,8 +13,6 @@ import static java.util.Collections.emptyMap; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; -import static org.eclipse.che.api.devfile.server.DevFileConverter.devFileToWorkspaceConfig; -import static org.eclipse.che.api.devfile.server.DevFileConverter.workspaceToDevFile; import static org.eclipse.che.api.workspace.server.DtoConverter.asDto; import com.fasterxml.jackson.core.JsonProcessingException; @@ -50,6 +48,7 @@ public class DevFileService extends Service { private DevFileSchemaValidator schemaValidator; private WorkspaceManager workspaceManager; private ObjectMapper objectMapper; + private DevFileConverter devFileConverter; @Inject public DevFileService( @@ -60,6 +59,7 @@ public DevFileService( this.schemaValidator = schemaValidator; this.workspaceManager = workspaceManager; this.objectMapper = new ObjectMapper(new YAMLFactory()); + this.devFileConverter = new DevFileConverter(); } // Creates a workspace by providing the url to the repository @@ -86,7 +86,7 @@ public WorkspaceDto createFromYaml(String data) try { schemaValidator.validateBySchema(data); devFile = objectMapper.readValue(data, Devfile.class); - workspaceConfig = devFileToWorkspaceConfig(devFile); + workspaceConfig = devFileConverter.devFileToWorkspaceConfig(devFile); } catch (IOException e) { throw new ServerException(e.getMessage()); } catch (DevFileFormatException e) { @@ -114,7 +114,7 @@ public Response createFromWorkspace(@PathParam("key") String key) throws NotFoundException, ServerException { // TODO: validate key WorkspaceImpl workspace = workspaceManager.getWorkspace(key); - Devfile workspaceDevFile = workspaceToDevFile(workspace.getConfig()); + Devfile workspaceDevFile = devFileConverter.workspaceToDevFile(workspace.getConfig()); // Write object as YAML try { return Response.ok().entity(objectMapper.writeValueAsString(workspaceDevFile)).build(); diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java index 0699d5fa03e..6435f63130d 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java @@ -29,6 +29,7 @@ public class DevFileConverterTest { private ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); + private DevFileConverter devFileConverter = new DevFileConverter(); @Test public void shouldBuildWorkspaceConfigFromYamlDevFile() throws Exception { @@ -38,7 +39,7 @@ public void shouldBuildWorkspaceConfigFromYamlDevFile() throws Exception { Devfile devFile = objectMapper.readValue(yamlContent, Devfile.class); - WorkspaceConfigImpl wsConfigImpl = DevFileConverter.devFileToWorkspaceConfig(devFile); + WorkspaceConfigImpl wsConfigImpl = devFileConverter.devFileToWorkspaceConfig(devFile); String jsonContent = Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_impl.json")); @@ -54,7 +55,7 @@ public void shouldBuildYamlDevFileFromWorkspaceConfig() throws Exception { Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_impl.json")); WorkspaceConfigImpl workspaceConfig = JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null); - Devfile devFile = DevFileConverter.workspaceToDevFile(workspaceConfig); + Devfile devFile = devFileConverter.workspaceToDevFile(workspaceConfig); String yamlContent = Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); From 71f5d178aec3350753d69a71b4bcd9a45d3d4255 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Wed, 21 Nov 2018 17:18:33 +0200 Subject: [PATCH 15/46] Minor code refactorings --- .../webapp/WEB-INF/classes/che/che.properties | 3 + .../che/api/devfile/server/Constants.java | 1 + .../api/devfile/server/DevFileConverter.java | 143 ++++++++++-------- .../server/DevFileSchemaValidator.java | 41 ++--- .../server/DevFileSchemaValidatorTest.java | 2 +- 5 files changed, 105 insertions(+), 85 deletions(-) diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index c673991dbde..84321590bf9 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -546,3 +546,6 @@ che.server.secure_exposer.jwtproxy.memory_limit=128mb # Maximum size of the json processing pool # in case if pool size would be exceeded message execution will be rejected che.core.jsonrpc.processor_max_pool_size=100 + +# Devile JSON schema location (relative to api.war resources folder) +che.devfile.schema.file_location=schema/devfile.json \ No newline at end of file diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java index 63e8103f69b..695ce5e2fb6 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java @@ -13,5 +13,6 @@ public class Constants { + public static final String SCHEMA_FILE_LOCATION = "schema/devfile.json"; public static final String CURRENT_SPEC_VERSION = "0.0.1"; } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index 5dbe2b0dd8d..015a0f31553 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -36,52 +36,29 @@ import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; +/** Helps to convert Devfile into workspace config and back. */ public class DevFileConverter { public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { - Devfile devFile = new Devfile().withVersion(CURRENT_SPEC_VERSION).withName(wsConfig.getName()); // Manage projects List projects = new ArrayList<>(); - for (ProjectConfigImpl project : wsConfig.getProjects()) { - Source source = - new Source() - .withType(project.getSource().getType()) - .withLocation(project.getSource().getLocation()); - Project devProject = new Project().withName(project.getName()).withSource(source); - projects.add(devProject); - } + wsConfig + .getProjects() + .forEach(projectConfig -> projects.add(projectConfigToDevProject(projectConfig))); devFile.setProjects(projects); // Manage commands List commands = new ArrayList<>(); - for (CommandImpl command : wsConfig.getCommands()) { - Command devCommand = new Command().withName(command.getName()); - Action action = - new Action().withCommand(command.getCommandLine()).withType(command.getType()); - if (!isNullOrEmpty(command.getAttributes().get("workingDir"))) { - action.setWorkdir(command.getAttributes().get("workingDir")); - } - // Remove internal attributes - command.getAttributes().remove("workingDir"); - command.getAttributes().remove("pluginId"); - // Put others - if (devCommand.getAttributes() == null) { - devCommand.withAttributes(command.getAttributes()); - } else { - devCommand.getAttributes().putAll(command.getAttributes()); - } - - commands.add(devCommand); - } + wsConfig.getCommands().forEach(command -> commands.add(commandImplToDevCommand(command))); devFile.setCommands(commands); // Manage tools List tools = new ArrayList<>(); - for (Map.Entry entry : wsConfig.getAttributes().entrySet()) { + for (Map.Entry entry : wsConfig.getAttributes().entrySet()) { if (entry.getKey().equals("editor")) { - String editorId = wsConfig.getAttributes().get("editor"); + String editorId = entry.getValue(); Tool editorTool = new Tool() .withType("cheEditor") @@ -89,7 +66,7 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { .withName(wsConfig.getAttributes().get(editorId)); tools.add(editorTool); } else if (entry.getKey().equals("plugins")) { - for (String pluginId : wsConfig.getAttributes().get("plugins").split(",")) { + for (String pluginId : entry.getValue().split(",")) { Tool pluginTool = new Tool() .withId(pluginId) @@ -99,7 +76,6 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { } } } - devFile.setTools(tools); return devFile; } @@ -113,16 +89,7 @@ public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) // Manage projects List projects = new ArrayList<>(); - for (Project devProject : devFile.getProjects()) { - ProjectConfigImpl projectConfig = new ProjectConfigImpl(); - projectConfig.setName(devProject.getName()); - projectConfig.setPath("/" + projectConfig.getName()); - SourceStorageImpl sourceStorage = new SourceStorageImpl(); - sourceStorage.setType(devProject.getSource().getType()); - sourceStorage.setLocation(devProject.getSource().getLocation()); - projectConfig.setSource(sourceStorage); - projects.add(projectConfig); - } + devFile.getProjects().forEach(project -> projects.add(devProjectToProjectConfig(project))); config.setProjects(projects); // Manage tools @@ -141,31 +108,9 @@ public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) // Manage commands List commands = new ArrayList<>(); - for (Command devCommand : devFile.getCommands()) { - for (Action devAction : devCommand.getActions()) { - CommandImpl command = new CommandImpl(); - command.setName(devCommand.getName() + ":" + devAction.getTool()); - command.setType(devAction.getType()); - command.setCommandLine(devAction.getCommand()); - if (devAction.getWorkdir() != null) { - command.getAttributes().put("workingDir", devAction.getWorkdir()); - } - Optional toolOfCommand = - devFile - .getTools() - .stream() - .filter(tool -> tool.getName().equals(devAction.getTool())) - .findFirst(); - if (toolOfCommand.isPresent() && !isNullOrEmpty(toolOfCommand.get().getId())) { - command.getAttributes().put("pluginId", toolOfCommand.get().getId()); - } - if (devCommand.getAttributes() != null) { - command.getAttributes().putAll(devCommand.getAttributes()); - } - commands.add(command); - } - } - + devFile + .getCommands() + .forEach(command -> commands.addAll(devCommandToCommandImpls(devFile, command))); config.setCommands(commands); // TODO: Add default environment. Remove when it will be possible @@ -182,6 +127,70 @@ public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) return config; } + private List devCommandToCommandImpls(Devfile devFile, Command devCommand) { + List commands = new ArrayList<>(); + for (Action devAction : devCommand.getActions()) { + CommandImpl command = new CommandImpl(); + command.setName(devCommand.getName() + ":" + devAction.getTool()); + command.setType(devAction.getType()); + command.setCommandLine(devAction.getCommand()); + if (devAction.getWorkdir() != null) { + command.getAttributes().put("workingDir", devAction.getWorkdir()); + } + Optional toolOfCommand = + devFile + .getTools() + .stream() + .filter(tool -> tool.getName().equals(devAction.getTool())) + .findFirst(); + if (toolOfCommand.isPresent() && !isNullOrEmpty(toolOfCommand.get().getId())) { + command.getAttributes().put("pluginId", toolOfCommand.get().getId()); + } + if (devCommand.getAttributes() != null) { + command.getAttributes().putAll(devCommand.getAttributes()); + } + commands.add(command); + } + return commands; + } + + private Command commandImplToDevCommand(CommandImpl command) { + Command devCommand = new Command().withName(command.getName()); + Action action = new Action().withCommand(command.getCommandLine()).withType(command.getType()); + if (!isNullOrEmpty(command.getAttributes().get("workingDir"))) { + action.setWorkdir(command.getAttributes().get("workingDir")); + } + // Remove internal attributes + command.getAttributes().remove("workingDir"); + command.getAttributes().remove("pluginId"); + // Put others + if (devCommand.getAttributes() == null) { + devCommand.withAttributes(command.getAttributes()); + } else { + devCommand.getAttributes().putAll(command.getAttributes()); + } + return devCommand; + } + + private Project projectConfigToDevProject(ProjectConfigImpl projectConfig) { + Source source = + new Source() + .withType(projectConfig.getSource().getType()) + .withLocation(projectConfig.getSource().getLocation()); + return new Project().withName(projectConfig.getName()).withSource(source); + } + + private ProjectConfigImpl devProjectToProjectConfig(Project devProject) { + ProjectConfigImpl projectConfig = new ProjectConfigImpl(); + projectConfig.setName(devProject.getName()); + projectConfig.setPath("/" + projectConfig.getName()); + SourceStorageImpl sourceStorage = new SourceStorageImpl(); + sourceStorage.setType(devProject.getSource().getType()); + sourceStorage.setLocation(devProject.getSource().getLocation()); + projectConfig.setSource(sourceStorage); + return projectConfig; + } + private static void validateCurrentVersion(Devfile devFile) throws DevFileFormatException { if (!CURRENT_SPEC_VERSION.equals(devFile.getVersion())) { throw new DevFileFormatException( diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java index 3a2c020e3f6..8b5372b9382 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java @@ -11,6 +11,8 @@ */ package org.eclipse.che.api.devfile.server; +import static java.lang.String.format; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; @@ -22,8 +24,12 @@ import com.github.fge.jsonschema.main.JsonValidator; import java.io.IOException; import java.net.URL; +import java.util.stream.StreamSupport; +import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; +/** Validates YAML content against given JSON schema. */ @Singleton public class DevFileSchemaValidator { @@ -31,34 +37,35 @@ public class DevFileSchemaValidator { private JsonNode schema; private ObjectMapper yamlReader; - public DevFileSchemaValidator() throws IOException { - final JsonSchemaFactory factory = JsonSchemaFactory.byDefault(); - URL schemaURL = getClass().getClassLoader().getResource("schema/devfile.json"); + @Inject + public DevFileSchemaValidator(@Named("che.devfile.schema.file_location") String schemaFile) + throws IOException { + final URL schemaURL = getClass().getClassLoader().getResource(schemaFile); + if (schemaURL == null) { + throw new IOException("Devfile schema is not found at specified path:" + schemaFile); + } this.schema = JsonLoader.fromURL(schemaURL); - this.validator = factory.getValidator(); + this.validator = JsonSchemaFactory.byDefault().getValidator(); this.yamlReader = new ObjectMapper(new YAMLFactory()); } - public void validateBySchema(String content) throws DevFileFormatException { + public void validateBySchema(String yamlContent) throws DevFileFormatException { ProcessingReport report; try { - final JsonNode data = yamlReader.readTree(content); + final JsonNode data = yamlReader.readTree(yamlContent); report = validator.validate(schema, data); } catch (IOException | ProcessingException e) { - throw new DevFileFormatException( - String.format("Unable to validate devfile. Error: %s" + e.getMessage())); + throw new DevFileFormatException("Unable to validate devfile. Error: " + e.getMessage()); } if (!report.isSuccess()) { StringBuilder sb = new StringBuilder(); - report.forEach( - jsonError -> { - if (jsonError.getLogLevel() == LogLevel.ERROR - || jsonError.getLogLevel() == LogLevel.FATAL) { - sb.append(String.format("[%s] ", jsonError.getMessage())); - } - }); - throw new DevFileFormatException( - String.format("Devfile schema validation failed. Errors: %s", sb.toString())); + StreamSupport.stream(report.spliterator(), false) + .filter( + message -> + message.getLogLevel() == LogLevel.ERROR + || message.getLogLevel() == LogLevel.FATAL) + .forEach(message -> sb.append(format("[%s] ", message.getMessage()))); + throw new DevFileFormatException(format("Devfile schema validation failed. Errors: %s", sb)); } } } diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java index e9604608f0c..3842b8b49a7 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java @@ -21,7 +21,7 @@ public class DevFileSchemaValidatorTest { @BeforeClass public void setUp() throws Exception { - schemaValidator = new DevFileSchemaValidator(); + schemaValidator = new DevFileSchemaValidator("schema/devfile.json"); } @Test From 93ce24c7f84dac5b8caa80f246132b5b8291243a Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Thu, 22 Nov 2018 09:07:00 +0200 Subject: [PATCH 16/46] Fixup --- .../main/java/org/eclipse/che/api/devfile/server/Constants.java | 1 - 1 file changed, 1 deletion(-) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java index 695ce5e2fb6..63e8103f69b 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java @@ -13,6 +13,5 @@ public class Constants { - public static final String SCHEMA_FILE_LOCATION = "schema/devfile.json"; public static final String CURRENT_SPEC_VERSION = "0.0.1"; } From 8a3e5f0f57d9ce8c7191086d600e0c66654c5e99 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Thu, 22 Nov 2018 14:52:04 +0200 Subject: [PATCH 17/46] Review fixes --- .../webapp/WEB-INF/classes/che/che.properties | 2 +- .../api/devfile/server/DevFileConverter.java | 16 -------------- .../src/test/resources/workspace_impl.json | 21 +------------------ 3 files changed, 2 insertions(+), 37 deletions(-) diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index 84321590bf9..37b2dc5e6f6 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -548,4 +548,4 @@ che.server.secure_exposer.jwtproxy.memory_limit=128mb che.core.jsonrpc.processor_max_pool_size=100 # Devile JSON schema location (relative to api.war resources folder) -che.devfile.schema.file_location=schema/devfile.json \ No newline at end of file +che.devfile.schema.file_location=schema/devfile.json diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index 015a0f31553..0ed30aa7d1a 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -13,7 +13,6 @@ import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; -import static java.util.Collections.singletonMap; import static org.eclipse.che.api.devfile.server.Constants.CURRENT_SPEC_VERSION; import java.util.ArrayList; @@ -29,10 +28,7 @@ import org.eclipse.che.api.devfile.model.Source; import org.eclipse.che.api.devfile.model.Tool; import org.eclipse.che.api.workspace.server.model.impl.CommandImpl; -import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl; -import org.eclipse.che.api.workspace.server.model.impl.MachineConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl; -import org.eclipse.che.api.workspace.server.model.impl.RecipeImpl; import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; @@ -112,18 +108,6 @@ public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) .getCommands() .forEach(command -> commands.addAll(devCommandToCommandImpls(devFile, command))); config.setCommands(commands); - - // TODO: Add default environment. Remove when it will be possible - config.setDefaultEnv("default"); - EnvironmentImpl environment = new EnvironmentImpl(); - RecipeImpl recipe = new RecipeImpl(); - recipe.setType("dockerimage"); - recipe.setContent("eclipse/ubuntu_jdk8"); - environment.setRecipe(recipe); - MachineConfigImpl machine = new MachineConfigImpl(); - machine.setAttributes(singletonMap("memoryLimitBytes", "2147483648")); - environment.setMachines(singletonMap("dev-machine", machine)); - config.setEnvironments(singletonMap("default", environment)); return config; } diff --git a/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json b/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json index ac6f36be144..61b001aed82 100644 --- a/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json +++ b/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json @@ -41,26 +41,7 @@ } } ], - "environments": { - "default": { - "recipe": { - "type": "dockerimage", - "content": "eclipse/ubuntu_jdk8" - }, - "machines": { - "dev-machine": { - "installers": [], - "servers": {}, - "env": {}, - "volumes": {}, - "attributes": { - "memoryLimitBytes": "2147483648" - } - } - } - } - }, - "defaultEnv": "default", + "environments": {}, "name": "petclinic-dev-environment", "attributes": { "eclipse/maven-jdk8:1.0.0": "mvn-stack", From db334a43bc5acdb841a1175ce1f984fbba7fb2bf Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Tue, 27 Nov 2018 12:50:37 +0200 Subject: [PATCH 18/46] Review fixes --- wsmaster/che-core-api-devfile/pom.xml | 13 ++++- .../src/main/resources/schema/devfile.json | 58 +++++-------------- 2 files changed, 28 insertions(+), 43 deletions(-) diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index 5b5de8d367f..0108db9749d 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -23,6 +23,10 @@ jar Che Core :: API :: Devfile + + com.fasterxml.jackson.core + jackson-annotations + com.fasterxml.jackson.core jackson-core @@ -35,10 +39,17 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml + + com.github.java-json-tools + jackson-coreutils + + + com.github.java-json-tools + json-schema-core + com.github.java-json-tools json-schema-validator - 2.2.10 com.google.guava diff --git a/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json b/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json index 258f16bb135..bb37b82f988 100644 --- a/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json +++ b/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json @@ -7,7 +7,6 @@ } }, "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "http://example.com/root.json", "type": "object", "title": "The Root Schema of DevFile object", "required": [ @@ -19,44 +18,37 @@ ], "properties": { "version": { - "$id": "#/properties/version", "type": "string", - "title": "The Version Schema", + "title": "Devfile Schema Version", "examples": [ "0.0.1" ] }, "name": { - "$id": "#/properties/name", "type": "string", - "title": "The Name Schema", + "title": "Devfile Name", "examples": [ "petclinic-dev-environment" ] }, "projects": { - "$id": "#/properties/projects", "type": "array", "title": "The Projects Schema", + "description" : "Description of the project sources location and type", "items": { - "$id": "#/properties/projects/items", "type": "object", - "title": "The Project Items Schema", "required": [ "name", "source" ], "properties": { "name": { - "$id": "#/properties/projects/items/properties/name", "type": "string", - "title": "The Project Name Schema", "examples": [ "petclinic" ] }, "source": { - "$id": "#/properties/projects/items/properties/source", "type": "object", "title": "The Project Source Schema", "required": [ @@ -65,17 +57,17 @@ ], "properties": { "type": { - "$id": "#/properties/projects/items/properties/source/properties/type", "type": "string", - "title": "The Project Source Type Schema", + "description": "Project-s source type.", "examples": [ - "git" + "git", + "github", + "zip" ] }, "location": { - "$id": "#/properties/projects/items/properties/source/properties/location", "type": "string", - "title": "The Project Source Location Schema", + "description": "Project-s source location address. Should be URL for git and github located projects, and file:// for zip.", "examples": [ "git@github.com:spring-projects/spring-petclinic.git" ] @@ -86,13 +78,10 @@ } }, "tools": { - "$id": "#/properties/tools", "type": "array", "title": "The Tools Schema", "items": { - "$id": "#/properties/tools/items", "type": "object", - "title": "The Items Schema", "required": [ "name", "type", @@ -100,25 +89,22 @@ ], "properties": { "name": { - "$id": "#/properties/tools/items/properties/name", "type": "string", - "title": "The Tool Name Schema", "examples": [ "mvn-stack" ] }, "type": { - "$id": "#/properties/tools/items/properties/type", + "description": "Describes type or tool, e.g. whether it is and plugin or editor or other type", "type": "string", - "title": "The Tool Type Schema", "examples": [ - "chePlugin" + "chePlugin", + "cheEditor" ] }, "id": { - "$id": "#/properties/tools/items/properties/id", "type": "string", - "title": "The Tool Id Schema", + "description": "Describes the tool FQN", "examples": [ "eclipse/maven-jdk8:1.0.0" ] @@ -127,22 +113,17 @@ } }, "commands": { - "$id": "#/properties/commands", "type": "array", "title": "The Commands Schema", "items": { - "$id": "#/properties/commands/items", "type": "object", - "title": "The Items Schema", "required": [ "name", "actions" ], "properties": { "name": { - "$id": "#/properties/commands/items/properties/name", "type": "string", - "title": "The Command Name Schema", "examples": [ "build" ] @@ -151,13 +132,10 @@ "$ref": "#/definitions/attributes" }, "actions": { - "$id": "#/properties/commands/items/properties/actions", "type": "array", "title": "The Command Actions Schema", "items": { - "$id": "#/properties/commands/items/properties/actions/items", "type": "object", - "title": "The Command Items Schema", "required": [ "type", "tool", @@ -165,33 +143,29 @@ ], "properties": { "type": { - "$id": "#/properties/commands/items/properties/actions/items/properties/type", + "description": "Describes action type", "type": "string", - "title": "The Action Type Schema", "examples": [ "exec" ] }, "tool": { - "$id": "#/properties/commands/items/properties/actions/items/properties/tool", "type": "string", - "title": "The Action Tool Schema", + "description": "Describes tool to which given action relates", "examples": [ "mvn-stack" ] }, "command": { - "$id": "#/properties/commands/items/properties/actions/items/properties/command", "type": "string", - "title": "The Action Command Schema", + "description": "The actual action command-line string", "examples": [ "mvn package" ] }, "workdir": { - "$id": "#/properties/commands/items/properties/actions/items/properties/workdir", "type": "string", - "title": "The Action Workdir Schema", + "description": "Working directory where the schema should be executed", "examples": [ "/projects/spring-petclinic" ] From 78ec48c16fec080d10c690a8ac17339717c5ec67 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Wed, 28 Nov 2018 11:40:56 +0200 Subject: [PATCH 19/46] Review fixups; --- .../main/webapp/WEB-INF/classes/che/che.properties | 3 --- .../org/eclipse/che/api/devfile/server/Constants.java | 2 ++ .../api/devfile/server/DevFileSchemaValidator.java | 11 ++++------- .../che/api/devfile/server/DevFileConverterTest.java | 1 - .../devfile/server/DevFileSchemaValidatorTest.java | 2 +- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index deb1793045b..ebea733b635 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -549,6 +549,3 @@ che.server.secure_exposer.jwtproxy.memory_limit=128mb # Maximum size of the json processing pool # in case if pool size would be exceeded message execution will be rejected che.core.jsonrpc.processor_max_pool_size=100 - -# Devile JSON schema location (relative to api.war resources folder) -che.devfile.schema.file_location=schema/devfile.json diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java index 63e8103f69b..91e14bfd1a7 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java @@ -13,5 +13,7 @@ public class Constants { + public static final String SCHEMA_LOCATION = "schema/devfile.json"; + public static final String CURRENT_SPEC_VERSION = "0.0.1"; } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java index 8b5372b9382..d818fe79b38 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java @@ -12,6 +12,7 @@ package org.eclipse.che.api.devfile.server; import static java.lang.String.format; +import static org.eclipse.che.api.devfile.server.Constants.SCHEMA_LOCATION; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -25,8 +26,6 @@ import java.io.IOException; import java.net.URL; import java.util.stream.StreamSupport; -import javax.inject.Inject; -import javax.inject.Named; import javax.inject.Singleton; /** Validates YAML content against given JSON schema. */ @@ -37,12 +36,10 @@ public class DevFileSchemaValidator { private JsonNode schema; private ObjectMapper yamlReader; - @Inject - public DevFileSchemaValidator(@Named("che.devfile.schema.file_location") String schemaFile) - throws IOException { - final URL schemaURL = getClass().getClassLoader().getResource(schemaFile); + public DevFileSchemaValidator() throws IOException { + final URL schemaURL = getClass().getClassLoader().getResource(SCHEMA_LOCATION); if (schemaURL == null) { - throw new IOException("Devfile schema is not found at specified path:" + schemaFile); + throw new IOException("Devfile schema is not found at specified path:" + SCHEMA_LOCATION); } this.schema = JsonLoader.fromURL(schemaURL); this.validator = JsonSchemaFactory.byDefault().getValidator(); diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java index 6435f63130d..e3f55579ca7 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java @@ -43,7 +43,6 @@ public void shouldBuildWorkspaceConfigFromYamlDevFile() throws Exception { String jsonContent = Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_impl.json")); - System.out.println(JsonHelper.toJson(wsConfigImpl)); assertEquals(wsConfigImpl, JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null)); } diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java index 3842b8b49a7..e9604608f0c 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java @@ -21,7 +21,7 @@ public class DevFileSchemaValidatorTest { @BeforeClass public void setUp() throws Exception { - schemaValidator = new DevFileSchemaValidator("schema/devfile.json"); + schemaValidator = new DevFileSchemaValidator(); } @Test From f2b5a80eaa2381fa8ff48acdf2cf60317f6e76c6 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Wed, 28 Nov 2018 17:52:25 +0200 Subject: [PATCH 20/46] Added ws name validation and verbose mode --- wsmaster/che-core-api-devfile/pom.xml | 4 --- .../server/DevFileSchemaValidator.java | 6 ++-- .../api/devfile/server/DevFileService.java | 35 +++++++++++++++---- .../server/DevFileSchemaValidatorTest.java | 4 +-- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index 0108db9749d..755d2400cb7 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -63,10 +63,6 @@ org.eclipse.che.core che-core-api-core - - org.eclipse.che.core - che-core-api-model - org.eclipse.che.core che-core-api-workspace diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java index d818fe79b38..dd3584a6d44 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java @@ -46,7 +46,7 @@ public DevFileSchemaValidator() throws IOException { this.yamlReader = new ObjectMapper(new YAMLFactory()); } - public void validateBySchema(String yamlContent) throws DevFileFormatException { + public void validateBySchema(String yamlContent, boolean verbose) throws DevFileFormatException { ProcessingReport report; try { final JsonNode data = yamlReader.readTree(yamlContent); @@ -61,7 +61,9 @@ public void validateBySchema(String yamlContent) throws DevFileFormatException { message -> message.getLogLevel() == LogLevel.ERROR || message.getLogLevel() == LogLevel.FATAL) - .forEach(message -> sb.append(format("[%s] ", message.getMessage()))); + .forEach( + message -> + sb.append(format("[%s] ", verbose ? message.asJson() : message.getMessage()))); throw new DevFileFormatException(format("Devfile schema validation failed. Errors: %s", sb)); } } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index 0174c90a90c..c9679c25206 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -26,17 +26,18 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.Response; import org.eclipse.che.api.core.BadRequestException; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.ValidationException; -import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; import org.eclipse.che.api.core.rest.Service; import org.eclipse.che.api.devfile.model.Devfile; import org.eclipse.che.api.workspace.server.WorkspaceLinksGenerator; import org.eclipse.che.api.workspace.server.WorkspaceManager; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; import org.eclipse.che.commons.env.EnvironmentContext; @@ -73,18 +74,24 @@ public DevFileService( // // - /** Generates a workspace from provided devfile to a rest API */ + /** + * Creates workspace from provided devfile + * + * @param data devfile content + * @param verbose return more explained validation error messages if any + * @return created workspace configuration + */ @POST @Consumes({"text/yaml", "text/x-yaml", "application/yaml"}) @Produces(APPLICATION_JSON) - public WorkspaceDto createFromYaml(String data) + public WorkspaceDto createFromYaml(String data, @QueryParam("verbose") boolean verbose) throws ServerException, ConflictException, NotFoundException, ValidationException, BadRequestException { Devfile devFile; - WorkspaceConfig workspaceConfig; + WorkspaceConfigImpl workspaceConfig; try { - schemaValidator.validateBySchema(data); + schemaValidator.validateBySchema(data, verbose); devFile = objectMapper.readValue(data, Devfile.class); workspaceConfig = devFileConverter.devFileToWorkspaceConfig(devFile); } catch (IOException e) { @@ -95,7 +102,7 @@ public WorkspaceDto createFromYaml(String data) final String namespace = EnvironmentContext.getCurrent().getSubject().getUserName(); WorkspaceImpl workspace = - workspaceManager.createWorkspace(workspaceConfig, namespace, emptyMap()); + workspaceManager.createWorkspace(findAvailableName(workspaceConfig), namespace, emptyMap()); WorkspaceDto workspaceDto = asDto(workspace).withLinks(linksGenerator.genLinks(workspace, getServiceContext())); return workspaceDto; @@ -122,4 +129,20 @@ public Response createFromWorkspace(@PathParam("key") String key) throw new ServerException(e.getMessage(), e); } } + + private WorkspaceConfigImpl findAvailableName(WorkspaceConfigImpl config) throws ServerException { + String nameCandidate = config.getName(); + String namespace = EnvironmentContext.getCurrent().getSubject().getUserName(); + int counter = 0; + while (true) { + try { + workspaceManager.getWorkspace(nameCandidate, namespace); + nameCandidate = config.getName() + "_" + ++counter; + } catch (NotFoundException nf) { + config.setName(nameCandidate); + break; + } + } + return config; + } } diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java index e9604608f0c..ba26cf64bbb 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java @@ -29,7 +29,7 @@ public void shouldValidateCorrectYamlBySchema() throws Exception { String devFileYamlContent = Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); // when - schemaValidator.validateBySchema(devFileYamlContent); + schemaValidator.validateBySchema(devFileYamlContent, false); } @Test( @@ -40,6 +40,6 @@ public void shouldValidateIncorrectYamlBySchema() throws Exception { String devFileYamlContent = Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile_bad.yaml")); // when - schemaValidator.validateBySchema(devFileYamlContent); + schemaValidator.validateBySchema(devFileYamlContent, false); } } From a78699885425ab8e58dde15183f3dc19c413cde7 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Thu, 29 Nov 2018 10:35:33 +0200 Subject: [PATCH 21/46] Chavge version -> spec version --- .../eclipse/che/api/devfile/server/DevFileConverter.java | 7 ++++--- .../src/main/resources/schema/devfile.json | 6 +++--- .../che/api/devfile/server/DevFileConverterTest.java | 2 +- .../che-core-api-devfile/src/test/resources/devfile.yaml | 2 +- .../src/test/resources/devfile_bad.yaml | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index 0ed30aa7d1a..e12efa75112 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -36,7 +36,8 @@ public class DevFileConverter { public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { - Devfile devFile = new Devfile().withVersion(CURRENT_SPEC_VERSION).withName(wsConfig.getName()); + Devfile devFile = + new Devfile().withSpecVersion(CURRENT_SPEC_VERSION).withName(wsConfig.getName()); // Manage projects List projects = new ArrayList<>(); @@ -176,9 +177,9 @@ private ProjectConfigImpl devProjectToProjectConfig(Project devProject) { } private static void validateCurrentVersion(Devfile devFile) throws DevFileFormatException { - if (!CURRENT_SPEC_VERSION.equals(devFile.getVersion())) { + if (!CURRENT_SPEC_VERSION.equals(devFile.getSpecVersion())) { throw new DevFileFormatException( - format("Provided devfile has unsupported version %s", devFile.getVersion())); + format("Provided devfile has unsupported version %s", devFile.getSpecVersion())); } } } diff --git a/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json b/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json index bb37b82f988..9a3aeaf77c3 100644 --- a/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json +++ b/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json @@ -10,16 +10,16 @@ "type": "object", "title": "The Root Schema of DevFile object", "required": [ - "version", + "specVersion", "name", "projects", "tools", "commands" ], "properties": { - "version": { + "specVersion": { "type": "string", - "title": "Devfile Schema Version", + "title": "Devfile Schema Specification Version", "examples": [ "0.0.1" ] diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java index e3f55579ca7..be2ce1ee132 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java @@ -62,7 +62,7 @@ public void shouldBuildYamlDevFileFromWorkspaceConfig() throws Exception { Devfile expectedDevFile = objectMapper.readValue(yamlContent, Devfile.class); // Recursively compare - assertEquals(devFile.getVersion(), expectedDevFile.getVersion()); + assertEquals(devFile.getSpecVersion(), expectedDevFile.getSpecVersion()); assertEquals(devFile.getName(), expectedDevFile.getName()); assertEquals(devFile.getProjects().size(), expectedDevFile.getProjects().size()); for (Project project : devFile.getProjects()) { diff --git a/wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml b/wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml index d3794ebaf78..02bd815b982 100644 --- a/wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml +++ b/wsmaster/che-core-api-devfile/src/test/resources/devfile.yaml @@ -11,7 +11,7 @@ # --- -version: 0.0.1 +specVersion: 0.0.1 name: petclinic-dev-environment projects: - name: petclinic diff --git a/wsmaster/che-core-api-devfile/src/test/resources/devfile_bad.yaml b/wsmaster/che-core-api-devfile/src/test/resources/devfile_bad.yaml index e5805fa1756..fca1187910a 100644 --- a/wsmaster/che-core-api-devfile/src/test/resources/devfile_bad.yaml +++ b/wsmaster/che-core-api-devfile/src/test/resources/devfile_bad.yaml @@ -11,7 +11,7 @@ # --- -version: 0.0.1 +specVersion: 0.0.1 name: petclinic-dev-environment projects: - name: petclinic From 781134e3b26ab084453a1ca706e3232cc07efd04 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Thu, 29 Nov 2018 16:44:45 +0200 Subject: [PATCH 22/46] Review fixes --- wsmaster/che-core-api-devfile/pom.xml | 32 ++-------- .../api/devfile/server/DevFileConverter.java | 22 +++++-- .../server/DevFileFormatException.java | 4 +- .../server/DevFileSchemaValidator.java | 27 ++++----- .../api/devfile/server/DevFileService.java | 47 +++++++++++++-- .../server/DevfileSchemaCachedProvider.java | 58 +++++++++++++++++++ .../server/DevFileSchemaValidatorTest.java | 2 +- .../src/test/resources/logback-test.xml | 2 - .../src/test/resources/workspace_impl.json | 6 +- 9 files changed, 142 insertions(+), 58 deletions(-) create mode 100644 wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaCachedProvider.java diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index 755d2400cb7..0be31e694c5 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -71,24 +71,16 @@ org.eclipse.che.core che-core-api-workspace-shared - - org.eclipse.che.core - che-core-commons-json - - - org.everrest - everrest-core - - - javax.servlet - javax.servlet-api - provided - javax.ws.rs javax.ws.rs-api provided + + org.eclipse.che.core + che-core-commons-json + test + org.testng testng @@ -137,20 +129,6 @@ true - - org.apache.maven.plugins - maven-dependency-plugin - - - analyze - - - org.everrest:everrest-core - - - - - diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index e12efa75112..022e18c71f0 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -11,11 +11,13 @@ */ package org.eclipse.che.api.devfile.server; +import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; import static org.eclipse.che.api.devfile.server.Constants.CURRENT_SPEC_VERSION; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -60,7 +62,7 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { new Tool() .withType("cheEditor") .withId(editorId) - .withName(wsConfig.getAttributes().get(editorId)); + .withName(findToolName(wsConfig, editorId)); tools.add(editorTool); } else if (entry.getKey().equals("plugins")) { for (String pluginId : entry.getValue().split(",")) { @@ -68,7 +70,7 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { new Tool() .withId(pluginId) .withType("chePlugin") - .withName(wsConfig.getAttributes().get(pluginId)); + .withName(findToolName(wsConfig, pluginId)); tools.add(pluginTool); } } @@ -92,15 +94,17 @@ public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) // Manage tools Map attributes = new HashMap<>(); StringJoiner pluginsStringJoiner = new StringJoiner(","); + StringJoiner toolIdToNameMappingStringJoiner = new StringJoiner(","); for (Tool tool : devFile.getTools()) { if (tool.getType().equals("cheEditor")) { attributes.put("editor", tool.getId()); } else if (tool.getType().equals("chePlugin")) { pluginsStringJoiner.add(tool.getId()); } - attributes.put(tool.getId(), tool.getName()); + toolIdToNameMappingStringJoiner.add(tool.getId() + "=" + tool.getName()); } attributes.put("plugins", pluginsStringJoiner.toString()); + attributes.put("toolsAliases", toolIdToNameMappingStringJoiner.toString()); config.setAttributes(attributes); // Manage commands @@ -176,10 +180,20 @@ private ProjectConfigImpl devProjectToProjectConfig(Project devProject) { return projectConfig; } + private String findToolName(WorkspaceConfigImpl wsConfig, String toolId) { + String aliasesString = firstNonNull(wsConfig.getAttributes().get("toolsAliases"), ""); + Optional valueOpt = + Arrays.stream(aliasesString.split(",")) + .filter(s -> s.split("=")[0].equals(toolId)) + .map(s -> s.split("=")[1]) + .findAny(); + return valueOpt.isPresent() ? valueOpt.get() : toolId.substring(0, toolId.indexOf(":")); + } + private static void validateCurrentVersion(Devfile devFile) throws DevFileFormatException { if (!CURRENT_SPEC_VERSION.equals(devFile.getSpecVersion())) { throw new DevFileFormatException( - format("Provided devfile has unsupported version %s", devFile.getSpecVersion())); + format("Provided Devfile has unsupported version %s", devFile.getSpecVersion())); } } } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java index c4a0a8963e6..62d3ba9c118 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java @@ -11,9 +11,7 @@ */ package org.eclipse.che.api.devfile.server; -import org.eclipse.che.api.core.ApiException; - -public class DevFileFormatException extends ApiException { +public class DevFileFormatException extends Exception { public DevFileFormatException(String serviceError) { super(serviceError); diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java index dd3584a6d44..8cc912d4b0c 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java @@ -25,6 +25,7 @@ import com.github.fge.jsonschema.main.JsonValidator; import java.io.IOException; import java.net.URL; +import java.util.stream.Collectors; import java.util.stream.StreamSupport; import javax.inject.Singleton; @@ -46,25 +47,25 @@ public DevFileSchemaValidator() throws IOException { this.yamlReader = new ObjectMapper(new YAMLFactory()); } - public void validateBySchema(String yamlContent, boolean verbose) throws DevFileFormatException { + public JsonNode validateBySchema(String yamlContent, boolean verbose) + throws DevFileFormatException { ProcessingReport report; + JsonNode data; try { - final JsonNode data = yamlReader.readTree(yamlContent); + data = yamlReader.readTree(yamlContent); report = validator.validate(schema, data); } catch (IOException | ProcessingException e) { - throw new DevFileFormatException("Unable to validate devfile. Error: " + e.getMessage()); + throw new DevFileFormatException("Unable to validate Devfile. Error: " + e.getMessage()); } if (!report.isSuccess()) { - StringBuilder sb = new StringBuilder(); - StreamSupport.stream(report.spliterator(), false) - .filter( - message -> - message.getLogLevel() == LogLevel.ERROR - || message.getLogLevel() == LogLevel.FATAL) - .forEach( - message -> - sb.append(format("[%s] ", verbose ? message.asJson() : message.getMessage()))); - throw new DevFileFormatException(format("Devfile schema validation failed. Errors: %s", sb)); + String error = + StreamSupport.stream(report.spliterator(), false) + .filter(m -> m.getLogLevel() == LogLevel.ERROR || m.getLogLevel() == LogLevel.FATAL) + .map(message -> verbose ? message.asJson().toString() : message.getMessage()) + .collect(Collectors.joining(", ", "[", "]")); + throw new DevFileFormatException( + format("Devfile schema validation failed. Errors: %s", error)); } + return data; } } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index c9679c25206..e121bc1cd1a 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -11,11 +11,13 @@ */ package org.eclipse.che.api.devfile.server; +import static java.lang.String.format; import static java.util.Collections.emptyMap; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static org.eclipse.che.api.workspace.server.DtoConverter.asDto; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import java.io.IOException; @@ -47,6 +49,7 @@ public class DevFileService extends Service { private WorkspaceLinksGenerator linksGenerator; private DevFileSchemaValidator schemaValidator; + private DevfileSchemaCachedProvider schemaCachedProvider; private WorkspaceManager workspaceManager; private ObjectMapper objectMapper; private DevFileConverter devFileConverter; @@ -55,9 +58,11 @@ public class DevFileService extends Service { public DevFileService( WorkspaceLinksGenerator linksGenerator, DevFileSchemaValidator schemaValidator, + DevfileSchemaCachedProvider schemaCachedProvider, WorkspaceManager workspaceManager) { this.linksGenerator = linksGenerator; this.schemaValidator = schemaValidator; + this.schemaCachedProvider = schemaCachedProvider; this.workspaceManager = workspaceManager; this.objectMapper = new ObjectMapper(new YAMLFactory()); this.devFileConverter = new DevFileConverter(); @@ -74,6 +79,17 @@ public DevFileService( // // + /** + * Retrieves the json schema. + * + * @return json schema + */ + @GET + @Produces(APPLICATION_JSON) + public Response getSchema() throws ServerException { + return Response.ok(schemaCachedProvider.getSchemaContent()).build(); + } + /** * Creates workspace from provided devfile * @@ -91,8 +107,8 @@ public WorkspaceDto createFromYaml(String data, @QueryParam("verbose") boolean v Devfile devFile; WorkspaceConfigImpl workspaceConfig; try { - schemaValidator.validateBySchema(data, verbose); - devFile = objectMapper.readValue(data, Devfile.class); + JsonNode parsed = schemaValidator.validateBySchema(data, verbose); + devFile = objectMapper.treeToValue(parsed, Devfile.class); workspaceConfig = devFileConverter.devFileToWorkspaceConfig(devFile); } catch (IOException e) { throw new ServerException(e.getMessage()); @@ -118,8 +134,8 @@ public WorkspaceDto createFromYaml(String data, @QueryParam("verbose") boolean v @Path("/{key:.*}") @Produces("text/yml") public Response createFromWorkspace(@PathParam("key") String key) - throws NotFoundException, ServerException { - // TODO: validate key + throws NotFoundException, ServerException, BadRequestException { + validateKey(key); WorkspaceImpl workspace = workspaceManager.getWorkspace(key); Devfile workspaceDevFile = devFileConverter.workspaceToDevFile(workspace.getConfig()); // Write object as YAML @@ -145,4 +161,27 @@ private WorkspaceConfigImpl findAvailableName(WorkspaceConfigImpl config) throws } return config; } + + private void validateKey(String key) throws BadRequestException { + String[] parts = key.split(":", -1); // -1 is to prevent skipping trailing part + switch (parts.length) { + case 1: + { + return; // consider it's id + } + case 2: + { + if (parts[1].isEmpty()) { + throw new BadRequestException( + "Wrong composite key format - workspace name required to be set."); + } + break; + } + default: + { + throw new BadRequestException( + format("Wrong composite key %s. Format should be 'username:workspace_name'. ", key)); + } + } + } } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaCachedProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaCachedProvider.java new file mode 100644 index 00000000000..2524dbfe6e7 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaCachedProvider.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.server; + +import static org.eclipse.che.api.devfile.server.Constants.SCHEMA_LOCATION; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.ref.SoftReference; +import java.util.stream.Collectors; +import javax.inject.Singleton; +import org.eclipse.che.api.core.ServerException; + +/** Loads a schema content and stores it in soft reference. */ +@Singleton +public class DevfileSchemaCachedProvider { + + private SoftReference schemaRef; + + public DevfileSchemaCachedProvider() throws IOException { + this.schemaRef = new SoftReference<>(loadFile()); + } + + public String getSchemaContent() throws ServerException { + String schemaStream = schemaRef.get(); + if (schemaStream == null) { + try { + schemaStream = loadFile(); + } catch (IOException e) { + throw new ServerException(e); + } + schemaRef = new SoftReference<>(schemaStream); + } + return schemaStream; + } + + private String loadFile() throws IOException { + + try (InputStream schemaStream = + getClass().getClassLoader().getResourceAsStream(SCHEMA_LOCATION)) { + return new BufferedReader(new InputStreamReader(schemaStream)) + .lines() + .parallel() + .collect(Collectors.joining("\n")); + } + } +} diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java index ba26cf64bbb..ffbee94ae0a 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java @@ -35,7 +35,7 @@ public void shouldValidateCorrectYamlBySchema() throws Exception { @Test( expectedExceptions = DevFileFormatException.class, expectedExceptionsMessageRegExp = - "Devfile schema validation failed. Errors: \\[object has missing required properties \\(\\[.+\\]\\)\\] $") + "Devfile schema validation failed. Errors: \\[object has missing required properties \\(\\[\"name\"\\]\\)\\]$") public void shouldValidateIncorrectYamlBySchema() throws Exception { String devFileYamlContent = Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile_bad.yaml")); diff --git a/wsmaster/che-core-api-devfile/src/test/resources/logback-test.xml b/wsmaster/che-core-api-devfile/src/test/resources/logback-test.xml index a38570dd2a6..e8944d1d9c4 100644 --- a/wsmaster/che-core-api-devfile/src/test/resources/logback-test.xml +++ b/wsmaster/che-core-api-devfile/src/test/resources/logback-test.xml @@ -27,8 +27,6 @@ - - diff --git a/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json b/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json index 61b001aed82..c6a85608c54 100644 --- a/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json +++ b/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json @@ -44,10 +44,8 @@ "environments": {}, "name": "petclinic-dev-environment", "attributes": { - "eclipse/maven-jdk8:1.0.0": "mvn-stack", + "toolsAliases": "eclipse/maven-jdk8:1.0.0=mvn-stack,eclipse/theia:0.0.3=theia-ide,eclipse/theia-jdtls:0.0.3=jdt.ls", "editor": "eclipse/theia:0.0.3", - "eclipse/theia-jdtls:0.0.3": "jdt.ls", - "plugins": "eclipse/maven-jdk8:1.0.0,eclipse/theia-jdtls:0.0.3", - "eclipse/theia:0.0.3": "theia-ide" + "plugins": "eclipse/maven-jdk8:1.0.0,eclipse/theia-jdtls:0.0.3" } } From f992bc46bca16b039fedbb049d0aa5e6a9e61458 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 30 Nov 2018 10:23:30 +0200 Subject: [PATCH 23/46] Minor fixup --- .../che/api/devfile/server/DevfileSchemaCachedProvider.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaCachedProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaCachedProvider.java index 2524dbfe6e7..e864ddcad77 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaCachedProvider.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaCachedProvider.java @@ -46,12 +46,10 @@ public String getSchemaContent() throws ServerException { } private String loadFile() throws IOException { - try (InputStream schemaStream = getClass().getClassLoader().getResourceAsStream(SCHEMA_LOCATION)) { return new BufferedReader(new InputStreamReader(schemaStream)) .lines() - .parallel() .collect(Collectors.joining("\n")); } } From ed8e22453d420424725dce0e68a2425b1fb1c117 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 30 Nov 2018 16:05:41 +0200 Subject: [PATCH 24/46] Use schema provider in validator --- ....java => DevFileSchemaCachedProvider.java} | 29 +++++++++---------- .../server/DevFileSchemaValidator.java | 11 +++---- .../api/devfile/server/DevFileService.java | 10 +++++-- .../server/DevFileSchemaValidatorTest.java | 2 +- 4 files changed, 27 insertions(+), 25 deletions(-) rename wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/{DevfileSchemaCachedProvider.java => DevFileSchemaCachedProvider.java} (64%) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaCachedProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaCachedProvider.java similarity index 64% rename from wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaCachedProvider.java rename to wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaCachedProvider.java index e864ddcad77..91b9e99a68c 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaCachedProvider.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaCachedProvider.java @@ -13,6 +13,8 @@ import static org.eclipse.che.api.devfile.server.Constants.SCHEMA_LOCATION; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.fge.jackson.JsonLoader; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -20,29 +22,24 @@ import java.lang.ref.SoftReference; import java.util.stream.Collectors; import javax.inject.Singleton; -import org.eclipse.che.api.core.ServerException; /** Loads a schema content and stores it in soft reference. */ @Singleton -public class DevfileSchemaCachedProvider { +public class DevFileSchemaCachedProvider { - private SoftReference schemaRef; + private SoftReference schemaRef = new SoftReference(null); - public DevfileSchemaCachedProvider() throws IOException { - this.schemaRef = new SoftReference<>(loadFile()); + public String getSchemaContent() throws IOException { + String schema = schemaRef.get(); + if (schema == null) { + schema = loadFile(); + schemaRef = new SoftReference<>(schema); + } + return schema; } - public String getSchemaContent() throws ServerException { - String schemaStream = schemaRef.get(); - if (schemaStream == null) { - try { - schemaStream = loadFile(); - } catch (IOException e) { - throw new ServerException(e); - } - schemaRef = new SoftReference<>(schemaStream); - } - return schemaStream; + public JsonNode getJsoneNode() throws IOException { + return JsonLoader.fromString(getSchemaContent()); } private String loadFile() throws IOException { diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java index 8cc912d4b0c..a222d385b4d 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java @@ -17,7 +17,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.github.fge.jackson.JsonLoader; import com.github.fge.jsonschema.core.exceptions.ProcessingException; import com.github.fge.jsonschema.core.report.LogLevel; import com.github.fge.jsonschema.core.report.ProcessingReport; @@ -27,6 +26,7 @@ import java.net.URL; import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import javax.inject.Inject; import javax.inject.Singleton; /** Validates YAML content against given JSON schema. */ @@ -34,15 +34,16 @@ public class DevFileSchemaValidator { private JsonValidator validator; - private JsonNode schema; private ObjectMapper yamlReader; + private DevFileSchemaCachedProvider schemaProvider; - public DevFileSchemaValidator() throws IOException { + @Inject + public DevFileSchemaValidator(DevFileSchemaCachedProvider schemaProvider) throws IOException { final URL schemaURL = getClass().getClassLoader().getResource(SCHEMA_LOCATION); if (schemaURL == null) { throw new IOException("Devfile schema is not found at specified path:" + SCHEMA_LOCATION); } - this.schema = JsonLoader.fromURL(schemaURL); + this.schemaProvider = schemaProvider; this.validator = JsonSchemaFactory.byDefault().getValidator(); this.yamlReader = new ObjectMapper(new YAMLFactory()); } @@ -53,7 +54,7 @@ public JsonNode validateBySchema(String yamlContent, boolean verbose) JsonNode data; try { data = yamlReader.readTree(yamlContent); - report = validator.validate(schema, data); + report = validator.validate(schemaProvider.getJsoneNode(), data); } catch (IOException | ProcessingException e) { throw new DevFileFormatException("Unable to validate Devfile. Error: " + e.getMessage()); } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index e121bc1cd1a..bdec3a44605 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -49,7 +49,7 @@ public class DevFileService extends Service { private WorkspaceLinksGenerator linksGenerator; private DevFileSchemaValidator schemaValidator; - private DevfileSchemaCachedProvider schemaCachedProvider; + private DevFileSchemaCachedProvider schemaCachedProvider; private WorkspaceManager workspaceManager; private ObjectMapper objectMapper; private DevFileConverter devFileConverter; @@ -58,7 +58,7 @@ public class DevFileService extends Service { public DevFileService( WorkspaceLinksGenerator linksGenerator, DevFileSchemaValidator schemaValidator, - DevfileSchemaCachedProvider schemaCachedProvider, + DevFileSchemaCachedProvider schemaCachedProvider, WorkspaceManager workspaceManager) { this.linksGenerator = linksGenerator; this.schemaValidator = schemaValidator; @@ -87,7 +87,11 @@ public DevFileService( @GET @Produces(APPLICATION_JSON) public Response getSchema() throws ServerException { - return Response.ok(schemaCachedProvider.getSchemaContent()).build(); + try { + return Response.ok(schemaCachedProvider.getSchemaContent()).build(); + } catch (IOException e) { + throw new ServerException(e); + } } /** diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java index ffbee94ae0a..2474cbcc0e3 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java @@ -21,7 +21,7 @@ public class DevFileSchemaValidatorTest { @BeforeClass public void setUp() throws Exception { - schemaValidator = new DevFileSchemaValidator(); + schemaValidator = new DevFileSchemaValidator(new DevFileSchemaCachedProvider()); } @Test From eab51325882f51c2e64a630ab336ccbea4534312 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Sat, 1 Dec 2018 13:51:52 +0200 Subject: [PATCH 25/46] Added tests --- wsmaster/che-core-api-devfile/pom.xml | 39 ++++ .../server/DevFileSchemaCachedProvider.java | 53 ------ .../server/DevFileSchemaValidator.java | 4 +- .../api/devfile/server/DevFileService.java | 10 +- .../devfile/server/DevFileConverterTest.java | 4 +- .../server/DevFileSchemaValidatorTest.java | 2 +- .../devfile/server/DevFileServiceTest.java | 173 ++++++++++++++++++ ...kspace_impl.json => workspace_config.json} | 0 8 files changed, 221 insertions(+), 64 deletions(-) delete mode 100644 wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaCachedProvider.java create mode 100644 wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java rename wsmaster/che-core-api-devfile/src/test/resources/{workspace_impl.json => workspace_config.json} (100%) diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index 0be31e694c5..df69fab8e5f 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -63,6 +63,10 @@ org.eclipse.che.core che-core-api-core + + org.eclipse.che.core + che-core-api-model + org.eclipse.che.core che-core-api-workspace @@ -76,11 +80,46 @@ javax.ws.rs-api provided + + com.jayway.restassured + rest-assured + test + + + org.eclipse.che.core + che-core-api-account + test + + + org.eclipse.che.core + che-core-api-dto + test + org.eclipse.che.core che-core-commons-json test + + org.everrest + everrest-assured + test + + + org.everrest + everrest-core + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-testng + test + org.testng testng diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaCachedProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaCachedProvider.java deleted file mode 100644 index 91b9e99a68c..00000000000 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaCachedProvider.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2012-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -package org.eclipse.che.api.devfile.server; - -import static org.eclipse.che.api.devfile.server.Constants.SCHEMA_LOCATION; - -import com.fasterxml.jackson.databind.JsonNode; -import com.github.fge.jackson.JsonLoader; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.ref.SoftReference; -import java.util.stream.Collectors; -import javax.inject.Singleton; - -/** Loads a schema content and stores it in soft reference. */ -@Singleton -public class DevFileSchemaCachedProvider { - - private SoftReference schemaRef = new SoftReference(null); - - public String getSchemaContent() throws IOException { - String schema = schemaRef.get(); - if (schema == null) { - schema = loadFile(); - schemaRef = new SoftReference<>(schema); - } - return schema; - } - - public JsonNode getJsoneNode() throws IOException { - return JsonLoader.fromString(getSchemaContent()); - } - - private String loadFile() throws IOException { - try (InputStream schemaStream = - getClass().getClassLoader().getResourceAsStream(SCHEMA_LOCATION)) { - return new BufferedReader(new InputStreamReader(schemaStream)) - .lines() - .collect(Collectors.joining("\n")); - } - } -} diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java index a222d385b4d..b02805c4ddd 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java @@ -35,10 +35,10 @@ public class DevFileSchemaValidator { private JsonValidator validator; private ObjectMapper yamlReader; - private DevFileSchemaCachedProvider schemaProvider; + private DevFileSchemaProvider schemaProvider; @Inject - public DevFileSchemaValidator(DevFileSchemaCachedProvider schemaProvider) throws IOException { + public DevFileSchemaValidator(DevFileSchemaProvider schemaProvider) throws IOException { final URL schemaURL = getClass().getClassLoader().getResource(SCHEMA_LOCATION); if (schemaURL == null) { throw new IOException("Devfile schema is not found at specified path:" + SCHEMA_LOCATION); diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index bdec3a44605..b4d2144fcd5 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -49,7 +49,7 @@ public class DevFileService extends Service { private WorkspaceLinksGenerator linksGenerator; private DevFileSchemaValidator schemaValidator; - private DevFileSchemaCachedProvider schemaCachedProvider; + private DevFileSchemaProvider schemaCachedProvider; private WorkspaceManager workspaceManager; private ObjectMapper objectMapper; private DevFileConverter devFileConverter; @@ -58,7 +58,7 @@ public class DevFileService extends Service { public DevFileService( WorkspaceLinksGenerator linksGenerator, DevFileSchemaValidator schemaValidator, - DevFileSchemaCachedProvider schemaCachedProvider, + DevFileSchemaProvider schemaCachedProvider, WorkspaceManager workspaceManager) { this.linksGenerator = linksGenerator; this.schemaValidator = schemaValidator; @@ -102,7 +102,7 @@ public Response getSchema() throws ServerException { * @return created workspace configuration */ @POST - @Consumes({"text/yaml", "text/x-yaml", "application/yaml"}) + @Consumes({"text/yaml", "text/x-yaml", "application/yaml", "application/json"}) @Produces(APPLICATION_JSON) public WorkspaceDto createFromYaml(String data, @QueryParam("verbose") boolean verbose) throws ServerException, ConflictException, NotFoundException, ValidationException, @@ -123,9 +123,7 @@ public WorkspaceDto createFromYaml(String data, @QueryParam("verbose") boolean v final String namespace = EnvironmentContext.getCurrent().getSubject().getUserName(); WorkspaceImpl workspace = workspaceManager.createWorkspace(findAvailableName(workspaceConfig), namespace, emptyMap()); - WorkspaceDto workspaceDto = - asDto(workspace).withLinks(linksGenerator.genLinks(workspace, getServiceContext())); - return workspaceDto; + return asDto(workspace).withLinks(linksGenerator.genLinks(workspace, getServiceContext())); } /** diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java index be2ce1ee132..aa589978a15 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java @@ -42,7 +42,7 @@ public void shouldBuildWorkspaceConfigFromYamlDevFile() throws Exception { WorkspaceConfigImpl wsConfigImpl = devFileConverter.devFileToWorkspaceConfig(devFile); String jsonContent = - Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_impl.json")); + Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_config.json")); assertEquals(wsConfigImpl, JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null)); } @@ -51,7 +51,7 @@ public void shouldBuildWorkspaceConfigFromYamlDevFile() throws Exception { public void shouldBuildYamlDevFileFromWorkspaceConfig() throws Exception { String jsonContent = - Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_impl.json")); + Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_config.json")); WorkspaceConfigImpl workspaceConfig = JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null); Devfile devFile = devFileConverter.workspaceToDevFile(workspaceConfig); diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java index 2474cbcc0e3..c6615513aad 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java @@ -21,7 +21,7 @@ public class DevFileSchemaValidatorTest { @BeforeClass public void setUp() throws Exception { - schemaValidator = new DevFileSchemaValidator(new DevFileSchemaCachedProvider()); + schemaValidator = new DevFileSchemaValidator(new DevFileSchemaProvider()); } @Test diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java new file mode 100644 index 00000000000..572438e46a9 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.server; + +import static com.jayway.restassured.RestAssured.given; +import static org.everrest.assured.JettyHttpServer.ADMIN_USER_NAME; +import static org.everrest.assured.JettyHttpServer.ADMIN_USER_PASSWORD; +import static org.everrest.assured.JettyHttpServer.SECURE_PATH; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.response.Response; +import java.io.IOException; +import org.eclipse.che.account.spi.AccountImpl; +import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; +import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; +import org.eclipse.che.api.devfile.model.Devfile; +import org.eclipse.che.api.workspace.server.WorkspaceLinksGenerator; +import org.eclipse.che.api.workspace.server.WorkspaceManager; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; +import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; +import org.eclipse.che.commons.env.EnvironmentContext; +import org.eclipse.che.commons.json.JsonHelper; +import org.eclipse.che.commons.json.JsonParseException; +import org.eclipse.che.commons.subject.Subject; +import org.eclipse.che.commons.subject.SubjectImpl; +import org.everrest.assured.EverrestJetty; +import org.everrest.core.Filter; +import org.everrest.core.GenericContainerRequest; +import org.everrest.core.RequestFilter; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; +import org.testng.reporters.Files; + +@Listeners({EverrestJetty.class, MockitoTestNGListener.class}) +public class DevFileServiceTest { + + @Mock private WorkspaceLinksGenerator linksGenerator; + + @Mock private WorkspaceManager workspaceManager; + @Mock private EnvironmentContext environmentContext; + private DevFileSchemaProvider schemaProvider = new DevFileSchemaProvider(); + private DevFileSchemaValidator validator; + + @SuppressWarnings("unused") + private static final EnvironmentFilter FILTER = new EnvironmentFilter(); + private static final Subject SUBJECT = new SubjectImpl("user", "user123", "token", false); + + @SuppressWarnings("unused") + private DevFileService devFileService; + + @BeforeMethod + public void initService() throws IOException { + this.validator = spy(new DevFileSchemaValidator(schemaProvider)); + this.devFileService = + new DevFileService(linksGenerator, validator, schemaProvider, workspaceManager); + } + + @Test + public void shouldRetrieveSchema() throws Exception { + final Response response = + given() + .auth() + .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) + .when() + .get(SECURE_PATH + "/devfile"); + + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getBody().asString(), schemaProvider.getSchemaContent()); + } + + @Test + public void shouldAcceptDevFileAndFindAvailableName() throws Exception { + ArgumentCaptor captor = ArgumentCaptor.forClass(WorkspaceConfigImpl.class); + EnvironmentContext.setCurrent(environmentContext); + WorkspaceImpl ws = mock(WorkspaceImpl.class); + when(workspaceManager.createWorkspace(any(), eq(SUBJECT.getUserName()), anyMap())) + .thenReturn(createWorkspace(WorkspaceStatus.STOPPED)); + String yamlContent = + Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); + when(workspaceManager.getWorkspace(anyString(), anyString())) + .thenAnswer( + invocation -> { + String wsname = invocation.getArgument(0); + if (wsname.equals("petclinic-dev-environment") + || wsname.equals("petclinic-dev-environment_1")) { + return ws; + } + throw new NotFoundException("ws not found"); + }); + + final Response response = + given() + .auth() + .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) + .contentType(ContentType.JSON) + .body(yamlContent) + .when() + .post(SECURE_PATH + "/devfile"); + + assertEquals(response.getStatusCode(), 200); + verify(validator).validateBySchema(eq(yamlContent), eq(false)); + verify(workspaceManager).createWorkspace(captor.capture(), eq(SUBJECT.getUserName()), anyMap()); + assertEquals("petclinic-dev-environment_2", captor.getValue().getName()); + } + + @Test + public void shouldCreateDevFileFromWorkspace() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); + when(workspaceManager.getWorkspace(anyString())) + .thenReturn(createWorkspace(WorkspaceStatus.STOPPED)); + + final Response response = + given() + .auth() + .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) + .when() + .get(SECURE_PATH + "/devfile/ws123456"); + + assertEquals(response.getStatusCode(), 200); + Devfile devFile = objectMapper.readValue(response.getBody().asString(), Devfile.class); + assertNotNull(devFile); + } + + private WorkspaceImpl createWorkspace(WorkspaceStatus status) + throws IOException, JsonParseException { + return WorkspaceImpl.builder() + .setConfig(createConfig()) + .generateId() + .setAccount(new AccountImpl("anyId", SUBJECT.getUserName(), "test")) + .setStatus(status) + .build(); + } + + private WorkspaceConfig createConfig() throws IOException, JsonParseException { + String jsonContent = + Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_config.json")); + return JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null); + } + + @Filter + public static class EnvironmentFilter implements RequestFilter { + @Override + public void doFilter(GenericContainerRequest request) { + EnvironmentContext.getCurrent().setSubject(SUBJECT); + } + } +} diff --git a/wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json b/wsmaster/che-core-api-devfile/src/test/resources/workspace_config.json similarity index 100% rename from wsmaster/che-core-api-devfile/src/test/resources/workspace_impl.json rename to wsmaster/che-core-api-devfile/src/test/resources/workspace_config.json From ce0de4dfa5f60610e96bcf8f7ed87a123699f619 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Sat, 1 Dec 2018 17:44:46 +0200 Subject: [PATCH 26/46] Fmt fix --- .../org/eclipse/che/api/devfile/server/DevFileServiceTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java index 572438e46a9..21fed55b23f 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java @@ -69,6 +69,7 @@ public class DevFileServiceTest { @SuppressWarnings("unused") private static final EnvironmentFilter FILTER = new EnvironmentFilter(); + private static final Subject SUBJECT = new SubjectImpl("user", "user123", "token", false); @SuppressWarnings("unused") From decb5245605050bb224e8100be2592f9afe3e2ae Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Sat, 1 Dec 2018 18:03:29 +0200 Subject: [PATCH 27/46] Rename class --- .../devfile/server/DevFileSchemaProvider.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java new file mode 100644 index 00000000000..db0ce34e420 --- /dev/null +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.devfile.server; + +import static org.eclipse.che.api.devfile.server.Constants.SCHEMA_LOCATION; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.fge.jackson.JsonLoader; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.ref.SoftReference; +import java.util.stream.Collectors; +import javax.inject.Singleton; + +/** Loads a schema content and stores it in soft reference. */ +@Singleton +public class DevFileSchemaProvider { + + private SoftReference schemaRef = new SoftReference(null); + + public String getSchemaContent() throws IOException { + String schema = schemaRef.get(); + if (schema == null) { + schema = loadFile(); + schemaRef = new SoftReference<>(schema); + } + return schema; + } + + public JsonNode getJsoneNode() throws IOException { + return JsonLoader.fromString(getSchemaContent()); + } + + private String loadFile() throws IOException { + try (InputStream schemaStream = + getClass().getClassLoader().getResourceAsStream(SCHEMA_LOCATION)) { + return new BufferedReader(new InputStreamReader(schemaStream)) + .lines() + .collect(Collectors.joining("\n")); + } + } +} From 80c738262b089b13f9af93f98bb3d8f06aa4ddbe Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Sun, 2 Dec 2018 10:51:54 +0200 Subject: [PATCH 28/46] Minor fixes --- .../api/devfile/server/DevFileSchemaProvider.java | 15 +++++---------- .../devfile/server/DevFileSchemaValidator.java | 6 ------ 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java index db0ce34e420..1e4faaa06c1 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java @@ -15,12 +15,10 @@ import com.fasterxml.jackson.databind.JsonNode; import com.github.fge.jackson.JsonLoader; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.lang.ref.SoftReference; -import java.util.stream.Collectors; +import java.nio.file.Files; +import java.nio.file.Paths; import javax.inject.Singleton; /** Loads a schema content and stores it in soft reference. */ @@ -43,11 +41,8 @@ public JsonNode getJsoneNode() throws IOException { } private String loadFile() throws IOException { - try (InputStream schemaStream = - getClass().getClassLoader().getResourceAsStream(SCHEMA_LOCATION)) { - return new BufferedReader(new InputStreamReader(schemaStream)) - .lines() - .collect(Collectors.joining("\n")); - } + return new String( + Files.readAllBytes( + Paths.get(getClass().getClassLoader().getResource(SCHEMA_LOCATION).getFile()))); } } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java index b02805c4ddd..46a23c758f6 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java @@ -12,7 +12,6 @@ package org.eclipse.che.api.devfile.server; import static java.lang.String.format; -import static org.eclipse.che.api.devfile.server.Constants.SCHEMA_LOCATION; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -23,7 +22,6 @@ import com.github.fge.jsonschema.main.JsonSchemaFactory; import com.github.fge.jsonschema.main.JsonValidator; import java.io.IOException; -import java.net.URL; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import javax.inject.Inject; @@ -39,10 +37,6 @@ public class DevFileSchemaValidator { @Inject public DevFileSchemaValidator(DevFileSchemaProvider schemaProvider) throws IOException { - final URL schemaURL = getClass().getClassLoader().getResource(SCHEMA_LOCATION); - if (schemaURL == null) { - throw new IOException("Devfile schema is not found at specified path:" + SCHEMA_LOCATION); - } this.schemaProvider = schemaProvider; this.validator = JsonSchemaFactory.byDefault().getValidator(); this.yamlReader = new ObjectMapper(new YAMLFactory()); From c99c3bceaa7d98b155e0a24ea3d1ab004dc2b0b9 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Sun, 2 Dec 2018 11:04:50 +0200 Subject: [PATCH 29/46] Code fix --- .../che/api/devfile/server/DevFileSchemaProvider.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java index 1e4faaa06c1..7022a3cff5c 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java @@ -17,6 +17,7 @@ import com.github.fge.jackson.JsonLoader; import java.io.IOException; import java.lang.ref.SoftReference; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; import javax.inject.Singleton; @@ -25,7 +26,7 @@ @Singleton public class DevFileSchemaProvider { - private SoftReference schemaRef = new SoftReference(null); + private SoftReference schemaRef = new SoftReference<>(null); public String getSchemaContent() throws IOException { String schema = schemaRef.get(); @@ -41,8 +42,10 @@ public JsonNode getJsoneNode() throws IOException { } private String loadFile() throws IOException { - return new String( - Files.readAllBytes( - Paths.get(getClass().getClassLoader().getResource(SCHEMA_LOCATION).getFile()))); + URL schemaURL = getClass().getClassLoader().getResource(SCHEMA_LOCATION); + if (schemaURL != null) { + return new String(Files.readAllBytes(Paths.get(schemaURL.getFile()))); + } + throw new IOException("Schema file cannot be found"); } } From 62c40123ee8a1bcafe129b38a19e4269c5f8720b Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Sun, 2 Dec 2018 11:09:28 +0200 Subject: [PATCH 30/46] Code fix --- .../eclipse/che/api/devfile/server/DevFileSchemaProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java index 7022a3cff5c..93b86902dec 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java @@ -11,6 +11,7 @@ */ package org.eclipse.che.api.devfile.server; +import static java.lang.String.format; import static org.eclipse.che.api.devfile.server.Constants.SCHEMA_LOCATION; import com.fasterxml.jackson.databind.JsonNode; @@ -46,6 +47,6 @@ private String loadFile() throws IOException { if (schemaURL != null) { return new String(Files.readAllBytes(Paths.get(schemaURL.getFile()))); } - throw new IOException("Schema file cannot be found"); + throw new IOException(format("Schema file %s cannot be found", SCHEMA_LOCATION)); } } From 786fc90e99c2cf94cdbb136ea6645a2b08947cf5 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Sun, 2 Dec 2018 11:12:28 +0200 Subject: [PATCH 31/46] Code fix --- .../eclipse/che/api/devfile/server/DevFileSchemaProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java index 93b86902dec..3491483a7e9 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java @@ -47,6 +47,6 @@ private String loadFile() throws IOException { if (schemaURL != null) { return new String(Files.readAllBytes(Paths.get(schemaURL.getFile()))); } - throw new IOException(format("Schema file %s cannot be found", SCHEMA_LOCATION)); + throw new IllegalStateException(format("Schema file %s cannot be found", SCHEMA_LOCATION)); } } From 0c9f2ce21f982196b214426148ac421d9b716997 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 3 Dec 2018 12:21:10 +0200 Subject: [PATCH 32/46] Review fixes --- .../che/api/devfile/server/DevFileConverter.java | 16 ++++++---------- .../devfile/server/DevFileFormatException.java | 5 +++-- .../devfile/server/DevFileSchemaProvider.java | 4 +++- .../che/api/devfile/server/DevFileService.java | 11 ----------- 4 files changed, 12 insertions(+), 24 deletions(-) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index 022e18c71f0..f0a11c309cd 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -146,18 +146,14 @@ private List devCommandToCommandImpls(Devfile devFile, Command devC private Command commandImplToDevCommand(CommandImpl command) { Command devCommand = new Command().withName(command.getName()); Action action = new Action().withCommand(command.getCommandLine()).withType(command.getType()); - if (!isNullOrEmpty(command.getAttributes().get("workingDir"))) { - action.setWorkdir(command.getAttributes().get("workingDir")); + String workingDir = command.getAttributes().get("workingDir"); + if (!isNullOrEmpty(workingDir)) { + action.setWorkdir(workingDir); } + devCommand.setAttributes(command.getAttributes()); // Remove internal attributes - command.getAttributes().remove("workingDir"); - command.getAttributes().remove("pluginId"); - // Put others - if (devCommand.getAttributes() == null) { - devCommand.withAttributes(command.getAttributes()); - } else { - devCommand.getAttributes().putAll(command.getAttributes()); - } + devCommand.getAttributes().remove("workingDir"); + devCommand.getAttributes().remove("pluginId"); return devCommand; } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java index 62d3ba9c118..f56d9b7327a 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java @@ -11,9 +11,10 @@ */ package org.eclipse.che.api.devfile.server; +/** Thrown when Devfile schema or integrity validation is failed. */ public class DevFileFormatException extends Exception { - public DevFileFormatException(String serviceError) { - super(serviceError); + public DevFileFormatException(String formatError) { + super(formatError); } } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java index 3491483a7e9..8e6ec719c8b 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.lang.ref.SoftReference; import java.net.URL; +import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; import javax.inject.Singleton; @@ -45,7 +46,8 @@ public JsonNode getJsoneNode() throws IOException { private String loadFile() throws IOException { URL schemaURL = getClass().getClassLoader().getResource(SCHEMA_LOCATION); if (schemaURL != null) { - return new String(Files.readAllBytes(Paths.get(schemaURL.getFile()))); + return new String( + Files.readAllBytes(Paths.get(schemaURL.getFile())), Charset.defaultCharset()); } throw new IllegalStateException(format("Schema file %s cannot be found", SCHEMA_LOCATION)); } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index b4d2144fcd5..f9879098c40 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -68,17 +68,6 @@ public DevFileService( this.devFileConverter = new DevFileConverter(); } - // Creates a workspace by providing the url to the repository - // Initially this method will return - // empty workspace configuration. And will start che-devfile-broker on a background to clone - // sources and get devfile. - // @POST - // @Produces(APPLICATION_JSON) - // public Response create(@QueryParam("repo_url") String repo_url){ - // } - // - // - /** * Retrieves the json schema. * From 1a3c281e6b478a38ec4880dc97432fbdd35dae31 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 3 Dec 2018 12:47:27 +0200 Subject: [PATCH 33/46] Review fixes --- .../che/api/devfile/server/Constants.java | 14 ++++++ .../api/devfile/server/DevFileConverter.java | 13 +++-- .../api/devfile/server/DevFileService.java | 25 +--------- .../server/WorkspaceKeyValidator.java | 49 +++++++++++++++++++ .../workspace/server/WorkspaceService.java | 28 +---------- 5 files changed, 73 insertions(+), 56 deletions(-) create mode 100644 wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceKeyValidator.java diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java index 91e14bfd1a7..06a25f25bb5 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java @@ -16,4 +16,18 @@ public class Constants { public static final String SCHEMA_LOCATION = "schema/devfile.json"; public static final String CURRENT_SPEC_VERSION = "0.0.1"; + + public static final String EDITOR_WORKSPACE_ATTRIBUTE_NAME = "editor"; + + public static final String PLUGINS_WORKSPACE_ATTRIBUTE_NAME = "plugins"; + + /** + * Workspace attribute which contains comma-separated list of mappings of tool id to its name + * Example: + * + *
+   * eclipse/maven-jdk8:1.0.0=mvn-stack,eclipse/theia:0.0.3=theia-ide,eclipse/theia-jdtls:0.0.3=jdt.ls
+   * 
+ */ + public static final String ALIASES_WORKSPACE_ATTRIBUTE_NAME = "toolsAliases"; } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index f0a11c309cd..dd7ffbee0b7 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -14,7 +14,10 @@ import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; +import static org.eclipse.che.api.devfile.server.Constants.ALIASES_WORKSPACE_ATTRIBUTE_NAME; import static org.eclipse.che.api.devfile.server.Constants.CURRENT_SPEC_VERSION; +import static org.eclipse.che.api.devfile.server.Constants.EDITOR_WORKSPACE_ATTRIBUTE_NAME; +import static org.eclipse.che.api.devfile.server.Constants.PLUGINS_WORKSPACE_ATTRIBUTE_NAME; import java.util.ArrayList; import java.util.Arrays; @@ -56,7 +59,7 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { // Manage tools List tools = new ArrayList<>(); for (Map.Entry entry : wsConfig.getAttributes().entrySet()) { - if (entry.getKey().equals("editor")) { + if (entry.getKey().equals(EDITOR_WORKSPACE_ATTRIBUTE_NAME)) { String editorId = entry.getValue(); Tool editorTool = new Tool() @@ -64,7 +67,7 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { .withId(editorId) .withName(findToolName(wsConfig, editorId)); tools.add(editorTool); - } else if (entry.getKey().equals("plugins")) { + } else if (entry.getKey().equals(PLUGINS_WORKSPACE_ATTRIBUTE_NAME)) { for (String pluginId : entry.getValue().split(",")) { Tool pluginTool = new Tool() @@ -97,14 +100,14 @@ public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) StringJoiner toolIdToNameMappingStringJoiner = new StringJoiner(","); for (Tool tool : devFile.getTools()) { if (tool.getType().equals("cheEditor")) { - attributes.put("editor", tool.getId()); + attributes.put(EDITOR_WORKSPACE_ATTRIBUTE_NAME, tool.getId()); } else if (tool.getType().equals("chePlugin")) { pluginsStringJoiner.add(tool.getId()); } toolIdToNameMappingStringJoiner.add(tool.getId() + "=" + tool.getName()); } - attributes.put("plugins", pluginsStringJoiner.toString()); - attributes.put("toolsAliases", toolIdToNameMappingStringJoiner.toString()); + attributes.put(PLUGINS_WORKSPACE_ATTRIBUTE_NAME, pluginsStringJoiner.toString()); + attributes.put(ALIASES_WORKSPACE_ATTRIBUTE_NAME, toolIdToNameMappingStringJoiner.toString()); config.setAttributes(attributes); // Manage commands diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index f9879098c40..9706210e644 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -11,10 +11,10 @@ */ package org.eclipse.che.api.devfile.server; -import static java.lang.String.format; import static java.util.Collections.emptyMap; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static org.eclipse.che.api.workspace.server.DtoConverter.asDto; +import static org.eclipse.che.api.workspace.server.WorkspaceKeyValidator.validateKey; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; @@ -152,27 +152,4 @@ private WorkspaceConfigImpl findAvailableName(WorkspaceConfigImpl config) throws } return config; } - - private void validateKey(String key) throws BadRequestException { - String[] parts = key.split(":", -1); // -1 is to prevent skipping trailing part - switch (parts.length) { - case 1: - { - return; // consider it's id - } - case 2: - { - if (parts[1].isEmpty()) { - throw new BadRequestException( - "Wrong composite key format - workspace name required to be set."); - } - break; - } - default: - { - throw new BadRequestException( - format("Wrong composite key %s. Format should be 'username:workspace_name'. ", key)); - } - } - } } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceKeyValidator.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceKeyValidator.java new file mode 100644 index 00000000000..bbfb97a2109 --- /dev/null +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceKeyValidator.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.workspace.server; + +import static java.lang.String.format; + +import org.eclipse.che.api.core.BadRequestException; + +/** Helper class to validate workspace composite keys. */ +public class WorkspaceKeyValidator { + + /** + * Checks that key consists either from workspaceId or username:workspace_name string. + * + * @param key key string to validate + * @throws BadRequestException if validation is failed + */ + public static void validateKey(String key) throws BadRequestException { + String[] parts = key.split(":", -1); // -1 is to prevent skipping trailing part + switch (parts.length) { + case 1: + { + return; // consider it's id + } + case 2: + { + if (parts[1].isEmpty()) { + throw new BadRequestException( + "Wrong composite key format - workspace name required to be set."); + } + break; + } + default: + { + throw new BadRequestException( + format("Wrong composite key %s. Format should be 'username:workspace_name'. ", key)); + } + } + } +} diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java index 22e466acfc2..2266ff63a8d 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java @@ -17,6 +17,7 @@ import static java.util.stream.Collectors.toList; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static org.eclipse.che.api.workspace.server.DtoConverter.asDto; +import static org.eclipse.che.api.workspace.server.WorkspaceKeyValidator.validateKey; import static org.eclipse.che.api.workspace.shared.Constants.CHE_WORKSPACE_AUTO_START; import static org.eclipse.che.api.workspace.shared.Constants.CHE_WORKSPACE_PLUGIN_REGISTRY_URL_PROPERTY; @@ -733,33 +734,6 @@ private void requiredNotNull(Object object, String subject) throws BadRequestExc } } - /* - * Validate composite key. - * - */ - private void validateKey(String key) throws BadRequestException { - String[] parts = key.split(":", -1); // -1 is to prevent skipping trailing part - switch (parts.length) { - case 1: - { - return; // consider it's id - } - case 2: - { - if (parts[1].isEmpty()) { - throw new BadRequestException( - "Wrong composite key format - workspace name required to be set."); - } - break; - } - default: - { - throw new BadRequestException( - format("Wrong composite key %s. Format should be 'username:workspace_name'. ", key)); - } - } - } - private void relativizeRecipeLinks(WorkspaceConfigDto config) { if (config != null) { Map environments = config.getEnvironments(); From 414800b9239eff1d67b0f010e84911c05befee23 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 3 Dec 2018 12:58:26 +0200 Subject: [PATCH 34/46] Review fixes --- .../che/api/core/model/workspace/config/Command.java | 6 ++++++ .../wsplugins/KubernetesPluginsToolingApplier.java | 3 ++- .../che/api/devfile/server/DevFileConverter.java | 10 ++++++---- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/Command.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/Command.java index 76c9d8d3041..9cf13a7ad01 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/Command.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/Command.java @@ -21,6 +21,12 @@ */ public interface Command { + /** + * {@link Command} attribute which indicates the working directory where the given command must be + * run + */ + String WORKING_DIRECTORY_ATTRIBUTE = "workingDir"; + /** * Returns command name (i.e. 'start tomcat') The name should be unique per user in one workspace, * which means that user may create only one command with the same name in the same workspace diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java index 716418602c1..154d72d8754 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java @@ -13,6 +13,7 @@ import static java.lang.String.format; import static java.util.Collections.emptyList; +import static org.eclipse.che.api.core.model.workspace.config.Command.WORKING_DIRECTORY_ATTRIBUTE; import static org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider.SECURE_EXPOSER_IMPL_PROPERTY; import com.google.common.annotations.Beta; @@ -212,7 +213,7 @@ private CommandImpl asCommand(String machineName, Command command) { command.getName(), command.getCommand().stream().collect(Collectors.joining(" ")), "custom"); - cmd.getAttributes().put("workDir", command.getWorkingDir()); + cmd.getAttributes().put(WORKING_DIRECTORY_ATTRIBUTE, command.getWorkingDir()); cmd.getAttributes().put("machineName", machineName); return cmd; } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index dd7ffbee0b7..acb0cbc62b3 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -14,6 +14,7 @@ import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; +import static org.eclipse.che.api.core.model.workspace.config.Command.WORKING_DIRECTORY_ATTRIBUTE; import static org.eclipse.che.api.devfile.server.Constants.ALIASES_WORKSPACE_ATTRIBUTE_NAME; import static org.eclipse.che.api.devfile.server.Constants.CURRENT_SPEC_VERSION; import static org.eclipse.che.api.devfile.server.Constants.EDITOR_WORKSPACE_ATTRIBUTE_NAME; @@ -41,6 +42,7 @@ public class DevFileConverter { public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { + Devfile devFile = new Devfile().withSpecVersion(CURRENT_SPEC_VERSION).withName(wsConfig.getName()); @@ -127,7 +129,7 @@ private List devCommandToCommandImpls(Devfile devFile, Command devC command.setType(devAction.getType()); command.setCommandLine(devAction.getCommand()); if (devAction.getWorkdir() != null) { - command.getAttributes().put("workingDir", devAction.getWorkdir()); + command.getAttributes().put(WORKING_DIRECTORY_ATTRIBUTE, devAction.getWorkdir()); } Optional toolOfCommand = devFile @@ -149,13 +151,13 @@ private List devCommandToCommandImpls(Devfile devFile, Command devC private Command commandImplToDevCommand(CommandImpl command) { Command devCommand = new Command().withName(command.getName()); Action action = new Action().withCommand(command.getCommandLine()).withType(command.getType()); - String workingDir = command.getAttributes().get("workingDir"); + String workingDir = command.getAttributes().get(WORKING_DIRECTORY_ATTRIBUTE); if (!isNullOrEmpty(workingDir)) { action.setWorkdir(workingDir); } devCommand.setAttributes(command.getAttributes()); // Remove internal attributes - devCommand.getAttributes().remove("workingDir"); + devCommand.getAttributes().remove(WORKING_DIRECTORY_ATTRIBUTE); devCommand.getAttributes().remove("pluginId"); return devCommand; } @@ -180,7 +182,7 @@ private ProjectConfigImpl devProjectToProjectConfig(Project devProject) { } private String findToolName(WorkspaceConfigImpl wsConfig, String toolId) { - String aliasesString = firstNonNull(wsConfig.getAttributes().get("toolsAliases"), ""); + String aliasesString = firstNonNull(wsConfig.getAttributes().get(ALIASES_WORKSPACE_ATTRIBUTE_NAME), ""); Optional valueOpt = Arrays.stream(aliasesString.split(",")) .filter(s -> s.split("=")[0].equals(toolId)) From d6c5df1b568125eaf040838fa6e019c091a78779 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 3 Dec 2018 13:47:23 +0200 Subject: [PATCH 35/46] Add swagger docs --- wsmaster/che-core-api-devfile/pom.xml | 4 ++ .../api/devfile/server/DevFileConverter.java | 3 +- .../api/devfile/server/DevFileService.java | 39 ++++++++++++++++++- .../devfile/server/DevFileServiceTest.java | 2 +- 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml index df69fab8e5f..f59002678c1 100644 --- a/wsmaster/che-core-api-devfile/pom.xml +++ b/wsmaster/che-core-api-devfile/pom.xml @@ -55,6 +55,10 @@ com.google.guava guava
+ + io.swagger + swagger-annotations + javax.inject javax.inject diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java index acb0cbc62b3..216476cd86c 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java @@ -182,7 +182,8 @@ private ProjectConfigImpl devProjectToProjectConfig(Project devProject) { } private String findToolName(WorkspaceConfigImpl wsConfig, String toolId) { - String aliasesString = firstNonNull(wsConfig.getAttributes().get(ALIASES_WORKSPACE_ATTRIBUTE_NAME), ""); + String aliasesString = + firstNonNull(wsConfig.getAttributes().get(ALIASES_WORKSPACE_ATTRIBUTE_NAME), ""); Optional valueOpt = Arrays.stream(aliasesString.split(",")) .filter(s -> s.split("=")[0].equals(toolId)) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java index 9706210e644..6fede5f44fd 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java @@ -20,6 +20,9 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; import java.io.IOException; import javax.inject.Inject; import javax.ws.rs.Consumes; @@ -75,6 +78,11 @@ public DevFileService( */ @GET @Produces(APPLICATION_JSON) + @ApiOperation(value = "Retrieves current version of Devfile JSON schema") + @ApiResponses({ + @ApiResponse(code = 200, message = "The schema successfully retrieved"), + @ApiResponse(code = 500, message = "Internal server error occurred") + }) public Response getSchema() throws ServerException { try { return Response.ok(schemaCachedProvider.getSchemaContent()).build(); @@ -93,7 +101,22 @@ public Response getSchema() throws ServerException { @POST @Consumes({"text/yaml", "text/x-yaml", "application/yaml", "application/json"}) @Produces(APPLICATION_JSON) - public WorkspaceDto createFromYaml(String data, @QueryParam("verbose") boolean verbose) + @ApiOperation( + value = "Create a new workspace based on provided devfile", + notes = + "This operation can be performed only by authorized user," + + "this user will be the owner of the created workspace", + response = WorkspaceDto.class) + @ApiResponses({ + @ApiResponse(code = 200, message = "The workspace successfully created"), + @ApiResponse( + code = 400, + message = + "Provided devfile syntactically incorrect, doesn't match with actual schema or has integrity violations"), + @ApiResponse(code = 403, message = "The user does not have access to create a new workspace"), + @ApiResponse(code = 500, message = "Internal server error occurred") + }) + public Response createFromYaml(String data, @QueryParam("verbose") boolean verbose) throws ServerException, ConflictException, NotFoundException, ValidationException, BadRequestException { @@ -112,7 +135,9 @@ public WorkspaceDto createFromYaml(String data, @QueryParam("verbose") boolean v final String namespace = EnvironmentContext.getCurrent().getSubject().getUserName(); WorkspaceImpl workspace = workspaceManager.createWorkspace(findAvailableName(workspaceConfig), namespace, emptyMap()); - return asDto(workspace).withLinks(linksGenerator.genLinks(workspace, getServiceContext())); + return Response.status(201) + .entity(asDto(workspace).withLinks(linksGenerator.genLinks(workspace, getServiceContext()))) + .build(); } /** @@ -124,6 +149,16 @@ public WorkspaceDto createFromYaml(String data, @QueryParam("verbose") boolean v @GET @Path("/{key:.*}") @Produces("text/yml") + @ApiOperation( + value = "Generates the devfile from giben workspace", + notes = + "This operation can be performed only by authorized user," + + "this user must be the owner of the exported workspace") + @ApiResponses({ + @ApiResponse(code = 200, message = "The workspace successfully exported"), + @ApiResponse(code = 403, message = "The user does not have access to create a new workspace"), + @ApiResponse(code = 500, message = "Internal server error occurred") + }) public Response createFromWorkspace(@PathParam("key") String key) throws NotFoundException, ServerException, BadRequestException { validateKey(key); diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java index 21fed55b23f..1232eb53537 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java @@ -124,7 +124,7 @@ public void shouldAcceptDevFileAndFindAvailableName() throws Exception { .when() .post(SECURE_PATH + "/devfile"); - assertEquals(response.getStatusCode(), 200); + assertEquals(response.getStatusCode(), 201); verify(validator).validateBySchema(eq(yamlContent), eq(false)); verify(workspaceManager).createWorkspace(captor.capture(), eq(SUBJECT.getUserName()), anyMap()); assertEquals("petclinic-dev-environment_2", captor.getValue().getName()); From 8fc42133db4317ec45bf9f5e3233d0729407a860 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 3 Dec 2018 14:20:04 +0200 Subject: [PATCH 36/46] Review fixes --- .../che/api/deploy/WsMasterModule.java | 6 ++-- .../KubernetesPluginsToolingApplierTest.java | 4 ++- ...leConverter.java => DevfileConverter.java} | 35 +++++++++---------- ...ption.java => DevfileFormatException.java} | 4 +-- ...ovider.java => DevfileSchemaProvider.java} | 2 +- ...dator.java => DevfileSchemaValidator.java} | 12 +++---- ...evFileService.java => DevfileService.java} | 22 ++++++------ ...terTest.java => DevfileConverterTest.java} | 8 ++--- ...t.java => DevfileSchemaValidatorTest.java} | 8 ++--- ...rviceTest.java => DevfileServiceTest.java} | 12 +++---- 10 files changed, 58 insertions(+), 55 deletions(-) rename wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/{DevFileConverter.java => DevfileConverter.java} (90%) rename wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/{DevFileFormatException.java => DevfileFormatException.java} (81%) rename wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/{DevFileSchemaProvider.java => DevfileSchemaProvider.java} (97%) rename wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/{DevFileSchemaValidator.java => DevfileSchemaValidator.java} (88%) rename wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/{DevFileService.java => DevfileService.java} (92%) rename wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/{DevFileConverterTest.java => DevfileConverterTest.java} (95%) rename wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/{DevFileSchemaValidatorTest.java => DevfileSchemaValidatorTest.java} (86%) rename wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/{DevFileServiceTest.java => DevfileServiceTest.java} (95%) diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index abbb1e961bc..63cd77266d0 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -30,6 +30,8 @@ import org.eclipse.che.api.core.rest.CheJsonProvider; import org.eclipse.che.api.core.rest.MessageBodyAdapter; import org.eclipse.che.api.core.rest.MessageBodyAdapterInterceptor; +import org.eclipse.che.api.devfile.server.DevfileSchemaValidator; +import org.eclipse.che.api.devfile.server.DevfileService; import org.eclipse.che.api.factory.server.FactoryAcceptValidator; import org.eclipse.che.api.factory.server.FactoryCreateValidator; import org.eclipse.che.api.factory.server.FactoryEditValidator; @@ -152,8 +154,8 @@ protected void configure() { bind(org.eclipse.che.api.user.server.PreferencesService.class); bind(org.eclipse.che.security.oauth.OAuthAuthenticationService.class); - bind(org.eclipse.che.api.devfile.server.DevFileSchemaValidator.class); - bind(org.eclipse.che.api.devfile.server.DevFileService.class); + bind(DevfileSchemaValidator.class); + bind(DevfileService.class); MapBinder stacks = MapBinder.newMapBinder( diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java index 0739ad8eb6f..5fdecc4d973 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplierTest.java @@ -17,6 +17,7 @@ import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; +import static org.eclipse.che.api.core.model.workspace.config.Command.WORKING_DIRECTORY_ATTRIBUTE; import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE; import static org.eclipse.che.commons.lang.NameGenerator.generate; import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_ORIGINAL_NAME_LABEL; @@ -136,7 +137,8 @@ public void shouldProvisionPluginsCommandsToEnvironment() throws Exception { envCommand.getCommandLine(), pluginCommand.getCommand().stream().collect(Collectors.joining(" "))); assertEquals(envCommand.getType(), "custom"); - assertEquals(envCommand.getAttributes().get("workDir"), pluginCommand.getWorkingDir()); + assertEquals( + envCommand.getAttributes().get(WORKING_DIRECTORY_ATTRIBUTE), pluginCommand.getWorkingDir()); assertEquals(envCommand.getAttributes().get("machineName"), POD_NAME + "/plugin-container"); } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java similarity index 90% rename from wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java rename to wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java index 216476cd86c..a5e95f928a6 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileConverter.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Optional; import java.util.StringJoiner; +import java.util.stream.Collectors; import org.eclipse.che.api.devfile.model.Action; import org.eclipse.che.api.devfile.model.Command; import org.eclipse.che.api.devfile.model.Devfile; @@ -39,11 +40,11 @@ import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; /** Helps to convert Devfile into workspace config and back. */ -public class DevFileConverter { +public class DevfileConverter { public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { - Devfile devFile = + Devfile devfile = new Devfile().withSpecVersion(CURRENT_SPEC_VERSION).withName(wsConfig.getName()); // Manage projects @@ -51,15 +52,16 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { wsConfig .getProjects() .forEach(projectConfig -> projects.add(projectConfigToDevProject(projectConfig))); - devFile.setProjects(projects); + devfile.setProjects(projects); // Manage commands List commands = new ArrayList<>(); wsConfig.getCommands().forEach(command -> commands.add(commandImplToDevCommand(command))); - devFile.setCommands(commands); + devfile.setCommands(commands); // Manage tools List tools = new ArrayList<>(); + Map toolIdToName = parseTools(wsConfig); for (Map.Entry entry : wsConfig.getAttributes().entrySet()) { if (entry.getKey().equals(EDITOR_WORKSPACE_ATTRIBUTE_NAME)) { String editorId = entry.getValue(); @@ -67,7 +69,7 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { new Tool() .withType("cheEditor") .withId(editorId) - .withName(findToolName(wsConfig, editorId)); + .withName(toolIdToName.getOrDefault(editorId, editorId)); tools.add(editorTool); } else if (entry.getKey().equals(PLUGINS_WORKSPACE_ATTRIBUTE_NAME)) { for (String pluginId : entry.getValue().split(",")) { @@ -75,17 +77,17 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) { new Tool() .withId(pluginId) .withType("chePlugin") - .withName(findToolName(wsConfig, pluginId)); + .withName(toolIdToName.getOrDefault(pluginId, pluginId)); tools.add(pluginTool); } } } - devFile.setTools(tools); - return devFile; + devfile.setTools(tools); + return devfile; } public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile) - throws DevFileFormatException { + throws DevfileFormatException { validateCurrentVersion(devFile); WorkspaceConfigImpl config = new WorkspaceConfigImpl(); @@ -181,20 +183,17 @@ private ProjectConfigImpl devProjectToProjectConfig(Project devProject) { return projectConfig; } - private String findToolName(WorkspaceConfigImpl wsConfig, String toolId) { + private Map parseTools(WorkspaceConfigImpl wsConfig) { String aliasesString = firstNonNull(wsConfig.getAttributes().get(ALIASES_WORKSPACE_ATTRIBUTE_NAME), ""); - Optional valueOpt = - Arrays.stream(aliasesString.split(",")) - .filter(s -> s.split("=")[0].equals(toolId)) - .map(s -> s.split("=")[1]) - .findAny(); - return valueOpt.isPresent() ? valueOpt.get() : toolId.substring(0, toolId.indexOf(":")); + return Arrays.stream(aliasesString.split(",")) + .map(s -> s.split("=", 2)) + .collect(Collectors.toMap(arr -> arr[0], arr -> arr[1])); } - private static void validateCurrentVersion(Devfile devFile) throws DevFileFormatException { + private static void validateCurrentVersion(Devfile devFile) throws DevfileFormatException { if (!CURRENT_SPEC_VERSION.equals(devFile.getSpecVersion())) { - throw new DevFileFormatException( + throw new DevfileFormatException( format("Provided Devfile has unsupported version %s", devFile.getSpecVersion())); } } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileFormatException.java similarity index 81% rename from wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java rename to wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileFormatException.java index f56d9b7327a..d46af66d7c2 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileFormatException.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileFormatException.java @@ -12,9 +12,9 @@ package org.eclipse.che.api.devfile.server; /** Thrown when Devfile schema or integrity validation is failed. */ -public class DevFileFormatException extends Exception { +public class DevfileFormatException extends Exception { - public DevFileFormatException(String formatError) { + public DevfileFormatException(String formatError) { super(formatError); } } diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java similarity index 97% rename from wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java rename to wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java index 8e6ec719c8b..22e0084f9dd 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaProvider.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java @@ -26,7 +26,7 @@ /** Loads a schema content and stores it in soft reference. */ @Singleton -public class DevFileSchemaProvider { +public class DevfileSchemaProvider { private SoftReference schemaRef = new SoftReference<>(null); diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java similarity index 88% rename from wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java rename to wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java index 46a23c758f6..3bf42621328 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidator.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java @@ -29,28 +29,28 @@ /** Validates YAML content against given JSON schema. */ @Singleton -public class DevFileSchemaValidator { +public class DevfileSchemaValidator { private JsonValidator validator; private ObjectMapper yamlReader; - private DevFileSchemaProvider schemaProvider; + private DevfileSchemaProvider schemaProvider; @Inject - public DevFileSchemaValidator(DevFileSchemaProvider schemaProvider) throws IOException { + public DevfileSchemaValidator(DevfileSchemaProvider schemaProvider) throws IOException { this.schemaProvider = schemaProvider; this.validator = JsonSchemaFactory.byDefault().getValidator(); this.yamlReader = new ObjectMapper(new YAMLFactory()); } public JsonNode validateBySchema(String yamlContent, boolean verbose) - throws DevFileFormatException { + throws DevfileFormatException { ProcessingReport report; JsonNode data; try { data = yamlReader.readTree(yamlContent); report = validator.validate(schemaProvider.getJsoneNode(), data); } catch (IOException | ProcessingException e) { - throw new DevFileFormatException("Unable to validate Devfile. Error: " + e.getMessage()); + throw new DevfileFormatException("Unable to validate Devfile. Error: " + e.getMessage()); } if (!report.isSuccess()) { String error = @@ -58,7 +58,7 @@ public JsonNode validateBySchema(String yamlContent, boolean verbose) .filter(m -> m.getLogLevel() == LogLevel.ERROR || m.getLogLevel() == LogLevel.FATAL) .map(message -> verbose ? message.asJson().toString() : message.getMessage()) .collect(Collectors.joining(", ", "[", "]")); - throw new DevFileFormatException( + throw new DevfileFormatException( format("Devfile schema validation failed. Errors: %s", error)); } return data; diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java similarity index 92% rename from wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java rename to wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java index 6fede5f44fd..5196bd0b3d1 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevFileService.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java @@ -48,27 +48,27 @@ import org.eclipse.che.commons.env.EnvironmentContext; @Path("/devfile") -public class DevFileService extends Service { +public class DevfileService extends Service { private WorkspaceLinksGenerator linksGenerator; - private DevFileSchemaValidator schemaValidator; - private DevFileSchemaProvider schemaCachedProvider; + private DevfileSchemaValidator schemaValidator; + private DevfileSchemaProvider schemaCachedProvider; private WorkspaceManager workspaceManager; private ObjectMapper objectMapper; - private DevFileConverter devFileConverter; + private DevfileConverter devfileConverter; @Inject - public DevFileService( + public DevfileService( WorkspaceLinksGenerator linksGenerator, - DevFileSchemaValidator schemaValidator, - DevFileSchemaProvider schemaCachedProvider, + DevfileSchemaValidator schemaValidator, + DevfileSchemaProvider schemaCachedProvider, WorkspaceManager workspaceManager) { this.linksGenerator = linksGenerator; this.schemaValidator = schemaValidator; this.schemaCachedProvider = schemaCachedProvider; this.workspaceManager = workspaceManager; this.objectMapper = new ObjectMapper(new YAMLFactory()); - this.devFileConverter = new DevFileConverter(); + this.devfileConverter = new DevfileConverter(); } /** @@ -125,10 +125,10 @@ public Response createFromYaml(String data, @QueryParam("verbose") boolean verbo try { JsonNode parsed = schemaValidator.validateBySchema(data, verbose); devFile = objectMapper.treeToValue(parsed, Devfile.class); - workspaceConfig = devFileConverter.devFileToWorkspaceConfig(devFile); + workspaceConfig = devfileConverter.devFileToWorkspaceConfig(devFile); } catch (IOException e) { throw new ServerException(e.getMessage()); - } catch (DevFileFormatException e) { + } catch (DevfileFormatException e) { throw new BadRequestException(e.getMessage()); } @@ -163,7 +163,7 @@ public Response createFromWorkspace(@PathParam("key") String key) throws NotFoundException, ServerException, BadRequestException { validateKey(key); WorkspaceImpl workspace = workspaceManager.getWorkspace(key); - Devfile workspaceDevFile = devFileConverter.workspaceToDevFile(workspace.getConfig()); + Devfile workspaceDevFile = devfileConverter.workspaceToDevFile(workspace.getConfig()); // Write object as YAML try { return Response.ok().entity(objectMapper.writeValueAsString(workspaceDevFile)).build(); diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileConverterTest.java similarity index 95% rename from wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java rename to wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileConverterTest.java index aa589978a15..fc56959d8de 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileConverterTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileConverterTest.java @@ -26,10 +26,10 @@ import org.testng.annotations.Test; import org.testng.reporters.Files; -public class DevFileConverterTest { +public class DevfileConverterTest { private ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); - private DevFileConverter devFileConverter = new DevFileConverter(); + private DevfileConverter devfileConverter = new DevfileConverter(); @Test public void shouldBuildWorkspaceConfigFromYamlDevFile() throws Exception { @@ -39,7 +39,7 @@ public void shouldBuildWorkspaceConfigFromYamlDevFile() throws Exception { Devfile devFile = objectMapper.readValue(yamlContent, Devfile.class); - WorkspaceConfigImpl wsConfigImpl = devFileConverter.devFileToWorkspaceConfig(devFile); + WorkspaceConfigImpl wsConfigImpl = devfileConverter.devFileToWorkspaceConfig(devFile); String jsonContent = Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_config.json")); @@ -54,7 +54,7 @@ public void shouldBuildYamlDevFileFromWorkspaceConfig() throws Exception { Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_config.json")); WorkspaceConfigImpl workspaceConfig = JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null); - Devfile devFile = devFileConverter.workspaceToDevFile(workspaceConfig); + Devfile devFile = devfileConverter.workspaceToDevFile(workspaceConfig); String yamlContent = Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml")); diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidatorTest.java similarity index 86% rename from wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java rename to wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidatorTest.java index c6615513aad..b5088af5371 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileSchemaValidatorTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidatorTest.java @@ -15,13 +15,13 @@ import org.testng.annotations.Test; import org.testng.reporters.Files; -public class DevFileSchemaValidatorTest { +public class DevfileSchemaValidatorTest { - private DevFileSchemaValidator schemaValidator; + private DevfileSchemaValidator schemaValidator; @BeforeClass public void setUp() throws Exception { - schemaValidator = new DevFileSchemaValidator(new DevFileSchemaProvider()); + schemaValidator = new DevfileSchemaValidator(new DevfileSchemaProvider()); } @Test @@ -33,7 +33,7 @@ public void shouldValidateCorrectYamlBySchema() throws Exception { } @Test( - expectedExceptions = DevFileFormatException.class, + expectedExceptions = DevfileFormatException.class, expectedExceptionsMessageRegExp = "Devfile schema validation failed. Errors: \\[object has missing required properties \\(\\[\"name\"\\]\\)\\]$") public void shouldValidateIncorrectYamlBySchema() throws Exception { diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileServiceTest.java similarity index 95% rename from wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java rename to wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileServiceTest.java index 1232eb53537..2198bbff768 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevFileServiceTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileServiceTest.java @@ -58,14 +58,14 @@ import org.testng.reporters.Files; @Listeners({EverrestJetty.class, MockitoTestNGListener.class}) -public class DevFileServiceTest { +public class DevfileServiceTest { @Mock private WorkspaceLinksGenerator linksGenerator; @Mock private WorkspaceManager workspaceManager; @Mock private EnvironmentContext environmentContext; - private DevFileSchemaProvider schemaProvider = new DevFileSchemaProvider(); - private DevFileSchemaValidator validator; + private DevfileSchemaProvider schemaProvider = new DevfileSchemaProvider(); + private DevfileSchemaValidator validator; @SuppressWarnings("unused") private static final EnvironmentFilter FILTER = new EnvironmentFilter(); @@ -73,13 +73,13 @@ public class DevFileServiceTest { private static final Subject SUBJECT = new SubjectImpl("user", "user123", "token", false); @SuppressWarnings("unused") - private DevFileService devFileService; + private DevfileService devFileService; @BeforeMethod public void initService() throws IOException { - this.validator = spy(new DevFileSchemaValidator(schemaProvider)); + this.validator = spy(new DevfileSchemaValidator(schemaProvider)); this.devFileService = - new DevFileService(linksGenerator, validator, schemaProvider, workspaceManager); + new DevfileService(linksGenerator, validator, schemaProvider, workspaceManager); } @Test From e90cb3978f4cc406eb59a4f357907af4408c9f65 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 3 Dec 2018 15:05:23 +0200 Subject: [PATCH 37/46] Fix javadocs --- .../che/api/devfile/server/Constants.java | 2 +- .../api/devfile/server/DevfileConverter.java | 17 +++++++++++------ .../devfile/server/DevfileFormatException.java | 2 +- .../devfile/server/DevfileSchemaValidator.java | 2 +- .../che/api/devfile/server/DevfileService.java | 4 ++-- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java index 06a25f25bb5..9dd302f8319 100644 --- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java +++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java @@ -23,7 +23,7 @@ public class Constants { /** * Workspace attribute which contains comma-separated list of mappings of tool id to its name - * Example: + * Example value: * *
    * eclipse/maven-jdk8:1.0.0=mvn-stack,eclipse/theia:0.0.3=theia-ide,eclipse/theia-jdtls:0.0.3=jdt.ls
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
index a5e95f928a6..8d971872f72 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
@@ -39,12 +39,17 @@
 import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
 import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
 
-/** Helps to convert Devfile into workspace config and back. */
+/** Helps to convert devfile into workspace config and back. */
 public class DevfileConverter {
 
   public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) {
 
-    Devfile devfile =
+    if (!isNullOrEmpty(wsConfig.getDefaultEnv()) || !wsConfig.getEnvironments().isEmpty()) {
+      //  throw new UnsupportedOperationException("Given workspace cannot be converted to devfile
+      // since it is contains environments.");
+    }
+
+    Devfile devFile =
         new Devfile().withSpecVersion(CURRENT_SPEC_VERSION).withName(wsConfig.getName());
 
     // Manage projects
@@ -52,12 +57,12 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) {
     wsConfig
         .getProjects()
         .forEach(projectConfig -> projects.add(projectConfigToDevProject(projectConfig)));
-    devfile.setProjects(projects);
+    devFile.setProjects(projects);
 
     // Manage commands
     List commands = new ArrayList<>();
     wsConfig.getCommands().forEach(command -> commands.add(commandImplToDevCommand(command)));
-    devfile.setCommands(commands);
+    devFile.setCommands(commands);
 
     // Manage tools
     List tools = new ArrayList<>();
@@ -82,8 +87,8 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) {
         }
       }
     }
-    devfile.setTools(tools);
-    return devfile;
+    devFile.setTools(tools);
+    return devFile;
   }
 
   public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile)
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileFormatException.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileFormatException.java
index d46af66d7c2..1fc4c6fbd0c 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileFormatException.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileFormatException.java
@@ -11,7 +11,7 @@
  */
 package org.eclipse.che.api.devfile.server;
 
-/** Thrown when Devfile schema or integrity validation is failed. */
+/** Thrown when devfile schema or integrity validation is failed. */
 public class DevfileFormatException extends Exception {
 
   public DevfileFormatException(String formatError) {
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java
index 3bf42621328..04531346160 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java
@@ -27,7 +27,7 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-/** Validates YAML content against given JSON schema. */
+/** Validates YAML devfile content against given JSON schema. */
 @Singleton
 public class DevfileSchemaValidator {
 
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
index 5196bd0b3d1..7e73de6e817 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
@@ -78,7 +78,7 @@ public DevfileService(
    */
   @GET
   @Produces(APPLICATION_JSON)
-  @ApiOperation(value = "Retrieves current version of Devfile JSON schema")
+  @ApiOperation(value = "Retrieves current version of devfile JSON schema")
   @ApiResponses({
     @ApiResponse(code = 200, message = "The schema successfully retrieved"),
     @ApiResponse(code = 500, message = "Internal server error occurred")
@@ -150,7 +150,7 @@ public Response createFromYaml(String data, @QueryParam("verbose") boolean verbo
   @Path("/{key:.*}")
   @Produces("text/yml")
   @ApiOperation(
-      value = "Generates the devfile from giben workspace",
+      value = "Generates the devfile from given workspace",
       notes =
           "This operation can be performed only by authorized user,"
               + "this user must be the owner of the exported workspace")

From cd9c8d276356519f79ea88b0cdddd21a845b9280 Mon Sep 17 00:00:00 2001
From: Max Shaposhnik 
Date: Mon, 3 Dec 2018 18:20:58 +0200
Subject: [PATCH 38/46] Code fixups

---
 .../api/devfile/server/DevfileConverter.java  | 22 +++++++++++++------
 .../devfile/server/DevfileSchemaProvider.java | 20 ++++++++---------
 .../api/devfile/server/DevfileService.java    |  2 ++
 .../devfile/server/DevfileConverterTest.java  |  2 +-
 4 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
index 8d971872f72..9332adf20f1 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
@@ -60,13 +60,15 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) {
     devFile.setProjects(projects);
 
     // Manage commands
+    Map toolsIdToName = parseTools(wsConfig);
     List commands = new ArrayList<>();
-    wsConfig.getCommands().forEach(command -> commands.add(commandImplToDevCommand(command)));
+    wsConfig
+        .getCommands()
+        .forEach(command -> commands.add(commandImplToDevCommand(command, toolsIdToName)));
     devFile.setCommands(commands);
 
     // Manage tools
     List tools = new ArrayList<>();
-    Map toolIdToName = parseTools(wsConfig);
     for (Map.Entry entry : wsConfig.getAttributes().entrySet()) {
       if (entry.getKey().equals(EDITOR_WORKSPACE_ATTRIBUTE_NAME)) {
         String editorId = entry.getValue();
@@ -74,7 +76,7 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) {
             new Tool()
                 .withType("cheEditor")
                 .withId(editorId)
-                .withName(toolIdToName.getOrDefault(editorId, editorId));
+                .withName(toolsIdToName.getOrDefault(editorId, editorId));
         tools.add(editorTool);
       } else if (entry.getKey().equals(PLUGINS_WORKSPACE_ATTRIBUTE_NAME)) {
         for (String pluginId : entry.getValue().split(",")) {
@@ -82,7 +84,7 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) {
               new Tool()
                   .withId(pluginId)
                   .withType("chePlugin")
-                  .withName(toolIdToName.getOrDefault(pluginId, pluginId));
+                  .withName(toolsIdToName.getOrDefault(pluginId, pluginId));
           tools.add(pluginTool);
         }
       }
@@ -115,8 +117,12 @@ public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile)
       }
       toolIdToNameMappingStringJoiner.add(tool.getId() + "=" + tool.getName());
     }
-    attributes.put(PLUGINS_WORKSPACE_ATTRIBUTE_NAME, pluginsStringJoiner.toString());
-    attributes.put(ALIASES_WORKSPACE_ATTRIBUTE_NAME, toolIdToNameMappingStringJoiner.toString());
+    if (pluginsStringJoiner.length() > 0) {
+      attributes.put(PLUGINS_WORKSPACE_ATTRIBUTE_NAME, pluginsStringJoiner.toString());
+    }
+    if (toolIdToNameMappingStringJoiner.length() > 0) {
+      attributes.put(ALIASES_WORKSPACE_ATTRIBUTE_NAME, toolIdToNameMappingStringJoiner.toString());
+    }
     config.setAttributes(attributes);
 
     // Manage commands
@@ -155,13 +161,15 @@ private List devCommandToCommandImpls(Devfile devFile, Command devC
     return commands;
   }
 
-  private Command commandImplToDevCommand(CommandImpl command) {
+  private Command commandImplToDevCommand(CommandImpl command, Map toolsIdToName) {
     Command devCommand = new Command().withName(command.getName());
     Action action = new Action().withCommand(command.getCommandLine()).withType(command.getType());
     String workingDir = command.getAttributes().get(WORKING_DIRECTORY_ATTRIBUTE);
     if (!isNullOrEmpty(workingDir)) {
       action.setWorkdir(workingDir);
     }
+    action.setTool(toolsIdToName.getOrDefault(command.getAttributes().get("pluginId"), ""));
+    devCommand.getActions().add(action);
     devCommand.setAttributes(command.getAttributes());
     // Remove internal attributes
     devCommand.getAttributes().remove(WORKING_DIRECTORY_ATTRIBUTE);
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java
index 22e0084f9dd..c290d940990 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java
@@ -11,17 +11,16 @@
  */
 package org.eclipse.che.api.devfile.server;
 
-import static java.lang.String.format;
 import static org.eclipse.che.api.devfile.server.Constants.SCHEMA_LOCATION;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.github.fge.jackson.JsonLoader;
+import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.lang.ref.SoftReference;
-import java.net.URL;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.util.stream.Collectors;
 import javax.inject.Singleton;
 
 /** Loads a schema content and stores it in soft reference. */
@@ -44,11 +43,12 @@ public JsonNode getJsoneNode() throws IOException {
   }
 
   private String loadFile() throws IOException {
-    URL schemaURL = getClass().getClassLoader().getResource(SCHEMA_LOCATION);
-    if (schemaURL != null) {
-      return new String(
-          Files.readAllBytes(Paths.get(schemaURL.getFile())), Charset.defaultCharset());
+    try (InputStream is = getClass().getClassLoader().getResourceAsStream(SCHEMA_LOCATION)) {
+      if (is != null) {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+        return reader.lines().collect(Collectors.joining(System.lineSeparator()));
+      }
+      return null;
     }
-    throw new IllegalStateException(format("Schema file %s cannot be found", SCHEMA_LOCATION));
   }
 }
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
index 7e73de6e817..c38f73fafc1 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
@@ -20,6 +20,7 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
@@ -47,6 +48,7 @@
 import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
 import org.eclipse.che.commons.env.EnvironmentContext;
 
+@Api(value = "/devfile", description = "Devfile REST API")
 @Path("/devfile")
 public class DevfileService extends Service {
 
diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileConverterTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileConverterTest.java
index fc56959d8de..4b07b27cbf7 100644
--- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileConverterTest.java
+++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileConverterTest.java
@@ -86,7 +86,7 @@ public void shouldBuildYamlDevFileFromWorkspaceConfig() throws Exception {
               .filter(command1 -> command1.getName().equals(command.getName().split(":")[0]))
               .findFirst()
               .get();
-      for (Action action : expectedCommand.getActions()) {
+      for (Action action : command.getActions()) {
         Action expectedAction =
             expectedCommand
                 .getActions()

From dbd754b9675569f04dc9a76ec6e7d09822fba243 Mon Sep 17 00:00:00 2001
From: Max Shaposhnik 
Date: Tue, 4 Dec 2018 18:52:36 +0200
Subject: [PATCH 39/46] Review fixes

---
 .../api/devfile/server/DevfileConverter.java  | 11 +++++++---
 .../api/devfile/server/DevfileService.java    |  8 +++++---
 .../server/WorkspaceExportException.java      | 20 +++++++++++++++++++
 .../devfile/server/DevfileConverterTest.java  | 15 ++++++++++++++
 4 files changed, 48 insertions(+), 6 deletions(-)
 create mode 100644 wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/WorkspaceExportException.java

diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
index 9332adf20f1..54d78b6004c 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
@@ -42,11 +42,13 @@
 /** Helps to convert devfile into workspace config and back. */
 public class DevfileConverter {
 
-  public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) {
+  public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) throws WorkspaceExportException {
 
     if (!isNullOrEmpty(wsConfig.getDefaultEnv()) || !wsConfig.getEnvironments().isEmpty()) {
-      //  throw new UnsupportedOperationException("Given workspace cannot be converted to devfile
-      // since it is contains environments.");
+      throw new WorkspaceExportException(
+          format(
+              "Workspace %s cannot be converted to devfile since it is contains environments (which have no equivalent in devfile model)",
+              wsConfig.getName()));
     }
 
     Devfile devFile =
@@ -114,6 +116,9 @@ public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile)
         attributes.put(EDITOR_WORKSPACE_ATTRIBUTE_NAME, tool.getId());
       } else if (tool.getType().equals("chePlugin")) {
         pluginsStringJoiner.add(tool.getId());
+      } else {
+        throw new DevfileFormatException(
+            format("Unsupported tool %s type provided: %s", tool.getName(), tool.getType()));
       }
       toolIdToNameMappingStringJoiner.add(tool.getId() + "=" + tool.getName());
     }
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
index c38f73fafc1..3bffe577a32 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
@@ -162,15 +162,17 @@ public Response createFromYaml(String data, @QueryParam("verbose") boolean verbo
     @ApiResponse(code = 500, message = "Internal server error occurred")
   })
   public Response createFromWorkspace(@PathParam("key") String key)
-      throws NotFoundException, ServerException, BadRequestException {
+      throws NotFoundException, ServerException, BadRequestException, ConflictException {
     validateKey(key);
     WorkspaceImpl workspace = workspaceManager.getWorkspace(key);
-    Devfile workspaceDevFile = devfileConverter.workspaceToDevFile(workspace.getConfig());
-    // Write object as YAML
     try {
+      Devfile workspaceDevFile = devfileConverter.workspaceToDevFile(workspace.getConfig());
+      // Write object as YAML
       return Response.ok().entity(objectMapper.writeValueAsString(workspaceDevFile)).build();
     } catch (JsonProcessingException e) {
       throw new ServerException(e.getMessage(), e);
+    } catch (WorkspaceExportException e) {
+      throw new ConflictException(e.getMessage());
     }
   }
 
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/WorkspaceExportException.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/WorkspaceExportException.java
new file mode 100644
index 00000000000..e030c1d3da2
--- /dev/null
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/WorkspaceExportException.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *   Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.devfile.server;
+
+/** Thrown when workspace can not be exported into devfile by some reason. */
+public class WorkspaceExportException extends Exception {
+
+  public WorkspaceExportException(String error) {
+    super(error);
+  }
+}
diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileConverterTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileConverterTest.java
index 4b07b27cbf7..e9a5f62760e 100644
--- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileConverterTest.java
+++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileConverterTest.java
@@ -21,6 +21,7 @@
 import org.eclipse.che.api.devfile.model.Devfile;
 import org.eclipse.che.api.devfile.model.Project;
 import org.eclipse.che.api.devfile.model.Tool;
+import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl;
 import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
 import org.eclipse.che.commons.json.JsonHelper;
 import org.testng.annotations.Test;
@@ -120,4 +121,18 @@ public void shouldBuildYamlDevFileFromWorkspaceConfig() throws Exception {
       assertEquals(tool.getType(), expectedTool.getType());
     }
   }
+
+  @Test(
+      expectedExceptions = WorkspaceExportException.class,
+      expectedExceptionsMessageRegExp =
+          "Workspace .* cannot be converted to devfile since it is contains environments \\(which have no equivalent in devfile model\\)")
+  public void shouldThrowExceptionWhenWorkspaceHasEnvironments() throws Exception {
+    String jsonContent =
+        Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_config.json"));
+    WorkspaceConfigImpl workspaceConfig =
+        JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null);
+    workspaceConfig.getEnvironments().put("env1", new EnvironmentImpl());
+
+    devfileConverter.workspaceToDevFile(workspaceConfig);
+  }
 }

From b0165f3015474cad8a829efd88ce83939f138667 Mon Sep 17 00:00:00 2001
From: Max Shaposhnik 
Date: Wed, 5 Dec 2018 13:49:44 +0200
Subject: [PATCH 40/46] Add permissions for devfile export method

---
 assembly/assembly-wsmaster-war/pom.xml        |   4 +
 .../che/api/deploy/WsMasterModule.java        |   1 +
 .../che-multiuser-permission-devfile/pom.xml  | 122 ++++++++++++++++++
 .../devfile/DevfilePermissionsFilter.java     |  74 +++++++++++
 .../devfile/DevfilePermissionsFilterTest.java | 116 +++++++++++++++++
 .../src/test/resources/logback-test.xml       |  26 ++++
 multiuser/permission/pom.xml                  |   1 +
 pom.xml                                       |   5 +
 8 files changed, 349 insertions(+)
 create mode 100644 multiuser/permission/che-multiuser-permission-devfile/pom.xml
 create mode 100644 multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/DevfilePermissionsFilter.java
 create mode 100644 multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permissions/devfile/DevfilePermissionsFilterTest.java
 create mode 100644 multiuser/permission/che-multiuser-permission-devfile/src/test/resources/logback-test.xml

diff --git a/assembly/assembly-wsmaster-war/pom.xml b/assembly/assembly-wsmaster-war/pom.xml
index 79cba4e135a..4badb716eb3 100644
--- a/assembly/assembly-wsmaster-war/pom.xml
+++ b/assembly/assembly-wsmaster-war/pom.xml
@@ -309,6 +309,10 @@
             org.eclipse.che.multiuser
             che-multiuser-machine-authentication
         
+        
+            org.eclipse.che.multiuser
+            che-multiuser-permission-devfile
+        
         
             org.eclipse.che.multiuser
             che-multiuser-permission-factory
diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java
index 63cd77266d0..529e5bc9fa8 100644
--- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java
+++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java
@@ -368,6 +368,7 @@ private void configureMultiUserMode(
     bind(org.eclipse.che.multiuser.permission.logger.LoggerServicePermissionsFilter.class);
 
     bind(org.eclipse.che.multiuser.permission.factory.FactoryPermissionsFilter.class);
+    bind(org.eclipse.che.multiuser.permission.devfile.DevfilePermissionsFilter.class);
     bind(
         org.eclipse.che.multiuser.permission.installer.InstallerRegistryServicePermissionsFilter
             .class);
diff --git a/multiuser/permission/che-multiuser-permission-devfile/pom.xml b/multiuser/permission/che-multiuser-permission-devfile/pom.xml
new file mode 100644
index 00000000000..a311bcaae81
--- /dev/null
+++ b/multiuser/permission/che-multiuser-permission-devfile/pom.xml
@@ -0,0 +1,122 @@
+
+
+
+    4.0.0
+    
+        che-multiuser-permission
+        org.eclipse.che.multiuser
+        6.15.0-SNAPSHOT
+    
+    che-multiuser-permission-devfile
+    Che Multiuser :: Devfile Permissions
+    
+        
+            javax.inject
+            javax.inject
+        
+        
+            javax.ws.rs
+            javax.ws.rs-api
+        
+        
+            org.eclipse.che.core
+            che-core-api-core
+        
+        
+            org.eclipse.che.core
+            che-core-api-devfile
+        
+        
+            org.eclipse.che.core
+            che-core-api-workspace
+        
+        
+            org.eclipse.che.core
+            che-core-commons-test
+        
+        
+            org.eclipse.che.multiuser
+            che-multiuser-api-permission
+        
+        
+            org.eclipse.che.multiuser
+            che-multiuser-permission-workspace
+        
+        
+            org.everrest
+            everrest-core
+        
+        
+            ch.qos.logback
+            logback-classic
+            test
+        
+        
+            com.jayway.restassured
+            rest-assured
+            test
+        
+        
+            org.eclipse.che.core
+            che-core-api-dto
+            test
+        
+        
+            org.eclipse.che.core
+            che-core-api-factory-shared
+            test
+        
+        
+            org.everrest
+            everrest-assured
+            test
+        
+        
+            org.mockito
+            mockito-core
+            test
+        
+        
+            org.mockito
+            mockito-testng
+            test
+        
+        
+            org.testng
+            testng
+            test
+        
+    
+    
+        
+            
+                org.apache.maven.plugins
+                maven-dependency-plugin
+                
+                    
+                    
+                        analyze
+                        
+                            
+                                org.eclipse.che.multiuser:che-multiuser-api-permission
+                                org.eclipse.che.core:che-core-api-devfile
+                            
+                        
+                    
+                
+            
+        
+    
+
diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/DevfilePermissionsFilter.java b/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/DevfilePermissionsFilter.java
new file mode 100644
index 00000000000..17e55e9ca06
--- /dev/null
+++ b/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/DevfilePermissionsFilter.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *   Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.multiuser.permission.devfile;
+
+import javax.inject.Inject;
+import javax.ws.rs.Path;
+import org.eclipse.che.api.core.ForbiddenException;
+import org.eclipse.che.api.core.NotFoundException;
+import org.eclipse.che.api.core.ServerException;
+import org.eclipse.che.api.devfile.server.DevfileService;
+import org.eclipse.che.api.workspace.server.WorkspaceManager;
+import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
+import org.eclipse.che.commons.env.EnvironmentContext;
+import org.eclipse.che.commons.subject.Subject;
+import org.eclipse.che.everrest.CheMethodInvokerFilter;
+import org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain;
+import org.everrest.core.Filter;
+import org.everrest.core.resource.GenericResourceMethod;
+
+/** Restricts access to methods of {@link DevfileService} by users' permissions. */
+@Filter
+@Path("/devfile{path:(/.*)?}")
+public class DevfilePermissionsFilter extends CheMethodInvokerFilter {
+
+  private final WorkspaceManager workspaceManager;
+
+  @Inject
+  public DevfilePermissionsFilter(WorkspaceManager workspaceManager) {
+    this.workspaceManager = workspaceManager;
+  }
+
+  @Override
+  protected void filter(GenericResourceMethod genericResourceMethod, Object[] arguments)
+      throws ForbiddenException, NotFoundException, ServerException {
+    final String methodName = genericResourceMethod.getMethod().getName();
+    switch (methodName) {
+        // public methods
+      case "getSchema":
+      case "createFromYaml":
+        return;
+      case "createFromWorkspace":
+        {
+          // check user has reading rights
+          String wsKey = ((String) arguments[0]);
+          checkPermissionsWithCompositeKey(wsKey);
+          return;
+        }
+      default:
+        throw new ForbiddenException("The user does not have permission to perform this operation");
+    }
+  }
+
+  private void checkPermissionsWithCompositeKey(String key)
+      throws ForbiddenException, NotFoundException, ServerException {
+    final Subject currentSubject = EnvironmentContext.getCurrent().getSubject();
+    if (!key.contains(":") && !key.contains("/")) {
+      // key is id
+      currentSubject.checkPermission(WorkspaceDomain.DOMAIN_ID, key, WorkspaceDomain.READ);
+    } else {
+      final WorkspaceImpl workspace = workspaceManager.getWorkspace(key);
+      currentSubject.checkPermission(
+          WorkspaceDomain.DOMAIN_ID, workspace.getId(), WorkspaceDomain.READ);
+    }
+  }
+}
diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permissions/devfile/DevfilePermissionsFilterTest.java b/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permissions/devfile/DevfilePermissionsFilterTest.java
new file mode 100644
index 00000000000..88f841e4400
--- /dev/null
+++ b/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permissions/devfile/DevfilePermissionsFilterTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *   Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.multiuser.permissions.devfile;
+
+import static com.jayway.restassured.RestAssured.given;
+import static org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain.DOMAIN_ID;
+import static org.eclipse.che.multiuser.permission.workspace.server.WorkspaceDomain.READ;
+import static org.everrest.assured.JettyHttpServer.ADMIN_USER_NAME;
+import static org.everrest.assured.JettyHttpServer.ADMIN_USER_PASSWORD;
+import static org.everrest.assured.JettyHttpServer.SECURE_PATH;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+
+import com.jayway.restassured.response.Response;
+import org.eclipse.che.api.core.ForbiddenException;
+import org.eclipse.che.api.devfile.server.DevfileService;
+import org.eclipse.che.api.workspace.server.WorkspaceManager;
+import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
+import org.eclipse.che.commons.env.EnvironmentContext;
+import org.eclipse.che.commons.subject.Subject;
+import org.eclipse.che.multiuser.permission.devfile.DevfilePermissionsFilter;
+import org.everrest.assured.EverrestJetty;
+import org.everrest.core.Filter;
+import org.everrest.core.GenericContainerRequest;
+import org.everrest.core.RequestFilter;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.testng.MockitoTestNGListener;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+
+@Listeners(value = {EverrestJetty.class, MockitoTestNGListener.class})
+public class DevfilePermissionsFilterTest {
+
+  @SuppressWarnings("unused")
+  private static final EnvironmentFilter FILTER = new EnvironmentFilter();
+
+  @Mock private static Subject subject;
+  @Mock private WorkspaceManager workspaceManager;
+  @Mock private DevfileService service;
+
+  @SuppressWarnings("unused")
+  @InjectMocks
+  private DevfilePermissionsFilter permissionsFilter;
+
+  @Test
+  public void shouldCheckPermissionsOnExportingWorkspaceById() throws Exception {
+    final String wsId = "workspace123";
+    final Response response =
+        given()
+            .auth()
+            .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
+            .when()
+            .get(SECURE_PATH + "/devfile/" + wsId);
+
+    assertEquals(response.getStatusCode(), 204);
+    verify(subject).checkPermission(DOMAIN_ID, wsId, READ);
+    verify(service).createFromWorkspace((eq(wsId)));
+  }
+
+  @Test
+  public void shouldCheckPermissionsOnExportingWorkspaceByKey() throws Exception {
+    final String key = "namespace/ws_name";
+    final String wsId = "workspace123";
+    WorkspaceImpl workspace = new WorkspaceImpl();
+    workspace.setId(wsId);
+    when(workspaceManager.getWorkspace(eq(key))).thenReturn(workspace);
+    final Response response =
+        given()
+            .auth()
+            .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
+            .when()
+            .get(SECURE_PATH + "/devfile/" + key);
+
+    assertEquals(response.getStatusCode(), 204);
+    verify(subject).checkPermission(DOMAIN_ID, wsId, READ);
+    verify(service).createFromWorkspace((eq(key)));
+  }
+
+  @Test
+  public void shouldReturnForbiddenWhenUserDoesHavePermissionsToReadWorkspaceOnGettingFactoryJson()
+      throws Exception {
+    doThrow(new ForbiddenException("User in not authorized"))
+        .when(subject)
+        .checkPermission(anyString(), anyString(), anyString());
+
+    final Response response =
+        given()
+            .auth()
+            .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
+            .when()
+            .get(SECURE_PATH + "/devfile/workspace123");
+
+    assertEquals(response.getStatusCode(), 403);
+  }
+
+  @Filter
+  public static class EnvironmentFilter implements RequestFilter {
+    public void doFilter(GenericContainerRequest request) {
+      EnvironmentContext.getCurrent().setSubject(subject);
+    }
+  }
+}
diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/test/resources/logback-test.xml b/multiuser/permission/che-multiuser-permission-devfile/src/test/resources/logback-test.xml
new file mode 100644
index 00000000000..e7bf50602e3
--- /dev/null
+++ b/multiuser/permission/che-multiuser-permission-devfile/src/test/resources/logback-test.xml
@@ -0,0 +1,26 @@
+
+
+
+
+    
+        
+            %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n
+        
+    
+    
+        
+    
+
+
diff --git a/multiuser/permission/pom.xml b/multiuser/permission/pom.xml
index a1acc21bd5b..3514c3c38f1 100644
--- a/multiuser/permission/pom.xml
+++ b/multiuser/permission/pom.xml
@@ -25,6 +25,7 @@
     Che Multiuser :: Permissions Parent
     
         che-multiuser-permission-user
+        che-multiuser-permission-devfile
         che-multiuser-permission-workspace
         che-multiuser-permission-workspace-activity
         che-multiuser-permission-factory
diff --git a/pom.xml b/pom.xml
index 28b0058d19b..fadadb59ae5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1066,6 +1066,11 @@
                 ${che.version}
                 sources
             
+            
+                org.eclipse.che.multiuser
+                che-multiuser-permission-devfile
+                ${che.version}
+            
             
                 org.eclipse.che.multiuser
                 che-multiuser-permission-factory

From 1cc89bf13bc62ae628dcb27592787fd2b8801f1b Mon Sep 17 00:00:00 2001
From: Max Shaposhnik 
Date: Wed, 5 Dec 2018 13:54:38 +0200
Subject: [PATCH 41/46] Fixup

---
 .../permission/devfile/DevfilePermissionsFilter.java         | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/DevfilePermissionsFilter.java b/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/DevfilePermissionsFilter.java
index 17e55e9ca06..3600f4f0be8 100644
--- a/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/DevfilePermissionsFilter.java
+++ b/multiuser/permission/che-multiuser-permission-devfile/src/main/java/org/eclipse/che/multiuser/permission/devfile/DevfilePermissionsFilter.java
@@ -26,7 +26,7 @@
 import org.everrest.core.Filter;
 import org.everrest.core.resource.GenericResourceMethod;
 
-/** Restricts access to methods of {@link DevfileService} by users' permissions. */
+/** Restricts access to methods of {@link DevfileService} by user's permissions. */
 @Filter
 @Path("/devfile{path:(/.*)?}")
 public class DevfilePermissionsFilter extends CheMethodInvokerFilter {
@@ -50,8 +50,7 @@ protected void filter(GenericResourceMethod genericResourceMethod, Object[] argu
       case "createFromWorkspace":
         {
           // check user has reading rights
-          String wsKey = ((String) arguments[0]);
-          checkPermissionsWithCompositeKey(wsKey);
+          checkPermissionsWithCompositeKey((String) arguments[0]);
           return;
         }
       default:

From 1d7f5c4f50627f7293be38c2cdf11e3a2b634169 Mon Sep 17 00:00:00 2001
From: Max Shaposhnik 
Date: Wed, 5 Dec 2018 14:41:40 +0200
Subject: [PATCH 42/46] Minor fixups

---
 .../che/api/devfile/server/Constants.java     |  4 ---
 .../api/devfile/server/DevfileConverter.java  | 27 ++++++++++---------
 .../server/DevfileSchemaValidator.java        |  5 ++--
 .../api/devfile/server/DevfileService.java    | 23 ++++++++++++++--
 4 files changed, 38 insertions(+), 21 deletions(-)

diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java
index 9dd302f8319..58e83df0deb 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/Constants.java
@@ -17,10 +17,6 @@ public class Constants {
 
   public static final String CURRENT_SPEC_VERSION = "0.0.1";
 
-  public static final String EDITOR_WORKSPACE_ATTRIBUTE_NAME = "editor";
-
-  public static final String PLUGINS_WORKSPACE_ATTRIBUTE_NAME = "plugins";
-
   /**
    * Workspace attribute which contains comma-separated list of mappings of tool id to its name
    * Example value:
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
index 54d78b6004c..a8627a99082 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileConverter.java
@@ -17,8 +17,8 @@
 import static org.eclipse.che.api.core.model.workspace.config.Command.WORKING_DIRECTORY_ATTRIBUTE;
 import static org.eclipse.che.api.devfile.server.Constants.ALIASES_WORKSPACE_ATTRIBUTE_NAME;
 import static org.eclipse.che.api.devfile.server.Constants.CURRENT_SPEC_VERSION;
-import static org.eclipse.che.api.devfile.server.Constants.EDITOR_WORKSPACE_ATTRIBUTE_NAME;
-import static org.eclipse.che.api.devfile.server.Constants.PLUGINS_WORKSPACE_ATTRIBUTE_NAME;
+import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_TOOLING_EDITOR_ATTRIBUTE;
+import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -72,7 +72,7 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) throws Workspace
     // Manage tools
     List tools = new ArrayList<>();
     for (Map.Entry entry : wsConfig.getAttributes().entrySet()) {
-      if (entry.getKey().equals(EDITOR_WORKSPACE_ATTRIBUTE_NAME)) {
+      if (entry.getKey().equals(WORKSPACE_TOOLING_EDITOR_ATTRIBUTE)) {
         String editorId = entry.getValue();
         Tool editorTool =
             new Tool()
@@ -80,7 +80,7 @@ public Devfile workspaceToDevFile(WorkspaceConfigImpl wsConfig) throws Workspace
                 .withId(editorId)
                 .withName(toolsIdToName.getOrDefault(editorId, editorId));
         tools.add(editorTool);
-      } else if (entry.getKey().equals(PLUGINS_WORKSPACE_ATTRIBUTE_NAME)) {
+      } else if (entry.getKey().equals(WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE)) {
         for (String pluginId : entry.getValue().split(",")) {
           Tool pluginTool =
               new Tool()
@@ -112,18 +112,21 @@ public WorkspaceConfigImpl devFileToWorkspaceConfig(Devfile devFile)
     StringJoiner pluginsStringJoiner = new StringJoiner(",");
     StringJoiner toolIdToNameMappingStringJoiner = new StringJoiner(",");
     for (Tool tool : devFile.getTools()) {
-      if (tool.getType().equals("cheEditor")) {
-        attributes.put(EDITOR_WORKSPACE_ATTRIBUTE_NAME, tool.getId());
-      } else if (tool.getType().equals("chePlugin")) {
-        pluginsStringJoiner.add(tool.getId());
-      } else {
-        throw new DevfileFormatException(
-            format("Unsupported tool %s type provided: %s", tool.getName(), tool.getType()));
+      switch (tool.getType()) {
+        case "cheEditor":
+          attributes.put(WORKSPACE_TOOLING_EDITOR_ATTRIBUTE, tool.getId());
+          break;
+        case "chePlugin":
+          pluginsStringJoiner.add(tool.getId());
+          break;
+        default:
+          throw new DevfileFormatException(
+              format("Unsupported tool %s type provided: %s", tool.getName(), tool.getType()));
       }
       toolIdToNameMappingStringJoiner.add(tool.getId() + "=" + tool.getName());
     }
     if (pluginsStringJoiner.length() > 0) {
-      attributes.put(PLUGINS_WORKSPACE_ATTRIBUTE_NAME, pluginsStringJoiner.toString());
+      attributes.put(WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE, pluginsStringJoiner.toString());
     }
     if (toolIdToNameMappingStringJoiner.length() > 0) {
       attributes.put(ALIASES_WORKSPACE_ATTRIBUTE_NAME, toolIdToNameMappingStringJoiner.toString());
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java
index 04531346160..00b827c3e46 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java
@@ -36,14 +36,13 @@ public class DevfileSchemaValidator {
   private DevfileSchemaProvider schemaProvider;
 
   @Inject
-  public DevfileSchemaValidator(DevfileSchemaProvider schemaProvider) throws IOException {
+  DevfileSchemaValidator(DevfileSchemaProvider schemaProvider) {
     this.schemaProvider = schemaProvider;
     this.validator = JsonSchemaFactory.byDefault().getValidator();
     this.yamlReader = new ObjectMapper(new YAMLFactory());
   }
 
-  public JsonNode validateBySchema(String yamlContent, boolean verbose)
-      throws DevfileFormatException {
+  JsonNode validateBySchema(String yamlContent, boolean verbose) throws DevfileFormatException {
     ProcessingReport report;
     JsonNode data;
     try {
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
index 3bffe577a32..705ce65bdcb 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
@@ -22,11 +22,15 @@
 import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
 import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Example;
+import io.swagger.annotations.ExampleProperty;
 import java.io.IOException;
 import javax.inject.Inject;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
@@ -118,7 +122,12 @@ public Response getSchema() throws ServerException {
     @ApiResponse(code = 403, message = "The user does not have access to create a new workspace"),
     @ApiResponse(code = 500, message = "Internal server error occurred")
   })
-  public Response createFromYaml(String data, @QueryParam("verbose") boolean verbose)
+  public Response createFromYaml(
+      String data,
+      @ApiParam(value = "Provide extended validation messages")
+          @DefaultValue("false")
+          @QueryParam("verbose")
+          boolean verbose)
       throws ServerException, ConflictException, NotFoundException, ValidationException,
           BadRequestException {
 
@@ -161,7 +170,17 @@ public Response createFromYaml(String data, @QueryParam("verbose") boolean verbo
     @ApiResponse(code = 403, message = "The user does not have access to create a new workspace"),
     @ApiResponse(code = 500, message = "Internal server error occurred")
   })
-  public Response createFromWorkspace(@PathParam("key") String key)
+  public Response createFromWorkspace(
+      @ApiParam(
+              value = "Composite key",
+              examples =
+                  @Example({
+                    @ExampleProperty("workspace12345678"),
+                    @ExampleProperty("namespace/workspace_name"),
+                    @ExampleProperty("namespace_part_1/namespace_part_2/workspace_name")
+                  }))
+          @PathParam("key")
+          String key)
       throws NotFoundException, ServerException, BadRequestException, ConflictException {
     validateKey(key);
     WorkspaceImpl workspace = workspaceManager.getWorkspace(key);

From ff05d07b7509d08ba3f08c4edc0dbd15a1771ae8 Mon Sep 17 00:00:00 2001
From: Max Shaposhnik 
Date: Thu, 6 Dec 2018 10:12:35 +0200
Subject: [PATCH 43/46] Upgrade version

---
 multiuser/permission/che-multiuser-permission-devfile/pom.xml | 2 +-
 wsmaster/che-core-api-devfile/pom.xml                         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/multiuser/permission/che-multiuser-permission-devfile/pom.xml b/multiuser/permission/che-multiuser-permission-devfile/pom.xml
index a311bcaae81..446c0ffbc04 100644
--- a/multiuser/permission/che-multiuser-permission-devfile/pom.xml
+++ b/multiuser/permission/che-multiuser-permission-devfile/pom.xml
@@ -17,7 +17,7 @@
     
         che-multiuser-permission
         org.eclipse.che.multiuser
-        6.15.0-SNAPSHOT
+        6.16.0-SNAPSHOT
     
     che-multiuser-permission-devfile
     Che Multiuser :: Devfile Permissions
diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml
index f59002678c1..b3ded9e2453 100644
--- a/wsmaster/che-core-api-devfile/pom.xml
+++ b/wsmaster/che-core-api-devfile/pom.xml
@@ -17,7 +17,7 @@
     
         che-master-parent
         org.eclipse.che.core
-        6.15.0-SNAPSHOT
+        6.16.0-SNAPSHOT
     
     che-core-api-devfile
     jar

From 597bb7702c45ad9180f6bbb2fdff7fdf99509629 Mon Sep 17 00:00:00 2001
From: Max Shaposhnik 
Date: Thu, 6 Dec 2018 10:19:09 +0200
Subject: [PATCH 44/46] Rename test method

---
 .../permissions/devfile/DevfilePermissionsFilterTest.java       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permissions/devfile/DevfilePermissionsFilterTest.java b/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permissions/devfile/DevfilePermissionsFilterTest.java
index 88f841e4400..09048af0e01 100644
--- a/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permissions/devfile/DevfilePermissionsFilterTest.java
+++ b/multiuser/permission/che-multiuser-permission-devfile/src/test/java/org/eclipse/che/multiuser/permissions/devfile/DevfilePermissionsFilterTest.java
@@ -91,7 +91,7 @@ public void shouldCheckPermissionsOnExportingWorkspaceByKey() throws Exception {
   }
 
   @Test
-  public void shouldReturnForbiddenWhenUserDoesHavePermissionsToReadWorkspaceOnGettingFactoryJson()
+  public void shouldReturnForbiddenWhenUserDoesHavePermissionsToExportWorkspaceToDevfile()
       throws Exception {
     doThrow(new ForbiddenException("User in not authorized"))
         .when(subject)

From a1bbe9fe11188e72fda208381684195c251c22bb Mon Sep 17 00:00:00 2001
From: Max Shaposhnik 
Date: Thu, 6 Dec 2018 12:07:40 +0200
Subject: [PATCH 45/46] Use IOutil to read file

---
 wsmaster/che-core-api-devfile/pom.xml              |  4 ++++
 .../api/devfile/server/DevfileSchemaProvider.java  | 14 +++++---------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/wsmaster/che-core-api-devfile/pom.xml b/wsmaster/che-core-api-devfile/pom.xml
index b3ded9e2453..cea2e310c91 100644
--- a/wsmaster/che-core-api-devfile/pom.xml
+++ b/wsmaster/che-core-api-devfile/pom.xml
@@ -79,6 +79,10 @@
             org.eclipse.che.core
             che-core-api-workspace-shared
         
+        
+            org.eclipse.che.core
+            che-core-commons-lang
+        
         
             javax.ws.rs
             javax.ws.rs-api
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java
index c290d940990..43c62053fbe 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java
@@ -12,15 +12,13 @@
 package org.eclipse.che.api.devfile.server;
 
 import static org.eclipse.che.api.devfile.server.Constants.SCHEMA_LOCATION;
+import static org.eclipse.che.commons.lang.IoUtil.readAndCloseQuietly;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.github.fge.jackson.JsonLoader;
-import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.lang.ref.SoftReference;
-import java.util.stream.Collectors;
 import javax.inject.Singleton;
 
 /** Loads a schema content and stores it in soft reference. */
@@ -43,12 +41,10 @@ public JsonNode getJsoneNode() throws IOException {
   }
 
   private String loadFile() throws IOException {
-    try (InputStream is = getClass().getClassLoader().getResourceAsStream(SCHEMA_LOCATION)) {
-      if (is != null) {
-        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
-        return reader.lines().collect(Collectors.joining(System.lineSeparator()));
-      }
-      return null;
+    InputStream is = getClass().getClassLoader().getResourceAsStream(SCHEMA_LOCATION);
+    if (is != null) {
+      return readAndCloseQuietly(is);
     }
+    return null;
   }
 }

From 33116b01fd906872181c9c4c81f5dd602d0a39c1 Mon Sep 17 00:00:00 2001
From: Max Shaposhnik 
Date: Thu, 6 Dec 2018 12:20:30 +0200
Subject: [PATCH 46/46] Use IOutil to read file

---
 .../che/api/devfile/server/DevfileSchemaProvider.java     | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java
index 43c62053fbe..22e29114e01 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java
@@ -12,12 +12,12 @@
 package org.eclipse.che.api.devfile.server;
 
 import static org.eclipse.che.api.devfile.server.Constants.SCHEMA_LOCATION;
+import static org.eclipse.che.commons.lang.IoUtil.getResource;
 import static org.eclipse.che.commons.lang.IoUtil.readAndCloseQuietly;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.github.fge.jackson.JsonLoader;
 import java.io.IOException;
-import java.io.InputStream;
 import java.lang.ref.SoftReference;
 import javax.inject.Singleton;
 
@@ -41,10 +41,6 @@ public JsonNode getJsoneNode() throws IOException {
   }
 
   private String loadFile() throws IOException {
-    InputStream is = getClass().getClassLoader().getResourceAsStream(SCHEMA_LOCATION);
-    if (is != null) {
-      return readAndCloseQuietly(is);
-    }
-    return null;
+    return readAndCloseQuietly(getResource(SCHEMA_LOCATION));
   }
 }