private PostResult putGroup(ChangeResource rsrc, Input input) throws BadRequestException, UnprocessableEntityException, OrmException, EmailException, IOException { GroupDescription.Basic group = groupsCollection.get().parseInternal(input.reviewer); PostResult result = new PostResult(); if (!isLegalReviewerGroup(group.getGroupUUID())) { result.error = MessageFormat.format(ChangeMessages.get().groupIsNotAllowed, group.getName()); return result; } Set<IdentifiedUser> reviewers = Sets.newLinkedHashSet(); ChangeControl control = rsrc.getControl(); Set<Account> members; try { members = groupMembersFactory .create(control.getCurrentUser()) .listAccounts(group.getGroupUUID(), control.getProject().getNameKey()); } catch (NoSuchGroupException e) { throw new UnprocessableEntityException(e.getMessage()); } catch (NoSuchProjectException e) { throw new BadRequestException(e.getMessage()); } // if maxAllowed is set to 0, it is allowed to add any number of // reviewers int maxAllowed = cfg.getInt("addreviewer", "maxAllowed", DEFAULT_MAX_REVIEWERS); if (maxAllowed > 0 && members.size() > maxAllowed) { result.error = MessageFormat.format(ChangeMessages.get().groupHasTooManyMembers, group.getName()); return result; } // if maxWithoutCheck is set to 0, we never ask for confirmation int maxWithoutConfirmation = cfg.getInt("addreviewer", "maxWithoutConfirmation", DEFAULT_MAX_REVIEWERS_WITHOUT_CHECK); if (!input.confirmed() && maxWithoutConfirmation > 0 && members.size() > maxWithoutConfirmation) { result.confirm = true; result.error = MessageFormat.format( ChangeMessages.get().groupManyMembersConfirmation, group.getName(), members.size()); return result; } for (Account member : members) { if (member.isActive()) { IdentifiedUser user = identifiedUserFactory.create(member.getId()); // Does not account for draft status as a user might want to let a // reviewer see a draft. if (control.forUser(user).isRefVisible()) { reviewers.add(user); } } } addReviewers(rsrc, result, reviewers); return result; }
private BatchMetaDataUpdate saveToBatch( ChangeControl ctl, ChangeUpdate callerUpdate, LabelNormalizer.Result normalized, Timestamp timestamp) throws IOException { Table<Account.Id, String, Optional<Short>> byUser = HashBasedTable.create(); for (PatchSetApproval psa : normalized.updated()) { byUser.put(psa.getAccountId(), psa.getLabel(), Optional.of(psa.getValue())); } for (PatchSetApproval psa : normalized.deleted()) { byUser.put(psa.getAccountId(), psa.getLabel(), Optional.<Short>absent()); } BatchMetaDataUpdate batch = callerUpdate.openUpdate(); for (Account.Id accountId : byUser.rowKeySet()) { if (!accountId.equals(callerUpdate.getUser().getAccountId())) { ChangeUpdate update = updateFactory.create(ctl.forUser(identifiedUserFactory.create(accountId)), timestamp); update.setSubject("Finalize approvals at submit"); putApprovals(update, byUser.row(accountId)); CommitBuilder commit = new CommitBuilder(); commit.setCommitter(new PersonIdent(serverIdent, timestamp)); batch.write(update, commit); } } putApprovals(callerUpdate, byUser.row(callerUpdate.getUser().getAccountId())); return batch; }
protected RequestContext newRequestContext(Account.Id requestUserId) { final CurrentUser requestUser = userFactory.create(Providers.of(db), requestUserId); return new RequestContext() { @Override public CurrentUser getCurrentUser() { return requestUser; } @Override public Provider<ReviewDb> getReviewDbProvider() { return Providers.of(db); } }; }
@Before public void setUpInjector() throws Exception { lifecycle = new LifecycleManager(); Injector injector = createInjector(); lifecycle.add(injector); injector.injectMembers(this); lifecycle.start(); db = schemaFactory.open(); schemaCreator.create(db); userId = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId(); Account userAccount = db.accounts().get(userId); userAccount.setPreferredEmail("*****@*****.**"); db.accounts().update(ImmutableList.of(userAccount)); user = userFactory.create(Providers.of(db), userId); requestContext.setContext(newRequestContext(userAccount.getId())); }
@Before public void setUp() throws Exception { mergeResults = Maps.newHashMap(); CurrentUser listenerUser = factory.create(user.id); source.addEventListener( new EventListener() { @Override public void onEvent(Event event) { if (event instanceof ChangeMergedEvent) { ChangeMergedEvent changeMergedEvent = (ChangeMergedEvent) event; mergeResults.put(changeMergedEvent.change.number, changeMergedEvent.newRev); } } }, listenerUser); }
private void abandonOneChange(Change change) throws OrmException, NoSuchChangeException, IOException { db.changes().beginTransaction(change.getId()); // TODO(dborowitz): support InternalUser in ChangeUpdate ChangeControl control = changeControlFactory.controlFor(change, identifiedUserFactory.create(change.getOwner())); ChangeUpdate update = updateFactory.create(control); try { change = db.changes() .atomicUpdate( change.getId(), new AtomicUpdate<Change>() { @Override public Change update(Change change) { if (change.getStatus().isOpen()) { change.setStatus(Change.Status.ABANDONED); return change; } return null; } }); if (change != null) { ChangeMessage msg = new ChangeMessage( new ChangeMessage.Key(change.getId(), ChangeUtil.messageUUID(db)), null, change.getLastUpdatedOn(), change.currentPatchSetId()); msg.setMessage("Project was deleted."); // TODO(yyonas): atomic change is not propagated. cmUtil.addChangeMessage(db, update, msg); db.commit(); indexer.index(db, change); } } finally { db.rollback(); } update.commit(); }
protected ChangeInserter newChange( TestRepository<Repo> repo, @Nullable RevCommit commit, @Nullable String key, @Nullable Integer owner, @Nullable String branch) throws Exception { if (commit == null) { commit = repo.parseBody(repo.commit().message("message").create()); } Account.Id ownerId = owner != null ? new Account.Id(owner) : userId; branch = MoreObjects.firstNonNull(branch, "refs/heads/master"); if (!branch.startsWith("refs/heads/")) { branch = "refs/heads/" + branch; } Project.NameKey project = new Project.NameKey(repo.getRepository().getDescription().getRepositoryName()); Change.Id id = new Change.Id(db.nextChangeId()); if (key == null) { key = "I" + Hashing.sha1() .newHasher() .putInt(id.get()) .putString(project.get(), UTF_8) .putString(commit.name(), UTF_8) .putInt(ownerId.get()) .putString(branch, UTF_8) .hash() .toString(); } Change change = new Change( new Change.Key(key), id, ownerId, new Branch.NameKey(project, branch), TimeUtil.nowTs()); IdentifiedUser user = userFactory.create(Providers.of(db), ownerId); return changeFactory.create(projectControlFactory.controlFor(project, user), change, commit); }
private RefUpdate updateBranch(Branch.NameKey destBranch, IdentifiedUser caller) throws IntegrationException { RefUpdate branchUpdate = getPendingRefUpdate(destBranch); CodeReviewCommit branchTip = getBranchTip(destBranch); MergeTip mergeTip = mergeTips.get(destBranch); CodeReviewCommit currentTip = mergeTip != null ? mergeTip.getCurrentTip() : null; if (Objects.equals(branchTip, 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 null; } else if (currentTip == null) { logDebug("No merge tip, no update to perform"); return null; } if (RefNames.REFS_CONFIG.equals(branchUpdate.getName())) { logDebug("Loading new configuration from {}", RefNames.REFS_CONFIG); try { ProjectConfig cfg = new ProjectConfig(destProject.getProject().getNameKey()); cfg.load(repo, currentTip); } catch (Exception e) { throw new IntegrationException( "Submit would store invalid" + " project configuration " + currentTip.name() + " for " + destProject.getProject().getName(), e); } } branchUpdate.setRefLogIdent( identifiedUserFactory.create(caller.getAccountId()).newRefLogIdent()); branchUpdate.setForceUpdate(false); branchUpdate.setNewObjectId(currentTip); branchUpdate.setRefLogMessage("merged", true); try { RefUpdate.Result result = branchUpdate.update(rw); logDebug( "Update of {}: {}..{} returned status {}", branchUpdate.getName(), branchUpdate.getOldObjectId(), branchUpdate.getNewObjectId(), result); switch (result) { case NEW: case FAST_FORWARD: if (branchUpdate.getResult() == RefUpdate.Result.FAST_FORWARD) { tagCache.updateFastForward( destBranch.getParentKey(), branchUpdate.getName(), branchUpdate.getOldObjectId(), currentTip); } if (RefNames.REFS_CONFIG.equals(branchUpdate.getName())) { Project p = destProject.getProject(); projectCache.evict(p); destProject = projectCache.get(p.getNameKey()); repoManager.setProjectDescription(p.getNameKey(), p.getDescription()); } return branchUpdate; case LOCK_FAILURE: throw new IntegrationException("Failed to lock " + branchUpdate.getName()); default: throw new IOException(branchUpdate.getResult().name() + '\n' + branchUpdate); } } catch (IOException e) { throw new IntegrationException("Cannot update " + branchUpdate.getName(), e); } }
private ChangeControl changeControl(Change c) throws NoSuchChangeException { return changeControlFactory.controlFor(c, identifiedUserFactory.create(c.getOwner())); }
@Override public void onPreMerge( final Repository repo, final CodeReviewCommit commit, final ProjectState destProject, final Branch.NameKey destBranch, final PatchSet.Id patchSetId) throws MergeValidationException { if (RefNames.REFS_CONFIG.equals(destBranch.get())) { final Project.NameKey newParent; try { ProjectConfig cfg = new ProjectConfig(destProject.getProject().getNameKey()); cfg.load(repo, commit); newParent = cfg.getProject().getParent(allProjectsName); final Project.NameKey oldParent = destProject.getProject().getParent(allProjectsName); if (oldParent == null) { // update of the 'All-Projects' project if (newParent != null) { throw new MergeValidationException(ROOT_NO_PARENT); } } else { if (!oldParent.equals(newParent)) { PatchSetApproval psa = approvalsUtil.getSubmitter(db, commit.notes(), patchSetId); if (psa == null) { throw new MergeValidationException(SET_BY_ADMIN); } final IdentifiedUser submitter = identifiedUserFactory.create(psa.getAccountId()); if (!submitter.getCapabilities().canAdministrateServer()) { throw new MergeValidationException(SET_BY_ADMIN); } if (projectCache.get(newParent) == null) { throw new MergeValidationException(PARENT_NOT_FOUND); } } } for (Entry<ProjectConfigEntry> e : pluginConfigEntries) { PluginConfig pluginCfg = cfg.getPluginConfig(e.getPluginName()); ProjectConfigEntry configEntry = e.getProvider().get(); String value = pluginCfg.getString(e.getExportName()); String oldValue = destProject .getConfig() .getPluginConfig(e.getPluginName()) .getString(e.getExportName()); if ((value == null ? oldValue != null : !value.equals(oldValue)) && !configEntry.isEditable(destProject)) { throw new MergeValidationException(PLUGIN_VALUE_NOT_EDITABLE); } if (ProjectConfigEntry.Type.LIST.equals(configEntry.getType()) && value != null && !configEntry.getPermittedValues().contains(value)) { throw new MergeValidationException(PLUGIN_VALUE_NOT_PERMITTED); } } } catch (ConfigInvalidException | IOException e) { throw new MergeValidationException(INVALID_CONFIG); } } }
private Context newRequestContext(TestAccount account) { return atrScope.newContext( reviewDbProvider, new SshSession(server, admin), identifiedUserFactory.create(Providers.of(db), account.getId())); }
public String createCherryPickCommitMessage(RevCommit n, ChangeControl ctl, PatchSet.Id psId) { Change c = ctl.getChange(); final List<FooterLine> footers = n.getFooterLines(); final StringBuilder msgbuf = new StringBuilder(); msgbuf.append(n.getFullMessage()); if (msgbuf.length() == 0) { // WTF, an empty commit message? msgbuf.append("<no commit message provided>"); } if (msgbuf.charAt(msgbuf.length() - 1) != '\n') { // Missing a trailing LF? Correct it (perhaps the editor was broken). msgbuf.append('\n'); } if (footers.isEmpty()) { // Doesn't end in a "Signed-off-by: ..." style line? Add another line // break to start a new paragraph for the reviewed-by tag lines. // msgbuf.append('\n'); } if (!contains(footers, FooterConstants.CHANGE_ID, c.getKey().get())) { msgbuf.append(FooterConstants.CHANGE_ID.getName()); msgbuf.append(": "); msgbuf.append(c.getKey().get()); msgbuf.append('\n'); } final String siteUrl = urlProvider.get(); if (siteUrl != null) { final String url = siteUrl + c.getId().get(); if (!contains(footers, FooterConstants.REVIEWED_ON, url)) { msgbuf.append(FooterConstants.REVIEWED_ON.getName()); msgbuf.append(": "); msgbuf.append(url); msgbuf.append('\n'); } } PatchSetApproval submitAudit = null; for (final PatchSetApproval a : safeGetApprovals(ctl, psId)) { if (a.getValue() <= 0) { // Negative votes aren't counted. continue; } if (a.isSubmit()) { // Submit is treated specially, below (becomes committer) // if (submitAudit == null || a.getGranted().compareTo(submitAudit.getGranted()) > 0) { submitAudit = a; } continue; } final Account acc = identifiedUserFactory.create(a.getAccountId()).getAccount(); final StringBuilder identbuf = new StringBuilder(); if (acc.getFullName() != null && acc.getFullName().length() > 0) { if (identbuf.length() > 0) { identbuf.append(' '); } identbuf.append(acc.getFullName()); } if (acc.getPreferredEmail() != null && acc.getPreferredEmail().length() > 0) { if (isSignedOffBy(footers, acc.getPreferredEmail())) { continue; } if (identbuf.length() > 0) { identbuf.append(' '); } identbuf.append('<'); identbuf.append(acc.getPreferredEmail()); identbuf.append('>'); } if (identbuf.length() == 0) { // Nothing reasonable to describe them by? Ignore them. continue; } final String tag; if (isCodeReview(a.getLabelId())) { tag = "Reviewed-by"; } else if (isVerified(a.getLabelId())) { tag = "Tested-by"; } else { final LabelType lt = project.getLabelTypes().byLabel(a.getLabelId()); if (lt == null) { continue; } tag = lt.getName(); } if (!contains(footers, new FooterKey(tag), identbuf.toString())) { msgbuf.append(tag); msgbuf.append(": "); msgbuf.append(identbuf); msgbuf.append('\n'); } } return msgbuf.toString(); }