private void integrateIntoHistory(ChangeSet cs, IdentifiedUser caller) throws IntegrationException, NoSuchChangeException, ResourceConflictException { logDebug("Beginning merge attempt on {}", cs); Map<Branch.NameKey, BranchBatch> toSubmit = new HashMap<>(); logDebug("Perform the merges"); try { Multimap<Project.NameKey, Branch.NameKey> br = cs.branchesByProject(); Multimap<Branch.NameKey, ChangeData> cbb = cs.changesByBranch(); for (Branch.NameKey branch : cbb.keySet()) { OpenRepo or = openRepo(branch.getParentKey()); toSubmit.put(branch, validateChangeList(or, cbb.get(branch))); } failFast(cs); // Done checks that don't involve running submit strategies. for (Branch.NameKey branch : cbb.keySet()) { OpenRepo or = openRepo(branch.getParentKey()); OpenBranch ob = or.getBranch(branch); BranchBatch submitting = toSubmit.get(branch); SubmitStrategy strategy = createStrategy(or, branch, submitting.submitType(), ob.oldTip, caller); ob.mergeTip = preMerge(strategy, submitting.changes(), ob.oldTip); } checkMergeStrategyResults(cs, toSubmit.values()); for (Project.NameKey project : br.keySet()) { openRepo(project).ins.flush(); } Set<Branch.NameKey> done = Sets.newHashSetWithExpectedSize(cbb.keySet().size()); logDebug("Write out the new branch tips"); SubmoduleOp subOp = subOpProvider.get(); for (Project.NameKey project : br.keySet()) { OpenRepo or = openRepo(project); for (Branch.NameKey branch : br.get(project)) { OpenBranch ob = or.getBranch(branch); boolean updated = updateBranch(or, branch, caller); BranchBatch submitting = toSubmit.get(branch); updateChangeStatus(ob, submitting.changes(), caller); updateSubmoduleSubscriptions(ob, subOp); if (updated) { fireRefUpdated(ob); } done.add(branch); } } updateSuperProjects(subOp, br.values()); checkState( done.equals(cbb.keySet()), "programmer error: did not process" + " all branches in input set.\nExpected: %s\nActual: %s", done, cbb.keySet()); } catch (NoSuchProjectException noProject) { logWarn("Project " + noProject.project() + " no longer exists, " + "abandoning open changes"); abandonAllOpenChanges(noProject.project()); } catch (OrmException e) { throw new IntegrationException("Cannot query the database", e); } catch (IOException e) { throw new IntegrationException("Cannot query the database", e); } }
private boolean updateBranch(OpenRepo or, Branch.NameKey destBranch, IdentifiedUser caller) throws IntegrationException { OpenBranch ob = or.getBranch(destBranch); CodeReviewCommit currentTip = ob.getCurrentTip(); if (Objects.equals(ob.oldTip, currentTip)) { if (currentTip != null) { logDebug("Branch already at merge tip {}, no update to perform", currentTip.name()); } else { logDebug("Both branch and merge tip are nonexistent, no update"); } return false; } else if (currentTip == null) { logDebug("No merge tip, no update to perform"); return false; } if (RefNames.REFS_CONFIG.equals(ob.update.getName())) { logDebug("Loading new configuration from {}", RefNames.REFS_CONFIG); try { ProjectConfig cfg = new ProjectConfig(or.getProjectName()); cfg.load(or.repo, currentTip); } catch (Exception e) { throw new IntegrationException( "Submit would store invalid" + " project configuration " + currentTip.name() + " for " + or.getProjectName(), e); } } ob.update.setRefLogIdent(identifiedUserFactory.create(caller.getAccountId()).newRefLogIdent()); ob.update.setForceUpdate(false); ob.update.setNewObjectId(currentTip); ob.update.setRefLogMessage("merged", true); try { RefUpdate.Result result = ob.update.update(or.rw); logDebug( "Update of {}: {}..{} returned status {}", ob.update.getName(), ob.update.getOldObjectId(), ob.update.getNewObjectId(), result); switch (result) { case NEW: case FAST_FORWARD: if (ob.update.getResult() == RefUpdate.Result.FAST_FORWARD) { tagCache.updateFastForward( destBranch.getParentKey(), ob.update.getName(), ob.update.getOldObjectId(), currentTip); } if (RefNames.REFS_CONFIG.equals(ob.update.getName())) { Project p = or.project.getProject(); projectCache.evict(p); or.project = projectCache.get(p.getNameKey()); repoManager.setProjectDescription(p.getNameKey(), p.getDescription()); } return true; case LOCK_FAILURE: throw new IntegrationException("Failed to lock " + ob.update.getName()); default: throw new IOException(ob.update.getResult().name() + '\n' + ob.update); } } catch (IOException e) { throw new IntegrationException("Cannot update " + ob.update.getName(), e); } }
@Override public void close() { for (OpenRepo repo : openRepos.values()) { repo.close(); } }