#44 - Added infrastructure to prevent passwords from being printed to the console.
Introduced value objects to properly abstract command line arguments and introduced an interface Masked that allows masking a String value when printed to the console.
This commit is contained in:
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright 2017 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.build;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.data.release.model.Masked;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Value object to represent a Maven command line.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Value
|
||||
class CommandLine {
|
||||
|
||||
@NonNull List<Goal> goals;
|
||||
@NonNull List<Argument> arguments;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public static CommandLine of(Goal goal, Argument... argument) {
|
||||
return new CommandLine(Collections.singletonList(goal), Arrays.asList(argument));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public static CommandLine of(Goal first, Goal second, Argument... argument) {
|
||||
return new CommandLine(Arrays.asList(first, second), Arrays.asList(argument));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public CommandLine conditionalAnd(Argument argument, BooleanSupplier condition) {
|
||||
return condition.getAsBoolean() ? and(argument) : this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link CommandLine} with the given {@link Argument} added.
|
||||
*
|
||||
* @param argument must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public CommandLine and(Argument argument) {
|
||||
|
||||
Assert.notNull(argument, "Argument must not be null!");
|
||||
|
||||
List<Argument> newArguments = new ArrayList<Argument>(arguments.size() + 1);
|
||||
newArguments.addAll(arguments);
|
||||
newArguments.add(argument);
|
||||
|
||||
return new CommandLine(goals, newArguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public List<String> toCommandLine(Function<Goal, String> goalExpansion) {
|
||||
|
||||
Stream<String> goalStream = goals.stream().map(goalExpansion);
|
||||
Stream<String> argumentStream = arguments.stream().map(it -> it.toCommandLineArgument());
|
||||
|
||||
return Stream.concat(goalStream, argumentStream).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
Stream<String> goalStream = goals.stream().map(it -> it.getGoal());
|
||||
Stream<String> argumentStream = arguments.stream().map(Object::toString);
|
||||
|
||||
return Stream.concat(goalStream, argumentStream).collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a Maven goal to invoke. Can be a custom one but also one of the predefined instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Value(staticConstructor = "goal")
|
||||
public static class Goal {
|
||||
|
||||
public static final Goal CLEAN = Goal.goal("clean");
|
||||
public static final Goal INSTALL = Goal.goal("install");
|
||||
public static final Goal DEPLOY = Goal.goal("deploy");
|
||||
public static final Goal VALIDATE = Goal.goal("validate");
|
||||
|
||||
String goal;
|
||||
}
|
||||
|
||||
@Value
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public static class Argument {
|
||||
|
||||
public static Argument SKIP_TESTS = Argument.arg("skipTests");
|
||||
|
||||
@NonNull String name;
|
||||
@NonNull Optional<ArgumentValue<?>> value;
|
||||
|
||||
private Argument(String name, ArgumentValue<?> value) {
|
||||
this(name, Optional.of(value));
|
||||
}
|
||||
|
||||
static Argument of(String name) {
|
||||
return new Argument(name, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the given comma-separated profiles for the {@link CommandLine}.
|
||||
*
|
||||
* @param name must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public static Argument profile(String name, String... others) {
|
||||
|
||||
Assert.hasText(name, "Profiles must not be null or empty!");
|
||||
Assert.notNull(others, "Other profiles must not be null!");
|
||||
|
||||
String profiles = Stream.concat(Stream.of(name), Arrays.stream(others)).collect(Collectors.joining(","));
|
||||
|
||||
return Argument.of("-P".concat(profiles));
|
||||
}
|
||||
|
||||
public static Argument arg(String name) {
|
||||
return Argument.of("-D".concat(name));
|
||||
}
|
||||
|
||||
public Argument withValue(Object value) {
|
||||
return new Argument(name, ArgumentValue.of(value));
|
||||
}
|
||||
|
||||
public Argument withQuotedValue(Object value) {
|
||||
return new Argument(name, ArgumentValue.of(value, it -> String.format("\"%s\"", it.toString())));
|
||||
}
|
||||
|
||||
public Argument withValue(Masked masked) {
|
||||
return new Argument(name, ArgumentValue.of(masked));
|
||||
}
|
||||
|
||||
public String toCommandLineArgument() {
|
||||
return toNameValuePair(value.map(ArgumentValue::toCommandLine));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toNameValuePair(value.map(Object::toString));
|
||||
}
|
||||
|
||||
private String toNameValuePair(Optional<String> source) {
|
||||
|
||||
return source//
|
||||
.map(it -> String.format("%s=%s", name, it))//
|
||||
.orElse(name);
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
private static class ArgumentValue<T> {
|
||||
|
||||
private final @NonNull T value;
|
||||
private final @NonNull Optional<Function<T, String>> preparer;
|
||||
private final @NonNull Optional<Function<T, String>> toString;
|
||||
|
||||
public static <T> ArgumentValue<T> of(T value) {
|
||||
return new ArgumentValue<>(value, Optional.empty(), Optional.empty());
|
||||
}
|
||||
|
||||
public static <T> ArgumentValue<T> of(T value, Function<T, String> preparer) {
|
||||
return new ArgumentValue<>(value, Optional.of(preparer), Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ArgumentValue} for the given {@link Masked} value.
|
||||
*
|
||||
* @param masked must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static <T extends Masked> ArgumentValue<T> of(T masked) {
|
||||
return new ArgumentValue<>(masked, Optional.empty(), Optional.of(it -> it.masked()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link String} variant of the argument value.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String toCommandLine() {
|
||||
return preparer.map(it -> it.apply(value)).orElseGet(() -> value.toString());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
return toString.map(it -> it.apply(value)).orElseGet(() -> toCommandLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.release.build;
|
||||
|
||||
import static org.springframework.data.release.build.CommandLine.Argument.*;
|
||||
import static org.springframework.data.release.build.CommandLine.Goal.*;
|
||||
import static org.springframework.data.release.model.Projects.*;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
@@ -22,11 +24,11 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.data.release.build.CommandLine.Argument;
|
||||
import org.springframework.data.release.build.CommandLine.Goal;
|
||||
import org.springframework.data.release.deployment.DefaultDeploymentInformation;
|
||||
import org.springframework.data.release.deployment.DeploymentInformation;
|
||||
import org.springframework.data.release.deployment.DeploymentProperties;
|
||||
@@ -109,7 +111,8 @@ class MavenBuildSystem implements BuildSystem {
|
||||
|
||||
logger.log(project, "Triggering distribution build…");
|
||||
|
||||
mvn.execute(project, "clean", "deploy", "-DskipTests", "-Pdistribute", "-B");
|
||||
mvn.execute(project, CommandLine.of(Goal.CLEAN, Goal.DEPLOY, //
|
||||
SKIP_TESTS, profile("distribute"), Argument.of("-B")));
|
||||
|
||||
logger.log(project, "Successfully finished distribution build!");
|
||||
|
||||
@@ -186,17 +189,8 @@ class MavenBuildSystem implements BuildSystem {
|
||||
|
||||
logger.log(project, "Triggering distribution build…");
|
||||
|
||||
ArtifactVersion version = ArtifactVersion.of(module);
|
||||
|
||||
String profile = "-Pdistribute";
|
||||
|
||||
if (version.isMilestoneVersion()) {
|
||||
profile = profile.concat(",milestone");
|
||||
} else if (version.isReleaseVersion()) {
|
||||
profile = profile.concat(",release");
|
||||
}
|
||||
|
||||
mvn.execute(project, "clean", "deploy", "-DskipTests", profile);
|
||||
mvn.execute(project,
|
||||
CommandLine.of(Goal.CLEAN, Goal.DEPLOY, ReleaseVersion.of(module).getDistributionProfiles(), SKIP_TESTS));
|
||||
|
||||
logger.log(project, "Successfully finished distribution build!");
|
||||
});
|
||||
@@ -212,17 +206,18 @@ class MavenBuildSystem implements BuildSystem {
|
||||
Project project = module.getProject();
|
||||
UpdateInformation information = UpdateInformation.of(module.getTrainIteration(), phase);
|
||||
|
||||
mvn.execute(project, "versions:set", "versions:commit",
|
||||
"-DnewVersion=".concat(information.getProjectVersionToSet(project).toString()));
|
||||
CommandLine goals = CommandLine.of(goal("versions:set"), goal("versions:commit"));
|
||||
|
||||
mvn.execute(project, goals.and(arg("newVersion").withValue(information.getProjectVersionToSet(project))));
|
||||
|
||||
if (BUILD.equals(project)) {
|
||||
|
||||
mvn.execute(project, "versions:set", //
|
||||
"-DnewVersion=".concat(information.getReleaseTrainVersion()), //
|
||||
"-DgroupId=org.springframework.data", //
|
||||
"-DartifactId=spring-data-releasetrain");
|
||||
mvn.execute(project,
|
||||
goals.and(arg("newVersion").withValue(information.getReleaseTrainVersion()))//
|
||||
.and(arg("groupId").withValue("org.springframework.data"))//
|
||||
.and(arg("artifactId").withValue("spring-data-releasetrain")));
|
||||
|
||||
mvn.execute(project, "install");
|
||||
mvn.execute(project, CommandLine.of(Goal.INSTALL));
|
||||
}
|
||||
|
||||
return module;
|
||||
@@ -252,13 +247,8 @@ class MavenBuildSystem implements BuildSystem {
|
||||
@Override
|
||||
public ModuleIteration triggerBuild(ModuleIteration module) {
|
||||
|
||||
List<String> arguments = new ArrayList<>();
|
||||
arguments.add("clean");
|
||||
arguments.add("install");
|
||||
|
||||
if (module.getProject().skipTests()) {
|
||||
arguments.add("-DskipTests");
|
||||
}
|
||||
CommandLine arguments = CommandLine.of(Goal.CLEAN, Goal.INSTALL)//
|
||||
.conditionalAnd(SKIP_TESTS, () -> module.getProject().skipTests());
|
||||
|
||||
mvn.execute(module.getProject(), arguments);
|
||||
|
||||
@@ -271,7 +261,7 @@ class MavenBuildSystem implements BuildSystem {
|
||||
*/
|
||||
public ModuleIteration triggerPreReleaseCheck(ModuleIteration module) {
|
||||
|
||||
mvn.execute(module.getProject(), "clean", "validate", "-Ppre-release");
|
||||
mvn.execute(module.getProject(), CommandLine.of(Goal.CLEAN, Goal.VALIDATE, profile("pre-release")));
|
||||
|
||||
return module;
|
||||
}
|
||||
@@ -298,18 +288,15 @@ class MavenBuildSystem implements BuildSystem {
|
||||
|
||||
logger.log(module, "Deploying artifacts to Spring Artifactory…");
|
||||
|
||||
List<String> arguments = new ArrayList<>();
|
||||
arguments.add("clean");
|
||||
arguments.add("deploy");
|
||||
|
||||
arguments.add("-Pci,release");
|
||||
arguments.add("-DskipTests");
|
||||
arguments.add("-Dartifactory.server=".concat(properties.getServer().getUri()));
|
||||
arguments.add("-Dartifactory.staging-repository=".concat(properties.getStagingRepository()));
|
||||
arguments.add("-Dartifactory.username=".concat(properties.getUsername()));
|
||||
arguments.add("-Dartifactory.password=".concat(properties.getPassword()));
|
||||
arguments.add("-Dartifactory.build-name=\"".concat(information.getBuildName()).concat("\""));
|
||||
arguments.add("-Dartifactory.build-number=".concat(information.getBuildNumber()));
|
||||
CommandLine arguments = CommandLine.of(Goal.CLEAN, Goal.DEPLOY, //
|
||||
profile("ci,release"), //
|
||||
SKIP_TESTS, //
|
||||
arg("artifactory.server").withValue(properties.getServer().getUri()),
|
||||
arg("artifactory.staging-repository").withValue(properties.getStagingRepository()),
|
||||
arg("artifactory.username").withValue(properties.getUsername()),
|
||||
arg("artifactory.password").withValue(properties.getPassword()),
|
||||
arg("artifactory.build-name").withQuotedValue(information.getBuildName()),
|
||||
arg("artifactory.build-number").withValue(information.getBuildNumber()));
|
||||
|
||||
mvn.execute(module.getProject(), arguments);
|
||||
}
|
||||
@@ -332,16 +319,13 @@ class MavenBuildSystem implements BuildSystem {
|
||||
|
||||
logger.log(module, "Deploying artifacts to Sonatype OSS Nexus…");
|
||||
|
||||
List<String> arguments = new ArrayList<>();
|
||||
arguments.add("deploy");
|
||||
arguments.add("-Pci,central");
|
||||
arguments.add("-DskipTests");
|
||||
|
||||
Gpg gpg = properties.getGpg();
|
||||
|
||||
arguments.add("-Dgpg.executable=".concat(gpg.getExecutable()));
|
||||
arguments.add("-Dgpg.keyname=".concat(gpg.getKeyname()));
|
||||
arguments.add("-Dgpg.password=".concat(gpg.getPassword()));
|
||||
CommandLine arguments = CommandLine.of(Goal.DEPLOY, //
|
||||
profile("ci,central"), //
|
||||
SKIP_TESTS, //
|
||||
arg("gpg.executable").withValue(gpg.getExecutable()), arg("gpg.keyname").withValue(gpg.getKeyname()),
|
||||
arg("gpg.password").withValue(gpg.getPassword()));
|
||||
|
||||
mvn.execute(module.getProject(), arguments);
|
||||
}
|
||||
@@ -371,4 +355,42 @@ class MavenBuildSystem implements BuildSystem {
|
||||
throw new RuntimeException(o_O);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
private static class ReleaseVersion {
|
||||
|
||||
private final ArtifactVersion version;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ReleaseVersion} for the given {@link ModuleIteration}.
|
||||
*
|
||||
* @param module must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static ReleaseVersion of(ModuleIteration module) {
|
||||
|
||||
ArtifactVersion artifactVersion = ArtifactVersion.of(module);
|
||||
|
||||
Assert.isTrue(artifactVersion.isMilestoneVersion() || artifactVersion.isReleaseVersion(),
|
||||
String.format("Given module is not in a fixed version, detected %s!", artifactVersion));
|
||||
|
||||
return new ReleaseVersion(ArtifactVersion.of(module));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Maven profiles to be used during the distribution build.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Argument getDistributionProfiles() {
|
||||
|
||||
if (version.isMilestoneVersion()) {
|
||||
return profile("distribute", "milestone");
|
||||
} else if (version.isReleaseVersion()) {
|
||||
return profile("distribute", "release");
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Should not occur!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,6 @@ package org.springframework.data.release.build;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.maven.shared.invoker.DefaultInvocationRequest;
|
||||
import org.apache.maven.shared.invoker.DefaultInvoker;
|
||||
@@ -75,24 +72,16 @@ class MavenRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
public void execute(Project project, String... arguments) {
|
||||
execute(project, Arrays.asList(arguments));
|
||||
}
|
||||
|
||||
public void execute(Project project, List<String> arguments) {
|
||||
public void execute(Project project, CommandLine arguments) {
|
||||
|
||||
DefaultInvocationRequest request = new DefaultInvocationRequest();
|
||||
request.setJavaHome(os.getJavaHome());
|
||||
request.setShellEnvironmentInherited(true);
|
||||
request.setBaseDirectory(workspace.getProjectDirectory(project));
|
||||
|
||||
List<String> goals = arguments.stream()//
|
||||
.map(argument -> properties.getFullyQualifiedPlugin(argument))//
|
||||
.collect(Collectors.toList());
|
||||
logger.log(project, "Executing mvn %s", arguments.toString());
|
||||
|
||||
request.setGoals(goals);
|
||||
|
||||
logger.log(project, "Executing mvn %s", goals.stream().collect(Collectors.joining(" ")));
|
||||
request.setGoals(arguments.toCommandLine(it -> properties.getFullyQualifiedPlugin(it.getGoal())));
|
||||
|
||||
try {
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import lombok.Data;
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.data.release.model.Password;
|
||||
import org.springframework.data.release.utils.HttpBasicCredentials;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -48,7 +49,7 @@ public class DeploymentProperties {
|
||||
/**
|
||||
* The deployer's password.
|
||||
*/
|
||||
private String password;
|
||||
private Password password;
|
||||
|
||||
/**
|
||||
* The repository to deploy the artifacts to.
|
||||
@@ -110,6 +111,7 @@ public class DeploymentProperties {
|
||||
|
||||
@Data
|
||||
public static class Gpg {
|
||||
private String keyname, password, executable;
|
||||
private String keyname, executable;
|
||||
private Password password;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.model.Password;
|
||||
import org.springframework.data.release.utils.HttpBasicCredentials;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -39,14 +40,14 @@ import org.springframework.util.Assert;
|
||||
@ConfigurationProperties(prefix = "git")
|
||||
public class GitProperties {
|
||||
|
||||
private @Getter(AccessLevel.PRIVATE) String password;
|
||||
private @Getter(AccessLevel.PRIVATE) Password password;
|
||||
private String username, author, email;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
|
||||
Assert.hasText(username, "No GitHub username (git.username) configured!");
|
||||
Assert.hasText(password, "No GitHub password (git.password) configured!");
|
||||
Assert.notNull(password, "No GitHub password (git.password) configured!");
|
||||
Assert.hasText(author, "No Git author (git.author) configured!");
|
||||
Assert.hasText(email, "No Git email (git.email) configured!");
|
||||
}
|
||||
@@ -57,7 +58,7 @@ public class GitProperties {
|
||||
* @return
|
||||
*/
|
||||
public CredentialsProvider getCredentials() {
|
||||
return new UsernamePasswordCredentialsProvider(username, password);
|
||||
return new UsernamePasswordCredentialsProvider(username, password.toString());
|
||||
}
|
||||
|
||||
public HttpBasicCredentials getHttpCredentials() {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2017 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.model;
|
||||
|
||||
/**
|
||||
* Interface to exposes a method {@link #masked()} to hide an actual value (usually for security reasons).
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface Masked {
|
||||
|
||||
/**
|
||||
* Returns a masked {@link String} as well as information about the type whose String representation was masked.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
default String masked() {
|
||||
return String.format("******** (%s)", getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2017 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.model;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Value object to represent a password.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Value
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class Password implements Masked {
|
||||
|
||||
@Getter(AccessLevel.NONE) String value;
|
||||
|
||||
/**
|
||||
* Create a new {@link Password} for the given value.
|
||||
*
|
||||
* @param password
|
||||
* @return
|
||||
*/
|
||||
public static Password of(String password) {
|
||||
|
||||
Assert.hasText(password, "Password must not be null or empty!");
|
||||
return new Password(password);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -20,13 +20,16 @@ import lombok.Value;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
import org.springframework.data.release.model.Password;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Value
|
||||
public class HttpBasicCredentials {
|
||||
|
||||
private final String username, password;
|
||||
private final String username;
|
||||
private final Password password;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -34,7 +37,7 @@ public class HttpBasicCredentials {
|
||||
*/
|
||||
public String toString() {
|
||||
|
||||
String header = username.concat(":").concat(password);
|
||||
String header = username.concat(":").concat(password.toString());
|
||||
byte[] encodedAuth = Base64.getEncoder().encode(header.getBytes(StandardCharsets.US_ASCII));
|
||||
|
||||
return "Basic ".concat(new String(encodedAuth));
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2017 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.build;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.release.build.CommandLine.Argument;
|
||||
import org.springframework.data.release.model.Password;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link Argument}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class ArgumentUnitTest {
|
||||
|
||||
@Test
|
||||
public void masksMaskedForToString() {
|
||||
|
||||
Argument argument = Argument.of("password").withValue(Password.of("password"));
|
||||
|
||||
assertThat(argument.toCommandLineArgument(), is("password=password"));
|
||||
assertThat(argument.toString(), startsWith("password=********"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quotesValue() {
|
||||
|
||||
Argument argument = Argument.of("quoted").withQuotedValue("value");
|
||||
|
||||
assertThat(argument.toCommandLineArgument(), is("quoted=\"value\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void argCreatesJvmArgument() {
|
||||
assertThat(Argument.arg("foo").toCommandLineArgument(), is("-Dfoo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void profileCreatesMavenProfile() {
|
||||
assertThat(Argument.profile("foo").toCommandLineArgument(), is("-Pfoo"));
|
||||
assertThat(Argument.profile("foo", "bar").toCommandLineArgument(), is("-Pfoo,bar"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user