Merge changes from topic 'commit-footers'

* changes:
  ChangeJson: Add option to include review footers
  ChangeJson: Refactor revision codepath
This commit is contained in:
Dave Borowitz 2015-05-04 19:06:56 +00:00 committed by Gerrit Code Review
commit 829c429dd6
8 changed files with 206 additions and 80 deletions

View File

@ -310,6 +310,12 @@ default. Optional fields are:
* `CHECK`: include potential problems with the change. * `CHECK`: include potential problems with the change.
-- --
[[commit-footers]]
--
* `COMMIT_FOOTERS`: include the full commit message with
Gerrit-specific commit footers in the
link:#revision-info[RevisionInfo].
.Request .Request
---- ----
GET /changes/?q=97&o=CURRENT_REVISION&o=CURRENT_COMMIT&o=CURRENT_FILES&o=DOWNLOAD_COMMANDS HTTP/1.0 GET /changes/?q=97&o=CURRENT_REVISION&o=CURRENT_COMMIT&o=CURRENT_FILES&o=DOWNLOAD_COMMANDS HTTP/1.0
@ -4215,6 +4221,12 @@ entities.
|`reviewed` |optional| |`reviewed` |optional|
Indicates whether the caller is authenticated and has commented on the Indicates whether the caller is authenticated and has commented on the
current revision. Only set if link:#reviewed[REVIEWED] option is requested. current revision. Only set if link:#reviewed[REVIEWED] option is requested.
|`messageWithFooter` |optional|
If the link:#commit-footers[COMMIT_FOOTERS] option is requested and
this is the current patch set, contains the full commit message with
Gerrit-specific commit footers, as if this revision were submitted
using the link:project-configuration.html#cherry_pick[Cherry Pick]
submit type.
|=========================== |===========================
[[rule-input]] [[rule-input]]

View File

