From 422ca27d17aa8cc3092645dc80014204d8aec227 Mon Sep 17 00:00:00 2001 From: Angel Misevski Date: Tue, 21 May 2019 12:06:48 -0400 Subject: [PATCH] Make plugin references without version use 'latest' implicitly Changes necessary to make plugin references without a version specified, e.g. eclipse/che-theia to parse as 'eclipse/che-theia/latest' by default. As a side effect, this commit disables: - Validation of plugin references with a custom registry. This allows using direct links to meta.yamls (no need to have a path ending in publisher/name/version) but also works by arbitrarily splitting the URL into a 'registry' and 'id' - Devfile aliases and similar features are disabled for plugins from custom registries - Some tests that depend on having a custom registry specified are disabled until issue https://github.com/eclipse/che/issues/13385 is resolved. Signed-off-by: Angel Misevski --- .../src/main/resources/schema/devfile.json | 4 +- .../convert/DefaultEditorProvisionerTest.java | 2 +- ...EditorComponentToWorkspaceApplierTest.java | 2 +- ...PluginComponentToWorkspaceApplierTest.java | 2 +- .../plugin/PluginProvisionerTest.java | 2 +- .../validator/DevfileSchemaValidatorTest.java | 9 +- .../server/wsplugins/PluginFQNParser.java | 59 ++++-- .../server/wsplugins/PluginFQNParserTest.java | 180 +++++++++--------- 8 files changed, 140 insertions(+), 120 deletions(-) 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 e5dbfe3c026..86e50b2ea70 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 @@ -171,8 +171,8 @@ "alias": {}, "id": { "type": "string", - "description": "Describes the component id. It has the following format: [{REGISTRY_URL}/]{plugin/editor PUBLISHER}/{plugin/editor NAME}/{plugin/editor VERSION}, where {REGISTRY_URL}/ is an optional part.", - "pattern": "^((https?://)[a-zA-Z0-9_\\-./]+/)?[a-z0-9_\\-.]+/[a-z0-9_\\-.]+/[a-z0-9_\\-.]+$", + "description": "Describes the component id. It has the following format: [{REGISTRY_URL}/]{plugin/editor PUBLISHER}/{plugin/editor NAME}/{plugin/editor VERSION}, where {REGISTRY_URL}/ is an optional part. If /{VERSION} is omitted, 'latest' is implicitly applied.", + "pattern": "^((https?://)[a-zA-Z0-9_\\-./]+/)?[a-z0-9_\\-.]+/[a-z0-9_\\-.]+(/[a-z0-9_\\-.]+)?$", "examples": [ "eclipse/maven-jdk8/1.0.0", "https://che-plugin-registry.openshift.io/eclipse/maven-jdk8/1.0.0" diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/DefaultEditorProvisionerTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/DefaultEditorProvisionerTest.java index c2d21e270f7..980e169eb9c 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/DefaultEditorProvisionerTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/DefaultEditorProvisionerTest.java @@ -108,7 +108,7 @@ public void shouldProvisionDefaultPluginsIfTheyAreNotSpecifiedAndDefaultEditorIs assertTrue(components.contains(new ComponentImpl(PLUGIN_COMPONENT_TYPE, TERMINAL_PLUGIN_REF))); } - @Test + @Test(enabled = false) // Issue: https://github.com/eclipse/che/issues/13385 public void shouldProvisionDefaultPluginsIfTheyAreNotSpecifiedAndDefaultEditorFromCustomRegistryIsConfigured() throws DevfileException { diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/editor/EditorComponentToWorkspaceApplierTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/editor/EditorComponentToWorkspaceApplierTest.java index dcc2ac3c80b..b2e403243d1 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/editor/EditorComponentToWorkspaceApplierTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/editor/EditorComponentToWorkspaceApplierTest.java @@ -88,7 +88,7 @@ public void shouldProvisionPluginCommandAttributesDuringCheEditorComponentApplyi "eclipse/super-editor/0.0.1"); } - @Test + @Test(enabled = false) // Issue: https://github.com/eclipse/che/issues/13385 public void shouldProvisionPluginCommandAttributeWhenIdIsURLToCustomPluginRegistry() throws DevfileException { // given diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/plugin/PluginComponentToWorkspaceApplierTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/plugin/PluginComponentToWorkspaceApplierTest.java index 73fbc0a2444..85e6533a082 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/plugin/PluginComponentToWorkspaceApplierTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/plugin/PluginComponentToWorkspaceApplierTest.java @@ -104,7 +104,7 @@ public void shouldProvisionPluginCommandAttributesDuringChePluginComponentApplyi "eclipse/super-plugin/0.0.1"); } - @Test + @Test(enabled = false) // Issue: https://github.com/eclipse/che/issues/13385 public void shouldProvisionPluginCommandAttributeWhenIdIsURLToCustomPluginRegistry() throws DevfileException { // given diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/plugin/PluginProvisionerTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/plugin/PluginProvisionerTest.java index 6a7d2793da4..99935e7ed36 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/plugin/PluginProvisionerTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/convert/component/plugin/PluginProvisionerTest.java @@ -46,7 +46,7 @@ public void shouldProvisionChePluginComponent() throws WorkspaceExportException .getAttributes() .put( WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE, - "eclipse/super-plugin/0.0.1,https://localhost:8080/publisher1/custom-plugin/v1"); + "eclipse/super-plugin/0.0.1,publisher1/custom-plugin/v1"); workspaceConfig .getAttributes() .put( diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/validator/DevfileSchemaValidatorTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/validator/DevfileSchemaValidatorTest.java index 88ed0dd14d1..6f88fb603c9 100644 --- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/validator/DevfileSchemaValidatorTest.java +++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/validator/DevfileSchemaValidatorTest.java @@ -60,7 +60,8 @@ public Object[][] validDevfiles() { {"dockerimage_component/devfile_dockerimage_component.yaml"}, {"dockerimage_component/devfile_dockerimage_component_without_entry_point.yaml"}, {"editor_plugin_component/devfile_editor_component_with_custom_registry.yaml"}, - {"editor_plugin_component/devfile_editor_plugins_components_with_memory_limit.yaml"} + {"editor_plugin_component/devfile_editor_plugins_components_with_memory_limit.yaml"}, + {"editor_plugin_component/devfile_editor_component_without_version.yaml"}, }; } @@ -134,17 +135,13 @@ public Object[][] invalidDevfiles() { "editor_plugin_component/devfile_editor_component_with_indistinctive_field_reference.yaml", "(/components/0/reference):The object must not have a property whose name is \"reference\"." }, - { - "editor_plugin_component/devfile_editor_component_without_version.yaml", - "(/components/0/id):The string value must match the pattern \"^((https?://)[a-zA-Z0-9_\\-./]+/)?[a-z0-9_\\-.]+/[a-z0-9_\\-.]+/[a-z0-9_\\-.]+$\"." - }, { "editor_plugin_component/devfile_editor_plugins_components_with_invalid_memory_limit.yaml", "(/components/0/memoryLimit):The value must be of string type, but actual type is integer." }, { "editor_plugin_component/devfile_editor_component_with_multiple_colons_in_id.yaml", - "(/components/0/id):The string value must match the pattern \"^((https?://)[a-zA-Z0-9_\\-./]+/)?[a-z0-9_\\-.]+/[a-z0-9_\\-.]+/[a-z0-9_\\-.]+$\"." + "(/components/0/id):The string value must match the pattern \"^((https?://)[a-zA-Z0-9_\\-./]+/)?[a-z0-9_\\-.]+/[a-z0-9_\\-.]+(/[a-z0-9_\\-.]+)?$\"." }, // kubernetes/openshift component model testing { diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/wsplugins/PluginFQNParser.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/wsplugins/PluginFQNParser.java index bff4be959a3..02ea4695d82 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/wsplugins/PluginFQNParser.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/wsplugins/PluginFQNParser.java @@ -42,8 +42,11 @@ public class PluginFQNParser { private static final String INCORRECT_PLUGIN_FORMAT_TEMPLATE = - "Plugin '%s' has incorrect format. Should be: 'registryURL/publisher/name/version' or 'publisher/name/version'"; - private static final String REGISTRY_PATTERN = "https?://[-./\\w]+(:[0-9]+)?(/[-./\\w]+)?"; + "Plugin '%s' has incorrect format. Should be: 'registryURL/path', 'publisher/name/version', or 'publisher/name'"; + + // First potential format: 'publisher/name/version', where 'version' is optional. No alternate + // registry + // is permitted here. private static final String PUBLISHER_PATTERN = "[-a-z0-9]+"; private static final String NAME_PATTERN = "[-a-z0-9]+"; private static final String VERSION_PATTERN = "[-.a-z0-9]+"; @@ -52,11 +55,18 @@ public class PluginFQNParser { + PUBLISHER_PATTERN + ")/(?" + NAME_PATTERN - + ")/(?" + + ")(:?/(?" + VERSION_PATTERN - + ")"; - private static final Pattern PLUGIN_PATTERN = - Pattern.compile("((?" + REGISTRY_PATTERN + ")/)?(?" + ID_PATTERN + ")"); + + "))?"; + private static final Pattern PLUGIN_PATTERN = Pattern.compile("(?" + ID_PATTERN + ")"); + private static final String LATEST_VERSION = "latest"; + + // Second potential format: 'registryURL/identifier'. We do not extract publisher, name, and + // version here. + private static final String REGISTRY_PATTERN = "https?://[-./\\w]+(:[0-9]+)?(/[-./\\w]+)?"; + private static final String REGISTRY_ID_PATTERN = "[-_.A-Za-z0-9]+"; + private static final Pattern PLUGIN_WITH_REGISTRY_PATTERN = + Pattern.compile("(?" + REGISTRY_PATTERN + "/)(?" + REGISTRY_ID_PATTERN + ")/?"); /** * Parses a workspace attributes map into a collection of {@link PluginFQN}. @@ -115,23 +125,28 @@ private Collection parsePluginFQNs(String attribute) throws Infrastru } public ExtendedPluginFQN parsePluginFQN(String plugin) throws InfrastructureException { - String registry; - String id; - String publisher; - String name; - String version; - URI registryURI = null; + // Check if plugin matches default format: 'publisher/name/version' or 'publisher/name' Matcher matcher = PLUGIN_PATTERN.matcher(plugin); if (matcher.matches()) { - registry = matcher.group("registry"); - id = matcher.group("id"); - publisher = matcher.group("publisher"); - name = matcher.group("name"); - version = matcher.group("version"); - } else { - throw new InfrastructureException(format(INCORRECT_PLUGIN_FORMAT_TEMPLATE, plugin)); + String id = matcher.group("id"); + String publisher = matcher.group("publisher"); + String name = matcher.group("name"); + String version = matcher.group("version"); + if (isNullOrEmpty(version)) { + version = LATEST_VERSION; + id = String.format("%s/%s", id, version); + } + return new ExtendedPluginFQN(null, id, publisher, name, version); } - if (!isNullOrEmpty(registry)) { + + // Check if plugin matches registry format: 'registryURL/identifier' + Matcher referenceMatcher = PLUGIN_WITH_REGISTRY_PATTERN.matcher(plugin); + if (referenceMatcher.matches()) { + // Workaround; plugin broker expects an 'id' field for each plugin, so it's necessary to split + // the URL arbitrarily. See issue: https://github.com/eclipse/che/issues/13385 + String registry = referenceMatcher.group("registry"); + String id = referenceMatcher.group("id"); + URI registryURI = null; try { registryURI = new URI(registry); } catch (URISyntaxException e) { @@ -140,9 +155,11 @@ public ExtendedPluginFQN parsePluginFQN(String plugin) throws InfrastructureExce "Plugin registry URL '%s' is invalid. Problematic plugin entry: '%s'", registry, plugin)); } + return new ExtendedPluginFQN(registryURI, id, null, null, null); } - return new ExtendedPluginFQN(registryURI, id, publisher, name, version); + // Failed to match above options. + throw new InfrastructureException(format(INCORRECT_PLUGIN_FORMAT_TEMPLATE, plugin)); } private String[] splitAttribute(String attribute) { diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/wsplugins/PluginFQNParserTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/wsplugins/PluginFQNParserTest.java index d44bc89f0df..ca674864a32 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/wsplugins/PluginFQNParserTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/wsplugins/PluginFQNParserTest.java @@ -103,8 +103,8 @@ public void shouldThrowExceptionWhenDuplicatePluginDefined() throws Exception { Map attributes = createAttributes( "", - formatPlugin("http://testregistry1:8080", "publisher1/testplugin/1.0"), - formatPlugin("http://testregistry2:8080", "publisher1/testplugin/1.0")); + formatPlugin(null, "publisher1/testplugin/1.0"), + formatPlugin(null, "publisher1/testplugin/1.0")); parser.parsePlugins(attributes); } @@ -118,8 +118,22 @@ public void shouldDetectDuplicatedPluginsIfTheyArePrefixedOrSuffixedWithEmptySpa Map attributes = createAttributes( "", - " " + formatPlugin("http://testregistry1:8080", "publisher1/testplugin/1.0"), - formatPlugin("http://testregistry2:8080", "publisher1/testplugin/1.0") + " "); + " " + formatPlugin(null, "publisher1/testplugin/1.0"), + formatPlugin(null, "publisher1/testplugin/1.0") + " "); + + parser.parsePlugins(attributes); + } + + @Test( + expectedExceptions = InfrastructureException.class, + expectedExceptionsMessageRegExp = + "Invalid Che tooling plugins configuration: plugin publisher1/testplugin/latest is duplicated") + public void shouldDetectDuplicatedPluginsIfOneLatestAndOtherNoVersion() throws Exception { + Map attributes = + createAttributes( + "", + formatPlugin(null, "publisher1/testplugin"), + formatPlugin(null, "publisher1/testplugin/latest")); parser.parsePlugins(attributes); } @@ -128,78 +142,62 @@ public void shouldDetectDuplicatedPluginsIfTheyArePrefixedOrSuffixedWithEmptySpa public static Object[][] invalidAttributeStringProvider() { return new Object[][] { {formatPlugin("http://bad registry url", "testplugin/1.0")}, - {formatPlugin("http://testregistry:8080", "bad:pluginname/1.0")}, - {formatPlugin("http://testregistry:8080", "/version")}, - {formatPlugin("http://testregistry:8080", "id/")}, - {formatPlugin("http://testregistry:8080", "name/version")}, - {formatPlugin("http://testregistry:8080", "id:version")}, - {formatPlugin("http://testregistry:8080", "publisher/name:version")}, {formatPlugin("http://testregistry:8080", "")} }; } @DataProvider(name = "validAttributesProvider") public static Object[][] validAttributesProvider() { - PluginFQN basicEditor = - new PluginFQN(URI.create("http://registry:8080"), "publisher/editor/ver"); - PluginFQN withRegistry = - new PluginFQN(URI.create("http://registry:8080"), "publisher/plugin/1.0"); - PluginFQN noRegistry = new PluginFQN(null, "publisher/pluginnoregistry/2.0"); - PluginFQN pathRegistry = + PluginFQN basicEditor = new PluginFQN(null, "publisher/editor/ver"); + PluginFQN basicEditorNoVersion = new PluginFQN(null, "publisher/editor"); + PluginFQN basicEditorLatestVersion = new PluginFQN(null, "publisher/editor/latest"); + PluginFQN basicPlugin = new PluginFQN(null, "publisher/plugin/ver"); + PluginFQN basicPluginNoVersion = new PluginFQN(null, "publisher/plugin"); + PluginFQN basicPluginLatestVersion = new PluginFQN(null, "publisher/plugin/latest"); + + PluginFQN customRegistry = + new PluginFQN(URI.create("http://registry.com/plugins/"), "pluginId"); + PluginFQN complexRegistry = new PluginFQN( - URI.create("http://registry/multiple/path/"), "publisher/pluginpathregistry/3.0"); + URI.create("https://registry.com/plugins.v2/multiple.components_plugin/"), + "id.version"); + return new AttributeParsingTestCase[][] { { new AttributeParsingTestCase( - "Test plugin with registry", - ImmutableList.of(basicEditor, withRegistry), - createAttributes(formatPlugin(basicEditor), formatPlugins(withRegistry))) + "Test basic plugin and editor", + ImmutableList.of(basicEditor, basicPlugin), + createAttributes(formatPlugin(basicEditor), formatPlugins(basicPlugin))) }, { new AttributeParsingTestCase( - "Test plugin with https registry", - ImmutableList.of( - new PluginFQN(URI.create("https://registry:8080"), "publisher/editor/ver")), - createAttributes( - null, - formatPlugin( - new PluginFQN(URI.create("https://registry:8080"), "publisher/editor/ver")))) + "Test basic plugin with no version", + ImmutableList.of(basicEditor, basicPluginLatestVersion), + createAttributes(formatPlugin(basicEditor), formatPlugin(basicPluginNoVersion))) }, { new AttributeParsingTestCase( - "Test plugin with registry containing path", - ImmutableList.of( - new PluginFQN( - URI.create("https://registry:8080/some/path/v3"), "publisher/editor/ver")), - createAttributes( - null, - formatPlugin( - new PluginFQN( - URI.create("https://registry:8080/some/path/v3"), "publisher/editor/ver")))) + "Test basic editor with no version", + ImmutableList.of(basicEditorLatestVersion, basicPlugin), + createAttributes(formatPlugin(basicEditorNoVersion), formatPlugin(basicPlugin))) }, { - new AttributeParsingTestCase( - "Test plugin without registry", - ImmutableList.of(basicEditor, noRegistry), - createAttributes(formatPlugin(basicEditor), formatPlugins(noRegistry))) - }, - { - new AttributeParsingTestCase( - "Test plugin with multi-level path in registry", - ImmutableList.of(basicEditor, pathRegistry), - createAttributes(formatPlugin(basicEditor), formatPlugins(pathRegistry))) + new AttributeParsingTestCase( // TODO + "Test basic plugin with version 'latest'", + ImmutableList.of(basicEditor, basicPluginLatestVersion), + createAttributes(formatPlugin(basicEditor), formatPlugin(basicPluginLatestVersion))) }, { new AttributeParsingTestCase( "Test attributes with no editor field", - ImmutableList.of(withRegistry), - createAttributes(null, formatPlugins(withRegistry))) + ImmutableList.of(basicPlugin), + createAttributes(null, formatPlugins(basicPlugin))) }, { new AttributeParsingTestCase( "Test attributes with empty editor field", - ImmutableList.of(withRegistry), - createAttributes("", formatPlugins(withRegistry))) + ImmutableList.of(basicPlugin), + createAttributes("", formatPlugins(basicPlugin))) }, { new AttributeParsingTestCase( @@ -228,9 +226,29 @@ public static Object[][] validAttributesProvider() { { new AttributeParsingTestCase( "Test multiple plugins and an editor", - ImmutableList.of(basicEditor, withRegistry, noRegistry, pathRegistry), + ImmutableList.of(basicEditor, basicPlugin, basicPluginLatestVersion), createAttributes( - formatPlugin(basicEditor), formatPlugins(withRegistry, noRegistry, pathRegistry))) + formatPlugin(basicEditor), formatPlugins(basicPlugin, basicPluginLatestVersion))) + }, + { + new AttributeParsingTestCase( + "Test multiple plugins and an editor, no version specified", + ImmutableList.of(basicEditorLatestVersion, basicPlugin, basicPluginLatestVersion), + createAttributes( + formatPlugin(basicEditorNoVersion), + formatPlugins(basicPlugin, basicPluginLatestVersion))) + }, + { + new AttributeParsingTestCase( + "Test plugin with custom registry", + ImmutableList.of(basicEditor, customRegistry), + createAttributes(formatPlugin(basicEditor), formatPlugin(customRegistry))) + }, + { + new AttributeParsingTestCase( + "Test plugin with complex registry", + ImmutableList.of(basicEditor, complexRegistry), + createAttributes(formatPlugin(basicEditor), formatPlugin(complexRegistry))) }, }; } @@ -243,56 +261,35 @@ public static Object[][] validPluginStringProvider() { { "http://registry:8080/publisher/editor/ver", new ExtendedPluginFQN( - URI.create("http://registry:8080"), - "publisher/editor/ver", - "publisher", - "editor", - "ver") + URI.create("http://registry:8080/publisher/editor/"), "ver", null, null, null) }, { "https://registry:8080/publisher/editor/ver", new ExtendedPluginFQN( - URI.create("https://registry:8080"), - "publisher/editor/ver", - "publisher", - "editor", - "ver") + URI.create("https://registry:8080/publisher/editor/"), "ver", null, null, null) }, { "https://che-registry.com.ua/publisher/editor/ver", new ExtendedPluginFQN( - URI.create("https://che-registry.com.ua"), - "publisher/editor/ver", - "publisher", - "editor", - "ver") + URI.create("https://che-registry.com.ua/publisher/editor/"), "ver", null, null, null) }, { "https://che-registry.com.ua/plugins/publisher/editor/ver", new ExtendedPluginFQN( - URI.create("https://che-registry.com.ua/plugins"), - "publisher/editor/ver", - "publisher", - "editor", - "ver") - }, - { - "https://che-registry.com.ua/plugins/v3/publisher/editor/ver", - new ExtendedPluginFQN( - URI.create("https://che-registry.com.ua/plugins/v3"), - "publisher/editor/ver", - "publisher", - "editor", - "ver") + URI.create("https://che-registry.com.ua/plugins/publisher/editor/"), + "ver", + null, + null, + null) }, { "https://che-registry.com.ua/some/long/path/publisher/editor/ver", new ExtendedPluginFQN( - URI.create("https://che-registry.com.ua/some/long/path"), - "publisher/editor/ver", - "publisher", - "editor", - "ver") + URI.create("https://che-registry.com.ua/some/long/path/publisher/editor/"), + "ver", + null, + null, + null) }, { "publisher/editor/ver", @@ -315,6 +312,11 @@ public static Object[][] validPluginStringProvider() { new ExtendedPluginFQN( null, "publisher/che-theia/2.12-latest", "publisher", "che-theia", "2.12-latest") }, + { + "publisher/che-theia", + new ExtendedPluginFQN( + null, "publisher/che-theia/latest", "publisher", "che-theia", "latest") + }, }; } @@ -331,10 +333,14 @@ private static String formatPlugin(String registry, String id) { if (registry == null) { return id; } else { - return registry + "/" + id; + return registry + id; } } + private static String formatPluginWithLatest(PluginFQN plugin) { + return plugin.getId() + "/latest"; + } + private static Map createAttributes(String editor, String... plugins) { Map attributes = new HashMap<>(); if (plugins != null) {