Merge branch 'stable-2.11' * stable-2.11: Add CommitValidationListener example Consume API version 2.11.4 Change-Id: I37fa123d5cf9121050537d7fb31801e8c7767b5c
diff --git a/BUCK b/BUCK index b28f661..f47a479 100644 --- a/BUCK +++ b/BUCK
@@ -19,10 +19,11 @@ java_test( name = 'cookbook_tests', - srcs = glob(['src/test/java/**/*.java']), - deps = [ + srcs = glob(['src/test/java/**/*IT.java']), + labels = ['cookbook-plugin'], + source_under_test = [':cookbook-plugin__plugin'], + deps = GERRIT_PLUGIN_API + GERRIT_TESTS + [ ':cookbook-plugin__plugin', - '//lib:junit', ], )
diff --git a/lib/BUCK b/lib/BUCK new file mode 100644 index 0000000..9c596fa --- /dev/null +++ b/lib/BUCK
@@ -0,0 +1,26 @@ +include_defs('//bucklets/maven_jar.bucklet') + +maven_jar( + name = 'guava', + id = 'com.google.guava:guava:19.0-rc2', + sha1 = '93e17f60bc524c2610b41c494bb829c11ca89436', + license = 'Apache2.0', +) + +maven_jar( + name = 'junit', + id = 'junit:junit:4.11', + sha1 = '4e031bb61df09069aeb2bffb4019e7a5034a4ee0', + license = 'DO_NOT_DISTRIBUTE', +) + +maven_jar( + name = 'truth', + id = 'com.google.truth:truth:0.27', + sha1 = 'bd17774d2dc0fffa884d42c07d2537e86c67acd6', + license = 'DO_NOT_DISTRIBUTE', + exported_deps = [ + ':guava', + ':junit', + ], +)
diff --git a/lib/gerrit/BUCK b/lib/gerrit/BUCK index 8d4790a..968cdb1 100644 --- a/lib/gerrit/BUCK +++ b/lib/gerrit/BUCK
@@ -1,12 +1,19 @@ include_defs('//bucklets/maven_jar.bucklet') -VER = '2.11.4' -REPO = MAVEN_CENTRAL +VER = '2.12-SNAPSHOT' +REPO = MAVEN_LOCAL + +maven_jar( + name = 'acceptance-framework', + id = 'com.google.gerrit:gerrit-acceptance-framework:' + VER, + license = 'Apache2.0', + attach_source = False, + repository = REPO, +) maven_jar( name = 'plugin-api', id = 'com.google.gerrit:gerrit-plugin-api:' + VER, - sha1 = 'c112d2c35250ea3d75c9388a4167cd6b45c7a37c', license = 'Apache2.0', attach_source = False, repository = REPO, @@ -15,7 +22,6 @@ maven_jar( name = 'gwtui-api', id = 'com.google.gerrit:gerrit-plugin-gwtui:' + VER, - sha1 = '67617dd41acd90c2dfa28368871b23ecefca3d08', license = 'Apache2.0', attach_source = False, repository = REPO,
diff --git a/pom.xml b/pom.xml index 0bcd9cf..b7ff1cc 100644 --- a/pom.xml +++ b/pom.xml
@@ -22,7 +22,7 @@ <groupId>com.googlesource.gerrit.plugins</groupId> <artifactId>cookbook-plugin</artifactId> <packaging>jar</packaging> - <version>2.11.4</version> + <version>2.12-SNAPSHOT</version> <properties> <Gerrit-ApiType>plugin</Gerrit-ApiType> <Gerrit-ApiVersion>${project.version}</Gerrit-ApiVersion>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/Greetings.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/Greetings.java index 58a9017..f53b066 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/Greetings.java +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/Greetings.java
@@ -17,17 +17,12 @@ import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.RestReadView; import com.google.gerrit.server.change.RevisionResource; -import com.google.inject.Inject; import java.util.ArrayList; import java.util.Collection; class Greetings implements RestReadView<RevisionResource> { - @Inject - Greetings() { - } - @Override public Response<Collection<GreetInfo>> apply(RevisionResource rev) { Collection<GreetInfo> l = new ArrayList<>(3); @@ -40,7 +35,7 @@ return Response.ok(l); } - class GreetInfo { + static class GreetInfo { String message; String country; String href;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWeblink.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWeblink.java index 248dad3..48829c5 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWeblink.java +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWeblink.java
@@ -16,10 +16,12 @@ import com.google.gerrit.extensions.common.WebLinkInfo; import com.google.gerrit.extensions.webui.BranchWebLink; +import com.google.gerrit.extensions.webui.FileHistoryWebLink; import com.google.gerrit.extensions.webui.PatchSetWebLink; import com.google.gerrit.extensions.webui.ProjectWebLink; -public class HelloWeblink implements PatchSetWebLink, ProjectWebLink, BranchWebLink { +public class HelloWeblink implements PatchSetWebLink, ProjectWebLink, + BranchWebLink, FileHistoryWebLink { private String name = "HelloLink"; private String placeHolderUrlProject = "http://my.hellolink.com/project=%s"; @@ -27,6 +29,8 @@ "http://my.hellolink.com/project=%s-branch=%s"; private String placeHolderUrlProjectCommit = placeHolderUrlProject + "/commit=%s"; + private String placeHolderUrlProjectRevisionFileName = + placeHolderUrlProject + "-revision=%s-file=%s"; private String myImageUrl = "http://placehold.it/16x16.gif"; @Override @@ -52,4 +56,14 @@ String.format(placeHolderUrlProjectCommit, projectName, commit), Target.BLANK); } + + @Override + public WebLinkInfo getFileHistoryWebLink(String projectName, String revision, + String fileName) { + return new WebLinkInfo(name, + myImageUrl, + String.format(placeHolderUrlProjectRevisionFileName, projectName, + revision, fileName), + Target.BLANK); + } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWorldServlet.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWorldServlet.java index d2c3935..b1493c2 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWorldServlet.java +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWorldServlet.java
@@ -46,12 +46,12 @@ final HttpServletResponse rsp) throws IOException, ServletException { rsp.setContentType("text/html"); rsp.setCharacterEncoding("UTF-8"); - final Writer out = rsp.getWriter(); - out.write("<html>"); - out.write("<body>"); - out.write("<h2>Hello world!</h2>"); - out.write("</body>"); - out.write("</html>"); - out.close(); + try (Writer out = rsp.getWriter()) { + out.write("<html>"); + out.write("<body>"); + out.write("<h2>Hello world!</h2>"); + out.write("</body>"); + out.write("</html>"); + } } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java index 814c295..b182159 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java
@@ -25,6 +25,7 @@ import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.restapi.RestApiModule; import com.google.gerrit.extensions.webui.BranchWebLink; +import com.google.gerrit.extensions.webui.FileHistoryWebLink; import com.google.gerrit.extensions.webui.PatchSetWebLink; import com.google.gerrit.extensions.webui.ProjectWebLink; import com.google.gerrit.extensions.webui.TopMenu; @@ -47,6 +48,7 @@ DynamicSet.bind(binder(), PatchSetWebLink.class).to(HelloWeblink.class); DynamicSet.bind(binder(), ProjectWebLink.class).to(HelloWeblink.class); DynamicSet.bind(binder(), BranchWebLink.class).to(HelloWeblink.class); + DynamicSet.bind(binder(), FileHistoryWebLink.class).to(HelloWeblink.class); DynamicSet.bind(binder(), ServerPluginProvider.class).to( HelloSshPluginProvider.class); DynamicSet.bind(binder(), UsageDataPublishedListener.class).to(UsageDataLogger.class); @@ -65,6 +67,8 @@ .to(MergeUserValidator.class); DynamicSet.bind(binder(), HashtagValidationListener.class) .to(HashtagValidator.class); + DynamicSet.bind(binder(), CommitValidationListener.class) + .to(CommitValidator.class); DynamicSet.bind(binder(), NewProjectCreatedListener.class) .to(ProjectCreatedListener.class); DynamicSet.bind(binder(), CommitValidationListener.class)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/BuildsDropDownPanel.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/BuildsDropDownPanel.java new file mode 100644 index 0000000..86b7034 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/BuildsDropDownPanel.java
@@ -0,0 +1,74 @@ +// 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.googlesource.gerrit.plugins.cookbook.client; + +import com.google.gerrit.plugin.client.extension.Panel; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.Image; +import com.google.gwt.user.client.ui.InlineHyperlink; +import com.google.gwt.user.client.ui.InlineLabel; + +/** + * Extension for change screen that displays a status in the header bar. + */ +public class BuildsDropDownPanel extends FlowPanel { + static class Factory implements Panel.EntryPoint { + @Override + public void onLoad(Panel panel) { + panel.setWidget(new BuildsDropDownPanel()); + } + } + + BuildsDropDownPanel() { + Grid g = new Grid(3, 4); + g.addStyleName("infoBlock"); + CellFormatter fmt = g.getCellFormatter(); + + g.setText(0, 0, "State"); + fmt.addStyleName(0, 0, "header"); + g.setText(0, 1, "PS"); + fmt.addStyleName(0, 1, "header"); + g.setText(0, 2, "Date"); + fmt.addStyleName(0, 2, "header"); + g.setText(0, 3, "Log"); + fmt.addStyleName(0, 3, "header"); + + HorizontalPanel p = new HorizontalPanel(); + p.add(new Image(CookBookPlugin.RESOURCES.greenCheck())); + p.add(new InlineLabel("OK")); + g.setWidget(1, 0, p); + g.setWidget(1, 1, new InlineLabel("2")); + g.setWidget(1, 2, new InlineLabel("2015-07-09 11:06:13")); + g.setWidget(1, 3, new InlineHyperlink("Build Log", "TODO")); + + p = new HorizontalPanel(); + p.add(new Image(CookBookPlugin.RESOURCES.redNot())); + p.add(new InlineLabel("FAILED")); + g.setWidget(2, 0, p); + g.setWidget(2, 1, new InlineLabel("1")); + g.setWidget(2, 2, new InlineLabel("2015-07-09 09:17:28")); + g.setWidget(2, 3, new InlineHyperlink("Build Log", "TODO")); + + fmt.addStyleName(0, 0, "topmost"); + fmt.addStyleName(0, 1, "topmost"); + fmt.addStyleName(0, 2, "topmost"); + fmt.addStyleName(0, 3, "topmost"); + + add(new PopDownButton("Builds", g)); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/ChangeScreenPreferencePanel.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/ChangeScreenPreferencePanel.java new file mode 100644 index 0000000..b610f87 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/ChangeScreenPreferencePanel.java
@@ -0,0 +1,154 @@ +// 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.googlesource.gerrit.plugins.cookbook.client; + +import com.google.gerrit.client.info.AccountPreferencesInfo; +import com.google.gerrit.plugin.client.Plugin; +import com.google.gerrit.plugin.client.extension.Panel; +import com.google.gerrit.plugin.client.rpc.RestApi; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.VerticalPanel; + +import java.util.Map; + +public class ChangeScreenPreferencePanel extends VerticalPanel { + private static final String DEFAULT = "DEFAULT"; + private static final String COOKBOOK = "COOKBOOK"; + private static final String OTHER = "OTHER"; + private static final String DEFAULT_URL_MATCH = "/c/(.*)"; + private static final String COOKBOOK_URL_TOKEN = + "/x/" + Plugin.get().getName() + "/c/$1"; + + static class Factory implements Panel.EntryPoint { + @Override + public void onLoad(Panel panel) { + panel.setWidget(new ChangeScreenPreferencePanel()); + } + } + + private Label savedLabel; + private Timer hideTimer; + + ChangeScreenPreferencePanel() { + new RestApi("accounts").id("self").view("preferences") + .get(new AsyncCallback<AccountPreferencesInfo>() { + @Override + public void onSuccess(AccountPreferencesInfo result) { + display(result); + } + + @Override + public void onFailure(Throwable caught) { + // never invoked + } + }); + } + + private void display(final AccountPreferencesInfo info) { + Label heading = new Label(Plugin.get().getName() + " plugin"); + heading.setStyleName("smallHeading"); + add(heading); + HorizontalPanel p = new HorizontalPanel(); + add(p); + + Label label = new Label("Change Screen:"); + p.add(label); + label.getElement().getStyle().setMarginRight(5, Unit.PX); + label.getElement().getStyle().setMarginTop(2, Unit.PX); + final ListBox box = new ListBox(); + p.add(box); + savedLabel = new Label("Saved"); + savedLabel.getElement().getStyle().setMarginLeft(5, Unit.PX); + savedLabel.getElement().getStyle().setMarginTop(2, Unit.PX); + savedLabel.setVisible(false); + p.add(savedLabel); + + box.addItem(DEFAULT, DEFAULT); + box.addItem(COOKBOOK, COOKBOOK); + + String selected = DEFAULT; + if (info.urlAliases().containsKey(DEFAULT_URL_MATCH)) { + String token = info.urlAliases().get(DEFAULT_URL_MATCH); + if (token.equals(COOKBOOK_URL_TOKEN)) { + selected = COOKBOOK; + } else if (!token.equals(DEFAULT_URL_MATCH)) { + box.addItem(OTHER, OTHER); + selected = OTHER; + } + } + + for (int i = 0; i < box.getItemCount(); i++) { + if (selected.equals(box.getValue(i))) { + box.setSelectedIndex(i); + break; + } + } + + box.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + savedLabel.setVisible(false); + if (box.getSelectedValue().equals(OTHER)) { + return; + } + + Map<String, String> urlAliases = info.urlAliases(); + if (box.getSelectedValue().equals(COOKBOOK)) { + urlAliases.put(DEFAULT_URL_MATCH, COOKBOOK_URL_TOKEN); + } else { + urlAliases.remove(DEFAULT_URL_MATCH); + } + info.setUrlAliases(urlAliases); + + new RestApi("accounts").id("self").view("preferences") + .put(info, new AsyncCallback<AccountPreferencesInfo>() { + @Override + public void onSuccess(AccountPreferencesInfo result) { + Plugin.get().refreshUserPreferences(); + showSavedStatus(); + } + + @Override + public void onFailure(Throwable caught) { + // never invoked + } + }); + } + }); + } + + private void showSavedStatus() { + if (hideTimer != null) { + hideTimer.cancel(); + hideTimer = null; + } + savedLabel.setVisible(true); + hideTimer = new Timer() { + @Override + public void run() { + savedLabel.setVisible(false); + hideTimer = null; + } + }; + hideTimer.schedule(1000); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/ChangeScreenStatusExtension.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/ChangeScreenStatusExtension.java new file mode 100644 index 0000000..e0ceeed --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/ChangeScreenStatusExtension.java
@@ -0,0 +1,39 @@ +// 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.googlesource.gerrit.plugins.cookbook.client; + +import com.google.gerrit.plugin.client.extension.Panel; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Image; +import com.google.gwt.user.client.ui.InlineLabel; + +/** + * Extension for change screen that displays a status in the header bar. + */ +public class ChangeScreenStatusExtension extends FlowPanel { + static class Factory implements Panel.EntryPoint { + @Override + public void onLoad(Panel panel) { + panel.setWidget(new ChangeScreenStatusExtension()); + } + } + + ChangeScreenStatusExtension() { + getElement().getStyle().setPadding(5, Unit.PX); + add(new Image(CookBookPlugin.RESOURCES.greenCheck())); + add(new InlineLabel("OK")); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookChangeScreen.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookChangeScreen.java new file mode 100644 index 0000000..9a9bf86 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookChangeScreen.java
@@ -0,0 +1,34 @@ +// 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.googlesource.gerrit.plugins.cookbook.client; + +import com.google.gerrit.plugin.client.screen.Screen; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.VerticalPanel; + +class CookBookChangeScreen extends VerticalPanel { + static class Factory implements Screen.EntryPoint { + @Override + public void onLoad(Screen screen) { + screen.setPageTitle("CookBook Change Screen"); + screen.show(new CookBookChangeScreen()); + } + } + + CookBookChangeScreen() { + setStyleName("cookbook-panel"); + add(new Label("TODO: implement this screen")); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookChangeScreenExtension.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookChangeScreenExtension.java new file mode 100644 index 0000000..d5d6e8a --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookChangeScreenExtension.java
@@ -0,0 +1,54 @@ +// 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.googlesource.gerrit.plugins.cookbook.client; + +import com.google.gerrit.client.GerritUiExtensionPoint; +import com.google.gerrit.client.info.ChangeInfo; +import com.google.gerrit.plugin.client.extension.Panel; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwtexpui.clippy.client.CopyableLabel; + +/** + * Extension for change screen that displays the numeric change ID with + * copy-to-clipboard icon. + */ +public class CookBookChangeScreenExtension extends VerticalPanel { + static class Factory implements Panel.EntryPoint { + @Override + public void onLoad(Panel panel) { + panel.setWidget(new CookBookChangeScreenExtension(panel)); + } + } + + CookBookChangeScreenExtension(Panel panel) { + ChangeInfo change = + panel.getObject(GerritUiExtensionPoint.Key.CHANGE_INFO).cast(); + + Grid g = new Grid(1, 2); + g.addStyleName("infoBlock"); + CellFormatter fmt = g.getCellFormatter(); + + g.setText(0, 0, "Numeric Change ID"); + fmt.addStyleName(0, 0, "header"); + g.setWidget(0, 1, new CopyableLabel(Integer.toString(change._number()))); + add(g); + + fmt.addStyleName(0, 0, "topmost"); + fmt.addStyleName(0, 1, "topmost"); + fmt.addStyleName(0, 0, "bottomheader"); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookPlugin.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookPlugin.java index e9ace38..c51ec3c 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookPlugin.java +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookPlugin.java
@@ -14,12 +14,53 @@ package com.googlesource.gerrit.plugins.cookbook.client; +import com.google.gerrit.client.GerritUiExtensionPoint; +import com.google.gerrit.client.Resources; import com.google.gerrit.plugin.client.Plugin; import com.google.gerrit.plugin.client.PluginEntryPoint; +import com.google.gerrit.plugin.client.extension.Panel; +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Button; public class CookBookPlugin extends PluginEntryPoint { + public static final Resources RESOURCES = GWT.create(Resources.class); + @Override public void onPluginLoad() { Plugin.get().screen("", new IndexScreen.Factory()); + Plugin.get().screenRegex("c/(.*)", new CookBookChangeScreen.Factory()); + Plugin.get().settingsScreen("preferences", "Food Preferences", + new FoodPreferencesScreen.Factory()); + Plugin.get().panel( + GerritUiExtensionPoint.PREFERENCES_SCREEN_BOTTOM, + new ChangeScreenPreferencePanel.Factory()); + Plugin.get().panel(GerritUiExtensionPoint.PROFILE_SCREEN_BOTTOM, + new CookBookProfileExtension.Factory()); + Plugin.get().panel( + GerritUiExtensionPoint.CHANGE_SCREEN_BELOW_CHANGE_INFO_BLOCK, + new CookBookChangeScreenExtension.Factory()); + Plugin.get().panel(GerritUiExtensionPoint.CHANGE_SCREEN_HEADER, + new ChangeScreenStatusExtension.Factory()); + Plugin.get().panel( + GerritUiExtensionPoint.CHANGE_SCREEN_HEADER_RIGHT_OF_POP_DOWNS, + new BuildsDropDownPanel.Factory()); + Plugin.get().panel( + GerritUiExtensionPoint.CHANGE_SCREEN_HEADER_RIGHT_OF_BUTTONS, + new Panel.EntryPoint() { + @Override + public void onLoad(Panel panel) { + Button b = new HighlightButton("Library-Compliance+1"); + b.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + Window.alert("TODO"); + } + }); + panel.setWidget(b); + } + }); } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookProfileExtension.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookProfileExtension.java new file mode 100644 index 0000000..e50427a --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookProfileExtension.java
@@ -0,0 +1,65 @@ +// 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.googlesource.gerrit.plugins.cookbook.client; + +import com.google.gerrit.client.GerritUiExtensionPoint; +import com.google.gerrit.client.info.AccountInfo; +import com.google.gerrit.plugin.client.extension.Panel; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; +import com.google.gwt.user.client.ui.VerticalPanel; + +/** + * Extension for the user profile screen. + */ +public class CookBookProfileExtension extends VerticalPanel { + static class Factory implements Panel.EntryPoint { + @Override + public void onLoad(Panel panel) { + AccountInfo accountInfo = + panel.getObject(GerritUiExtensionPoint.Key.ACCOUNT_INFO).cast(); + panel.setWidget(new CookBookProfileExtension(accountInfo)); + } + } + + CookBookProfileExtension(AccountInfo accountInfo) { + Grid g = new Grid(3, 2); + g.addStyleName("infoBlock"); + g.addStyleName("accountInfoBlock"); + CellFormatter fmt = g.getCellFormatter(); + + // TODO: fetch employer and department via REST from server, + // e.g. GET /accounts/self/cookbook~info + + g.setText(0, 0, "Employer"); + fmt.addStyleName(0, 0, "header"); + g.setText(0, 1, "CookBook Corporation"); + + g.setText(1, 0, "Department"); + fmt.addStyleName(1, 0, "header"); + g.setText(1, 1, "Cookies " + accountInfo.email()); + + g.setText(2, 0, "CookBook Email"); + fmt.addStyleName(2, 0, "header"); + g.setText(2, 1, accountInfo.username() != null + ? accountInfo.username() + "@cookbook.com" + : "N/A"); + add(g); + + fmt.addStyleName(0, 0, "topmost"); + fmt.addStyleName(0, 1, "topmost"); + fmt.addStyleName(2, 0, "bottomheader"); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/FoodPreferencesScreen.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/FoodPreferencesScreen.java new file mode 100644 index 0000000..6ba46fd --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/FoodPreferencesScreen.java
@@ -0,0 +1,67 @@ +// 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.googlesource.gerrit.plugins.cookbook.client; + +import com.google.gerrit.plugin.client.screen.Screen; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.KeyPressEvent; +import com.google.gwt.event.dom.client.KeyPressHandler; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.Panel; +import com.google.gwt.user.client.ui.TextArea; +import com.google.gwt.user.client.ui.VerticalPanel; + +class FoodPreferencesScreen extends VerticalPanel { + static class Factory implements Screen.EntryPoint { + @Override + public void onLoad(Screen screen) { + screen.setPageTitle("Settings"); + screen.show(new FoodPreferencesScreen()); + } + } + + FoodPreferencesScreen() { + setStyleName("cookbook-panel"); + + Panel messagePanel = new VerticalPanel(); + messagePanel.add(new Label("Food Allergies or Dietary Concerns:")); + TextArea txt = new TextArea(); + txt.addKeyPressHandler(new KeyPressHandler() { + @Override + public void onKeyPress(final KeyPressEvent event) { + event.stopPropagation(); + } + }); + txt.setVisibleLines(12); + txt.setCharacterWidth(80); + txt.getElement().setPropertyBoolean("spellcheck", false); + messagePanel.add(txt); + add(messagePanel); + + Button helloButton = new Button("Save"); + helloButton.addStyleName("cookbook-helloButton"); + helloButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(final ClickEvent event) { + Window.alert("TODO: implement save"); + } + }); + add(helloButton); + helloButton.setEnabled(true); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/HighlightButton.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/HighlightButton.java new file mode 100644 index 0000000..0af633f --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/HighlightButton.java
@@ -0,0 +1,36 @@ +// 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.googlesource.gerrit.plugins.cookbook.client; + +import com.google.gwt.user.client.ui.Button; +import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; + +/** + * Highlight button for header line in change screen. + * + * This class can *only* be used within a panel that extends the header line of + * the change screen, but will not work standalone. + */ +public class HighlightButton extends Button { + + public HighlightButton(String text) { + // Create Button with inner div. This is required to get proper styling + // in the context of the change screen. + super((new SafeHtmlBuilder()).openDiv() + .appendAttribute("style", "color: #fff;").append(text).closeDiv()); + getElement().removeClassName("gwt-Button"); + getElement().getStyle().setBackgroundColor("#4d90fe"); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/IndexScreen.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/IndexScreen.java index 0edf949..774ec3d 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/IndexScreen.java +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/IndexScreen.java
@@ -14,9 +14,7 @@ package com.googlesource.gerrit.plugins.cookbook.client; -import com.google.gerrit.client.Resources; import com.google.gerrit.plugin.client.screen.Screen; -import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.event.dom.client.ClickEvent; @@ -45,14 +43,13 @@ private TextBox usernameTxt; private TextArea greetingTxt; - private Resources RESOURCES = GWT.create(Resources.class); IndexScreen() { setStyleName("cookbook-panel"); Panel labelImagePanel = new HorizontalPanel(); Panel usernamePanel = new VerticalPanel(); - Image img = new Image(RESOURCES.info()); + Image img = new Image(CookBookPlugin.RESOURCES.info()); img.setTitle("User to send greetings to"); labelImagePanel.add(new Label("Username")); labelImagePanel.add(img);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/PopDownButton.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/PopDownButton.java new file mode 100644 index 0000000..3cbe5d6 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/PopDownButton.java
@@ -0,0 +1,101 @@ +// 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.googlesource.gerrit.plugins.cookbook.client; + +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.FontWeight; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.logical.shared.CloseEvent; +import com.google.gwt.event.logical.shared.CloseHandler; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.PopupPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwtexpui.globalkey.client.GlobalKey; +import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; + +/** + * Pop down button for header line in change screen. + * + * This class implements a button that on click opens a pop down panel with the + * provided widget, similar to the "Patch Sets", "Download" or "Included In" pop + * down panels on the change screen. + * + * This class can *only* be used within a panel that extends the header line of + * the change screen, but will not work standalone. + */ +public class PopDownButton extends Button { + private final Widget widget; + private PopupPanel popup; + + public PopDownButton(String text, Widget widget) { + // Create Button with inner div. This is required to get proper styling + // in the context of the change screen. + super((new SafeHtmlBuilder()).openDiv().append(text).closeDiv()); + getElement().removeClassName("gwt-Button"); + addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + show(); + } + }); + this.widget = widget; + } + + private void show() { + if (popup != null) { + getElement().getStyle().clearFontWeight(); + popup.hide(); + return; + } + + final Widget relativeTo = getParent(); + final PopupPanel p = new PopupPanel(true) { + @Override + public void setPopupPosition(int left, int top) { + top -= Document.get().getBodyOffsetTop(); + + int w = Window.getScrollLeft() + Window.getClientWidth(); + int r = relativeTo.getAbsoluteLeft() + relativeTo.getOffsetWidth(); + int right = w - r; + Style style = getElement().getStyle(); + style.clearProperty("left"); + style.setPropertyPx("right", right); + style.setPropertyPx("top", top); + } + }; + Style popupStyle = p.getElement().getStyle(); + popupStyle.setBorderWidth(0, Unit.PX); + popupStyle.setBackgroundColor("#EEEEEE"); + p.addAutoHidePartner(getElement()); + p.addCloseHandler(new CloseHandler<PopupPanel>() { + @Override + public void onClose(CloseEvent<PopupPanel> event) { + if (popup == p) { + getElement().getStyle().clearFontWeight(); + popup = null; + } + } + }); + p.add(widget); + p.showRelativeTo(relativeTo); + GlobalKey.dialog(p); + getElement().getStyle().setFontWeight(FontWeight.BOLD); + popup = p; + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshCommand.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshCommand.java index b1da6de..853d04d 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshCommand.java +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshCommand.java
@@ -14,39 +14,64 @@ package com.googlesource.gerrit.plugins.cookbook.pluginprovider; +import com.google.gerrit.extensions.annotations.PluginData; import com.google.gerrit.extensions.annotations.PluginName; import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.sshd.CommandMetaData; import com.google.gerrit.sshd.SshCommand; import com.google.inject.Inject; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; +import org.kohsuke.args4j.Argument; -/** - * SSH command defined by dynamically registered plugins. - * - */ -@CommandMetaData(name = "print", description = "Print content of the plugin file") +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/** SSH command defined by dynamically registered plugins. */ +@CommandMetaData(name = "cat", description = "Print content of plugin file") public final class HelloSshCommand extends SshCommand { private final String pluginName; - private final File pluginDir; + private final Path pluginDir; + private final Path dataDir; + + @Argument(usage = "files in data directory to print") + private List<String> files = new ArrayList<>(); @Inject - public HelloSshCommand(@PluginName String pluginName, SitePaths sitePaths) { + public HelloSshCommand(@PluginName String pluginName, + SitePaths sitePaths, + @PluginData Path dataDir) { this.pluginName = pluginName; - this.pluginDir = sitePaths.plugins_dir; + this.pluginDir = sitePaths.plugins_dir.normalize(); + this.dataDir = dataDir.normalize(); } @Override public void run() { - File pluginFile = new File(pluginDir, pluginName + ".ssh"); + Path pluginPath = pluginDir.resolve(pluginName + ".ssh"); + printOne(pluginPath); + for (String name : files) { + Path p = dataDir.resolve(name).normalize(); + if (!p.startsWith(dataDir)) { + throw new RuntimeException(p + " is outside data directory " + dataDir); + } + printOne(p); + } + } + + private void printOne(Path p) { try { - Files.copy(pluginFile.toPath(), out); + Files.copy(p, out); } catch (IOException e) { - throw new RuntimeException("Cannot read plugin content of " + pluginFile, - e); + try (PrintWriter w = new PrintWriter(err)) { + w.write("Error reading contents of "); + w.write(p.toAbsolutePath().toString()); + w.write(": \n"); + e.printStackTrace(w); + } } } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshPluginProvider.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshPluginProvider.java index a7d7268..8ffd8c2 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshPluginProvider.java +++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshPluginProvider.java
@@ -22,19 +22,25 @@ import org.eclipse.jgit.internal.storage.file.FileSnapshot; -import java.io.File; +import java.nio.file.Path; /** - * Dynamic provider of Gerrit plugins derived by *.ssh files under $GERRIT_SITE/plugins. - * + * Dynamic provider of Gerrit plugins derived by *.ssh files under + * $GERRIT_SITE/plugins. + * <p> * Example of how to define a dynamic Gerrit plugin provider to register * a new plugin based on the content of *.ssh files. - * + * <p> * This provider allows to define a Gerrit plugin by simply dropping a .ssh file * (e.g. hello.ssh) under $GERRIT_SITE/plugins. + * <p> * Once the file is created a new plugin is automatically loaded with the name - * without extension of the .ssh file (e.g. hello) and a new 'cat' SSH command is - * automatically available from the registered plugin. + * without extension of the .ssh file (e.g. hello) and a new 'cat' SSH command + * is automatically available from the registered plugin. + * <p> + * The 'cat' command will print the contents of the .ssh file, along with the + * contents of any arguments, resolved against the plugin's data directory + * $GERRIT_SITE/data/name. */ public class HelloSshPluginProvider implements ServerPluginProvider { private static final String SSH_EXT = ".ssh"; @@ -46,22 +52,22 @@ } @Override - public boolean handles(File srcFile) { - return srcFile.getName().endsWith(SSH_EXT); + public boolean handles(Path srcPath) { + return srcPath.getFileName().toString().endsWith(SSH_EXT); } @Override - public String getPluginName(File srcFile) { - String srcFileName = srcFile.getName(); - return srcFileName.substring(0, srcFileName.length() - SSH_EXT.length()); + public String getPluginName(Path srcPath) { + String name = srcPath.getFileName().toString(); + return name.substring(0, name.length() - SSH_EXT.length()); } @Override - public ServerPlugin get(File srcFile, FileSnapshot snapshot, + public ServerPlugin get(Path srcPath, FileSnapshot snapshot, PluginDescription pluginDescriptor) throws InvalidPluginException { - String name = getPluginName(srcFile); + String name = getPluginName(srcPath); return new ServerPlugin(name, pluginDescriptor.canonicalUrl, - pluginDescriptor.user, srcFile, snapshot, + pluginDescriptor.user, srcPath, snapshot, new HelloSshPluginContentScanner(name), pluginDescriptor.dataDir, getClass().getClassLoader()); }
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md index 0fc79fc..2379943 100644 --- a/src/main/resources/Documentation/build.md +++ b/src/main/resources/Documentation/build.md
@@ -30,7 +30,6 @@ To build the plugin, issue the following command: - ``` buck build plugin ``` @@ -41,6 +40,12 @@ buck-out/gen/cookbook-plugin/cookbook-plugin.jar ``` +To execute the tests run: + +``` + buck test +``` + Build in Gerrit tree -------------------- @@ -63,6 +68,12 @@ ./tools/eclipse/project.py ``` +To execute the tests run: + +``` + buck test --include cookbook-plugin +``` + Note that for compatibility reasons a Maven build is provided, but is considered to be deprecated and will be removed in a future version of this plugin.
diff --git a/src/test/java/com/googlesource/gerrit/plugins/cookbook/CookbookIT.java b/src/test/java/com/googlesource/gerrit/plugins/cookbook/CookbookIT.java new file mode 100644 index 0000000..4c5bf0e --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/cookbook/CookbookIT.java
@@ -0,0 +1,32 @@ +// 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.googlesource.gerrit.plugins.cookbook; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.gerrit.acceptance.NoHttpd; +import com.google.gerrit.acceptance.PluginDaemonTest; + +import org.junit.Test; + +@NoHttpd +public class CookbookIT extends PluginDaemonTest { + + @Test + public void printTest() throws Exception { + assertThat(sshSession.exec("cookbook print")).isEqualTo("Hello world!\n"); + assertThat(sshSession.hasError()).isFalse(); + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/cookbook/CookbookTest.java b/src/test/java/com/googlesource/gerrit/plugins/cookbook/CookbookTest.java deleted file mode 100644 index d6376ae..0000000 --- a/src/test/java/com/googlesource/gerrit/plugins/cookbook/CookbookTest.java +++ /dev/null
@@ -1,28 +0,0 @@ -// 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.googlesource.gerrit.plugins.cookbook; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -public class CookbookTest { - @Test - public void cookbookTest() { - // Dummy test, only used to make sure the cookbook plugin gets compiled - // when running `buck test`, thus highlighting any compilation errors. - assertTrue(true); - } -}