Skip to content

Commit

Permalink
Merge pull request #352 from reflectoring/delete-branches
Browse files Browse the repository at this point in the history
Add functionallity for deleting branches.
  • Loading branch information
maximAtanasov authored Apr 17, 2020
2 parents 664e250 + 81fa5e4 commit 19435bf
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package io.reflectoring.coderadar.projectadministration.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/** This class represents a branch in a project. */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Branch {
private String name;
private String commitHash;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.reflectoring.coderadar.projectadministration.port.driven.branch;

import io.reflectoring.coderadar.projectadministration.domain.Branch;

public interface DeleteBranchPort {

/**
* Deletes a branch in a project. Any commits that only exist as part of the branch are also
* deleted.
*
* @param projectId The id of the project.
* @param branch The branch to delete.
*/
void delete(long projectId, Branch branch);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.reflectoring.coderadar.projectadministration.port.driver.branch.get;
package io.reflectoring.coderadar.projectadministration.port.driver.branch.list;

import io.reflectoring.coderadar.projectadministration.domain.Branch;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import io.reflectoring.coderadar.projectadministration.domain.Branch;
import io.reflectoring.coderadar.projectadministration.port.driven.branch.ListBranchesPort;
import io.reflectoring.coderadar.projectadministration.port.driven.project.GetProjectPort;
import io.reflectoring.coderadar.projectadministration.port.driver.branch.get.ListBranchesUseCase;
import io.reflectoring.coderadar.projectadministration.port.driver.branch.list.ListBranchesUseCase;
import java.util.List;
import org.springframework.stereotype.Service;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io.reflectoring.coderadar.projectadministration.domain.Module;
import io.reflectoring.coderadar.projectadministration.domain.Project;
import io.reflectoring.coderadar.projectadministration.port.driven.analyzer.AddCommitsPort;
import io.reflectoring.coderadar.projectadministration.port.driven.branch.DeleteBranchPort;
import io.reflectoring.coderadar.projectadministration.port.driven.module.CreateModulePort;
import io.reflectoring.coderadar.projectadministration.port.driven.module.DeleteModulePort;
import io.reflectoring.coderadar.projectadministration.port.driven.project.GetProjectPort;
Expand Down Expand Up @@ -49,6 +50,7 @@ public class ScanProjectScheduler {
private final AddCommitsPort addCommitsPort;
private final DeleteModulePort deleteModulePort;
private final TaskExecutor taskExecutor;
private final DeleteBranchPort deleteBranchPort;

private final Logger logger = LoggerFactory.getLogger(ScanProjectScheduler.class);

Expand All @@ -66,7 +68,8 @@ public ScanProjectScheduler(
CreateModulePort createModulePort,
AddCommitsPort addCommitsPort,
DeleteModulePort deleteModulePort,
TaskExecutor taskExecutor) {
TaskExecutor taskExecutor,
DeleteBranchPort deleteBranchPort) {
this.updateLocalRepositoryUseCase = updateLocalRepositoryUseCase;
this.coderadarConfigurationProperties = coderadarConfigurationProperties;
this.extractProjectCommitsUseCase = extractProjectCommitsUseCase;
Expand All @@ -79,6 +82,7 @@ public ScanProjectScheduler(
this.addCommitsPort = addCommitsPort;
this.deleteModulePort = deleteModulePort;
this.taskExecutor = taskExecutor;
this.deleteBranchPort = deleteBranchPort;
}

/** Starts the scheduleCheckTask tasks upon application start */
Expand Down Expand Up @@ -164,6 +168,12 @@ private void checkForNewCommits(Project project) {
.setUsername(project.getVcsUsername())
.setRemoteUrl(project.getVcsUrl()));
if (!updatedBranches.isEmpty()) {
for (Branch branch : updatedBranches) {
if (branch.getCommitHash().equals("0000000000000000000000000000000000000000")) {
deleteBranchPort.delete(project.getId(), branch);
}
}

// Check what modules where previously in the project
List<Module> modules = listModulesOfProjectUseCase.listModules(project.getId());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,16 @@ List<Map<String, Object>> findByProjectIdNonAnalyzedWithFiles(
+ "MATCH (c2:CommitEntity) WHERE c2.name = {1} WITH c1, c2 LIMIT 1 "
+ "RETURN c1.timestamp > c2.timestamp")
boolean commitIsNewer(@NonNull String commit1, @NonNull String commit2);

@Query("MATCH (c)-[:IS_CHILD_OF]->(c2) WHERE ID(c) = {0} RETURN c2")
List<CommitEntity> getCommitParents(long commitId);

@Query("MATCH (c2)-[:IS_CHILD_OF]->(c) WHERE ID(c) = {0} RETURN c2")
List<CommitEntity> getCommitChildren(long commitId);

@Query(
"MATCH (c) WHERE ID(c) = {0} WITH c "
+ "OPTIONAL MATCH (f)-[r:CHANGED_IN]->(c) "
+ "WHERE r.changeType = \"ADD\" OR r.changeType = \"RENAME\" DETACH DELETE c, f")
void deleteCommitAndAddedOrRenamedFiles(long commitId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,7 @@ public interface MetricRepository extends Neo4jRepository<MetricValueEntity, Lon
+ "NOT(f IN deletes OR f IN renames) AND m.value <> 0 WITH ID(f) as id, m.name as name, head(collect(m)) as metric "
+ "RETURN id, collect(metric) as metrics")
List<FileIdAndMetricQueryResult> getLastMetricsForFiles(long projectId, String branchName);

@Query("MATCH (c)<-[:VALID_FOR]-(m) WHERE ID(c) = {0} DETACH DELETE m")
void deleteMetricsForCommit(Long id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package io.reflectoring.coderadar.graph.projectadministration.branch.adapter;

import io.reflectoring.coderadar.graph.analyzer.repository.CommitRepository;
import io.reflectoring.coderadar.graph.analyzer.repository.MetricRepository;
import io.reflectoring.coderadar.graph.projectadministration.branch.repository.BranchRepository;
import io.reflectoring.coderadar.graph.projectadministration.domain.BranchEntity;
import io.reflectoring.coderadar.graph.projectadministration.domain.CommitEntity;
import io.reflectoring.coderadar.projectadministration.domain.Branch;
import io.reflectoring.coderadar.projectadministration.port.driven.branch.DeleteBranchPort;
import java.util.List;
import org.springframework.stereotype.Service;

@Service
public class DeleteBranchAdapter implements DeleteBranchPort {

private final BranchRepository branchRepository;
private final CommitRepository commitRepository;
private final MetricRepository metricRepository;

public DeleteBranchAdapter(
BranchRepository branchRepository,
CommitRepository commitRepository,
MetricRepository metricRepository) {
this.branchRepository = branchRepository;
this.commitRepository = commitRepository;
this.metricRepository = metricRepository;
}

@Override
public void delete(long projectId, Branch branch) {
CommitEntity branchCommit = branchRepository.getBranchCommit(projectId, branch.getName());
BranchEntity branchEntity =
branchRepository.findBranchInProjectByName(projectId, branch.getName());
branchRepository.delete(branchEntity);
List<BranchEntity> branchesInProject = branchRepository.getBranchesInProject(projectId);
deleteCommits(branchCommit, branchesInProject);
}

/**
* Recursive method that walks the parents of the head of the branch and deletes them if: The
* commit has no children. There is no branch pointer on the commit.
*
* <p>Also deletes any files that have been added or renamed as those are the only change types
* for which new nodes are created and would therefore be no longer needed.
*
* <p>Metrics attached to the commit are also deleted if they exist.
*
* @param commit The commit to delete.
* @param branchesInProject The currently available branches in the project.
*/
private void deleteCommits(CommitEntity commit, List<BranchEntity> branchesInProject) {
List<CommitEntity> children = commitRepository.getCommitChildren(commit.getId());
if (children != null
&& commitRepository.getCommitChildren(commit.getId()).isEmpty()
&& branchesInProject.stream().noneMatch(b -> b.getCommitHash().equals(commit.getName()))) {
List<CommitEntity> parents = commitRepository.getCommitParents(commit.getId());
metricRepository.deleteMetricsForCommit(commit.getId());
commitRepository.deleteCommitAndAddedOrRenamedFiles(commit.getId());
for (CommitEntity parent : parents) {
deleteCommits(parent, branchesInProject);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.reflectoring.coderadar.graph.projectadministration.branch.repository;

import io.reflectoring.coderadar.graph.projectadministration.domain.BranchEntity;
import io.reflectoring.coderadar.graph.projectadministration.domain.CommitEntity;
import java.util.List;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.Neo4jRepository;
Expand Down Expand Up @@ -55,4 +56,13 @@ public interface BranchRepository extends Neo4jRepository<BranchEntity, Long> {
"MATCH (p)-[:HAS_BRANCH]->(b)-[r:POINTS_TO]->() WHERE ID(p) = {0} AND b.name = {1} WITH p, b, r LIMIT 1 DELETE r WITH p, b "
+ "MATCH (p)-[:CONTAINS_COMMIT]->(c:CommitEntity) WHERE c.name = {2} WITH c, b LIMIT 1 CREATE (b)-[r1:POINTS_TO]->(c) SET b.commitHash = c.name")
void moveBranchToCommit(long projectId, @NonNull String branchName, @NonNull String commitHash);

@Query(
"MATCH (p)-[:HAS_BRANCH]->(b) WHERE ID(p) = {0} "
+ "AND b.name = {1} WITH b LIMIT 1 "
+ "MATCH (b)-[:POINTS_TO]->(c) RETURN c LIMIT 1")
CommitEntity getBranchCommit(long projectId, String branchName);

@Query("MATCH (p)-[:HAS_BRANCH]->(b) WHERE ID(p) = {0} AND b.name = {1} RETURN b LIMIT 1")
BranchEntity findBranchInProjectByName(long projectId, String name);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.reflectoring.coderadar.rest.branch;

import io.reflectoring.coderadar.projectadministration.domain.Branch;
import io.reflectoring.coderadar.projectadministration.port.driver.branch.get.ListBranchesUseCase;
import io.reflectoring.coderadar.projectadministration.port.driver.branch.list.ListBranchesUseCase;
import io.reflectoring.coderadar.rest.domain.GetBranchResponse;
import java.util.ArrayList;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package io.reflectoring.coderadar.rest.branches;

import io.reflectoring.coderadar.graph.analyzer.repository.CommitRepository;
import io.reflectoring.coderadar.graph.analyzer.repository.FileRepository;
import io.reflectoring.coderadar.projectadministration.domain.Branch;
import io.reflectoring.coderadar.projectadministration.port.driven.branch.DeleteBranchPort;
import io.reflectoring.coderadar.projectadministration.port.driven.branch.ListBranchesPort;
import io.reflectoring.coderadar.projectadministration.port.driver.project.create.CreateProjectCommand;
import io.reflectoring.coderadar.projectadministration.service.project.CreateProjectService;
import io.reflectoring.coderadar.rest.ControllerTestTemplate;
import java.net.URL;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

public class DeleteBranchTest extends ControllerTestTemplate {

@Autowired private CreateProjectService createProjectService;

@Autowired private FileRepository fileRepository;
@Autowired private CommitRepository commitRepository;
@Autowired private ListBranchesPort listBranchesPort;
@Autowired private DeleteBranchPort deleteBranchPort;

private Long projectId;
private final Branch master = new Branch("master", "e9f7ff6fdd8c0863fdb5b24c9ed35a3651e20382");
private final Branch testBranch1 =
new Branch("testBranch1", "d3272b3793bc4b2bc36a1a3a7c8293fcf8fe27df");
private final Branch testBranch2 =
new Branch("testBranch2", "fcd9a0e7c34086fdb0aedc82497f8ddfa142e961");

@BeforeEach
void setUp() {
URL testRepoURL = this.getClass().getClassLoader().getResource("test-repository");
projectId =
createProjectService.createProject(
new CreateProjectCommand(
"testProject", null, null, testRepoURL.toString(), false, null, null));
}

@Test
void testDeleteBranch() {
deleteBranchPort.delete(projectId, testBranch2);

Assertions.assertThat(listBranchesPort.listBranchesInProject(projectId))
.containsExactlyInAnyOrder(testBranch1, master);

Assertions.assertThat(commitRepository.findByProjectId(projectId)).hasSize(14);
Assertions.assertThat(fileRepository.findAllinProject(projectId)).hasSize(8);
}

@Test
void testDeleteBranchThatHasChildren() {
deleteBranchPort.delete(projectId, testBranch1);

Assertions.assertThat(listBranchesPort.listBranchesInProject(projectId))
.containsExactlyInAnyOrder(testBranch2, master);

Assertions.assertThat(commitRepository.findByProjectId(projectId)).hasSize(15);
Assertions.assertThat(fileRepository.findAllinProject(projectId)).hasSize(9);
}

@Test
void testDeleteBranchWithFileOnlyModified() {
deleteBranchPort.delete(projectId, master);

Assertions.assertThat(listBranchesPort.listBranchesInProject(projectId))
.containsExactlyInAnyOrder(testBranch2, testBranch1);

Assertions.assertThat(commitRepository.findByProjectId(projectId)).hasSize(14);
Assertions.assertThat(fileRepository.findAllinProject(projectId)).hasSize(9);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

public class ListBranchesControllerTest extends ControllerTestTemplate {

@Autowired CreateProjectService createProjectService;
@Autowired private CreateProjectService createProjectService;

private Long projectId;

Expand Down
1 change: 1 addition & 0 deletions coderadar-ui/src/app/view/file-view/file-view.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export class FileViewComponent implements OnInit, AfterViewChecked {
for (const finding of value.findings) {
if (finding.lineStart === +lineStart) {
found = true;
break;
}
}
if (found) {
Expand Down

0 comments on commit 19435bf

Please sign in to comment.