mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-05 04:55:50 +01:00
work in progress
This commit is contained in:
@@ -30,6 +30,7 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.checkerframework.checker.nullness.Opt;
|
||||
import org.eclipse.jgit.api.FetchCommand;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
@@ -52,17 +53,23 @@ import org.eclipse.jgit.transport.RefSpec;
|
||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||
import org.eclipse.jgit.util.FS;
|
||||
import org.eclipse.jgit.util.LfsFactory;
|
||||
import org.eclipse.jgit.util.RawParseUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.security.GPG;
|
||||
import sonia.scm.security.PublicKey;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
import sonia.scm.util.Util;
|
||||
import sonia.scm.web.GitUserAgentProvider;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -451,6 +458,26 @@ public final class GitUtil
|
||||
return commit;
|
||||
}
|
||||
|
||||
public static RevTag getTag(org.eclipse.jgit.lib.Repository repository,
|
||||
RevWalk revWalk, Ref ref)
|
||||
throws IOException
|
||||
{
|
||||
RevTag tag = null;
|
||||
ObjectId id = ref.getObjectId();
|
||||
|
||||
if (id != null)
|
||||
{
|
||||
if (revWalk == null)
|
||||
{
|
||||
revWalk = new RevWalk(repository);
|
||||
}
|
||||
|
||||
tag = revWalk.parseTag(id);
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
@@ -683,6 +710,59 @@ public final class GitUtil
|
||||
return name;
|
||||
}
|
||||
|
||||
private static final byte[] GPG_HEADER = {'P', 'G', 'P'};
|
||||
|
||||
public static Optional<Signature> getTagSignature(RevObject revObject, GPG gpg) {
|
||||
if (revObject instanceof RevTag) {
|
||||
RevTag tag = (RevTag) revObject;
|
||||
byte[] raw = tag.getFullMessage().getBytes();
|
||||
|
||||
int start = RawParseUtils.headerStart(GPG_HEADER, raw, 0);
|
||||
if (start < 0) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
int end = RawParseUtils.headerEnd(raw, start);
|
||||
byte[] signature = Arrays.copyOfRange(raw, start, end);
|
||||
|
||||
String publicKeyId = gpg.findPublicKeyId(signature);
|
||||
if (Strings.isNullOrEmpty(publicKeyId)) {
|
||||
// key not found
|
||||
return Optional.of(new Signature(publicKeyId, "gpg", SignatureStatus.NOT_FOUND, null, Collections.emptySet()));
|
||||
}
|
||||
|
||||
Optional<PublicKey> publicKeyById = gpg.findPublicKey(publicKeyId);
|
||||
if (!publicKeyById.isPresent()) {
|
||||
// key not found
|
||||
return Optional.of(new Signature(publicKeyId, "gpg", SignatureStatus.NOT_FOUND, null, Collections.emptySet()));
|
||||
}
|
||||
|
||||
PublicKey publicKey = publicKeyById.get();
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
byte[] headerPrefix = Arrays.copyOfRange(raw, 0, start - GPG_HEADER.length - 1);
|
||||
baos.write(headerPrefix);
|
||||
|
||||
byte[] headerSuffix = Arrays.copyOfRange(raw, end + 1, raw.length);
|
||||
baos.write(headerSuffix);
|
||||
} catch (IOException ex) {
|
||||
// this will never happen, because we are writing into memory
|
||||
throw new IllegalStateException("failed to write into memory", ex);
|
||||
}
|
||||
|
||||
boolean verified = publicKey.verify(baos.toByteArray(), signature);
|
||||
return Optional.of(new Signature(
|
||||
publicKeyId,
|
||||
"gpg",
|
||||
verified ? SignatureStatus.VERIFIED : SignatureStatus.INVALID,
|
||||
publicKey.getOwner().orElse(null),
|
||||
publicKey.getContacts()
|
||||
));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the request comes from a git client.
|
||||
*
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Injector;
|
||||
import sonia.scm.repository.Feature;
|
||||
import sonia.scm.repository.api.Command;
|
||||
import sonia.scm.security.GPG;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
@@ -61,12 +62,14 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider
|
||||
protected static final Set<Feature> FEATURES = EnumSet.of(Feature.INCOMING_REVISION);
|
||||
|
||||
private final GitContext context;
|
||||
private final GPG gpg;
|
||||
private final Injector commandInjector;
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
GitRepositoryServiceProvider(Injector injector, GitContext context) {
|
||||
GitRepositoryServiceProvider(Injector injector, GitContext context, GPG gpg) {
|
||||
this.context = context;
|
||||
this.gpg = gpg;
|
||||
commandInjector = injector.createChildInjector(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
@@ -142,7 +145,7 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider
|
||||
|
||||
@Override
|
||||
public TagsCommand getTagsCommand() {
|
||||
return new GitTagsCommand(context);
|
||||
return new GitTagsCommand(context, gpg);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.google.inject.Injector;
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.repository.GitRepositoryHandler;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.security.GPG;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -41,17 +42,19 @@ public class GitRepositoryServiceResolver implements RepositoryServiceResolver {
|
||||
|
||||
private final Injector injector;
|
||||
private final GitContextFactory contextFactory;
|
||||
private final GPG gpg;
|
||||
|
||||
@Inject
|
||||
public GitRepositoryServiceResolver(Injector injector, GitContextFactory contextFactory) {
|
||||
public GitRepositoryServiceResolver(Injector injector, GitContextFactory contextFactory, GPG gpg) {
|
||||
this.injector = injector;
|
||||
this.contextFactory = contextFactory;
|
||||
this.gpg = gpg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GitRepositoryServiceProvider resolve(Repository repository) {
|
||||
if (GitRepositoryHandler.TYPE_NAME.equalsIgnoreCase(repository.getType())) {
|
||||
return new GitRepositoryServiceProvider(injector, contextFactory.create(repository));
|
||||
return new GitRepositoryServiceProvider(injector, contextFactory.create(repository), gpg);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.revwalk.RevObject;
|
||||
import org.eclipse.jgit.revwalk.RevTag;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.util.RawParseUtils;
|
||||
import sonia.scm.repository.GitUtil;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.Signature;
|
||||
import sonia.scm.repository.SignatureStatus;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.api.TagDeleteRequest;
|
||||
import sonia.scm.repository.api.TagCreateRequest;
|
||||
import sonia.scm.security.GPG;
|
||||
import sonia.scm.security.PublicKey;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
public class GitTagCommand extends AbstractGitCommand implements TagCommand {
|
||||
private final GPG gpg;
|
||||
|
||||
GitTagCommand(GitContext context, GPG gpg) {
|
||||
super(context);
|
||||
this.gpg = gpg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag create(TagCreateRequest request) {
|
||||
try (Git git = new Git(context.open())) {
|
||||
Tag tag;
|
||||
String revision = request.getRevision();
|
||||
|
||||
RevObject revObject = null;
|
||||
Long tagTime = null;
|
||||
|
||||
if (!Strings.isNullOrEmpty(revision)) {
|
||||
ObjectId id = git.getRepository().resolve(revision);
|
||||
|
||||
try (RevWalk walk = new RevWalk(git.getRepository())) {
|
||||
revObject = walk.parseAny(id);
|
||||
tagTime = GitUtil.getTagTime(walk, id);
|
||||
}
|
||||
}
|
||||
|
||||
Ref ref;
|
||||
|
||||
if (revObject != null) {
|
||||
ref =
|
||||
git.tag()
|
||||
.setObjectId(revObject)
|
||||
.setTagger(new PersonIdent("SCM-Manager", "noreply@scm-manager.org"))
|
||||
.setName(request.getName())
|
||||
.call();
|
||||
} else {
|
||||
throw new InternalRepositoryException(repository, "could not create tag because revision does not exist");
|
||||
}
|
||||
|
||||
ObjectId objectId;
|
||||
if (ref.isPeeled()) {
|
||||
objectId = ref.getPeeledObjectId();
|
||||
} else {
|
||||
objectId = ref.getObjectId();
|
||||
}
|
||||
tag = new Tag(request.getName(), objectId.toString(), tagTime);
|
||||
|
||||
try (RevWalk walk = new RevWalk(git.getRepository())) {
|
||||
revObject = walk.parseTag(objectId);
|
||||
tag.addSignature(getTagSignature((RevTag) revObject));
|
||||
}
|
||||
|
||||
return tag;
|
||||
} catch (IOException | GitAPIException ex) {
|
||||
throw new InternalRepositoryException(repository, "could not create tag " + request.getName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(TagDeleteRequest request) {
|
||||
try (Git git = new Git(context.open())) {
|
||||
git.tagDelete().setTags(request.getName()).call();
|
||||
} catch (GitAPIException | IOException e) {
|
||||
throw new InternalRepositoryException(repository, "could not delete tag", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final byte[] GPG_HEADER = {'g', 'p', 'g', 's', 'i', 'g'};
|
||||
|
||||
private Signature getTagSignature(RevTag tag) {
|
||||
byte[] raw = tag.getFullMessage().getBytes();
|
||||
|
||||
int start = RawParseUtils.headerStart(GPG_HEADER, raw, 0);
|
||||
if (start < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int end = RawParseUtils.headerEnd(raw, start);
|
||||
byte[] signature = Arrays.copyOfRange(raw, start, end);
|
||||
|
||||
String publicKeyId = gpg.findPublicKeyId(signature);
|
||||
if (Strings.isNullOrEmpty(publicKeyId)) {
|
||||
// key not found
|
||||
return new Signature(publicKeyId, "gpg", SignatureStatus.NOT_FOUND, null, Collections.emptySet());
|
||||
}
|
||||
|
||||
Optional<PublicKey> publicKeyById = gpg.findPublicKey(publicKeyId);
|
||||
if (!publicKeyById.isPresent()) {
|
||||
// key not found
|
||||
return new Signature(publicKeyId, "gpg", SignatureStatus.NOT_FOUND, null, Collections.emptySet());
|
||||
}
|
||||
|
||||
PublicKey publicKey = publicKeyById.get();
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
byte[] headerPrefix = Arrays.copyOfRange(raw, 0, start - GPG_HEADER.length - 1);
|
||||
baos.write(headerPrefix);
|
||||
|
||||
byte[] headerSuffix = Arrays.copyOfRange(raw, end + 1, raw.length);
|
||||
baos.write(headerSuffix);
|
||||
} catch (IOException ex) {
|
||||
// this will never happen, because we are writing into memory
|
||||
throw new IllegalStateException("failed to write into memory", ex);
|
||||
}
|
||||
|
||||
boolean verified = publicKey.verify(baos.toByteArray(), signature);
|
||||
return new Signature(
|
||||
publicKeyId,
|
||||
"gpg",
|
||||
verified ? SignatureStatus.VERIFIED : SignatureStatus.INVALID,
|
||||
publicKey.getOwner().orElse(null),
|
||||
publicKey.getContacts()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -30,17 +30,22 @@ import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.revwalk.RevObject;
|
||||
import org.eclipse.jgit.revwalk.RevTag;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.GitUtil;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.Signature;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.security.GPG;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
@@ -49,20 +54,23 @@ import java.util.List;
|
||||
*/
|
||||
public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
||||
|
||||
private final GPG gpg;
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
public GitTagsCommand(GitContext context) {
|
||||
public GitTagsCommand(GitContext context, GPG gpp) {
|
||||
super(context);
|
||||
this.gpg = gpp;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public List<Tag> getTags() throws IOException {
|
||||
List<Tag> tags = null;
|
||||
List<Tag> tags;
|
||||
|
||||
RevWalk revWalk = null;
|
||||
|
||||
@@ -74,7 +82,7 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
||||
List<Ref> tagList = git.tagList().call();
|
||||
|
||||
tags = Lists.transform(tagList,
|
||||
new TransformFuntion(git.getRepository(), revWalk));
|
||||
new TransformFuntion(git.getRepository(), revWalk, gpg, git));
|
||||
} catch (GitAPIException ex) {
|
||||
throw new InternalRepositoryException(repository, "could not read tags from repository", ex);
|
||||
} finally {
|
||||
@@ -109,9 +117,13 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
||||
* @param revWalk
|
||||
*/
|
||||
public TransformFuntion(org.eclipse.jgit.lib.Repository repository,
|
||||
RevWalk revWalk) {
|
||||
RevWalk revWalk,
|
||||
GPG gpg,
|
||||
Git git) {
|
||||
this.repository = repository;
|
||||
this.revWalk = revWalk;
|
||||
this.gpg = gpg;
|
||||
this.git = git;
|
||||
}
|
||||
|
||||
//~--- methods ------------------------------------------------------------
|
||||
@@ -133,6 +145,18 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
||||
String name = GitUtil.getTagName(ref);
|
||||
|
||||
tag = new Tag(name, revObject.getId().name(), GitUtil.getTagTime(revWalk, ref.getObjectId()));
|
||||
|
||||
try {
|
||||
RevTag revTag = GitUtil.getTag(repository, revWalk, ref);
|
||||
|
||||
final Optional<Signature> tagSignature = GitUtil.getTagSignature(revTag, gpg);
|
||||
if (tagSignature.isPresent()) {
|
||||
tag.addSignature(tagSignature.get());
|
||||
}
|
||||
} catch (IncorrectObjectTypeException e) {
|
||||
// Ignore, this must be a lightweight tag
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} catch (IOException ex) {
|
||||
@@ -153,5 +177,7 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
||||
* Field description
|
||||
*/
|
||||
private RevWalk revWalk;
|
||||
private final GPG gpg;
|
||||
private final Git git;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.Branch;
|
||||
import sonia.scm.repository.BranchCreatedEvent;
|
||||
import sonia.scm.repository.PostReceiveRepositoryHookEvent;
|
||||
import sonia.scm.repository.PreReceiveRepositoryHookEvent;
|
||||
import sonia.scm.repository.api.BranchRequest;
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.repository.GitRepositoryHandler;
|
||||
import sonia.scm.security.GPG;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -45,6 +46,9 @@ class GitRepositoryServiceProviderTest {
|
||||
@Mock
|
||||
private GitContext context;
|
||||
|
||||
@Mock
|
||||
private GPG gpg;
|
||||
|
||||
@Test
|
||||
void shouldCreatePushCommand() {
|
||||
GitRepositoryServiceProvider provider = createProvider();
|
||||
@@ -59,7 +63,7 @@ class GitRepositoryServiceProviderTest {
|
||||
}
|
||||
|
||||
private GitRepositoryServiceProvider createProvider() {
|
||||
return new GitRepositoryServiceProvider(createParentInjector(), context);
|
||||
return new GitRepositoryServiceProvider(createParentInjector(), context, gpg);
|
||||
}
|
||||
|
||||
private Injector createParentInjector() {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import org.eclipse.jgit.lib.GpgSigner;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.GitTestHelper;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.api.TagDeleteRequest;
|
||||
import sonia.scm.repository.api.TagCreateRequest;
|
||||
import sonia.scm.security.GPG;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GitTagCommandTest extends AbstractGitCommandTestBase {
|
||||
|
||||
@Mock
|
||||
private GPG gpg;
|
||||
|
||||
@Before
|
||||
public void setSigner() {
|
||||
GpgSigner.setDefault(new GitTestHelper.SimpleGpgSigner());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateATag() throws IOException {
|
||||
createCommand().create(new TagCreateRequest("592d797cd36432e591416e8b2b98154f4f163411", "newtag"));
|
||||
Optional<Tag> tag = findTag(createContext(), "newtag");
|
||||
assertThat(tag).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeleteATag() throws IOException {
|
||||
final GitContext context = createContext();
|
||||
Optional<Tag> tag = findTag(context, "test-tag");
|
||||
assertThat(tag).isNotEmpty();
|
||||
|
||||
createCommand().delete(new TagDeleteRequest("test-tag"));
|
||||
|
||||
tag = findTag(context, "test-tag");
|
||||
assertThat(tag).isEmpty();
|
||||
}
|
||||
|
||||
private GitTagCommand createCommand() {
|
||||
return new GitTagCommand(createContext(), gpg);
|
||||
}
|
||||
|
||||
private List<Tag> readTags(GitContext context) throws IOException {
|
||||
return new GitTagsCommand(context, gpg).getTags();
|
||||
}
|
||||
|
||||
private Optional<Tag> findTag(GitContext context, String name) throws IOException {
|
||||
List<Tag> branches = readTags(context);
|
||||
return branches.stream().filter(b -> name.equals(b.getName())).findFirst();
|
||||
}
|
||||
}
|
||||
@@ -29,14 +29,22 @@ import com.github.sdorra.shiro.SubjectAware;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.security.GPG;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.anyOf;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SubjectAware(configuration = "classpath:sonia/scm/configuration/shiro.ini", username = "admin", password = "secret")
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GitTagsCommandTest extends AbstractGitCommandTestBase {
|
||||
|
||||
@Rule
|
||||
@@ -48,24 +56,41 @@ public class GitTagsCommandTest extends AbstractGitCommandTestBase {
|
||||
@Rule
|
||||
public ShiroRule shiro = new ShiroRule();
|
||||
|
||||
@Mock
|
||||
GPG gpg;
|
||||
|
||||
@Test
|
||||
public void shouldGetDatesCorrectly() throws IOException {
|
||||
final GitContext gitContext = createContext();
|
||||
final GitTagsCommand tagsCommand = new GitTagsCommand(gitContext);
|
||||
final GitTagsCommand tagsCommand = new GitTagsCommand(gitContext, gpg);
|
||||
final List<Tag> tags = tagsCommand.getTags();
|
||||
assertThat(tags).hasSize(2);
|
||||
assertThat(tags).hasSize(3);
|
||||
|
||||
Tag annotatedTag = tags.get(0);
|
||||
assertThat(annotatedTag.getName()).isEqualTo("1.0.0");
|
||||
assertThat(annotatedTag.getDate()).contains(1598348105000L); // Annotated - Take tag date
|
||||
assertThat(annotatedTag.getRevision()).isEqualTo("fcd0ef1831e4002ac43ea539f4094334c79ea9ec");
|
||||
|
||||
Tag lightweightTag = tags.get(1);
|
||||
Tag lightweightTag = tags.get(2);
|
||||
assertThat(lightweightTag.getName()).isEqualTo("test-tag");
|
||||
assertThat(lightweightTag.getDate()).contains(1339416344000L); // Lightweight - Take commit date
|
||||
assertThat(lightweightTag.getRevision()).isEqualTo("86a6645eceefe8b9a247db5eb16e3d89a7e6e6d1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetSignatures() throws IOException {
|
||||
Mockito.when(gpg.findPublicKeyId(ArgumentMatchers.any())).thenReturn("2BA27721F113C005CC16F06BAE63EFBC49F140CF");
|
||||
|
||||
final GitContext gitContext = createContext();
|
||||
final GitTagsCommand tagsCommand = new GitTagsCommand(gitContext, gpg);
|
||||
final List<Tag> tags = tagsCommand.getTags();
|
||||
|
||||
assertThat(tags).hasSize(3);
|
||||
|
||||
Tag signedTag = tags.get(1);
|
||||
assertThat(signedTag.getSignatures()).isNotEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getZippedRepositoryResource() {
|
||||
return "sonia/scm/repository/spi/scm-git-spi-test-tags.zip";
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user