use of com.google.gerrit.extensions.restapi.UnprocessableEntityException in project gerrit by GerritCodeReview.
the class ChangeInserter method updateChange.
@Override
public boolean updateChange(ChangeContext ctx) throws RestApiException, IOException, PermissionBackendException, ConfigInvalidException {
// Use defensive copy created by ChangeControl.
change = ctx.getChange();
patchSetInfo = patchSetInfoFactory.get(ctx.getRevWalk(), ctx.getRevWalk().parseCommit(commitId), psId);
ctx.getChange().setCurrentPatchSet(patchSetInfo);
ChangeUpdate update = ctx.getUpdate(psId);
update.setChangeId(change.getKey().get());
update.setSubjectForCommit("Create change");
update.setBranch(change.getDest().branch());
try {
update.setTopic(change.getTopic());
} catch (ValidationException ex) {
throw new BadRequestException(ex.getMessage());
}
update.setPsDescription(patchSetDescription);
update.setPrivate(isPrivate);
update.setWorkInProgress(workInProgress);
if (revertOf != null) {
update.setRevertOf(revertOf.get());
}
if (cherryPickOf != null) {
update.setCherryPickOf(cherryPickOf.getCommaSeparatedChangeAndPatchSetId());
}
List<String> newGroups = groups;
if (newGroups.isEmpty()) {
newGroups = GroupCollector.getDefaultGroups(commitId);
}
patchSet = psUtil.insert(ctx.getRevWalk(), update, psId, commitId, newGroups, pushCert, patchSetDescription);
/* TODO: fixStatusToMerged is used here because the tests
* (byStatusClosed() in AbstractQueryChangesTest)
* insert changes that are already merged,
* and setStatus may not be used to set the Status to merged
*
* is it possible to make the tests use the merge code path,
* instead of setting the status directly?
*/
if (change.getStatus() == Change.Status.MERGED) {
update.fixStatusToMerged(new SubmissionId(change));
} else {
update.setStatus(change.getStatus());
}
reviewerAdditions = reviewerModifier.prepare(ctx.getNotes(), ctx.getUser(), getReviewerInputs(), true);
Optional<ReviewerModification> reviewerError = reviewerAdditions.getFailures().stream().findFirst();
if (reviewerError.isPresent()) {
throw new UnprocessableEntityException(reviewerError.get().result.error);
}
reviewerAdditions.updateChange(ctx, patchSet);
LabelTypes labelTypes = projectState.getLabelTypes();
approvalsUtil.addApprovalsForNewPatchSet(update, labelTypes, patchSet, ctx.getUser(), approvals);
// TODO(dborowitz): Still necessary?
if (!approvals.isEmpty()) {
update.putReviewer(ctx.getAccountId(), REVIEWER);
}
if (message != null) {
changeMessage = cmUtil.setChangeMessage(update, message, ChangeMessagesUtil.uploadedPatchSetTag(workInProgress));
}
return true;
}
use of com.google.gerrit.extensions.restapi.UnprocessableEntityException in project gerrit by GerritCodeReview.
the class ProjectsConsistencyChecker method checkForAutoCloseableChanges.
private AutoCloseableChangesCheckResult checkForAutoCloseableChanges(Project.NameKey projectName, AutoCloseableChangesCheckInput input) throws IOException, RestApiException {
AutoCloseableChangesCheckResult r = new AutoCloseableChangesCheckResult();
if (Strings.isNullOrEmpty(input.branch)) {
throw new BadRequestException("branch is required");
}
boolean fix = input.fix != null ? input.fix : false;
if (input.maxCommits != null && input.maxCommits > AUTO_CLOSE_MAX_COMMITS_LIMIT) {
throw new BadRequestException("max commits can at most be set to " + AUTO_CLOSE_MAX_COMMITS_LIMIT);
}
int maxCommits = input.maxCommits != null ? input.maxCommits : AUTO_CLOSE_MAX_COMMITS_LIMIT;
// Result that we want to return to the client.
List<ChangeInfo> autoCloseableChanges = new ArrayList<>();
// Remember the change IDs of all changes that we already included into the result, so that we
// can avoid including the same change twice.
Set<Change.Id> seenChanges = new HashSet<>();
try (Repository repo = repoManager.openRepository(projectName);
RevWalk rw = new RevWalk(repo)) {
String branch = RefNames.fullName(input.branch);
Ref ref = repo.exactRef(branch);
if (ref == null) {
throw new UnprocessableEntityException(String.format("branch '%s' not found", input.branch));
}
rw.reset();
rw.markStart(rw.parseCommit(ref.getObjectId()));
rw.sort(RevSort.TOPO);
rw.sort(RevSort.REVERSE);
// Cache the SHA1's of all merged commits. We need this for knowing which commit merged the
// change when auto-closing changes by commit.
List<ObjectId> mergedSha1s = new ArrayList<>();
// Cache the Change-Id to commit SHA1 mapping for all Change-Id's that we find in merged
// commits. We need this for knowing which commit merged the change when auto-closing
// changes by Change-Id.
Map<Change.Key, ObjectId> changeIdToMergedSha1 = new HashMap<>();
// Base predicate which is fixed for every change query.
Predicate<ChangeData> basePredicate = and(ChangePredicates.project(projectName), ChangePredicates.ref(branch), open());
int maxLeafPredicates = indexConfig.maxTerms() - basePredicate.getLeafCount();
// List of predicates by which we want to find open changes for the branch. These predicates
// will be combined with the 'or' operator.
List<Predicate<ChangeData>> predicates = new ArrayList<>(maxLeafPredicates);
RevCommit commit;
int skippedCommits = 0;
int walkedCommits = 0;
while ((commit = rw.next()) != null) {
if (input.skipCommits != null && skippedCommits < input.skipCommits) {
skippedCommits++;
continue;
}
if (walkedCommits >= maxCommits) {
break;
}
walkedCommits++;
ObjectId commitId = commit.copy();
mergedSha1s.add(commitId);
// Consider all Change-Id lines since this is what ReceiveCommits#autoCloseChanges does.
List<String> changeIds = ChangeUtil.getChangeIdsFromFooter(commit, urlFormatter.get());
// Number of predicates that we need to add for this commit, 1 per Change-Id plus one for
// the commit.
int newPredicatesCount = changeIds.size() + 1;
// the query and start a new one.
if (predicates.size() + newPredicatesCount > maxLeafPredicates) {
autoCloseableChanges.addAll(executeQueryAndAutoCloseChanges(basePredicate, seenChanges, predicates, fix, changeIdToMergedSha1, mergedSha1s));
mergedSha1s.clear();
changeIdToMergedSha1.clear();
predicates.clear();
if (newPredicatesCount > maxLeafPredicates) {
// Whee, a single commit generates more than maxLeafPredicates predicates. Give up.
throw new ResourceConflictException(String.format("commit %s contains more Change-Ids than we can handle", commit.name()));
}
}
changeIds.forEach(changeId -> {
// It can happen that there are multiple merged commits with the same Change-Id
// footer (e.g. if a change was cherry-picked to a stable branch stable branch which
// then got merged back into master, or just by directly pushing several commits
// with the same Change-Id). In this case it is hard to say which of the commits
// should be used to auto-close an open change with the same Change-Id (and branch).
// Possible approaches are:
// 1. use the oldest commit with that Change-Id to auto-close the change
// 2. use the newest commit with that Change-Id to auto-close the change
// Possibility 1. has the disadvantage that the commit may have been merged before
// the change was created in which case it is strange how it could auto-close the
// change. Also this strategy would require to walk all commits since otherwise we
// cannot be sure that we have seen the oldest commit with that Change-Id.
// Possibility 2 has the disadvantage that it doesn't produce the same result as if
// auto-closing on push would have worked, since on direct push the first commit with
// a Change-Id of an open change would have closed that change. Also for this we
// would need to consider all commits that are skipped.
// Since both possibilities are not perfect and require extra effort we choose the
// easiest approach, which is use the newest commit with that Change-Id that we have
// seen (this means we ignore skipped commits). This should be okay since the
// important thing for callers is that auto-closable changes are closed. Which of the
// commits is used to auto-close a change if there are several candidates is of minor
// importance and hence can be non-deterministic.
Change.Key changeKey = Change.key(changeId);
if (!changeIdToMergedSha1.containsKey(changeKey)) {
changeIdToMergedSha1.put(changeKey, commitId);
}
// Find changes that have a matching Change-Id.
predicates.add(ChangePredicates.idPrefix(changeId));
});
// Find changes that have a matching commit.
predicates.add(ChangePredicates.commitPrefix(commit.name()));
}
if (!predicates.isEmpty()) {
// Execute the query with the remaining predicates that were collected.
autoCloseableChanges.addAll(executeQueryAndAutoCloseChanges(basePredicate, seenChanges, predicates, fix, changeIdToMergedSha1, mergedSha1s));
}
}
r.autoCloseableChanges = autoCloseableChanges;
return r;
}
use of com.google.gerrit.extensions.restapi.UnprocessableEntityException in project gerrit by GerritCodeReview.
the class AddMembers method apply.
@Override
public Response<List<AccountInfo>> apply(GroupResource resource, Input input) throws AuthException, NotInternalGroupException, UnprocessableEntityException, IOException, ConfigInvalidException, ResourceNotFoundException, PermissionBackendException {
GroupDescription.Internal internalGroup = resource.asInternalGroup().orElseThrow(NotInternalGroupException::new);
input = Input.init(input);
GroupControl control = resource.getControl();
if (!control.canAddMember()) {
throw new AuthException("Cannot add members to group " + internalGroup.getName());
}
Set<Account.Id> newMemberIds = new LinkedHashSet<>();
for (String nameOrEmailOrId : input.members) {
Account a = findAccount(nameOrEmailOrId);
if (!a.isActive()) {
throw new UnprocessableEntityException(String.format("Account Inactive: %s", nameOrEmailOrId));
}
newMemberIds.add(a.id());
}
AccountGroup.UUID groupUuid = internalGroup.getGroupUUID();
try {
addMembers(groupUuid, newMemberIds);
} catch (NoSuchGroupException e) {
throw new ResourceNotFoundException(String.format("Group %s not found", groupUuid), e);
}
return Response.ok(toAccountInfoList(newMemberIds));
}
use of com.google.gerrit.extensions.restapi.UnprocessableEntityException in project gerrit by GerritCodeReview.
the class ConfirmEmail method apply.
@Override
public Response<?> apply(ConfigResource rsrc, Input input) throws AuthException, UnprocessableEntityException, IOException, ConfigInvalidException {
CurrentUser user = self.get();
if (!user.isIdentifiedUser()) {
throw new AuthException("Authentication required");
}
if (input == null) {
input = new Input();
}
if (input.token == null) {
throw new UnprocessableEntityException("missing token");
}
try {
EmailTokenVerifier.ParsedToken token = emailTokenVerifier.decode(input.token);
Account.Id accId = user.getAccountId();
if (accId.equals(token.getAccountId())) {
accountManager.link(accId, token.toAuthRequest());
return Response.none();
}
throw new UnprocessableEntityException("invalid token");
} catch (EmailTokenVerifier.InvalidTokenException e) {
throw new UnprocessableEntityException("invalid token", e);
} catch (AccountException e) {
throw new UnprocessableEntityException(e.getMessage());
}
}
use of com.google.gerrit.extensions.restapi.UnprocessableEntityException in project gerrit by GerritCodeReview.
the class SetAccessUtil method getAccessSections.
ImmutableList<AccessSection> getAccessSections(Map<String, AccessSectionInfo> sectionInfos) throws UnprocessableEntityException {
if (sectionInfos == null) {
return ImmutableList.of();
}
ImmutableList.Builder<AccessSection> sections = ImmutableList.builderWithExpectedSize(sectionInfos.size());
for (Map.Entry<String, AccessSectionInfo> entry : sectionInfos.entrySet()) {
if (entry.getValue().permissions == null) {
continue;
}
AccessSection.Builder accessSection = AccessSection.builder(entry.getKey());
for (Map.Entry<String, PermissionInfo> permissionEntry : entry.getValue().permissions.entrySet()) {
if (permissionEntry.getValue().rules == null) {
continue;
}
Permission.Builder p = Permission.builder(permissionEntry.getKey());
if (permissionEntry.getValue().exclusive != null) {
p.setExclusiveGroup(permissionEntry.getValue().exclusive);
}
for (Map.Entry<String, PermissionRuleInfo> permissionRuleInfoEntry : permissionEntry.getValue().rules.entrySet()) {
GroupDescription.Basic group = groupResolver.parseId(permissionRuleInfoEntry.getKey());
if (group == null) {
throw new UnprocessableEntityException(permissionRuleInfoEntry.getKey() + " is not a valid group ID");
}
PermissionRuleInfo pri = permissionRuleInfoEntry.getValue();
PermissionRule.Builder r = PermissionRule.builder(GroupReference.forGroup(group));
if (pri != null) {
if (pri.max != null) {
r.setMax(pri.max);
}
if (pri.min != null) {
r.setMin(pri.min);
}
if (pri.action != null) {
r.setAction(GetAccess.ACTION_TYPE.inverse().get(pri.action));
}
if (pri.force != null) {
r.setForce(pri.force);
}
}
p.add(r);
}
accessSection.addPermission(p);
}
sections.add(accessSection.build());
}
return sections.build();
}
Aggregations