mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-12 00:15:44 +01:00
fix review findings
This commit is contained in:
@@ -31,6 +31,7 @@ import lombok.ToString;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a tag in a repository.
|
* Represents a tag in a repository.
|
||||||
@@ -43,6 +44,9 @@ import java.util.Optional;
|
|||||||
@Getter
|
@Getter
|
||||||
public final class Tag {
|
public final class Tag {
|
||||||
|
|
||||||
|
public static final String VALID_REV = "[0-9a-z]+";
|
||||||
|
public static final Pattern VALID_REV_PATTERN = Pattern.compile(VALID_REV);
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final String revision;
|
private final String revision;
|
||||||
private final Long date;
|
private final Long date;
|
||||||
|
|||||||
@@ -29,29 +29,52 @@ import sonia.scm.repository.spi.TagCommand;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class TagCommandBuilder {
|
/**
|
||||||
|
* @since 2.11.0
|
||||||
|
*/
|
||||||
|
public final class TagCommandBuilder {
|
||||||
private final TagCommand command;
|
private final TagCommand command;
|
||||||
|
|
||||||
public TagCommandBuilder(TagCommand command) {
|
public TagCommandBuilder(TagCommand command) {
|
||||||
this.command = command;
|
this.command = command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a command to tag a revision.
|
||||||
|
*
|
||||||
|
* Set parameters and call {@link TagCreateCommandBuilder#execute()}.
|
||||||
|
*
|
||||||
|
* @since 2.11.0
|
||||||
|
*/
|
||||||
public TagCreateCommandBuilder create() {
|
public TagCreateCommandBuilder create() {
|
||||||
return new TagCreateCommandBuilder();
|
return new TagCreateCommandBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a command to delete a tag.
|
||||||
|
*
|
||||||
|
* Set parameters and call {@link TagDeleteCommandBuilder#execute()}.
|
||||||
|
*
|
||||||
|
* @since 2.11.0
|
||||||
|
*/
|
||||||
public TagDeleteCommandBuilder delete() {
|
public TagDeleteCommandBuilder delete() {
|
||||||
return new TagDeleteCommandBuilder();
|
return new TagDeleteCommandBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TagCreateCommandBuilder {
|
public final class TagCreateCommandBuilder {
|
||||||
private final TagCreateRequest request = new TagCreateRequest();
|
private final TagCreateRequest request = new TagCreateRequest();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param revision The revision identifier for which to create the tag
|
||||||
|
*/
|
||||||
public TagCreateCommandBuilder setRevision(String revision) {
|
public TagCreateCommandBuilder setRevision(String revision) {
|
||||||
request.setRevision(revision);
|
request.setRevision(revision);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name The name of the tag
|
||||||
|
*/
|
||||||
public TagCreateCommandBuilder setName(String name) {
|
public TagCreateCommandBuilder setName(String name) {
|
||||||
request.setName(name);
|
request.setName(name);
|
||||||
return this;
|
return this;
|
||||||
@@ -62,9 +85,12 @@ public class TagCommandBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TagDeleteCommandBuilder {
|
public final class TagDeleteCommandBuilder {
|
||||||
private final TagDeleteRequest request = new TagDeleteRequest();
|
private final TagDeleteRequest request = new TagDeleteRequest();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name The name of the tag that should be deleted
|
||||||
|
*/
|
||||||
public TagDeleteCommandBuilder setName(String name) {
|
public TagDeleteCommandBuilder setName(String name) {
|
||||||
request.setName(name);
|
request.setName(name);
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -246,11 +246,9 @@ public abstract class RepositoryServiceProvider implements Closeable
|
|||||||
throw new CommandNotSupportedException(Command.TAGS);
|
throw new CommandNotSupportedException(Command.TAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* @since 2.11.0
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public TagCommand getTagCommand()
|
public TagCommand getTagCommand()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -82,60 +82,16 @@ import static java.util.Optional.of;
|
|||||||
public final class GitUtil {
|
public final class GitUtil {
|
||||||
|
|
||||||
private static final GitUserAgentProvider GIT_USER_AGENT_PROVIDER = new GitUserAgentProvider();
|
private static final GitUserAgentProvider GIT_USER_AGENT_PROVIDER = new GitUserAgentProvider();
|
||||||
|
|
||||||
/**
|
|
||||||
* Field description
|
|
||||||
*/
|
|
||||||
public static final String REF_HEAD = "HEAD";
|
public static final String REF_HEAD = "HEAD";
|
||||||
|
|
||||||
/**
|
|
||||||
* Field description
|
|
||||||
*/
|
|
||||||
public static final String REF_HEAD_PREFIX = "refs/heads/";
|
public static final String REF_HEAD_PREFIX = "refs/heads/";
|
||||||
|
|
||||||
/**
|
|
||||||
* Field description
|
|
||||||
*/
|
|
||||||
public static final String REF_MASTER = "master";
|
public static final String REF_MASTER = "master";
|
||||||
|
|
||||||
/**
|
|
||||||
* Field description
|
|
||||||
*/
|
|
||||||
private static final String DIRECTORY_DOTGIT = ".git";
|
private static final String DIRECTORY_DOTGIT = ".git";
|
||||||
|
|
||||||
/**
|
|
||||||
* Field description
|
|
||||||
*/
|
|
||||||
private static final String DIRECTORY_OBJETCS = "objects";
|
private static final String DIRECTORY_OBJETCS = "objects";
|
||||||
|
|
||||||
/**
|
|
||||||
* Field description
|
|
||||||
*/
|
|
||||||
private static final String DIRECTORY_REFS = "refs";
|
private static final String DIRECTORY_REFS = "refs";
|
||||||
|
|
||||||
/**
|
|
||||||
* Field description
|
|
||||||
*/
|
|
||||||
private static final String PREFIX_HEADS = "refs/heads/";
|
private static final String PREFIX_HEADS = "refs/heads/";
|
||||||
|
|
||||||
/**
|
|
||||||
* Field description
|
|
||||||
*/
|
|
||||||
private static final String PREFIX_TAG = "refs/tags/";
|
private static final String PREFIX_TAG = "refs/tags/";
|
||||||
|
|
||||||
/**
|
|
||||||
* Field description
|
|
||||||
*/
|
|
||||||
private static final String REFSPEC = "+refs/heads/*:refs/remote/scm/%s/*";
|
private static final String REFSPEC = "+refs/heads/*:refs/remote/scm/%s/*";
|
||||||
|
|
||||||
/**
|
|
||||||
* Field description
|
|
||||||
*/
|
|
||||||
private static final String REMOTE_REF = "refs/remote/scm/%s/%s";
|
private static final String REMOTE_REF = "refs/remote/scm/%s/%s";
|
||||||
|
|
||||||
/**
|
|
||||||
* Field description
|
|
||||||
*/
|
|
||||||
private static final int TIMEOUT = 5;
|
private static final int TIMEOUT = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -145,19 +101,11 @@ public final class GitUtil {
|
|||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
//~--- constructors ---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*/
|
|
||||||
private GitUtil() {
|
private GitUtil() {
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
* @param repo
|
|
||||||
*/
|
|
||||||
public static void close(org.eclipse.jgit.lib.Repository repo) {
|
public static void close(org.eclipse.jgit.lib.Repository repo) {
|
||||||
if (repo != null) {
|
if (repo != null) {
|
||||||
repo.close();
|
repo.close();
|
||||||
@@ -186,7 +134,7 @@ public final class GitUtil {
|
|||||||
|
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
tags.put(c.getId(), e.getKey());
|
tags.put(c.getId(), e.getKey());
|
||||||
} else if (logger.isWarnEnabled()) {
|
} else {
|
||||||
logger.warn("could not find commit for tag {}", e.getKey());
|
logger.warn("could not find commit for tag {}", e.getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,13 +162,6 @@ public final class GitUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
* @param directory
|
|
||||||
* @return
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static org.eclipse.jgit.lib.Repository open(File directory)
|
public static org.eclipse.jgit.lib.Repository open(File directory)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
FS fs = FS.DETECTED;
|
FS fs = FS.DETECTED;
|
||||||
@@ -239,33 +180,18 @@ public final class GitUtil {
|
|||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
* @param formatter
|
|
||||||
*/
|
|
||||||
public static void release(DiffFormatter formatter) {
|
public static void release(DiffFormatter formatter) {
|
||||||
if (formatter != null) {
|
if (formatter != null) {
|
||||||
formatter.close();
|
formatter.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
* @param walk
|
|
||||||
*/
|
|
||||||
public static void release(TreeWalk walk) {
|
public static void release(TreeWalk walk) {
|
||||||
if (walk != null) {
|
if (walk != null) {
|
||||||
walk.close();
|
walk.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
* @param walk
|
|
||||||
*/
|
|
||||||
public static void release(RevWalk walk) {
|
public static void release(RevWalk walk) {
|
||||||
if (walk != null) {
|
if (walk != null) {
|
||||||
walk.close();
|
walk.close();
|
||||||
@@ -274,12 +200,6 @@ public final class GitUtil {
|
|||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
//~--- get methods ----------------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
* @param ref
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getBranch(Ref ref) {
|
public static String getBranch(Ref ref) {
|
||||||
String branch = null;
|
String branch = null;
|
||||||
|
|
||||||
@@ -290,12 +210,6 @@ public final class GitUtil {
|
|||||||
return branch;
|
return branch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getBranch(String name) {
|
public static String getBranch(String name) {
|
||||||
String branch = null;
|
String branch = null;
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
package sonia.scm.repository.spi;
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
@@ -34,6 +35,7 @@ import org.eclipse.jgit.lib.Repository;
|
|||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
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 sonia.scm.NotFoundException;
|
||||||
import sonia.scm.event.ScmEventBus;
|
import sonia.scm.event.ScmEventBus;
|
||||||
import sonia.scm.repository.GitUtil;
|
import sonia.scm.repository.GitUtil;
|
||||||
import sonia.scm.repository.InternalRepositoryException;
|
import sonia.scm.repository.InternalRepositoryException;
|
||||||
@@ -41,7 +43,6 @@ import sonia.scm.repository.PostReceiveRepositoryHookEvent;
|
|||||||
import sonia.scm.repository.PreReceiveRepositoryHookEvent;
|
import sonia.scm.repository.PreReceiveRepositoryHookEvent;
|
||||||
import sonia.scm.repository.RepositoryHookEvent;
|
import sonia.scm.repository.RepositoryHookEvent;
|
||||||
import sonia.scm.repository.RepositoryHookType;
|
import sonia.scm.repository.RepositoryHookType;
|
||||||
import sonia.scm.repository.Signature;
|
|
||||||
import sonia.scm.repository.Tag;
|
import sonia.scm.repository.Tag;
|
||||||
import sonia.scm.repository.api.HookContext;
|
import sonia.scm.repository.api.HookContext;
|
||||||
import sonia.scm.repository.api.HookContextFactory;
|
import sonia.scm.repository.api.HookContextFactory;
|
||||||
@@ -50,6 +51,7 @@ import sonia.scm.repository.api.HookTagProvider;
|
|||||||
import sonia.scm.repository.api.TagCreateRequest;
|
import sonia.scm.repository.api.TagCreateRequest;
|
||||||
import sonia.scm.repository.api.TagDeleteRequest;
|
import sonia.scm.repository.api.TagDeleteRequest;
|
||||||
import sonia.scm.security.GPG;
|
import sonia.scm.security.GPG;
|
||||||
|
import sonia.scm.user.User;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -76,53 +78,72 @@ public class GitTagCommand extends AbstractGitCommand implements TagCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Tag create(TagCreateRequest request) {
|
public Tag create(TagCreateRequest request) {
|
||||||
try (Git git = new Git(context.open())) {
|
final String name = request.getName();
|
||||||
String revision = request.getRevision();
|
final String revision = request.getRevision();
|
||||||
|
|
||||||
RevObject revObject;
|
|
||||||
Long tagTime;
|
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(revision)) {
|
if (Strings.isNullOrEmpty(revision)) {
|
||||||
throw new IllegalArgumentException("Revision is required");
|
throw new IllegalArgumentException("Revision is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Strings.isNullOrEmpty(name)) {
|
||||||
|
throw new IllegalArgumentException("Name is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Git git = new Git(context.open())) {
|
||||||
|
|
||||||
|
RevObject revObject;
|
||||||
|
Long tagTime;
|
||||||
|
|
||||||
ObjectId taggedCommitObjectId = git.getRepository().resolve(revision);
|
ObjectId taggedCommitObjectId = git.getRepository().resolve(revision);
|
||||||
|
|
||||||
|
if (taggedCommitObjectId == null) {
|
||||||
|
throw new NotFoundException("revision", revision);
|
||||||
|
}
|
||||||
|
|
||||||
try (RevWalk walk = new RevWalk(git.getRepository())) {
|
try (RevWalk walk = new RevWalk(git.getRepository())) {
|
||||||
revObject = walk.parseAny(taggedCommitObjectId);
|
revObject = walk.parseAny(taggedCommitObjectId);
|
||||||
tagTime = GitUtil.getTagTime(walk, taggedCommitObjectId);
|
tagTime = GitUtil.getTagTime(walk, taggedCommitObjectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Tag tag = new Tag(request.getName(), revision, tagTime);
|
Tag tag = new Tag(name, revision, tagTime);
|
||||||
|
|
||||||
RepositoryHookEvent hookEvent = createTagHookEvent(TagHookContextProvider.createHookEvent(tag));
|
RepositoryHookEvent hookEvent = createTagHookEvent(TagHookContextProvider.createHookEvent(tag));
|
||||||
eventBus.post(new PreReceiveRepositoryHookEvent(hookEvent));
|
eventBus.post(new PreReceiveRepositoryHookEvent(hookEvent));
|
||||||
|
|
||||||
Ref ref =
|
User user = SecurityUtils.getSubject().getPrincipals().oneByType(User.class);
|
||||||
|
PersonIdent taggerIdent = new PersonIdent(user.getDisplayName(), user.getMail());
|
||||||
|
|
||||||
|
// Ref ref =
|
||||||
git.tag()
|
git.tag()
|
||||||
.setObjectId(revObject)
|
.setObjectId(revObject)
|
||||||
.setTagger(new PersonIdent("SCM-Manager", "noreply@scm-manager.org"))
|
.setTagger(taggerIdent)
|
||||||
.setName(request.getName())
|
.setName(name)
|
||||||
.call();
|
.call();
|
||||||
|
|
||||||
try (RevWalk walk = new RevWalk(git.getRepository())) {
|
// Uncomment lines once jgit added support for signing tags
|
||||||
revObject = walk.parseTag(ref.getObjectId());
|
// try (RevWalk walk = new RevWalk(git.getRepository())) {
|
||||||
final Optional<Signature> tagSignature = GitUtil.getTagSignature(revObject, gpg, walk);
|
// revObject = walk.parseTag(ref.getObjectId());
|
||||||
tagSignature.ifPresent(tag::addSignature);
|
// final Optional<Signature> tagSignature = GitUtil.getTagSignature(revObject, gpg, walk);
|
||||||
}
|
// tagSignature.ifPresent(tag::addSignature);
|
||||||
|
// }
|
||||||
|
|
||||||
eventBus.post(new PostReceiveRepositoryHookEvent(hookEvent));
|
eventBus.post(new PostReceiveRepositoryHookEvent(hookEvent));
|
||||||
|
|
||||||
return tag;
|
return tag;
|
||||||
} catch (IOException | GitAPIException ex) {
|
} catch (IOException | GitAPIException ex) {
|
||||||
throw new InternalRepositoryException(repository, "could not create tag " + request.getName(), ex);
|
throw new InternalRepositoryException(repository, "could not create tag " + name + " for revision " + revision, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(TagDeleteRequest request) {
|
public void delete(TagDeleteRequest request) {
|
||||||
try (Git git = new Git(context.open())) {
|
|
||||||
String name = request.getName();
|
String name = request.getName();
|
||||||
|
|
||||||
|
if (Strings.isNullOrEmpty(name)) {
|
||||||
|
throw new IllegalArgumentException("Name is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Git git = new Git(context.open())) {
|
||||||
final Repository repository = git.getRepository();
|
final Repository repository = git.getRepository();
|
||||||
Optional<Ref> tagRef = findTagRef(git, name);
|
Optional<Ref> tagRef = findTagRef(git, name);
|
||||||
Tag tag;
|
Tag tag;
|
||||||
@@ -135,7 +156,7 @@ public class GitTagCommand extends AbstractGitCommand implements TagCommand {
|
|||||||
|
|
||||||
try (RevWalk walk = new RevWalk(repository)) {
|
try (RevWalk walk = new RevWalk(repository)) {
|
||||||
final RevCommit commit = GitUtil.getCommit(repository, walk, tagRef.get());
|
final RevCommit commit = GitUtil.getCommit(repository, walk, tagRef.get());
|
||||||
Long tagTime = GitUtil.getTagTime(walk, commit.toObjectId());
|
Long tagTime = GitUtil.getTagTime(walk, tagRef.get().getObjectId());
|
||||||
tag = new Tag(name, commit.name(), tagTime);
|
tag = new Tag(name, commit.name(), tagTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +165,7 @@ public class GitTagCommand extends AbstractGitCommand implements TagCommand {
|
|||||||
git.tagDelete().setTags(name).call();
|
git.tagDelete().setTags(name).call();
|
||||||
eventBus.post(new PostReceiveRepositoryHookEvent(hookEvent));
|
eventBus.post(new PostReceiveRepositoryHookEvent(hookEvent));
|
||||||
} catch (GitAPIException | IOException e) {
|
} catch (GitAPIException | IOException e) {
|
||||||
throw new InternalRepositoryException(repository, "could not delete tag", e);
|
throw new InternalRepositoryException(repository, "could not delete tag " + name, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +179,7 @@ public class GitTagCommand extends AbstractGitCommand implements TagCommand {
|
|||||||
return new RepositoryHookEvent(context, this.context.getRepository(), RepositoryHookType.PRE_RECEIVE);
|
return new RepositoryHookEvent(context, this.context.getRepository(), RepositoryHookType.PRE_RECEIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TagHookContextProvider extends HookContextProvider {
|
private static class TagHookContextProvider extends HookContextProvider {
|
||||||
private final List<Tag> newTags;
|
private final List<Tag> newTags;
|
||||||
private final List<Tag> deletedTags;
|
private final List<Tag> deletedTags;
|
||||||
|
|
||||||
@@ -177,7 +198,7 @@ public class GitTagCommand extends AbstractGitCommand implements TagCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<HookFeature> getSupportedFeatures() {
|
public Set<HookFeature> getSupportedFeatures() {
|
||||||
return singleton(HookFeature.BRANCH_PROVIDER);
|
return singleton(HookFeature.TAG_PROVIDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -199,5 +220,5 @@ public class GitTagCommand extends AbstractGitCommand implements TagCommand {
|
|||||||
public HookChangesetProvider getChangesetProvider() {
|
public HookChangesetProvider getChangesetProvider() {
|
||||||
return r -> new HookChangesetResponse(emptyList());
|
return r -> new HookChangesetResponse(emptyList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,10 @@ import com.google.common.collect.Lists;
|
|||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||||
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import org.eclipse.jgit.revwalk.RevObject;
|
import org.eclipse.jgit.revwalk.RevObject;
|
||||||
import org.eclipse.jgit.revwalk.RevTag;
|
import org.eclipse.jgit.revwalk.RevTag;
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
@@ -76,15 +79,13 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
|||||||
|
|
||||||
RevWalk revWalk = null;
|
RevWalk revWalk = null;
|
||||||
|
|
||||||
try {
|
try (Git git = new Git(open())) {
|
||||||
final Git git = new Git(open());
|
|
||||||
|
|
||||||
revWalk = new RevWalk(git.getRepository());
|
revWalk = new RevWalk(git.getRepository());
|
||||||
|
|
||||||
List<Ref> tagList = git.tagList().call();
|
List<Ref> tagList = git.tagList().call();
|
||||||
|
|
||||||
tags = Lists.transform(tagList,
|
tags = Lists.transform(tagList,
|
||||||
new TransformFunction(git.getRepository(), revWalk, gpg, git));
|
new TransformFunction(git.getRepository(), revWalk, gpg));
|
||||||
} catch (GitAPIException ex) {
|
} catch (GitAPIException ex) {
|
||||||
throw new InternalRepositoryException(repository, "could not read tags from repository", ex);
|
throw new InternalRepositoryException(repository, "could not read tags from repository", ex);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -114,18 +115,15 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs ...
|
* Constructs ...
|
||||||
*
|
|
||||||
* @param repository
|
* @param repository
|
||||||
* @param revWalk
|
* @param revWalk
|
||||||
*/
|
*/
|
||||||
public TransformFunction(org.eclipse.jgit.lib.Repository repository,
|
public TransformFunction(Repository repository,
|
||||||
RevWalk revWalk,
|
RevWalk revWalk,
|
||||||
GPG gpg,
|
GPG gpg) {
|
||||||
Git git) {
|
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.revWalk = revWalk;
|
this.revWalk = revWalk;
|
||||||
this.gpg = gpg;
|
this.gpg = gpg;
|
||||||
this.git = git;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- methods ------------------------------------------------------------
|
//~--- methods ------------------------------------------------------------
|
||||||
@@ -141,26 +139,17 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
|||||||
Tag tag = null;
|
Tag tag = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
RevObject revObject = GitUtil.getCommit(repository, revWalk, ref);
|
RevCommit revCommit = GitUtil.getCommit(repository, revWalk, ref);
|
||||||
|
if (revCommit != null) {
|
||||||
if (revObject != null) {
|
|
||||||
String name = GitUtil.getTagName(ref);
|
String name = GitUtil.getTagName(ref);
|
||||||
|
tag = new Tag(name, revCommit.getId().name(), GitUtil.getTagTime(revWalk, ref.getObjectId()));
|
||||||
tag = new Tag(name, revObject.getId().name(), GitUtil.getTagTime(revWalk, ref.getObjectId()));
|
RevObject revObject = revWalk.parseAny(ref.getObjectId());
|
||||||
|
if (revObject.getType() == Constants.OBJ_TAG) {
|
||||||
try {
|
RevTag revTag = (RevTag) revObject;
|
||||||
RevTag revTag = GitUtil.getTag(repository, revWalk, ref);
|
GitUtil.getTagSignature(revTag, gpg, revWalk)
|
||||||
|
.ifPresent(tag::addSignature);
|
||||||
final Optional<Signature> tagSignature = GitUtil.getTagSignature(revTag, gpg, revWalk);
|
|
||||||
if (tagSignature.isPresent()) {
|
|
||||||
tag.addSignature(tagSignature.get());
|
|
||||||
}
|
}
|
||||||
} catch (IncorrectObjectTypeException e) {
|
|
||||||
// Ignore because it is a lightweight tag which cannot have signatures
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.error("could not get commit for tag", ex);
|
logger.error("could not get commit for tag", ex);
|
||||||
}
|
}
|
||||||
@@ -173,13 +162,12 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
|||||||
/**
|
/**
|
||||||
* Field description
|
* Field description
|
||||||
*/
|
*/
|
||||||
private org.eclipse.jgit.lib.Repository repository;
|
private final org.eclipse.jgit.lib.Repository repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Field description
|
* Field description
|
||||||
*/
|
*/
|
||||||
private RevWalk revWalk;
|
private final RevWalk revWalk;
|
||||||
private final GPG gpg;
|
private final GPG gpg;
|
||||||
private final Git git;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,8 +134,8 @@ public class GitTagCommandTest extends AbstractGitCommandTestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Optional<Tag> findTag(GitContext context, String name) throws IOException {
|
private Optional<Tag> findTag(GitContext context, String name) throws IOException {
|
||||||
List<Tag> branches = readTags(context);
|
List<Tag> tags = readTags(context);
|
||||||
return branches.stream().filter(b -> name.equals(b.getName())).findFirst();
|
return tags.stream().filter(t -> name.equals(t.getName())).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
private HookContext createMockedContext(InvocationOnMock invocation) {
|
private HookContext createMockedContext(InvocationOnMock invocation) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ package sonia.scm.repository.spi;
|
|||||||
import com.aragost.javahg.Repository;
|
import com.aragost.javahg.Repository;
|
||||||
import com.aragost.javahg.commands.PullCommand;
|
import com.aragost.javahg.commands.PullCommand;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
import sonia.scm.repository.InternalRepositoryException;
|
import sonia.scm.repository.InternalRepositoryException;
|
||||||
import sonia.scm.repository.Tag;
|
import sonia.scm.repository.Tag;
|
||||||
import sonia.scm.repository.api.TagCreateRequest;
|
import sonia.scm.repository.api.TagCreateRequest;
|
||||||
@@ -37,6 +38,7 @@ import java.io.IOException;
|
|||||||
|
|
||||||
public class HgTagCommand extends AbstractCommand implements TagCommand {
|
public class HgTagCommand extends AbstractCommand implements TagCommand {
|
||||||
|
|
||||||
|
public static final String DEFAULT_BRANCH_NAME = "default";
|
||||||
private final HgWorkingCopyFactory workingCopyFactory;
|
private final HgWorkingCopyFactory workingCopyFactory;
|
||||||
|
|
||||||
public HgTagCommand(HgCommandContext context, HgWorkingCopyFactory workingCopyFactory) {
|
public HgTagCommand(HgCommandContext context, HgWorkingCopyFactory workingCopyFactory) {
|
||||||
@@ -46,7 +48,7 @@ public class HgTagCommand extends AbstractCommand implements TagCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Tag create(TagCreateRequest request) {
|
public Tag create(TagCreateRequest request) {
|
||||||
try (WorkingCopy<Repository, Repository> workingCopy = workingCopyFactory.createWorkingCopy(getContext(), "default")) {
|
try (WorkingCopy<Repository, Repository> workingCopy = workingCopyFactory.createWorkingCopy(getContext(), DEFAULT_BRANCH_NAME)) {
|
||||||
Repository repository = getContext().open();
|
Repository repository = getContext().open();
|
||||||
String rev = request.getRevision();
|
String rev = request.getRevision();
|
||||||
if (Strings.isNullOrEmpty(rev)) {
|
if (Strings.isNullOrEmpty(rev)) {
|
||||||
@@ -54,22 +56,22 @@ public class HgTagCommand extends AbstractCommand implements TagCommand {
|
|||||||
}
|
}
|
||||||
com.aragost.javahg.commands.TagCommand.on(workingCopy.getWorkingRepository())
|
com.aragost.javahg.commands.TagCommand.on(workingCopy.getWorkingRepository())
|
||||||
.rev(rev)
|
.rev(rev)
|
||||||
.user("SCM-Manager")
|
.user(SecurityUtils.getSubject().getPrincipal().toString())
|
||||||
.execute(request.getName());
|
.execute(request.getName());
|
||||||
pullChangesIntoCentralRepository(workingCopy, "default");
|
pullChangesIntoCentralRepository(workingCopy, DEFAULT_BRANCH_NAME);
|
||||||
return new Tag(request.getName(), rev);
|
return new Tag(request.getName(), rev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(TagDeleteRequest request) {
|
public void delete(TagDeleteRequest request) {
|
||||||
try (WorkingCopy<Repository, Repository> workingCopy = workingCopyFactory.createWorkingCopy(getContext(), "default")) {
|
try (WorkingCopy<Repository, Repository> workingCopy = workingCopyFactory.createWorkingCopy(getContext(), DEFAULT_BRANCH_NAME)) {
|
||||||
com.aragost.javahg.commands.TagCommand.on(workingCopy.getWorkingRepository())
|
com.aragost.javahg.commands.TagCommand.on(workingCopy.getWorkingRepository())
|
||||||
.user("SCM-Manager")
|
.user(SecurityUtils.getSubject().getPrincipal().toString())
|
||||||
.remove()
|
.remove()
|
||||||
.execute(request.getName());
|
.execute(request.getName());
|
||||||
|
|
||||||
pullChangesIntoCentralRepository(workingCopy, "default");
|
pullChangesIntoCentralRepository(workingCopy, DEFAULT_BRANCH_NAME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,34 +24,15 @@
|
|||||||
|
|
||||||
package sonia.scm.repository.spi;
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
import com.aragost.javahg.commands.PullCommand;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import sonia.scm.repository.Tag;
|
import sonia.scm.repository.Tag;
|
||||||
import sonia.scm.repository.api.TagCommandBuilder;
|
|
||||||
import sonia.scm.repository.work.NoneCachingWorkingCopyPool;
|
|
||||||
import sonia.scm.repository.work.WorkdirProvider;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
public class HgTagsCommandTest extends AbstractHgCommandTestBase {
|
public class HgTagsCommandTest extends AbstractHgCommandTestBase {
|
||||||
|
|
||||||
private SimpleHgWorkingCopyFactory workingCopyFactory;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void initWorkingCopyFactory() {
|
|
||||||
|
|
||||||
workingCopyFactory = new SimpleHgWorkingCopyFactory(new NoneCachingWorkingCopyPool(new WorkdirProvider())) {
|
|
||||||
@Override
|
|
||||||
public void configure(PullCommand pullCommand) {
|
|
||||||
// we do not want to configure http hooks in this unit test
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldGetTagDatesCorrectly() {
|
public void shouldGetTagDatesCorrectly() {
|
||||||
HgTagsCommand hgTagsCommand = new HgTagsCommand(cmdContext);
|
HgTagsCommand hgTagsCommand = new HgTagsCommand(cmdContext);
|
||||||
@@ -61,15 +42,4 @@ public class HgTagsCommandTest extends AbstractHgCommandTestBase {
|
|||||||
assertThat(tags.get(0).getDate()).contains(1339586381000L);
|
assertThat(tags.get(0).getDate()).contains(1339586381000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldNotDie() throws IOException {
|
|
||||||
HgTagCommand hgTagCommand = new HgTagCommand(cmdContext, workingCopyFactory);
|
|
||||||
new TagCommandBuilder(hgTagCommand).create().setRevision("79b6baf49711").setName("newtag").execute();
|
|
||||||
|
|
||||||
HgTagsCommand hgTagsCommand = new HgTagsCommand(cmdContext);
|
|
||||||
final List<Tag> tags = hgTagsCommand.getTags();
|
|
||||||
|
|
||||||
assertThat(tags).isNotEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,11 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {FC, useEffect, useState} from "react";
|
import React, { FC, useEffect, useState } from "react";
|
||||||
import { Modal, InputField, Button, apiClient } from "@scm-manager/ui-components";
|
import { Modal, InputField, Button, apiClient } from "@scm-manager/ui-components";
|
||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
import {Tag} from "@scm-manager/ui-types";
|
import { Tag } from "@scm-manager/ui-types";
|
||||||
import {isBranchValid} from "../validation";
|
import { isBranchValid } from "../validation";
|
||||||
|
|
||||||
type Props = WithTranslation & {
|
type Props = WithTranslation & {
|
||||||
existingTagsLink: string;
|
existingTagsLink: string;
|
||||||
@@ -91,7 +91,12 @@ const CreateTagModal: FC<Props> = ({ t, onClose, tagCreationLink, existingTagsLi
|
|||||||
footer={
|
footer={
|
||||||
<>
|
<>
|
||||||
<Button action={onClose}>{t("tags.create.cancel")}</Button>
|
<Button action={onClose}>{t("tags.create.cancel")}</Button>
|
||||||
<Button color="success" action={() => createTag()} loading={loading} disabled={!!validationError || newTagName.length === 0}>
|
<Button
|
||||||
|
color="success"
|
||||||
|
action={() => createTag()}
|
||||||
|
loading={loading}
|
||||||
|
disabled={!!validationError || newTagName.length === 0}
|
||||||
|
>
|
||||||
{t("tags.create.confirm")}
|
{t("tags.create.confirm")}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Links } from "./hal";
|
import { Links } from "./hal";
|
||||||
import {Signature} from "./Signature";
|
import { Signature } from "./Signature";
|
||||||
|
|
||||||
export type Tag = {
|
export type Tag = {
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
"delete": {
|
"delete": {
|
||||||
"button": "Delete branch",
|
"button": "Delete branch",
|
||||||
"subtitle": "Delete branch",
|
"subtitle": "Delete branch",
|
||||||
"description": "Deleted branches can not be restored.",
|
"description": "Deleted branches cannot be restored.",
|
||||||
"confirmAlert": {
|
"confirmAlert": {
|
||||||
"title": "Delete branch",
|
"title": "Delete branch",
|
||||||
"message": "Do you really want to delete the branch \"{{branch}}\"?",
|
"message": "Do you really want to delete the branch \"{{branch}}\"?",
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { Trans, useTranslation, WithTranslation, withTranslation } from "react-i
|
|||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
import {Changeset, Link, ParentChangeset, Repository, Tag} from "@scm-manager/ui-types";
|
import { Changeset, Link, ParentChangeset, Repository, Tag } from "@scm-manager/ui-types";
|
||||||
import {
|
import {
|
||||||
AvatarImage,
|
AvatarImage,
|
||||||
AvatarWrapper,
|
AvatarWrapper,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ type Props = {
|
|||||||
tag: Tag;
|
tag: Tag;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
onDelete: (tag: Tag) => void;
|
onDelete: (tag: Tag) => void;
|
||||||
|
// deleting: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Created = styled.span`
|
const Created = styled.span`
|
||||||
|
|||||||
@@ -22,11 +22,11 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {FC, useState} from "react";
|
import React, { FC, useState } from "react";
|
||||||
import {Link, Tag} from "@scm-manager/ui-types";
|
import { Link, Tag } from "@scm-manager/ui-types";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import TagRow from "./TagRow";
|
import TagRow from "./TagRow";
|
||||||
import {apiClient, ConfirmAlert, ErrorNotification} from "@scm-manager/ui-components";
|
import { apiClient, ConfirmAlert, ErrorNotification } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
@@ -98,7 +98,8 @@ const TagTable: FC<Props> = ({ baseUrl, tags, fetchTags }) => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>{renderRow()}</tbody>
|
<tbody>{renderRow()}</tbody>
|
||||||
</table>
|
</table>
|
||||||
</>);
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TagTable;
|
export default TagTable;
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ const TagsOverview: FC<Props> = ({ repository, baseUrl }) => {
|
|||||||
const renderTagsTable = () => {
|
const renderTagsTable = () => {
|
||||||
if (!loading && tags?.length > 0) {
|
if (!loading && tags?.length > 0) {
|
||||||
orderTags(tags);
|
orderTags(tags);
|
||||||
return <TagTable baseUrl={baseUrl} tags={tags} fetchTags={() => fetchTags()} />;
|
return <TagTable baseUrl={baseUrl} tags={tags} fetchTags={fetchTags} />;
|
||||||
}
|
}
|
||||||
return <Notification type="info">{t("tags.overview.noTags")}</Notification>;
|
return <Notification type="info">{t("tags.overview.noTags")}</Notification>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,16 +29,20 @@ import lombok.Setter;
|
|||||||
import org.hibernate.validator.constraints.Length;
|
import org.hibernate.validator.constraints.Length;
|
||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.Pattern;
|
||||||
|
|
||||||
|
import static sonia.scm.repository.Branch.VALID_BRANCH_NAMES;
|
||||||
|
import static sonia.scm.repository.Tag.VALID_REV;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class TagRequestDto {
|
public class TagRequestDto {
|
||||||
// TODO: Validate revision via regex
|
@Pattern(regexp = VALID_REV)
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
@Length(min = 1, max = 100)
|
@Length(min = 1, max = 100)
|
||||||
private String revision;
|
private String revision;
|
||||||
|
|
||||||
// TODO: Validate name via regex
|
@Pattern(regexp = VALID_BRANCH_NAMES)
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
@Length(min = 1, max = 100)
|
@Length(min = 1, max = 100)
|
||||||
private String name;
|
private String name;
|
||||||
|
|||||||
Reference in New Issue
Block a user