From 5e10f6b7302639d1910045d6756faf9c055141f5 Mon Sep 17 00:00:00 2001 From: Eduard Heimbuch Date: Wed, 22 Jul 2020 10:18:52 +0200 Subject: [PATCH] Invalidate branches cache synchronously on create new branch --- CHANGELOG.md | 1 + .../scm/repository/BranchCreatedEvent.java | 40 +++++++++++++++++++ .../api/RepositoryServiceFactory.java | 12 +++++- .../scm/repository/spi/GitBranchCommand.java | 3 ++ .../repository/spi/GitBranchCommandTest.java | 2 + 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/BranchCreatedEvent.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d6de96521..fe05c67239 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix incorrect trimming of whitespaces in helm chart templates - Fixed error on empty diff expand response ([#1247](https://github.com/scm-manager/scm-manager/pull/1247)) - Ignore ports on proxy exclusions ([#1256](https://github.com/scm-manager/scm-manager/pull/1256)) +- Invalidate branches cache synchronously on create new branch ([#1261](https://github.com/scm-manager/scm-manager/pull/1261)) ## [2.2.0] - 2020-07-03 ### Added diff --git a/scm-core/src/main/java/sonia/scm/repository/BranchCreatedEvent.java b/scm-core/src/main/java/sonia/scm/repository/BranchCreatedEvent.java new file mode 100644 index 0000000000..e7f5fdb364 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/BranchCreatedEvent.java @@ -0,0 +1,40 @@ +/* + * 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; + +import lombok.Value; +import sonia.scm.event.Event; + +/** + * This event is fired when a new branch was created from SCM-Manager. + * Warning: This event will not be fired if a new branch was pushed. + * @since 2.3.0 + */ +@Event +@Value +public class BranchCreatedEvent { + private Repository repository; + private String branchName; +} diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java index 60b11162d1..31ca9ca15d 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java @@ -42,6 +42,7 @@ import sonia.scm.cache.Cache; import sonia.scm.cache.CacheManager; import sonia.scm.config.ScmConfiguration; import sonia.scm.event.ScmEventBus; +import sonia.scm.repository.BranchCreatedEvent; import sonia.scm.repository.ClearRepositoryCacheEvent; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.PostReceiveRepositoryHookEvent; @@ -287,6 +288,7 @@ public final class RepositoryServiceFactory { private final Set> caches = Sets.newHashSet(); + private final CacheManager cacheManager; /** * Constructs a new instance and collect all repository relevant @@ -296,6 +298,7 @@ public final class RepositoryServiceFactory */ public CacheClearHook(CacheManager cacheManager) { + this.cacheManager = cacheManager; this.caches.add(cacheManager.getCache(BlameCommandBuilder.CACHE_NAME)); this.caches.add(cacheManager.getCache(BrowseCommandBuilder.CACHE_NAME)); this.caches.add(cacheManager.getCache(LogCommandBuilder.CACHE_NAME)); @@ -347,7 +350,14 @@ public final class RepositoryServiceFactory } } - @SuppressWarnings("unchecked") + @Subscribe(async = false) + @SuppressWarnings({"unchecked", "java:S3740", "rawtypes"}) + public void onEvent(BranchCreatedEvent event) { + RepositoryCacheKeyPredicate predicate = new RepositoryCacheKeyPredicate(event.getRepository().getId()); + cacheManager.getCache(BranchesCommandBuilder.CACHE_NAME).removeAll(predicate); + } + + @SuppressWarnings({"unchecked", "java:S3740", "rawtypes"}) private void clearCaches(final String repositoryId) { if (logger.isDebugEnabled()) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBranchCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBranchCommand.java index 506580d5a9..eb372ff063 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBranchCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBranchCommand.java @@ -30,6 +30,7 @@ import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.Ref; import sonia.scm.event.ScmEventBus; import sonia.scm.repository.Branch; +import sonia.scm.repository.BranchCreatedEvent; import sonia.scm.repository.GitUtil; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.PostReceiveRepositoryHookEvent; @@ -69,6 +70,8 @@ public class GitBranchCommand extends AbstractGitCommand implements BranchComman eventBus.post(new PreReceiveRepositoryHookEvent(hookEvent)); Ref ref = git.branchCreate().setStartPoint(request.getParentBranch()).setName(request.getNewBranch()).call(); eventBus.post(new PostReceiveRepositoryHookEvent(hookEvent)); + // Clear cache synchronously to avoid branch not found in invalid cache + eventBus.post(new BranchCreatedEvent(repository, request.getNewBranch())); return Branch.normalBranch(request.getNewBranch(), GitUtil.getId(ref.getObjectId())); } catch (GitAPIException | IOException ex) { throw new InternalRepositoryException(repository, "could not create branch " + request.getNewBranch(), ex); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBranchCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBranchCommandTest.java index 020bde53c9..7338c447fb 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBranchCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBranchCommandTest.java @@ -32,6 +32,7 @@ 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; @@ -129,6 +130,7 @@ public class GitBranchCommandTest extends AbstractGitCommandTestBase { List events = captor.getAllValues(); assertThat(events.get(0)).isInstanceOf(PreReceiveRepositoryHookEvent.class); assertThat(events.get(1)).isInstanceOf(PostReceiveRepositoryHookEvent.class); + assertThat(events.get(2)).isInstanceOf(BranchCreatedEvent.class); PreReceiveRepositoryHookEvent event = (PreReceiveRepositoryHookEvent) events.get(0); assertThat(event.getContext().getBranchProvider().getCreatedOrModified()).containsExactly("new_branch");