Support raw devfile urls without yaml extension (#683)
On handling raw devfile urls, request content by the url, and check if the content is a devfile. If yes treat the url as a raw devfile url. --------- Signed-off-by: ivinokur <ivinokur@redhat.com> Co-authored-by: Anatolii Bazko <abazko@redhat.com>pr-main-to-7.87.0-SNAPSHOT
parent
e072c7642b
commit
88cbaebd1a
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2023 Red Hat, Inc.
|
* Copyright (c) 2012-2024 Red Hat, Inc.
|
||||||
* This program and the accompanying materials are made
|
* This program and the accompanying materials are made
|
||||||
* available under the terms of the Eclipse Public License 2.0
|
* available under the terms of the Eclipse Public License 2.0
|
||||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
|
@ -16,7 +16,9 @@ import static java.lang.String.format;
|
||||||
import static org.eclipse.che.api.factory.server.FactoryResolverPriority.HIGHEST;
|
import static org.eclipse.che.api.factory.server.FactoryResolverPriority.HIGHEST;
|
||||||
import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME;
|
import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
|
@ -30,8 +32,10 @@ import org.eclipse.che.api.factory.server.urlfactory.DefaultFactoryUrl;
|
||||||
import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl;
|
import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl;
|
||||||
import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder;
|
import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder;
|
||||||
import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto;
|
import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto;
|
||||||
|
import org.eclipse.che.api.workspace.server.devfile.DevfileParser;
|
||||||
import org.eclipse.che.api.workspace.server.devfile.URLFetcher;
|
import org.eclipse.che.api.workspace.server.devfile.URLFetcher;
|
||||||
import org.eclipse.che.api.workspace.server.devfile.URLFileContentProvider;
|
import org.eclipse.che.api.workspace.server.devfile.URLFileContentProvider;
|
||||||
|
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileFormatException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link FactoryParametersResolver} implementation to resolve factory based on url parameter as a
|
* {@link FactoryParametersResolver} implementation to resolve factory based on url parameter as a
|
||||||
|
|
@ -45,13 +49,15 @@ public class RawDevfileUrlFactoryParameterResolver extends BaseFactoryParameterR
|
||||||
|
|
||||||
protected final URLFactoryBuilder urlFactoryBuilder;
|
protected final URLFactoryBuilder urlFactoryBuilder;
|
||||||
protected final URLFetcher urlFetcher;
|
protected final URLFetcher urlFetcher;
|
||||||
|
private final DevfileParser devfileParser;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public RawDevfileUrlFactoryParameterResolver(
|
public RawDevfileUrlFactoryParameterResolver(
|
||||||
URLFactoryBuilder urlFactoryBuilder, URLFetcher urlFetcher) {
|
URLFactoryBuilder urlFactoryBuilder, URLFetcher urlFetcher, DevfileParser devfileParser) {
|
||||||
super(null, urlFactoryBuilder, PROVIDER_NAME);
|
super(null, urlFactoryBuilder, PROVIDER_NAME);
|
||||||
this.urlFactoryBuilder = urlFactoryBuilder;
|
this.urlFactoryBuilder = urlFactoryBuilder;
|
||||||
this.urlFetcher = urlFetcher;
|
this.urlFetcher = urlFetcher;
|
||||||
|
this.devfileParser = devfileParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -64,7 +70,17 @@ public class RawDevfileUrlFactoryParameterResolver extends BaseFactoryParameterR
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(Map<String, String> factoryParameters) {
|
public boolean accept(Map<String, String> factoryParameters) {
|
||||||
String url = factoryParameters.get(URL_PARAMETER_NAME);
|
String url = factoryParameters.get(URL_PARAMETER_NAME);
|
||||||
return !isNullOrEmpty(url) && PATTERN.matcher(url).matches();
|
return !isNullOrEmpty(url) && (PATTERN.matcher(url).matches() || containsYaml(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean containsYaml(String requestURL) {
|
||||||
|
try {
|
||||||
|
String fetch = urlFetcher.fetch(requestURL);
|
||||||
|
JsonNode parsedYaml = devfileParser.parseYamlRaw(fetch);
|
||||||
|
return !parsedYaml.isEmpty();
|
||||||
|
} catch (IOException | DevfileFormatException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,14 @@ import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
import static org.testng.Assert.assertFalse;
|
import static org.testng.Assert.assertFalse;
|
||||||
import static org.testng.Assert.fail;
|
import static org.testng.Assert.fail;
|
||||||
import static org.testng.AssertJUnit.assertEquals;
|
import static org.testng.AssertJUnit.assertEquals;
|
||||||
import static org.testng.AssertJUnit.assertTrue;
|
import static org.testng.AssertJUnit.assertTrue;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.eclipse.che.api.core.BadRequestException;
|
import org.eclipse.che.api.core.BadRequestException;
|
||||||
|
|
@ -63,6 +66,7 @@ public class RawDevfileUrlFactoryParameterResolverTest {
|
||||||
+ " reference: ../localfile\n";
|
+ " reference: ../localfile\n";
|
||||||
|
|
||||||
@Mock private URLFetcher urlFetcher;
|
@Mock private URLFetcher urlFetcher;
|
||||||
|
@Mock private DevfileParser devfileParser;
|
||||||
|
|
||||||
@InjectMocks private RawDevfileUrlFactoryParameterResolver rawDevfileUrlFactoryParameterResolver;
|
@InjectMocks private RawDevfileUrlFactoryParameterResolver rawDevfileUrlFactoryParameterResolver;
|
||||||
|
|
||||||
|
|
@ -84,7 +88,7 @@ public class RawDevfileUrlFactoryParameterResolverTest {
|
||||||
"editor", "plugin", false, devfileParser, new DevfileVersionDetector());
|
"editor", "plugin", false, devfileParser, new DevfileVersionDetector());
|
||||||
|
|
||||||
RawDevfileUrlFactoryParameterResolver res =
|
RawDevfileUrlFactoryParameterResolver res =
|
||||||
new RawDevfileUrlFactoryParameterResolver(factoryBuilder, urlFetcher);
|
new RawDevfileUrlFactoryParameterResolver(factoryBuilder, urlFetcher, devfileParser);
|
||||||
|
|
||||||
// set up our factory with the location of our devfile that is referencing our localfile
|
// set up our factory with the location of our devfile that is referencing our localfile
|
||||||
Map<String, String> factoryParameters = new HashMap<>();
|
Map<String, String> factoryParameters = new HashMap<>();
|
||||||
|
|
@ -106,7 +110,7 @@ public class RawDevfileUrlFactoryParameterResolverTest {
|
||||||
URLFetcher urlFetcher = mock(URLFetcher.class);
|
URLFetcher urlFetcher = mock(URLFetcher.class);
|
||||||
|
|
||||||
RawDevfileUrlFactoryParameterResolver res =
|
RawDevfileUrlFactoryParameterResolver res =
|
||||||
new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher);
|
new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher, devfileParser);
|
||||||
|
|
||||||
Map<String, String> factoryParameters = new HashMap<>();
|
Map<String, String> factoryParameters = new HashMap<>();
|
||||||
factoryParameters.put(URL_PARAMETER_NAME, "http://myloc/devfile");
|
factoryParameters.put(URL_PARAMETER_NAME, "http://myloc/devfile");
|
||||||
|
|
@ -137,7 +141,7 @@ public class RawDevfileUrlFactoryParameterResolverTest {
|
||||||
URLFetcher urlFetcher = mock(URLFetcher.class);
|
URLFetcher urlFetcher = mock(URLFetcher.class);
|
||||||
|
|
||||||
RawDevfileUrlFactoryParameterResolver res =
|
RawDevfileUrlFactoryParameterResolver res =
|
||||||
new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher);
|
new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher, devfileParser);
|
||||||
|
|
||||||
Map<String, String> factoryParameters = new HashMap<>();
|
Map<String, String> factoryParameters = new HashMap<>();
|
||||||
factoryParameters.put(URL_PARAMETER_NAME, url);
|
factoryParameters.put(URL_PARAMETER_NAME, url);
|
||||||
|
|
@ -165,12 +169,67 @@ public class RawDevfileUrlFactoryParameterResolverTest {
|
||||||
assertTrue(result);
|
assertTrue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "devfileUrlsWithoutExtension")
|
||||||
|
public void shouldAcceptRawDevfileUrlWithoutExtension(String url) throws Exception {
|
||||||
|
// given
|
||||||
|
JsonNode jsonNode = mock(JsonNode.class);
|
||||||
|
when(urlFetcher.fetch(eq(url))).thenReturn(DEVFILE);
|
||||||
|
when(devfileParser.parseYamlRaw(eq(DEVFILE))).thenReturn(jsonNode);
|
||||||
|
when(jsonNode.isEmpty()).thenReturn(false);
|
||||||
|
|
||||||
|
// when
|
||||||
|
boolean result =
|
||||||
|
rawDevfileUrlFactoryParameterResolver.accept(singletonMap(URL_PARAMETER_NAME, url));
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldNotAcceptRawDevfileUrl() {
|
public void shouldAcceptRawDevfileUrlWithYaml() throws Exception {
|
||||||
|
// given
|
||||||
|
JsonNode jsonNode = mock(JsonNode.class);
|
||||||
|
String url = "https://host/path/devfile";
|
||||||
|
when(urlFetcher.fetch(eq(url))).thenReturn(DEVFILE);
|
||||||
|
when(devfileParser.parseYamlRaw(eq(DEVFILE))).thenReturn(jsonNode);
|
||||||
|
when(jsonNode.isEmpty()).thenReturn(false);
|
||||||
|
|
||||||
|
// when
|
||||||
|
boolean result =
|
||||||
|
rawDevfileUrlFactoryParameterResolver.accept(singletonMap(URL_PARAMETER_NAME, url));
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotAcceptPublicGitRepositoryUrl() throws Exception {
|
||||||
|
// given
|
||||||
|
JsonNode jsonNode = mock(JsonNode.class);
|
||||||
|
String gitRepositoryUrl = "https://host/user/repo.git";
|
||||||
|
when(urlFetcher.fetch(eq(gitRepositoryUrl))).thenReturn("unsupported content");
|
||||||
|
when(devfileParser.parseYamlRaw(eq("unsupported content"))).thenReturn(jsonNode);
|
||||||
|
when(jsonNode.isEmpty()).thenReturn(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
boolean result =
|
boolean result =
|
||||||
rawDevfileUrlFactoryParameterResolver.accept(
|
rawDevfileUrlFactoryParameterResolver.accept(
|
||||||
singletonMap(URL_PARAMETER_NAME, "https://host/user/repo.git"));
|
singletonMap(URL_PARAMETER_NAME, gitRepositoryUrl));
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotAcceptPrivateGitRepositoryUrl() throws Exception {
|
||||||
|
// given
|
||||||
|
String gitRepositoryUrl = "https://host/user/private-repo.git";
|
||||||
|
when(urlFetcher.fetch(eq(gitRepositoryUrl))).thenThrow(new FileNotFoundException());
|
||||||
|
|
||||||
|
// when
|
||||||
|
boolean result =
|
||||||
|
rawDevfileUrlFactoryParameterResolver.accept(
|
||||||
|
singletonMap(URL_PARAMETER_NAME, gitRepositoryUrl));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertFalse(result);
|
assertFalse(result);
|
||||||
|
|
@ -201,4 +260,9 @@ public class RawDevfileUrlFactoryParameterResolverTest {
|
||||||
"https://host/path/any-name.yml?token=TOKEN123"
|
"https://host/path/any-name.yml?token=TOKEN123"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DataProvider(name = "devfileUrlsWithoutExtension")
|
||||||
|
private Object[] devfileUrlsWithoutExtension() {
|
||||||
|
return new String[] {"https://host/path/any-name", "https://host/path/any-name?token=TOKEN123"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue