Merge "Rename "slave" to "replica" in documentation and command-line"
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 30249d0..4fa4ba9 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -4783,47 +4783,6 @@
link:#schedule-configuration-examples[Schedule examples] can be found
in the link:#schedule-configuration[Schedule Configuration] section.
-[[urlAlias]]
-=== Section urlAlias
-
-URL aliases define regular expressions for URL tokens that are mapped
-to target URL tokens.
-
-Each URL alias must be specified in its own subsection. The subsection
-name should be a descriptive name. It must be unique, but is not
-interpreted in any way.
-
-The URL aliases are applied in no particular order. The first matching
-URL alias is used and further matches are ignored.
-
-URL aliases can be used to map plugin screens into the Gerrit URL
-namespace, or to replace Gerrit screens by plugin screens.
-
-Example:
-
-----
-[urlAlias "MyPluginScreen"]
- match = /myscreen/(.*)
- token = /x/myplugin/myscreen/$1
-[urlAlias "MyChangeScreen"]
- match = /c/(.*)
- token = /x/myplugin/c/$1
-----
-
-[[urlAlias.match]]urlAlias.match::
-+
-A regular expression for a URL token.
-+
-The matched URL token is replaced by `urlAlias.token`.
-
-[[urlAlias.token]]urlAlias.token::
-+
-The target URL token.
-+
-It can contain placeholders for the groups matched by the
-`urlAlias.match` regular expression: `$1` for the first matched group,
-`$2` for the second matched group, etc.
-
[[submodule]]
=== Section submodule
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 77ef60d..74ed725 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -2738,6 +2738,20 @@
}
----
+[[exception-hook]]
+== ExceptionHook
+
+An `ExceptionHook` allows implementors to control how certain
+exceptions should be handled.
+
+This interface is intended to be implemented for multi-master setups to
+control the behavior for handling exceptions that are thrown by a lower
+layer that handles the consensus and synchronization between different
+server nodes. E.g. if an operation fails because consensus for a Git
+update could not be achieved (e.g. due to slow responding server nodes)
+this interface can be used to retry the request instead of failing it
+immediately.
+
[[quota-enforcer]]
== Quota Enforcer
diff --git a/Documentation/js-api.txt b/Documentation/js-api.txt
index d909c00..258ded2 100644
--- a/Documentation/js-api.txt
+++ b/Documentation/js-api.txt
@@ -24,123 +24,17 @@
The plugin instance is passed to the plugin's initialization function
and provides a number of utility services to plugin authors.
-[[self_delete]]
-=== self.delete() / self.del()
-Issues a DELETE REST API request to the Gerrit server.
-
-.Signature
-[source,javascript]
-----
-Gerrit.delete(url, callback)
-Gerrit.del(url, callback)
-----
-
-* url: URL relative to the plugin's URL space. The JavaScript
- library prefixes the supplied URL with `/plugins/{getPluginName}/`.
-
-* callback: JavaScript function to be invoked with the parsed
- JSON result of the API call. DELETE methods often return
- `204 No Content`, which is passed as null.
-
-[[self_get]]
-=== self.get()
-Issues a GET REST API request to the Gerrit server.
-
-.Signature
-[source,javascript]
-----
-self.get(url, callback)
-----
-
-* url: URL relative to the plugin's URL space. The JavaScript
- library prefixes the supplied URL with `/plugins/{getPluginName}/`.
-
-* callback: JavaScript function to be invoked with the parsed JSON
- result of the API call. If the API returns a string the result is
- a string, otherwise the result is a JavaScript object or array,
- as described in the relevant REST API documentation.
-
[[self_getServerInfo]]
=== self.getServerInfo()
Returns the server's link:rest-api-config.html#server-info[ServerInfo]
data.
-[[self_getCurrentUser]]
-=== self.getCurrentUser()
-Returns the currently signed in user's AccountInfo data; empty account
-data if no user is currently signed in.
-
-[[Gerrit_getUserPreferences]]
-=== Gerrit.getUserPreferences()
-Returns the preferences of the currently signed in user; the default
-preferences if no user is currently signed in.
-
-[[Gerrit_refreshUserPreferences]]
-=== Gerrit.refreshUserPreferences()
-Refreshes the preferences of the current user.
-
[[self_getPluginName]]
=== self.getPluginName()
Returns the name this plugin was installed as by the server
administrator. The plugin name is required to access REST API
views installed by the plugin, or to access resources.
-[[self_post]]
-=== self.post()
-Issues a POST REST API request to the Gerrit server.
-
-.Signature
-[source,javascript]
-----
-self.post(url, input, callback)
-----
-
-* url: URL relative to the plugin's URL space. The JavaScript
- library prefixes the supplied URL with `/plugins/{getPluginName}/`.
-
-* input: JavaScript object to serialize as the request payload.
-
-* callback: JavaScript function to be invoked with the parsed JSON
- result of the API call. If the API returns a string the result is
- a string, otherwise the result is a JavaScript object or array,
- as described in the relevant REST API documentation.
-
-[source,javascript]
-----
-self.post(
- '/my-servlet',
- {start_build: true, platform_type: 'Linux'},
- function (r) {});
-----
-
-[[self_put]]
-=== self.put()
-Issues a PUT REST API request to the Gerrit server.
-
-.Signature
-[source,javascript]
-----
-self.put(url, input, callback)
-----
-
-* url: URL relative to the plugin's URL space. The JavaScript
- library prefixes the supplied URL with `/plugins/{getPluginName}/`.
-
-* input: JavaScript object to serialize as the request payload.
-
-* callback: JavaScript function to be invoked with the parsed JSON
- result of the API call. If the API returns a string the result is
- a string, otherwise the result is a JavaScript object or array,
- as described in the relevant REST API documentation.
-
-[source,javascript]
-----
-self.put(
- '/builds',
- {start_build: true, platform_type: 'Linux'},
- function (r) {});
-----
-
[[self_on]]
=== self.on()
Register a JavaScript callback to be invoked when events occur within
@@ -149,7 +43,7 @@
.Signature
[source,javascript]
----
-Gerrit.on(event, callback);
+self.on(event, callback);
----
* event: A supported event type. See below for description.
@@ -194,39 +88,26 @@
This event can be used to register a new language highlighter with
the highlight.js library before syntax highlighting begins.
-[[self_onAction]]
-=== self.onAction()
-Register a JavaScript callback to be invoked when the user clicks
-on a button associated with a server side `UiAction`.
+[[self_changeActions]]
+=== self.changeActions()
+Returns an instance of ChangeActions API.
.Signature
[source,javascript]
----
-self.onAction(type, view_name, callback);
+self.changeActions();
----
-* type: `'change'`, `'edit'`, `'revision'`, `'project'`, or `'branch'`
- indicating which type of resource the `UiAction` was bound to
- in the server.
-
-* view_name: string appearing in URLs to name the view. This is the
- second argument of the `get()`, `post()`, `put()`, and `delete()`
- binding methods in a `RestApiModule`.
-
-* callback: JavaScript function to invoke when the user clicks. The
- function will be passed a link:#ActionContext[action context].
-
[[self_screen]]
=== self.screen()
-Register a JavaScript callback to be invoked when the user navigates
+Register a module to be attached when the user navigates
to an extension screen provided by the plugin. Extension screens are
usually linked from the link:dev-plugins.html#top-menu-extensions[top menu].
-The callback can populate the DOM with the screen's contents.
.Signature
[source,javascript]
----
-self.screen(pattern, callback);
+self.screen(pattern, opt_moduleName);
----
* pattern: URL token pattern to identify the screen. Argument can be
@@ -234,52 +115,34 @@
If a RegExp is used the matching groups will be available inside of
the context as `token_match`.
-* callback: JavaScript function to invoke when the user navigates to
+* opt_moduleName: The module to load when the user navigates to
the screen. The function will be passed a link:#ScreenContext[screen context].
-[[self_settingsScreen]]
-=== self.settingsScreen()
-Register a JavaScript callback to be invoked when the user navigates
-to an extension settings screen provided by the plugin. Extension settings
-screens are automatically linked from the settings menu under the given
-menu entry.
-The callback can populate the DOM with the screen's contents.
+[[self_settings]]
+=== self.settings()
+Returns the Settings API.
.Signature
[source,javascript]
----
-self.settingsScreen(path, menu, callback);
+self.settings();
----
-* path: URL path to identify the settings screen.
-
-* menu: The name of the menu entry in the settings menu that should
- link to the settings screen.
-
-* callback: JavaScript function to invoke when the user navigates to
- the settings screen. The function will be passed a
- link:#SettingsScreenContext[settings screen context].
-
-[[self_panel]]
-=== self.panel()
-Register a JavaScript callback to be invoked when a screen with the
-given extension point is loaded.
-The callback can populate the DOM with the panel's contents.
+[[self_registerCustomComponent]]
+=== self.registerCustomComponent()
+Register a custom component to a specific endpoint.
.Signature
[source,javascript]
----
-self.panel(extensionpoint, callback);
+self.registerCustomComponent(endpointName, opt_moduleName, opt_options);
----
-* extensionpoint: The name of the extension point that marks the
- position where the panel is added to an existing screen. The
- available extension points are described in the
- link:dev-plugins.html#panels[plugin development documentation].
+* endpointName: The endpoint this plugin should be reigistered to.
-* callback: JavaScript function to invoke when a screen with the
- extension point is loaded. The function will be passed a
- link:#PanelContext[panel context].
+* opt_moduleName: The module name the custom component will use.
+
+* opt_options: Options to register this custom component.
[[self_url]]
=== self.url()
@@ -293,398 +156,260 @@
self.url('/static/icon.png'); // "https://gerrit-review.googlesource.com/plugins/demo/static/icon.png"
----
-
-[[ActionContext]]
-== Action Context
-A new action context is passed to the `onAction` callback function
-each time the associated action button is clicked by the user. A
-context is initialized with sufficient state to issue the associated
-REST API RPC.
-
-[[context_action]]
-=== context.action
-An link:rest-api-changes.html#action-info[ActionInfo] object instance
-supplied by the server describing the UI button the user used to
-invoke the action.
-
-[[context_call]]
-=== context.call()
-Issues the REST API call associated with the action. The HTTP method
-used comes from `context.action.method`, hiding the JavaScript from
-needing to care.
+[[self_restApi]]
+=== self.restApi()
+Returns an instance of the Plugin REST API.
.Signature
[source,javascript]
----
-context.call(input, callback)
+self.restApi(prefix_url)
----
-* input: JavaScript object to serialize as the request payload. This
- parameter is ignored for GET and DELETE methods.
+* prefix_url: Base url for subsequent .get(), .post() etc requests.
-* callback: JavaScript function to be invoked with the parsed JSON
- result of the API call. If the API returns a string the result is
- a string, otherwise the result is a JavaScript object or array,
- as described in the relevant REST API documentation.
+[[PluginRestAPI]]
+== Plugin Rest API
-[source,javascript]
-----
-context.call(
- {message: "..."},
- function (result) {
- // ... use result here ...
- });
-----
-
-[[context_change]]
-=== context.change
-When the action is invoked on a change a
-link:rest-api-changes.html#change-info[ChangeInfo] object instance
-describing the change. Available fields of the ChangeInfo may vary
-based on the options used by the UI when it loaded the change.
-
-[[context_delete]]
-=== context.delete()
-Issues a DELETE REST API call to the URL associated with the action.
+[[plugin_rest_delete]]
+=== restApi.delete()
+Issues a DELETE REST API request to the Gerrit server.
+Returns a promise with the response of the request.
.Signature
[source,javascript]
----
-context.delete(callback)
+restApi.delete(url)
----
-* callback: JavaScript function to be invoked with the parsed
- JSON result of the API call. DELETE methods often return
- `204 No Content`, which is passed as null.
+* url: URL relative to the base url.
-[source,javascript]
-----
-context.delete(function () {});
-----
-
-[[context_get]]
-=== context.get()
-Issues a GET REST API call to the URL associated with the action.
+[[plugin_rest_get]]
+=== restApi.get()
+Issues a GET REST API request to the Gerrit server.
+Returns a promise with the response of the request.
.Signature
[source,javascript]
----
-context.get(callback)
+restApi.get(url)
----
-* callback: JavaScript function to be invoked with the parsed JSON
- result of the API call. If the API returns a string the result is
- a string, otherwise the result is a JavaScript object or array,
- as described in the relevant REST API documentation.
+* url: URL relative to the base url.
-[source,javascript]
-----
-context.get(function (result) {
- // ... use result here ...
-});
-----
-
-[[context_go]]
-=== context.go()
-Go to a screen. Shorthand for link:#Gerrit_go[`Gerrit.go()`].
-
-[[context_hide]]
-=== context.hide()
-Hide the currently visible popup displayed by
-link:#context_popup[`context.popup()`].
-
-[[context_post]]
-=== context.post()
-Issues a POST REST API call to the URL associated with the action.
+[[plugin_rest_post]]
+=== restApi.post()
+Issues a POST REST API request to the Gerrit server.
+Returns a promise with the response of the request.
.Signature
[source,javascript]
----
-context.post(input, callback)
+restApi.post(url, opt_payload, opt_errFn, opt_contentType)
----
-* input: JavaScript object to serialize as the request payload.
+* url: URL relative to the base url.
-* callback: JavaScript function to be invoked with the parsed JSON
- result of the API call. If the API returns a string the result is
- a string, otherwise the result is a JavaScript object or array,
- as described in the relevant REST API documentation.
+* opt_payload: JavaScript object to serialize as the request payload.
+
+* opt_errFn: JavaScript function to be invoked when error occured.
+
+* opt_contentType: Content-Type to be sent along with the request.
[source,javascript]
----
-context.post(
- {message: "..."},
- function (result) {
- // ... use result here ...
- });
+restApi.post(
+ '/my-servlet',
+ {start_build: true, platform_type: 'Linux'});
----
-[[context_popup]]
-=== context.popup()
-
-Displays a small popup near the activation button to gather
-additional input from the user before executing the REST API RPC.
-
-The caller is always responsible for closing the popup with
-link#context_hide[`context.hide()`]. Gerrit will handle closing a
-popup if the user presses `Escape` while keyboard focus is within
-the popup.
+[[plugin_rest_put]]
+=== restApi.put()
+Issues a PUT REST API request to the Gerrit server.
+Returns a promise with the response of the request.
.Signature
[source,javascript]
----
-context.popup(element)
+restApi.put(url, opt_payload, opt_errFn, opt_contentType)
----
-* element: an HTML DOM element to display as the body of the
- popup. This is typically a `div` element but can be any valid HTML
- element. CSS can be used to style the element beyond the defaults.
+* url: URL relative to the base url.
-A common usage is to gather more input:
+* opt_payload: JavaScript object to serialize as the request payload.
+
+* opt_errFn: JavaScript function to be invoked when error occured.
+
+* opt_contentType: Content-Type to be sent along with the request.
[source,javascript]
----
-self.onAction('revision', 'start-build', function (c) {
- var l = c.checkbox();
- var m = c.checkbox();
- c.popup(c.div(
- c.div(c.label(l, 'Linux')),
- c.div(c.label(m, 'Mac OS X')),
- c.button('Build', {onclick: function() {
- c.call(
- {
- commit: c.revision.name,
- linux: l.checked,
- mac: m.checked,
- },
- function() { c.hide() });
- });
-});
+restApi.put(
+ '/builds',
+ {start_build: true, platform_type: 'Linux'});
----
-[[context_put]]
-=== context.put()
-Issues a PUT REST API call to the URL associated with the action.
+[[ChangeActions]]
+== Change Actions API
+A new Change Actions API instance will be created when `changeActions()`
+is invoked.
+
+[[change_actions_add]]
+=== changeActions.add()
+Adds a new action to the change actions section.
+Returns the key of the newly added action.
.Signature
[source,javascript]
----
-context.put(input, callback)
+changeActions.add(type, label)
----
-* input: JavaScript object to serialize as the request payload.
+* type: The type of the action, either `change` or `revision`.
-* callback: JavaScript function to be invoked with the parsed JSON
- result of the API call. If the API returns a string the result is
- a string, otherwise the result is a JavaScript object or array,
- as described in the relevant REST API documentation.
+* label: The label to be used in UI for this action.
[source,javascript]
----
-context.put(
- {message: "..."},
- function (result) {
- // ... use result here ...
- });
+changeActions.add("change", "test")
----
-[[context_refresh]]
-=== context.refresh()
-Refresh the current display. Shorthand for
-link:#Gerrit_refresh[`Gerrit.refresh()`].
-
-[[context_revision]]
-=== context.revision
-When the action is invoked on a specific revision of a change,
-a link:rest-api-changes.html#revision-info[RevisionInfo]
-object instance describing the revision. Available fields of the
-RevisionInfo may vary based on the options used by the UI when it
-loaded the change.
-
-[[context_project]]
-=== context.project
-When the action is invoked on a specific project,
-the name of the project.
-
-=== HTML Helpers
-The link:#ActionContext[action context] includes some HTML helper
-functions to make working with DOM based widgets less painful.
-
-* `br()`: new `<br>` element.
-
-* `button(label, options)`: new `<button>` with the string `label`
- wrapped inside of a `div`. The optional `options` object may
- define `onclick` as a function to be invoked upon clicking. This
- calling pattern avoids circular references between the element
- and the onclick handler.
-
-* `checkbox()`: new `<input type='checkbox'>` element.
-* `div(...)`: a new `<div>` wrapping the (optional) arguments.
-* `hr()`: new `<hr>` element.
-
-* `label(c, label)`: a new `<label>` element wrapping element `c`
- and the string `label`. Used to wrap a checkbox with its label,
- `label(checkbox(), 'Click Me')`.
-
-* `prependLabel(label, c)`: a new `<label>` element wrapping element `c`
- and the string `label`. Used to wrap an input field with its label,
- `prependLabel('Greeting message', textfield())`.
-
-* `textarea(options)`: new `<textarea>` element. The options
- object may optionally include `rows` and `cols`. The textarea
- comes with an onkeypress handler installed to play nicely with
- Gerrit's keyboard binding system.
-
-* `textfield()`: new `<input type='text'>` element. The text field
- comes with an onkeypress handler installed to play nicely with
- Gerrit's keyboard binding system.
-
-* `select(a,i)`: a new `<select>` element containing one `<option>`
- element for each entry in the provided array `a`. The option with
- the index `i` will be pre-selected in the drop-down-list.
-
-* `selected(s)`: returns the text of the `<option>` element that is
- currently selected in the provided `<select>` element `s`.
-
-* `span(...)`: a new `<span>` wrapping the (optional) arguments.
-
-* `msg(label)`: a new label.
-
-
-[[ScreenContext]]
-== Screen Context
-A new screen context is passed to the `screen` callback function
-each time the user navigates to a matching URL.
-
-[[screen_body]]
-=== screen.body
-Empty HTML `<div>` node the plugin should add its content to. The
-node is already attached to the document, but is invisible. Plugins
-must call `screen.show()` to display the DOM node. Deferred display
-allows an implementor to partially populate the DOM, make remote HTTP
-requests, finish populating when the callbacks arrive, and only then
-make the view visible to the user.
-
-[[screen_token]]
-=== screen.token
-URL token fragment that activated this screen. The value is identical
-to `screen.token_match[0]`. If the URL is `/#/x/hello/list` the token
-will be `"list"`.
-
-[[screen_token_match]]
-=== screen.token_match
-Array of matching subgroups from the pattern specified to `screen()`.
-This is identical to the result of RegExp.exec. Index 0 contains the
-entire matching expression; index 1 the first matching group, etc.
-
-[[screen_onUnload]]
-=== screen.onUnload()
-Configures an optional callback to be invoked just before the screen
-is deleted from the browser DOM. Plugins can use this callback to
-remove event listeners from DOM nodes, preventing memory leaks.
+[[change_actions_remove]]
+=== changeActions.remove()
+Removes an action from the change actions section.
.Signature
[source,javascript]
----
-screen.onUnload(callback)
+changeActions.remove(key)
----
-* callback: JavaScript function to be invoked just before the
- `screen.body` DOM element is removed from the browser DOM.
- This event happens when the user navigates to another screen.
+* key: The key of the action.
-[[screen.setTitle]]
-=== screen.setTitle()
-Sets the heading text to be displayed when the screen is visible.
-This is presented in a large bold font below the menus, but above the
-content in `screen.body`. Setting the title also sets the window
-title to the same string, if it has not already been set.
+[[change_actions_addTapListener]]
+=== changeActions.addTapListener()
+Adds a tap listener to an action that will be invoked when the action
+is tapped.
.Signature
[source,javascript]
----
-screen.setPageTitle(titleText)
+changeActions.addTapListener(key, callback)
----
-[[screen.setWindowTitle]]
-=== screen.setWindowTitle()
-Sets the text to be displayed in the browser's title bar when the
-screen is visible. Plugins should always prefer this method over
-trying to set `window.title` directly. The window title defaults to
-the title given to `setTitle`.
+* key: The key of the action.
+
+* callback: JavaScript function to be invoked when action tapped.
+
+[source,javascript]
+----
+changeActions.addTapListener("__key_for_my_action__", () => {
+ // do something when my action gets clicked
+})
+----
+
+[[change_actions_removeTapListener]]
+=== changeActions.removeTapListener()
+Removes an existing tap listener on an action.
.Signature
[source,javascript]
----
-screen.setWindowTitle(titleText)
+changeActions.removeTapListener(key, callback)
----
-[[screen_show]]
-=== screen.show()
-Destroy the currently visible screen and display the plugin's screen.
-This method must be called after adding content to `screen.body`.
+* key: The key of the action.
-[[SettingsScreenContext]]
-== Settings Screen Context
-A new settings screen context is passed to the `settingsScreen` callback
-function each time the user navigates to a matching URL.
+* callback: JavaScript function to be removed.
-[[settingsScreen_body]]
-=== settingsScreen.body
-Empty HTML `<div>` node the plugin should add its content to. The
-node is already attached to the document, but is invisible. Plugins
-must call `settingsScreen.show()` to display the DOM node. Deferred
-display allows an implementor to partially populate the DOM, make
-remote HTTP requests, finish populating when the callbacks arrive, and
-only then make the view visible to the user.
-
-[[settingsScreen_onUnload]]
-=== settingsScreen.onUnload()
-Configures an optional callback to be invoked just before the screen
-is deleted from the browser DOM. Plugins can use this callback to
-remove event listeners from DOM nodes, preventing memory leaks.
+[[change_actions_setLabel]]
+=== changeActions.setLabel()
+Sets the label for an action.
.Signature
[source,javascript]
----
-settingsScreen.onUnload(callback)
+changeActions.setLabel(key, label)
----
-* callback: JavaScript function to be invoked just before the
- `settingsScreen.body` DOM element is removed from the browser DOM.
- This event happens when the user navigates to another screen.
+* key: The key of the action.
-[[settingsScreen.setTitle]]
-=== settingsScreen.setTitle()
-Sets the heading text to be displayed when the screen is visible.
-This is presented in a large bold font below the menus, but above the
-content in `settingsScreen.body`. Setting the title also sets the
-window title to the same string, if it has not already been set.
+* label: The label of the action.
+
+[[change_actions_setTitle]]
+=== changeActions.setTitle()
+Sets the title for an action.
.Signature
[source,javascript]
----
-settingsScreen.setPageTitle(titleText)
+changeActions.setTitle(key, title)
----
-[[settingsScreen.setWindowTitle]]
-=== settingsScreen.setWindowTitle()
-Sets the text to be displayed in the browser's title bar when the
-screen is visible. Plugins should always prefer this method over
-trying to set `window.title` directly. The window title defaults to
-the title given to `setTitle`.
+* key: The key of the action.
+
+* title: The title of the action.
+
+[[change_actions_setIcon]]
+=== changeActions.setIcon()
+Sets an icon for an action.
.Signature
[source,javascript]
----
-settingsScreen.setWindowTitle(titleText)
+changeActions.setIcon(key, icon)
----
-[[settingsScreen_show]]
-=== settingsScreen.show()
-Destroy the currently visible screen and display the plugin's screen.
-This method must be called after adding content to
-`settingsScreen.body`.
+* key: The key of the action.
+
+* icon: The name of the icon.
+
+[[change_actions_setEnabled]]
+=== changeActions.setEnabled()
+Sets an action to enabled or disabled.
+
+.Signature
+[source,javascript]
+----
+changeActions.setEnabled(key, enabled)
+----
+
+* key: The key of the action.
+
+* enabled: The status of the action, true to enable.
+
+[[change_actions_setActionHidden]]
+=== changeActions.setActionHidden()
+Sets an action to be hidden.
+
+.Signature
+[source,javascript]
+----
+changeActions.setActionHidden(type, key, hidden)
+----
+
+* type: The type of the action.
+
+* key: The key of the action.
+
+* hidden: True to hide the action, false to show the action.
+
+[[change_actions_setActionOverflow]]
+=== changeActions.setActionOverflow()
+Sets an action to show in overflow menu.
+
+.Signature
+[source,javascript]
+----
+changeActions.setActionOverflow(type, key, overflow)
+----
+
+* type: The type of the action.
+
+* key: The key of the action.
+
+* overflow: True to move the action to overflow menu, false to move
+ the action out of the overflow menu.
[[PanelContext]]
== Panel Context
@@ -734,59 +459,6 @@
});
----
-[[Gerrit_delete]]
-=== Gerrit.delete()
-Issues a DELETE REST API request to the Gerrit server. For plugin
-private REST API URLs see link:#self_delete[self.delete()].
-
-.Signature
-[source,javascript]
-----
-Gerrit.delete(url, callback)
-----
-
-* url: URL relative to the Gerrit server. For example to access the
- link:rest-api-changes.html[changes REST API] use `'/changes/'`.
-
-* callback: JavaScript function to be invoked with the parsed
- JSON result of the API call. DELETE methods often return
- `204 No Content`, which is passed as null.
-
-[source,javascript]
-----
-Gerrit.delete(
- '/changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/topic',
- function () {});
-----
-
-[[Gerrit_get]]
-=== Gerrit.get()
-Issues a GET REST API request to the Gerrit server. For plugin
-private REST API URLs see link:#self_get[self.get()].
-
-.Signature
-[source,javascript]
-----
-Gerrit.get(url, callback)
-----
-
-* url: URL relative to the Gerrit server. For example to access the
- link:rest-api-changes.html[changes REST API] use `'/changes/'`.
-
-* callback: JavaScript function to be invoked with the parsed JSON
- result of the API call. If the API returns a string the result is
- a string, otherwise the result is a JavaScript object or array,
- as described in the relevant REST API documentation.
-
-[source,javascript]
-----
-Gerrit.get('/changes/?q=status:open', function (open) {
- for (var i = 0; i < open.length; i++) {
- console.log(open[i].change_id);
- }
-});
-----
-
[[Gerrit_getCurrentUser]]
=== Gerrit.getCurrentUser()
Returns the currently signed in user's AccountInfo data; empty account
@@ -828,136 +500,6 @@
});
----
-[[Gerrit_post]]
-=== Gerrit.post()
-Issues a POST REST API request to the Gerrit server. For plugin
-private REST API URLs see link:#self_post[self.post()].
-
-.Signature
-[source,javascript]
-----
-Gerrit.post(url, input, callback)
-----
-
-* url: URL relative to the Gerrit server. For example to access the
- link:rest-api-changes.html[changes REST API] use `'/changes/'`.
-
-* input: JavaScript object to serialize as the request payload.
-
-* callback: JavaScript function to be invoked with the parsed JSON
- result of the API call. If the API returns a string the result is
- a string, otherwise the result is a JavaScript object or array,
- as described in the relevant REST API documentation.
-
-[source,javascript]
-----
-Gerrit.post(
- '/changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/topic',
- {topic: 'tests', message: 'Classify work as for testing.'},
- function (r) {});
-----
-
-[[Gerrit_put]]
-=== Gerrit.put()
-Issues a PUT REST API request to the Gerrit server. For plugin
-private REST API URLs see link:#self_put[self.put()].
-
-.Signature
-[source,javascript]
-----
-Gerrit.put(url, input, callback)
-----
-
-* url: URL relative to the Gerrit server. For example to access the
- link:rest-api-changes.html[changes REST API] use `'/changes/'`.
-
-* input: JavaScript object to serialize as the request payload.
-
-* callback: JavaScript function to be invoked with the parsed JSON
- result of the API call. If the API returns a string the result is
- a string, otherwise the result is a JavaScript object or array,
- as described in the relevant REST API documentation.
-
-[source,javascript]
-----
-Gerrit.put(
- '/changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/topic',
- {topic: 'tests', message: 'Classify work as for testing.'},
- function (r) {});
-----
-
-[[Gerrit_onAction]]
-=== Gerrit.onAction()
-Register a JavaScript callback to be invoked when the user clicks
-on a button associated with a server side `UiAction`.
-
-.Signature
-[source,javascript]
-----
-Gerrit.onAction(type, view_name, callback);
-----
-
-* type: `'change'`, `'edit'`, `'revision'`, `'project'` or `'branch'`
- indicating what sort of resource the `UiAction` was bound to in the server.
-
-* view_name: string appearing in URLs to name the view. This is the
- second argument of the `get()`, `post()`, `put()`, and `delete()`
- binding methods in a `RestApiModule`.
-
-* callback: JavaScript function to invoke when the user clicks. The
- function will be passed a link:#ActionContext[ActionContext].
-
-[[Gerrit_screen]]
-=== Gerrit.screen()
-Register a JavaScript callback to be invoked when the user navigates
-to an extension screen provided by the plugin. Extension screens are
-usually linked from the link:dev-plugins.html#top-menu-extensions[top menu].
-The callback can populate the DOM with the screen's contents.
-
-.Signature
-[source,javascript]
-----
-Gerrit.screen(pattern, callback);
-----
-
-* pattern: URL token pattern to identify the screen. Argument can be
- either a string (`'index'`) or a RegExp object (`/list\/(.*)/`).
- If a RegExp is used the matching groups will be available inside of
- the context as `token_match`.
-
-* callback: JavaScript function to invoke when the user navigates to
- the screen. The function will be passed link:#ScreenContext[screen context].
-
-[[Gerrit_refresh]]
-=== Gerrit.refresh()
-Redisplays the current web UI view, refreshing all information.
-
-[[Gerrit_refreshMenuBar]]
-=== Gerrit.refreshMenuBar()
-Refreshes Gerrit's menu bar.
-
-[[Gerrit_isSignedIn]]
-=== Gerrit.isSignedIn()
-Checks if user is signed in.
-
-[[Gerrit_url]]
-=== Gerrit.url()
-Returns the URL of the Gerrit Code Review server. If invoked with
-no parameter the URL of the site is returned. If passed a string
-the argument is appended to the site URL.
-
-[source,javascript]
-----
-Gerrit.url(); // "https://gerrit-review.googlesource.com/"
-Gerrit.url('/123'); // "https://gerrit-review.googlesource.com/123"
-----
-
-For a plugin specific version see link:#self_url()[`self.url()`].
-
-[[Gerrit_showError]]
-=== Gerrit.showError(message)
-Displays the given message in the Gerrit ErrorDialog.
-
GERRIT
------
Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index 6fb9220..7097a16 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -2764,9 +2764,6 @@
|`change_table` ||
The columns to display in the change table (PolyGerrit only). The default is
empty, which will default columns as determined by the frontend.
-|`url_aliases` |optional|
-A map of URL path pairs, where the first URL path is an alias for the
-second URL path.
|`email_strategy` ||
The type of email strategy to use. On `ENABLED`, the user will receive emails
from Gerrit. On `CC_ON_OWN_COMMENTS` the user will also receive emails for
@@ -2829,9 +2826,6 @@
|`change_table` ||
The columns to display in the change table (PolyGerrit only). The default is
empty, which will default columns as determined by the frontend.
-|`url_aliases` |optional|
-A map of URL path pairs, where the first URL path is an alias for the
-second URL path.
|`email_strategy` |optional|
The type of email strategy to use. On `ENABLED`, the user will receive emails
from Gerrit. On `CC_ON_OWN_COMMENTS` the user will also receive emails for
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index 2b10e33..021a1bb 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -1963,11 +1963,6 @@
Information about the configuration from the
link:config-gerrit.html#suggest[suggest] section as link:#suggest-info[
SuggestInfo] entity.
-|`url_aliases` |optional|
-A map of URL aliases, where a regular expression for an URL token is
-mapped to a target URL token. The target URL token can contain
-placeholders for the groups matched by the regular expression: `$1` for
-the first matched group, `$2` for the second matched group, etc.
|`user` ||
Information about the configuration from the
link:config-gerrit.html#user[user] section as link:#user-config-info[
diff --git a/WORKSPACE b/WORKSPACE
index a21fe31..75a7eed 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -56,29 +56,6 @@
check_bazel_version()
-# Protobuf rules support
-http_archive(
- name = "rules_proto",
- sha256 = "602e7161d9195e50246177e7c55b2f39950a9cf7366f74ed5f22fd45750cd208",
- strip_prefix = "rules_proto-97d8af4dc474595af3900dd85cb3a29ad28cc313",
- urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz",
- "https://github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz",
- ],
-)
-
-# Rules Python
-http_archive(
- name = "rules_python",
- sha256 = "b5bab4c47e863e0fbb77df4a40c45ca85f98f5a2826939181585644c9f31b97b",
- strip_prefix = "rules_python-9d68f24659e8ce8b736590ba1e4418af06ec2552",
- urls = ["https://github.com/bazelbuild/rules_python/archive/9d68f24659e8ce8b736590ba1e4418af06ec2552.tar.gz"],
-)
-
-load("@rules_python//python:repositories.bzl", "py_repositories")
-
-py_repositories()
-
load("@io_bazel_rules_closure//closure:repositories.bzl", "closure_repositories")
# Prevent redundant loading of dependencies.
@@ -118,17 +95,6 @@
gazelle_dependencies()
-# Protobuf rules support
-http_archive(
- name = "rules_proto",
- sha256 = "602e7161d9195e50246177e7c55b2f39950a9cf7366f74ed5f22fd45750cd208",
- strip_prefix = "rules_proto-97d8af4dc474595af3900dd85cb3a29ad28cc313",
- urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz",
- "https://github.com/bazelbuild/rules_proto/archive/97d8af4dc474595af3900dd85cb3a29ad28cc313.tar.gz",
- ],
-)
-
# Dependencies for PolyGerrit local dev server.
go_repository(
name = "com_github_howeyc_fsnotify",
diff --git a/contrib/benchmark-createchange.go b/contrib/benchmark-createchange.go
new file mode 100644
index 0000000..dc320d6
--- /dev/null
+++ b/contrib/benchmark-createchange.go
@@ -0,0 +1,103 @@
+// Copyright (C) 2019 Google LLC
+//
+// 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.
+
+// Program to benchmark Gerrit. Creates pending changes in a loop,
+// which tests performance of BatchRefUpdate and Lucene indexing
+package main
+
+import (
+ "bytes"
+ "encoding/base64"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "sort"
+ "time"
+)
+
+func main() {
+ user := flag.String("user", "admin", "username for basic auth")
+ pw := flag.String("password", "secret", "HTTP password for basic auth")
+ project := flag.String("project", "", "project to create changes in")
+ gerritURL := flag.String("url", "http://localhost:8080/", "URL to gerrit instance")
+ numChanges := flag.Int("n", 100, "number of changes to create")
+ flag.Parse()
+ if *gerritURL == "" {
+ log.Fatal("provide --url")
+ }
+ if *project == "" {
+ log.Fatal("provide --project")
+ }
+
+ u, err := url.Parse(*gerritURL)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ basicAuth := fmt.Sprintf("%s:%s", *user, *pw)
+ authHeader := base64.StdEncoding.EncodeToString([]byte(basicAuth))
+
+ client := &http.Client{}
+
+ var dts []time.Duration
+ startAll := time.Now()
+ var lastSec int
+ for i := 0; i < *numChanges; i++ {
+ body := fmt.Sprintf(`{
+ "project" : "%s",
+ "subject" : "change %d",
+ "branch" : "master",
+ "status" : "NEW"
+ }`, *project, i)
+ start := time.Now()
+
+ thisSec := int(start.Sub(startAll) / time.Second)
+ if thisSec != lastSec {
+ log.Printf("change %d", i)
+ }
+ lastSec = thisSec
+
+ u.Path = "/a/changes/"
+ req, err := http.NewRequest("POST", u.String(), bytes.NewBufferString(body))
+ if err != nil {
+ log.Fatal(err)
+ }
+ req.Header.Add("Authorization", "Basic "+authHeader)
+ req.Header.Add("Content-Type", "application/json; charset=UTF-8")
+ resp, err := client.Do(req)
+ if err != nil {
+ log.Fatal(err)
+ }
+ dt := time.Now().Sub(start)
+ dts = append(dts, dt)
+
+ if resp.StatusCode/100 == 2 {
+ continue
+ }
+ log.Println("code", resp.StatusCode)
+ io.Copy(os.Stdout, resp.Body)
+ }
+
+ sort.Slice(dts, func(i, j int) bool { return dts[i] < dts[j] })
+
+ var total time.Duration
+ for _, dt := range dts {
+ total += dt
+ }
+ log.Printf("min %v max %v median %v avg %v", dts[0], dts[len(dts)-1], dts[len(dts)/2], total/time.Duration(len(dts)))
+}
diff --git a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 97394c7..c631aca 100644
--- a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -805,7 +805,7 @@
}
protected Account getAccount(Account.Id accountId) {
- return getAccountState(accountId).getAccount();
+ return getAccountState(accountId).account();
}
protected AccountState getAccountState(Account.Id accountId) {
diff --git a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
index ec2d75e..d46cb97 100644
--- a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
+++ b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
@@ -61,9 +61,9 @@
private Account.Id createAccount(TestAccountCreation accountCreation) throws Exception {
AccountsUpdate.AccountUpdater accountUpdater =
(account, updateBuilder) ->
- fillBuilder(updateBuilder, accountCreation, account.getAccount().id());
+ fillBuilder(updateBuilder, accountCreation, account.account().id());
AccountState createdAccount = createAccount(accountUpdater);
- return createdAccount.getAccount().id();
+ return createdAccount.account().id();
}
private AccountState createAccount(AccountsUpdate.AccountUpdater accountUpdater)
@@ -129,13 +129,13 @@
}
private TestAccount toTestAccount(AccountState accountState) {
- Account account = accountState.getAccount();
+ Account account = accountState.account();
return TestAccount.builder()
.accountId(account.id())
.preferredEmail(Optional.ofNullable(account.preferredEmail()))
.fullname(Optional.ofNullable(account.fullName()))
- .username(accountState.getUserName())
- .active(accountState.getAccount().isActive())
+ .username(accountState.userName())
+ .active(accountState.account().isActive())
.build();
}
diff --git a/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java b/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
index 10ecd68..f7533a4 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
@@ -85,7 +85,7 @@
throw new StorageException(
String.format(
"Failed to replace account %s in index %s: %s",
- as.getAccount().id(), indexName, statusCode));
+ as.account().id(), indexName, statusCode));
}
}
@@ -108,7 +108,7 @@
@Override
protected String getId(AccountState as) {
- return as.getAccount().id().toString();
+ return as.account().id().toString();
}
@Override
diff --git a/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java b/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java
index f5a740e..458bcf5 100644
--- a/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java
+++ b/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java
@@ -15,7 +15,6 @@
package com.google.gerrit.extensions.client;
import java.util.List;
-import java.util.Map;
/** Preferences about a single user. */
public class GeneralPreferencesInfo {
@@ -145,7 +144,6 @@
public Boolean workInProgressByDefault;
public List<MenuItem> my;
public List<String> changeTable;
- public Map<String, String> urlAliases;
public DateFormat getDateFormat() {
if (dateFormat == null) {
diff --git a/java/com/google/gerrit/extensions/common/ServerInfo.java b/java/com/google/gerrit/extensions/common/ServerInfo.java
index 8904f0a..82d5bc8 100644
--- a/java/com/google/gerrit/extensions/common/ServerInfo.java
+++ b/java/com/google/gerrit/extensions/common/ServerInfo.java
@@ -14,8 +14,6 @@
package com.google.gerrit.extensions.common;
-import java.util.Map;
-
public class ServerInfo {
public AccountsInfo accounts;
public AuthInfo auth;
@@ -26,7 +24,6 @@
public PluginConfigInfo plugin;
public SshdInfo sshd;
public SuggestInfo suggest;
- public Map<String, String> urlAliases;
public UserConfigInfo user;
public ReceiveInfo receive;
public String defaultTheme;
diff --git a/java/com/google/gerrit/git/BUILD b/java/com/google/gerrit/git/BUILD
index 5ece37a..1edba38 100644
--- a/java/com/google/gerrit/git/BUILD
+++ b/java/com/google/gerrit/git/BUILD
@@ -7,6 +7,8 @@
deps = [
"//java/com/google/gerrit/common:annotations",
"//lib:guava",
+ "//lib/auto:auto-value",
+ "//lib/auto:auto-value-annotations",
"//lib/jgit/org.eclipse.jgit:jgit",
],
)
diff --git a/java/com/google/gerrit/git/GitUpdateFailureException.java b/java/com/google/gerrit/git/GitUpdateFailureException.java
new file mode 100644
index 0000000..76ef217
--- /dev/null
+++ b/java/com/google/gerrit/git/GitUpdateFailureException.java
@@ -0,0 +1,95 @@
+// 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.
+
+package com.google.gerrit.git;
+
+import static com.google.common.collect.ImmutableList.toImmutableList;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.common.UsedAt;
+import java.io.IOException;
+import java.util.Optional;
+import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.transport.ReceiveCommand;
+
+/** Thrown when updating a ref in Git fails. */
+public class GitUpdateFailureException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ private final ImmutableList<GitUpdateFailure> failures;
+
+ public GitUpdateFailureException(String message, RefUpdate refUpdate) {
+ super(message);
+ this.failures = ImmutableList.of(GitUpdateFailure.create(refUpdate));
+ }
+
+ public GitUpdateFailureException(String message, BatchRefUpdate batchRefUpdate) {
+ super(message);
+ this.failures =
+ batchRefUpdate.getCommands().stream()
+ .filter(c -> c.getResult() != ReceiveCommand.Result.OK)
+ .map(GitUpdateFailure::create)
+ .collect(toImmutableList());
+ }
+
+ /** @return the names of the refs for which the update failed. */
+ public ImmutableList<String> getFailedRefs() {
+ return failures.stream().map(GitUpdateFailure::ref).collect(toImmutableList());
+ }
+
+ /** @return the failures that caused this exception. */
+ @UsedAt(UsedAt.Project.GOOGLE)
+ public ImmutableList<GitUpdateFailure> getFailures() {
+ return failures;
+ }
+
+ @AutoValue
+ public abstract static class GitUpdateFailure {
+ private static GitUpdateFailure create(RefUpdate refUpdate) {
+ return builder().ref(refUpdate.getName()).result(refUpdate.getResult().name()).build();
+ }
+
+ private static GitUpdateFailure create(ReceiveCommand receiveCommand) {
+ return builder()
+ .ref(receiveCommand.getRefName())
+ .result(receiveCommand.getResult().name())
+ .message(receiveCommand.getMessage())
+ .build();
+ }
+
+ public abstract String ref();
+
+ public abstract String result();
+
+ public abstract Optional<String> message();
+
+ public static GitUpdateFailure.Builder builder() {
+ return new AutoValue_GitUpdateFailureException_GitUpdateFailure.Builder();
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ abstract Builder ref(String ref);
+
+ abstract Builder result(String result);
+
+ abstract Builder message(@Nullable String message);
+
+ abstract GitUpdateFailure build();
+ }
+ }
+}
diff --git a/java/com/google/gerrit/git/LockFailureException.java b/java/com/google/gerrit/git/LockFailureException.java
index 9e67d70..371488d 100644
--- a/java/com/google/gerrit/git/LockFailureException.java
+++ b/java/com/google/gerrit/git/LockFailureException.java
@@ -14,36 +14,18 @@
package com.google.gerrit.git;
-import static com.google.common.collect.ImmutableList.toImmutableList;
-
-import com.google.common.collect.ImmutableList;
-import java.io.IOException;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.RefUpdate;
-import org.eclipse.jgit.transport.ReceiveCommand;
/** Thrown when updating a ref in Git fails with LOCK_FAILURE. */
-public class LockFailureException extends IOException {
+public class LockFailureException extends GitUpdateFailureException {
private static final long serialVersionUID = 1L;
- private final ImmutableList<String> refs;
-
public LockFailureException(String message, RefUpdate refUpdate) {
- super(message);
- refs = ImmutableList.of(refUpdate.getName());
+ super(message, refUpdate);
}
public LockFailureException(String message, BatchRefUpdate batchRefUpdate) {
- super(message);
- refs =
- batchRefUpdate.getCommands().stream()
- .filter(c -> c.getResult() == ReceiveCommand.Result.LOCK_FAILURE)
- .map(ReceiveCommand::getRefName)
- .collect(toImmutableList());
- }
-
- /** Subset of ref names that caused the lock failure. */
- public ImmutableList<String> getFailedRefs() {
- return refs;
+ super(message, batchRefUpdate);
}
}
diff --git a/java/com/google/gerrit/git/RefUpdateUtil.java b/java/com/google/gerrit/git/RefUpdateUtil.java
index 520d0f2..fa7b98f 100644
--- a/java/com/google/gerrit/git/RefUpdateUtil.java
+++ b/java/com/google/gerrit/git/RefUpdateUtil.java
@@ -99,7 +99,7 @@
if (lockFailure + aborted == bru.getCommands().size()) {
throw new LockFailureException("Update aborted with one or more lock failures: " + bru, bru);
} else if (failure > 0) {
- throw new IOException("Update failed: " + bru);
+ throw new GitUpdateFailureException("Update failed: " + bru, bru);
}
}
@@ -130,7 +130,8 @@
case REJECTED_CURRENT_BRANCH:
case REJECTED_MISSING_OBJECT:
case REJECTED_OTHER_REASON:
- throw new IOException("Failed to update " + ru.getName() + ": " + ru.getResult());
+ throw new GitUpdateFailureException(
+ "Failed to update " + ru.getName() + ": " + ru.getResult(), ru);
}
}
@@ -174,7 +175,8 @@
case REJECTED_MISSING_OBJECT:
case REJECTED_OTHER_REASON:
default:
- throw new IOException("Failed to delete " + refName + ": " + ru.getResult());
+ throw new GitUpdateFailureException(
+ "Failed to delete " + refName + ": " + ru.getResult(), ru);
}
}
diff --git a/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java b/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
index 9c08857..9477cb6 100644
--- a/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
+++ b/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
@@ -201,7 +201,7 @@
private Set<String> getAllowedUserIds(IdentifiedUser user) {
Set<String> result = new HashSet<>();
result.addAll(user.getEmailAddresses());
- for (ExternalId extId : user.state().getExternalIds()) {
+ for (ExternalId extId : user.state().externalIds()) {
if (extId.isScheme(SCHEME_GPGKEY)) {
continue; // Omit GPG keys.
}
diff --git a/java/com/google/gerrit/gpg/server/PostGpgKeys.java b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
index bfd7d27..62c8660 100644
--- a/java/com/google/gerrit/gpg/server/PostGpgKeys.java
+++ b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
@@ -304,12 +304,12 @@
String msg = "GPG key " + extIdKey.get() + " associated with multiple accounts: [";
msg =
accountStates.stream()
- .map(a -> a.getAccount().id().toString())
+ .map(a -> a.account().id().toString())
.collect(joining(", ", msg, "]"));
throw new IllegalStateException(msg);
}
- return accountStates.get(0).getAccount();
+ return accountStates.get(0).account();
}
private Map<String, GpgKeyInfo> toJson(
diff --git a/java/com/google/gerrit/httpd/ContainerAuthFilter.java b/java/com/google/gerrit/httpd/ContainerAuthFilter.java
index 03ed90d..517d5db 100644
--- a/java/com/google/gerrit/httpd/ContainerAuthFilter.java
+++ b/java/com/google/gerrit/httpd/ContainerAuthFilter.java
@@ -112,13 +112,13 @@
username = username.toLowerCase(Locale.US);
}
Optional<AccountState> who =
- accountCache.getByUsername(username).filter(a -> a.getAccount().isActive());
+ accountCache.getByUsername(username).filter(a -> a.account().isActive());
if (!who.isPresent()) {
rsp.sendError(SC_UNAUTHORIZED);
return false;
}
WebSession ws = session.get();
- ws.setUserAccountId(who.get().getAccount().id());
+ ws.setUserAccountId(who.get().account().id());
ws.setAccessPathOk(AccessPath.GIT, true);
ws.setAccessPathOk(AccessPath.REST_API, true);
return true;
diff --git a/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java b/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
index aa38c27..95b0447 100644
--- a/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
+++ b/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
@@ -129,7 +129,7 @@
}
Optional<AccountState> accountState =
- accountCache.getByUsername(username).filter(a -> a.getAccount().isActive());
+ accountCache.getByUsername(username).filter(a -> a.account().isActive());
if (!accountState.isPresent()) {
logger.atWarning().log(
"Authentication failed for %s: account inactive or not provisioned in Gerrit", username);
@@ -141,7 +141,7 @@
GitBasicAuthPolicy gitBasicAuthPolicy = authConfig.getGitBasicAuthPolicy();
if (gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP
|| gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP_LDAP) {
- if (PasswordVerifier.checkPassword(who.getExternalIds(), username, password)) {
+ if (PasswordVerifier.checkPassword(who.externalIds(), username, password)) {
return succeedAuthentication(who);
}
}
@@ -158,7 +158,7 @@
setUserIdentified(whoAuthResult.getAccountId());
return true;
} catch (NoSuchUserException e) {
- if (PasswordVerifier.checkPassword(who.getExternalIds(), username, password)) {
+ if (PasswordVerifier.checkPassword(who.externalIds(), username, password)) {
return succeedAuthentication(who);
}
logger.atWarning().withCause(e).log(authenticationFailedMsg(username, req));
@@ -178,7 +178,7 @@
}
private boolean succeedAuthentication(AccountState who) {
- setUserIdentified(who.getAccount().id());
+ setUserIdentified(who.account().id());
return true;
}
diff --git a/java/com/google/gerrit/httpd/ProjectOAuthFilter.java b/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
index 3bb728f..0aa9c79 100644
--- a/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
+++ b/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
@@ -152,7 +152,7 @@
}
Optional<AccountState> who =
- accountCache.getByUsername(authInfo.username).filter(a -> a.getAccount().isActive());
+ accountCache.getByUsername(authInfo.username).filter(a -> a.account().isActive());
if (!who.isPresent()) {
logger.atWarning().log(
authenticationFailedMsg(authInfo.username, req)
@@ -161,7 +161,7 @@
return false;
}
- Account account = who.get().getAccount();
+ Account account = who.get().account();
AuthRequest authRequest = AuthRequest.forExternalUser(authInfo.username);
authRequest.setEmailAddress(account.preferredEmail());
authRequest.setDisplayName(account.fullName());
diff --git a/java/com/google/gerrit/httpd/RunAsFilter.java b/java/com/google/gerrit/httpd/RunAsFilter.java
index 0055fc7..b985741 100644
--- a/java/com/google/gerrit/httpd/RunAsFilter.java
+++ b/java/com/google/gerrit/httpd/RunAsFilter.java
@@ -105,7 +105,7 @@
Account.Id target;
try {
- target = accountResolver.resolve(runas).asUnique().getAccount().id();
+ target = accountResolver.resolve(runas).asUnique().account().id();
} catch (UnprocessableEntityException e) {
replyError(req, res, SC_FORBIDDEN, "no account matches " + RUN_AS, null);
return;
diff --git a/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java b/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
index 3eb4bcc..a600454 100644
--- a/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
@@ -153,10 +153,10 @@
if (!accountState.isPresent()) {
continue;
}
- Account account = accountState.get().getAccount();
+ Account account = accountState.get().account();
String displayName;
- if (accountState.get().getUserName().isPresent()) {
- displayName = accountState.get().getUserName().get();
+ if (accountState.get().userName().isPresent()) {
+ displayName = accountState.get().userName().get();
} else if (account.fullName() != null && !account.fullName().isEmpty()) {
displayName = account.fullName();
} else if (account.preferredEmail() != null) {
@@ -176,7 +176,7 @@
}
private Optional<AuthResult> auth(Optional<AccountState> account) {
- return account.map(a -> new AuthResult(a.getAccount().id(), null, false));
+ return account.map(a -> new AuthResult(a.account().id(), null, false));
}
private AuthResult auth(Account.Id account) {
@@ -196,7 +196,7 @@
getServletContext().log("Multiple accounts with username " + userName + " found");
return null;
}
- return auth(accountStates.get(0).getAccount().id());
+ return auth(accountStates.get(0).account().id());
}
private Optional<AuthResult> byPreferredEmail(String email) {
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index 0366e1d..7af7f45 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -166,6 +166,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
@@ -209,6 +210,7 @@
public static final String XD_AUTHORIZATION = "access_token";
public static final String XD_CONTENT_TYPE = "$ct";
public static final String XD_METHOD = "$m";
+ public static final int SC_TOO_MANY_REQUESTS = 429;
private static final int HEAP_EST_SIZE = 10 * 8 * 1024; // Presize 10 blocks.
private static final String PLAIN_TEXT = "text/plain";
@@ -280,6 +282,7 @@
private final Globals globals;
private final Provider<RestCollection<RestResource, RestResource>> members;
+ private Optional<String> traceId;
public RestApiServlet(
Globals globals, RestCollection<? extends RestResource, ? extends RestResource> members) {
@@ -551,7 +554,8 @@
throw new ResourceNotFoundException();
}
- response.traceId().ifPresent(traceId -> res.addHeader(X_GERRIT_TRACE, traceId));
+ traceId = response.traceId();
+ traceId.ifPresent(traceId -> res.addHeader(X_GERRIT_TRACE, traceId));
if (response instanceof Response.Redirect) {
CacheHeaders.setNotCacheable(res);
@@ -648,7 +652,13 @@
}
} catch (QuotaException e) {
responseBytes =
- replyError(req, res, status = 429, messageOr(e, "Quota limit reached"), e.caching(), e);
+ replyError(
+ req,
+ res,
+ status = SC_TOO_MANY_REQUESTS,
+ messageOr(e, "Quota limit reached"),
+ e.caching(),
+ e);
} catch (Exception e) {
status = SC_INTERNAL_SERVER_ERROR;
responseBytes = handleException(e, req, res);
@@ -1485,11 +1495,12 @@
}
}
- private static long handleException(
- Throwable err, HttpServletRequest req, HttpServletResponse res) throws IOException {
+ private long handleException(Throwable err, HttpServletRequest req, HttpServletResponse res)
+ throws IOException {
logger.atSevere().withCause(err).log("Error in %s %s", req.getMethod(), uriForLogging(req));
if (!res.isCommitted()) {
res.reset();
+ traceId.ifPresent(traceId -> res.addHeader(X_GERRIT_TRACE, traceId));
return replyError(req, res, SC_INTERNAL_SERVER_ERROR, "Internal server error", err);
}
return 0;
diff --git a/java/com/google/gerrit/index/query/TooManyTermsInQueryException.java b/java/com/google/gerrit/index/query/TooManyTermsInQueryException.java
new file mode 100644
index 0000000..b0a394e
--- /dev/null
+++ b/java/com/google/gerrit/index/query/TooManyTermsInQueryException.java
@@ -0,0 +1,29 @@
+// 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.
+
+package com.google.gerrit.index.query;
+
+public class TooManyTermsInQueryException extends QueryParseException {
+ private static final long serialVersionUID = 1L;
+
+ private static final String MESSAGE = "too many terms in query";
+
+ public TooManyTermsInQueryException() {
+ super(MESSAGE);
+ }
+
+ public TooManyTermsInQueryException(Throwable why) {
+ super(MESSAGE, why);
+ }
+}
diff --git a/java/com/google/gerrit/lucene/LuceneAccountIndex.java b/java/com/google/gerrit/lucene/LuceneAccountIndex.java
index 8e67fda..27aa37f 100644
--- a/java/com/google/gerrit/lucene/LuceneAccountIndex.java
+++ b/java/com/google/gerrit/lucene/LuceneAccountIndex.java
@@ -62,7 +62,7 @@
private static final String ID_SORT_FIELD = sortFieldName(ID);
private static Term idTerm(AccountState as) {
- return idTerm(as.getAccount().id());
+ return idTerm(as.account().id());
}
private static Term idTerm(Account.Id id) {
diff --git a/java/com/google/gerrit/server/ExceptionHook.java b/java/com/google/gerrit/server/ExceptionHook.java
new file mode 100644
index 0000000..ea76330
--- /dev/null
+++ b/java/com/google/gerrit/server/ExceptionHook.java
@@ -0,0 +1,42 @@
+// 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.
+
+package com.google.gerrit.server;
+
+import com.google.gerrit.extensions.annotations.ExtensionPoint;
+
+/**
+ * Allows implementors to control how certain exceptions should be handled.
+ *
+ * <p>This interface is intended to be implemented for multi-master setups to control the behavior
+ * for handling exceptions that are thrown by a lower layer that handles the consensus and
+ * synchronization between different server nodes. E.g. if an operation fails because consensus for
+ * a Git update could not be achieved (e.g. due to slow responding server nodes) this interface can
+ * be used to retry the request instead of failing it immediately.
+ */
+@ExtensionPoint
+public interface ExceptionHook {
+ /**
+ * Whether an operation should be retried if it failed with the given throwable.
+ *
+ * <p>Only affects operations that are executed with {@link
+ * com.google.gerrit.server.update.RetryHelper}.
+ *
+ * @param throwable throwable that was thrown while executing the operation
+ * @return whether the operation should be retried
+ */
+ default boolean shouldRetry(Throwable throwable) {
+ return false;
+ }
+}
diff --git a/java/com/google/gerrit/server/IdentifiedUser.java b/java/com/google/gerrit/server/IdentifiedUser.java
index 7e18280..f29850a 100644
--- a/java/com/google/gerrit/server/IdentifiedUser.java
+++ b/java/com/google/gerrit/server/IdentifiedUser.java
@@ -234,7 +234,7 @@
groupBackend,
enableReverseDnsLookup,
remotePeerProvider,
- state.getAccount().id(),
+ state.account().id(),
realUser);
this.state = state;
}
@@ -323,7 +323,7 @@
*/
@Override
public Optional<String> getUserName() {
- return state().getUserName();
+ return state().userName();
}
/** @return unique name of the user for logging, never {@code null} */
@@ -339,7 +339,7 @@
* @return the account of the identified user, an empty account if the account is missing
*/
public Account getAccount() {
- return state().getAccount();
+ return state().account();
}
public boolean hasEmailAddress(String email) {
@@ -376,7 +376,7 @@
@Override
public GroupMembership getEffectiveGroups() {
if (effectiveGroups == null) {
- if (authConfig.isIdentityTrustable(state().getExternalIds())) {
+ if (authConfig.isIdentityTrustable(state().externalIds())) {
effectiveGroups = groupBackend.membershipsOf(this);
logger.atFinest().log(
"Known groups of %s: %s", getLoggableName(), lazy(effectiveGroups::getKnownGroups));
diff --git a/java/com/google/gerrit/server/StarredChangesUtil.java b/java/com/google/gerrit/server/StarredChangesUtil.java
index 6a23084..1b1fab6 100644
--- a/java/com/google/gerrit/server/StarredChangesUtil.java
+++ b/java/com/google/gerrit/server/StarredChangesUtil.java
@@ -32,6 +32,7 @@
import com.google.common.primitives.Ints;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.exceptions.StorageException;
+import com.google.gerrit.git.GitUpdateFailureException;
import com.google.gerrit.git.LockFailureException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
@@ -268,7 +269,7 @@
if (command.getResult() == ReceiveCommand.Result.LOCK_FAILURE) {
throw new LockFailureException(message, batchUpdate);
}
- throw new IOException(message);
+ throw new GitUpdateFailureException(message, batchUpdate);
}
}
}
diff --git a/java/com/google/gerrit/server/account/AbstractRealm.java b/java/com/google/gerrit/server/account/AbstractRealm.java
index e61736d..380001d 100644
--- a/java/com/google/gerrit/server/account/AbstractRealm.java
+++ b/java/com/google/gerrit/server/account/AbstractRealm.java
@@ -53,7 +53,7 @@
@Override
public boolean hasEmailAddress(IdentifiedUser user, String email) {
- for (ExternalId ext : user.state().getExternalIds()) {
+ for (ExternalId ext : user.state().externalIds()) {
if (email != null && email.equalsIgnoreCase(ext.email())) {
return true;
}
@@ -63,7 +63,7 @@
@Override
public Set<String> getEmailAddresses(IdentifiedUser user) {
- Collection<ExternalId> ids = user.state().getExternalIds();
+ Collection<ExternalId> ids = user.state().externalIds();
Set<String> emails = Sets.newHashSetWithExpectedSize(ids.size());
for (ExternalId ext : ids) {
if (!Strings.isNullOrEmpty(ext.email())) {
diff --git a/java/com/google/gerrit/server/account/AccountCacheImpl.java b/java/com/google/gerrit/server/account/AccountCacheImpl.java
index fe386ee..0decc91 100644
--- a/java/com/google/gerrit/server/account/AccountCacheImpl.java
+++ b/java/com/google/gerrit/server/account/AccountCacheImpl.java
@@ -133,7 +133,7 @@
}
for (Future<Optional<AccountState>> f : futures) {
try {
- f.get().ifPresent(s -> accountStates.put(s.getAccount().id(), s));
+ f.get().ifPresent(s -> accountStates.put(s.account().id(), s));
} catch (InterruptedException | ExecutionException e) {
logger.atSevere().withCause(e).log("Cannot load AccountState");
}
diff --git a/java/com/google/gerrit/server/account/AccountConfig.java b/java/com/google/gerrit/server/account/AccountConfig.java
index 5263bad..441391f 100644
--- a/java/com/google/gerrit/server/account/AccountConfig.java
+++ b/java/com/google/gerrit/server/account/AccountConfig.java
@@ -68,7 +68,7 @@
* <li>'account.config': Contains the account properties. Parsing and writing it is delegated to
* {@link AccountProperties}.
* <li>'preferences.config': Contains the preferences. Parsing and writing it is delegated to
- * {@link Preferences}.
+ * {@link StoredPreferences}.
* <li>'account.config': Contains the project watches. Parsing and writing it is delegated to
* {@link ProjectWatches}.
* </ul>
@@ -85,7 +85,7 @@
private Optional<AccountProperties> loadedAccountProperties;
private Optional<ObjectId> externalIdsRev;
private ProjectWatches projectWatches;
- private Preferences preferences;
+ private StoredPreferences preferences;
private Optional<InternalAccountUpdate> accountUpdate = Optional.empty();
private List<ValidationError> validationErrors;
@@ -242,10 +242,10 @@
projectWatches = new ProjectWatches(accountId, readConfig(ProjectWatches.WATCH_CONFIG), this);
preferences =
- new Preferences(
+ new StoredPreferences(
accountId,
- readConfig(Preferences.PREFERENCES_CONFIG),
- Preferences.readDefaultConfig(allUsersName, repo),
+ readConfig(StoredPreferences.PREFERENCES_CONFIG),
+ StoredPreferences.readDefaultConfig(allUsersName, repo),
this);
projectWatches.parse();
@@ -256,8 +256,11 @@
projectWatches = new ProjectWatches(accountId, new Config(), this);
preferences =
- new Preferences(
- accountId, new Config(), Preferences.readDefaultConfig(allUsersName, repo), this);
+ new StoredPreferences(
+ accountId,
+ new Config(),
+ StoredPreferences.readDefaultConfig(allUsersName, repo),
+ this);
}
Ref externalIdsRef = repo.exactRef(RefNames.REFS_EXTERNAL_IDS);
@@ -331,7 +334,7 @@
}
saveConfig(
- Preferences.PREFERENCES_CONFIG,
+ StoredPreferences.PREFERENCES_CONFIG,
preferences.saveGeneralPreferences(
accountUpdate.get().getGeneralPreferences(),
accountUpdate.get().getDiffPreferences(),
diff --git a/java/com/google/gerrit/server/account/AccountControl.java b/java/com/google/gerrit/server/account/AccountControl.java
index fc0bfd0..05749a1 100644
--- a/java/com/google/gerrit/server/account/AccountControl.java
+++ b/java/com/google/gerrit/server/account/AccountControl.java
@@ -133,7 +133,7 @@
new OtherUser() {
@Override
Account.Id getId() {
- return otherUser.getAccount().id();
+ return otherUser.account().id();
}
@Override
diff --git a/java/com/google/gerrit/server/account/AccountDeactivator.java b/java/com/google/gerrit/server/account/AccountDeactivator.java
index 1bd17bc..3465459 100644
--- a/java/com/google/gerrit/server/account/AccountDeactivator.java
+++ b/java/com/google/gerrit/server/account/AccountDeactivator.java
@@ -100,15 +100,15 @@
}
private boolean processAccount(AccountState accountState) {
- if (!accountState.getUserName().isPresent()) {
+ if (!accountState.userName().isPresent()) {
return false;
}
- String userName = accountState.getUserName().get();
+ String userName = accountState.userName().get();
logger.atFine().log("processing account %s", userName);
try {
- if (realm.accountBelongsToRealm(accountState.getExternalIds()) && !realm.isActive(userName)) {
- sif.deactivate(accountState.getAccount().id());
+ if (realm.accountBelongsToRealm(accountState.externalIds()) && !realm.isActive(userName)) {
+ sif.deactivate(accountState.account().id());
logger.atInfo().log("deactivated account %s", userName);
return true;
}
@@ -117,7 +117,7 @@
} catch (Exception e) {
logger.atSevere().withCause(e).log(
"Error deactivating account: %s (%s) %s",
- userName, accountState.getAccount().id(), e.getMessage());
+ userName, accountState.account().id(), e.getMessage());
}
return false;
}
diff --git a/java/com/google/gerrit/server/account/AccountManager.java b/java/com/google/gerrit/server/account/AccountManager.java
index 09757eb..c5d291e 100644
--- a/java/com/google/gerrit/server/account/AccountManager.java
+++ b/java/com/google/gerrit/server/account/AccountManager.java
@@ -151,7 +151,7 @@
}
// Account exists
- Optional<Account> act = updateAccountActiveStatus(who, accountState.get().getAccount());
+ Optional<Account> act = updateAccountActiveStatus(who, accountState.get().account());
if (!act.isPresent()) {
// The account was deleted since we checked for it last time. This should never happen
// since we don't support deletion of accounts.
@@ -207,7 +207,7 @@
throw new AccountException("Unable to deactivate account " + account.id(), e);
}
}
- return byIdCache.get(account.id()).map(AccountState::getAccount);
+ return byIdCache.get(account.id()).map(AccountState::account);
}
private boolean shouldUpdateActiveStatus(AuthRequest authRequest) {
@@ -337,7 +337,7 @@
addGroupMember(adminGroupUuid, user);
}
- realm.onCreateAccount(who, accountState.getAccount());
+ realm.onCreateAccount(who, accountState.account());
return new AuthResult(newId, extId.key(), true);
}
@@ -421,7 +421,7 @@
to,
(a, u) -> {
u.addExternalId(newExtId);
- if (who.getEmailAddress() != null && a.getAccount().preferredEmail() == null) {
+ if (who.getEmailAddress() != null && a.account().preferredEmail() == null) {
u.setPreferredEmail(who.getEmailAddress());
}
});
@@ -450,7 +450,7 @@
to,
(a, u) -> {
Set<ExternalId> filteredExtIdsByScheme =
- a.getExternalIds().stream()
+ a.externalIds().stream()
.filter(e -> e.key().isScheme(who.getExternalIdKey().scheme()))
.collect(toImmutableSet());
if (filteredExtIdsByScheme.isEmpty()) {
@@ -514,9 +514,9 @@
from,
(a, u) -> {
u.deleteExternalIds(extIds);
- if (a.getAccount().preferredEmail() != null
+ if (a.account().preferredEmail() != null
&& extIds.stream()
- .anyMatch(e -> a.getAccount().preferredEmail().equals(e.email()))) {
+ .anyMatch(e -> a.account().preferredEmail().equals(e.email()))) {
u.setPreferredEmail(null);
}
});
diff --git a/java/com/google/gerrit/server/account/AccountResolver.java b/java/com/google/gerrit/server/account/AccountResolver.java
index d07765c..058cb62 100644
--- a/java/com/google/gerrit/server/account/AccountResolver.java
+++ b/java/com/google/gerrit/server/account/AccountResolver.java
@@ -113,9 +113,9 @@
}
private static String formatForException(Result result, AccountState state) {
- return state.getAccount().id()
+ return state.account().id()
+ ": "
- + state.getAccount().getNameEmail(result.accountResolver().anonymousCowardName);
+ + state.account().getNameEmail(result.accountResolver().anonymousCowardName);
}
public static boolean isSelf(String input) {
@@ -135,7 +135,7 @@
}
private ImmutableList<AccountState> canonicalize(List<AccountState> list) {
- TreeSet<AccountState> set = new TreeSet<>(comparing(a -> a.getAccount().id().get()));
+ TreeSet<AccountState> set = new TreeSet<>(comparing(a -> a.account().id().get()));
set.addAll(requireNonNull(list));
return ImmutableList.copyOf(set);
}
@@ -160,7 +160,7 @@
}
public ImmutableSet<Account.Id> asIdSet() {
- return list.stream().map(a -> a.getAccount().id()).collect(toImmutableSet());
+ return list.stream().map(a -> a.account().id()).collect(toImmutableSet());
}
public AccountState asUnique() throws UnresolvableAccountException {
@@ -192,7 +192,7 @@
return self.get().asIdentifiedUser();
}
return userFactory.runAs(
- null, list.get(0).getAccount().id(), requireNonNull(caller).getRealUser());
+ null, list.get(0).account().id(), requireNonNull(caller).getRealUser());
}
@VisibleForTesting
@@ -349,7 +349,7 @@
String name = nameOrEmail.substring(0, lt - 1);
ImmutableList<AccountState> nameMatches =
allMatches.stream()
- .filter(a -> name.equals(a.getAccount().fullName()))
+ .filter(a -> name.equals(a.account().fullName()))
.collect(toImmutableList());
return !nameMatches.isEmpty() ? nameMatches.stream() : allMatches.stream();
}
@@ -558,7 +558,7 @@
}
private Predicate<AccountState> accountActivityPredicate() {
- return (AccountState accountState) -> accountState.getAccount().isActive();
+ return (AccountState accountState) -> accountState.account().isActive();
}
@VisibleForTesting
diff --git a/java/com/google/gerrit/server/account/AccountState.java b/java/com/google/gerrit/server/account/AccountState.java
index 6eb6ca1..745f197 100644
--- a/java/com/google/gerrit/server/account/AccountState.java
+++ b/java/com/google/gerrit/server/account/AccountState.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.account;
+import com.google.auto.value.AutoValue;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -39,7 +40,8 @@
* <p>Most callers should not construct AccountStates directly but rather lookup accounts via the
* account cache (see {@link AccountCache#get(Account.Id)}).
*/
-public class AccountState {
+@AutoValue
+public abstract class AccountState {
/**
* Creates an AccountState from the given account config.
*
@@ -90,13 +92,22 @@
// an open Repository instance.
ImmutableMap<ProjectWatchKey, ImmutableSet<NotifyType>> projectWatches =
accountConfig.getProjectWatches();
- GeneralPreferencesInfo generalPreferences = accountConfig.getGeneralPreferences();
- DiffPreferencesInfo diffPreferences = accountConfig.getDiffPreferences();
- EditPreferencesInfo editPreferences = accountConfig.getEditPreferences();
+ Preferences.General generalPreferences =
+ Preferences.General.fromInfo(accountConfig.getGeneralPreferences());
+ Preferences.Diff diffPreferences =
+ Preferences.Diff.fromInfo(accountConfig.getDiffPreferences());
+ Preferences.Edit editPreferences =
+ Preferences.Edit.fromInfo(accountConfig.getEditPreferences());
return Optional.of(
- new AccountState(
- account, extIds, projectWatches, generalPreferences, diffPreferences, editPreferences));
+ new AutoValue_AccountState(
+ account,
+ extIds,
+ ExternalId.getUserName(extIds),
+ projectWatches,
+ generalPreferences,
+ diffPreferences,
+ editPreferences));
}
/**
@@ -118,44 +129,20 @@
* @return the account state
*/
public static AccountState forAccount(Account account, Collection<ExternalId> extIds) {
- return new AccountState(
+ return new AutoValue_AccountState(
account,
ImmutableSet.copyOf(extIds),
+ ExternalId.getUserName(extIds),
ImmutableMap.of(),
- GeneralPreferencesInfo.defaults(),
- DiffPreferencesInfo.defaults(),
- EditPreferencesInfo.defaults());
- }
-
- private final Account account;
- private final ImmutableSet<ExternalId> externalIds;
- private final Optional<String> userName;
- private final ImmutableMap<ProjectWatchKey, ImmutableSet<NotifyType>> projectWatches;
- private final GeneralPreferencesInfo generalPreferences;
- private final DiffPreferencesInfo diffPreferences;
- private final EditPreferencesInfo editPreferences;
-
- private AccountState(
- Account account,
- ImmutableSet<ExternalId> externalIds,
- ImmutableMap<ProjectWatchKey, ImmutableSet<NotifyType>> projectWatches,
- GeneralPreferencesInfo generalPreferences,
- DiffPreferencesInfo diffPreferences,
- EditPreferencesInfo editPreferences) {
- this.account = account;
- this.externalIds = externalIds;
- this.userName = ExternalId.getUserName(externalIds);
- this.projectWatches = projectWatches;
- this.generalPreferences = generalPreferences;
- this.diffPreferences = diffPreferences;
- this.editPreferences = editPreferences;
+ Preferences.General.fromInfo(GeneralPreferencesInfo.defaults()),
+ Preferences.Diff.fromInfo(DiffPreferencesInfo.defaults()),
+ Preferences.Edit.fromInfo(EditPreferencesInfo.defaults()));
}
/** Get the cached account metadata. */
- public Account getAccount() {
- return account;
- }
-
+ public abstract Account account();
+ /** The external identities that identify the account holder. */
+ public abstract ImmutableSet<ExternalId> externalIds();
/**
* Get the username, if one has been declared for this user.
*
@@ -164,39 +151,36 @@
* @return the username, {@link Optional#empty()} if the user has no username, or if the username
* is empty
*/
- public Optional<String> getUserName() {
- return userName;
- }
-
- /** The external identities that identify the account holder. */
- public ImmutableSet<ExternalId> getExternalIds() {
- return externalIds;
- }
-
+ public abstract Optional<String> userName();
/** The project watches of the account. */
- public ImmutableMap<ProjectWatchKey, ImmutableSet<NotifyType>> getProjectWatches() {
- return projectWatches;
- }
+ public abstract ImmutableMap<ProjectWatchKey, ImmutableSet<NotifyType>> projectWatches();
+ /** The general preferences of the account. */
/** The general preferences of the account. */
- public GeneralPreferencesInfo getGeneralPreferences() {
- return generalPreferences;
+ public GeneralPreferencesInfo generalPreferences() {
+ return immutableGeneralPreferences().toInfo();
}
/** The diff preferences of the account. */
- public DiffPreferencesInfo getDiffPreferences() {
- return diffPreferences;
+ public DiffPreferencesInfo diffPreferences() {
+ return immutableDiffPreferences().toInfo();
}
/** The edit preferences of the account. */
- public EditPreferencesInfo getEditPreferences() {
- return editPreferences;
+ public EditPreferencesInfo editPreferences() {
+ return immutableEditPreferences().toInfo();
}
@Override
- public String toString() {
+ public final String toString() {
MoreObjects.ToStringHelper h = MoreObjects.toStringHelper(this);
- h.addValue(getAccount().id());
+ h.addValue(account().id());
return h.toString();
}
+
+ protected abstract Preferences.General immutableGeneralPreferences();
+
+ protected abstract Preferences.Diff immutableDiffPreferences();
+
+ protected abstract Preferences.Edit immutableEditPreferences();
}
diff --git a/java/com/google/gerrit/server/account/AccountsConsistencyChecker.java b/java/com/google/gerrit/server/account/AccountsConsistencyChecker.java
index 6ec3a05..289a587 100644
--- a/java/com/google/gerrit/server/account/AccountsConsistencyChecker.java
+++ b/java/com/google/gerrit/server/account/AccountsConsistencyChecker.java
@@ -35,9 +35,9 @@
List<ConsistencyProblemInfo> problems = new ArrayList<>();
for (AccountState accountState : accounts.all()) {
- Account account = accountState.getAccount();
+ Account account = accountState.account();
if (account.preferredEmail() != null) {
- if (!accountState.getExternalIds().stream()
+ if (!accountState.externalIds().stream()
.anyMatch(e -> account.preferredEmail().equals(e.email()))) {
addError(
String.format(
diff --git a/java/com/google/gerrit/server/account/AccountsUpdate.java b/java/com/google/gerrit/server/account/AccountsUpdate.java
index 2920cef..db49467 100644
--- a/java/com/google/gerrit/server/account/AccountsUpdate.java
+++ b/java/com/google/gerrit/server/account/AccountsUpdate.java
@@ -88,9 +88,9 @@
* The timestamp of the first commit on a user branch denotes the registration date. The initial
* commit on the user branch may be empty (since having an 'account.config' is optional). See {@link
* AccountConfig} for details of the 'account.config' file format. In addition the user branch can
- * contain a 'preferences.config' config file to store preferences (see {@link Preferences}) and a
- * 'watch.config' config file to store project watches (see {@link ProjectWatches}). External IDs
- * are stored separately in the {@code refs/meta/external-ids} notes branch (see {@link
+ * contain a 'preferences.config' config file to store preferences (see {@link StoredPreferences})
+ * and a 'watch.config' config file to store project watches (see {@link ProjectWatches}). External
+ * IDs are stored separately in the {@code refs/meta/external-ids} notes branch (see {@link
* ExternalIdNotes}).
*
* <p>On updating an account the account is evicted from the account cache and reindexed. The
diff --git a/java/com/google/gerrit/server/account/Emails.java b/java/com/google/gerrit/server/account/Emails.java
index 1d53ed2..ee2b672 100644
--- a/java/com/google/gerrit/server/account/Emails.java
+++ b/java/com/google/gerrit/server/account/Emails.java
@@ -82,7 +82,7 @@
}
return executeIndexQuery(() -> queryProvider.get().byPreferredEmail(email).stream())
- .map(a -> a.getAccount().id())
+ .map(a -> a.account().id())
.collect(toImmutableSet());
}
@@ -102,7 +102,7 @@
if (!emailsToBackfill.isEmpty()) {
executeIndexQuery(
() -> queryProvider.get().byPreferredEmail(emailsToBackfill).entries().stream())
- .forEach(e -> result.put(e.getKey(), e.getValue().getAccount().id()));
+ .forEach(e -> result.put(e.getKey(), e.getValue().account().id()));
}
return ImmutableSetMultimap.copyOf(result);
}
diff --git a/java/com/google/gerrit/server/account/GroupMembers.java b/java/com/google/gerrit/server/account/GroupMembers.java
index d7e97ba..1ce3ccf 100644
--- a/java/com/google/gerrit/server/account/GroupMembers.java
+++ b/java/com/google/gerrit/server/account/GroupMembers.java
@@ -131,7 +131,7 @@
.filter(groupControl::canSeeMember)
.map(accountCache::get)
.flatMap(Streams::stream)
- .map(AccountState::getAccount)
+ .map(AccountState::account)
.collect(toImmutableSet());
Set<Account> indirectMembers = new HashSet<>();
diff --git a/java/com/google/gerrit/server/account/InternalAccountDirectory.java b/java/com/google/gerrit/server/account/InternalAccountDirectory.java
index dde8f25..160e355 100644
--- a/java/com/google/gerrit/server/account/InternalAccountDirectory.java
+++ b/java/com/google/gerrit/server/account/InternalAccountDirectory.java
@@ -105,7 +105,7 @@
AccountState state = accountStates.get(id);
if (state != null) {
if (!options.contains(FillOptions.SECONDARY_EMAILS)
- || Objects.equals(currentUserId, state.getAccount().id())
+ || Objects.equals(currentUserId, state.account().id())
|| canModifyAccount) {
fill(info, accountStates.get(id), options);
} else {
@@ -120,7 +120,7 @@
}
private void fill(AccountInfo info, AccountState accountState, Set<FillOptions> options) {
- Account account = accountState.getAccount();
+ Account account = accountState.account();
if (options.contains(FillOptions.ID)) {
info._accountId = account.id().get();
} else {
@@ -130,17 +130,17 @@
if (options.contains(FillOptions.NAME)) {
info.name = Strings.emptyToNull(account.fullName());
if (info.name == null) {
- info.name = accountState.getUserName().orElse(null);
+ info.name = accountState.userName().orElse(null);
}
}
if (options.contains(FillOptions.EMAIL)) {
info.email = account.preferredEmail();
}
if (options.contains(FillOptions.SECONDARY_EMAILS)) {
- info.secondaryEmails = getSecondaryEmails(account, accountState.getExternalIds());
+ info.secondaryEmails = getSecondaryEmails(account, accountState.externalIds());
}
if (options.contains(FillOptions.USERNAME)) {
- info.username = accountState.getUserName().orElse(null);
+ info.username = accountState.userName().orElse(null);
}
if (options.contains(FillOptions.STATUS)) {
diff --git a/java/com/google/gerrit/server/account/Preferences.java b/java/com/google/gerrit/server/account/Preferences.java
index bba5843..c15e6b0 100644
--- a/java/com/google/gerrit/server/account/Preferences.java
+++ b/java/com/google/gerrit/server/account/Preferences.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2018 The Android Open Source Project
+// 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.
@@ -11,606 +11,446 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
package com.google.gerrit.server.account;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.gerrit.server.config.ConfigUtil.loadSection;
-import static com.google.gerrit.server.config.ConfigUtil.skipField;
-import static com.google.gerrit.server.config.ConfigUtil.storeSection;
-import static com.google.gerrit.server.git.UserConfigSections.CHANGE_TABLE;
-import static com.google.gerrit.server.git.UserConfigSections.CHANGE_TABLE_COLUMN;
-import static com.google.gerrit.server.git.UserConfigSections.KEY_ID;
-import static com.google.gerrit.server.git.UserConfigSections.KEY_MATCH;
-import static com.google.gerrit.server.git.UserConfigSections.KEY_TARGET;
-import static com.google.gerrit.server.git.UserConfigSections.KEY_TOKEN;
-import static com.google.gerrit.server.git.UserConfigSections.KEY_URL;
-import static com.google.gerrit.server.git.UserConfigSections.URL_ALIAS;
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import com.google.common.flogger.FluentLogger;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import com.google.gerrit.extensions.client.EditPreferencesInfo;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
+import com.google.gerrit.extensions.client.GeneralPreferencesInfo.DateFormat;
+import com.google.gerrit.extensions.client.GeneralPreferencesInfo.DefaultBase;
+import com.google.gerrit.extensions.client.GeneralPreferencesInfo.DiffView;
+import com.google.gerrit.extensions.client.GeneralPreferencesInfo.DownloadCommand;
+import com.google.gerrit.extensions.client.GeneralPreferencesInfo.EmailFormat;
+import com.google.gerrit.extensions.client.GeneralPreferencesInfo.EmailStrategy;
+import com.google.gerrit.extensions.client.GeneralPreferencesInfo.TimeFormat;
+import com.google.gerrit.extensions.client.KeyMapType;
import com.google.gerrit.extensions.client.MenuItem;
-import com.google.gerrit.extensions.restapi.BadRequestException;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.git.UserConfigSections;
-import com.google.gerrit.server.git.ValidationError;
-import com.google.gerrit.server.git.meta.MetaDataUpdate;
-import com.google.gerrit.server.git.meta.VersionedMetaData;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import com.google.gerrit.extensions.client.Theme;
import java.util.Optional;
-import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.lib.CommitBuilder;
-import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.Repository;
-/**
- * Parses/writes preferences from/to a {@link Config} file.
- *
- * <p>This is a low-level API. Read/write of preferences in a user branch should be done through
- * {@link AccountsUpdate} or {@link AccountConfig}.
- *
- * <p>The config file has separate sections for general, diff and edit preferences:
- *
- * <pre>
- * [diff]
- * hideTopMenu = true
- * [edit]
- * lineLength = 80
- * </pre>
- *
- * <p>The parameter names match the names that are used in the preferences REST API.
- *
- * <p>If the preference is omitted in the config file, then the default value for the preference is
- * used.
- *
- * <p>Defaults for preferences that apply for all accounts can be configured in the {@code
- * refs/users/default} branch in the {@code All-Users} repository. The config for the default
- * preferences must be provided to this class so that it can read default values from it.
- *
- * <p>The preferences are lazily parsed.
- */
-public class Preferences {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+@AutoValue
+public abstract class Preferences {
+ @AutoValue
+ public abstract static class General {
+ public abstract Optional<Integer> changesPerPage();
- public static final String PREFERENCES_CONFIG = "preferences.config";
+ public abstract Optional<String> downloadScheme();
- private final Account.Id accountId;
- private final Config cfg;
- private final Config defaultCfg;
- private final ValidationError.Sink validationErrorSink;
+ public abstract Optional<DownloadCommand> downloadCommand();
- private GeneralPreferencesInfo generalPreferences;
- private DiffPreferencesInfo diffPreferences;
- private EditPreferencesInfo editPreferences;
+ public abstract Optional<DateFormat> dateFormat();
- Preferences(
- Account.Id accountId,
- Config cfg,
- Config defaultCfg,
- ValidationError.Sink validationErrorSink) {
- this.accountId = requireNonNull(accountId, "accountId");
- this.cfg = requireNonNull(cfg, "cfg");
- this.defaultCfg = requireNonNull(defaultCfg, "defaultCfg");
- this.validationErrorSink = requireNonNull(validationErrorSink, "validationErrorSink");
- }
+ public abstract Optional<TimeFormat> timeFormat();
- public GeneralPreferencesInfo getGeneralPreferences() {
- if (generalPreferences == null) {
- parse();
- }
- return generalPreferences;
- }
+ public abstract Optional<Boolean> expandInlineDiffs();
- public DiffPreferencesInfo getDiffPreferences() {
- if (diffPreferences == null) {
- parse();
- }
- return diffPreferences;
- }
+ public abstract Optional<Boolean> highlightAssigneeInChangeTable();
- public EditPreferencesInfo getEditPreferences() {
- if (editPreferences == null) {
- parse();
- }
- return editPreferences;
- }
+ public abstract Optional<Boolean> relativeDateInChangeTable();
- public void parse() {
- generalPreferences = parseGeneralPreferences(null);
- diffPreferences = parseDiffPreferences(null);
- editPreferences = parseEditPreferences(null);
- }
+ public abstract Optional<DiffView> diffView();
- public Config saveGeneralPreferences(
- Optional<GeneralPreferencesInfo> generalPreferencesInput,
- Optional<DiffPreferencesInfo> diffPreferencesInput,
- Optional<EditPreferencesInfo> editPreferencesInput)
- throws ConfigInvalidException {
- if (generalPreferencesInput.isPresent()) {
- GeneralPreferencesInfo mergedGeneralPreferencesInput =
- parseGeneralPreferences(generalPreferencesInput.get());
+ public abstract Optional<Boolean> sizeBarInChangeTable();
- storeSection(
- cfg,
- UserConfigSections.GENERAL,
- null,
- mergedGeneralPreferencesInput,
- parseDefaultGeneralPreferences(defaultCfg, null));
- setChangeTable(cfg, mergedGeneralPreferencesInput.changeTable);
- setMy(cfg, mergedGeneralPreferencesInput.my);
- setUrlAliases(cfg, mergedGeneralPreferencesInput.urlAliases);
+ public abstract Optional<Boolean> legacycidInChangeTable();
- // evict the cached general preferences
- this.generalPreferences = null;
+ public abstract Optional<Boolean> muteCommonPathPrefixes();
+
+ public abstract Optional<Boolean> signedOffBy();
+
+ public abstract Optional<EmailStrategy> emailStrategy();
+
+ public abstract Optional<EmailFormat> emailFormat();
+
+ public abstract Optional<DefaultBase> defaultBaseForMerges();
+
+ public abstract Optional<Boolean> publishCommentsOnPush();
+
+ public abstract Optional<Boolean> workInProgressByDefault();
+
+ public abstract Optional<ImmutableList<MenuItem>> my();
+
+ public abstract Optional<ImmutableList<String>> changeTable();
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+ abstract Builder changesPerPage(@Nullable Integer val);
+
+ abstract Builder downloadScheme(@Nullable String val);
+
+ abstract Builder downloadCommand(@Nullable DownloadCommand val);
+
+ abstract Builder dateFormat(@Nullable DateFormat val);
+
+ abstract Builder timeFormat(@Nullable TimeFormat val);
+
+ abstract Builder expandInlineDiffs(@Nullable Boolean val);
+
+ abstract Builder highlightAssigneeInChangeTable(@Nullable Boolean val);
+
+ abstract Builder relativeDateInChangeTable(@Nullable Boolean val);
+
+ abstract Builder diffView(@Nullable DiffView val);
+
+ abstract Builder sizeBarInChangeTable(@Nullable Boolean val);
+
+ abstract Builder legacycidInChangeTable(@Nullable Boolean val);
+
+ abstract Builder muteCommonPathPrefixes(@Nullable Boolean val);
+
+ abstract Builder signedOffBy(@Nullable Boolean val);
+
+ abstract Builder emailStrategy(@Nullable EmailStrategy val);
+
+ abstract Builder emailFormat(@Nullable EmailFormat val);
+
+ abstract Builder defaultBaseForMerges(@Nullable DefaultBase val);
+
+ abstract Builder publishCommentsOnPush(@Nullable Boolean val);
+
+ abstract Builder workInProgressByDefault(@Nullable Boolean val);
+
+ abstract Builder my(@Nullable ImmutableList<MenuItem> val);
+
+ abstract Builder changeTable(@Nullable ImmutableList<String> val);
+
+ abstract General build();
}
- if (diffPreferencesInput.isPresent()) {
- DiffPreferencesInfo mergedDiffPreferencesInput =
- parseDiffPreferences(diffPreferencesInput.get());
-
- storeSection(
- cfg,
- UserConfigSections.DIFF,
- null,
- mergedDiffPreferencesInput,
- parseDefaultDiffPreferences(defaultCfg, null));
-
- // evict the cached diff preferences
- this.diffPreferences = null;
+ public static General fromInfo(GeneralPreferencesInfo info) {
+ return (new AutoValue_Preferences_General.Builder())
+ .changesPerPage(info.changesPerPage)
+ .downloadScheme(info.downloadScheme)
+ .downloadCommand(info.downloadCommand)
+ .dateFormat(info.dateFormat)
+ .timeFormat(info.timeFormat)
+ .expandInlineDiffs(info.expandInlineDiffs)
+ .highlightAssigneeInChangeTable(info.highlightAssigneeInChangeTable)
+ .relativeDateInChangeTable(info.relativeDateInChangeTable)
+ .diffView(info.diffView)
+ .sizeBarInChangeTable(info.sizeBarInChangeTable)
+ .legacycidInChangeTable(info.legacycidInChangeTable)
+ .muteCommonPathPrefixes(info.muteCommonPathPrefixes)
+ .signedOffBy(info.signedOffBy)
+ .emailStrategy(info.emailStrategy)
+ .emailFormat(info.emailFormat)
+ .defaultBaseForMerges(info.defaultBaseForMerges)
+ .publishCommentsOnPush(info.publishCommentsOnPush)
+ .workInProgressByDefault(info.workInProgressByDefault)
+ .my(info.my == null ? null : ImmutableList.copyOf(info.my))
+ .changeTable(info.changeTable == null ? null : ImmutableList.copyOf(info.changeTable))
+ .build();
}
- if (editPreferencesInput.isPresent()) {
- EditPreferencesInfo mergedEditPreferencesInput =
- parseEditPreferences(editPreferencesInput.get());
-
- storeSection(
- cfg,
- UserConfigSections.EDIT,
- null,
- mergedEditPreferencesInput,
- parseDefaultEditPreferences(defaultCfg, null));
-
- // evict the cached edit preferences
- this.editPreferences = null;
- }
-
- return cfg;
- }
-
- private GeneralPreferencesInfo parseGeneralPreferences(@Nullable GeneralPreferencesInfo input) {
- try {
- return parseGeneralPreferences(cfg, defaultCfg, input);
- } catch (ConfigInvalidException e) {
- validationErrorSink.error(
- new ValidationError(
- PREFERENCES_CONFIG,
- String.format(
- "Invalid general preferences for account %d: %s",
- accountId.get(), e.getMessage())));
- return new GeneralPreferencesInfo();
+ public GeneralPreferencesInfo toInfo() {
+ GeneralPreferencesInfo info = new GeneralPreferencesInfo();
+ info.changesPerPage = changesPerPage().orElse(null);
+ info.downloadScheme = downloadScheme().orElse(null);
+ info.downloadCommand = downloadCommand().orElse(null);
+ info.dateFormat = dateFormat().orElse(null);
+ info.timeFormat = timeFormat().orElse(null);
+ info.expandInlineDiffs = expandInlineDiffs().orElse(null);
+ info.highlightAssigneeInChangeTable = highlightAssigneeInChangeTable().orElse(null);
+ info.relativeDateInChangeTable = relativeDateInChangeTable().orElse(null);
+ info.diffView = diffView().orElse(null);
+ info.sizeBarInChangeTable = sizeBarInChangeTable().orElse(null);
+ info.legacycidInChangeTable = legacycidInChangeTable().orElse(null);
+ info.muteCommonPathPrefixes = muteCommonPathPrefixes().orElse(null);
+ info.signedOffBy = signedOffBy().orElse(null);
+ info.emailStrategy = emailStrategy().orElse(null);
+ info.emailFormat = emailFormat().orElse(null);
+ info.defaultBaseForMerges = defaultBaseForMerges().orElse(null);
+ info.publishCommentsOnPush = publishCommentsOnPush().orElse(null);
+ info.workInProgressByDefault = workInProgressByDefault().orElse(null);
+ info.my = my().orElse(null);
+ info.changeTable = changeTable().orElse(null);
+ return info;
}
}
- private DiffPreferencesInfo parseDiffPreferences(@Nullable DiffPreferencesInfo input) {
- try {
- return parseDiffPreferences(cfg, defaultCfg, input);
- } catch (ConfigInvalidException e) {
- validationErrorSink.error(
- new ValidationError(
- PREFERENCES_CONFIG,
- String.format(
- "Invalid diff preferences for account %d: %s", accountId.get(), e.getMessage())));
- return new DiffPreferencesInfo();
+ @AutoValue
+ public abstract static class Edit {
+ public abstract Optional<Integer> tabSize();
+
+ public abstract Optional<Integer> lineLength();
+
+ public abstract Optional<Integer> indentUnit();
+
+ public abstract Optional<Integer> cursorBlinkRate();
+
+ public abstract Optional<Boolean> hideTopMenu();
+
+ public abstract Optional<Boolean> showTabs();
+
+ public abstract Optional<Boolean> showWhitespaceErrors();
+
+ public abstract Optional<Boolean> syntaxHighlighting();
+
+ public abstract Optional<Boolean> hideLineNumbers();
+
+ public abstract Optional<Boolean> matchBrackets();
+
+ public abstract Optional<Boolean> lineWrapping();
+
+ public abstract Optional<Boolean> indentWithTabs();
+
+ public abstract Optional<Boolean> autoCloseBrackets();
+
+ public abstract Optional<Boolean> showBase();
+
+ public abstract Optional<Theme> theme();
+
+ public abstract Optional<KeyMapType> keyMapType();
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+ abstract Builder tabSize(@Nullable Integer val);
+
+ abstract Builder lineLength(@Nullable Integer val);
+
+ abstract Builder indentUnit(@Nullable Integer val);
+
+ abstract Builder cursorBlinkRate(@Nullable Integer val);
+
+ abstract Builder hideTopMenu(@Nullable Boolean val);
+
+ abstract Builder showTabs(@Nullable Boolean val);
+
+ abstract Builder showWhitespaceErrors(@Nullable Boolean val);
+
+ abstract Builder syntaxHighlighting(@Nullable Boolean val);
+
+ abstract Builder hideLineNumbers(@Nullable Boolean val);
+
+ abstract Builder matchBrackets(@Nullable Boolean val);
+
+ abstract Builder lineWrapping(@Nullable Boolean val);
+
+ abstract Builder indentWithTabs(@Nullable Boolean val);
+
+ abstract Builder autoCloseBrackets(@Nullable Boolean val);
+
+ abstract Builder showBase(@Nullable Boolean val);
+
+ abstract Builder theme(@Nullable Theme val);
+
+ abstract Builder keyMapType(@Nullable KeyMapType val);
+
+ abstract Edit build();
+ }
+
+ public static Edit fromInfo(EditPreferencesInfo info) {
+ return (new AutoValue_Preferences_Edit.Builder())
+ .tabSize(info.tabSize)
+ .lineLength(info.lineLength)
+ .indentUnit(info.indentUnit)
+ .cursorBlinkRate(info.cursorBlinkRate)
+ .hideTopMenu(info.hideTopMenu)
+ .showTabs(info.showTabs)
+ .showWhitespaceErrors(info.showWhitespaceErrors)
+ .syntaxHighlighting(info.syntaxHighlighting)
+ .hideLineNumbers(info.hideLineNumbers)
+ .matchBrackets(info.matchBrackets)
+ .lineWrapping(info.lineWrapping)
+ .indentWithTabs(info.indentWithTabs)
+ .autoCloseBrackets(info.autoCloseBrackets)
+ .showBase(info.showBase)
+ .theme(info.theme)
+ .keyMapType(info.keyMapType)
+ .build();
+ }
+
+ public EditPreferencesInfo toInfo() {
+ EditPreferencesInfo info = new EditPreferencesInfo();
+ info.tabSize = tabSize().orElse(null);
+ info.lineLength = lineLength().orElse(null);
+ info.indentUnit = indentUnit().orElse(null);
+ info.cursorBlinkRate = cursorBlinkRate().orElse(null);
+ info.hideTopMenu = hideTopMenu().orElse(null);
+ info.showTabs = showTabs().orElse(null);
+ info.showWhitespaceErrors = showWhitespaceErrors().orElse(null);
+ info.syntaxHighlighting = syntaxHighlighting().orElse(null);
+ info.hideLineNumbers = hideLineNumbers().orElse(null);
+ info.matchBrackets = matchBrackets().orElse(null);
+ info.lineWrapping = lineWrapping().orElse(null);
+ info.indentWithTabs = indentWithTabs().orElse(null);
+ info.autoCloseBrackets = autoCloseBrackets().orElse(null);
+ info.showBase = showBase().orElse(null);
+ info.theme = theme().orElse(null);
+ info.keyMapType = keyMapType().orElse(null);
+ return info;
}
}
- private EditPreferencesInfo parseEditPreferences(@Nullable EditPreferencesInfo input) {
- try {
- return parseEditPreferences(cfg, defaultCfg, input);
- } catch (ConfigInvalidException e) {
- validationErrorSink.error(
- new ValidationError(
- PREFERENCES_CONFIG,
- String.format(
- "Invalid edit preferences for account %d: %s", accountId.get(), e.getMessage())));
- return new EditPreferencesInfo();
- }
- }
+ @AutoValue
+ public abstract static class Diff {
+ public abstract Optional<Integer> context();
- private static GeneralPreferencesInfo parseGeneralPreferences(
- Config cfg, @Nullable Config defaultCfg, @Nullable GeneralPreferencesInfo input)
- throws ConfigInvalidException {
- GeneralPreferencesInfo r =
- loadSection(
- cfg,
- UserConfigSections.GENERAL,
- null,
- new GeneralPreferencesInfo(),
- defaultCfg != null
- ? parseDefaultGeneralPreferences(defaultCfg, input)
- : GeneralPreferencesInfo.defaults(),
- input);
- if (input != null) {
- r.changeTable = input.changeTable;
- r.my = input.my;
- r.urlAliases = input.urlAliases;
- } else {
- r.changeTable = parseChangeTableColumns(cfg, defaultCfg);
- r.my = parseMyMenus(cfg, defaultCfg);
- r.urlAliases = parseUrlAliases(cfg, defaultCfg);
- }
- return r;
- }
+ public abstract Optional<Integer> tabSize();
- private static DiffPreferencesInfo parseDiffPreferences(
- Config cfg, @Nullable Config defaultCfg, @Nullable DiffPreferencesInfo input)
- throws ConfigInvalidException {
- return loadSection(
- cfg,
- UserConfigSections.DIFF,
- null,
- new DiffPreferencesInfo(),
- defaultCfg != null
- ? parseDefaultDiffPreferences(defaultCfg, input)
- : DiffPreferencesInfo.defaults(),
- input);
- }
+ public abstract Optional<Integer> fontSize();
- private static EditPreferencesInfo parseEditPreferences(
- Config cfg, @Nullable Config defaultCfg, @Nullable EditPreferencesInfo input)
- throws ConfigInvalidException {
- return loadSection(
- cfg,
- UserConfigSections.EDIT,
- null,
- new EditPreferencesInfo(),
- defaultCfg != null
- ? parseDefaultEditPreferences(defaultCfg, input)
- : EditPreferencesInfo.defaults(),
- input);
- }
+ public abstract Optional<Integer> lineLength();
- private static GeneralPreferencesInfo parseDefaultGeneralPreferences(
- Config defaultCfg, GeneralPreferencesInfo input) throws ConfigInvalidException {
- GeneralPreferencesInfo allUserPrefs = new GeneralPreferencesInfo();
- loadSection(
- defaultCfg,
- UserConfigSections.GENERAL,
- null,
- allUserPrefs,
- GeneralPreferencesInfo.defaults(),
- input);
- return updateGeneralPreferencesDefaults(allUserPrefs);
- }
+ public abstract Optional<Integer> cursorBlinkRate();
- private static DiffPreferencesInfo parseDefaultDiffPreferences(
- Config defaultCfg, DiffPreferencesInfo input) throws ConfigInvalidException {
- DiffPreferencesInfo allUserPrefs = new DiffPreferencesInfo();
- loadSection(
- defaultCfg,
- UserConfigSections.DIFF,
- null,
- allUserPrefs,
- DiffPreferencesInfo.defaults(),
- input);
- return updateDiffPreferencesDefaults(allUserPrefs);
- }
+ public abstract Optional<Boolean> expandAllComments();
- private static EditPreferencesInfo parseDefaultEditPreferences(
- Config defaultCfg, EditPreferencesInfo input) throws ConfigInvalidException {
- EditPreferencesInfo allUserPrefs = new EditPreferencesInfo();
- loadSection(
- defaultCfg,
- UserConfigSections.EDIT,
- null,
- allUserPrefs,
- EditPreferencesInfo.defaults(),
- input);
- return updateEditPreferencesDefaults(allUserPrefs);
- }
+ public abstract Optional<Boolean> intralineDifference();
- private static GeneralPreferencesInfo updateGeneralPreferencesDefaults(
- GeneralPreferencesInfo input) {
- GeneralPreferencesInfo result = GeneralPreferencesInfo.defaults();
- try {
- for (Field field : input.getClass().getDeclaredFields()) {
- if (skipField(field)) {
- continue;
- }
- Object newVal = field.get(input);
- if (newVal != null) {
- field.set(result, newVal);
- }
- }
- } catch (IllegalAccessException e) {
- logger.atSevere().withCause(e).log("Failed to apply default general preferences");
- return GeneralPreferencesInfo.defaults();
- }
- return result;
- }
+ public abstract Optional<Boolean> manualReview();
- private static DiffPreferencesInfo updateDiffPreferencesDefaults(DiffPreferencesInfo input) {
- DiffPreferencesInfo result = DiffPreferencesInfo.defaults();
- try {
- for (Field field : input.getClass().getDeclaredFields()) {
- if (skipField(field)) {
- continue;
- }
- Object newVal = field.get(input);
- if (newVal != null) {
- field.set(result, newVal);
- }
- }
- } catch (IllegalAccessException e) {
- logger.atSevere().withCause(e).log("Failed to apply default diff preferences");
- return DiffPreferencesInfo.defaults();
- }
- return result;
- }
+ public abstract Optional<Boolean> showLineEndings();
- private static EditPreferencesInfo updateEditPreferencesDefaults(EditPreferencesInfo input) {
- EditPreferencesInfo result = EditPreferencesInfo.defaults();
- try {
- for (Field field : input.getClass().getDeclaredFields()) {
- if (skipField(field)) {
- continue;
- }
- Object newVal = field.get(input);
- if (newVal != null) {
- field.set(result, newVal);
- }
- }
- } catch (IllegalAccessException e) {
- logger.atSevere().withCause(e).log("Failed to apply default edit preferences");
- return EditPreferencesInfo.defaults();
- }
- return result;
- }
+ public abstract Optional<Boolean> showTabs();
- private static List<String> parseChangeTableColumns(Config cfg, @Nullable Config defaultCfg) {
- List<String> changeTable = changeTable(cfg);
- if (changeTable == null && defaultCfg != null) {
- changeTable = changeTable(defaultCfg);
- }
- return changeTable;
- }
+ public abstract Optional<Boolean> showWhitespaceErrors();
- private static List<MenuItem> parseMyMenus(Config cfg, @Nullable Config defaultCfg) {
- List<MenuItem> my = my(cfg);
- if (my.isEmpty() && defaultCfg != null) {
- my = my(defaultCfg);
- }
- if (my.isEmpty()) {
- my.add(new MenuItem("Changes", "#/dashboard/self", null));
- my.add(new MenuItem("Draft Comments", "#/q/has:draft", null));
- my.add(new MenuItem("Edits", "#/q/has:edit", null));
- my.add(new MenuItem("Watched Changes", "#/q/is:watched+is:open", null));
- my.add(new MenuItem("Starred Changes", "#/q/is:starred", null));
- my.add(new MenuItem("Groups", "#/settings/#Groups", null));
- }
- return my;
- }
+ public abstract Optional<Boolean> syntaxHighlighting();
- private static Map<String, String> parseUrlAliases(Config cfg, @Nullable Config defaultCfg) {
- Map<String, String> urlAliases = urlAliases(cfg);
- if (urlAliases == null && defaultCfg != null) {
- urlAliases = urlAliases(defaultCfg);
- }
- return urlAliases;
- }
+ public abstract Optional<Boolean> hideTopMenu();
- public static GeneralPreferencesInfo readDefaultGeneralPreferences(
- AllUsersName allUsersName, Repository allUsersRepo)
- throws IOException, ConfigInvalidException {
- return parseGeneralPreferences(readDefaultConfig(allUsersName, allUsersRepo), null, null);
- }
+ public abstract Optional<Boolean> autoHideDiffTableHeader();
- public static DiffPreferencesInfo readDefaultDiffPreferences(
- AllUsersName allUsersName, Repository allUsersRepo)
- throws IOException, ConfigInvalidException {
- return parseDiffPreferences(readDefaultConfig(allUsersName, allUsersRepo), null, null);
- }
+ public abstract Optional<Boolean> hideLineNumbers();
- public static EditPreferencesInfo readDefaultEditPreferences(
- AllUsersName allUsersName, Repository allUsersRepo)
- throws IOException, ConfigInvalidException {
- return parseEditPreferences(readDefaultConfig(allUsersName, allUsersRepo), null, null);
- }
+ public abstract Optional<Boolean> renderEntireFile();
- static Config readDefaultConfig(AllUsersName allUsersName, Repository allUsersRepo)
- throws IOException, ConfigInvalidException {
- VersionedDefaultPreferences defaultPrefs = new VersionedDefaultPreferences();
- defaultPrefs.load(allUsersName, allUsersRepo);
- return defaultPrefs.getConfig();
- }
+ public abstract Optional<Boolean> hideEmptyPane();
- public static GeneralPreferencesInfo updateDefaultGeneralPreferences(
- MetaDataUpdate md, GeneralPreferencesInfo input) throws IOException, ConfigInvalidException {
- VersionedDefaultPreferences defaultPrefs = new VersionedDefaultPreferences();
- defaultPrefs.load(md);
- storeSection(
- defaultPrefs.getConfig(),
- UserConfigSections.GENERAL,
- null,
- input,
- GeneralPreferencesInfo.defaults());
- setMy(defaultPrefs.getConfig(), input.my);
- setChangeTable(defaultPrefs.getConfig(), input.changeTable);
- setUrlAliases(defaultPrefs.getConfig(), input.urlAliases);
- defaultPrefs.commit(md);
+ public abstract Optional<Boolean> matchBrackets();
- return parseGeneralPreferences(defaultPrefs.getConfig(), null, null);
- }
+ public abstract Optional<Boolean> lineWrapping();
- public static DiffPreferencesInfo updateDefaultDiffPreferences(
- MetaDataUpdate md, DiffPreferencesInfo input) throws IOException, ConfigInvalidException {
- VersionedDefaultPreferences defaultPrefs = new VersionedDefaultPreferences();
- defaultPrefs.load(md);
- storeSection(
- defaultPrefs.getConfig(),
- UserConfigSections.DIFF,
- null,
- input,
- DiffPreferencesInfo.defaults());
- defaultPrefs.commit(md);
+ public abstract Optional<Theme> theme();
- return parseDiffPreferences(defaultPrefs.getConfig(), null, null);
- }
+ public abstract Optional<Whitespace> ignoreWhitespace();
- public static EditPreferencesInfo updateDefaultEditPreferences(
- MetaDataUpdate md, EditPreferencesInfo input) throws IOException, ConfigInvalidException {
- VersionedDefaultPreferences defaultPrefs = new VersionedDefaultPreferences();
- defaultPrefs.load(md);
- storeSection(
- defaultPrefs.getConfig(),
- UserConfigSections.EDIT,
- null,
- input,
- EditPreferencesInfo.defaults());
- defaultPrefs.commit(md);
+ public abstract Optional<Boolean> retainHeader();
- return parseEditPreferences(defaultPrefs.getConfig(), null, null);
- }
+ public abstract Optional<Boolean> skipDeleted();
- private static List<String> changeTable(Config cfg) {
- return Lists.newArrayList(cfg.getStringList(CHANGE_TABLE, null, CHANGE_TABLE_COLUMN));
- }
+ public abstract Optional<Boolean> skipUnchanged();
- private static void setChangeTable(Config cfg, List<String> changeTable) {
- if (changeTable != null) {
- unsetSection(cfg, UserConfigSections.CHANGE_TABLE);
- cfg.setStringList(UserConfigSections.CHANGE_TABLE, null, CHANGE_TABLE_COLUMN, changeTable);
- }
- }
+ public abstract Optional<Boolean> skipUncommented();
- private static List<MenuItem> my(Config cfg) {
- List<MenuItem> my = new ArrayList<>();
- for (String subsection : cfg.getSubsections(UserConfigSections.MY)) {
- String url = my(cfg, subsection, KEY_URL, "#/");
- String target = my(cfg, subsection, KEY_TARGET, url.startsWith("#") ? null : "_blank");
- my.add(new MenuItem(subsection, url, target, my(cfg, subsection, KEY_ID, null)));
- }
- return my;
- }
+ @AutoValue.Builder
+ public abstract static class Builder {
+ abstract Builder context(@Nullable Integer val);
- private static String my(Config cfg, String subsection, String key, String defaultValue) {
- String val = cfg.getString(UserConfigSections.MY, subsection, key);
- return !Strings.isNullOrEmpty(val) ? val : defaultValue;
- }
+ abstract Builder tabSize(@Nullable Integer val);
- private static void setMy(Config cfg, List<MenuItem> my) {
- if (my != null) {
- unsetSection(cfg, UserConfigSections.MY);
- for (MenuItem item : my) {
- checkState(!isNullOrEmpty(item.name), "MenuItem.name must not be null or empty");
- checkState(!isNullOrEmpty(item.url), "MenuItem.url must not be null or empty");
+ abstract Builder fontSize(@Nullable Integer val);
- setMy(cfg, item.name, KEY_URL, item.url);
- setMy(cfg, item.name, KEY_TARGET, item.target);
- setMy(cfg, item.name, KEY_ID, item.id);
- }
- }
- }
+ abstract Builder lineLength(@Nullable Integer val);
- public static void validateMy(List<MenuItem> my) throws BadRequestException {
- if (my == null) {
- return;
- }
- for (MenuItem item : my) {
- checkRequiredMenuItemField(item.name, "name");
- checkRequiredMenuItemField(item.url, "URL");
- }
- }
+ abstract Builder cursorBlinkRate(@Nullable Integer val);
- private static void checkRequiredMenuItemField(String value, String name)
- throws BadRequestException {
- if (isNullOrEmpty(value)) {
- throw new BadRequestException(name + " for menu item is required");
- }
- }
+ abstract Builder expandAllComments(@Nullable Boolean val);
- private static boolean isNullOrEmpty(String value) {
- return value == null || value.trim().isEmpty();
- }
+ abstract Builder intralineDifference(@Nullable Boolean val);
- private static void setMy(Config cfg, String section, String key, @Nullable String val) {
- if (val == null || val.trim().isEmpty()) {
- cfg.unset(UserConfigSections.MY, section.trim(), key);
- } else {
- cfg.setString(UserConfigSections.MY, section.trim(), key, val.trim());
- }
- }
+ abstract Builder manualReview(@Nullable Boolean val);
- private static Map<String, String> urlAliases(Config cfg) {
- HashMap<String, String> urlAliases = new HashMap<>();
- for (String subsection : cfg.getSubsections(URL_ALIAS)) {
- urlAliases.put(
- cfg.getString(URL_ALIAS, subsection, KEY_MATCH),
- cfg.getString(URL_ALIAS, subsection, KEY_TOKEN));
- }
- return !urlAliases.isEmpty() ? urlAliases : null;
- }
+ abstract Builder showLineEndings(@Nullable Boolean val);
- private static void setUrlAliases(Config cfg, Map<String, String> urlAliases) {
- if (urlAliases != null) {
- for (String subsection : cfg.getSubsections(URL_ALIAS)) {
- cfg.unsetSection(URL_ALIAS, subsection);
- }
+ abstract Builder showTabs(@Nullable Boolean val);
- int i = 1;
- for (Map.Entry<String, String> e : urlAliases.entrySet()) {
- cfg.setString(URL_ALIAS, URL_ALIAS + i, KEY_MATCH, e.getKey());
- cfg.setString(URL_ALIAS, URL_ALIAS + i, KEY_TOKEN, e.getValue());
- i++;
- }
- }
- }
+ abstract Builder showWhitespaceErrors(@Nullable Boolean val);
- private static void unsetSection(Config cfg, String section) {
- cfg.unsetSection(section, null);
- for (String subsection : cfg.getSubsections(section)) {
- cfg.unsetSection(section, subsection);
- }
- }
+ abstract Builder syntaxHighlighting(@Nullable Boolean val);
- private static class VersionedDefaultPreferences extends VersionedMetaData {
- private Config cfg;
+ abstract Builder hideTopMenu(@Nullable Boolean val);
- @Override
- protected String getRefName() {
- return RefNames.REFS_USERS_DEFAULT;
+ abstract Builder autoHideDiffTableHeader(@Nullable Boolean val);
+
+ abstract Builder hideLineNumbers(@Nullable Boolean val);
+
+ abstract Builder renderEntireFile(@Nullable Boolean val);
+
+ abstract Builder hideEmptyPane(@Nullable Boolean val);
+
+ abstract Builder matchBrackets(@Nullable Boolean val);
+
+ abstract Builder lineWrapping(@Nullable Boolean val);
+
+ abstract Builder theme(@Nullable Theme val);
+
+ abstract Builder ignoreWhitespace(@Nullable Whitespace val);
+
+ abstract Builder retainHeader(@Nullable Boolean val);
+
+ abstract Builder skipDeleted(@Nullable Boolean val);
+
+ abstract Builder skipUnchanged(@Nullable Boolean val);
+
+ abstract Builder skipUncommented(@Nullable Boolean val);
+
+ abstract Diff build();
}
- private Config getConfig() {
- checkState(cfg != null, "Default preferences not loaded yet.");
- return cfg;
+ public static Diff fromInfo(DiffPreferencesInfo info) {
+ return (new AutoValue_Preferences_Diff.Builder())
+ .context(info.context)
+ .tabSize(info.tabSize)
+ .fontSize(info.fontSize)
+ .lineLength(info.lineLength)
+ .cursorBlinkRate(info.cursorBlinkRate)
+ .expandAllComments(info.expandAllComments)
+ .intralineDifference(info.intralineDifference)
+ .manualReview(info.manualReview)
+ .showLineEndings(info.showLineEndings)
+ .showTabs(info.showTabs)
+ .showWhitespaceErrors(info.showWhitespaceErrors)
+ .syntaxHighlighting(info.syntaxHighlighting)
+ .hideTopMenu(info.hideTopMenu)
+ .autoHideDiffTableHeader(info.autoHideDiffTableHeader)
+ .hideLineNumbers(info.hideLineNumbers)
+ .renderEntireFile(info.renderEntireFile)
+ .hideEmptyPane(info.hideEmptyPane)
+ .matchBrackets(info.matchBrackets)
+ .lineWrapping(info.lineWrapping)
+ .theme(info.theme)
+ .ignoreWhitespace(info.ignoreWhitespace)
+ .retainHeader(info.retainHeader)
+ .skipDeleted(info.skipDeleted)
+ .skipUnchanged(info.skipUnchanged)
+ .skipUncommented(info.skipUncommented)
+ .build();
}
- @Override
- protected void onLoad() throws IOException, ConfigInvalidException {
- cfg = readConfig(PREFERENCES_CONFIG);
- }
-
- @Override
- protected boolean onSave(CommitBuilder commit) throws IOException, ConfigInvalidException {
- if (Strings.isNullOrEmpty(commit.getMessage())) {
- commit.setMessage("Update default preferences\n");
- }
- saveConfig(PREFERENCES_CONFIG, cfg);
- return true;
+ public DiffPreferencesInfo toInfo() {
+ DiffPreferencesInfo info = new DiffPreferencesInfo();
+ info.context = context().orElse(null);
+ info.tabSize = tabSize().orElse(null);
+ info.fontSize = fontSize().orElse(null);
+ info.lineLength = lineLength().orElse(null);
+ info.cursorBlinkRate = cursorBlinkRate().orElse(null);
+ info.expandAllComments = expandAllComments().orElse(null);
+ info.intralineDifference = intralineDifference().orElse(null);
+ info.manualReview = manualReview().orElse(null);
+ info.showLineEndings = showLineEndings().orElse(null);
+ info.showTabs = showTabs().orElse(null);
+ info.showWhitespaceErrors = showWhitespaceErrors().orElse(null);
+ info.syntaxHighlighting = syntaxHighlighting().orElse(null);
+ info.hideTopMenu = hideTopMenu().orElse(null);
+ info.autoHideDiffTableHeader = autoHideDiffTableHeader().orElse(null);
+ info.hideLineNumbers = hideLineNumbers().orElse(null);
+ info.renderEntireFile = renderEntireFile().orElse(null);
+ info.hideEmptyPane = hideEmptyPane().orElse(null);
+ info.matchBrackets = matchBrackets().orElse(null);
+ info.lineWrapping = lineWrapping().orElse(null);
+ info.theme = theme().orElse(null);
+ info.ignoreWhitespace = ignoreWhitespace().orElse(null);
+ info.retainHeader = retainHeader().orElse(null);
+ info.skipDeleted = skipDeleted().orElse(null);
+ info.skipUnchanged = skipUnchanged().orElse(null);
+ info.skipUncommented = skipUncommented().orElse(null);
+ return info;
}
}
}
diff --git a/java/com/google/gerrit/server/account/SetInactiveFlag.java b/java/com/google/gerrit/server/account/SetInactiveFlag.java
index da2d640..5d0b6ec 100644
--- a/java/com/google/gerrit/server/account/SetInactiveFlag.java
+++ b/java/com/google/gerrit/server/account/SetInactiveFlag.java
@@ -56,7 +56,7 @@
"Deactivate Account via API",
accountId,
(a, u) -> {
- if (!a.getAccount().isActive()) {
+ if (!a.account().isActive()) {
alreadyInactive.set(true);
} else {
try {
@@ -89,7 +89,7 @@
"Activate Account via API",
accountId,
(a, u) -> {
- if (a.getAccount().isActive()) {
+ if (a.account().isActive()) {
alreadyActive.set(true);
} else {
try {
diff --git a/java/com/google/gerrit/server/account/StoredPreferences.java b/java/com/google/gerrit/server/account/StoredPreferences.java
new file mode 100644
index 0000000..05b8f41
--- /dev/null
+++ b/java/com/google/gerrit/server/account/StoredPreferences.java
@@ -0,0 +1,574 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.account;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.gerrit.server.config.ConfigUtil.loadSection;
+import static com.google.gerrit.server.config.ConfigUtil.skipField;
+import static com.google.gerrit.server.config.ConfigUtil.storeSection;
+import static com.google.gerrit.server.git.UserConfigSections.CHANGE_TABLE;
+import static com.google.gerrit.server.git.UserConfigSections.CHANGE_TABLE_COLUMN;
+import static com.google.gerrit.server.git.UserConfigSections.KEY_ID;
+import static com.google.gerrit.server.git.UserConfigSections.KEY_TARGET;
+import static com.google.gerrit.server.git.UserConfigSections.KEY_URL;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.client.EditPreferencesInfo;
+import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
+import com.google.gerrit.extensions.client.MenuItem;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.git.UserConfigSections;
+import com.google.gerrit.server.git.ValidationError;
+import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import com.google.gerrit.server.git.meta.VersionedMetaData;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * Parses/writes preferences from/to a {@link Config} file.
+ *
+ * <p>This is a low-level API. Read/write of preferences in a user branch should be done through
+ * {@link AccountsUpdate} or {@link AccountConfig}.
+ *
+ * <p>The config file has separate sections for general, diff and edit preferences:
+ *
+ * <pre>
+ * [diff]
+ * hideTopMenu = true
+ * [edit]
+ * lineLength = 80
+ * </pre>
+ *
+ * <p>The parameter names match the names that are used in the preferences REST API.
+ *
+ * <p>If the preference is omitted in the config file, then the default value for the preference is
+ * used.
+ *
+ * <p>Defaults for preferences that apply for all accounts can be configured in the {@code
+ * refs/users/default} branch in the {@code All-Users} repository. The config for the default
+ * preferences must be provided to this class so that it can read default values from it.
+ *
+ * <p>The preferences are lazily parsed.
+ */
+public class StoredPreferences {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ public static final String PREFERENCES_CONFIG = "preferences.config";
+
+ private final Account.Id accountId;
+ private final Config cfg;
+ private final Config defaultCfg;
+ private final ValidationError.Sink validationErrorSink;
+
+ private GeneralPreferencesInfo generalPreferences;
+ private DiffPreferencesInfo diffPreferences;
+ private EditPreferencesInfo editPreferences;
+
+ StoredPreferences(
+ Account.Id accountId,
+ Config cfg,
+ Config defaultCfg,
+ ValidationError.Sink validationErrorSink) {
+ this.accountId = requireNonNull(accountId, "accountId");
+ this.cfg = requireNonNull(cfg, "cfg");
+ this.defaultCfg = requireNonNull(defaultCfg, "defaultCfg");
+ this.validationErrorSink = requireNonNull(validationErrorSink, "validationErrorSink");
+ }
+
+ public GeneralPreferencesInfo getGeneralPreferences() {
+ if (generalPreferences == null) {
+ parse();
+ }
+ return generalPreferences;
+ }
+
+ public DiffPreferencesInfo getDiffPreferences() {
+ if (diffPreferences == null) {
+ parse();
+ }
+ return diffPreferences;
+ }
+
+ public EditPreferencesInfo getEditPreferences() {
+ if (editPreferences == null) {
+ parse();
+ }
+ return editPreferences;
+ }
+
+ public void parse() {
+ generalPreferences = parseGeneralPreferences(null);
+ diffPreferences = parseDiffPreferences(null);
+ editPreferences = parseEditPreferences(null);
+ }
+
+ public Config saveGeneralPreferences(
+ Optional<GeneralPreferencesInfo> generalPreferencesInput,
+ Optional<DiffPreferencesInfo> diffPreferencesInput,
+ Optional<EditPreferencesInfo> editPreferencesInput)
+ throws ConfigInvalidException {
+ if (generalPreferencesInput.isPresent()) {
+ GeneralPreferencesInfo mergedGeneralPreferencesInput =
+ parseGeneralPreferences(generalPreferencesInput.get());
+
+ storeSection(
+ cfg,
+ UserConfigSections.GENERAL,
+ null,
+ mergedGeneralPreferencesInput,
+ parseDefaultGeneralPreferences(defaultCfg, null));
+ setChangeTable(cfg, mergedGeneralPreferencesInput.changeTable);
+ setMy(cfg, mergedGeneralPreferencesInput.my);
+
+ // evict the cached general preferences
+ this.generalPreferences = null;
+ }
+
+ if (diffPreferencesInput.isPresent()) {
+ DiffPreferencesInfo mergedDiffPreferencesInput =
+ parseDiffPreferences(diffPreferencesInput.get());
+
+ storeSection(
+ cfg,
+ UserConfigSections.DIFF,
+ null,
+ mergedDiffPreferencesInput,
+ parseDefaultDiffPreferences(defaultCfg, null));
+
+ // evict the cached diff preferences
+ this.diffPreferences = null;
+ }
+
+ if (editPreferencesInput.isPresent()) {
+ EditPreferencesInfo mergedEditPreferencesInput =
+ parseEditPreferences(editPreferencesInput.get());
+
+ storeSection(
+ cfg,
+ UserConfigSections.EDIT,
+ null,
+ mergedEditPreferencesInput,
+ parseDefaultEditPreferences(defaultCfg, null));
+
+ // evict the cached edit preferences
+ this.editPreferences = null;
+ }
+
+ return cfg;
+ }
+
+ private GeneralPreferencesInfo parseGeneralPreferences(@Nullable GeneralPreferencesInfo input) {
+ try {
+ return parseGeneralPreferences(cfg, defaultCfg, input);
+ } catch (ConfigInvalidException e) {
+ validationErrorSink.error(
+ new ValidationError(
+ PREFERENCES_CONFIG,
+ String.format(
+ "Invalid general preferences for account %d: %s",
+ accountId.get(), e.getMessage())));
+ return new GeneralPreferencesInfo();
+ }
+ }
+
+ private DiffPreferencesInfo parseDiffPreferences(@Nullable DiffPreferencesInfo input) {
+ try {
+ return parseDiffPreferences(cfg, defaultCfg, input);
+ } catch (ConfigInvalidException e) {
+ validationErrorSink.error(
+ new ValidationError(
+ PREFERENCES_CONFIG,
+ String.format(
+ "Invalid diff preferences for account %d: %s", accountId.get(), e.getMessage())));
+ return new DiffPreferencesInfo();
+ }
+ }
+
+ private EditPreferencesInfo parseEditPreferences(@Nullable EditPreferencesInfo input) {
+ try {
+ return parseEditPreferences(cfg, defaultCfg, input);
+ } catch (ConfigInvalidException e) {
+ validationErrorSink.error(
+ new ValidationError(
+ PREFERENCES_CONFIG,
+ String.format(
+ "Invalid edit preferences for account %d: %s", accountId.get(), e.getMessage())));
+ return new EditPreferencesInfo();
+ }
+ }
+
+ private static GeneralPreferencesInfo parseGeneralPreferences(
+ Config cfg, @Nullable Config defaultCfg, @Nullable GeneralPreferencesInfo input)
+ throws ConfigInvalidException {
+ GeneralPreferencesInfo r =
+ loadSection(
+ cfg,
+ UserConfigSections.GENERAL,
+ null,
+ new GeneralPreferencesInfo(),
+ defaultCfg != null
+ ? parseDefaultGeneralPreferences(defaultCfg, input)
+ : GeneralPreferencesInfo.defaults(),
+ input);
+ if (input != null) {
+ r.changeTable = input.changeTable;
+ r.my = input.my;
+ } else {
+ r.changeTable = parseChangeTableColumns(cfg, defaultCfg);
+ r.my = parseMyMenus(cfg, defaultCfg);
+ }
+ return r;
+ }
+
+ private static DiffPreferencesInfo parseDiffPreferences(
+ Config cfg, @Nullable Config defaultCfg, @Nullable DiffPreferencesInfo input)
+ throws ConfigInvalidException {
+ return loadSection(
+ cfg,
+ UserConfigSections.DIFF,
+ null,
+ new DiffPreferencesInfo(),
+ defaultCfg != null
+ ? parseDefaultDiffPreferences(defaultCfg, input)
+ : DiffPreferencesInfo.defaults(),
+ input);
+ }
+
+ private static EditPreferencesInfo parseEditPreferences(
+ Config cfg, @Nullable Config defaultCfg, @Nullable EditPreferencesInfo input)
+ throws ConfigInvalidException {
+ return loadSection(
+ cfg,
+ UserConfigSections.EDIT,
+ null,
+ new EditPreferencesInfo(),
+ defaultCfg != null
+ ? parseDefaultEditPreferences(defaultCfg, input)
+ : EditPreferencesInfo.defaults(),
+ input);
+ }
+
+ private static GeneralPreferencesInfo parseDefaultGeneralPreferences(
+ Config defaultCfg, GeneralPreferencesInfo input) throws ConfigInvalidException {
+ GeneralPreferencesInfo allUserPrefs = new GeneralPreferencesInfo();
+ loadSection(
+ defaultCfg,
+ UserConfigSections.GENERAL,
+ null,
+ allUserPrefs,
+ GeneralPreferencesInfo.defaults(),
+ input);
+ return updateGeneralPreferencesDefaults(allUserPrefs);
+ }
+
+ private static DiffPreferencesInfo parseDefaultDiffPreferences(
+ Config defaultCfg, DiffPreferencesInfo input) throws ConfigInvalidException {
+ DiffPreferencesInfo allUserPrefs = new DiffPreferencesInfo();
+ loadSection(
+ defaultCfg,
+ UserConfigSections.DIFF,
+ null,
+ allUserPrefs,
+ DiffPreferencesInfo.defaults(),
+ input);
+ return updateDiffPreferencesDefaults(allUserPrefs);
+ }
+
+ private static EditPreferencesInfo parseDefaultEditPreferences(
+ Config defaultCfg, EditPreferencesInfo input) throws ConfigInvalidException {
+ EditPreferencesInfo allUserPrefs = new EditPreferencesInfo();
+ loadSection(
+ defaultCfg,
+ UserConfigSections.EDIT,
+ null,
+ allUserPrefs,
+ EditPreferencesInfo.defaults(),
+ input);
+ return updateEditPreferencesDefaults(allUserPrefs);
+ }
+
+ private static GeneralPreferencesInfo updateGeneralPreferencesDefaults(
+ GeneralPreferencesInfo input) {
+ GeneralPreferencesInfo result = GeneralPreferencesInfo.defaults();
+ try {
+ for (Field field : input.getClass().getDeclaredFields()) {
+ if (skipField(field)) {
+ continue;
+ }
+ Object newVal = field.get(input);
+ if (newVal != null) {
+ field.set(result, newVal);
+ }
+ }
+ } catch (IllegalAccessException e) {
+ logger.atSevere().withCause(e).log("Failed to apply default general preferences");
+ return GeneralPreferencesInfo.defaults();
+ }
+ return result;
+ }
+
+ private static DiffPreferencesInfo updateDiffPreferencesDefaults(DiffPreferencesInfo input) {
+ DiffPreferencesInfo result = DiffPreferencesInfo.defaults();
+ try {
+ for (Field field : input.getClass().getDeclaredFields()) {
+ if (skipField(field)) {
+ continue;
+ }
+ Object newVal = field.get(input);
+ if (newVal != null) {
+ field.set(result, newVal);
+ }
+ }
+ } catch (IllegalAccessException e) {
+ logger.atSevere().withCause(e).log("Failed to apply default diff preferences");
+ return DiffPreferencesInfo.defaults();
+ }
+ return result;
+ }
+
+ private static EditPreferencesInfo updateEditPreferencesDefaults(EditPreferencesInfo input) {
+ EditPreferencesInfo result = EditPreferencesInfo.defaults();
+ try {
+ for (Field field : input.getClass().getDeclaredFields()) {
+ if (skipField(field)) {
+ continue;
+ }
+ Object newVal = field.get(input);
+ if (newVal != null) {
+ field.set(result, newVal);
+ }
+ }
+ } catch (IllegalAccessException e) {
+ logger.atSevere().withCause(e).log("Failed to apply default edit preferences");
+ return EditPreferencesInfo.defaults();
+ }
+ return result;
+ }
+
+ private static List<String> parseChangeTableColumns(Config cfg, @Nullable Config defaultCfg) {
+ List<String> changeTable = changeTable(cfg);
+ if (changeTable == null && defaultCfg != null) {
+ changeTable = changeTable(defaultCfg);
+ }
+ return changeTable;
+ }
+
+ private static List<MenuItem> parseMyMenus(Config cfg, @Nullable Config defaultCfg) {
+ List<MenuItem> my = my(cfg);
+ if (my.isEmpty() && defaultCfg != null) {
+ my = my(defaultCfg);
+ }
+ if (my.isEmpty()) {
+ my.add(new MenuItem("Changes", "#/dashboard/self", null));
+ my.add(new MenuItem("Draft Comments", "#/q/has:draft", null));
+ my.add(new MenuItem("Edits", "#/q/has:edit", null));
+ my.add(new MenuItem("Watched Changes", "#/q/is:watched+is:open", null));
+ my.add(new MenuItem("Starred Changes", "#/q/is:starred", null));
+ my.add(new MenuItem("Groups", "#/settings/#Groups", null));
+ }
+ return my;
+ }
+
+ public static GeneralPreferencesInfo readDefaultGeneralPreferences(
+ AllUsersName allUsersName, Repository allUsersRepo)
+ throws IOException, ConfigInvalidException {
+ return parseGeneralPreferences(readDefaultConfig(allUsersName, allUsersRepo), null, null);
+ }
+
+ public static DiffPreferencesInfo readDefaultDiffPreferences(
+ AllUsersName allUsersName, Repository allUsersRepo)
+ throws IOException, ConfigInvalidException {
+ return parseDiffPreferences(readDefaultConfig(allUsersName, allUsersRepo), null, null);
+ }
+
+ public static EditPreferencesInfo readDefaultEditPreferences(
+ AllUsersName allUsersName, Repository allUsersRepo)
+ throws IOException, ConfigInvalidException {
+ return parseEditPreferences(readDefaultConfig(allUsersName, allUsersRepo), null, null);
+ }
+
+ static Config readDefaultConfig(AllUsersName allUsersName, Repository allUsersRepo)
+ throws IOException, ConfigInvalidException {
+ VersionedDefaultPreferences defaultPrefs = new VersionedDefaultPreferences();
+ defaultPrefs.load(allUsersName, allUsersRepo);
+ return defaultPrefs.getConfig();
+ }
+
+ public static GeneralPreferencesInfo updateDefaultGeneralPreferences(
+ MetaDataUpdate md, GeneralPreferencesInfo input) throws IOException, ConfigInvalidException {
+ VersionedDefaultPreferences defaultPrefs = new VersionedDefaultPreferences();
+ defaultPrefs.load(md);
+ storeSection(
+ defaultPrefs.getConfig(),
+ UserConfigSections.GENERAL,
+ null,
+ input,
+ GeneralPreferencesInfo.defaults());
+ setMy(defaultPrefs.getConfig(), input.my);
+ setChangeTable(defaultPrefs.getConfig(), input.changeTable);
+ defaultPrefs.commit(md);
+
+ return parseGeneralPreferences(defaultPrefs.getConfig(), null, null);
+ }
+
+ public static DiffPreferencesInfo updateDefaultDiffPreferences(
+ MetaDataUpdate md, DiffPreferencesInfo input) throws IOException, ConfigInvalidException {
+ VersionedDefaultPreferences defaultPrefs = new VersionedDefaultPreferences();
+ defaultPrefs.load(md);
+ storeSection(
+ defaultPrefs.getConfig(),
+ UserConfigSections.DIFF,
+ null,
+ input,
+ DiffPreferencesInfo.defaults());
+ defaultPrefs.commit(md);
+
+ return parseDiffPreferences(defaultPrefs.getConfig(), null, null);
+ }
+
+ public static EditPreferencesInfo updateDefaultEditPreferences(
+ MetaDataUpdate md, EditPreferencesInfo input) throws IOException, ConfigInvalidException {
+ VersionedDefaultPreferences defaultPrefs = new VersionedDefaultPreferences();
+ defaultPrefs.load(md);
+ storeSection(
+ defaultPrefs.getConfig(),
+ UserConfigSections.EDIT,
+ null,
+ input,
+ EditPreferencesInfo.defaults());
+ defaultPrefs.commit(md);
+
+ return parseEditPreferences(defaultPrefs.getConfig(), null, null);
+ }
+
+ private static List<String> changeTable(Config cfg) {
+ return Lists.newArrayList(cfg.getStringList(CHANGE_TABLE, null, CHANGE_TABLE_COLUMN));
+ }
+
+ private static void setChangeTable(Config cfg, List<String> changeTable) {
+ if (changeTable != null) {
+ unsetSection(cfg, UserConfigSections.CHANGE_TABLE);
+ cfg.setStringList(UserConfigSections.CHANGE_TABLE, null, CHANGE_TABLE_COLUMN, changeTable);
+ }
+ }
+
+ private static List<MenuItem> my(Config cfg) {
+ List<MenuItem> my = new ArrayList<>();
+ for (String subsection : cfg.getSubsections(UserConfigSections.MY)) {
+ String url = my(cfg, subsection, KEY_URL, "#/");
+ String target = my(cfg, subsection, KEY_TARGET, url.startsWith("#") ? null : "_blank");
+ my.add(new MenuItem(subsection, url, target, my(cfg, subsection, KEY_ID, null)));
+ }
+ return my;
+ }
+
+ private static String my(Config cfg, String subsection, String key, String defaultValue) {
+ String val = cfg.getString(UserConfigSections.MY, subsection, key);
+ return !Strings.isNullOrEmpty(val) ? val : defaultValue;
+ }
+
+ private static void setMy(Config cfg, List<MenuItem> my) {
+ if (my != null) {
+ unsetSection(cfg, UserConfigSections.MY);
+ for (MenuItem item : my) {
+ checkState(!isNullOrEmpty(item.name), "MenuItem.name must not be null or empty");
+ checkState(!isNullOrEmpty(item.url), "MenuItem.url must not be null or empty");
+
+ setMy(cfg, item.name, KEY_URL, item.url);
+ setMy(cfg, item.name, KEY_TARGET, item.target);
+ setMy(cfg, item.name, KEY_ID, item.id);
+ }
+ }
+ }
+
+ public static void validateMy(List<MenuItem> my) throws BadRequestException {
+ if (my == null) {
+ return;
+ }
+ for (MenuItem item : my) {
+ checkRequiredMenuItemField(item.name, "name");
+ checkRequiredMenuItemField(item.url, "URL");
+ }
+ }
+
+ private static void checkRequiredMenuItemField(String value, String name)
+ throws BadRequestException {
+ if (isNullOrEmpty(value)) {
+ throw new BadRequestException(name + " for menu item is required");
+ }
+ }
+
+ private static boolean isNullOrEmpty(String value) {
+ return value == null || value.trim().isEmpty();
+ }
+
+ private static void setMy(Config cfg, String section, String key, @Nullable String val) {
+ if (val == null || val.trim().isEmpty()) {
+ cfg.unset(UserConfigSections.MY, section.trim(), key);
+ } else {
+ cfg.setString(UserConfigSections.MY, section.trim(), key, val.trim());
+ }
+ }
+
+ private static void unsetSection(Config cfg, String section) {
+ cfg.unsetSection(section, null);
+ for (String subsection : cfg.getSubsections(section)) {
+ cfg.unsetSection(section, subsection);
+ }
+ }
+
+ private static class VersionedDefaultPreferences extends VersionedMetaData {
+ private Config cfg;
+
+ @Override
+ protected String getRefName() {
+ return RefNames.REFS_USERS_DEFAULT;
+ }
+
+ private Config getConfig() {
+ checkState(cfg != null, "Default preferences not loaded yet.");
+ return cfg;
+ }
+
+ @Override
+ protected void onLoad() throws IOException, ConfigInvalidException {
+ cfg = readConfig(PREFERENCES_CONFIG);
+ }
+
+ @Override
+ protected boolean onSave(CommitBuilder commit) throws IOException, ConfigInvalidException {
+ if (Strings.isNullOrEmpty(commit.getMessage())) {
+ commit.setMessage("Update default preferences\n");
+ }
+ saveConfig(PREFERENCES_CONFIG, cfg);
+ return true;
+ }
+ }
+}
diff --git a/java/com/google/gerrit/server/api/groups/GroupsImpl.java b/java/com/google/gerrit/server/api/groups/GroupsImpl.java
index a46b59a..95dcad4 100644
--- a/java/com/google/gerrit/server/api/groups/GroupsImpl.java
+++ b/java/com/google/gerrit/server/api/groups/GroupsImpl.java
@@ -141,7 +141,7 @@
if (req.getUser() != null) {
try {
- list.setUser(accountResolver.resolve(req.getUser()).asUnique().getAccount().id());
+ list.setUser(accountResolver.resolve(req.getUser()).asUnique().account().id());
} catch (Exception e) {
throw asRestApiException("Error looking up user " + req.getUser(), e);
}
diff --git a/java/com/google/gerrit/server/args4j/AccountIdHandler.java b/java/com/google/gerrit/server/args4j/AccountIdHandler.java
index 36ae88a..26bef4c 100644
--- a/java/com/google/gerrit/server/args4j/AccountIdHandler.java
+++ b/java/com/google/gerrit/server/args4j/AccountIdHandler.java
@@ -62,7 +62,7 @@
Account.Id accountId;
try {
try {
- accountId = accountResolver.resolve(token).asUnique().getAccount().id();
+ accountId = accountResolver.resolve(token).asUnique().account().id();
} catch (UnprocessableEntityException e) {
switch (authType) {
case HTTP_LDAP:
diff --git a/java/com/google/gerrit/server/auth/InternalAuthBackend.java b/java/com/google/gerrit/server/auth/InternalAuthBackend.java
index 2821bf6..2f8886b 100644
--- a/java/com/google/gerrit/server/auth/InternalAuthBackend.java
+++ b/java/com/google/gerrit/server/auth/InternalAuthBackend.java
@@ -56,14 +56,14 @@
AccountState who = accountCache.getByUsername(username).orElseThrow(UnknownUserException::new);
- if (!who.getAccount().isActive()) {
+ if (!who.account().isActive()) {
throw new UserNotAllowedException(
"Authentication failed for "
+ username
+ ": account inactive or not provisioned in Gerrit");
}
- if (!PasswordVerifier.checkPassword(who.getExternalIds(), username, req.getPassword().get())) {
+ if (!PasswordVerifier.checkPassword(who.externalIds(), username, req.getPassword().get())) {
throw new InvalidCredentialsException();
}
return new AuthUser(AuthUser.UUID.create(username), username);
diff --git a/java/com/google/gerrit/server/auth/ldap/LdapGroupBackend.java b/java/com/google/gerrit/server/auth/ldap/LdapGroupBackend.java
index 2433f67..4a75158 100644
--- a/java/com/google/gerrit/server/auth/ldap/LdapGroupBackend.java
+++ b/java/com/google/gerrit/server/auth/ldap/LdapGroupBackend.java
@@ -179,7 +179,7 @@
@Override
public GroupMembership membershipsOf(IdentifiedUser user) {
- String id = findId(user.state().getExternalIds());
+ String id = findId(user.state().externalIds());
if (id == null) {
return GroupMembership.EMPTY;
}
diff --git a/java/com/google/gerrit/server/change/AbandonOp.java b/java/com/google/gerrit/server/change/AbandonOp.java
index 31332ec..230a03c 100644
--- a/java/com/google/gerrit/server/change/AbandonOp.java
+++ b/java/com/google/gerrit/server/change/AbandonOp.java
@@ -112,7 +112,7 @@
try {
ReplyToChangeSender cm = abandonedSenderFactory.create(ctx.getProject(), change.getId());
if (accountState != null) {
- cm.setFrom(accountState.getAccount().id());
+ cm.setFrom(accountState.account().id());
}
cm.setChangeMessage(message.getMessage(), ctx.getWhen());
cm.setNotify(notify);
diff --git a/java/com/google/gerrit/server/change/ChangeResource.java b/java/com/google/gerrit/server/change/ChangeResource.java
index d8d82c6..4566919 100644
--- a/java/com/google/gerrit/server/change/ChangeResource.java
+++ b/java/com/google/gerrit/server/change/ChangeResource.java
@@ -223,9 +223,8 @@
}
private void hashAccount(Hasher h, AccountState accountState, byte[] buf) {
- h.putInt(accountState.getAccount().id().get());
- h.putString(
- MoreObjects.firstNonNull(accountState.getAccount().metaId(), ZERO_ID_STRING), UTF_8);
- accountState.getExternalIds().stream().forEach(e -> hashObjectId(h, e.blobId(), buf));
+ h.putInt(accountState.account().id().get());
+ h.putString(MoreObjects.firstNonNull(accountState.account().metaId(), ZERO_ID_STRING), UTF_8);
+ accountState.externalIds().stream().forEach(e -> hashObjectId(h, e.blobId(), buf));
}
}
diff --git a/java/com/google/gerrit/server/change/DeleteReviewerOp.java b/java/com/google/gerrit/server/change/DeleteReviewerOp.java
index 4cb06ba..7a6c11f 100644
--- a/java/com/google/gerrit/server/change/DeleteReviewerOp.java
+++ b/java/com/google/gerrit/server/change/DeleteReviewerOp.java
@@ -108,7 +108,7 @@
@Override
public boolean updateChange(ChangeContext ctx)
throws AuthException, ResourceNotFoundException, PermissionBackendException, IOException {
- Account.Id reviewerId = reviewer.getAccount().id();
+ Account.Id reviewerId = reviewer.account().id();
// Check of removing this reviewer (even if there is no vote processed by the loop below) is OK
removeReviewerControl.checkRemoveReviewer(ctx.getNotes(), ctx.getUser(), reviewerId);
@@ -125,7 +125,7 @@
}
StringBuilder msg = new StringBuilder();
- msg.append("Removed reviewer " + reviewer.getAccount().fullName());
+ msg.append("Removed reviewer " + reviewer.account().fullName());
StringBuilder removedVotesMsg = new StringBuilder();
removedVotesMsg.append(" with the following votes:\n\n");
List<PatchSetApproval> del = new ArrayList<>();
@@ -212,13 +212,13 @@
NotifyResolver.Result notify)
throws EmailException {
Account.Id userId = user.get().getAccountId();
- if (userId.equals(reviewer.getAccount().id())) {
+ if (userId.equals(reviewer.account().id())) {
// The user knows they removed themselves, don't bother emailing them.
return;
}
DeleteReviewerSender cm = deleteReviewerSenderFactory.create(projectName, change.getId());
cm.setFrom(userId);
- cm.addReviewers(Collections.singleton(reviewer.getAccount().id()));
+ cm.addReviewers(Collections.singleton(reviewer.account().id()));
cm.setChangeMessage(changeMessage.getMessage(), changeMessage.getWrittenOn());
cm.setNotify(notify);
cm.send();
diff --git a/java/com/google/gerrit/server/change/NotifyResolver.java b/java/com/google/gerrit/server/change/NotifyResolver.java
index 62c0fdf..491885d 100644
--- a/java/com/google/gerrit/server/change/NotifyResolver.java
+++ b/java/com/google/gerrit/server/change/NotifyResolver.java
@@ -99,7 +99,7 @@
List<String> problems = new ArrayList<>(inputs.size());
for (String nameOrEmail : inputs) {
try {
- r.add(accountResolver.resolve(nameOrEmail).asUnique().getAccount().id());
+ r.add(accountResolver.resolve(nameOrEmail).asUnique().account().id());
} catch (UnprocessableEntityException e) {
problems.add(e.getMessage());
}
diff --git a/java/com/google/gerrit/server/config/GerritGlobalModule.java b/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 45b70b2..3794f04 100644
--- a/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -78,6 +78,7 @@
import com.google.gerrit.server.CmdLineParserModule;
import com.google.gerrit.server.CreateGroupPermissionSyncer;
import com.google.gerrit.server.DynamicOptions;
+import com.google.gerrit.server.ExceptionHook;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.RequestListener;
import com.google.gerrit.server.TraceRequestListener;
@@ -390,6 +391,7 @@
DynamicSet.setOf(binder(), RequestListener.class);
DynamicSet.bind(binder(), RequestListener.class).to(TraceRequestListener.class);
DynamicSet.setOf(binder(), ChangeETagComputation.class);
+ DynamicSet.setOf(binder(), ExceptionHook.class);
DynamicMap.mapOf(binder(), MailFilter.class);
bind(MailFilter.class).annotatedWith(Exports.named("ListMailFilter")).to(ListMailFilter.class);
diff --git a/java/com/google/gerrit/server/events/EventFactory.java b/java/com/google/gerrit/server/events/EventFactory.java
index bc91807..4d5f158 100644
--- a/java/com/google/gerrit/server/events/EventFactory.java
+++ b/java/com/google/gerrit/server/events/EventFactory.java
@@ -571,9 +571,9 @@
*/
public AccountAttribute asAccountAttribute(AccountState accountState) {
AccountAttribute who = new AccountAttribute();
- who.name = accountState.getAccount().fullName();
- who.email = accountState.getAccount().preferredEmail();
- who.username = accountState.getUserName().orElse(null);
+ who.name = accountState.account().fullName();
+ who.email = accountState.account().preferredEmail();
+ who.username = accountState.userName().orElse(null);
return who;
}
diff --git a/java/com/google/gerrit/server/extensions/events/EventUtil.java b/java/com/google/gerrit/server/extensions/events/EventUtil.java
index 8b58f4f..1c4cf4f 100644
--- a/java/com/google/gerrit/server/extensions/events/EventUtil.java
+++ b/java/com/google/gerrit/server/extensions/events/EventUtil.java
@@ -89,14 +89,14 @@
}
public AccountInfo accountInfo(AccountState accountState) {
- if (accountState == null || accountState.getAccount().id() == null) {
+ if (accountState == null || accountState.account().id() == null) {
return null;
}
- Account account = accountState.getAccount();
+ Account account = accountState.account();
AccountInfo accountInfo = new AccountInfo(account.id().get());
accountInfo.email = account.preferredEmail();
accountInfo.name = account.fullName();
- accountInfo.username = accountState.getUserName().orElse(null);
+ accountInfo.username = accountState.userName().orElse(null);
return accountInfo;
}
@@ -106,8 +106,7 @@
for (Map.Entry<String, Short> e : approvals.entrySet()) {
Integer value = e.getValue() != null ? Integer.valueOf(e.getValue()) : null;
result.put(
- e.getKey(),
- new ApprovalInfo(accountState.getAccount().id().get(), value, null, null, ts));
+ e.getKey(), new ApprovalInfo(accountState.account().id().get(), value, null, null, ts));
}
return result;
}
diff --git a/java/com/google/gerrit/server/git/UserConfigSections.java b/java/com/google/gerrit/server/git/UserConfigSections.java
index 859e40d..0ef908c 100644
--- a/java/com/google/gerrit/server/git/UserConfigSections.java
+++ b/java/com/google/gerrit/server/git/UserConfigSections.java
@@ -25,9 +25,6 @@
public static final String KEY_URL = "url";
public static final String KEY_TARGET = "target";
public static final String KEY_ID = "id";
- public static final String URL_ALIAS = "urlAlias";
- public static final String KEY_MATCH = "match";
- public static final String KEY_TOKEN = "token";
/** The table column user preferences. */
public static final String CHANGE_TABLE = "changeTable";
diff --git a/java/com/google/gerrit/server/git/meta/VersionedMetaData.java b/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
index d8829bf..aa735f9 100644
--- a/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
+++ b/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
@@ -18,6 +18,7 @@
import com.google.common.base.MoreObjects;
import com.google.gerrit.common.Nullable;
+import com.google.gerrit.git.GitUpdateFailureException;
import com.google.gerrit.git.LockFailureException;
import com.google.gerrit.git.ObjectIds;
import com.google.gerrit.reviewdb.client.Change;
@@ -433,13 +434,14 @@
case REJECTED_MISSING_OBJECT:
case REJECTED_OTHER_REASON:
default:
- throw new IOException(
+ throw new GitUpdateFailureException(
"Cannot update "
+ ru.getName()
+ " in "
+ db.getDirectory()
+ ": "
- + ru.getResult());
+ + ru.getResult(),
+ ru);
}
}
};
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 3dcb695..f67f465 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -1578,10 +1578,10 @@
this.cmd = cmd;
this.draft = cmd.getRefName().startsWith(MagicBranch.NEW_DRAFT_CHANGE);
this.labelTypes = labelTypes;
- GeneralPreferencesInfo prefs = user.state().getGeneralPreferences();
+ GeneralPreferencesInfo prefs = user.state().generalPreferences();
this.defaultPublishComments =
prefs != null
- ? firstNonNull(user.state().getGeneralPreferences().publishCommentsOnPush, false)
+ ? firstNonNull(user.state().generalPreferences().publishCommentsOnPush, false)
: false;
}
@@ -1696,7 +1696,7 @@
}
return projectState.is(BooleanProjectConfig.WORK_IN_PROGRESS_BY_DEFAULT)
- || firstNonNull(user.state().getGeneralPreferences().workInProgressByDefault, false);
+ || firstNonNull(user.state().generalPreferences().workInProgressByDefault, false);
}
NotifyResolver.Result getNotifyForNewChange() {
diff --git a/java/com/google/gerrit/server/git/receive/ReplaceOp.java b/java/com/google/gerrit/server/git/receive/ReplaceOp.java
index a9a49bf..8640670 100644
--- a/java/com/google/gerrit/server/git/receive/ReplaceOp.java
+++ b/java/com/google/gerrit/server/git/receive/ReplaceOp.java
@@ -544,7 +544,7 @@
try {
ReplacePatchSetSender cm =
replacePatchSetFactory.create(projectState.getNameKey(), notes.getChangeId());
- cm.setFrom(ctx.getAccount().getAccount().id());
+ cm.setFrom(ctx.getAccount().account().id());
cm.setPatchSet(newPatchSet, info);
cm.setChangeMessage(msg.getMessage(), ctx.getWhen());
cm.setNotify(ctx.getNotify(notes.getChangeId()));
diff --git a/java/com/google/gerrit/server/group/db/AuditLogFormatter.java b/java/com/google/gerrit/server/group/db/AuditLogFormatter.java
index 454ce68..f263d18 100644
--- a/java/com/google/gerrit/server/group/db/AuditLogFormatter.java
+++ b/java/com/google/gerrit/server/group/db/AuditLogFormatter.java
@@ -51,7 +51,7 @@
}
private static Optional<Account> getAccount(AccountCache accountCache, Account.Id accountId) {
- return accountCache.get(accountId).map(AccountState::getAccount);
+ return accountCache.get(accountId).map(AccountState::account);
}
private static Optional<GroupDescription.Basic> getGroup(
diff --git a/java/com/google/gerrit/server/group/db/AuditLogReader.java b/java/com/google/gerrit/server/group/db/AuditLogReader.java
index fb58577..77e0e0c 100644
--- a/java/com/google/gerrit/server/group/db/AuditLogReader.java
+++ b/java/com/google/gerrit/server/group/db/AuditLogReader.java
@@ -27,7 +27,6 @@
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.config.GerritServerId;
import com.google.gerrit.server.notedb.NoteDbUtil;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -51,12 +50,10 @@
public class AuditLogReader {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final String serverId;
private final AllUsersName allUsersName;
@Inject
- public AuditLogReader(@GerritServerId String serverId, AllUsersName allUsersName) {
- this.serverId = serverId;
+ public AuditLogReader(AllUsersName allUsersName) {
this.allUsersName = allUsersName;
}
@@ -143,7 +140,7 @@
}
private Optional<ParsedCommit> parse(AccountGroup.UUID uuid, RevCommit c) {
- Optional<Account.Id> authorId = NoteDbUtil.parseIdent(c.getAuthorIdent(), serverId);
+ Optional<Account.Id> authorId = NoteDbUtil.parseIdent(c.getAuthorIdent());
if (!authorId.isPresent()) {
// Only report audit events from identified users, since this was a non-nullable field in
// ReviewDb. May be revisited.
@@ -179,7 +176,7 @@
private Optional<Account.Id> parseAccount(AccountGroup.UUID uuid, RevCommit c, FooterLine line) {
Optional<Account.Id> result =
Optional.ofNullable(RawParseUtils.parsePersonIdent(line.getValue()))
- .flatMap(ident -> NoteDbUtil.parseIdent(ident, serverId));
+ .flatMap(ident -> NoteDbUtil.parseIdent(ident));
if (!result.isPresent()) {
logInvalid(uuid, c, line);
}
diff --git a/java/com/google/gerrit/server/index/account/AccountField.java b/java/com/google/gerrit/server/index/account/AccountField.java
index f425339..c6835a0 100644
--- a/java/com/google/gerrit/server/index/account/AccountField.java
+++ b/java/com/google/gerrit/server/index/account/AccountField.java
@@ -44,7 +44,7 @@
/** Secondary index schemas for accounts. */
public class AccountField {
public static final FieldDef<AccountState, Integer> ID =
- integer("id").stored().build(a -> a.getAccount().id().get());
+ integer("id").stored().build(a -> a.account().id().get());
/**
* External IDs.
@@ -54,7 +54,7 @@
*/
public static final FieldDef<AccountState, Iterable<String>> EXTERNAL_ID =
exact("external_id")
- .buildRepeatable(a -> Iterables.transform(a.getExternalIds(), id -> id.key().get()));
+ .buildRepeatable(a -> Iterables.transform(a.externalIds(), id -> id.key().get()));
/**
* Fuzzy prefix match on name and email parts.
@@ -69,7 +69,7 @@
public static final FieldDef<AccountState, Iterable<String>> NAME_PART =
prefix("name")
.buildRepeatable(
- a -> getNameParts(a, Iterables.transform(a.getExternalIds(), ExternalId::email)));
+ a -> getNameParts(a, Iterables.transform(a.externalIds(), ExternalId::email)));
/**
* Fuzzy prefix match on name and preferred email parts. Parts of secondary emails are not
@@ -77,13 +77,13 @@
*/
public static final FieldDef<AccountState, Iterable<String>> NAME_PART_NO_SECONDARY_EMAIL =
prefix("name2")
- .buildRepeatable(a -> getNameParts(a, Arrays.asList(a.getAccount().preferredEmail())));
+ .buildRepeatable(a -> getNameParts(a, Arrays.asList(a.account().preferredEmail())));
public static final FieldDef<AccountState, String> FULL_NAME =
- exact("full_name").build(a -> a.getAccount().fullName());
+ exact("full_name").build(a -> a.account().fullName());
public static final FieldDef<AccountState, String> ACTIVE =
- exact("inactive").build(a -> a.getAccount().isActive() ? "1" : "0");
+ exact("inactive").build(a -> a.account().isActive() ? "1" : "0");
/**
* All emails (preferred email + secondary emails). Use this field only if the current user is
@@ -95,9 +95,9 @@
prefix("email")
.buildRepeatable(
a ->
- FluentIterable.from(a.getExternalIds())
+ FluentIterable.from(a.externalIds())
.transform(ExternalId::email)
- .append(Collections.singleton(a.getAccount().preferredEmail()))
+ .append(Collections.singleton(a.account().preferredEmail()))
.filter(Objects::nonNull)
.transform(String::toLowerCase)
.toSet());
@@ -106,24 +106,24 @@
prefix("preferredemail")
.build(
a -> {
- String preferredEmail = a.getAccount().preferredEmail();
+ String preferredEmail = a.account().preferredEmail();
return preferredEmail != null ? preferredEmail.toLowerCase() : null;
});
public static final FieldDef<AccountState, String> PREFERRED_EMAIL_EXACT =
- exact("preferredemail_exact").build(a -> a.getAccount().preferredEmail());
+ exact("preferredemail_exact").build(a -> a.account().preferredEmail());
public static final FieldDef<AccountState, Timestamp> REGISTERED =
- timestamp("registered").build(a -> a.getAccount().registeredOn());
+ timestamp("registered").build(a -> a.account().registeredOn());
public static final FieldDef<AccountState, String> USERNAME =
- exact("username").build(a -> a.getUserName().map(String::toLowerCase).orElse(""));
+ exact("username").build(a -> a.userName().map(String::toLowerCase).orElse(""));
public static final FieldDef<AccountState, Iterable<String>> WATCHED_PROJECT =
exact("watchedproject")
.buildRepeatable(
a ->
- FluentIterable.from(a.getProjectWatches().keySet())
+ FluentIterable.from(a.projectWatches().keySet())
.transform(k -> k.project().get())
.toSet());
@@ -138,14 +138,14 @@
storedOnly("ref_state")
.buildRepeatable(
a -> {
- if (a.getAccount().metaId() == null) {
+ if (a.account().metaId() == null) {
return ImmutableList.of();
}
return ImmutableList.of(
RefState.create(
- RefNames.refsUsers(a.getAccount().id()),
- ObjectId.fromString(a.getAccount().metaId()))
+ RefNames.refsUsers(a.account().id()),
+ ObjectId.fromString(a.account().metaId()))
// We use the default AllUsers name to avoid having to pass around that
// variable just for indexing.
// This field is only used for staleness detection which will discover the
@@ -163,13 +163,13 @@
storedOnly("external_id_state")
.buildRepeatable(
a ->
- a.getExternalIds().stream()
+ a.externalIds().stream()
.filter(e -> e.blobId() != null)
.map(ExternalId::toByteArray)
.collect(toSet()));
private static final Set<String> getNameParts(AccountState a, Iterable<String> emails) {
- String fullName = a.getAccount().fullName();
+ String fullName = a.account().fullName();
Set<String> parts = SchemaUtil.getNameParts(fullName, emails);
// Additional values not currently added by getPersonParts.
diff --git a/java/com/google/gerrit/server/index/account/AccountIndexRewriter.java b/java/com/google/gerrit/server/index/account/AccountIndexRewriter.java
index 35b967c..643c249 100644
--- a/java/com/google/gerrit/server/index/account/AccountIndexRewriter.java
+++ b/java/com/google/gerrit/server/index/account/AccountIndexRewriter.java
@@ -16,22 +16,27 @@
import static java.util.Objects.requireNonNull;
+import com.google.gerrit.index.IndexConfig;
import com.google.gerrit.index.IndexRewriter;
import com.google.gerrit.index.QueryOptions;
+import com.google.gerrit.index.query.IndexPredicate;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
+import com.google.gerrit.index.query.TooManyTermsInQueryException;
import com.google.gerrit.server.account.AccountState;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import org.eclipse.jgit.util.MutableInteger;
@Singleton
public class AccountIndexRewriter implements IndexRewriter<AccountState> {
-
private final AccountIndexCollection indexes;
+ private final IndexConfig config;
@Inject
- AccountIndexRewriter(AccountIndexCollection indexes) {
+ AccountIndexRewriter(AccountIndexCollection indexes, IndexConfig config) {
this.indexes = indexes;
+ this.config = config;
}
@Override
@@ -39,6 +44,32 @@
throws QueryParseException {
AccountIndex index = indexes.getSearchIndex();
requireNonNull(index, "no active search index configured for accounts");
+ validateMaxTermsInQuery(in);
return new IndexedAccountQuery(index, in, opts);
}
+
+ /**
+ * Validates whether a query has too many terms.
+ *
+ * @param predicate the predicate for which the leaf predicates should be counted
+ * @throws QueryParseException thrown if the query has too many terms
+ */
+ public void validateMaxTermsInQuery(Predicate<AccountState> predicate)
+ throws QueryParseException {
+ MutableInteger leafTerms = new MutableInteger();
+ validateMaxTermsInQuery(predicate, leafTerms);
+ }
+
+ private void validateMaxTermsInQuery(Predicate<AccountState> predicate, MutableInteger leafTerms)
+ throws TooManyTermsInQueryException {
+ if (!(predicate instanceof IndexPredicate)) {
+ if (++leafTerms.value > config.maxTerms()) {
+ throw new TooManyTermsInQueryException();
+ }
+ }
+
+ for (Predicate<AccountState> childPredicate : predicate.getChildren()) {
+ validateMaxTermsInQuery(childPredicate, leafTerms);
+ }
+ }
}
diff --git a/java/com/google/gerrit/server/index/change/ChangeIndexRewriter.java b/java/com/google/gerrit/server/index/change/ChangeIndexRewriter.java
index e92a0f6..476ddc9 100644
--- a/java/com/google/gerrit/server/index/change/ChangeIndexRewriter.java
+++ b/java/com/google/gerrit/server/index/change/ChangeIndexRewriter.java
@@ -31,6 +31,7 @@
import com.google.gerrit.index.query.OrPredicate;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
+import com.google.gerrit.index.query.TooManyTermsInQueryException;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Change.Status;
import com.google.gerrit.server.query.change.AndChangeSource;
@@ -183,7 +184,7 @@
throws QueryParseException {
if (isIndexPredicate(in, index)) {
if (++leafTerms.value > config.maxTerms()) {
- throw new QueryParseException("too many terms in query");
+ throw new TooManyTermsInQueryException();
}
return in;
} else if (in instanceof LimitPredicate) {
diff --git a/java/com/google/gerrit/server/mail/MailUtil.java b/java/com/google/gerrit/server/mail/MailUtil.java
index 26ebb5c..be01aa9 100644
--- a/java/com/google/gerrit/server/mail/MailUtil.java
+++ b/java/com/google/gerrit/server/mail/MailUtil.java
@@ -62,7 +62,7 @@
@SuppressWarnings("deprecation")
private static Account.Id toAccountId(AccountResolver accountResolver, String nameOrEmail)
throws UnprocessableEntityException, IOException, ConfigInvalidException {
- return accountResolver.resolveByNameOrEmail(nameOrEmail).asUnique().getAccount().id();
+ return accountResolver.resolveByNameOrEmail(nameOrEmail).asUnique().account().id();
}
private static boolean isReviewer(FooterLine candidateFooterLine) {
diff --git a/java/com/google/gerrit/server/mail/receive/MailProcessor.java b/java/com/google/gerrit/server/mail/receive/MailProcessor.java
index 034bcc9..4f23fe2 100644
--- a/java/com/google/gerrit/server/mail/receive/MailProcessor.java
+++ b/java/com/google/gerrit/server/mail/receive/MailProcessor.java
@@ -205,7 +205,7 @@
logger.atWarning().log("Mail: Account %s doesn't exist. Will delete message.", accountId);
return;
}
- if (!accountState.get().getAccount().isActive()) {
+ if (!accountState.get().account().isActive()) {
logger.atWarning().log("Mail: Account %s is inactive. Will delete message.", accountId);
sendRejectionEmail(message, InboundEmailRejectionSender.Error.INACTIVE_ACCOUNT);
return;
diff --git a/java/com/google/gerrit/server/mail/send/ChangeEmail.java b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
index 949541e..21c796a 100644
--- a/java/com/google/gerrit/server/mail/send/ChangeEmail.java
+++ b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
@@ -334,7 +334,7 @@
protected void removeUsersThatIgnoredTheChange() {
for (Map.Entry<Account.Id, Collection<String>> e : stars.asMap().entrySet()) {
if (e.getValue().contains(StarredChangesUtil.IGNORE_LABEL)) {
- args.accountCache.get(e.getKey()).ifPresent(a -> removeUser(a.getAccount()));
+ args.accountCache.get(e.getKey()).ifPresent(a -> removeUser(a.account()));
}
}
}
diff --git a/java/com/google/gerrit/server/mail/send/FromAddressGeneratorProvider.java b/java/com/google/gerrit/server/mail/send/FromAddressGeneratorProvider.java
index c5f0257..bd42c26 100644
--- a/java/com/google/gerrit/server/mail/send/FromAddressGeneratorProvider.java
+++ b/java/com/google/gerrit/server/mail/send/FromAddressGeneratorProvider.java
@@ -123,7 +123,7 @@
public Address from(Account.Id fromId) {
String senderName;
if (fromId != null) {
- Optional<Account> a = accountCache.get(fromId).map(AccountState::getAccount);
+ Optional<Account> a = accountCache.get(fromId).map(AccountState::account);
String fullName = a.map(Account::fullName).orElse(null);
String userEmail = a.map(Account::preferredEmail).orElse(null);
if (canRelay(userEmail)) {
@@ -208,7 +208,7 @@
final String senderName;
if (fromId != null) {
- String fullName = accountCache.get(fromId).map(a -> a.getAccount().fullName()).orElse(null);
+ String fullName = accountCache.get(fromId).map(a -> a.account().fullName()).orElse(null);
if (fullName == null || "".equals(fullName)) {
fullName = anonymousCowardName;
}
diff --git a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
index 61b5327..3e32628 100644
--- a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
+++ b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
@@ -116,7 +116,7 @@
if (fromId != null) {
Optional<AccountState> fromUser = args.accountCache.get(fromId);
if (fromUser.isPresent()) {
- GeneralPreferencesInfo senderPrefs = fromUser.get().getGeneralPreferences();
+ GeneralPreferencesInfo senderPrefs = fromUser.get().generalPreferences();
if (senderPrefs != null && senderPrefs.getEmailStrategy() == CC_ON_OWN_COMMENTS) {
// If we are impersonating a user, make sure they receive a CC of
// this message so they can always review and audit what we sent
@@ -127,7 +127,7 @@
// If they don't want a copy, but we queued one up anyway,
// drop them from the recipient lists.
//
- removeUser(fromUser.get().getAccount());
+ removeUser(fromUser.get().account());
}
}
}
@@ -137,8 +137,8 @@
for (Account.Id id : rcptTo) {
Optional<AccountState> thisUser = args.accountCache.get(id);
if (thisUser.isPresent()) {
- Account thisUserAccount = thisUser.get().getAccount();
- GeneralPreferencesInfo prefs = thisUser.get().getGeneralPreferences();
+ Account thisUserAccount = thisUser.get().account();
+ GeneralPreferencesInfo prefs = thisUser.get().generalPreferences();
if (prefs == null || prefs.getEmailStrategy() == DISABLED) {
removeUser(thisUserAccount);
} else if (useHtml() && prefs.getEmailFormat() == EmailFormat.PLAINTEXT) {
@@ -248,7 +248,7 @@
protected String getFromLine() {
StringBuilder f = new StringBuilder();
- Optional<Account> account = args.accountCache.get(fromId).map(AccountState::getAccount);
+ Optional<Account> account = args.accountCache.get(fromId).map(AccountState::account);
if (account.isPresent()) {
String name = account.get().fullName();
String email = account.get().preferredEmail();
@@ -324,7 +324,7 @@
return args.gerritPersonIdent.getName();
}
- Optional<Account> account = args.accountCache.get(accountId).map(AccountState::getAccount);
+ Optional<Account> account = args.accountCache.get(accountId).map(AccountState::account);
String name = null;
if (account.isPresent()) {
name = account.get().fullName();
@@ -346,7 +346,7 @@
* @return name/email of account, or Anonymous Coward if unset.
*/
protected String getNameEmailFor(Account.Id accountId) {
- Optional<Account> account = args.accountCache.get(accountId).map(AccountState::getAccount);
+ Optional<Account> account = args.accountCache.get(accountId).map(AccountState::account);
if (account.isPresent()) {
String name = account.get().fullName();
String email = account.get().preferredEmail();
@@ -374,7 +374,7 @@
return null;
}
- Account account = accountState.get().getAccount();
+ Account account = accountState.get().account();
String name = account.fullName();
String email = account.preferredEmail();
if (name != null && email != null) {
@@ -384,7 +384,7 @@
} else if (name != null) {
return name;
}
- return accountState.get().getUserName().orElse(null);
+ return accountState.get().userName().orElse(null);
}
protected boolean shouldSendMessage() {
@@ -505,7 +505,7 @@
}
private Address toAddress(Account.Id id) {
- Optional<Account> accountState = args.accountCache.get(id).map(AccountState::getAccount);
+ Optional<Account> accountState = args.accountCache.get(id).map(AccountState::account);
if (!accountState.isPresent()) {
return null;
}
diff --git a/java/com/google/gerrit/server/mail/send/ProjectWatch.java b/java/com/google/gerrit/server/mail/send/ProjectWatch.java
index 8b426ac..37ef801 100644
--- a/java/com/google/gerrit/server/mail/send/ProjectWatch.java
+++ b/java/com/google/gerrit/server/mail/send/ProjectWatch.java
@@ -66,9 +66,8 @@
Set<Account.Id> projectWatchers = new HashSet<>();
for (AccountState a : args.accountQueryProvider.get().byWatchedProject(project)) {
- Account.Id accountId = a.getAccount().id();
- for (Map.Entry<ProjectWatchKey, ImmutableSet<NotifyType>> e :
- a.getProjectWatches().entrySet()) {
+ Account.Id accountId = a.account().id();
+ for (Map.Entry<ProjectWatchKey, ImmutableSet<NotifyType>> e : a.projectWatches().entrySet()) {
if (project.equals(e.getKey().project())
&& add(matching, accountId, e.getKey(), e.getValue(), type)) {
// We only want to prevent matching All-Projects if this filter hits
@@ -78,10 +77,9 @@
}
for (AccountState a : args.accountQueryProvider.get().byWatchedProject(args.allProjectsName)) {
- for (Map.Entry<ProjectWatchKey, ImmutableSet<NotifyType>> e :
- a.getProjectWatches().entrySet()) {
+ for (Map.Entry<ProjectWatchKey, ImmutableSet<NotifyType>> e : a.projectWatches().entrySet()) {
if (args.allProjectsName.equals(e.getKey().project())) {
- Account.Id accountId = a.getAccount().id();
+ Account.Id accountId = a.account().id();
if (!projectWatchers.contains(accountId)) {
add(matching, accountId, e.getKey(), e.getValue(), type);
}
diff --git a/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java b/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java
index 9cc1c84..10bae48 100644
--- a/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java
+++ b/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java
@@ -25,6 +25,7 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.GerritServerId;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.notedb.ChangeNotesCommit.ChangeNotesRevWalk;
import com.google.gerrit.server.project.NoSuchChangeException;
@@ -51,6 +52,7 @@
public final AllUsersName allUsers;
public final LegacyChangeNoteRead legacyChangeNoteRead;
public final NoteDbMetrics metrics;
+ public final String serverId;
// Providers required to avoid dependency cycles.
@@ -64,7 +66,8 @@
ChangeNoteJson changeNoteJson,
LegacyChangeNoteRead legacyChangeNoteRead,
NoteDbMetrics metrics,
- Provider<ChangeNotesCache> cache) {
+ Provider<ChangeNotesCache> cache,
+ @GerritServerId String serverId) {
this.failOnLoadForTest = new AtomicBoolean();
this.repoManager = repoManager;
this.allUsers = allUsers;
@@ -72,6 +75,7 @@
this.changeNoteJson = changeNoteJson;
this.metrics = metrics;
this.cache = cache;
+ this.serverId = serverId;
}
}
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotes.java b/java/com/google/gerrit/server/notedb/ChangeNotes.java
index e1217c2..929974d 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotes.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotes.java
@@ -22,6 +22,7 @@
import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableSet;
@@ -503,6 +504,19 @@
ChangeNotesCache.Value v =
args.cache.get().get(getProjectName(), getChangeId(), rev, handle::walk);
state = v.state();
+
+ String stateServerId = state.serverId();
+ /**
+ * In earlier Gerrit versions serverId wasn't part of the change notes cache. That's why the
+ * earlier cached entries don't have the serverId attribute. That's fine because in earlier
+ * gerrit version serverId was already validated. Another approach to simplify the check would
+ * be to bump the cache version, but that would invalidate all persistent cache entries, what we
+ * rather try to avoid.
+ */
+ checkState(
+ Strings.isNullOrEmpty(stateServerId) || args.serverId.equals(stateServerId),
+ String.format("invalid server id, expected %s: actual: %s", args.serverId, stateServerId));
+
state.copyColumnsTo(change);
revisionNoteMap = v.revisionNoteMap();
}
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotesParser.java b/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
index 27c2aa6..b5087ff 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
@@ -135,6 +135,7 @@
private Timestamp createdOn;
private Timestamp lastUpdatedOn;
private Account.Id ownerId;
+ private String serverId;
private String changeId;
private String subject;
private String originalSubject;
@@ -223,6 +224,7 @@
createdOn,
lastUpdatedOn,
ownerId,
+ serverId,
branch,
buildCurrentPatchSetId(),
subject,
@@ -334,6 +336,10 @@
Account.Id accountId = parseIdent(commit);
if (accountId != null) {
ownerId = accountId;
+ PersonIdent personIdent = commit.getAuthorIdent();
+ serverId = NoteDbUtil.extractHostPartFromPersonIdent(personIdent);
+ } else {
+ serverId = "UNKNOWN_SERVER_ID";
}
Account.Id realAccountId = parseRealAccountId(commit, accountId);
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotesState.java b/java/com/google/gerrit/server/notedb/ChangeNotesState.java
index 2728516..5adc196 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotesState.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotesState.java
@@ -96,6 +96,7 @@
Timestamp createdOn,
Timestamp lastUpdatedOn,
Account.Id owner,
+ String serverId,
String branch,
@Nullable PatchSet.Id currentPatchSetId,
String subject,
@@ -154,6 +155,7 @@
.build())
.pastAssignees(pastAssignees)
.hashtags(hashtags)
+ .serverId(serverId)
.patchSets(patchSets.entrySet())
.approvals(approvals.entries())
.reviewers(reviewers)
@@ -276,6 +278,9 @@
abstract ImmutableSet<String> hashtags();
+ @Nullable
+ abstract String serverId();
+
abstract ImmutableList<Map.Entry<PatchSet.Id, PatchSet>> patchSets();
abstract ImmutableList<Map.Entry<PatchSet.Id, PatchSetApproval>> approvals();
@@ -376,6 +381,8 @@
abstract Builder columns(ChangeColumns columns);
+ abstract Builder serverId(String serverId);
+
abstract Builder pastAssignees(Set<Account.Id> pastAssignees);
abstract Builder hashtags(Iterable<String> hashtags);
@@ -427,6 +434,10 @@
.setChangeId(object.changeId().get())
.setColumns(toChangeColumnsProto(object.columns()));
+ if (object.serverId() != null) {
+ b.setServerId(object.serverId());
+ b.setHasServerId(true);
+ }
object.pastAssignees().forEach(a -> b.addPastAssignee(a.get()));
object.hashtags().forEach(b::addHashtag);
object
@@ -549,6 +560,7 @@
.metaId(ObjectIdConverter.create().fromByteString(proto.getMetaId()))
.changeId(changeId)
.columns(toChangeColumns(changeId, proto.getColumns()))
+ .serverId(proto.getHasServerId() ? proto.getServerId() : null)
.pastAssignees(
proto.getPastAssigneeList().stream().map(Account::id).collect(toImmutableSet()))
.hashtags(proto.getHashtagList())
diff --git a/java/com/google/gerrit/server/notedb/LegacyChangeNoteRead.java b/java/com/google/gerrit/server/notedb/LegacyChangeNoteRead.java
index 36bfe47..7e301f7 100644
--- a/java/com/google/gerrit/server/notedb/LegacyChangeNoteRead.java
+++ b/java/com/google/gerrit/server/notedb/LegacyChangeNoteRead.java
@@ -50,14 +50,11 @@
public Account.Id parseIdent(PersonIdent ident, Change.Id changeId)
throws ConfigInvalidException {
- return NoteDbUtil.parseIdent(ident, serverId)
+ return NoteDbUtil.parseIdent(ident)
.orElseThrow(
() ->
parseException(
- changeId,
- "invalid identity, expected <id>@%s: %s",
- serverId,
- ident.getEmailAddress()));
+ changeId, "cannot retrieve account id: %s", ident.getEmailAddress()));
}
private static boolean match(byte[] note, MutableInteger p, byte[] expected) {
diff --git a/java/com/google/gerrit/server/notedb/NoteDbUtil.java b/java/com/google/gerrit/server/notedb/NoteDbUtil.java
index c53f4b9..bfbdd18 100644
--- a/java/com/google/gerrit/server/notedb/NoteDbUtil.java
+++ b/java/com/google/gerrit/server/notedb/NoteDbUtil.java
@@ -37,25 +37,28 @@
ImmutableSet.of(
"com.google.gerrit.httpd.restapi.RestApiServlet", RetryingRestModifyView.class.getName());
- /**
- * Returns an AccountId for the given email address. Returns empty if the address isn't on this
- * server.
- */
- public static Optional<Account.Id> parseIdent(PersonIdent ident, String serverId) {
+ /** Returns an AccountId for the given email address. */
+ public static Optional<Account.Id> parseIdent(PersonIdent ident) {
String email = ident.getEmailAddress();
int at = email.indexOf('@');
if (at >= 0) {
- String host = email.substring(at + 1);
- if (host.equals(serverId)) {
- Integer id = Ints.tryParse(email.substring(0, at));
- if (id != null) {
- return Optional.of(Account.id(id));
- }
+ Integer id = Ints.tryParse(email.substring(0, at));
+ if (id != null) {
+ return Optional.of(Account.id(id));
}
}
return Optional.empty();
}
+ public static String extractHostPartFromPersonIdent(PersonIdent ident) {
+ String email = ident.getEmailAddress();
+ int at = email.indexOf('@');
+ if (at >= 0) {
+ return email.substring(at + 1);
+ }
+ throw new IllegalArgumentException("No host part found: " + email);
+ }
+
public static String formatTime(PersonIdent ident, Timestamp t) {
GitDateFormatter dateFormatter = new GitDateFormatter(Format.DEFAULT);
// TODO(dborowitz): Use a ThreadLocal or use Joda.
diff --git a/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java b/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java
index 19d2215..2e29bbd 100644
--- a/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java
+++ b/java/com/google/gerrit/server/query/account/AccountQueryProcessor.java
@@ -77,6 +77,6 @@
@Override
protected String formatForLogging(AccountState accountState) {
- return accountState.getAccount().id().toString();
+ return accountState.account().id().toString();
}
}
diff --git a/java/com/google/gerrit/server/query/account/CanSeeChangePredicate.java b/java/com/google/gerrit/server/query/account/CanSeeChangePredicate.java
index c2d8de9..0252a06 100644
--- a/java/com/google/gerrit/server/query/account/CanSeeChangePredicate.java
+++ b/java/com/google/gerrit/server/query/account/CanSeeChangePredicate.java
@@ -37,7 +37,7 @@
public boolean match(AccountState accountState) {
try {
permissionBackend
- .absentUser(accountState.getAccount().id())
+ .absentUser(accountState.account().id())
.change(changeNotes)
.check(ChangePermission.READ);
return true;
diff --git a/java/com/google/gerrit/server/query/account/InternalAccountQuery.java b/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
index 09c2d51..ef6f2cb 100644
--- a/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
+++ b/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
@@ -76,8 +76,7 @@
msg.append("Ambiguous external ID ").append(externalId).append(" for accounts: ");
Joiner.on(", ")
.appendTo(
- msg,
- accountStates.stream().map(a -> a.getAccount().id().toString()).collect(toList()));
+ msg, accountStates.stream().map(a -> a.account().id().toString()).collect(toList()));
logger.atWarning().log(msg.toString());
}
return null;
@@ -103,7 +102,7 @@
}
return query(AccountPredicates.preferredEmail(email)).stream()
- .filter(a -> a.getAccount().preferredEmail().equals(email))
+ .filter(a -> a.account().preferredEmail().equals(email))
.collect(toList());
}
@@ -136,7 +135,7 @@
String email = emails.get(i);
Set<AccountState> matchingAccounts =
r.get(i).stream()
- .filter(a -> a.getAccount().preferredEmail().equals(email))
+ .filter(a -> a.account().preferredEmail().equals(email))
.collect(toSet());
accountsByEmail.putAll(email, matchingAccounts);
}
diff --git a/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java b/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
index 6028f2d..218a89d 100644
--- a/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
+++ b/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
@@ -93,7 +93,7 @@
throws QueryParseException {
CurrentUser user = args.getUser();
if (user.isIdentifiedUser()) {
- return user.asIdentifiedUser().state().getProjectWatches().keySet();
+ return user.asIdentifiedUser().state().projectWatches().keySet();
}
return Collections.emptySet();
}
diff --git a/java/com/google/gerrit/server/restapi/account/GetDiffPreferences.java b/java/com/google/gerrit/server/restapi/account/GetDiffPreferences.java
index c9773f5..e6c17a9 100644
--- a/java/com/google/gerrit/server/restapi/account/GetDiffPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/GetDiffPreferences.java
@@ -59,7 +59,7 @@
return Response.ok(
accountCache
.get(id)
- .map(AccountState::getDiffPreferences)
+ .map(AccountState::diffPreferences)
.orElseThrow(() -> new ResourceNotFoundException(IdString.fromDecoded(id.toString()))));
}
}
diff --git a/java/com/google/gerrit/server/restapi/account/GetEditPreferences.java b/java/com/google/gerrit/server/restapi/account/GetEditPreferences.java
index ae3a215..ccc678f 100644
--- a/java/com/google/gerrit/server/restapi/account/GetEditPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/GetEditPreferences.java
@@ -59,7 +59,7 @@
return Response.ok(
accountCache
.get(id)
- .map(AccountState::getEditPreferences)
+ .map(AccountState::editPreferences)
.orElseThrow(() -> new ResourceNotFoundException(IdString.fromDecoded(id.toString()))));
}
}
diff --git a/java/com/google/gerrit/server/restapi/account/GetPreferences.java b/java/com/google/gerrit/server/restapi/account/GetPreferences.java
index 90884c7..508d294 100644
--- a/java/com/google/gerrit/server/restapi/account/GetPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/GetPreferences.java
@@ -65,7 +65,7 @@
GeneralPreferencesInfo preferencesInfo =
accountCache
.get(id)
- .map(AccountState::getGeneralPreferences)
+ .map(AccountState::generalPreferences)
.orElseThrow(() -> new ResourceNotFoundException(IdString.fromDecoded(id.toString())));
return Response.ok(unsetDownloadSchemeIfUnsupported(preferencesInfo));
}
diff --git a/java/com/google/gerrit/server/restapi/account/GetWatchedProjects.java b/java/com/google/gerrit/server/restapi/account/GetWatchedProjects.java
index d60bfd5..fbf1770 100644
--- a/java/com/google/gerrit/server/restapi/account/GetWatchedProjects.java
+++ b/java/com/google/gerrit/server/restapi/account/GetWatchedProjects.java
@@ -66,7 +66,7 @@
Account.Id accountId = rsrc.getUser().getAccountId();
AccountState account = accounts.get(accountId).orElseThrow(ResourceNotFoundException::new);
return Response.ok(
- account.getProjectWatches().entrySet().stream()
+ account.projectWatches().entrySet().stream()
.map(e -> toProjectWatchInfo(e.getKey(), e.getValue()))
.sorted(
comparing((ProjectWatchInfo pwi) -> pwi.project)
diff --git a/java/com/google/gerrit/server/restapi/account/PutAgreement.java b/java/com/google/gerrit/server/restapi/account/PutAgreement.java
index 5985e17..991f43c 100644
--- a/java/com/google/gerrit/server/restapi/account/PutAgreement.java
+++ b/java/com/google/gerrit/server/restapi/account/PutAgreement.java
@@ -93,7 +93,7 @@
AccountState accountState = self.get().state();
try {
- addMembers.addMembers(uuid, ImmutableSet.of(accountState.getAccount().id()));
+ addMembers.addMembers(uuid, ImmutableSet.of(accountState.account().id()));
} catch (NoSuchGroupException e) {
throw new ResourceConflictException("autoverify group not found");
}
diff --git a/java/com/google/gerrit/server/restapi/account/PutName.java b/java/com/google/gerrit/server/restapi/account/PutName.java
index 9e8f5be..d5f6333c 100644
--- a/java/com/google/gerrit/server/restapi/account/PutName.java
+++ b/java/com/google/gerrit/server/restapi/account/PutName.java
@@ -84,8 +84,8 @@
.get()
.update("Set Full Name via API", user.getAccountId(), u -> u.setFullName(newName))
.orElseThrow(() -> new ResourceNotFoundException("account not found"));
- return Strings.isNullOrEmpty(accountState.getAccount().fullName())
+ return Strings.isNullOrEmpty(accountState.account().fullName())
? Response.none()
- : Response.ok(accountState.getAccount().fullName());
+ : Response.ok(accountState.account().fullName());
}
}
diff --git a/java/com/google/gerrit/server/restapi/account/PutPreferred.java b/java/com/google/gerrit/server/restapi/account/PutPreferred.java
index 3799b24..2ddea2f 100644
--- a/java/com/google/gerrit/server/restapi/account/PutPreferred.java
+++ b/java/com/google/gerrit/server/restapi/account/PutPreferred.java
@@ -85,13 +85,13 @@
"Set Preferred Email via API",
user.getAccountId(),
(a, u) -> {
- if (preferredEmail.equals(a.getAccount().preferredEmail())) {
+ if (preferredEmail.equals(a.account().preferredEmail())) {
alreadyPreferred.set(true);
} else {
// check if the user has a matching email
String matchingEmail = null;
for (String email :
- a.getExternalIds().stream()
+ a.externalIds().stream()
.map(ExternalId::email)
.filter(Objects::nonNull)
.collect(toSet())) {
@@ -128,7 +128,7 @@
}
// claim the email now
- u.addExternalId(ExternalId.createEmail(a.getAccount().id(), preferredEmail));
+ u.addExternalId(ExternalId.createEmail(a.account().id(), preferredEmail));
matchingEmail = preferredEmail;
} else {
// Realm says that the email doesn't belong to the user. This can only happen as
diff --git a/java/com/google/gerrit/server/restapi/account/PutStatus.java b/java/com/google/gerrit/server/restapi/account/PutStatus.java
index 29f69ab..7e27489 100644
--- a/java/com/google/gerrit/server/restapi/account/PutStatus.java
+++ b/java/com/google/gerrit/server/restapi/account/PutStatus.java
@@ -73,8 +73,8 @@
.get()
.update("Set Status via API", user.getAccountId(), u -> u.setStatus(newStatus))
.orElseThrow(() -> new ResourceNotFoundException("account not found"));
- return Strings.isNullOrEmpty(accountState.getAccount().status())
+ return Strings.isNullOrEmpty(accountState.account().status())
? Response.none()
- : Response.ok(accountState.getAccount().status());
+ : Response.ok(accountState.account().status());
}
}
diff --git a/java/com/google/gerrit/server/restapi/account/QueryAccounts.java b/java/com/google/gerrit/server/restapi/account/QueryAccounts.java
index 55019f46..fb2d7d1 100644
--- a/java/com/google/gerrit/server/restapi/account/QueryAccounts.java
+++ b/java/com/google/gerrit/server/restapi/account/QueryAccounts.java
@@ -210,7 +210,7 @@
}
QueryResult<AccountState> result = queryProcessor.query(queryPred);
for (AccountState accountState : result.entities()) {
- Account.Id id = accountState.getAccount().id();
+ Account.Id id = accountState.account().id();
matches.put(id, accountLoader.get(id));
}
diff --git a/java/com/google/gerrit/server/restapi/account/SetDiffPreferences.java b/java/com/google/gerrit/server/restapi/account/SetDiffPreferences.java
index 1a63993..2d188970 100644
--- a/java/com/google/gerrit/server/restapi/account/SetDiffPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/SetDiffPreferences.java
@@ -70,7 +70,7 @@
accountsUpdateProvider
.get()
.update("Set Diff Preferences via API", id, u -> u.setDiffPreferences(input))
- .map(AccountState::getDiffPreferences)
+ .map(AccountState::diffPreferences)
.orElseThrow(() -> new ResourceNotFoundException(IdString.fromDecoded(id.toString()))));
}
}
diff --git a/java/com/google/gerrit/server/restapi/account/SetEditPreferences.java b/java/com/google/gerrit/server/restapi/account/SetEditPreferences.java
index c85adde..b5c7305 100644
--- a/java/com/google/gerrit/server/restapi/account/SetEditPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/SetEditPreferences.java
@@ -71,7 +71,7 @@
accountsUpdateProvider
.get()
.update("Set Edit Preferences via API", id, u -> u.setEditPreferences(input))
- .map(AccountState::getEditPreferences)
+ .map(AccountState::editPreferences)
.orElseThrow(() -> new ResourceNotFoundException(IdString.fromDecoded(id.toString()))));
}
}
diff --git a/java/com/google/gerrit/server/restapi/account/SetPreferences.java b/java/com/google/gerrit/server/restapi/account/SetPreferences.java
index 7967f2d..ad22851 100644
--- a/java/com/google/gerrit/server/restapi/account/SetPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/SetPreferences.java
@@ -31,7 +31,7 @@
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.AccountsUpdate;
-import com.google.gerrit.server.account.Preferences;
+import com.google.gerrit.server.account.StoredPreferences;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -68,14 +68,14 @@
}
checkDownloadScheme(input.downloadScheme);
- Preferences.validateMy(input.my);
+ StoredPreferences.validateMy(input.my);
Account.Id id = rsrc.getUser().getAccountId();
return Response.ok(
accountsUpdateProvider
.get()
.update("Set General Preferences via API", id, u -> u.setGeneralPreferences(input))
- .map(AccountState::getGeneralPreferences)
+ .map(AccountState::generalPreferences)
.orElseThrow(() -> new ResourceNotFoundException(IdString.fromDecoded(id.toString()))));
}
diff --git a/java/com/google/gerrit/server/restapi/change/CreateChange.java b/java/com/google/gerrit/server/restapi/change/CreateChange.java
index c6c9595..564f9e7 100644
--- a/java/com/google/gerrit/server/restapi/change/CreateChange.java
+++ b/java/com/google/gerrit/server/restapi/change/CreateChange.java
@@ -258,7 +258,7 @@
input.workInProgress = true;
} else {
input.workInProgress =
- firstNonNull(me.state().getGeneralPreferences().workInProgressByDefault, false);
+ firstNonNull(me.state().generalPreferences().workInProgressByDefault, false);
}
}
@@ -426,15 +426,14 @@
commitMessage = ChangeIdUtil.insertId(commitMessage, id);
}
- if (Boolean.TRUE.equals(me.state().getGeneralPreferences().signedOffBy)) {
+ if (Boolean.TRUE.equals(me.state().generalPreferences().signedOffBy)) {
commitMessage =
Joiner.on("\n")
.join(
commitMessage.trim(),
String.format(
"%s%s",
- SIGNED_OFF_BY_TAG,
- me.state().getAccount().getNameEmail(anonymousCowardName)));
+ SIGNED_OFF_BY_TAG, me.state().account().getNameEmail(anonymousCowardName)));
}
return commitMessage;
diff --git a/java/com/google/gerrit/server/restapi/change/DeleteAssignee.java b/java/com/google/gerrit/server/restapi/change/DeleteAssignee.java
index 2a4f16b..01945fd 100644
--- a/java/com/google/gerrit/server/restapi/change/DeleteAssignee.java
+++ b/java/com/google/gerrit/server/restapi/change/DeleteAssignee.java
@@ -104,7 +104,7 @@
}
public Account.Id getDeletedAssignee() {
- return deletedAssignee != null ? deletedAssignee.getAccount().id() : null;
+ return deletedAssignee != null ? deletedAssignee.account().id() : null;
}
private void addMessage(
diff --git a/java/com/google/gerrit/server/restapi/change/DeleteVote.java b/java/com/google/gerrit/server/restapi/change/DeleteVote.java
index a80863e..3d85631 100644
--- a/java/com/google/gerrit/server/restapi/change/DeleteVote.java
+++ b/java/com/google/gerrit/server/restapi/change/DeleteVote.java
@@ -170,7 +170,7 @@
boolean found = false;
LabelTypes labelTypes = projectState.getLabelTypes(ctx.getNotes());
- Account.Id accountId = accountState.getAccount().id();
+ Account.Id accountId = accountState.account().id();
for (PatchSetApproval a :
approvalsUtil.byPatchSetUser(
diff --git a/java/com/google/gerrit/server/restapi/change/ReviewersUtil.java b/java/com/google/gerrit/server/restapi/change/ReviewersUtil.java
index 7fd5ecf..1aeb1a7 100644
--- a/java/com/google/gerrit/server/restapi/change/ReviewersUtil.java
+++ b/java/com/google/gerrit/server/restapi/change/ReviewersUtil.java
@@ -24,9 +24,11 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.client.ReviewerState;
import com.google.gerrit.extensions.common.GroupBaseInfo;
import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
+import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.index.IndexConfig;
import com.google.gerrit.index.QueryOptions;
@@ -34,6 +36,7 @@
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.index.query.ResultSet;
+import com.google.gerrit.index.query.TooManyTermsInQueryException;
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.Description.Units;
import com.google.gerrit.metrics.MetricMaker;
@@ -50,6 +53,7 @@
import com.google.gerrit.server.change.ReviewerAdder;
import com.google.gerrit.server.index.account.AccountField;
import com.google.gerrit.server.index.account.AccountIndexCollection;
+import com.google.gerrit.server.index.account.AccountIndexRewriter;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.NoSuchProjectException;
@@ -120,6 +124,7 @@
private final AccountLoader.Factory accountLoaderFactory;
private final AccountQueryBuilder accountQueryBuilder;
+ private final AccountIndexRewriter accountIndexRewriter;
private final GroupBackend groupBackend;
private final GroupMembers groupMembers;
private final ReviewerRecommender reviewerRecommender;
@@ -133,6 +138,7 @@
ReviewersUtil(
AccountLoader.Factory accountLoaderFactory,
AccountQueryBuilder accountQueryBuilder,
+ AccountIndexRewriter accountIndexRewriter,
GroupBackend groupBackend,
GroupMembers groupMembers,
ReviewerRecommender reviewerRecommender,
@@ -143,6 +149,7 @@
Provider<CurrentUser> self) {
this.accountLoaderFactory = accountLoaderFactory;
this.accountQueryBuilder = accountQueryBuilder;
+ this.accountIndexRewriter = accountIndexRewriter;
this.groupBackend = groupBackend;
this.groupMembers = groupMembers;
this.reviewerRecommender = reviewerRecommender;
@@ -164,7 +171,7 @@
ProjectState projectState,
VisibilityControl visibilityControl,
boolean excludeGroups)
- throws IOException, ConfigInvalidException, PermissionBackendException {
+ throws IOException, ConfigInvalidException, PermissionBackendException, BadRequestException {
CurrentUser currentUser = self.get();
if (changeNotes != null) {
logger.atFine().log(
@@ -224,37 +231,48 @@
return suggestedReviewers;
}
- private List<Account.Id> suggestAccounts(SuggestReviewers suggestReviewers) {
+ private List<Account.Id> suggestAccounts(SuggestReviewers suggestReviewers)
+ throws BadRequestException {
try (Timer0.Context ctx = metrics.queryAccountsLatency.start()) {
- try {
- // For performance reasons we don't use AccountQueryProvider as it would always load the
- // complete account from the cache (or worse, from NoteDb) even though we only need the ID
- // which we can directly get from the returned results.
- Predicate<AccountState> pred =
- Predicate.and(
- AccountPredicates.isActive(),
- accountQueryBuilder.defaultQuery(suggestReviewers.getQuery()));
- logger.atFine().log("accounts index query: %s", pred);
- ResultSet<FieldBundle> result =
- accountIndexes
- .getSearchIndex()
- .getSource(
- pred,
- QueryOptions.create(
- indexConfig,
- 0,
- suggestReviewers.getLimit() * CANDIDATE_LIST_MULTIPLIER,
- ImmutableSet.of(AccountField.ID.getName())))
- .readRaw();
- List<Account.Id> matches =
- result.toList().stream()
- .map(f -> Account.id(f.getValue(AccountField.ID).intValue()))
- .collect(toList());
- logger.atFine().log("Matches: %s", matches);
- return matches;
- } catch (QueryParseException e) {
+ // For performance reasons we don't use AccountQueryProvider as it would always load the
+ // complete account from the cache (or worse, from NoteDb) even though we only need the ID
+ // which we can directly get from the returned results.
+ Predicate<AccountState> pred =
+ Predicate.and(
+ AccountPredicates.isActive(),
+ accountQueryBuilder.defaultQuery(suggestReviewers.getQuery()));
+ logger.atFine().log("accounts index query: %s", pred);
+ accountIndexRewriter.validateMaxTermsInQuery(pred);
+ ResultSet<FieldBundle> result =
+ accountIndexes
+ .getSearchIndex()
+ .getSource(
+ pred,
+ QueryOptions.create(
+ indexConfig,
+ 0,
+ suggestReviewers.getLimit() * CANDIDATE_LIST_MULTIPLIER,
+ ImmutableSet.of(AccountField.ID.getName())))
+ .readRaw();
+ List<Account.Id> matches =
+ result.toList().stream()
+ .map(f -> Account.id(f.getValue(AccountField.ID).intValue()))
+ .collect(toList());
+ logger.atFine().log("Matches: %s", matches);
+ return matches;
+ } catch (TooManyTermsInQueryException e) {
+ throw new BadRequestException(e.getMessage());
+ } catch (QueryParseException e) {
+ logger.atWarning().withCause(e).log("Suggesting accounts failed, return empty result.");
+ return ImmutableList.of();
+ } catch (StorageException e) {
+ if (e.getCause() instanceof TooManyTermsInQueryException) {
+ throw new BadRequestException(e.getMessage());
+ }
+ if (e.getCause() instanceof QueryParseException) {
return ImmutableList.of();
}
+ throw e;
}
}
diff --git a/java/com/google/gerrit/server/restapi/change/Submit.java b/java/com/google/gerrit/server/restapi/change/Submit.java
index 01ef7f5..fdca897 100644
--- a/java/com/google/gerrit/server/restapi/change/Submit.java
+++ b/java/com/google/gerrit/server/restapi/change/Submit.java
@@ -19,6 +19,7 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
+import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Sets;
@@ -183,13 +184,13 @@
}
projectCache.checkedGet(rsrc.getProject()).checkStatePermitsWrite();
- return Response.ok(new Output(mergeChange(rsrc, submitter, input)));
+ return mergeChange(rsrc, submitter, input);
}
@UsedAt(UsedAt.Project.GOOGLE)
- public Change mergeChange(RevisionResource rsrc, IdentifiedUser submitter, SubmitInput input)
- throws RestApiException, IOException, UpdateException, ConfigInvalidException,
- PermissionBackendException {
+ public Response<Output> mergeChange(
+ RevisionResource rsrc, IdentifiedUser submitter, SubmitInput input)
+ throws RestApiException, IOException {
Change change = rsrc.getChange();
if (!change.isNew()) {
throw new ResourceConflictException("change is " + ChangeUtil.status(change));
@@ -204,10 +205,17 @@
}
try (MergeOp op = mergeOpProvider.get()) {
- Change updatedChange = op.merge(change, submitter, true, input, false);
+ Change updatedChange;
+
+ try {
+ updatedChange = op.merge(change, submitter, true, input, false);
+ } catch (Exception e) {
+ Throwables.throwIfInstanceOf(e, RestApiException.class);
+ return Response.<Output>internalServerError(e).traceId(op.getTraceId().orElse(null));
+ }
if (updatedChange.isMerged()) {
- return change;
+ return Response.ok(new Output(change));
}
String msg =
@@ -462,8 +470,14 @@
throw new ResourceConflictException("current revision is missing");
}
- Output out = submit.apply(new RevisionResource(rsrc, ps), input).value();
- return Response.ok(json.noOptions().format(out.change));
+ Response<Output> response = submit.apply(new RevisionResource(rsrc, ps), input);
+ if (response instanceof Response.InternalServerError) {
+ Response.InternalServerError<?> ise = (Response.InternalServerError<?>) response;
+ return Response.<ChangeInfo>internalServerError(ise.cause())
+ .traceId(ise.traceId().orElse(null));
+ }
+
+ return Response.ok(json.noOptions().format(response.value().change));
}
}
}
diff --git a/java/com/google/gerrit/server/restapi/config/GetDiffPreferences.java b/java/com/google/gerrit/server/restapi/config/GetDiffPreferences.java
index 5cf93d8..44c71b3 100644
--- a/java/com/google/gerrit/server/restapi/config/GetDiffPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/GetDiffPreferences.java
@@ -19,7 +19,7 @@
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.account.Preferences;
+import com.google.gerrit.server.account.StoredPreferences;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -45,7 +45,7 @@
public Response<DiffPreferencesInfo> apply(ConfigResource configResource)
throws BadRequestException, ResourceConflictException, IOException, ConfigInvalidException {
try (Repository git = gitManager.openRepository(allUsersName)) {
- return Response.ok(Preferences.readDefaultDiffPreferences(allUsersName, git));
+ return Response.ok(StoredPreferences.readDefaultDiffPreferences(allUsersName, git));
}
}
}
diff --git a/java/com/google/gerrit/server/restapi/config/GetEditPreferences.java b/java/com/google/gerrit/server/restapi/config/GetEditPreferences.java
index d2e1031..a5ab967 100644
--- a/java/com/google/gerrit/server/restapi/config/GetEditPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/GetEditPreferences.java
@@ -19,7 +19,7 @@
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.account.Preferences;
+import com.google.gerrit.server.account.StoredPreferences;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -44,7 +44,7 @@
public Response<EditPreferencesInfo> apply(ConfigResource configResource)
throws BadRequestException, ResourceConflictException, IOException, ConfigInvalidException {
try (Repository git = gitManager.openRepository(allUsersName)) {
- return Response.ok(Preferences.readDefaultEditPreferences(allUsersName, git));
+ return Response.ok(StoredPreferences.readDefaultEditPreferences(allUsersName, git));
}
}
}
diff --git a/java/com/google/gerrit/server/restapi/config/GetPreferences.java b/java/com/google/gerrit/server/restapi/config/GetPreferences.java
index bf0ad39..8da9134 100644
--- a/java/com/google/gerrit/server/restapi/config/GetPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/GetPreferences.java
@@ -17,7 +17,7 @@
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.account.Preferences;
+import com.google.gerrit.server.account.StoredPreferences;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -42,7 +42,7 @@
public Response<GeneralPreferencesInfo> apply(ConfigResource rsrc)
throws IOException, ConfigInvalidException {
try (Repository git = gitMgr.openRepository(allUsersName)) {
- return Response.ok(Preferences.readDefaultGeneralPreferences(allUsersName, git));
+ return Response.ok(StoredPreferences.readDefaultGeneralPreferences(allUsersName, git));
}
}
}
diff --git a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
index a36e75c..2d504c7 100644
--- a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
+++ b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
@@ -66,16 +66,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import org.eclipse.jgit.lib.Config;
public class GetServerInfo implements RestReadView<ConfigResource> {
- private static final String URL_ALIAS = "urlAlias";
- private static final String KEY_MATCH = "match";
- private static final String KEY_TOKEN = "token";
-
private final Config config;
private final AccountVisibilityProvider accountVisibilityProvider;
private final AuthConfig authConfig;
@@ -152,9 +147,6 @@
info.sshd = getSshdInfo();
info.suggest = getSuggestInfo();
- Map<String, String> urlAliases = getUrlAliasesInfo();
- info.urlAliases = !urlAliases.isEmpty() ? urlAliases : null;
-
info.user = getUserInfo();
info.receive = getReceiveInfo();
return Response.ok(info);
@@ -347,16 +339,6 @@
return null;
}
- private Map<String, String> getUrlAliasesInfo() {
- Map<String, String> urlAliases = new HashMap<>();
- for (String subsection : config.getSubsections(URL_ALIAS)) {
- urlAliases.put(
- config.getString(URL_ALIAS, subsection, KEY_MATCH),
- config.getString(URL_ALIAS, subsection, KEY_TOKEN));
- }
- return urlAliases;
- }
-
private SshdInfo getSshdInfo() {
String[] addr = config.getStringList("sshd", null, "listenAddress");
if (addr.length == 1 && isOff(addr[0])) {
diff --git a/java/com/google/gerrit/server/restapi/config/SetDiffPreferences.java b/java/com/google/gerrit/server/restapi/config/SetDiffPreferences.java
index fb81665..96654a9 100644
--- a/java/com/google/gerrit/server/restapi/config/SetDiffPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/SetDiffPreferences.java
@@ -24,7 +24,7 @@
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.account.AccountCache;
-import com.google.gerrit.server.account.Preferences;
+import com.google.gerrit.server.account.StoredPreferences;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
@@ -66,7 +66,7 @@
}
try (MetaDataUpdate md = metaDataUpdateFactory.get().create(allUsersName)) {
- DiffPreferencesInfo updatedPrefs = Preferences.updateDefaultDiffPreferences(md, input);
+ DiffPreferencesInfo updatedPrefs = StoredPreferences.updateDefaultDiffPreferences(md, input);
accountCache.evictAll();
return Response.ok(updatedPrefs);
}
diff --git a/java/com/google/gerrit/server/restapi/config/SetEditPreferences.java b/java/com/google/gerrit/server/restapi/config/SetEditPreferences.java
index 178a4e1..4bb420b 100644
--- a/java/com/google/gerrit/server/restapi/config/SetEditPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/SetEditPreferences.java
@@ -24,7 +24,7 @@
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.account.AccountCache;
-import com.google.gerrit.server.account.Preferences;
+import com.google.gerrit.server.account.StoredPreferences;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
@@ -66,7 +66,7 @@
}
try (MetaDataUpdate md = metaDataUpdateFactory.get().create(allUsersName)) {
- EditPreferencesInfo updatedPrefs = Preferences.updateDefaultEditPreferences(md, input);
+ EditPreferencesInfo updatedPrefs = StoredPreferences.updateDefaultEditPreferences(md, input);
accountCache.evictAll();
return Response.ok(updatedPrefs);
}
diff --git a/java/com/google/gerrit/server/restapi/config/SetPreferences.java b/java/com/google/gerrit/server/restapi/config/SetPreferences.java
index 779f3e7..c88c1119 100644
--- a/java/com/google/gerrit/server/restapi/config/SetPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/SetPreferences.java
@@ -24,7 +24,7 @@
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.account.AccountCache;
-import com.google.gerrit.server.account.Preferences;
+import com.google.gerrit.server.account.StoredPreferences;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
@@ -60,9 +60,10 @@
if (!hasSetFields(input)) {
throw new BadRequestException("unsupported option");
}
- Preferences.validateMy(input.my);
+ StoredPreferences.validateMy(input.my);
try (MetaDataUpdate md = metaDataUpdateFactory.get().create(allUsersName)) {
- GeneralPreferencesInfo updatedPrefs = Preferences.updateDefaultGeneralPreferences(md, input);
+ GeneralPreferencesInfo updatedPrefs =
+ StoredPreferences.updateDefaultGeneralPreferences(md, input);
accountCache.evictAll();
return Response.ok(updatedPrefs);
}
diff --git a/java/com/google/gerrit/server/restapi/group/AddMembers.java b/java/com/google/gerrit/server/restapi/group/AddMembers.java
index 6efca52..4e308a0 100644
--- a/java/com/google/gerrit/server/restapi/group/AddMembers.java
+++ b/java/com/google/gerrit/server/restapi/group/AddMembers.java
@@ -146,7 +146,7 @@
throws UnprocessableEntityException, IOException, ConfigInvalidException {
AccountResolver.Result result = accountResolver.resolve(nameOrEmailOrId);
try {
- return result.asUnique().getAccount();
+ return result.asUnique().account();
} catch (UnresolvableAccountException e) {
switch (authType) {
case HTTP_LDAP:
@@ -193,7 +193,7 @@
req.setSkipAuthentication(true);
return accountCache
.get(accountManager.authenticate(req).getAccountId())
- .map(AccountState::getAccount);
+ .map(AccountState::account);
} catch (AccountException e) {
return Optional.empty();
}
diff --git a/java/com/google/gerrit/server/restapi/group/DeleteMembers.java b/java/com/google/gerrit/server/restapi/group/DeleteMembers.java
index 5d1d447..3428779 100644
--- a/java/com/google/gerrit/server/restapi/group/DeleteMembers.java
+++ b/java/com/google/gerrit/server/restapi/group/DeleteMembers.java
@@ -68,7 +68,7 @@
Set<Account.Id> membersToRemove = new HashSet<>();
for (String nameOrEmail : input.members) {
- membersToRemove.add(accountResolver.resolve(nameOrEmail).asUnique().getAccount().id());
+ membersToRemove.add(accountResolver.resolve(nameOrEmail).asUnique().account().id());
}
AccountGroup.UUID groupUuid = internalGroup.getGroupUUID();
try {
diff --git a/java/com/google/gerrit/server/restapi/project/CheckAccess.java b/java/com/google/gerrit/server/restapi/project/CheckAccess.java
index 516e126..78ffdda 100644
--- a/java/com/google/gerrit/server/restapi/project/CheckAccess.java
+++ b/java/com/google/gerrit/server/restapi/project/CheckAccess.java
@@ -73,7 +73,7 @@
throw new BadRequestException("input requires 'account'");
}
- Account.Id match = accountResolver.resolve(input.account).asUnique().getAccount().id();
+ Account.Id match = accountResolver.resolve(input.account).asUnique().account().id();
AccessCheckInfo info = new AccessCheckInfo();
try {
diff --git a/java/com/google/gerrit/server/submit/MergeOp.java b/java/com/google/gerrit/server/submit/MergeOp.java
index 024880f..813f9ab0 100644
--- a/java/com/google/gerrit/server/submit/MergeOp.java
+++ b/java/com/google/gerrit/server/submit/MergeOp.java
@@ -91,6 +91,7 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -247,6 +248,7 @@
private Set<Project.NameKey> allProjects;
private boolean dryrun;
private TopicMetrics topicMetrics;
+ private String traceId;
@Inject
MergeOp(
@@ -518,6 +520,7 @@
.multipliedBy(cs.projects().size()))
.caller(getClass())
.retryWithTrace(t -> !(t instanceof RestApiException))
+ .onAutoTrace(traceId -> this.traceId = traceId)
.build());
if (projects > 1) {
@@ -538,6 +541,10 @@
}
}
+ public Optional<String> getTraceId() {
+ return Optional.ofNullable(traceId);
+ }
+
private void openRepoManager() {
if (orm != null) {
orm.close();
diff --git a/java/com/google/gerrit/server/submit/SubmitStrategyOp.java b/java/com/google/gerrit/server/submit/SubmitStrategyOp.java
index bcffbc9..b8f1966 100644
--- a/java/com/google/gerrit/server/submit/SubmitStrategyOp.java
+++ b/java/com/google/gerrit/server/submit/SubmitStrategyOp.java
@@ -396,7 +396,7 @@
private String getByAccountName() {
requireNonNull(submitter, "getByAccountName called before submitter populated");
Optional<Account> account =
- args.accountCache.get(submitter.accountId()).map(AccountState::getAccount);
+ args.accountCache.get(submitter.accountId()).map(AccountState::account);
if (account.isPresent() && account.get().fullName() != null) {
return " by " + account.get().fullName();
}
diff --git a/java/com/google/gerrit/server/update/Context.java b/java/com/google/gerrit/server/update/Context.java
index 8704cf0..12ea986 100644
--- a/java/com/google/gerrit/server/update/Context.java
+++ b/java/com/google/gerrit/server/update/Context.java
@@ -114,7 +114,7 @@
/**
* Get the account of the user performing the update.
*
- * <p>Convenience method for {@code getIdentifiedUser().getAccount()}.
+ * <p>Convenience method for {@code getIdentifiedUser().account()}.
*
* @see CurrentUser#asIdentifiedUser()
* @return account.
diff --git a/java/com/google/gerrit/server/update/RetryHelper.java b/java/com/google/gerrit/server/update/RetryHelper.java
index b120379..bea3867 100644
--- a/java/com/google/gerrit/server/update/RetryHelper.java
+++ b/java/com/google/gerrit/server/update/RetryHelper.java
@@ -39,10 +39,12 @@
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.Field;
import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.server.ExceptionHook;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.logging.RequestId;
import com.google.gerrit.server.logging.TraceContext;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.time.Duration;
@@ -182,14 +184,19 @@
private final Metrics metrics;
private final BatchUpdate.Factory updateFactory;
+ private final PluginSetContext<ExceptionHook> exceptionHooks;
private final Map<ActionType, Duration> defaultTimeouts;
private final WaitStrategy waitStrategy;
@Nullable private final Consumer<RetryerBuilder<?>> overwriteDefaultRetryerStrategySetup;
private final boolean retryWithTraceOnFailure;
@Inject
- RetryHelper(@GerritServerConfig Config cfg, Metrics metrics, BatchUpdate.Factory updateFactory) {
- this(cfg, metrics, updateFactory, null);
+ RetryHelper(
+ @GerritServerConfig Config cfg,
+ Metrics metrics,
+ PluginSetContext<ExceptionHook> exceptionHooks,
+ BatchUpdate.Factory updateFactory) {
+ this(cfg, metrics, updateFactory, exceptionHooks, null);
}
@VisibleForTesting
@@ -197,9 +204,11 @@
@GerritServerConfig Config cfg,
Metrics metrics,
BatchUpdate.Factory updateFactory,
+ PluginSetContext<ExceptionHook> exceptionHooks,
@Nullable Consumer<RetryerBuilder<?>> overwriteDefaultRetryerStrategySetup) {
this.metrics = metrics;
this.updateFactory = updateFactory;
+ this.exceptionHooks = exceptionHooks;
Duration defaultTimeout =
Duration.ofMillis(
@@ -308,6 +317,11 @@
return true;
}
+ // Exception hooks may identify additional exceptions for retry.
+ if (exceptionHooks.stream().anyMatch(h -> h.shouldRetry(t))) {
+ return true;
+ }
+
// A non-recoverable failure occurred. Check if we should retry to capture a trace
// of the failure. If a trace was already done there is no need to retry.
if (retryWithTraceOnFailure
diff --git a/java/com/google/gerrit/sshd/GerritGSSAuthenticator.java b/java/com/google/gerrit/sshd/GerritGSSAuthenticator.java
index 01a8cb6..72a6f3a 100644
--- a/java/com/google/gerrit/sshd/GerritGSSAuthenticator.java
+++ b/java/com/google/gerrit/sshd/GerritGSSAuthenticator.java
@@ -66,7 +66,7 @@
}
Optional<Account> account =
- accounts.getByUsername(username).map(AccountState::getAccount).filter(Account::isActive);
+ accounts.getByUsername(username).map(AccountState::account).filter(Account::isActive);
if (!account.isPresent()) {
return false;
}
diff --git a/java/com/google/gerrit/sshd/commands/LsUserRefs.java b/java/com/google/gerrit/sshd/commands/LsUserRefs.java
index ae3d59e..648256a 100644
--- a/java/com/google/gerrit/sshd/commands/LsUserRefs.java
+++ b/java/com/google/gerrit/sshd/commands/LsUserRefs.java
@@ -76,7 +76,7 @@
protected void run() throws Failure {
Account.Id userAccountId;
try {
- userAccountId = accountResolver.resolve(userName).asUnique().getAccount().id();
+ userAccountId = accountResolver.resolve(userName).asUnique().account().id();
} catch (UnprocessableEntityException e) {
stdout.println(e.getMessage());
stdout.flush();
diff --git a/java/com/google/gerrit/sshd/commands/SetMembersCommand.java b/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
index 578f6fe..de3d4f0 100644
--- a/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
+++ b/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
@@ -140,7 +140,7 @@
return "n/a";
}
return MoreObjects.firstNonNull(
- accountState.get().getAccount().preferredEmail(), "n/a");
+ accountState.get().account().preferredEmail(), "n/a");
})
.collect(joining(", "));
out.write(
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index 405c463..47bc7b3 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -134,6 +134,8 @@
import com.google.gerrit.server.notedb.Sequences;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackend.RefFilterOptions;
+import com.google.gerrit.server.plugincontext.PluginContext.PluginMetrics;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.server.project.RefPattern;
import com.google.gerrit.server.query.account.InternalAccountQuery;
@@ -431,7 +433,7 @@
"Create Account Atomically",
accountId,
u -> u.setFullName(fullName).addExternalId(extId));
- assertThat(accountState.getAccount().fullName()).isEqualTo(fullName);
+ assertThat(accountState.account().fullName()).isEqualTo(fullName);
AccountInfo info = gApi.accounts().id(accountId.get()).get();
assertThat(info.name).isEqualTo(fullName);
@@ -471,7 +473,7 @@
.get()
.update("Set status", anonymousCoward.id(), u -> u.setStatus(status));
assertThat(accountState).isPresent();
- Account account = accountState.get().getAccount();
+ Account account = accountState.get().account();
assertThat(account.fullName()).isNull();
assertThat(account.status()).isEqualTo(status);
assertUserBranch(anonymousCoward.id(), null, status);
@@ -594,7 +596,7 @@
new AccountActivationValidationListener() {
@Override
public void validateActivation(AccountState account) throws ValidationException {
- String preferredEmail = account.getAccount().preferredEmail();
+ String preferredEmail = account.account().preferredEmail();
if (preferredEmail == null || !preferredEmail.endsWith("@activatable.com")) {
throw new ValidationException("not allowed to active account");
}
@@ -602,7 +604,7 @@
@Override
public void validateDeactivation(AccountState account) throws ValidationException {
- String preferredEmail = account.getAccount().preferredEmail();
+ String preferredEmail = account.account().preferredEmail();
if (preferredEmail == null || !preferredEmail.endsWith("@deactivatable.com")) {
throw new ValidationException("not allowed to deactive account");
}
@@ -2459,21 +2461,20 @@
@Test
public void checkMetaId() throws Exception {
// metaId is set when account is loaded
- assertThat(accounts.get(admin.id()).get().getAccount().metaId())
- .isEqualTo(getMetaId(admin.id()));
+ assertThat(accounts.get(admin.id()).get().account().metaId()).isEqualTo(getMetaId(admin.id()));
// metaId is set when account is created
AccountsUpdate au = accountsUpdateProvider.get();
Account.Id accountId = Account.id(seq.nextAccountId());
AccountState accountState = au.insert("Create Test Account", accountId, u -> {});
- assertThat(accountState.getAccount().metaId()).isEqualTo(getMetaId(accountId));
+ assertThat(accountState.account().metaId()).isEqualTo(getMetaId(accountId));
// metaId is set when account is updated
Optional<AccountState> updatedAccountState =
au.update("Set Full Name", accountId, u -> u.setFullName("foo"));
assertThat(updatedAccountState).isPresent();
- Account updatedAccount = updatedAccountState.get().getAccount();
- assertThat(accountState.getAccount().metaId()).isNotEqualTo(updatedAccount.metaId());
+ Account updatedAccount = updatedAccountState.get().account();
+ assertThat(accountState.account().metaId()).isNotEqualTo(updatedAccount.metaId());
assertThat(updatedAccount.metaId()).isEqualTo(getMetaId(accountId));
}
@@ -2589,7 +2590,11 @@
externalIds,
metaDataUpdateInternalFactory,
new RetryHelper(
- cfg, retryMetrics, null, r -> r.withBlockStrategy(noSleepBlockStrategy)),
+ cfg,
+ retryMetrics,
+ null,
+ new PluginSetContext<>(DynamicSet.emptySet(), PluginMetrics.DISABLED_INSTANCE),
+ r -> r.withBlockStrategy(noSleepBlockStrategy)),
extIdNotesFactory,
ident,
ident,
@@ -2615,7 +2620,7 @@
assertThat(doneBgUpdate.get()).isTrue();
assertThat(updatedAccountState).isPresent();
- Account updatedAccount = updatedAccountState.get().getAccount();
+ Account updatedAccount = updatedAccountState.get().account();
assertThat(updatedAccount.status()).isEqualTo(status);
assertThat(updatedAccount.fullName()).isEqualTo(fullName);
@@ -2642,6 +2647,7 @@
cfg,
retryMetrics,
null,
+ new PluginSetContext<>(DynamicSet.emptySet(), PluginMetrics.DISABLED_INSTANCE),
r ->
r.withStopStrategy(StopStrategies.stopAfterAttempt(status.size()))
.withBlockStrategy(noSleepBlockStrategy)),
@@ -2671,7 +2677,7 @@
() -> update.update("Set Full Name", admin.id(), u -> u.setFullName(fullName)));
assertThat(bgCounter.get()).isEqualTo(status.size());
- Account updatedAccount = accounts.get(admin.id()).get().getAccount();
+ Account updatedAccount = accounts.get(admin.id()).get().account();
assertThat(updatedAccount.status()).isEqualTo(Iterables.getLast(status));
assertThat(updatedAccount.fullName()).isEqualTo(admin.fullName());
@@ -2696,7 +2702,11 @@
externalIds,
metaDataUpdateInternalFactory,
new RetryHelper(
- cfg, retryMetrics, null, r -> r.withBlockStrategy(noSleepBlockStrategy)),
+ cfg,
+ retryMetrics,
+ null,
+ new PluginSetContext<>(DynamicSet.emptySet(), PluginMetrics.DISABLED_INSTANCE),
+ r -> r.withBlockStrategy(noSleepBlockStrategy)),
extIdNotesFactory,
ident,
ident,
@@ -2719,12 +2729,12 @@
"Set Status",
admin.id(),
(a, u) -> {
- if ("A-1".equals(a.getAccount().status())) {
+ if ("A-1".equals(a.account().status())) {
bgCounterA1.getAndIncrement();
u.setStatus("B-1");
}
- if ("A-2".equals(a.getAccount().status())) {
+ if ("A-2".equals(a.account().status())) {
bgCounterA2.getAndIncrement();
u.setStatus("B-2");
}
@@ -2734,8 +2744,8 @@
assertThat(bgCounterA2.get()).isEqualTo(1);
assertThat(updatedAccountState).isPresent();
- assertThat(updatedAccountState.get().getAccount().status()).isEqualTo("B-2");
- assertThat(accounts.get(admin.id()).get().getAccount().status()).isEqualTo("B-2");
+ assertThat(updatedAccountState.get().account().status()).isEqualTo("B-2");
+ assertThat(accounts.get(admin.id()).get().account().status()).isEqualTo("B-2");
assertThat(gApi.accounts().id(admin.id().get()).get().status).isEqualTo("B-2");
}
@@ -2765,7 +2775,11 @@
externalIds,
metaDataUpdateInternalFactory,
new RetryHelper(
- cfg, retryMetrics, null, r -> r.withBlockStrategy(noSleepBlockStrategy)),
+ cfg,
+ retryMetrics,
+ null,
+ new PluginSetContext<>(DynamicSet.emptySet(), PluginMetrics.DISABLED_INSTANCE),
+ r -> r.withBlockStrategy(noSleepBlockStrategy)),
extIdNotesFactory,
ident,
ident,
@@ -2797,12 +2811,12 @@
"Update External ID",
accountId,
(a, u) -> {
- if (a.getExternalIds().contains(extIdA1)) {
+ if (a.externalIds().contains(extIdA1)) {
bgCounterA1.getAndIncrement();
u.replaceExternalId(extIdA1, extIdB1);
}
- if (a.getExternalIds().contains(extIdA2)) {
+ if (a.externalIds().contains(extIdA2)) {
bgCounterA2.getAndIncrement();
u.replaceExternalId(extIdA2, extIdB2);
}
@@ -2812,8 +2826,8 @@
assertThat(bgCounterA2.get()).isEqualTo(1);
assertThat(updatedAccount).isPresent();
- assertThat(updatedAccount.get().getExternalIds()).containsExactly(extIdB2);
- assertThat(accounts.get(accountId).get().getExternalIds()).containsExactly(extIdB2);
+ assertThat(updatedAccount.get().externalIds()).containsExactly(extIdB2);
+ assertThat(accounts.get(accountId).get().externalIds()).containsExactly(extIdB2);
assertThat(
gApi.accounts().id(accountId.get()).getExternalIds().stream()
.map(i -> i.identity)
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIndexerIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIndexerIT.java
index 75a727d..e7ae49a 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIndexerIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIndexerIT.java
@@ -66,7 +66,7 @@
List<AccountState> matchedAccountStates =
accountQueryProvider.get().byPreferredEmail(preferredEmail);
assertThat(matchedAccountStates).hasSize(1);
- assertThat(matchedAccountStates.get(0).getAccount().id()).isEqualTo(accountId);
+ assertThat(matchedAccountStates.get(0).account().id()).isEqualTo(accountId);
}
@Test
@@ -82,7 +82,7 @@
List<AccountState> matchedAccountStates =
accountQueryProvider.get().byPreferredEmail(preferredEmail);
assertThat(matchedAccountStates).hasSize(1);
- assertThat(matchedAccountStates.get(0).getAccount().id()).isEqualTo(accountId);
+ assertThat(matchedAccountStates.get(0).account().id()).isEqualTo(accountId);
}
@Test
@@ -91,10 +91,10 @@
loadAccountToCache(accountId);
String status = "ooo";
updateAccountWithoutCacheOrIndex(accountId, newAccountUpdate().setStatus(status).build());
- assertThat(accountCache.get(accountId).get().getAccount().status()).isNull();
+ assertThat(accountCache.get(accountId).get().account().status()).isNull();
accountIndexer.index(accountId);
- assertThat(accountCache.get(accountId).get().getAccount().status()).isEqualTo(status);
+ assertThat(accountCache.get(accountId).get().account().status()).isEqualTo(status);
}
@Test
@@ -109,7 +109,7 @@
List<AccountState> matchedAccountStates =
accountQueryProvider.get().byPreferredEmail(preferredEmail);
assertThat(matchedAccountStates).hasSize(1);
- assertThat(matchedAccountStates.get(0).getAccount().id()).isEqualTo(accountId);
+ assertThat(matchedAccountStates.get(0).account().id()).isEqualTo(accountId);
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java
index c48ee9d..9ccb74b 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java
@@ -192,7 +192,7 @@
Optional<AccountState> accountState = accounts.get(accountId);
assertThat(accountState).isPresent();
- assertThat(accountState.get().getAccount().preferredEmail()).isEqualTo(newEmail);
+ assertThat(accountState.get().account().preferredEmail()).isEqualTo(newEmail);
}
@Test
@@ -217,7 +217,7 @@
Optional<AccountState> accountState = accounts.get(accountId);
assertThat(accountState).isPresent();
- assertThat(accountState.get().getAccount().fullName()).isEqualTo(newName);
+ assertThat(accountState.get().account().fullName()).isEqualTo(newName);
}
@Test
@@ -296,7 +296,7 @@
assertAuthResultForExistingAccount(authResult, accountId, gerritExtIdKey);
Optional<AccountState> accountState = accounts.get(accountId);
assertThat(accountState).isPresent();
- assertThat(accountState.get().getAccount().isActive()).isTrue();
+ assertThat(accountState.get().account().isActive()).isTrue();
}
@Test
@@ -317,7 +317,7 @@
assertAuthResultForExistingAccount(authResult, accountId, gerritExtIdKey);
Optional<AccountState> accountState = accounts.get(accountId);
assertThat(accountState).isPresent();
- assertThat(accountState.get().getAccount().isActive()).isTrue();
+ assertThat(accountState.get().account().isActive()).isTrue();
}
@Test
@@ -341,7 +341,7 @@
Optional<AccountState> accountState = accounts.get(accountId);
assertThat(accountState).isPresent();
- assertThat(accountState.get().getAccount().isActive()).isFalse();
+ assertThat(accountState.get().account().isActive()).isFalse();
}
@Test
@@ -433,7 +433,7 @@
// Verify that the preferred email was not updated.
Optional<AccountState> accountState = accounts.get(accountId);
assertThat(accountState).isPresent();
- assertThat(accountState.get().getAccount().preferredEmail()).isEqualTo(email);
+ assertThat(accountState.get().account().preferredEmail()).isEqualTo(email);
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/GeneralPreferencesIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/GeneralPreferencesIT.java
index f253533..76d8044 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/GeneralPreferencesIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/GeneralPreferencesIT.java
@@ -38,7 +38,6 @@
import com.google.inject.Inject;
import com.google.inject.util.Providers;
import java.util.ArrayList;
-import java.util.HashMap;
import org.junit.Before;
import org.junit.Test;
@@ -90,8 +89,6 @@
i.my.add(new MenuItem("name", "url"));
i.changeTable = new ArrayList<>();
i.changeTable.add("Status");
- i.urlAliases = new HashMap<>();
- i.urlAliases.put("foo", "bar");
o = gApi.accounts().id(user42.id().toString()).setPreferences(i);
assertPrefs(o, i, "my");
diff --git a/javatests/com/google/gerrit/acceptance/api/change/PostReviewIT.java b/javatests/com/google/gerrit/acceptance/api/change/PostReviewIT.java
index 216a2ec..7156c8d 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/PostReviewIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/PostReviewIT.java
@@ -16,6 +16,10 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -40,11 +44,10 @@
import com.google.inject.Inject;
import com.google.inject.Module;
import java.sql.Timestamp;
-import org.easymock.Capture;
-import org.easymock.EasyMock;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
/** Tests for comment validation in {@link PostReview}. */
public class PostReviewIT extends AbstractDaemonTest {
@@ -53,14 +56,14 @@
private static final String COMMENT_TEXT = "The comment text";
- private Capture<ImmutableList<CommentForValidation>> capture = new Capture<>();
+ @Captor private ArgumentCaptor<ImmutableList<CommentForValidation>> capture;
@Override
public Module createModule() {
return new FactoryModule() {
@Override
public void configure() {
- CommentValidator mockCommentValidator = EasyMock.createMock(CommentValidator.class);
+ CommentValidator mockCommentValidator = mock(CommentValidator.class);
bind(CommentValidator.class)
.annotatedWith(Exports.named(mockCommentValidator.getClass()))
.toInstance(mockCommentValidator);
@@ -71,23 +74,17 @@
@Before
public void resetMock() {
- EasyMock.reset(mockCommentValidator);
- }
-
- @After
- public void verifyMock() {
- EasyMock.verify(mockCommentValidator);
+ initMocks(this);
+ clearInvocations(mockCommentValidator);
}
@Test
public void validateCommentsInInput_commentOK() throws Exception {
- EasyMock.expect(
- mockCommentValidator.validateComments(
- ImmutableList.of(
- CommentForValidation.create(
- CommentForValidation.CommentType.FILE_COMMENT, COMMENT_TEXT))))
- .andReturn(ImmutableList.of());
- EasyMock.replay(mockCommentValidator);
+ when(mockCommentValidator.validateComments(
+ ImmutableList.of(
+ CommentForValidation.create(
+ CommentForValidation.CommentType.FILE_COMMENT, COMMENT_TEXT))))
+ .thenReturn(ImmutableList.of());
PushOneCommit.Result r = createChange();
@@ -106,12 +103,9 @@
public void validateCommentsInInput_commentRejected() throws Exception {
CommentForValidation commentForValidation =
CommentForValidation.create(CommentType.FILE_COMMENT, COMMENT_TEXT);
- EasyMock.expect(
- mockCommentValidator.validateComments(
- ImmutableList.of(
- CommentForValidation.create(CommentType.FILE_COMMENT, COMMENT_TEXT))))
- .andReturn(ImmutableList.of(commentForValidation.failValidation("Oh no!")));
- EasyMock.replay(mockCommentValidator);
+ when(mockCommentValidator.validateComments(
+ ImmutableList.of(CommentForValidation.create(CommentType.FILE_COMMENT, COMMENT_TEXT))))
+ .thenReturn(ImmutableList.of(commentForValidation.failValidation("Oh no!")));
PushOneCommit.Result r = createChange();
@@ -139,8 +133,6 @@
@Test
public void validateCommentsInInput_commentCleanedUp() throws Exception {
- EasyMock.replay(mockCommentValidator);
-
PushOneCommit.Result r = createChange();
assertThat(testCommentHelper.getPublishedComments(r.getChangeId())).isEmpty();
@@ -159,13 +151,11 @@
@Test
public void validateDrafts_draftOK() throws Exception {
- EasyMock.expect(
- mockCommentValidator.validateComments(
- ImmutableList.of(
- CommentForValidation.create(
- CommentForValidation.CommentType.INLINE_COMMENT, COMMENT_TEXT))))
- .andReturn(ImmutableList.of());
- EasyMock.replay(mockCommentValidator);
+ when(mockCommentValidator.validateComments(
+ ImmutableList.of(
+ CommentForValidation.create(
+ CommentForValidation.CommentType.INLINE_COMMENT, COMMENT_TEXT))))
+ .thenReturn(ImmutableList.of());
PushOneCommit.Result r = createChange();
@@ -186,13 +176,11 @@
public void validateDrafts_draftRejected() throws Exception {
CommentForValidation commentForValidation =
CommentForValidation.create(CommentType.INLINE_COMMENT, COMMENT_TEXT);
- EasyMock.expect(
- mockCommentValidator.validateComments(
- ImmutableList.of(
- CommentForValidation.create(
- CommentForValidation.CommentType.INLINE_COMMENT, COMMENT_TEXT))))
- .andReturn(ImmutableList.of(commentForValidation.failValidation("Oh no!")));
- EasyMock.replay(mockCommentValidator);
+ when(mockCommentValidator.validateComments(
+ ImmutableList.of(
+ CommentForValidation.create(
+ CommentForValidation.CommentType.INLINE_COMMENT, COMMENT_TEXT))))
+ .thenReturn(ImmutableList.of(commentForValidation.failValidation("Oh no!")));
PushOneCommit.Result r = createChange();
DraftInput draft =
@@ -230,16 +218,14 @@
testCommentHelper.addDraft(r.getChangeId(), r.getCommit().getName(), draftFile);
assertThat(testCommentHelper.getPublishedComments(r.getChangeId())).isEmpty();
- EasyMock.expect(mockCommentValidator.validateComments(EasyMock.capture(capture)))
- .andReturn(ImmutableList.of());
- EasyMock.replay(mockCommentValidator);
+ when(mockCommentValidator.validateComments(capture.capture())).thenReturn(ImmutableList.of());
ReviewInput input = new ReviewInput();
input.drafts = DraftHandling.PUBLISH;
gApi.changes().id(r.getChangeId()).current().review(input);
assertThat(testCommentHelper.getPublishedComments(r.getChangeId())).hasSize(2);
- assertThat(capture.getValues()).hasSize(1);
+ assertThat(capture.getAllValues()).hasSize(1);
assertThat(capture.getValue())
.containsExactly(
CommentForValidation.create(
@@ -250,12 +236,10 @@
@Test
public void validateCommentsInChangeMessage_messageOK() throws Exception {
- EasyMock.expect(
- mockCommentValidator.validateComments(
- ImmutableList.of(
- CommentForValidation.create(CommentType.CHANGE_MESSAGE, COMMENT_TEXT))))
- .andReturn(ImmutableList.of());
- EasyMock.replay(mockCommentValidator);
+ when(mockCommentValidator.validateComments(
+ ImmutableList.of(
+ CommentForValidation.create(CommentType.CHANGE_MESSAGE, COMMENT_TEXT))))
+ .thenReturn(ImmutableList.of());
PushOneCommit.Result r = createChange();
ReviewInput input = new ReviewInput().message(COMMENT_TEXT);
@@ -271,12 +255,10 @@
public void validateCommentsInChangeMessage_messageRejected() throws Exception {
CommentForValidation commentForValidation =
CommentForValidation.create(CommentType.CHANGE_MESSAGE, COMMENT_TEXT);
- EasyMock.expect(
- mockCommentValidator.validateComments(
- ImmutableList.of(
- CommentForValidation.create(CommentType.CHANGE_MESSAGE, COMMENT_TEXT))))
- .andReturn(ImmutableList.of(commentForValidation.failValidation("Oh no!")));
- EasyMock.replay(mockCommentValidator);
+ when(mockCommentValidator.validateComments(
+ ImmutableList.of(
+ CommentForValidation.create(CommentType.CHANGE_MESSAGE, COMMENT_TEXT))))
+ .thenReturn(ImmutableList.of(commentForValidation.failValidation("Oh no!")));
PushOneCommit.Result r = createChange();
ReviewInput input = new ReviewInput().message(COMMENT_TEXT);
diff --git a/javatests/com/google/gerrit/acceptance/rest/TraceIT.java b/javatests/com/google/gerrit/acceptance/rest/TraceIT.java
index af4a22e..0e51208 100644
--- a/javatests/com/google/gerrit/acceptance/rest/TraceIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/TraceIT.java
@@ -36,6 +36,7 @@
import com.google.gerrit.extensions.registration.RegistrationHandle;
import com.google.gerrit.httpd.restapi.ParameterParser;
import com.google.gerrit.httpd.restapi.RestApiServlet;
+import com.google.gerrit.server.ExceptionHook;
import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.validators.CommitValidationException;
@@ -85,6 +86,7 @@
@Inject private DynamicSet<ChangeIndexedListener> changeIndexedListeners;
@Inject private DynamicSet<PerformanceLogger> performanceLoggers;
@Inject private DynamicSet<SubmitRule> submitRules;
+ @Inject private DynamicSet<ExceptionHook> exceptionHooks;
@Inject private WorkQueue workQueue;
private TraceValidatingProjectCreationValidationListener projectCreationListener;
@@ -585,17 +587,18 @@
assertThat(projectCreationListener.tags.get("project")).containsExactly("new24");
}
+ @Test
@GerritConfig(name = "retry.retryWithTraceOnFailure", value = "true")
public void autoRetryWithTrace() throws Exception {
String changeId = createChange().getChangeId();
approve(changeId);
TraceSubmitRule traceSubmitRule = new TraceSubmitRule();
- traceSubmitRule.failOnce = true;
+ traceSubmitRule.failAlways = true;
RegistrationHandle submitRuleRegistrationHandle = submitRules.add("gerrit", traceSubmitRule);
try {
RestResponse response = adminRestSession.post("/changes/" + changeId + "/submit");
- assertThat(response.getStatusCode()).isEqualTo(SC_OK);
+ assertThat(response.getStatusCode()).isEqualTo(SC_INTERNAL_SERVER_ERROR);
assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).startsWith("retry-on-failure-");
assertThat(traceSubmitRule.traceId).startsWith("retry-on-failure-");
assertThat(traceSubmitRule.isLoggingForced).isTrue();
@@ -605,6 +608,36 @@
}
@Test
+ @GerritConfig(name = "retry.retryWithTraceOnFailure", value = "true")
+ public void noAutoRetryIfExceptionCausesNormalRetrying() throws Exception {
+ String changeId = createChange().getChangeId();
+ approve(changeId);
+
+ TraceSubmitRule traceSubmitRule = new TraceSubmitRule();
+ traceSubmitRule.failAlways = true;
+ RegistrationHandle submitRuleRegistrationHandle = submitRules.add("gerrit", traceSubmitRule);
+ RegistrationHandle exceptionHookRegistrationHandle =
+ exceptionHooks.add(
+ "gerrit",
+ new ExceptionHook() {
+ @Override
+ public boolean shouldRetry(Throwable t) {
+ return true;
+ }
+ });
+ try {
+ RestResponse response = adminRestSession.post("/changes/" + changeId + "/submit");
+ assertThat(response.getStatusCode()).isEqualTo(SC_INTERNAL_SERVER_ERROR);
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isNull();
+ assertThat(traceSubmitRule.traceId).isNull();
+ assertThat(traceSubmitRule.isLoggingForced).isFalse();
+ } finally {
+ submitRuleRegistrationHandle.remove();
+ exceptionHookRegistrationHandle.remove();
+ }
+ }
+
+ @Test
public void noAutoRetryWithTraceIfDisabled() throws Exception {
String changeId = createChange().getChangeId();
approve(changeId);
@@ -617,7 +650,7 @@
assertThat(response.getStatusCode()).isEqualTo(SC_INTERNAL_SERVER_ERROR);
assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isNull();
assertThat(traceSubmitRule.traceId).isNull();
- assertThat(traceSubmitRule.isLoggingForced).isNull();
+ assertThat(traceSubmitRule.isLoggingForced).isFalse();
} finally {
submitRuleRegistrationHandle.remove();
}
@@ -677,18 +710,19 @@
String traceId;
Boolean isLoggingForced;
boolean failOnce;
+ boolean failAlways;
@Override
public Optional<SubmitRecord> evaluate(ChangeData changeData) {
- if (failOnce) {
- failOnce = false;
- throw new IllegalStateException("forced failure from test");
- }
-
this.traceId =
Iterables.getFirst(LoggingContext.getInstance().getTagsAsMap().get("TRACE_ID"), null);
this.isLoggingForced = LoggingContext.getInstance().shouldForceLogging(null, null, false);
+ if (failOnce || failAlways) {
+ failOnce = false;
+ throw new IllegalStateException("forced failure from test");
+ }
+
SubmitRecord submitRecord = new SubmitRecord();
submitRecord.status = SubmitRecord.Status.OK;
return Optional.of(submitRecord);
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java b/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
index e9e8b7f..2bba4e6 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
@@ -112,7 +112,7 @@
@Test
public void getExternalIds() throws Exception {
- Collection<ExternalId> expectedIds = getAccountState(user.id()).getExternalIds();
+ Collection<ExternalId> expectedIds = getAccountState(user.id()).externalIds();
List<AccountExternalIdInfo> expectedIdInfos = toExternalIdInfos(expectedIds);
RestResponse response = userRestSession.get("/accounts/self/external.ids");
@@ -142,7 +142,7 @@
.add(allowCapability(GlobalCapability.ACCESS_DATABASE).group(REGISTERED_USERS))
.update();
- Collection<ExternalId> expectedIds = getAccountState(admin.id()).getExternalIds();
+ Collection<ExternalId> expectedIds = getAccountState(admin.id()).externalIds();
List<AccountExternalIdInfo> expectedIdInfos = toExternalIdInfos(expectedIds);
RestResponse response = userRestSession.get("/accounts/" + admin.id() + "/external.ids");
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java b/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
index 7ac655f..42b82c5 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
@@ -21,6 +21,7 @@
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block;
import static com.google.gerrit.common.data.Permission.READ;
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static java.util.stream.Collectors.toList;
import com.google.common.collect.ImmutableList;
@@ -39,6 +40,7 @@
import com.google.gerrit.extensions.client.ReviewerState;
import com.google.gerrit.extensions.common.ChangeInput;
import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
+import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -136,6 +138,27 @@
}
@Test
+ @GerritConfig(name = "index.maxTerms", value = "10")
+ public void suggestReviewersTooManyQueryTerms() throws Exception {
+ String changeId = createChange().getChangeId();
+
+ // Do a query which doesn't exceed index.maxTerms succeeds (add only 9 terms, since on
+ // 'inactive:1' term is implicitly added) and assert that a result is returned
+ StringBuilder query = new StringBuilder();
+ for (int i = 1; i <= 9; i++) {
+ query.append(name("u")).append(" ");
+ }
+ assertThat(suggestReviewers(changeId, query.toString())).isNotEmpty();
+
+ // Do a query which exceed index.maxTerms succeeds (10 terms plus 'inactive:1' term which is
+ // implicitly added).
+ query.append(name("u"));
+ BadRequestException exception =
+ assertThrows(BadRequestException.class, () -> suggestReviewers(changeId, query.toString()));
+ assertThat(exception).hasMessageThat().isEqualTo("too many terms in query");
+ }
+
+ @Test
public void suggestReviewersWithExcludeGroups() throws Exception {
String changeId = createChange().getChangeId();
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/WorkInProgressByDefaultIT.java b/javatests/com/google/gerrit/acceptance/rest/change/WorkInProgressByDefaultIT.java
index ccf1c0d..51d524b 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/WorkInProgressByDefaultIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/WorkInProgressByDefaultIT.java
@@ -22,12 +22,16 @@
import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
+import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
import com.google.gerrit.extensions.api.projects.ConfigInput;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
import com.google.gerrit.extensions.client.InheritableBoolean;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeInput;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
import com.google.inject.Inject;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
@@ -37,6 +41,7 @@
public class WorkInProgressByDefaultIT extends AbstractDaemonTest {
@Inject private ProjectOperations projectOperations;
+ @Inject private RequestScopeOperations requestScopeOperations;
@Test
public void createChangeWithWorkInProgressByDefaultForProjectDisabled() throws Exception {
@@ -175,6 +180,14 @@
setWorkInProgressByDefaultForUser();
+ // Clone the repo again. The test connection keeps an AccountState internally, so we need to
+ // create a new connection after changing account properties.
+ PatchSet.Id ps1OfChange1 =
+ PatchSet.id(Change.id(gApi.changes().id(changeId1).get()._number), 1);
+ testRepo = cloneProject(project);
+ testRepo.git().fetch().setRefSpecs(RefNames.patchSetRef(ps1OfChange1) + ":c1").call();
+ testRepo.reset("c1");
+
// Create a new patch set on the existing change and in the same push create a new successor
// change.
RevCommit commit1b = testRepo.amend(commit1a).create();
@@ -199,9 +212,12 @@
}
private void setWorkInProgressByDefaultForUser() throws Exception {
- GeneralPreferencesInfo prefs = gApi.accounts().id(admin.id().get()).getPreferences();
+ GeneralPreferencesInfo prefs = new GeneralPreferencesInfo();
prefs.workInProgressByDefault = true;
gApi.accounts().id(admin.id().get()).setPreferences(prefs);
+ // Generate a new API scope. User preferences are stored in IdentifiedUser, so we need to flush
+ // that entity.
+ requestScopeOperations.resetCurrentApiUser();
}
private PushOneCommit.Result createChange(Project.NameKey p) throws Exception {
diff --git a/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java b/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java
index 7627e65..68f10e6 100644
--- a/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java
@@ -340,6 +340,6 @@
accountsUpdateProvider
.get()
.update("Force set preferred email", id, (s, u) -> u.setPreferredEmail(email));
- assertThat(result.map(a -> a.getAccount().preferredEmail())).hasValue(email);
+ assertThat(result.map(a -> a.account().preferredEmail())).hasValue(email);
}
}
diff --git a/javatests/com/google/gerrit/acceptance/server/git/receive/ReceiveCommitsCommentValidationIT.java b/javatests/com/google/gerrit/acceptance/server/git/receive/ReceiveCommitsCommentValidationIT.java
index cb5add3..6677583 100644
--- a/javatests/com/google/gerrit/acceptance/server/git/receive/ReceiveCommitsCommentValidationIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/git/receive/ReceiveCommitsCommentValidationIT.java
@@ -15,6 +15,10 @@
package com.google.gerrit.acceptance.server.git.receive;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.acceptance.AbstractDaemonTest;
@@ -30,11 +34,10 @@
import com.google.gerrit.testing.TestCommentHelper;
import com.google.inject.Inject;
import com.google.inject.Module;
-import org.easymock.Capture;
-import org.easymock.EasyMock;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
/**
* Tests for comment validation when publishing drafts via the {@code --publish-comments} option.
@@ -45,14 +48,14 @@
private static final String COMMENT_TEXT = "The comment text";
- private Capture<ImmutableList<CommentForValidation>> capture = new Capture<>();
+ @Captor private ArgumentCaptor<ImmutableList<CommentForValidation>> capture;
@Override
public Module createModule() {
return new FactoryModule() {
@Override
public void configure() {
- CommentValidator mockCommentValidator = EasyMock.createMock(CommentValidator.class);
+ CommentValidator mockCommentValidator = mock(CommentValidator.class);
bind(CommentValidator.class)
.annotatedWith(Exports.named(mockCommentValidator.getClass()))
.toInstance(mockCommentValidator);
@@ -63,23 +66,17 @@
@Before
public void resetMock() {
- EasyMock.reset(mockCommentValidator);
- }
-
- @After
- public void verifyMock() {
- EasyMock.verify(mockCommentValidator);
+ initMocks(this);
+ clearInvocations(mockCommentValidator);
}
@Test
public void validateComments_commentOK() throws Exception {
- EasyMock.expect(
- mockCommentValidator.validateComments(
- ImmutableList.of(
- CommentForValidation.create(
- CommentForValidation.CommentType.FILE_COMMENT, COMMENT_TEXT))))
- .andReturn(ImmutableList.of());
- EasyMock.replay(mockCommentValidator);
+ when(mockCommentValidator.validateComments(
+ ImmutableList.of(
+ CommentForValidation.create(
+ CommentForValidation.CommentType.FILE_COMMENT, COMMENT_TEXT))))
+ .thenReturn(ImmutableList.of());
PushOneCommit.Result result = createChange();
String changeId = result.getChangeId();
String revId = result.getCommit().getName();
@@ -96,13 +93,11 @@
public void validateComments_commentRejected() throws Exception {
CommentForValidation commentForValidation =
CommentForValidation.create(CommentType.FILE_COMMENT, COMMENT_TEXT);
- EasyMock.expect(
- mockCommentValidator.validateComments(
- ImmutableList.of(
- CommentForValidation.create(
- CommentForValidation.CommentType.FILE_COMMENT, COMMENT_TEXT))))
- .andReturn(ImmutableList.of(commentForValidation.failValidation("Oh no!")));
- EasyMock.replay(mockCommentValidator);
+ when(mockCommentValidator.validateComments(
+ ImmutableList.of(
+ CommentForValidation.create(
+ CommentForValidation.CommentType.FILE_COMMENT, COMMENT_TEXT))))
+ .thenReturn(ImmutableList.of(commentForValidation.failValidation("Oh no!")));
PushOneCommit.Result result = createChange();
String changeId = result.getChangeId();
String revId = result.getCommit().getName();
@@ -117,9 +112,7 @@
@Test
public void validateComments_inlineVsFileComments_allOK() throws Exception {
- EasyMock.expect(mockCommentValidator.validateComments(EasyMock.capture(capture)))
- .andReturn(ImmutableList.of());
- EasyMock.replay(mockCommentValidator);
+ when(mockCommentValidator.validateComments(capture.capture())).thenReturn(ImmutableList.of());
PushOneCommit.Result result = createChange();
String changeId = result.getChangeId();
String revId = result.getCommit().getName();
@@ -132,7 +125,7 @@
assertThat(testCommentHelper.getPublishedComments(result.getChangeId())).isEmpty();
amendChange(changeId, "refs/for/master%publish-comments", admin, testRepo);
assertThat(testCommentHelper.getPublishedComments(result.getChangeId())).hasSize(2);
- assertThat(capture.getValues()).hasSize(1);
+ assertThat(capture.getAllValues()).hasSize(1);
assertThat(capture.getValue())
.containsExactly(
CommentForValidation.create(
diff --git a/javatests/com/google/gerrit/acceptance/server/quota/DefaultQuotaBackendIT.java b/javatests/com/google/gerrit/acceptance/server/quota/DefaultQuotaBackendIT.java
index 7d4b95e..8e0cd3d 100644
--- a/javatests/com/google/gerrit/acceptance/server/quota/DefaultQuotaBackendIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/quota/DefaultQuotaBackendIT.java
@@ -16,9 +16,9 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.resetToStrict;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.extensions.annotations.Exports;
@@ -35,13 +35,12 @@
import com.google.inject.Inject;
import com.google.inject.Module;
import java.util.Collections;
-import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
public class DefaultQuotaBackendIT extends AbstractDaemonTest {
- private static final QuotaEnforcer quotaEnforcer = EasyMock.createStrictMock(QuotaEnforcer.class);
+ private static final QuotaEnforcer quotaEnforcer = mock(QuotaEnforcer.class);
private IdentifiedUser identifiedAdmin;
@Inject private QuotaBackend quotaBackend;
@@ -61,14 +60,13 @@
@Before
public void setUp() {
identifiedAdmin = identifiedUserFactory.create(admin.id());
- resetToStrict(quotaEnforcer);
+ clearInvocations(quotaEnforcer);
}
@Test
public void requestTokenForUser() {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcer.requestTokens("testGroup", ctx, 1)).andReturn(QuotaResponse.ok());
- replay(quotaEnforcer);
+ when(quotaEnforcer.requestTokens("testGroup", ctx, 1)).thenReturn(QuotaResponse.ok());
assertThat(quotaBackend.user(identifiedAdmin).requestToken("testGroup"))
.isEqualTo(singletonAggregation(QuotaResponse.ok()));
}
@@ -77,8 +75,7 @@
public void requestTokenForUserAndAccount() {
QuotaRequestContext ctx =
QuotaRequestContext.builder().user(identifiedAdmin).account(user.id()).build();
- expect(quotaEnforcer.requestTokens("testGroup", ctx, 1)).andReturn(QuotaResponse.ok());
- replay(quotaEnforcer);
+ when(quotaEnforcer.requestTokens("testGroup", ctx, 1)).thenReturn(QuotaResponse.ok());
assertThat(quotaBackend.user(identifiedAdmin).account(user.id()).requestToken("testGroup"))
.isEqualTo(singletonAggregation(QuotaResponse.ok()));
}
@@ -87,8 +84,7 @@
public void requestTokenForUserAndProject() {
QuotaRequestContext ctx =
QuotaRequestContext.builder().user(identifiedAdmin).project(project).build();
- expect(quotaEnforcer.requestTokens("testGroup", ctx, 1)).andReturn(QuotaResponse.ok());
- replay(quotaEnforcer);
+ when(quotaEnforcer.requestTokens("testGroup", ctx, 1)).thenReturn(QuotaResponse.ok());
assertThat(quotaBackend.user(identifiedAdmin).project(project).requestToken("testGroup"))
.isEqualTo(singletonAggregation(QuotaResponse.ok()));
}
@@ -102,8 +98,7 @@
.change(changeId)
.project(project)
.build();
- expect(quotaEnforcer.requestTokens("testGroup", ctx, 1)).andReturn(QuotaResponse.ok());
- replay(quotaEnforcer);
+ when(quotaEnforcer.requestTokens("testGroup", ctx, 1)).thenReturn(QuotaResponse.ok());
assertThat(
quotaBackend.user(identifiedAdmin).change(changeId, project).requestToken("testGroup"))
.isEqualTo(singletonAggregation(QuotaResponse.ok()));
@@ -112,8 +107,7 @@
@Test
public void requestTokens() {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcer.requestTokens("testGroup", ctx, 123)).andReturn(QuotaResponse.ok());
- replay(quotaEnforcer);
+ when(quotaEnforcer.requestTokens("testGroup", ctx, 123)).thenReturn(QuotaResponse.ok());
assertThat(quotaBackend.user(identifiedAdmin).requestTokens("testGroup", 123))
.isEqualTo(singletonAggregation(QuotaResponse.ok()));
}
@@ -121,8 +115,7 @@
@Test
public void dryRun() {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcer.dryRun("testGroup", ctx, 123)).andReturn(QuotaResponse.ok());
- replay(quotaEnforcer);
+ when(quotaEnforcer.dryRun("testGroup", ctx, 123)).thenReturn(QuotaResponse.ok());
assertThat(quotaBackend.user(identifiedAdmin).dryRun("testGroup", 123))
.isEqualTo(singletonAggregation(QuotaResponse.ok()));
}
@@ -132,8 +125,7 @@
QuotaRequestContext ctx =
QuotaRequestContext.builder().user(identifiedAdmin).account(user.id()).build();
QuotaResponse r = QuotaResponse.ok(10L);
- expect(quotaEnforcer.availableTokens("testGroup", ctx)).andReturn(r);
- replay(quotaEnforcer);
+ when(quotaEnforcer.availableTokens("testGroup", ctx)).thenReturn(r);
assertThat(quotaBackend.user(identifiedAdmin).account(user.id()).availableTokens("testGroup"))
.isEqualTo(singletonAggregation(r));
}
@@ -143,8 +135,7 @@
QuotaRequestContext ctx =
QuotaRequestContext.builder().user(identifiedAdmin).project(project).build();
QuotaResponse r = QuotaResponse.ok(10L);
- expect(quotaEnforcer.availableTokens("testGroup", ctx)).andReturn(r);
- replay(quotaEnforcer);
+ when(quotaEnforcer.availableTokens("testGroup", ctx)).thenReturn(r);
assertThat(quotaBackend.user(identifiedAdmin).project(project).availableTokens("testGroup"))
.isEqualTo(singletonAggregation(r));
}
@@ -159,8 +150,7 @@
.project(project)
.build();
QuotaResponse r = QuotaResponse.ok(10L);
- expect(quotaEnforcer.availableTokens("testGroup", ctx)).andReturn(r);
- replay(quotaEnforcer);
+ when(quotaEnforcer.availableTokens("testGroup", ctx)).thenReturn(r);
assertThat(
quotaBackend
.user(identifiedAdmin)
@@ -173,8 +163,7 @@
public void availableTokens() {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
QuotaResponse r = QuotaResponse.ok(10L);
- expect(quotaEnforcer.availableTokens("testGroup", ctx)).andReturn(r);
- replay(quotaEnforcer);
+ when(quotaEnforcer.availableTokens("testGroup", ctx)).thenReturn(r);
assertThat(quotaBackend.user(identifiedAdmin).availableTokens("testGroup"))
.isEqualTo(singletonAggregation(r));
}
@@ -182,9 +171,8 @@
@Test
public void requestTokenError() throws Exception {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcer.requestTokens("testGroup", ctx, 1))
- .andReturn(QuotaResponse.error("failed"));
- replay(quotaEnforcer);
+ when(quotaEnforcer.requestTokens("testGroup", ctx, 1))
+ .thenReturn(QuotaResponse.error("failed"));
QuotaResponse.Aggregated result = quotaBackend.user(identifiedAdmin).requestToken("testGroup");
assertThat(result).isEqualTo(singletonAggregation(QuotaResponse.error("failed")));
@@ -195,9 +183,7 @@
@Test
public void availableTokensError() throws Exception {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcer.availableTokens("testGroup", ctx))
- .andReturn(QuotaResponse.error("failed"));
- replay(quotaEnforcer);
+ when(quotaEnforcer.availableTokens("testGroup", ctx)).thenReturn(QuotaResponse.error("failed"));
QuotaResponse.Aggregated result =
quotaBackend.user(identifiedAdmin).availableTokens("testGroup");
assertThat(result).isEqualTo(singletonAggregation(QuotaResponse.error("failed")));
@@ -208,8 +194,7 @@
@Test
public void requestTokenPluginThrowsAndRethrows() {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcer.requestTokens("testGroup", ctx, 1)).andThrow(new NullPointerException());
- replay(quotaEnforcer);
+ when(quotaEnforcer.requestTokens("testGroup", ctx, 1)).thenThrow(new NullPointerException());
assertThrows(
NullPointerException.class,
@@ -219,8 +204,7 @@
@Test
public void availableTokensPluginThrowsAndRethrows() {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcer.availableTokens("testGroup", ctx)).andThrow(new NullPointerException());
- replay(quotaEnforcer);
+ when(quotaEnforcer.availableTokens("testGroup", ctx)).thenThrow(new NullPointerException());
assertThrows(
NullPointerException.class,
diff --git a/javatests/com/google/gerrit/acceptance/server/quota/MultipleQuotaPluginsIT.java b/javatests/com/google/gerrit/acceptance/server/quota/MultipleQuotaPluginsIT.java
index 0ad2010..c6b09cc 100644
--- a/javatests/com/google/gerrit/acceptance/server/quota/MultipleQuotaPluginsIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/quota/MultipleQuotaPluginsIT.java
@@ -17,11 +17,10 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.resetToStrict;
-import static org.easymock.EasyMock.verify;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.acceptance.AbstractDaemonTest;
@@ -35,15 +34,12 @@
import com.google.inject.Inject;
import com.google.inject.Module;
import java.util.OptionalLong;
-import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
public class MultipleQuotaPluginsIT extends AbstractDaemonTest {
- private static final QuotaEnforcer quotaEnforcerA =
- EasyMock.createStrictMock(QuotaEnforcer.class);
- private static final QuotaEnforcer quotaEnforcerB =
- EasyMock.createStrictMock(QuotaEnforcer.class);
+ private static final QuotaEnforcer quotaEnforcerA = mock(QuotaEnforcer.class);
+ private static final QuotaEnforcer quotaEnforcerB = mock(QuotaEnforcer.class);
private IdentifiedUser identifiedAdmin;
@Inject private QuotaBackend quotaBackend;
@@ -67,39 +63,32 @@
@Before
public void setUp() {
identifiedAdmin = identifiedUserFactory.create(admin.id());
- resetToStrict(quotaEnforcerA);
- resetToStrict(quotaEnforcerB);
+ clearInvocations(quotaEnforcerA);
+ clearInvocations(quotaEnforcerB);
}
@Test
public void refillsOnError() {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcerA.requestTokens("testGroup", ctx, 1)).andReturn(QuotaResponse.ok());
- expect(quotaEnforcerB.requestTokens("testGroup", ctx, 1))
- .andReturn(QuotaResponse.error("fail"));
- quotaEnforcerA.refill("testGroup", ctx, 1);
- expectLastCall();
-
- replay(quotaEnforcerA);
- replay(quotaEnforcerB);
+ when(quotaEnforcerA.requestTokens("testGroup", ctx, 1)).thenReturn(QuotaResponse.ok());
+ when(quotaEnforcerB.requestTokens("testGroup", ctx, 1)).thenReturn(QuotaResponse.error("fail"));
assertThat(quotaBackend.user(identifiedAdmin).requestToken("testGroup"))
.isEqualTo(
QuotaResponse.Aggregated.create(
ImmutableList.of(QuotaResponse.ok(), QuotaResponse.error("fail"))));
+
+ verify(quotaEnforcerA).requestTokens("testGroup", ctx, 1);
+ verify(quotaEnforcerB).requestTokens("testGroup", ctx, 1);
+ verify(quotaEnforcerA).refill("testGroup", ctx, 1);
}
@Test
public void refillsOnException() {
NullPointerException exception = new NullPointerException();
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcerA.requestTokens("testGroup", ctx, 1)).andThrow(exception);
- expect(quotaEnforcerB.requestTokens("testGroup", ctx, 1)).andReturn(QuotaResponse.ok());
- quotaEnforcerB.refill("testGroup", ctx, 1);
- expectLastCall();
-
- replay(quotaEnforcerA);
- replay(quotaEnforcerB);
+ when(quotaEnforcerA.requestTokens("testGroup", ctx, 1)).thenReturn(QuotaResponse.ok());
+ when(quotaEnforcerB.requestTokens("testGroup", ctx, 1)).thenThrow(exception);
NullPointerException thrown =
assertThrows(
@@ -107,52 +96,53 @@
() -> quotaBackend.user(identifiedAdmin).requestToken("testGroup"));
assertThat(thrown).isEqualTo(exception);
- verify(quotaEnforcerA);
+ verify(quotaEnforcerA).requestTokens("testGroup", ctx, 1);
+ verify(quotaEnforcerB).requestTokens("testGroup", ctx, 1);
+ verify(quotaEnforcerA).refill("testGroup", ctx, 1);
}
@Test
public void doesNotRefillNoOp() {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcerA.requestTokens("testGroup", ctx, 1))
- .andReturn(QuotaResponse.error("fail"));
- expect(quotaEnforcerB.requestTokens("testGroup", ctx, 1)).andReturn(QuotaResponse.noOp());
-
- replay(quotaEnforcerA);
- replay(quotaEnforcerB);
+ when(quotaEnforcerA.requestTokens("testGroup", ctx, 1)).thenReturn(QuotaResponse.error("fail"));
+ when(quotaEnforcerB.requestTokens("testGroup", ctx, 1)).thenReturn(QuotaResponse.noOp());
assertThat(quotaBackend.user(identifiedAdmin).requestToken("testGroup"))
.isEqualTo(
QuotaResponse.Aggregated.create(
ImmutableList.of(QuotaResponse.error("fail"), QuotaResponse.noOp())));
+
+ verify(quotaEnforcerA).requestTokens("testGroup", ctx, 1);
+ verify(quotaEnforcerB).requestTokens("testGroup", ctx, 1);
}
@Test
public void minimumAvailableTokens() {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcerA.availableTokens("testGroup", ctx)).andReturn(QuotaResponse.ok(20L));
- expect(quotaEnforcerB.availableTokens("testGroup", ctx)).andReturn(QuotaResponse.ok(10L));
-
- replay(quotaEnforcerA);
- replay(quotaEnforcerB);
+ when(quotaEnforcerA.availableTokens("testGroup", ctx)).thenReturn(QuotaResponse.ok(20L));
+ when(quotaEnforcerB.availableTokens("testGroup", ctx)).thenReturn(QuotaResponse.ok(10L));
OptionalLong tokens =
quotaBackend.user(identifiedAdmin).availableTokens("testGroup").availableTokens();
assertThat(tokens).isPresent();
assertThat(tokens.getAsLong()).isEqualTo(10L);
+
+ verify(quotaEnforcerA).availableTokens("testGroup", ctx);
+ verify(quotaEnforcerB).availableTokens("testGroup", ctx);
}
@Test
public void ignoreNoOpForAvailableTokens() {
QuotaRequestContext ctx = QuotaRequestContext.builder().user(identifiedAdmin).build();
- expect(quotaEnforcerA.availableTokens("testGroup", ctx)).andReturn(QuotaResponse.noOp());
- expect(quotaEnforcerB.availableTokens("testGroup", ctx)).andReturn(QuotaResponse.ok(20L));
-
- replay(quotaEnforcerA);
- replay(quotaEnforcerB);
+ when(quotaEnforcerA.availableTokens("testGroup", ctx)).thenReturn(QuotaResponse.noOp());
+ when(quotaEnforcerB.availableTokens("testGroup", ctx)).thenReturn(QuotaResponse.ok(20L));
OptionalLong tokens =
quotaBackend.user(identifiedAdmin).availableTokens("testGroup").availableTokens();
assertThat(tokens).isPresent();
assertThat(tokens.getAsLong()).isEqualTo(20L);
+
+ verify(quotaEnforcerA).availableTokens("testGroup", ctx);
+ verify(quotaEnforcerB).availableTokens("testGroup", ctx);
}
}
diff --git a/javatests/com/google/gerrit/acceptance/server/quota/RepositorySizeQuotaIT.java b/javatests/com/google/gerrit/acceptance/server/quota/RepositorySizeQuotaIT.java
index 05b3b83..801288a 100644
--- a/javatests/com/google/gerrit/acceptance/server/quota/RepositorySizeQuotaIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/quota/RepositorySizeQuotaIT.java
@@ -15,15 +15,16 @@
package com.google.gerrit.acceptance.server.quota;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.gerrit.server.quota.QuotaGroupDefinitions.REPOSITORY_SIZE_GROUP;
import static com.google.gerrit.server.quota.QuotaResponse.ok;
-import static org.easymock.EasyMock.anyLong;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.resetToStrict;
-import static org.easymock.EasyMock.verify;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.UseLocalDisk;
@@ -33,7 +34,6 @@
import com.google.gerrit.server.quota.QuotaResponse;
import com.google.inject.Module;
import java.util.Collections;
-import org.easymock.EasyMock;
import org.eclipse.jgit.api.errors.TooLargeObjectInPackException;
import org.eclipse.jgit.api.errors.TransportException;
import org.junit.Before;
@@ -42,9 +42,9 @@
@UseLocalDisk
public class RepositorySizeQuotaIT extends AbstractDaemonTest {
private static final QuotaBackend.WithResource quotaBackendWithResource =
- EasyMock.createStrictMock(QuotaBackend.WithResource.class);
+ mock(QuotaBackend.WithResource.class);
private static final QuotaBackend.WithUser quotaBackendWithUser =
- EasyMock.createStrictMock(QuotaBackend.WithUser.class);
+ mock(QuotaBackend.WithUser.class);
@Override
public Module createModule() {
@@ -70,64 +70,42 @@
@Before
public void setUp() {
- resetToStrict(quotaBackendWithResource);
- resetToStrict(quotaBackendWithUser);
+ clearInvocations(quotaBackendWithResource);
+ clearInvocations(quotaBackendWithUser);
}
@Test
public void pushWithAvailableTokens() throws Exception {
- expect(quotaBackendWithResource.availableTokens(REPOSITORY_SIZE_GROUP))
- .andReturn(singletonAggregation(ok(276L)))
- .times(2);
- expect(quotaBackendWithResource.requestTokens(eq(REPOSITORY_SIZE_GROUP), anyLong()))
- .andReturn(singletonAggregation(ok()));
- expect(quotaBackendWithUser.project(project)).andReturn(quotaBackendWithResource).anyTimes();
- replay(quotaBackendWithResource);
- replay(quotaBackendWithUser);
+ when(quotaBackendWithResource.availableTokens(REPOSITORY_SIZE_GROUP))
+ .thenReturn(singletonAggregation(ok(276L)));
+ when(quotaBackendWithResource.requestTokens(eq(REPOSITORY_SIZE_GROUP), anyLong()))
+ .thenReturn(singletonAggregation(ok()));
+ when(quotaBackendWithUser.project(project)).thenReturn(quotaBackendWithResource);
pushCommit();
- verify(quotaBackendWithUser);
- verify(quotaBackendWithResource);
+ verify(quotaBackendWithResource, times(2)).availableTokens(REPOSITORY_SIZE_GROUP);
}
@Test
public void pushWithNotSufficientTokens() throws Exception {
long availableTokens = 1L;
- expect(quotaBackendWithResource.availableTokens(REPOSITORY_SIZE_GROUP))
- .andReturn(singletonAggregation(ok(availableTokens)))
- .anyTimes();
- expect(quotaBackendWithUser.project(project)).andReturn(quotaBackendWithResource).anyTimes();
- replay(quotaBackendWithResource);
- replay(quotaBackendWithUser);
- try {
- pushCommit();
- assertWithMessage("expected TooLargeObjectInPackException").fail();
- } catch (TooLargeObjectInPackException e) {
- String msg = e.getMessage();
- assertThat(msg).contains("Object too large");
- assertThat(msg)
- .contains(String.format("Max object size limit is %d bytes.", availableTokens));
- }
- verify(quotaBackendWithUser);
- verify(quotaBackendWithResource);
+ when(quotaBackendWithResource.availableTokens(REPOSITORY_SIZE_GROUP))
+ .thenReturn(singletonAggregation(ok(availableTokens)));
+ when(quotaBackendWithUser.project(project)).thenReturn(quotaBackendWithResource);
+ TooLargeObjectInPackException thrown =
+ assertThrows(TooLargeObjectInPackException.class, () -> pushCommit());
+ assertThat(thrown).hasMessageThat().contains("Object too large");
+ assertThat(thrown)
+ .hasMessageThat()
+ .contains(String.format("Max object size limit is %d bytes.", availableTokens));
}
@Test
public void errorGettingAvailableTokens() throws Exception {
String msg = "quota error";
- expect(quotaBackendWithResource.availableTokens(REPOSITORY_SIZE_GROUP))
- .andReturn(singletonAggregation(QuotaResponse.error(msg)))
- .anyTimes();
- expect(quotaBackendWithUser.project(project)).andReturn(quotaBackendWithResource).anyTimes();
- replay(quotaBackendWithResource);
- replay(quotaBackendWithUser);
- try {
- pushCommit();
- assertWithMessage("expected TransportException").fail();
- } catch (TransportException e) {
- // TransportException has not much info about the cause
- }
- verify(quotaBackendWithUser);
- verify(quotaBackendWithResource);
+ when(quotaBackendWithResource.availableTokens(REPOSITORY_SIZE_GROUP))
+ .thenReturn(singletonAggregation(QuotaResponse.error(msg)));
+ when(quotaBackendWithUser.project(project)).thenReturn(quotaBackendWithResource);
+ assertThrows(TransportException.class, () -> pushCommit());
}
private void pushCommit() throws Exception {
diff --git a/javatests/com/google/gerrit/acceptance/server/quota/RestApiQuotaIT.java b/javatests/com/google/gerrit/acceptance/server/quota/RestApiQuotaIT.java
index 802f55f..917d597 100644
--- a/javatests/com/google/gerrit/acceptance/server/quota/RestApiQuotaIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/quota/RestApiQuotaIT.java
@@ -14,10 +14,11 @@
package com.google.gerrit.acceptance.server.quota;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
+import static com.google.gerrit.httpd.restapi.RestApiServlet.SC_TOO_MANY_REQUESTS;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.extensions.common.ChangeInfo;
@@ -29,15 +30,14 @@
import com.google.gerrit.server.quota.QuotaResponse;
import com.google.inject.Module;
import java.util.Collections;
-import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
public class RestApiQuotaIT extends AbstractDaemonTest {
private static final QuotaBackend.WithResource quotaBackendWithResource =
- EasyMock.createStrictMock(QuotaBackend.WithResource.class);
+ mock(QuotaBackend.WithResource.class);
private static final QuotaBackend.WithUser quotaBackendWithUser =
- EasyMock.createStrictMock(QuotaBackend.WithUser.class);
+ mock(QuotaBackend.WithUser.class);
@Override
public Module createModule() {
@@ -63,72 +63,65 @@
@Before
public void setUp() {
- reset(quotaBackendWithResource);
- reset(quotaBackendWithUser);
+ clearInvocations(quotaBackendWithResource);
+ clearInvocations(quotaBackendWithUser);
}
@Test
public void changeDetail() throws Exception {
Change.Id changeId = retrieveChangeId();
- expect(quotaBackendWithResource.requestToken("/restapi/changes/detail:GET"))
- .andReturn(singletonAggregation(QuotaResponse.ok()));
- replay(quotaBackendWithResource);
- expect(quotaBackendWithUser.change(changeId, project)).andReturn(quotaBackendWithResource);
- replay(quotaBackendWithUser);
+ when(quotaBackendWithResource.requestToken("/restapi/changes/detail:GET"))
+ .thenReturn(singletonAggregation(QuotaResponse.ok()));
+ when(quotaBackendWithUser.change(changeId, project)).thenReturn(quotaBackendWithResource);
adminRestSession.get("/changes/" + changeId + "/detail").assertOK();
- verify(quotaBackendWithUser);
- verify(quotaBackendWithResource);
+ verify(quotaBackendWithResource).requestToken("/restapi/changes/detail:GET");
+ verify(quotaBackendWithUser).change(changeId, project);
}
@Test
public void revisionDetail() throws Exception {
Change.Id changeId = retrieveChangeId();
- expect(quotaBackendWithResource.requestToken("/restapi/changes/revisions/actions:GET"))
- .andReturn(singletonAggregation(QuotaResponse.ok()));
- replay(quotaBackendWithResource);
- expect(quotaBackendWithUser.change(changeId, project)).andReturn(quotaBackendWithResource);
- replay(quotaBackendWithUser);
+ when(quotaBackendWithResource.requestToken("/restapi/changes/revisions/actions:GET"))
+ .thenReturn(singletonAggregation(QuotaResponse.ok()));
+ when(quotaBackendWithUser.change(changeId, project)).thenReturn(quotaBackendWithResource);
adminRestSession.get("/changes/" + changeId + "/revisions/current/actions").assertOK();
- verify(quotaBackendWithUser);
- verify(quotaBackendWithResource);
+ verify(quotaBackendWithResource).requestToken("/restapi/changes/revisions/actions:GET");
+ verify(quotaBackendWithUser).change(changeId, project);
}
@Test
public void createChangePost() throws Exception {
- expect(quotaBackendWithUser.requestToken("/restapi/changes:POST"))
- .andReturn(singletonAggregation(QuotaResponse.ok()));
- replay(quotaBackendWithUser);
+ when(quotaBackendWithUser.requestToken("/restapi/changes:POST"))
+ .thenReturn(singletonAggregation(QuotaResponse.ok()));
ChangeInput changeInput = new ChangeInput(project.get(), "master", "test");
adminRestSession.post("/changes/", changeInput).assertCreated();
- verify(quotaBackendWithUser);
+ verify(quotaBackendWithUser).requestToken("/restapi/changes:POST");
}
@Test
public void accountDetail() throws Exception {
- expect(quotaBackendWithResource.requestToken("/restapi/accounts/detail:GET"))
- .andReturn(singletonAggregation(QuotaResponse.ok()));
- replay(quotaBackendWithResource);
- expect(quotaBackendWithUser.account(admin.id())).andReturn(quotaBackendWithResource);
- replay(quotaBackendWithUser);
+ when(quotaBackendWithResource.requestToken("/restapi/accounts/detail:GET"))
+ .thenReturn(singletonAggregation(QuotaResponse.ok()));
+ when(quotaBackendWithUser.account(admin.id())).thenReturn(quotaBackendWithResource);
adminRestSession.get("/accounts/self/detail").assertOK();
- verify(quotaBackendWithUser);
- verify(quotaBackendWithResource);
+ verify(quotaBackendWithResource).requestToken("/restapi/accounts/detail:GET");
+ verify(quotaBackendWithUser).account(admin.id());
}
@Test
public void config() throws Exception {
- expect(quotaBackendWithUser.requestToken("/restapi/config/version:GET"))
- .andReturn(singletonAggregation(QuotaResponse.ok()));
- replay(quotaBackendWithUser);
+ when(quotaBackendWithUser.requestToken("/restapi/config/version:GET"))
+ .thenReturn(singletonAggregation(QuotaResponse.ok()));
adminRestSession.get("/config/server/version").assertOK();
+ verify(quotaBackendWithUser).requestToken("/restapi/config/version:GET");
}
@Test
public void outOfQuotaReturnsError() throws Exception {
- expect(quotaBackendWithUser.requestToken("/restapi/config/version:GET"))
- .andReturn(singletonAggregation(QuotaResponse.error("no quota")));
- replay(quotaBackendWithUser);
- adminRestSession.get("/config/server/version").assertStatus(429);
+ when(quotaBackendWithUser.requestToken("/restapi/config/version:GET"))
+ .thenReturn(singletonAggregation(QuotaResponse.error("no quota")));
+ adminRestSession.get("/config/server/version").assertStatus(SC_TOO_MANY_REQUESTS);
+ verify(quotaBackendWithUser).requestToken("/restapi/config/version:GET");
}
private Change.Id retrieveChangeId() throws Exception {
diff --git a/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java b/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
index bc035af..1f101ef 100644
--- a/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
+++ b/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
@@ -198,7 +198,7 @@
.update(
"Delete External IDs",
user.getAccountId(),
- (a, u) -> u.deleteExternalIds(a.getExternalIds()));
+ (a, u) -> u.deleteExternalIds(a.externalIds()));
reloadUser();
TestKey key = validKeyWithSecondUserId();
diff --git a/javatests/com/google/gerrit/httpd/BUILD b/javatests/com/google/gerrit/httpd/BUILD
index 6849d66..2254c4e 100644
--- a/javatests/com/google/gerrit/httpd/BUILD
+++ b/javatests/com/google/gerrit/httpd/BUILD
@@ -19,11 +19,11 @@
"//lib:junit",
"//lib:servlet-api-3_1-without-neverlink",
"//lib:soy",
- "//lib/easymock",
"//lib/guice",
"//lib/guice:guice-servlet",
"//lib/jgit/org.eclipse.jgit:jgit",
"//lib/jgit/org.eclipse.jgit.junit:junit",
+ "//lib/mockito",
"//lib/truth",
"//lib/truth:truth-java8-extension",
],
diff --git a/javatests/com/google/gerrit/httpd/raw/IndexServletTest.java b/javatests/com/google/gerrit/httpd/raw/IndexServletTest.java
index 99835dd..77ab58b 100644
--- a/javatests/com/google/gerrit/httpd/raw/IndexServletTest.java
+++ b/javatests/com/google/gerrit/httpd/raw/IndexServletTest.java
@@ -15,10 +15,8 @@
package com.google.gerrit.httpd.raw;
import static com.google.common.truth.Truth.assertThat;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.extensions.api.GerritApi;
@@ -35,22 +33,22 @@
@Test
public void renderTemplate() throws Exception {
- Accounts accountsApi = createMock(Accounts.class);
- expect(accountsApi.self()).andThrow(new AuthException("user needs to be authenticated"));
+ Accounts accountsApi = mock(Accounts.class);
+ when(accountsApi.self()).thenThrow(new AuthException("user needs to be authenticated"));
- Server serverApi = createMock(Server.class);
- expect(serverApi.getVersion()).andReturn("123");
- expect(serverApi.topMenus()).andReturn(ImmutableList.of());
+ Server serverApi = mock(Server.class);
+ when(serverApi.getVersion()).thenReturn("123");
+ when(serverApi.topMenus()).thenReturn(ImmutableList.of());
ServerInfo serverInfo = new ServerInfo();
serverInfo.defaultTheme = "my-default-theme";
- expect(serverApi.getInfo()).andReturn(serverInfo);
+ when(serverApi.getInfo()).thenReturn(serverInfo);
- Config configApi = createMock(Config.class);
- expect(configApi.server()).andReturn(serverApi);
+ Config configApi = mock(Config.class);
+ when(configApi.server()).thenReturn(serverApi);
- GerritApi gerritApi = createMock(GerritApi.class);
- expect(gerritApi.accounts()).andReturn(accountsApi);
- expect(gerritApi.config()).andReturn(configApi);
+ GerritApi gerritApi = mock(GerritApi.class);
+ when(gerritApi.accounts()).thenReturn(accountsApi);
+ when(gerritApi.config()).thenReturn(configApi);
String testCanonicalUrl = "foo-url";
String testCdnPath = "bar-cdn";
@@ -60,18 +58,8 @@
FakeHttpServletResponse response = new FakeHttpServletResponse();
- replay(gerritApi);
- replay(configApi);
- replay(serverApi);
- replay(accountsApi);
-
servlet.doGet(new FakeHttpServletRequest(), response);
- verify(gerritApi);
- verify(configApi);
- verify(serverApi);
- verify(accountsApi);
-
String output = response.getActualBodyString();
assertThat(output).contains("<!DOCTYPE html>");
assertThat(output).contains("window.CANONICAL_PATH = '" + testCanonicalUrl);
diff --git a/javatests/com/google/gerrit/server/BUILD b/javatests/com/google/gerrit/server/BUILD
index 1bb22e4..4383431 100644
--- a/javatests/com/google/gerrit/server/BUILD
+++ b/javatests/com/google/gerrit/server/BUILD
@@ -45,6 +45,7 @@
"//java/com/google/gerrit/index",
"//java/com/google/gerrit/index:query_exception",
"//java/com/google/gerrit/jgit",
+ "//java/com/google/gerrit/json",
"//java/com/google/gerrit/lifecycle",
"//java/com/google/gerrit/mail",
"//java/com/google/gerrit/metrics",
diff --git a/javatests/com/google/gerrit/server/account/AccountResolverTest.java b/javatests/com/google/gerrit/server/account/AccountResolverTest.java
index e9e5e54..f5788ca 100644
--- a/javatests/com/google/gerrit/server/account/AccountResolverTest.java
+++ b/javatests/com/google/gerrit/server/account/AccountResolverTest.java
@@ -84,7 +84,7 @@
@Override
public String toString() {
return accounts.stream()
- .map(a -> a.getAccount().id().toString())
+ .map(a -> a.account().id().toString())
.collect(joining(",", pattern + "(", ")"));
}
}
@@ -156,7 +156,7 @@
// Searchers always short-circuit when finding a non-empty result list, and this one didn't
// filter out inactive results, so the second searcher never ran.
assertThat(result.asIdSet()).containsExactlyElementsIn(ids(1));
- assertThat(getOnlyElement(result.asList()).getAccount().isActive()).isFalse();
+ assertThat(getOnlyElement(result.asList()).account().isActive()).isFalse();
assertThat(filteredInactiveIds(result)).isEmpty();
}
@@ -173,7 +173,7 @@
// and this one didn't filter out inactive results,
// so the second searcher never ran.
assertThat(result.asIdSet()).containsExactlyElementsIn(ids(1));
- assertThat(getOnlyElement(result.asList()).getAccount().isActive()).isFalse();
+ assertThat(getOnlyElement(result.asList()).account().isActive()).isFalse();
assertThat(filteredInactiveIds(result)).isEmpty();
}
@@ -255,8 +255,8 @@
AccountState account = newAccount(1);
ImmutableList<Searcher<?>> searchers =
ImmutableList.of(new TestSearcher("foo", false, account));
- assertThat(search("foo", searchers, allVisible()).asUnique().getAccount().id())
- .isEqualTo(account.getAccount().id());
+ assertThat(search("foo", searchers, allVisible()).asUnique().account().id())
+ .isEqualTo(account.account().id());
}
@Test
@@ -375,18 +375,16 @@
}
private Predicate<AccountState> activityPrediate() {
- return (AccountState accountState) -> accountState.getAccount().isActive();
+ return (AccountState accountState) -> accountState.account().isActive();
}
private static Supplier<Predicate<AccountState>> only(int... ids) {
ImmutableSet<Account.Id> idSet =
Arrays.stream(ids).mapToObj(Account::id).collect(toImmutableSet());
- return () -> a -> idSet.contains(a.getAccount().id());
+ return () -> a -> idSet.contains(a.account().id());
}
private static ImmutableSet<Account.Id> filteredInactiveIds(Result result) {
- return result.filteredInactive().stream()
- .map(a -> a.getAccount().id())
- .collect(toImmutableSet());
+ return result.filteredInactive().stream().map(a -> a.account().id()).collect(toImmutableSet());
}
}
diff --git a/javatests/com/google/gerrit/server/account/PreferencesTest.java b/javatests/com/google/gerrit/server/account/PreferencesTest.java
index b1d31bf..9866481 100644
--- a/javatests/com/google/gerrit/server/account/PreferencesTest.java
+++ b/javatests/com/google/gerrit/server/account/PreferencesTest.java
@@ -15,52 +15,36 @@
package com.google.gerrit.server.account;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
+import com.google.gerrit.extensions.client.EditPreferencesInfo;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.git.ValidationError;
-import org.eclipse.jgit.lib.Config;
+import com.google.gerrit.json.OutputFormat;
+import com.google.gson.Gson;
import org.junit.Test;
-import org.mockito.Mockito;
-/** Tests for parsing user preferences from Git. */
public class PreferencesTest {
- enum Unknown {
- STATE
+ private static final Gson GSON = OutputFormat.JSON_COMPACT.newGson();
+
+ @Test
+ public void generalPreferencesRoundTrip() {
+ GeneralPreferencesInfo original = GeneralPreferencesInfo.defaults();
+ assertThat(GSON.toJson(original))
+ .isEqualTo(GSON.toJson(Preferences.General.fromInfo(original).toInfo()));
}
@Test
- public void ignoreUnknownAccountPreferencesWhenParsing() {
- ValidationError.Sink errorSink = Mockito.mock(ValidationError.Sink.class);
- Preferences preferences =
- new Preferences(Account.id(1), configWithUnknownEntries(), new Config(), errorSink);
- GeneralPreferencesInfo parsedPreferences = preferences.getGeneralPreferences();
-
- assertThat(parsedPreferences).isNotNull();
- assertThat(parsedPreferences.expandInlineDiffs).isTrue();
- verifyNoMoreInteractions(errorSink);
+ public void diffPreferencesRoundTrip() {
+ DiffPreferencesInfo original = DiffPreferencesInfo.defaults();
+ assertThat(GSON.toJson(original))
+ .isEqualTo(GSON.toJson(Preferences.Diff.fromInfo(original).toInfo()));
}
@Test
- public void ignoreUnknownDefaultAccountPreferencesWhenParsing() {
- ValidationError.Sink errorSink = Mockito.mock(ValidationError.Sink.class);
- Preferences preferences =
- new Preferences(Account.id(1), new Config(), configWithUnknownEntries(), errorSink);
- GeneralPreferencesInfo parsedPreferences = preferences.getGeneralPreferences();
-
- assertThat(parsedPreferences).isNotNull();
- assertThat(parsedPreferences.expandInlineDiffs).isTrue();
- verifyNoMoreInteractions(errorSink);
- }
-
- private static Config configWithUnknownEntries() {
- Config cfg = new Config();
- cfg.setBoolean("general", null, "expandInlineDiffs", true);
- cfg.setBoolean("general", null, "unknown", true);
- cfg.setEnum("general", null, "unknownenum", Unknown.STATE);
- cfg.setString("general", null, "unknownstring", "bla");
- return cfg;
+ public void editPreferencesRoundTrip() {
+ EditPreferencesInfo original = EditPreferencesInfo.defaults();
+ assertThat(GSON.toJson(original))
+ .isEqualTo(GSON.toJson(Preferences.Edit.fromInfo(original).toInfo()));
}
}
diff --git a/javatests/com/google/gerrit/server/account/StoredPreferencesTest.java b/javatests/com/google/gerrit/server/account/StoredPreferencesTest.java
new file mode 100644
index 0000000..2bb0deb
--- /dev/null
+++ b/javatests/com/google/gerrit/server/account/StoredPreferencesTest.java
@@ -0,0 +1,66 @@
+// 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.
+
+package com.google.gerrit.server.account;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.server.git.ValidationError;
+import org.eclipse.jgit.lib.Config;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/** Tests for parsing user preferences from Git. */
+public class StoredPreferencesTest {
+
+ enum Unknown {
+ STATE
+ }
+
+ @Test
+ public void ignoreUnknownAccountPreferencesWhenParsing() {
+ ValidationError.Sink errorSink = Mockito.mock(ValidationError.Sink.class);
+ StoredPreferences preferences =
+ new StoredPreferences(Account.id(1), configWithUnknownEntries(), new Config(), errorSink);
+ GeneralPreferencesInfo parsedPreferences = preferences.getGeneralPreferences();
+
+ assertThat(parsedPreferences).isNotNull();
+ assertThat(parsedPreferences.expandInlineDiffs).isTrue();
+ verifyNoMoreInteractions(errorSink);
+ }
+
+ @Test
+ public void ignoreUnknownDefaultAccountPreferencesWhenParsing() {
+ ValidationError.Sink errorSink = Mockito.mock(ValidationError.Sink.class);
+ StoredPreferences preferences =
+ new StoredPreferences(Account.id(1), new Config(), configWithUnknownEntries(), errorSink);
+ GeneralPreferencesInfo parsedPreferences = preferences.getGeneralPreferences();
+
+ assertThat(parsedPreferences).isNotNull();
+ assertThat(parsedPreferences.expandInlineDiffs).isTrue();
+ verifyNoMoreInteractions(errorSink);
+ }
+
+ private static Config configWithUnknownEntries() {
+ Config cfg = new Config();
+ cfg.setBoolean("general", null, "expandInlineDiffs", true);
+ cfg.setBoolean("general", null, "unknown", true);
+ cfg.setEnum("general", null, "unknownenum", Unknown.STATE);
+ cfg.setString("general", null, "unknownstring", "bla");
+ return cfg;
+ }
+}
diff --git a/javatests/com/google/gerrit/server/account/UniversalGroupBackendTest.java b/javatests/com/google/gerrit/server/account/UniversalGroupBackendTest.java
index 8bac910..9f083b2 100644
--- a/javatests/com/google/gerrit/server/account/UniversalGroupBackendTest.java
+++ b/javatests/com/google/gerrit/server/account/UniversalGroupBackendTest.java
@@ -17,18 +17,15 @@
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
import static com.google.gerrit.server.group.SystemGroupBackend.PROJECT_OWNERS;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.getCurrentArguments;
-import static org.easymock.EasyMock.not;
-import static org.easymock.EasyMock.replay;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalMatchers.not;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -41,6 +38,8 @@
import org.eclipse.jgit.lib.Config;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
public class UniversalGroupBackendTest {
private static final AccountGroup.UUID OTHER_UUID = AccountGroup.uuid("other");
@@ -52,8 +51,7 @@
@Before
public void setup() {
- user = createNiceMock(IdentifiedUser.class);
- replay(user);
+ user = mock(IdentifiedUser.class);
backends = new DynamicSet<>();
backends.add("gerrit", new SystemGroupBackend(new Config()));
backend =
@@ -103,23 +101,24 @@
public void otherMemberships() {
final AccountGroup.UUID handled = AccountGroup.uuid("handled");
final AccountGroup.UUID notHandled = AccountGroup.uuid("not handled");
- final IdentifiedUser member = createNiceMock(IdentifiedUser.class);
- final IdentifiedUser notMember = createNiceMock(IdentifiedUser.class);
+ final IdentifiedUser member = mock(IdentifiedUser.class);
+ final IdentifiedUser notMember = mock(IdentifiedUser.class);
- GroupBackend backend = createMock(GroupBackend.class);
- expect(backend.handles(handled)).andStubReturn(true);
- expect(backend.handles(not(eq(handled)))).andStubReturn(false);
- expect(backend.membershipsOf(anyObject(IdentifiedUser.class)))
- .andStubAnswer(
- () -> {
- Object[] args = getCurrentArguments();
- GroupMembership membership = createMock(GroupMembership.class);
- expect(membership.contains(eq(handled))).andStubReturn(args[0] == member);
- expect(membership.contains(not(eq(notHandled)))).andStubReturn(false);
- replay(membership);
- return membership;
+ GroupBackend backend = mock(GroupBackend.class);
+ when(backend.handles(eq(handled))).thenReturn(true);
+ when(backend.handles(not(eq(handled)))).thenReturn(false);
+ when(backend.membershipsOf(any(IdentifiedUser.class)))
+ .thenAnswer(
+ new Answer<GroupMembership>() {
+ @Override
+ public GroupMembership answer(InvocationOnMock invocation) {
+ GroupMembership membership = mock(GroupMembership.class);
+ when(membership.contains(eq(handled)))
+ .thenReturn(invocation.getArguments()[0] == member);
+ when(membership.contains(eq(notHandled))).thenReturn(false);
+ return membership;
+ }
});
- replay(member, notMember, backend);
backends = new DynamicSet<>();
backends.add("gerrit", backend);
diff --git a/javatests/com/google/gerrit/server/fixes/FixReplacementInterpreterTest.java b/javatests/com/google/gerrit/server/fixes/FixReplacementInterpreterTest.java
index c8df548..2174927 100644
--- a/javatests/com/google/gerrit/server/fixes/FixReplacementInterpreterTest.java
+++ b/javatests/com/google/gerrit/server/fixes/FixReplacementInterpreterTest.java
@@ -16,8 +16,8 @@
import static com.google.gerrit.server.edit.tree.TreeModificationSubject.assertThatList;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.replay;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.extensions.restapi.BinaryResult;
@@ -30,17 +30,16 @@
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
-import org.easymock.EasyMock;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.junit.Before;
import org.junit.Test;
public class FixReplacementInterpreterTest {
- private final FileContentUtil fileContentUtil = createMock(FileContentUtil.class);
- private final Repository repository = createMock(Repository.class);
- private final ProjectState projectState = createMock(ProjectState.class);
- private final ObjectId patchSetCommitId = createMock(ObjectId.class);
+ private final FileContentUtil fileContentUtil = mock(FileContentUtil.class);
+ private final Repository repository = mock(Repository.class);
+ private final ProjectState projectState = mock(ProjectState.class);
+ private final ObjectId patchSetCommitId = mock(ObjectId.class);
private final String filePath1 = "an/arbitrary/file.txt";
private final String filePath2 = "another/arbitrary/file.txt";
@@ -68,7 +67,6 @@
new FixReplacement(filePath2, new Range(2, 0, 3, 0), "Another modified content");
mockFileContent(filePath2, "1st line\n2nd line\n3rd line\n");
- replay(fileContentUtil);
List<TreeModification> treeModifications =
toTreeModifications(fixReplacement, fixReplacement3, fixReplacement2);
List<TreeModification> sortedTreeModifications = getSortedCopy(treeModifications);
@@ -99,7 +97,6 @@
FixReplacement fixReplacement = new FixReplacement(filePath1, new Range(2, 0, 3, 0), "");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
assertThatList(treeModifications)
.onlyElement()
@@ -114,7 +111,6 @@
new FixReplacement(filePath1, new Range(2, 0, 2, 0), "A new line\n");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
assertThatList(treeModifications)
.onlyElement()
@@ -128,7 +124,6 @@
FixReplacement fixReplacement = new FixReplacement(filePath1, new Range(1, 6, 3, 1), "and t");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
assertThatList(treeModifications)
.onlyElement()
@@ -144,7 +139,6 @@
new FixReplacement(filePath1, new Range(2, 7, 2, 11), "modification");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
List<TreeModification> treeModifications =
toTreeModifications(fixReplacement1, fixReplacement2);
assertThatList(treeModifications)
@@ -162,7 +156,6 @@
new FixReplacement(filePath1, new Range(2, 7, 3, 5), "content");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
List<TreeModification> treeModifications =
toTreeModifications(fixReplacement1, fixReplacement2);
assertThatList(treeModifications)
@@ -178,7 +171,6 @@
new FixReplacement(filePath1, new Range(4, 0, 4, 0), "New content");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
assertThatList(treeModifications)
.onlyElement()
@@ -198,7 +190,6 @@
new FixReplacement(filePath2, new Range(3, 0, 4, 0), "Second modification\n");
mockFileContent(filePath2, "1st line\n2nd line\n3rd line\n");
- replay(fileContentUtil);
List<TreeModification> treeModifications =
toTreeModifications(fixReplacement3, fixReplacement1, fixReplacement2);
List<TreeModification> sortedTreeModifications = getSortedCopy(treeModifications);
@@ -219,7 +210,6 @@
FixReplacement fixReplacement = new FixReplacement(filePath1, new Range(2, 11, 3, 0), "\r");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
List<TreeModification> treeModifications = toTreeModifications(fixReplacement);
assertThatList(treeModifications)
.onlyElement()
@@ -238,7 +228,6 @@
new FixReplacement(filePath1, new Range(4, 0, 5, 0), "3rd modification\n");
mockFileContent(filePath1, "First line\nSecond line\nThird line\nFourth line\nFifth line\n");
- replay(fileContentUtil);
List<TreeModification> treeModifications =
toTreeModifications(fixReplacement2, fixReplacement1, fixReplacement3);
assertThatList(treeModifications)
@@ -255,7 +244,6 @@
new FixReplacement(filePath1, new Range(5, 0, 5, 0), "A new line\n");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
assertThrows(ResourceConflictException.class, () -> toTreeModifications(fixReplacement));
}
@@ -265,8 +253,6 @@
new FixReplacement(filePath1, new Range(0, 0, 0, 0), "A new line\n");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
-
assertThrows(ResourceConflictException.class, () -> toTreeModifications(fixReplacement));
}
@@ -276,7 +262,6 @@
new FixReplacement(filePath1, new Range(1, 0, 1, 11), "modified");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
assertThrows(ResourceConflictException.class, () -> toTreeModifications(fixReplacement));
}
@@ -286,8 +271,6 @@
new FixReplacement(filePath1, new Range(3, 0, 3, 11), "modified");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
-
assertThrows(ResourceConflictException.class, () -> toTreeModifications(fixReplacement));
}
@@ -297,14 +280,12 @@
new FixReplacement(filePath1, new Range(1, -1, 1, 5), "modified");
mockFileContent(filePath1, "First line\nSecond line\nThird line\n");
- replay(fileContentUtil);
assertThrows(ResourceConflictException.class, () -> toTreeModifications(fixReplacement));
}
private void mockFileContent(String filePath, String fileContent) throws Exception {
- EasyMock.expect(
- fileContentUtil.getContent(repository, projectState, patchSetCommitId, filePath))
- .andReturn(BinaryResult.create(fileContent));
+ when(fileContentUtil.getContent(repository, projectState, patchSetCommitId, filePath))
+ .thenReturn(BinaryResult.create(fileContent));
}
private List<TreeModification> toTreeModifications(FixReplacement... fixReplacements)
diff --git a/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java b/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
index 491594b..cbef04a 100644
--- a/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
+++ b/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
@@ -16,10 +16,8 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reset;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.reviewdb.client.Project;
@@ -55,9 +53,8 @@
site.resolve("git").toFile().mkdir();
cfg = new Config();
cfg.setString("gerrit", null, "basePath", "git");
- configMock = createNiceMock(RepositoryConfig.class);
- expect(configMock.getAllBasePaths()).andReturn(ImmutableList.of()).anyTimes();
- replay(configMock);
+ configMock = mock(RepositoryConfig.class);
+ when(configMock.getAllBasePaths()).thenReturn(ImmutableList.of());
repoManager = new MultiBaseLocalDiskRepositoryManager(site, cfg, configMock);
}
@@ -90,10 +87,8 @@
public void alternateRepositoryLocation() throws IOException {
Path alternateBasePath = temporaryFolder.newFolder().toPath();
Project.NameKey someProjectKey = Project.nameKey("someProject");
- reset(configMock);
- expect(configMock.getBasePath(someProjectKey)).andReturn(alternateBasePath).anyTimes();
- expect(configMock.getAllBasePaths()).andReturn(ImmutableList.of(alternateBasePath)).anyTimes();
- replay(configMock);
+ when(configMock.getBasePath(someProjectKey)).thenReturn(alternateBasePath);
+ when(configMock.getAllBasePaths()).thenReturn(ImmutableList.of(alternateBasePath));
Repository repo = repoManager.createRepository(someProjectKey);
assertThat(repo.getDirectory()).isNotNull();
@@ -123,11 +118,9 @@
Path alternateBasePath = temporaryFolder.newFolder().toPath();
- reset(configMock);
- expect(configMock.getBasePath(altPathProject)).andReturn(alternateBasePath).anyTimes();
- expect(configMock.getBasePath(misplacedProject2)).andReturn(alternateBasePath).anyTimes();
- expect(configMock.getAllBasePaths()).andReturn(ImmutableList.of(alternateBasePath)).anyTimes();
- replay(configMock);
+ when(configMock.getBasePath(altPathProject)).thenReturn(alternateBasePath);
+ when(configMock.getBasePath(misplacedProject2)).thenReturn(alternateBasePath);
+ when(configMock.getAllBasePaths()).thenReturn(ImmutableList.of(alternateBasePath));
repoManager.createRepository(basePathProject);
repoManager.createRepository(altPathProject);
@@ -155,11 +148,8 @@
assertThrows(
IllegalStateException.class,
() -> {
- configMock = createNiceMock(RepositoryConfig.class);
- expect(configMock.getAllBasePaths())
- .andReturn(ImmutableList.of(Paths.get("repos")))
- .anyTimes();
- replay(configMock);
+ configMock = mock(RepositoryConfig.class);
+ when(configMock.getAllBasePaths()).thenReturn(ImmutableList.of(Paths.get("repos")));
repoManager = new MultiBaseLocalDiskRepositoryManager(site, cfg, configMock);
});
}
diff --git a/javatests/com/google/gerrit/server/group/db/AuditLogReaderTest.java b/javatests/com/google/gerrit/server/group/db/AuditLogReaderTest.java
index a5b755e..81108ea 100644
--- a/javatests/com/google/gerrit/server/group/db/AuditLogReaderTest.java
+++ b/javatests/com/google/gerrit/server/group/db/AuditLogReaderTest.java
@@ -37,7 +37,7 @@
@Before
public void setUp() throws Exception {
- auditLogReader = new AuditLogReader(SERVER_ID, allUsersName);
+ auditLogReader = new AuditLogReader(allUsersName);
}
@Test
diff --git a/javatests/com/google/gerrit/server/mail/send/FromAddressGeneratorProviderTest.java b/javatests/com/google/gerrit/server/mail/send/FromAddressGeneratorProviderTest.java
index ff114fa7..27f5938 100644
--- a/javatests/com/google/gerrit/server/mail/send/FromAddressGeneratorProviderTest.java
+++ b/javatests/com/google/gerrit/server/mail/send/FromAddressGeneratorProviderTest.java
@@ -15,11 +15,11 @@
package com.google.gerrit.server.mail.send;
import static com.google.common.truth.Truth.assertThat;
-import static org.easymock.EasyMock.createStrictMock;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
import com.google.gerrit.mail.Address;
import com.google.gerrit.reviewdb.client.Account;
@@ -43,7 +43,7 @@
public void setUp() throws Exception {
config = new Config();
ident = new PersonIdent("NAME", "e@email", 0, 0);
- accountCache = createStrictMock(AccountCache.class);
+ accountCache = mock(AccountCache.class);
}
private FromAddressGenerator create() {
@@ -83,12 +83,11 @@
final String email = "a.u.thor@test.example.com";
final Account.Id user = user(name, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(name);
assertThat(r.getEmail()).isEqualTo(email);
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
@@ -98,12 +97,11 @@
final String email = "a.u.thor@test.example.com";
final Account.Id user = user(null, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isNull();
assertThat(r.getEmail()).isEqualTo(email);
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
@@ -113,23 +111,21 @@
final String name = "A U. Thor";
final Account.Id user = user(name, null);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(name + " (Code Review)");
assertThat(r.getEmail()).isEqualTo(ident.getEmailAddress());
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
public void USER_NullUser() {
setFrom("USER");
- replay(accountCache);
final Address r = create().from(null);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(ident.getName());
assertThat(r.getEmail()).isEqualTo(ident.getEmailAddress());
- verify(accountCache);
+ verifyZeroInteractions(accountCache);
}
@Test
@@ -140,12 +136,11 @@
final String email = "a.u.thor@test.example.com";
final Account.Id user = user(name, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(name);
assertThat(r.getEmail()).isEqualTo(email);
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
@@ -156,12 +151,11 @@
final String email = "a.u.thor@test.com";
final Account.Id user = user(name, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(name + " (Code Review)");
assertThat(r.getEmail()).isEqualTo(ident.getEmailAddress());
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
@@ -173,12 +167,11 @@
final String email = "a.u.thor@test.com";
final Account.Id user = user(name, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(name);
assertThat(r.getEmail()).isEqualTo(email);
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
@@ -190,12 +183,11 @@
final String email = "a.u.thor@test.com";
final Account.Id user = user(name, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(name + " (Code Review)");
assertThat(r.getEmail()).isEqualTo(ident.getEmailAddress());
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
@@ -206,12 +198,11 @@
final String email = "a.u.thor@test.com";
final Account.Id user = user(name, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(name);
assertThat(r.getEmail()).isEqualTo(email);
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
@@ -234,23 +225,21 @@
final String email = "a.u.thor@test.example.com";
final Account.Id user = userNoLookup(name, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(ident.getName());
assertThat(r.getEmail()).isEqualTo(ident.getEmailAddress());
- verify(accountCache);
+ verifyZeroInteractions(accountCache);
}
@Test
public void SERVER_NullUser() {
setFrom("SERVER");
- replay(accountCache);
final Address r = create().from(null);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(ident.getName());
assertThat(r.getEmail()).isEqualTo(ident.getEmailAddress());
- verify(accountCache);
+ verifyZeroInteractions(accountCache);
}
@Test
@@ -273,12 +262,11 @@
final String email = "a.u.thor@test.example.com";
final Account.Id user = user(name, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(name + " (Code Review)");
assertThat(r.getEmail()).isEqualTo(ident.getEmailAddress());
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
@@ -288,12 +276,11 @@
final String email = "a.u.thor@test.example.com";
final Account.Id user = user(null, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo("Anonymous Coward (Code Review)");
assertThat(r.getEmail()).isEqualTo(ident.getEmailAddress());
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
@@ -303,23 +290,21 @@
final String name = "A U. Thor";
final Account.Id user = user(name, null);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(name + " (Code Review)");
assertThat(r.getEmail()).isEqualTo(ident.getEmailAddress());
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
public void MIXED_NullUser() {
setFrom("MIXED");
- replay(accountCache);
final Address r = create().from(null);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(ident.getName());
assertThat(r.getEmail()).isEqualTo(ident.getEmailAddress());
- verify(accountCache);
+ verifyZeroInteractions(accountCache);
}
@Test
@@ -330,12 +315,11 @@
final String email = "a.u.thor@test.example.com";
final Account.Id user = user(name, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo("A " + name + " B");
assertThat(r.getEmail()).isEqualTo("my.server@email.address");
- verify(accountCache);
+ verifyAccountCacheGet(user);
}
@Test
@@ -345,35 +329,35 @@
final String email = "a.u.thor@test.example.com";
final Account.Id user = user(null, email);
- replay(accountCache);
final Address r = create().from(user);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo("A Anonymous Coward B");
assertThat(r.getEmail()).isEqualTo("my.server@email.address");
- verify(accountCache);
}
@Test
public void CUSTOM_NullUser() {
setFrom("A ${user} B <my.server@email.address>");
- replay(accountCache);
final Address r = create().from(null);
assertThat(r).isNotNull();
assertThat(r.getName()).isEqualTo(ident.getName());
assertThat(r.getEmail()).isEqualTo("my.server@email.address");
- verify(accountCache);
}
private Account.Id user(String name, String email) {
final AccountState s = makeUser(name, email);
- expect(accountCache.get(eq(s.getAccount().id()))).andReturn(Optional.of(s));
- return s.getAccount().id();
+ when(accountCache.get(eq(s.account().id()))).thenReturn(Optional.of(s));
+ return s.account().id();
+ }
+
+ private void verifyAccountCacheGet(Account.Id id) {
+ verify(accountCache).get(eq(id));
}
private Account.Id userNoLookup(String name, String email) {
final AccountState s = makeUser(name, email);
- return s.getAccount().id();
+ return s.account().id();
}
private AccountState makeUser(String name, String email) {
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java
index 3e54863..a4602e19 100644
--- a/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java
+++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java
@@ -56,6 +56,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.UUID;
import org.eclipse.jgit.lib.ObjectId;
import org.junit.Before;
import org.junit.Test;
@@ -66,6 +67,7 @@
ObjectId.fromString("1234567812345678123456781234567812345678");
private static final ByteString SHA_BYTES = ObjectIdConverter.create().toByteString(SHA);
private static final String CHANGE_KEY = "Iabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd";
+ private static final String DEFAULT_SERVER_ID = UUID.randomUUID().toString();
private ChangeColumns cols;
private ChangeColumnsProto colsProto;
@@ -717,6 +719,7 @@
ImmutableMap.<String, Type>builder()
.put("metaId", ObjectId.class)
.put("changeId", Change.Id.class)
+ .put("serverId", String.class)
.put("columns", ChangeColumns.class)
.put("pastAssignees", new TypeLiteral<ImmutableSet<Account.Id>>() {}.getType())
.put("hashtags", new TypeLiteral<ImmutableSet<String>>() {}.getType())
@@ -918,6 +921,19 @@
.build());
}
+ @Test
+ public void serializeServerId() throws Exception {
+ assertRoundTrip(
+ newBuilder().serverId(DEFAULT_SERVER_ID).build(),
+ ChangeNotesStateProto.newBuilder()
+ .setMetaId(SHA_BYTES)
+ .setChangeId(ID.get())
+ .setServerId(DEFAULT_SERVER_ID)
+ .setHasServerId(true)
+ .setColumns(colsProto.toBuilder())
+ .build());
+ }
+
private static ChangeNotesStateProto toProto(ChangeNotesState state) throws Exception {
return ChangeNotesStateProto.parseFrom(Serializer.INSTANCE.serialize(state));
}
diff --git a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
index 33f47b2..fce3744 100644
--- a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
+++ b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
@@ -816,7 +816,7 @@
}
protected void assertAccounts(List<AccountState> accounts, AccountInfo... expectedAccounts) {
- assertThat(accounts.stream().map(a -> a.getAccount().id().get()).collect(toList()))
+ assertThat(accounts.stream().map(a -> a.account().id().get()).collect(toList()))
.containsExactlyElementsIn(
Arrays.asList(expectedAccounts).stream().map(a -> a._accountId).collect(toList()));
}
diff --git a/plugins/replication b/plugins/replication
index 5a3519e..4ca9342 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 5a3519e6e1733e2515900866b8db9ca98ba9da7e
+Subproject commit 4ca93421cb84b80da2c76ac6bba95117aa53543c
diff --git a/plugins/reviewnotes b/plugins/reviewnotes
index 3667220..10dd134 160000
--- a/plugins/reviewnotes
+++ b/plugins/reviewnotes
@@ -1 +1 @@
-Subproject commit 3667220b860d444406ca5fa5cc27d87858642596
+Subproject commit 10dd13408ac80985fabd1b90da81887fa0472c58
diff --git a/plugins/singleusergroup b/plugins/singleusergroup
index 731af7e..3c4e63c 160000
--- a/plugins/singleusergroup
+++ b/plugins/singleusergroup
@@ -1 +1 @@
-Subproject commit 731af7e23c5a235c5ce087aaeb44dc8a12070bcb
+Subproject commit 3c4e63c40937a9b47c9536851ae4c286ec94db3f
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
index 63f3eaf..8e57534 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
@@ -329,17 +329,8 @@
name: 'ldap/tests tests'}});
assert.equal(element._rules.length, 3);
assert.equal(Object.keys(element._groupsWithRules).length, 3);
- if (Polymer.Element) {
- // Under Polymer 2 gr-rule-editor.js#_handleValueChange get's
- // fully loaded before this change, thus `modified: true` get's managed
- // to be added. Under Polymer 1 it was a mix hence why it was not
- // added in time for when this test ran.
- assert.deepEqual(element.permission.value.rules['ldap:CN=test test'],
- {action: 'ALLOW', min: -2, max: 2, modified: true, added: true});
- } else {
- assert.deepEqual(element.permission.value.rules['ldap:CN=test test'],
- {action: 'ALLOW', min: -2, max: 2, added: true});
- }
+ assert.deepEqual(element.permission.value.rules['ldap:CN=test test'],
+ {action: 'ALLOW', min: -2, max: 2, added: true});
// New rule should be removed if cancel from editing.
element.editing = false;
assert.equal(element._rules.length, 2);
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
index 53db6d5..f22c5a5 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
@@ -102,10 +102,12 @@
const SCHEMES = {http: {}, repo: {}, ssh: {}};
function getFormFields() {
- const selects = Polymer.dom(element.root).querySelectorAll('select');
- const textareas =
- Polymer.dom(element.root).querySelectorAll('iron-autogrow-textarea');
- const inputs = Polymer.dom(element.root).querySelectorAll('input');
+ const selects = Array.from(
+ Polymer.dom(element.root).querySelectorAll('select'));
+ const textareas = Array.from(
+ Polymer.dom(element.root).querySelectorAll('iron-autogrow-textarea'));
+ const inputs = Array.from(
+ Polymer.dom(element.root).querySelectorAll('input'));
return inputs.concat(textareas).concat(selects);
}
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
index f206514..df5a9f3 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
@@ -118,11 +118,20 @@
this._setupValues(this.rule);
},
+ attached() {
+ if (!this.rule) { return; } // Check needed for test purposes.
+ if (!this._originalRuleValues) {
+ // Observer _handleValueChange is called after the ready()
+ // method finishes. Original values must be set later to
+ // avoid set .modified flag to true
+ this._setOriginalRuleValues(this.rule.value);
+ }
+ },
+
_setupValues(rule) {
if (!rule.value) {
this._setDefaultRuleValues();
}
- this._setOriginalRuleValues(rule.value);
},
_computeForce(permission, action) {
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html
index 17e8c6c..4ea3817 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html
@@ -202,7 +202,7 @@
});
suite('already existing generic rule', () => {
- setup(() => {
+ setup(done => {
element.group = 'Group Name';
element.permission = 'submit';
element.rule = {
@@ -218,6 +218,10 @@
// by the parent element.
element._setupValues(element.rule);
flushAsynchronousOperations();
+ flush(() => {
+ element.attached();
+ done();
+ });
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -313,7 +317,7 @@
});
suite('new edit rule', () => {
- setup(() => {
+ setup(done => {
element.group = 'Group Name';
element.permission = 'editTopicName';
element.rule = {
@@ -323,6 +327,10 @@
element._setupValues(element.rule);
flushAsynchronousOperations();
element.rule.value.added = true;
+ flush(() => {
+ element.attached();
+ done();
+ });
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -362,7 +370,7 @@
});
suite('already existing rule with labels', () => {
- setup(() => {
+ setup(done => {
element.label = {values: [
{value: -2, text: 'This shall not be merged'},
{value: -1, text: 'I would prefer this is not merged as is'},
@@ -384,6 +392,10 @@
element.section = 'refs/*';
element._setupValues(element.rule);
flushAsynchronousOperations();
+ flush(() => {
+ element.attached();
+ done();
+ });
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -416,7 +428,7 @@
});
suite('new rule with labels', () => {
- setup(() => {
+ setup(done => {
sandbox.spy(element, '_setDefaultRuleValues');
element.label = {values: [
{value: -2, text: 'This shall not be merged'},
@@ -434,6 +446,10 @@
element._setupValues(element.rule);
flushAsynchronousOperations();
element.rule.value.added = true;
+ flush(() => {
+ element.attached();
+ done();
+ });
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -474,7 +490,7 @@
});
suite('already existing push rule', () => {
- setup(() => {
+ setup(done => {
element.group = 'Group Name';
element.permission = 'push';
element.rule = {
@@ -487,6 +503,10 @@
element.section = 'refs/*';
element._setupValues(element.rule);
flushAsynchronousOperations();
+ flush(() => {
+ element.attached();
+ done();
+ });
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -515,7 +535,7 @@
});
suite('new push rule', () => {
- setup(() => {
+ setup(done => {
element.group = 'Group Name';
element.permission = 'push';
element.rule = {
@@ -525,6 +545,10 @@
element._setupValues(element.rule);
flushAsynchronousOperations();
element.rule.value.added = true;
+ flush(() => {
+ element.attached();
+ done();
+ });
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -555,7 +579,7 @@
});
suite('already existing edit rule', () => {
- setup(() => {
+ setup(done => {
element.group = 'Group Name';
element.permission = 'editTopicName';
element.rule = {
@@ -568,6 +592,10 @@
element.section = 'refs/*';
element._setupValues(element.rule);
flushAsynchronousOperations();
+ flush(() => {
+ element.attached();
+ done();
+ });
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
index b582b0e..6d638b4 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
@@ -160,16 +160,14 @@
<td class="cell owner"
hidden$="[[isColumnHidden('Owner', visibleChangeTableColumns)]]">
<gr-account-link
- account="[[change.owner]]"
- additional-text="[[_computeAccountStatusString(change.owner)]]"></gr-account-link>
+ account="[[change.owner]]"></gr-account-link>
</td>
<td class="cell assignee"
hidden$="[[isColumnHidden('Assignee', visibleChangeTableColumns)]]">
<template is="dom-if" if="[[change.assignee]]">
<gr-account-link
id="assigneeAccountLink"
- account="[[change.assignee]]"
- additional-text="[[_computeAccountStatusString(change.assignee)]]"></gr-account-link>
+ account="[[change.assignee]]"></gr-account-link>
</template>
<template is="dom-if" if="[[!change.assignee]]">
<span class="placeholder">--</span>
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
index 1f0da2b..9cf2ad6 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
@@ -165,10 +165,6 @@
return str;
},
- _computeAccountStatusString(account) {
- return account && account.status ? `(${account.status})` : '';
- },
-
_computeSizeTooltip(change) {
if (change.insertions + change.deletions === 0 ||
isNaN(change.insertions + change.deletions)) {
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
index df4a442..1cddbc5 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
@@ -189,14 +189,6 @@
};
flushAsynchronousOperations();
assert.isOk(element.$$('.assignee gr-account-link'));
- assert.equal(Polymer.dom(element.root)
- .querySelector('#assigneeAccountLink').additionalText, '(test)');
- });
-
- test('_computeAccountStatusString', () => {
- assert.equal(element._computeAccountStatusString({}), '');
- assert.equal(element._computeAccountStatusString({status: 'Working'}),
- '(Working)');
});
test('TShirt sizing tooltip', () => {
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
index 282d8de..de02923 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
@@ -146,7 +146,8 @@
});
test('anchors use download attribute', () => {
- const anchors = Polymer.dom(element.root).querySelectorAll('a');
+ const anchors = Array.from(
+ Polymer.dom(element.root).querySelectorAll('a'));
assert.isTrue(!anchors.some(a => !a.hasAttribute('download')));
});
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
index 4920e20..5f7ccbe 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
@@ -267,7 +267,7 @@
assert.isTrue(element.$$('iron-selector').hidden);
});
- test('asymetrical labels', () => {
+ test('asymetrical labels', done => {
element.permittedLabels = {
'Code-Review': [
'-2',
@@ -281,30 +281,35 @@
'+1',
],
};
- flushAsynchronousOperations();
- assert.strictEqual(element.$$('iron-selector')
- .items.length, 2);
- assert.strictEqual(Polymer.dom(element.root).
- querySelectorAll('.placeholder').length, 3);
+ flush(() => {
+ assert.strictEqual(element.$$('iron-selector')
+ .items.length, 2);
+ assert.strictEqual(
+ Polymer.dom(element.root).querySelectorAll('.placeholder').length,
+ 3);
- element.permittedLabels = {
- 'Code-Review': [
- ' 0',
- '+1',
- ],
- 'Verified': [
- '-2',
- '-1',
- ' 0',
- '+1',
- '+2',
- ],
- };
- flushAsynchronousOperations();
- assert.strictEqual(element.$$('iron-selector')
- .items.length, 5);
- assert.strictEqual(Polymer.dom(element.root).
- querySelectorAll('.placeholder').length, 0);
+ element.permittedLabels = {
+ 'Code-Review': [
+ ' 0',
+ '+1',
+ ],
+ 'Verified': [
+ '-2',
+ '-1',
+ ' 0',
+ '+1',
+ '+2',
+ ],
+ };
+ flush(() => {
+ assert.strictEqual(element.$$('iron-selector')
+ .items.length, 5);
+ assert.strictEqual(
+ Polymer.dom(element.root).querySelectorAll('.placeholder').length,
+ 0);
+ done();
+ });
+ });
});
test('default_value', () => {
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
index 01f1f4d..6b738d8 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
@@ -277,17 +277,19 @@
});
});
- test('setlabelValue', () => {
+ test('setlabelValue', done => {
element._account = {_account_id: 1};
- flushAsynchronousOperations();
- const label = 'Verified';
- const value = '+1';
- element.setLabelValue(label, value);
- flushAsynchronousOperations();
- const labels = element.$.labelScores.getLabelValues();
- assert.deepEqual(labels, {
- 'Code-Review': 0,
- 'Verified': 1,
+ flush(() => {
+ const label = 'Verified';
+ const value = '+1';
+ element.setLabelValue(label, value);
+
+ const labels = element.$.labelScores.getLabelValues();
+ assert.deepEqual(labels, {
+ 'Code-Review': 0,
+ 'Verified': 1,
+ });
+ done();
});
});
@@ -310,6 +312,26 @@
});
}
+ function isFocusInsideElement(element) {
+ // In Polymer 2 focused element either <paper-input> or nested
+ // native input <input> element depending on the current focus
+ // in browser window.
+ // For example, the focus is changed if the developer console
+ // get a focus.
+ let activeElement = getActiveElement();
+ while (activeElement) {
+ if (activeElement === element) {
+ return true;
+ }
+ if (activeElement.parentElement) {
+ activeElement = activeElement.parentElement;
+ } else {
+ activeElement = activeElement.getRootNode().host;
+ }
+ }
+ return false;
+ }
+
function testConfirmationDialog(done, cc) {
const yesButton =
element.$$('.reviewerConfirmationButtons gr-button:first-child');
@@ -363,7 +385,8 @@
assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
// We should be focused on account entry input.
- assert.equal(getActiveElement().id, 'input');
+ assert.isTrue(
+ isFocusInsideElement(element.$.reviewers.$.entry.$.input.$.input));
// No reviewer/CC should have been added.
assert.equal(element.$$('#ccs').additions().length, 0);
@@ -408,7 +431,13 @@
]);
// We should be focused on account entry input.
- assert.equal(getActiveElement().id, 'input');
+ if (cc) {
+ assert.isTrue(
+ isFocusInsideElement(element.$.ccs.$.entry.$.input.$.input));
+ } else {
+ assert.isTrue(
+ isFocusInsideElement(element.$.reviewers.$.entry.$.input.$.input));
+ }
}).then(done);
}
@@ -1239,4 +1268,4 @@
assert.equal(element.$.pluginMessage.textContent, 'foo');
});
});
-</script>
\ No newline at end of file
+</script>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
index 4a98ef3..f29a5da 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
@@ -227,8 +227,10 @@
this.$.coverageLayerLeft,
this.$.coverageLayerRight,
];
- layers.push(...this.pluginLayers);
+ if (this.pluginLayers) {
+ layers.push(...this.pluginLayers);
+ }
this._layers = layers;
},
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
index 325ac05..6831a8d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
@@ -37,7 +37,7 @@
<test-fixture id="basic">
<template is="dom-template">
- <gr-diff-builder plugin-layers="[[pluginLayers]]">
+ <gr-diff-builder>
<table id="diffTable"></table>
</gr-diff-builder>
</template>
@@ -596,7 +596,8 @@
let withPluginLayerCount;
setup(() => {
const pluginLayers = [];
- element = fixture('basic', {pluginLayers});
+ element = fixture('basic');
+ element.pluginLayers = pluginLayers;
element._showTrailingWhitespace = true;
element._setupAnnotationLayers();
initialLayersCount = element._layers.length;
@@ -610,7 +611,8 @@
suite('with plugin layers', () => {
const pluginLayers = [{}, {}];
setup(() => {
- element = fixture('basic', {pluginLayers});
+ element = fixture('basic');
+ element.pluginLayers = pluginLayers;
element._showTrailingWhitespace = true;
element._setupAnnotationLayers();
withPluginLayerCount = element._layers.length;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js
index 2a54fbb..e3a4821 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js
@@ -65,7 +65,10 @@
/**
* If set, the cursor will attempt to move to the line number (instead of
* the first chunk) the next time the diff renders. It is set back to null
- * when used.
+ * when used. It should be only used if you want the line to be focused
+ * after initialization of the component and page should scroll
+ * to that position. This parameter should be set at most for one gr-diff
+ * element in the page.
*
* @type (?number)
*/
@@ -223,9 +226,12 @@
handleDiffUpdate() {
this._updateStops();
- this._scrollBehavior =
- ScrollBehavior.NEVER; // Never scroll during initialization.
if (!this.diffRow) {
+ // does not scroll during init unless requested
+ const scrollingBehaviorForInit = this.initialLineNumber ?
+ ScrollBehavior.KEEP_VISIBLE :
+ ScrollBehavior.NEVER;
+ this._scrollBehavior = scrollingBehaviorForInit;
this.reInitCursor();
}
this._scrollBehavior = ScrollBehavior.KEEP_VISIBLE;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
index d36a72d4..7280f2f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
@@ -209,34 +209,40 @@
assert.equal(cursorElement.side, 'left');
});
- test('initialLineNumber disabled', done => {
+ test('initialLineNumber not provided', done => {
+ let scrollBehaviorDuringMove;
const moveToNumStub = sandbox.stub(cursorElement, 'moveToLineNumber');
- const moveToChunkStub = sandbox.stub(cursorElement, 'moveToFirstChunk');
+ const moveToChunkStub = sandbox.stub(cursorElement, 'moveToFirstChunk',
+ () => { scrollBehaviorDuringMove = cursorElement._scrollBehavior; });
function renderHandler() {
diffElement.removeEventListener('render', renderHandler);
assert.isFalse(moveToNumStub.called);
assert.isTrue(moveToChunkStub.called);
+ assert.equal(scrollBehaviorDuringMove, 'never');
+ assert.equal(cursorElement._scrollBehavior, 'keep-visible');
done();
}
diffElement.addEventListener('render', renderHandler);
diffElement._diffChanged(mockDiffResponse.diffResponse);
});
- test('initialLineNumber enabled', done => {
- const moveToNumStub = sandbox.stub(cursorElement, 'moveToLineNumber');
+ test('initialLineNumber provided', done => {
+ let scrollBehaviorDuringMove;
+ const moveToNumStub = sandbox.stub(cursorElement, 'moveToLineNumber',
+ () => { scrollBehaviorDuringMove = cursorElement._scrollBehavior; });
const moveToChunkStub = sandbox.stub(cursorElement, 'moveToFirstChunk');
-
function renderHandler() {
diffElement.removeEventListener('render', renderHandler);
assert.isFalse(moveToChunkStub.called);
assert.isTrue(moveToNumStub.called);
assert.equal(moveToNumStub.lastCall.args[0], 10);
assert.equal(moveToNumStub.lastCall.args[1], 'right');
+ assert.equal(scrollBehaviorDuringMove, 'keep-visible');
+ assert.equal(cursorElement._scrollBehavior, 'keep-visible');
done();
}
diffElement.addEventListener('render', renderHandler);
-
cursorElement.initialLineNumber = 10;
cursorElement.side = 'right';
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
index db3f4a3..f87ef7a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
@@ -267,7 +267,15 @@
element.path = 'some/path';
element.projectName = 'Some project';
const threadEls = threads.map(
- thread => element._createThreadElement(thread));
+ thread => {
+ const threadEl = element._createThreadElement(thread);
+ // Polymer 2 doesn't fire ready events and doesn't execute
+ // observers if element is not added to the Dom.
+ // See https://github.com/Polymer/old-docs-site/issues/2322
+ // and https://github.com/Polymer/polymer/issues/4526
+ element._attachThreadElement(threadEl);
+ return threadEl;
+ });
assert.equal(threadEls.length, 2);
assert.equal(threadEls[0].rootId, 4711);
assert.equal(threadEls[1].rootId, 42);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
index ff7593b..9cd0527 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
@@ -163,6 +163,7 @@
_handleCopy(e) {
// Let the browser handle the copy event for polymer 2
// as selection across shadow DOM will be hard to process
+ // If you remove the following line, please remove it from tests also.
if (window.POLYMER2) return;
let commentSelected = false;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
index 0f5c6dd..a2696c2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
@@ -189,12 +189,18 @@
});
test('ignores copy for non-content Element', () => {
+ // See _handleCopy for explanation
+ if (window.POLYMER2) return;
+
sandbox.stub(element, '_getSelectedText');
emulateCopyOn(element.querySelector('.not-diff-row'));
assert.isFalse(element._getSelectedText.called);
});
test('asks for text for left side Elements', () => {
+ // See _handleCopy for explanation
+ if (window.POLYMER2) return;
+
element._cachedDiffBuilder.getSideByLineEl.returns('left');
sandbox.stub(element, '_getSelectedText');
emulateCopyOn(element.querySelector('div.contentText'));
@@ -202,12 +208,18 @@
});
test('reacts to copy for content Elements', () => {
+ // See _handleCopy for explanation
+ if (window.POLYMER2) return;
+
sandbox.stub(element, '_getSelectedText');
emulateCopyOn(element.querySelector('div.contentText'));
assert.isTrue(element._getSelectedText.called);
});
test('copy event is prevented for content Elements', () => {
+ // See _handleCopy for explanation
+ if (window.POLYMER2) return;
+
sandbox.stub(element, '_getSelectedText');
element._cachedDiffBuilder.getSideByLineEl.returns('left');
element._getSelectedText.returns('test');
@@ -216,6 +228,9 @@
});
test('inserts text into clipboard on copy', () => {
+ // See _handleCopy for explanation
+ if (window.POLYMER2) return;
+
sandbox.stub(element, '_getSelectedText').returns('the text');
const event = emulateCopyOn(element.querySelector('div.contentText'));
assert.deepEqual(
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js
index ece15bc..35b78ca 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js
@@ -168,7 +168,11 @@
// just make two separate queries.
dialog.querySelectorAll('gr-autocomplete')
.forEach(input => { input.text = ''; });
- dialog.querySelectorAll('input')
+
+ // TODO: reveiw binding for input after drop Polymer 1 support
+ // All docs related to Polymer 2 set binding only for iron-input,
+ // and doesn't add binding to input.
+ dialog.querySelectorAll(window.POLYMER2 ? 'iron-input' : 'input')
.forEach(input => { input.bindValue = ''; });
}
diff --git a/polygerrit-ui/app/elements/gr-app-element.html b/polygerrit-ui/app/elements/gr-app-element.html
index 5c297e7..193f861 100644
--- a/polygerrit-ui/app/elements/gr-app-element.html
+++ b/polygerrit-ui/app/elements/gr-app-element.html
@@ -198,12 +198,13 @@
<gr-endpoint-decorator name="footer-left"></gr-endpoint-decorator>
</div>
<div>
- <a class="feedback"
- href$="[[_feedbackUrl]]"
- rel="noopener"
- target="_blank"
- hidden$="[[!_showFeedbackUrl(_feedbackUrl)]]">Report bug</a>
- | Press “?” for keyboard shortcuts
+ <template is="dom-if" if="[[_feedbackUrl]]">
+ <a class="feedback"
+ href$="[[_feedbackUrl]]"
+ rel="noopener"
+ target="_blank">Report bug</a> |
+ </template>
+ Press “?” for keyboard shortcuts
<gr-endpoint-decorator name="footer-right"></gr-endpoint-decorator>
</div>
</footer>
diff --git a/polygerrit-ui/app/elements/gr-app-element.js b/polygerrit-ui/app/elements/gr-app-element.js
index 3c146f8..5692969 100644
--- a/polygerrit-ui/app/elements/gr-app-element.js
+++ b/polygerrit-ui/app/elements/gr-app-element.js
@@ -435,7 +435,9 @@
if (window.VERSION_INFO) {
console.log(`UI Version Info: ${window.VERSION_INFO}`);
}
- console.log(`Please file bugs and feedback at: ${this._feedbackUrl}`);
+ if (this._feedbackUrl) {
+ console.log(`Please file bugs and feedback at: ${this._feedbackUrl}`);
+ }
console.groupEnd();
},
@@ -453,14 +455,6 @@
this.mobileSearch = !this.mobileSearch;
},
- _showFeedbackUrl(feedbackUrl) {
- if (feedbackUrl) {
- return feedbackUrl;
- }
-
- return false;
- },
-
getThemeEndpoint() {
// For now, we only have dark mode and light mode
return window.localStorage.getItem('dark-theme') ?
diff --git a/polygerrit-ui/app/elements/gr-app_test.html b/polygerrit-ui/app/elements/gr-app_test.html
index 73d012a..ebf1304 100644
--- a/polygerrit-ui/app/elements/gr-app_test.html
+++ b/polygerrit-ui/app/elements/gr-app_test.html
@@ -24,7 +24,13 @@
<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<script src="/bower_components/web-component-tester/browser.js"></script>
<link rel="import" href="../test/common-test-setup.html"/>
-<link rel="import" href="gr-app.html">
+
+<script>
+ const link = document.createElement('link');
+ link.setAttribute('rel', 'import');
+ link.setAttribute('href', window.POLYMER2 ? 'gr-app-p2.html' : 'gr-app.html');
+ document.head.appendChild(link);
+</script>
<script>void(0);</script>
@@ -34,6 +40,12 @@
</template>
</test-fixture>
+<test-fixture id="basic-p2">
+ <template>
+ <gr-app-p2 id="app"></gr-app-p2>
+ </template>
+</test-fixture>
+
<script>
suite('gr-app tests', () => {
let sandbox;
@@ -68,7 +80,7 @@
probePath() { return Promise.resolve(42); },
});
- element = fixture('basic');
+ element = fixture(window.POLYMER2 ? 'basic-p2' : 'basic');
flush(done);
});
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html
index fa097ac..0883707 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html
@@ -88,7 +88,7 @@
test('decoration', () => {
const element =
container.querySelector('gr-endpoint-decorator[name="first"]');
- const modules = Polymer.dom(element.root).children.filter(
+ const modules = Array.from(Polymer.dom(element.root).children).filter(
element => element.nodeName === 'SOME-MODULE');
assert.equal(modules.length, 1);
const [module] = modules;
@@ -105,7 +105,7 @@
test('replacement', () => {
const element =
container.querySelector('gr-endpoint-decorator[name="second"]');
- const module = Polymer.dom(element.root).children.find(
+ const module = Array.from(Polymer.dom(element.root).children).find(
element => element.nodeName === 'OTHER-MODULE');
assert.isOk(module);
assert.equal(module['someparam'], 'foofoo');
@@ -122,7 +122,7 @@
flush(() => {
const element =
container.querySelector('gr-endpoint-decorator[name="banana"]');
- const module = Polymer.dom(element.root).children.find(
+ const module = Array.from(Polymer.dom(element.root).children).find(
element => element.nodeName === 'NOOB-NOOB');
assert.isOk(module);
done();
@@ -135,10 +135,10 @@
flush(() => {
const element =
container.querySelector('gr-endpoint-decorator[name="banana"]');
- const module1 = Polymer.dom(element.root).children.find(
+ const module1 = Array.from(Polymer.dom(element.root).children).find(
element => element.nodeName === 'MOD-ONE');
assert.isOk(module1);
- const module2 = Polymer.dom(element.root).children.find(
+ const module2 = Array.from(Polymer.dom(element.root).children).find(
element => element.nodeName === 'MOD-TWO');
assert.isOk(module2);
done();
@@ -152,14 +152,14 @@
param['value'] = undefined;
plugin.registerCustomComponent('banana', 'noob-noob');
flush(() => {
- let module = Polymer.dom(element.root).children.find(
+ let module = Array.from(Polymer.dom(element.root).children).find(
element => element.nodeName === 'NOOB-NOOB');
// Module waits for param to be defined.
assert.isNotOk(module);
const value = {abc: 'def'};
param.value = value;
flush(() => {
- module = Polymer.dom(element.root).children.find(
+ module = Array.from(Polymer.dom(element.root).children).find(
element => element.nodeName === 'NOOB-NOOB');
assert.isOk(module);
assert.strictEqual(module['someParam'], value);
@@ -177,7 +177,7 @@
param.value = value1;
plugin.registerCustomComponent('banana', 'noob-noob');
flush(() => {
- const module = Polymer.dom(element.root).children.find(
+ const module = Array.from(Polymer.dom(element.root).children).find(
element => element.nodeName === 'NOOB-NOOB');
assert.strictEqual(module['someParam'], value1);
param.value = value2;
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
index e8b7212..f865e77 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
@@ -57,6 +57,7 @@
// Within <gr-external-style> itself the styles would have no effect.
const topEl = document.getElementsByTagName('body')[0];
topEl.insertBefore(cs, topEl.firstChild);
+ Polymer.updateStyles();
},
_importAndApply() {
diff --git a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.js b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.js
index 879b392..1de8283 100644
--- a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.js
+++ b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.js
@@ -37,8 +37,11 @@
* @return {string} Appropriate class name for the element is returned
*/
GrStyleObject.prototype.getClassName = function(element) {
- const rootNode = Polymer.Settings.useShadow
+ let rootNode = Polymer.Settings.useShadow
? element.getRootNode() : document.body;
+ if (rootNode === document) {
+ rootNode = document.head;
+ }
if (!rootNode.__pg_js_api_style_tags) {
rootNode.__pg_js_api_style_tags = {};
}
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.html b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.html
index f508288..b30bd52 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.html
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.html
@@ -68,7 +68,7 @@
type="radio"
on-change="_handlePreferredChange"
name="preferred"
- value="[[item.email]]"
+ bind-value="[[item.email]]"
checked$="[[item.preferred]]">
<input
is="iron-input"
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
index e8ecd7a..8d3f2d2 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
@@ -51,7 +51,7 @@
element = fixture('basic');
- element.loadData().then(done);
+ element.loadData().then(flush(done));
});
test('renders', () => {
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
index ac17521..3c3ece36 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
@@ -73,7 +73,8 @@
teardown(() => { sandbox.restore(); });
test('renders', () => {
- const rows = Polymer.dom(element.root).querySelectorAll('tbody tr');
+ const rows = Array.from(
+ Polymer.dom(element.root).querySelectorAll('tbody tr'));
assert.equal(rows.length, 3);
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html
index a663fd2..1277424 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html
@@ -71,7 +71,8 @@
});
test('renders', () => {
- const rows = Polymer.dom(element.root).querySelectorAll('tbody tr');
+ const rows = Array.from(
+ Polymer.dom(element.root).querySelectorAll('tbody tr'));
assert.equal(rows.length, 2);
@@ -84,7 +85,8 @@
});
test('renders email', () => {
- const rows = Polymer.dom(element.root).querySelectorAll('tbody tr');
+ const rows = Array.from(
+ Polymer.dom(element.root).querySelectorAll('tbody tr'));
assert.equal(rows.length, 2);
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
index 917026a..134e018 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
@@ -57,7 +57,7 @@
MockInteractions.tap(button);
}
- setup(() => {
+ setup(done => {
element = fixture('basic');
menu = [
{url: '/first/url', name: 'first name', target: '_blank'},
@@ -66,6 +66,7 @@
];
element.set('menuItems', menu);
Polymer.dom.flush();
+ flush(done);
});
test('renders', () => {
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
index 4193382..7a238ec 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
@@ -189,6 +189,7 @@
element.$.newProject.value = {id: 'project b'};
element.$.newProject.setText('project b');
element.$.newFilter.bindValue = 'filter 1';
+ element.$.newFilter.value = 'filter 1';
element._handleAddProject();
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.js b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.js
index 9edc9c8..1be55d2 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.js
@@ -253,8 +253,13 @@
console.warn('received remove event for missing account', toRemove);
},
+ _getNativeInput(paperInput) {
+ // In Polymer 2 inputElement isn't nativeInput anymore
+ return paperInput.$.nativeInput || paperInput.inputElement;
+ },
+
_handleInputKeydown(e) {
- const input = e.detail.input.inputElement;
+ const input = this._getNativeInput(e.detail.input);
if (input.selectionStart !== input.selectionEnd ||
input.selectionStart !== 0) {
return;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html
index 22e3a3d..6f265e7 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.html
@@ -417,43 +417,51 @@
});
suite('keyboard interactions', () => {
- test('backspace at text input start removes last account', () => {
+ test('backspace at text input start removes last account', done => {
const input = element.$.entry.$.input;
sandbox.stub(input, '_updateSuggestions');
sandbox.stub(element, '_computeRemovable').returns(true);
- // Next line is a workaround for Firefix not moving cursor
- // on input field update
- assert.equal(input.$.input.inputElement.selectionStart, 0);
- input.text = 'test';
- MockInteractions.focus(input.$.input);
- flushAsynchronousOperations();
- assert.equal(element.accounts.length, 2);
- MockInteractions.pressAndReleaseKeyOn(
- input.$.input.inputElement, 8); // Backspace
- assert.equal(element.accounts.length, 2);
- input.text = '';
- MockInteractions.pressAndReleaseKeyOn(
- input.$.input.inputElement, 8); // Backspace
- assert.equal(element.accounts.length, 1);
+ flush(() => {
+ // Next line is a workaround for Firefix not moving cursor
+ // on input field update
+ assert.equal(
+ element._getNativeInput(input.$.input).selectionStart, 0);
+ input.text = 'test';
+ MockInteractions.focus(input.$.input);
+ flushAsynchronousOperations();
+ assert.equal(element.accounts.length, 2);
+ MockInteractions.pressAndReleaseKeyOn(
+ element._getNativeInput(input.$.input), 8); // Backspace
+ assert.equal(element.accounts.length, 2);
+ input.text = '';
+ MockInteractions.pressAndReleaseKeyOn(
+ element._getNativeInput(input.$.input), 8); // Backspace
+ flushAsynchronousOperations();
+ assert.equal(element.accounts.length, 1);
+ done();
+ });
});
- test('arrow key navigation', () => {
+ test('arrow key navigation', done => {
const input = element.$.entry.$.input;
input.text = '';
element.accounts = [makeAccount(), makeAccount()];
- MockInteractions.focus(input.$.input);
- flushAsynchronousOperations();
- const chips = element.accountChips;
- const chipsOneSpy = sandbox.spy(chips[1], 'focus');
- MockInteractions.pressAndReleaseKeyOn(input.$.input, 37); // Left
- assert.isTrue(chipsOneSpy.called);
- const chipsZeroSpy = sandbox.spy(chips[0], 'focus');
- MockInteractions.pressAndReleaseKeyOn(chips[1], 37); // Left
- assert.isTrue(chipsZeroSpy.called);
- MockInteractions.pressAndReleaseKeyOn(chips[0], 37); // Left
- assert.isTrue(chipsZeroSpy.calledOnce);
- MockInteractions.pressAndReleaseKeyOn(chips[0], 39); // Right
- assert.isTrue(chipsOneSpy.calledTwice);
+ flush(() => {
+ MockInteractions.focus(input.$.input);
+ flushAsynchronousOperations();
+ const chips = element.accountChips;
+ const chipsOneSpy = sandbox.spy(chips[1], 'focus');
+ MockInteractions.pressAndReleaseKeyOn(input.$.input, 37); // Left
+ assert.isTrue(chipsOneSpy.called);
+ const chipsZeroSpy = sandbox.spy(chips[0], 'focus');
+ MockInteractions.pressAndReleaseKeyOn(chips[1], 37); // Left
+ assert.isTrue(chipsZeroSpy.called);
+ MockInteractions.pressAndReleaseKeyOn(chips[0], 37); // Left
+ assert.isTrue(chipsZeroSpy.calledOnce);
+ MockInteractions.pressAndReleaseKeyOn(chips[0], 39); // Right
+ assert.isTrue(chipsOneSpy.calledTwice);
+ done();
+ });
});
test('delete', done => {
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
index af31473..745cff1 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
@@ -177,6 +177,11 @@
'_updateSuggestions(text, threshold, noDebounce)',
],
+ get _nativeInput() {
+ // In Polymer 2 inputElement isn't nativeInput anymore
+ return this.$.input.$.nativeInput || this.$.input.inputElement;
+ },
+
attached() {
this.listen(document.body, 'tap', '_handleBodyTap');
},
@@ -195,7 +200,7 @@
},
selectAll() {
- const nativeInputElement = this.$.input.inputElement;
+ const nativeInputElement = this._nativeInput;
if (!this.$.input.value) { return; }
nativeInputElement.setSelectionRange(0, this.$.input.value.length);
},
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
index cff35b4..ea1fd50 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
@@ -82,16 +82,19 @@
});
});
- test('selectAll', () => {
- const nativeInput = element.$.input.inputElement;
- const selectionStub = sandbox.stub(nativeInput, 'setSelectionRange');
+ test('selectAll', done => {
+ flush(() => {
+ const nativeInput = element._nativeInput;
+ const selectionStub = sandbox.stub(nativeInput, 'setSelectionRange');
- element.selectAll();
- assert.isFalse(selectionStub.called);
+ element.selectAll();
+ assert.isFalse(selectionStub.called);
- element.$.input.value = 'test';
- element.selectAll();
- assert.isTrue(selectionStub.called);
+ element.$.input.value = 'test';
+ element.selectAll();
+ assert.isTrue(selectionStub.called);
+ done();
+ });
});
test('esc key behavior', done => {
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
index 42d7678..1c2afaa 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
@@ -129,14 +129,31 @@
element.style.backgroundImage.includes('/accounts/123/avatar?s=64'));
});
});
+ });
+
+ suite('plugin has avatars', () => {
+ let element;
+ let sandbox;
+
+ setup(() => {
+ sandbox = sinon.sandbox.create();
+
+ stub('gr-avatar', {
+ _getConfig: () => {
+ return Promise.resolve({plugin: {has_avatars: true}});
+ },
+ });
+
+ element = fixture('basic');
+ });
+
+ teardown(() => {
+ sandbox.restore();
+ });
test('dom for non available account', () => {
assert.isFalse(element.hasAttribute('hidden'));
- sandbox.stub(element, '_getConfig', () => {
- return Promise.resolve({plugin: {has_avatars: true}});
- });
-
// Emulate plugins loaded.
Gerrit._setPluginsPending([]);
@@ -149,45 +166,45 @@
assert.strictEqual(element.style.backgroundImage, '');
});
});
+ });
- test('avatar config not set and account not set', () => {
- assert.isFalse(element.hasAttribute('hidden'));
+ suite('config not set', () => {
+ let element;
+ let sandbox;
- sandbox.stub(element, '_getConfig', () => {
- return Promise.resolve({});
+ setup(() => {
+ sandbox = sinon.sandbox.create();
+
+ stub('gr-avatar', {
+ _getConfig: () => {
+ return Promise.resolve({});
+ },
});
- // Emulate plugins loaded.
- Gerrit._setPluginsPending([]);
-
- return Promise.all([
- element.$.restAPI.getConfig(),
- Gerrit.awaitPluginsLoaded(),
- ]).then(() => {
- assert.isTrue(element.hasAttribute('hidden'));
- });
+ element = fixture('basic');
});
- test('avatar config not set and account set', () => {
- assert.isFalse(element.hasAttribute('hidden'));
+ teardown(() => {
+ sandbox.restore();
+ });
- sandbox.stub(element, '_getConfig', () => {
- return Promise.resolve({});
- });
+ test('avatar hidden when account set', () => {
+ flush(() => {
+ assert.isFalse(element.hasAttribute('hidden'));
- element.imageSize = 64;
- element.account = {
- _account_id: 123,
- };
+ element.imageSize = 64;
+ element.account = {
+ _account_id: 123,
+ };
+ // Emulate plugins loaded.
+ Gerrit._setPluginsPending([]);
- // Emulate plugins loaded.
- Gerrit._setPluginsPending([]);
-
- return Promise.all([
- element.$.restAPI.getConfig(),
- Gerrit.awaitPluginsLoaded(),
- ]).then(() => {
- assert.isTrue(element.hasAttribute('hidden'));
+ return Promise.all([
+ element.$.restAPI.getConfig(),
+ Gerrit.awaitPluginsLoaded(),
+ ]).then(() => {
+ assert.isTrue(element.hasAttribute('hidden'));
+ });
});
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
index c092b7c..574dc1e 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
@@ -39,12 +39,13 @@
let element;
let sandbox;
- setup(() => {
+ setup(done => {
sandbox = sinon.sandbox.create();
element = fixture('basic');
element.text = `git fetch http://gerrit@localhost:8080/a/test-project
refs/changes/05/5/1 && git checkout FETCH_HEAD`;
flushAsynchronousOperations();
+ flush(done);
});
teardown(() => {
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
index 3b7e8f8..85a5b1f 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
@@ -67,12 +67,13 @@
});
suite('unauthenticated', () => {
- setup(() => {
+ setup(done => {
element = fixture('basic');
element.schemes = SCHEMES;
element.commands = COMMANDS;
element.selectedScheme = SELECTED_SCHEME;
flushAsynchronousOperations();
+ flush(done);
});
test('focusOnCopy', () => {
@@ -91,13 +92,13 @@
assert.isTrue(isHidden(element.$$('.commands')));
});
- test('tab selection', () => {
+ test('tab selection', done => {
assert.equal(element.$.downloadTabs.selected, '0');
MockInteractions.tap(element.$$('[data-scheme="ssh"]'));
flushAsynchronousOperations();
-
assert.equal(element.selectedScheme, 'ssh');
assert.equal(element.$.downloadTabs.selected, '2');
+ done();
});
test('loads scheme from preferences', done => {
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html
index 5f07fc9..312cc34 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html
@@ -94,77 +94,79 @@
];
assert.equal(element.$$('paper-listbox').selected, element.value);
assert.equal(element.text, 'Button Text 2');
- flushAsynchronousOperations();
- const items = Polymer.dom(element.root).querySelectorAll('paper-item');
- const mobileItems = Polymer.dom(element.root).querySelectorAll('option');
- assert.equal(items.length, 3);
- assert.equal(mobileItems.length, 3);
+ flush(() => {
+ const items = Polymer.dom(element.root).querySelectorAll('paper-item');
+ const mobileItems = Polymer.dom(element.root).querySelectorAll('option');
+ assert.equal(items.length, 3);
+ assert.equal(mobileItems.length, 3);
- // First Item
- // The first item should be disabled, has no bottom text, and no date.
- assert.isFalse(!!items[0].disabled);
- assert.isFalse(mobileItems[0].disabled);
- assert.isFalse(items[0].classList.contains('iron-selected'));
- assert.isFalse(mobileItems[0].selected);
+ // First Item
+ // The first item should be disabled, has no bottom text, and no date.
+ assert.isFalse(!!items[0].disabled);
+ assert.isFalse(mobileItems[0].disabled);
+ assert.isFalse(items[0].classList.contains('iron-selected'));
+ assert.isFalse(mobileItems[0].selected);
- assert.isNotOk(Polymer.dom(items[0]).querySelector('gr-date-formatter'));
- assert.isNotOk(Polymer.dom(items[0]).querySelector('.bottomContent'));
- assert.equal(items[0].value, element.items[0].value);
- assert.equal(mobileItems[0].value, element.items[0].value);
- assert.equal(Polymer.dom(items[0]).querySelector('.topContent div')
- .innerText, element.items[0].text);
+ assert.isNotOk(Polymer.dom(items[0]).querySelector('gr-date-formatter'));
+ assert.isNotOk(Polymer.dom(items[0]).querySelector('.bottomContent'));
+ assert.equal(items[0].value, element.items[0].value);
+ assert.equal(mobileItems[0].value, element.items[0].value);
+ assert.equal(Polymer.dom(items[0]).querySelector('.topContent div')
+ .innerText, element.items[0].text);
- // Since no mobile specific text, it should fall back to text.
- assert.equal(mobileItems[0].text, element.items[0].text);
+ // Since no mobile specific text, it should fall back to text.
+ assert.equal(mobileItems[0].text, element.items[0].text);
- // Second Item
- // The second item should have top text, bottom text, and no date.
- assert.isFalse(!!items[1].disabled);
- assert.isFalse(mobileItems[1].disabled);
- assert.isTrue(items[1].classList.contains('iron-selected'));
- assert.isTrue(mobileItems[1].selected);
+ // Second Item
+ // The second item should have top text, bottom text, and no date.
+ assert.isFalse(!!items[1].disabled);
+ assert.isFalse(mobileItems[1].disabled);
+ assert.isTrue(items[1].classList.contains('iron-selected'));
+ assert.isTrue(mobileItems[1].selected);
- assert.isNotOk(Polymer.dom(items[1]).querySelector('gr-date-formatter'));
- assert.isOk(Polymer.dom(items[1]).querySelector('.bottomContent'));
- assert.equal(items[1].value, element.items[1].value);
- assert.equal(mobileItems[1].value, element.items[1].value);
- assert.equal(Polymer.dom(items[1]).querySelector('.topContent div')
- .innerText, element.items[1].text);
+ assert.isNotOk(Polymer.dom(items[1]).querySelector('gr-date-formatter'));
+ assert.isOk(Polymer.dom(items[1]).querySelector('.bottomContent'));
+ assert.equal(items[1].value, element.items[1].value);
+ assert.equal(mobileItems[1].value, element.items[1].value);
+ assert.equal(Polymer.dom(items[1]).querySelector('.topContent div')
+ .innerText, element.items[1].text);
- // Since there is mobile specific text, it should that.
- assert.equal(mobileItems[1].text, element.items[1].mobileText);
+ // Since there is mobile specific text, it should that.
+ assert.equal(mobileItems[1].text, element.items[1].mobileText);
- // Since this item is selected, and it has triggerText defined, that
- // should be used.
- assert.equal(element.text, element.items[1].triggerText);
+ // Since this item is selected, and it has triggerText defined, that
+ // should be used.
+ assert.equal(element.text, element.items[1].triggerText);
- // Third item
- // The third item should be disabled, and have a date, and bottom content.
- assert.isTrue(!!items[2].disabled);
- assert.isTrue(mobileItems[2].disabled);
- assert.isFalse(items[2].classList.contains('iron-selected'));
- assert.isFalse(mobileItems[2].selected);
+ // Third item
+ // The third item should be disabled, and have a date, and bottom content.
+ assert.isTrue(!!items[2].disabled);
+ assert.isTrue(mobileItems[2].disabled);
+ assert.isFalse(items[2].classList.contains('iron-selected'));
+ assert.isFalse(mobileItems[2].selected);
- assert.isOk(Polymer.dom(items[2]).querySelector('gr-date-formatter'));
- assert.isOk(Polymer.dom(items[2]).querySelector('.bottomContent'));
- assert.equal(items[2].value, element.items[2].value);
- assert.equal(mobileItems[2].value, element.items[2].value);
- assert.equal(Polymer.dom(items[2]).querySelector('.topContent div')
- .innerText, element.items[2].text);
+ assert.isOk(Polymer.dom(items[2]).querySelector('gr-date-formatter'));
+ assert.isOk(Polymer.dom(items[2]).querySelector('.bottomContent'));
+ assert.equal(items[2].value, element.items[2].value);
+ assert.equal(mobileItems[2].value, element.items[2].value);
+ assert.equal(Polymer.dom(items[2]).querySelector('.topContent div')
+ .innerText, element.items[2].text);
- // Since there is mobile specific text, it should that.
- assert.equal(mobileItems[2].text, element.items[2].mobileText);
+ // Since there is mobile specific text, it should that.
+ assert.equal(mobileItems[2].text, element.items[2].mobileText);
- // Select a new item.
- MockInteractions.tap(items[0]);
- flushAsynchronousOperations();
- assert.equal(element.value, 1);
- assert.isTrue(items[0].classList.contains('iron-selected'));
- assert.isTrue(mobileItems[0].selected);
+ // Select a new item.
+ MockInteractions.tap(items[0]);
+ flushAsynchronousOperations();
+ assert.equal(element.value, 1);
+ assert.isTrue(items[0].classList.contains('iron-selected'));
+ assert.isTrue(mobileItems[0].selected);
- // Since no triggerText, the fallback is used.
- assert.equal(element.text, element.items[0].text);
+ // Since no triggerText, the fallback is used.
+ assert.equal(element.text, element.items[0].text);
+ done();
+ });
});
});
</script>
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
index 5dad9a6..7ff0a14 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
@@ -61,13 +61,17 @@
let label;
let sandbox;
- setup(() => {
+ setup(done => {
element = fixture('basic');
elementNoPlaceholder = fixture('no-placeholder');
- input = element.$.input.$.input;
label = element.$$('label');
sandbox = sinon.sandbox.create();
+ flush(() => {
+ // In Polymer 2 inputElement isn't nativeInput anymore
+ input = element.$.input.$.nativeInput || element.$.input.inputElement;
+ done();
+ });
});
teardown(() => {
@@ -79,7 +83,7 @@
assert.isFalse(element.$.dropdown.opened);
assert.isTrue(label.classList.contains('editable'));
assert.equal(label.textContent, 'value text');
- const focusSpy = sandbox.spy(element.$.input.$.input, 'focus');
+ const focusSpy = sandbox.spy(input, 'focus');
const showSpy = sandbox.spy(element, '_showDropdown');
MockInteractions.tap(label);
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
index 2a6487e..3223636 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
@@ -56,6 +56,7 @@
el.setAttribute('data-side', 'right');
lineNumberEl = document.createElement('td');
lineNumberEl.classList.add('right');
+ document.body.appendChild(el);
instance = new GrAnnotationActionsContext(
el, lineNumberEl, line, 'dummy/path', '123', '1');
});
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
index 95b1fa1..c7e4f09 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
@@ -320,7 +320,7 @@
});
test('getAccount', done => {
- Gerrit.getLoggedIn().then(loggedIn => {
+ plugin.restApi().getLoggedIn().then(loggedIn => {
assert.isTrue(loggedIn);
done();
});
diff --git a/polygerrit-ui/app/elements/shared/gr-select/gr-select.js b/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
index ecf542f..333bede 100644
--- a/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
+++ b/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
@@ -66,7 +66,7 @@
ready() {
// If not set via the property, set bind-value to the element value.
- if (this.bindValue == undefined) {
+ if (this.bindValue == undefined && this.nativeSelect.options.length > 0) {
this.bindValue = this.nativeSelect.value;
}
},
diff --git a/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html b/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
index 66ebb79..b3abe5f 100644
--- a/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
@@ -40,6 +40,15 @@
</template>
</test-fixture>
+<test-fixture id="noOptions">
+ <template>
+ <gr-select>
+ <select>
+ </select>
+ </gr-select>
+ </template>
+</test-fixture>
+
<script>
suite('gr-select tests', () => {
let element;
@@ -48,6 +57,10 @@
element = fixture('basic');
});
+ test('bindValue must be set to the first option value', () => {
+ assert.equal(element.bindValue, '1');
+ });
+
test('value of 0 should still trigger value updates', () => {
element.bindValue = 0;
assert.equal(element.nativeSelect.value, 0);
@@ -90,4 +103,16 @@
assert.isTrue(changeStub.called);
});
});
+
+ suite('gr-select no options tests', () => {
+ let element;
+
+ setup(() => {
+ element = fixture('noOptions');
+ });
+
+ test('bindValue must not be changed', () => {
+ assert.isUndefined(element.bindValue);
+ });
+ });
</script>
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
index 8b6eff2..077f4b7 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
@@ -33,6 +33,18 @@
</template>
</test-fixture>
+<test-fixture id="monospace">
+ <template>
+ <gr-textarea monospace="true"></gr-textarea>
+ </template>
+</test-fixture>
+
+<test-fixture id="hideBorder">
+ <template>
+ <gr-textarea hide-border="true"></gr-textarea>
+ </template>
+</test-fixture>
+
<script>
suite('gr-textarea tests', () => {
let element;
@@ -49,16 +61,10 @@
test('monospace is set properly', () => {
assert.isFalse(element.classList.contains('monospace'));
- element.monospace = true;
- element.ready();
- assert.isTrue(element.classList.contains('monospace'));
});
test('hideBorder is set properly', () => {
assert.isFalse(element.$.textarea.classList.contains('noBorder'));
- element.hideBorder = true;
- element.ready();
- assert.isTrue(element.$.textarea.classList.contains('noBorder'));
});
test('emoji selector is not open with the textarea lacks focus', () => {
@@ -235,4 +241,52 @@
});
});
});
+
+ suite('gr-textarea monospace', () => {
+ // gr-textarea set monospace class in the ready() method.
+ // In Polymer2, ready() is called from the fixture(...) method,
+ // If ready() is called again later, some nested elements doesn't
+ // handle it correctly. A separate test-fixture is used to set
+ // properties before ready() is called.
+
+ let element;
+ let sandbox;
+
+ setup(() => {
+ sandbox = sinon.sandbox.create();
+ element = fixture('monospace');
+ });
+
+ teardown(() => {
+ sandbox.restore();
+ });
+
+ test('monospace is set properly', () => {
+ assert.isTrue(element.classList.contains('monospace'));
+ });
+ });
+
+ suite('gr-textarea hideBorder', () => {
+ // gr-textarea set noBorder class in the ready() method.
+ // In Polymer2, ready() is called from the fixture(...) method,
+ // If ready() is called again later, some nested elements doesn't
+ // handle it correctly. A separate test-fixture is used to set
+ // properties before ready() is called.
+
+ let element;
+ let sandbox;
+
+ setup(() => {
+ sandbox = sinon.sandbox.create();
+ element = fixture('hideBorder');
+ });
+
+ teardown(() => {
+ sandbox.restore();
+ });
+
+ test('hideBorder is set properly', () => {
+ assert.isTrue(element.$.textarea.classList.contains('noBorder'));
+ });
+ });
</script>
diff --git a/proto/cache.proto b/proto/cache.proto
index 77b6908..7e6abcc 100644
--- a/proto/cache.proto
+++ b/proto/cache.proto
@@ -186,6 +186,9 @@
// Number of updates to the change's meta ref.
int32 update_count = 19;
+
+ string server_id = 20;
+ bool has_server_id = 21;
}
diff --git a/resources/com/google/gerrit/server/mail/Abandoned.soy b/resources/com/google/gerrit/server/mail/Abandoned.soy
index 2785ffc..d5aac0e 100644
--- a/resources/com/google/gerrit/server/mail/Abandoned.soy
+++ b/resources/com/google/gerrit/server/mail/Abandoned.soy
@@ -17,7 +17,7 @@
{namespace com.google.gerrit.server.mail.template}
/**
- * .Abandoned template will determine the contents of the email related to a
+ * The .Abandoned template will determine the contents of the email related to a
* change being abandoned.
*/
{template .Abandoned kind="text"}