Visualize in which revisions a merged change is included
Introduced a new "Included in" panel on merged changes. The panel will produce sorted lists all branches and tags which contains the merged change. Provides a simple way for users to determine in which revisions of the project the change is included. Change-Id: If94b2604607f53a2e45330b56d55cc5de8288054
This commit is contained in:
parent
04132a143f
commit
56f76b2bd0
@ -26,6 +26,8 @@ import com.google.gwtjsonrpc.client.RpcImpl.Version;
|
||||
public interface ChangeDetailService extends RemoteJsonService {
|
||||
void changeDetail(Change.Id id, AsyncCallback<ChangeDetail> callback);
|
||||
|
||||
void includedInDetail(Change.Id id, AsyncCallback<IncludedInDetail> callback);
|
||||
|
||||
void patchSetDetail(PatchSet.Id key, AsyncCallback<PatchSetDetail> callback);
|
||||
|
||||
@SignInRequired
|
||||
|
@ -0,0 +1,44 @@
|
||||
// Copyright (C) 2010 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.common.data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class IncludedInDetail {
|
||||
private List<String> branches;
|
||||
private List<String> tags;
|
||||
|
||||
public IncludedInDetail() {
|
||||
}
|
||||
|
||||
public void setBranches(final List<String> b) {
|
||||
Collections.sort(b);
|
||||
branches = b;
|
||||
}
|
||||
|
||||
public List<String> getBranches() {
|
||||
return branches;
|
||||
}
|
||||
|
||||
public void setTags(final List<String> t) {
|
||||
Collections.sort(t);
|
||||
tags = t;
|
||||
}
|
||||
|
||||
public List<String> getTags() {
|
||||
return tags;
|
||||
}
|
||||
}
|
@ -63,6 +63,7 @@ public interface ChangeConstants extends Constants {
|
||||
String prevPatchLinkIcon();
|
||||
String nextPatchLinkIcon();
|
||||
|
||||
String changeScreenIncludedIn();
|
||||
String changeScreenDependencies();
|
||||
String changeScreenDependsOn();
|
||||
String changeScreenNeededBy();
|
||||
@ -79,6 +80,9 @@ public interface ChangeConstants extends Constants {
|
||||
String changeInfoBlockStatus();
|
||||
String changePermalink();
|
||||
|
||||
String includedInTableBranch();
|
||||
String includedInTableTag();
|
||||
|
||||
String messageNoAuthor();
|
||||
String messageExpandRecent();
|
||||
String messageExpandAll();
|
||||
|
@ -40,6 +40,7 @@ patchTablePrev = Previous file
|
||||
patchTableNext = Next file
|
||||
patchTableOpen = Open file
|
||||
|
||||
changeScreenIncludedIn = Included in
|
||||
changeScreenDependencies = Dependencies
|
||||
changeScreenDependsOn = Depends On
|
||||
changeScreenNeededBy = Needed By
|
||||
@ -56,6 +57,9 @@ changeInfoBlockUpdated = Updated
|
||||
changeInfoBlockStatus = Status
|
||||
changePermalink = Permalink
|
||||
|
||||
includedInTableBranch = Branch Name
|
||||
includedInTableTag = Tag Name
|
||||
|
||||
messageNoAuthor = Gerrit Code Review
|
||||
messageExpandRecent = Expand Recent
|
||||
messageExpandAll = Expand All
|
||||
|
@ -34,6 +34,7 @@ import com.google.gerrit.reviewdb.Account;
|
||||
import com.google.gerrit.reviewdb.Change;
|
||||
import com.google.gerrit.reviewdb.ChangeMessage;
|
||||
import com.google.gerrit.reviewdb.PatchSet;
|
||||
import com.google.gerrit.reviewdb.Change.Status;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.event.dom.client.KeyPressEvent;
|
||||
@ -64,6 +65,8 @@ public class ChangeScreen extends Screen {
|
||||
private ChangeDescriptionBlock descriptionBlock;
|
||||
private ApprovalTable approvals;
|
||||
|
||||
private IncludedInTable includedInTable;
|
||||
private DisclosurePanel includedInPanel;
|
||||
private DisclosurePanel dependenciesPanel;
|
||||
private ChangeTable dependencies;
|
||||
private ChangeTable.Section dependsOn;
|
||||
@ -171,6 +174,12 @@ public class ChangeScreen extends Screen {
|
||||
approvals = new ApprovalTable();
|
||||
add(approvals);
|
||||
|
||||
includedInPanel = new DisclosurePanel(Util.C.changeScreenIncludedIn());
|
||||
includedInTable = new IncludedInTable(changeId);
|
||||
|
||||
includedInPanel.setContent(includedInTable);
|
||||
add(includedInPanel);
|
||||
|
||||
dependencies = new ChangeTable() {
|
||||
{
|
||||
table.setWidth("98%");
|
||||
@ -219,6 +228,13 @@ public class ChangeScreen extends Screen {
|
||||
setStarred(detail.isStarred());
|
||||
}
|
||||
|
||||
if (Status.MERGED == detail.getChange().getStatus()) {
|
||||
includedInPanel.setVisible(true);
|
||||
includedInPanel.addOpenHandler(includedInTable);
|
||||
} else {
|
||||
includedInPanel.setVisible(false);
|
||||
}
|
||||
|
||||
dependencies.setAccountInfoCache(detail.getAccounts());
|
||||
approvals.setAccountInfoCache(detail.getAccounts());
|
||||
|
||||
|
@ -0,0 +1,85 @@
|
||||
// Copyright (C) 2010 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.client.changes;
|
||||
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.common.data.IncludedInDetail;
|
||||
import com.google.gerrit.reviewdb.Change;
|
||||
import com.google.gwt.event.logical.shared.OpenEvent;
|
||||
import com.google.gwt.event.logical.shared.OpenHandler;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.DisclosurePanel;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
|
||||
|
||||
|
||||
/** Displays a table of Branches and Tags containing the change record. */
|
||||
public class IncludedInTable extends Composite implements
|
||||
OpenHandler<DisclosurePanel> {
|
||||
private final Grid table;
|
||||
private final Change.Id changeId;
|
||||
private boolean loaded = false;
|
||||
|
||||
public IncludedInTable(final Change.Id chId) {
|
||||
changeId = chId;
|
||||
table = new Grid(1, 1);
|
||||
initWidget(table);
|
||||
}
|
||||
|
||||
public void loadTable(final IncludedInDetail detail) {
|
||||
int row = 0;
|
||||
table.resizeRows(detail.getBranches().size() + 1);
|
||||
table.addStyleName(Gerrit.RESOURCES.css().changeTable());
|
||||
final CellFormatter fmt = table.getCellFormatter();
|
||||
fmt.addStyleName(row, 0, Gerrit.RESOURCES.css().dataHeader());
|
||||
table.setText(row, 0, Util.C.includedInTableBranch());
|
||||
|
||||
for (final String branch : detail.getBranches()) {
|
||||
fmt.addStyleName(++row, 0, Gerrit.RESOURCES.css().dataCell());
|
||||
fmt.addStyleName(row, 0, Gerrit.RESOURCES.css().leftMostCell());
|
||||
table.setText(row, 0, branch);
|
||||
}
|
||||
|
||||
if (!detail.getTags().isEmpty()) {
|
||||
table.resizeRows(table.getRowCount() + 2 + detail.getTags().size());
|
||||
row++;
|
||||
fmt.addStyleName(++row, 0, Gerrit.RESOURCES.css().dataHeader());
|
||||
table.setText(row, 0, Util.C.includedInTableTag());
|
||||
|
||||
for (final String tag : detail.getTags()) {
|
||||
fmt.addStyleName(++row, 0, Gerrit.RESOURCES.css().dataCell());
|
||||
fmt.addStyleName(row, 0, Gerrit.RESOURCES.css().leftMostCell());
|
||||
table.setText(row, 0, tag);
|
||||
}
|
||||
}
|
||||
|
||||
table.setVisible(true);
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(OpenEvent<DisclosurePanel> event) {
|
||||
if (!loaded) {
|
||||
Util.DETAIL_SVC.includedInDetail(changeId,
|
||||
new GerritCallback<IncludedInDetail>() {
|
||||
@Override
|
||||
public void onSuccess(final IncludedInDetail result) {
|
||||
loadTable(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ package com.google.gerrit.httpd.rpc.changedetail;
|
||||
|
||||
import com.google.gerrit.common.data.ChangeDetail;
|
||||
import com.google.gerrit.common.data.ChangeDetailService;
|
||||
import com.google.gerrit.common.data.IncludedInDetail;
|
||||
import com.google.gerrit.common.data.PatchSetDetail;
|
||||
import com.google.gerrit.common.data.PatchSetPublishDetail;
|
||||
import com.google.gerrit.reviewdb.Change;
|
||||
@ -25,14 +26,17 @@ import com.google.inject.Inject;
|
||||
|
||||
class ChangeDetailServiceImpl implements ChangeDetailService {
|
||||
private final ChangeDetailFactory.Factory changeDetail;
|
||||
private final IncludedInDetailFactory.Factory includedInDetail;
|
||||
private final PatchSetDetailFactory.Factory patchSetDetail;
|
||||
private final PatchSetPublishDetailFactory.Factory patchSetPublishDetail;
|
||||
|
||||
@Inject
|
||||
ChangeDetailServiceImpl(final ChangeDetailFactory.Factory changeDetail,
|
||||
final IncludedInDetailFactory.Factory includedInDetail,
|
||||
final PatchSetDetailFactory.Factory patchSetDetail,
|
||||
final PatchSetPublishDetailFactory.Factory patchSetPublishDetail) {
|
||||
this.changeDetail = changeDetail;
|
||||
this.includedInDetail = includedInDetail;
|
||||
this.patchSetDetail = patchSetDetail;
|
||||
this.patchSetPublishDetail = patchSetPublishDetail;
|
||||
}
|
||||
@ -42,6 +46,11 @@ class ChangeDetailServiceImpl implements ChangeDetailService {
|
||||
changeDetail.create(id).to(callback);
|
||||
}
|
||||
|
||||
public void includedInDetail(final Change.Id id,
|
||||
final AsyncCallback<IncludedInDetail> callback) {
|
||||
includedInDetail.create(id).to(callback);
|
||||
}
|
||||
|
||||
public void patchSetDetail(final PatchSet.Id id,
|
||||
final AsyncCallback<PatchSetDetail> callback) {
|
||||
patchSetDetail.create(id).to(callback);
|
||||
|
@ -30,6 +30,7 @@ public class ChangeModule extends RpcServletModule {
|
||||
protected void configure() {
|
||||
factory(AbandonChange.Factory.class);
|
||||
factory(ChangeDetailFactory.Factory.class);
|
||||
factory(IncludedInDetailFactory.Factory.class);
|
||||
factory(PatchSetDetailFactory.Factory.class);
|
||||
factory(PatchSetPublishDetailFactory.Factory.class);
|
||||
factory(SubmitAction.Factory.class);
|
||||
|
@ -0,0 +1,111 @@
|
||||
// Copyright (C) 2010 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.httpd.rpc.changedetail;
|
||||
|
||||
import com.google.gerrit.common.data.IncludedInDetail;
|
||||
import com.google.gerrit.common.errors.InvalidRevisionException;
|
||||
import com.google.gerrit.common.errors.NoSuchEntityException;
|
||||
import com.google.gerrit.httpd.rpc.Handler;
|
||||
import com.google.gerrit.reviewdb.Change;
|
||||
import com.google.gerrit.reviewdb.PatchSet;
|
||||
import com.google.gerrit.reviewdb.ReviewDb;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gwtorm.client.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||
import org.eclipse.jgit.errors.MissingObjectException;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** Creates a {@link IncludedInDetail} of a {@link Change}. */
|
||||
class IncludedInDetailFactory extends Handler<IncludedInDetail> {
|
||||
interface Factory {
|
||||
IncludedInDetailFactory create(Change.Id id);
|
||||
}
|
||||
|
||||
private final ReviewDb db;
|
||||
private final ChangeControl.Factory changeControlFactory;
|
||||
private final GitRepositoryManager repoManager;
|
||||
private final Change.Id changeId;
|
||||
|
||||
private IncludedInDetail detail;
|
||||
private ChangeControl control;
|
||||
|
||||
@Inject
|
||||
IncludedInDetailFactory(final ReviewDb db,
|
||||
final ChangeControl.Factory changeControlFactory,
|
||||
final GitRepositoryManager repoManager, @Assisted final Change.Id changeId) {
|
||||
this.changeControlFactory = changeControlFactory;
|
||||
this.repoManager = repoManager;
|
||||
this.changeId = changeId;
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IncludedInDetail call() throws OrmException, NoSuchChangeException,
|
||||
NoSuchEntityException, IOException, InvalidRevisionException {
|
||||
control = changeControlFactory.validateFor(changeId);
|
||||
final PatchSet patch =
|
||||
db.patchSets().get(control.getChange().currentPatchSetId());
|
||||
final Repository repo =
|
||||
repoManager.openRepository(control.getProject().getName());
|
||||
final Map<String, Ref> refsHeads =
|
||||
repo.getRefDatabase().getRefs(Constants.R_HEADS);
|
||||
final Map<String, Ref> refsTags =
|
||||
repo.getRefDatabase().getRefs(Constants.R_TAGS);
|
||||
RevWalk rw = new RevWalk(repo);
|
||||
|
||||
try {
|
||||
final RevCommit rev =
|
||||
rw.parseCommit(ObjectId.fromString(patch.getRevision().get()));
|
||||
final List<String> branches = new ArrayList<String>();
|
||||
for (final String branch : refsHeads.keySet()) {
|
||||
if (rw.isMergedInto(rev, rw.parseCommit(refsHeads.get(branch)
|
||||
.getObjectId()))) {
|
||||
branches.add(branch);
|
||||
}
|
||||
}
|
||||
final List<String> tags = new ArrayList<String>();
|
||||
for (final String tag : refsTags.keySet()) {
|
||||
if (rw.isMergedInto(rev, rw
|
||||
.parseCommit(refsTags.get(tag).getObjectId()))) {
|
||||
tags.add(tag);
|
||||
}
|
||||
}
|
||||
detail = new IncludedInDetail();
|
||||
detail.setBranches(branches);
|
||||
detail.setTags(tags);
|
||||
|
||||
return detail;
|
||||
} catch (IncorrectObjectTypeException err) {
|
||||
throw new InvalidRevisionException();
|
||||
} catch (MissingObjectException err) {
|
||||
throw new InvalidRevisionException();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user