Introduce verify command to verify configuration settings.
Closes #182.
This commit is contained in:
@@ -19,8 +19,13 @@ Add an `application-local.properties` to the project root and add the following
|
||||
- `deployment.password` - The encrypted Artifactory password..
|
||||
- `gpg.keyname` - The GPG key name.
|
||||
- `gpg.password` - The password of your GPG key.
|
||||
- `gpg.executable` - Path to your GPG executable, typically `/usr/local/MacGPG2/bin/gpg2` or `/usr/local/bin/gpg`.
|
||||
- `sagan.key` - Sagan authentication token. Must be a valid GitHub token. Can be the same as `git.password` when using a GitHub token as password.
|
||||
- `gpg.executable` - Path to your GPG executable, typically `/usr/local/MacGPG2/bin/gpg2`
|
||||
or `/usr/local/bin/gpg`.
|
||||
- `sagan.key` - Sagan authentication token. Must be a valid GitHub token. Can be the same
|
||||
as `git.password` when using a GitHub token as password.
|
||||
|
||||
After that, run the `verify` command (`$ verify`) to verify your settings (authentication,
|
||||
correct Maven, Java, and GPG setup).
|
||||
|
||||
See `application-local.template` for details.
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.data.release.model.Module;
|
||||
import org.springframework.data.release.model.ModuleIteration;
|
||||
import org.springframework.data.release.model.Phase;
|
||||
import org.springframework.data.release.model.Project;
|
||||
import org.springframework.data.release.model.Projects;
|
||||
import org.springframework.data.release.model.Train;
|
||||
import org.springframework.data.release.model.TrainIteration;
|
||||
import org.springframework.data.release.utils.Logger;
|
||||
@@ -198,6 +199,12 @@ public class BuildOperations {
|
||||
executor.doWithBuildSystemAnyOrder(iteration, BuildSystem::triggerPreReleaseCheck);
|
||||
}
|
||||
|
||||
public void verify() {
|
||||
|
||||
BuildSystem buildSystem = buildSystems.getRequiredPluginFor(Projects.BUILD);
|
||||
buildSystem.verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the build system for the module contained in the given {@link ModuleIteration} and executes the given
|
||||
* function with it.
|
||||
@@ -215,4 +222,5 @@ public class BuildOperations {
|
||||
|
||||
return function.apply(buildSystems.getPluginFor(module.getProject(), exception), module);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,4 +72,9 @@ interface BuildSystem extends Plugin<Project> {
|
||||
* @return
|
||||
*/
|
||||
<M extends ProjectAware> M triggerPreReleaseCheck(M module);
|
||||
|
||||
/**
|
||||
* Verify general functionality and correctness of the build setup.
|
||||
*/
|
||||
void verify();
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Value object to represent a Maven command line.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Value
|
||||
@@ -46,7 +46,7 @@ class CommandLine {
|
||||
|
||||
/**
|
||||
* Creates a new {@link CommandLine} for the given {@link Goal} and {@link Argument}s.
|
||||
*
|
||||
*
|
||||
* @param goal must not be {@literal null}.
|
||||
* @param argument must not be {@literal null}.
|
||||
* @return
|
||||
@@ -57,7 +57,7 @@ class CommandLine {
|
||||
|
||||
/**
|
||||
* Creates a new {@link CommandLine} for the given {@link Goal}s and {@link Argument}s.
|
||||
*
|
||||
*
|
||||
* @param goal must not be {@literal null}.
|
||||
* @param argument must not be {@literal null}.
|
||||
* @return
|
||||
@@ -69,7 +69,7 @@ class CommandLine {
|
||||
/**
|
||||
* Returns a new {@link CommandLine} with the given {@link Argument} added in case the given {@link BooleanSupplier}
|
||||
* evaluates to {@literal true}.
|
||||
*
|
||||
*
|
||||
* @param argument must not be {@literal null}.
|
||||
* @param condition must not be {@literal null}.
|
||||
* @return
|
||||
@@ -80,7 +80,7 @@ class CommandLine {
|
||||
|
||||
/**
|
||||
* Returns a new {@link CommandLine} with the given {@link Argument} added.
|
||||
*
|
||||
*
|
||||
* @param argument must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -98,7 +98,7 @@ class CommandLine {
|
||||
/**
|
||||
* Renders the current {@link CommandLine} as a plain {@link List} of {@link String}s using the given {@link Function}
|
||||
* to expand the {@link Goal}s.
|
||||
*
|
||||
*
|
||||
* @param goalExpansion must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -110,7 +110,7 @@ class CommandLine {
|
||||
return Stream.concat(goalStream, argumentStream).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@@ -135,6 +135,7 @@ class CommandLine {
|
||||
public static final Goal INSTALL = Goal.goal("install");
|
||||
public static final Goal DEPLOY = Goal.goal("deploy");
|
||||
public static final Goal VALIDATE = Goal.goal("validate");
|
||||
public static final Goal VERIFY = Goal.goal("verify");
|
||||
|
||||
String goal;
|
||||
}
|
||||
@@ -158,7 +159,7 @@ class CommandLine {
|
||||
|
||||
/**
|
||||
* Enables the given comma-separated profiles for the {@link CommandLine}.
|
||||
*
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
@@ -196,7 +197,7 @@ class CommandLine {
|
||||
return toNameValuePair(value.map(ArgumentValue::toCommandLine));
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@@ -229,7 +230,7 @@ class CommandLine {
|
||||
|
||||
/**
|
||||
* Returns an {@link ArgumentValue} for the given {@link Masked} value.
|
||||
*
|
||||
*
|
||||
* @param masked must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -239,7 +240,7 @@ class CommandLine {
|
||||
|
||||
/**
|
||||
* Returns the {@link String} variant of the argument value.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String toCommandLine() {
|
||||
|
||||
@@ -306,6 +306,28 @@ class MavenBuildSystem implements BuildSystem {
|
||||
return isMavenProject(project);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.release.build.BuildSystem#verify()
|
||||
*/
|
||||
@Override
|
||||
public void verify() {
|
||||
|
||||
logger.log(BUILD, "Verifying Maven Build System…");
|
||||
|
||||
CommandLine arguments = CommandLine.of(Goal.CLEAN, Goal.VERIFY, //
|
||||
profile("central"), //
|
||||
SKIP_TESTS, //
|
||||
arg("gpg.executable").withValue(gpg.getExecutable()), //
|
||||
arg("gpg.keyname").withValue(gpg.getKeyname()), //
|
||||
arg("gpg.password").withValue(gpg.getPassword()));
|
||||
|
||||
mvn.execute(BUILD, arguments);
|
||||
|
||||
mvn.execute(BUILD, CommandLine.of(Goal.goal("nexus-staging:rc-list-profiles"), //
|
||||
profile("central")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers Maven commands to deploy module artifacts to Spring Artifactory.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2021 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
|
||||
*
|
||||
* https://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.cli;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import org.springframework.data.release.CliComponent;
|
||||
import org.springframework.data.release.TimedCommand;
|
||||
import org.springframework.data.release.build.BuildOperations;
|
||||
import org.springframework.data.release.deployment.DeploymentOperations;
|
||||
import org.springframework.data.release.git.GitOperations;
|
||||
import org.springframework.data.release.issues.github.GitHub;
|
||||
import org.springframework.data.release.issues.jira.Jira;
|
||||
import org.springframework.data.release.sagan.SaganClient;
|
||||
import org.springframework.data.release.utils.Logger;
|
||||
import org.springframework.shell.core.annotation.CliCommand;
|
||||
|
||||
/**
|
||||
* Commands to verify a correct Release Tools Setup.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@CliComponent
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
|
||||
class VerifyCommands extends TimedCommand {
|
||||
|
||||
@NonNull GitOperations git;
|
||||
@NonNull GitHub github;
|
||||
@NonNull DeploymentOperations deployment;
|
||||
@NonNull BuildOperations build;
|
||||
@NonNull Jira jira;
|
||||
@NonNull SaganClient saganClient;
|
||||
@NonNull Logger logger;
|
||||
|
||||
@CliCommand("verify")
|
||||
public void verifyReleaseTools() {
|
||||
|
||||
// Git checkout build
|
||||
git.verify();
|
||||
|
||||
// Maven interaction
|
||||
build.verify();
|
||||
|
||||
// Artifactory verification
|
||||
deployment.verifyAuthentication();
|
||||
|
||||
// GitHub verification
|
||||
github.verifyAuthentication();
|
||||
|
||||
// Jira verification
|
||||
jira.verifyAuthentication();
|
||||
|
||||
// Sagan Verification
|
||||
saganClient.verifyAuthentication();
|
||||
|
||||
logger.log("Verify", "All settings are verified. You can ship a release now.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -812,6 +812,13 @@ public class GitOperations {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify general Git operations.
|
||||
*/
|
||||
public void verify() {
|
||||
checkout(Projects.BUILD, Branch.MASTER);
|
||||
}
|
||||
|
||||
private void cherryPickCommitToBranch(ObjectId id, Project project, Branch branch) {
|
||||
|
||||
doWithGit(project, git -> {
|
||||
|
||||
@@ -53,6 +53,7 @@ import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
@@ -62,7 +63,7 @@ import org.springframework.web.client.HttpStatusCodeException;
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Component
|
||||
class GitHub extends GitHubSupport implements IssueTracker {
|
||||
public class GitHub extends GitHubSupport implements IssueTracker {
|
||||
|
||||
private static final String MILESTONE_URI = "/repos/spring-projects/{repoName}/milestones?state={state}";
|
||||
private static final String ISSUES_BY_MILESTONE_AND_ASSIGNEE_URI_TEMPLATE = "/repos/spring-projects/{repoName}/issues?milestone={id}&state=all&assignee={assignee}";
|
||||
@@ -565,6 +566,28 @@ class GitHub extends GitHubSupport implements IssueTracker {
|
||||
logger.log(module, "GitHub Release up to date");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify GitHub authentication.
|
||||
*/
|
||||
public void verifyAuthentication() {
|
||||
|
||||
logger.log("GitHub", "Verifying GitHub Authentication…");
|
||||
|
||||
String repositoryName = GitProject.of(Projects.BUILD).getRepositoryName();
|
||||
|
||||
Map<String, Object> parameters = newUrlTemplateVariables();
|
||||
parameters.put("repoName", repositoryName);
|
||||
|
||||
// /user requires authentication
|
||||
ResponseEntity<Object> entity = operations.getForEntity("/user", Object.class);
|
||||
|
||||
if (!entity.getStatusCode().is2xxSuccessful()) {
|
||||
throw new IllegalStateException(String.format("Cannot obtain /user. Status: %s", entity.getStatusCode()));
|
||||
}
|
||||
|
||||
logger.log("GitHub", "Authentication verified!");
|
||||
}
|
||||
|
||||
private String getDocumentationLinks(ModuleIteration module, DocumentationMetadata documentation) {
|
||||
|
||||
String referenceDocUrl = documentation.getReferenceDocUrl(module.getTrain());
|
||||
|
||||
@@ -59,7 +59,7 @@ import org.springframework.web.util.DefaultUriBuilderFactory;
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Component
|
||||
class Jira implements JiraConnector {
|
||||
public class Jira implements JiraConnector {
|
||||
|
||||
private static final String CREATE_ISSUES_TEMPLATE = "/issue";
|
||||
private static final String ISSUE_TEMPLATE = "/issue/{ticketId}";
|
||||
@@ -620,6 +620,22 @@ class Jira implements JiraConnector {
|
||||
return project.uses(Tracker.JIRA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify Jira Authentication.
|
||||
*/
|
||||
public void verifyAuthentication() {
|
||||
|
||||
logger.log("Jira", "Verifying Jira Authentication…");
|
||||
|
||||
ResponseEntity<Object> entity = operations.getForEntity("/myself", Object.class);
|
||||
|
||||
if (!entity.getStatusCode().is2xxSuccessful()) {
|
||||
throw new IllegalStateException("Cannot access Jira user profile");
|
||||
}
|
||||
|
||||
logger.log("Jira", "Authentication verified!");
|
||||
}
|
||||
|
||||
protected JiraComponents getJiraComponents(ProjectKey projectKey) {
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
@@ -27,7 +27,9 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.release.model.Project;
|
||||
import org.springframework.data.release.model.Projects;
|
||||
import org.springframework.data.release.utils.Logger;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
@@ -104,6 +106,26 @@ class DefaultSaganClient implements SaganClient {
|
||||
createVersions(versions, resource, versionsInSagan);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.release.sagan.SaganClient#verifyAuthentication()
|
||||
*/
|
||||
@Override
|
||||
public void verifyAuthentication() {
|
||||
|
||||
URI resource = properties.getProjectReleasesResource(Projects.BUILD);
|
||||
|
||||
logger.log("Sagan", "Verifying Sagan Authentication…");
|
||||
|
||||
ResponseEntity<String> entity = operations.getForEntity(resource, String.class);
|
||||
|
||||
if (!entity.getStatusCode().is2xxSuccessful()) {
|
||||
throw new IllegalStateException("Cannot access Jira user profile");
|
||||
}
|
||||
|
||||
logger.log("Sagan", "Authentication verified!");
|
||||
}
|
||||
|
||||
private void createVersions(MaintainedVersions versions, URI resource, List<String> versionsInSagan) {
|
||||
|
||||
versions.stream() //
|
||||
|
||||
@@ -85,4 +85,13 @@ class DummySaganClient implements SaganClient {
|
||||
public String getProjectMetadata(Project project) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.release.sagan.SaganClient#verifyAuthentication()
|
||||
*/
|
||||
@Override
|
||||
public void verifyAuthentication() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,15 @@ import org.springframework.data.release.model.Project;
|
||||
|
||||
/**
|
||||
* Interface to abstract the actual interaction with the Sagan server.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
interface SaganClient {
|
||||
public interface SaganClient {
|
||||
|
||||
/**
|
||||
* Returns the project metadata for the given {@link MaintainedVersion}.
|
||||
*
|
||||
*
|
||||
* @param version must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -34,7 +35,7 @@ interface SaganClient {
|
||||
|
||||
/**
|
||||
* Returns all project release metadata for the given {@link Project}.
|
||||
*
|
||||
*
|
||||
* @param project must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -42,9 +43,14 @@ interface SaganClient {
|
||||
|
||||
/**
|
||||
* Updates the project metadata for the given {@link Project} to the given {@link MaintainedVersions}.
|
||||
*
|
||||
*
|
||||
* @param project must not be {@literal null}.
|
||||
* @param versions must not be {@literal null}.
|
||||
*/
|
||||
void updateProjectMetadata(Project project, MaintainedVersions versions);
|
||||
|
||||
/**
|
||||
* Verify correct authentication setup.
|
||||
*/
|
||||
void verifyAuthentication();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user