Verify Artifactory authentication before release build.

We now explicitly access an Artifactory resource to verify authentication so that it's less likely the deployment and promotion will fail later on. Added "artifactory verify" as command to be executed from the shell.
This commit is contained in:
Oliver Gierke
2016-02-10 16:22:35 +01:00
parent 7e99f3dfd1
commit 57ea732e2c
10 changed files with 139 additions and 16 deletions

View File

@@ -102,6 +102,8 @@ public class ReleaseCommands implements CommandMarker {
} else {
deployment.verifyAuthentication();
List<DeploymentInformation> deploymentInformation = build.performRelease(iteration);
git.commit(iteration, "Release version %s.");
deploymentInformation.forEach(deployment::promote);

View File

@@ -59,15 +59,32 @@ class ArtifactoryClient {
try {
template.postForEntity(uri, new PromotionRequest(information.getTargetRepository()), String.class);
} catch (HttpClientErrorException o_O) {
handle(o_O, module);
handle("Promotion failed!", o_O, module);
}
}
private void handle(HttpClientErrorException o_O, ModuleIteration module) {
public void verify() {
URI verificationResource = properties.getServer().getVerificationResource();
try {
logger.log(module, "Promotion failed!");
logger.log("Artifactory", "Verifying authentication using a GET call to %s.", verificationResource);
template.getForEntity(verificationResource, String.class);
logger.log("Artifactory", "Authentication verified!");
} catch (HttpClientErrorException o_O) {
handle("Authentication verification failed!", o_O);
}
}
private void handle(String log, HttpClientErrorException o_O, ModuleIteration module) {
try {
logger.log(module, log);
Errors errors = new ObjectMapper().readValue(o_O.getResponseBodyAsByteArray(), Errors.class);
errors.getErrors().forEach(error -> logger.log(module, error));
@@ -78,6 +95,21 @@ class ArtifactoryClient {
}
}
private void handle(String log, HttpClientErrorException o_O) {
try {
logger.log("Artifactory Client", log);
Errors errors = new ObjectMapper().readValue(o_O.getResponseBodyAsByteArray(), Errors.class);
errors.getErrors().forEach(error -> logger.log("Artifactory Client", error));
errors.getMessages().forEach(message -> logger.log("Artifactory Client", message));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void deleteArtifacts(DeploymentInformation information) {
template.delete(properties.getServer().getDeleteBuildResource(information));
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.release.deployment;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.CliComponent;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.annotation.CliCommand;
/**
* @author Oliver Gierke
*/
@CliComponent
@RequiredArgsConstructor(onConstructor = @__(@Autowired) )
public class ArtifactoryCommands implements CommandMarker {
private final DeploymentOperations deployment;
@CliCommand(value = "artifactory verify", help = "Verifies authentication at Artifactory.")
public void verify() {
deployment.verifyAuthentication();
}
}

View File

@@ -50,7 +50,7 @@ class DeploymentConfiguration {
public RestTemplate artifactoryRestTemplate() {
RestTemplate template = new RestTemplate();
template.setInterceptors(Arrays.asList(new AuthenticatingClientHttpRequestInterceptor(properties.getApiKey())));
template.setInterceptors(Arrays.asList(new AuthenticatingClientHttpRequestInterceptor(properties)));
return template;
}
@@ -58,7 +58,7 @@ class DeploymentConfiguration {
@RequiredArgsConstructor
private static class AuthenticatingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
private final @NonNull String apiKey;
private final @NonNull DeploymentProperties properties;
/*
* (non-Javadoc)
@@ -68,7 +68,8 @@ class DeploymentConfiguration {
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
request.getHeaders().add("X-Api-Key", apiKey);
request.getHeaders().add("X-Api-Key", properties.getApiKey());
request.getHeaders().add("Authentication", properties.getCredentials().toString());
return execution.execute(request, body);
}

View File

@@ -32,6 +32,10 @@ public class DeploymentOperations {
private final ArtifactoryClient client;
public void verifyAuthentication() {
client.verify();
}
/**
* Promotes the artifacts identified by the given {@link DeploymentInformation}.
*

View File

@@ -20,6 +20,7 @@ import lombok.Data;
import java.net.URI;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.data.release.utils.HttpBasicCredentials;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.util.UriTemplate;
@@ -69,11 +70,16 @@ public class DeploymentProperties {
return server.getUri().toString().concat("/").concat(stagingRepository);
}
public HttpBasicCredentials getCredentials() {
return new HttpBasicCredentials(username, password);
}
@Data
public static class Server {
private static final String PROMOTION_RESOURCE = "/api/build/promote/{buildName}/{buildNumber}";
private static final String DELETE_BUILD_RESOURCE = "/api/build/{buildName}?buildNumbers={buildNumber}&artifacts=1";
private static final String VERIFICATION_RESOURCE = "/api/storage/test-libs-staging-local";
private String uri;
@@ -94,5 +100,9 @@ public class DeploymentProperties {
return new UriTemplate(uri.concat(DELETE_BUILD_RESOURCE)).expand(information.getBuildInfoParameters());
}
public URI getVerificationResource() {
return URI.create(uri.concat(VERIFICATION_RESOURCE));
}
}
}

View File

@@ -24,6 +24,7 @@ import javax.annotation.PostConstruct;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.data.release.utils.HttpBasicCredentials;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@@ -58,7 +59,7 @@ public class GitProperties {
return new UsernamePasswordCredentialsProvider(username, password);
}
public String getAuthenticationHeader() {
return username.concat(":").concat(password);
public HttpBasicCredentials getHttpCredentials() {
return new HttpBasicCredentials(username, password);
}
}

View File

@@ -18,9 +18,7 @@ package org.springframework.data.release.jira;
import lombok.RequiredArgsConstructor;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -154,12 +152,8 @@ class GitHubIssueTracker implements IssueTracker {
private HttpHeaders getAuthenticationHeaders() {
byte[] encodedAuth = Base64.getEncoder()
.encode(properties.getAuthenticationHeader().getBytes(Charset.forName("US-ASCII")));
String authHeader = "Basic " + new String(encodedAuth);
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", authHeader);
headers.set("Authorization", properties.getHttpCredentials().toString());
return headers;
}

View File

@@ -51,7 +51,6 @@ public class ExecutionUtils {
throw new RuntimeException(o_O);
}
})).collect(Collectors.toList()).forEach(future -> future.join());
}
/**

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.release.utils;
import lombok.Value;
import java.nio.charset.Charset;
import java.util.Base64;
/**
* @author Oliver Gierke
*/
@Value
public class HttpBasicCredentials {
private final String username, password;
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
String header = username.concat(":").concat(password);
byte[] encodedAuth = Base64.getEncoder().encode(header.getBytes(Charset.forName("US-ASCII")));
return "Basic ".concat(new String(encodedAuth));
}
}