summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Wolf <thomas.wolf@paranor.ch>2020-12-05 22:01:25 +0100
committerThomas Wolf <thomas.wolf@paranor.ch>2020-12-07 09:33:57 +0100
commit41b9159795d6f64bba6a67ce2f22fe1b7679ea55 (patch)
tree1fbbf43003479ea855a6f7a09f7c8abb02524e50
parent5abd8a4feb5da689982c12b65faef34aabedeb26 (diff)
downloadjgit-41b9159795d6f64bba6a67ce2f22fe1b7679ea55.tar.gz
jgit-41b9159795d6f64bba6a67ce2f22fe1b7679ea55.zip
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>
-rw-r--r--org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties7
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java32
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java70
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java178
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java16
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java25
8 files changed, 285 insertions, 45 deletions
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index 6112a272e4..bf2455283e 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -143,6 +143,7 @@ metaVar_s3Region=REGION
metaVar_s3StorageClass=STORAGE-CLASS
metaVar_seconds=SECONDS
metaVar_service=SERVICE
+metaVar_tagLocalUser=<GPG key ID>
metaVar_treeish=tree-ish
metaVar_uriish=uri-ish
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_tags=fetch all 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_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_updateRef=reference to update
usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
index b408b78f3c..4cc62b339c 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
@@ -4,7 +4,7 @@
* 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@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
* 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")
private boolean delete;
+ @Option(name = "--annotate", aliases = {
+ "-a" }, usage = "usage_tagAnnotated")
+ private boolean annotated;
+
@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")
private String tagName;
@@ -70,6 +86,18 @@ class Tag extends TextBuiltin {
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 {
command.call();
} catch (RefAlreadyExistsException e) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java
index b1c54b9eff..9630474b87 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/TagCommandTest.java
@@ -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
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -11,6 +11,8 @@ package org.eclipse.jgit.api;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
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 java.io.IOException;
@@ -29,6 +31,59 @@ import org.junit.Test;
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
public void testTaggingOnHead() throws GitAPIException, IOException {
try (Git git = new Git(db);
RevWalk walk = new RevWalk(db)) {
@@ -93,19 +148,6 @@ public class TagCommandTest extends RepositoryTestCase {
}
}
- @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 {
return db.getRefDatabase().getRefsByPrefix(R_TAGS);
}
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 6d15464d5a..2b5f929dd5 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -618,7 +618,6 @@ shortReadOfBlock=Short read of block.
shortReadOfOptionalDIRCExtensionExpectedAnotherBytes=Short read of optional DIRC extension {0}; expected another {1} bytes within the section.
shortSkipOfBlock=Short skip of block.
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
similarityScoreMustBeWithinBounds=Similarity score must be between 0 and 100.
skipMustBeNonNegative=skip must be >= 0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
index 9a328a6eaa..c8d4e413fb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
@@ -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
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -18,8 +18,13 @@ import org.eclipse.jgit.api.errors.InvalidTagNameException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoHeadException;
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.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.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
@@ -29,8 +34,10 @@ import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.lib.TagBuilder;
+import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.CredentialsProvider;
/**
* Create/update an annotated tag object or a simple unannotated tag
@@ -56,6 +63,7 @@ import org.eclipse.jgit.revwalk.RevWalk;
* >Git documentation about Tag</a>
*/
public class TagCommand extends GitCommand<Ref> {
+
private RevObject id;
private String name;
@@ -64,11 +72,17 @@ public class TagCommand extends GitCommand<Ref> {
private PersonIdent tagger;
- private boolean signed;
+ private Boolean signed;
private boolean forceUpdate;
- private boolean annotated = true;
+ private Boolean annotated;
+
+ private String signingKey;
+
+ private GpgObjectSigner gpgSigner;
+
+ private CredentialsProvider credentialsProvider;
/**
* <p>Constructor for TagCommand.</p>
@@ -77,6 +91,7 @@ public class TagCommand extends GitCommand<Ref> {
*/
protected TagCommand(Repository repo) {
super(repo);
+ this.credentialsProvider = CredentialsProvider.getDefault();
}
/**
@@ -108,10 +123,7 @@ public class TagCommand extends GitCommand<Ref> {
id = revWalk.parseCommit(objectId);
}
- if (!annotated) {
- if (message != null || tagger != null)
- throw new JGitInternalException(
- JGitText.get().messageAndTaggerNotAllowedInUnannotatedTags);
+ if (!isAnnotated()) {
return updateTagRef(id, revWalk, name,
"SimpleTag[" + name + " : " + id //$NON-NLS-1$ //$NON-NLS-2$
+ "]"); //$NON-NLS-1$
@@ -124,6 +136,11 @@ public class TagCommand extends GitCommand<Ref> {
newTag.setTagger(tagger);
newTag.setObjectId(id);
+ if (gpgSigner != null) {
+ gpgSigner.signObject(newTag, signingKey, tagger,
+ credentialsProvider);
+ }
+
// write the tag object
try (ObjectInserter inserter = repo.newObjectInserter()) {
ObjectId tagId = inserter.insert(newTag);
@@ -177,20 +194,60 @@ public class TagCommand extends GitCommand<Ref> {
*
* @throws InvalidTagNameException
* if the tag name is null or invalid
- * @throws UnsupportedOperationException
- * if the tag is signed (not supported yet)
+ * @throws ServiceUnavailableException
+ * 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)
- throws InvalidTagNameException {
- if (tagger == null && annotated)
- tagger = new PersonIdent(repo);
- if (name == null || !Repository.isValidRefName(Constants.R_TAGS + name))
+ throws InvalidTagNameException, ServiceUnavailableException,
+ UnsupportedSigningFormatException {
+ if (name == null
+ || !Repository.isValidRefName(Constants.R_TAGS + name)) {
throw new InvalidTagNameException(
MessageFormat.format(JGitText.get().tagNameInvalid,
name == null ? "<null>" : name)); //$NON-NLS-1$
- if (signed)
- throw new UnsupportedOperationException(
- JGitText.get().signingNotSupportedOnTag);
+ }
+ if (!isAnnotated()) {
+ 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 class TagCommand extends GitCommand<Ref> {
}
/**
- * 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
*/
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
- * 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
- * a boolean.
+ * whether to sign
* @return {@code this}
*/
public TagCommand setSigned(boolean signed) {
- this.signed = signed;
+ checkCallable();
+ this.signed = Boolean.valueOf(signed);
return this;
}
@@ -268,6 +332,7 @@ public class TagCommand extends GitCommand<Ref> {
* @return {@code this}
*/
public TagCommand setTagger(PersonIdent tagger) {
+ checkCallable();
this.tagger = tagger;
return this;
}
@@ -291,14 +356,15 @@ public class TagCommand extends GitCommand<Ref> {
}
/**
- * Sets the object id of the tag. If the object id is null, the commit
- * pointed to from HEAD will be used.
+ * Sets the object id of the tag. If the object id is {@code null}, the
+ * commit pointed to from HEAD will be used.
*
* @param id
* a {@link org.eclipse.jgit.revwalk.RevObject} object.
* @return {@code this}
*/
public TagCommand setObjectId(RevObject id) {
+ checkCallable();
this.id = id;
return this;
}
@@ -321,6 +387,7 @@ public class TagCommand extends GitCommand<Ref> {
* @return {@code this}
*/
public TagCommand setForceUpdate(boolean forceUpdate) {
+ checkCallable();
this.forceUpdate = forceUpdate;
return this;
}
@@ -334,18 +401,77 @@ public class TagCommand extends GitCommand<Ref> {
* @since 3.0
*/
public TagCommand setAnnotated(boolean annotated) {
- this.annotated = annotated;
+ checkCallable();
+ this.annotated = Boolean.valueOf(annotated);
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
* true)
* @since 3.0
*/
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;
+ }
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index a7daed1318..154f32c25f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -646,7 +646,6 @@ public class JGitText extends TranslationBundle {
/***/ public String shortReadOfOptionalDIRCExtensionExpectedAnotherBytes;
/***/ public String shortSkipOfBlock;
/***/ public String signedTagMessageNoLf;
- /***/ public String signingNotSupportedOnTag;
/***/ public String signingServiceUnavailable;
/***/ public String similarityScoreMustBeWithinBounds;
/***/ public String skipMustBeNonNegative;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index 834fff5dd9..2587947c3f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -117,13 +117,29 @@ public final class ConfigConstants {
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
+ *
* @since 5.2
*/
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.
+ *
* @since 5.6
*/
public static final String CONFIG_KEY_HOOKS_PATH = "hooksPath";
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java
index c1527bc47b..5b43729739 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgConfig.java
@@ -85,4 +85,29 @@ public class GpgConfig {
return config.getBoolean(ConfigConstants.CONFIG_COMMIT_SECTION,
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);
+ }
}