Skip to content

Commit

Permalink
#26 Latest artifact resolution fix for snapshot and release artifacts
Browse files Browse the repository at this point in the history
  • Loading branch information
galovics committed Jun 11, 2020
1 parent 7e4df54 commit ac658c5
Show file tree
Hide file tree
Showing 24 changed files with 362 additions and 120 deletions.
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,22 @@ but to resolve the latest artifact containing the Swagger definition file from a
repository (including Nexus and Artifactory as well). This feature requires that
the API definition file is packed into a JAR.

Using the functionality needs 3 parameters:
Using the functionality requires the following parameters:
- `--maven-repo-url`
- Specifies the repository base URL. Example: `https://oss.jfrog.org/oss-snapshot-local`
- Specifies the release repository base URL. Example: `https://oss.jfrog.org/oss-release-local/`
- `--maven-snapshot-repo-url`
- Specifies the snapshot repository base URL. Example: `https://oss.jfrog.org/oss-snapshot-local/`
- `--groupId`
- The groupId of the artifact
- `--artifactId`
- The artifactId
- `--current-artifact-version`
- The version of the artifact that contains the new API. This is mostly used to determine if the snapshot
or the release repository needs to be used. Example values are: 1.0.0, 1.0.0-SNAPSHOT

Example command:
```bash
$ java -jar swagger-brake.jar --new-api=/home/user/petstore_v2.yaml --maven-repo-url=https://oss.jfrog.org/oss-snapshot-local --groupId=com.example --artifactId=petstore-api
$ java -jar swagger-brake.jar --new-api=/home/user/petstore_v2.yaml --maven-repo-url=https://oss.jfrog.org/oss-snapshot-local --maven-snapshot-repo-url=https://oss.jfrog.org/oss-snapshot-local --groupId=com.example --artifactId=petstore-api --current-artifact-version=1.0.0-SNAPSHOT
```

By default, Swagger Brake scans the downloaded artifact for one of the following 3 files:
Expand All @@ -93,12 +98,12 @@ By default, Swagger Brake scans the downloaded artifact for one of the following
- swagger.yml

This behavior can be customized by providing the `--api-filename` parameter.
Note that it's enough to provide the filename without the extension as well, in that case the JSON, YAML and YML
Note that it's enough to provide the filename without the extension, in that case the JSON, YAML and YML
extension will be used for scanning.

Example command:
```bash
$ java -jar swagger-brake.jar --new-api=/home/user/petstore_v2.yaml --maven-repo-url=https://oss.jfrog.org/oss-snapshot-local --groupId=com.example --artifactId=petstore-api --api-filename=something.yaml
$ java -jar swagger-brake.jar --new-api=/home/user/petstore_v2.yaml --maven-repo-url=https://oss.jfrog.org/oss-snapshot-local --maven-snapshot-repo-url=https://oss.jfrog.org/oss-snapshot-local --groupId=com.example --artifactId=petstore-api --current-artifact-version=1.0.0-SNAPSHOT --api-filename=something.yaml
```

#### Secured Maven repository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ public abstract class CliOptions {
public static final String OUTPUT_PATH = "output-path";

public static final String MAVEN_REPO_URL = "maven-repo-url";
public static final String MAVEN_SNAPSHOT_REPO_URL = "maven-snapshot-repo-url";
public static final String ARTIFACT_ID = "artifactId";
public static final String GROUP_ID = "groupId";
public static final String CURRENT_ARTIFACT_VERSION = "current-artifact-version";

public static final String DEPRECATED_API_DELETION_ALLOWED = "deprecated-api-deletion-allowed";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.redskap.swagger.brake.cli.options.handler;

import io.redskap.swagger.brake.cli.options.CliOptions;
import io.redskap.swagger.brake.runner.Options;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

