Add support for file web links

Change-Id: I362297fd483a0eeb77ee889899a636f2788cb71c
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
Edwin Kempin 2014-09-11 09:41:42 +02:00
parent 0f697bdbec
commit b3696c8d7a
10 changed files with 129 additions and 9 deletions

View File

@ -1778,6 +1778,9 @@ public class MyWeblinkPlugin implements PatchSetWebLink {
} }
---- ----
FileWebLinks will appear in the side-by-side diff screen on the right
side of the patch selection on each side.
ProjectWebLinks will appear in the project list in the ProjectWebLinks will appear in the project list in the
`Repository Browser` column. `Repository Browser` column.

View File

@ -3389,6 +3389,12 @@ Intraline status (`OK`, `ERROR`, `TIMEOUT`).
|`diff_header` ||A list of strings representing the patch set diff header. |`diff_header` ||A list of strings representing the patch set diff header.
|`content` ||The content differences in the file as a list of |`content` ||The content differences in the file as a list of
link:#diff-content[DiffContent] entities. link:#diff-content[DiffContent] entities.
|'web_links_a' |optional|
Links to the side A file in external sites as a list of
link:rest-api-changes.html#web-link-info[WebLinkInfo] entries.
|'web_links_b' |optional|
Links to the side B file in external sites as a list of
link:rest-api-changes.html#web-link-info[WebLinkInfo] entries.
|========================== |==========================
[[diff-intraline-info]] [[diff-intraline-info]]

View File

@ -0,0 +1,31 @@
// Copyright (C) 2014 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.extensions.webui;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
@ExtensionPoint
public interface FileWebLink extends WebLink {
/**
* URL to file in external service.
*
* @param projectName Name of the project
* @param revision Name of the revision (e.g. branch or commit ID)
* @param fileName Name of the file
* @return url to project in external service.
*/
String getFileUrl(String projectName, String revision, String fileName);
}

View File

