mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-13 00:45:44 +01:00
create RepositoryInitializer which can be used to create new files in the initial commit on a new repository
This commit is contained in:
@@ -7,6 +7,7 @@ import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryInitializer;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryPermission;
|
||||
import sonia.scm.search.SearchRequest;
|
||||
@@ -24,7 +25,7 @@ import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
@@ -38,13 +39,15 @@ public class RepositoryCollectionResource {
|
||||
private final RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper;
|
||||
private final RepositoryDtoToRepositoryMapper dtoToRepositoryMapper;
|
||||
private final ResourceLinks resourceLinks;
|
||||
private final RepositoryInitializer repositoryInitializer;
|
||||
|
||||
@Inject
|
||||
public RepositoryCollectionResource(RepositoryManager manager, RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper, RepositoryDtoToRepositoryMapper dtoToRepositoryMapper, ResourceLinks resourceLinks) {
|
||||
public RepositoryCollectionResource(RepositoryManager manager, RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper, RepositoryDtoToRepositoryMapper dtoToRepositoryMapper, ResourceLinks resourceLinks, RepositoryInitializer repositoryInitializer) {
|
||||
this.adapter = new CollectionResourceManagerAdapter<>(manager, Repository.class);
|
||||
this.repositoryCollectionToDtoMapper = repositoryCollectionToDtoMapper;
|
||||
this.dtoToRepositoryMapper = dtoToRepositoryMapper;
|
||||
this.resourceLinks = resourceLinks;
|
||||
this.repositoryInitializer = repositoryInitializer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,10 +71,10 @@ public class RepositoryCollectionResource {
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response getAll(@DefaultValue("0") @QueryParam("page") int page,
|
||||
@DefaultValue("" + DEFAULT_PAGE_SIZE) @QueryParam("pageSize") int pageSize,
|
||||
@QueryParam("sortBy") String sortBy,
|
||||
@DefaultValue("false") @QueryParam("desc") boolean desc,
|
||||
@DefaultValue("") @QueryParam("q") String search
|
||||
@DefaultValue("" + DEFAULT_PAGE_SIZE) @QueryParam("pageSize") int pageSize,
|
||||
@QueryParam("sortBy") String sortBy,
|
||||
@DefaultValue("false") @QueryParam("desc") boolean desc,
|
||||
@DefaultValue("") @QueryParam("q") String search
|
||||
) {
|
||||
return adapter.getAll(page, pageSize, createSearchPredicate(search), sortBy, desc,
|
||||
pageResult -> repositoryCollectionToDtoMapper.map(page, pageSize, pageResult));
|
||||
@@ -81,7 +84,7 @@ public class RepositoryCollectionResource {
|
||||
* Creates a new repository.
|
||||
*
|
||||
* <strong>Note:</strong> This method requires "repository" privilege. The namespace of the given repository will
|
||||
* be ignored and set by the configured namespace strategy.
|
||||
* be ignored and set by the configured namespace strategy.
|
||||
*
|
||||
* @param repository The repository to be created.
|
||||
* @return A response with the link to the new repository (if created successfully).
|
||||
@@ -98,10 +101,18 @@ public class RepositoryCollectionResource {
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@ResponseHeaders(@ResponseHeader(name = "Location", description = "uri to the created repository"))
|
||||
public Response create(@Valid RepositoryDto repository) {
|
||||
return adapter.create(repository,
|
||||
public Response create(@Valid RepositoryDto repository, @QueryParam("initialize") boolean initialize) {
|
||||
AtomicReference<Repository> reference = new AtomicReference<>();
|
||||
Response response = adapter.create(repository,
|
||||
() -> createModelObjectFromDto(repository),
|
||||
r -> resourceLinks.repository().self(r.getNamespace(), r.getName()));
|
||||
r -> {
|
||||
reference.set(r);
|
||||
return resourceLinks.repository().self(r.getNamespace(), r.getName());
|
||||
});
|
||||
if (initialize) {
|
||||
repositoryInitializer.initialize(reference.get());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private Repository createModelObjectFromDto(@Valid RepositoryDto repositoryDto) {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package sonia.scm.repository;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import sonia.scm.Priority;
|
||||
import sonia.scm.plugin.Extension;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Extension
|
||||
@Priority(1) // should always be the first, so that plugins can overwrite the readme.md
|
||||
public class ReadmeRepositoryContentInitializer implements RepositoryContentInitializer {
|
||||
@Override
|
||||
public void initialize(InitializerContext context) throws IOException {
|
||||
Repository repository = context.getRepository();
|
||||
|
||||
String content = "# " + repository.getName();
|
||||
String description = repository.getDescription();
|
||||
if (!Strings.isNullOrEmpty(description)) {
|
||||
content += "\n\n" + description;
|
||||
}
|
||||
context.create("README.md").from(content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package sonia.scm.repository;
|
||||
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.CharSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.Priorities;
|
||||
import sonia.scm.repository.api.ModifyCommandBuilder;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Set;
|
||||
|
||||
@Singleton
|
||||
public class RepositoryInitializer {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RepositoryInitializer.class);
|
||||
|
||||
private final RepositoryServiceFactory serviceFactory;
|
||||
private final Iterable<RepositoryContentInitializer> contentInitializers;
|
||||
|
||||
@Inject
|
||||
public RepositoryInitializer(RepositoryServiceFactory serviceFactory, Set<RepositoryContentInitializer> contentInitializerSet) {
|
||||
this.serviceFactory = serviceFactory;
|
||||
this.contentInitializers = Priorities.sortInstances(contentInitializerSet);
|
||||
}
|
||||
|
||||
public void initialize(Repository repository) {
|
||||
try (RepositoryService service = serviceFactory.create(repository)) {
|
||||
ModifyCommandBuilder modifyCommandBuilder = service.getModifyCommand();
|
||||
|
||||
InitializerContextImpl initializerContext = new InitializerContextImpl(repository, modifyCommandBuilder);
|
||||
|
||||
for (RepositoryContentInitializer initializer : contentInitializers) {
|
||||
initializer.initialize(initializerContext);
|
||||
}
|
||||
|
||||
modifyCommandBuilder.setCommitMessage("initialize repository");
|
||||
String revision = modifyCommandBuilder.execute();
|
||||
LOG.info("initialized repository {} as revision {}", repository.getNamespaceAndName(), revision);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new InternalRepositoryException(repository, "failed to initialize repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
private class InitializerContextImpl implements RepositoryContentInitializer.InitializerContext {
|
||||
|
||||
private final Repository repository;
|
||||
private final ModifyCommandBuilder builder;
|
||||
|
||||
InitializerContextImpl(Repository repository, ModifyCommandBuilder builder) {
|
||||
this.repository = repository;
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Repository getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepositoryContentInitializer.CreateFile create(String path) {
|
||||
return new CreateFileImpl(this, builder.createFile(path).setOverwrite(true));
|
||||
}
|
||||
}
|
||||
|
||||
private class CreateFileImpl implements RepositoryContentInitializer.CreateFile {
|
||||
|
||||
private final RepositoryContentInitializer.InitializerContext initializerContext;
|
||||
private final ModifyCommandBuilder.WithOverwriteFlagContentLoader contentLoader;
|
||||
|
||||
CreateFileImpl(RepositoryContentInitializer.InitializerContext initializerContext, ModifyCommandBuilder.WithOverwriteFlagContentLoader contentLoader) {
|
||||
this.initializerContext = initializerContext;
|
||||
this.contentLoader = contentLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepositoryContentInitializer.InitializerContext from(String content) throws IOException {
|
||||
return from(CharSource.wrap(content).asByteSource(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepositoryContentInitializer.InitializerContext from(InputStream input) throws IOException {
|
||||
contentLoader.withData(input);
|
||||
return initializerContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepositoryContentInitializer.InitializerContext from(ByteSource byteSource) throws IOException {
|
||||
contentLoader.withData(byteSource);
|
||||
return initializerContext;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user