Merge "Added OutgoingEmailValidationListener"
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 0fefc82..50686d2 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1515,10 +1515,10 @@
+
Optional command to install the `commit-msg` hook. Typically of the
form:
++
----
fetch-cmd some://url/to/commit-msg .git/hooks/commit-msg ; chmod +x .git/hooks/commit-msg
----
-
+
By default unset; falls back to using scp from the canonical SSH host,
or curl from the canonical HTTP URL for the server. Only necessary if a
@@ -1722,41 +1722,61 @@
+
Optional path to hooks, if not specified then `'$site_path'/hooks` will be used.
-[[hooks.patchsetCreatedHook]]hooks.patchsetCreatedHook::
+[[hooks.syncHookTimeout]]hooks.syncHookTimeout::
+
-Optional filename for the patchset created hook, if not specified then
-`patchset-created` will be used.
-
-[[hooks.draftPublishedHook]]hooks.draftPublishedHook::
-+
-Optional filename for the draft published hook, if not specified then
-`draft-published` will be used.
-
-[[hooks.commentAddedHook]]hooks.commentAddedHook::
-+
-Optional filename for the comment added hook, if not specified then
-`comment-added` will be used.
-
-[[hooks.changeMergedHook]]hooks.changeMergedHook::
-+
-Optional filename for the change merged hook, if not specified then
-`change-merged` will be used.
-
-[[hooks.mergeFailedHook]]hooks.mergeFailedHook::
-+
-Optional filename for the merge failed hook, if not specified then
-`merge-failed` will be used.
+Optional timeout value in seconds for synchronous hooks, if not specified
+then 30 seconds will be used.
[[hooks.changeAbandonedHook]]hooks.changeAbandonedHook::
+
Optional filename for the change abandoned hook, if not specified then
`change-abandoned` will be used.
+[[hooks.changeMergedHook]]hooks.changeMergedHook::
++
+Optional filename for the change merged hook, if not specified then
+`change-merged` will be used.
+
[[hooks.changeRestoredHook]]hooks.changeRestoredHook::
+
Optional filename for the change restored hook, if not specified then
`change-restored` will be used.
+[[hooks.claSignedHook]]hooks.claSignedHook::
++
+Optional filename for the CLA signed hook, if not specified then
+`cla-signed` will be used.
+
+[[hooks.commentAddedHook]]hooks.commentAddedHook::
++
+Optional filename for the comment added hook, if not specified then
+`comment-added` will be used.
+
+[[hooks.draftPublishedHook]]hooks.draftPublishedHook::
++
+Optional filename for the draft published hook, if not specified then
+`draft-published` will be used.
+
+[[hooks.hashtagsChangedHook]]hooks.hashtagsChangedHook::
++
+Optional filename for the hashtags changed hook, if not specified then
+`hashtags-changed` will be used.
+
+[[hooks.mergeFailedHook]]hooks.mergeFailedHook::
++
+Optional filename for the merge failed hook, if not specified then
+`merge-failed` will be used.
+
+[[hooks.patchsetCreatedHook]]hooks.patchsetCreatedHook::
++
+Optional filename for the patchset created hook, if not specified then
+`patchset-created` will be used.
+
+[[hooks.refUpdateHook]]hooks.refUpdateHook::
++
+Optional filename for the ref update hook, if not specified then
+`ref-update` will be used.
+
[[hooks.refUpdatedHook]]hooks.refUpdatedHook::
+
Optional filename for the ref updated hook, if not specified then
@@ -1772,26 +1792,6 @@
Optional filename for the topic changed hook, if not specified then
`topic-changed` will be used.
-[[hooks.claSignedHook]]hooks.claSignedHook::
-+
-Optional filename for the CLA signed hook, if not specified then
-`cla-signed` will be used.
-
-[[hooks.refUpdateHook]]hooks.refUpdateHook::
-+
-Optional filename for the ref update hook, if not specified then
-`ref-update` will be used.
-
-[[hooks.hashtagsChangedHook]]hooks.hashtagsChangedHook::
-+
-Optional filename for the hashtags changed hook, if not specified then
-`hashtags-changed` will be used.
-
-[[hooks.syncHookTimeout]]hooks.syncHookTimeout::
-+
-Optional timeout value in seconds for synchronous hooks, if not specified
-then 30 seconds will be used.
-
[[http]]
=== Section http
diff --git a/Documentation/dev-contributing.txt b/Documentation/dev-contributing.txt
index c356dab..f5caf40 100644
--- a/Documentation/dev-contributing.txt
+++ b/Documentation/dev-contributing.txt
@@ -336,6 +336,33 @@
* Update to the same GWT version in the `gwtjsonrpc` project, and release a
new version.
+=== Updating to new version of CodeMirror
+
+* Clone the git from https://github.com/codemirror/CodeMirror
+* Checkout the version needed
+* If the needed version is not a tagged version, use `git describe` to determine
+the version number:
++
+----
+ git describe --tags
+----
+
+* Create the release zip file:
++
+----
+ git archive --format=zip --prefix=codemirror-4.10.0-6-gd0a2dda/ d0a2dda > 4.10.0-6-gd0a2dda.zip
+----
+
+* Determine the sha1 hash of the zip file:
++
+----
+ openssl sha1 4.10.0-6-gd0a2dda.zip
+----
+
+* Upload the zip file to the
+link:https://console.developers.google.com/project/164060093628/storage/gerrit-maven/[
+gerrit-maven] storage bucket
+
GERRIT
------
Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/images/inline-edit-add-file-suggestion.png b/Documentation/images/inline-edit-add-file-suggestion.png
new file mode 100644
index 0000000..25a33f8
--- /dev/null
+++ b/Documentation/images/inline-edit-add-file-suggestion.png
Binary files differ
diff --git a/Documentation/images/inline-edit-confirm-unsaved-edits.png b/Documentation/images/inline-edit-confirm-unsaved-edits.png
new file mode 100644
index 0000000..87e4a32
--- /dev/null
+++ b/Documentation/images/inline-edit-confirm-unsaved-edits.png
Binary files differ
diff --git a/Documentation/images/inline-edit-edit-in-diff-screen-patch-list.png b/Documentation/images/inline-edit-edit-in-diff-screen-patch-list.png
new file mode 100644
index 0000000..bdbc59d
--- /dev/null
+++ b/Documentation/images/inline-edit-edit-in-diff-screen-patch-list.png
Binary files differ
diff --git a/Documentation/images/inline-edit-edit-in-patch-list.png b/Documentation/images/inline-edit-edit-in-patch-list.png
new file mode 100644
index 0000000..9a31e02
--- /dev/null
+++ b/Documentation/images/inline-edit-edit-in-patch-list.png
Binary files differ
diff --git a/Documentation/images/inline-edit-enter-edit-mode-from-diff.png b/Documentation/images/inline-edit-enter-edit-mode-from-diff.png
new file mode 100644
index 0000000..46dd0ff
--- /dev/null
+++ b/Documentation/images/inline-edit-enter-edit-mode-from-diff.png
Binary files differ
diff --git a/Documentation/images/inline-edit-enter-edit-mode-from-file-list.png b/Documentation/images/inline-edit-enter-edit-mode-from-file-list.png
new file mode 100644
index 0000000..b8c52c9
--- /dev/null
+++ b/Documentation/images/inline-edit-enter-edit-mode-from-file-list.png
Binary files differ
diff --git a/Documentation/images/inline-edit-file-list-in-edit-mode.png b/Documentation/images/inline-edit-file-list-in-edit-mode.png
new file mode 100644
index 0000000..8f355335
--- /dev/null
+++ b/Documentation/images/inline-edit-file-list-in-edit-mode.png
Binary files differ
diff --git a/Documentation/images/inline-edit-full-screen-editor.png b/Documentation/images/inline-edit-full-screen-editor.png
new file mode 100644
index 0000000..474fae5
--- /dev/null
+++ b/Documentation/images/inline-edit-full-screen-editor.png
Binary files differ
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index bb5e148..6fd0ef2 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -1408,8 +1408,16 @@
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/edit/foo HTTP/1.0
----
-The content of the file is returned as text encoded inside base64. When
-specified file was deleted in the change edit "`204 No Content`" is returned.
+The content of the file is returned as text encoded inside base64.
+The Content-Type header will always be `text/plain` reflecting the
+outer base64 encoding. A Gerrit-specific `X-FYI-Content-Type` header
+can be examined to find the server detected content type of the file.
+
+When the specified file was deleted in the change edit
+"`204 No Content`" is returned.
+
+If only the content type is required, callers should use HEAD to
+avoid downloading the encoded file contents.
.Response
----
@@ -1417,33 +1425,11 @@
Content-Disposition: attachment
Content-Type: text/plain; charset=ISO-8859-1
X-FYI-Content-Encoding: base64
+ X-FYI-Content-Type: text/xml
RnJvbSA3ZGFkY2MxNTNmZGVhMTdhYTg0ZmYzMmE2ZTI0NWRiYjY...
----
-[[get-edit-file-mime-type]]
-=== Retrieve file content MIME type from Change Edit
---
-'GET /changes/link:#change-id[\{change-id\}]/edit/path%2fto%2ffile/type
---
-
-Retrieves content MIME type of a file from a change edit.
-
-.Request
-----
- GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/edit/foo%2fbar%2fbaz%2fqux.txt/type HTTP/1.0
-----
-
-.Response
-----
- HTTP/1.1 200 OK
- Content-Disposition: attachment
- Content-Type: application/json; charset=UTF-8
-
- )]}'
- "text/plain"
-----
-
[[get-edit-message]]
=== Retrieve commit message from Change Edit or current patch set of the change
--
@@ -2081,6 +2067,9 @@
}
----
+A review cannot be set on a change edit. Trying to post a review for a
+change edit fails with `409 Conflict`.
+
[[rebase-revision]]
=== Rebase Revision
--
@@ -2758,6 +2747,11 @@
of the paths the caller has marked as reviewed. Clients that also
need the FileInfo should make two requests.
+The request parameter `q` changes the response to return a list
+of all files (modified or unmodified) that contain that substring
+in the path name. This is useful to implement suggestion services
+finding a file by partial name.
+
.Request
----
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/files/?reviewed HTTP/1.0
@@ -2789,43 +2783,25 @@
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/files/gerrit-server%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgoogle%2Fgerrit%2Fserver%2Fproject%2FRefControl.java/content HTTP/1.0
----
-The content is returned as base64 encoded string.
+The content is returned as base64 encoded string. The HTTP response
+Content-Type is always `text/plain`, reflecting the base64 wrapping.
+A Gerrit-specific `X-FYI-Content-Type` header is returned describing
+the server detected content type of the file.
+
+If only the content type is required, callers should use HEAD to
+avoid downloading the encoded file contents.
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
- Content-Type: text/plain; charset=UTF-8
+ Content-Type: text/plain; charset=ISO-8859-1
+ X-FYI-Content-Encoding: base64
+ X-FYI-Content-Type: text/xml
Ly8gQ29weXJpZ2h0IChDKSAyMDEwIFRoZSBBbmRyb2lkIE9wZW4gU291cmNlIFByb2plY...
----
-[[get-content-type]]
-=== Get Content MIME Type
---
-'GET /changes/link:#change-id[\{change-id\}]/revisions/link:#revision-id[\{revision-id\}]/files/link:#file-id[\{file-id\}]/type'
---
-
-Gets the content MIME type of a file from a certain revision.
-
-.Request
-----
- GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/files/readme.txt/type HTTP/1.0
-----
-
-The content MIME type is returned as string. The content type for the commit
-message (`/COMMIT_MSG`) is always returned as "text/plain".
-
-.Response
-----
- HTTP/1.1 200 OK
- Content-Disposition: attachment
- Content-Type: application/json; charset=UTF-8
-
- )]}'
- "text/plain"
-----
-
[[get-diff]]
=== Get Diff
--
@@ -4072,10 +4048,6 @@
|`commit` ||The commit of change edit as
link:#commit-info[CommitInfo] entity.
|`baseRevision`||The revision of the patch set change edit is based on.
-|`actions` ||
-Actions the caller might be able to perform on this change edit. The
-information is a map of view name to link:#action-info[ActionInfo]
-entities.
|`fetch` ||
Information about how to fetch this patch set. The fetch information is
provided as a map that maps the protocol name ("`git`", "`http`",
diff --git a/Documentation/user-inline-edit.txt b/Documentation/user-inline-edit.txt
index e44fb94..9be89a2 100644
--- a/Documentation/user-inline-edit.txt
+++ b/Documentation/user-inline-edit.txt
@@ -29,6 +29,70 @@
image::images/inline-edit-create-follow-up-change.png[width=800, link="images/inline-edit-create-follow-up-change.png"]
+[[editing-change]]
+== Editing Changes
+
+To switch to edit mode, press the 'Edit' button at the top of the file list:
+
+[[switch-to-edit-mode]]
+image::images/inline-edit-enter-edit-mode-from-file-list.png[width=800, link="images/inline-edit-enter-edit-mode-from-file-list.png"]
+
+While in edit mode, it is possible to add new files to the change by clicking
+the 'Add...' button at the top of the file list.
+
+Files can be removed from the change, or restored, by clicking the icon to the
+left of the file name.
+
+To switch from edit mode back to review mode, click the 'Done Editing' button.
+
+image::images/inline-edit-file-list-in-edit-mode.png[width=800, link="images/inline-edit-file-list-in-edit-mode.png"]
+
+[[open-full-screen-editor]]
+While in edit mode, clicking on a file name in the file list opens a full
+screen editor for that file.
+
+To save edits, click the 'Save' button or press `CTRL-S`. To return to the
+change screen, click the 'Close' button.
+
+image::images/inline-edit-full-screen-editor.png[width=800, link="images/inline-edit-full-screen-editor.png"]
+
+If there are unsaved edits when the 'Close' button is pressed, a dialog will
+pop up asking to confirm the edits.
+
+image::images/inline-edit-confirm-unsaved-edits.png[width=800, link="images/inline-edit-confirm-unsaved-edits.png"]
+
+To discard the unsaved edits and return to the change screen, click the 'OK'
+button. To continue editing, click 'Cancel'.
+
+[[switch-to-edit-mode-from-side-by-side]]
+
+While in review mode, it is possible to switch directly to edit mode and into an
+editor for a file under review by clicking on the edit icon in the patch set list
+on the side-by-side diff view.
+
+image::images/inline-edit-enter-edit-mode-from-diff.png[width=800, link="images/inline-edit-enter-edit-mode-from-diff.png"]
+
+[[reviewing-changes-made-in-change-edit]]
+== Reviewing Change Edits
+
+Change edits are reviewed in the same way as regular patch sets, using the
+side-by-side diff screen. Change edits are shown as 'edit' in the patch list
+on the diff screen:
+
+image::images/inline-edit-edit-in-diff-screen-patch-list.png[width=800, link="images/inline-edit-edit-in-diff-screen-patch-list.png"]
+
+and on the change screen:
+
+image::images/inline-edit-edit-in-patch-list.png[width=800, link="images/inline-edit-edit-in-patch-list.png"]
+
+Note that patch sets may exist that were created after the change edit was created.
+
+For example this sequence:
+
+`1 2 3 4 5 6 7 8 9 edit 10`
+
+means that the change edit was created on top of patch set number 9 and a regular
+patch set was uploaded later.
GERRIT
------
diff --git a/ReleaseNotes/ReleaseNotes-2.11.txt b/ReleaseNotes/ReleaseNotes-2.11.txt
index 34f2997..43a8ce6 100644
--- a/ReleaseNotes/ReleaseNotes-2.11.txt
+++ b/ReleaseNotes/ReleaseNotes-2.11.txt
@@ -21,7 +21,18 @@
a later 2.1.x version), and then to 2.11.x. If you are upgrading from 2.2.x.x or
later, you may ignore this warning and upgrade directly to 2.11.x.
-*WARNING:* The 'Generate HTTP Password' capability has been removed.
+*WARNING:* The 'Generate HTTP Password' capability has been
+link:#remove-generate-http-password-capability[removed].
+
+*WARNING:* Google will
+link:https://developers.google.com/+/api/auth-migration[shut down their OpenID
+service on 20th April 2015]. Administrators of sites whose users are registered
+with Google OpenID accounts should encourage the users to
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-sso.html#_multiple_identities[
+add an alternative identity to their account] before this date. Users who do
+not add an alternative identity before this date will need to create a new
+account and ask the site administrator to
+link:https://code.google.com/p/gerrit/wiki/SqlMergeUserAccounts[merge it].
Release Highlights
@@ -29,10 +40,39 @@
* link:http://code.google.com/p/gerrit/issues/detail?id=505[Issue 505]:
-Inline editing: Changes can be edited directly in the browser.
+Changes can be created and edited directly in the browser. See the
+link:#inline-editing[Inline editing] section for more details.
+
+
+Experimental Features
+---------------------
+
+The following new features are experimental. They are not fully documented yet,
+and it is not recommended to enable them in live production systems.
+
+* Migration of review information from database to git notes.
+
-Files can be added, deleted, restored or edited directly in the browser. Change
-edits can be published, deleted and rebased on top of the latest patch set.
+Groundwork has been done to implement migration of review information from the
+database to a git notes based backend.
++
+Existing review information can be migrated from the review database to
+git notes with the `RebuildNotedb` program.
++
+This feature can be enabled with the following settings in `gerrit.config`:
+----
+[gerrit]
+ notedbpath = notedb
+[notedb "changes"]
+ write = true
+ read = true
+----
+
+* Hashtags.
++
+Hashtags can be added to changes. The hashtags are stored in git notes and
+are indexed in the secondary index.
++
+This feature requires the notedb to be enabled.
New Features
@@ -42,32 +82,348 @@
Web UI
~~~~~~
-TODO
+[[inline-editing]]
+Inline Editing
+^^^^^^^^^^^^^^
-Global
-^^^^^^
+Refer to the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/user-inline-edit.html[
+inline editing user guide] for detailed instructions.
-TODO
+* The inline editing feature only works with the new change screen.
+
+* New changes can be created directly in the browser via a 'Create Change'
+button on the project info screen.
+
+* New follow-up changes can be created via a 'Follow-Up' button on the change
+screen.
+
+* File content can be edited in a full screen CodeMirror window with support for
+themes, syntax highlighting, different key maps (Emacs, Vim, Default).
+
+* The CodeMirror screen can be configured in the same way as the side-by-side
+diff screen.
+
+* The file table in the change screen supports edit mode with seamless navigation
+to CodeMirror for editing.
+
+* Edit mode can be started from the side-by-side diff screen with seamless
+navigation to CodeMirror.
+
+* The commit message can be changed in context of change edit. The 'Edit Message'
+button is still supported, but now it creates a change edit that must be published.
+
+* Files can be added, deleted, restored and modified directly in browser.
+
+* User-specific configuration dedicated to edit mode in CodeMirror are stored in
+the `All-Users` repository rather than in the database.
+
+Change Screen
+^^^^^^^^^^^^^
+
+* Show the parent commit's subject as a tooltip.
+
+* link:http://code.google.com/p/gerrit/issues/detail?id=2541[Issue 2541],
+link:http://code.google.com/p/gerrit/issues/detail?id=2974[Issue 2974]:
+Allow the 'Reply' button's
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#change.replyLabel[
+label and tooltip] to be configured.
+
+Side-By-Side Diff
+^^^^^^^^^^^^^^^^^
+
+* New preference setting to toggle auto-hiding of the diff table header.
++
+The setting determines whether or not the diff table header with the patch set
+selection should be automatically hidden when scrolling down more than half of
+a page.
+
+* Highlight search results on scrollbar.
++
+Search results in vim mode are highlighted in the scrollbar with gold
+colored annotations.
+
+* Set line length to 72 characters for commit messages.
+
+* Add syntax highlighting for several new modes:
+
+** link:https://code.google.com/p/gerrit/issues/detail?id=2848[Issue 2848]: CSharp
+** Dart
+** Dockerfile
+** GLSL shader
+** Objective C
+** link:http://code.google.com/p/gerrit/issues/detail?id=2779[Issue 2779]: reStructured text
+** Soy
REST
~~~~
-TODO
+Changes
+^^^^^^^
-SSH
+* Add new
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#check-change[
+check change endpoint].
++
+In the past, Gerrit bugs, lack of transactions, and unreliable NoSQL backends
+have at various times produced a bewildering variety of corrupt states.
++
+This endpoint can be used to detect and explain some of these possible states
+of a change.
+
+Change Edits
+^^^^^^^^^^^^
+
+Several new endpoints are added to support the inline edit feature.
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#get-edit-detail[
+Get Edit Detail].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#put-edit-file[
+Change file content in Change Edit].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#post-edit[
+Restore file content in Change Edit].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#put-change-edit-message[
+Change commit message in Change Edit].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#delete-edit-file[
+Delete file in Change Edit].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#get-edit-file[
+Retrieve file content from Change Edit].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#get-edit-message[
+Retrieve commit message from Change Edit or current patch set of the change].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#publish-edit[
+Publish Change Edit].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#rebase-edit[
+Rebase Change Edit].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#delete-edit[
+Delete Change Edit].
+
+
+Projects
+^^^^^^^^
+
+* Add filtering and pagination options on the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-projects.html#list-branches[
+list branches] endpoint.
+
+* Add new
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-projects.html#list-tags[
+list tags] endpoint.
+
+* Add new
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-projects.html#get-tag[
+get tag] endpoint.
+
+
+Configuration
+~~~~~~~~~~~~~
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2786[Issue 2786]:
+Allow non-administrators to modify user accounts.
++
+A new global capability,
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/access-control.html#capability_modifyAccount[
+'Modify Account'], allows the granted group members to modify user account
+settings via the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/cmd-set-account.html[
+`set-account` SSH command].
++
+Modification of users' SSH keys is still restricted to administrators.
+
+* Add support for
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#ldap.useConnectionPooling[
+LDAP connection pooling].
+
+* Allow to
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#receive.maxBatchChanges[
+limit max number of changes pushed in a batch].
++
+Can be overridden by members of groups that are granted the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/access-control.html#capability_batchChangesLimit[
+Batch Changes Limit] capability.
+
+* Allow to
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#gerrit.disableReverseDnsLookup[
+disable reverse DNS lookup].
++
+This option can be set to improve push time from hosts without a reverse DNS
+entry.
+
+* Allow to
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#cache.projects.loadOnStartup[
+load the project cache at server startup].
+
+* Allow members of groups granted the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/access-control.html#capability_accessDatabase[
+AccessDatabase capability] to view metadata refs.
+
+* Allow to
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#http.addUserAsRequestAttribute[
+add the user to the http request attributes].
+
+* Allow to
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#suggest.fullTextSearch[
+enable full text search in memory for review suggestions].
++
+The maximum number of reviewers evaluated can be limited with
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#suggest.fullTextSearchMaxMatches[
+suggest.fullTextSearchMaxMatches].
+
+* Allow to provide an alternative
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#gerrit.secureStoreClass[
+secure store implementation].
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=1195[Issue 1195]:
+Allow projects to be configured to create a new change for every uploaded commit that is not in the target branch.
+
+* Allow to configure
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#container.daemonOpt[
+options to pass to the daemon].
+
+* Remove support for Google accounts and add support for Launchpad accounts on
+the OpenID login page.
+
+Daemon
+~~~~~~
+
+* Allow to enable the http daemon when running in slave mode.
+
+The `--enable-httpd` option can be used in conjunction with the `--slave` option
+to allow clients to fetch from the slave over the http protocol.
+
+* Include the submitter's name in the change message when a change is submitted.
+
+
+ssh
~~~
-TODO
+* Add new commands
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/cmd-logging-ls-level.html[
+`logging ls-level`] and
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/cmd-logging-set-level.html[
+`logging set-level`] to show and set the logging level at runtime.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=602[Issue 602]:
+Add `--json` option to the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/cmd-review.html[
+`review` SSH command].
++
+Review input can be given to the `review` command in JSON format corresponding
+to the REST API's
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#review-input[
+ReviewInput] entity.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2824[Issue 2824]:
+Add `--rebase` option to the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/cmd-review.html[
+`review` SSH command].
+
+* Add `--clear-http-password` option to the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/cmd-set-account.html[
+`set-account` SSH command].
+
+* Add `--preferred-email` option to the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/cmd-set-account.html[
+`set-account` SSH command].
+
Plugins
~~~~~~~
-TODO
+General
+^^^^^^^
-Other
-~~~~~
+* Plugins can listen to account group membership changes
++
+The audit log service allows to register listeners to group member added and
+group member deleted events. A default listener logs these events to the database
+as before, but additional listeners may now be registered for these events using
+the `GroupMemberAuditListener` interface.
-* The 'Generate HTTP Password' capability is removed.
+* Plugins can validate ref operations.
++
+Plugins implementing the `RefOperationValidationListener` interface can
+perform additional validation checks against ref creation/deletion operations
+before they are applied to the git repository.
+
+* Plugins can provide project-aware top menu extensions
++
+Plugins can provide sub-menu items within the 'Projects' context. The
+'${projectName}' placeholder is replaced by the project name.
+
+* Auto register static/init.js as JavaScript plugin.
++
+When a plugin does not expose Guice Modules explicitly, auto discover and
+register static/init.js as WebUi extension if found by the plugin content
+scanner.
+
+* Plugins that provide initialization steps may now use functionality
+from InitUtil in core Gerrit.
+
+* New extensions in the Java Plugin API:
+
+** Set/Put topic.
+** Get mergeable status.
+** link:https://code.google.com/p/gerrit/issues/detail?id=461[Issue 461]:
+Get current user.
+
+Replication
+^^^^^^^^^^^
+
+* Projects can be specified with wildcard in the `start` command.
+
+
+Bug Fixes
+---------
+
+Daemon
+~~~~~~
+
+* Change "Merge topic" to "Merge changes from topic".
++
+When multiple changes from a topic are submitted resulting in a merge commit,
+the title of the merge commit is now "Merge changes from topic" instead of
+"Merge topic".
+
+* Fix visibility checks for `refs/meta/config`.
++
+Under some conditions it was possible for the `refs/meta/config` branch to be
+erroneously considerered not visible to the user.
+
+* Sort list of updated changes in output from push.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2940[Issue 2940]:
+Improve warning messages when Change-Id is missing in the commit message.
+
+** Add a hint to amend the commit after installing the commit-msg hook.
+** Don't show "Suggestion for commit message" when Change-Id is missing.
+
+
+Secondary Index / Search
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2822[Issue 2822]:
+Improve Lucene analysis of words linked with '_' or '.'.
++
+Instead of treating words linked with '_' or '.' as one word, Lucene now
+treats them as separate words.
+
+* Fix support for change~branch~id in query syntax.
+
+
+Configuration
+~~~~~~~~~~~~~
+
+[[remove-generate-http-password-capability]]
+* Remove the 'Generate HTTP Password' capability.
+
The 'Generate HTTP Password' capability has been removed to close a security
vulnerability. Now only administrators are allowed to generate and delete other
@@ -75,7 +431,127 @@
+
It is encouraged to clean up your `project.config` settings after upgrading.
+
+Web UI
+~~~~~~
+
+Change Screen
+^^^^^^^^^^^^^
+
+* Differentiate between conflicts and already merged errors in cherry-pick
++
+When a cherry-pick operation failed with "Cherry pick failed" error, there was no
+way to know the reason for the failure: merge conflict or the commit is already
+on the target branch. These failures are now differentiated and a proper error
+is reported to the client.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2837[Issue 2837]:
+Improve display of long user names for collapsed comments in history.
++
+If there were several users with long user names with the same prefix, e.g.
+'AutomaticGerritVoterLinux' and 'AutomaticGerritVoterWindows', they would both
+be shown as 'AutomaticGerritVo...' and users had to expand the comment to see
+the full user name.
++
+The ellipsis is now inserted in the middle of the user name so that the start
+and end of the user name are always visible, e.g. 'AutomaticG...VoterLinux' and
+'AutomaticG...terWindows'.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2992[Issue 2992]:
+Fix display of review comments for Chrome on Android.
++
+Chrome for Android has Font Boosting, which caused the review comments to
+be displayed too large.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2909[Issue 2909]:
+Make change owner votes removable.
++
+If a change owner voted on a change, it was not possible for anyone other
+than the owner to remove the vote.
+
+* Preserve topic when cherry-picking.
++
+When a change is cherry-picked, the topic from the source change is preserved
+on the newly created change.
+
+* link:http://code.google.com/p/gerrit/issues/detail?id=3007[Issue 3007]:
+Make the selected tab persistent.
++
+If a change from the "Same Topic" tab was clicked, the selected tab would reset
+to the default tab ("Related Changes").
+
+
+Side-By-Side Diff
+^^^^^^^^^^^^^^^^^
+
+* Return to normal mode after editing a draft comment.
++
+Previously it would remain in visual mode.
+
+
+Project Screen
+^^^^^^^^^^^^^^
+
+* Fix alignment of checkboxes on project access screen.
++
+The "Exclusive" checkbox was not aligned with the other checkboxes.
+
+REST API
+~~~~~~~~
+
+Changes
+^^^^^^^
+
+* Remove the administrator restriction on the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#index-change[
+index change] endpoint.
++
+The endpoint can now be used by any user who has visibility of the change.
+
+* Only include account ID in responses unless `DETAILED_ACCOUNTS` option is set.
++
+The behaviour was inconsistent with the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-accounts.html#account-info[
+documentation]. In the default case it was including only the account name,
+rather than only the account ID.
+
+* Include revision's ref in responses.
++
+The ref of a revision was only returned as part of the fetch info, which is only
+available if the download commands are installed.
+
+* Correctly set the limit to the default when no limit is given in the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-changes.html#suggest-reviewers[
+suggest reviewers] endpoint.
+
+Projects
+^^^^^^^^
+
+* Make it mandatory to specify at least one of the `--prefix`, `--match` or `--regex`
+options in the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/rest-api-projects.html#list-projects[
+list projects] endpoint.
+
+
Upgrades
--------
-TODO
+* Update Antlr to 3.5.2.
+
+* Update ASM to 5.0.3.
+
+* Update CodeMirror to 4.10.0-6-gd0a2dda.
+
+* Update Guava to 18.0.
+
+* Update Guice to 4.0-beta5.
+
+* Update GWT to 2.7.
+
+* Update Jetty to 9.2.2.
+
+* Update JGit to 3.6.0.201412230720-r.
+
+* Update Lucene to 4.10.2.
+
+* Update Pegdown to 1.4.2.
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
index abcdf3f..aec1845 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
@@ -59,6 +59,7 @@
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
import org.joda.time.DateTime;
@@ -194,10 +195,10 @@
Date beforeRebase = edit.getEditCommit().getCommitterIdent().getWhen();
modifier.rebaseEdit(edit, current);
edit = editUtil.byChange(change).get();
- assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
- .getRevision().get(), FILE_NAME), CONTENT_NEW);
- assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
- .getRevision().get(), FILE_NAME2), CONTENT_NEW2);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
+ ObjectId.fromString(edit.getRevision().get()), FILE_NAME), CONTENT_NEW);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
+ ObjectId.fromString(edit.getRevision().get()), FILE_NAME2), CONTENT_NEW2);
assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo(
current.getPatchSetId());
Date afterRebase = edit.getEditCommit().getCommitterIdent().getWhen();
@@ -218,10 +219,10 @@
RestResponse r = adminSession.post(urlRebase());
assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT);
edit = editUtil.byChange(change).get();
- assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
- .getRevision().get(), FILE_NAME), CONTENT_NEW);
- assertByteArray(fileUtil.getContent(edit.getChange().getProject(), edit
- .getRevision().get(), FILE_NAME2), CONTENT_NEW2);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
+ ObjectId.fromString(edit.getRevision().get()), FILE_NAME), CONTENT_NEW);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()),
+ ObjectId.fromString(edit.getRevision().get()), FILE_NAME2), CONTENT_NEW2);
assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo(
current.getPatchSetId());
Date afterRebase = edit.getEditCommit().getCommitterIdent().getWhen();
@@ -235,9 +236,8 @@
assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW)))
.isEqualTo(RefUpdate.Result.FORCED);
edit = editUtil.byChange(change);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME), CONTENT_NEW);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
editUtil.delete(edit.get());
edit = editUtil.byChange(change);
assertThat(edit.isPresent()).isFalse();
@@ -364,8 +364,8 @@
RefUpdate.Result.FORCED);
edit = editUtil.byChange(change);
try {
- fileUtil.getContent(edit.get().getChange().getProject(),
- edit.get().getRevision().get(), FILE_NAME);
+ fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
fail("ResourceNotFoundException expected");
} catch (ResourceNotFoundException rnfe) {
}
@@ -377,8 +377,8 @@
assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT);
Optional<ChangeEdit> edit = editUtil.byChange(change);
try {
- fileUtil.getContent(edit.get().getChange().getProject(),
- edit.get().getRevision().get(), FILE_NAME);
+ fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
fail("ResourceNotFoundException expected");
} catch (ResourceNotFoundException rnfe) {
}
@@ -397,8 +397,8 @@
SC_NO_CONTENT);
Optional<ChangeEdit> edit = editUtil.byChange(change);
try {
- fileUtil.getContent(edit.get().getChange().getProject(),
- edit.get().getRevision().get(), FILE_NAME);
+ fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
fail("ResourceNotFoundException expected");
} catch (ResourceNotFoundException rnfe) {
}
@@ -412,9 +412,8 @@
assertThat(modifier.restoreFile(edit.get(), FILE_NAME)).isEqualTo(
RefUpdate.Result.FORCED);
edit = editUtil.byChange(change2);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME), CONTENT_OLD);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD);
}
@Test
@@ -424,9 +423,8 @@
assertThat(adminSession.post(urlEdit2(), in).getStatusCode()).isEqualTo(
SC_NO_CONTENT);
Optional<ChangeEdit> edit = editUtil.byChange(change2);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME), CONTENT_OLD);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD);
}
@Test
@@ -436,15 +434,13 @@
assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW)))
.isEqualTo(RefUpdate.Result.FORCED);
edit = editUtil.byChange(change);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME), CONTENT_NEW);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW2)))
.isEqualTo(RefUpdate.Result.FORCED);
edit = editUtil.byChange(change);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME), CONTENT_NEW2);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW2);
}
@Test
@@ -454,16 +450,14 @@
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
.isEqualTo(SC_NO_CONTENT);
Optional<ChangeEdit> edit = editUtil.byChange(change);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME), CONTENT_NEW);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
in.content = RestSession.newRawInput(CONTENT_NEW2);
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
.isEqualTo(SC_NO_CONTENT);
edit = editUtil.byChange(change);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME), CONTENT_NEW2);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW2);
}
@Test
@@ -474,9 +468,8 @@
assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
.isEqualTo(SC_NO_CONTENT);
Optional<ChangeEdit> edit = editUtil.byChange(change);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME), CONTENT_NEW);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW);
}
@Test
@@ -485,9 +478,8 @@
assertThat(adminSession.put(urlEditFile()).getStatusCode()).isEqualTo(
SC_NO_CONTENT);
Optional<ChangeEdit> edit = editUtil.byChange(change);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME), "".getBytes());
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), "".getBytes());
}
@Test
@@ -495,9 +487,8 @@
assertThat(adminSession.post(urlEdit()).getStatusCode()).isEqualTo(
SC_NO_CONTENT);
Optional<ChangeEdit> edit = editUtil.byChange(change);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME), CONTENT_OLD);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD);
}
@Test
@@ -518,26 +509,14 @@
}
@Test
- public void getFileContentTypeRest() throws Exception {
- Put.Input in = new Put.Input();
- in.content = RestSession.newRawInput(CONTENT_NEW);
- assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode())
- .isEqualTo(SC_NO_CONTENT);
- RestResponse r = adminSession.get(urlEditFileContentType());
- assertThat(r.getStatusCode()).isEqualTo(SC_OK);
- String res = newGson().fromJson(r.getReader(), String.class);
- assertThat(res).isEqualTo("application/octet-stream");
- }
-
- @Test
public void getFileNotFoundRest() throws Exception {
assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW);
assertThat(adminSession.delete(urlEditFile()).getStatusCode()).isEqualTo(
SC_NO_CONTENT);
Optional<ChangeEdit> edit = editUtil.byChange(change);
try {
- fileUtil.getContent(edit.get().getChange().getProject(),
- edit.get().getRevision().get(), FILE_NAME);
+ fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME);
fail("ResourceNotFoundException expected");
} catch (ResourceNotFoundException rnfe) {
}
@@ -552,9 +531,8 @@
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW)))
.isEqualTo(RefUpdate.Result.FORCED);
edit = editUtil.byChange(change);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME2), CONTENT_NEW);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW);
}
@Test
@@ -564,15 +542,13 @@
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW)))
.isEqualTo(RefUpdate.Result.FORCED);
edit = editUtil.byChange(change);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME2), CONTENT_NEW);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW);
assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW2)))
.isEqualTo(RefUpdate.Result.FORCED);
edit = editUtil.byChange(change);
- assertByteArray(
- fileUtil.getContent(edit.get().getChange().getProject(), edit.get()
- .getRevision().get(), FILE_NAME2), CONTENT_NEW2);
+ assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()),
+ ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW2);
}
@Test
@@ -684,13 +660,6 @@
+ FILE_NAME;
}
- private String urlEditFileContentType() {
- return urlEdit()
- + "/"
- + FILE_NAME
- + "/type";
- }
-
private String urlGetFiles() {
return urlEdit()
+ "?list";
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java b/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java
index fc5bb56..ffdae9d 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java
@@ -14,9 +14,8 @@
package com.google.gerrit.common;
-import com.google.common.base.Objects;
-
import java.io.File;
+import java.util.Objects;
public class PluginData {
public final String name;
@@ -33,14 +32,14 @@
public boolean equals(Object obj) {
if (obj instanceof PluginData) {
PluginData o = (PluginData) obj;
- return Objects.equal(name, o.name) && Objects.equal(version, o.version)
- && Objects.equal(pluginFile, o.pluginFile);
+ return Objects.equals(name, o.name) && Objects.equals(version, o.version)
+ && Objects.equals(pluginFile, o.pluginFile);
}
return super.equals(obj);
}
@Override
public int hashCode() {
- return Objects.hashCode(name, version, pluginFile);
+ return Objects.hash(name, version, pluginFile);
}
}
\ No newline at end of file
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
index a060245..f76252f 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
@@ -56,7 +56,6 @@
protected AccountGeneralPreferences.ChangeScreen changeScreen;
protected List<String> archiveFormats;
protected int largeChangeSize;
- protected boolean newFeatures;
protected String replyLabel;
protected String replyTitle;
@@ -303,14 +302,6 @@
archiveFormats = formats;
}
- public boolean getNewFeatures() {
- return newFeatures;
- }
-
- public void setNewFeatures(boolean n) {
- newFeatures = n;
- }
-
public String getReplyTitle() {
return replyTitle;
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/EditInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/EditInfo.java
index 5b2fd78..9dc92a8 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/EditInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/EditInfo.java
@@ -19,7 +19,6 @@
public class EditInfo {
public CommitInfo commit;
public String baseRevision;
- public Map<String, ActionInfo> actions;
public Map<String, FetchInfo> fetch;
public Map<String, FileInfo> files;
}
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/Resources.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/Resources.java
index b1312db..c4e2167 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/Resources.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/Resources.java
@@ -81,9 +81,6 @@
@Source("merge.png")
public ImageResource merge();
- @Source("removeReviewer.png")
- public ImageResource removeReviewer();
-
@Source("deleteNormal.png")
public ImageResource deleteNormal();
diff --git a/gerrit-gwtui-common/src/main/resources/com/google/gerrit/client/removeReviewer.png b/gerrit-gwtui-common/src/main/resources/com/google/gerrit/client/removeReviewer.png
deleted file mode 100644
index 5a3e6f0..0000000
--- a/gerrit-gwtui-common/src/main/resources/com/google/gerrit/client/removeReviewer.png
+++ /dev/null
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
index a9cdbb3..8af7e74 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
@@ -628,9 +628,7 @@
}
public static boolean isChangeScreen2() {
- if (!Gerrit.getConfig().getNewFeatures()) {
- return false;
- } else if (changeScreen2) {
+ if (changeScreen2) {
return true;
}
@@ -707,7 +705,7 @@
sbs1(token, baseId, id, patchIndex, patchSetDetail, patchTable, topView,
PatchScreen.Type.UNIFIED);
return;
- } else if ("cm".equals(panel) && Gerrit.getConfig().getNewFeatures()) {
+ } else if ("cm".equals(panel)) {
if (Gerrit.isSignedIn()
&& DiffView.UNIFIED_DIFF.equals(Gerrit.getUserAccount()
.getGeneralPreferences().getDiffView())) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
index 6fb2fe0..9e78866 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
@@ -196,32 +196,29 @@
formGrid.setWidget(row, fieldIdx, dateTimePanel);
row++;
- if (Gerrit.getConfig().getNewFeatures()) {
- formGrid.setText(row, labelIdx, "");
- formGrid.setWidget(row, fieldIdx, relativeDateInChangeTable);
- row++;
+ formGrid.setText(row, labelIdx, "");
+ formGrid.setWidget(row, fieldIdx, relativeDateInChangeTable);
+ row++;
- formGrid.setText(row, labelIdx, "");
- formGrid.setWidget(row, fieldIdx, sizeBarInChangeTable);
- row++;
+ formGrid.setText(row, labelIdx, "");
+ formGrid.setWidget(row, fieldIdx, sizeBarInChangeTable);
+ row++;
- formGrid.setText(row, labelIdx, "");
- formGrid.setWidget(row, fieldIdx, legacycidInChangeTable);
- row++;
- }
+ formGrid.setText(row, labelIdx, "");
+ formGrid.setWidget(row, fieldIdx, legacycidInChangeTable);
+ row++;
formGrid.setText(row, labelIdx, Util.C.commentVisibilityLabel());
formGrid.setWidget(row, fieldIdx, commentVisibilityStrategy);
row++;
- if (Gerrit.getConfig().getNewFeatures()) {
- formGrid.setText(row, labelIdx, Util.C.changeScreenLabel());
- formGrid.setWidget(row, fieldIdx, changeScreen);
- row++;
+ formGrid.setText(row, labelIdx, Util.C.changeScreenLabel());
+ formGrid.setWidget(row, fieldIdx, changeScreen);
+ row++;
- formGrid.setText(row, labelIdx, Util.C.diffViewLabel());
- formGrid.setWidget(row, fieldIdx, diffView);
- }
+ formGrid.setText(row, labelIdx, Util.C.diffViewLabel());
+ formGrid.setWidget(row, fieldIdx, diffView);
+
add(formGrid);
save = new Button(Util.C.buttonSaveChanges());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
index b5090ca..bee2f53 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
@@ -19,7 +19,6 @@
import com.google.gerrit.client.actions.ActionInfo;
import com.google.gerrit.client.changes.ChangeInfo;
import com.google.gerrit.client.changes.ChangeInfo.CommitInfo;
-import com.google.gerrit.client.changes.ChangeInfo.EditInfo;
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.reviewdb.client.Change;
@@ -45,12 +44,6 @@
private static final Binder uiBinder = GWT.create(Binder.class);
@UiField Button cherrypick;
- @UiField Button deleteChange;
- @UiField Button deleteRevision;
- @UiField Button deleteEdit;
- @UiField Button publishEdit;
- @UiField Button rebaseEdit;
- @UiField Button publish;
@UiField Button rebase;
@UiField Button revert;
@UiField Button submit;
@@ -95,7 +88,6 @@
initChangeActions(info, hasUser);
initRevisionActions(info, revInfo, hasUser);
- initEditActions(info, info.edit(), hasUser);
}
private void initChangeActions(ChangeInfo info, boolean hasUser) {
@@ -105,7 +97,6 @@
actions.copyKeysIntoChildren("id");
if (hasUser) {
- a2b(actions, "/", deleteChange);
a2b(actions, "abandon", abandon);
a2b(actions, "restore", restore);
a2b(actions, "revert", revert);
@@ -116,26 +107,6 @@
}
}
- private void initEditActions(ChangeInfo info, EditInfo editInfo,
- boolean hasUser) {
- if (!info.has_edit() || !info.current_revision().equals(editInfo.name())) {
- return;
- }
- NativeMap<ActionInfo> actions = editInfo.has_actions()
- ? editInfo.actions()
- : NativeMap.<ActionInfo> create();
- actions.copyKeysIntoChildren("id");
-
- if (hasUser) {
- a2b(actions, "/", deleteEdit);
- a2b(actions, "publish", publishEdit);
- a2b(actions, "rebase", rebaseEdit);
- for (String id : filterNonCore(actions)) {
- add(new ActionButton(info, editInfo, actions.get(id)));
- }
- }
- }
-
private void initRevisionActions(ChangeInfo info, RevisionInfo revInfo,
boolean hasUser) {
NativeMap<ActionInfo> actions = revInfo.has_actions()
@@ -154,9 +125,7 @@
.append(action.label())
.closeDiv());
}
- a2b(actions, "/", deleteRevision);
a2b(actions, "cherrypick", cherrypick);
- a2b(actions, "publish", publish);
a2b(actions, "rebase", rebase);
for (String id : filterNonCore(actions)) {
add(new ActionButton(info, revInfo, actions.get(id)));
@@ -201,36 +170,6 @@
abandonAction.show();
}
- @UiHandler("publish")
- void onPublish(@SuppressWarnings("unused") ClickEvent e) {
- DraftActions.publish(changeId, revision);
- }
-
- @UiHandler("deleteEdit")
- void onDeleteEdit(@SuppressWarnings("unused") ClickEvent e) {
- EditActions.deleteEdit(changeId);
- }
-
- @UiHandler("publishEdit")
- void onPublishEdit(@SuppressWarnings("unused") ClickEvent e) {
- EditActions.publishEdit(changeId);
- }
-
- @UiHandler("rebaseEdit")
- void onRebaseEdit(@SuppressWarnings("unused") ClickEvent e) {
- EditActions.rebaseEdit(changeId);
- }
-
- @UiHandler("deleteRevision")
- void onDeleteRevision(@SuppressWarnings("unused") ClickEvent e) {
- DraftActions.delete(changeId, revision);
- }
-
- @UiHandler("deleteChange")
- void onDeleteChange(@SuppressWarnings("unused") ClickEvent e) {
- DraftActions.delete(changeId);
- }
-
@UiHandler("restore")
void onRestore(@SuppressWarnings("unused") ClickEvent e) {
if (restoreAction == null) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml
index 496e048..40d732a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml
@@ -45,12 +45,6 @@
line-height: BUTTON_HEIGHT;
}
- #change_actions button.red {
- color: #d14836;
- background-color: #d14836;
- }
- #change_actions button.red div {color: #fff;}
-
#change_actions button.submit {
float: right;
background-color: #4d90fe;
@@ -75,29 +69,10 @@
<g:Button ui:field='revert' styleName='' visible='false'>
<div><ui:msg>Revert</ui:msg></div>
</g:Button>
- <g:Button ui:field='deleteChange' styleName='' visible='false'>
- <div><ui:msg>Delete Change</ui:msg></div>
- </g:Button>
- <g:Button ui:field='deleteRevision' styleName='' visible='false'>
- <div><ui:msg>Delete Revision</ui:msg></div>
- </g:Button>
- <g:Button ui:field='publish' styleName='' visible='false'>
- <div><ui:msg>Publish</ui:msg></div>
- </g:Button>
- <g:Button ui:field='deleteEdit' styleName='' visible='false'>
- <div><ui:msg>Delete Edit</ui:msg></div>
- </g:Button>
- <g:Button ui:field='publishEdit' styleName='' visible='false'>
- <div><ui:msg>Publish Edit</ui:msg></div>
- </g:Button>
- <g:Button ui:field='rebaseEdit' styleName='' visible='false'>
- <div><ui:msg>Rebase Edit</ui:msg></div>
- </g:Button>
-
- <g:Button ui:field='abandon' styleName='{style.red}' visible='false'>
+ <g:Button ui:field='abandon' styleName='' visible='false'>
<div><ui:msg>Abandon</ui:msg></div>
</g:Button>
- <g:Button ui:field='restore' styleName='{style.red}' visible='false'>
+ <g:Button ui:field='restore' styleName='' visible='false'>
<div><ui:msg>Restore</ui:msg></div>
</g:Button>
<g:Button ui:field='followUp' styleName='' visible='false'>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileAction.java
new file mode 100644
index 0000000..6e2ee00
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileAction.java
@@ -0,0 +1,71 @@
+//Copyright (C) 2013 The Android Open Source Project
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+package com.google.gerrit.client.change;
+
+import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwtexpui.globalkey.client.GlobalKey;
+import com.google.gwtexpui.user.client.PluginSafePopupPanel;
+
+class AddFileAction {
+ private final Change.Id changeId;
+ private final RevisionInfo revision;
+ private final ChangeScreen2.Style style;
+ private final Widget addButton;
+
+ private AddFileBox addBox;
+ private PopupPanel popup;
+
+ AddFileAction(Change.Id changeId, RevisionInfo revision,
+ ChangeScreen2.Style style, Widget addButton) {
+ this.changeId = changeId;
+ this.revision = revision;
+ this.style = style;
+ this.addButton = addButton;
+ }
+
+ public void onEdit() {
+ if (popup != null) {
+ popup.hide();
+ return;
+ }
+
+ if (addBox == null) {
+ addBox = new AddFileBox(changeId, revision);
+ }
+ addBox.clearPath();
+
+ final PluginSafePopupPanel p = new PluginSafePopupPanel(true);
+ p.setStyleName(style.replyBox());
+ p.addAutoHidePartner(addButton.getElement());
+ p.addCloseHandler(new CloseHandler<PopupPanel>() {
+ @Override
+ public void onClose(CloseEvent<PopupPanel> event) {
+ if (popup == p) {
+ popup = null;
+ }
+ }
+ });
+ p.add(addBox);
+ p.showRelativeTo(addButton);
+ GlobalKey.dialog(p);
+ addBox.setFocus(true);
+ popup = p;
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.java
new file mode 100644
index 0000000..6e47f26
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.java
@@ -0,0 +1,159 @@
+//Copyright (C) 2013 The Android Open Source Project
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+package com.google.gerrit.client.change;
+
+import com.google.gerrit.client.Dispatcher;
+import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.changes.ChangeApi;
+import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
+import com.google.gerrit.client.rpc.Natives;
+import com.google.gerrit.client.ui.RemoteSuggestBox;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.event.logical.shared.SelectionEvent;
+import com.google.gwt.event.logical.shared.SelectionHandler;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiHandler;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTMLPanel;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwtexpui.safehtml.client.HighlightSuggestOracle;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+class AddFileBox extends Composite {
+ interface Binder extends UiBinder<HTMLPanel, AddFileBox> {}
+ private static final Binder uiBinder = GWT.create(Binder.class);
+
+ private final Change.Id changeId;
+ private final RevisionInfo revision;
+
+ @UiField Button open;
+ @UiField Button cancel;
+
+ @UiField(provided = true)
+ RemoteSuggestBox path;
+
+ AddFileBox(Change.Id changeId, RevisionInfo revision) {
+ this.changeId = changeId;
+ this.revision = revision;
+
+ path = new RemoteSuggestBox(new PathSuggestOracle());
+ path.addSelectionHandler(new SelectionHandler<String>() {
+ @Override
+ public void onSelection(SelectionEvent<String> event) {
+ open(event.getSelectedItem());
+ }
+ });
+ path.addCloseHandler(new CloseHandler<RemoteSuggestBox>() {
+ @Override
+ public void onClose(CloseEvent<RemoteSuggestBox> event) {
+ hide();
+ }
+ });
+
+ initWidget(uiBinder.createAndBindUi(this));
+ }
+
+ void setFocus(boolean focus) {
+ path.setFocus(focus);
+ }
+
+ void clearPath() {
+ path.setText("");
+ }
+
+ @UiHandler("open")
+ void onOpen(@SuppressWarnings("unused") ClickEvent e) {
+ open(path.getText());
+ }
+
+ private void open(String path) {
+ hide();
+ Gerrit.display(Dispatcher.toEditScreen(
+ new PatchSet.Id(changeId, revision._number()),
+ path));
+ }
+
+ @UiHandler("cancel")
+ void onCancel(@SuppressWarnings("unused") ClickEvent e) {
+ hide();
+ }
+
+ private void hide() {
+ for (Widget w = getParent(); w != null; w = w.getParent()) {
+ if (w instanceof PopupPanel) {
+ ((PopupPanel) w).hide();
+ break;
+ }
+ }
+ }
+
+ private class PathSuggestOracle extends HighlightSuggestOracle {
+ @Override
+ protected void onRequestSuggestions(final Request req, final Callback cb) {
+ ChangeApi.revision(changeId.get(), revision.name())
+ .view("files")
+ .addParameter("q", req.getQuery())
+ .background()
+ .get(new AsyncCallback<JsArrayString>() {
+ @Override
+ public void onSuccess(JsArrayString result) {
+ List<Suggestion> r = new ArrayList<>();
+ for (String path : Natives.asList(result)) {
+ r.add(new PathSuggestion(path));
+ }
+ cb.onSuggestionsReady(req, new Response(r));
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ List<Suggestion> none = Collections.emptyList();
+ cb.onSuggestionsReady(req, new Response(none));
+ }
+ });
+ }
+ }
+
+ private static class PathSuggestion implements Suggestion {
+ private final String path;
+
+ PathSuggestion(String path) {
+ this.path = path;
+ }
+
+ @Override
+ public String getDisplayString() {
+ return path;
+ }
+
+ @Override
+ public String getReplacementString() {
+ return path;
+ }
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditFileBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.ui.xml
similarity index 65%
rename from gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditFileBox.ui.xml
rename to gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.ui.xml
index 3a0e0be..d8236e6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditFileBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.ui.xml
@@ -16,40 +16,22 @@
-->
<ui:UiBinder
xmlns:ui='urn:ui:com.google.gwt.uibinder'
- xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'
- xmlns:f='urn:import:com.google.gerrit.client.change'
+ xmlns:u='urn:import:com.google.gerrit.client.ui'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
<ui:style>
- .fileContent {
- background-color: white;
- font-family: monospace;
- }
.cancel { float: right; }
</ui:style>
<g:HTMLPanel>
<div class='{res.style.section}'>
- <div>
- <ui:msg>Path:</ui:msg>
- </div>
- <div>
- <f:FileTextBox ui:field='file' visibleLength='79'/>
- </div>
- <div>
- <ui:msg>Content:</ui:msg>
- </div>
- <c:NpTextArea
- visibleLines='30'
- characterWidth='78'
- styleName='{style.fileContent}'
- ui:field='content'/>
+ <ui:msg>Path: <u:RemoteSuggestBox ui:field='path' visibleLength='86'/></ui:msg>
</div>
<div class='{res.style.section}'>
- <g:Button ui:field='save'
- title='Create new revision edit'
+ <g:Button ui:field='open'
+ title='Open file in editor'
styleName='{res.style.button}'>
<ui:attribute name='title'/>
- <div><ui:msg>Save</ui:msg></div>
+ <div><ui:msg>Open</ui:msg></div>
</g:Button>
<g:Button ui:field='cancel'
styleName='{res.style.button}'
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java
index a7d4945..be6879e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java
@@ -49,4 +49,8 @@
String indirectAncestor();
String merged();
String abandoned();
+
+ String deleteChangeEdit();
+ String deleteDraftChange();
+ String deleteDraftRevision();
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties
index 8852d4e..682cd18 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties
@@ -30,3 +30,9 @@
indirectAncestor = Indirect ancestor
merged = Merged
abandoned = Abandoned
+
+deleteChangeEdit = Delete Change Edit?\n\
+ \n\
+ All changes made in the edit revision will be lost.
+deleteDraftChange = Delete Draft Change?
+deleteDraftRevision = Delete Draft Revision?
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
index 5d6fa38..2ef12e3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
@@ -77,6 +77,7 @@
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
+import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
@@ -179,6 +180,12 @@
@UiField Element patchSetsText;
@UiField Button download;
@UiField Button reply;
+ @UiField Button publishEdit;
+ @UiField Button rebaseEdit;
+ @UiField Button deleteEdit;
+ @UiField Button publish;
+ @UiField Button deleteChange;
+ @UiField Button deleteRevision;
@UiField Button openAll;
@UiField Button editMode;
@UiField Button reviewMode;
@@ -193,7 +200,7 @@
private IncludedInAction includedInAction;
private PatchSetsAction patchSetsAction;
private DownloadAction downloadAction;
- private EditFileAction editFileAction;
+ private AddFileAction addFileAction;
public ChangeScreen2(Change.Id changeId, String base, String revision,
boolean openReplyBox, FileTable.Mode mode) {
@@ -215,11 +222,15 @@
CallbackGroup group = new CallbackGroup();
if (Gerrit.isSignedIn()) {
ChangeApi.editWithFiles(changeId.get(), group.add(
- new GerritCallback<EditInfo>() {
+ new AsyncCallback<EditInfo>() {
@Override
public void onSuccess(EditInfo result) {
edit = result;
}
+
+ @Override
+ public void onFailure(Throwable caught) {
+ }
}));
}
loadChangeInfo(true, group.addFinal(
@@ -269,8 +280,6 @@
reviewers.init(style, ccText);
hashtags.init(style);
- initReplyButton();
-
keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
keysNavigation.add(new KeyCommand(0, 'u', Util.C.upToChangeList()) {
@Override
@@ -335,12 +344,15 @@
}
}
- private void initReplyButton() {
- reply.setTitle(Gerrit.getConfig().getReplyTitle());
- reply.setHTML(new SafeHtmlBuilder()
- .openDiv()
- .append(Gerrit.getConfig().getReplyLabel())
- .closeDiv());
+ private void initReplyButton(ChangeInfo info, String revision) {
+ if (!info.revision(revision).is_edit()) {
+ reply.setTitle(Gerrit.getConfig().getReplyTitle());
+ reply.setHTML(new SafeHtmlBuilder()
+ .openDiv()
+ .append(Gerrit.getConfig().getReplyLabel())
+ .closeDiv());
+ reply.setVisible(true);
+ }
}
private void gotoSibling(final int offset) {
@@ -376,6 +388,19 @@
}
}
+ private void initChangeAction(ChangeInfo info) {
+ if (info.status() == Status.DRAFT) {
+ NativeMap<ActionInfo> actions = info.has_actions()
+ ? info.actions()
+ : NativeMap.<ActionInfo> create();
+ actions.copyKeysIntoChildren("id");
+ if (actions.containsKey("/")) {
+ deleteChange.setVisible(true);
+ deleteChange.setTitle(actions.get("/").title());
+ }
+ }
+ }
+
private void initRevisionsAction(ChangeInfo info, String revision) {
int currentPatchSet;
if (info.current_revision() != null
@@ -401,6 +426,23 @@
patchSetsAction = new PatchSetsAction(
info.legacy_id(), revision,
style, headerLine, patchSets);
+
+ RevisionInfo revInfo = info.revision(revision);
+ if (revInfo.draft()) {
+ NativeMap<ActionInfo> actions = revInfo.has_actions()
+ ? revInfo.actions()
+ : NativeMap.<ActionInfo> create();
+ actions.copyKeysIntoChildren("id");
+
+ if (actions.containsKey("publish")) {
+ publish.setVisible(true);
+ publish.setTitle(actions.get("publish").title());
+ }
+ if (actions.containsKey("/")) {
+ deleteRevision.setVisible(true);
+ deleteRevision.setTitle(actions.get("/").title());
+ }
+ }
}
private void initDownloadAction(ChangeInfo info, String revision) {
@@ -444,14 +486,23 @@
editMode.setVisible(fileTableMode == FileTable.Mode.REVIEW);
addFile.setVisible(!editMode.isVisible());
reviewMode.setVisible(!editMode.isVisible());
- editFileAction = new EditFileAction(
- new PatchSet.Id(changeId, edit == null ? rev._number() : 0),
- "", "", style, editMessage, reply);
+ addFileAction = new AddFileAction(
+ changeId, info.revision(revision),
+ style, addFile);
} else {
editMode.setVisible(false);
addFile.setVisible(false);
reviewMode.setVisible(false);
}
+
+ if (rev.is_edit()) {
+ if (isEditBasedOnCurrentPatchSet(info)) {
+ publishEdit.setVisible(true);
+ } else {
+ rebaseEdit.setVisible(true);
+ }
+ deleteEdit.setVisible(true);
+ }
}
}
@@ -466,6 +517,13 @@
info.revisions().values());
}
+ private boolean isEditBasedOnCurrentPatchSet(ChangeInfo info) {
+ JsArray<RevisionInfo> revList = info.revisions().values();
+ RevisionInfo.sortRevisionInfoByNumber(revList);
+ int currentPatchSetOrEdit = revList.get(revList.length() - 1)._number();
+ return currentPatchSetOrEdit == 0;
+ }
+
private void initEditMessageAction(ChangeInfo info, String revision) {
RevisionInfo revisionInfo = info.revision(revision);
NativeMap<ActionInfo> actions = revisionInfo.actions();
@@ -487,6 +545,42 @@
}
}
+ @UiHandler("publishEdit")
+ void onPublishEdit(@SuppressWarnings("unused") ClickEvent e) {
+ EditActions.publishEdit(changeId);
+ }
+
+ @UiHandler("rebaseEdit")
+ void onRebaseEdit(@SuppressWarnings("unused") ClickEvent e) {
+ EditActions.rebaseEdit(changeId);
+ }
+
+ @UiHandler("deleteEdit")
+ void onDeleteEdit(@SuppressWarnings("unused") ClickEvent e) {
+ if (Window.confirm(Resources.C.deleteChangeEdit())) {
+ EditActions.deleteEdit(changeId);
+ }
+ }
+
+ @UiHandler("publish")
+ void onPublish(@SuppressWarnings("unused") ClickEvent e) {
+ DraftActions.publish(changeId, revision);
+ }
+
+ @UiHandler("deleteRevision")
+ void onDeleteRevision(@SuppressWarnings("unused") ClickEvent e) {
+ if (Window.confirm(Resources.C.deleteDraftRevision())) {
+ DraftActions.delete(changeId, revision);
+ }
+ }
+
+ @UiHandler("deleteChange")
+ void onDeleteChange(@SuppressWarnings("unused") ClickEvent e) {
+ if (Window.confirm(Resources.C.deleteDraftChange())) {
+ DraftActions.delete(changeId);
+ }
+ }
+
@Override
public void registerKeys() {
super.registerKeys();
@@ -621,7 +715,7 @@
@UiHandler("addFile")
void onAddFile(@SuppressWarnings("unused") ClickEvent e) {
- editFileAction.onEdit();
+ addFileAction.onEdit();
}
private void refreshFileTable() {
@@ -975,7 +1069,9 @@
renderOwner(info);
renderActionTextDate(info);
renderDiffBaseListBox(info);
+ initReplyButton(info, revision);
initIncludedInAction(info);
+ initChangeAction(info);
initRevisionsAction(info, revision);
initDownloadAction(info, revision);
initProjectLinks(info);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
index 85c93a1..cecf5b3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
@@ -272,10 +272,10 @@
height: BUTTON_HEIGHT;
line-height: BUTTON_HEIGHT;
}
- button.quickApprove {
+ button.highlight {
background-color: #4d90fe;
}
- button.quickApprove div { color: #fff; }
+ button.highlight div { color: #fff; }
.sectionHeader {
position: relative;
@@ -355,14 +355,36 @@
<div class='{style.headerButtons} {style.infoLineHeaderButtons}'>
<g:Button ui:field='reply'
styleName=''
- title=''>
+ title=''
+ visible='false'>
<ui:attribute name='title'/>
</g:Button>
<c:QuickApprove ui:field='quickApprove'
- styleName='{style.quickApprove}'
+ styleName='{style.highlight}'
title='Apply score with one click'>
<ui:attribute name='title'/>
</c:QuickApprove>
+ <g:Button ui:field='publishEdit'
+ styleName='{style.highlight}' visible='false'>
+ <div><ui:msg>Publish Edit</ui:msg></div>
+ </g:Button>
+ <g:Button ui:field='rebaseEdit'
+ styleName='{style.highlight}' visible='false'>
+ <div><ui:msg>Rebase Edit</ui:msg></div>
+ </g:Button>
+ <g:Button ui:field='deleteEdit' styleName='' visible='false'>
+ <div><ui:msg>Delete Edit</ui:msg></div>
+ </g:Button>
+ <g:Button ui:field='publish'
+ styleName='{style.highlight}' visible='false'>
+ <div><ui:msg>Publish</ui:msg></div>
+ </g:Button>
+ <g:Button ui:field='deleteChange' styleName='' visible='false'>
+ <div><ui:msg>Delete Change</ui:msg></div>
+ </g:Button>
+ <g:Button ui:field='deleteRevision' styleName='' visible='false'>
+ <div><ui:msg>Delete Revision</ui:msg></div>
+ </g:Button>
</div>
</div>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditFileAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditFileAction.java
deleted file mode 100644
index 951c84d..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditFileAction.java
+++ /dev/null
@@ -1,80 +0,0 @@
-//Copyright (C) 2013 The Android Open Source Project
-//
-//Licensed under the Apache License, Version 2.0 (the "License");
-//you may not use this file except in compliance with the License.
-//You may obtain a copy of the License at
-//
-//http://www.apache.org/licenses/LICENSE-2.0
-//
-//Unless required by applicable law or agreed to in writing, software
-//distributed under the License is distributed on an "AS IS" BASIS,
-//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//See the License for the specific language governing permissions and
-//limitations under the License.
-
-package com.google.gerrit.client.change;
-
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.event.logical.shared.CloseEvent;
-import com.google.gwt.event.logical.shared.CloseHandler;
-import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtexpui.globalkey.client.GlobalKey;
-import com.google.gwtexpui.user.client.PluginSafePopupPanel;
-
-class EditFileAction {
- private final PatchSet.Id id;
- private final String content;
- private final String file;
- private final ChangeScreen2.Style style;
- private final Widget editMessageButton;
- private final Widget relativeTo;
-
- private EditFileBox editBox;
- private PopupPanel popup;
-
- EditFileAction(
- PatchSet.Id id,
- String content,
- String file,
- ChangeScreen2.Style style,
- Widget editButton,
- Widget relativeTo) {
- this.id = id;
- this.content = content;
- this.file = file;
- this.style = style;
- this.editMessageButton = editButton;
- this.relativeTo = relativeTo;
- }
-
- public void onEdit() {
- if (popup != null) {
- popup.hide();
- return;
- }
-
- if (editBox == null) {
- editBox = new EditFileBox(
- id,
- content,
- file);
- }
-
- final PluginSafePopupPanel p = new PluginSafePopupPanel(true);
- p.setStyleName(style.replyBox());
- p.addAutoHidePartner(editMessageButton.getElement());
- p.addCloseHandler(new CloseHandler<PopupPanel>() {
- @Override
- public void onClose(CloseEvent<PopupPanel> event) {
- if (popup == p) {
- popup = null;
- }
- }
- });
- p.add(editBox);
- p.showRelativeTo(relativeTo);
- GlobalKey.dialog(p);
- popup = p;
- }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditFileBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditFileBox.java
deleted file mode 100644
index 67f9265..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditFileBox.java
+++ /dev/null
@@ -1,119 +0,0 @@
-//Copyright (C) 2013 The Android Open Source Project
-//
-//Licensed under the Apache License, Version 2.0 (the "License");
-//you may not use this file except in compliance with the License.
-//You may obtain a copy of the License at
-//
-//http://www.apache.org/licenses/LICENSE-2.0
-//
-//Unless required by applicable law or agreed to in writing, software
-//distributed under the License is distributed on an "AS IS" BASIS,
-//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//See the License for the specific language governing permissions and
-//limitations under the License.
-
-package com.google.gerrit.client.change;
-
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.VoidResult;
-import com.google.gerrit.client.changes.ChangeFileApi;
-import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.ui.TextBoxChangeListener;
-import com.google.gerrit.common.PageLinks;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.uibinder.client.UiBinder;
-import com.google.gwt.uibinder.client.UiField;
-import com.google.gwt.uibinder.client.UiHandler;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HTMLPanel;
-import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.TextBoxBase;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtexpui.globalkey.client.NpTextArea;
-
-class EditFileBox extends Composite {
- interface Binder extends UiBinder<HTMLPanel, EditFileBox> {}
- private static final Binder uiBinder = GWT.create(Binder.class);
-
- private final PatchSet.Id id;
- private final String fileName;
- private final String fileContent;
-
- @UiField FileTextBox file;
- @UiField NpTextArea content;
- @UiField Button save;
- @UiField Button cancel;
-
- EditFileBox(
- PatchSet.Id id,
- String fileC,
- String fileName) {
- this.id = id;
- this.fileName = fileName;
- this.fileContent = fileC;
- initWidget(uiBinder.createAndBindUi(this));
- new EditFileBoxListener(content);
- new EditFileBoxListener(file);
- }
-
- @Override
- protected void onLoad() {
- file.set(id, content);
- file.setText(fileName);
- file.setEnabled(fileName.isEmpty());
- content.setText(fileContent);
- save.setEnabled(false);
- Scheduler.get().scheduleDeferred(new ScheduledCommand() {
- @Override
- public void execute() {
- if (fileName.isEmpty()) {
- file.setFocus(true);
- } else {
- content.setFocus(true);
- }
- }});
- }
-
- @UiHandler("save")
- void onSave(@SuppressWarnings("unused") ClickEvent e) {
- ChangeFileApi.putContent(id, file.getText(), content.getText(),
- new GerritCallback<VoidResult>() {
- @Override
- public void onSuccess(VoidResult result) {
- Gerrit.display(PageLinks.toChangeInEditMode(id.getParentKey()));
- hide();
- }
- });
- }
-
- @UiHandler("cancel")
- void onCancel(@SuppressWarnings("unused") ClickEvent e) {
- hide();
- }
-
- protected void hide() {
- for (Widget w = getParent(); w != null; w = w.getParent()) {
- if (w instanceof PopupPanel) {
- ((PopupPanel) w).hide();
- break;
- }
- }
- }
-
- private class EditFileBoxListener extends TextBoxChangeListener {
- public EditFileBoxListener(TextBoxBase base) {
- super(base);
- }
-
- @Override
- public void onTextChanged(String newText) {
- save.setEnabled(!file.getText().trim().isEmpty()
- && !newText.trim().equals(fileContent));
- }
- }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java
index 74600ab..317e9ac 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java
@@ -16,7 +16,7 @@
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.VoidResult;
-import com.google.gerrit.client.changes.ChangeFileApi;
+import com.google.gerrit.client.changes.ChangeEditApi;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.ui.TextBoxChangeListener;
import com.google.gerrit.common.PageLinks;
@@ -79,7 +79,7 @@
@UiHandler("save")
void onSave(@SuppressWarnings("unused") ClickEvent e) {
save.setEnabled(false);
- ChangeFileApi.putMessage(changeId, message.getText().trim(),
+ ChangeEditApi.putMessage(changeId.get(), message.getText().trim(),
new GerritCallback<VoidResult>() {
@Override
public void onSuccess(VoidResult result) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
index 429dd55..c0fe3e0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
@@ -18,7 +18,7 @@
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.VoidResult;
import com.google.gerrit.client.changes.ChangeApi;
-import com.google.gerrit.client.changes.ChangeFileApi;
+import com.google.gerrit.client.changes.ChangeEditApi;
import com.google.gerrit.client.changes.CommentInfo;
import com.google.gerrit.client.changes.ReviewInfo;
import com.google.gerrit.client.changes.Util;
@@ -317,7 +317,7 @@
void onDelete(int idx) {
String path = list.get(idx).path();
- ChangeFileApi.deleteContent(curr, path,
+ ChangeEditApi.delete(curr.getParentKey().get(), path,
new AsyncCallback<VoidResult>() {
@Override
public void onSuccess(VoidResult result) {
@@ -333,7 +333,7 @@
void onRestore(int idx) {
String path = list.get(idx).path();
- ChangeFileApi.restoreContent(curr, path,
+ ChangeEditApi.restore(curr.getParentKey().get(), path,
new AsyncCallback<VoidResult>() {
@Override
public void onSuccess(VoidResult result) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTextBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTextBox.java
deleted file mode 100644
index 52d2a25..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTextBox.java
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.change;
-
-import com.google.gerrit.client.changes.ChangeFileApi;
-import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.rpc.RestApi;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.event.dom.client.BlurEvent;
-import com.google.gwt.event.dom.client.BlurHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwtexpui.globalkey.client.NpTextArea;
-import com.google.gwtexpui.globalkey.client.NpTextBox;
-
-class FileTextBox extends NpTextBox {
- private HandlerRegistration blurHandler;
- private NpTextArea textArea;
- private PatchSet.Id id;
-
- @Override
- protected void onLoad() {
- blurHandler = addBlurHandler(new BlurHandler() {
- @Override
- public void onBlur(BlurEvent event) {
- loadFileContent();
- }
- });
- }
-
- @Override
- protected void onUnload() {
- super.onUnload();
- blurHandler.removeHandler();
- }
-
- void set(PatchSet.Id id, NpTextArea content) {
- this.id = id;
- this.textArea = content;
- }
-
- private void loadFileContent() {
- ChangeFileApi.getContent(id, getText(), new GerritCallback<String>() {
- @Override
- public void onSuccess(String result) {
- textArea.setText(result);
- }
-
- @Override
- public void onFailure(Throwable caught) {
- if (RestApi.isNotFound(caught)) {
- // that means that the file doesn't exist in the repository
- } else {
- super.onFailure(caught);
- }
- }
- });
- }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java
index 6e86730..6638dbe 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java
@@ -46,6 +46,10 @@
setVisible(false);
return;
}
+ if (info.revision(commit).is_edit() || info.revision(commit).draft()) {
+ setVisible(false);
+ return;
+ }
String qName = null;
String qValueStr = null;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/common.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/common.css
index 612ffed..bb7cb27 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/common.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/common.css
@@ -29,7 +29,7 @@
.popup button,
.popup input[type='button'] {
margin: 0 3px 0 0;
- border-color: rgba(0, 0, 0, 0.1);
+ border-color: rgba(0, 0, 0, 0.15) !important;
text-align: center;
font-size: 11px;
font-weight: bold;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeEditApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeEditApi.java
new file mode 100644
index 0000000..ca5d434
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeEditApi.java
@@ -0,0 +1,90 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.client.changes;
+
+import com.google.gerrit.client.VoidResult;
+import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gerrit.client.rpc.HttpCallback;
+import com.google.gerrit.client.rpc.NativeString;
+import com.google.gerrit.client.rpc.RestApi;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+/** REST API helpers to remotely edit a change. */
+public class ChangeEditApi {
+ /** Get file (or commit message) contents. */
+ public static void get(PatchSet.Id id, String path,
+ HttpCallback<NativeString> cb) {
+ RestApi api;
+ if (id.get() != 0) {
+ // Read from a published revision, when change edit doesn't
+ // exist for the caller, or is not currently active.
+ api = ChangeApi.revision(id).view("files").id(path).view("content");
+ } else if (Patch.COMMIT_MSG.equals(path)) {
+ api = editMessage(id.getParentKey().get());
+ } else {
+ api = editFile(id.getParentKey().get(), path);
+ }
+ api.get(cb);
+ }
+
+ /** Put message into a change edit. */
+ public static void putMessage(int id, String m, GerritCallback<VoidResult> cb) {
+ editMessage(id).put(m, cb);
+ }
+
+ /** Put contents into a file or commit message in a change edit. */
+ public static void put(int id, String path, String content,
+ GerritCallback<VoidResult> cb) {
+ if (Patch.COMMIT_MSG.equals(path)) {
+ putMessage(id, content, cb);
+ } else {
+ editFile(id, path).put(content, cb);
+ }
+ }
+
+ /** Delete a file in the pending edit. */
+ public static void delete(int id, String path, AsyncCallback<VoidResult> cb) {
+ editFile(id, path).delete(cb);
+ }
+
+ /** Restore (undo delete/modify) a file in the pending edit. */
+ public static void restore(int id, String path, AsyncCallback<VoidResult> cb) {
+ Input in = Input.create();
+ in.restore_path(path);
+ ChangeApi.edit(id).post(in, cb);
+ }
+
+ private static RestApi editMessage(int id) {
+ return ChangeApi.change(id).view("edit:message");
+ }
+
+ private static RestApi editFile(int id, String path) {
+ return ChangeApi.edit(id).id(path);
+ }
+
+ private static class Input extends JavaScriptObject {
+ static Input create() {
+ return createObject().cast();
+ }
+
+ final native void restore_path(String p) /*-{ this.restore_path=p }-*/;
+
+ protected Input() {
+ }
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeFileApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeFileApi.java
deleted file mode 100644
index c25f0cf..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeFileApi.java
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.changes;
-
-import com.google.gerrit.client.VoidResult;
-import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.rpc.NativeString;
-import com.google.gerrit.client.rpc.RestApi;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-
-/**
- * A collection of static methods which work on the Gerrit REST API for specific
- * files in a change.
- */
-public class ChangeFileApi {
- static abstract class CallbackWrapper<I, O> implements AsyncCallback<I> {
- protected AsyncCallback<O> wrapped;
-
- public CallbackWrapper(AsyncCallback<O> callback) {
- wrapped = callback;
- }
-
- @Override
- public abstract void onSuccess(I result);
-
- @Override
- public void onFailure(Throwable caught) {
- wrapped.onFailure(caught);
- }
- }
-
- private static CallbackWrapper<NativeString, String> wrapper(
- AsyncCallback<String> cb) {
- return new CallbackWrapper<NativeString, String>(cb) {
- @Override
- public void onSuccess(NativeString b64) {
- if (b64 != null) {
- wrapped.onSuccess(b64decode(b64.asString()));
- }
- }
- };
- }
-
- /** Get the contents of a File in a PatchSet or change edit. */
- public static void getContent(PatchSet.Id id, String filename,
- AsyncCallback<String> cb) {
- contentEditOrPs(id, filename).get(wrapper(cb));
- }
-
- /** Get the content type of a File in a PatchSet or change edit. */
- public static void getContentType(PatchSet.Id id, String filename,
- AsyncCallback<String> cb) {
- contentTypeEditOrPs(id, filename).get(
- new CallbackWrapper<NativeString, String>(cb) {
- @Override
- public void onSuccess(NativeString str) {
- if (str != null) {
- wrapped.onSuccess(str.asString());
- }
- }
- });
- }
-
- /**
- * Get the contents of a file or commit message in a PatchSet or change
- * edit.
- **/
- public static void getContentOrMessage(PatchSet.Id id, String path,
- AsyncCallback<String> cb) {
- RestApi api = (Patch.COMMIT_MSG.equals(path) && id.get() == 0)
- ? messageEdit(id)
- : contentEditOrPs(id, path);
- api.get(wrapper(cb));
- }
-
- /** Put contents into a File in a change edit. */
- public static void putContent(PatchSet.Id id, String filename,
- String content, GerritCallback<VoidResult> result) {
- contentEdit(id.getParentKey(), filename).put(content, result);
- }
-
- /** Put contents into a File or commit message in a change edit. */
- public static void putContentOrMessage(PatchSet.Id id, String path,
- String content, GerritCallback<VoidResult> result) {
- if (Patch.COMMIT_MSG.equals(path)) {
- putMessage(id, content, result);
- } else {
- contentEdit(id.getParentKey(), path).put(content, result);
- }
- }
-
- /** Put message into a change edit. */
- private static void putMessage(PatchSet.Id id, String m,
- GerritCallback<VoidResult> r) {
- putMessage(id.getParentKey(), m, r);
- }
-
- /** Put message into a change edit. */
- public static void putMessage(Change.Id id, String m,
- GerritCallback<VoidResult> r) {
- ChangeApi.change(id.get()).view("edit:message").put(m, r);
- }
-
- /** Restore contents of a File in a change edit. */
- public static void restoreContent(PatchSet.Id id, String filename,
- AsyncCallback<VoidResult> result) {
- Input in = Input.create();
- in.restore_path(filename);
- ChangeApi.edit(id.getParentKey().get()).post(in, result);
- }
-
- /** Delete a file from a change edit. */
- public static void deleteContent(PatchSet.Id id, String filename,
- AsyncCallback<VoidResult> result) {
- contentEdit(id.getParentKey(), filename).delete(result);
- }
-
- private static RestApi contentEditOrPs(PatchSet.Id id, String filename) {
- return id.get() == 0
- ? contentEdit(id.getParentKey(), filename)
- : ChangeApi.revision(id).view("files").id(filename).view("content");
- }
-
- private static RestApi messageEdit(PatchSet.Id id) {
- return ChangeApi.change(id.getParentKey().get()).view("edit:message");
- }
-
- private static RestApi contentTypeEditOrPs(PatchSet.Id id, String filename) {
- return id.get() == 0
- ? contentEdit(id.getParentKey(), filename).view("type")
- : ChangeApi.revision(id).view("files").id(filename).view("type");
- }
-
- private static RestApi contentEdit(Change.Id id, String filename) {
- return ChangeApi.edit(id.get()).id(filename);
- }
-
- private static native String b64decode(String a) /*-{ return window.atob(a); }-*/;
-
- private static class Input extends JavaScriptObject {
- final native void restore_path(String p) /*-{ if(p)this.restore_path=p; }-*/;
-
- static Input create() {
- return (Input) createObject();
- }
-
- protected Input() {
- }
- }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java
index 5f5cf8f..a4f3145 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java
@@ -122,8 +122,7 @@
}
table.setText(R_SUBMIT_TYPE, 1, submitType);
final Change.Status status = chg.getStatus();
- if (Gerrit.getConfig().getNewFeatures()
- && (status.equals(Change.Status.NEW) || status.equals(Change.Status.DRAFT))) {
+ if (status.equals(Change.Status.NEW) || status.equals(Change.Status.DRAFT)) {
table.getRowFormatter().setVisible(R_MERGE_TEST, true);
table.setText(R_MERGE_TEST, 1, changeDetail.isMergeable() ? Util.C
.changeInfoBlockCanMergeYes() : Util.C.changeInfoBlockCanMergeNo());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable2.java
index ca7157a..4c37a28 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable2.java
@@ -59,19 +59,21 @@
private static final int C_SIZE = 9;
private static final int BASE_COLUMNS = 10;
-
- private final boolean useNewFeatures = Gerrit.getConfig().getNewFeatures();
private final List<Section> sections;
private int columns;
+ private boolean showLegacyId;
private List<String> labelNames;
public ChangeTable2() {
super(Util.C.changeItemHelp());
- columns = useNewFeatures ? BASE_COLUMNS : BASE_COLUMNS - 1;
+ columns = BASE_COLUMNS;
labelNames = Collections.emptyList();
if (Gerrit.isSignedIn()) {
keysAction.add(new StarKeyCommand(0, 's', Util.C.changeTableStar()));
+ showLegacyId = Gerrit.getUserAccount()
+ .getGeneralPreferences()
+ .isLegacycidInChangeTable();
}
sections = new ArrayList<>();
@@ -83,19 +85,14 @@
table.setText(0, C_PROJECT, Util.C.changeTableColumnProject());
table.setText(0, C_BRANCH, Util.C.changeTableColumnBranch());
table.setText(0, C_LAST_UPDATE, Util.C.changeTableColumnLastUpdate());
- if (useNewFeatures) {
- table.setText(0, C_SIZE, Util.C.changeTableColumnSize());
- }
+ table.setText(0, C_SIZE, Util.C.changeTableColumnSize());
final FlexCellFormatter fmt = table.getFlexCellFormatter();
fmt.addStyleName(0, C_STAR, Gerrit.RESOURCES.css().iconHeader());
for (int i = C_ID; i < columns; i++) {
fmt.addStyleName(0, i, Gerrit.RESOURCES.css().dataHeader());
}
-
- if (!Gerrit.isSignedIn() ||
- (!Gerrit.getUserAccount().getGeneralPreferences()
- .isLegacycidInChangeTable())) {
+ if (!showLegacyId) {
fmt.addStyleName(0, C_ID, Gerrit.RESOURCES.css().dataHeaderHidden());
}
@@ -152,22 +149,16 @@
for (int i = C_ID; i < columns; i++) {
fmt.addStyleName(row, i, Gerrit.RESOURCES.css().dataCell());
}
+ if (!showLegacyId) {
+ fmt.addStyleName(row, C_ID, Gerrit.RESOURCES.css().dataCellHidden());
+ }
fmt.addStyleName(row, C_SUBJECT, Gerrit.RESOURCES.css().cSUBJECT());
fmt.addStyleName(row, C_STATUS, Gerrit.RESOURCES.css().cSTATUS());
fmt.addStyleName(row, C_OWNER, Gerrit.RESOURCES.css().cOWNER());
fmt.addStyleName(row, C_LAST_UPDATE, Gerrit.RESOURCES.css().cLastUpdate());
+ fmt.addStyleName(row, C_SIZE, Gerrit.RESOURCES.css().cSIZE());
- if (!Gerrit.isSignedIn() ||
- (!Gerrit.getUserAccount().getGeneralPreferences()
- .isLegacycidInChangeTable())) {
- fmt.addStyleName(row, C_ID, Gerrit.RESOURCES.css().dataCellHidden());
- }
-
- int i = C_SIZE;
- if (useNewFeatures) {
- fmt.addStyleName(row, i++, Gerrit.RESOURCES.css().cSIZE());
- }
- for (; i < columns; i++) {
+ for (int i = C_SIZE + 1; i < columns; i++) {
fmt.addStyleName(row, i, Gerrit.RESOURCES.css().cAPPROVAL());
}
}
@@ -185,7 +176,7 @@
}
Collections.sort(labelNames);
- int baseColumns = useNewFeatures ? BASE_COLUMNS : BASE_COLUMNS - 1;
+ int baseColumns = BASE_COLUMNS;
if (baseColumns + labelNames.size() < columns) {
int n = columns - (baseColumns + labelNames.size());
for (int row = 0; row < table.getRowCount(); row++) {
@@ -228,7 +219,7 @@
Change.Status status = c.status();
if (status != Change.Status.NEW) {
table.setText(row, C_STATUS, Util.toLongString(status));
- } else if (!c.mergeable() && useNewFeatures) {
+ } else if (!c.mergeable()) {
table.setText(row, C_STATUS, Util.C.changeTableNotMergeable());
}
@@ -248,20 +239,19 @@
} else {
table.setText(row, C_LAST_UPDATE, shortFormat(c.updated()));
}
+
int col = C_SIZE;
- if (useNewFeatures) {
- if (Gerrit.isSignedIn()
- && !Gerrit.getUserAccount().getGeneralPreferences()
- .isSizeBarInChangeTable()) {
- table.setText(row, col,
- Util.M.insertionsAndDeletions(c.insertions(), c.deletions()));
- } else {
- table.setWidget(row, col, getSizeWidget(c));
- fmt.getElement(row, col).setTitle(
- Util.M.insertionsAndDeletions(c.insertions(), c.deletions()));
- }
- col++;
+ if (Gerrit.isSignedIn()
+ && !Gerrit.getUserAccount().getGeneralPreferences()
+ .isSizeBarInChangeTable()) {
+ table.setText(row, col,
+ Util.M.insertionsAndDeletions(c.insertions(), c.deletions()));
+ } else {
+ table.setWidget(row, col, getSizeWidget(c));
+ fmt.getElement(row, col).setTitle(
+ Util.M.insertionsAndDeletions(c.insertions(), c.deletions()));
}
+ col++;
boolean displayInfo = Gerrit.isSignedIn() && Gerrit.getUserAccount()
.getGeneralPreferences().isShowInfoInReviewCategory();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
index 887978f..c829976 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
@@ -341,14 +341,13 @@
@Override
public void run() {
if (cm.extras().hasActiveLine()) {
- newDraft(cm);
+ newDraft(cm, cm.getLineNumber(cm.extras().activeLine()) + 1);
}
}
};
}
- private void newDraft(CodeMirror cm) {
- int line = cm.getLineNumber(cm.extras().activeLine()) + 1;
+ void newDraft(CodeMirror cm, int line) {
if (cm.somethingSelected()) {
FromTo fromTo = cm.getSelectedRange();
Pos end = fromTo.to();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java
index 1fe85b3..b23a8cf 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java
@@ -18,11 +18,11 @@
import com.google.gerrit.client.changes.CommentApi;
import com.google.gerrit.client.changes.CommentInfo;
import com.google.gerrit.client.rpc.CallbackGroup;
-import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.JsArray;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import java.util.Collections;
import java.util.Comparator;
@@ -53,39 +53,55 @@
}
}
- private GerritCallback<NativeMap<JsArray<CommentInfo>>> publishedBase() {
- return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
+ private AsyncCallback<NativeMap<JsArray<CommentInfo>>> publishedBase() {
+ return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
@Override
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
publishedBase = sort(result.get(path));
}
+
+ @Override
+ public void onFailure(Throwable caught) {
+ }
};
}
- private GerritCallback<NativeMap<JsArray<CommentInfo>>> publishedRevision() {
- return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
+ private AsyncCallback<NativeMap<JsArray<CommentInfo>>> publishedRevision() {
+ return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
@Override
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
publishedRevision = sort(result.get(path));
}
- };
- }
- private GerritCallback<NativeMap<JsArray<CommentInfo>>> draftsBase() {
- return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
@Override
- public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
- draftsBase = sort(result.get(path));
+ public void onFailure(Throwable caught) {
}
};
}
- private GerritCallback<NativeMap<JsArray<CommentInfo>>> draftsRevision() {
- return new GerritCallback<NativeMap<JsArray<CommentInfo>>>() {
+ private AsyncCallback<NativeMap<JsArray<CommentInfo>>> draftsBase() {
+ return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
+ @Override
+ public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
+ draftsBase = sort(result.get(path));
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ }
+ };
+ }
+
+ private AsyncCallback<NativeMap<JsArray<CommentInfo>>> draftsRevision() {
+ return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
@Override
public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
draftsRevision = sort(result.get(path));
}
+
+ @Override
+ public void onFailure(Throwable caught) {
+ }
};
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
index 4eec4ba..70bde00 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
@@ -32,6 +32,7 @@
import com.google.gerrit.extensions.common.Theme;
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
+import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.Patch.ChangeType;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
@@ -147,7 +148,13 @@
setIgnoreWhitespace(prefs.ignoreWhitespace());
tabWidth.setIntValue(prefs.tabSize());
- lineLength.setIntValue(prefs.lineLength());
+ if (Patch.COMMIT_MSG.equals(view.getPath())) {
+ lineLength.setEnabled(false);
+ lineLength.setIntValue(72);
+ } else {
+ lineLength.setEnabled(true);
+ lineLength.setIntValue(prefs.lineLength());
+ }
syntaxHighlighting.setValue(prefs.syntaxHighlighting());
whitespaceErrors.setValue(prefs.showWhitespaceErrors());
showTabs.setValue(prefs.showTabs());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
index 2f22cdd..62d2eac 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
@@ -73,6 +73,10 @@
color: #dddd00;
}
+ .box input.gwt-TextBox:disabled {
+ background-color: #cacaca;
+ }
+
.box .gwt-ToggleButton {
position: relative;
height: 19px;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
index 2675235..5195024 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
@@ -40,6 +40,7 @@
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.extensions.common.ListChangesOption;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArray;
@@ -167,26 +168,36 @@
protected void onLoad() {
super.onLoad();
- CallbackGroup cmGroup = new CallbackGroup();
- CodeMirror.initLibrary(cmGroup.<Void> addEmpty());
+ CallbackGroup group1 = new CallbackGroup();
+ final CallbackGroup group2 = new CallbackGroup();
- final CallbackGroup group = new CallbackGroup();
- final AsyncCallback<Void> themeCallback = group.addEmpty();
- final AsyncCallback<Void> modeInjectorCb = group.addEmpty();
+ CodeMirror.initLibrary(group1.add(new AsyncCallback<Void>() {
+ final AsyncCallback<Void> themeCallback = group2.addEmpty();
+
+ @Override
+ public void onSuccess(Void result) {
+ // Load theme after CM library to ensure theme can override CSS.
+ ThemeLoader.loadTheme(prefs.theme(), themeCallback);
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ }
+ }));
DiffApi.diff(revision, path)
.base(base)
.wholeFile()
.intraline(prefs.intralineDifference())
.ignoreWhitespace(prefs.ignoreWhitespace())
- .get(cmGroup.addFinal(new GerritCallback<DiffInfo>() {
+ .get(group1.addFinal(new GerritCallback<DiffInfo>() {
+ final AsyncCallback<Void> modeInjectorCb = group2.addEmpty();
+
@Override
public void onSuccess(DiffInfo diffInfo) {
diff = diffInfo;
fileSize = bucketFileSize(diffInfo);
- // Load theme after CM library to ensure theme can override CSS.
- ThemeLoader.loadTheme(prefs.theme(), themeCallback);
if (prefs.syntaxHighlighting()) {
if (fileSize.compareTo(FileSize.SMALL) > 0) {
modeInjectorCb.onSuccess(null);
@@ -200,22 +211,26 @@
}));
if (Gerrit.isSignedIn()) {
- ChangeApi.edit(changeId.get(), group.add(
- new GerritCallback<EditInfo>() {
+ ChangeApi.edit(changeId.get(), group2.add(
+ new AsyncCallback<EditInfo>() {
@Override
public void onSuccess(EditInfo result) {
edit = result;
}
+
+ @Override
+ public void onFailure(Throwable caught) {
+ }
}));
}
final CommentsCollections comments = new CommentsCollections();
- comments.load(base, revision, path, group);
+ comments.load(base, revision, path, group2);
RestApi call = ChangeApi.detail(changeId.get());
ChangeList.addOptions(call, EnumSet.of(
ListChangesOption.ALL_REVISIONS));
- call.get(group.add(new GerritCallback<ChangeInfo>() {
+ call.get(group2.add(new AsyncCallback<ChangeInfo>() {
@Override
public void onSuccess(ChangeInfo info) {
info.revisions().copyKeysIntoChildren("name");
@@ -230,9 +245,14 @@
diffTable.set(prefs, list, diff, edit != null, currentPatchSet,
info.status().isOpen());
header.setChangeInfo(info);
- }}));
+ }
- ConfigInfoCache.get(changeId, group.addFinal(
+ @Override
+ public void onFailure(Throwable caught) {
+ }
+ }));
+
+ ConfigInfoCache.get(changeId, group2.addFinal(
new ScreenLoadCallback<ConfigInfoCache.Entry>(SideBySide2.this) {
@Override
protected void preDisplay(ConfigInfoCache.Entry result) {
@@ -270,7 +290,7 @@
cmB.refresh();
}
});
- setLineLength(prefs.lineLength());
+ setLineLength(Patch.COMMIT_MSG.equals(path) ? 72 : prefs.lineLength());
diffTable.refresh();
if (startLine == 0) {
@@ -797,21 +817,18 @@
private GutterClickHandler onGutterClick(final CodeMirror cm) {
return new GutterClickHandler() {
@Override
- public void handle(CodeMirror instance, int line, String gutter,
+ public void handle(CodeMirror instance, final int line, String gutter,
NativeEvent clickEvent) {
if (clickEvent.getButton() == NativeEvent.BUTTON_LEFT
&& !clickEvent.getMetaKey()
&& !clickEvent.getAltKey()
&& !clickEvent.getCtrlKey()
&& !clickEvent.getShiftKey()) {
- if (!(cm.extras().hasActiveLine() &&
- cm.getLineNumber(cm.extras().activeLine()) == line)) {
- cm.setCursor(Pos.create(line));
- }
+ cm.setCursor(Pos.create(line));
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
- commentManager.insertNewDraft(cm).run();
+ commentManager.newDraft(cm, line + 1);
}
});
}
@@ -931,6 +948,10 @@
.inject(cb);
}
+ String getPath() {
+ return path;
+ }
+
DiffPreferences getPrefs() {
return prefs;
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
index 70855ce..6566ee4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
@@ -14,17 +14,24 @@
package com.google.gerrit.client.editor;
+import static com.google.gwt.dom.client.Style.Visibility.HIDDEN;
+import static com.google.gwt.dom.client.Style.Visibility.VISIBLE;
+
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.JumpKeys;
import com.google.gerrit.client.VoidResult;
import com.google.gerrit.client.account.DiffPreferences;
import com.google.gerrit.client.changes.ChangeApi;
-import com.google.gerrit.client.changes.ChangeFileApi;
+import com.google.gerrit.client.changes.ChangeEditApi;
import com.google.gerrit.client.changes.ChangeInfo;
import com.google.gerrit.client.diff.FileInfo;
import com.google.gerrit.client.diff.Header;
import com.google.gerrit.client.rpc.CallbackGroup;
import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gerrit.client.rpc.HttpCallback;
+import com.google.gerrit.client.rpc.HttpResponse;
+import com.google.gerrit.client.rpc.NativeString;
+import com.google.gerrit.client.rpc.RestApi;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.PageLinks;
@@ -68,11 +75,14 @@
private final String path;
private DiffPreferences prefs;
private CodeMirror cm;
- private String type;
+ private HttpResponse<NativeString> content;
@UiField Element header;
@UiField Element project;
@UiField Element filePath;
+ @UiField Element cursLine;
+ @UiField Element cursCol;
+ @UiField Element dirty;
@UiField Button close;
@UiField Button save;
@UiField Element editor;
@@ -100,10 +110,12 @@
protected void onLoad() {
super.onLoad();
- CallbackGroup cmGroup = new CallbackGroup();
- final CallbackGroup group = new CallbackGroup();
- CodeMirror.initLibrary(cmGroup.add(new AsyncCallback<Void>() {
- final AsyncCallback<Void> themeCallback = group.addEmpty();
+ CallbackGroup group1 = new CallbackGroup();
+ CallbackGroup group2 = new CallbackGroup();
+ final CallbackGroup group3 = new CallbackGroup();
+
+ CodeMirror.initLibrary(group1.add(new AsyncCallback<Void>() {
+ final AsyncCallback<Void> themeCallback = group3.addEmpty();
@Override
public void onSuccess(Void result) {
@@ -116,36 +128,55 @@
}
}));
- if (prefs.syntaxHighlighting() && !Patch.COMMIT_MSG.equals(path)) {
- final AsyncCallback<Void> modeInjectorCb = group.addEmpty();
- ChangeFileApi.getContentType(revision, path,
- cmGroup.add(new GerritCallback<String>() {
- @Override
- public void onSuccess(String result) {
- ModeInfo mode = ModeInfo.findMode(result, path);
- type = mode != null ? mode.mime() : null;
- injectMode(result, modeInjectorCb);
- }
- }));
- }
- cmGroup.done();
-
ChangeApi.detail(revision.getParentKey().get(),
- group.add(new GerritCallback<ChangeInfo>() {
+ group1.add(new AsyncCallback<ChangeInfo>() {
@Override
public void onSuccess(ChangeInfo c) {
project.setInnerText(c.project());
SafeHtml.setInnerHTML(filePath, Header.formatPath(path, null, null));
}
- }));
- ChangeFileApi.getContentOrMessage(revision, path,
- group.addFinal(new ScreenLoadCallback<String>(this) {
@Override
- protected void preDisplay(String content) {
- initEditor(content);
+ public void onFailure(Throwable caught) {
}
}));
+
+ ChangeEditApi.get(revision, path,
+ group2.add(new HttpCallback<NativeString>() {
+ final AsyncCallback<Void> modeCallback = group3.addEmpty();
+
+ @Override
+ public void onSuccess(HttpResponse<NativeString> fc) {
+ content = fc;
+ if (prefs.syntaxHighlighting()) {
+ injectMode(fc.getContentType(), modeCallback);
+ } else {
+ modeCallback.onSuccess(null);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable e) {
+ // "Not Found" means it's a new file.
+ if (RestApi.isNotFound(e)) {
+ content = null;
+ modeCallback.onSuccess(null);
+ } else {
+ GerritCallback.showFailure(e);
+ }
+ }
+ }));
+
+ group3.addListener(new ScreenLoadCallback<Void>(this) {
+ @Override
+ protected void preDisplay(Void result) {
+ initEditor(content);
+ content = null;
+ }
+ });
+ group1.done();
+ group2.done();
+ group3.done();
}
@Override
@@ -172,18 +203,19 @@
});
generation = cm.changeGeneration(true);
- save.setEnabled(false);
+ setClean(true);
cm.on(new ChangesHandler() {
@Override
public void handle(CodeMirror cm) {
- save.setEnabled(!cm.isClean(generation));
+ setClean(cm.isClean(generation));
}
});
cm.adjustHeight(header.getOffsetHeight());
cm.on("cursorActivity", updateCursorPosition());
cm.extras().showTabs(prefs.showTabs());
- cm.extras().lineLength(prefs.lineLength());
+ cm.extras().lineLength(
+ Patch.COMMIT_MSG.equals(path) ? 72 : prefs.lineLength());
cm.refresh();
cm.focus();
updateActiveLine();
@@ -223,10 +255,15 @@
Gerrit.display(PageLinks.toChangeInEditMode(revision.getParentKey()));
}
- private void initEditor(String content) {
- ModeInfo mode = prefs.syntaxHighlighting()
- ? ModeInfo.findMode(type, path)
- : null;
+ private void initEditor(HttpResponse<NativeString> file) {
+ ModeInfo mode = null;
+ String content = "";
+ if (file != null) {
+ content = file.getResult().asString();
+ if (prefs.syntaxHighlighting()) {
+ mode = ModeInfo.findMode(file.getContentType(), path);
+ }
+ }
cm = CodeMirror.create(editor, Configuration.create()
.set("value", content)
.set("readOnly", false)
@@ -272,9 +309,16 @@
private void updateActiveLine() {
Pos p = cm.getCursor("end");
+ cursLine.setInnerText(Integer.toString(p.line() + 1));
+ cursCol.setInnerText(Integer.toString(p.ch() + 1));
cm.extras().activeLine(cm.getLineHandleVisualStart(p.line()));
}
+ private void setClean(boolean clean) {
+ save.setEnabled(!clean);
+ dirty.getStyle().setVisibility(!clean ? VISIBLE : HIDDEN);
+ }
+
private Runnable save() {
return new Runnable() {
@Override
@@ -282,12 +326,12 @@
if (!cm.isClean(generation)) {
String text = cm.getValue();
final int g = cm.changeGeneration(false);
- ChangeFileApi.putContentOrMessage(revision, path, text,
+ ChangeEditApi.put(revision.getParentKey().get(), path, text,
new GerritCallback<VoidResult>() {
@Override
public void onSuccess(VoidResult result) {
generation = g;
- save.setEnabled(!cm.isClean(g));
+ setClean(cm.isClean(g));
}
});
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml
index 50bd3bc..1fd44d2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.ui.xml
@@ -62,6 +62,34 @@
.path {
white-space: nowrap;
}
+
+ .statusLine {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 175px;
+ height: 19px;
+ background-color: #f7f7f7;
+ border-top: 1px solid #ddd;
+ border-right: 1px solid #ddd;
+ }
+ .statusLine div {
+ height: inherit;
+ }
+
+ .cursorPosition {
+ display: inline-block;
+ margin: 0 5px 0 35px;
+ white-space: nowrap;
+ }
+
+ .dirty {
+ display: inline-block;
+ margin: 0 5px 0 5px;
+ padding: 0 0 0 5px;
+ border-left: 1px solid #ddd;
+ font-weight: bold;
+ }
</ui:style>
<g:HTMLPanel>
<div class='{style.headerLine}' ui:field='header'>
@@ -82,5 +110,9 @@
<span class='{style.path}'><span ui:field='project'/> / <span ui:field='filePath'/></span>
</div>
<div ui:field='editor' />
+ <div class='{style.statusLine}'>
+ <div class='{style.cursorPosition}'><span ui:field='cursLine'/> : <span ui:field='cursCol'/></div>
+ <div class='{style.dirty}' ui:field='dirty'>Unsaved</div>
+ </div>
</g:HTMLPanel>
</ui:UiBinder>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/CallbackGroup.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/CallbackGroup.java
index 6a9ddb5..071ca72 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/CallbackGroup.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/CallbackGroup.java
@@ -42,8 +42,8 @@
* processing it.
*/
public class CallbackGroup {
- private final List<CallbackImpl<?>> callbacks;
- private final Set<CallbackImpl<?>> remaining;
+ private final List<CallbackGlue> callbacks;
+ private final Set<CallbackGlue> remaining;
private boolean finalAdded;
private boolean failed;
@@ -76,6 +76,27 @@
return handleAdd(cb);
}
+ public <T> HttpCallback<T> add(HttpCallback<T> cb) {
+ checkFinalAdded();
+ if (failed) {
+ cb.onFailure(failedThrowable);
+ return new HttpCallback<T>() {
+ @Override
+ public void onSuccess(HttpResponse<T> result) {
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ }
+ };
+ }
+
+ HttpCallbackImpl<T> w = new HttpCallbackImpl<>(cb);
+ callbacks.add(w);
+ remaining.add(w);
+ return w;
+ }
+
public <T> Callback<T> addFinal(final AsyncCallback<T> cb) {
checkFinalAdded();
finalAdded = true;
@@ -84,7 +105,7 @@
public void done() {
finalAdded = true;
- applyAllSuccess();
+ apply();
}
public void addListener(AsyncCallback<Void> cb) {
@@ -99,19 +120,30 @@
addListener(group.<Void> addEmpty());
}
- private void applyAllSuccess() {
- if (!failed && finalAdded && remaining.isEmpty()) {
- for (CallbackImpl<?> cb : callbacks) {
- cb.applySuccess();
- }
- callbacks.clear();
- }
+ private void success(CallbackGlue cb) {
+ remaining.remove(cb);
+ apply();
}
- private void applyAllFailed() {
- if (failed && finalAdded && remaining.isEmpty()) {
- for (CallbackImpl<?> cb : callbacks) {
- cb.applyFailed();
+ private <T> void failure(CallbackGlue w, Throwable caught) {
+ if (!failed) {
+ failed = true;
+ failedThrowable = caught;
+ }
+ remaining.remove(w);
+ apply();
+ }
+
+ private void apply() {
+ if (finalAdded && remaining.isEmpty()) {
+ if (failed) {
+ for (CallbackGlue cb : callbacks) {
+ cb.applyFailed();
+ }
+ } else {
+ for (CallbackGlue cb : callbacks) {
+ cb.applySuccess();
+ }
}
callbacks.clear();
}
@@ -139,7 +171,12 @@
extends AsyncCallback<T>, com.google.gwtjsonrpc.common.AsyncCallback<T> {
}
- private class CallbackImpl<T> implements Callback<T> {
+ private interface CallbackGlue {
+ void applySuccess();
+ void applyFailed();
+ }
+
+ private class CallbackImpl<T> implements Callback<T>, CallbackGlue {
AsyncCallback<T> delegate;
T result;
@@ -150,21 +187,16 @@
@Override
public void onSuccess(T value) {
this.result = value;
- remaining.remove(this);
- CallbackGroup.this.applyAllSuccess();
+ success(this);
}
@Override
public void onFailure(Throwable caught) {
- if (!failed) {
- failed = true;
- failedThrowable = caught;
- }
- remaining.remove(this);
- CallbackGroup.this.applyAllFailed();
+ failure(this, caught);
}
- void applySuccess() {
+ @Override
+ public void applySuccess() {
AsyncCallback<T> cb = delegate;
if (cb != null) {
delegate = null;
@@ -173,7 +205,8 @@
}
}
- void applyFailed() {
+ @Override
+ public void applyFailed() {
AsyncCallback<T> cb = delegate;
if (cb != null) {
delegate = null;
@@ -182,4 +215,44 @@
}
}
}
+
+ private class HttpCallbackImpl<T> implements HttpCallback<T>, CallbackGlue {
+ private HttpCallback<T> delegate;
+ private HttpResponse<T> result;
+
+ HttpCallbackImpl(HttpCallback<T> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void onSuccess(HttpResponse<T> result) {
+ this.result = result;
+ success(this);
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ failure(this, caught);
+ }
+
+ @Override
+ public void applySuccess() {
+ HttpCallback<T> cb = delegate;
+ if (cb != null) {
+ delegate = null;
+ cb.onSuccess(result);
+ result = null;
+ }
+ }
+
+ @Override
+ public void applyFailed() {
+ HttpCallback<T> cb = delegate;
+ if (cb != null) {
+ delegate = null;
+ result = null;
+ cb.onFailure(failedThrowable);
+ }
+ }
+ }
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java
index 08ff7d9..bccd237 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java
@@ -23,7 +23,6 @@
import com.google.gerrit.common.errors.NoSuchEntityException;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.common.errors.NotSignedInException;
-import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.InvocationException;
import com.google.gwtjsonrpc.client.RemoteJsonException;
import com.google.gwtjsonrpc.client.ServerUnavailableException;
@@ -35,6 +34,10 @@
com.google.gwt.user.client.rpc.AsyncCallback<T> {
@Override
public void onFailure(final Throwable caught) {
+ showFailure(caught);
+ }
+
+ public static void showFailure(Throwable caught) {
if (isNotSignedIn(caught) || isInvalidXSRF(caught)) {
new NotSignedInDialog().center();
@@ -70,7 +73,6 @@
new ErrorDialog(RpcConstants.C.errorServerUnavailable()).center();
} else {
- GWT.log(getClass().getName() + " caught " + caught, caught);
new ErrorDialog(caught).center();
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/HttpCallback.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/HttpCallback.java
new file mode 100644
index 0000000..a97642e
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/HttpCallback.java
@@ -0,0 +1,21 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.client.rpc;
+
+/** AsyncCallback supplied with HTTP response headers. */
+public interface HttpCallback<T> {
+ void onSuccess(HttpResponse<T> result);
+ void onFailure(Throwable caught);
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/HttpResponse.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/HttpResponse.java
new file mode 100644
index 0000000..969dd30
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/HttpResponse.java
@@ -0,0 +1,56 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.client.rpc;
+
+import com.google.gwt.http.client.Response;
+
+/** Wraps decoded server reply with HTTP headers. */
+public class HttpResponse<T> {
+ private final Response httpResponse;
+ private final String contentType;
+ private final T result;
+
+ HttpResponse(Response httpResponse, String contentType, T result) {
+ this.httpResponse = httpResponse;
+ this.contentType = contentType;
+ this.result = result;
+ }
+
+ /** HTTP status code, always in the 2xx family. */
+ public int getStatusCode() {
+ return httpResponse.getStatusCode();
+ }
+
+ /**
+ * Content type supplied by the server.
+ *
+ * This helper simplifies the common {@code getHeader("Content-Type")} case.
+ */
+ public String getContentType() {
+ return contentType;
+ }
+
+ /** Lookup an arbitrary reply header. */
+ public String getHeader(String header) {
+ if ("Content-Type".equals(header)) {
+ return contentType;
+ }
+ return httpResponse.getHeader(header);
+ }
+
+ public T getResult() {
+ return result;
+ }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
index b677276..e87853b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
@@ -104,21 +104,21 @@
}
}
- private static class HttpCallback<T extends JavaScriptObject>
+ private static class HttpImpl<T extends JavaScriptObject>
implements RequestCallback {
private final boolean background;
- private final AsyncCallback<T> cb;
+ private final HttpCallback<T> cb;
- HttpCallback(boolean bg, AsyncCallback<T> cb) {
+ HttpImpl(boolean bg, HttpCallback<T> cb) {
this.background = bg;
this.cb = cb;
}
@Override
- public void onResponseReceived(Request req, Response res) {
+ public void onResponseReceived(Request req, final Response res) {
int status = res.getStatusCode();
if (status == Response.SC_NO_CONTENT) {
- cb.onSuccess(null);
+ cb.onSuccess(new HttpResponse<T>(res, null, null));
if (!background) {
RpcStatus.INSTANCE.onRpcComplete();
}
@@ -126,12 +126,12 @@
} else if (200 <= status && status < 300) {
long start = System.currentTimeMillis();
final T data;
- if (isTextBody(res)) {
- data = NativeString.wrap(res.getText()).cast();
- } else if (isJsonBody(res)) {
+ final String type;
+ if (isJsonBody(res)) {
try {
// javac generics bug
- data = RestApi.<T>cast(parseJson(res));
+ data = RestApi.<T> cast(parseJson(res));
+ type = JSON_TYPE;
} catch (JSONException e) {
if (!background) {
RpcStatus.INSTANCE.onRpcComplete();
@@ -140,6 +140,12 @@
"Invalid JSON: " + e.getMessage()));
return;
}
+ } else if (isEncodedBase64(res)) {
+ data = NativeString.wrap(decodeBase64(res.getText())).cast();
+ type = simpleType(res.getHeader("X-FYI-Content-Type"));
+ } else if (isTextBody(res)) {
+ data = NativeString.wrap(res.getText()).cast();
+ type = TEXT_TYPE;
} else {
if (!background) {
RpcStatus.INSTANCE.onRpcComplete();
@@ -154,7 +160,7 @@
@Override
public void execute() {
try {
- cb.onSuccess(data);
+ cb.onSuccess(new HttpResponse<>(res, type, data));
} finally {
if (!background) {
RpcStatus.INSTANCE.onRpcComplete();
@@ -318,21 +324,24 @@
}
public <T extends JavaScriptObject> void get(AsyncCallback<T> cb) {
+ get(wrap(cb));
+ }
+
+ public <T extends JavaScriptObject> void get(HttpCallback<T> cb) {
send(GET, cb);
}
public <T extends JavaScriptObject> void delete(AsyncCallback<T> cb) {
+ delete(wrap(cb));
+ }
+
+ public <T extends JavaScriptObject> void delete(HttpCallback<T> cb) {
send(DELETE, cb);
}
- public <T extends JavaScriptObject> void delete(JavaScriptObject content,
- AsyncCallback<T> cb) {
- sendJSON(DELETE, content, cb);
- }
-
- private <T extends JavaScriptObject> void send(
- Method method, AsyncCallback<T> cb) {
- HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
+ private <T extends JavaScriptObject> void send(Method method,
+ HttpCallback<T> cb) {
+ HttpImpl<T> httpCallback = new HttpImpl<>(background, cb);
try {
if (!background) {
RpcStatus.INSTANCE.onRpcStart();
@@ -346,33 +355,59 @@
public <T extends JavaScriptObject> void post(
JavaScriptObject content,
AsyncCallback<T> cb) {
+ post(content, wrap(cb));
+ }
+
+ public <T extends JavaScriptObject> void post(
+ JavaScriptObject content,
+ HttpCallback<T> cb) {
sendJSON(POST, content, cb);
}
public <T extends JavaScriptObject> void post(String content,
AsyncCallback<T> cb) {
+ post(content, wrap(cb));
+ }
+
+ public <T extends JavaScriptObject> void post(String content,
+ HttpCallback<T> cb) {
sendRaw(POST, content, cb);
}
public <T extends JavaScriptObject> void put(AsyncCallback<T> cb) {
+ put(wrap(cb));
+ }
+
+ public <T extends JavaScriptObject> void put(HttpCallback<T> cb) {
send(PUT, cb);
}
public <T extends JavaScriptObject> void put(String content,
AsyncCallback<T> cb) {
+ put(content, wrap(cb));
+ }
+
+ public <T extends JavaScriptObject> void put(String content,
+ HttpCallback<T> cb) {
sendRaw(PUT, content, cb);
}
public <T extends JavaScriptObject> void put(
JavaScriptObject content,
AsyncCallback<T> cb) {
+ put(content, wrap(cb));
+ }
+
+ public <T extends JavaScriptObject> void put(
+ JavaScriptObject content,
+ HttpCallback<T> cb) {
sendJSON(PUT, content, cb);
}
private <T extends JavaScriptObject> void sendJSON(
Method method, JavaScriptObject content,
- AsyncCallback<T> cb) {
- HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
+ HttpCallback<T> cb) {
+ HttpImpl<T> httpCallback = new HttpImpl<>(background, cb);
try {
if (!background) {
RpcStatus.INSTANCE.onRpcStart();
@@ -385,11 +420,15 @@
}
}
- private static native String str(JavaScriptObject jso) /*-{ return JSON.stringify(jso); }-*/;
+ private static native String str(JavaScriptObject jso)
+ /*-{ return JSON.stringify(jso) }-*/;
+
+ private static native String decodeBase64(String a)
+ /*-{ return $wnd.atob(a) }-*/;
private <T extends JavaScriptObject> void sendRaw(Method method, String body,
- AsyncCallback<T> cb) {
- HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
+ HttpCallback<T> cb) {
+ HttpImpl<T> httpCallback = new HttpImpl<>(background, cb);
try {
if (!background) {
RpcStatus.INSTANCE.onRpcStart();
@@ -422,16 +461,22 @@
return isContentType(res, TEXT_TYPE);
}
+ private static boolean isEncodedBase64(Response res) {
+ return "base64".equals(res.getHeader("X-FYI-Content-Encoding"))
+ && isTextBody(res);
+ }
+
private static boolean isContentType(Response res, String want) {
String type = res.getHeader("Content-Type");
- if (type == null) {
- return false;
- }
+ return type != null && want.equals(simpleType(type));
+ }
+
+ private static String simpleType(String type) {
int semi = type.indexOf(';');
if (semi >= 0) {
- type = type.substring(0, semi).trim();
+ return type.substring(0, semi).trim();
}
- return want.equals(type);
+ return type;
}
private static JSONValue parseJson(Response res)
@@ -464,4 +509,19 @@
throw new JSONException("unsupported JSON type");
}
}
+
+ private static <T extends JavaScriptObject> HttpCallback<T> wrap(
+ final AsyncCallback<T> cb) {
+ return new HttpCallback<T>() {
+ @Override
+ public void onSuccess(HttpResponse<T> r) {
+ cb.onSuccess(r.getResult());
+ }
+
+ @Override
+ public void onFailure(Throwable e) {
+ cb.onFailure(e);
+ }
+ };
+ }
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/SuggestAfterTypingNCharsOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/SuggestAfterTypingNCharsOracle.java
index 4f54ba5..26c0ce6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/SuggestAfterTypingNCharsOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/SuggestAfterTypingNCharsOracle.java
@@ -17,6 +17,9 @@
import com.google.gerrit.client.Gerrit;
import com.google.gwtexpui.safehtml.client.HighlightSuggestOracle;
+import java.util.Collections;
+import java.util.List;
+
/**
* Suggest oracle that only provides suggestions if the user has typed at least
* as many characters as configured by 'suggest.from'. If 'suggest.from' is set
@@ -25,10 +28,12 @@
public abstract class SuggestAfterTypingNCharsOracle extends HighlightSuggestOracle {
@Override
- protected void onRequestSuggestions(final Request request, final Callback done) {
- final int suggestFrom = Gerrit.getConfig().getSuggestFrom();
- if (suggestFrom == 0 || request.getQuery().length() >= suggestFrom) {
- _onRequestSuggestions(request, done);
+ protected void onRequestSuggestions(Request req, Callback cb) {
+ if (req.getQuery().length() >= Gerrit.getConfig().getSuggestFrom()) {
+ _onRequestSuggestions(req, cb);
+ } else {
+ List<Suggestion> none = Collections.emptyList();
+ cb.onSuggestionsReady(req, new Response(none));
}
}
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
index c731476..e607b43 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
@@ -326,7 +326,7 @@
}-*/;
public final native Element scrollbarV() /*-{
- return this.display.scrollbarV
+ return this.display.scrollbars.vert.node;
}-*/;
public static final native KeyMap cloneKeyMap(String name) /*-{
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java
index f2822b7..379cb3c 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java
@@ -15,7 +15,6 @@
package net.codemirror.lib;
import com.google.gerrit.client.rpc.CallbackGroup;
-import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.ScriptInjector;
import com.google.gwt.dom.client.ScriptElement;
@@ -39,11 +38,15 @@
CallbackGroup group = new CallbackGroup();
injectCss(Lib.I.css(), group.<Void> addEmpty());
- injectScript(Lib.I.js().getSafeUri(), group.add(new GerritCallback<Void>() {
+ injectScript(Lib.I.js().getSafeUri(), group.add(new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
Vim.initKeyMap();
}
+
+ @Override
+ public void onFailure(Throwable caught) {
+ }
}));
group.addListener(cb);
group.done();
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
index c4ca15d..b727bc6 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
@@ -146,8 +146,6 @@
}
})));
- config.setNewFeatures(cfg.getBoolean("gerrit", "enableNewFeatures", true));
-
config.setReportBugUrl(cfg.getString("gerrit", null, "reportBugUrl"));
config.setReportBugText(cfg.getString("gerrit", null, "reportBugText"));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
index 02ad0c4..81ffe1c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
@@ -18,7 +18,6 @@
import static com.google.gerrit.server.change.ChangeKind.NO_CODE_CHANGE;
import static com.google.gerrit.server.change.ChangeKind.TRIVIAL_REBASE;
-import com.google.common.base.Objects;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Maps;
@@ -47,6 +46,7 @@
import java.util.Collection;
import java.util.List;
import java.util.NavigableSet;
+import java.util.Objects;
import java.util.SortedSet;
import java.util.TreeMap;
@@ -156,7 +156,7 @@
LabelType type = project.getLabelTypes().byLabel(psa.getLabelId());
if (type == null) {
return false;
- } else if (Objects.equal(n, previous(allPsIds, psId.get())) && (
+ } else if (Objects.equals(n, previous(allPsIds, psId.get())) && (
type.isCopyMinScore() && type.isMaxNegative(psa)
|| type.isCopyMaxScore() && type.isMaxPositive(psa))) {
// Copy min/max score only from the immediately preceding patch set (which
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
index 3e169f3..92b78d1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
@@ -18,7 +18,6 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
-import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
@@ -57,6 +56,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -91,7 +91,7 @@
return Iterables.filter(psas, new Predicate<PatchSetApproval>() {
@Override
public boolean apply(PatchSetApproval input) {
- return Objects.equal(input.getAccountId(), accountId);
+ return Objects.equals(input.getAccountId(), accountId);
}
});
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
index 566b298..ab788c9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
@@ -187,7 +187,7 @@
return ImmutableSet.copyOf((Iterable<String>) listFiles
.get().setReviewed(true)
.apply(revision).value());
- } catch (OrmException e) {
+ } catch (OrmException | IOException e) {
throw new RestApiException("Cannot list reviewed files", e);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/AuthRequest.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/AuthRequest.java
index 09ab56b..e194eb7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/AuthRequest.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/AuthRequest.java
@@ -14,9 +14,10 @@
package com.google.gerrit.server.auth;
-import com.google.common.base.Objects;
import com.google.gerrit.common.Nullable;
+import java.util.Objects;
+
/**
* Defines an abstract request for user authentication to Gerrit.
*/
@@ -50,7 +51,7 @@
}
public void checkPassword(String pwd) throws AuthException {
- if (!Objects.equal(getPassword(), pwd)) {
+ if (!Objects.equals(getPassword(), pwd)) {
throw new InvalidCredentialsException();
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
index a2e4604..4f11044 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
@@ -52,6 +52,7 @@
import com.google.inject.Singleton;
import com.google.inject.assistedinject.Assisted;
+import org.eclipse.jgit.lib.ObjectId;
import org.kohsuke.args4j.Option;
import java.io.IOException;
@@ -433,8 +434,8 @@
throws ResourceNotFoundException, IOException {
try {
return Response.ok(fileContentUtil.getContent(
- rsrc.getChangeEdit().getChange().getProject(),
- rsrc.getChangeEdit().getRevision().get(),
+ rsrc.getControl().getProjectControl().getProjectState(),
+ ObjectId.fromString(rsrc.getChangeEdit().getRevision().get()),
rsrc.getPath()));
} catch (ResourceNotFoundException rnfe) {
return Response.none();
@@ -502,29 +503,12 @@
IOException, ResourceNotFoundException {
Optional<ChangeEdit> edit = editUtil.byChange(rsrc.getChange());
if (edit.isPresent()) {
- return BinaryResult.create(
- edit.get().getEditCommit().getFullMessage()).base64();
+ String msg = edit.get().getEditCommit().getFullMessage();
+ return BinaryResult.create(msg)
+ .setContentType(FileContentUtil.TEXT_X_GERRIT_COMMIT_MESSAGE)
+ .base64();
}
throw new ResourceNotFoundException();
}
}
-
- @Singleton
- public static class GetType implements RestReadView<ChangeEditResource> {
- private final FileContentUtil fileContentUtil;
-
- @Inject
- GetType(FileContentUtil fileContentUtil) {
- this.fileContentUtil = fileContentUtil;
- }
-
- @Override
- public String apply(ChangeEditResource rsrc)
- throws ResourceNotFoundException, IOException {
- return fileContentUtil.getContentType(
- rsrc.getChangeEdit().getChange().getProject(),
- rsrc.getChangeEdit().getRevision().get(),
- rsrc.getPath());
- }
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
index 8d98a4c..a5e7d12 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
@@ -19,7 +19,6 @@
import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.Weigher;
@@ -53,6 +52,7 @@
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
+import java.util.Objects;
import java.util.concurrent.ExecutionException;
public class ChangeKindCacheImpl implements ChangeKindCache {
@@ -156,16 +156,16 @@
public boolean equals(Object o) {
if (o instanceof Key) {
Key k = (Key) o;
- return Objects.equal(prior, k.prior)
- && Objects.equal(next, k.next)
- && Objects.equal(strategyName, k.strategyName);
+ return Objects.equals(prior, k.prior)
+ && Objects.equals(next, k.next)
+ && Objects.equals(strategyName, k.strategyName);
}
return false;
}
@Override
public int hashCode() {
- return Objects.hashCode(prior, next, strategyName);
+ return Objects.hash(prior, next, strategyName);
}
private void writeObject(ObjectOutputStream out) throws IOException {
@@ -185,7 +185,7 @@
private static class Loader extends CacheLoader<Key, ChangeKind> {
@Override
public ChangeKind load(Key key) throws IOException {
- if (Objects.equal(key.prior, key.next)) {
+ if (Objects.equals(key.prior, key.next)) {
return ChangeKind.NO_CODE_CHANGE;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java
index 5d07402..bc48917 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java
@@ -16,14 +16,19 @@
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import com.google.gerrit.common.data.PatchScript.FileMode;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
-import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.server.FileTypeRegistry;
import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.project.ProjectState;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import org.eclipse.jgit.errors.LargeObjectException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
@@ -36,6 +41,11 @@
@Singleton
public class FileContentUtil {
+ public static final String TEXT_X_GERRIT_COMMIT_MESSAGE = "text/x-gerrit-commit-message";
+ private static final String X_GIT_SYMLINK = "x-git/symlink";
+ private static final String X_GIT_GITLINK = "x-git/gitlink";
+ private static final int MAX_SIZE = 5 << 20;
+
private final GitRepositoryManager repoManager;
private final FileTypeRegistry registry;
@@ -46,28 +56,50 @@
this.registry = ftr;
}
- public BinaryResult getContent(Project.NameKey project, String revstr,
+ public BinaryResult getContent(ProjectState project, ObjectId revstr,
String path) throws ResourceNotFoundException, IOException {
- Repository repo = repoManager.openRepository(project);
+ Repository repo = openRepository(project);
try {
RevWalk rw = new RevWalk(repo);
try {
- RevCommit commit = rw.parseCommit(repo.resolve(revstr));
- TreeWalk tw =
- TreeWalk.forPath(rw.getObjectReader(), path,
- commit.getTree().getId());
+ RevCommit commit = rw.parseCommit(revstr);
+ ObjectReader reader = rw.getObjectReader();
+ TreeWalk tw = TreeWalk.forPath(reader, path, commit.getTree());
if (tw == null) {
throw new ResourceNotFoundException();
}
- final ObjectLoader object = repo.open(tw.getObjectId(0));
- @SuppressWarnings("resource")
- BinaryResult result = new BinaryResult() {
- @Override
- public void writeTo(OutputStream os) throws IOException {
- object.copyTo(os);
- }
- };
- return result.setContentLength(object.getSize()).base64();
+
+ org.eclipse.jgit.lib.FileMode mode = tw.getFileMode(0);
+ ObjectId id = tw.getObjectId(0);
+ if (mode == org.eclipse.jgit.lib.FileMode.GITLINK) {
+ return BinaryResult.create(id.name())
+ .setContentType(X_GIT_GITLINK)
+ .base64();
+ }
+
+ final ObjectLoader obj = repo.open(id, OBJ_BLOB);
+ byte[] raw;
+ try {
+ raw = obj.getCachedBytes(MAX_SIZE);
+ } catch (LargeObjectException e) {
+ raw = null;
+ }
+
+ BinaryResult result;
+ if (raw != null) {
+ result = BinaryResult.create(raw);
+ } else {
+ result = asBinaryResult(obj);
+ }
+
+ String type;
+ if (mode == org.eclipse.jgit.lib.FileMode.SYMLINK) {
+ type = X_GIT_SYMLINK;
+ } else {
+ type = registry.getMimeType(path, raw).toString();
+ type = resolveContentType(project, path, FileMode.FILE, type);
+ }
+ return result.setContentType(type).base64();
} finally {
rw.release();
}
@@ -76,31 +108,44 @@
}
}
- public String getContentType(Project.NameKey project, String revstr,
- String path) throws ResourceNotFoundException, IOException {
- Repository repo = repoManager.openRepository(project);
- try {
- RevWalk rw = new RevWalk(repo);
- ObjectReader reader = repo.newObjectReader();
- try {
- RevCommit commit = rw.parseCommit(repo.resolve(revstr));
- TreeWalk tw =
- TreeWalk.forPath(rw.getObjectReader(), path,
- commit.getTree().getId());
- if (tw == null) {
- throw new ResourceNotFoundException();
- }
- ObjectLoader blobLoader = reader.open(tw.getObjectId(0), OBJ_BLOB);
- byte[] raw = blobLoader.isLarge()
- ? null
- : blobLoader.getCachedBytes();
- return registry.getMimeType(path, raw).toString();
- } finally {
- reader.release();
- rw.release();
+ private static BinaryResult asBinaryResult(final ObjectLoader obj) {
+ @SuppressWarnings("resource")
+ BinaryResult result = new BinaryResult() {
+ @Override
+ public void writeTo(OutputStream os) throws IOException {
+ obj.copyTo(os);
}
- } finally {
- repo.close();
+ }.setContentLength(obj.getSize());
+ return result;
+ }
+
+ public static String resolveContentType(ProjectState project, String path,
+ FileMode fileMode, String mimeType) {
+ switch (fileMode) {
+ case FILE:
+ if (Patch.COMMIT_MSG.equals(path)) {
+ return TEXT_X_GERRIT_COMMIT_MESSAGE;
+ }
+ if (project != null) {
+ for (ProjectState p : project.tree()) {
+ String t = p.getConfig().getMimeTypes().getMimeType(path);
+ if (t != null) {
+ return t;
+ }
+ }
+ }
+ return mimeType;
+ case GITLINK:
+ return X_GIT_GITLINK;
+ case SYMLINK:
+ return X_GIT_SYMLINK;
+ default:
+ throw new IllegalStateException("file mode: " + fileMode);
}
}
+
+ private Repository openRepository(ProjectState project)
+ throws RepositoryNotFoundException, IOException {
+ return repoManager.openRepository(project.getProject().getNameKey());
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java
index 3035ce1..4a3082c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java
@@ -43,8 +43,11 @@
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
@@ -53,6 +56,7 @@
import org.slf4j.LoggerFactory;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -96,6 +100,9 @@
@Option(name = "--reviewed")
boolean reviewed;
+ @Option(name = "-q")
+ String query;
+
private final Provider<ReviewDb> db;
private final Provider<CurrentUser> self;
private final FileInfoJson fileInfoJson;
@@ -125,11 +132,13 @@
@Override
public Response<?> apply(RevisionResource resource) throws AuthException,
- BadRequestException, ResourceNotFoundException, OrmException {
- if (base != null && reviewed) {
- throw new BadRequestException("cannot combine base and reviewed");
- } else if (reviewed) {
+ BadRequestException, ResourceNotFoundException, OrmException,
+ RepositoryNotFoundException, IOException {
+ checkOptions();
+ if (reviewed) {
return Response.ok(reviewed(resource));
+ } else if (query != null) {
+ return Response.ok(query(resource));
}
PatchSet basePatchSet = null;
@@ -152,6 +161,51 @@
}
}
+ private void checkOptions() throws BadRequestException {
+ int supplied = 0;
+ if (base != null) {
+ supplied++;
+ }
+ if (reviewed) {
+ supplied++;
+ }
+ if (query != null) {
+ supplied++;
+ }
+ if (supplied > 1) {
+ throw new BadRequestException("cannot combine base, reviewed, query");
+ }
+ }
+
+ private List<String> query(RevisionResource resource)
+ throws RepositoryNotFoundException, IOException {
+ Repository git =
+ gitManager.openRepository(resource.getChange().getProject());
+ try {
+ TreeWalk tw = new TreeWalk(git);
+ try {
+ RevCommit c = new RevWalk(tw.getObjectReader())
+ .parseCommit(ObjectId.fromString(
+ resource.getPatchSet().getRevision().get()));
+
+ tw.addTree(c.getTree());
+ tw.setRecursive(true);
+ List<String> paths = new ArrayList<>();
+ while (tw.next() && paths.size() < 20) {
+ String s = tw.getPathString();
+ if (s.contains(query)) {
+ paths.add(s);
+ }
+ }
+ return paths;
+ } finally {
+ tw.release();
+ }
+ } finally {
+ git.close();
+ }
+ }
+
private List<String> reviewed(RevisionResource resource)
throws AuthException, OrmException {
CurrentUser user = self.get();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java
index 67c68fc..810a3a6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java
@@ -24,6 +24,8 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import org.eclipse.jgit.lib.ObjectId;
+
import java.io.IOException;
@Singleton
@@ -44,12 +46,14 @@
OrmException {
String path = rsrc.getPatchKey().get();
if (Patch.COMMIT_MSG.equals(path)) {
- return BinaryResult.create(
- changeUtil.getMessage(rsrc.getRevision().getChange())).base64();
+ String msg = changeUtil.getMessage(rsrc.getRevision().getChange());
+ return BinaryResult.create(msg)
+ .setContentType(FileContentUtil.TEXT_X_GERRIT_COMMIT_MESSAGE)
+ .base64();
}
return fileContentUtil.getContent(
- rsrc.getRevision().getControl().getProject().getNameKey(),
- rsrc.getRevision().getPatchSet().getRevision().get(),
+ rsrc.getRevision().getControl().getProjectControl().getProjectState(),
+ ObjectId.fromString(rsrc.getRevision().getPatchSet().getRevision().get()),
path);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContentType.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContentType.java
deleted file mode 100644
index 2fa3126..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContentType.java
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.server.change;
-
-import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
-import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-import java.io.IOException;
-
-@Singleton
-public class GetContentType implements RestReadView<FileResource> {
- private final FileContentUtil fileContentUtil;
-
- @Inject
- GetContentType(FileContentUtil fileContentUtil) {
- this.fileContentUtil = fileContentUtil;
- }
-
- @Override
- public String apply(FileResource rsrc)
- throws ResourceNotFoundException, IOException {
- String path = rsrc.getPatchKey().get();
- if (Patch.COMMIT_MSG.equals(path)) {
- return "text/plain";
- }
- return fileContentUtil.getContentType(
- rsrc.getRevision().getControl().getProject().getNameKey(),
- rsrc.getRevision().getPatchSet().getRevision().get(),
- path);
- }
-}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
index 04b1386..7c7bcdae 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
@@ -24,7 +24,6 @@
import com.google.common.collect.Maps;
import com.google.gerrit.common.data.PatchScript;
import com.google.gerrit.common.data.PatchScript.DisplayMethod;
-import com.google.gerrit.common.data.PatchScript.FileMode;
import com.google.gerrit.extensions.common.ChangeType;
import com.google.gerrit.extensions.common.DiffInfo;
import com.google.gerrit.extensions.common.DiffInfo.ContentEntry;
@@ -194,7 +193,8 @@
result.metaA = new FileMeta();
result.metaA.name = MoreObjects.firstNonNull(ps.getOldName(),
ps.getNewName());
- setContentType(result.metaA, state, ps.getFileModeA(), ps.getMimeTypeA());
+ result.metaA.contentType = FileContentUtil.resolveContentType(
+ state, result.metaA.name, ps.getFileModeA(), ps.getMimeTypeA());
result.metaA.lines = ps.getA().size();
result.metaA.webLinks =
getFileWebLinks(state.getProject(), revA, result.metaA.name);
@@ -203,7 +203,8 @@
if (ps.getDisplayMethodB() != DisplayMethod.NONE) {
result.metaB = new FileMeta();
result.metaB.name = ps.getNewName();
- setContentType(result.metaB, state, ps.getFileModeB(), ps.getMimeTypeB());
+ result.metaB.contentType = FileContentUtil.resolveContentType(
+ state, result.metaB.name, ps.getFileModeB(), ps.getMimeTypeB());
result.metaB.lines = ps.getB().size();
result.metaB.webLinks =
getFileWebLinks(state.getProject(), revB, result.metaB.name);
@@ -250,34 +251,6 @@
return links.isEmpty() ? null : links.toList();
}
- private void setContentType(FileMeta meta, ProjectState project,
- FileMode fileMode, String mimeType) {
- switch (fileMode) {
- case FILE:
- if (Patch.COMMIT_MSG.equals(meta.name)) {
- mimeType = "text/x-gerrit-commit-message";
- } else if (project != null) {
- for (ProjectState p : project.tree()) {
- String t = p.getConfig().getMimeTypes().getMimeType(meta.name);
- if (t != null) {
- mimeType = t;
- break;
- }
- }
- }
- meta.contentType = mimeType;
- break;
- case GITLINK:
- meta.contentType = "x-git/gitlink";
- break;
- case SYMLINK:
- meta.contentType = "x-git/symlink";
- break;
- default:
- throw new IllegalStateException("file mode: " + fileMode);
- }
- }
-
private static class Content {
final List<ContentEntry> lines;
final SparseFileContent fileA;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
index f89c981..4cf7692 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
@@ -103,7 +103,6 @@
put(FILE_KIND, "reviewed").to(PutReviewed.class);
delete(FILE_KIND, "reviewed").to(DeleteReviewed.class);
get(FILE_KIND, "content").to(GetContent.class);
- get(FILE_KIND, "type").to(GetContentType.class);
get(FILE_KIND, "diff").to(GetDiff.class);
child(CHANGE_KIND, "edit").to(ChangeEdits.class);
@@ -115,7 +114,6 @@
put(CHANGE_EDIT_KIND, "/").to(ChangeEdits.Put.class);
delete(CHANGE_EDIT_KIND).to(ChangeEdits.DeleteContent.class);
get(CHANGE_EDIT_KIND, "/").to(ChangeEdits.Get.class);
- get(CHANGE_EDIT_KIND, "type").to(ChangeEdits.GetType.class);
install(new FactoryModule() {
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
index 18b08b5..a01f049 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
@@ -37,6 +37,7 @@
import com.google.gerrit.extensions.common.Comment.Side;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.extensions.restapi.Url;
@@ -130,8 +131,11 @@
@Override
public Output apply(RevisionResource revision, ReviewInput input)
- throws AuthException, BadRequestException, UnprocessableEntityException,
- OrmException, IOException {
+ throws AuthException, BadRequestException, ResourceConflictException,
+ UnprocessableEntityException, OrmException, IOException {
+ if (revision.getEdit().isPresent()) {
+ throw new ResourceConflictException("cannot post review on edit");
+ }
if (input.onBehalfOf != null) {
revision = onBehalfOf(revision, input);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Revisions.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Revisions.java
index f32b41c..dc5e445 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Revisions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Revisions.java
@@ -17,6 +17,7 @@
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.gerrit.extensions.registration.DynamicMap;
@@ -32,6 +33,7 @@
import com.google.gerrit.server.edit.ChangeEdit;
import com.google.gerrit.server.edit.ChangeEditUtil;
import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -76,11 +78,10 @@
}
throw new ResourceNotFoundException(id);
}
+
List<RevisionResource> match = Lists.newArrayListWithExpectedSize(2);
for (RevisionResource rsrc : find(change, id.get())) {
- Change.Id changeId = rsrc.getChange().getId();
- if (changeId.equals(change.getChange().getId())
- && visible(change, rsrc.getPatchSet())) {
+ if (visible(change, rsrc.getPatchSet())) {
match.add(rsrc);
}
}
@@ -103,19 +104,11 @@
private List<RevisionResource> find(ChangeResource change, String id)
throws OrmException {
- ReviewDb db = dbProvider.get();
-
if (id.equals("0")) {
return loadEdit(change, null);
} else if (id.length() < 6 && id.matches("^[1-9][0-9]{0,4}$")) {
// Legacy patch set number syntax.
- PatchSet ps = dbProvider.get().patchSets().get(new PatchSet.Id(
- change.getChange().getId(),
- Integer.parseInt(id)));
- if (ps != null) {
- return toResources(change, ps);
- }
- return Collections.emptyList();
+ return byLegacyPatchSetId(change, id);
} else if (id.length() < 4 || id.length() > RevId.LEN) {
// Require a minimum of 4 digits.
// Impossibly long identifier will never match.
@@ -127,20 +120,15 @@
// for all patch sets in the change.
RevId revid = new RevId(id);
if (revid.isComplete()) {
- List<RevisionResource> list =
- toResources(change, db.patchSets().byRevision(revid));
- if (list.isEmpty()) {
- return loadEdit(change, revid);
- }
- return list;
- } else {
- return toResources(
- change, db.patchSets().byRevisionRange(revid, revid.max()));
+ List<RevisionResource> m = toResources(change, findExactMatch(revid));
+ return m.isEmpty() ? loadEdit(change, revid) : m;
}
+ return toResources(change, findByPrefix(revid));
} else {
// Chance of collision rises; look at all patch sets on the change.
List<RevisionResource> out = Lists.newArrayList();
- for (PatchSet ps : db.patchSets().byChange(change.getChange().getId())) {
+ for (PatchSet ps : dbProvider.get().patchSets()
+ .byChange(change.getChange().getId())) {
if (ps.getRevision() != null && ps.getRevision().get().startsWith(id)) {
out.add(new RevisionResource(change, ps));
}
@@ -149,6 +137,25 @@
}
}
+ private List<RevisionResource> byLegacyPatchSetId(ChangeResource change,
+ String id) throws OrmException {
+ PatchSet ps = dbProvider.get().patchSets().get(new PatchSet.Id(
+ change.getChange().getId(),
+ Integer.parseInt(id)));
+ if (ps != null) {
+ return Collections.singletonList(new RevisionResource(change, ps));
+ }
+ return Collections.emptyList();
+ }
+
+ private ResultSet<PatchSet> findExactMatch(RevId revid) throws OrmException {
+ return dbProvider.get().patchSets().byRevision(revid);
+ }
+
+ private ResultSet<PatchSet> findByPrefix(RevId revid) throws OrmException {
+ return dbProvider.get().patchSets().byRevisionRange(revid, revid.max());
+ }
+
private List<RevisionResource> loadEdit(ChangeResource change, RevId revid)
throws OrmException {
try {
@@ -162,25 +169,26 @@
new RevisionResource(change, ps, edit));
}
}
+ return Collections.emptyList();
} catch (AuthException | IOException e) {
throw new OrmException(e);
}
- return Collections.emptyList();
}
private static List<RevisionResource> toResources(final ChangeResource change,
Iterable<PatchSet> patchSets) {
+ final Change.Id changeId = change.getChange().getId();
return FluentIterable.from(patchSets)
- .transform(new Function<PatchSet, RevisionResource>() {
+ .filter(new Predicate<PatchSet>() {
+ @Override
+ public boolean apply(PatchSet in) {
+ return changeId.equals(in.getId().getParentKey());
+ }
+ }).transform(new Function<PatchSet, RevisionResource>() {
@Override
public RevisionResource apply(PatchSet in) {
return new RevisionResource(change, in);
}
}).toList();
}
-
- private static List<RevisionResource> toResources(ChangeResource change,
- PatchSet ps) {
- return Collections.singletonList(new RevisionResource(change, ps));
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditJson.java
index 008a217..738d309 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditJson.java
@@ -15,16 +15,12 @@
package com.google.gerrit.server.edit;
import com.google.common.collect.Maps;
-import com.google.gerrit.extensions.common.ActionInfo;
import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.common.FetchInfo;
import com.google.gerrit.extensions.config.DownloadCommand;
import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.webui.PrivateInternals_UiActionDescription;
-import com.google.gerrit.extensions.webui.UiAction;
-import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.CommonConverters;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.change.ChangeJson;
@@ -56,7 +52,6 @@
EditInfo out = new EditInfo();
out.commit = fillCommit(edit.getEditCommit());
out.baseRevision = edit.getBasePatchSet().getRevision().get();
- out.actions = fillActions(edit);
if (downloadCommands) {
out.fetch = fillFetchMap(edit);
}
@@ -82,35 +77,6 @@
return commit;
}
- private static Map<String, ActionInfo> fillActions(ChangeEdit edit) {
- Map<String, ActionInfo> actions = Maps.newTreeMap();
-
- UiAction.Description descr = new UiAction.Description();
- PrivateInternals_UiActionDescription.setId(descr, "/");
- PrivateInternals_UiActionDescription.setMethod(descr, "DELETE");
- descr.setTitle("Delete edit");
- actions.put(descr.getId(), new ActionInfo(descr));
-
- // Only expose publish action when the edit is on top of current ps
- PatchSet.Id current = edit.getChange().currentPatchSetId();
- PatchSet basePs = edit.getBasePatchSet();
- if (basePs.getId().equals(current)) {
- descr = new UiAction.Description();
- PrivateInternals_UiActionDescription.setId(descr, "publish");
- PrivateInternals_UiActionDescription.setMethod(descr, "POST");
- descr.setTitle("Publish edit");
- actions.put(descr.getId(), new ActionInfo(descr));
- } else {
- descr = new UiAction.Description();
- PrivateInternals_UiActionDescription.setId(descr, "rebase");
- PrivateInternals_UiActionDescription.setMethod(descr, "POST");
- descr.setTitle("Rebase edit");
- actions.put(descr.getId(), new ActionInfo(descr));
- }
-
- return actions;
- }
-
private Map<String, FetchInfo> fillFetchMap(ChangeEdit edit) {
Map<String, FetchInfo> r = Maps.newLinkedHashMap();
for (DynamicMap.Entry<DownloadScheme> e : downloadSchemes) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/LabelNormalizer.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/LabelNormalizer.java
index 71a68b4..9127acd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/LabelNormalizer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/LabelNormalizer.java
@@ -18,7 +18,6 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
-import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -38,6 +37,7 @@
import java.util.Collection;
import java.util.List;
+import java.util.Objects;
/**
* Normalizes votes on labels according to project config and permissions.
@@ -85,16 +85,16 @@
public boolean equals(Object o) {
if (o instanceof Result) {
Result r = (Result) o;
- return Objects.equal(unchanged, r.unchanged)
- && Objects.equal(updated, r.updated)
- && Objects.equal(deleted, r.deleted);
+ return Objects.equals(unchanged, r.unchanged)
+ && Objects.equals(updated, r.updated)
+ && Objects.equals(deleted, r.deleted);
}
return false;
}
@Override
public int hashCode() {
- return Objects.hashCode(unchanged, updated, deleted);
+ return Objects.hash(unchanged, updated, deleted);
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
index 112b1a8..b859dc2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -20,7 +20,6 @@
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.eclipse.jgit.lib.RefDatabase.ALL;
-import com.google.common.base.Objects;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
@@ -97,6 +96,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -1058,8 +1058,8 @@
try {
ChangeMessage last = Iterables.getLast(cmUtil.byChange(db, notes));
if (last != null) {
- if (Objects.equal(last.getAuthor(), msg.getAuthor())
- && Objects.equal(last.getMessage(), msg.getMessage())) {
+ if (Objects.equals(last.getAuthor(), msg.getAuthor())
+ && Objects.equals(last.getMessage(), msg.getMessage())) {
long lastMs = last.getWrittenOn().getTime();
long msgMs = msg.getWrittenOn().getTime();
long sinceMs = msgMs - lastMs;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
index 599a305..09846d6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.git;
import com.google.common.base.MoreObjects;
-import com.google.common.base.Objects;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
@@ -47,6 +46,7 @@
import org.eclipse.jgit.util.RawParseUtils;
import java.io.IOException;
+import java.util.Objects;
/**
* Support for metadata stored within a version controlled branch.
@@ -275,7 +275,7 @@
@Override
public RevCommit createRef(String refName) throws IOException {
- if (Objects.equal(src, revision)) {
+ if (Objects.equals(src, revision)) {
return revision;
}
return updateRef(ObjectId.zeroId(), src, refName);
@@ -306,7 +306,7 @@
@Override
public RevCommit commitAt(ObjectId expected) throws IOException {
- if (Objects.equal(src, expected)) {
+ if (Objects.equals(src, expected)) {
return revision;
}
return updateRef(MoreObjects.firstNonNull(expected, ObjectId.zeroId()),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilder.java
index 2eacd09..fb39462 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilder.java
@@ -19,7 +19,6 @@
import static com.google.gerrit.server.notedb.CommentsInNotesUtil.getCommentPsId;
import com.google.common.base.MoreObjects;
-import com.google.common.base.Objects;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Lists;
@@ -52,6 +51,7 @@
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
@@ -232,13 +232,13 @@
}
protected void checkUpdate(AbstractChangeUpdate update) {
- checkState(Objects.equal(update.getPatchSetId(), psId),
+ checkState(Objects.equals(update.getPatchSetId(), psId),
"cannot apply event for %s to update for %s",
update.getPatchSetId(), psId);
checkState(when.getTime() - update.getWhen().getTime() <= TS_WINDOW_MS,
"event at %s outside update window starting at %s",
when, update.getWhen());
- checkState(Objects.equal(update.getUser().getAccountId(), who),
+ checkState(Objects.equals(update.getUser().getAccountId(), who),
"cannot apply event by %s to update by %s",
who, update.getUser().getAccountId());
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchResource.java
index 6681d94..98531ce 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchResource.java
@@ -41,4 +41,8 @@
public String getRef() {
return branchInfo.ref;
}
+
+ public String getRevision() {
+ return branchInfo.revision;
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CommitResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CommitResource.java
index 2543818..36186a4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CommitResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CommitResource.java
@@ -16,7 +16,6 @@
import com.google.gerrit.extensions.restapi.RestResource;
import com.google.gerrit.extensions.restapi.RestView;
-import com.google.gerrit.reviewdb.client.Project;
import com.google.inject.TypeLiteral;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -33,8 +32,8 @@
this.commit = commit;
}
- public Project.NameKey getProject() {
- return project.getNameKey();
+ public ProjectControl getProject() {
+ return project.getControl();
}
public RevCommit getCommit() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/FileResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/FileResource.java
index c7c6675..47942be 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/FileResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/FileResource.java
@@ -16,28 +16,29 @@
import com.google.gerrit.extensions.restapi.RestResource;
import com.google.gerrit.extensions.restapi.RestView;
-import com.google.gerrit.reviewdb.client.Project;
import com.google.inject.TypeLiteral;
+import org.eclipse.jgit.lib.ObjectId;
+
public class FileResource implements RestResource {
public static final TypeLiteral<RestView<FileResource>> FILE_KIND =
new TypeLiteral<RestView<FileResource>>() {};
- private final Project.NameKey project;
- private final String rev;
+ private final ProjectControl project;
+ private final ObjectId rev;
private final String path;
- public FileResource(Project.NameKey project, String rev, String path) {
+ public FileResource(ProjectControl project, ObjectId rev, String path) {
this.project = project;
this.rev = rev;
this.path = path;
}
- public Project.NameKey getProject() {
+ public ProjectControl getProject() {
return project;
}
- public String getRev() {
+ public ObjectId getRev() {
return rev;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java
index f0544fe..d0460d5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java
@@ -22,6 +22,8 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import org.eclipse.jgit.lib.ObjectId;
+
@Singleton
public class FilesCollection implements
ChildCollection<BranchResource, FileResource> {
@@ -39,7 +41,10 @@
@Override
public FileResource parse(BranchResource parent, IdString id) {
- return new FileResource(parent.getNameKey(), parent.getRef(), id.get());
+ return new FileResource(
+ parent.getControl(),
+ ObjectId.fromString(parent.getRevision()),
+ id.get());
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesInCommitCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesInCommitCollection.java
index f383230..8e0aab8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesInCommitCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesInCommitCollection.java
@@ -40,8 +40,7 @@
@Override
public FileResource parse(CommitResource parent, IdString id)
throws ResourceNotFoundException {
- return new FileResource(parent.getProject(), parent.getCommit().getName(),
- id.get());
+ return new FileResource(parent.getProject(), parent.getCommit(), id.get());
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java
index 00f25bc..23e9e30 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java
@@ -35,7 +35,9 @@
@Override
public BinaryResult apply(FileResource rsrc)
throws ResourceNotFoundException, IOException {
- return fileContentUtil.getContent(rsrc.getProject(), rsrc.getRev(),
+ return fileContentUtil.getContent(
+ rsrc.getProject().getProjectState(),
+ rsrc.getRev(),
rsrc.getPath());
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
index 0e4ff98..de12e9b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
@@ -16,7 +16,6 @@
import com.google.common.base.CharMatcher;
import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.extensions.api.projects.ProjectInput.ConfigValue;
@@ -57,6 +56,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Objects;
@Singleton
public class PutConfig implements RestModifyView<ProjectResource, Input> {
@@ -178,7 +178,7 @@
ObjectId baseRev = projectConfig.getRevision();
ObjectId commitRev = projectConfig.commit(md);
// Only fire hook if project was actually changed.
- if (!Objects.equal(baseRev, commitRev)) {
+ if (!Objects.equals(baseRev, commitRev)) {
IdentifiedUser user = (IdentifiedUser) currentUser.get();
hooks.doRefUpdatedHook(
new Branch.NameKey(projectName, RefNames.REFS_CONFIG),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java
index db67ce0..536bfa7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.project;
import com.google.common.base.MoreObjects;
-import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -40,6 +39,7 @@
import org.eclipse.jgit.lib.ObjectId;
import java.io.IOException;
+import java.util.Objects;
@Singleton
class PutDescription implements RestModifyView<ProjectResource, Input> {
@@ -97,7 +97,7 @@
ObjectId baseRev = config.getRevision();
ObjectId commitRev = config.commit(md);
// Only fire hook if project was actually changed.
- if (!Objects.equal(baseRev, commitRev)) {
+ if (!Objects.equals(baseRev, commitRev)) {
hooks.doRefUpdatedHook(
new Branch.NameKey(resource.getNameKey(), RefNames.REFS_CONFIG),
baseRev, commitRev, user.getAccount());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictKey.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictKey.java
index e64ff13..3ad0ea4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictKey.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictKey.java
@@ -14,12 +14,12 @@
package com.google.gerrit.server.query.change;
-import com.google.common.base.Objects;
import com.google.gerrit.extensions.common.SubmitType;
import org.eclipse.jgit.lib.ObjectId;
import java.io.Serializable;
+import java.util.Objects;
public class ConflictKey implements Serializable {
private static final long serialVersionUID = 2L;
@@ -73,6 +73,6 @@
@Override
public int hashCode() {
- return Objects.hashCode(commit, otherCommit, submitType, contentMerge);
+ return Objects.hash(commit, otherCommit, submitType, contentMerge);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_102.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_102.java
index bcefe78..990cefe 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_102.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_102.java
@@ -24,6 +24,8 @@
import java.sql.SQLException;
import java.sql.Statement;
+import java.util.Set;
+import java.util.regex.Pattern;
public class Schema_102 extends SchemaVersion {
@Inject
@@ -37,6 +39,20 @@
JdbcSchema schema = (JdbcSchema) db;
SqlDialect dialect = schema.getDialect();
try (Statement stmt = schema.getConnection().createStatement()) {
+ // Drop left over indexes that were missed to be removed in schema 84.
+ // See "Delete SQL index support" commit for more details:
+ // d4ae3a16d5e1464574bd04f429a63eb9c02b3b43
+ Pattern pattern =
+ Pattern.compile("^changes_(allOpen|allClosed|byBranchClosed)$",
+ Pattern.CASE_INSENSITIVE);
+ Set<String> listIndexes = dialect.listIndexes(
+ schema.getConnection(), "changes");
+ for (String index : listIndexes) {
+ if (pattern.matcher(index).matches()) {
+ stmt.executeUpdate("DROP INDEX " + index);
+ }
+ }
+
stmt.executeUpdate("DROP INDEX changes_byProjectOpen");
if (dialect instanceof DialectPostgreSQL) {
stmt.executeUpdate("CREATE INDEX changes_byProjectOpen"
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStoreData.java b/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStoreData.java
index 0da7567..20c7010 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStoreData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/securestore/SecureStoreData.java
@@ -15,11 +15,11 @@
package com.google.gerrit.server.securestore;
import com.google.common.base.MoreObjects;
-import com.google.common.base.Objects;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.Objects;
public class SecureStoreData {
public final File pluginFile;
@@ -73,6 +73,6 @@
@Override
public int hashCode() {
- return Objects.hashCode(storeName);
+ return Objects.hash(storeName);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/LabelVote.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/LabelVote.java
index 0192355..b69ab64 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/LabelVote.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/LabelVote.java
@@ -16,11 +16,12 @@
import static com.google.common.base.Preconditions.checkArgument;
-import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import java.util.Objects;
+
/** A single vote on a label, consisting of a label name and a value. */
public class LabelVote {
public static LabelVote parse(String text) {
@@ -99,7 +100,7 @@
public boolean equals(Object o) {
if (o instanceof LabelVote) {
LabelVote l = (LabelVote) o;
- return Objects.equal(name, l.name)
+ return Objects.equals(name, l.name)
&& value == l.value;
}
return false;
diff --git a/lib/antlr/BUCK b/lib/antlr/BUCK
index 732b459..edf153c 100644
--- a/lib/antlr/BUCK
+++ b/lib/antlr/BUCK
@@ -1,11 +1,11 @@
include_defs('//lib/maven.defs')
-VERSION = '3.2'
+VERSION = '3.5.2'
maven_jar(
name = 'java_runtime',
id = 'org.antlr:antlr-runtime:' + VERSION,
- sha1 = '31c746001016c6226bd7356c9f87a6a084ce3715',
+ sha1 = 'cd9cd41361c155f3af0f653009dcecb08d8b4afd',
license = 'antlr',
)
@@ -18,8 +18,8 @@
maven_jar(
name = 'stringtemplate',
- id = 'org.antlr:stringtemplate:' + VERSION,
- sha1 = '6fe2e3bb57daebd1555494818909f9664376dd6c',
+ id = 'org.antlr:stringtemplate:4.0.2',
+ sha1 = 'e28e09e2d44d60506a7bcb004d6c23ff35c6ac08',
license = 'antlr',
attach_source = False,
visibility = [],
@@ -28,7 +28,7 @@
maven_jar(
name = 'tool',
id = 'org.antlr:antlr:' + VERSION,
- sha1 = '6b0acabea7bb3da058200a77178057e47e25cb69',
+ sha1 = 'c4a65c950bfc3e7d04309c515b2177c00baf7764',
license = 'antlr',
deps = [
':java_runtime',