Add basic PolyGerrit UI This basic variant of the UI shows the CRDs and provides links. But it does not yet color them red if cycles are detected. Depends-On: I783a00df00d386292ac458e925079219bb6392c7 Change-Id: I019d3b35de2933abecb5caef0613a02904c8eb68
diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/.eslintignore
diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..6d9ae7c --- /dev/null +++ b/.eslintrc.json
@@ -0,0 +1,166 @@ +{ + "extends": ["eslint:recommended", "google"], + "parserOptions": { + "ecmaVersion": 8, + "sourceType": "module" + }, + "env": { + "browser": true, + "es6": true + }, + "globals": { + "__dirname": false, + "app": false, + "page": false, + "Polymer": false, + "process": false, + "require": false, + "Gerrit": false, + "Promise": false, + "assert": false, + "test": false, + "flushAsynchronousOperations": false + }, + "rules": { + "arrow-parens": ["error", "as-needed"], + "block-spacing": ["error", "always"], + "brace-style": ["error", "1tbs", { "allowSingleLine": true }], + "camelcase": "off", + "comma-dangle": ["error", { + "arrays": "always-multiline", + "objects": "always-multiline", + "imports": "always-multiline", + "exports": "always-multiline", + "functions": "never" + }], + "eol-last": "off", + "indent": ["error", 2, { + "MemberExpression": 2, + "FunctionDeclaration": {"body": 1, "parameters": 2}, + "FunctionExpression": {"body": 1, "parameters": 2}, + "CallExpression": {"arguments": 2 }, + "ArrayExpression": 1, + "ObjectExpression": 1, + "SwitchCase": 1 + }], + "keyword-spacing": ["error", { "after": true, "before": true }], + "lines-between-class-members": ["error", "always"], + "max-len": [ + "error", + 80, + 2, + { + "ignoreComments": true, + "ignorePattern": "^import .*;$" + } + ], + "new-cap": ["error", { "capIsNewExceptions": ["Polymer", "LegacyElementMixin", "GestureEventListeners", "LegacyDataMixin"] }], + "no-console": "off", + "no-multiple-empty-lines": [ "error", { "max": 1 } ], + "no-prototype-builtins": "off", + "no-redeclare": "off", + "no-restricted-syntax": [ + "error", + { + "selector": "ExpressionStatement > CallExpression > MemberExpression[object.name='test'][property.name='only']", + "message": "Remove test.only." + }, + { + "selector": "ExpressionStatement > CallExpression > MemberExpression[object.name='suite'][property.name='only']", + "message": "Remove suite.only." + } + ], + "no-undef": "off", + "no-useless-escape": "off", + "no-var": "error", + "object-shorthand": ["error", "always"], + "padding-line-between-statements": [ + "error", + { + "blankLine": "always", + "prev": "class", + "next": "*" + }, + { + "blankLine": "always", + "prev": "*", + "next": "class" + } + ], + "prefer-arrow-callback": "error", + "prefer-const": "error", + "prefer-spread": "error", + "quote-props": ["error", "consistent-as-needed"], + "semi": [2, "always"], + "template-curly-spacing": "error", + "valid-jsdoc": "off", + + "require-jsdoc": 0, + "valid-jsdoc": 0, + "jsdoc/check-alignment": 2, + "jsdoc/check-examples": 0, + "jsdoc/check-indentation": 0, + "jsdoc/check-param-names": 0, + "jsdoc/check-syntax": 0, + "jsdoc/check-tag-names": 0, + "jsdoc/check-types": 0, + "jsdoc/implements-on-classes": 2, + "jsdoc/match-description": 0, + "jsdoc/newline-after-description": 2, + "jsdoc/no-types": 0, + "jsdoc/no-undefined-types": 0, + "jsdoc/require-description": 0, + "jsdoc/require-description-complete-sentence": 0, + "jsdoc/require-example": 0, + "jsdoc/require-hyphen-before-param-description": 0, + "jsdoc/require-jsdoc": 0, + "jsdoc/require-param": 0, + "jsdoc/require-param-description": 0, + "jsdoc/require-param-name": 2, + "jsdoc/require-param-type": 2, + "jsdoc/require-returns": 0, + "jsdoc/require-returns-check": 0, + "jsdoc/require-returns-description": 0, + "jsdoc/require-returns-type": 2, + "jsdoc/valid-types": 2, + "jsdoc/require-file-overview": ["error", { + "tags": { + "license": { + "mustExist": true, + "preventDuplicates": true + } + } + }], + "import/named": 2, + "import/no-unresolved": 2, + "import/no-self-import": 2, + // The no-cycle rule is slow, because it doesn't cache dependencies. + // Disable it. + "import/no-cycle": 0, + "import/no-useless-path-segments": 2, + "import/no-unused-modules": 2, + "import/no-default-export": 2 + }, + "plugins": [ + "html", + "jsdoc", + "import" + ], + "settings": { + "html/report-bad-indent": "error" + }, + "overrides": [ + { + "files": ["*_html.js", "*-styles.js", "externs.js"], + "rules": { + "max-len": "off" + } + }, + { + "files": ["*.html"], + "rules": { + "jsdoc/require-file-overview": "off" + } + } + ] +}
diff --git a/BUILD b/BUILD index 5368f19..5f1c689 100644 --- a/BUILD +++ b/BUILD
@@ -1,11 +1,15 @@ load("@rules_java//java:defs.bzl", "java_library") +load("@npm_bazel_rollup//:index.bzl", "rollup_bundle") load("//tools/bzl:junit.bzl", "junit_tests") +load("//tools/js:eslint.bzl", "eslint") load( "//tools/bzl:plugin.bzl", "PLUGIN_DEPS", "PLUGIN_TEST_DEPS", "gerrit_plugin", ) +load("//tools/bzl:genrule2.bzl", "genrule2") +load("//tools/bzl:js.bzl", "polygerrit_plugin") gerrit_plugin( name = "zuul", @@ -14,7 +18,9 @@ manifest_entries = [ "Gerrit-PluginName: zuul", "Gerrit-Module: com.googlesource.gerrit.plugins.zuul.Module", + "Gerrit-HttpModule: com.googlesource.gerrit.plugins.zuul.HttpModule", ], + resource_jars = [":gr-zuul-static"], ) junit_tests( @@ -36,3 +42,54 @@ ], ) +genrule2( + name = "gr-zuul-static", + srcs = [":gr-zuul"], + outs = ["gr-zuul-static.jar"], + cmd = " && ".join([ + "mkdir $$TMP/static", + "cp $(locations :gr-zuul) $$TMP/static", + "cd $$TMP", + "zip -Drq $$ROOT/$@ -g .", + ]), +) + +polygerrit_plugin( + name = "gr-zuul", + app = "zuul-bundle.js", + plugin_name = "zuul", +) + +rollup_bundle( + name = "zuul-bundle", + srcs = glob(["gr-zuul/*.js"]), + entry_point = "gr-zuul/plugin.js", + rollup_bin = "//tools/node_tools:rollup-bin", + sourcemap = "hidden", + format = "iife", + deps = [ + "@tools_npm//rollup-plugin-node-resolve", + ], +) + +# Define the eslinter for the plugin +# The eslint macro creates 2 rules: lint_test and lint_bin +eslint( + name = "lint", + srcs = glob([ + "gr-zuul/**/*.js", + ]), + config = ".eslintrc.json", + data = [], + extensions = [ + ".js", + ], + ignore = ".eslintignore", + plugins = [ + "@npm//eslint-config-google", + "@npm//eslint-plugin-html", + "@npm//eslint-plugin-import", + "@npm//eslint-plugin-jsdoc", + ], +) +
diff --git a/gr-zuul/gr-zuul.js b/gr-zuul/gr-zuul.js new file mode 100644 index 0000000..9bcd761 --- /dev/null +++ b/gr-zuul/gr-zuul.js
@@ -0,0 +1,58 @@ +/** + * @license + * Copyright (C) 2020 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. + */ + +import {htmlTemplate} from './gr-zuul_html.js'; + +class GrZuul extends Polymer.Element { + /** @returns {string} name of the component */ + static get is() { return 'gr-zuul'; } + + /** @returns {?} template for this component */ + static get template() { return htmlTemplate; } + + static get properties() { + return { + change: { + type: Object, + observer: '_onChangeChanged', + }, + _crd: { + type: Object, + value: {}, + }, + _crd_loaded: { + type: Boolean, + value: false, + }, + }; + } + + _onChangeChanged() { + this._crd_loaded = false; + const url = '/changes/' + this.change.id + '/revisions/current/crd'; + return this.plugin.restApi().send('GET', url).then(crd => { + this._crd = crd; + this._crd_loaded = true; + }); + } + + _computeDependencyUrl(changeId) { + return Gerrit.Nav.getUrlForSearchQuery(changeId); + } +} + +customElements.define(GrZuul.is, GrZuul);
diff --git a/gr-zuul/gr-zuul_html.js b/gr-zuul/gr-zuul_html.js new file mode 100644 index 0000000..a5328e2 --- /dev/null +++ b/gr-zuul/gr-zuul_html.js
@@ -0,0 +1,88 @@ +/** + * @license + * Copyright (C) 2020 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. + */ + +export const htmlTemplate = Polymer.html` + <style include="shared-styles"> + section.related-changes-section { + margin-bottom: 1.4em; /* Same as line height for collapse purposes */ + display: block; + } + div.foo { + margin-bottom: 1.4em; /* Same as line height for collapse purposes */ + } + a { + display: block; + } + .changeContainer, + a { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .changeContainer { + display: flex; + } + .changeContainer.thisChange:before { + content: '➔'; + width: 1.2em; + } + h4, + section div { + display: flex; + } + h4:before, + section div:before { + content: ' '; + flex-shrink: 0; + width: 1.2em; + } + </style> + <template is="dom-if" if="[[_crd_loaded]]"> + <template is="dom-if" if="[[_crd.depends_on.length]]"> + <section class="related-changes-section"> + <h4>Depends on</h4> + <template is="dom-repeat" items="[[_crd.depends_on]]"> + <div class="changeContainer zuulDependencyContainer"> + <a + href$="[[_computeDependencyUrl(item)]]" + title$="[[item]]" + > + [[item]] + </a> + </div> + </template> + </section> + </template> + <template is="dom-if" if="[[_crd.needed_by.length]]"> + <section class="related-changes-section"> + <h4>Needed by</h4> + <template is="dom-repeat" items="[[_crd.needed_by]]"> + <div class="changeContainer zuulDependencyContainer"> + <a + href$="[[_computeDependencyUrl(item)]]" + title$="[[item]]" + > + [[item]] + </a> + </div> + </template> + </section> + </template> + </template> +`; +
diff --git a/gr-zuul/plugin.js b/gr-zuul/plugin.js new file mode 100644 index 0000000..475f053 --- /dev/null +++ b/gr-zuul/plugin.js
@@ -0,0 +1,22 @@ +/** + * @license + * Copyright (C) 2020 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. + */ +import './gr-zuul.js'; + +Gerrit.install(plugin => { + plugin.registerCustomComponent( + 'related-changes-section', 'gr-zuul', {slot: 'bottom'}); +});
diff --git a/src/main/java/com/googlesource/gerrit/plugins/zuul/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/zuul/HttpModule.java new file mode 100644 index 0000000..bc6db6b --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/zuul/HttpModule.java
@@ -0,0 +1,27 @@ +// Copyright (C) 2020 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.zuul; + +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.extensions.webui.JavaScriptPlugin; +import com.google.gerrit.extensions.webui.WebUiPlugin; +import com.google.inject.servlet.ServletModule; + +public class HttpModule extends ServletModule { + @Override + protected void configureServlets() { + DynamicSet.bind(binder(), WebUiPlugin.class).toInstance(new JavaScriptPlugin("zuul.html")); + } +}