@ -14,6 +14,7 @@
package com.google.gerrit.client.diff; package com.google.gerrit.client.diff;
import com.google.gerrit.client.WebLinkInfo;
import com.google.gerrit.reviewdb.client.Patch.ChangeType; import com.google.gerrit.reviewdb.client.Patch.ChangeType;
import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsArray;
@ -27,6 +28,8 @@ public class DiffInfo extends JavaScriptObject {
public final native FileMeta meta_b() /*-{ return this.meta_b; }-*/; public final native FileMeta meta_b() /*-{ return this.meta_b; }-*/;
public final native JsArrayString diff_header() /*-{ return this.diff_header; }-*/; public final native JsArrayString diff_header() /*-{ return this.diff_header; }-*/;
public final native JsArray<Region> content() /*-{ return this.content; }-*/; public final native JsArray<Region> content() /*-{ return this.content; }-*/;
public final native JsArray<WebLinkInfo> web_links_a() /*-{ return this.web_links_a; }-*/;
public final native JsArray<WebLinkInfo> web_links_b() /*-{ return this.web_links_b; }-*/;
public final ChangeType change_type() { public final ChangeType change_type() {
return ChangeType.valueOf(change_typeRaw()); return ChangeType.valueOf(change_typeRaw());

View File

@ -16,6 +16,7 @@ package com.google.gerrit.client.diff;
import com.google.gerrit.client.account.DiffPreferences; import com.google.gerrit.client.account.DiffPreferences;
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo; import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.reviewdb.client.Patch.ChangeType; import com.google.gerrit.reviewdb.client.Patch.ChangeType;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.GWT;
@ -158,8 +159,10 @@ class DiffTable extends Composite {
void set(DiffPreferences prefs, JsArray<RevisionInfo> list, DiffInfo info) { void set(DiffPreferences prefs, JsArray<RevisionInfo> list, DiffInfo info) {
this.changeType = info.change_type(); this.changeType = info.change_type();
patchSetSelectBoxA.setUpPatchSetNav(list, info.meta_a()); patchSetSelectBoxA.setUpPatchSetNav(list, info.meta_a(),
patchSetSelectBoxB.setUpPatchSetNav(list, info.meta_b()); Natives.asList(info.web_links_a()));
patchSetSelectBoxB.setUpPatchSetNav(list, info.meta_b(),
Natives.asList(info.web_links_b()));
JsArrayString hdr = info.diff_header(); JsArrayString hdr = info.diff_header();
if (hdr != null) { if (hdr != null) {

View File

@ -16,6 +16,7 @@ package com.google.gerrit.client.diff;
import com.google.gerrit.client.Dispatcher; import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.Gerrit; import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.WebLinkInfo;
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo; import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
import com.google.gerrit.client.patches.PatchUtil; import com.google.gerrit.client.patches.PatchUtil;
import com.google.gerrit.client.ui.InlineHyperlink; import com.google.gerrit.client.ui.InlineHyperlink;
@ -36,6 +37,8 @@ import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.ImageResourceRenderer; import com.google.gwt.user.client.ui.ImageResourceRenderer;
import com.google.gwtorm.client.KeyUtil; import com.google.gwtorm.client.KeyUtil;
import java.util.List;
/** HTMLPanel to select among patch sets */ /** HTMLPanel to select among patch sets */
class PatchSetSelectBox2 extends Composite { class PatchSetSelectBox2 extends Composite {
interface Binder extends UiBinder<HTMLPanel, PatchSetSelectBox2> {} interface Binder extends UiBinder<HTMLPanel, PatchSetSelectBox2> {}
@ -76,7 +79,8 @@ class PatchSetSelectBox2 extends Composite {
this.path = path; this.path = path;
} }
void setUpPatchSetNav(JsArray<RevisionInfo> list, DiffInfo.FileMeta meta) { void setUpPatchSetNav(JsArray<RevisionInfo> list, DiffInfo.FileMeta meta,
List<WebLinkInfo> webLinks) {
InlineHyperlink baseLink = null; InlineHyperlink baseLink = null;
InlineHyperlink selectedLink = null; InlineHyperlink selectedLink = null;
if (sideA) { if (sideA) {
@ -100,6 +104,22 @@ class PatchSetSelectBox2 extends Composite {
if (meta != null && !Patch.COMMIT_MSG.equals(path)) { if (meta != null && !Patch.COMMIT_MSG.equals(path)) {
linkPanel.add(createDownloadLink()); linkPanel.add(createDownloadLink());
} }
if (webLinks != null) {
for (WebLinkInfo weblink : webLinks) {
Anchor a = new Anchor();
a.setHref(weblink.url());
if (weblink.imageUrl() != null && !weblink.imageUrl().isEmpty()) {
Image img = new Image();
img.setAltText(weblink.name());
img.setUrl(weblink.imageUrl());
img.setTitle(weblink.name());
a.getElement().appendChild(img.getElement());
} else {
a.setText("(" + weblink.name() + ")");
}
linkPanel.add(a);
}
}
} }
static void link(PatchSetSelectBox2 a, PatchSetSelectBox2 b) { static void link(PatchSetSelectBox2 a, PatchSetSelectBox2 b) {

View File

@ -19,6 +19,7 @@ import com.google.gerrit.extensions.common.WebLinkInfo;
import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.webui.BranchWebLink; import com.google.gerrit.extensions.webui.BranchWebLink;
import com.google.gerrit.extensions.webui.PatchSetWebLink; import com.google.gerrit.extensions.webui.PatchSetWebLink;
import com.google.gerrit.extensions.webui.FileWebLink;
import com.google.gerrit.extensions.webui.ProjectWebLink; import com.google.gerrit.extensions.webui.ProjectWebLink;
import java.util.List; import java.util.List;
@ -26,13 +27,16 @@ import java.util.List;
public class WebLinks { public class WebLinks {
private final DynamicSet<PatchSetWebLink> patchSetLinks; private final DynamicSet<PatchSetWebLink> patchSetLinks;
private final DynamicSet<FileWebLink> fileLinks;
private final DynamicSet<ProjectWebLink> projectLinks; private final DynamicSet<ProjectWebLink> projectLinks;
private final DynamicSet<BranchWebLink> branchLinks; private final DynamicSet<BranchWebLink> branchLinks;
public WebLinks(DynamicSet<PatchSetWebLink> patchSetLinks, public WebLinks(DynamicSet<PatchSetWebLink> patchSetLinks,
DynamicSet<FileWebLink> fileLinks,
DynamicSet<ProjectWebLink> projectLinks, DynamicSet<ProjectWebLink> projectLinks,
DynamicSet<BranchWebLink> branchLinks) { DynamicSet<BranchWebLink> branchLinks) {
this.patchSetLinks = patchSetLinks; this.patchSetLinks = patchSetLinks;
this.fileLinks = fileLinks;
this.projectLinks = projectLinks; this.projectLinks = projectLinks;
this.branchLinks = branchLinks; this.branchLinks = branchLinks;
} }
@ -47,6 +51,17 @@ public class WebLinks {
return links; return links;
} }
public Iterable<WebLinkInfo> getPatchLinks(String project, String revision,
String file) {
List<WebLinkInfo> links = Lists.newArrayList();
for (FileWebLink webLink : fileLinks) {
links.add(new WebLinkInfo(webLink.getLinkName(),
webLink.getImageUrl(),
webLink.getFileUrl(project, revision, file)));
}
return links;
}
public Iterable<WebLinkInfo> getProjectLinks(String project) { public Iterable<WebLinkInfo> getProjectLinks(String project) {
List<WebLinkInfo> links = Lists.newArrayList(); List<WebLinkInfo> links = Lists.newArrayList();
for (ProjectWebLink webLink : projectLinks) { for (ProjectWebLink webLink : projectLinks) {

View File

@ -17,6 +17,7 @@ package com.google.gerrit.server;
import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.webui.BranchWebLink; import com.google.gerrit.extensions.webui.BranchWebLink;
import com.google.gerrit.extensions.webui.PatchSetWebLink; import com.google.gerrit.extensions.webui.PatchSetWebLink;
import com.google.gerrit.extensions.webui.FileWebLink;
import com.google.gerrit.extensions.webui.ProjectWebLink; import com.google.gerrit.extensions.webui.ProjectWebLink;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
@ -24,21 +25,23 @@ import com.google.inject.Provider;
public class WebLinksProvider implements Provider<WebLinks> { public class WebLinksProvider implements Provider<WebLinks> {
private final DynamicSet<PatchSetWebLink> patchSetLinks; private final DynamicSet<PatchSetWebLink> patchSetLinks;
private final DynamicSet<FileWebLink> fileLinks;
private final DynamicSet<ProjectWebLink> projectLinks; private final DynamicSet<ProjectWebLink> projectLinks;
private final DynamicSet<BranchWebLink> branchLinks; private final DynamicSet<BranchWebLink> branchLinks;
@Inject @Inject
public WebLinksProvider(DynamicSet<PatchSetWebLink> patchSetLinks, public WebLinksProvider(DynamicSet<PatchSetWebLink> patchSetLinks,
DynamicSet<FileWebLink> fileLinks,
DynamicSet<ProjectWebLink> projectLinks, DynamicSet<ProjectWebLink> projectLinks,
DynamicSet<BranchWebLink> branchLinks) { DynamicSet<BranchWebLink> branchLinks) {
this.patchSetLinks = patchSetLinks; this.patchSetLinks = patchSetLinks;
this.fileLinks = fileLinks;
this.projectLinks = projectLinks; this.projectLinks = projectLinks;
this.branchLinks = branchLinks; this.branchLinks = branchLinks;
} }
@Override @Override
public WebLinks get() { public WebLinks get() {
WebLinks webLinks = new WebLinks(patchSetLinks, projectLinks, branchLinks); return new WebLinks(patchSetLinks, fileLinks, projectLinks, branchLinks);
return webLinks;
} }
} }

View File

@ -17,11 +17,13 @@ package com.google.gerrit.server.change;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.gerrit.common.data.PatchScript; import com.google.gerrit.common.data.PatchScript;
import com.google.gerrit.common.data.PatchScript.DisplayMethod; import com.google.gerrit.common.data.PatchScript.DisplayMethod;
import com.google.gerrit.common.data.PatchScript.FileMode; import com.google.gerrit.common.data.PatchScript.FileMode;
import com.google.gerrit.extensions.common.WebLinkInfo;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.CacheControl; import com.google.gerrit.extensions.restapi.CacheControl;
import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.IdString;
@ -35,6 +37,8 @@ import com.google.gerrit.reviewdb.client.AccountDiffPreference;
import com.google.gerrit.reviewdb.client.Patch; import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.Patch.ChangeType; import com.google.gerrit.reviewdb.client.Patch.ChangeType;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.WebLinks;
import com.google.gerrit.server.git.LargeObjectException; import com.google.gerrit.server.git.LargeObjectException;
import com.google.gerrit.server.patch.PatchScriptFactory; import com.google.gerrit.server.patch.PatchScriptFactory;
import com.google.gerrit.server.project.InvalidChangeOperationException; import com.google.gerrit.server.project.InvalidChangeOperationException;
@ -43,6 +47,7 @@ import com.google.gerrit.server.project.ProjectCache;
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.Inject; import com.google.inject.Inject;
import com.google.inject.Provider;
import org.eclipse.jgit.diff.Edit; import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.diff.ReplaceEdit; import org.eclipse.jgit.diff.ReplaceEdit;
@ -56,6 +61,7 @@ import org.kohsuke.args4j.spi.Parameters;
import org.kohsuke.args4j.spi.Setter; import org.kohsuke.args4j.spi.Setter;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -63,6 +69,7 @@ public class GetDiff implements RestReadView<FileResource> {
private final ProjectCache projectCache; private final ProjectCache projectCache;
private final PatchScriptFactory.Factory patchScriptFactoryFactory; private final PatchScriptFactory.Factory patchScriptFactoryFactory;
private final Revisions revisions; private final Revisions revisions;
private final Provider<WebLinks> webLinks;
@Option(name = "--base", metaVar = "REVISION") @Option(name = "--base", metaVar = "REVISION")
String base; String base;
@ -79,21 +86,23 @@ public class GetDiff implements RestReadView<FileResource> {
@Inject @Inject
GetDiff(ProjectCache projectCache, GetDiff(ProjectCache projectCache,
PatchScriptFactory.Factory patchScriptFactoryFactory, PatchScriptFactory.Factory patchScriptFactoryFactory,
Revisions revisions) { Revisions revisions,
Provider<WebLinks> webLinks) {
this.projectCache = projectCache; this.projectCache = projectCache;
this.patchScriptFactoryFactory = patchScriptFactoryFactory; this.patchScriptFactoryFactory = patchScriptFactoryFactory;
this.revisions = revisions; this.revisions = revisions;
this.webLinks = webLinks;
} }
@Override @Override
public Response<Result> apply(FileResource resource) public Response<Result> apply(FileResource resource)
throws ResourceConflictException, ResourceNotFoundException, throws ResourceConflictException, ResourceNotFoundException,
OrmException, AuthException, InvalidChangeOperationException, IOException { OrmException, AuthException, InvalidChangeOperationException, IOException {
PatchSet.Id basePatchSet = null; PatchSet basePatchSet = null;
if (base != null) { if (base != null) {
RevisionResource baseResource = revisions.parse( RevisionResource baseResource = revisions.parse(
resource.getRevision().getChangeResource(), IdString.fromDecoded(base)); resource.getRevision().getChangeResource(), IdString.fromDecoded(base));
basePatchSet = baseResource.getPatchSet().getId(); basePatchSet = baseResource.getPatchSet();
} }
AccountDiffPreference prefs = new AccountDiffPreference(new Account.Id(0)); AccountDiffPreference prefs = new AccountDiffPreference(new Account.Id(0));
prefs.setIgnoreWhitespace(ignoreWhitespace.whitespace); prefs.setIgnoreWhitespace(ignoreWhitespace.whitespace);
@ -104,7 +113,7 @@ public class GetDiff implements RestReadView<FileResource> {
PatchScriptFactory psf = patchScriptFactoryFactory.create( PatchScriptFactory psf = patchScriptFactoryFactory.create(
resource.getRevision().getControl(), resource.getRevision().getControl(),
resource.getPatchKey().getFileName(), resource.getPatchKey().getFileName(),
basePatchSet, basePatchSet != null ? basePatchSet.getId() : null,
resource.getPatchKey().getParentKey(), resource.getPatchKey().getParentKey(),
prefs); prefs);
psf.setLoadHistory(false); psf.setLoadHistory(false);
@ -147,6 +156,14 @@ public class GetDiff implements RestReadView<FileResource> {
ps.getNewName()); ps.getNewName());
setContentType(result.metaA, state, ps.getFileModeA(), ps.getMimeTypeA()); setContentType(result.metaA, state, ps.getFileModeA(), ps.getMimeTypeA());
result.metaA.lines = ps.getA().size(); result.metaA.lines = ps.getA().size();
// TODO referring to the parent commit by refs/changes/12/60012/1^1
// will likely not work for inline edits
String rev = basePatchSet != null
? basePatchSet.getRefName()
: resource.getRevision().getPatchSet().getRefName() + "^1";
result.webLinksA =
getFileWebLinks(state.getProject(), rev, result.metaA.name);
} }
if (ps.getDisplayMethodB() != DisplayMethod.NONE) { if (ps.getDisplayMethodB() != DisplayMethod.NONE) {
@ -154,6 +171,9 @@ public class GetDiff implements RestReadView<FileResource> {
result.metaB.name = ps.getNewName(); result.metaB.name = ps.getNewName();
setContentType(result.metaB, state, ps.getFileModeB(), ps.getMimeTypeB()); setContentType(result.metaB, state, ps.getFileModeB(), ps.getMimeTypeB());
result.metaB.lines = ps.getB().size(); result.metaB.lines = ps.getB().size();
result.webLinksB = getFileWebLinks(state.getProject(),
resource.getRevision().getPatchSet().getRefName(),
result.metaB.name);
} }
if (intraline) { if (intraline) {
@ -183,6 +203,18 @@ public class GetDiff implements RestReadView<FileResource> {
} }
} }
private List<WebLinkInfo> getFileWebLinks(Project project, String rev,
String file) {
List<WebLinkInfo> fileWebLinks = new ArrayList<>();
for (WebLinkInfo link : webLinks.get().getPatchLinks(project.getName(),
rev, file)) {
if (!Strings.isNullOrEmpty(link.name) && !Strings.isNullOrEmpty(link.url)) {
fileWebLinks.add(link);
}
}
return fileWebLinks;
}
static class Result { static class Result {
FileMeta metaA; FileMeta metaA;
FileMeta metaB; FileMeta metaB;
@ -190,6 +222,8 @@ public class GetDiff implements RestReadView<FileResource> {
ChangeType changeType; ChangeType changeType;
List<String> diffHeader; List<String> diffHeader;
List<ContentEntry> content; List<ContentEntry> content;
List<WebLinkInfo> webLinksA;
List<WebLinkInfo> webLinksB;
} }
static class FileMeta { static class FileMeta {

View File

@ -34,6 +34,7 @@ import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.systemstatus.MessageOfTheDay; import com.google.gerrit.extensions.systemstatus.MessageOfTheDay;
import com.google.gerrit.extensions.webui.BranchWebLink; import com.google.gerrit.extensions.webui.BranchWebLink;
import com.google.gerrit.extensions.webui.PatchSetWebLink; import com.google.gerrit.extensions.webui.PatchSetWebLink;
import com.google.gerrit.extensions.webui.FileWebLink;
import com.google.gerrit.extensions.webui.ProjectWebLink; import com.google.gerrit.extensions.webui.ProjectWebLink;
import com.google.gerrit.extensions.webui.TopMenu; import com.google.gerrit.extensions.webui.TopMenu;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
@ -281,6 +282,7 @@ public class GerritGlobalModule extends FactoryModule {
DynamicMap.mapOf(binder(), DownloadCommand.class); DynamicMap.mapOf(binder(), DownloadCommand.class);
DynamicMap.mapOf(binder(), ProjectConfigEntry.class); DynamicMap.mapOf(binder(), ProjectConfigEntry.class);
DynamicSet.setOf(binder(), PatchSetWebLink.class); DynamicSet.setOf(binder(), PatchSetWebLink.class);
DynamicSet.setOf(binder(), FileWebLink.class);
DynamicSet.setOf(binder(), ProjectWebLink.class); DynamicSet.setOf(binder(), ProjectWebLink.class);
DynamicSet.setOf(binder(), BranchWebLink.class); DynamicSet.setOf(binder(), BranchWebLink.class);