@Component
public class CurrentArtifactVersionHandler implements CliOptionHandler {
@Override
public void handle(String propertyValue, Options options) {
if (StringUtils.isNotBlank(propertyValue)) {
options.setCurrentArtifactVersion(propertyValue);
}
}

@Override
public String getHandledPropertyName() {
return CliOptions.CURRENT_ARTIFACT_VERSION;
}

@Override
public String getHelpMessage() {
return "Specifies the current artifact version against the latest artifact resolution. Example: 1.0.0, 1.0.0-SNAPSHOT";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ public String getHandledPropertyName() {

@Override
public String getHelpMessage() {
return "Specifies the Nexus snapshot repository URL where the latest artifact denoted by the groupId and artifactId will be downloaded";
return "Specifies the Maven repository URL where the latest artifact denoted by the groupId and artifactId will be downloaded";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.redskap.swagger.brake.cli.options.handler;

import io.redskap.swagger.brake.cli.options.CliOptions;
import io.redskap.swagger.brake.runner.Options;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

@Component
public class MavenSnapshotRepoUrlHandler implements CliOptionHandler {
@Override
public void handle(String propertyValue, Options options) {
if (StringUtils.isNotBlank(propertyValue)) {
options.setMavenSnapshotRepoUrl(propertyValue);
}
}

@Override
public String getHandledPropertyName() {
return CliOptions.MAVEN_SNAPSHOT_REPO_URL;
}

@Override
public String getHelpMessage() {
return "Specifies the Maven snapshot repository URL where the latest artifact denoted by the groupId and artifactId will be downloaded";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
@Data
public class DownloadOptions {
private String repoUrl;
private String snapshotRepoUrl;
private String groupId;
private String artifactId;
private String username;
private String password;
private String currentArtifactVersion;

public boolean isAuthenticationNeeded() {
return StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.redskap.swagger.brake.maven.maven2;

public abstract class ArtifactVersionDecider {
public static boolean isSnapshot(String version) {
return version.endsWith("-SNAPSHOT");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,25 @@
import io.redskap.swagger.brake.maven.DownloadOptions;
import io.redskap.swagger.brake.maven.model.MavenMetadata;
import io.redskap.swagger.brake.maven.model.MavenSnapshot;
import io.redskap.swagger.brake.maven.url.UrlFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
class LatestSnapshotNameResolver {
private final UrlFactory urlFactory;
class LatestArtifactNameResolver {
private final Maven2UrlFactory urlFactory;
private final MavenMetadataDownloader metadataDownloader;
private final RepositoryRequestFactory requestFactory;

String resolve(DownloadOptions options, String latestVersion) {
String resolveSnapshot(DownloadOptions options, String latestVersion) {
String metadataUrl = urlFactory.createLatestArtifactSnapshotMetadataUrl(options, latestVersion);
MavenMetadata snapshotMetadata = metadataDownloader.download(requestFactory.create(metadataUrl, options));
MavenSnapshot snapshot = snapshotMetadata.getVersioning().getSnapshot();
String snapshotVersion = latestVersion.replaceAll("SNAPSHOT", snapshot.getTimestamp());
return format("%s-%s-%s", snapshotMetadata.getArtifactId(), snapshotVersion, snapshot.getBuildNumber());
}

String resolveRelease(DownloadOptions options, String latestVersion) {
return format("%s-%s", options.getArtifactId(), latestVersion);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

import io.redskap.swagger.brake.maven.DownloadOptions;
import io.redskap.swagger.brake.maven.model.MavenMetadata;
import io.redskap.swagger.brake.maven.url.UrlFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
class LatestArtifactVersionResolver {
private final UrlFactory urlFactory;
private final Maven2UrlFactory urlFactory;
private final MavenMetadataDownloader metadataDownloader;
private final RepositoryRequestFactory requestFactory;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
import java.io.File;

import io.redskap.swagger.brake.maven.DownloadOptions;
import io.redskap.swagger.brake.maven.url.UrlFactory;
import lombok.RequiredArgsConstructor;
import org.apache.http.client.methods.HttpUriRequest;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
class LatestJarArtifactDownloader {
private final UrlFactory urlFactory;
private final Maven2UrlFactory urlFactory;
private final TemporaryJarFileDownloader temporaryJarFileDownloader;
private final RepositoryRequestFactory requestFactory;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@
@RequiredArgsConstructor
class Maven2LatestArtifactDownloader implements LatestArtifactDownloader {
private final LatestArtifactVersionResolver latestArtifactVersionResolver;
private final LatestSnapshotNameResolver latestSnapshotNameResolver;
private final LatestArtifactNameResolver latestArtifactNameResolver;
private final LatestJarArtifactDownloader latestJarArtifactDownloader;

@Override
public File download(DownloadOptions options) {
String latestVersion = latestArtifactVersionResolver.resolve(options);
String latestSnapshotName = latestSnapshotNameResolver.resolve(options, latestVersion);
return latestJarArtifactDownloader.download(options, latestSnapshotName, latestVersion);
String latestFilename;
if (ArtifactVersionDecider.isSnapshot(latestVersion)) {
latestFilename = latestArtifactNameResolver.resolveSnapshot(options, latestVersion);
} else {
latestFilename = latestArtifactNameResolver.resolveRelease(options, latestVersion);
}
return latestJarArtifactDownloader.download(options, latestFilename, latestVersion);
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,39 @@
package io.redskap.swagger.brake.maven.url;
package io.redskap.swagger.brake.maven.maven2;

import static java.lang.String.format;

import io.redskap.swagger.brake.maven.DownloadOptions;
import org.springframework.stereotype.Component;

@Component
public class UrlFactory {
public class Maven2UrlFactory {
public String createLatestArtifactSnapshotMetadataUrl(DownloadOptions options, String latestVersion) {
String artifactBasePathUrl = createLatestArtifactBasePathUrl(options);
String artifactBasePathUrl = createLatestArtifactBasePathUrl(options, options.getSnapshotRepoUrl());
return format("%s/%s/maven-metadata.xml", artifactBasePathUrl, latestVersion);
}

public String createLatestArtifactVersionMetadataUrl(DownloadOptions options) {
String artifactBasePathUrl = createLatestArtifactBasePathUrl(options);
String repoUrl = getRepoUrl(options);
String artifactBasePathUrl = createLatestArtifactBasePathUrl(options, repoUrl);
return format("%s/maven-metadata.xml", artifactBasePathUrl);
}

public String createLatestArtifactUrl(DownloadOptions options, String latestVersion, String latestSnapshotName) {
String artifactBasePathUrl = createLatestArtifactBasePathUrl(options);
String repoUrl = getRepoUrl(options);
String artifactBasePathUrl = createLatestArtifactBasePathUrl(options, repoUrl);
return format("%s/%s/%s.jar", artifactBasePathUrl, latestVersion, latestSnapshotName);
}

private String createLatestArtifactBasePathUrl(DownloadOptions options) {
private String createLatestArtifactBasePathUrl(DownloadOptions options, String repoUrl) {
String groupPath = options.getGroupId().replaceAll("\\.", "/");
return format("%s/%s/%s", options.getRepoUrl(), groupPath, options.getArtifactId());
return format("%s/%s/%s", repoUrl, groupPath, options.getArtifactId());
}

private String getRepoUrl(DownloadOptions options) {
String repoUrl = options.getRepoUrl();
if (ArtifactVersionDecider.isSnapshot(options.getCurrentArtifactVersion())) {
repoUrl = options.getSnapshotRepoUrl();
}
return repoUrl;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ public class Options {
private String outputFilePath;

private String mavenRepoUrl;
private String mavenSnapshotRepoUrl;
private String groupId;
private String artifactId;
private String mavenRepoUsername;
private String mavenRepoPassword;
private String currentArtifactVersion;

private Boolean deprecatedApiDeletionAllowed;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,11 @@ public class ArtifactDownloaderHandler {

public void handle(Options options) {
if (isLatestArtifactDownloadEnabled(options)) {
String url = options.getMavenRepoUrl();
String username = options.getMavenRepoUsername();
String password = options.getMavenRepoPassword();
String groupId = options.getGroupId();
String artifactId = options.getArtifactId();
try {
log.info("Downloading latest artifact from repository '{}' with groupId '{}' artifactId '{}'", url, groupId, artifactId);
DownloadOptions downloadOptions = downloadOptionsFactory.create(url, groupId, artifactId, username, password);
String groupId = options.getGroupId();
String artifactId = options.getArtifactId();
log.info("Downloading latest artifact with groupId '{}' artifactId '{}'", groupId, artifactId);
DownloadOptions downloadOptions = downloadOptionsFactory.create(options);
File apiJar = downloaderFactory.create(options).download(downloadOptions);
ApiFileResolverParameter apiFileResolverParameter = new ApiFileResolverParameter(apiJar, options.getApiFilename());
File swaggerFile = apiFileResolver.resolve(apiFileResolverParameter);
Expand All @@ -42,10 +39,24 @@ public void handle(Options options) {
} catch (Exception e) {
throw new LatestArtifactDownloadException("Error while downloading the latest version of the artifact", e);
}
} else if (isLatestArtifactDownloadWronglyConfigured(options)) {
log.warn("Seems like latest artifact resolution is intended to be used but missing some of the parameters");
}
}

private boolean isLatestArtifactDownloadEnabled(Options options) {
return isNotBlank(options.getMavenRepoUrl()) && isNotBlank(options.getGroupId()) && isNotBlank(options.getArtifactId());
return isNotBlank(options.getMavenRepoUrl())
&& isNotBlank(options.getMavenSnapshotRepoUrl())
&& isNotBlank(options.getGroupId())
&& isNotBlank(options.getArtifactId())
&& isNotBlank(options.getCurrentArtifactVersion());
}

private boolean isLatestArtifactDownloadWronglyConfigured(Options options) {
return isNotBlank(options.getMavenRepoUrl())
|| isNotBlank(options.getMavenSnapshotRepoUrl())
|| isNotBlank(options.getGroupId())
|| isNotBlank(options.getArtifactId())
|| isNotBlank(options.getCurrentArtifactVersion());
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package io.redskap.swagger.brake.runner.download;

import io.redskap.swagger.brake.maven.DownloadOptions;
import io.redskap.swagger.brake.runner.Options;
import org.springframework.stereotype.Component;

@Component
class DownloadOptionsFactory {
public DownloadOptions create(String mavenRepoUrl, String groupId, String artifactId, String mavenRepoUsername, String mavenRepoPassword) {
public DownloadOptions create(Options options) {
DownloadOptions result = new DownloadOptions();
result.setRepoUrl(mavenRepoUrl);
result.setGroupId(groupId);
result.setArtifactId(artifactId);
result.setUsername(mavenRepoUsername);
result.setPassword(mavenRepoPassword);
result.setRepoUrl(options.getMavenRepoUrl());
result.setSnapshotRepoUrl(options.getMavenSnapshotRepoUrl());
result.setGroupId(options.getGroupId());
result.setArtifactId(options.getArtifactId());
result.setUsername(options.getMavenRepoUsername());
result.setPassword(options.getMavenRepoPassword());
result.setCurrentArtifactVersion(options.getCurrentArtifactVersion());
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.redskap.swagger.brake.maven.maven2;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class ArtifactVersionDeciderTest {
@Test
public void testIsSnapshotReturnsTrueWhenVersionIsEndingWithSnapshot() {
// given
// when
boolean result = ArtifactVersionDecider.isSnapshot("1.0.0-SNAPSHOT");
// then
assertTrue(result);
}

@Test
public void testIsSnapshotReturnsFalseWhenVersionIsNotEndingWithSnapshot() {
// given
// when
boolean result = ArtifactVersionDecider.isSnapshot("1.0.0");
// then
assertFalse(result);
}

@Test
public void testIsSnapshotReturnsFalseWhenVersionIsCompletelyRandom() {
// given
// when
boolean result = ArtifactVersionDecider.isSnapshot("something-else-that-is-not-a-version");
// then
assertFalse(result);
}
}
Loading

0 comments on commit ac658c5

Please sign in to comment.