#130 - Enable commit signing if gpg Properties are set.
We now sign commits if GPG properties are set. We pulled GPG properties from deployment.gpg to the top level (gpg). For the deployment, we fall back to deployment.gpg if toplevel GPG properties aren't set.
This commit is contained in:
@@ -20,9 +20,9 @@ jira.password=
|
||||
jira.url=https://jira.spring.io
|
||||
|
||||
# GPG
|
||||
deployment.gpg.keyname=
|
||||
deployment.gpg.password=
|
||||
# deployment.gpg.executable=/usr/local/bin/gpg2
|
||||
gpg.keyname=
|
||||
gpg.password=
|
||||
# gpg.executable=/usr/local/bin/gpg2
|
||||
|
||||
# A GitHub token with user:email, read:user and read:org scopes.
|
||||
# User needs to be part of the Spring team on GitHub as well.
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jgit</groupId>
|
||||
<artifactId>org.eclipse.jgit</artifactId>
|
||||
<version>4.2.0.201601211800-r</version>
|
||||
<version>5.7.0.202003110725-r</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -16,6 +16,10 @@ Add an `application-local.properties` to the project root and add the following
|
||||
- `maven.mavenHome` - Pointing to the location of your Maven installation.
|
||||
- `deployment.api-key` - The API key to use for artifact promotion.
|
||||
- `deployment.password` - The password of the deployment user (buildmaster).
|
||||
- `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`.
|
||||
|
||||
|
||||
See `application-local.template` for details.
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ import org.springframework.data.release.build.Pom.Artifact;
|
||||
import org.springframework.data.release.deployment.DefaultDeploymentInformation;
|
||||
import org.springframework.data.release.deployment.DeploymentInformation;
|
||||
import org.springframework.data.release.deployment.DeploymentProperties;
|
||||
import org.springframework.data.release.deployment.DeploymentProperties.Gpg;
|
||||
import org.springframework.data.release.io.Workspace;
|
||||
import org.springframework.data.release.model.ArtifactVersion;
|
||||
import org.springframework.data.release.model.Gpg;
|
||||
import org.springframework.data.release.model.ModuleIteration;
|
||||
import org.springframework.data.release.model.Phase;
|
||||
import org.springframework.data.release.model.Project;
|
||||
@@ -66,6 +66,7 @@ class MavenBuildSystem implements BuildSystem {
|
||||
Logger logger;
|
||||
MavenRuntime mvn;
|
||||
DeploymentProperties properties;
|
||||
Gpg gpg;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -331,7 +332,7 @@ class MavenBuildSystem implements BuildSystem {
|
||||
|
||||
logger.log(module, "Deploying artifacts to Sonatype OSS Nexus…");
|
||||
|
||||
Gpg gpg = properties.getGpg();
|
||||
Gpg gpg = this.gpg.isGpgAvailable() ? this.gpg : properties.getGpg();
|
||||
|
||||
CommandLine arguments = CommandLine.of(Goal.DEPLOY, //
|
||||
profile("ci,release,central"), //
|
||||
|
||||
@@ -20,6 +20,8 @@ import lombok.Data;
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
|
||||
import org.springframework.data.release.model.Gpg;
|
||||
import org.springframework.data.release.model.Password;
|
||||
import org.springframework.data.release.utils.HttpBasicCredentials;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -74,6 +76,11 @@ public class DeploymentProperties {
|
||||
return repositoryPrefix.concat(distributionRepository);
|
||||
}
|
||||
|
||||
@DeprecatedConfigurationProperty(reason = "Moved to gpg.", replacement = "gpg")
|
||||
public Gpg getGpg() {
|
||||
return gpg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URI of the staging repository.
|
||||
*
|
||||
@@ -119,9 +126,4 @@ public class DeploymentProperties {
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Gpg {
|
||||
private String keyname, executable;
|
||||
private Password password;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,10 @@ import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -32,22 +34,31 @@ import java.util.stream.Stream;
|
||||
import org.eclipse.jgit.api.CheckoutCommand;
|
||||
import org.eclipse.jgit.api.CherryPickResult;
|
||||
import org.eclipse.jgit.api.CherryPickResult.CherryPickStatus;
|
||||
import org.eclipse.jgit.api.CommitCommand;
|
||||
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.ResetCommand.ResetType;
|
||||
import org.eclipse.jgit.api.errors.RefNotFoundException;
|
||||
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
|
||||
import org.eclipse.jgit.transport.CredentialItem;
|
||||
import org.eclipse.jgit.transport.CredentialItem.CharArrayType;
|
||||
import org.eclipse.jgit.transport.CredentialItem.InformationalMessage;
|
||||
import org.eclipse.jgit.transport.CredentialsProvider;
|
||||
import org.eclipse.jgit.transport.RefSpec;
|
||||
import org.eclipse.jgit.transport.TagOpt;
|
||||
import org.eclipse.jgit.transport.URIish;
|
||||
|
||||
import org.springframework.data.release.io.Workspace;
|
||||
import org.springframework.data.release.issues.IssueTracker;
|
||||
import org.springframework.data.release.issues.Ticket;
|
||||
import org.springframework.data.release.model.ArtifactVersion;
|
||||
import org.springframework.data.release.model.Gpg;
|
||||
import org.springframework.data.release.model.Iteration;
|
||||
import org.springframework.data.release.model.ModuleIteration;
|
||||
import org.springframework.data.release.model.Project;
|
||||
@@ -63,6 +74,7 @@ import org.springframework.util.Assert;
|
||||
* Component to execute Git related operations.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@@ -78,6 +90,7 @@ public class GitOperations {
|
||||
Logger logger;
|
||||
PluginRegistry<IssueTracker, Project> issueTracker;
|
||||
GitProperties gitProperties;
|
||||
Gpg gpg;
|
||||
|
||||
/**
|
||||
* Returns the {@link GitProject} for the given {@link Project}.
|
||||
@@ -93,7 +106,6 @@ public class GitOperations {
|
||||
* Resets the repositories for all modules of the given {@link Train}.
|
||||
*
|
||||
* @param train must not be {@literal null}.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void reset(TrainIteration train) {
|
||||
|
||||
@@ -437,16 +449,25 @@ public class GitOperations {
|
||||
String author = gitProperties.getAuthor();
|
||||
String email = gitProperties.getEmail();
|
||||
|
||||
logger.log(module, "git commit -m \"%s\" --author=\"%s <%s>\"", commit, author, email);
|
||||
logger.log(module, "git commit -m \"%s\" %s --author=\"%s <%s>\"", commit,
|
||||
gpg.isGpgAvailable() ? "-S" + gpg.getKeyname() : "", author, email);
|
||||
|
||||
doWithGit(project, git -> {
|
||||
|
||||
git.commit()//
|
||||
CommitCommand commitCommand = git.commit()//
|
||||
.setMessage(commit.toString())//
|
||||
.setAuthor(author, email)//
|
||||
.setCommitter(author, email)//
|
||||
.setAll(true)//
|
||||
.call();
|
||||
.setAll(true);
|
||||
|
||||
if (gpg.isGpgAvailable()) {
|
||||
commitCommand.setSign(true).setSigningKey(gpg.getKeyname())
|
||||
.setCredentialsProvider(new GpgPassphraseProvider(gpg));
|
||||
} else {
|
||||
commitCommand.setSign(false);
|
||||
}
|
||||
|
||||
commitCommand.call();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -783,4 +804,54 @@ public class GitOperations {
|
||||
private static interface VoidGitCallback {
|
||||
void doWithGit(Git git) throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link CredentialsProvider} for GPG Keys used with JGit Commit Signing.
|
||||
*/
|
||||
private static class GpgPassphraseProvider extends CredentialsProvider {
|
||||
|
||||
private final Gpg gpg;
|
||||
|
||||
private GpgPassphraseProvider(Gpg gpg) {
|
||||
this.gpg = gpg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInteractive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(CredentialItem... items) {
|
||||
|
||||
boolean matchesKey = matchesKey(items);
|
||||
boolean hasSettableCharArray = Arrays.stream(items).anyMatch(CharArrayType.class::isInstance);
|
||||
|
||||
return matchesKey && hasSettableCharArray;
|
||||
}
|
||||
|
||||
private boolean matchesKey(CredentialItem[] items) {
|
||||
return Arrays.stream(items).filter(InformationalMessage.class::isInstance) //
|
||||
.map(CredentialItem::getPromptText) //
|
||||
.map(it -> it.toLowerCase(Locale.US)) //
|
||||
.anyMatch(it -> it.contains(gpg.getKeyname().toLowerCase(Locale.US)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean get(URIish uri, CredentialItem... items) throws UnsupportedCredentialItem {
|
||||
|
||||
if (!matchesKey(items)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (CredentialItem item : items) {
|
||||
if (item instanceof CharArrayType) {
|
||||
((CharArrayType) item).setValueNoCopy(gpg.getPassword().toString().toCharArray());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2019 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.Data;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "gpg")
|
||||
public class Gpg {
|
||||
private String keyname, executable;
|
||||
private Password password;
|
||||
|
||||
public boolean isGpgAvailable() {
|
||||
return this.password != null && StringUtils.hasText(keyname);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
spring.main.banner-mode=off
|
||||
io.work-dir=~/temp/spring-data-shell/workspace
|
||||
io.logs=logs
|
||||
|
||||
# Maven setup
|
||||
maven.local-repository=~/temp/spring-data-shell/repository
|
||||
maven.plugins.versions=org.codehaus.mojo:versions-maven-plugin:2.2
|
||||
@@ -10,12 +11,15 @@ deployment.staging-repository=libs-staging-local
|
||||
deployment.distribution-repository=temp-private-local
|
||||
deployment.username=buildmaster
|
||||
#deployment.password <- local
|
||||
|
||||
# GPG setup
|
||||
deployment.gpg.executable=/usr/local/bin/gpg2
|
||||
# deployment.gpg.keyname
|
||||
# deployment.gpg.password
|
||||
gpg.executable=/usr/local/bin/gpg2
|
||||
# gpg.keyname
|
||||
# gpg.password
|
||||
|
||||
# JIRA
|
||||
jira.api-url=https://jira.spring.io
|
||||
|
||||
# GitHub
|
||||
github.api-url=https://api.github.com
|
||||
logging.pattern.console=%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(%-20.20logger{19}){cyan}%clr(:){faint} %m%n%wEx
|
||||
|
||||
Reference in New Issue
Block a user