diff --git a/CHANGELOG.md b/CHANGELOG.md index 82abb84b2e..e170cab88e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased +### Fixed +- Migration of non-bare repositories ([#1213](https://github.com/scm-manager/scm-manager/pull/1213)) + ## [2.1.0] - 2020-06-18 ### Added - Option to configure jvm parameter of docker container with env JAVA_OPTS or with arguments ([#1175](https://github.com/scm-manager/scm-manager/pull/1175)) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/update/GitV2UpdateStep.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/update/GitV2UpdateStep.java index 0bbb479ed6..d805fae53c 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/update/GitV2UpdateStep.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/update/GitV2UpdateStep.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.update; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; @@ -38,6 +38,7 @@ import sonia.scm.version.Version; import javax.inject.Inject; import java.io.File; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import static sonia.scm.version.Version.parse; @@ -60,7 +61,8 @@ public class GitV2UpdateStep implements UpdateStep { (repositoryId, path) -> { Repository repository = repositoryMetadataAccess.read(path); if (isGitDirectory(repository)) { - try (org.eclipse.jgit.lib.Repository gitRepository = build(path.resolve("data").toFile())) { + final Path effectiveGitPath = determineEffectiveGitFolder(path); + try (org.eclipse.jgit.lib.Repository gitRepository = build(effectiveGitPath.toFile())) { new GitConfigHelper().createScmmConfig(repository, gitRepository); } catch (IOException e) { throw new UpdateException("could not update repository with id " + repositoryId + " in path " + path, e); @@ -70,6 +72,18 @@ public class GitV2UpdateStep implements UpdateStep { ); } + public Path determineEffectiveGitFolder(Path path) { + Path bareGitFolder = path.resolve("data"); + Path nonBareGitFolder = bareGitFolder.resolve(".git"); + final Path effectiveGitPath; + if (Files.exists(nonBareGitFolder)) { + effectiveGitPath = nonBareGitFolder; + } else { + effectiveGitPath = bareGitFolder; + } + return effectiveGitPath; + } + private org.eclipse.jgit.lib.Repository build(File directory) throws IOException { return new FileRepositoryBuilder() .setGitDir(directory) diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/update/GitV2UpdateStepTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/update/GitV2UpdateStepTest.java new file mode 100644 index 0000000000..c207a4bf54 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/update/GitV2UpdateStepTest.java @@ -0,0 +1,92 @@ +/* + * 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.update; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryLocationResolver; +import sonia.scm.update.UpdateStepRepositoryMetadataAccess; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.function.BiConsumer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class GitV2UpdateStepTest { + + @Mock + RepositoryLocationResolver locationResolver; + @Mock + RepositoryLocationResolver.RepositoryLocationResolverInstance locationResolverInstance; + @Mock + UpdateStepRepositoryMetadataAccess repositoryMetadataAccess; + + @InjectMocks + GitV2UpdateStep updateStep; + + @BeforeEach + void createDataDirectory(@TempDir Path temp) throws IOException { + Files.createDirectories(temp.resolve("data")); + } + + @BeforeEach + void initRepositoryFolder(@TempDir Path temp) { + when(locationResolver.forClass(Path.class)).thenReturn(locationResolverInstance); + when(repositoryMetadataAccess.read(temp)).thenReturn(new Repository("123", "git", "space", "X")); + doAnswer(invocation -> { + invocation.getArgument(0, BiConsumer.class).accept("123", temp); + return null; + }).when(locationResolverInstance).forAllLocations(any()); + } + + @Test + void shouldWriteConfigFileForBareRepositories(@TempDir Path temp) { + updateStep.doUpdate(); + + assertThat(temp.resolve("data").resolve("config")).exists(); + } + + @Test + void shouldWriteConfigFileForNonBareRepositories(@TempDir Path temp) throws IOException { + Files.createDirectories(temp.resolve("data").resolve(".git")); + + updateStep.doUpdate(); + + assertThat(temp.resolve("data").resolve("config")).doesNotExist(); + assertThat(temp.resolve("data").resolve(".git").resolve("config")).exists(); + } +}