Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit tests for caching, handled HTTP errors from shields.io - closes #35 #38

Merged
merged 1 commit into from
Nov 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- [#11](https://github.com/devatherock/artifactory-badge/issues/11): Shortened pulls count
- [#25](https://github.com/devatherock/artifactory-badge/issues/25): Used a different `shields.io` URL, so that badge values with `-` are supported
- [#15](https://github.com/devatherock/artifactory-badge/issues/15): Handled HTTP 404s from artifactory APIs
- [#35](https://github.com/devatherock/artifactory-badge/issues/35): Handled HTTP errors from `shields.io`

### Removed
- [#13](https://github.com/devatherock/artifactory-badge/issues/13): Apache HTTP Client
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
package io.github.devatherock.artifactory.config;

import javax.inject.Singleton;

import io.micronaut.context.annotation.Factory;
import io.micronaut.http.client.BlockingHttpClient;
import io.micronaut.http.client.HttpClient;
import io.micronaut.http.client.annotation.Client;

import javax.inject.Singleton;

/**
* Bean definitions for the application
*/
@Factory
public class AppConfig {

/**
* HTTP client for interacting with artifactory APIs
*
* @param artifactoryClient
* HTTP client for interacting with HTTP APIs
*
* @param httpClient
* @return a http client
*/
@Singleton
public BlockingHttpClient httpClient(@Client("${artifactory.url}") HttpClient artifactoryClient) {
return artifactoryClient.toBlocking();
public BlockingHttpClient httpClient(@Client HttpClient httpClient) {
return httpClient.toBlocking();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package io.github.devatherock.artifactory.config;

import javax.annotation.PostConstruct;

import io.micronaut.context.annotation.ConfigurationProperties;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;

Expand All @@ -13,4 +16,17 @@ public class ShieldsIOProperties {
* generate the badge
*/
private boolean enabled = true;

/**
* The {@code shields.io} URL
*/
private String url = "https://img.shields.io";

@Setter(AccessLevel.NONE)
private String badgeUrl;

@PostConstruct
public void init() {
badgeUrl = url + "/static/v1";
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,40 +1,67 @@
package io.github.devatherock.artifactory.util;

import io.github.devatherock.artifactory.config.ShieldsIOProperties;
import io.github.devatherock.artifactory.service.ShieldsIOClient;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.client.BlockingHttpClient;
import io.micronaut.http.client.exceptions.HttpClientResponseException;
import io.micronaut.http.uri.UriBuilder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import javax.inject.Singleton;

/**
* Class to generate the badges
*
* @author devaprasadh
*
* @author devaprasadh
*/
@Slf4j
@Singleton
@RequiredArgsConstructor
public class BadgeGenerator {
private static final int WIDTH_ONE_CHAR = 8;

private final ShieldsIOClient shieldsIOClient;
private final BlockingHttpClient shieldsIOClient;
private final ShieldsIOProperties config;

/**
* Generates a badge with the supplied label and value using
* {@code shields.io} or custom logic
*
* @param label
* @param value
* @return a badge
*/
public String generateBadge(String label, String value) {
LOGGER.debug("In generateBadge");
String badge = null;

if (config.isEnabled()) {
badge = shieldsIOClient.downloadBadge(label, value, "blue");
try {
HttpRequest<Object> badgeRequest = HttpRequest.GET(UriBuilder.of(config.getBadgeUrl())
.queryParam("label", label)
.queryParam("message", value)
.queryParam("color", "blue").build());
badge = shieldsIOClient.retrieve(badgeRequest, String.class);
} catch (HttpClientResponseException exception) {
LOGGER.warn("Exception from shields.io when generating badge for label={}, value={}", label, value,
exception);
badge = generateSvg(label, value);
}
} else {
badge = generateSvg(label, value);
}

return badge;
}

/**
* Generates a custom badge with the supplied label and value
*
* @param label
* @param value
* @return a badge
*/
private String generateSvg(String label, String value) {
LOGGER.debug("Generating custom SVG");
int labelWidth = (label.length() + 2) * WIDTH_ONE_CHAR;
Expand All @@ -43,9 +70,9 @@ private String generateSvg(String label, String value) {
String title = label + ": " + value;

StringBuilder svg = new StringBuilder();
svg.append(
String.format("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"%d\" height=\"20\" role=\"img\" aria-label=\"%s\">",
totalWidth, title));
svg.append(String.format(
"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"%d\" height=\"20\" role=\"img\" aria-label=\"%s\">",
totalWidth, title));
svg.append("<title>");
svg.append(title);
svg.append("</title>");
Expand All @@ -58,15 +85,15 @@ private String generateSvg(String label, String value) {
svg.append("</clipPath>");
svg.append("<g clip-path=\"url(#r)\">");
svg.append(String.format("<rect width=\"%d\" height=\"20\" fill=\"#555\"/>", labelWidth));
svg.append(String.format("<rect x=\"%d\" width=\"%d\" height=\"20\" fill=\"#007ec6\"/>",
labelWidth, valueWidth));
svg.append(
String.format("<rect x=\"%d\" width=\"%d\" height=\"20\" fill=\"#007ec6\"/>", labelWidth, valueWidth));
svg.append(String.format("<rect width=\"%d\" height=\"20\" fill=\"url(#s)\"/>", totalWidth));
svg.append("</g>");
svg.append("<g font-family=\"monospace\">");
svg.append(
String.format("<text aria-hidden=\"true\" x=\"0\" y=\"15\" fill=\"#fff\" xml:space=\"preserve\"> %s </text>",
label));
svg.append(String.format("<text aria-hidden=\"true\" x=\"%d\" y=\"15\" fill=\"#fff\" xml:space=\"preserve\"> %s </text>",
svg.append(String.format(
"<text aria-hidden=\"true\" x=\"0\" y=\"15\" fill=\"#fff\" xml:space=\"preserve\"> %s </text>", label));
svg.append(String.format(
"<text aria-hidden=\"true\" x=\"%d\" y=\"15\" fill=\"#fff\" xml:space=\"preserve\"> %s </text>",
labelWidth, value));
svg.append("</g>");
svg.append("</svg>");
Expand Down
6 changes: 1 addition & 5 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,4 @@ micronaut:
mapping: /swagger/**
swagger-ui:
paths: classpath:META-INF/swagger/views/swagger-ui
mapping: /swagger-ui/**
artifactory:
badge:
shields-io:
url: https://img.shields.io
mapping: /swagger-ui/**
8 changes: 5 additions & 3 deletions src/main/resources/graal/access-filter.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"rules": [
{"excludeClasses": "io.github.devatherock.artifactory.controllers.DockerControllerSpec"},
{"excludeClasses": "io.github.devatherock.artifactory.controllers.VersionControllerSpec"},
{"excludeClasses": "io.github.devatherock.artifactory.config.AppConfigSpec"},
{"excludeClasses": "io.github.devatherock.artifactory.config.ArtifactoryPropertiesSpec"},
{"excludeClasses": "io.github.devatherock.artifactory.util.BadgeGeneratorSpec"},
{"excludeClasses": "io.github.devatherock.artifactory.config.ShieldsIOPropertiesSpec"},
{"excludeClasses": "io.github.devatherock.artifactory.controllers.DockerControllerSpec"},
{"excludeClasses": "io.github.devatherock.artifactory.controllers.VersionControllerSpec"},
{"excludeClasses": "io.github.devatherock.artifactory.service.DockerBadgeServiceSpec"},
{"excludeClasses": "io.github.devatherock.artifactory.util.BadgeGeneratorSpec"},
{"excludeClasses": "io.github.devatherock.test.TestUtil"},
{"excludeClasses": "org.spockframework.**"},
{"excludeClasses": "org.gradle.**"},
{"excludeClasses": "net.sf.cglib.**"},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.devatherock.artifactory.config

import spock.lang.Specification
import spock.lang.Subject

/**
* Test class for {@link ShieldsIOProperties}
*/
class ShieldsIOPropertiesSpec extends Specification {
@Subject
ShieldsIOProperties config = new ShieldsIOProperties()

void 'test init'() {
when:
config.init()

then:
config.badgeUrl == 'https://img.shields.io/static/v1'
}
}
Loading