mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-05 04:55:50 +01:00
Post receive hook after import (#1544)
Fire post receive repository hook event after pull from remote and after unbundle (Git, HG and SVN) Co-authored-by: René Pfeuffer <rene.pfeuffer@cloudogu.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.revwalk.RevCommit;
|
||||
import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.GitChangesetConverter;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
class GitConvertingChangesetIterable implements Iterable<Changeset> {
|
||||
|
||||
private final Iterable<RevCommit> commitIterable;
|
||||
private final GitChangesetConverter converter;
|
||||
|
||||
GitConvertingChangesetIterable(Iterable<RevCommit> commitIterable,
|
||||
GitChangesetConverter converter) {
|
||||
this.commitIterable = commitIterable;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Changeset> iterator() {
|
||||
return new ConvertingChangesetIterator(commitIterable.iterator());
|
||||
}
|
||||
|
||||
class ConvertingChangesetIterator implements Iterator<Changeset> {
|
||||
|
||||
private final Iterator<RevCommit> commitIterator;
|
||||
|
||||
private ConvertingChangesetIterator(Iterator<RevCommit> commitIterator) {
|
||||
this.commitIterator = commitIterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return commitIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Changeset next() {
|
||||
return converter.createChangeset(commitIterator.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.collect.ImmutableSet;
|
||||
import sonia.scm.repository.GitChangesetConverter;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.api.HookBranchProvider;
|
||||
import sonia.scm.repository.api.HookFeature;
|
||||
import sonia.scm.repository.api.HookTagProvider;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
class GitImportHookContextProvider extends HookContextProvider {
|
||||
private final GitChangesetConverter converter;
|
||||
private final List<Tag> newTags;
|
||||
private final GitLazyChangesetResolver changesetResolver;
|
||||
private final List<String> newBranches;
|
||||
|
||||
GitImportHookContextProvider(GitChangesetConverter converter,
|
||||
List<String> newBranches,
|
||||
List<Tag> newTags,
|
||||
GitLazyChangesetResolver changesetResolver) {
|
||||
this.converter = converter;
|
||||
this.newTags = newTags;
|
||||
this.changesetResolver = changesetResolver;
|
||||
this.newBranches = newBranches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<HookFeature> getSupportedFeatures() {
|
||||
return ImmutableSet.of(HookFeature.CHANGESET_PROVIDER, HookFeature.BRANCH_PROVIDER, HookFeature.TAG_PROVIDER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HookTagProvider getTagProvider() {
|
||||
return new HookTagProvider() {
|
||||
@Override
|
||||
public List<Tag> getCreatedTags() {
|
||||
return newTags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tag> getDeletedTags() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public HookBranchProvider getBranchProvider() {
|
||||
return new HookBranchProvider() {
|
||||
@Override
|
||||
public List<String> getCreatedOrModified() {
|
||||
return newBranches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDeletedOrClosed() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public HookChangesetProvider getChangesetProvider() {
|
||||
GitConvertingChangesetIterable changesets = new GitConvertingChangesetIterable(changesetResolver.call(), converter);
|
||||
return r -> new HookChangesetResponse(changesets);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.Repository;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
|
||||
class GitLazyChangesetResolver implements Callable<Iterable<RevCommit>> {
|
||||
private final Repository repository;
|
||||
private final Git git;
|
||||
|
||||
public GitLazyChangesetResolver(Repository repository, Git git) {
|
||||
this.repository = repository;
|
||||
this.git = git;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RevCommit> call() {
|
||||
try {
|
||||
return git.log().all().call();
|
||||
} catch (IOException | GitAPIException e) {
|
||||
throw new InternalRepositoryException(
|
||||
entity(repository).build(),
|
||||
"Could not resolve changesets for imported repository",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 sonia.scm.repository.GitChangesetConverter;
|
||||
import sonia.scm.repository.GitChangesetConverterFactory;
|
||||
import sonia.scm.repository.PostReceiveRepositoryHookEvent;
|
||||
import sonia.scm.repository.RepositoryHookEvent;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.api.HookContext;
|
||||
import sonia.scm.repository.api.HookContextFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static sonia.scm.repository.RepositoryHookType.POST_RECEIVE;
|
||||
|
||||
class GitPostReceiveRepositoryHookEventFactory {
|
||||
|
||||
private final HookContextFactory hookContextFactory;
|
||||
private final GitChangesetConverterFactory changesetConverterFactory;
|
||||
|
||||
@Inject
|
||||
public GitPostReceiveRepositoryHookEventFactory(HookContextFactory hookContextFactory, GitChangesetConverterFactory changesetConverterFactory) {
|
||||
this.hookContextFactory = hookContextFactory;
|
||||
this.changesetConverterFactory = changesetConverterFactory;
|
||||
}
|
||||
|
||||
PostReceiveRepositoryHookEvent createEvent(GitContext gitContext,
|
||||
List<String> branches,
|
||||
List<Tag> tags,
|
||||
GitLazyChangesetResolver changesetResolver
|
||||
) throws IOException {
|
||||
GitChangesetConverter converter = changesetConverterFactory.create(gitContext.open());
|
||||
GitImportHookContextProvider contextProvider = new GitImportHookContextProvider(converter, branches, tags, changesetResolver);
|
||||
HookContext context = hookContextFactory.createContext(contextProvider, gitContext.getRepository());
|
||||
RepositoryHookEvent repositoryHookEvent = new RepositoryHookEvent(context, gitContext.getRepository(), POST_RECEIVE);
|
||||
return new PostReceiveRepositoryHookEvent(repositoryHookEvent);
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Iterables;
|
||||
@@ -41,15 +39,19 @@ import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.GitRepositoryHandler;
|
||||
import sonia.scm.repository.GitUtil;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.api.ImportFailedException;
|
||||
import sonia.scm.repository.api.PullResponse;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Sebastian Sdorra
|
||||
@@ -57,39 +59,21 @@ import java.io.IOException;
|
||||
public class GitPullCommand extends AbstractGitPushOrPullCommand
|
||||
implements PullCommand {
|
||||
|
||||
/**
|
||||
* Field description
|
||||
*/
|
||||
private static final String REF_SPEC = "refs/heads/*:refs/heads/*";
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GitPullCommand.class);
|
||||
private final ScmEventBus eventBus;
|
||||
private final GitPostReceiveRepositoryHookEventFactory eventFactory;
|
||||
|
||||
/**
|
||||
* Field description
|
||||
*/
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(GitPullCommand.class);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
* @param handler
|
||||
* @param context
|
||||
*/
|
||||
@Inject
|
||||
public GitPullCommand(GitRepositoryHandler handler, GitContext context) {
|
||||
public GitPullCommand(GitRepositoryHandler handler,
|
||||
GitContext context,
|
||||
ScmEventBus eventBus,
|
||||
GitPostReceiveRepositoryHookEventFactory eventFactory) {
|
||||
super(handler, context);
|
||||
this.eventBus = eventBus;
|
||||
this.eventFactory = eventFactory;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public PullResponse pull(PullCommandRequest request)
|
||||
throws IOException {
|
||||
@@ -108,24 +92,17 @@ public class GitPullCommand extends AbstractGitPushOrPullCommand
|
||||
}
|
||||
|
||||
private PullResponse convert(Git git, FetchResult fetch) {
|
||||
long counter = 0l;
|
||||
long counter = 0;
|
||||
|
||||
for (TrackingRefUpdate tru : fetch.getTrackingRefUpdates()) {
|
||||
counter += count(git, tru);
|
||||
}
|
||||
|
||||
logger.debug("received {} changesets by pull", counter);
|
||||
LOG.debug("received {} changesets by pull", counter);
|
||||
|
||||
return new PullResponse(counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
* @param git
|
||||
* @param tru
|
||||
* @return
|
||||
*/
|
||||
private long count(Git git, TrackingRefUpdate tru) {
|
||||
long counter = 0;
|
||||
|
||||
@@ -151,12 +128,12 @@ public class GitPullCommand extends AbstractGitPushOrPullCommand
|
||||
counter += Iterables.size(commits);
|
||||
}
|
||||
|
||||
logger.trace("counting {} commits for ref update {}", counter, tru);
|
||||
LOG.trace("counting {} commits for ref update {}", counter, tru);
|
||||
} catch (Exception ex) {
|
||||
logger.error("could not count pushed/pulled changesets", ex);
|
||||
LOG.error("could not count pushed/pulled changesets", ex);
|
||||
}
|
||||
} else {
|
||||
logger.debug("do not count non branch ref update {}", tru);
|
||||
LOG.debug("do not count non branch ref update {}", tru);
|
||||
}
|
||||
|
||||
return counter;
|
||||
@@ -174,10 +151,10 @@ public class GitPullCommand extends AbstractGitPushOrPullCommand
|
||||
Preconditions.checkArgument(sourceDirectory.exists(),
|
||||
"target repository directory does not exists");
|
||||
|
||||
logger.debug("pull changes from {} to {}",
|
||||
LOG.debug("pull changes from {} to {}",
|
||||
sourceDirectory.getAbsolutePath(), repository.getId());
|
||||
|
||||
PullResponse response = null;
|
||||
PullResponse response;
|
||||
|
||||
org.eclipse.jgit.lib.Repository source = null;
|
||||
|
||||
@@ -193,14 +170,14 @@ public class GitPullCommand extends AbstractGitPushOrPullCommand
|
||||
|
||||
private PullResponse pullFromUrl(PullCommandRequest request)
|
||||
throws IOException {
|
||||
logger.debug("pull changes from {} to {}", request.getRemoteUrl(), repository);
|
||||
LOG.debug("pull changes from {} to {}", request.getRemoteUrl(), repository);
|
||||
|
||||
PullResponse response;
|
||||
Git git = Git.wrap(open());
|
||||
|
||||
FetchResult result;
|
||||
try {
|
||||
//J-
|
||||
FetchResult result = git.fetch()
|
||||
result = git.fetch()
|
||||
.setCredentialsProvider(
|
||||
new UsernamePasswordCredentialsProvider(
|
||||
Strings.nullToEmpty(request.getUsername()),
|
||||
@@ -223,6 +200,37 @@ public class GitPullCommand extends AbstractGitPushOrPullCommand
|
||||
);
|
||||
}
|
||||
|
||||
firePostReceiveRepositoryHookEvent(git, result);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private void firePostReceiveRepositoryHookEvent(Git git, FetchResult result) {
|
||||
try {
|
||||
List<String> branches = getBranchesFromFetchResult(result);
|
||||
List<Tag> tags = getTagsFromFetchResult(result);
|
||||
GitLazyChangesetResolver changesetResolver = new GitLazyChangesetResolver(context.getRepository(), git);
|
||||
eventBus.post(eventFactory.createEvent(context, branches, tags, changesetResolver));
|
||||
} catch (IOException e) {
|
||||
throw new ImportFailedException(
|
||||
ContextEntry.ContextBuilder.entity(context.getRepository()).build(),
|
||||
"Could not fire post receive repository hook event after unbundle",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Tag> getTagsFromFetchResult(FetchResult result) {
|
||||
return result.getAdvertisedRefs().stream()
|
||||
.filter(r -> r.getName().startsWith("refs/tags/"))
|
||||
.map(r -> new Tag(r.getName().substring("refs/tags/".length()), r.getObjectId().getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<String> getBranchesFromFetchResult(FetchResult result) {
|
||||
return result.getAdvertisedRefs().stream()
|
||||
.filter(r -> r.getName().startsWith("refs/heads/"))
|
||||
.map(r -> r.getLeaf().getName().substring("refs/heads/".length()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider {
|
||||
|
||||
@Override
|
||||
public UnbundleCommand getUnbundleCommand() {
|
||||
return new GitUnbundleCommand(context);
|
||||
return commandInjector.getInstance(GitUnbundleCommand.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,13 +24,23 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import com.google.common.io.ByteSource;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.api.ImportFailedException;
|
||||
import sonia.scm.repository.api.UnbundleResponse;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static sonia.scm.util.Archives.extractTar;
|
||||
@@ -39,13 +49,21 @@ public class GitUnbundleCommand extends AbstractGitCommand implements UnbundleCo
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GitUnbundleCommand.class);
|
||||
|
||||
GitUnbundleCommand(GitContext context) {
|
||||
private final ScmEventBus eventBus;
|
||||
private final GitPostReceiveRepositoryHookEventFactory eventFactory;
|
||||
|
||||
@Inject
|
||||
GitUnbundleCommand(GitContext context,
|
||||
ScmEventBus eventBus,
|
||||
GitPostReceiveRepositoryHookEventFactory eventFactory) {
|
||||
super(context);
|
||||
this.eventBus = eventBus;
|
||||
this.eventFactory = eventFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbundleResponse unbundle(UnbundleCommandRequest request) throws IOException {
|
||||
ByteSource archive = checkNotNull(request.getArchive(),"archive is required");
|
||||
ByteSource archive = checkNotNull(request.getArchive(), "archive is required");
|
||||
Path repositoryDir = context.getDirectory().toPath();
|
||||
LOG.debug("archive repository {} to {}", repositoryDir, archive);
|
||||
|
||||
@@ -54,9 +72,39 @@ public class GitUnbundleCommand extends AbstractGitCommand implements UnbundleCo
|
||||
}
|
||||
|
||||
unbundleRepositoryFromRequest(request, repositoryDir);
|
||||
firePostReceiveRepositoryHookEvent();
|
||||
|
||||
return new UnbundleResponse(0);
|
||||
}
|
||||
|
||||
private void firePostReceiveRepositoryHookEvent() {
|
||||
try {
|
||||
Git git = Git.wrap(context.open());
|
||||
List<String> branches = extractBranches(git);
|
||||
List<Tag> tags = extractTags(git);
|
||||
GitLazyChangesetResolver changesetResolver = new GitLazyChangesetResolver(context.getRepository(), git);
|
||||
eventBus.post(eventFactory.createEvent(context, branches, tags, changesetResolver));
|
||||
} catch (IOException | GitAPIException e) {
|
||||
throw new ImportFailedException(
|
||||
ContextEntry.ContextBuilder.entity(context.getRepository()).build(),
|
||||
"Could not fire post receive repository hook event after unbundle",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Tag> extractTags(Git git) throws GitAPIException {
|
||||
return git.tagList().call().stream()
|
||||
.map(r -> new Tag(r.getName(), r.getObjectId().getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<String> extractBranches(Git git) throws GitAPIException {
|
||||
return git.branchList().call().stream()
|
||||
.map(Ref::getName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void unbundleRepositoryFromRequest(UnbundleCommandRequest request, Path repositoryDir) throws IOException {
|
||||
extractTar(request.getArchive().openBufferedStream(), repositoryDir).run();
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ package sonia.scm.repository.spi;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.inject.Provider;
|
||||
import org.eclipse.jgit.api.CommitCommand;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
@@ -39,8 +38,8 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.GitChangesetConverterFactory;
|
||||
import sonia.scm.repository.GitRepositoryHandler;
|
||||
import sonia.scm.repository.GitTestHelper;
|
||||
import sonia.scm.repository.Repository;
|
||||
@@ -57,22 +56,18 @@ import static org.mockito.Mockito.when;
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class AbstractRemoteCommandTestBase
|
||||
{
|
||||
public class AbstractRemoteCommandTestBase {
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws GitAPIException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Before
|
||||
public void setup() throws IOException, GitAPIException
|
||||
{
|
||||
public void setup() throws IOException, GitAPIException {
|
||||
incomingDirectory = tempFolder.newFile("incoming");
|
||||
incomingDirectory.delete();
|
||||
outgoingDirectory = tempFolder.newFile("outgoing");
|
||||
@@ -84,6 +79,9 @@ public class AbstractRemoteCommandTestBase
|
||||
incoming = Git.init().setDirectory(incomingDirectory).setBare(false).call();
|
||||
outgoing = Git.init().setDirectory(outgoingDirectory).setBare(false).call();
|
||||
|
||||
eventBus = mock(ScmEventBus.class);
|
||||
eventFactory = mock(GitPostReceiveRepositoryHookEventFactory.class);
|
||||
|
||||
handler = mock(GitRepositoryHandler.class);
|
||||
when(handler.getDirectory(incomingRepository.getId())).thenReturn(
|
||||
incomingDirectory);
|
||||
@@ -93,11 +91,9 @@ public class AbstractRemoteCommandTestBase
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
@After
|
||||
public void tearDownProtocol()
|
||||
{
|
||||
public void tearDownProtocol() {
|
||||
Transport.unregister(proto);
|
||||
}
|
||||
|
||||
@@ -105,11 +101,9 @@ public class AbstractRemoteCommandTestBase
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
@Before
|
||||
public void setUpProtocol()
|
||||
{
|
||||
public void setUpProtocol() {
|
||||
|
||||
// store reference to handle weak references
|
||||
proto = new ScmTransportProtocol(GitTestHelper::createConverterFactory, () -> null, () -> null);
|
||||
@@ -121,12 +115,10 @@ public class AbstractRemoteCommandTestBase
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param expected
|
||||
* @param actual
|
||||
*/
|
||||
protected void assertCommitsEquals(RevCommit expected, Changeset actual)
|
||||
{
|
||||
protected void assertCommitsEquals(RevCommit expected, Changeset actual) {
|
||||
assertEquals(expected.getId().name(), actual.getId());
|
||||
assertEquals(expected.getAuthorIdent().getName(),
|
||||
actual.getAuthor().getName());
|
||||
@@ -138,16 +130,12 @@ public class AbstractRemoteCommandTestBase
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param git
|
||||
* @param message
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws GitAPIException
|
||||
*/
|
||||
protected RevCommit commit(Git git, String message) throws GitAPIException
|
||||
{
|
||||
protected RevCommit commit(Git git, String message) throws GitAPIException {
|
||||
User trillian = UserTestData.createTrillian();
|
||||
CommitCommand cc = git.commit();
|
||||
|
||||
@@ -160,18 +148,15 @@ public class AbstractRemoteCommandTestBase
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param git
|
||||
* @param parent
|
||||
* @param name
|
||||
* @param content
|
||||
*
|
||||
* @throws GitAPIException
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void write(Git git, File parent, String name, String content)
|
||||
throws IOException, GitAPIException
|
||||
{
|
||||
throws IOException, GitAPIException {
|
||||
File file = new File(parent, name);
|
||||
|
||||
Files.write(content, file, Charsets.UTF_8);
|
||||
@@ -180,31 +165,52 @@ public class AbstractRemoteCommandTestBase
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
/**
|
||||
* Field description
|
||||
*/
|
||||
@Rule
|
||||
public TemporaryFolder tempFolder = new TemporaryFolder();
|
||||
|
||||
/** Field description */
|
||||
/**
|
||||
* Field description
|
||||
*/
|
||||
protected GitRepositoryHandler handler;
|
||||
|
||||
/** Field description */
|
||||
/**
|
||||
* Field description
|
||||
*/
|
||||
protected Repository incomingRepository;
|
||||
|
||||
/** Field description */
|
||||
/**
|
||||
* Field description
|
||||
*/
|
||||
protected Git incoming;
|
||||
|
||||
/** Field description */
|
||||
/**
|
||||
* Field description
|
||||
*/
|
||||
protected File incomingDirectory;
|
||||
|
||||
/** Field description */
|
||||
/**
|
||||
* Field description
|
||||
*/
|
||||
protected Git outgoing;
|
||||
|
||||
/** Field description */
|
||||
/**
|
||||
* Field description
|
||||
*/
|
||||
protected File outgoingDirectory;
|
||||
|
||||
/** Field description */
|
||||
/**
|
||||
* Field description
|
||||
*/
|
||||
protected Repository outgoingRepository;
|
||||
|
||||
/** Field description */
|
||||
/**
|
||||
* Field description
|
||||
*/
|
||||
private ScmTransportProtocol proto;
|
||||
|
||||
protected ScmEventBus eventBus;
|
||||
protected GitPostReceiveRepositoryHookEventFactory eventFactory;
|
||||
}
|
||||
|
||||
@@ -44,24 +44,20 @@ import static org.junit.Assert.assertNotNull;
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitIncomingCommandTest
|
||||
extends AbstractRemoteCommandTestBase
|
||||
{
|
||||
extends AbstractRemoteCommandTestBase {
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws GitAPIException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testGetIncomingChangesets()
|
||||
throws IOException, GitAPIException
|
||||
{
|
||||
throws IOException, GitAPIException {
|
||||
write(outgoing, outgoingDirectory, "a.txt", "content of a.txt");
|
||||
|
||||
RevCommit c1 = commit(outgoing, "added a");
|
||||
@@ -84,22 +80,25 @@ public class GitIncomingCommandTest
|
||||
assertCommitsEquals(c2, cpr.getChangesets().get(1));
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws GitAPIException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testGetIncomingChangesetsWithAllreadyPullChangesets()
|
||||
throws IOException, GitAPIException
|
||||
{
|
||||
public void testGetIncomingChangesetsWithAlreadyPulledChangesets()
|
||||
throws IOException, GitAPIException {
|
||||
write(outgoing, outgoingDirectory, "a.txt", "content of a.txt");
|
||||
|
||||
commit(outgoing, "added a");
|
||||
|
||||
GitPullCommand pull = new GitPullCommand(handler, new GitContext(incomingDirectory, incomingRepository, new GitRepositoryConfigStoreProvider(new InMemoryConfigurationStoreFactory()), new GitConfig()));
|
||||
GitPullCommand pull = new GitPullCommand(
|
||||
handler,
|
||||
new GitContext(incomingDirectory, incomingRepository, new GitRepositoryConfigStoreProvider(new InMemoryConfigurationStoreFactory()), new GitConfig()),
|
||||
eventBus,
|
||||
eventFactory
|
||||
);
|
||||
PullCommandRequest req = new PullCommandRequest();
|
||||
req.setRemoteRepository(outgoingRepository);
|
||||
pull.pull(req);
|
||||
@@ -124,13 +123,11 @@ public class GitIncomingCommandTest
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testGetIncomingChangesetsWithEmptyRepository()
|
||||
throws IOException
|
||||
{
|
||||
throws IOException {
|
||||
GitIncomingCommand cmd = createCommand();
|
||||
IncomingCommandRequest request = new IncomingCommandRequest();
|
||||
|
||||
@@ -146,15 +143,13 @@ public class GitIncomingCommandTest
|
||||
/**
|
||||
* Check for correct behaviour
|
||||
*
|
||||
*
|
||||
* @throws GitAPIException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testGetIncomingChangesetsWithUnrelatedRepository()
|
||||
throws IOException, GitAPIException
|
||||
{
|
||||
throws IOException, GitAPIException {
|
||||
write(outgoing, outgoingDirectory, "a.txt", "content of a.txt");
|
||||
|
||||
commit(outgoing, "added a");
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.collect.Iterables;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.junit.Test;
|
||||
import sonia.scm.repository.api.ImportFailedException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class GitLazyChangesetResolverTest extends AbstractGitCommandTestBase {
|
||||
|
||||
@Test
|
||||
public void shouldResolveChangesets() throws IOException {
|
||||
GitLazyChangesetResolver changesetResolver = new GitLazyChangesetResolver(repository, Git.wrap(createContext().open()));
|
||||
Iterable<RevCommit> commits = changesetResolver.call();
|
||||
|
||||
RevCommit firstCommit = commits.iterator().next();
|
||||
assertThat(firstCommit.getId().toString()).isEqualTo("commit a8495c0335a13e6e432df90b3727fa91943189a7 1602078219 -----sp");
|
||||
assertThat(firstCommit.getCommitTime()).isEqualTo(1602078219);
|
||||
assertThat(firstCommit.getFullMessage()).isEqualTo("add deeper paths\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldResolveAllChangesets() throws IOException, GitAPIException {
|
||||
Git git = Git.wrap(createContext().open());
|
||||
GitLazyChangesetResolver changesetResolver = new GitLazyChangesetResolver(repository, git);
|
||||
Iterable<RevCommit> allCommits = changesetResolver.call();
|
||||
int allCommitsCounter = Iterables.size(allCommits);
|
||||
int singleBranchCommitsCounter = Iterables.size(git.log().call());
|
||||
|
||||
assertThat(allCommitsCounter).isGreaterThan(singleBranchCommitsCounter);
|
||||
}
|
||||
|
||||
@Test(expected = ImportFailedException.class)
|
||||
public void shouldThrowImportFailedException() {
|
||||
Git git = mock(Git.class);
|
||||
doThrow(ImportFailedException.class).when(git).log();
|
||||
new GitLazyChangesetResolver(repository, git).call();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import sonia.scm.repository.GitConfig;
|
||||
import sonia.scm.repository.GitTestHelper;
|
||||
import sonia.scm.repository.Modifications;
|
||||
|
||||
import java.io.File;
|
||||
@@ -111,7 +112,12 @@ public class GitModificationsCommandTest extends AbstractRemoteCommandTestBase {
|
||||
PushCommandRequest request = new PushCommandRequest();
|
||||
request.setRemoteRepository(incomingRepository);
|
||||
cmd.push(request);
|
||||
GitPullCommand pullCommand = new GitPullCommand(handler, new GitContext(incomingDirectory, incomingRepository, null, new GitConfig()));
|
||||
GitPullCommand pullCommand = new GitPullCommand(
|
||||
handler,
|
||||
new GitContext(incomingDirectory, incomingRepository, null, new GitConfig()),
|
||||
eventBus,
|
||||
eventFactory
|
||||
);
|
||||
PullCommandRequest pullRequest = new PullCommandRequest();
|
||||
pullRequest.setRemoteRepository(incomingRepository);
|
||||
pullCommand.pull(pullRequest);
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.collect.ImmutableList;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.GitChangesetConverterFactory;
|
||||
import sonia.scm.repository.PostReceiveRepositoryHookEvent;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.api.HookContext;
|
||||
import sonia.scm.repository.api.HookContextFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class GitPostReceiveRepositoryHookEventFactoryTest extends AbstractGitCommandTestBase {
|
||||
|
||||
private HookContext hookContext;
|
||||
|
||||
private GitPostReceiveRepositoryHookEventFactory eventFactory;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
HookContextFactory hookContextFactory = mock(HookContextFactory.class);
|
||||
hookContext = mock(HookContext.class, RETURNS_DEEP_STUBS);
|
||||
when(hookContextFactory.createContext(any(), eq(repository))).thenReturn(hookContext);
|
||||
GitChangesetConverterFactory converterFactory = mock(GitChangesetConverterFactory.class);
|
||||
eventFactory = new GitPostReceiveRepositoryHookEventFactory(hookContextFactory, converterFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateEvent() throws IOException {
|
||||
ImmutableList<String> branches = ImmutableList.of("master", "develop");
|
||||
ImmutableList<Tag> tags = ImmutableList.of(new Tag("1.0", "123"), new Tag("2.0", "456"));
|
||||
ImmutableList<Changeset> changesets = ImmutableList.of(new Changeset("1", 0L, null, "first"));
|
||||
when(hookContext.getChangesetProvider().getChangesetList()).thenReturn(changesets);
|
||||
when(hookContext.getBranchProvider().getCreatedOrModified()).thenReturn(branches);
|
||||
when(hookContext.getTagProvider().getCreatedTags()).thenReturn(tags);
|
||||
|
||||
PostReceiveRepositoryHookEvent event = eventFactory.createEvent(
|
||||
createContext(),
|
||||
branches,
|
||||
tags,
|
||||
new GitLazyChangesetResolver(repository, Git.wrap(createContext().open()))
|
||||
);
|
||||
|
||||
assertThat(event.getContext().getBranchProvider().getCreatedOrModified()).isSameAs(branches);
|
||||
assertThat(event.getContext().getTagProvider().getCreatedTags()).isSameAs(tags);
|
||||
assertThat(event.getContext().getChangesetProvider().getChangesetList().get(0).getId()).isEqualTo("1");
|
||||
}
|
||||
}
|
||||
@@ -24,70 +24,79 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Files;
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.PostReceiveRepositoryHookEvent;
|
||||
import sonia.scm.repository.RepositoryHookEvent;
|
||||
import sonia.scm.repository.RepositoryHookType;
|
||||
import sonia.scm.util.Archives;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class GitUnbundleCommandTest extends AbstractGitCommandTestBase {
|
||||
private GitContext gitContext;
|
||||
public class GitUnbundleCommandTest extends AbstractGitCommandTestBase {
|
||||
private ScmEventBus eventBus;
|
||||
private GitUnbundleCommand unbundleCommand;
|
||||
private GitPostReceiveRepositoryHookEventFactory eventFactory;
|
||||
|
||||
@BeforeEach
|
||||
void initCommand() {
|
||||
gitContext = mock(GitContext.class);
|
||||
unbundleCommand = new GitUnbundleCommand(gitContext);
|
||||
@Before
|
||||
public void initUnbundleCommand() {
|
||||
eventBus = mock(ScmEventBus.class);
|
||||
eventFactory = mock(GitPostReceiveRepositoryHookEventFactory.class);
|
||||
unbundleCommand = new GitUnbundleCommand(createContext(), eventBus, eventFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUnbundleRepositoryFiles(@TempDir Path temp) throws IOException {
|
||||
public void shouldUnbundleRepositoryFiles() throws IOException {
|
||||
when(eventFactory.createEvent(eq(createContext()), any(), any(), any()))
|
||||
.thenReturn(new PostReceiveRepositoryHookEvent(new RepositoryHookEvent(null, repository, RepositoryHookType.POST_RECEIVE)));
|
||||
|
||||
String filePath = "test-input";
|
||||
String fileContent = "HeartOfGold";
|
||||
UnbundleCommandRequest unbundleCommandRequest = createUnbundleCommandRequestForFile(temp, filePath, fileContent);
|
||||
UnbundleCommandRequest unbundleCommandRequest = createUnbundleCommandRequestForFile(filePath, fileContent);
|
||||
|
||||
unbundleCommand.unbundle(unbundleCommandRequest);
|
||||
|
||||
assertFileWithContentWasCreated(temp, filePath, fileContent);
|
||||
assertFileWithContentWasCreated(createContext().getDirectory(), filePath, fileContent);
|
||||
|
||||
verify(eventBus).post(any(PostReceiveRepositoryHookEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUnbundleNestedRepositoryFiles(@TempDir Path temp) throws IOException {
|
||||
public void shouldUnbundleNestedRepositoryFiles() throws IOException {
|
||||
String filePath = "objects/pack/test-input";
|
||||
String fileContent = "hitchhiker";
|
||||
UnbundleCommandRequest unbundleCommandRequest = createUnbundleCommandRequestForFile(temp, filePath, fileContent);
|
||||
UnbundleCommandRequest unbundleCommandRequest = createUnbundleCommandRequestForFile(filePath, fileContent);
|
||||
|
||||
unbundleCommand.unbundle(unbundleCommandRequest);
|
||||
|
||||
assertFileWithContentWasCreated(temp, filePath, fileContent);
|
||||
assertFileWithContentWasCreated(createContext().getDirectory(), filePath, fileContent);
|
||||
}
|
||||
|
||||
private void assertFileWithContentWasCreated(@TempDir Path temp, String filePath, String fileContent) throws IOException {
|
||||
File createdFile = temp.resolve(filePath).toFile();
|
||||
private void assertFileWithContentWasCreated(File temp, String filePath, String fileContent) throws IOException {
|
||||
File createdFile = temp.toPath().resolve(filePath).toFile();
|
||||
assertThat(createdFile).exists();
|
||||
assertThat(Files.readLines(createdFile, StandardCharsets.UTF_8).get(0)).isEqualTo(fileContent);
|
||||
assertThat(createdFile).hasContent(fileContent);
|
||||
}
|
||||
|
||||
private UnbundleCommandRequest createUnbundleCommandRequestForFile(Path temp, String filePath, String fileContent) throws IOException {
|
||||
private UnbundleCommandRequest createUnbundleCommandRequestForFile(String filePath, String fileContent) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
TarArchiveOutputStream taos = Archives.createTarOutputStream(baos);
|
||||
addEntry(taos, filePath, fileContent);
|
||||
taos.finish();
|
||||
taos.close();
|
||||
|
||||
when(gitContext.getDirectory()).thenReturn(temp.toFile());
|
||||
ByteSource byteSource = ByteSource.wrap(baos.toByteArray());
|
||||
UnbundleCommandRequest unbundleCommandRequest = new UnbundleCommandRequest(byteSource);
|
||||
return unbundleCommandRequest;
|
||||
|
||||
Reference in New Issue
Block a user