Merge changes I4aa7ab9c,I5ba29aa5,Ie824acdb * changes: SubmittedTogether: Also work for already submitted changes MergeOp: Record the change set Move SubmittedTogether assertion to AbstractDaemon
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java index 8d97136..42fc81c 100644 --- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java +++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -14,12 +14,15 @@ package com.google.gerrit.acceptance; +import static com.google.common.truth.Truth.assertThat; import static com.google.gerrit.acceptance.GitUtil.initSsh; import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; import static com.google.gerrit.server.project.Util.block; +import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Strings; +import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.google.common.primitives.Chars; import com.google.gerrit.acceptance.AcceptanceTestRequestScope.Context; @@ -594,4 +597,17 @@ .revision(1) .actions(); } + + protected void assertSubmittedTogether(String chId, String... expected) + throws Exception { + List<ChangeInfo> actual = gApi.changes().id(chId).submittedTogether(); + assertThat(actual).hasSize(expected.length); + assertThat(Iterables.transform(actual, + new Function<ChangeInfo, String>() { + @Override + public String apply(ChangeInfo input) { + return input.changeId; + } + })).containsExactly((Object[])expected).inOrder(); + } }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java index 2af3c25..9aa4b34 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java
@@ -49,8 +49,10 @@ PushOneCommit.Result change = createChange(); PushOneCommit.Result change2 = createChange(); - approve(change.getChangeId()); - submit(change2.getChangeId()); + String id1 = change.getChangeId(); + String id2 = change2.getChangeId(); + approve(id1); + submit(id2); RevCommit head = getRemoteHead(); assertThat(head.getId()).isEqualTo(change2.getCommitId()); @@ -59,6 +61,8 @@ assertSubmitter(change2.getChangeId(), 1); assertPersonEquals(admin.getIdent(), head.getAuthorIdent()); assertPersonEquals(admin.getIdent(), head.getCommitterIdent()); + assertSubmittedTogether(id1, id1, id2); + assertSubmittedTogether(id2, id1, id2); } @Test
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java index 6ac34ce..3841c03 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java
@@ -14,15 +14,11 @@ package com.google.gerrit.acceptance.server.change; -import static com.google.common.truth.Truth.assertThat; import static com.google.gerrit.acceptance.GitUtil.pushHead; -import com.google.common.base.Function; -import com.google.common.collect.Iterables; import com.google.gerrit.acceptance.AbstractDaemonTest; import com.google.gerrit.acceptance.GitUtil; import com.google.gerrit.extensions.client.SubmitType; -import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.server.git.ProjectConfig; @@ -33,8 +29,6 @@ import org.junit.Test; import java.io.IOException; -import java.util.Arrays; -import java.util.List; public class SubmittedTogetherIT extends AbstractDaemonTest { @@ -167,20 +161,6 @@ assertSubmittedTogether(id2); } - private void assertSubmittedTogether(String chId, String... expected) - throws Exception { - List<ChangeInfo> actual = gApi.changes().id(chId).submittedTogether(); - assertThat(actual).hasSize(expected.length); - assertThat(Arrays.asList(expected)) - .containsExactlyElementsIn( - Iterables.transform(actual, new Function<ChangeInfo, String>() { - @Override - public String apply(ChangeInfo input) { - return input.changeId; - } - })).inOrder(); - } - private RevCommit getRemoteHead() throws IOException { try (Repository repo = repoManager.openRepository(project); RevWalk rw = new RevWalk(repo)) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java index ae1a608..9612f71 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
@@ -228,11 +228,9 @@ new TabChangeListCallback(Tab.SAME_TOPIC, info.project(), revision)); } else { // TODO(sbeller): show only on latest revision - if (info.status().isOpen()) { - ChangeApi.change(info.legacyId().get()).view("submitted_together") - .get(new TabChangeListCallback(Tab.SUBMITTED_TOGETHER, - info.project(), revision)); - } + ChangeApi.change(info.legacyId().get()).view("submitted_together") + .get(new TabChangeListCallback(Tab.SUBMITTED_TOGETHER, + info.project(), revision)); } }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java index 0701771..6aa6699 100644 --- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java +++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
@@ -453,6 +453,13 @@ @Column(id = 17, notNull = false) protected String originalSubject; + /** + * Unique id for the changes submitted together assigned during merging. + * Only set if the status is MERGED. + */ + @Column(id = 18, notNull = false) + protected String submissionId; + protected Change() { } @@ -479,6 +486,7 @@ currentPatchSetId = other.currentPatchSetId; subject = other.subject; originalSubject = other.originalSubject; + submissionId = other.submissionId; topic = other.topic; } @@ -562,6 +570,14 @@ } } + public String getSubmissionId() { + return submissionId; + } + + public void setSubmissionId(String id) { + this.submissionId = id; + } + public Status getStatus() { return Status.forCode(status); }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java index a4f9fef..dec56a7 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java
@@ -14,15 +14,20 @@ package com.google.gerrit.server.change; +import com.google.common.collect.Lists; +import com.google.gerrit.extensions.client.ChangeStatus; import com.google.gerrit.extensions.client.ListChangesOption; import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.BadRequestException; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.RestReadView; +import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.git.ChangeSet; import com.google.gerrit.server.git.MergeSuperSet; +import com.google.gerrit.server.query.change.ChangeData; +import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; import com.google.inject.Provider; @@ -43,14 +48,17 @@ private final ChangeJson.Factory json; private final Provider<ReviewDb> dbProvider; + private final Provider<InternalChangeQuery> queryProvider; private final MergeSuperSet mergeSuperSet; @Inject SubmittedTogether(ChangeJson.Factory json, Provider<ReviewDb> dbProvider, + Provider<InternalChangeQuery> queryProvider, MergeSuperSet mergeSuperSet) { this.json = json; this.dbProvider = dbProvider; + this.queryProvider = queryProvider; this.mergeSuperSet = mergeSuperSet; } @@ -59,16 +67,32 @@ throws AuthException, BadRequestException, ResourceConflictException, Exception { try { - ChangeSet cs = mergeSuperSet.completeChangeSet(dbProvider.get(), - resource.getChange()); - if (cs.size() > 1) { - return json.create(EnumSet.of( - ListChangesOption.CURRENT_REVISION, - ListChangesOption.CURRENT_COMMIT)) - .format(cs.ids()); + Change c = resource.getChange(); + List<Change.Id> ids; + if (c.getStatus().isOpen()) { + ChangeSet cs = mergeSuperSet.completeChangeSet(dbProvider.get(), c); + ids = cs.ids().asList(); + } else if (c.getStatus().asChangeStatus() == ChangeStatus.MERGED) { + ids = Lists.newArrayList(); + String subId = c.getSubmissionId(); + if (subId.isEmpty()) { + ids = Collections.emptyList(); + } else { + for (ChangeData cd : queryProvider.get().bySubmissionId(subId)) { + ids.add(cd.getId()); + } + } } else { - return Collections.emptyList(); + // ABANDONED + ids = Collections.emptyList(); } + if (ids.size() <= 1) { + ids = Collections.emptyList(); + } + return json.create(EnumSet.of( + ListChangesOption.CURRENT_REVISION, + ListChangesOption.CURRENT_COMMIT)) + .format(ids); } catch (OrmException | IOException e) { log.error("Error on getting a ChangeSet", e); throw e;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java index 8ec8cbc..c5367ff 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -27,6 +27,8 @@ import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Table; +import com.google.common.hash.Hasher; +import com.google.common.hash.Hashing; import com.google.gerrit.common.ChangeHooks; import com.google.gerrit.common.TimeUtil; import com.google.gerrit.common.data.SubmitRecord; @@ -91,6 +93,8 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collection; @@ -143,7 +147,19 @@ private final Map<Change.Id, List<SubmitRecord>> records; private final Map<Change.Id, CodeReviewCommit> commits; - private String logPrefix; + + private static final String MACHINE_ID; + static { + String id; + try { + id = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + id = "unknown"; + } + MACHINE_ID = id; + } + private String staticSubmissionId; + private String submissionId; private ProjectState destProject; private ReviewDb db; @@ -336,10 +352,19 @@ } } + private void updateSubmissionId(Change change) { + Hasher h = Hashing.sha1().newHasher(); + h.putLong(Thread.currentThread().getId()) + .putUnencodedChars(MACHINE_ID); + staticSubmissionId = h.hash().toString().substring(0, 8); + submissionId = change.getId().get() + "-" + TimeUtil.nowMs() + + "-" + staticSubmissionId; + } + public void merge(ReviewDb db, Change change, IdentifiedUser caller, boolean checkSubmitRules) throws NoSuchChangeException, OrmException, ResourceConflictException { - logPrefix = String.format("[%s]: ", String.valueOf(change.hashCode())); + updateSubmissionId(change); this.db = db; logDebug("Beginning integration of {}", change); try { @@ -997,6 +1022,7 @@ @Override public Change update(Change c) { c.setStatus(Change.Status.MERGED); + c.setSubmissionId(submissionId); if (!merged.equals(c.currentPatchSetId())) { // Uncool; the patch set changed after we merged it. // Go back to the patch set that was actually merged. @@ -1253,28 +1279,28 @@ private void logDebug(String msg, Object... args) { if (log.isDebugEnabled()) { - log.debug(logPrefix + msg, args); + log.debug("[" + submissionId + "]" + msg, args); } } private void logWarn(String msg, Throwable t) { if (log.isWarnEnabled()) { - log.warn(logPrefix + msg, t); + log.warn("[" + submissionId + "]" + msg, t); } } private void logWarn(String msg) { if (log.isWarnEnabled()) { - log.warn(logPrefix + msg); + log.warn("[" + submissionId + "]" + msg); } } private void logError(String msg, Throwable t) { if (log.isErrorEnabled()) { if (t != null) { - log.error(logPrefix + msg, t); + log.error("[" + submissionId + "]" + msg, t); } else { - log.error(logPrefix + msg); + log.error("[" + submissionId + "]" + msg); } } }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java index e711306..4fa5cd3 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java
@@ -207,6 +207,21 @@ } }; + /** Submission id assigned by MergeOp. */ + public static final FieldDef<ChangeData, String> SUBMISSIONID = + new FieldDef.Single<ChangeData, String>( + "submissionid", FieldType.EXACT, false) { + @Override + public String get(ChangeData input, FillArgs args) + throws OrmException { + Change c = input.change(); + if (c == null) { + return null; + } + return c.getSubmissionId(); + } + }; + /** Last update time since January 1, 1970. */ public static final FieldDef<ChangeData, Timestamp> UPDATED = new FieldDef.Single<ChangeData, Timestamp>(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java index a8a97a8..4789a14 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
@@ -377,6 +377,42 @@ ChangeField.AUTHOR, ChangeField.COMMITTER); + static final Schema<ChangeData> V25 = schema( + ChangeField.LEGACY_ID2, + ChangeField.ID, + ChangeField.STATUS, + ChangeField.PROJECT, + ChangeField.PROJECTS, + ChangeField.REF, + ChangeField.EXACT_TOPIC, + ChangeField.FUZZY_TOPIC, + ChangeField.UPDATED, + ChangeField.FILE_PART, + ChangeField.PATH, + ChangeField.OWNER, + ChangeField.REVIEWER, + ChangeField.COMMIT, + ChangeField.TR, + ChangeField.LABEL, + ChangeField.COMMIT_MESSAGE, + ChangeField.COMMENT, + ChangeField.CHANGE, + ChangeField.APPROVAL, + ChangeField.MERGEABLE, + ChangeField.ADDED, + ChangeField.DELETED, + ChangeField.DELTA, + ChangeField.HASHTAG, + ChangeField.COMMENTBY, + ChangeField.PATCH_SET, + ChangeField.GROUP, + ChangeField.SUBMISSIONID, + ChangeField.EDITBY, + ChangeField.REVIEWEDBY, + ChangeField.EXACT_COMMIT, + ChangeField.AUTHOR, + ChangeField.COMMITTER); + private static Schema<ChangeData> schema(Collection<FieldDef<ChangeData, ?>> fields) { return new Schema<>(ImmutableList.copyOf(fields)); }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java index 31c35c2..bb11c05 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
@@ -41,6 +41,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; /** @@ -194,6 +195,14 @@ return query(commit(schema(indexes), id.name())); } + public List<ChangeData> bySubmissionId(String cs) throws OrmException { + if (cs.isEmpty()) { + return Collections.emptyList(); + } else { + return query(new SubmissionIdPredicate(cs)); + } + } + public List<ChangeData> byProjectGroups(Project.NameKey project, Collection<String> groups) throws OrmException { List<GroupPredicate> groupPredicates = new ArrayList<>(groups.size());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SubmissionIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SubmissionIdPredicate.java new file mode 100644 index 0000000..3b2dd94 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SubmissionIdPredicate.java
@@ -0,0 +1,44 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.query.change; + +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.server.index.ChangeField; +import com.google.gerrit.server.index.IndexPredicate; +import com.google.gwtorm.server.OrmException; + +class SubmissionIdPredicate extends IndexPredicate<ChangeData> { + + SubmissionIdPredicate(String changeSet) { + super(ChangeField.SUBMISSIONID, changeSet); + } + + @Override + public boolean match(ChangeData object) throws OrmException { + Change change = object.change(); + if (change == null) { + return false; + } + if (change.getSubmissionId() == null) { + return false; + } + return getValue().equals(change.getSubmissionId()); + } + + @Override + public int getCost() { + return 1; + } +}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java index 769329d..9022bfe 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
@@ -32,7 +32,7 @@ /** A version of the database schema. */ public abstract class SchemaVersion { /** The current schema version. */ - public static final Class<Schema_111> C = Schema_111.class; + public static final Class<Schema_112> C = Schema_112.class; public static int getBinaryVersion() { return guessVersion(C);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_112.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_112.java new file mode 100644 index 0000000..6364c48 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_112.java
@@ -0,0 +1,30 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.schema; + +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gwtorm.jdbc.JdbcSchema; +import com.google.inject.Inject; +import com.google.inject.Provider; + +import java.sql.SQLException; +import java.sql.Statement; + +public class Schema_112 extends SchemaVersion { + @Inject + Schema_112(Provider<Schema_111> prior) { + super(prior); + } +}