@ -42,6 +42,7 @@ import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.OutputFormat; import com.google.gerrit.server.OutputFormat;
import com.google.gerrit.server.account.GroupCache; import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.config.AllProjectsName; import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate; import com.google.gerrit.server.git.MetaDataUpdate;
@ -131,6 +132,10 @@ public abstract class AbstractDaemonTest {
@Inject @Inject
protected Provider<InternalChangeQuery> queryProvider; protected Provider<InternalChangeQuery> queryProvider;
@Inject
@CanonicalWebUrl
protected Provider<String> canonicalWebUrl;
@Inject @Inject
@GerritServerConfig @GerritServerConfig
protected Config cfg; protected Config cfg;

View File

@ -15,6 +15,11 @@
package com.google.gerrit.acceptance.api.change; package com.google.gerrit.acceptance.api.change;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.PushOneCommit.FILE_NAME;
import static com.google.gerrit.acceptance.PushOneCommit.SUBJECT;
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
import static com.google.gerrit.server.project.Util.category;
import static com.google.gerrit.server.project.Util.value;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -22,6 +27,8 @@ import com.google.common.collect.Sets;
import com.google.gerrit.acceptance.AbstractDaemonTest; import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd; import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit; import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.extensions.api.changes.AddReviewerInput; import com.google.gerrit.extensions.api.changes.AddReviewerInput;
import com.google.gerrit.extensions.api.changes.RebaseInput; import com.google.gerrit.extensions.api.changes.RebaseInput;
import com.google.gerrit.extensions.api.changes.ReviewInput; import com.google.gerrit.extensions.api.changes.ReviewInput;
@ -33,8 +40,12 @@ import com.google.gerrit.extensions.common.LabelInfo;
import com.google.gerrit.extensions.common.RevisionInfo; import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.project.Util;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.junit.Test; import org.junit.Test;
@ -376,4 +387,60 @@ public class ChangeIT extends AbstractDaemonTest {
.get(EnumSet.of(ListChangesOption.CHECK)) .get(EnumSet.of(ListChangesOption.CHECK))
.problems).isEmpty(); .problems).isEmpty();
} }
@Test
public void commitFooters() throws Exception {
LabelType verified = category("Verified",
value(1, "Failed"), value(0, "No score"), value(-1, "Passes"));
LabelType custom1 = category("Custom1",
value(1, "Positive"), value(0, "No score"), value(-1, "Negative"));
LabelType custom2 = category("Custom2",
value(1, "Positive"), value(0, "No score"), value(-1, "Negative"));
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
cfg.getLabelSections().put(verified.getName(), verified);
cfg.getLabelSections().put(custom1.getName(), verified);
cfg.getLabelSections().put(custom2.getName(), verified);
String heads = "refs/heads/*";
AccountGroup.UUID anon =
SystemGroupBackend.getGroup(ANONYMOUS_USERS).getUUID();
Util.allow(cfg, Permission.forLabel("Verified"), -1, 1, anon, heads);
Util.allow(cfg, Permission.forLabel("Custom1"), -1, 1, anon, heads);
Util.allow(cfg, Permission.forLabel("Custom2"), -1, 1, anon, heads);
saveProjectConfig(project, cfg);
PushOneCommit.Result r1 = createChange();
r1.assertOkStatus();
PushOneCommit.Result r2 = pushFactory.create(
db, admin.getIdent(), testRepo, SUBJECT, FILE_NAME, "new content",
r1.getChangeId())
.to("refs/for/master");
r2.assertOkStatus();
ReviewInput in = new ReviewInput();
in.label("Code-Review", 1);
in.label("Verified", 1);
in.label("Custom1", -1);
in.label("Custom2", 1);
gApi.changes().id(r2.getChangeId()).current().review(in);
EnumSet<ListChangesOption> options = EnumSet.of(
ListChangesOption.ALL_REVISIONS, ListChangesOption.COMMIT_FOOTERS);
ChangeInfo actual = gApi.changes().id(r2.getChangeId()).get(options);
assertThat(actual.revisions).hasSize(2);
// No footers except on latest patch set.
assertThat(actual.revisions.get(r1.getCommit().getName()).commitWithFooters)
.isNull();
String expected = SUBJECT + "\n"
+ "\n"
+ "Change-Id: " + r2.getChangeId() + "\n"
+ "Reviewed-on: "
+ canonicalWebUrl.get() + r2.getChange().getId() + "\n"
+ "Reviewed-by: Administrator <admin@example.com>\n"
+ "Custom2: Administrator <admin@example.com>\n"
+ "Tested-by: Administrator <admin@example.com>\n";
assertThat(actual.revisions.get(r2.getCommit().getName()).commitWithFooters)
.isEqualTo(expected);
}
} }

View File

@ -58,7 +58,10 @@ public enum ListChangesOption {
CHECK(15), CHECK(15),
/** Include allowed change actions client could perform. */ /** Include allowed change actions client could perform. */
CHANGE_ACTIONS(16); CHANGE_ACTIONS(16),
/** Include a copy of commit messages including review footers. */
COMMIT_FOOTERS(17);
private final int value; private final int value;

View File

@ -29,4 +29,5 @@ public class RevisionInfo {
public CommitInfo commit; public CommitInfo commit;
public Map<String, FileInfo> files; public Map<String, FileInfo> files;
public Map<String, ActionInfo> actions; public Map<String, ActionInfo> actions;
public String commitWithFooters;
} }

View File

