diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryContentInitializer.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryContentInitializer.java index eb403d122b..6d89a65e5d 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryContentInitializer.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryContentInitializer.java @@ -71,7 +71,7 @@ public interface RepositoryContentInitializer { * @return context object or empty optional * @since 2.5.0 */ - default Optional getCreationContext(String key, Class type) { + default Optional oneByType(String key, Class type) { return Optional.empty(); } } diff --git a/scm-webapp/src/main/java/sonia/scm/repository/RepositoryInitializer.java b/scm-webapp/src/main/java/sonia/scm/repository/RepositoryInitializer.java index 32a2253017..59380a0539 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/RepositoryInitializer.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/RepositoryInitializer.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; import com.fasterxml.jackson.databind.JsonNode; @@ -97,8 +97,12 @@ public class RepositoryInitializer { } @Override - public Optional getCreationContext(String key, Class type) { - return Optional.of(mapper.convertValue(creationContext.get(key), type)); + public Optional oneByType(String key, Class type) { + JsonNode node = creationContext.get(key); + if (node != null) { + return Optional.of(mapper.convertValue(node, type)); + } + return Optional.empty(); } @Override diff --git a/scm-webapp/src/test/java/sonia/scm/repository/RepositoryInitializerTest.java b/scm-webapp/src/test/java/sonia/scm/repository/RepositoryInitializerTest.java index 53a1ea4b02..a8cd0986aa 100644 --- a/scm-webapp/src/test/java/sonia/scm/repository/RepositoryInitializerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/repository/RepositoryInitializerTest.java @@ -24,6 +24,8 @@ package sonia.scm.repository; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableSet; import com.google.common.io.ByteSource; import com.google.common.io.ByteStreams; @@ -44,6 +46,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Collections; +import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; @@ -51,15 +54,13 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class RepositoryInitializerTest { + private final ObjectMapper mapper = new ObjectMapper(); + @Mock private RepositoryServiceFactory repositoryServiceFactory; @@ -154,6 +155,43 @@ class RepositoryInitializerTest { verify(repositoryService).close(); } + @Test + void shouldCallRepositoryContentInitializerWithContext() throws IOException { + ModifyCommandBuilder.WithOverwriteFlagContentLoader slartiContentLoader = mockContentLoader("Slarti.md"); + + Set repositoryContentInitializers = ImmutableSet.of( + new NamedFileInitializer() + ); + + RepositoryInitializer initializer = new RepositoryInitializer(repositoryServiceFactory, repositoryContentInitializers); + Named named = new Named(); + named.setName("Slarti"); + initializer.initialize(repository, Collections.singletonMap("named", mapper.valueToTree(named))); + + verifyFileCreation(slartiContentLoader, "# Named file"); + + verify(modifyCommand).setCommitMessage("initialize repository"); + verify(modifyCommand).execute(); + + verify(repositoryService).close(); + } + + @Test + void shouldDoNoInitializationWithoutContextType() { + Set repositoryContentInitializers = ImmutableSet.of( + new NamedFileInitializer() + ); + + RepositoryInitializer initializer = new RepositoryInitializer(repositoryServiceFactory, repositoryContentInitializers); + initializer.initialize(repository, Collections.emptyMap()); + + verify(modifyCommand, never()).createFile(any()); + verify(modifyCommand).setCommitMessage("initialize repository"); + verify(modifyCommand).execute(); + + verify(repositoryService).close(); + } + private ModifyCommandBuilder.WithOverwriteFlagContentLoader mockContentLoader(String path) { ModifyCommandBuilder.WithOverwriteFlagContentLoader contentLoader = mock(ModifyCommandBuilder.WithOverwriteFlagContentLoader.class); doReturn(contentLoader).when(modifyCommand).createFile(path); @@ -175,6 +213,29 @@ class RepositoryInitializerTest { assertThat(new String(bytes, StandardCharsets.UTF_8)).isEqualTo(expectedContent); } + private static class NamedFileInitializer implements RepositoryContentInitializer { + + @Override + public void initialize(InitializerContext context) throws IOException { + Optional named = context.oneByType("named", Named.class); + if (named.isPresent()) { + context.create(named.get().getName() + ".md").from("# Named file"); + } + } + } + + static class Named { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + @Priority(1) private static class ReadmeContentInitializer implements RepositoryContentInitializer {