only map additional information for branches on branchesOverview to improve performance

This commit is contained in:
Eduard Heimbuch
2020-09-16 14:37:18 +02:00
parent 909f5ebec9
commit d6c129915b
10 changed files with 54 additions and 33 deletions

View File

@@ -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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
- Tags overview for repository [#1331](https://github.com/scm-manager/scm-manager/pull/1331)
## [2.5.0] - 2020-09-10 ## [2.5.0] - 2020-09-10
### Added ### Added
- Tags now have date information attached ([#1305](https://github.com/scm-manager/scm-manager/pull/1305)) - Tags now have date information attached ([#1305](https://github.com/scm-manager/scm-manager/pull/1305))

View File

@@ -117,7 +117,7 @@ const mapStateToProps = (state: any, ownProps: Props) => {
const mapDispatchToProps = (dispatch: any) => { const mapDispatchToProps = (dispatch: any) => {
return { return {
fetchBranches: (repository: Repository) => { fetchBranches: (repository: Repository) => {
dispatch(fetchBranches(repository)); dispatch(fetchBranches(repository, true));
} }
}; };
}; };

View File

@@ -119,7 +119,7 @@ class CreateBranch extends React.Component<Props> {
const mapDispatchToProps = (dispatch: any) => { const mapDispatchToProps = (dispatch: any) => {
return { return {
fetchBranches: (repository: Repository) => { fetchBranches: (repository: Repository) => {
dispatch(fetchBranches(repository)); dispatch(fetchBranches(repository, false));
}, },
createBranch: ( createBranch: (
createLink: string, createLink: string,

View File

@@ -24,7 +24,7 @@
import { FAILURE_SUFFIX, PENDING_SUFFIX, RESET_SUFFIX, SUCCESS_SUFFIX } from "../../../modules/types"; import { FAILURE_SUFFIX, PENDING_SUFFIX, RESET_SUFFIX, SUCCESS_SUFFIX } from "../../../modules/types";
import { apiClient } from "@scm-manager/ui-components"; import { apiClient } from "@scm-manager/ui-components";
import { Action, Branch, BranchRequest, Repository } from "@scm-manager/ui-types"; import { Action, Branch, BranchRequest, Repository, Link } from "@scm-manager/ui-types";
import { isPending } from "../../../modules/pending"; import { isPending } from "../../../modules/pending";
import { getFailure } from "../../../modules/failure"; import { getFailure } from "../../../modules/failure";
@@ -50,7 +50,7 @@ const CONTENT_TYPE_BRANCH_REQUEST = "application/vnd.scmm-branchRequest+json;v=2
// Fetching branches // Fetching branches
export function fetchBranches(repository: Repository) { export function fetchBranches(repository: Repository, fullInformation: boolean) {
if (!repository._links.branches) { if (!repository._links.branches) {
return { return {
type: FETCH_BRANCHES_SUCCESS, type: FETCH_BRANCHES_SUCCESS,
@@ -64,8 +64,12 @@ export function fetchBranches(repository: Repository) {
return function(dispatch: any) { return function(dispatch: any) {
dispatch(fetchBranchesPending(repository)); dispatch(fetchBranchesPending(repository));
let link = (repository._links.branches as Link).href;
if (fullInformation) {
link += "?fullInformation=true";
}
return apiClient return apiClient
.get(repository._links.branches.href) .get(link)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
dispatch(fetchBranchesSuccess(data, repository)); dispatch(fetchBranchesSuccess(data, repository));
@@ -77,7 +81,7 @@ export function fetchBranches(repository: Repository) {
} }
export function fetchBranch(repository: Repository, name: string) { export function fetchBranch(repository: Repository, name: string) {
let link = repository._links.branches.href; let link = (repository._links.branches as Link).href;
if (!link.endsWith("/")) { if (!link.endsWith("/")) {
link += "/"; link += "/";
} }
@@ -125,8 +129,8 @@ export function createBranch(
// Selectors // Selectors
function collectBranches(repoState) { function collectBranches(repoState: any) {
return repoState.list._embedded.branches.map(name => repoState.byName[name]); return repoState.list._embedded.branches.map((name: string) => repoState.byName[name]);
} }
const memoizedBranchCollector = memoizeOne(collectBranches); const memoizedBranchCollector = memoizeOne(collectBranches);

View File

@@ -108,7 +108,7 @@ class CodeOverview extends React.Component<Props> {
const mapDispatchToProps = (dispatch: any) => { const mapDispatchToProps = (dispatch: any) => {
return { return {
fetchBranches: (repo: Repository) => { fetchBranches: (repo: Repository) => {
dispatch(fetchBranches(repo)); dispatch(fetchBranches(repo, false));
} }
}; };
}; };

View File

@@ -52,14 +52,14 @@ public class BranchCollectionToDtoMapper {
this.branchToDtoMapper = branchToDtoMapper; this.branchToDtoMapper = branchToDtoMapper;
} }
public HalRepresentation map(Repository repository, Collection<Branch> branches) { public HalRepresentation map(Repository repository, Collection<Branch> branches, boolean fullInformation) {
return new HalRepresentation( return new HalRepresentation(
createLinks(repository), createLinks(repository),
embedDtos(getBranchDtoList(repository.getNamespace(), repository.getName(), branches))); embedDtos(getBranchDtoList(repository.getNamespace(), repository.getName(), branches, fullInformation)));
} }
public List<BranchDto> getBranchDtoList(String namespace, String name, Collection<Branch> branches) { public List<BranchDto> getBranchDtoList(String namespace, String name, Collection<Branch> branches, boolean fullInformation) {
return branches.stream().map(branch -> branchToDtoMapper.map(branch, new NamespaceAndName(namespace, name))).collect(toList()); return branches.stream().map(branch -> branchToDtoMapper.map(branch, new NamespaceAndName(namespace, name), fullInformation)).collect(toList());
} }
private Links createLinks(Repository repository) { private Links createLinks(Repository repository) {

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
package sonia.scm.api.v2.resources; package sonia.scm.api.v2.resources;
import com.google.common.base.Strings; import com.google.common.base.Strings;
@@ -120,7 +120,12 @@ public class BranchRootResource {
schema = @Schema(implementation = ErrorDto.class) schema = @Schema(implementation = ErrorDto.class)
) )
) )
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("branch") String branchName) throws IOException { public Response get(
@PathParam("namespace") String namespace,
@PathParam("name") String name,
@PathParam("branch") String branchName,
@QueryParam("fullInformation") @DefaultValue("false") boolean fullInformation
) throws IOException {
NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name); NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name);
try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) { try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) {
Branches branches = repositoryService.getBranchesCommand().getBranches(); Branches branches = repositoryService.getBranchesCommand().getBranches();
@@ -128,7 +133,7 @@ public class BranchRootResource {
.stream() .stream()
.filter(branch -> branchName.equals(branch.getName())) .filter(branch -> branchName.equals(branch.getName()))
.findFirst() .findFirst()
.map(branch -> branchToDtoMapper.map(branch, namespaceAndName)) .map(branch -> branchToDtoMapper.map(branch, namespaceAndName, fullInformation))
.map(Response::ok) .map(Response::ok)
.orElseThrow(() -> notFound(entity("branch", branchName).in(namespaceAndName))) .orElseThrow(() -> notFound(entity("branch", branchName).in(namespaceAndName)))
.build(); .build();
@@ -293,10 +298,14 @@ public class BranchRootResource {
mediaType = VndMediaType.ERROR_TYPE, mediaType = VndMediaType.ERROR_TYPE,
schema = @Schema(implementation = ErrorDto.class) schema = @Schema(implementation = ErrorDto.class)
)) ))
public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name) throws IOException { public Response getAll(
@PathParam("namespace") String namespace,
@PathParam("name") String name,
@QueryParam("fullInformation") @DefaultValue("false") boolean fullInformation
) throws IOException {
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) { try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
Branches branches = repositoryService.getBranchesCommand().getBranches(); Branches branches = repositoryService.getBranchesCommand().getBranches();
return Response.ok(branchCollectionToDtoMapper.map(repositoryService.getRepository(), branches.getBranches())).build(); return Response.ok(branchCollectionToDtoMapper.map(repositoryService.getRepository(), branches.getBranches(), fullInformation)).build();
} catch (CommandNotSupportedException ex) { } catch (CommandNotSupportedException ex) {
return Response.status(Response.Status.BAD_REQUEST).build(); return Response.status(Response.Status.BAD_REQUEST).build();
} }

View File

@@ -57,12 +57,12 @@ public abstract class BranchToBranchDtoMapper extends HalAppenderMapper {
private RepositoryServiceFactory serviceFactory; private RepositoryServiceFactory serviceFactory;
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes @Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
public abstract BranchDto map(Branch branch, @Context NamespaceAndName namespaceAndName); public abstract BranchDto map(Branch branch, @Context NamespaceAndName namespaceAndName, boolean fullInformation);
abstract PersonDto map(Person person); abstract PersonDto map(Person person);
@ObjectFactory @ObjectFactory
BranchDto createDto(@Context NamespaceAndName namespaceAndName, Branch branch) { BranchDto createDto(@Context NamespaceAndName namespaceAndName, Branch branch, boolean fullInformation) {
Links.Builder linksBuilder = linkingTo() Links.Builder linksBuilder = linkingTo()
.self(resourceLinks.branch().self(namespaceAndName, branch.getName())) .self(resourceLinks.branch().self(namespaceAndName, branch.getName()))
.single(linkBuilder("history", resourceLinks.branch().history(namespaceAndName, branch.getName())).build()) .single(linkBuilder("history", resourceLinks.branch().history(namespaceAndName, branch.getName())).build())
@@ -73,16 +73,18 @@ public abstract class BranchToBranchDtoMapper extends HalAppenderMapper {
applyEnrichers(new EdisonHalAppender(linksBuilder, embeddedBuilder), branch, namespaceAndName); applyEnrichers(new EdisonHalAppender(linksBuilder, embeddedBuilder), branch, namespaceAndName);
BranchDto branchDto = new BranchDto(linksBuilder.build(), embeddedBuilder.build()); BranchDto branchDto = new BranchDto(linksBuilder.build(), embeddedBuilder.build());
try (RepositoryService service = serviceFactory.create(namespaceAndName)) { if (fullInformation) {
Changeset latestChangeset = service.getLogCommand().setBranch(branch.getName()).getChangesets().getChangesets().get(0); try (RepositoryService service = serviceFactory.create(namespaceAndName)) {
branchDto.setLastModified(Instant.ofEpochMilli(latestChangeset.getDate())); Changeset latestChangeset = service.getLogCommand().setBranch(branch.getName()).getChangesets().getChangesets().get(0);
branchDto.setLastModifier(map(latestChangeset.getAuthor())); branchDto.setLastModified(Instant.ofEpochMilli(latestChangeset.getDate()));
} catch (IOException e) { branchDto.setLastModifier(map(latestChangeset.getAuthor()));
throw new InternalRepositoryException( } catch (IOException e) {
ContextEntry.ContextBuilder.entity(Branch.class, branch.getName()), throw new InternalRepositoryException(
"Could not read latest changeset for branch", ContextEntry.ContextBuilder.entity(Branch.class, branch.getName()),
e "Could not read latest changeset for branch",
); e
);
}
} }
return branchDto; return branchDto;

View File

@@ -133,7 +133,7 @@ public abstract class DefaultChangesetToChangesetDtoMapper extends HalAppenderMa
} }
if (repositoryService.isSupported(Command.BRANCHES)) { if (repositoryService.isSupported(Command.BRANCHES)) {
embeddedBuilder.with("branches", branchCollectionToDtoMapper.getBranchDtoList(namespace, name, embeddedBuilder.with("branches", branchCollectionToDtoMapper.getBranchDtoList(namespace, name,
getListOfObjects(source.getBranches(), branchName -> Branch.normalBranch(branchName, source.getId())))); getListOfObjects(source.getBranches(), branchName -> Branch.normalBranch(branchName, source.getId())), false));
} }
if (repositoryService.isSupported(Command.DIFF_RESULT)) { if (repositoryService.isSupported(Command.DIFF_RESULT)) {

View File

@@ -79,8 +79,10 @@ class BranchToBranchDtoMapperTest {
Branch branch = Branch.normalBranch("master", "42"); Branch branch = Branch.normalBranch("master", "42");
BranchDto dto = mapper.map(branch, new NamespaceAndName("hitchhiker", "heart-of-gold")); BranchDto dto = mapper.map(branch, new NamespaceAndName("hitchhiker", "heart-of-gold"), false);
assertThat(dto.getLinks().getLinkBy("ka").get().getHref()).isEqualTo("http://hitchhiker/heart-of-gold/master"); assertThat(dto.getLinks().getLinkBy("ka").get().getHref()).isEqualTo("http://hitchhiker/heart-of-gold/master");
assertThat(dto.getLastModified()).isNull();
assertThat(dto.getLastModifier()).isNull();
} }
@Test @Test
@@ -94,7 +96,7 @@ class BranchToBranchDtoMapperTest {
when(logCommandBuilder.getChangesets()).thenReturn(new ChangesetPagingResult(1, ImmutableList.of(changeset))); when(logCommandBuilder.getChangesets()).thenReturn(new ChangesetPagingResult(1, ImmutableList.of(changeset)));
Branch branch = Branch.normalBranch("master", "42"); Branch branch = Branch.normalBranch("master", "42");
BranchDto dto = mapper.map(branch, new NamespaceAndName("hitchhiker", "heart-of-gold")); BranchDto dto = mapper.map(branch, new NamespaceAndName("hitchhiker", "heart-of-gold"), true);
assertThat(dto.getLastModified()).isEqualTo(Instant.ofEpochMilli(creationTime)); assertThat(dto.getLastModified()).isEqualTo(Instant.ofEpochMilli(creationTime));
assertThat(dto.getLastModifier().getName()).isEqualTo(PersonTestData.ZAPHOD.getName()); assertThat(dto.getLastModifier().getName()).isEqualTo(PersonTestData.ZAPHOD.getName());