TagCommand: support signing annotated tags
Add the two config constants from C git that can switch on signing of annotated tags. Add them to the GpgConfig, and implement actually signing a tag in TagCommand. The interactions between command line options for "git tag" and config options is a bit murky in C git. There are two config settings for it: * tag.gpgSign is the main option, if set to true, it kicks in if neither -s nor -u are given on the command line. * tag.forceSignAnnotated signs only tags created via "git tag -m", but only if command-line option "-a" is not present. It applies even if tag.gpgSign is set explicitly to false. Giving -s or -u on the command line also forces an annotated tag since lightweight tags cannot be signed. Bug: 386908 Change-Id: Ic8a1a44b5f12f47d5cdf3aae2456c1f6ca9ef057 Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
parent
5abd8a4feb
commit
41b9159795
|
@ -143,6 +143,7 @@ metaVar_s3Region=REGION
|
||||||
metaVar_s3StorageClass=STORAGE-CLASS
|
metaVar_s3StorageClass=STORAGE-CLASS
|
||||||
metaVar_seconds=SECONDS
|
metaVar_seconds=SECONDS
|
||||||
metaVar_service=SERVICE
|
metaVar_service=SERVICE
|
||||||
|
metaVar_tagLocalUser=<GPG key ID>
|
||||||
metaVar_treeish=tree-ish
|
metaVar_treeish=tree-ish
|
||||||
metaVar_uriish=uri-ish
|
metaVar_uriish=uri-ish
|
||||||
metaVar_url=URL
|
metaVar_url=URL
|
||||||
|
@ -421,8 +422,12 @@ usage_sshDriver=Selects the built-in ssh library to use, JSch or Apache MINA ssh
|
||||||
usage_symbolicVersionForTheProject=Symbolic version for the project
|
usage_symbolicVersionForTheProject=Symbolic version for the project
|
||||||
usage_tags=fetch all tags
|
usage_tags=fetch all tags
|
||||||
usage_notags=do not fetch tags
|
usage_notags=do not fetch tags
|
||||||
|
usage_tagAnnotated=create an annotated tag, unsigned unless -s or -u are given, or config tag.gpgSign is true
|
||||||
usage_tagDelete=delete tag
|
usage_tagDelete=delete tag
|
||||||
usage_tagMessage=tag message
|
usage_tagLocalUser=create a signed annotated tag using the specified GPG key ID
|
||||||
|
usage_tagMessage=create an annotated tag with the given message, unsigned unless -s or -u are given, or config tag.gpgSign is true, or tar.forceSignAnnotated is true and -a is not given
|
||||||
|
usage_tagSign=create a signed annotated tag
|
||||||
|
usage_tagNoSign=suppress signing the tag
|
||||||
usage_untrackedFilesMode=show untracked files
|
usage_untrackedFilesMode=show untracked files
|
||||||
usage_updateRef=reference to update
|
usage_updateRef=reference to update
|
||||||
usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository
|
usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* Copyright (C) 2008, Charles O'Farrell <charleso@charleso.org>
|
* Copyright (C) 2008, Charles O'Farrell <charleso@charleso.org>
|
||||||
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg.lists@dewire.com>
|
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg.lists@dewire.com>
|
||||||
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
|
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
|
||||||
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
|
* Copyright (C) 2008, 2020 Shawn O. Pearce <spearce@spearce.org> and others
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available under the
|
* This program and the accompanying materials are made available under the
|
||||||
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
@ -40,8 +40,24 @@ class Tag extends TextBuiltin {
|
||||||
@Option(name = "-d", usage = "usage_tagDelete")
|
@Option(name = "-d", usage = "usage_tagDelete")
|
||||||
private boolean delete;
|
private boolean delete;
|
||||||
|
|
||||||
|
@Option(name = "--annotate", aliases = {
|
||||||
|
"-a" }, usage = "usage_tagAnnotated")
|
||||||
|
private boolean annotated;
|
||||||
|
|
||||||
@Option(name = "-m", metaVar = "metaVar_message", usage = "usage_tagMessage")
|
@Option(name = "-m", metaVar = "metaVar_message", usage = "usage_tagMessage")
|
||||||
private String message = ""; //$NON-NLS-1$
|
private String message;
|
||||||
|
|
||||||
|
@Option(name = "--sign", aliases = { "-s" }, forbids = {
|
||||||
|
"--no-sign" }, usage = "usage_tagSign")
|
||||||
|
private boolean sign;
|
||||||
|
|
||||||
|
@Option(name = "--no-sign", usage = "usage_tagNoSign", forbids = {
|
||||||
|
"--sign" })
|
||||||
|
private boolean noSign;
|
||||||
|
|
||||||
|
@Option(name = "--local-user", aliases = {
|
||||||
|
"-u" }, metaVar = "metaVar_tagLocalUser", usage = "usage_tagLocalUser")
|
||||||
|
private String gpgKeyId;
|
||||||
|
|
||||||
@Argument(index = 0, metaVar = "metaVar_name")
|
@Argument(index = 0, metaVar = "metaVar_name")
|
||||||
private String tagName;
|
private String tagName;
|
||||||
|
@ -70,6 +86,18 @@ protected void run() {
|
||||||
command.setObjectId(walk.parseAny(object));
|
command.setObjectId(walk.parseAny(object));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (noSign) {
|
||||||
|
command.setSigned(false);
|
||||||
|
} else if (sign) {
|
||||||
|
command.setSigned(true);
|
||||||
|
}
|
||||||
|
if (annotated) {
|
||||||
|
command.setAnnotated(true);
|
||||||
|
} else if (message == null && !sign && gpgKeyId == null) {
|
||||||
|
// None of -a, -m, -s, -u given
|
||||||
|
command.setAnnotated(false);
|
||||||
|
}
|
||||||
|
command.setSigningKey(gpgKeyId);
|
||||||
try {
|
try {
|
||||||
command.call();
|
command.call();
|
||||||
} catch (RefAlreadyExistsException e) {
|
} catch (RefAlreadyExistsException e) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2010, 2013 Chris Aniszczyk <caniszczyk@gmail.com> and others
|
* Copyright (C) 2010, 2020 Chris Aniszczyk <caniszczyk@gmail.com> and others
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available under the
|
* This program and the accompanying materials are made available under the
|
||||||
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
import static org.eclipse.jgit.lib.Constants.R_TAGS;
|
import static org.eclipse.jgit.lib.Constants.R_TAGS;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -28,6 +30,59 @@
|
||||||
|
|
||||||
public class TagCommandTest extends RepositoryTestCase {
|
public class TagCommandTest extends RepositoryTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTagKind() {
|
||||||
|
try (Git git = new Git(db)) {
|
||||||
|
assertTrue(git.tag().isAnnotated());
|
||||||
|
assertTrue(git.tag().setSigned(true).isAnnotated());
|
||||||
|
assertTrue(git.tag().setSigned(false).isAnnotated());
|
||||||
|
assertTrue(git.tag().setSigningKey(null).isAnnotated());
|
||||||
|
assertTrue(git.tag().setSigningKey("something").isAnnotated());
|
||||||
|
assertTrue(git.tag().setSigned(false).setSigningKey(null)
|
||||||
|
.isAnnotated());
|
||||||
|
assertTrue(git.tag().setSigned(false).setSigningKey("something")
|
||||||
|
.isAnnotated());
|
||||||
|
assertTrue(git.tag().setSigned(true).setSigningKey(null)
|
||||||
|
.isAnnotated());
|
||||||
|
assertTrue(git.tag().setSigned(true).setSigningKey("something")
|
||||||
|
.isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(true).isAnnotated());
|
||||||
|
assertTrue(
|
||||||
|
git.tag().setAnnotated(true).setSigned(true).isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(true).setSigned(false)
|
||||||
|
.isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(true).setSigningKey(null)
|
||||||
|
.isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(true).setSigningKey("something")
|
||||||
|
.isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(true).setSigned(false)
|
||||||
|
.setSigningKey(null).isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(true).setSigned(false)
|
||||||
|
.setSigningKey("something").isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(true).setSigned(true)
|
||||||
|
.setSigningKey(null).isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(true).setSigned(true)
|
||||||
|
.setSigningKey("something").isAnnotated());
|
||||||
|
assertFalse(git.tag().setAnnotated(false).isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(false).setSigned(true)
|
||||||
|
.isAnnotated());
|
||||||
|
assertFalse(git.tag().setAnnotated(false).setSigned(false)
|
||||||
|
.isAnnotated());
|
||||||
|
assertFalse(git.tag().setAnnotated(false).setSigningKey(null)
|
||||||
|
.isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(false).setSigningKey("something")
|
||||||
|
.isAnnotated());
|
||||||
|
assertFalse(git.tag().setAnnotated(false).setSigned(false)
|
||||||
|
.setSigningKey(null).isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(false).setSigned(false)
|
||||||
|
.setSigningKey("something").isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(false).setSigned(true)
|
||||||
|
.setSigningKey(null).isAnnotated());
|
||||||
|
assertTrue(git.tag().setAnnotated(false).setSigned(true)
|
||||||
|
.setSigningKey("something").isAnnotated());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTaggingOnHead() throws GitAPIException, IOException {
|
public void testTaggingOnHead() throws GitAPIException, IOException {
|
||||||
try (Git git = new Git(db);
|
try (Git git = new Git(db);
|
||||||
|
@ -93,19 +148,6 @@ public void testInvalidTagName() throws GitAPIException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFailureOnSignedTags() throws GitAPIException {
|
|
||||||
try (Git git = new Git(db)) {
|
|
||||||
git.commit().setMessage("initial commit").call();
|
|
||||||
try {
|
|
||||||
git.tag().setSigned(true).setName("tag").call();
|
|
||||||
fail("We should have failed with an UnsupportedOperationException due to signed tag");
|
|
||||||
} catch (UnsupportedOperationException e) {
|
|
||||||
// should hit here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Ref> getTags() throws Exception {
|
private List<Ref> getTags() throws Exception {
|
||||||
return db.getRefDatabase().getRefsByPrefix(R_TAGS);
|
return db.getRefDatabase().getRefsByPrefix(R_TAGS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -618,7 +618,6 @@ shortReadOfBlock=Short read of block.
|
||||||
shortReadOfOptionalDIRCExtensionExpectedAnotherBytes=Short read of optional DIRC extension {0}; expected another {1} bytes within the section.
|
shortReadOfOptionalDIRCExtensionExpectedAnotherBytes=Short read of optional DIRC extension {0}; expected another {1} bytes within the section.
|
||||||
shortSkipOfBlock=Short skip of block.
|
shortSkipOfBlock=Short skip of block.
|
||||||
signedTagMessageNoLf=A non-empty message of a signed tag must end in LF.
|
signedTagMessageNoLf=A non-empty message of a signed tag must end in LF.
|
||||||
signingNotSupportedOnTag=Signing isn't supported on tag operations yet.
|
|
||||||
signingServiceUnavailable=Signing service is not available
|
signingServiceUnavailable=Signing service is not available
|
||||||
similarityScoreMustBeWithinBounds=Similarity score must be between 0 and 100.
|
similarityScoreMustBeWithinBounds=Similarity score must be between 0 and 100.
|
||||||
skipMustBeNonNegative=skip must be >= 0
|
skipMustBeNonNegative=skip must be >= 0
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2010, 2013 Chris Aniszczyk <caniszczyk@gmail.com> and others
|
* Copyright (C) 2010, 2020 Chris Aniszczyk <caniszczyk@gmail.com> and others
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available under the
|
* This program and the accompanying materials are made available under the
|
||||||
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
@ -18,8 +18,13 @@
|
||||||
import org.eclipse.jgit.api.errors.JGitInternalException;
|
import org.eclipse.jgit.api.errors.JGitInternalException;
|
||||||
import org.eclipse.jgit.api.errors.NoHeadException;
|
import org.eclipse.jgit.api.errors.NoHeadException;
|
||||||
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
|
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
|
||||||
|
import org.eclipse.jgit.api.errors.ServiceUnavailableException;
|
||||||
|
import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException;
|
||||||
import org.eclipse.jgit.internal.JGitText;
|
import org.eclipse.jgit.internal.JGitText;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
|
import org.eclipse.jgit.lib.GpgConfig;
|
||||||
|
import org.eclipse.jgit.lib.GpgObjectSigner;
|
||||||
|
import org.eclipse.jgit.lib.GpgSigner;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectInserter;
|
import org.eclipse.jgit.lib.ObjectInserter;
|
||||||
import org.eclipse.jgit.lib.PersonIdent;
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
|
@ -29,8 +34,10 @@
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.lib.RepositoryState;
|
import org.eclipse.jgit.lib.RepositoryState;
|
||||||
import org.eclipse.jgit.lib.TagBuilder;
|
import org.eclipse.jgit.lib.TagBuilder;
|
||||||
|
import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
|
||||||
import org.eclipse.jgit.revwalk.RevObject;
|
import org.eclipse.jgit.revwalk.RevObject;
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
import org.eclipse.jgit.transport.CredentialsProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create/update an annotated tag object or a simple unannotated tag
|
* Create/update an annotated tag object or a simple unannotated tag
|
||||||
|
@ -56,6 +63,7 @@
|
||||||
* >Git documentation about Tag</a>
|
* >Git documentation about Tag</a>
|
||||||
*/
|
*/
|
||||||
public class TagCommand extends GitCommand<Ref> {
|
public class TagCommand extends GitCommand<Ref> {
|
||||||
|
|
||||||
private RevObject id;
|
private RevObject id;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
@ -64,11 +72,17 @@ public class TagCommand extends GitCommand<Ref> {
|
||||||
|
|
||||||
private PersonIdent tagger;
|
private PersonIdent tagger;
|
||||||
|
|
||||||
private boolean signed;
|
private Boolean signed;
|
||||||
|
|
||||||
private boolean forceUpdate;
|
private boolean forceUpdate;
|
||||||
|
|
||||||
private boolean annotated = true;
|
private Boolean annotated;
|
||||||
|
|
||||||
|
private String signingKey;
|
||||||
|
|
||||||
|
private GpgObjectSigner gpgSigner;
|
||||||
|
|
||||||
|
private CredentialsProvider credentialsProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Constructor for TagCommand.</p>
|
* <p>Constructor for TagCommand.</p>
|
||||||
|
@ -77,6 +91,7 @@ public class TagCommand extends GitCommand<Ref> {
|
||||||
*/
|
*/
|
||||||
protected TagCommand(Repository repo) {
|
protected TagCommand(Repository repo) {
|
||||||
super(repo);
|
super(repo);
|
||||||
|
this.credentialsProvider = CredentialsProvider.getDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,10 +123,7 @@ public Ref call() throws GitAPIException, ConcurrentRefUpdateException,
|
||||||
id = revWalk.parseCommit(objectId);
|
id = revWalk.parseCommit(objectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!annotated) {
|
if (!isAnnotated()) {
|
||||||
if (message != null || tagger != null)
|
|
||||||
throw new JGitInternalException(
|
|
||||||
JGitText.get().messageAndTaggerNotAllowedInUnannotatedTags);
|
|
||||||
return updateTagRef(id, revWalk, name,
|
return updateTagRef(id, revWalk, name,
|
||||||
"SimpleTag[" + name + " : " + id //$NON-NLS-1$ //$NON-NLS-2$
|
"SimpleTag[" + name + " : " + id //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
+ "]"); //$NON-NLS-1$
|
+ "]"); //$NON-NLS-1$
|
||||||
|
@ -124,6 +136,11 @@ public Ref call() throws GitAPIException, ConcurrentRefUpdateException,
|
||||||
newTag.setTagger(tagger);
|
newTag.setTagger(tagger);
|
||||||
newTag.setObjectId(id);
|
newTag.setObjectId(id);
|
||||||
|
|
||||||
|
if (gpgSigner != null) {
|
||||||
|
gpgSigner.signObject(newTag, signingKey, tagger,
|
||||||
|
credentialsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
// write the tag object
|
// write the tag object
|
||||||
try (ObjectInserter inserter = repo.newObjectInserter()) {
|
try (ObjectInserter inserter = repo.newObjectInserter()) {
|
||||||
ObjectId tagId = inserter.insert(newTag);
|
ObjectId tagId = inserter.insert(newTag);
|
||||||
|
@ -177,20 +194,60 @@ private Ref updateTagRef(ObjectId tagId, RevWalk revWalk,
|
||||||
*
|
*
|
||||||
* @throws InvalidTagNameException
|
* @throws InvalidTagNameException
|
||||||
* if the tag name is null or invalid
|
* if the tag name is null or invalid
|
||||||
* @throws UnsupportedOperationException
|
* @throws ServiceUnavailableException
|
||||||
* if the tag is signed (not supported yet)
|
* if the tag should be signed but no signer can be found
|
||||||
|
* @throws UnsupportedSigningFormatException
|
||||||
|
* if the tag should be signed but {@code gpg.format} is not
|
||||||
|
* {@link GpgFormat#OPENPGP}
|
||||||
*/
|
*/
|
||||||
private void processOptions(RepositoryState state)
|
private void processOptions(RepositoryState state)
|
||||||
throws InvalidTagNameException {
|
throws InvalidTagNameException, ServiceUnavailableException,
|
||||||
if (tagger == null && annotated)
|
UnsupportedSigningFormatException {
|
||||||
tagger = new PersonIdent(repo);
|
if (name == null
|
||||||
if (name == null || !Repository.isValidRefName(Constants.R_TAGS + name))
|
|| !Repository.isValidRefName(Constants.R_TAGS + name)) {
|
||||||
throw new InvalidTagNameException(
|
throw new InvalidTagNameException(
|
||||||
MessageFormat.format(JGitText.get().tagNameInvalid,
|
MessageFormat.format(JGitText.get().tagNameInvalid,
|
||||||
name == null ? "<null>" : name)); //$NON-NLS-1$
|
name == null ? "<null>" : name)); //$NON-NLS-1$
|
||||||
if (signed)
|
}
|
||||||
throw new UnsupportedOperationException(
|
if (!isAnnotated()) {
|
||||||
JGitText.get().signingNotSupportedOnTag);
|
if ((message != null && !message.isEmpty()) || tagger != null) {
|
||||||
|
throw new JGitInternalException(JGitText
|
||||||
|
.get().messageAndTaggerNotAllowedInUnannotatedTags);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (tagger == null) {
|
||||||
|
tagger = new PersonIdent(repo);
|
||||||
|
}
|
||||||
|
// Figure out whether to sign.
|
||||||
|
if (!(Boolean.FALSE.equals(signed) && signingKey == null)) {
|
||||||
|
GpgConfig gpgConfig = new GpgConfig(repo.getConfig());
|
||||||
|
boolean doSign = isSigned() || gpgConfig.isSignAllTags();
|
||||||
|
if (!Boolean.TRUE.equals(annotated) && !doSign) {
|
||||||
|
doSign = gpgConfig.isSignAnnotated();
|
||||||
|
}
|
||||||
|
if (doSign) {
|
||||||
|
if (signingKey == null) {
|
||||||
|
signingKey = gpgConfig.getSigningKey();
|
||||||
|
}
|
||||||
|
if (gpgConfig.getKeyFormat() != GpgFormat.OPENPGP) {
|
||||||
|
throw new UnsupportedSigningFormatException(
|
||||||
|
JGitText.get().onlyOpenPgpSupportedForSigning);
|
||||||
|
}
|
||||||
|
GpgSigner signer = GpgSigner.getDefault();
|
||||||
|
if (!(signer instanceof GpgObjectSigner)) {
|
||||||
|
throw new ServiceUnavailableException(
|
||||||
|
JGitText.get().signingServiceUnavailable);
|
||||||
|
}
|
||||||
|
gpgSigner = (GpgObjectSigner) signer;
|
||||||
|
// The message of a signed tag must end in a newline because
|
||||||
|
// the signature will be appended.
|
||||||
|
if (message != null && !message.isEmpty()
|
||||||
|
&& !message.endsWith("\n")) { //$NON-NLS-1$
|
||||||
|
message += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -238,24 +295,31 @@ public TagCommand setMessage(String message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this tag is signed
|
* Whether {@link #setSigned(boolean) setSigned(true)} has been called or
|
||||||
|
* whether a {@link #setSigningKey(String) signing key ID} has been set;
|
||||||
|
* i.e., whether -s or -u was specified explicitly.
|
||||||
*
|
*
|
||||||
* @return whether the tag is signed
|
* @return whether the tag is signed
|
||||||
*/
|
*/
|
||||||
public boolean isSigned() {
|
public boolean isSigned() {
|
||||||
return signed;
|
return Boolean.TRUE.equals(signed) || signingKey != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set to true the Tag command creates a signed tag object. This
|
* If set to true the Tag command creates a signed tag object. This
|
||||||
* corresponds to the parameter -s on the command line.
|
* corresponds to the parameter -s (--sign or --no-sign) on the command
|
||||||
|
* line.
|
||||||
|
* <p>
|
||||||
|
* If {@code true}, the tag will be a signed annotated tag.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param signed
|
* @param signed
|
||||||
* a boolean.
|
* whether to sign
|
||||||
* @return {@code this}
|
* @return {@code this}
|
||||||
*/
|
*/
|
||||||
public TagCommand setSigned(boolean signed) {
|
public TagCommand setSigned(boolean signed) {
|
||||||
this.signed = signed;
|
checkCallable();
|
||||||
|
this.signed = Boolean.valueOf(signed);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,6 +332,7 @@ public TagCommand setSigned(boolean signed) {
|
||||||
* @return {@code this}
|
* @return {@code this}
|
||||||
*/
|
*/
|
||||||
public TagCommand setTagger(PersonIdent tagger) {
|
public TagCommand setTagger(PersonIdent tagger) {
|
||||||
|
checkCallable();
|
||||||
this.tagger = tagger;
|
this.tagger = tagger;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -291,14 +356,15 @@ public RevObject getObjectId() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the object id of the tag. If the object id is null, the commit
|
* Sets the object id of the tag. If the object id is {@code null}, the
|
||||||
* pointed to from HEAD will be used.
|
* commit pointed to from HEAD will be used.
|
||||||
*
|
*
|
||||||
* @param id
|
* @param id
|
||||||
* a {@link org.eclipse.jgit.revwalk.RevObject} object.
|
* a {@link org.eclipse.jgit.revwalk.RevObject} object.
|
||||||
* @return {@code this}
|
* @return {@code this}
|
||||||
*/
|
*/
|
||||||
public TagCommand setObjectId(RevObject id) {
|
public TagCommand setObjectId(RevObject id) {
|
||||||
|
checkCallable();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -321,6 +387,7 @@ public boolean isForceUpdate() {
|
||||||
* @return {@code this}
|
* @return {@code this}
|
||||||
*/
|
*/
|
||||||
public TagCommand setForceUpdate(boolean forceUpdate) {
|
public TagCommand setForceUpdate(boolean forceUpdate) {
|
||||||
|
checkCallable();
|
||||||
this.forceUpdate = forceUpdate;
|
this.forceUpdate = forceUpdate;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -334,18 +401,77 @@ public TagCommand setForceUpdate(boolean forceUpdate) {
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public TagCommand setAnnotated(boolean annotated) {
|
public TagCommand setAnnotated(boolean annotated) {
|
||||||
this.annotated = annotated;
|
checkCallable();
|
||||||
|
this.annotated = Boolean.valueOf(annotated);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this will create an annotated command
|
* Whether this will create an annotated tag.
|
||||||
*
|
*
|
||||||
* @return true if this command will create an annotated tag (default is
|
* @return true if this command will create an annotated tag (default is
|
||||||
* true)
|
* true)
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public boolean isAnnotated() {
|
public boolean isAnnotated() {
|
||||||
return annotated;
|
boolean setExplicitly = Boolean.TRUE.equals(annotated) || isSigned();
|
||||||
|
if (setExplicitly) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Annotated at default (not set explicitly)
|
||||||
|
return annotated == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the signing key.
|
||||||
|
* <p>
|
||||||
|
* Per spec of {@code user.signingKey}: this will be sent to the GPG program
|
||||||
|
* as is, i.e. can be anything supported by the GPG program.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Note, if none was set or {@code null} is specified a default will be
|
||||||
|
* obtained from the configuration.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* If set to a non-{@code null} value, the tag will be a signed annotated
|
||||||
|
* tag.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param signingKey
|
||||||
|
* signing key; {@code null} allowed
|
||||||
|
* @return {@code this}
|
||||||
|
* @since 5.11
|
||||||
|
*/
|
||||||
|
public TagCommand setSigningKey(String signingKey) {
|
||||||
|
checkCallable();
|
||||||
|
this.signingKey = signingKey;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the signing key ID.
|
||||||
|
*
|
||||||
|
* @return the key ID set, or {@code null} if none is set
|
||||||
|
* @since 5.11
|
||||||
|
*/
|
||||||
|
public String getSigningKey() {
|
||||||
|
return signingKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a {@link CredentialsProvider}
|
||||||
|
*
|
||||||
|
* @param credentialsProvider
|
||||||
|
* the provider to use when querying for credentials (eg., during
|
||||||
|
* signing)
|
||||||
|
* @return {@code this}
|
||||||
|
* @since 5.11
|
||||||
|
*/
|
||||||
|
public TagCommand setCredentialsProvider(
|
||||||
|
CredentialsProvider credentialsProvider) {
|
||||||
|
checkCallable();
|
||||||
|
this.credentialsProvider = credentialsProvider;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -646,7 +646,6 @@ public static JGitText get() {
|
||||||
/***/ public String shortReadOfOptionalDIRCExtensionExpectedAnotherBytes;
|
/***/ public String shortReadOfOptionalDIRCExtensionExpectedAnotherBytes;
|
||||||
/***/ public String shortSkipOfBlock;
|
/***/ public String shortSkipOfBlock;
|
||||||
/***/ public String signedTagMessageNoLf;
|
/***/ public String signedTagMessageNoLf;
|
||||||
/***/ public String signingNotSupportedOnTag;
|
|
||||||
/***/ public String signingServiceUnavailable;
|
/***/ public String signingServiceUnavailable;
|
||||||
/***/ public String similarityScoreMustBeWithinBounds;
|
/***/ public String similarityScoreMustBeWithinBounds;
|
||||||
/***/ public String skipMustBeNonNegative;
|
/***/ public String skipMustBeNonNegative;
|
||||||
|
|
|
@ -116,14 +116,30 @@ public final class ConfigConstants {
|
||||||
*/
|
*/
|
||||||
public static final String CONFIG_COMMIT_SECTION = "commit";
|
public static final String CONFIG_COMMIT_SECTION = "commit";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "tag" section
|
||||||
|
*
|
||||||
|
* @since 5.11
|
||||||
|
*/
|
||||||
|
public static final String CONFIG_TAG_SECTION = "tag";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "gpgSign" key
|
* The "gpgSign" key
|
||||||
|
*
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
*/
|
*/
|
||||||
public static final String CONFIG_KEY_GPGSIGN = "gpgSign";
|
public static final String CONFIG_KEY_GPGSIGN = "gpgSign";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "forceSignAnnotated" key
|
||||||
|
*
|
||||||
|
* @since 5.11
|
||||||
|
*/
|
||||||
|
public static final String CONFIG_KEY_FORCE_SIGN_ANNOTATED = "forceSignAnnotated";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "hooksPath" key.
|
* The "hooksPath" key.
|
||||||
|
*
|
||||||
* @since 5.6
|
* @since 5.6
|
||||||
*/
|
*/
|
||||||
public static final String CONFIG_KEY_HOOKS_PATH = "hooksPath";
|
public static final String CONFIG_KEY_HOOKS_PATH = "hooksPath";
|
||||||
|
|
|
@ -85,4 +85,29 @@ public boolean isSignCommits() {
|
||||||
return config.getBoolean(ConfigConstants.CONFIG_COMMIT_SECTION,
|
return config.getBoolean(ConfigConstants.CONFIG_COMMIT_SECTION,
|
||||||
ConfigConstants.CONFIG_KEY_GPGSIGN, false);
|
ConfigConstants.CONFIG_KEY_GPGSIGN, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the value of git config {@code tag.gpgSign}.
|
||||||
|
*
|
||||||
|
* @return the value of {@code tag.gpgSign}; by default {@code false}
|
||||||
|
*
|
||||||
|
* @since 5.11
|
||||||
|
*/
|
||||||
|
public boolean isSignAllTags() {
|
||||||
|
return config.getBoolean(ConfigConstants.CONFIG_TAG_SECTION,
|
||||||
|
ConfigConstants.CONFIG_KEY_GPGSIGN, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the value of git config {@code tag.forceSignAnnotated}.
|
||||||
|
*
|
||||||
|
* @return the value of {@code tag.forceSignAnnotated}; by default
|
||||||
|
* {@code false}
|
||||||
|
*
|
||||||
|
* @since 5.11
|
||||||
|
*/
|
||||||
|
public boolean isSignAnnotated() {
|
||||||
|
return config.getBoolean(ConfigConstants.CONFIG_TAG_SECTION,
|
||||||
|
ConfigConstants.CONFIG_KEY_FORCE_SIGN_ANNOTATED, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue