From 31a9c8268dc73fdfd0d8ad2845ef6c4492568f83 Mon Sep 17 00:00:00 2001 From: devatherock Date: Wed, 14 Apr 2021 21:09:29 -0500 Subject: [PATCH] Changes to not treat _uploads subfolder as a docker tag Closes #40 --- CHANGELOG.md | 3 + README.md | 9 +- build.gradle | 5 +- .../config/ArtifactoryProperties.java | 15 ++ .../service/DockerBadgeService.java | 156 ++--------------- .../service/DockerBadgeServiceHelper.java | 165 ++++++++++++++++++ .../test/ArtifactoryController.java | 2 + ...ication-mock.yml => application-local.yml} | 0 .../controllers/DockerControllerSpec.groovy | 6 + .../controllers/VersionControllerSpec.groovy | 8 + .../DockerBadgeServiceHelperSpec.groovy | 52 ++++++ .../service/DockerBadgeServiceSpec.groovy | 47 +---- .../github/devatherock/test/TestUtil.groovy | 4 + 13 files changed, 284 insertions(+), 188 deletions(-) create mode 100644 src/main/java/io/github/devatherock/artifactory/service/DockerBadgeServiceHelper.java rename src/main/resources/{application-mock.yml => application-local.yml} (100%) create mode 100644 src/test/groovy/io/github/devatherock/artifactory/service/DockerBadgeServiceHelperSpec.groovy diff --git a/CHANGELOG.md b/CHANGELOG.md index fcbf446..7a02695 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ### Added - Spotless gradle plugin to format code +### Changed +- [#40](https://github.com/devatherock/artifactory-badge/issues/40): To not treat `_uploads` subfolder as a docker tag + ### Removed - Custom environment variables with `LOGGING_LEVEL` prefix and updated documentation to use environment variables with `LOGGER_LEVELS` prefix supported out of the box by micronaut diff --git a/README.md b/README.md index 7c78be2..c54e5c4 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,11 @@ docker run --rm \ |---------------------------------------|--------------|------------------|-----------------------------------------------------------------------------------| | ARTIFACTORY_URL | true | (None) | The JFrog artifactory URL that hosts the docker registry | | ARTIFACTORY_API_KEY | true | (None) | API key for interacting with artifactory's REST API | -| ARTIFACTORY_BADGE_SHIELDS_IO_ENABLED | false | true | Indicates if shields.io should be used to generate the badge | -| LOGGING_LEVEL_ROOT | false | INFO | [SLF4J](http://www.slf4j.org/api/org/apache/commons/logging/Log.html) log level, for all(framework and custom) code | -| LOGGING_LEVEL_IO_GITHUB_DEVATHEROCK | false | INFO | [SLF4J](http://www.slf4j.org/api/org/apache/commons/logging/Log.html) log level, for custom code | -| MICRONAUT_ENVIRONMENTS | false | (None) | Setting the value to `mock` will mock the calls to the artifactory. Only for testing purposes | +| ARTIFACTORY_EXCLUDED_FOLDERS | false | /_uploads | Subfolders to be not treated as docker tags | +| ARTIFACTORY_BADGE_SHIELDS_IO_ENABLED | false | true | Indicates if shields.io should be used to generate the badge | +| LOGGER_LEVELS_ROOT | false | INFO | [SLF4J](http://www.slf4j.org/api/org/apache/commons/logging/Log.html) log level, for all(framework and custom) code | +| LOGGER_LEVELS_IO_GITHUB_DEVATHEROCK | false | INFO | [SLF4J](http://www.slf4j.org/api/org/apache/commons/logging/Log.html) log level, for custom code | +| MICRONAUT_ENVIRONMENTS | false | (None) | Setting the value to `local` will mock the calls to the artifactory. Only for testing purposes | | MICRONAUT_SERVER_PORT | false | 8080 | Port in which the app listens on | | JAVA_OPTS | false | (None) | Additional JVM arguments to be passed to the container's java process | diff --git a/build.gradle b/build.gradle index 727037b..2c8eea9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,12 @@ plugins { - id "net.ltgt.apt-eclipse" version "0.21" id "com.github.johnrengelman.shadow" version "6.1.0" - id "application" + id 'io.micronaut.application' version '1.4.4' id 'java' id 'groovy' id 'jacoco' id 'org.sonarqube' version '3.1.1' id 'com.github.kt3k.coveralls' version '2.12.0' - id 'com.diffplug.spotless' version '5.12.0' + id 'com.diffplug.spotless' version '5.12.1' } version "0.4.0" diff --git a/src/main/java/io/github/devatherock/artifactory/config/ArtifactoryProperties.java b/src/main/java/io/github/devatherock/artifactory/config/ArtifactoryProperties.java index 42782fd..b4a6ba6 100644 --- a/src/main/java/io/github/devatherock/artifactory/config/ArtifactoryProperties.java +++ b/src/main/java/io/github/devatherock/artifactory/config/ArtifactoryProperties.java @@ -1,5 +1,9 @@ package io.github.devatherock.artifactory.config; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import javax.annotation.PostConstruct; import javax.validation.constraints.NotBlank; @@ -9,6 +13,12 @@ import lombok.Getter; import lombok.Setter; +/** + * Configurable properties for the application + * + * @author devaprasadh + * + */ @Getter @Setter @Context @@ -32,6 +42,11 @@ public class ArtifactoryProperties { @Setter(AccessLevel.NONE) private String storageUrlPrefix; + /** + * Subfolders to be not treated as docker tags + */ + private List excludedFolders = new ArrayList<>(Arrays.asList("/_uploads")); + @PostConstruct public void init() { urlPrefix = url + "/artifactory/"; diff --git a/src/main/java/io/github/devatherock/artifactory/service/DockerBadgeService.java b/src/main/java/io/github/devatherock/artifactory/service/DockerBadgeService.java index 26cd005..1dcbe59 100644 --- a/src/main/java/io/github/devatherock/artifactory/service/DockerBadgeService.java +++ b/src/main/java/io/github/devatherock/artifactory/service/DockerBadgeService.java @@ -1,10 +1,7 @@ package io.github.devatherock.artifactory.service; -import java.text.DecimalFormat; import java.time.Instant; import java.time.format.DateTimeFormatter; -import java.util.HashMap; -import java.util.Map; import java.util.regex.Pattern; import javax.inject.Singleton; @@ -41,8 +38,6 @@ public class DockerBadgeService { private static final double BYTES_IN_MB = 1024d * 1024; private static final String FILE_NAME_MANIFEST = "/manifest.json"; private static final String HDR_API_KEY = "X-JFrog-Art-Api"; - private static final double PULLS_REDUCER = 1000; - private static final int MAX_REDUCTIONS = 3; /** * Constant for sort by semantic version @@ -52,18 +47,6 @@ public class DockerBadgeService { * Major version part of a semantic version */ private static final String VERSION_PART_MAJOR = "major"; - /** - * Minor version part of a semantic version - */ - private static final String VERSION_PART_MINOR = "minor"; - /** - * Patch version part of a semantic version - */ - private static final String VERSION_PART_PATCH = "patch"; - /** - * Map containing suffixes for download count - */ - private static final Map PULLS_SUFFIX = new HashMap<>(); /** * Formatter to parse dates like {@code 2020-10-01T00:00:00.000Z} */ @@ -74,17 +57,6 @@ public class DockerBadgeService { */ private static final Pattern PTRN_NUMERIC_VERSION = Pattern.compile( "^(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))*(\\-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$"); - /** - * Pattern to match numbers - */ - private static final Pattern PTRN_NUMBER = Pattern.compile("^[0-9]+$"); - - static { - PULLS_SUFFIX.put(0, ""); - PULLS_SUFFIX.put(1, "k"); - PULLS_SUFFIX.put(2, "M"); - PULLS_SUFFIX.put(3, "G"); - } private final BlockingHttpClient artifactoryClient; private final BadgeGenerator badgeGenerator; @@ -100,7 +72,8 @@ public String getImageSizeBadge(String packageName, String tag, String badgeLabe .reduce((totalSize, currentLayerSize) -> totalSize + currentLayerSize).get() / BYTES_IN_MB; LOGGER.info("Size of {}/{}: {} MB", packageName, tag, imageSize); - return badgeGenerator.generateBadge(badgeLabel, String.format("%s MB", formatDecimal(imageSize, "0.##"))); + return badgeGenerator.generateBadge(badgeLabel, + String.format("%s MB", DockerBadgeServiceHelper.formatDecimal(imageSize, "0.##"))); } else { return generateNotFoundBadge(badgeLabel); } @@ -128,7 +101,7 @@ public String getPullsCountBadge(String packageName, String badgeLabel) { long downloadCount = 0; for (ArtifactoryFolderElement child : folderInfo.getChildren()) { - if (child.isFolder()) { + if (isTag(child)) { ArtifactoryFileStats fileStats = getManifestStats(packageName, child.getUri()); if (null != fileStats) { @@ -137,7 +110,8 @@ public String getPullsCountBadge(String packageName, String badgeLabel) { } } LOGGER.info("Download count of {}: {}", packageName, downloadCount); - return badgeGenerator.generateBadge(badgeLabel, formatDownloadCount(downloadCount)); + return badgeGenerator.generateBadge(badgeLabel, + DockerBadgeServiceHelper.formatDownloadCount(downloadCount)); } else { return generateNotFoundBadge(badgeLabel); } @@ -160,7 +134,7 @@ public String getLatestVersionBadge(String packageName, String badgeLabel, Strin ArtifactoryFolderInfo latestVersion = null; for (ArtifactoryFolderElement child : folderInfo.getChildren()) { - if (child.isFolder()) { + if (isTag(child)) { if (SORT_TYPE_SEMVER.equals(sortType)) { // Substring to remove the leading slash String currentVersion = child.getUri().substring(1); @@ -170,7 +144,8 @@ public String getLatestVersionBadge(String packageName, String badgeLabel, Strin latestVersion = ArtifactoryFolderInfo.builder().path(child.getUri()).build(); } else { // Substring to remove the leading slash - int result = compareVersions(latestVersion.getPath().substring(1), currentVersion, + int result = DockerBadgeServiceHelper.compareVersions( + latestVersion.getPath().substring(1), currentVersion, VERSION_PART_MAJOR); if (result == -1) { latestVersion = ArtifactoryFolderInfo.builder().path(child.getUri()).build(); @@ -178,6 +153,8 @@ public String getLatestVersionBadge(String packageName, String badgeLabel, Strin } } } else { + // Find the modified time of each subfolder - each subfolder corresponds to a + // tag ArtifactoryFolderInfo currentVersion = getArtifactoryFolderInfo(packageName + child.getUri()); if (null == latestVersion || (null != currentVersion @@ -192,7 +169,8 @@ public String getLatestVersionBadge(String packageName, String badgeLabel, Strin if (null != latestVersion) { LOGGER.info("Latest version of {}: {}", packageName, latestVersion.getPath()); - return badgeGenerator.generateBadge(badgeLabel, getVersionBadgeValue(latestVersion)); + return badgeGenerator.generateBadge(badgeLabel, + DockerBadgeServiceHelper.getVersionBadgeValue(latestVersion)); } else { return generateNotFoundBadge(badgeLabel); } @@ -280,110 +258,12 @@ private String generateNotFoundBadge(String badgeLabel) { } /** - * Compares two versions - * - * @param versionOne - * @param versionTwo - * @param versionPartType - * @return {@literal -1} if {@code versionTwo} greater than {@code versionOne}, - * {@literal 1} otherwise - */ - private int compareVersions(String versionOne, String versionTwo, String versionPartType) { - int result = 0; - - int versionPartEndOne = getVersionPartEndIndex(versionOne); - String versionPartOneText = versionOne.substring(0, - versionPartEndOne != -1 ? versionPartEndOne : versionOne.length()); - long versionPartOne = readVersionAsNumber(versionPartOneText); - int versionPartEndTwo = getVersionPartEndIndex(versionTwo); - String versionPartTwoText = versionTwo.substring(0, - versionPartEndTwo != -1 ? versionPartEndTwo : versionTwo.length()); - long versionPartTwo = readVersionAsNumber(versionPartTwoText); - - if (versionPartOne > versionPartTwo) { - result = 1; - } else if (versionPartOne < versionPartTwo) { - result = -1; - } else { - if ((versionPartOneText.length() + 1) >= versionOne.length()) { - if ((versionPartTwoText.length() + 1) < versionTwo.length()) { - result = -1; - } - } else if ((versionPartTwoText.length() + 1) < versionTwo.length()) { - if (!VERSION_PART_PATCH.equals(versionPartType)) { - result = compareVersions(versionOne.substring(versionPartEndOne + 1), - versionTwo.substring(versionPartEndTwo + 1), - VERSION_PART_MAJOR.equals(versionPartType) ? VERSION_PART_MINOR : VERSION_PART_PATCH); - } - } else { - result = 1; - } - } - - return result; - } - - /** - * Returns the index at which the first version part ends - * - * @param version - * @return the index + * Checks if the supplied artifactory folder content corresponds to a tag + * + * @param child + * @return a flag */ - private int getVersionPartEndIndex(String version) { - return version.indexOf('.') != -1 ? version.indexOf('.') : version.indexOf('-'); - } - - /** - * Converts version string into a number - * - * @param version - * @return the version as number - */ - private long readVersionAsNumber(String version) { - return PTRN_NUMBER.matcher(version).matches() ? Long.parseLong(version) : 0; - } - - /** - * Returns the formatted value to be displayed in the version badge - * - * @param version - * @return the version badge value - */ - private String getVersionBadgeValue(ArtifactoryFolderInfo version) { - String versionValue = version.getPath().substring(version.getPath().lastIndexOf('/') + 1); - - // Append v prefix if version is numeric or a semantic version - return PTRN_NUMERIC_VERSION.matcher(versionValue).matches() ? 'v' + versionValue : versionValue; - } - - /** - * Formats a decimal number into a string - * - * @param inputDecimal the decimal number to format - * @param format the pattern to which to format to - * @return a formatted string - */ - private String formatDecimal(double inputDecimal, String format) { - DecimalFormat decimalFormat = new DecimalFormat(format); - decimalFormat.setDecimalSeparatorAlwaysShown(false); - return decimalFormat.format(inputDecimal); - } - - /** - * Formats the download count with a suffix - * - * @param downloadCount number of downloads - * @return a formatted string - */ - private String formatDownloadCount(long downloadCount) { - double reducedCount = downloadCount; - int reductions = 0; - - while (reducedCount > PULLS_REDUCER && reductions < MAX_REDUCTIONS) { - reductions++; - reducedCount = reducedCount / PULLS_REDUCER; - } - - return formatDecimal(reducedCount, "0.#") + PULLS_SUFFIX.get(reductions); + private boolean isTag(ArtifactoryFolderElement child) { + return child.isFolder() && !artifactoryConfig.getExcludedFolders().contains(child.getUri()); } } diff --git a/src/main/java/io/github/devatherock/artifactory/service/DockerBadgeServiceHelper.java b/src/main/java/io/github/devatherock/artifactory/service/DockerBadgeServiceHelper.java new file mode 100644 index 0000000..1cd1a3c --- /dev/null +++ b/src/main/java/io/github/devatherock/artifactory/service/DockerBadgeServiceHelper.java @@ -0,0 +1,165 @@ +package io.github.devatherock.artifactory.service; + +import java.text.DecimalFormat; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import io.github.devatherock.artifactory.entities.ArtifactoryFolderInfo; + +import io.micronaut.core.annotation.Blocking; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * Helper class for {@link DockerBadgeService} + * + * @author devaprasadh + */ +@Blocking +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DockerBadgeServiceHelper { + private static final double PULLS_REDUCER = 1000; + private static final int MAX_REDUCTIONS = 3; + + /** + * Major version part of a semantic version + */ + private static final String VERSION_PART_MAJOR = "major"; + /** + * Minor version part of a semantic version + */ + private static final String VERSION_PART_MINOR = "minor"; + /** + * Patch version part of a semantic version + */ + private static final String VERSION_PART_PATCH = "patch"; + /** + * Map containing suffixes for download count + */ + private static final Map PULLS_SUFFIX = new HashMap<>(); + /** + * Pattern to match versions like {@code 1}, {@code 1.2} and {@code 1.2.2} + */ + private static final Pattern PTRN_NUMERIC_VERSION = Pattern.compile( + "^(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))*(\\-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$"); + /** + * Pattern to match numbers + */ + private static final Pattern PTRN_NUMBER = Pattern.compile("^[0-9]+$"); + + static { + PULLS_SUFFIX.put(0, ""); + PULLS_SUFFIX.put(1, "k"); + PULLS_SUFFIX.put(2, "M"); + PULLS_SUFFIX.put(3, "G"); + } + + /** + * Compares two versions + * + * @param versionOne + * @param versionTwo + * @param versionPartType + * @return {@literal -1} if {@code versionTwo} greater than {@code versionOne}, + * {@literal 1} otherwise + */ + static int compareVersions(String versionOne, String versionTwo, String versionPartType) { + int result = 0; + + int versionPartEndOne = getVersionPartEndIndex(versionOne); + String versionPartOneText = versionOne.substring(0, + versionPartEndOne != -1 ? versionPartEndOne : versionOne.length()); + long versionPartOne = readVersionAsNumber(versionPartOneText); + int versionPartEndTwo = getVersionPartEndIndex(versionTwo); + String versionPartTwoText = versionTwo.substring(0, + versionPartEndTwo != -1 ? versionPartEndTwo : versionTwo.length()); + long versionPartTwo = readVersionAsNumber(versionPartTwoText); + + if (versionPartOne > versionPartTwo) { + result = 1; + } else if (versionPartOne < versionPartTwo) { + result = -1; + } else { + if ((versionPartOneText.length() + 1) >= versionOne.length()) { + if ((versionPartTwoText.length() + 1) < versionTwo.length()) { + result = -1; + } + } else if ((versionPartTwoText.length() + 1) < versionTwo.length()) { + if (!VERSION_PART_PATCH.equals(versionPartType)) { + result = compareVersions(versionOne.substring(versionPartEndOne + 1), + versionTwo.substring(versionPartEndTwo + 1), + VERSION_PART_MAJOR.equals(versionPartType) ? VERSION_PART_MINOR : VERSION_PART_PATCH); + } + } else { + result = 1; + } + } + + return result; + } + + /** + * Returns the formatted value to be displayed in the version badge + * + * @param version + * @return the version badge value + */ + static String getVersionBadgeValue(ArtifactoryFolderInfo version) { + String versionValue = version.getPath().substring(version.getPath().lastIndexOf('/') + 1); + + // Append v prefix if version is numeric or a semantic version + return PTRN_NUMERIC_VERSION.matcher(versionValue).matches() ? 'v' + versionValue : versionValue; + } + + /** + * Formats a decimal number into a string + * + * @param inputDecimal the decimal number to format + * @param format the pattern to which to format to + * @return a formatted string + */ + static String formatDecimal(double inputDecimal, String format) { + DecimalFormat decimalFormat = new DecimalFormat(format); + decimalFormat.setDecimalSeparatorAlwaysShown(false); + return decimalFormat.format(inputDecimal); + } + + /** + * Formats the download count with a suffix + * + * @param downloadCount number of downloads + * @return a formatted string + */ + static String formatDownloadCount(long downloadCount) { + double reducedCount = downloadCount; + int reductions = 0; + + while (reducedCount > PULLS_REDUCER && reductions < MAX_REDUCTIONS) { + reductions++; + reducedCount = reducedCount / PULLS_REDUCER; + } + + return formatDecimal(reducedCount, "0.#") + PULLS_SUFFIX.get(reductions); + } + + /** + * Returns the index at which the first version part ends + * + * @param version + * @return the index + */ + private static int getVersionPartEndIndex(String version) { + return version.indexOf('.') != -1 ? version.indexOf('.') : version.indexOf('-'); + } + + /** + * Converts version string into a number + * + * @param version + * @return the version as number + */ + private static long readVersionAsNumber(String version) { + return PTRN_NUMBER.matcher(version).matches() ? Long.parseLong(version) : 0; + } +} diff --git a/src/main/java/io/github/devatherock/test/ArtifactoryController.java b/src/main/java/io/github/devatherock/test/ArtifactoryController.java index 4c8f714..659d2e5 100644 --- a/src/main/java/io/github/devatherock/test/ArtifactoryController.java +++ b/src/main/java/io/github/devatherock/test/ArtifactoryController.java @@ -33,6 +33,7 @@ public class ArtifactoryController { MODIFIED_TIME.put("latest", "2020-10-01T00:00:00.000Z"); MODIFIED_TIME.put("1.1.0", "2020-10-08T00:00:00.000Z"); MODIFIED_TIME.put("1.1.2-rc.1", "2020-10-15T00:00:00.000Z"); + MODIFIED_TIME.put("_uploads", "2021-03-15T00:00:00.000Z"); } @Get(value = "/{fileName:.*}", produces = MediaType.APPLICATION_JSON) @@ -68,6 +69,7 @@ public Object getFolderInfo(@PathVariable String folderName, .child(ArtifactoryFolderElement.builder().uri("/1.1.0").folder(true).build()) .child(ArtifactoryFolderElement.builder().uri("/1.1.2-rc.1").folder(true).build()) .child(ArtifactoryFolderElement.builder().uri("/latest").folder(true).build()) + .child(ArtifactoryFolderElement.builder().uri("/_uploads").folder(true).build()) .child(ArtifactoryFolderElement.builder().uri("/dummy").folder(false).build()) .build(); } diff --git a/src/main/resources/application-mock.yml b/src/main/resources/application-local.yml similarity index 100% rename from src/main/resources/application-mock.yml rename to src/main/resources/application-local.yml diff --git a/src/test/groovy/io/github/devatherock/artifactory/controllers/DockerControllerSpec.groovy b/src/test/groovy/io/github/devatherock/artifactory/controllers/DockerControllerSpec.groovy index a97749d..e1c9684 100644 --- a/src/test/groovy/io/github/devatherock/artifactory/controllers/DockerControllerSpec.groovy +++ b/src/test/groovy/io/github/devatherock/artifactory/controllers/DockerControllerSpec.groovy @@ -87,6 +87,8 @@ class DockerControllerSpec extends Specification { WireMock.verify(1, WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/abcdefgh/manifest.json?stats")) .withHeader(DockerBadgeService.HDR_API_KEY, equalTo('dummyKey'))) + WireMock.verify(0, + WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/_uploads/manifest.json?stats"))) WireMock.verify(1, WireMock.getRequestedFor(WireMock.urlPathEqualTo("/static/v1"))) badge == TestUtil.getCustomBadgeResponse() } @@ -135,6 +137,8 @@ class DockerControllerSpec extends Specification { WireMock.verify(1, WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/abcdefgh/manifest.json?stats")) .withHeader(DockerBadgeService.HDR_API_KEY, equalTo('dummyKey'))) + WireMock.verify(0, + WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/_uploads/manifest.json?stats"))) WireMock.verify(1, WireMock.getRequestedFor(WireMock.urlPathEqualTo("/static/v1"))) badge == 'dummyBadge' } @@ -187,6 +191,8 @@ class DockerControllerSpec extends Specification { WireMock.verify(1, WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/abcdefgh/manifest.json?stats")) .withHeader(DockerBadgeService.HDR_API_KEY, equalTo('dummyKey'))) + WireMock.verify(0, + WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/_uploads/manifest.json?stats"))) WireMock.verify(1, WireMock.getRequestedFor(WireMock.urlPathEqualTo("/static/v1"))) badge == 'dummyBadge' cachedBadge == badge diff --git a/src/test/groovy/io/github/devatherock/artifactory/controllers/VersionControllerSpec.groovy b/src/test/groovy/io/github/devatherock/artifactory/controllers/VersionControllerSpec.groovy index b580f3d..f79d3b4 100644 --- a/src/test/groovy/io/github/devatherock/artifactory/controllers/VersionControllerSpec.groovy +++ b/src/test/groovy/io/github/devatherock/artifactory/controllers/VersionControllerSpec.groovy @@ -91,6 +91,8 @@ class VersionControllerSpec extends Specification { WireMock.verify(1, WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/abcdefgh")) .withHeader(DockerBadgeService.HDR_API_KEY, equalTo('dummyKey'))) + WireMock.verify(0, + WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/_uploads"))) WireMock.verify(1, WireMock.getRequestedFor(WireMock.urlPathEqualTo("/static/v1"))) badge == 'dummyBadge' } @@ -143,6 +145,8 @@ class VersionControllerSpec extends Specification { WireMock.verify(1, WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/abcdefgh")) .withHeader(DockerBadgeService.HDR_API_KEY, equalTo('dummyKey'))) + WireMock.verify(0, + WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/_uploads"))) WireMock.verify(1, WireMock.getRequestedFor(WireMock.urlPathEqualTo("/static/v1"))) badge == 'dummyBadge' } @@ -199,6 +203,8 @@ class VersionControllerSpec extends Specification { WireMock.verify(1, WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/abcdefgh")) .withHeader(DockerBadgeService.HDR_API_KEY, equalTo('dummyKey'))) + WireMock.verify(0, + WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/_uploads"))) WireMock.verify(1, WireMock.getRequestedFor(WireMock.urlPathEqualTo("/static/v1"))) badge == 'dummyBadge' cachedBadge == badge @@ -237,6 +243,8 @@ class VersionControllerSpec extends Specification { WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/latest"))) WireMock.verify(0, WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/abcdefgh"))) + WireMock.verify(0, + WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/_uploads"))) WireMock.verify(1, WireMock.getRequestedFor(WireMock.urlPathEqualTo("/static/v1"))) badge == 'dummyBadge' } diff --git a/src/test/groovy/io/github/devatherock/artifactory/service/DockerBadgeServiceHelperSpec.groovy b/src/test/groovy/io/github/devatherock/artifactory/service/DockerBadgeServiceHelperSpec.groovy new file mode 100644 index 0000000..7097307 --- /dev/null +++ b/src/test/groovy/io/github/devatherock/artifactory/service/DockerBadgeServiceHelperSpec.groovy @@ -0,0 +1,52 @@ +package io.github.devatherock.artifactory.service + +import io.github.devatherock.artifactory.entities.ArtifactoryFolderInfo + +import spock.lang.Specification + +/** + * Test class for {@link DockerBadgeServiceHelper} + */ +class DockerBadgeServiceHelperSpec extends Specification { + + void 'test get version badge value'() { + expect: + DockerBadgeServiceHelper.getVersionBadgeValue(new ArtifactoryFolderInfo(path: path)) == outputVersion + + where: + path | outputVersion + 'docker/devatherock/simple-slack/1.1.0' | 'v1.1.0' + 'docker/devatherock/simple-slack/latest' | 'latest' + } + + void 'test format download count'() { + expect: + DockerBadgeServiceHelper.formatDownloadCount(downloadCount) == formattedCount + + where: + downloadCount | formattedCount + 450 | '450' + 1249 | '1.2k' + 1251 | '1.3k' + 1_100_000 | '1.1M' + 1_100_000_000 | '1.1G' + 1_100_000_000_000 | '1100G' + } + + void 'test compare versions'() { + expect: + DockerBadgeServiceHelper.compareVersions(versionOne, versionTwo, 'major') == expectedResult + + where: + versionOne | versionTwo | expectedResult + '2' | '1.1' | 1 + '1' | '1.1' | -1 + '1.1-alpha' | '1.1-beta' | 0 + '1.1.1-alpha' | '1.1.1-beta' | 0 + '2.5-alpine' | '2.5' | 1 + '2.5' | '2.5-alpine' | -1 + '1.1.1' | '1.1.2' | -1 + '1.1.2' | '1.1.1' | 1 + '1.1.2' | '1.1.2' | 0 + } +} diff --git a/src/test/groovy/io/github/devatherock/artifactory/service/DockerBadgeServiceSpec.groovy b/src/test/groovy/io/github/devatherock/artifactory/service/DockerBadgeServiceSpec.groovy index b32b869..0b46063 100644 --- a/src/test/groovy/io/github/devatherock/artifactory/service/DockerBadgeServiceSpec.groovy +++ b/src/test/groovy/io/github/devatherock/artifactory/service/DockerBadgeServiceSpec.groovy @@ -308,6 +308,8 @@ class DockerBadgeServiceSpec extends Specification { WireMock.verify(1, WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/abcdefgh")) .withHeader(DockerBadgeService.HDR_API_KEY, equalTo('dummyKey'))) + WireMock.verify(0, + WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/_uploads"))) 1 * badgeGenerator.generateBadge('version', 'v1.1.0') >> 'dummyBadge' badge == 'dummyBadge' } @@ -328,37 +330,13 @@ class DockerBadgeServiceSpec extends Specification { WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}")) .withHeader(DockerBadgeService.HDR_API_KEY, equalTo('dummyKey'))) WireMock.verify(0, - WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/1.1.0"))) + WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/1.1.0-alpha"))) WireMock.verify(0, - WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/1.1.2"))) + WireMock.getRequestedFor(urlEqualTo("/artifactory/api/storage/${packageName}/1.1.0-beta"))) 1 * badgeGenerator.generateBadge('version', 'v1.1.0-alpha') >> 'dummyBadge' badge == 'dummyBadge' } - void 'test get version badge value'() { - expect: - dockerBadgeService.getVersionBadgeValue(new ArtifactoryFolderInfo(path: path)) == outputVersion - - where: - path | outputVersion - 'docker/devatherock/simple-slack/1.1.0' | 'v1.1.0' - 'docker/devatherock/simple-slack/latest' | 'latest' - } - - void 'test format download count'() { - expect: - dockerBadgeService.formatDownloadCount(downloadCount) == formattedCount - - where: - downloadCount | formattedCount - 450 | '450' - 1249 | '1.2k' - 1251 | '1.3k' - 1_100_000 | '1.1M' - 1_100_000_000 | '1.1G' - 1_100_000_000_000 | '1100G' - } - void 'test generate not found badge'() { when: String badge = dockerBadgeService.generateNotFoundBadge('layers') @@ -367,21 +345,4 @@ class DockerBadgeServiceSpec extends Specification { 1 * badgeGenerator.generateBadge('layers', 'Not Found') >> 'dummyBadge' badge == 'dummyBadge' } - - void 'test compare versions'() { - expect: - dockerBadgeService.compareVersions(versionOne, versionTwo, 'major') == expectedResult - - where: - versionOne | versionTwo | expectedResult - '2' | '1.1' | 1 - '1' | '1.1' | -1 - '1.1-alpha' | '1.1-beta' | 0 - '1.1.1-alpha' | '1.1.1-beta' | 0 - '2.5-alpine' | '2.5' | 1 - '2.5' | '2.5-alpine' | -1 - '1.1.1' | '1.1.2' | -1 - '1.1.2' | '1.1.1' | 1 - '1.1.2' | '1.1.2' | 0 - } } diff --git a/src/test/groovy/io/github/devatherock/test/TestUtil.groovy b/src/test/groovy/io/github/devatherock/test/TestUtil.groovy index 3647f85..02791d0 100644 --- a/src/test/groovy/io/github/devatherock/test/TestUtil.groovy +++ b/src/test/groovy/io/github/devatherock/test/TestUtil.groovy @@ -23,6 +23,10 @@ class TestUtil { "uri": "/1.1.2", "folder": true }, + { + "uri": "/_uploads", + "folder": true + }, { "uri": "/latest", "folder": true