Skip to content

Commit

Permalink
Support raw devfile urls without yaml extension (#683)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
vinokurig and tolusha authored May 15, 2024
1 parent e072c76 commit 88cbaeb
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -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
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
Expand All @@ -16,7 +16,9 @@
import static org.eclipse.che.api.factory.server.FactoryResolverPriority.HIGHEST;
import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME;

import com.fasterxml.jackson.databind.JsonNode;
import jakarta.validation.constraints.NotNull;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
Expand All @@ -30,8 +32,10 @@
import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl;
import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder;
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.URLFileContentProvider;
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileFormatException;

/**
* {@link FactoryParametersResolver} implementation to resolve factory based on url parameter as a
Expand All @@ -45,13 +49,15 @@ public class RawDevfileUrlFactoryParameterResolver extends BaseFactoryParameterR

protected final URLFactoryBuilder urlFactoryBuilder;
protected final URLFetcher urlFetcher;
private final DevfileParser devfileParser;

@Inject
public RawDevfileUrlFactoryParameterResolver(
URLFactoryBuilder urlFactoryBuilder, URLFetcher urlFetcher) {
URLFactoryBuilder urlFactoryBuilder, URLFetcher urlFetcher, DevfileParser devfileParser) {
super(null, urlFactoryBuilder, PROVIDER_NAME);
this.urlFactoryBuilder = urlFactoryBuilder;
this.urlFetcher = urlFetcher;
this.devfileParser = devfileParser;
}

/**
Expand All @@ -64,7 +70,17 @@ public RawDevfileUrlFactoryParameterResolver(
@Override
public boolean accept(Map<String, String> factoryParameters) {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.fail;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;

import com.fasterxml.jackson.databind.JsonNode;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.che.api.core.BadRequestException;
Expand Down Expand Up @@ -63,6 +66,7 @@ public class RawDevfileUrlFactoryParameterResolverTest {
+ " reference: ../localfile\n";

@Mock private URLFetcher urlFetcher;
@Mock private DevfileParser devfileParser;

@InjectMocks private RawDevfileUrlFactoryParameterResolver rawDevfileUrlFactoryParameterResolver;

Expand All @@ -84,7 +88,7 @@ public void shouldResolveRelativeFiles() throws Exception {
"editor", "plugin", false, devfileParser, new DevfileVersionDetector());

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
Map<String, String> factoryParameters = new HashMap<>();
Expand All @@ -106,7 +110,7 @@ public void shouldFilterAndProvideOverrideParameters() throws Exception {
URLFetcher urlFetcher = mock(URLFetcher.class);

RawDevfileUrlFactoryParameterResolver res =
new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher);
new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher, devfileParser);

Map<String, String> factoryParameters = new HashMap<>();
factoryParameters.put(URL_PARAMETER_NAME, "http://myloc/devfile");
Expand Down Expand Up @@ -137,7 +141,7 @@ public void shouldThrowExceptionOnInvalidURL(String url, String message) throws
URLFetcher urlFetcher = mock(URLFetcher.class);

RawDevfileUrlFactoryParameterResolver res =
new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher);
new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher, devfileParser);

Map<String, String> factoryParameters = new HashMap<>();
factoryParameters.put(URL_PARAMETER_NAME, url);
Expand Down Expand Up @@ -165,12 +169,67 @@ public void shouldAcceptRawDevfileUrl(String url) {
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
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
boolean result =
rawDevfileUrlFactoryParameterResolver.accept(
singletonMap(URL_PARAMETER_NAME, gitRepositoryUrl));

// then
assertFalse(result);
}

@Test
public void shouldNotAcceptRawDevfileUrl() {
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, "https://host/user/repo.git"));
singletonMap(URL_PARAMETER_NAME, gitRepositoryUrl));

// then
assertFalse(result);
Expand Down Expand Up @@ -201,4 +260,9 @@ private Object[] devfileUrls() {
"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"};
}
}

0 comments on commit 88cbaeb

Please sign in to comment.