use of com.google.gerrit.entities.PatchSet in project gerrit by GerritCodeReview.
the class CatServlet method doGet.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
String keyStr = req.getPathInfo();
// We shouldn't have to do this extra decode pass, but somehow we
// are now receiving our "^1" suffix as "%5E1", which confuses us
// downstream. Other times we get our embedded "," as "%2C", which
// is equally bad. And yet when these happen a "%2F" is left as-is,
// rather than escaped as "%252F", which makes me feel really really
// uncomfortable with a blind decode right here.
//
keyStr = Url.decode(keyStr);
if (!keyStr.startsWith("/")) {
rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
keyStr = keyStr.substring(1);
final Patch.Key patchKey;
final int side;
{
final int c = keyStr.lastIndexOf('^');
if (c == 0) {
rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (c < 0) {
side = 0;
} else {
try {
side = Integer.parseInt(keyStr.substring(c + 1));
keyStr = keyStr.substring(0, c);
} catch (NumberFormatException e) {
rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
}
try {
patchKey = Patch.Key.parse(keyStr);
} catch (NumberFormatException e) {
rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
}
final Change.Id changeId = patchKey.patchSetId().changeId();
String revision;
try {
ChangeNotes notes = changeNotesFactory.createCheckedUsingIndexLookup(changeId);
permissionBackend.currentUser().change(notes).check(ChangePermission.READ);
projectCache.get(notes.getProjectName()).orElseThrow(illegalState(notes.getProjectName())).checkStatePermitsRead();
if (patchKey.patchSetId().get() == 0) {
// change edit
Optional<ChangeEdit> edit = changeEditUtil.byChange(notes);
if (edit.isPresent()) {
revision = ObjectId.toString(edit.get().getEditCommit());
} else {
rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
} else {
PatchSet patchSet = psUtil.get(notes, patchKey.patchSetId());
if (patchSet == null) {
rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
revision = patchSet.commitId().name();
}
} catch (ResourceConflictException | NoSuchChangeException | AuthException e) {
rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
} catch (PermissionBackendException | IOException e) {
getServletContext().log("Cannot query database", e);
rsp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
String path = patchKey.fileName();
String restUrl = String.format("%s/changes/%d/revisions/%s/files/%s/download?parent=%d", req.getContextPath(), changeId.get(), revision, Url.encode(path), side);
rsp.sendRedirect(restUrl);
}
use of com.google.gerrit.entities.PatchSet in project gerrit by GerritCodeReview.
the class PublishCommentsOp method postUpdate.
@Override
public void postUpdate(PostUpdateContext ctx) {
if (Strings.isNullOrEmpty(mailMessage) || comments.isEmpty()) {
return;
}
ChangeNotes changeNotes = changeNotesFactory.createChecked(projectNameKey, psId.changeId());
PatchSet ps = psUtil.get(changeNotes, psId);
NotifyResolver.Result notify = ctx.getNotify(changeNotes.getChangeId());
if (notify.shouldNotify()) {
RepoView repoView;
try {
repoView = ctx.getRepoView();
} catch (IOException ex) {
throw new StorageException(String.format("Repository %s not found", ctx.getProject().get()), ex);
}
email.create(notify, changeNotes, ps, user, mailMessage, ctx.getWhen(), comments, null, labelDelta, repoView).sendAsync();
}
commentAdded.fire(ctx.getChangeData(changeNotes), ps, ctx.getAccount(), mailMessage, ImmutableMap.of(), ImmutableMap.of(), ctx.getWhen());
}
use of com.google.gerrit.entities.PatchSet in project gerrit by GerritCodeReview.
the class PublishCommentUtil method publish.
public void publish(ChangeContext ctx, ChangeUpdate changeUpdate, Collection<HumanComment> draftComments, @Nullable String tag) {
ChangeNotes notes = ctx.getNotes();
checkArgument(notes != null);
if (draftComments.isEmpty()) {
return;
}
Map<PatchSet.Id, PatchSet> patchSets = psUtil.getAsMap(notes, draftComments.stream().map(d -> psId(notes, d)).collect(toSet()));
Set<HumanComment> commentsToPublish = new HashSet<>();
for (HumanComment draftComment : draftComments) {
PatchSet.Id psIdOfDraftComment = psId(notes, draftComment);
PatchSet ps = patchSets.get(psIdOfDraftComment);
if (ps == null) {
// This can happen if changes with the same numeric ID exist:
// - change 12345 has 3 patch sets in repo X
// - another change 12345 has 7 patch sets in repo Y
// - the user saves a draft comment on patch set 6 of the change in repo Y
// - this draft comment gets stored in:
// AllUsers -> refs/draft-comments/45/12345/<account-id>
// - when posting a review with draft handling PUBLISH_ALL_REVISIONS on the change in
// repo X, the draft comments are loaded from
// AllUsers -> refs/draft-comments/45/12345/<account-id>, including the draft
// comment that was saved for patch set 6 of the change in repo Y
// - patch set 6 does not exist for the change in repo x, hence we get null for the patch
// set here
// Instead of failing hard (and returning an Internal Server Error) to the caller,
// just ignore that comment.
// Gerrit ensures that numeric change IDs are unique, but you can get duplicates if
// change refs of one repo are copied/pushed to another repo on the same host (this
// should never be done, but we know it happens).
logger.atWarning().log("Ignoring draft comment %s on non existing patch set %s (repo = %s)", draftComment, psIdOfDraftComment, notes.getProjectName());
continue;
}
draftComment.writtenOn = Timestamp.from(ctx.getWhen());
draftComment.tag = tag;
// Draft may have been created by a different real user; copy the current real user. (Only
// applies to X-Gerrit-RunAs, since modifying drafts via on_behalf_of is not allowed.)
ctx.getUser().updateRealAccountId(draftComment::setRealAuthor);
commentsUtil.setCommentCommitId(draftComment, notes.getChange(), ps);
commentsToPublish.add(draftComment);
}
commentsUtil.putHumanComments(changeUpdate, HumanComment.Status.PUBLISHED, commentsToPublish);
}
use of com.google.gerrit.entities.PatchSet in project gerrit by GerritCodeReview.
the class ChangeJson method loadPatchSets.
private Map<PatchSet.Id, PatchSet> loadPatchSets(ChangeData cd, Optional<PatchSet.Id> limitToPsId) {
Collection<PatchSet> src;
if (has(ALL_REVISIONS) || has(MESSAGES)) {
src = cd.patchSets();
} else {
PatchSet ps;
if (limitToPsId.isPresent()) {
ps = cd.patchSet(limitToPsId.get());
if (ps == null) {
throw new StorageException("missing patch set " + limitToPsId.get());
}
} else {
ps = cd.currentPatchSet();
if (ps == null) {
throw new StorageException("missing current patch set for change " + cd.getId());
}
}
src = Collections.singletonList(ps);
}
Map<PatchSet.Id, PatchSet> map = Maps.newHashMapWithExpectedSize(src.size());
for (PatchSet patchSet : src) {
map.put(patchSet.id(), patchSet);
}
return map;
}
use of com.google.gerrit.entities.PatchSet in project gerrit by GerritCodeReview.
the class GroupCollector method create.
/**
* Returns a new {@link GroupCollector} instance.
*
* @see GroupCollector for what this class does.
*/
public static GroupCollector create(ReceivePackRefCache receivePackRefCache, PatchSetUtil psUtil, ChangeNotes.Factory notesFactory, Project.NameKey project) {
return new GroupCollector(receivePackRefCache, psId -> {
// TODO(dborowitz): Reuse open repository from caller.
ChangeNotes notes = notesFactory.createChecked(project, psId.changeId());
PatchSet ps = psUtil.get(notes, psId);
return ps != null ? ps.groups() : null;
});
}
Aggregations