@ -19,6 +19,7 @@ import static com.google.gerrit.extensions.client.ListChangesOption.ALL_FILES;
import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS; import static com.google.gerrit.extensions.client.ListChangesOption.ALL_REVISIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.CHANGE_ACTIONS; import static com.google.gerrit.extensions.client.ListChangesOption.CHANGE_ACTIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.CHECK; import static com.google.gerrit.extensions.client.ListChangesOption.CHECK;
import static com.google.gerrit.extensions.client.ListChangesOption.COMMIT_FOOTERS;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_ACTIONS; import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_ACTIONS;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_COMMIT; import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_COMMIT;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_FILES; import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_FILES;
@ -31,12 +32,14 @@ import static com.google.gerrit.extensions.client.ListChangesOption.LABELS;
import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES; import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES;
import static com.google.gerrit.extensions.client.ListChangesOption.REVIEWED; import static com.google.gerrit.extensions.client.ListChangesOption.REVIEWED;
import static com.google.gerrit.extensions.client.ListChangesOption.WEB_LINKS; import static com.google.gerrit.extensions.client.ListChangesOption.WEB_LINKS;
import static com.google.gerrit.server.CommonConverters.toGitPerson;
import com.google.auto.value.AutoValue; import com.google.auto.value.AutoValue;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.base.Throwables;
import com.google.common.collect.FluentIterable; import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashBasedTable; import com.google.common.collect.HashBasedTable;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
@ -65,7 +68,6 @@ import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeMessageInfo; import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.common.CommitInfo; import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.common.FetchInfo; import com.google.gerrit.extensions.common.FetchInfo;
import com.google.gerrit.extensions.common.GitPerson;
import com.google.gerrit.extensions.common.LabelInfo; import com.google.gerrit.extensions.common.LabelInfo;
import com.google.gerrit.extensions.common.ProblemInfo; import com.google.gerrit.extensions.common.ProblemInfo;
import com.google.gerrit.extensions.common.RevisionInfo; import com.google.gerrit.extensions.common.RevisionInfo;
@ -80,10 +82,7 @@ import com.google.gerrit.reviewdb.client.ChangeMessage;
import com.google.gerrit.reviewdb.client.Patch; import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval; import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.client.PatchSetInfo;
import com.google.gerrit.reviewdb.client.PatchSetInfo.ParentInfo;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.UserIdentity;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.AnonymousUser; import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.ChangeMessagesUtil; import com.google.gerrit.server.ChangeMessagesUtil;
@ -92,12 +91,13 @@ import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PatchLineCommentsUtil; import com.google.gerrit.server.PatchLineCommentsUtil;
import com.google.gerrit.server.WebLinks; import com.google.gerrit.server.WebLinks;
import com.google.gerrit.server.account.AccountLoader; import com.google.gerrit.server.account.AccountLoader;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LabelNormalizer; import com.google.gerrit.server.git.LabelNormalizer;
import com.google.gerrit.server.git.MergeUtil;
import com.google.gerrit.server.notedb.ChangeNotes; import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.PatchListNotAvailableException; import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.SubmitRuleEvaluator; import com.google.gerrit.server.project.SubmitRuleEvaluator;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeData.ChangedLines; import com.google.gerrit.server.query.change.ChangeData.ChangedLines;
@ -106,10 +106,16 @@ import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@ -129,9 +135,11 @@ public class ChangeJson {
private final LabelNormalizer labelNormalizer; private final LabelNormalizer labelNormalizer;
private final Provider<CurrentUser> userProvider; private final Provider<CurrentUser> userProvider;
private final AnonymousUser anonymous; private final AnonymousUser anonymous;
private final GitRepositoryManager repoManager;
private final ProjectCache projectCache;
private final MergeUtil.Factory mergeUtilFactory;
private final IdentifiedUser.GenericFactory userFactory; private final IdentifiedUser.GenericFactory userFactory;
private final ChangeData.Factory changeDataFactory; private final ChangeData.Factory changeDataFactory;
private final PatchSetInfoFactory patchSetInfoFactory;
private final FileInfoJson fileInfoJson; private final FileInfoJson fileInfoJson;
private final AccountLoader.Factory accountLoaderFactory; private final AccountLoader.Factory accountLoaderFactory;
private final DynamicMap<DownloadScheme> downloadSchemes; private final DynamicMap<DownloadScheme> downloadSchemes;
@ -153,9 +161,11 @@ public class ChangeJson {
LabelNormalizer ln, LabelNormalizer ln,
Provider<CurrentUser> user, Provider<CurrentUser> user,
AnonymousUser au, AnonymousUser au,
GitRepositoryManager repoManager,
ProjectCache projectCache,
MergeUtil.Factory mergeUtilFactory,
IdentifiedUser.GenericFactory uf, IdentifiedUser.GenericFactory uf,
ChangeData.Factory cdf, ChangeData.Factory cdf,
PatchSetInfoFactory psi,
FileInfoJson fileInfoJson, FileInfoJson fileInfoJson,
AccountLoader.Factory ailf, AccountLoader.Factory ailf,
DynamicMap<DownloadScheme> downloadSchemes, DynamicMap<DownloadScheme> downloadSchemes,
@ -170,9 +180,11 @@ public class ChangeJson {
this.labelNormalizer = ln; this.labelNormalizer = ln;
this.userProvider = user; this.userProvider = user;
this.anonymous = au; this.anonymous = au;
this.userFactory = uf;
this.changeDataFactory = cdf; this.changeDataFactory = cdf;
this.patchSetInfoFactory = psi; this.repoManager = repoManager;
this.userFactory = uf;
this.projectCache = projectCache;
this.mergeUtilFactory = mergeUtilFactory;
this.fileInfoJson = fileInfoJson; this.fileInfoJson = fileInfoJson;
this.accountLoaderFactory = ailf; this.accountLoaderFactory = ailf;
this.downloadSchemes = downloadSchemes; this.downloadSchemes = downloadSchemes;
@ -237,9 +249,11 @@ public class ChangeJson {
ChangeInfo res = toChangeInfo(cd, reviewed, limitToPsId); ChangeInfo res = toChangeInfo(cd, reviewed, limitToPsId);
accountLoader.fill(); accountLoader.fill();
return res; return res;
} catch (OrmException | RuntimeException e) { } catch (PatchListNotAvailableException | OrmException | IOException
| RuntimeException e) {
if (!has(CHECK)) { if (!has(CHECK)) {
throw e; Throwables.propagateIfPossible(e, OrmException.class);
throw new OrmException(e);
} }
return checkOnly(cd); return checkOnly(cd);
} }
@ -297,7 +311,8 @@ public class ChangeJson {
if (i == null) { if (i == null) {
try { try {
i = toChangeInfo(cd, reviewed, Optional.<PatchSet.Id> absent()); i = toChangeInfo(cd, reviewed, Optional.<PatchSet.Id> absent());
} catch (OrmException | RuntimeException e) { } catch (PatchListNotAvailableException | OrmException | IOException
| RuntimeException e) {
if (has(CHECK)) { if (has(CHECK)) {
i = checkOnly(cd); i = checkOnly(cd);
} else { } else {
@ -340,7 +355,8 @@ public class ChangeJson {
} }
private ChangeInfo toChangeInfo(ChangeData cd, Set<Change.Id> reviewed, private ChangeInfo toChangeInfo(ChangeData cd, Set<Change.Id> reviewed,
Optional<PatchSet.Id> limitToPsId) throws OrmException { Optional<PatchSet.Id> limitToPsId)
throws PatchListNotAvailableException, OrmException, IOException {
ChangeInfo out = new ChangeInfo(); ChangeInfo out = new ChangeInfo();
if (has(CHECK)) { if (has(CHECK)) {
@ -404,7 +420,7 @@ public class ChangeJson {
if (has(ALL_REVISIONS) if (has(ALL_REVISIONS)
|| has(CURRENT_REVISION) || has(CURRENT_REVISION)
|| limitToPsId.isPresent()) { || limitToPsId.isPresent()) {
out.revisions = revisions(ctl, cd, src); out.revisions = revisions(ctl, src);
if (out.revisions != null) { if (out.revisions != null) {
for (Map.Entry<String, RevisionInfo> entry : out.revisions.entrySet()) { for (Map.Entry<String, RevisionInfo> entry : out.revisions.entrySet()) {
if (entry.getValue().isCurrent) { if (entry.getValue().isCurrent) {
@ -819,14 +835,15 @@ public class ChangeJson {
return false; return false;
} }
private Map<String, RevisionInfo> revisions(ChangeControl ctl, ChangeData cd, private Map<String, RevisionInfo> revisions(ChangeControl ctl,
Map<PatchSet.Id, PatchSet> map) throws OrmException { Map<PatchSet.Id, PatchSet> map)
throws PatchListNotAvailableException, OrmException, IOException {
Map<String, RevisionInfo> res = Maps.newLinkedHashMap(); Map<String, RevisionInfo> res = Maps.newLinkedHashMap();
for (PatchSet in : map.values()) { for (PatchSet in : map.values()) {
if ((has(ALL_REVISIONS) if ((has(ALL_REVISIONS)
|| in.getId().equals(cd.change().currentPatchSetId())) || in.getId().equals(ctl.getChange().currentPatchSetId()))
&& ctl.isPatchVisible(in, db.get())) { && ctl.isPatchVisible(in, db.get())) {
res.put(in.getRevision().get(), toRevisionInfo(ctl, cd, in)); res.put(in.getRevision().get(), toRevisionInfo(ctl, in));
} }
} }
return res; return res;
@ -860,10 +877,11 @@ public class ChangeJson {
return map; return map;
} }
private RevisionInfo toRevisionInfo(ChangeControl ctl, ChangeData cd, private RevisionInfo toRevisionInfo(ChangeControl ctl, PatchSet in)
PatchSet in) throws OrmException { throws PatchListNotAvailableException, OrmException, IOException {
Change c = ctl.getChange();
RevisionInfo out = new RevisionInfo(); RevisionInfo out = new RevisionInfo();
out.isCurrent = in.getId().equals(cd.change().currentPatchSetId()); out.isCurrent = in.getId().equals(c.currentPatchSetId());
out._number = in.getId().get(); out._number = in.getId().get();
out.ref = in.getRefName(); out.ref = in.getRefName();
out.created = in.getCreatedOn(); out.created = in.getCreatedOn();
@ -871,21 +889,30 @@ public class ChangeJson {
out.draft = in.isDraft() ? true : null; out.draft = in.isDraft() ? true : null;
out.fetch = makeFetchMap(ctl, in); out.fetch = makeFetchMap(ctl, in);
if (has(ALL_COMMITS) || (out.isCurrent && has(CURRENT_COMMIT))) { boolean setCommit = has(ALL_COMMITS)
try { || (out.isCurrent && has(CURRENT_COMMIT));
out.commit = toCommit(in, cd.change().getProject(), has(WEB_LINKS)); boolean addFooters = out.isCurrent && has(COMMIT_FOOTERS);
} catch (PatchSetInfoNotAvailableException e) { if (setCommit || addFooters) {
throw new OrmException(e); Project.NameKey project = c.getProject();
try (Repository repo = repoManager.openRepository(project);
RevWalk rw = new RevWalk(repo)) {
String rev = in.getRevision().get();
RevCommit commit = rw.parseCommit(ObjectId.fromString(rev));
rw.parseBody(commit);
if (setCommit) {
out.commit = toCommit(ctl, rw, commit, has(WEB_LINKS));
}
if (addFooters) {
out.commitWithFooters = mergeUtilFactory
.create(projectCache.get(project))
.createCherryPickCommitMessage(commit, ctl, in.getId());
}
} }
} }
if (has(ALL_FILES) || (out.isCurrent && has(CURRENT_FILES))) { if (has(ALL_FILES) || (out.isCurrent && has(CURRENT_FILES))) {
try { out.files = fileInfoJson.toFileInfoMap(c, in);
out.files = fileInfoJson.toFileInfoMap(cd.change(), in); out.files.remove(Patch.COMMIT_MSG);
out.files.remove(Patch.COMMIT_MSG);
} catch (PatchListNotAvailableException e) {
throw new OrmException(e);
}
} }
if ((out.isCurrent || (out.draft != null && out.draft)) if ((out.isCurrent || (out.draft != null && out.draft))
@ -908,34 +935,35 @@ public class ChangeJson {
return out; return out;
} }
CommitInfo toCommit(PatchSet in, Project.NameKey project, boolean addLinks) CommitInfo toCommit(ChangeControl ctl, RevWalk rw, RevCommit commit,
throws PatchSetInfoNotAvailableException { boolean addLinks) throws IOException {
PatchSetInfo info = patchSetInfoFactory.get(db.get(), in.getId()); Project.NameKey project = ctl.getChange().getProject();
CommitInfo commit = new CommitInfo(); CommitInfo info = new CommitInfo();
commit.parents = Lists.newArrayListWithCapacity(info.getParents().size()); info.parents = new ArrayList<>(commit.getParentCount());
commit.author = toGitPerson(info.getAuthor()); info.author = toGitPerson(commit.getAuthorIdent());
commit.committer = toGitPerson(info.getCommitter()); info.committer = toGitPerson(commit.getCommitterIdent());
commit.subject = info.getSubject(); info.subject = commit.getShortMessage();
commit.message = info.getMessage(); info.message = commit.getFullMessage();
if (addLinks) { if (addLinks) {
FluentIterable<WebLinkInfo> links = FluentIterable<WebLinkInfo> links =
webLinks.getPatchSetLinks(project, in.getRevision().get()); webLinks.getPatchSetLinks(project, commit.name());
commit.webLinks = links.isEmpty() ? null : links.toList(); info.webLinks = links.isEmpty() ? null : links.toList();
} }
for (ParentInfo parent : info.getParents()) { for (RevCommit parent : commit.getParents()) {
rw.parseBody(parent);
CommitInfo i = new CommitInfo(); CommitInfo i = new CommitInfo();
i.commit = parent.id.get(); i.commit = parent.name();
i.subject = parent.shortMessage; i.subject = parent.getShortMessage();
if (addLinks) { if (addLinks) {
FluentIterable<WebLinkInfo> parentLinks = FluentIterable<WebLinkInfo> parentLinks =
webLinks.getPatchSetLinks(project, parent.id.get()); webLinks.getPatchSetLinks(project, parent.name());
i.webLinks = parentLinks.isEmpty() ? null : parentLinks.toList(); i.webLinks = parentLinks.isEmpty() ? null : parentLinks.toList();
} }
commit.parents.add(i); info.parents.add(i);
} }
return commit; return info;
} }
private Map<String, FetchInfo> makeFetchMap(ChangeControl ctl, PatchSet in) private Map<String, FetchInfo> makeFetchMap(ChangeControl ctl, PatchSet in)
@ -991,15 +1019,6 @@ public class ChangeJson {
fetchInfo.commands.put(commandName, c); fetchInfo.commands.put(commandName, c);
} }
private static GitPerson toGitPerson(UserIdentity committer) {
GitPerson p = new GitPerson();
p.name = committer.getName();
p.email = committer.getEmail();
p.date = committer.getDate();
p.tz = committer.getTimeZone();
return p;
}
static void finish(ChangeInfo info) { static void finish(ChangeInfo info) {
info.id = Joiner.on('~').join( info.id = Joiner.on('~').join(
Url.encode(info.project), Url.encode(info.project),

View File

@ -18,38 +18,47 @@ import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.restapi.CacheControl; import com.google.gerrit.extensions.restapi.CacheControl;
import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView; import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException; import com.google.gerrit.reviewdb.client.Project;
import com.google.gwtorm.server.OrmException; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.kohsuke.args4j.Option; import org.kohsuke.args4j.Option;
import java.io.IOException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class GetCommit implements RestReadView<RevisionResource> { public class GetCommit implements RestReadView<RevisionResource> {
private final GitRepositoryManager repoManager;
private final ChangeJson json; private final ChangeJson json;
@Option(name = "--links", usage = "Add weblinks") @Option(name = "--links", usage = "Add weblinks")
private boolean addLinks; private boolean addLinks;
@Inject @Inject
GetCommit(ChangeJson json) { GetCommit(GitRepositoryManager repoManager,
ChangeJson json) {
this.repoManager = repoManager;
this.json = json; this.json = json;
} }
@Override @Override
public Response<CommitInfo> apply(RevisionResource resource) public Response<CommitInfo> apply(RevisionResource rsrc) throws IOException {
throws OrmException { Project.NameKey p = rsrc.getChange().getProject();
try { try (Repository repo = repoManager.openRepository(p);
Response<CommitInfo> r = RevWalk rw = new RevWalk(repo)) {
Response.ok(json.toCommit(resource.getPatchSet(), resource String rev = rsrc.getPatchSet().getRevision().get();
.getChange().getProject(), addLinks)); RevCommit commit = rw.parseCommit(ObjectId.fromString(rev));
if (resource.isCacheable()) { rw.parseBody(commit);
Response<CommitInfo> r = Response.ok(
json.toCommit(rsrc.getControl(), rw, commit, addLinks));
if (rsrc.isCacheable()) {
r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS)); r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS));
} }
return r; return r;
} catch (PatchSetInfoNotAvailableException e) {
throw new OrmException(e);
} }
} }
} }

View File

@ -25,13 +25,16 @@ import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.LabelType; import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Branch; import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.LabelId; import com.google.gerrit.reviewdb.client.LabelId;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval; import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ApprovalsUtil; import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.CanonicalWebUrl; import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectState; import com.google.gerrit.server.project.ProjectState;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Provider; import com.google.inject.Provider;
@ -195,7 +198,9 @@ public class MergeUtil {
} }
} }
public String createCherryPickCommitMessage(final CodeReviewCommit n) { public String createCherryPickCommitMessage(RevCommit n, ChangeControl ctl,
PatchSet.Id psId) {
Change c = ctl.getChange();
final List<FooterLine> footers = n.getFooterLines(); final List<FooterLine> footers = n.getFooterLines();
final StringBuilder msgbuf = new StringBuilder(); final StringBuilder msgbuf = new StringBuilder();
msgbuf.append(n.getFullMessage()); msgbuf.append(n.getFullMessage());
@ -215,16 +220,16 @@ public class MergeUtil {
msgbuf.append('\n'); msgbuf.append('\n');
} }
if (!contains(footers, FooterConstants.CHANGE_ID, n.change().getKey().get())) { if (!contains(footers, FooterConstants.CHANGE_ID, c.getKey().get())) {
msgbuf.append(FooterConstants.CHANGE_ID.getName()); msgbuf.append(FooterConstants.CHANGE_ID.getName());
msgbuf.append(": "); msgbuf.append(": ");
msgbuf.append(n.change().getKey().get()); msgbuf.append(c.getKey().get());
msgbuf.append('\n'); msgbuf.append('\n');
} }
final String siteUrl = urlProvider.get(); final String siteUrl = urlProvider.get();
if (siteUrl != null) { if (siteUrl != null) {
final String url = siteUrl + n.getPatchsetId().getParentKey().get(); final String url = siteUrl + c.getId().get();
if (!contains(footers, FooterConstants.REVIEWED_ON, url)) { if (!contains(footers, FooterConstants.REVIEWED_ON, url)) {
msgbuf.append(FooterConstants.REVIEWED_ON.getName()); msgbuf.append(FooterConstants.REVIEWED_ON.getName());
msgbuf.append(": "); msgbuf.append(": ");
@ -235,7 +240,7 @@ public class MergeUtil {
PatchSetApproval submitAudit = null; PatchSetApproval submitAudit = null;
for (final PatchSetApproval a : safeGetApprovals(n)) { for (final PatchSetApproval a : safeGetApprovals(ctl, psId)) {
if (a.getValue() <= 0) { if (a.getValue() <= 0) {
// Negative votes aren't counted. // Negative votes aren't counted.
continue; continue;
@ -301,6 +306,10 @@ public class MergeUtil {
return msgbuf.toString(); return msgbuf.toString();
} }
public String createCherryPickCommitMessage(final CodeReviewCommit n) {
return createCherryPickCommitMessage(n, n.getControl(), n.getPatchsetId());
}
private static boolean isCodeReview(LabelId id) { private static boolean isCodeReview(LabelId id) {
return "Code-Review".equalsIgnoreCase(id.get()); return "Code-Review".equalsIgnoreCase(id.get());
} }
@ -309,11 +318,12 @@ public class MergeUtil {
return "Verified".equalsIgnoreCase(id.get()); return "Verified".equalsIgnoreCase(id.get());
} }
private Iterable<PatchSetApproval> safeGetApprovals(CodeReviewCommit n) { private Iterable<PatchSetApproval> safeGetApprovals(
ChangeControl ctl, PatchSet.Id psId) {
try { try {
return approvalsUtil.byPatchSet(db.get(), n.getControl(), n.getPatchsetId()); return approvalsUtil.byPatchSet(db.get(), ctl, psId);
} catch (OrmException e) { } catch (OrmException e) {
log.error("Can't read approval records for " + n.getPatchsetId(), e); log.error("Can't read approval records for " + psId, e);
return Collections.emptyList(); return Collections.emptyList();
} }
} }