Merge branch 'stable-2.9' into stable-2.10
* stable-2.9:
Consume JGit artifacts from Maven Central
Change-Id: I373228681fc1c02f48bcc1e2b556d53b2024bb3f
diff --git a/.buckconfig b/.buckconfig
index d53edcf..43bfa5e 100644
--- a/.buckconfig
+++ b/.buckconfig
@@ -1,4 +1,5 @@
[alias]
+ all = //:all
api = //:api
api_deploy = //tools/maven:api_deploy
api_install = //tools/maven:api_install
@@ -6,8 +7,10 @@
war_install = //tools/maven:war_install
chrome = //:chrome
docs = //Documentation:html
+ firefox = //:firefox
gerrit = //:gerrit
release = //:release
+ safari = //:safari
withdocs = //:withdocs
[buildfile]
@@ -21,4 +24,4 @@
[cache]
mode = dir
- dir = buck-out/cache
+ dir = ~/.gerritcodereview/buck-cache/cache
diff --git a/.buckversion b/.buckversion
index ff1c137..a0c6bc2 100644
--- a/.buckversion
+++ b/.buckversion
@@ -1 +1 @@
-2b80cf780ae31bee6609ebc1bbab9ce6fd004dbe
+0fe4569e871fd6588f7cbfb4b1d4a14baa791a9f
diff --git a/.gitignore b/.gitignore
index e979409..b356144 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
+/.apt_generated
/.classpath
+/.factorypath
/.project
/.settings/org.maven.ide.eclipse.prefs
/.settings/org.eclipse.m2e.core.prefs
@@ -16,4 +18,5 @@
/local.properties
*.pyc
/gwt-unitCache
+*.swp
*.asc
diff --git a/BUCK b/BUCK
index 5165efe..2cd3fa8 100644
--- a/BUCK
+++ b/BUCK
@@ -3,8 +3,9 @@
gerrit_war(name = 'gerrit')
gerrit_war(name = 'chrome', ui = 'ui_chrome')
gerrit_war(name = 'firefox', ui = 'ui_firefox')
+gerrit_war(name = 'safari', ui = 'ui_safari')
gerrit_war(name = 'withdocs', docs = True)
-gerrit_war(name = 'release', docs = True, context = ['//plugins:core.zip'], visibility = ['//tools/maven:'])
+gerrit_war(name = 'release', docs = True, context = ['//plugins:core'], visibility = ['//tools/maven:'])
API_DEPS = [
'//gerrit-extension-api:extension-api',
@@ -27,3 +28,13 @@
deps = API_DEPS,
out = 'api.zip',
)
+
+genrule(
+ name = 'all',
+ cmd = 'echo done >$OUT',
+ deps = [
+ ':api',
+ ':release',
+ ],
+ out = '__fake.all__',
+)
diff --git a/Documentation/BUCK b/Documentation/BUCK
index 9c2aea8..f070d7e 100644
--- a/Documentation/BUCK
+++ b/Documentation/BUCK
@@ -10,33 +10,23 @@
name = 'html',
cmd = 'cd $TMP;' +
'mkdir -p %s/images;' % DOC_DIR +
- 'unzip -q $SRCDIR/only_html.zip -d %s/;' % DOC_DIR +
+ 'unzip -q $(location %s) -d %s/;'
+ % (':generate_html', DOC_DIR) +
'for s in $SRCS;do ln -s $s %s;done;' % DOC_DIR +
'mv %s/*.{jpg,png} %s/images;' % (DOC_DIR, DOC_DIR) +
- 'rm %s/only_html.zip;' % DOC_DIR +
- 'rm %s/licenses.txt;' % DOC_DIR +
- 'cp $SRCDIR/licenses.txt LICENSES.txt;' +
+ 'cp $(location %s) LICENSES.txt;' % ':licenses.txt' +
'zip -qr $OUT *',
srcs = glob([
'images/*.jpg',
'images/*.png',
- ]) + [
- 'doc.css',
- genfile('licenses.txt'),
- genfile('only_html.zip'),
- ],
- deps = [
- ':generate_html',
- ':licenses.txt',
- ],
+ ]) + ['doc.css'],
out = 'html.zip',
visibility = ['PUBLIC'],
)
genasciidoc(
name = 'generate_html',
- srcs = SRCS + [genfile('licenses.txt')],
- deps = [':licenses.txt'],
+ srcs = SRCS + [':licenses.txt'],
attributes = documentation_attributes(git_describe()),
backend = 'html5',
out = 'only_html.zip',
@@ -66,18 +56,14 @@
'--prefix "%s/" ' % DOC_DIR +
'--in-ext ".txt" ' +
'--out-ext ".html" ' +
- '$SRCS',
- srcs = SRCS + [genfile('licenses.txt')],
- deps = [
- ':licenses.txt',
- '//lib/asciidoctor:doc_indexer',
- ],
+ '$SRCS ' +
+ '$(location :licenses.txt)',
+ srcs = SRCS,
out = 'index.jar',
)
prebuilt_jar(
name = 'index_lib',
- binary_jar = genfile('index.jar'),
- deps = [':index'],
+ binary_jar = ':index',
visibility = ['PUBLIC'],
)
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index dd57249..909f972 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -741,9 +741,11 @@
This category permits users to remove other users from the list of
reviewers on a change.
-The change owner, project owner and site administrator can always
-remove reviewers (even without having the `Remove Reviewer` access
-right assigned).
+Change owners can always remove reviewers who have given a zero or positive
+score (even without having the `Remove Reviewer` access right assigned).
+
+Project owners and site administrators can always remove any reviewer (even
+without having the `Remove Reviewer` access right assigned).
Users without this access right can only remove themselves from the
reviewer list on a change.
@@ -862,7 +864,7 @@
If it's desired to have the possibility to upload temporarily hidden
changes there's a specific permission for that. This enables someone
to add specific reviewers for early feedback before making the change
-publically visible. If you want to allow others than the owners to
+publicly visible. If you want to allow others than the owners to
publish a draft you also need to grant them `Publish Drafts`.
Optional access rights to grant:
diff --git a/Documentation/asciidoc.defs b/Documentation/asciidoc.defs
index 0175431..7adf265 100644
--- a/Documentation/asciidoc.defs
+++ b/Documentation/asciidoc.defs
@@ -16,14 +16,12 @@
name,
out,
srcs = [],
- deps = [],
attributes = [],
backend = None,
visibility = []):
EXPN = '.expn'
asciidoc = [
- 'cd $SRCDIR;',
'$(exe //lib/asciidoctor:asciidoc)',
'-z', '$OUT',
'--tmp', '$TMP',
@@ -36,33 +34,35 @@
asciidoc.extend(['-a', attribute])
asciidoc.append('$SRCS')
newsrcs = ["doc.css"]
- newdeps = deps + ['//lib/asciidoctor:asciidoc']
-
for src in srcs:
- tx = []
fn = src
- if fn.startswith('BUCKGEN:') :
- fn = src[8:]
- tx = [':' + fn]
+ # We have two cases: regular source files and generated files.
+ # Generated files are passed as targets ':foo', and ':' is removed.
+ # 1. regular files: cmd = '-s foo', srcs = ['foo']
+ # 2. generated files: cmd = '-s $(location :foo)', srcs = []
+ srcs = [src]
+ passed_src = fn
+ if fn.startswith(':') :
+ fn = src[1:]
+ srcs = []
+ passed_src = '$(location :%s)' % fn
ex = fn + EXPN
genrule(
name = ex,
cmd = '$(exe :replace_macros) --suffix=' + EXPN +
- ' -s $SRCDIR/%s' % fn +
+ ' -s ' + passed_src +
' -o $OUT',
- srcs = [src],
- deps = tx + [':replace_macros'],
+ srcs = srcs,
out = ex,
)
- newdeps.append(':' + ex)
- newsrcs.append(genfile(ex))
+
+ asciidoc.append('$(location :%s)' % ex)
genrule(
name = name,
cmd = ' '.join(asciidoc),
srcs = newsrcs,
- deps = newdeps,
out = out,
visibility = visibility,
)
diff --git a/Documentation/cmd-review.txt b/Documentation/cmd-review.txt
index 40393be..4c9962d 100644
--- a/Documentation/cmd-review.txt
+++ b/Documentation/cmd-review.txt
@@ -2,7 +2,7 @@
==============
== NAME
-gerrit review - Verify, approve and/or submit one or more patch sets
+gerrit review - Apply reviews to one or more patch sets
== SYNOPSIS
--
diff --git a/Documentation/cmd-show-caches.txt b/Documentation/cmd-show-caches.txt
index facd133..dd79d8b 100644
--- a/Documentation/cmd-show-caches.txt
+++ b/Documentation/cmd-show-caches.txt
@@ -22,14 +22,23 @@
operating system, and other details about the environment
that Gerrit Code Review is running in.
+--show-threads::
+ Show detailed counts for Gerrit specific threads.
+
--width::
-w::
Width of the output table.
== ACCESS
-Caller must be a member of the privileged 'Administrators' group,
-or have been granted
-link:access-control.html#capability_viewCaches[the 'View Caches' global capability].
+The caller must be a member of a group that is granted the
+link:access-control.html#capability_viewCaches[View Caches] capability
+or the link:access-control.html#capability_administrateServer[
+Administrate Server] capability.
+
+The summary information about SSH, threads, tasks, memory and JVM are
+only printed out if the caller is a member of a group that is granted
+the link:access-control.html#capability_administrateServer[Administrate
+Server] capability.
== SCRIPTING
Intended for interactive use only.
@@ -72,7 +81,9 @@
Tasks: 10 total = 6 running + 0 ready + 4 sleeping
Mem: 14.94g total = 3.04g used + 11.89g free + 10.00m buffers
28.44g max
- 107 open files, 4 cpus available, 371 threads
+ 107 open files
+
+ Threads: 4 CPUs available, 371 threads
====
== SEE ALSO
diff --git a/Documentation/config-contact.txt b/Documentation/config-contact.txt
index 58df8ea..e0795be 100644
--- a/Documentation/config-contact.txt
+++ b/Documentation/config-contact.txt
@@ -142,7 +142,6 @@
Full-Name: John Doe
Preferred-Email: jdoe@example.com
Identity: jd15@some-isp.com
-Identity: jdoe@example.com <https://www.google.com/accounts/o8/id?id=AIt18axxafvda821aQZaHDF1k8akbalk218sak>
Identity: jdoe@example.com <http://jdoe.blogger.com/>
Address:
123 Any Street
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 95d5283..632965f 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -145,6 +145,16 @@
The configured <<ldap.username,ldap.username>> identity is not used to obtain
account information.
+
+* OAUTH
++
+OAuth is a protocol that lets external apps request authorization to private
+details in a user's account without getting their password. This is
+preferred over Basic Authentication because tokens can be limited to specific
+types of data, and can be revoked by users at any time.
++
+Site owners have to register their application before getting started. Note
+that provider specific plugins must be used with this authentication scheme.
++
* `DEVELOPMENT_BECOME_ANY_ACCOUNT`
+
*DO NOT USE*. Only for use in a development environment.
@@ -391,23 +401,6 @@
specific config option in the `project.config` must be set:
link:config-project-config.html[receive.requireContributorAgreement].
-auth.allowGoogleAccountUpgrade::
-+
-Allows Google Account users to automatically update their Gerrit
-account when/if their Google Account OpenID identity token changes.
-Identity tokens can change if the server changes hostnames, or
-for other reasons known only to Google. The upgrade path works
-by matching users by email address if the identity is not present,
-and then changing the identity.
-+
-This setting also permits old Gerrit 1.x users to seamlessly upgrade
-from Google Accounts on Google App Engine to OpenID authentication.
-+
-Having this enabled incurs an extra database query when Google
-Account users register with the Gerrit server.
-+
-By default, unset/false.
-
[[auth.trustContainerAuth]]auth.trustContainerAuth::
+
If true then it is the responsibility of the container hosting
@@ -713,14 +706,24 @@
==== [[cache_options]]Cache Options
-[[cache.diff_intraline.maxIdleWorkers]]cache.diff_intraline.maxIdleWorkers::
+[[cache.diff.timeout]]cache.diff.timeout::
+
-Number of idle worker threads to maintain for the intraline difference
-computations. There is no upper bound on how many concurrent requests
-can occur at once, if additional threads are started to handle a peak
-load, only this many will remain idle afterwards.
+Maximum number of milliseconds to wait for diff data before giving up and
+falling back on a simpler diff algorithm that will not be able to break down
+modified regions into smaller ones. This is a work around for an infinite loop
+bug in the default difference algorithm implementation.
+
-Default is 1.5x number of available CPUs.
+Values should use common unit suffixes to express their setting:
++
+* ms, milliseconds
+* s, sec, second, seconds
+* m, min, minute, minutes
+* h, hr, hour, hours
+
++
+If a unit suffix is not specified, `milliseconds` is assumed.
++
+Default is 5 seconds.
[[cache.diff_intraline.timeout]]cache.diff_intraline.timeout::
+
@@ -796,7 +799,7 @@
With a configured 30 second delay a server with 4900 active users will
typically need to dedicate 1 CPU to the update check. 4900 users
divided by an average delay of 30 seconds is 163 requests arriving per
-second. If requests are served at ~6 ms response time, 1 CPU is
+second. If requests are served at \~6 ms response time, 1 CPU is
necessary to keep up with the update request traffic. On a smaller
user base of 500 active users, the default 30 second delay is only 17
requests per second and requires ~10% CPU.
@@ -812,6 +815,21 @@
+
Default is true.
+[[change.submitLabel]]change.submitLabel::
++
+Label name for the submit button.
++
+Default is "Submit".
+
+[[change.submitTooltip]]change.submitTooltip::
++
+Tooltip for the submit button. Variables available for replacement
+include `${patchSet}` for the current patch set number (1, 2, 3),
+`${branch}` for the branch name ("master") and `${commit}` for the
+abbreviated commit SHA-1 (`c9c0edb`).
++
+Default is "Submit patch set ${patchSet} into ${branch}".
+
[[changeMerge]]
=== Section changeMerge
@@ -1095,17 +1113,21 @@
Size of the buffer to store logging events for asynchronous logging.
Putting a larger value can protect threads from stalling when the
AsyncAppender threads are not fast enough to consume the logging events
-from the buffer. It also protects from loosing log entries in this case.
+from the buffer. It also protects from losing log entries in this case.
+
Default is 64 entries.
[[core.useRecursiveMerge]]core.useRecursiveMerge::
+
-Use JGit's new, experimental recursive merger for three-way merges.
-This only affects projects configured to automatically resolve
-conflicts.
+Use JGit's recursive merger for three-way merges. This only affects
+projects configured to automatically resolve conflicts.
+
-Default is false, but in a future release may default to true.
+As explained in this
+link:http://codicesoftware.blogspot.com/2011/09/merge-recursive-strategy.html[
+blog], the recursive merge produces better results if the two commits
+that are merged have more than one common predecessor.
++
+Default is true.
[[database]]
=== Section database
@@ -1333,6 +1355,84 @@
If `download.scheme` is not specified, SSH, HTTP and Anonymous HTTP
downloads are allowed.
+[[download.archive]]download.archive::
++
+Specifies which archive formats, if any, should be offered on the change
+screen:
++
+----
+[download]
+ archive = tar
+ archive = tbz2
+ archive = tgz
+ archive = txz
+----
+
+If `download.archive` is not specified defaults to all archive
+commands. Set to `off` or empty string to disable.
+
+[[gc]]
+=== Section gc
+
+This section allows to configure the git garbage collection and schedules it
+to run periodically. It will be triggered and executed sequentially for all
+projects.
+
+[[gc.startTime]]gc.startTime::
++
+Start time to define the first execution of the git garbage collection.
+If the configured `'gc.interval'` is shorter than `'gc.startTime - now'`
+the start time will be preponed by the maximum integral multiple of
+`'gc.interval'` so that the start time is still in the future.
++
+----
+<day of week> <hours>:<minutes>
+or
+<hours>:<minutes>
+
+<day of week> : Mon, Tue, Wed, Thu, Fri, Sat, Sun
+<hours> : 00-23
+<minutes> : 0-59
+----
+
+
+[[gc.interval]]gc.interval::
++
+Interval for periodic repetition of triggering the git garbage collection.
+The interval must be larger than zero. The following suffixes are supported
+to define the time unit for the interval:
++
+* `s, sec, second, seconds`
+* `m, min, minute, minutes`
+* `h, hr, hour, hours`
+* `d, day, days`
+* `w, week, weeks` (`1 week` is treated as `7 days`)
+* `mon, month, months` (`1 month` is treated as `30 days`)
+* `y, year, years` (`1 year` is treated as `365 days`)
+
+Examples::
++
+----
+gc.startTime = Fri 10:30
+gc.interval = 2 day
+----
++
+Assuming the server is started on Mon 7:00 -> `'startTime - now = 4 days 3:30 hours'`.
+This is larger than the interval hence prepone the start time
+by the maximum integral multiple of the interval so that start
+time is still in the future, i.e. prepone by 4 days. This yields
+a start time of Mon 10:30, next executions are Wed 10:30, Fri 10:30
+etc.
++
+----
+gc.startTime = 6:00
+gc.interval = 1 day
+----
++
+Assuming the server is started on Mon 7:00 this yields the first run on next Tuesday
+at 6:00 and a repetition interval of 1 day.
+
+
[[gerrit]]
=== Section gerrit
@@ -1354,6 +1454,13 @@
+
Defaults to `All-Projects` if not set.
+[[gerrit.allUsers]]gerrit.allUsers::
++
+Name of the project in which meta data of all users is stored.
+The name is relative to `gerrit.basePath`.
++
+Defaults to `All-Users` if not set.
+
[[gerrit.canonicalWebUrl]]gerrit.canonicalWebUrl::
+
The default URL for Gerrit to be accessed through.
@@ -1890,6 +1997,12 @@
If the file doesn't exist or can't be read the default robots.txt file
bundled with the .war will be used instead.
+[[httpd.registerMBeans]]httpd.registerMBeans::
++
+Enable (or disable) registration of Jetty MBeans for Java JMX.
++
+By default, false.
+
[[index]]
=== Section index
@@ -1899,9 +2012,6 @@
using the link:pgm-reindex.html[reindex program] before restarting the
Gerrit server.
-Open and closed changes are indexed in separate indexes named
-'changes_open' and 'changes_closed' respectively.
-
[[index.type]]index.type::
+
Type of secondary indexing employed by Gerrit. The supported
@@ -1925,11 +2035,12 @@
+
Defaults to 1 if not set, or set to a negative value.
-[[index.url]]index.url::
-+
-Only used when the type is `SOLR`.
-+
-URL of the index server.
+==== Lucene configuration
+
+Open and closed changes are indexed in separate indexes named
+'open' and 'closed' respectively.
+
+The following settings are only used when the index type is `LUCENE`.
[[index.defaultMaxClauseCount]]index.defaultMaxClauseCount::
+
@@ -1941,8 +2052,6 @@
[[index.name.ramBufferSize]]index.name.ramBufferSize::
+
-Only used when the type is `LUCENE`.
-+
Determines the amount of RAM that may be used for buffering added documents
and deletions before they are flushed to the index. See the
link:http://lucene.apache.org/core/4_6_0/core/org/apache/lucene/index/LiveIndexWriterConfig.html#setRAMBufferSizeMB(double)[
@@ -1952,8 +2061,6 @@
[[index.name.maxBufferedDocs]]index.name.maxBufferedDocs::
+
-Only used when the type is `LUCENE`.
-+
Determines the minimal number of documents required before the buffered
in-memory documents are flushed to the index. Large values generally
give faster indexing. See the
@@ -1965,8 +2072,6 @@
[[index.name.commitWithin]]index.name.commitWithin::
+
-Only used when the type is `LUCENE`.
-+
Determines the period at which changes are automatically committed to
stable store on disk. This is a costly operation and may block
additional index writes, so lower with caution.
@@ -1981,10 +2086,10 @@
If negative, `commitWithin` is disabled. Changes are flushed to disk when
the in-memory buffer fills, but only committed and guaranteed to be synced
to disk when the process finishes.
-
++
Defaults to 300000 ms (5 minutes).
-Sample index configuration:
+Sample Lucene index configuration:
----
[index]
type = LUCENE
@@ -1999,6 +2104,17 @@
maxBufferedDocs = 500
----
+==== Solr configuration
+
+Open and closed changes are indexed in separate indexes named
+'changes_open' and 'changes_closed' respectively.
+
+The following settings are only used when the index type is `SOLR`.
+
+[[index.url]]index.url::
++
+URL of the index server.
+
[[ldap]]
=== Section ldap
@@ -2176,6 +2292,16 @@
Default is unset for RFC 2307 servers (disabled)
and `memberOf` for Active Directory.
+[[ldap.fetchMemberOfEagerly]]ldap.fetchMemberOfEagerly::
++
+_(Optional)_ Whether to fetch the `memberOf` account attribute on
+login. Setups which use LDAP for user authentication but don't make
+use of the LDAP groups may benefit from setting this option to `false`
+as this will result in a much faster LDAP login.
++
+Default is unset for RFC 2307 servers (disabled) and `true` for
+Active Directory.
+
[[ldap.groupBase]]ldap.groupBase::
+
Root of the tree containing all group objects. This is typically
@@ -2286,6 +2412,47 @@
must have the DWORD value `allowtgtsessionkey` set to 1 and the account must not
have local administrator privileges.
+[[ldap.useConnectionPooling]]ldap.useConnectionPooling::
++
+_(Optional)_ Enable the LDAP connection pooling or not.
++
+If it is true, the LDAP service provider maintains a pool of (possibly)
+previously used connections and assigns them to a Context instance as
+needed. When a Context instance is done with a connection (closed or
+garbage collected), the connection is returned to the pool for future use.
++
+For details, see link:http://docs.oracle.com/javase/tutorial/jndi/ldap/pool.html[
+LDAP connection management (Pool)] and link:http://docs.oracle.com/javase/tutorial/jndi/ldap/config.html[
+LDAP connection management (Configuration)]
++
+By default, false.
+
+[[ldap.connectTimeout]]ldap.connectTimeout::
++
+_(Optional)_ Timeout period for establishment of an LDAP connection.
++
+The value is in the usual time-unit format like "1 s", "100 ms",
+etc...
++
+By default there is no timeout and Gerrit will wait indefinitely.
+
+[[ldap-connection-pooling]]
+==== LDAP Connection Pooling
+Once LDAP connection pooling is enabled by setting the link:#ldap.useConnectionPooling[
+ldap.useConnectionPooling] configuration property to `true`, the connection pool
+can be configured using JVM system properties as explained in the
+link:http://docs.oracle.com/javase/7/docs/technotes/guides/jndi/jndi-ldap.html#POOL[
+Java SE Documentation].
+
+For standalone Gerrit (running with the embedded Jetty), JVM system properties
+are specified in the link:#container[container section]:
+
+----
+ javaOptions = -Dcom.sun.jndi.ldap.connect.pool.maxsize=20
+ javaOptions = -Dcom.sun.jndi.ldap.connect.pool.prefsize=10
+ javaOptions = -Dcom.sun.jndi.ldap.connect.pool.timeout=300000
+----
+
[[mimetype]]
=== Section mimetype
@@ -2696,6 +2863,14 @@
[[sshd]]
=== Section sshd
+[[sshd.backend]]sshd.backend::
++
+Starting from version 0.9.0 Apache SSHD project added support for NIO2
+IoSession. To use the new NIO2 session the `backend` option must be set
+to `NIO2`.
++
+By default, `MINA`.
+
[[sshd.listenAddress]]sshd.listenAddress::
+
Specifies the local addresses the internal SSHD should listen
@@ -2897,6 +3072,24 @@
+
By default, true.
+[[sshd.rekeyBytesLimit]]sshd.rekeyBytesLimit::
++
+The SSH daemon will issue a rekeying after a certain amount of data.
+This configuration option allows you to tweak that setting.
++
+By default, 1073741824 (bytes, 1GB).
++
+The rekeyBytesLimit cannot be set to lower than 32.
+
+[[sshd.rekeyTimeLimit]]sshd.rekeyTimeLimit::
++
+The SSH daemon will issue a rekeying after a certain amount of time.
+This configuration option allows you to tweak that setting.
++
+By default, 1h.
++
+Set to 0 to disable this check.
+
[[suggest]]
=== Section suggest
diff --git a/Documentation/config-gitweb.txt b/Documentation/config-gitweb.txt
index fb7c961..d1cee57 100644
--- a/Documentation/config-gitweb.txt
+++ b/Documentation/config-gitweb.txt
@@ -268,7 +268,7 @@
=== SEE ALSO
* link:config-gerrit.html#gitweb[Section gitweb]
-* link:http://hjemli.net/git/cgit/[cgit]
+* link:http://git.zx2c4.com/cgit/about/[cgit]
GERRIT
------
diff --git a/Documentation/config-hooks.txt b/Documentation/config-hooks.txt
index 0f4d094..8d58d36 100644
--- a/Documentation/config-hooks.txt
+++ b/Documentation/config-hooks.txt
@@ -41,15 +41,24 @@
changes and drafts).
====
- patchset-created --change <change id> --is-draft <boolean> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --uploader <uploader> --commit <sha1> --patchset <patchset id>
+ patchset-created --change <change id> --is-draft <boolean> --kind <change kind> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --uploader <uploader> --commit <sha1> --patchset <patchset id>
====
+kind:: change kind represents the kind of change uploaded, also represented in link:json.html#patchSet[patchSet]
+
+ REWORK;; Nontrivial content changes.
+
+ TRIVIAL_REBASE;; Conflict-free merge between the new parent and the prior patch set.
+
+ NO_CODE_CHANGE;; No code changed; same tree and same parents.
+
+
=== draft-published
This is called whenever a draft change is published.
====
- draft-published --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --uploader <uploader> --commit <sha1> --patchset <patchset id>
+ draft-published --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --uploader <uploader> --commit <sha1> --patchset <patchset id>
====
=== comment-added
@@ -57,7 +66,7 @@
This is called whenever a comment is added to a change.
====
- comment-added --change <change id> --is-draft <boolean> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --author <comment author> --commit <commit> --comment <comment> [--<approval category id> <score> --<approval category id> <score> ...]
+ comment-added --change <change id> --is-draft <boolean> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --author <comment author> --commit <commit> --comment <comment> [--<approval category id> <score> --<approval category id> <score> ...]
====
=== change-merged
@@ -65,7 +74,7 @@
Called whenever a change has been merged.
====
- change-merged --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --submitter <submitter> --commit <sha1>
+ change-merged --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --submitter <submitter> --commit <sha1>
====
=== merge-failed
@@ -73,7 +82,7 @@
Called whenever a change has failed to merge.
====
- merge-failed --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --submitter <submitter> --commit <sha1> --reason <reason>
+ merge-failed --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --submitter <submitter> --commit <sha1> --reason <reason>
====
=== change-abandoned
@@ -81,7 +90,7 @@
Called whenever a change has been abandoned.
====
- change-abandoned --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --abandoner <abandoner> --commit <sha1> --reason <reason>
+ change-abandoned --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --abandoner <abandoner> --commit <sha1> --reason <reason>
====
=== change-restored
@@ -89,7 +98,7 @@
Called whenever a change has been restored.
====
- change-restored --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --restorer <restorer> --commit <sha1> --reason <reason>
+ change-restored --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --restorer <restorer> --commit <sha1> --reason <reason>
====
=== ref-updated
@@ -105,7 +114,7 @@
Called whenever a reviewer is added to a change.
====
- reviewer-added --change <change id> --change-url <change url> --project <project name> --branch <branch> --reviewer <reviewer>
+ reviewer-added --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --reviewer <reviewer>
====
=== topic-changed
@@ -113,7 +122,7 @@
Called whenever a change's topic is changed from the Web UI or via the REST API.
====
- topic-changed --change <change id> --project <project name> --branch <branch> --changer <changer> --old-topic <old topic> --new-topic <new topic>
+ topic-changed --change <change id> --change-owner <change owner> --project <project name> --branch <branch> --changer <changer> --old-topic <old topic> --new-topic <new topic>
====
=== cla-signed
diff --git a/Documentation/config-labels.txt b/Documentation/config-labels.txt
index fc25f22..aaeb834 100644
--- a/Documentation/config-labels.txt
+++ b/Documentation/config-labels.txt
@@ -169,12 +169,18 @@
optional leading `+`.
-[[label_abbreviation]]
-=== `label.Label-Name.abbreviation`
+[[label_defaultValue]]
+=== `label.Label-Name.defaultValue`
-An abbreviated name for a label shown as a compact column header, for
-example on project dashboards. Defaults to all the uppercase characters
-in the label name, e.g. `Label-Name` is abbreviated by default as `LN`.
+The default value (or score) for the label. The defaultValue must be
+within the range of valid label values. It is an optional label setting,
+if not defined the defaultValue for the label will be 0. When a
+defaultValue is defined, that value will get set in the Reply dialog
+by default.
+
+A defaultValue can be set to a score that is outside of the permissible
+range for a user. In that case the score that will get set in the Reply
+box will be either the lowest or highest score in the permissible range.
[[label_function]]
@@ -297,6 +303,32 @@
copyright` will block submit, while `+1 Copyright clear` is required to
enable submit.
+=== Default Value Example
+
+This example attempts to describe how a label default value works with the
+user permissions. Assume the configuration below.
+
+====
+ [access "refs/heads/*"]
+ label-Snarky-Review = -3..+3 group Administrators
+ label-Snarky-Review = -2..+2 group Project Owners
+ label-Snarky-Review = -1..+1 group Registered Users
+ [label "Snarky-Review"]
+ value = -3 Ohh, hell no!
+ value = -2 Hmm, I'm not a fan
+ value = -1 I'm not sure I like this
+ value = 0 No score
+ value = +1 I like, but need another to like it as well
+ value = +2 Hmm, this is pretty nice
+ value = +3 Ohh, hell yes!
+ defaultValue = -3
+====
+
+Upon clicking the Reply button:
+* Administrators have all scores (-3..+3) available, -3 is set as the default.
+* Project Owners have limited scores (-2..+2) available, -2 is set as the default.
+* Registered Users have limited scores (-1..+1) available, -1 is set as the default.
+
GERRIT
------
Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/config-project-config.txt b/Documentation/config-project-config.txt
index e66343c..43ede06 100644
--- a/Documentation/config-project-config.txt
+++ b/Documentation/config-project-config.txt
@@ -171,6 +171,21 @@
documentation for a full list of available access rights.
+[[mimetype-section]]
+=== MIME Types section
+
+The +mimetype+ section may be configured to force the web code
+reviewer to return certain MIME types by file path. MIME types
+may be used to activate syntax highlighting.
+
+----
+[mimetype "text/x-c"]
+ path = *.pkt
+[mimetype "text/x-java"]
+ path = api/current.txt
+----
+
+
[[capability-section]]
=== Capability section
@@ -183,6 +198,41 @@
documentation for a full list of available capabilities.
+[[branchOrder-section]]
+=== branchOrder section
+
+Defines a branch ordering which is used for backporting of changes.
+Backporting will be offered for a change (in the Gerrit UI) for all
+more stable branches where the change can merge cleanly.
+
+[[branchOrder.branch]]branchOrder.branch::
++
+A branch name, typically multiple values will be defined. The order of branch
+names in this section defines the branch order. The topmost is considered to be
+the least stable branch (typically the master branch) and the last one the
+most stable (typically the last maintained release branch).
+
+Example:
+
+----
+[branchOrder]
+ branch = master
+ branch = stable-2.9
+ branch = stable-2.8
+ branch = stable-2.7
+----
+
+The `branchOrder` section is inheritable. This is useful when multiple or all
+projects follow the same branch rules. A `branchOrder` section in a child
+project completely overrides any `branchOrder` section from a parent i.e. there
+is no merging of `branchOrder` sections. A present but empty `branchOrder`
+section removes all inherited branch order.
+
+Branches not listed in this section will not be included in the mergeability
+check. If the `branchOrder` section is not defined then the mergeability of a
+change into other branches will not be done.
+
+
[[file-groups]]
== The file +groups+
diff --git a/Documentation/config-sso.txt b/Documentation/config-sso.txt
index 8c82091..e4cf20e 100644
--- a/Documentation/config-sso.txt
+++ b/Documentation/config-sso.txt
@@ -43,9 +43,9 @@
* `http://` -- trust all OpenID providers using the HTTP protocol
* `https://` -- trust all OpenID providers using the HTTPS protocol
-To trust only Google Accounts:
+To trust only Yahoo!:
====
- git config --file $site_path/etc/gerrit.config auth.trustedOpenID 'https://www.google.com/accounts/o8/id?id='
+ git config --file $site_path/etc/gerrit.config auth.trustedOpenID https://me.yahoo.com
====
=== Database Schema
diff --git a/Documentation/config-validation.txt b/Documentation/config-validation.txt
index b7843a7..5d23c79 100644
--- a/Documentation/config-validation.txt
+++ b/Documentation/config-validation.txt
@@ -32,6 +32,19 @@
If the commit fails the validation, the plugin can throw an exception
which will cause the merge to fail.
+[[pre-upload-validation]]
+== Pre-upload validation
+
+
+Plugins implementing the `UploadValidationListener` interface can
+perform additional validation checks before any upload operations
+(clone, fetch, pull). The validation is executed right before Gerrit
+begins to send a pack back to the git client.
+
+If upload fails the validation, the plugin can throw an exception
+which will cause the upload to fail and the exception's message text
+will be reported to the git client.
+
[[new-project-validation]]
== New project validation
diff --git a/Documentation/database-setup.txt b/Documentation/database-setup.txt
index bbaa748..4f854fb 100644
--- a/Documentation/database-setup.txt
+++ b/Documentation/database-setup.txt
@@ -103,6 +103,49 @@
password = secret_pasword
----
+[[createdb_maxdb]]
+=== SAP MaxDB
+
+SAP MaxDB is a supported database for running Gerrit Code Review. However it is
+recommended only for environments where you intend to run Gerrit on an existing
+MaxDB installation to reduce administrative overhead.
+
+In the MaxDB studio or using the SQLCLI command line interface create a user
+'gerrit2' with the user class 'RESOURCE' and a password <secret password>. This
+will also create an associated schema on the database.
+
+To run Gerrit on MaxDB, you need to obtain the MaxDB JDBC driver. It can be
+found in your MaxDB installation at the following location:
+
+- on Windows 64bit at "C:\Program Files\sdb\MaxDB\runtime\jar\sapdbc.jar"
+- on Linux at "/opt/sdb/MaxDB/runtime/jar/sapdbc.jar"
+
+It needs to be stored in the 'lib' folder of the review site.
+
+In the following sample database section it is assumed that the database name is
+'reviewdb' and the database is installed on localhost:
+
+In $site_path/etc/gerrit.config:
+
+----
+[database]
+ type = maxdb
+ database = reviewdb
+ hostname = localhost
+ username = gerrit2
+
+----
+
+In $site_path/etc/secure.config:
+
+----
+[database]
+ password = <secret password>
+----
+
+Visit SAP MaxDB's link:http://maxdb.sap.com/documentation/[documentation] for further
+information regarding using SAP MaxDB.
+
GERRIT
------
diff --git a/Documentation/dev-buck.txt b/Documentation/dev-buck.txt
index 98cd513..ce40a01 100644
--- a/Documentation/dev-buck.txt
+++ b/Documentation/dev-buck.txt
@@ -5,7 +5,7 @@
There is currently no binary distribution of Buck, so it has to be manually
built and installed. Apache Ant is required. Currently only Linux and Mac
-OS are supported. Gerrit's buck wrappers require Python version 2.6 or higher.
+OS are supported. Buck requires Python version 2.7 to be installed.
Clone the git and build it:
@@ -42,13 +42,6 @@
which buck
----
-If you plan to use the link:#buck-daemon[Buck daemon] add a symbolic
-link in `~/bin` to the buckd executable:
-
-----
- ln -s `pwd`/bin/buckd ~/bin/
-----
-
To enable autocompletion of buck commands, install the autocompletion
script from `./scripts/bash_completion` in the buck project. Refer to
the script's header comments for installation instructions.
@@ -249,13 +242,22 @@
buck-out/gen/release.war
----
+[[all]]
+=== Combined build target
+
+To build release and api targets, a combined build target is provided:
+
+----
+ buck build all
+----
+
[[tests]]
== Running Unit Tests
To run all tests including acceptance tests:
----
- buck test --all
+ buck test
----
To exclude slow tests:
@@ -264,6 +266,21 @@
buck test --all --exclude slow
----
+To include a specific group of acceptance tests:
+
+----
+ buck test --all --include api
+----
+
+The following groups of tests are currently supported:
+
+* api
+* git
+* pgm
+* rest
+* server
+* ssh
+
To run a specific test, e.g. the acceptance test
`com.google.gerrit.acceptance.git.HttpPushForReviewIT`:
@@ -436,17 +453,52 @@
directories and they will not interfere with each other. Buck's documentation
covers daemon in http://facebook.github.io/buck/command/buckd.html[buckd].
-The trivial use case is to run `buckd` from the project's root directory and
-run `buck` as usual:
+To use `buckd` the additional
+link:https://facebook.github.io/watchman[watchman] program must be installed.
+
+[[watchman]]
+=== Installing watchman
+
+Watchman is used internally by Buck to monitor directory trees and is needed
+for buck daemon to work properly. Because buckd is activated by default in the
+latest version of Buck, it searches for the watchman executable in the
+path and issues a warning when it is not found and kills buckd.
+
+To prepare watchman installation on Linux:
----
- buckd
- buck build gerrit
- Using buckd.
- [-] PARSING BUILD FILES...FINISHED 0.6s
- [-] BUILDING...FINISHED 0.2s
+ git clone https://github.com/facebook/watchman.git
+ cd watchman
+ ./autogen.sh
----
+To install it in user home directory (without root privileges):
+
+----
+ ./configure --prefix $HOME/watchman
+ make install
+----
+
+To install it system wide:
+
+----
+ ./configure
+ make
+ sudo make install
+----
+
+Put $HOME/watchman/bin/watchman in path or link to $HOME/bin/watchman.
+
+To install watchman on OS X:
+
+----
+ brew install --HEAD watchman
+----
+
+See the original documentation for more information:
+link:https://facebook.github.io/watchman/docs/install.html[Watchman
+installation].
+
=== Override Buck's settings
Additional JVM args for Buck can be set in `.buckjavaargs` in the
@@ -461,15 +513,14 @@
== Rerun unit tests
-If for some reasons tests, that were already run must be repeated, unit test
-cache must be removed fist. That's because the test execution results are
-cached by Buck:
+Test execution results are cached by Buck. If a test that was already run
+needs to be repeated, the unit test cache for that test must be removed first:
----
$ rm -rf buck-out/bin/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/.AddRemoveGroupMembersIT/
----
-After clearing the cache test can be rerun again:
+After clearing the cache, the test can be run again:
----
$ buck test //gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group:AddRemoveGroupMembersIT
@@ -478,25 +529,33 @@
TESTS PASSED
----
-An alternative approach is to use a Buck feature:
---test-selectors (-filters, -f) option:
+An alternative approach is to use Buck's `--filters` (`-f`) option:
----
- buck test --all -f 'com.google.gerrit.acceptance.rest.change.SubmitByMergeAlwaysIT'
+ buck test -f 'com.google.gerrit.acceptance.rest.change.SubmitByMergeAlwaysIT'
TESTING SELECTED TESTS
PASS 14,5s 6 Passed 0 Failed com.google.gerrit.acceptance.rest.change.SubmitByMergeAlwaysIT
TESTS PASSED
----
-When this option is used, cache is disabled per design and doesn't need to be deleted.
-Note: when -f option is used, the whole unit test cache is dropped. As a consequence,
+When this option is used, the cache is disabled per design and doesn't need to
+be explicitly deleted.
+
+Note that when this option is used, the whole unit test cache is dropped, so
repeating the
----
-buck test --all
+buck test
----
-would re-execute all tests again.
+causes all tests to be executed again.
+
+To run tests without using cached results at all, use the `--no-results-cache`
+option:
+
+----
+buck test --no-results-cache
+----
GERRIT
------
diff --git a/Documentation/dev-contributing.txt b/Documentation/dev-contributing.txt
index 5e307f9..95a5554 100644
--- a/Documentation/dev-contributing.txt
+++ b/Documentation/dev-contributing.txt
@@ -171,11 +171,13 @@
* Define any static interfaces next in your class.
* Define non static interfaces after static interfaces in your
class.
- * Next you should define static types and members.
+ * Next you should define static types, members, and methods, in
+ decreasing order of visibility (public to private).
* Finally instance members, then constructors, and then instance
methods.
- * Some common exceptions are private helper static methods which
- might appear near the instance methods which they help.
+ * Some common exceptions are private helper static methods, which
+ might appear near the instance methods which they help (but may
+ also appear at the top).
* Getters and setters for the same instance field should usually
be near each other baring a good reason not to.
* If you are using assisted injection, the factory for your class
diff --git a/Documentation/dev-inspector.txt b/Documentation/dev-inspector.txt
index 2d56283..7c13a7d 100644
--- a/Documentation/dev-inspector.txt
+++ b/Documentation/dev-inspector.txt
@@ -240,7 +240,7 @@
----
[2012-04-17 14:20:30,558] INFO com.google.gerrit.pgm.shell.JythonShell : Jython shell instance created.
-[2012-04-17 14:20:38,005] ERROR com.google.gerrit.pgm.shell.JythonShell : Exception occured while loading file Startup.py :
+[2012-04-17 14:20:38,005] ERROR com.google.gerrit.pgm.shell.JythonShell : Exception occurred while loading file Startup.py :
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 76c3da9..1030f63 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -36,7 +36,7 @@
----
mvn archetype:generate -DarchetypeGroupId=com.google.gerrit \
-DarchetypeArtifactId=gerrit-plugin-archetype \
- -DarchetypeVersion=2.9 \
+ -DarchetypeVersion=2.10.7 \
-DgroupId=com.googlesource.gerrit.plugins.testplugin \
-DartifactId=testplugin
----
@@ -400,6 +400,10 @@
+
Update of HEAD on a project
+* `com.google.gerrit.extensions.events.UsageDataPublishedListener`:
++
+Publication of usage data
+
[[stream-events]]
== Sending Events to the Events Stream
@@ -432,6 +436,14 @@
for those plugins which would like to monitor changes in Git
repositories.
+[[pre-upload-hook]]
+== Pre Upload-Pack Hooks
+
+Plugins may register PreUploadHook instances in order to get
+notified when JGit is about to upload a pack. This may be useful
+for those plugins which would like to monitor usage in Git
+repositories.
+
[[ssh]]
== SSH Commands
@@ -1707,6 +1719,42 @@
The download schemes and download commands which are used most often
are provided by the Gerrit core plugin `download-commands`.
+[[links-to-external-tools]]
+== Links To External Tools
+
+Gerrit has extension points that enables development of a
+light-weight plugin that links commits to external
+tools (GitBlit, CGit, company specific resources etc).
+
+PatchSetWebLinks will appear to the right of the commit-SHA1 in the UI.
+
+[source, java]
+----
+import com.google.gerrit.extensions.annotations.Listen;
+import com.google.gerrit.extensions.webui.PatchSetWebLink;;
+
+@Listen
+public class MyWeblinkPlugin implements PatchSetWebLink {
+
+ private String name = "MyLink";
+ private String placeHolderUrlProjectCommit = "http://my.tool.com/project=%s/commit=%s";
+
+ @Override
+ public String getLinkName() {
+ return name ;
+ }
+
+ @Override
+ public String getPatchSetUrl(String project, String commit) {
+ return String.format(placeHolderUrlProjectCommit, project, commit);
+ }
+
+}
+----
+
+ProjectWebLinks will appear in the project list in the
+`Repository Browser` column.
+
[[documentation]]
== Documentation
diff --git a/Documentation/dev-readme.txt b/Documentation/dev-readme.txt
index 2b0cda8..da1ca70 100644
--- a/Documentation/dev-readme.txt
+++ b/Documentation/dev-readme.txt
@@ -50,15 +50,24 @@
refer to: link:dev-buck.html#eclipse[Eclipse integration with Buck].
+== Configuring IntelliJ IDEA
+
+To use IntelliJ IDEA for development, the easiest way is to follow
+Eclipse integration and then open it as Eclipse project in IDEA.
+You need the Eclipse plugin activated in IntelliJ IDEA.
+
+
== Mac OS X
-On Mac OS X ensure "Java For Mac OS X 10.5 Upate 4" (or later) has
-been installed, and that `JAVA_HOME` is set to
-"/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home".
-Check the installed version by running `java -version` and looking
-for 'build 1.6.0_13-b03-211'. Versions of Java 6 prior to this
-version crash during the build due to a bug in the JIT compiler.
+On Mac OS X ensure "Java For Mac OS X 10.5 Update 4" (or later) has
+been installed, and that `JAVA_HOME` is set to the
+link:install.html#Requirements[required Java version].
+Java installations can typically be found in
+"/System/Library/Frameworks/JavaVM.framework/Versions".
+
+You can check the installed Java version by running `java -version` in
+the terminal.
[[init]]
== Site Initialization
diff --git a/Documentation/dev-release.txt b/Documentation/dev-release.txt
index e966899..6cf9edf 100644
--- a/Documentation/dev-release.txt
+++ b/Documentation/dev-release.txt
@@ -226,8 +226,8 @@
** Go to the link:https://oss.sonatype.org/[Sonatype Nexus Server] and
sign in with your Sonatype credentials.
-** Click in the left navigation bar under `Build Promotion` on
-`Staging Repositories` and find the `comgooglegerrit-XXXX` staging
+** Click on 'Build Promotion' in the left navigation bar under
+'Staging Repositories' and find the `comgooglegerrit-XXXX` staging
repository.
** Verify its content
@@ -282,6 +282,17 @@
+
http://central.maven.org/maven2/com/google/gerrit/
+* [optional]: View download statistics
+
+** Sign in to the
+link:https://oss.sonatype.org/[Sonatype Nexus Server].
+
+** Click on 'Views/Repositories' in the left navigation bar under
+'Central Statistics'.
+
+** Select `com.google.gerrit` as `Project`.
+
+
[[push-stable]]
==== Push the Stable Branch
diff --git a/Documentation/dev-rest-api.txt b/Documentation/dev-rest-api.txt
index d07da62..ec4b666 100644
--- a/Documentation/dev-rest-api.txt
+++ b/Documentation/dev-rest-api.txt
@@ -44,6 +44,11 @@
curl -X PUT --data-binary @testdata.txt --header "Content-Type: text/plain" http://localhost:8080/path/to/api/
----
+Example to set a Gerrit project's link:rest-api-projects.html#set-project-description[description]:
+
+----
+ curl -X PUT --digest --user john:2LlAB3K9B0PF --data-binary @project-desc.txt --header "Content-Type: application/json;charset=UTF-8" http://localhost:8080/a/projects/myproject/description
+----
=== Authentication
@@ -65,7 +70,6 @@
In both cases, the password should be the user's link:user-upload.html#http[HTTP password].
-
=== Verifying Header Content
To verify the headers returned from a REST API call, use `curl` in verbose mode:
diff --git a/Documentation/gen_licenses.py b/Documentation/gen_licenses.py
index fb03526..61d2e24 100755
--- a/Documentation/gen_licenses.py
+++ b/Documentation/gen_licenses.py
@@ -18,15 +18,23 @@
from __future__ import print_function
from collections import defaultdict, deque
+from os import chdir, path
import re
from shutil import copyfileobj
from subprocess import Popen, PIPE
-from sys import stdout
+from sys import stdout, stderr
MAIN = ['//gerrit-pgm:pgm', '//gerrit-gwtui:ui_module']
+KNOWN_PROVIDED_DEPS = [
+ '//lib/bouncycastle:bcpg',
+ '//lib/bouncycastle:bcpkix',
+ '//lib/bouncycastle:bcprov',
+]
def parse_graph():
graph = defaultdict(list)
+ while not path.isfile('.buckconfig'):
+ chdir('..')
p = Popen(
['buck', 'audit', 'classpath', '--dot'] + MAIN,
stdout = PIPE)
@@ -35,7 +43,14 @@
if not m:
continue
target, dep = m.group(1), m.group(2)
- if not target.endswith('__compile'):
+ # Dependencies included in provided_deps set are contained in audit
+ # classpath and must be sorted out. That's safe thing to do because
+ # they are not included in the final artifact.
+ if "DO_NOT_DISTRIBUTE" in dep:
+ if not target in KNOWN_PROVIDED_DEPS:
+ print('DO_NOT_DISTRIBUTE license for target: %s' % target, file=stderr)
+ exit(1)
+ else:
graph[target].append(dep)
r = p.wait()
if r != 0:
diff --git a/Documentation/images/link.png b/Documentation/images/link.png
new file mode 100644
index 0000000..621443e
--- /dev/null
+++ b/Documentation/images/link.png
Binary files differ
diff --git a/Documentation/images/user-review-ui-side-by-side-diff-screen-preferences-popup.png b/Documentation/images/user-review-ui-side-by-side-diff-screen-preferences-popup.png
index 06e1f1f..35e29a3 100644
--- a/Documentation/images/user-review-ui-side-by-side-diff-screen-preferences-popup.png
+++ b/Documentation/images/user-review-ui-side-by-side-diff-screen-preferences-popup.png
Binary files differ
diff --git a/Documentation/install-j2ee.txt b/Documentation/install-j2ee.txt
index 50eccc2..f7252e0 100644
--- a/Documentation/install-j2ee.txt
+++ b/Documentation/install-j2ee.txt
@@ -109,6 +109,24 @@
`system_config`) is as simple as touching the context config file:
`'$JETTY_HOME'/contexts/gerrit.xml`
+[[tomcat]]
+== Tomcat 7.x
+
+If a reverse proxy is used in front of Tomcat then see the
+link:config-reverseproxy.html[configuration instructions for encoding
+slashes]. Otherwise Tomcat must be configured to encode slashes, by adding
+`-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true` to the
+`CATALINA_OPTS` environment variable.
+
+Excerpt from the
+link:https://tomcat.apache.org/tomcat-7.0-doc/config/systemprops.html[
+documentation]:
+
+----
+Property org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH:
+If this is true '%2F' and '%5C' will be permitted as path delimiters.
+If not specified, the default value of false will be used.
+----
GERRIT
------
diff --git a/Documentation/intro-project-owner.txt b/Documentation/intro-project-owner.txt
index 78b819e..c55a43c 100644
--- a/Documentation/intro-project-owner.txt
+++ b/Documentation/intro-project-owner.txt
@@ -395,6 +395,30 @@
link:access-control.html#capability_streamEvents[Stream Events] global
capability assigned.
+[[commit-validation]]
+== Commit Validation
+
+Gerrit provides an
+link:https://gerrit-review.googlesource.com/Documentation/config-validation.html#new-commit-validation[
+extension point to do validation of new commits]. A Gerrit plugin
+implementing this extension point can perform validation checks when
+new commits are pushed to Gerrit. The plugin can either provide a
+message to the client or reject the commit and cause the push to fail.
+
+There are some plugins available that provide commit validation:
+
+- link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/uploadvalidator[
+ uploadvalidator]:
++
+The `uploadvalidator` plugin allows project owners to configure blocked
+file extensions, required footers and a maximum allowed path length.
+
+- link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/commit-message-length-validator[
+ commit-message-length-validator]
++
+The `commit-message-length-validator` core plugin validates that commit
+messages conform to line length limits.
+
[[branch-administration]]
== Branch Administration
diff --git a/Documentation/js-api.txt b/Documentation/js-api.txt
index 396edf6..883198a 100644
--- a/Documentation/js-api.txt
+++ b/Documentation/js-api.txt
@@ -168,8 +168,9 @@
self.onAction(type, view_name, callback);
----
-* type: `'change'`, `'revision'` or `'project'`, indicating which type
- of resource the `UiAction` was bound to in the server.
+* type: `'change'`, `'revision'`, `'project'`, or `'branch'`
+ indicating which type of resource the `UiAction` was bound to
+ in the server.
* view_name: string appearing in URLs to name the view. This is the
second argument of the `get()`, `post()`, `put()`, and `delete()`
@@ -837,8 +838,8 @@
Gerrit.onAction(type, view_name, callback);
----
-* type: `'change'` or `'revision'`, indicating what sort of resource
- the `UiAction` was bound to in the server.
+* type: `'change'`, `'revision'`, `'project'` or `'branch'` indicating
+ what sort of resource the `UiAction` was bound to in the server.
* view_name: string appearing in URLs to name the view. This is the
second argument of the `get()`, `post()`, `put()`, and `delete()`
diff --git a/Documentation/json.txt b/Documentation/json.txt
index 4034050..b45f404 100644
--- a/Documentation/json.txt
+++ b/Documentation/json.txt
@@ -115,6 +115,14 @@
isDraft:: Whether or not the patch set is a draft patch set.
+kind:: Kind of change uploaded.
+
+ REWORK;; Nontrivial content changes.
+
+ TRIVIAL_REBASE;; Conflict-free merge between the new parent and the prior patch set.
+
+ NO_CODE_CHANGE;; No code changed; same tree and same parents.
+
approvals:: The <<approval,approval attribute>> granted.
comments:: All comments for this patchset in <<patchsetcomment,patchsetComment attributes>>.
diff --git a/Documentation/prolog-cookbook.txt b/Documentation/prolog-cookbook.txt
index 5bff6bf..2fedb9e 100644
--- a/Documentation/prolog-cookbook.txt
+++ b/Documentation/prolog-cookbook.txt
@@ -139,15 +139,14 @@
* `ok(user(ID))` or just `ok(_)` if user info is not important. This status is
used to tell that this label/category has been met.
-* `need(_)` is used to tell that this label/category is needed for change to
- become submittable
-* `reject(user(ID))` or just `reject(_)`. This status is used to tell that label/category
- is blocking change submission
-* `impossible(_)` is used when the logic knows that the change cannot be submitted as-is.
- Administrative intervention is probably required. This is meant for cases
- where the logic requires members of "FooEng" to score "Code-Review +2" on a
- change, but nobody is in group "FooEng". It is to hint at permissions
- misconfigurations.
+* `need(_)` is used to tell that this label/category is needed for the change to
+ become submittable.
+* `reject(user(ID))` or just `reject(_)`. This status is used to tell that this
+ label/category is blocking submission of the change.
+* `impossible(_)` is used when the logic knows that the change cannot be submitted
+ as-is. This is meant for cases where the logic requires members of a specific
+ group to apply a specific label on a change, but no users are in that group.
+ This is usually caused by misconfiguration of permissions.
* `may(_)` allows expression of approval categories that are optional, i.e.
could either be set or unset without ever influencing whether the change
could be submitted.
diff --git a/Documentation/replace_macros.py b/Documentation/replace_macros.py
index 7623382..5cdfe91 100755
--- a/Documentation/replace_macros.py
+++ b/Documentation/replace_macros.py
@@ -80,6 +80,115 @@
"""
+LINK_SCRIPT = """
+
+++++
+<script type="text/javascript">
+ decorate(document.getElementsByTagName('h1'));
+ decorate(document.getElementsByTagName('h2'));
+ decorate(document.getElementsByTagName('h3'));
+ decorate(document.getElementsByTagName('h4'));
+
+ var divs = document.getElementsByTagName('div');
+ var arr = new Array();
+ var excluded = getExcludedIds();
+ for(var i = 0; i < divs.length; i++) {
+ var d = divs[i];
+ var id = d.getAttribute('id');
+ if (id != null && !(id in excluded)) {
+ arr[arr.length] = d;
+ }
+ }
+ decorate(arr);
+
+ var anchors = document.getElementsByTagName('a');
+ arr = new Array();
+ for(var i = 0; i < anchors.length; i++) {
+ var a = anchors[i];
+ // if the anchor has no id there is no target to
+ // which we can link
+ if (a.getAttribute('id') != null) {
+ // if the anchor is empty there is no content which
+ // can receive the mouseover event, an empty anchor
+ // applies to the element that follows, move the
+ // element that follows into the anchor so that there
+ // is content which can receive the mouseover event
+ if (a.firstChild == null) {
+ var next = a.nextSibling;
+ if (next != null) {
+ next.parentNode.removeChild(next);
+ a.appendChild(next);
+ }
+ }
+ arr[arr.length] = a;
+ }
+ }
+ decorate(arr);
+
+ function decorate(e) {
+ for(var i = 0; i < e.length; i++) {
+ e[i].onmouseover = function (evt) {
+ var element = this;
+ // do nothing if the link icon is currently showing
+ var a = element.firstChild;
+ if (a != null && a instanceof Element
+ && a.getAttribute('id') == 'LINK') {
+ return;
+ }
+
+ // if there is no id there is no target to link to
+ var id = element.getAttribute('id');
+ if (id == null) {
+ return;
+ }
+
+ // create and show a link icon that links to this element
+ a = document.createElement('a');
+ a.setAttribute('id', 'LINK');
+ a.setAttribute('href', '#' + id);
+ a.setAttribute('style', 'position: absolute;'
+ + ' left: ' + (element.offsetLeft - 16 - 2 * 4) + 'px;'
+ + ' padding-left: 4px; padding-right: 4px; padding-top:4px;');
+ var img = document.createElement('img');
+ img.setAttribute('src', 'images/link.png');
+ img.setAttribute('style', 'background-color: #FFFFFF;');
+ a.appendChild(img);
+ element.insertBefore(a, element.firstChild);
+
+ // remove the link icon when the mouse is moved away,
+ // but keep it shown if the mouse is over the element, the link or the icon
+ hide = function(evt) {
+ if (document.elementFromPoint(evt.clientX, evt.clientY) != element
+ && document.elementFromPoint(evt.clientX, evt.clientY) != a
+ && document.elementFromPoint(evt.clientX, evt.clientY) != img
+ && element.contains(a)) {
+ element.removeChild(a);
+ }
+ }
+ element.onmouseout = hide;
+ a.onmouseout = hide;
+ img.onmouseout = hide;
+ }
+ }
+ }
+
+ function getExcludedIds() {
+ var excluded = {};
+ excluded['header'] = true;
+ excluded['toc'] = true;
+ excluded['toctitle'] = true;
+ excluded['content'] = true;
+ excluded['preamble'] = true;
+ excluded['footer'] = true;
+ excluded['footer-text'] = true;
+ return excluded;
+ }
+</script>
+
+++++
+
+"""
+
opts = OptionParser()
opts.add_option('-o', '--out', help='output file')
opts.add_option('-s', '--src', help='source file')
@@ -127,6 +236,7 @@
out_file.write(last_line)
last_line = line
out_file.write(last_line)
+ out_file.write(LINK_SCRIPT)
out_file.close()
except IOError as err:
sys.stderr.write(
diff --git a/Documentation/rest-api-access.txt b/Documentation/rest-api-access.txt
index 3ff3595..42214fe 100644
--- a/Documentation/rest-api-access.txt
+++ b/Documentation/rest-api-access.txt
@@ -268,7 +268,6 @@
"MyProject": {
"revision": "61157ed63e14d261b6dca40650472a9b0bd88474",
"inherits_from": {
- "kind": "gerritcodereview#project",
"id": "All-Projects",
"name": "All-Projects",
"description": "Access inherited by all other projects."
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index 2276e40..201b020 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -753,7 +753,6 @@
)]}'
[
{
- "kind": "gerritcodereview#group",
"id": "global%3AAnonymous-Users",
"url": "#/admin/groups/uuid-global%3AAnonymous-Users",
"options": {
@@ -763,7 +762,6 @@
"owner_id": "6a1e70e1a88782771a91808c8af9bbb7a9871389"
},
{
- "kind": "gerritcodereview#group",
"id": "834ec36dd5e0ed21a2ff5d7e2255da082d63bbd7",
"url": "#/admin/groups/uuid-834ec36dd5e0ed21a2ff5d7e2255da082d63bbd7",
"options": {
@@ -773,7 +771,6 @@
"owner_id": "834ec36dd5e0ed21a2ff5d7e2255da082d63bbd7"
},
{
- "kind": "gerritcodereview#group",
"id": "global%3ARegistered-Users",
"url": "#/admin/groups/uuid-global%3ARegistered-Users",
"options": {
@@ -836,6 +833,172 @@
https://profiles/pictures/john.doe
----
+[[get-user-preferences]]
+=== Get User Preferences
+--
+'GET /accounts/link:#account-id[\{account-id\}]/preferences'
+--
+
+Retrieves the user's preferences.
+
+.Request
+----
+ GET /a/accounts/self/preferences HTTP/1.0
+----
+
+As result the account preferences of the user are returned as a
+link:#preferences-info[PreferencesInfo] entity.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "changes_per_page": 25,
+ "show_site_header": true,
+ "use_flash_clipboard": true,
+ "date_format": "STD",
+ "time_format": "HHMM_12",
+ "size_bar_in_change_table": true,
+ "review_category_strategy": "ABBREV",
+ "comment_visibility_strategy": "EXPAND_RECENT",
+ "diff_view": "SIDE_BY_SIDE",
+ "my": [
+ {
+ "url": "#/dashboard/self",
+ "name": "Changes"
+ },
+ {
+ "url": "#/q/is:draft",
+ "name": "Drafts"
+ },
+ {
+ "url": "#/q/has:draft",
+ "name": "Draft Comments"
+ },
+ {
+ "url": "#/q/is:watched+is:open",
+ "name": "Watched Changes"
+ },
+ {
+ "url": "#/q/is:starred",
+ "name": "Starred Changes"
+ },
+ {
+ "url": "#/groups/self",
+ "name": "Groups"
+ }
+ ]
+ }
+----
+
+[[set-user-preferences]]
+=== Set User Preferences
+--
+'PUT /accounts/link:#account-id[\{account-id\}]/preferences'
+--
+
+Sets the user's preferences.
+
+The new preferences must be provided in the request body as a
+link:#preferences-input[PreferencesInput] entity.
+
+.Request
+----
+ PUT /a/accounts/self/preferences HTTP/1.0
+ Content-Type: application/json;charset=UTF-8
+
+ {
+ "changes_per_page": 50,
+ "show_site_header": true,
+ "use_flash_clipboard": true,
+ "date_format": "STD",
+ "time_format": "HHMM_12",
+ "size_bar_in_change_table": true,
+ "review_category_strategy": "NAME",
+ "comment_visibility_strategy": "EXPAND_RECENT",
+ "diff_view": "SIDE_BY_SIDE",
+ "my": [
+ {
+ "url": "#/dashboard/self",
+ "name": "Changes"
+ },
+ {
+ "url": "#/q/is:draft",
+ "name": "Drafts"
+ },
+ {
+ "url": "#/q/has:draft",
+ "name": "Draft Comments"
+ },
+ {
+ "url": "#/q/is:watched+is:open",
+ "name": "Watched Changes"
+ },
+ {
+ "url": "#/q/is:starred",
+ "name": "Starred Changes"
+ },
+ {
+ "url": "#/groups/self",
+ "name": "Groups"
+ }
+ ]
+ }
+----
+
+As result the new preferences of the user are returned as a
+link:#preferences-info[PreferencesInfo] entity.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "changes_per_page": 50,
+ "show_site_header": true,
+ "use_flash_clipboard": true,
+ "date_format": "STD",
+ "time_format": "HHMM_12",
+ "size_bar_in_change_table": true,
+ "review_category_strategy": "NAME",
+ "comment_visibility_strategy": "EXPAND_RECENT",
+ "diff_view": "SIDE_BY_SIDE",
+ "my": [
+ {
+ "url": "#/dashboard/self",
+ "name": "Changes"
+ },
+ {
+ "url": "#/q/is:draft",
+ "name": "Drafts"
+ },
+ {
+ "url": "#/q/has:draft",
+ "name": "Draft Comments"
+ },
+ {
+ "url": "#/q/is:watched+is:open",
+ "name": "Watched Changes"
+ },
+ {
+ "url": "#/q/is:starred",
+ "name": "Starred Changes"
+ },
+ {
+ "url": "#/groups/self",
+ "name": "Groups"
+ }
+ ]
+ }
+----
+
[[get-diff-preferences]]
=== Get Diff Preferences
--
@@ -948,7 +1111,6 @@
)]}'
[
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
"project": "myProject",
"branch": "master",
@@ -1152,6 +1314,103 @@
link:access-control.html#capability_viewQueue[View Queue] capability.
|=================================
+[[preferences-info]]
+=== PreferencesInfo
+The `PreferencesInfo` entity contains information about a user's preferences.
+
+[options="header",width="50%",cols="1,^1,5"]
+|=====================================
+|Field Name ||Description
+|`changes_per_page` ||
+The number of changes to show on each page.
+Allowed values are `10`, `25`, `50`, `100`.
+|`show_site_header` |not set if `false`|
+Whether the site header should be shown.
+|`use_flash_clipboard` |not set if `false`|
+Whether to use the flash clipboard widget.
+|`download_scheme` ||
+The type of download URL the user prefers to use.
+|`download_command` ||
+The type of download command the user prefers to use.
+|`copy_self_on_email` |not set if `false`|
+Whether to CC me on comments I write.
+|`date_format` ||
+The format to display the date in.
+Allowed values are `STD`, `US`, `ISO`, `EURO`, `UK`.
+|`time_format` ||
+The format to display the time in.
+Allowed values are `HHMM_12`, `HHMM_24`.
+|`reverse_patch_set_order` |not set if `false`|
+Whether to display the patch sets in reverse order.
+|`relative_date_in_change_table` |not set if `false`|
+Whether to show relative dates in the changes table.
+|`size_bar_in_change_table` |not set if `false`|
+Whether to show the change sizes as colored bars in the change table.
+|`legacycid_in_change_table` |not set if `false`|
+Whether to show change number in the change table.
+|`review_category_strategy` ||
+The strategy used to displayed info in the review category column.
+Allowed values are `NONE`, `NAME`, `EMAIL`, `USERNAME`, `ABBREV`.
+|`comment_visibility_strategy` ||
+The strategy used to display the comments.
+Allowed values are `COLLAPSE_ALL`, `EXPAND_MOST_RECENT`, `EXPAND_RECENT`, `EXPAND_ALL`.
+|`diff_view` ||
+The type of diff view to show.
+Allowed values are `SIDE_BY_SIDE`, `UNIFIED_DIFF`.
+|`change_screen` ||
+The change screen to use.
+Allowed values are `OLD_UI`, `CHANGE_SCREEN2`.
+|=====================================
+
+[[preferences-input]]
+=== PreferencesInput
+The `PreferencesInput` entity contains information for setting the
+user preferences. Fields which are not set will not be updated.
+
+[options="header",width="50%",cols="1,^1,5"]
+|=====================================
+|Field Name ||Description
+|`changes_per_page` |optional|
+The number of changes to show on each page.
+Allowed values are `10`, `25`, `50`, `100`.
+|`show_site_header` |optional|
+Whether the site header should be shown.
+|`use_flash_clipboard` |optional|
+Whether to use the flash clipboard widget.
+|`download_scheme` |optional|
+The type of download URL the user prefers to use.
+|`download_command` |optional|
+The type of download command the user prefers to use.
+|`copy_self_on_email` |optional|
+Whether to CC me on comments I write.
+|`date_format` |optional|
+The format to display the date in.
+Allowed values are `STD`, `US`, `ISO`, `EURO`, `UK`.
+|`time_format` |optional|
+The format to display the time in.
+Allowed values are `HHMM_12`, `HHMM_24`.
+|`reverse_patch_set_order` |optional|
+Whether to display the patch sets in reverse order.
+|`relative_date_in_change_table` |optional|
+Whether to show relative dates in the changes table.
+|`size_bar_in_change_table` |optional|
+Whether to show the change sizes as colored bars in the change table.
+|`legacycid_in_change_table` |optional|
+Whether to show change number in the change table.
+|`review_category_strategy` |optional|
+The strategy used to displayed info in the review category column.
+Allowed values are `NONE`, `NAME`, `EMAIL`, `USERNAME`, `ABBREV`.
+|`comment_visibility_strategy` |optional|
+The strategy used to display the comments.
+Allowed values are `COLLAPSE_ALL`, `EXPAND_MOST_RECENT`, `EXPAND_RECENT`, `EXPAND_ALL`.
+|`diff_view` |optional|
+The type of diff view to show.
+Allowed values are `SIDE_BY_SIDE`, `UNIFIED_DIFF`.
+|`change_screen` |optional|
+The change screen to use.
+Allowed values are `OLD_UI`, `CHANGE_SCREEN2`.
+|=====================================
+
[[diff-preferences-info]]
=== DiffPreferencesInfo
The `DiffPreferencesInfo` entity contains information about the diff
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 26bf070..e5fd1b6 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -7,15 +7,72 @@
[[change-endpoints]]
== Change Endpoints
+[[create-change]]
+=== Create Change
+--
+'POST /changes'
+--
+
+The change info link:#change-info[ChangeInfo] entity must be provided in the
+request body. Only the following attributes are honored: `project`,
+`branch`, `subject`, `status` and `topic`. The first three attributes are
+mandatory. Valid values for status are: `DRAFT` and `NEW`.
+
+.Request
+----
+ POST /changes HTTP/1.0
+ Content-Type: application/json;charset=UTF-8
+
+ {
+ "project" : "myProject",
+ "subject" : "Let's support 100% Gerrit workflow direct in browser",
+ "branch" : "master",
+ "topic" : "create-change-in-browser",
+ "status" : "DRAFT"
+ }
+----
+
+As response a link:#change-info[ChangeInfo] entity is returned that describes
+the resulting change.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9941",
+ "project": "myProject",
+ "branch": "master",
+ "topic": "create-change-in-browser",
+ "change_id": "I8473b95934b5732ac55d26311a706c9c2bde9941",
+ "subject": "Let's support 100% Gerrit workflow direct in browser",
+ "status": "DRAFT",
+ "created": "2014-05-05 07:15:44.639000000",
+ "updated": "2014-05-05 07:15:44.639000000",
+ "mergeable": true,
+ "insertions": 0,
+ "deletions": 0,
+ "_sortkey": "002cbc25000004e5",
+ "_number": 4711,
+ "owner": {
+ "name": "John Doe"
+ }
+ }
+----
+
[[list-changes]]
=== Query Changes
--
'GET /changes/'
--
-Queries changes visible to the caller. The query string must be
-provided by the `q` parameter. The `n` parameter can be used to limit
-the returned results.
+Queries changes visible to the caller. The
+link:user-search.html#_search_operators[query string] must be provided
+by the `q` parameter. The `n` parameter can be used to limit the
+returned results.
As result a list of link:#change-info[ChangeInfo] entries is returned.
The change output is sorted by the last update time, most recently
@@ -37,7 +94,6 @@
)]}'
[
{
- "kind": "gerritcodereview#change",
"id": "demo~master~Idaf5e098d70898b7119f6f4af5a6c13343d64b57",
"project": "demo",
"branch": "master",
@@ -56,7 +112,6 @@
},
},
{
- "kind": "gerritcodereview#change",
"id": "demo~master~I09c8041b5867d5b33170316e2abc34b79bbb8501",
"project": "demo",
"branch": "master",
@@ -111,7 +166,6 @@
[
[
{
- "kind": "gerritcodereview#change",
"id": "demo~master~Idaf5e098d70898b7119f6f4af5a6c13343d64b57",
"project": "demo",
"branch": "master",
@@ -241,6 +295,11 @@
authenticated and has commented on the current revision.
--
+[[patch-set-links]]
+--
+* `PATCHSET_LINKS`: include the `web_links` field.
+--
+
.Request
----
GET /changes/?q=97&o=CURRENT_REVISION&o=CURRENT_COMMIT&o=CURRENT_FILES&o=DOWNLOAD_COMMANDS HTTP/1.0
@@ -255,8 +314,7 @@
)]}'
[
{
- "kind": "gerritcodereview#change",
- "id": "demo~master~I7ea46d2e2ee5c64c0d807677859cfb7d90b8966a",
+ "id": "gerrit~master~I7ea46d2e2ee5c64c0d807677859cfb7d90b8966a",
"project": "gerrit",
"branch": "master",
"change_id": "I7ea46d2e2ee5c64c0d807677859cfb7d90b8966a",
@@ -392,7 +450,6 @@
)]}'
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
"project": "myProject",
"branch": "master",
@@ -433,7 +490,10 @@
----
As response a link:#change-info[ChangeInfo] entity is returned that
-describes the change.
+describes the change. This response will contain all votes for each
+label and include one combined vote. The combined label vote is
+calculated in the following order (from highest to lowest):
+REJECTED > APPROVED > DISLIKED > RECOMMENDED.
.Response
----
@@ -443,7 +503,6 @@
)]}'
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
"project": "myProject",
"branch": "master",
@@ -488,12 +547,6 @@
}
},
"Code-Review": {
- "recommended": {
- "_account_id": 1000097,
- "name": "Jane Roe",
- "email": "jane.roe@example.com",
- "username": "jroe"
- },
"disliked": {
"_account_id": 1000096,
"name": "John Doe",
@@ -694,7 +747,6 @@
)]}'
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
"project": "myProject",
"branch": "master",
@@ -754,7 +806,6 @@
)]}'
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
"project": "myProject",
"branch": "master",
@@ -812,7 +863,6 @@
)]}'
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I3ea943139cb62e86071996f2480e58bf3eeb9dd2",
"project": "myProject",
"branch": "master",
@@ -905,7 +955,6 @@
)]}'
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
"project": "myProject",
"branch": "master",
@@ -971,7 +1020,6 @@
)]}'
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
"project": "myProject",
"branch": "master",
@@ -1061,7 +1109,6 @@
)]}'
{
- "kind": "gerritcodereview#includedininfo",
"branches": [
"master"
],
@@ -1119,7 +1166,6 @@
)]}'
[
{
- "kind": "gerritcodereview#reviewer",
"approvals": {
"Verified": "+1",
"Code-Review": "+2"
@@ -1129,7 +1175,6 @@
"email": "john.doe@example.com"
},
{
- "kind": "gerritcodereview#reviewer",
"approvals": {
"Verified": " 0",
"Code-Review": "-1"
@@ -1166,7 +1211,6 @@
)]}'
[
{
- "kind": "gerritcodereview#suggestedreviewer",
"account": {
"_account_id": 1000097,
"name": "Jane Roe",
@@ -1174,7 +1218,6 @@
}
},
{
- "kind": "gerritcodereview#suggestedreviewer",
"group": {
"id": "4fd581c0657268f2bdcc26699fbf9ddb76e3a279",
"name": "Joiner"
@@ -1207,7 +1250,6 @@
)]}'
{
- "kind": "gerritcodereview#reviewer",
"approvals": {
"Verified": "+1",
"Code-Review": "+2"
@@ -1252,7 +1294,6 @@
{
"reviewers": [
{
- "kind": "gerritcodereview#reviewer",
"approvals": {
"Verified": " 0",
"Code-Review": " 0"
@@ -1354,7 +1395,6 @@
)]}'
{
- "kind": "gerritcodereview#commit",
"parents": [
{
"commit": "1eee2c9d8f352483781e772f35dc586a69ff5646",
@@ -1409,7 +1449,6 @@
)]}'
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
"project": "myProject",
"branch": "master",
@@ -1514,6 +1553,79 @@
}
----
+[[get-related-changes]]
+=== Get Related Changes
+--
+'GET /changes/link:#change-id[\{change-id\}]/revisions/link:#revision-id[\{revision-id\}]/related'
+--
+
+Retrieves related changes of a revision. Related changes are changes that either
+depend on, or are dependencies of the revision.
+
+.Request
+----
+ GET /changes/gerrit~master~I5e4fc08ce34d33c090c9e0bf320de1b17309f774/revisions/b1cb4caa6be46d12b94c25aa68aebabcbb3f53fe/related HTTP/1.0
+----
+
+As result a link:#related-changes-info[RelatedChangesInfo] entity is returned
+describing the related changes.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "changes": [
+ {
+ "change_id": "Ic62ae3103fca2214904dbf2faf4c861b5f0ae9b5",
+ "commit": {
+ "commit": "78847477532e386f5a2185a4e8c90b2509e354e3",
+ "parents": [
+ {
+ "commit": "bb499510bbcdbc9164d96b0dbabb4aa45f59a87e"
+ }
+ ],
+ "author": {
+ "name": "David Ostrovsky",
+ "email": "david@ostrovsky.org",
+ "date": "2014-07-12 15:04:24.000000000",
+ "tz": 120
+ },
+ "subject": "Remove Solr"
+ },
+ "_change_number": 58478,
+ "_revision_number": 2,
+ "_current_revision_number": 2
+ },
+ {
+ "change_id": "I5e4fc08ce34d33c090c9e0bf320de1b17309f774",
+ "commit": {
+ "commit": "b1cb4caa6be46d12b94c25aa68aebabcbb3f53fe",
+ "parents": [
+ {
+ "commit": "d898f12a9b7a92eb37e7a80636195a1b06417aad"
+ }
+ ],
+ "author": {
+ "name": "David Pursehouse",
+ "email": "david.pursehouse@sonymobile.com",
+ "date": "2014-06-24 02:01:28.000000000",
+ "tz": 540
+ },
+ "subject": "Add support for secondary index with Elasticsearch"
+ },
+ "_change_number": 58081,
+ "_revision_number": 10,
+ "_current_revision_number": 10
+ }
+ ]
+ }
+----
+
+
[[set-review]]
=== Set Review
--
@@ -1601,7 +1713,6 @@
)]}'
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I3ea943139cb62e86071996f2480e58bf3eeb9dd2",
"project": "myProject",
"branch": "master",
@@ -1804,6 +1915,8 @@
GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/current/mergeable HTTP/1.0
----
+As response a link:#mergeable-info[MergeableInfo] entity is returned.
+
.Response
----
HTTP/1.1 200 OK
@@ -1817,6 +1930,37 @@
}
----
+If the `other-branches` parameter is specified, the mergeability will also be
+checked for all other branches.
+
+If the `force` parameter is specified, the mergeability against the destination
+will be rechecked, in case of prior transient failures or bugs.
+
+.Request
+----
+ GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/current/mergeable?other-branches HTTP/1.0
+----
+
+The response will then contain a list of all other branches where this changes
+could merge cleanly.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ submit_type: "MERGE_IF_NECESSARY",
+ mergeable: true,
+ mergeable_into: [
+ "refs/heads/stable-2.7",
+ "refs/heads/stable-2.8",
+ ]
+ }
+----
+
[[get-submit-type]]
=== Get Submit Type
--
@@ -1941,14 +2085,12 @@
{
"gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java": [
{
- "kind": "gerritcodereview#comment",
"id": "TvcXrmjM",
"line": 23,
"message": "[nit] trailing whitespace",
"updated": "2013-02-26 15:40:43.986000000"
},
{
- "kind": "gerritcodereview#comment",
"id": "TveXwFiA",
"line": 49,
"in_reply_to": "TfYX-Iuo",
@@ -1993,7 +2135,6 @@
)]}'
{
- "kind": "gerritcodereview#comment",
"id": "TvcXrmjM",
"path": "gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java",
"line": 23,
@@ -2027,7 +2168,6 @@
)]}'
{
- "kind": "gerritcodereview#comment",
"id": "TvcXrmjM",
"path": "gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java",
"line": 23,
@@ -2070,7 +2210,6 @@
)]}'
{
- "kind": "gerritcodereview#comment",
"id": "TvcXrmjM",
"path": "gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java",
"line": 23,
@@ -2107,7 +2246,9 @@
As result a map is returned that maps the file path to a list of
link:#comment-info[CommentInfo] entries. The entries in the map are
-sorted by file path.
+sorted by file path and only include file (or inline) comments. Use
+the link:#get-change-detail[Get Change Detail] endpoint to retrieve
+the general change message (or comment).
.Request
----
@@ -2124,7 +2265,6 @@
{
"gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java": [
{
- "kind": "gerritcodereview#comment",
"id": "TvcXrmjM",
"line": 23,
"message": "[nit] trailing whitespace",
@@ -2136,7 +2276,6 @@
}
},
{
- "kind": "gerritcodereview#comment",
"id": "TveXwFiA",
"line": 49,
"in_reply_to": "TfYX-Iuo",
@@ -2176,7 +2315,6 @@
)]}'
{
- "kind": "gerritcodereview#comment",
"id": "TvcXrmjM",
"path": "gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java",
"line": 23,
@@ -2516,7 +2654,6 @@
)]}'
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9941",
"project": "myProject",
"branch": "release-branch",
@@ -2568,7 +2705,6 @@
)]}'
{
- "kind": "gerritcodereview#change",
"id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9941",
"project": "myProject",
"branch": "release-branch",
@@ -2732,7 +2868,6 @@
[options="header",width="50%",cols="1,^1,5"]
|==================================
|Field Name ||Description
-|`kind` ||`gerritcodereview#change`
|`id` ||
The ID of the change in the format "'<project>\~<branch>~<Change-Id>'",
where 'project', 'branch' and 'Change-Id' are URL encoded. For 'branch' the
@@ -2761,7 +2896,7 @@
Only set if link:#reviewed[reviewed] is requested.
|`mergeable` |optional|
Whether the change is mergeable. +
-Not set for merged changes.
+Not set for merged changes, or if the change has not yet been tested.
|`insertions` ||
Number of inserted lines.
|`deletions` ||
@@ -2807,6 +2942,37 @@
Only set on either the last or the first change that is returned.
|==================================
+[[related-changes-info]]
+=== RelatedChangesInfo
+The `RelatedChangesInfo` entity contains information about related
+changes.
+
+[options="header",width="50%",cols="1,6"]
+|===========================
+|Field Name |Description
+|`changes` |A list of
+link:#related-change-and-commit-info[RelatedChangeAndCommitInfo] entities
+describing the related changes. Sorted by git commit order, newest to
+oldest. Empty if there are no related changes.
+|===========================
+
+[[related-change-and-commit-info]]
+=== RelatedChangeAndCommitInfo
+
+The `RelatedChangeAndCommitInfo` entity contains information about
+a related change and commit.
+
+[options="header",width="50%",cols="1,^1,5"]
+|===========================
+|Field Name ||Description
+|`change_id` |optional|The Change-Id of the change.
+|`commit` ||The commit as a
+link:#commit-info[CommitInfo] entity.
+|`_change_number` |optional|The change number.
+|`_revision_number` |optional|The revision number.
+|`_current_revision_number`|optional|The current revision number.
+|===========================
+
[[change-message-info]]
=== ChangeMessageInfo
The `ChangeMessageInfo` entity contains information about a message
@@ -2817,7 +2983,7 @@
|Field Name ||Description
|`id` ||The ID of the message.
|`author` |optional|
-Author of the message as an
+Author of the message as an
link:rest-api-accounts.html#account-info[AccountInfo] entity. +
Unset if written by the Gerrit system.
|`date` ||
@@ -2835,7 +3001,7 @@
|===========================
|Field Name |Description
|`message` |Commit message for the cherry-picked change
-|`destination` |Destination Branch
+|`destination` |Destination branch
|===========================
[[comment-info]]
@@ -2845,7 +3011,6 @@
[options="header",width="50%",cols="1,^1,5"]
|===========================
|Field Name ||Description
-|`kind` ||`gerritcodereview#comment`
|`id` ||The URL encoded UUID of the comment.
|`path` |optional|
The path of the file for which the inline comment was done. +
@@ -2881,8 +3046,6 @@
[options="header",width="50%",cols="1,^1,5"]
|===========================
|Field Name ||Description
-|`kind` |optional|
-Must be `gerritcodereview#comment` if provided.
|`id` |optional|
The URL encoded UUID of the comment if an existing draft comment should
be updated.
@@ -3119,6 +3282,8 @@
|`value` |optional|The voting value of the user who
recommended/disliked this label on the change if it is not
"`+1`"/"`-1`".
+|`default_value`|optional|The default voting value for the label.
+This value may be outside the range specified in permitted_labels.
|===========================
==== Fields set by `DETAILED_LABELS`
@@ -3132,6 +3297,23 @@
to the value descriptions.
|===========================
+[[mergeable-info]]
+=== MergeableInfo
+The `MergeableInfo` entity contains information about the mergeability of a
+change.
+
+[options="header",width="50%",cols="1,^1,5"]
+|============================
+|Field Name ||Description
+|`submit_type` ||
+Submit type used for this change, can be `MERGE_IF_NECESSARY`,
+`FAST_FORWARD_ONLY`, `REBASE_IF_NECESSARY`, `MERGE_ALWAYS` or
+`CHERRY_PICK`.
+|`mergeable` ||
+`true` if this change is cleanly mergeable, `false` otherwise
+|`mergeable_into`|optional|
+A list of other branch names where this change could merge cleanly
+|============================
[[restore-input]]
=== RestoreInput
@@ -3222,7 +3404,6 @@
[options="header",width="50%",cols="1,6"]
|==========================
|Field Name |Description
-|`kind` |`gerritcodereview#reviewer`
|`approvals` |
The approvals of the reviewer as a map that maps the label names to the
approval values ("`-2`", "`-1`", "`0`", "`+1`", "`+2`").
@@ -3274,6 +3455,9 @@
Actions the caller might be able to perform on this revision. The
information is a map of view name to link:#action-info[ActionInfo]
entities.
+|'web_links' |optional|
+Links to the patch set in external sites as a list of
+link:#web-link-info[WebLinkInfo] entities.
|===========================
[[rule-input]]
@@ -3396,13 +3580,22 @@
[options="header",width="50%",cols="1,6"]
|==========================
|Field Name |Description
-|`kind` |`gerritcodereview#includedininfo`
|`branches` | The list of branches this change was merged into.
Each branch is listed without the 'refs/head/' prefix.
|`tags` | The list of tags this change was tagged with.
Each tag is listed without the 'refs/tags/' prefix.
|==========================
+[[web-link-info]]
+=== WebLinkInfo
+The `WebLinkInfo` entity describes a link to an external site.
+
+[options="header",width="50%",cols="1,6"]
+|======================
+|Field Name|Description
+|`name` |The link name.
+|`url` |The link URL.
+|======================
GERRIT
------
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index 6a3b34e..2968ebb 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -30,6 +30,515 @@
"2.7"
----
+[[list-caches]]
+=== List Caches
+--
+'GET /config/server/caches/'
+--
+
+Lists the caches of the server. Caches defined by plugins are included.
+
+The caller must be a member of a group that is granted the
+link:access-control.html#capability_viewCaches[View Caches] capability
+or the link:access-control.html#capability_administrateServer[
+Administrate Server] capability.
+
+As result a map of link:#cache-info[CacheInfo] entities is returned.
+
+The entries in the map are sorted by cache name.
+
+.Request
+----
+ GET /config/server/caches/ HTTP/1.0
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "accounts": {
+ "type": "MEM",
+ "entries": {
+ "mem": 4
+ },
+ "average_get": "2.5ms",
+ "hit_ratio": {
+ "mem": 94
+ }
+ },
+ "accounts_byemail": {
+ "type": "MEM",
+ "entries": {
+ "mem": 4
+ },
+ "average_get": "771.8us",
+ "hit_ratio": {
+ "mem": 95
+ }
+ },
+ "accounts_byname": {
+ "type": "MEM",
+ "entries": {
+ "mem": 4
+ },
+ "hit_ratio": {
+ "mem": 100
+ }
+ },
+ "adv_bases": {
+ "type": "MEM",
+ "entries": {},
+ "hit_ratio": {}
+ },
+ "change_kind": {
+ "type": "DISK",
+ "entries": {
+ "space": "0.00k"
+ },
+ "hit_ratio": {}
+ },
+ "changes": {
+ "type": "MEM",
+ "entries": {},
+ "hit_ratio": {}
+ },
+ "conflicts": {
+ "type": "DISK",
+ "entries": {
+ "mem": 2,
+ "disk": 3,
+ "space": "2.75k"
+ },
+ "hit_ratio": {
+ "mem": 0,
+ "disk": 100
+ }
+ },
+ "diff": {
+ "type": "DISK",
+ "entries": {
+ "mem": 177,
+ "disk": 253,
+ "space": "170.97k"
+ },
+ "average_get": "1.1ms",
+ "hit_ratio": {
+ "mem": 67,
+ "disk": 100
+ }
+ },
+ "diff_intraline": {
+ "type": "DISK",
+ "entries": {
+ "mem": 1,
+ "disk": 1,
+ "space": "0.37k"
+ },
+ "average_get": "6.8ms",
+ "hit_ratio": {
+ "mem": 0
+ }
+ },
+ "git_tags": {
+ "type": "DISK",
+ "entries": {
+ "space": "0.00k"
+ },
+ "hit_ratio": {}
+ },
+ groups": {
+ "type": "MEM",
+ "entries": {
+ "mem": 27
+ },
+ "average_get": "183.2us",
+ "hit_ratio": {
+ "mem": 12
+ }
+ },
+ "groups_byinclude": {
+ "type": "MEM",
+ "entries": {},
+ "hit_ratio": {}
+ },
+ "groups_byname": {
+ "type": "MEM",
+ "entries": {},
+ "hit_ratio": {}
+ },
+ "groups_byuuid": {
+ "type": "MEM",
+ "entries": {
+ "mem": 25
+ },
+ "average_get": "173.4us",
+ "hit_ratio": {
+ "mem": 13
+ }
+ },
+ "groups_external": {
+ "type": "MEM",
+ "entries": {},
+ "hit_ratio": {}
+ },
+ groups_members": {
+ "type": "MEM",
+ "entries": {
+ "mem": 4
+ },
+ "average_get": "697.8us",
+ "hit_ratio": {
+ "mem": 82
+ }
+ },
+ "permission_sort": {
+ "type": "MEM",
+ "entries": {
+ "mem": 16
+ },
+ "hit_ratio": {
+ "mem": 96
+ }
+ },
+ "plugin_resources": {
+ "type": "MEM",
+ "entries": {
+ "mem": 2
+ },
+ "hit_ratio": {
+ "mem": 83
+ }
+ },
+ "project_list": {
+ "type": "MEM",
+ "entries": {
+ "mem": 1
+ },
+ "average_get": "18.6ms",
+ "hit_ratio": {
+ "mem": 0
+ }
+ },
+ "projects": {
+ "type": "MEM",
+ "entries": {
+ "mem": 35
+ },
+ "average_get": "8.6ms",
+ "hit_ratio": {
+ "mem": 99
+ }
+ },
+ "quota-repo_size": {
+ "type": "DISK",
+ "entries": {
+ "space": "0.00k"
+ },
+ "hit_ratio": {}
+ },
+ "sshkeys": {
+ "type": "MEM",
+ "entries": {
+ "mem": 1
+ },
+ "average_get": "3.2ms",
+ "hit_ratio": {
+ "mem": 50
+ }
+ },
+ "web_sessions": {
+ "type": "DISK",
+ "entries": {
+ "mem": 1,
+ "disk": 2,
+ "space": "0.78k"
+ },
+ "hit_ratio": {
+ "mem": 82
+ }
+ }
+ }
+----
+
+It is possible to get different output formats by specifying the
+`format` option:
+
+* `LIST`:
++
+Returns the cache names as JSON list.
++
+The cache names are alphabetically sorted.
++
+.Request
+----
+ GET /config/server/caches/?format=LIST HTTP/1.0
+----
++
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ [
+ "accounts",
+ "accounts_byemail",
+ "accounts_byname",
+ "adv_bases",
+ "change_kind",
+ "changes",
+ "conflicts",
+ "diff",
+ "diff_intraline",
+ "git_tags",
+ "groups",
+ "groups_byinclude",
+ "groups_byname",
+ "groups_byuuid",
+ "groups_external",
+ "groups_members",
+ "permission_sort",
+ "plugin_resources",
+ "project_list",
+ "projects",
+ "quota-repo_size",
+ "sshkeys",
+ "web_sessions"
+ ]
+----
+
+* `TEXT_LIST`:
++
+Returns the cache names as a UTF-8 list that is base64 encoded. The
+cache names are delimited by '\n'.
++
+The cache names are lexicographically sorted.
++
+.Request
+----
+ GET /config/server/caches/?format=TEXT_LIST HTTP/1.0
+----
++
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Type: text/plain;charset=UTF-8
+
+ YWNjb3VudHMKYW...ViX3Nlc3Npb25z
+----
++
+E.g. this could be used to flush all caches:
++
+----
+ for c in $(curl --digest --user jdoe:TNAuLkXsIV7w http://gerrit/a/config/server/caches/?format=TEXT_LIST | base64 -D)
+ do
+ curl --digest --user jdoe:TNAuLkXsIV7w -X POST http://gerrit/a/config/server/caches/$c/flush
+ done
+----
+
+[[cache-operations]]
+=== Cache Operations
+--
+'POST /config/server/caches/'
+--
+
+Executes a cache operation that is specified in the request body in a
+link:#cache-operation-input[CacheOperationInput] entity.
+
+[[flush-all-caches]]
+==== Flush All Caches
+
+.Request
+----
+ POST /config/server/caches/ HTTP/1.0
+ Content-Type: application/json;charset=UTF-8
+
+ {
+ "operation": "FLUSH_ALL"
+ }
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+----
+
+[[flush-several-caches]]
+==== Flush Several Caches At Once
+
+.Request
+----
+ POST /config/server/caches/ HTTP/1.0
+ Content-Type: application/json;charset=UTF-8
+
+ {
+ "operation": "FLUSH"
+ "caches": [
+ "projects",
+ "project_list"
+ ]
+ }
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+----
+
+[[get-cache]]
+=== Get Cache
+--
+'GET /config/server/caches/link:#cache-name[\{cache-name\}]'
+--
+
+Retrieves information about a cache.
+
+The caller must be a member of a group that is granted the
+link:access-control.html#capability_viewCaches[View Caches] capability
+or the link:access-control.html#capability_administrateServer[
+Administrate Server] capability.
+
+As result a link:#cache-info[CacheInfo] entity is returned.
+
+.Request
+----
+ GET /config/server/caches/projects HTTP/1.0
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "name": "projects",
+ "type": "MEM",
+ "entries": {
+ "mem": 35
+ },
+ "average_get": " 8.6ms",
+ "hit_ratio": {
+ "mem": 99
+ }
+ }
+----
+
+[[flush-cache]]
+=== Flush Cache
+--
+'POST /config/server/caches/link:#cache-name[\{cache-name\}]/flush'
+--
+
+Flushes a cache.
+
+The caller must be a member of a group that is granted the
+link:access-control.html#capability_flushCaches[Flush Caches] capability
+or the link:access-control.html#capability_administrateServer[
+Administrate Server] capability.
+
+The "web_sessions" cache can only be flushed if the caller is member of
+a group that is granted the
+link:access-control.html#capability_administrateServer[Administrate
+Server] capability.
+
+.Request
+----
+ POST /config/server/caches/projects/flush HTTP/1.0
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+----
+
+[[get-summary]]
+=== Get Summary
+--
+'GET /config/server/summary'
+--
+
+Retrieves a summary of the current server state.
+
+The caller must be a member of a group that is granted the
+link:access-control.html#capability_administrateServer[Administrate
+Server] capability.
+
+The following options are supported:
+
+* `jvm`:
++
+Includes a JVM summary.
+
+* `gc`:
++
+Requests a Java garbage collection before computing the information
+about the Java memory heap.
+
+.Request
+----
+ GET /config/server/summary?jvm HTTP/1.0
+----
+
+As result a link:#summary-info[SummaryInfo] entity is returned.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "task_summary": {
+ "total": 2,
+ "sleeping": 2
+ },
+ "mem_summary": {
+ "total": "341.06m",
+ "used": "57.16m",
+ "free": "283.90m",
+ "buffers": "0.00k",
+ "max": "1.67g",
+ }
+ "thread_summary": {
+ "cpus": 8,
+ "threads": 44,
+ "counts": {
+ "HTTP": {
+ "RUNNABLE": 3,
+ "TIMED_WAITING": 2
+ },
+ "SSH-Interactive-Worker": {
+ "WAITING": 1
+ },
+ "Other": {
+ "WAITING": 10,
+ "RUNNABLE": 2,
+ "TIMED_WAITING": 25
+ },
+ "SshCommandStart": {
+ "WAITING": 1
+ }
+ }
+ },
+ "jvm_summary": {
+ "vm_vendor": "Oracle Corporation",
+ "vm_name": "Java HotSpot(TM) 64-Bit Server VM",
+ "vm_version": "23.25-b01",
+ "os_name": "Mac OS X",
+ "os_version": "10.8.5",
+ "os_arch": "x86_64",
+ "user": "gerrit",
+ "host": "GERRIT",
+ "current_working_directory": "/Users/gerrit/site",
+ "site": "/Users/gerrit/site"
+ }
+ }
+----
+
[[list-capabilities]]
=== List Capabilities
--
@@ -57,88 +566,204 @@
)]}'
{
"accessDatabase": {
- "kind": "gerritcodereview#capability",
"id": "accessDatabase",
"name": "Access Database"
},
"administrateServer": {
- "kind": "gerritcodereview#capability",
"id": "administrateServer",
"name": "Administrate Server"
},
"createAccount": {
- "kind": "gerritcodereview#capability",
"id": "createAccount",
"name": "Create Account"
},
"createGroup": {
- "kind": "gerritcodereview#capability",
"id": "createGroup",
"name": "Create Group"
},
"createProject": {
- "kind": "gerritcodereview#capability",
"id": "createProject",
"name": "Create Project"
},
"emailReviewers": {
- "kind": "gerritcodereview#capability",
"id": "emailReviewers",
"name": "Email Reviewers"
},
"flushCaches": {
- "kind": "gerritcodereview#capability",
"id": "flushCaches",
"name": "Flush Caches"
},
"killTask": {
- "kind": "gerritcodereview#capability",
"id": "killTask",
"name": "Kill Task"
},
"priority": {
- "kind": "gerritcodereview#capability",
"id": "priority",
"name": "Priority"
},
"queryLimit": {
- "kind": "gerritcodereview#capability",
"id": "queryLimit",
"name": "Query Limit"
},
"runGC": {
- "kind": "gerritcodereview#capability",
"id": "runGC",
"name": "Run Garbage Collection"
},
"streamEvents": {
- "kind": "gerritcodereview#capability",
"id": "streamEvents",
"name": "Stream Events"
},
"viewCaches": {
- "kind": "gerritcodereview#capability",
"id": "viewCaches",
"name": "View Caches"
},
"viewConnections": {
- "kind": "gerritcodereview#capability",
"id": "viewConnections",
"name": "View Connections"
},
"viewPlugins": {
- "kind": "gerritcodereview#capability",
"id": "viewPlugins",
"name": "View Plugins"
},
"viewQueue": {
- "kind": "gerritcodereview#capability",
"id": "viewQueue",
"name": "View Queue"
}
}
----
+[[list-tasks]]
+=== List Tasks
+--
+'GET /config/server/tasks/'
+--
+
+Lists the tasks from the background work queues that the Gerrit daemon
+is currently performing, or will perform in the near future.
+
+Gerrit contains an internal scheduler, similar to cron, that it uses to
+queue and dispatch both short and long term tasks.
+
+Tasks that are completed or canceled exit the queue very quickly once
+they enter this state, but it can be possible to observe tasks in these
+states.
+
+End-users may see a task only if they can also see the project the task
+is associated with. Tasks operating on other projects, or that do not
+have a specific project, are hidden.
+
+Members of a group that is granted the
+link:access-control.html#capability_viewQueue[View Queue] capability or
+the link:access-control.html#capability_administrateServer[Administrate
+Server] capability can see all tasks.
+
+As result a list of link:#task-info[TaskInfo] entities is returned.
+
+The entries in the list are sorted by task state, remaining delay and
+command.
+
+.Request
+----
+ GET /config/server/tasks/ HTTP/1.0
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ [
+ {
+ "id": "1e688bea",
+ "state": "SLEEPING",
+ "start_time": "2014-06-11 12:58:51.991000000",
+ "delay": 3453,
+ "command": "Reload Submit Queue"
+ },
+ {
+ "id": "3e6d4ffa",
+ "state": "SLEEPING",
+ "start_time": "2014-06-11 12:58:51.508000000",
+ "delay": 3287966,
+ "command": "Log File Compressor"
+ }
+ ]
+----
+
+[[get-task]]
+=== Get Task
+--
+'GET /config/server/tasks/link:#task-id[\{task-id\}]'
+--
+
+Retrieves a task from the background work queue that the Gerrit daemon
+is currently performing, or will perform in the near future.
+
+End-users may see a task only if they can also see the project the task
+is associated with. Tasks operating on other projects, or that do not
+have a specific project, are hidden.
+
+Members of a group that is granted the
+link:access-control.html#capability_viewQueue[View Queue] capability or
+the link:access-control.html#capability_administrateServer[Administrate
+Server] capability can see all tasks.
+
+As result a link:#task-info[TaskInfo] entity is returned.
+
+.Request
+----
+ GET /config/server/tasks/1e688bea HTTP/1.0
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "id": "1e688bea",
+ "state": "SLEEPING",
+ "start_time": "2014-06-11 12:58:51.991000000",
+ "delay": 3453,
+ "command": "Reload Submit Queue"
+ }
+----
+
+[[delete-task]]
+=== Delete Task
+--
+'DELETE /config/server/tasks/link:#task-id[\{task-id\}]'
+--
+
+Kills a task from the background work queue that the Gerrit daemon
+is currently performing, or will perform in the near future.
+
+The caller must be a member of a group that is granted the
+link:access-control.html#capability_kill[Kill Task] capability
+or the link:access-control.html#capability_administrateServer[
+Administrate Server] capability.
+
+End-users may see a task only if they can also see the project the task
+is associated with. Tasks operating on other projects, or that do not
+have a specific project, are hidden.
+
+Members of a group that is granted the
+link:access-control.html#capability_viewQueue[View Queue] capability or
+the link:access-control.html#capability_administrateServer[Administrate
+Server] capability can see all tasks.
+
+.Request
+----
+ DELETE /config/server/tasks/1e688bea HTTP/1.0
+----
+
+.Response
+----
+ HTTP/1.1 204 No Content
+----
+
[[get-top-menus]]
=== Get Top Menus
--
@@ -176,9 +801,52 @@
----
+[[ids]]
+== IDs
+
+[[cache-name]]
+=== \{cache-name\}
+The name of the cache.
+
+If the cache is defined by a plugin the cache name must include the
+plugin name: "<plugin-name>-<cache-name>".
+
+Gerrit core caches can optionally be prefixed with "gerrit":
+"gerrit-<cache-name>".
+
+[[task-id]]
+=== \{task-id\}
+The ID of the task (hex string).
+
+
[[json-entities]]
== JSON Entities
+[[cache-info]]
+=== CacheInfo
+The `CacheInfo` entity contains information about a cache.
+
+[options="header",width="50%",cols="1,^1,5"]
+|==================================
+|Field Name ||Description
+|`name` |
+not set if returned in a map where the cache name is used as map key|
+The cache name. If the cache is defined by a plugin the cache name
+includes the plugin name: "<plugin-name>-<cache-name>".
+|`type` ||
+The type of the cache (`MEM`: in memory cache, `DISK`: disk cache).
+|`entries` ||
+Information about the entries in the cache as a
+link:#entries-info[EntriesInfo] entity.
+|`average_get` |optional|
+The average duration of getting one entry from the cache. The value is
+returned with a standard time unit abbreviation (`ns`: nanoseconds,
+`us`: microseconds, `ms`: milliseconds, `s`: seconds).
+|`hit_ratio` ||
+Information about the hit ratio as a link:#hit-ration-info[
+HitRatioInfo] entity.
+|==================================
+
[[capability-info]]
=== CapabilityInfo
The `CapabilityInfo` entity contains information about a capability.
@@ -186,11 +854,195 @@
[options="header",width="50%",cols="1,6"]
|=================================
|Field Name |Description
-|`kind` |`gerritcodereview#capability`
|`id` |capability ID
|`name` |capability name
|=================================
+[[cache-operation-input]]
+=== CacheOperationInput
+The `CacheOperationInput` entity contains information about an
+operation that should be executed on caches.
+
+[options="header",width="50%",cols="1,^1,5"]
+|==================================
+|Field Name ||Description
+|`operation` ||
+The cache operation that should be executed:
+
+`FLUSH_ALL`: Flushes all caches, except the `web_sessions` cache.
+
+`FLUSH`: Flushes the specified caches.
+|`caches` |optional|
+A list of cache names. This list defines the caches on which the
+specified operation should be executed. Whether this list must be
+specified depends on the operation being executed.
+|==================================
+
+[[entries-info]]
+=== EntriesInfo
+The `EntriesInfo` entity contains information about the entries in a
+cache.
+
+[options="header",width="50%",cols="1,^1,5"]
+|==================================
+|Field Name ||Description
+|`mem` |optional|Number of cache entries that are held in memory.
+|`disk` |optional|Number of cache entries on the disk. For non-disk
+caches this value is not set; for disk caches it is only set if there
+are entries in the cache.
+|`space` |optional|
+The space that is consumed by the cache on disk. The value is returned
+with a unit abbreviation (`k`: kilobytes, `m`: megabytes,
+`g`: gigabytes). Only set for disk caches.
+|==================================
+
+[[hit-ration-info]]
+=== HitRatioInfo
+The `HitRatioInfo` entity contains information about the hit ratio of a
+cache.
+
+[options="header",width="50%",cols="1,^1,5"]
+|==================================
+|Field Name ||Description
+|`mem` ||
+Hit ratio for cache entries that are held in memory (0 \<= value \<= 100).
+|`disk` |optional|
+Hit ratio for cache entries that are held on disk (0 \<= value \<= 100).
+Only set for disk caches.
+|==================================
+
+[[jvm-summary-info]]
+=== JvmSummaryInfo
+The `JvmSummaryInfo` entity contains information about the JVM.
+
+[options="header",width="50%",cols="1,^1,5"]
+|========================================
+|Field Name ||Description
+|`vm_vendor` ||The vendor of the virtual machine.
+|`vm_name` ||The name of the virtual machine.
+|`vm_version` ||The version of the virtual machine.
+|`os_name` ||The name of the operating system.
+|`os_version` ||The version of the operating system.
+|`os_arch` ||The architecture of the operating system.
+|`user` ||The user that is running Gerrit.
+|`host` |optional|
+The host on which Gerrit is running.
+|`current_working_directory`||The current working directory.
+|`site` ||The path to the review site.
+|========================================
+
+[[mem-summary-info]]
+=== MemSummaryInfo
+The `MemSummaryInfo` entity contains information about the current
+memory usage.
+
+[options="header",width="50%",cols="1,^1,5"]
+|============================
+|Field Name ||Description
+|`total` ||
+The total size of the memory. The value is returned with a unit
+abbreviation (`k`: kilobytes, `m`: megabytes, `g`: gigabytes).
+|`used` ||
+The size of used memory. The value is returned with a unit abbreviation
+(`k`: kilobytes, `m`: megabytes, `g`: gigabytes).
+|`free` ||
+The size of free memory. The value is returned with a unit abbreviation
+(`k`: kilobytes, `m`: megabytes, `g`: gigabytes).
+|`buffers` ||
+The size of memory used for JGit buffers. The value is returned with a
+unit abbreviation (`k`: kilobytes, `m`: megabytes, `g`: gigabytes).
+|`max` ||
+The maximal memory size. The value is returned with a unit abbreviation
+(`k`: kilobytes, `m`: megabytes, `g`: gigabytes).
+|`open_files` |optional|
+The number of open files.
+|============================
+
+[[summary-info]]
+=== SummaryInfo
+The `SummaryInfo` entity contains information about the current state
+of the server.
+
+[options="header",width="50%",cols="1,^1,5"]
+|============================
+|Field Name ||Description
+|`task_summary` ||
+Summary about current tasks as a link:#task-summary-info[
+TaskSummaryInfo] entity.
+|`mem_summary` ||
+Summary about current memory usage as a link:#mem-summary-info[
+MemSummaryInfo] entity.
+|`thread_summary` ||
+Summary about current threads as a link:#thread-summary-info[
+ThreadSummaryInfo] entity.
+|`jvm_summary` |optional|
+Summary about the JVM link:#jvm-summary-info[JvmSummaryInfo] entity.
+Only set if the `jvm` option was set.
+|============================
+
+[[task-info]]
+=== TaskInfo
+The `TaskInfo` entity contains information about a task in a background
+work queue.
+
+[options="header",width="50%",cols="1,^1,5"]
+|====================================
+|Field Name ||Description
+|`id` ||The ID of the task.
+|`state` ||
+The state of the task, can be `DONE`, `CANCELLED`, `RUNNING`, `READY`,
+`SLEEPING` and `OTHER`.
+|`start_time` ||The start time of the task.
+|`delay` ||The remaining delay of the task.
+|`command` ||The command of the task.
+|`remote_name`|optional|
+The remote name. May only be set for tasks that are associated with a
+project.
+|`project` |optional|The project the task is associated with.
+|====================================
+
+[[task-summary-info]]
+=== TaskSummaryInfo
+The `TaskSummaryInfo` entity contains information about the current
+tasks.
+
+[options="header",width="50%",cols="1,^1,5"]
+|============================
+|Field Name ||Description
+|`total` |optional|
+Total number of current tasks.
+|`running` |optional|
+Number of currently running tasks.
+|`ready` |optional|
+Number of currently ready tasks.
+|`sleeping` |optional|
+Number of currently sleeping tasks.
+|============================
+
+[[thread-summary-info]]
+=== ThreadSummaryInfo
+The `ThreadSummaryInfo` entity contains information about the current
+threads.
+
+[options="header",width="50%",cols="1,6"]
+|===========================
+|Field Name |Description
+|`cpus` |
+The number of available processors.
+|`threads` |
+The total number of current threads.
+|`counts` |
+Detailed thread counts as a map that maps a thread kind to a map that
+maps a thread state to the thread count. The thread kinds group the
+counts by threads that have the same name prefix (`HTTP`,
+`IntraLineDiff`, `ReceiveCommits`, `SSH git-receive-pack`,
+`SSH git-upload-pack`, `SSH-Interactive-Worker`, `SSH-Stream-Worker`,
+`SshCommandStart`). The counts for other threads are available under
+the thread kind `Other`. Counts for the following thread states can be
+included: `NEW`, `RUNNABLE`, `BLOCKED`, `WAITING`, `TIMED_WAITING` and
+`TERMINATED`.
+|===========================
+
[[top-menu-entry-info]]
=== TopMenuEntryInfo
The `TopMenuEntryInfo` entity contains information about a top menu
diff --git a/Documentation/rest-api-groups.txt b/Documentation/rest-api-groups.txt
index 5ca3039..afdcffd 100644
--- a/Documentation/rest-api-groups.txt
+++ b/Documentation/rest-api-groups.txt
@@ -35,7 +35,6 @@
)]}'
{
"Administrators": {
- "kind": "gerritcodereview#group",
"id": "6a1e70e1a88782771a91808c8af9bbb7a9871389",
"url": "#/admin/groups/uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389",
"options": {
@@ -46,7 +45,6 @@
"owner_id": "6a1e70e1a88782771a91808c8af9bbb7a9871389"
},
"Anonymous Users": {
- "kind": "gerritcodereview#group",
"id": "global%3AAnonymous-Users",
"url": "#/admin/groups/uuid-global%3AAnonymous-Users",
"options": {
@@ -57,7 +55,6 @@
"owner_id": "6a1e70e1a88782771a91808c8af9bbb7a9871389"
},
"MyProject_Committers": {
- "kind": "gerritcodereview#group",
"id": "834ec36dd5e0ed21a2ff5d7e2255da082d63bbd7",
"url": "#/admin/groups/uuid-834ec36dd5e0ed21a2ff5d7e2255da082d63bbd7",
"options": {
@@ -68,7 +65,6 @@
"owner_id": "834ec36dd5e0ed21a2ff5d7e2255da082d63bbd7"
},
"Non-Interactive Users": {
- "kind": "gerritcodereview#group",
"id": "5057f3cbd3519d6ab69364429a89ffdffba50f73",
"url": "#/admin/groups/uuid-5057f3cbd3519d6ab69364429a89ffdffba50f73",
"options": {
@@ -79,7 +75,6 @@
"owner_id": "6a1e70e1a88782771a91808c8af9bbb7a9871389"
},
"Project Owners": {
- "kind": "gerritcodereview#group",
"id": "global%3AProject-Owners",
"url": "#/admin/groups/uuid-global%3AProject-Owners",
"options": {
@@ -90,7 +85,6 @@
"owner_id": "6a1e70e1a88782771a91808c8af9bbb7a9871389"
},
"Registered Users": {
- "kind": "gerritcodereview#group",
"id": "global%3ARegistered-Users",
"url": "#/admin/groups/uuid-global%3ARegistered-Users",
"options": {
@@ -147,7 +141,6 @@
)]}'
{
"MyProject-Committers": {
- "kind": "gerritcodereview#group",
"id": "9999c971bb4ab872aab759d8c49833ee6b9ff320",
"url": "#/admin/groups/uuid-9999c971bb4ab872aab759d8c49833ee6b9ff320",
"options": {
@@ -203,7 +196,6 @@
)]}'
{
- "kind": "gerritcodereview#group",
"id": "6a1e70e1a88782771a91808c8af9bbb7a9871389",
"name": "Administrators",
"url": "#/admin/groups/uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389",
@@ -251,7 +243,6 @@
)]}'
{
- "kind": "gerritcodereview#group",
"id": "9999c971bb4ab872aab759d8c49833ee6b9ff320",
"name": "MyProject-Committers",
"url": "#/admin/groups/uuid-9999c971bb4ab872aab759d8c49833ee6b9ff320",
@@ -293,7 +284,6 @@
)]}'
{
- "kind": "gerritcodereview#group",
"id": "6a1e70e1a88782771a91808c8af9bbb7a9871389",
"name": "Administrators",
"url": "#/admin/groups/uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389",
@@ -544,7 +534,6 @@
)]}'
{
- "kind": "gerritcodereview#group",
"id": "6a1e70e1a88782771a91808c8af9bbb7a9871389",
"name": "Administrators",
"url": "#/admin/groups/uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389",
@@ -591,7 +580,6 @@
)]}'
{
- "kind": "gerritcodereview#group",
"id": "6a1e70e1a88782771a91808c8af9bbb7a9871389",
"name": "Administrators",
"url": "#/admin/groups/uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389",
@@ -892,7 +880,6 @@
)]}'
[
{
- "kind": "gerritcodereview#group",
"id": "7ca042f4d5847936fcb90ca91057673157fd06fc",
"name": "MyProject-Verifiers",
"url": "#/admin/groups/uuid-7ca042f4d5847936fcb90ca91057673157fd06fc",
@@ -929,7 +916,6 @@
)]}'
{
- "kind": "gerritcodereview#group",
"id": "7ca042f4d5847936fcb90ca91057673157fd06fc",
"name": "MyProject-Verifiers",
"url": "#/admin/groups/uuid-7ca042f4d5847936fcb90ca91057673157fd06fc",
@@ -966,7 +952,6 @@
)]}'
{
- "kind": "gerritcodereview#group",
"id": "6a1e70e1a88782771a91808c8af9bbb7a9871389",
"name": "MyGroup",
"url": "#/admin/groups/uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389",
@@ -1027,7 +1012,6 @@
)]}'
[
{
- "kind": "gerritcodereview#group",
"id": "6a1e70e1a88782771a91808c8af9bbb7a9871389",
"name": "MyGroup",
"url": "#/admin/groups/uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389",
@@ -1038,7 +1022,6 @@
"owner_id": "6a1e70e1a88782771a91808c8af9bbb7a9871389"
},
{
- "kind": "gerritcodereview#group",
"id": "5057f3cbd3519d6ab69364429a89ffdffba50f73",
"name": "MyOtherGroup",
"url": "#/admin/groups/uuid-5057f3cbd3519d6ab69364429a89ffdffba50f73",
@@ -1133,7 +1116,6 @@
[options="header",width="50%",cols="1,^1,5"]
|===========================
|Field Name ||Description
-|`kind` ||`gerritcodereview#group`
|`id` ||The URL encoded UUID of the group.
|`name` |
not set if returned in a map where the group name is used as map key|
diff --git a/Documentation/rest-api-plugins.txt b/Documentation/rest-api-plugins.txt
index 0011213..b8f7d36 100644
--- a/Documentation/rest-api-plugins.txt
+++ b/Documentation/rest-api-plugins.txt
@@ -45,13 +45,11 @@
)]}'
{
"delete-project": {
- "kind": "gerritcodereview#plugin",
"id": "delete-project",
"index_url": "plugins/delete-project/",
"version": "2.9-SNAPSHOT"
},
"reviewers-by-blame": {
- "kind": "gerritcodereview#plugin",
"id": "reviewers-by-blame",
"index_url": "plugins/reviewers-by-blame/",
"version": "2.9-SNAPSHOT",
@@ -103,7 +101,6 @@
)]}'
{
- "kind": "gerritcodereview#plugin",
"id": "delete-project",
"version": "2.8"
}
@@ -135,7 +132,6 @@
)]}'
{
- "kind": "gerritcodereview#plugin",
"id": "delete-project",
"version": "2.8"
}
@@ -165,7 +161,6 @@
)]}'
{
- "kind": "gerritcodereview#plugin",
"id": "delete-project",
"version": "2.8"
}
@@ -201,7 +196,6 @@
)]}'
{
- "kind": "gerritcodereview#plugin",
"id": "delete-project",
"version": "2.8",
"disabled": true
@@ -232,7 +226,6 @@
)]}'
{
- "kind": "gerritcodereview#plugin",
"id": "delete-project",
"version": "2.8",
"disabled": true
@@ -257,7 +250,6 @@
[options="header",width="50%",cols="1,^2,4"]
|=======================
|Field Name ||Description
-|`kind` ||`gerritcodereview#plugin`
|`id` ||The ID of the plugin.
|`version` ||The version of the plugin.
|`index_url`|optional|URL of the plugin's default page.
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index 39eabdf..2cc1e9a 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -35,43 +35,127 @@
)]}'
{
"external/bison": {
- "kind": "gerritcodereview#project",
"id": "external%2Fbison",
"description": "GNU parser generator"
},
"external/gcc": {
- "kind": "gerritcodereview#project",
- "id": "external%2Fgcc",
+ "id": "external%2Fgcc"
},
"external/openssl": {
- "kind": "gerritcodereview#project",
"id": "external%2Fopenssl",
"description": "encryption\ncrypto routines"
},
"test": {
- "kind": "gerritcodereview#project",
"id": "test",
"description": "\u003chtml\u003e is escaped"
}
}
----
-.Get all projects with their description
-****
-get::/projects/?d
-****
+[[project-options]]
+==== Project Options
+
+Branch(b)::
+Limit the results to the projects having the specified branch and
+include the sha1 of the branch in the results.
++
+Get projects that have a 'master' branch:
++
+.Request
+----
+GET /projects/?b=master HTTP/1.0
+----
++
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "some-project": {
+ "id": "some-project",
+ "branches": {
+ "master": "c5ed9dfcbf002ca0e432d788dab6ca2387829ca7"
+ }
+ },
+ "some-other-project": {
+ "id": "some-other-project",
+ "branches": {
+ "master": "ef1c270142f9581ecf768f4193fc8f8a81102ec2"
+ }
+ },
+ }
+----
+
+Description(d)::
+Include project description in the results.
++
+Get all the projects with their description:
++
+.Request
+----
+GET /projects/?d HTTP/1.0
+----
++
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "some-project": {
+ "id": "some-project",
+ "description": "Description of some project."
+ },
+ "some-other-project": {
+ "id": "some-other-project",
+ "description": "Description of some other project."
+ }
+ },
+ }
+----
+
+Limit(n)::
+Limit the number of projects to be included in the results.
++
+Query the first project in the project list:
++
+.Request
+----
+ GET /projects/?n=1 HTTP/1.0
+----
++
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "some-project": {
+ "id": "some-project"
+ }
+ }
+----
+
[[suggest-projects]]
-The `/projects/` URL also accepts a prefix string in the `p` parameter.
-This limits the results to those projects that start with the specified
+Prefix(p)::
+Limit the results to those projects that start with the specified
prefix.
++
List all projects that start with `platform/`:
-
++
.Request
----
GET /projects/?p=platform%2F HTTP/1.0
----
-
++
.Response
----
HTTP/1.1 200 OK
@@ -81,31 +165,157 @@
)]}'
{
"platform/drivers": {
- "kind": "gerritcodereview#project",
- "id": "platform%2Fdrivers",
+ "id": "platform%2Fdrivers"
},
"platform/tools": {
- "kind": "gerritcodereview#project",
- "id": "platform%2Ftools",
+ "id": "platform%2Ftools"
}
}
----
++
E.g. this feature can be used by suggestion client UI's to limit results.
-The `/projects/` URL also accepts a limit integer in the `n` parameter.
-This limits the results to show `n` projects.
-
-Query the first 25 projects in project list.
+Regex(r)::
+Limit the results to those projects that match the specified regex.
++
+Boundary matchers '^' and '$' are implicit. For example: the regex 'test.*' will
+match any projects that start with 'test' and regex '.*test' will match any
+project that end with 'test'.
++
+List all projects that match regex `test.*project`:
++
+.Request
----
- GET /projects/?n=25 HTTP/1.0
+ GET /projects/?r=test.*project HTTP/1.0
+----
++
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "test/some-project": {
+ "id": "test%2Fsome-project"
+ },
+ "test/some-other-project": {
+ "id": "test%2Fsome-other-project"
+ }
+ }
+
----
-The `/projects/` URL also accepts a start integer in the `S` parameter.
-The results will skip `S` projects from project list.
-
-Query 25 projects starting from index 50.
+Skip(S)::
+Skip the given number of projects from the beginning of the list.
++
+Query the second project in the project list:
++
+.Request
----
- GET /projects/?n=25&S=50 HTTP/1.0
+ GET /projects/?n=1&S=1 HTTP/1.0
+----
++
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "some-other-project": {
+ "id": "some-other-project"
+ }
+ }
+----
+
+Substring(m)::
+Limit the results to those projects that match the specified substring.
++
+List all projects that match substring `test/`:
++
+.Request
+----
+ GET /projects/?m=test%2F HTTP/1.0
+----
++
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "test/some-project": {
+ "id": "test%2Fsome-project"
+ },
+ "some-path/test/some-other-project": {
+ "id": "some-path%2Ftest%2Fsome-other-project"
+ }
+ }
+----
+
+Tree(t)::
+Get projects inheritance in a tree-like format. This option does
+not work together with the branch option.
++
+Get all the projects with tree option:
++
+.Request
+----
+GET /projects/?t HTTP/1.0
+----
++
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "All-Projects" {
+ "id": "All-Projects"
+ },
+ "child-project": {
+ "id": "child-project",
+ "parent":"parent-project"
+ },
+ "parent-project": {
+ "id": "parent-project",
+ "parent":"All-Projects"
+ }
+ }
+----
+
+Type(type)::
+Get projects with specified type: ALL, CODE, PERMISSIONS.
++
+Get all the projects of type 'PERMISSIONS':
++
+.Request
+----
+GET /projects/?type=PERMISSIONS HTTP/1.0
+----
++
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "All-Projects" {
+ "id": "All-Projects"
+ },
+ "some-parent-project": {
+ "id": "some-parent-project"
+ }
+ }
----
[[get-project]]
@@ -132,11 +342,11 @@
)]}'
{
- "kind": "gerritcodereview#project",
"id": "plugins%2Freplication",
"name": "plugins/replication",
"parent": "Public-Plugins",
- "description": "Copies to other servers using the Git protocol"
+ "description": "Copies to other servers using the Git protocol",
+ "state": "ACTIVE"
}
----
@@ -176,7 +386,6 @@
)]}'
{
- "kind": "gerritcodereview#project",
"id": "MyProject",
"name": "MyProject",
"parent": "All-Projects",
@@ -446,7 +655,6 @@
)]}'
{
- "kind": "gerritcodereview#project_config",
"description": "demo project",
"use_contributor_agreements": {
"value": true,
@@ -535,7 +743,6 @@
)]}'
{
- "kind": "gerritcodereview#project_config",
"use_contributor_agreements": {
"value": false,
"configured_value": "FALSE",
@@ -614,6 +821,57 @@
done.
----
+[[ban-commit]]
+=== Ban Commit
+--
+'PUT /projects/link:#project-name[\{project-name\}]/ban'
+--
+
+Marks commits as banned for the project. If a commit is banned Gerrit
+rejects every push that includes this commit with
+link:error-contains-banned-commit.html[contains banned commit ...].
+
+[NOTE]
+This REST endpoint only marks the commits as banned, but it does not
+remove the commits from the history of any central branch. This needs
+to be done manually.
+
+The commits to be banned must be specified in the request body as a
+link:#ban-input[BanInput] entity.
+
+The caller must be project owner.
+
+.Request
+----
+ PUT /projects/plugins%2Freplication/ban HTTP/1.0
+ Content-Type: application/json;charset=UTF-8
+
+ {
+ "commits": [
+ "a8a477efffbbf3b44169bb9a1d3a334cbbd9aa96",
+ "cf5b56541f84b8b57e16810b18daca9c3adc377b"
+ ],
+ "reason": "Violates IP"
+ }
+----
+
+As response a link:#ban-result-info[BanResultInfo] entity is returned.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "newly_banned": [
+ "a8a477efffbbf3b44169bb9a1d3a334cbbd9aa96",
+ "cf5b56541f84b8b57e16810b18daca9c3adc377b"
+ ]
+ }
+----
+
[[branch-endpoints]]
== Branch Endpoints
@@ -770,6 +1028,85 @@
Ly8gQ29weXJpZ2h0IChDKSAyMDEwIFRoZSBBbmRyb2lkIE9wZW4gU291cmNlIFByb2plY...
----
+[[get-reflog]]
+=== Get Reflog
+--
+'GET /projects/link:#project-name[\{project-name\}]/branches/link:#branch-id[\{branch-id\}]/reflog'
+--
+
+Gets the reflog of a certain branch.
+
+The caller must be project owner.
+
+.Request
+----
+ GET /projects/gerrit/branches/master/reflog HTTP/1.0
+----
+
+As response a list of link:#reflog-entry-info[ReflogEntryInfo] entities
+is returned that describe the reflog entries. The reflog entries are
+returned in reverse order.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ [
+ {
+ "old_id": "976ced8f4fc0909d7e1584d18455299545881d60",
+ "new_id": "2eaa94bac536654eb592c941e33b91f925698d16",
+ "who": {
+ "name": "Jane Roe",
+ "email": "jane.roe@example.com",
+ "date": "2014-06-30 11:53:43.000000000",
+ "tz": 120
+ },
+ "comment": "merged: fast forward"
+ },
+ {
+ "old_id": "c271c6a7161b74f85560c5899c8c73ee89ca5e29",
+ "new_id": "976ced8f4fc0909d7e1584d18455299545881d60",
+ "who": {
+ "name": "John Doe",
+ "email": "john.doe@example.com",
+ "date": "2013-10-02 10:45:26.000000000",
+ "tz": 120
+ },
+ "comment": "merged: fast forward"
+ },
+ {
+ "old_id": "0000000000000000000000000000000000000000",
+ "new_id": "c271c6a7161b74f85560c5899c8c73ee89ca5e29",
+ "who": {
+ "name": "John Doe",
+ "email": "john.doe@example.com",
+ "date": "2013-09-30 19:08:44.000000000",
+ "tz": 120
+ },
+ "comment": ""
+ }
+ ]
+----
+
+The get reflog endpoint also accepts a limit integer in the `n`
+parameter. This limits the results to show the last `n` reflog entries.
+
+Query the last 25 reflog entries.
+----
+ GET /projects/gerrit/branches/master/reflog?n=25 HTTP/1.0
+----
+
+The reflog can also be filtered by timestamp by specifying the `from`
+and `to` parameters. The timestamp for `from` and `to` must be given as
+UTC in the following format: `yyyyMMdd_HHmm`.
+
+----
+ GET /projects/gerrit/branches/master/reflog?from=20130101_0000&to=20140101_0000=25 HTTP/1.0
+----
+
[[child-project-endpoints]]
== Child Project Endpoints
@@ -798,21 +1135,18 @@
)]}'
[
{
- "kind": "gerritcodereview#project",
"id": "plugins%2Freplication",
"name": "plugins/replication",
"parent": "Public-Plugins",
"description": "Copies to other servers using the Git protocol"
},
{
- "kind": "gerritcodereview#project",
"id": "plugins%2Freviewnotes",
"name": "plugins/reviewnotes",
"parent": "Public-Plugins",
"description": "Annotates merged commits using notes on refs/notes/review."
},
{
- "kind": "gerritcodereview#project",
"id": "plugins%2Fsingleusergroup",
"name": "plugins/singleusergroup",
"parent": "Public-Plugins",
@@ -841,35 +1175,30 @@
)]}'
[
{
- "kind": "gerritcodereview#project",
"id": "gerrit",
"name": "gerrit",
"parent": "Public-Projects",
"description": "Gerrit Code Review"
},
{
- "kind": "gerritcodereview#project",
"id": "plugins%2Freplication",
"name": "plugins/replication",
"parent": "Public-Plugins",
"description": "Copies to other servers using the Git protocol"
},
{
- "kind": "gerritcodereview#project",
"id": "plugins%2Freviewnotes",
"name": "plugins/reviewnotes",
"parent": "Public-Plugins",
"description": "Annotates merged commits using notes on refs/notes/review."
},
{
- "kind": "gerritcodereview#project",
"id": "plugins%2Fsingleusergroup",
"name": "plugins/singleusergroup",
"parent": "Public-Plugins",
"description": "GroupBackend enabling users to be directly added to access rules"
},
{
- "kind": "gerritcodereview#project",
"id": "Public-Plugins",
"name": "Public-Plugins",
"parent": "Public-Projects",
@@ -903,7 +1232,6 @@
)]}'
{
- "kind": "gerritcodereview#project",
"id": "plugins%2Freplication",
"name": "plugins/replication",
"parent": "Public-Plugins",
@@ -911,6 +1239,83 @@
}
----
+[[commit-endpoints]]
+== Commit Endpoints
+
+[[get-commit]]
+=== Get Commit
+--
+'GET /projects/link:#project-name[\{project-name\}]/commits/link:#commit-id[\{commit-id\}]'
+--
+
+Retrieves a commit of a project.
+
+The commit must be visible to the caller.
+
+.Request
+----
+ GET /projects/work%2Fmy-project/commits/a8a477efffbbf3b44169bb9a1d3a334cbbd9aa96 HTTP/1.0
+----
+
+As response a link:rest-api-changes.html#commit-info[CommitInfo] entity
+is returned that describes the commit.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json;charset=UTF-8
+
+ )]}'
+ {
+ "commit": "184ebe53805e102605d11f6b143486d15c23a09c",
+ "parents": [
+ {
+ "commit": "1eee2c9d8f352483781e772f35dc586a69ff5646",
+ "subject": "Migrate contributor agreements to All-Projects."
+ }
+ ],
+ "author": {
+ "name": "Shawn O. Pearce",
+ "email": "sop@google.com",
+ "date": "2012-04-24 18:08:08.000000000",
+ "tz": -420
+ },
+ "committer": {
+ "name": "Shawn O. Pearce",
+ "email": "sop@google.com",
+ "date": "2012-04-24 18:08:08.000000000",
+ "tz": -420
+ },
+ "subject": "Use an EventBus to manage star icons",
+ "message": "Use an EventBus to manage star icons\n\nImage widgets that need to ..."
+ }
+----
+
+[[get-content]]
+=== Get Content
+--
+'GET /projects/link:#project-name[\{project-name\}]/commits/link:#commit-id[\{commit-id\}]/files/link:rest-api-changes.html#file-id[\{file-id\}]/content'
+--
+
+Gets the content of a file from a certain commit.
+
+.Request
+----
+ GET /projects/work%2Fmy-project/commits/a8a477efffbbf3b44169bb9a1d3a334cbbd9aa96/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.
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: text/plain;charset=UTF-8
+
+ Ly8gQ29weXJpZ2h0IChDKSAyMDEwIFRoZSBBbmRyb2lkIE9wZW4gU291cmNlIFByb2plY...
+----
+
[[dashboard-endpoints]]
== Dashboard Endpoints
@@ -941,7 +1346,6 @@
)]}'
[
{
- "kind": "gerritcodereview#dashboard",
"id": "main:closed",
"ref": "main",
"path": "closed",
@@ -993,7 +1397,6 @@
)]}'
{
- "kind": "gerritcodereview#dashboard",
"id": "main:closed",
"ref": "main",
"path": "closed",
@@ -1030,7 +1433,6 @@
)]}'
{
- "kind": "gerritcodereview#dashboard",
"id": "main:closed",
"ref": "main",
"path": "closed",
@@ -1086,7 +1488,6 @@
)]}'
{
- "kind": "gerritcodereview#dashboard",
"id": "main:closed",
"ref": "main",
"path": "closed",
@@ -1142,6 +1543,10 @@
The name of a branch or `HEAD`. The prefix `refs/heads/` can be
omitted.
+[[commit-id]]
+=== \{commit-id\}
+Commit ID.
+
[[dashboard-id]]
=== \{dashboard-id\}
The ID of a dashboard in the format '<ref>:<path>'.
@@ -1170,6 +1575,30 @@
Whether the calling user can delete this branch.
|=========================
+[[ban-input]]
+=== BanInput
+The `BanInput` entity contains information for banning commits in a
+project.
+
+[options="header",width="50%",cols="1,^2,4"]
+|=======================
+|Field Name||Description
+|`commits` ||List of commits to be banned.
+|`reason` |optional|Reason for banning the commits.
+|=======================
+
+[[ban-result-info]]
+=== BanResultInfo
+The `BanResultInfo` entity describes the result of banning commits.
+
+[options="header",width="50%",cols="1,^2,4"]
+|=============================
+|Field Name ||Description
+|`newly_banned` |optional|List of newly banned commits.
+|`already_banned`|optional|List of commits that were already banned.
+|`ignored` |optional|List of object IDs that were ignored.
+|=============================
+
[[branch-input]]
=== BranchInput
The `BranchInput` entity contains information for the creation of
@@ -1347,7 +1776,6 @@
[options="header",width="50%",cols="1,^2,4"]
|===============================
|Field Name ||Description
-|`kind` ||`gerritcodereview#dashboard`
|`id` ||
The ID of the dashboard. The ID has the format '<ref>:<path>',
where ref and path are URL encoded.
@@ -1490,7 +1918,6 @@
[options="header",width="50%",cols="1,^2,4"]
|===========================
|Field Name ||Description
-|`kind` ||`gerritcodereview#project`
|`id` ||The URL encoded project name.
|`name` |
not set if returned in a map where the project name is used as map key|
@@ -1500,7 +1927,11 @@
`?-<n>` if the parent project is not visible (`<n>` is a number which
is increased for each non-visible project).
|`description` |optional|The description of the project.
+|`state` |optional|`ACTIVE`, `READ_ONLY` or `HIDDEN`.
|`branches` |optional|Map of branch names to HEAD revisions.
+|'web_links' |optional|
+Links to the project in external sites as a list of
+link:rest-api-changes.html#web-link-info[WebLinkInfo] entries.
|===========================
[[project-input]]
@@ -1574,6 +2005,21 @@
in the `project.config` file to the `refs/meta/config` branch.
|=============================
+[[reflog-entry-info]]
+=== ReflogEntryInfo
+The `ReflogEntryInfo` entity describes an entry in a reflog.
+
+[options="header",width="50%",cols="1,6"]
+|============================
+|Field Name |Description
+|`old_id` |The old commit ID.
+|`new_id` |The new commit ID.
+|`who` |
+The user performing the change as a
+link:rest-api-changes.html#git-person-info[GitPersonInfo] entity.
+|`comment` |Comment of the reflog entry.
+|============================
+
[[repository-statistics-info]]
=== RepositoryStatisticsInfo
The `RepositoryStatisticsInfo` entity contains information about
diff --git a/Documentation/rest-api.txt b/Documentation/rest-api.txt
index 6c681e5..b228dda 100644
--- a/Documentation/rest-api.txt
+++ b/Documentation/rest-api.txt
@@ -32,11 +32,14 @@
results to correspond to what anonymous users can read (which may
be nothing at all).
-Users (and programs) may authenticate using HTTP authentication by
-supplying the HTTP password from the user's account settings page.
-Gerrit by default uses HTTP digest authentication. To authenticate,
-prefix the endpoint URL with `/a/`. For example to authenticate to
-`/projects/` request URL `/a/projects/`.
+Users (and programs) may authenticate by prefixing the endpoint URL with
+`/a/`. For example to authenticate to `/projects/`, request the URL
+`/a/projects/`.
+
+By default Gerrit uses HTTP digest authentication with the HTTP password
+from the user's account settings page. HTTP basic authentication is used
+if link:config-gerrit.html#auth.gitBasicAuth[`auth.gitBasicAuth`] is set
+to true in the Gerrit configuration.
[[preconditions]]
=== Preconditions
@@ -47,17 +50,22 @@
[[output]]
=== Output Format
-Most APIs return pretty printed JSON by default. Compact JSON can be
-requested by setting the `Accept` HTTP request header to include
-`application/json`, for example:
+JSON responses are encoded using UTF-8 and use content type
+`application/json`.
+
+By default most APIs return pretty-printed JSON, which uses extra
+whitespace to make the output more readable for humans.
+
+Compact JSON can be requested by setting the `pp=0` query parameter,
+or by setting the `Accept` HTTP request header to include `application/json`:
----
GET /projects/ HTTP/1.0
Accept: application/json
----
-JSON responses are encoded using UTF-8 and use content type
-`application/json`.
+Producing (and parsing) the non-pretty compact format is more efficient,
+so tools should request it whenever possible.
To prevent against Cross Site Script Inclusion (XSSI) attacks, the JSON
response body starts with a magic prefix line that must be stripped before
@@ -68,12 +76,6 @@
[ ... valid JSON ... ]
----
-The default JSON format is pretty, which uses extra whitespace to make
-the output more readable for a human. Producing (and parsing) the
-non-pretty compact format is more efficient so tools should request it
-by using the `Accept: application/json` header or `pp=0` query
-parameter whenever possible.
-
Responses will be gzip compressed by the server if the HTTP
`Accept-Encoding` request header is set to `gzip`. This may
save on network transfer time for larger responses.
@@ -81,7 +83,7 @@
[[timestamp]]
=== Timestamp
Timestamps are given in UTC and have the format
-"'yyyy-mm-dd hh:mm:ss.fffffffff'" where "'ffffffffff'" indicates the
+"'yyyy-mm-dd hh:mm:ss.fffffffff'" where "'ffffffffff'" represents
nanoseconds.
[[encoding]]
@@ -91,32 +93,33 @@
[[response-codes]]
=== Response Codes
-HTTP status codes are well defined and the Gerrit REST endpoints use
-them as described in the HTTP spec.
+The Gerrit REST endpoints use HTTP status codes as described
+in the link:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html[
+HTTP specification].
-Here are examples for some HTTP status codes that show how they are
-used in the context of the Gerrit REST API.
+Here are examples that show how HTTP status codes are used in the
+context of the Gerrit REST API.
==== 400 Bad Request
-`400 Bad Request` is used if the request is not understood by the
+`400 Bad Request` is returned if the request is not understood by the
server due to malformed syntax.
E.g. `400 Bad Request` is returned if JSON input is expected but the
'Content-Type' of the request is not 'application/json' or the request
body doesn't contain valid JSON.
-`400 Bad Request` is also used if required input fields are not set or
+`400 Bad Request` is also returned if required input fields are not set or
if options are set which cannot be used together.
==== 403 Forbidden
-`403 Forbidden` is used if the operation is not allowed because the
-calling user has no sufficient permissions.
+`403 Forbidden` is returned if the operation is not allowed because the
+calling user does not have sufficient permissions.
E.g. some REST endpoints require that the calling user has certain
link:access-control.html#global_capabilities[global capabilities]
assigned.
-`403 Forbidden` is also used if `self` is used as account ID and the
+`403 Forbidden` is also returned if `self` is used as account ID and the
REST call was done without authentication.
==== 404 Not Found
@@ -125,27 +128,27 @@
cannot be found if the URL contains a non-existing ID or view.
==== 405 Method Not Allowed
-`405 Method Not Allowed` is used if the resource exists but doesn't
+`405 Method Not Allowed` is returned if the resource exists but doesn't
support the operation.
E.g. some of the `/groups/` endpoints are only supported for Gerrit
-internal groups, if they are invoked for an external group the response
+internal groups; if they are invoked for an external group the response
is `405 Method Not Allowed`.
==== 409 Conflict
-`409 Conflict` is used if the request cannot be completed because the
+`409 Conflict` is returned if the request cannot be completed because the
current state of the resource doesn't allow the operation.
E.g. if you try to submit a change that is abandoned, this fails with
`409 Conflict` because the state of the change doesn't allow the submit
operation.
-`409 Conflict` is also used if you try to create a resource but the
+`409 Conflict` is also returned if you try to create a resource but the
name is already occupied by an existing resource.
==== 412 Precondition Failed
-`412 Precondition Failed` is used if a precondition from the request
-header fields is not fulfilled as described in the link:#preconditions[
+`412 Precondition Failed` is returned if a precondition from the request
+header fields is not fulfilled, as described in the link:#preconditions[
Preconditions] section.
==== 422 Unprocessable Entity
diff --git a/Documentation/user-review-ui.txt b/Documentation/user-review-ui.txt
index 5bc5b44..bb1aeef 100644
--- a/Documentation/user-review-ui.txt
+++ b/Documentation/user-review-ui.txt
@@ -1014,7 +1014,8 @@
Controls whether syntax highlighting should be enabled.
+
The language for the syntax highlighting is automatically detected from
-the file extension.
+the file extension. The language can also be set manually by selecting
+it from the `Language` drop-down list.
+
image::images/user-review-ui-side-by-side-diff-screen-syntax-coloring.png[width=800, link="images/user-review-ui-side-by-side-diff-screen-syntax-coloring.png"]
@@ -1030,6 +1031,17 @@
+
Controls whether line numbers are shown.
+- `Empty Pane`:
++
+Controls whether empty panes are shown or not. The Left pane is empty when a
+file was added; the right pane is empty when a file was deleted.
+
+- `Left Side`:
++
+Controls whether the left side is shown. This preference is not
+persistent and is ignored by the `Save` button. Every time a
+patch diff is opened, this preference is reset to `Show`.
+
- `Top Menu`:
+
Controls whether the top menu is shown.
@@ -1058,6 +1070,8 @@
DOM tree, which makes the rendering slow for large files. The advantage
of this setting is that `Ctrl+F` can be used to search in the complete
file.
++
+Large files that exceed 4000 lines will not be fully rendered.
[[keyboard-shortcuts]]
== Keyboard Shortcuts
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 16dab4e..eaf0f6e 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -43,11 +43,7 @@
Operators act as restrictions on the search. As more operators
are added to the same query string, they further restrict the
returned results. Search can also be performed by typing only a
-text with no operator. It will try to match a project name by
-substring.
-
-E.g. Searching for just "gerrit is:starred" will try to match a
-project name by "gerrit" as substring.
+text with no operator, which will match against a variety of fields.
[[age]]
age:'AGE'::
@@ -127,6 +123,11 @@
link:http://www.brics.dk/automaton/[dk.brics.automaton
library] is used for evaluation of such patterns.
+[[projects]]
+projects:'PREFIX'::
++
+Changes occurring in projects starting with 'PREFIX'.
+
[[parentproject]]
parentproject:'PROJECT'::
+
@@ -264,7 +265,7 @@
True on any change where the current user is a reviewer.
Same as `reviewer:self`.
-is:open::
+is:open, is:pending::
+
True if the change is either open or submitted, merge pending.
@@ -287,7 +288,7 @@
destination branch.
[[status]]
-status:open::
+status:open, status:pending::
+
True if the change state is either 'review in progress' or 'submitted,
merge pending'.
@@ -313,6 +314,18 @@
+
Change has been abandoned.
+[[size]]
+added:'RELATION''LINES', deleted:'RELATION''LINES', delta/size:'RELATION''LINES'::
++
+True if the number of lines added/deleted/changed satisfies the given relation
+for the given number of lines.
++
+For example, added:>50 will be true for any change which adds at least 50
+lines.
++
+Valid relations are >=, >, <=, <, or no relation, which will match if the
+number of lines is exactly equal.
+
== Argument Quoting
diff --git a/Documentation/user-upload.txt b/Documentation/user-upload.txt
index 17ca968..5c54259 100644
--- a/Documentation/user-upload.txt
+++ b/Documentation/user-upload.txt
@@ -20,7 +20,8 @@
When link:config-gerrit.html#auth.gitBasicAuth[gitBasicAuth] is enabled,
the user is authenticated using standard BasicAuth and credentials validated
-using the same authentication method configured for the Gerrit Web UI.
+using the randomly generated HTTP password on the `HTTP Password` tab
+in the user settings page or against LDAP when configured for the Gerrit Web UI.
When gitBasicAuth is not configured, the user's HTTP credentials can be
accessed within Gerrit by going to `Settings`, and then accessing the `HTTP
@@ -154,6 +155,20 @@
git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/experimental%topic=driver/i42
====
+[[review_labels]]
+Review labels can be applied to the change by using the -l option
+in the reference:
+
+====
+ git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/experimental%l=Verified+1
+====
+
+The `l='label[score]'` option may be specified more than once to
+apply multiple review labels.
+
+The value is optional. If not specified, it defaults to +1 (if
+the label range allows it).
+
If you are frequently uploading changes to the same Gerrit server,
consider adding an SSH host block in `~/.ssh/config` to remember
your username, hostname and port number. This permits the use of
diff --git a/ReleaseNotes/Makefile b/ReleaseNotes/Makefile
index 5137b59..3081600 100644
--- a/ReleaseNotes/Makefile
+++ b/ReleaseNotes/Makefile
@@ -14,39 +14,15 @@
ASCIIDOC ?= asciidoc
ASCIIDOC_EXTRA ?=
-SVN ?= svn
-PUB_ROOT ?= https://gerrit-documentation.googlecode.com/svn/ReleaseNotes
DOC_HTML := $(patsubst %.txt,%.html,$(wildcard ReleaseNotes*.txt))
-COMMIT := $(shell git describe HEAD | sed s/^v//)
-LOCAL_ROOT := .published
-PUB_DIR := $(PUB_ROOT)
all: html
html: index.html $(DOC_HTML)
-update: html
- @-rm -rf $(LOCAL_ROOT)
- @echo "Checking out current release notes"
- @$(SVN) checkout $(PUB_DIR) $(LOCAL_ROOT)
- @rm -f $(LOCAL_ROOT)/*.html
- @cp *.html $(LOCAL_ROOT)
- @cd $(LOCAL_ROOT) && \
- r=`$(SVN) status | perl -ne 'print if s/^! *//' ` && \
- if [ -n "$$r" ]; then $(SVN) rm $$r; fi && \
- a=`$(SVN) status | perl -ne 'print if s/^\? *//' ` && \
- if [ -n "$$a" ]; then \
- $(SVN) add $$a && \
- $(SVN) propset svn:mime-type text/html $$a ; \
- fi && \
- echo "Committing release notes at v$(COMMIT)" && \
- $(SVN) commit -m "Updated release notes to v$(COMMIT)"
- @-rm -rf $(LOCAL_ROOT)
-
clean:
rm -f *.html
- rm -rf $(LOCAL_ROOT)
index.html: index.txt
@echo FORMAT $@
@@ -61,9 +37,8 @@
@echo FORMAT $@
@rm -f $@+ $@
@v=$$(echo $< | sed 's/^ReleaseNotes-//;s/.txt$$//;') && \
- c=$$(git rev-list -1 HEAD -- $<) && \
- n=$$(git describe $$c) && \
- if [ "X$$n" != "Xv$$v" ]; then v="$$v (from $$n)"; fi && \
+ n=$$(git describe HEAD) && \
+ if ! git diff-index --quiet v$$v -- $< 2>/dev/null; then v="$$v (from $$n)"; fi && \
$(ASCIIDOC) --unsafe \
-a toc \
-a "revision=$$v" \
diff --git a/ReleaseNotes/ReleaseNotes-2.10.1.txt b/ReleaseNotes/ReleaseNotes-2.10.1.txt
new file mode 100644
index 0000000..df70b64
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.1.txt
@@ -0,0 +1,42 @@
+Release notes for Gerrit 2.10.1
+===============================
+
+There are no schema changes from link:ReleaseNotes-2.10.html[2.10].
+
+Download:
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.1.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.1.war]
+
+Bug Fixes
+---------
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2260[Issue 2260]:
+LDAP horrendous login time due to recursive lookup.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=3210[Issue 3210]:
+Null Pointer Exception for query command with --comments switch.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=3211[Issue 3211]:
+Intermittent Null Pointer Exception when showing process queue.
+
+LDAP
+----
+
+* Several performance improvements when using LDAP, both in the number of LDAP
+requests and in the amount of data transferred.
+
+* Sites using LDAP for authentication but otherwise rely on local Gerrit groups
+should set the new `ldap.fetchMemberOfEagerly` option to `false`.
+
+OAuth
+-----
+
+* Expose extension point for generic OAuth providers.
+
+OpenID
+------
+
+* Add support for Launchpad on the login form.
+
+* Remove pre-configured Google OpenID 2.0 provider from the login form, that is
+going to be shut down on 20, April 2015.
diff --git a/ReleaseNotes/ReleaseNotes-2.10.2.txt b/ReleaseNotes/ReleaseNotes-2.10.2.txt
new file mode 100644
index 0000000..2ca5505
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.2.txt
@@ -0,0 +1,31 @@
+Release notes for Gerrit 2.10.2
+===============================
+
+There are no schema changes from link:ReleaseNotes-2.10.1.html[2.10.1].
+
+Download:
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.2.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.2.war]
+
+Bug Fixes
+---------
+
+* Work around MyersDiff infinite loop in PatchListLoader. If the MyersDiff diff
+doesn't finish within 5 seconds, interrupt it and fall back to a different diff
+algorithm. From the user perspective, the only difference when the infinite
+loop is detected is that the files in the commit will not be compared in-depth,
+which will result in bigger edit regions.
+
+Secondary Index
+---------------
+
+* Online reindexing: log the number of done/failed changes in the error_log.
+Administrators can use the logged information to decide whether to activate the
+new index version or not.
+
+Gitweb
+------
+
+* Do not return `Forbidden` when clicking on Gitweb breadcrumb. Now when the
+user clicks on the parent folder, redirect to Gerrit projects list screen with
+the parent folder path as the filter.
diff --git a/ReleaseNotes/ReleaseNotes-2.10.3.1.txt b/ReleaseNotes/ReleaseNotes-2.10.3.1.txt
new file mode 100644
index 0000000..2b90a6d
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.3.1.txt
@@ -0,0 +1,11 @@
+Release notes for Gerrit 2.10.3.1
+=================================
+
+There are no schema changes from link:ReleaseNotes-2.10.3.html[2.10.3].
+
+Download:
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.3.1.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.3.1.war]
+
+The 2.10.3 release packaged wrong version of the core plugins due to a bug
+in our buck build scripts. This version fixes this issue.
diff --git a/ReleaseNotes/ReleaseNotes-2.10.3.txt b/ReleaseNotes/ReleaseNotes-2.10.3.txt
new file mode 100644
index 0000000..052840d
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.3.txt
@@ -0,0 +1,124 @@
+Release notes for Gerrit 2.10.3
+===============================
+
+Download:
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.3.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.3.war]
+
+Important Notes
+---------------
+
+*WARNING:* There are no schema changes from
+link:ReleaseNotes-2.10.2.html[2.10.2], but Bouncycastle was upgraded to 1.51.
+It is therefore important to upgrade the site with the `init` program, rather
+than only copying the .war file over the existing one.
+
+*WARNING:* When upgrading from version 2.8.4 or older with a site that uses
+Bouncy Castle Crypto, new versions of the libraries will be downloaded. The old
+libraries should be manually removed from site's `lib` folder to prevent the
+startup failure described in
+link:https://code.google.com/p/gerrit/issues/detail?id=3084[Issue 3084].
+
+It is recommended to run the `init` program in interactive mode. Warnings will
+be suppressed in batch mode.
+
+----
+ java -jar gerrit.war init -d site_path
+----
+
+New Features
+------------
+
+* Support hybrid OpenID and OAuth2 authentication
++
+OpenID auth scheme is aware of optional OAuth2 plugin-based authentication.
+This feature is considered to be experimental and hasn't reached full feature set yet.
+Particularly, linking of user identities across protocol boundaries and even from
+one OAuth2 identity to another OAuth2 identity wasn't implemented yet.
+
+Configuration
+~~~~~~~~~~~~~
+
+* Allow to configure
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10.3/config-gerrit.html#sshd.rekeyBytesLimit[
+SSHD rekey parameters].
+
+SSH
+---
+
+* Update SSHD to 0.14.0.
++
+This fixes link:https://issues.apache.org/jira/browse/SSHD-348[SSHD-348] which
+was causing ssh threads allocated to stream-events clients to get stuck.
++
+Also update SSHD Mina to 2.0.8 and Bouncycastle to 1.51.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2797[Issue 2797]:
+Add support for ECDSA based public key authentication.
+
+Bug Fixes
+---------
+
+* Prevent wrong content type for CSS files.
++
+The mime-util library contains two content type mappings for .css files:
+`application/x-pointplus` and `text/css`. Unfortunately, using the wrong one
+will result in most browsers discarding the file as a CSS file. Ensure we only
+use the correct type for CSS files.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=3289[Issue 3289]:
+Prevent NullPointerException in Gitweb servlet.
+
+Replication plugin
+~~~~~~~~~~~~~~~~~~
+
+* Set connection timeout to 120 seconds for SSH remote operations.
++
+The creation of a missing Git, before starting replication, is a blocking
+operation. By setting a timeout, we ensure the operation does not get stuck
+forever, essentially blocking all future remote git creation operations.
+
+OAuth extension point
+~~~~~~~~~~~~~~~~~~~~~
+
+* Respect servlet context path in URL for login token
++
+On sites with non empty context path, first redirect was broken and ended up
+with 404 Not found.
+
+* Invalidate OAuth session after web_sessions cache expiration
++
+After web session cache expiration there is no way to re-sign-in into Gerrit.
+
+Daemon
+~~~~~~
+
+* Print proper names for tasks in output of `show-queue` command.
++
+Some tasks were not displayed with the proper name.
+
+Web UI
+~~~~~~
+
+* link:http://code.google.com/p/gerrit/issues/detail?id=3044[Issue 3044]:
+Remove stripping `#` in login redirect.
+
+SSH
+~~~
+
+* Prevent double authentication for the same public key.
+
+
+Performance
+-----------
+
+* Improved performance when creating a new branch on a repository with a large
+number of changes.
+
+
+Upgrades
+--------
+
+* Update Bouncycastle to 1.51.
+
+* Update SSHD to 0.14.0.
diff --git a/ReleaseNotes/ReleaseNotes-2.10.4.txt b/ReleaseNotes/ReleaseNotes-2.10.4.txt
new file mode 100644
index 0000000..e221549
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.4.txt
@@ -0,0 +1,49 @@
+Release notes for Gerrit 2.10.4
+===============================
+
+There are no schema changes from link:ReleaseNotes-2.10.3.1.html[2.10.3.1].
+
+Download:
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.4.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.4.war]
+
+New Features
+------------
+
+* Support identity linking in hybrid OpenID and OAuth2 authentication.
++
+Linking of user identities across protocol boundaries and from one OAuth2
+identity to another OAuth2 identity is supported.
+
+* Support identity linking in OAuth2 extension point.
++
+Linking of user identities from one OAuth2 identity to another OAuth2
+identity is supported.
+
+Bug Fixes
+---------
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=3300[Issue 3300]:
+Fix >10x performance degradation for Git push and replication operations.
++
+A link:https://bugs.eclipse.org/bugs/show_bug.cgi?id=465509[regression in jgit]
+caused a performance degradation.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=3312[Issue 3312]:
+Flush padding on patches downloaded as base64.
++
+The padding was not flushed, which caused the downloaded patch to not be
+valid base64.
+
+OAuth extension point
+~~~~~~~~~~~~~~~~~~~~~
+
+* Check for session validity during logout.
++
+When user was trying to log out, after Gerrit restart, the session was
+invalidated and IllegalStateException was recorded in the error_log.
+
+Updates
+-------
+
+* Update jgit to 4.0.0.201505050340-m2.
diff --git a/ReleaseNotes/ReleaseNotes-2.10.5.txt b/ReleaseNotes/ReleaseNotes-2.10.5.txt
new file mode 100644
index 0000000..eb48c31
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.5.txt
@@ -0,0 +1,27 @@
+Release notes for Gerrit 2.10.5
+===============================
+
+There are no schema changes from link:ReleaseNotes-2.10.4.html[2.10.4].
+
+Download:
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.5.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.5.war]
+
+Bug Fixes
+---------
+
+* Update JGit to include a memory leak fix as discussed
+link:https://groups.google.com/forum/#!topic/repo-discuss/RRQT_xCqz4o[here]
+
+* Attempt to fix the "Cannot read project" issue in Gerrit, as discussed
+link:https://groups.google.com/forum/\#!topic/repo-discuss/ZeGWPyyJlrM[here]
+and
+link:https://groups.google.com/forum/#!topic/repo-discuss/CYYoHfDxCfA[here]
+
+* Fixed a regression caused by the defaultValue feature which broke the ability
+to remove labels in subprojects
+
+Updates
+-------
+
+* Update JGit to v4.0.0.201506090130-r
diff --git a/ReleaseNotes/ReleaseNotes-2.10.6.txt b/ReleaseNotes/ReleaseNotes-2.10.6.txt
new file mode 100644
index 0000000..94a95bd
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.6.txt
@@ -0,0 +1,14 @@
+Release notes for Gerrit 2.10.6
+===============================
+
+There are no schema changes from link:ReleaseNotes-2.10.5.html[2.10.5].
+
+Download:
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.6.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.6.war]
+
+Bug Fixes
+---------
+
+* Fix generation of licenses in documentation.
+
diff --git a/ReleaseNotes/ReleaseNotes-2.10.7.txt b/ReleaseNotes/ReleaseNotes-2.10.7.txt
new file mode 100644
index 0000000..28cf37b
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.7.txt
@@ -0,0 +1,19 @@
+Release notes for Gerrit 2.10.7
+===============================
+
+There are no schema changes from link:ReleaseNotes-2.10.6.html[2.10.6].
+
+Download:
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.7.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.7.war]
+
+Bug Fixes
+---------
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=3361[Issue 3361]:
+Synchronize Myers diff and Histogram diff invocations to prevent pack file
+corruption.
++
+See also the link:https://bugs.eclipse.org/bugs/show_bug.cgi?id=467467[
+bug report on JGit].
+
diff --git a/ReleaseNotes/ReleaseNotes-2.10.8.txt b/ReleaseNotes/ReleaseNotes-2.10.8.txt
new file mode 100644
index 0000000..e7de0e1
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.8.txt
@@ -0,0 +1,39 @@
+Release notes for Gerrit 2.10.8
+===============================
+
+There are no schema changes from link:ReleaseNotes-2.10.7.html[2.10.7].
+
+Download:
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.8.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.8.war]
+
+Bug Fixes
+---------
+
+* link:https://bugs.chromium.org/p/gerrit/issues/detail?id=10262[Issue 10262]: Fix validation of wants in git-upload-pack for protocol v0 stateless transports.
++
+See the following section for details.
+
+* Upgrade JGit to 4.5.5.201812240535-r.
++
+This upgrade includes several major versions since 4.0.0 used in Gerrit version 2.10.7.
+Important fixes are summarized below. Please refer to the corresponding JGit release notes for full details.
+
+** link:https://projects.eclipse.org/projects/technology.jgit/releases/4.5.5[JGit 4.5.5]: link:https://bugs.chromium.org/p/gerrit/issues/detail?id=10262[Issue 10262]: Fix validation of wants in git-upload-pack for protocol v0 stateless transports.
++
+AdvertiseRefsHook was not called for git-upload-pack in protocol v0 stateless transports, meaning that wants were not validated and a user could fetch anything that is pointed to by any ref (using fetch-by-sha1), as long as they could guess the object name.
+
+** link:https://projects.eclipse.org/projects/technology.jgit/releases/4.5.4[JGit 4.5.4]: Fix LockFile semantics when running on NFS.
++
+Honor trustFolderStats also when reading packed-refs.
+
+** link:https://projects.eclipse.org/projects/technology.jgit/releases/4.5.3[JGit 4.5.3]: Fix exception handling for opening bitmap index files.
+
+** link:https://projects.eclipse.org/projects/technology.jgit/releases/4.5.2[JGit 4.5.2]: Fix pack marked as corrupted even if it isn’t.
+
+** link:https://projects.eclipse.org/projects/technology.jgit/releases/4.5.1[JGit 4.5.1]: Don’t remove Pack when FileNotFoundException is transient.
+
+** link:https://projects.eclipse.org/projects/technology.jgit/releases/4.1.0[JGit 4.1.0]: Handle stale NFS file handles on packed-refs file.
++
+Use java.io.File instead of NIO to check existence of loose objects in ObjectDirectory to speed up inserting of loose objects.
+Reduce memory consumption when creating bitmaps during writing pack files.
\ No newline at end of file
diff --git a/ReleaseNotes/ReleaseNotes-2.10.txt b/ReleaseNotes/ReleaseNotes-2.10.txt
new file mode 100644
index 0000000..336f02f3
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.txt
@@ -0,0 +1,715 @@
+Release notes for Gerrit 2.10
+=============================
+
+
+Gerrit 2.10 is now available:
+
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.war]
+
+Gerrit 2.10 includes the bug fixes done with
+link:ReleaseNotes-2.9.1.html[Gerrit 2.9.1],
+link:ReleaseNotes-2.9.2.html[Gerrit 2.9.2],
+link:ReleaseNotes-2.9.3.html[Gerrit 2.9.3] and
+link:ReleaseNotes-2.9.4.html[Gerrit 2.9.4].
+These bug fixes are *not* listed in these release notes.
+
+Important Notes
+---------------
+
+
+*WARNING:* This release contains schema changes. To upgrade:
+----
+ java -jar gerrit.war init -d site_path
+----
+
+*WARNING:* When upgrading from an existing site that was initialized with Gerrit
+version 2.6 to version 2.9.1, the primary key column order will be updated for
+some tables. It is therefore important to upgrade the site with the `init` program,
+rather than only copying the .war file over the existing one.
+
+It is recommended to run the `init` program in interactive mode. Warnings will
+be suppressed in batch mode.
+
+*WARNING:* Upgrading to 2.10.x requires the server be first upgraded to 2.8
+(or 2.9) and then to 2.10.x. If you are upgrading from 2.8.x or
+later, you may ignore this warning and upgrade directly to 2.10.x.
+
+*WARNING:* The `auth.allowGoogleAccountUpgrade` setting is no longer supported.
+
+
+Release Highlights
+------------------
+
+
+* Support for externally loaded plugins.
++
+Plugins can be implemented in Scala or Groovy using the
+link:https://gerrit-review.googlesource.com/\#/admin/projects/plugins/scripting/groovy-provider[
+Groovy provider] and
+link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/scripting/scala-provider[
+Scala provider] plugins.
+
+* Customizable 'My' menu.
++
+Users can customize the contents of the 'My' menu in the top menu. Administrators
+can configure the default contents of the menu.
+
+
+New Features
+------------
+
+
+Web UI
+~~~~~~
+
+
+Global
+^^^^^^
+
+* Add 'All-Users' project to store meta data for all users.
+
+* Administrators can customize the default contents of the 'My' menu.
+
+* Add 'My' > 'Groups' menu entry that shows the list of own groups.
+
+* Allow UiActions to perform redirects without JavaScript.
+
+
+Change Screen
+^^^^^^^^^^^^^
+
+
+* Display avatar for author, committer, and change owner.
+
+* Remove message box when editing topic of change.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2573[Issue 2573]:
+Add option to quickly add current user as reviewer of a change.
++
+An 'Add Me' button is displayed next to the 'Add' button when searching for
+reviewers to add to a change. This allows users to quickly add themselves as a
+reviewer on the change without having to type their name in the search
+box.
+
+* Link project name to dashboard.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2667[Issue 2667]:
+Allow to customize Submit button label and tooltip.
+
+
+Side-by-Side Diff Screen
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Allow the user to select the syntax highlighter.
+
+* Add `Shift-a` keybinding to show/hide left side.
+
+* Allow to toggle empty pane for added and deleted files.
+
+* Add syntax highlighting of the commit message.
+
+
+Change List / Dashboards
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Remove age operator when drilling down from a dashboard to a query.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2646[Issue 2646]:
+Add option to show Change-ID in the change table.
+
+* Make the own user dashboard available under '/dashboard/self'.
+
+* Add 'R' key binding to refresh custom dashboards.
++
+Account dashboards, search results and the change screen refresh their content
+when 'R' is pressed. The same binding is added for custom dashboards.
+
+
+Project Screens
+^^^^^^^^^^^^^^^
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2751[Issue 2751]:
+Add support for filtering by regex in project list screen.
+
+* Disable content merge option if project's merge strategy is fast forward only.
+
+* Add branch actions to 'Projects > Branches' view.
+
+User Preferences
+^^^^^^^^^^^^^^^^
+
+
+* Users can customize the contents of the 'My' menu from the preferences
+screen.
+
+* link:http://code.google.com/p/gerrit/issues/detail?id=2628[Issue 2628]:
+Replace 'Display name in review category' preference with a list of options.
++
+Including new options 'Show Abbreviated Name' to display abbreviated reviewer
+names and 'Show Username' to show usernames in the change list.
+
+
+Secondary Index / Search
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+* Allow to search projects by prefix.
+
+* Add search fields for number of changed lines.
+
+* Add suggestions for 'is:pending' and 'status:pending'.
+
+* Add 'pending' as alias for 'open'.
+
+* link:http://code.google.com/p/gerrit/issues/detail?id=2545[Issue 2545]:
+Support `topic:""` to find changes with no topic.
+
+* Search more fields in the default search query.
++
+If a search is given with only a text, search over a variety of fields
+rather than just the project name.
+
+
+ssh
+~~~
+
+
+* Expose SSHD backend in
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/cmd-show-connections.html[
+`show connections`] SSH command.
+
+* Add support for JCE (Java Cryptography Extension) ciphers.
+
+REST API
+~~~~~~~~
+
+
+General
+^^^^^^^
+
+
+* Remove `kind` attribute from REST containers.
+
+* Support `AcceptsPost` on non top-level REST collections.
+
+* Accept `HEAD` in RestApiServlet.
+
+Accounts
+^^^^^^^^
+
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-accounts.html#get-user-preferences[
+Get user preferences].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-accounts.html#set-user-preferences[
+Set user preferences].
+
+Changes
+^^^^^^^
+
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2338[Issue 2338]:
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-changes.html#create-change[
+Create change].
+
+* Add `other-branches` option on
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-changes.html#get-mergeable[
+Get mergeable] endpoint.
++
+If the `other-branches` option is specified, the mergeability will also be
+checked for all other branches.
+
+Config
+^^^^^^
+
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-config.html#list-tasks[
+List tasks].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-config.html#get-task[
+Get task].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-config.html#delete-task[
+Delete task].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-config.html#list-caches[
+List caches].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-config.html#flush-cache[
+Flush cache].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-config.html#flush-several-caches[
+Flush several caches].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-config.html#flush-all-caches[
+Flush all caches].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-config.html#get-summary[
+Get server summary].
+
+Projects
+^^^^^^^^
+
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-projects.html#ban-commit[
+Ban commits].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-projects.html#get-content[
+Get the content of a file from a certain commit].
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2604[Issue 2604]:
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-projects.html#get-commit[
+Get an arbitrary commit from a project].
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-projects.html#get-reflog[
+Get the reflog of a branch].
+
+* Add option 'S' to
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-projects.html#list-projects[
+list projects endpoint] to support query offset.
+
+
+Daemon
+~~~~~~
+
+
+* Add change subject to output of change URL on push.
+
+* Indicate trivial rebase and commit message update on push.
+
+* Add support for
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/user-upload.html#review_labels[
+adding review labels on changes] during git push.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2634[Issue 2634]:
+Add change kind to PatchSetCreatedEvent.
+
+
+Configuration
+~~~~~~~~~~~~~
+
+* Use
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/config-gerrit.html#core.useRecursiveMerge[
+recursive merge] by default.
+
+* Allow to configure the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/config-gerrit.html#download.archive[
+available download archive formats].
+
+* Add support for
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/database-setup.html#createdb_maxdb[
+SAP MaxDB].
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2041[Issue 2041]:
+Allow
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/config-labels.html#label_defaultValue[
+configuration of a default value for a label].
+
+* Allow projects to
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/config-project-config.html#mimetype-section[
+configure MIME types for files].
+
+* Allow to configure
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/config-gerrit.html#gc[
+periodic garbage collection of all projects].
+
+* Remove `auth.allowGoogleAccountUpgrade` setting.
++
+It's been more than 5 years since Gerrit ran on Google AppEngine. It is assumed
+that everyone has upgraded their installations to a modern 2.x based server, and
+will not need to have this upgrade path enabled.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2618[Issue 2618]:
+Remove `label.Label-Name.abbreviation` setting.
++
+The setting was no longer used, so it has been removed.
+
+* New `httpd.registerMBeans` setting.
++
+The
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/config-gerrit.html#httpd.registerMBeans[
+`httpd.registerMBeans` setting] allows to enable (or disable) registration of
+Jetty MBeans for Java JMX.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2600[Issue 2600]:
+Add documentation of how to
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/install-j2ee.html#tomcat[
+configure Tomcat] to allow embedded slashes.
+
+
+Misc
+~~~~
+
+* Don't allow empty user name and passwords in InternalAuthBackend.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2596[Issue 2596]:
+Add change-owner parameter to gerrit hooks.
+
+
+Plugins
+~~~~~~~
+
+* Support for externally loaded plugins.
++
+Plugins can be implemented in Scala or Groovy using the
+link:https://gerrit-review.googlesource.com/\#/admin/projects/plugins/scripting/groovy-provider[
+Groovy provider] and
+link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/scripting/scala-provider[
+Scala provider] plugins.
+
+* Allow plugins to replace the WebSession implementation.
++
+Plugins can replace the existing implementation with the statement:
+`DynamicItem.bind(binder(), WebSession.class).to(...);`
+in a module designated as a `<Gerrit-HttpModule>` in the manifest.
++
+Just the Cache implementation used for web sessions can be changed
+by binding to a subclass of the now abstract `CacheBasedWebSession`
+which supplies the Cache in the superclass constructor.
++
+This is a step towards solving web session issues with multi-master.
++
+The link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/websession-flatfile[
+websession-flatfile plugin] replaces the built-in Gerrit WebSession implementation
+with one that uses a flat file based cache.
+
+* Allow http and ssh plugins to replace the Gerrit-provided DynamicItem.
+
+* New extension point to listen to usage data published events.
++
+Plugins implementing the `UsageDataPublishedListener` can listen to
+events published about usage data.
+
+* New extension point to link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/dev-plugins.html#pre-upload-hook[
+register JGit PreUploadHook].
++
+Plugins may register PreUploadHook instances in order to get
+notified when JGit is about to upload a pack. This may be useful
+for those plugins which would like to monitor usage in Git
+repositories.
+
+* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/config-validation.html#pre-upload-validation[
+pre-upload validation extension point].
++
+Plugins implementing the `UploadValidationListener` interface can
+perform additional validation checks before any upload operations
+(clone, fetch, pull). The validation is executed right before Gerrit
+begins to send a pack back to the git client.
+
+* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/dev-plugins.html#links-to-external-tools[
+external tool links extension points].
++
+Plugins can now contribute project links that will be displayed on the project
+list screen in the 'Repository Browser' column, and revision links that will be
+shown on the change screen.
+
+* Allow creation of persistent caches after server is started.
++
+This enables plugins to create own persistent caches when they are
+installed.
+
+* Make gerrit's HttpServletRequest and HttpServletResponse visible to http
+plugins.
+
+* New extensions in the Java Plugin API:
+
+** Query changes
+** Create/get/list projects
+** Get/set review status
+** Create change
+** Get account
+** Star/unstar changes
+** Check if revision needs rebase
+
+Bug Fixes
+---------
+
+General
+~~~~~~~
+
+* Use fixed rate instead of fixed delay for log file compression.
++
+Log file compression was scheduled using a fixed delay. This caused the start
+times to drift over time. Use a fixed rate instead so that the compression
+reoccurs at the same time every day.
+
+* Don't email project watchers on new draft changes.
++
+If a draft change is created by pushing to `refs/drafts/master`, only the reviewers
+explicitly named on the command line (which may be empty) should be notified of
+the change. Users watching the project should not be notified, as the change has
+not yet been published.
+
+* Fix resource exhaustion due to unclosed LDAP connection.
++
+When `auth.type` is set to `LDAP` (not `LDAP_BIND`), two LDAP connections are
+made, but one was not being closed. This eventually caused resource exhaustion
+and LDAP authentications failed.
+
+Access Permissions
+~~~~~~~~~~~~~~~~~~
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2995[Issue 2995]:
+Fix faulty behaviour in `BLOCK` permission.
++
+`BLOCK` can be overruled with `ALLOW` on the same project, however there was a
+bug when a child of the above project duplicates the `ALLOW` permission. In this
+case the `BLOCK` would always win for the child, even though the `BLOCK` was
+overruled in the parent.
+
+Web UI
+~~~~~~
+
+General
+^^^^^^^
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2595[Issue 2595]:
+Make gitweb redirect to login.
++
+Gitweb redirects to the login page if the user isn't currently logged.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2631[Issue 2631]:
+Re-arrange info at footer of Gerrit web UI pages.
++
+Move the Gerrit info link so that there are no links close to the next page link.
+
+* Only create All-Projects ACL once.
++
+If `refs/meta/config` already existed it was overwritten with default configuration
+if a site administrator ran `java -war gerrit.war init -d /some/existing/site --batch`.
+
+
+Change Screen
+^^^^^^^^^^^^^
+
+* Don't linkify trailing dot or comma in messages.
++
+As linkifying trailing dots and trailing commas does more harm than
+good, we only treat dots and commas as being part of urls, if they are
+neither followed by whitespace nor occur at the end of a string.
+
+* Re-enable the 'Cherry Pick' button after canceling the dialog.
++
+If the dialog was canceled, the button remained disabled and could not be
+used again.
+
+* Improve message when removing a reviewer.
+
+* link:http://code.google.com/p/gerrit/issues/detail?id=527[Issue 527]:
+Preserve line breaks in inline and review comments.
+
+* Always show 'No Score' as label help for zero votings.
+
+* Only reset the edited commit message text on cancel.
+
+* Only include message on quick approve if reply is open.
+
+* List reviewers with dummy approvals on closed changes.
+
+* link:http://code.google.com/p/gerrit/issues/detail?id=2890[Issue 2890]:
+Enable scrollbars for "Edit Commit Message" TextArea.
+
+* Use current time instead of submitter time for cherry-picked commits.
++
+Cherry picking with the submitter time could cause massive clock skew
+in the Git commit graph if the server was shutdown before the submit could
+finish, and restarted hours later.
+
+* Fix exception when clicking on a binary file without being signed in.
+
+
+Side-By-Side Diff
+^^^^^^^^^^^^^^^^^
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2970[Issue 2970]:
+Fix misalignment of side A and side B for long insertion/deletion blocks.
+
+* Give B side full width when A side is hidden.
+
+* Fix scroll alignment when showing hidden A side.
+
+* Bind Shift-N to search-prev in vim mode.
+
+* Allow text selection in diff header.
+
+* Display diff header on mode changes and renames.
+
+* Document Shift-{Left,Right} in `?` help popup.
+
+* Show `[` and `]` shortcut keys in nav arrow tooltips.
+
+* Disable "Render = Slow" mode on files over 4000 lines.
+
+* Keep keyboard bindings alive after click in padding.
+
+* Jump to the first change on either side.
+
+* Expand margin between paragraphs in comments.
+
+* Include content on identical files with mode change.
+
+
+User Settings
+^^^^^^^^^^^^^
+
+* Avoid loading all SSH keys when adding a new one.
+
+
+Secondary Index / Search
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+* Omit corrupt changes from search results.
+
+* Allow illegal label names from default search predicate.
+
+REST
+~~~~
+
+General
+^^^^^^^
+
+* Fix REST API responses for 3xx and 4xx classes.
+
+Changes
+^^^^^^^
+
+* Fix inconsistent behaviour in the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-changes.html#add-reviewer[
+add reviewer endpoint]
++
+When adding a single reviewer to a change, it was possible to use the endpoint
+to add a user who had no visibility to the change or whose account was invalid.
+
+
+Changes
+^^^^^^^
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2583[Issue 2583]:
+Reject inline comments on files that do not exist in the patch set.
+
+* Allow forcing mergeability check on
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-changes.html#get-mergeable[
+Get mergeable].
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2622[Issue 2622]:
+Respect patch set visibility for messages.
++
+Messages retrieval didn't check for patch set visbility and thus messages for
+draft patch sets were returned back to the client.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2782[Issue 2782]:
+Add missing documentation of the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-changes.html#get-related-changes[
+Get Related Changes] endpoint.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2723[Issue 2723]:
+Clarify the response info in the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-changes.html#get-change-detail[
+Get Change Detail] endpoint.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2693[Issue 2693]:
+Clarify the response info in the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/rest-api-changes.html#list-comments[
+List Comments] endpoint.
+
+SSH
+~~~
+
+
+* Prevent double authentication for the same public key.
++
+This is a workaround for link:https://issues.apache.org/jira/browse/SSHD-300[
+SSHD-300].
+
+* Let `kill` SSH command only kill tasks that are visible to the caller.
+
+* Require 'Administrate Server' capability to see server summary output from
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10/cmd-show-caches.html[
+`show-caches`] command.
+
+* Include all command arguments in SSH log entry.
++
+The SSH log only included the first argument. This prevented the repository name
+from being logged when `git receive-pack` was executed instead of `git-receive-pack`.
+
+
+Daemon
+~~~~~~
+
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2284[Issue 2284]:
+More detailed error message when failing to upload new change.
++
+When the uploaded change cannot be created on the underlying Git repository, a
+more descriptive error message is displayed on both client and server side. This
+allows to troubleshoot internal errors (e.g. JGit lock failures or other causes)
+and help out in the resolution.
+
+* Enforce HTTP password checking on gitBasicAuth.
+
+* Fix missing commit messages on submodule direct pushes.
++
+The commit message in superproject was missing on submodule's
+directly pushed changes.
+
+
+Plugins
+~~~~~~~
+
+General
+^^^^^^^
+
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2895[Issue 2895]:
+Fix reload of plugins that use DynamicItem.
+
+* Invoke `StartPluginListener` and `ReloadPluginListener` only after start/reload
+is fully done.
+
+* Set `Last-Modified` on cached Documentation resources.
+
+* Return HTTP 304 for not modified SmallResources.
+
+* Fix ChangeListener auto-registered implementations.
+
+Replication
+^^^^^^^^^^^
+
+
+* Move replication logs into a separate file.
+
+* Promote replication scheduled logs to info.
+
+* Show replication ID in the log and in show-queue command.
+
+
+Upgrades
+--------
+
+
+* Update Guava to 17.0
+
+* Update Guice to 4.0-beta5
+
+* Update GWT to 2.6.1
+
+* Update httpclient to 4.3.4
+
+* Update httpcore to 4.3.2
+
+* Update Jcraft SSH to 0.1.51
+
+* Update Jetty to 9.2
+
+* Update JGit to 3.6.2.201501210735-r
+
+* Update log4j to 1.2.17
+
+* Update Servlet API to 8.0.5
+
+* Update slf4j to 1.7.7
+
+* Update Velocity to 1.7
+
diff --git a/ReleaseNotes/ReleaseNotes-2.5.txt b/ReleaseNotes/ReleaseNotes-2.5.txt
index cdef554..4abed47 100644
--- a/ReleaseNotes/ReleaseNotes-2.5.txt
+++ b/ReleaseNotes/ReleaseNotes-2.5.txt
@@ -923,11 +923,11 @@
working tree dirty. Eclipse 4 (Juno) still overwrites these files but
doesn't write the timestamp. This should help to keep the working tree
clean. However, since the timestamp is currently present in these
-files, Eclispe 4 would still make them dirty by overwriting and
+files, Eclipse 4 would still make them dirty by overwriting and
effectively removing the timestamp.
+
This change removes the timestamp from these files. This helps those
-using Eclipse 4 and doesn't make it worse for those still using Eclispe
+using Eclipse 4 and doesn't make it worse for those still using Eclipse
3.
* Add Maven profile to skip build of plugin modules
diff --git a/ReleaseNotes/ReleaseNotes-2.8.txt b/ReleaseNotes/ReleaseNotes-2.8.txt
index 4f6768c..92cdda2 100644
--- a/ReleaseNotes/ReleaseNotes-2.8.txt
+++ b/ReleaseNotes/ReleaseNotes-2.8.txt
@@ -499,7 +499,10 @@
and to replicate the project deletions. By default project deletions are *not*
replicated.
-* The `{$name}` placeholder is optional when replicating a single project,
+* link:http://code.google.com/p/gerrit/issues/detail?id=1880[Issue 1880]:
+Make `{name}` placeholder optional when replicating a single project.
++
+The `{$name}` placeholder is optional when replicating a single project,
allowing a single project to be replicated under a different name.
* Project names can be matched with wildcard or regex patterns in `replication.config`.
@@ -622,7 +625,7 @@
* Do not persist default project state in `project.config`.
-* Honor the `gerrit.cannonicalWebUrl` setting when opening the browser after init.
+* Honor the `gerrit.canonicalWebUrl` setting when opening the browser after init.
* Fix 'query disabled' error when Query Limit is set.
diff --git a/ReleaseNotes/index.txt b/ReleaseNotes/index.txt
index 45385f9..2614335 100644
--- a/ReleaseNotes/index.txt
+++ b/ReleaseNotes/index.txt
@@ -1,6 +1,20 @@
Gerrit Code Review - Release Notes
==================================
+[[2_10]]
+Version 2.10.x
+--------------
+* link:ReleaseNotes-2.10.8.html[2.10.8]
+* link:ReleaseNotes-2.10.7.html[2.10.7]
+* link:ReleaseNotes-2.10.6.html[2.10.6]
+* link:ReleaseNotes-2.10.5.html[2.10.5]
+* link:ReleaseNotes-2.10.4.html[2.10.4]
+* link:ReleaseNotes-2.10.3.1.html[2.10.3.1]
+* link:ReleaseNotes-2.10.3.html[2.10.3]
+* link:ReleaseNotes-2.10.2.html[2.10.2]
+* link:ReleaseNotes-2.10.1.html[2.10.1]
+* link:ReleaseNotes-2.10.html[2.10]
+
[[2_9]]
Version 2.9.x
-------------
diff --git a/VERSION b/VERSION
index c9e9a5d..eaf28f2 100644
--- a/VERSION
+++ b/VERSION
@@ -2,5 +2,4 @@
# Used by :api_install and :api_deploy targets
# when talking to the destination repository.
#
-GERRIT_VERSION = '2.9.4'
-
+GERRIT_VERSION = '2.10.7'
diff --git a/bucklets/gerrit_plugin.bucklet b/bucklets/gerrit_plugin.bucklet
new file mode 100644
index 0000000..eb10456
--- /dev/null
+++ b/bucklets/gerrit_plugin.bucklet
@@ -0,0 +1,15 @@
+#
+# Dummy to make the co-existence of core and standalone plugins possible.
+# Intentionaly left empty as this doesn't suppose to have any side effects
+# in tree build, i. e.:
+#
+# cookbook-plugin/BUCK include this line:
+# include_defs('//bucklets/gerrit_plugin.bucklet')
+#
+# When executing from the Gerrit tree:
+# buck build plugins/cookbook-plugin
+#
+# this line has no effect.
+#
+# When compiling from standalone cookbook-plugin, bucklets directory points
+# to cloned bucklets library that includes real gerrit_plugin.bucklet code.
diff --git a/bucklets/maven_jar.bucklet b/bucklets/maven_jar.bucklet
new file mode 120000
index 0000000..130a747
--- /dev/null
+++ b/bucklets/maven_jar.bucklet
@@ -0,0 +1 @@
+../lib/maven.defs
\ No newline at end of file
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 5c5746b..2b01a22 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -21,6 +21,7 @@
import com.google.common.base.Joiner;
import com.google.common.primitives.Chars;
+import com.google.gerrit.acceptance.AcceptanceTestRequestScope.Context;
import com.google.gerrit.extensions.api.GerritApi;
import com.google.gerrit.extensions.api.changes.RevisionApi;
import com.google.gerrit.extensions.common.ChangeInfo;
@@ -128,9 +129,9 @@
userSession = new RestSession(server, user);
initSsh(admin);
db = reviewDbProvider.open();
- atrScope.set(atrScope.newContext(reviewDbProvider, sshSession,
- identifiedUserFactory.create(Providers.of(db), admin.getId())));
- sshSession = new SshSession(server, admin);
+ Context ctx = newRequestContext(admin);
+ atrScope.set(ctx);
+ sshSession = ctx.getSession();
project = new Project.NameKey("p");
createProject(sshSession, project.get());
git = cloneProject(sshSession.getUrl() + "/" + project.get());
@@ -145,6 +146,7 @@
db.close();
sshSession.close();
server.stop();
+ TempFileUtil.cleanup();
}
protected PushOneCommit.Result createChange() throws GitAPIException,
@@ -194,6 +196,19 @@
return gApi.changes().id(id).get(s);
}
+ protected List<ChangeInfo> query(String q) throws RestApiException {
+ return gApi.changes().query(q).get();
+ }
+
+ private Context newRequestContext(TestAccount account) {
+ return atrScope.newContext(reviewDbProvider, new SshSession(server, admin),
+ identifiedUserFactory.create(Providers.of(db), account.getId()));
+ }
+
+ protected Context setApiUser(TestAccount account) {
+ return atrScope.set(newRequestContext(account));
+ }
+
protected static Gson newGson() {
return OutputFormat.JSON_COMPACT.newGson();
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
index 63bdfd2..6ee7efa 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
@@ -130,8 +130,7 @@
}
}
- private static final ThreadLocal<Context> current =
- new ThreadLocal<Context>();
+ private static final ThreadLocal<Context> current = new ThreadLocal<>();
private static Context requireContext() {
final Context ctx = current.get();
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
index d427509..85da2f5 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
@@ -98,7 +98,7 @@
}
Injector i = createTestInjector(daemon);
- return new GerritServer(site, i, daemon, daemonService);
+ return new GerritServer(i, daemon, daemonService);
}
private static File initSite(Config base) throws Exception {
@@ -130,6 +130,7 @@
cfg.setString("httpd", null, "listenUrl", url);
cfg.setString("sshd", null, "listenAddress", forceEphemeralPort);
cfg.setString("cache", null, "directory", null);
+ cfg.setString("gerrit", null, "basePath", "git");
cfg.setBoolean("sendemail", null, "enable", false);
cfg.setInt("cache", "projects", "checkFrequency", 0);
cfg.setInt("plugins", null, "checkFrequency", 0);
@@ -159,7 +160,6 @@
return InetAddress.getLoopbackAddress();
}
- private File sitePath;
private Daemon daemon;
private ExecutorService daemonService;
private Injector testInjector;
@@ -167,9 +167,8 @@
private InetSocketAddress sshdAddress;
private InetSocketAddress httpAddress;
- private GerritServer(File sitePath, Injector testInjector, Daemon daemon,
+ private GerritServer(Injector testInjector, Daemon daemon,
ExecutorService daemonService) throws IOException, ConfigInvalidException {
- this.sitePath = sitePath;
this.testInjector = testInjector;
this.daemon = daemon;
this.daemonService = daemonService;
@@ -208,9 +207,6 @@
daemonService.shutdownNow();
daemonService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
}
- if (sitePath != null) {
- TempFileUtil.recursivelyDelete(sitePath);
- }
RepositoryCache.clear();
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/HttpSession.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/HttpSession.java
index b543aa7..5d81900 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/HttpSession.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/HttpSession.java
@@ -18,8 +18,10 @@
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.HttpClientBuilder;
import java.io.IOException;
import java.net.URI;
@@ -28,7 +30,7 @@
protected final String url;
private final TestAccount account;
- private DefaultHttpClient client;
+ private HttpClient client;
public HttpSession(GerritServer server, TestAccount account) {
this.url = CharMatcher.is('/').trimTrailingFrom(server.getUrl());
@@ -40,13 +42,19 @@
return new HttpResponse(getClient().execute(get));
}
- protected DefaultHttpClient getClient() {
+ protected HttpClient getClient() {
if (client == null) {
URI uri = URI.create(url);
- client = new DefaultHttpClient();
- client.getCredentialsProvider().setCredentials(
- new AuthScope(uri.getHost(), uri.getPort()),
- new UsernamePasswordCredentials(account.username, account.httpPassword));
+ BasicCredentialsProvider creds = new BasicCredentialsProvider();
+ creds.setCredentials(new AuthScope(uri.getHost(), uri.getPort()),
+ new UsernamePasswordCredentials(account.username,
+ account.httpPassword));
+ client = HttpClientBuilder
+ .create()
+ .setDefaultCredentialsProvider(creds)
+ .setMaxConnPerRoute(10)
+ .setMaxConnTotal(1024)
+ .build();
}
return client;
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
index cc19c15..32705ba 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
@@ -56,7 +56,7 @@
public class PushOneCommit {
public static final String SUBJECT = "test commit";
- static final String FILE_NAME = "a.txt";
+ public static final String FILE_NAME = "a.txt";
private static final String FILE_CONTENT = "some content";
public interface Factory {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TempFileUtil.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TempFileUtil.java
index ff0ca7b..0b78f57 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TempFileUtil.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TempFileUtil.java
@@ -16,17 +16,29 @@
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
public class TempFileUtil {
- public static File createTempDirectory() throws IOException {
- File tmp = File.createTempFile("gerrit_test_", "");
+ private static List<File> allDirsCreated = new ArrayList<>();
+
+ public synchronized static File createTempDirectory() throws IOException {
+ File tmp = File.createTempFile("gerrit_test_", "").getCanonicalFile();
if (!tmp.delete() || !tmp.mkdir()) {
throw new IOException("Cannot create " + tmp.getPath());
}
+ allDirsCreated.add(tmp);
return tmp;
}
- public static void recursivelyDelete(File dir) throws IOException {
+ public static synchronized void cleanup() throws IOException {
+ for (File dir : allDirsCreated) {
+ recursivelyDelete(dir);
+ }
+ allDirsCreated.clear();
+ }
+
+ private static void recursivelyDelete(File dir) throws IOException {
if (!dir.getPath().equals(dir.getCanonicalPath())) {
// Directory symlink reaching outside of temporary space.
return;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
new file mode 100644
index 0000000..c95f8c3
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -0,0 +1,69 @@
+// 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.acceptance.api.accounts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class AccountIT extends AbstractDaemonTest {
+
+ @Test
+ public void get() throws RestApiException {
+ AccountInfo info = gApi
+ .accounts()
+ .id("admin")
+ .get();
+ assertEquals("Administrator", info.name);
+ assertEquals("admin@example.com", info.email);
+ assertEquals("admin", info.username);
+ }
+
+ @Test
+ public void self() throws RestApiException {
+ AccountInfo info = gApi
+ .accounts()
+ .self()
+ .get();
+ assertEquals("Administrator", info.name);
+ assertEquals("admin@example.com", info.email);
+ assertEquals("admin", info.username);
+ }
+
+ @Test
+ public void starUnstarChange() throws GitAPIException,
+ IOException, RestApiException {
+ PushOneCommit.Result r = createChange();
+ String triplet = "p~master~" + r.getChangeId();
+ gApi.accounts()
+ .self()
+ .starChange(triplet);
+ assertTrue(getChange(triplet).starred);
+ gApi.accounts()
+ .self()
+ .unstarChange(triplet);
+ assertNull(getChange(triplet).starred);
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/BUCK
new file mode 100644
index 0000000..1152d88
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/BUCK
@@ -0,0 +1,6 @@
+include_defs('//gerrit-acceptance-tests/tests.defs')
+
+acceptance_tests(
+ srcs = glob(['*IT.java']),
+ labels = ['api'],
+)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK
index aa9703c..1152d88 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK
@@ -2,5 +2,5 @@
acceptance_tests(
srcs = glob(['*IT.java']),
- deps = ['//gerrit-acceptance-tests:lib'],
+ labels = ['api'],
)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 6dff20a..c79b198 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -15,21 +15,37 @@
package com.google.gerrit.acceptance.api.change;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.extensions.api.changes.AddReviewerInput;
+import com.google.gerrit.extensions.api.changes.ChangeApi;
import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.common.ApprovalInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeStatus;
+import com.google.gerrit.extensions.common.LabelInfo;
+import com.google.gerrit.extensions.common.ListChangesOption;
+import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.reviewdb.client.Account;
import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.Constants;
import org.junit.Test;
import java.io.IOException;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
@NoHttpd
public class ChangeIT extends AbstractDaemonTest {
@@ -48,6 +64,7 @@
assertEquals(true, c.mergeable);
assertEquals(r.getChangeId(), c.changeId);
assertEquals(c.created, c.updated);
+ assertEquals(1, c._number);
}
@Test
@@ -99,14 +116,166 @@
.rebase();
}
+ private static Set<Account.Id> getReviewers(ChangeInfo ci) {
+ Set<Account.Id> result = Sets.newHashSet();
+ for (LabelInfo li : ci.labels.values()) {
+ for (ApprovalInfo ai : li.all) {
+ result.add(new Account.Id(ai._accountId));
+ }
+ }
+ return result;
+ }
+
@Test
public void addReviewer() throws GitAPIException,
IOException, RestApiException {
PushOneCommit.Result r = createChange();
AddReviewerInput in = new AddReviewerInput();
in.reviewer = user.email;
+ ChangeApi cApi = gApi.changes().id("p~master~" + r.getChangeId());
+ cApi.addReviewer(in);
+ assertEquals(ImmutableSet.of(user.id), getReviewers(cApi.get()));
+ }
+
+ @Test
+ public void addReviewerToClosedChange() throws GitAPIException,
+ IOException, RestApiException {
+ PushOneCommit.Result r = createChange();
+ ChangeApi cApi = gApi.changes().id("p~master~" + r.getChangeId());
+ cApi.revision(r.getCommit().name())
+ .review(ReviewInput.approve());
+ cApi.revision(r.getCommit().name())
+ .submit();
+
+ assertEquals(ImmutableSet.of(admin.getId()), getReviewers(cApi.get()));
+
+ AddReviewerInput in = new AddReviewerInput();
+ in.reviewer = user.email;
gApi.changes()
.id("p~master~" + r.getChangeId())
.addReviewer(in);
+ assertEquals(ImmutableSet.of(admin.getId(), user.id),
+ getReviewers(cApi.get()));
+ }
+
+ @Test
+ public void createEmptyChange() throws RestApiException {
+ ChangeInfo in = new ChangeInfo();
+ in.branch = Constants.MASTER;
+ in.subject = "Create a change from the API";
+ in.project = project.get();
+ ChangeInfo info = gApi
+ .changes()
+ .create(in)
+ .get();
+ assertEquals(in.project, info.project);
+ assertEquals(in.branch, info.branch);
+ assertEquals(in.subject, info.subject);
+ }
+
+ @Test
+ public void queryChangesNoQuery() throws Exception {
+ PushOneCommit.Result r1 = createChange();
+ PushOneCommit.Result r2 = createChange();
+ List<ChangeInfo> results = gApi.changes().query().get();
+ assertEquals(2, results.size());
+ assertEquals(r2.getChangeId(), results.get(0).changeId);
+ assertEquals(r1.getChangeId(), results.get(1).changeId);
+ }
+
+ @Test
+ public void queryChangesNoResults() throws Exception {
+ createChange();
+ List<ChangeInfo> results = query("status:open");
+ assertEquals(1, results.size());
+ results = query("status:closed");
+ assertTrue(results.isEmpty());
+ }
+
+ @Test
+ public void queryChangesOneTerm() throws Exception {
+ PushOneCommit.Result r1 = createChange();
+ PushOneCommit.Result r2 = createChange();
+ List<ChangeInfo> results = query("status:open");
+ assertEquals(2, results.size());
+ assertEquals(r2.getChangeId(), results.get(0).changeId);
+ assertEquals(r1.getChangeId(), results.get(1).changeId);
+ }
+
+ @Test
+ public void queryChangesMultipleTerms() throws Exception {
+ PushOneCommit.Result r1 = createChange();
+ createChange();
+ List<ChangeInfo> results = query("status:open " + r1.getChangeId());
+ assertEquals(r1.getChangeId(), Iterables.getOnlyElement(results).changeId);
+ }
+
+ @Test
+ public void queryChangesLimit() throws Exception {
+ createChange();
+ PushOneCommit.Result r2 = createChange();
+ List<ChangeInfo> results = gApi.changes().query().withLimit(1).get();
+ assertEquals(1, results.size());
+ assertEquals(r2.getChangeId(), Iterables.getOnlyElement(results).changeId);
+ }
+
+ @Test
+ public void queryChangesStart() throws Exception {
+ PushOneCommit.Result r1 = createChange();
+ createChange();
+ List<ChangeInfo> results = gApi.changes().query().withStart(1).get();
+ assertEquals(r1.getChangeId(), Iterables.getOnlyElement(results).changeId);
+ }
+
+ @Test
+ public void queryChangesNoOptions() throws Exception {
+ PushOneCommit.Result r = createChange();
+ ChangeInfo result = Iterables.getOnlyElement(query(r.getChangeId()));
+ assertNull(result.labels);
+ assertNull(result.messages);
+ assertNull(result.revisions);
+ assertNull(result.actions);
+ }
+
+ @Test
+ public void queryChangesOptions() throws Exception {
+ PushOneCommit.Result r = createChange();
+ ChangeInfo result = Iterables.getOnlyElement(gApi.changes()
+ .query(r.getChangeId())
+ .withOptions(EnumSet.allOf(ListChangesOption.class))
+ .get());
+ assertEquals("Code-Review",
+ Iterables.getOnlyElement(result.labels.keySet()));
+ assertEquals(1, result.messages.size());
+ assertFalse(result.actions.isEmpty());
+
+ RevisionInfo rev = Iterables.getOnlyElement(result.revisions.values());
+ assertEquals(r.getPatchSetId().get(), rev._number);
+ assertFalse(rev.actions.isEmpty());
+ }
+
+ @Test
+ public void queryChangesOwnerWithDifferentUsers() throws Exception {
+ PushOneCommit.Result r = createChange();
+ assertEquals(r.getChangeId(),
+ Iterables.getOnlyElement(query("owner:self")).changeId);
+ setApiUser(user);
+ assertTrue(query("owner:self").isEmpty());
+ }
+
+ @Test
+ public void checkReviewedFlagBeforeAndAfterReview() throws Exception {
+ PushOneCommit.Result r = createChange();
+ AddReviewerInput in = new AddReviewerInput();
+ in.reviewer = user.email;
+ gApi.changes()
+ .id(r.getChangeId())
+ .addReviewer(in);
+
+ setApiUser(user);
+ assertNull(get(r.getChangeId()).reviewed);
+
+ revision(r).review(ReviewInput.recommend());
+ assertTrue(get(r.getChangeId()).reviewed);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/BUCK
index 8da456d..1152d88 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/BUCK
@@ -2,6 +2,5 @@
acceptance_tests(
srcs = glob(['*IT.java']),
- deps = ['//gerrit-acceptance-tests:lib'],
+ labels = ['api'],
)
-
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java
index 54afd0b..a10e026 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/ProjectIT.java
@@ -14,20 +14,60 @@
package com.google.gerrit.acceptance.api.project;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.extensions.api.projects.BranchInput;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
+import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestApiException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.junit.Test;
import java.io.IOException;
+import java.util.List;
@NoHttpd
public class ProjectIT extends AbstractDaemonTest {
@Test
+ public void createProjectFoo() throws RestApiException {
+ String name = "foo";
+ assertEquals(name,
+ gApi.projects()
+ .name(name)
+ .create()
+ .get()
+ .name);
+ }
+
+ @Test(expected = RestApiException.class)
+ public void createProjectFooBar() throws RestApiException {
+ ProjectInput in = new ProjectInput();
+ in.name = "foo";
+ gApi.projects()
+ .name("bar")
+ .create(in);
+ }
+
+ @Test(expected = ResourceConflictException.class)
+ public void createProjectDuplicate() throws RestApiException {
+ ProjectInput in = new ProjectInput();
+ in.name = "baz";
+ gApi.projects()
+ .name("baz")
+ .create(in);
+ gApi.projects()
+ .name("baz")
+ .create(in);
+ }
+
+ @Test
public void createBranch() throws GitAPIException,
IOException, RestApiException {
gApi.projects()
@@ -35,4 +75,45 @@
.branch("foo")
.create(new BranchInput());
}
+
+ @Test
+ public void listProjects() throws Exception {
+ List<ProjectInfo> initialProjects = gApi.projects().list().get();
+
+ gApi.projects().name("foo").create();
+ gApi.projects().name("bar").create();
+
+ List<ProjectInfo> allProjects = gApi.projects().list().get();
+ assertEquals(initialProjects.size() + 2, allProjects.size());
+
+ List<ProjectInfo> projectsWithDescription = gApi.projects().list()
+ .withDescription(true)
+ .get();
+ assertNotNull(projectsWithDescription.get(0).description);
+
+ List<ProjectInfo> projectsWithoutDescription = gApi.projects().list()
+ .withDescription(false)
+ .get();
+ assertNull(projectsWithoutDescription.get(0).description);
+
+ List<ProjectInfo> noMatchingProjects = gApi.projects().list()
+ .withPrefix("fox")
+ .get();
+ assertEquals(0, noMatchingProjects.size());
+
+ List<ProjectInfo> matchingProject = gApi.projects().list()
+ .withPrefix("fo")
+ .get();
+ assertEquals(1, matchingProject.size());
+
+ List<ProjectInfo> limitOneProject = gApi.projects().list()
+ .withLimit(1)
+ .get();
+ assertEquals(1, limitOneProject.size());
+
+ List<ProjectInfo> startAtOneProjects = gApi.projects().list()
+ .withStart(1)
+ .get();
+ assertEquals(allProjects.size() - 1, startAtOneProjects.size());
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK
index aa9703c..1152d88 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK
@@ -2,5 +2,5 @@
acceptance_tests(
srcs = glob(['*IT.java']),
- deps = ['//gerrit-acceptance-tests:lib'],
+ labels = ['api'],
)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 50522cd..9653ffa 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -14,6 +14,11 @@
package com.google.gerrit.acceptance.api.revision;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
@@ -21,6 +26,7 @@
import com.google.gerrit.extensions.api.changes.ChangeApi;
import com.google.gerrit.extensions.api.changes.CherryPickInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.changes.RevisionApi;
import com.google.gerrit.extensions.api.changes.SubmitInput;
import com.google.gerrit.extensions.api.projects.BranchInput;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -130,16 +136,87 @@
.name(project.get())
.branch(in.destination)
.create(new BranchInput());
- ChangeApi cApi = gApi.changes()
- .id(r.getChangeId())
- .revision(r.getCommit().name())
+ ChangeApi orig = gApi.changes()
+ .id("p~master~" + r.getChangeId());
+
+ assertEquals(1, orig.get().messages.size());
+ ChangeApi cherry = orig.revision(r.getCommit().name())
.cherryPick(in);
- cApi.current()
+ assertEquals(2, orig.get().messages.size());
+
+ assertTrue(cherry.get().subject.contains(in.message));
+ cherry.current()
.review(ReviewInput.approve());
- cApi.current()
+ cherry.current()
.submit();
}
+ @Test
+ public void canRebase()
+ throws GitAPIException, IOException, RestApiException, Exception {
+ PushOneCommit push = pushFactory.create(db, admin.getIdent());
+ PushOneCommit.Result r1 = push.to(git, "refs/for/master");
+ merge(r1);
+
+ push = pushFactory.create(db, admin.getIdent());
+ PushOneCommit.Result r2 = push.to(git, "refs/for/master");
+ assertFalse(gApi.changes()
+ .id(r2.getChangeId())
+ .revision(r2.getCommit().name())
+ .canRebase());
+ merge(r2);
+
+ git.checkout().setName(r1.getCommit().name()).call();
+ push = pushFactory.create(db, admin.getIdent());
+ PushOneCommit.Result r3 = push.to(git, "refs/for/master");
+
+ assertTrue(gApi.changes()
+ .id(r3.getChangeId())
+ .revision(r3.getCommit().name())
+ .canRebase());
+ }
+
+ @Test
+ public void setUnsetReviewedFlag() throws Exception {
+ PushOneCommit push = pushFactory.create(db, admin.getIdent());
+ PushOneCommit.Result r = push.to(git, "refs/for/master");
+
+ gApi.changes()
+ .id(r.getChangeId())
+ .current()
+ .setReviewed(PushOneCommit.FILE_NAME, true);
+
+ assertEquals(PushOneCommit.FILE_NAME,
+ Iterables.getOnlyElement(
+ gApi.changes()
+ .id(r.getChangeId())
+ .current()
+ .reviewed()));
+
+ gApi.changes()
+ .id(r.getChangeId())
+ .current()
+ .setReviewed(PushOneCommit.FILE_NAME, false);
+
+ assertTrue(
+ gApi.changes()
+ .id(r.getChangeId())
+ .current()
+ .reviewed()
+ .isEmpty());
+ }
+
+ protected RevisionApi revision(PushOneCommit.Result r) throws Exception {
+ return gApi.changes()
+ .id(r.getChangeId())
+ .current();
+ }
+
+ private void merge(PushOneCommit.Result r) throws Exception {
+ revision(r).review(ReviewInput.approve());
+ revision(r).submit();
+ }
+
private PushOneCommit.Result updateChange(PushOneCommit.Result r,
String content) throws GitAPIException, IOException {
PushOneCommit push = pushFactory.create(db, admin.getIdent(),
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 5a8ba0c..5b3795e 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -15,10 +15,14 @@
package com.google.gerrit.acceptance.git;
import static com.google.gerrit.acceptance.GitUtil.cloneProject;
+import static org.junit.Assert.assertEquals;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.LabelInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gwtorm.server.OrmException;
@@ -144,6 +148,43 @@
}
@Test
+ public void testPushForMasterWithApprovals() throws GitAPIException,
+ IOException, RestApiException {
+ PushOneCommit.Result r = pushTo("refs/for/master/%l=Code-Review");
+ r.assertOkStatus();
+ ChangeInfo ci = get(r.getChangeId());
+ LabelInfo cr = ci.labels.get("Code-Review");
+ assertEquals(1, cr.all.size());
+ assertEquals("Administrator", cr.all.get(0).name);
+ assertEquals(1, cr.all.get(0).value.intValue());
+
+ PushOneCommit push =
+ pushFactory.create(db, admin.getIdent(), PushOneCommit.SUBJECT,
+ "b.txt", "anotherContent", r.getChangeId());
+ r = push.to(git, "refs/for/master/%l=Code-Review+2");
+
+ ci = get(r.getChangeId());
+ cr = ci.labels.get("Code-Review");
+ assertEquals(1, cr.all.size());
+ assertEquals("Administrator", cr.all.get(0).name);
+ assertEquals(2, cr.all.get(0).value.intValue());
+ }
+
+ @Test
+ public void testPushForMasterWithApprovals_MissingLabel() throws GitAPIException,
+ IOException {
+ PushOneCommit.Result r = pushTo("refs/for/master/%l=Verify");
+ r.assertErrorStatus("label \"Verify\" is not a configured label");
+ }
+
+ @Test
+ public void testPushForMasterWithApprovals_ValueOutOfRange() throws GitAPIException,
+ IOException, RestApiException {
+ PushOneCommit.Result r = pushTo("refs/for/master/%l=Code-Review-3");
+ r.assertErrorStatus("label \"Code-Review\": -3 is not a valid value");
+ }
+
+ @Test
public void testPushForNonExistingBranch() throws GitAPIException,
OrmException, IOException {
String branchName = "non-existing";
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
index 5976f54..3ead2a1 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
@@ -2,12 +2,13 @@
acceptance_tests(
srcs = ['DraftChangeBlockedIT.java', 'SubmitOnPushIT.java'],
- deps = ['//gerrit-acceptance-tests:lib'],
+ labels = ['git'],
)
acceptance_tests(
srcs = ['HttpPushForReviewIT.java', 'SshPushForReviewIT.java'],
deps = [':push_for_review'],
+ labels = ['git'],
)
java_library(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java
index b69c264..20c8f76 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java
@@ -15,7 +15,7 @@
package com.google.gerrit.acceptance.git;
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
-import static com.google.gerrit.server.project.Util.grant;
+import static com.google.gerrit.server.project.Util.block;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
@@ -49,8 +49,7 @@
@Before
public void setUp() throws Exception {
ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
- grant(cfg, Permission.PUSH, ANONYMOUS_USERS,
- "refs/drafts/*").setBlock();
+ block(cfg, Permission.PUSH, ANONYMOUS_USERS, "refs/drafts/*");
saveProjectConfig(cfg);
projectCache.evict(cfg.getProject());
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/HttpPushForReviewIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/HttpPushForReviewIT.java
index 4d7897c..71f008a 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/HttpPushForReviewIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/HttpPushForReviewIT.java
@@ -24,7 +24,7 @@
public class HttpPushForReviewIT extends AbstractPushForReview {
@Before
- public void selectHttpUrl() throws GitAPIException, IOException {
+ public void selectHttpUrl() throws GitAPIException, IOException, URISyntaxException {
CredentialsProvider.setDefault(new UsernamePasswordCredentialsProvider(
admin.username, admin.httpPassword));
selectProtocol(Protocol.HTTP);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/BUCK
new file mode 100644
index 0000000..00b53f9
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/BUCK
@@ -0,0 +1,7 @@
+include_defs('//gerrit-acceptance-tests/tests.defs')
+
+acceptance_tests(
+ srcs = glob(['*IT.java']),
+ labels = ['pgm'],
+ source_under_test = ['//gerrit-pgm:pgm'],
+)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/ReindexIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/ReindexIT.java
new file mode 100644
index 0000000..4f9ef14
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/ReindexIT.java
@@ -0,0 +1,66 @@
+// 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.acceptance.pgm;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.gerrit.acceptance.TempFileUtil;
+import com.google.gerrit.launcher.GerritLauncher;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+
+public class ReindexIT {
+ private File sitePath;
+
+ @Before
+ public void createTempDirectory() throws Exception {
+ sitePath = TempFileUtil.createTempDirectory();
+ }
+
+ @After
+ public void destroySite() throws Exception {
+ if (sitePath != null) {
+ TempFileUtil.cleanup();
+ }
+ }
+
+ @Test
+ public void reindexEmptySite() throws Exception {
+ initSite();
+ runGerrit("reindex", "-d", sitePath.getPath(),
+ "--show-stack-trace");
+ }
+
+ @Test
+ public void reindexEmptySiteWithRecheckMergeable() throws Exception {
+ initSite();
+ runGerrit("reindex", "-d", sitePath.getPath(),
+ "--show-stack-trace",
+ "--recheck-mergeable");
+ }
+
+ private void initSite() throws Exception {
+ runGerrit("init", "-d", sitePath.getPath(),
+ "--batch", "--no-auto-start", "--skip-plugins", "--show-stack-trace");
+ }
+
+ private static void runGerrit(String... args) throws Exception {
+ assertEquals(0, GerritLauncher.mainImpl(args));
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/BUCK
index 77e0419..f081ada 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/BUCK
@@ -2,10 +2,8 @@
acceptance_tests(
srcs = glob(['*IT.java']),
- deps = [
- ':util',
- '//gerrit-acceptance-tests:lib',
- ],
+ deps = [':util'],
+ labels = ['rest']
)
java_library(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
index fa906a4..6c36e37 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
@@ -31,12 +31,12 @@
import com.google.gerrit.acceptance.SshSession;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.SubmitInput;
+import com.google.gerrit.extensions.common.InheritableBoolean;
+import com.google.gerrit.extensions.common.SubmitType;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.Project.InheritableBoolean;
-import com.google.gerrit.reviewdb.client.Project.SubmitType;
import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.change.ChangeJson.ChangeInfo;
import com.google.gerrit.server.change.ChangeJson.LabelInfo;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK
index c76c9a6..f42a134 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK
@@ -11,16 +11,18 @@
acceptance_tests(
srcs = OTHER_TESTS,
deps = [
- '//gerrit-acceptance-tests:lib',
+ ':submit_util',
+ '//lib/joda:joda-time',
],
+ labels = ['rest'],
)
acceptance_tests(
srcs = SUBMIT_TESTS,
deps = [
':submit_util',
- '//gerrit-acceptance-tests:lib',
],
+ labels = ['rest'],
)
java_library(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java
index 6352b50..acf50db 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java
@@ -14,6 +14,8 @@
package com.google.gerrit.acceptance.rest.change;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -23,14 +25,55 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.testutil.ConfigSuite;
import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.Config;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeUtils;
+import org.joda.time.DateTimeUtils.MillisProvider;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.io.IOException;
import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicLong;
+@RunWith(ConfigSuite.class)
public class ChangeMessagesIT extends AbstractDaemonTest {
+ private String systemTimeZone;
+ private volatile long clockStepMs;
+
+ @ConfigSuite.Config
+ public static Config noteDbEnabled() {
+ Config cfg = new Config();
+ cfg.setBoolean("notedb", null, "write", true);
+ cfg.setBoolean("notedb", "changeMessages", "read", true);
+ return cfg;
+ }
+
+ @Before
+ public void setTimeForTesting() {
+ systemTimeZone = System.setProperty("user.timezone", "US/Eastern");
+ clockStepMs = MILLISECONDS.convert(1, SECONDS);
+ final AtomicLong clockMs = new AtomicLong(
+ new DateTime(2009, 9, 30, 17, 0, 0).getMillis());
+
+ DateTimeUtils.setCurrentMillisProvider(new MillisProvider() {
+ @Override
+ public long getMillis() {
+ return clockMs.getAndAdd(clockStepMs);
+ }
+ });
+ }
+
+ @After
+ public void resetTime() {
+ DateTimeUtils.setCurrentMillisSystem();
+ System.setProperty("user.timezone", systemTimeZone);
+ }
@Test
public void messagesNotReturnedByDefault() throws Exception {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
new file mode 100644
index 0000000..2026ac1
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
@@ -0,0 +1,91 @@
+// 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.acceptance.rest.change;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.ChangeStatus;
+import com.google.gerrit.server.change.ChangeJson;
+
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+
+public class CreateChangeIT extends AbstractDaemonTest {
+
+ @Test
+ public void createEmptyChange_MissingBranch() throws Exception {
+ ChangeInfo ci = new ChangeInfo();
+ ci.project = project.get();
+ RestResponse r = adminSession.post("/changes/", ci);
+ assertEquals(HttpStatus.SC_BAD_REQUEST, r.getStatusCode());
+ assertTrue(r.getEntityContent().contains("branch must be non-empty"));
+ }
+
+ @Test
+ public void createEmptyChange_MissingMessage() throws Exception {
+ ChangeInfo ci = new ChangeInfo();
+ ci.project = project.get();
+ ci.branch = "master";
+ RestResponse r = adminSession.post("/changes/", ci);
+ assertEquals(HttpStatus.SC_BAD_REQUEST, r.getStatusCode());
+ assertTrue(r.getEntityContent().contains("commit message must be non-empty"));
+ }
+
+ @Test
+ public void createEmptyChange_InvalidStatus() throws Exception {
+ ChangeInfo ci = newChangeInfo(ChangeStatus.SUBMITTED);
+ RestResponse r = adminSession.post("/changes/", ci);
+ assertEquals(HttpStatus.SC_BAD_REQUEST, r.getStatusCode());
+ assertTrue(r.getEntityContent().contains("unsupported change status"));
+ }
+
+ @Test
+ public void createNewChange() throws Exception {
+ assertChange(newChangeInfo(ChangeStatus.NEW));
+ }
+
+ @Test
+ public void createDraftChange() throws Exception {
+ assertChange(newChangeInfo(ChangeStatus.DRAFT));
+ }
+
+ private ChangeInfo newChangeInfo(ChangeStatus status) {
+ ChangeInfo in = new ChangeInfo();
+ in.project = project.get();
+ in.branch = "master";
+ in.subject = "Empty change";
+ in.topic = "support-gerrit-workflow-in-browser";
+ in.status = status;
+ return in;
+ }
+
+ private void assertChange(ChangeInfo in) throws Exception {
+ RestResponse r = adminSession.post("/changes/", in);
+ assertEquals(HttpStatus.SC_CREATED, r.getStatusCode());
+
+ ChangeJson.ChangeInfo info = newGson().fromJson(r.getReader(),
+ ChangeJson.ChangeInfo.class);
+ ChangeInfo out = get(info.changeId);
+
+ assertEquals(in.branch, out.branch);
+ assertEquals(in.subject, out.subject);
+ assertEquals(in.topic, out.topic);
+ assertEquals(in.status, out.status);
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ListChangesOptionsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ListChangesOptionsIT.java
index 97ae2fd..02ecbd8 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ListChangesOptionsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ListChangesOptionsIT.java
@@ -16,6 +16,7 @@
import static com.google.gerrit.extensions.common.ListChangesOption.ALL_REVISIONS;
import static com.google.gerrit.extensions.common.ListChangesOption.CURRENT_REVISION;
+import static com.google.gerrit.extensions.common.ListChangesOption.MESSAGES;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -73,6 +74,15 @@
}
@Test
+ public void currentRevisionAndMessages() throws Exception {
+ ChangeInfo c = get(changeId, CURRENT_REVISION, MESSAGES);
+ assertEquals(1, c.revisions.size());
+ assertEquals(commitId(2), c.currentRevision);
+ assertEquals(ImmutableSet.of(commitId(2)), c.revisions.keySet());
+ assertEquals(3, c.revisions.get(commitId(2))._number);
+ }
+
+ @Test
public void allRevisions() throws Exception {
ChangeInfo c = get(changeId, ALL_REVISIONS);
assertEquals(commitId(2), c.currentRevision);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java
index d137e62..12d002e 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java
@@ -19,8 +19,8 @@
import static org.junit.Assert.assertSame;
import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.reviewdb.client.Project.SubmitType;
import com.google.gwtorm.server.OrmException;
+import com.google.gerrit.extensions.common.SubmitType;
import com.jcraft.jsch.JSchException;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java
index d6fbca4..2ef4ecc 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByFastForwardIT.java
@@ -18,7 +18,7 @@
import static org.junit.Assert.assertEquals;
import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.reviewdb.client.Project.SubmitType;
+import com.google.gerrit.extensions.common.SubmitType;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.revwalk.RevCommit;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeAlwaysIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeAlwaysIT.java
index 2a01d84..9512c7a 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeAlwaysIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeAlwaysIT.java
@@ -18,7 +18,7 @@
import static org.junit.Assert.assertEquals;
import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.reviewdb.client.Project.SubmitType;
+import com.google.gerrit.extensions.common.SubmitType;
import com.google.gwtorm.server.OrmException;
import com.jcraft.jsch.JSchException;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeIfNecessaryIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeIfNecessaryIT.java
index 486c529..fde462b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeIfNecessaryIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByMergeIfNecessaryIT.java
@@ -4,7 +4,7 @@
import static org.junit.Assert.assertEquals;
import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.reviewdb.client.Project.SubmitType;
+import com.google.gerrit.extensions.common.SubmitType;
import com.google.gwtorm.server.OrmException;
import com.jcraft.jsch.JSchException;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java
index 8968084..7b4d23d 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java
@@ -18,7 +18,7 @@
import static org.junit.Assert.assertEquals;
import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.reviewdb.client.Project.SubmitType;
+import com.google.gerrit.extensions.common.SubmitType;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.revwalk.RevCommit;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/BUCK
new file mode 100644
index 0000000..c89da30
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/BUCK
@@ -0,0 +1,6 @@
+include_defs('//gerrit-acceptance-tests/tests.defs')
+
+acceptance_tests(
+ srcs = glob(['*IT.java']),
+ labels = ['rest']
+)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
new file mode 100644
index 0000000..d2174bc
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
@@ -0,0 +1,166 @@
+// 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.acceptance.rest.config;
+
+import static com.google.gerrit.server.config.PostCaches.Operation.FLUSH;
+import static com.google.gerrit.server.config.PostCaches.Operation.FLUSH_ALL;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static com.google.gerrit.server.project.Util.allow;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.config.ListCaches.CacheInfo;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.PostCaches;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.inject.Inject;
+
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+public class CacheOperationsIT extends AbstractDaemonTest {
+
+ @Inject
+ private ProjectCache projectCache;
+
+ @Inject
+ private AllProjectsName allProjects;
+
+ @Inject
+ private MetaDataUpdate.Server metaDataUpdateFactory;
+
+ @Test
+ public void flushAll() throws IOException {
+ RestResponse r = adminSession.get("/config/server/caches/project_list");
+ CacheInfo cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
+ assertTrue(cacheInfo.entries.mem.longValue() > 0);
+
+ r = adminSession.post("/config/server/caches/", new PostCaches.Input(FLUSH_ALL));
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ r.consume();
+
+ r = adminSession.get("/config/server/caches/project_list");
+ cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
+ assertNull(cacheInfo.entries.mem);
+ }
+
+ @Test
+ public void flushAll_Forbidden() throws IOException {
+ RestResponse r = userSession.post("/config/server/caches/",
+ new PostCaches.Input(FLUSH_ALL));
+ assertEquals(HttpStatus.SC_FORBIDDEN, r.getStatusCode());
+ }
+
+ @Test
+ public void flushAll_BadRequest() throws IOException {
+ RestResponse r = adminSession.post("/config/server/caches/",
+ new PostCaches.Input(FLUSH_ALL, Arrays.asList("projects")));
+ assertEquals(HttpStatus.SC_BAD_REQUEST, r.getStatusCode());
+ }
+
+ @Test
+ public void flush() throws IOException {
+ RestResponse r = adminSession.get("/config/server/caches/project_list");
+ CacheInfo cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
+ assertTrue(cacheInfo.entries.mem.longValue() > 0);
+
+ r = adminSession.get("/config/server/caches/projects");
+ cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
+ assertTrue(cacheInfo.entries.mem.longValue() > 1);
+
+ r = adminSession.post("/config/server/caches/",
+ new PostCaches.Input(FLUSH, Arrays.asList("accounts", "project_list")));
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ r.consume();
+
+ r = adminSession.get("/config/server/caches/project_list");
+ cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
+ assertNull(cacheInfo.entries.mem);
+
+ r = adminSession.get("/config/server/caches/projects");
+ cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
+ assertTrue(cacheInfo.entries.mem.longValue() > 1);
+ }
+
+ @Test
+ public void flush_Forbidden() throws IOException {
+ RestResponse r = userSession.post("/config/server/caches/",
+ new PostCaches.Input(FLUSH, Arrays.asList("projects")));
+ assertEquals(HttpStatus.SC_FORBIDDEN, r.getStatusCode());
+ }
+
+ @Test
+ public void flush_BadRequest() throws IOException {
+ RestResponse r = adminSession.post("/config/server/caches/",
+ new PostCaches.Input(FLUSH));
+ assertEquals(HttpStatus.SC_BAD_REQUEST, r.getStatusCode());
+ }
+
+ @Test
+ public void flush_UnprocessableEntity() throws IOException {
+ RestResponse r = adminSession.get("/config/server/caches/projects");
+ CacheInfo cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
+ assertTrue(cacheInfo.entries.mem.longValue() > 0);
+
+ r = adminSession.post("/config/server/caches/",
+ new PostCaches.Input(FLUSH, Arrays.asList("projects", "unprocessable")));
+ assertEquals(HttpStatus.SC_UNPROCESSABLE_ENTITY, r.getStatusCode());
+ r.consume();
+
+ r = adminSession.get("/config/server/caches/projects");
+ cacheInfo = newGson().fromJson(r.getReader(), CacheInfo.class);
+ assertTrue(cacheInfo.entries.mem.longValue() > 0);
+ }
+
+ @Test
+ public void flushWebSessions_Forbidden() throws IOException {
+ ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ AccountGroup.UUID registeredUsers =
+ SystemGroupBackend.getGroup(REGISTERED_USERS).getUUID();
+ allow(cfg, GlobalCapability.VIEW_CACHES, registeredUsers);
+ allow(cfg, GlobalCapability.FLUSH_CACHES, registeredUsers);
+ saveProjectConfig(cfg);
+
+ RestResponse r = userSession.post("/config/server/caches/",
+ new PostCaches.Input(FLUSH, Arrays.asList("projects")));
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ r.consume();
+
+ r = userSession.post("/config/server/caches/",
+ new PostCaches.Input(FLUSH, Arrays.asList("web_sessions")));
+ assertEquals(HttpStatus.SC_FORBIDDEN, r.getStatusCode());
+ }
+
+ private void saveProjectConfig(ProjectConfig cfg) throws IOException {
+ MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
+ try {
+ cfg.commit(md);
+ } finally {
+ md.close();
+ }
+ projectCache.evict(allProjects);
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/FlushCacheIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/FlushCacheIT.java
new file mode 100644
index 0000000..aa8d7ba
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/FlushCacheIT.java
@@ -0,0 +1,116 @@
+// 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.acceptance.rest.config;
+
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static com.google.gerrit.server.project.Util.allow;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.ListCaches.CacheInfo;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.inject.Inject;
+
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class FlushCacheIT extends AbstractDaemonTest {
+
+ @Inject
+ private ProjectCache projectCache;
+
+ @Inject
+ private AllProjectsName allProjects;
+
+ @Inject
+ private MetaDataUpdate.Server metaDataUpdateFactory;
+
+ @Test
+ public void flushCache() throws IOException {
+ RestResponse r = adminSession.get("/config/server/caches/groups");
+ CacheInfo result = newGson().fromJson(r.getReader(), CacheInfo.class);
+ assertTrue(result.entries.mem.longValue() > 0);
+
+ r = adminSession.post("/config/server/caches/groups/flush");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ r.consume();
+
+ r = adminSession.get("/config/server/caches/groups");
+ result = newGson().fromJson(r.getReader(), CacheInfo.class);
+ assertNull(result.entries.mem);
+ }
+
+ @Test
+ public void flushCache_Forbidden() throws IOException {
+ RestResponse r = userSession.post("/config/server/caches/accounts/flush");
+ assertEquals(HttpStatus.SC_FORBIDDEN, r.getStatusCode());
+ }
+
+ @Test
+ public void flushCache_NotFound() throws IOException {
+ RestResponse r = adminSession.post("/config/server/caches/nonExisting/flush");
+ assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode());
+ }
+
+ @Test
+ public void flushCacheWithGerritPrefix() throws IOException {
+ RestResponse r = adminSession.post("/config/server/caches/gerrit-accounts/flush");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ }
+
+ @Test
+ public void flushWebSessionsCache() throws IOException {
+ RestResponse r = adminSession.post("/config/server/caches/web_sessions/flush");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ }
+
+ @Test
+ public void flushWebSessionsCache_Forbidden() throws IOException {
+ ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ AccountGroup.UUID registeredUsers =
+ SystemGroupBackend.getGroup(REGISTERED_USERS).getUUID();
+ allow(cfg, GlobalCapability.VIEW_CACHES, registeredUsers);
+ allow(cfg, GlobalCapability.FLUSH_CACHES, registeredUsers);
+ saveProjectConfig(cfg);
+
+ RestResponse r = userSession.post("/config/server/caches/accounts/flush");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ r.consume();
+
+ r = userSession.post("/config/server/caches/web_sessions/flush");
+ assertEquals(HttpStatus.SC_FORBIDDEN, r.getStatusCode());
+ }
+
+ private void saveProjectConfig(ProjectConfig cfg) throws IOException {
+ MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
+ try {
+ cfg.commit(md);
+ } finally {
+ md.close();
+ }
+ projectCache.evict(allProjects);
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetCacheIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetCacheIT.java
new file mode 100644
index 0000000..398d0c8
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetCacheIT.java
@@ -0,0 +1,75 @@
+// 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.acceptance.rest.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.server.config.ListCaches.CacheInfo;
+import com.google.gerrit.server.config.ListCaches.CacheType;
+
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class GetCacheIT extends AbstractDaemonTest {
+
+ @Test
+ public void getCache() throws IOException {
+ RestResponse r = adminSession.get("/config/server/caches/accounts");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ CacheInfo result = newGson().fromJson(r.getReader(), CacheInfo.class);
+
+ assertEquals("accounts", result.name);
+ assertEquals(CacheType.MEM, result.type);
+ assertEquals(1, result.entries.mem.longValue());
+ assertNotNull(result.averageGet);
+ assertTrue(result.averageGet.endsWith("s"));
+ assertNull(result.entries.disk);
+ assertNull(result.entries.space);
+ assertTrue(result.hitRatio.mem >= 0);
+ assertTrue(result.hitRatio.mem <= 100);
+ assertNull(result.hitRatio.disk);
+
+ userSession.get("/config/server/version").consume();
+ r = adminSession.get("/config/server/caches/accounts");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ result = newGson().fromJson(r.getReader(), CacheInfo.class);
+ assertEquals(2, result.entries.mem.longValue());
+ }
+
+ @Test
+ public void getCache_Forbidden() throws IOException {
+ RestResponse r = userSession.get("/config/server/caches/accounts");
+ assertEquals(HttpStatus.SC_FORBIDDEN, r.getStatusCode());
+ }
+
+ @Test
+ public void getCache_NotFound() throws IOException {
+ RestResponse r = adminSession.get("/config/server/caches/nonExisting");
+ assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode());
+ }
+
+ @Test
+ public void getCacheWithGerritPrefix() throws IOException {
+ RestResponse r = adminSession.get("/config/server/caches/gerrit-accounts");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetTaskIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetTaskIT.java
new file mode 100644
index 0000000..2feeab8
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetTaskIT.java
@@ -0,0 +1,67 @@
+// 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.acceptance.rest.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.server.config.ListTasks.TaskInfo;
+import com.google.gson.reflect.TypeToken;
+
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+public class GetTaskIT extends AbstractDaemonTest {
+
+ @Test
+ public void getTask() throws IOException {
+ RestResponse r =
+ adminSession.get("/config/server/tasks/" + getLogFileCompressorTaskId());
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ TaskInfo info =
+ newGson().fromJson(r.getReader(),
+ new TypeToken<TaskInfo>() {}.getType());
+ assertNotNull(info.id);
+ Long.parseLong(info.id, 16);
+ assertEquals("Log File Compressor", info.command);
+ assertNotNull(info.startTime);
+ }
+
+ @Test
+ public void getTask_NotFound() throws IOException {
+ RestResponse r =
+ userSession.get("/config/server/tasks/" + getLogFileCompressorTaskId());
+ assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode());
+ }
+
+ private String getLogFileCompressorTaskId() throws IOException {
+ RestResponse r = adminSession.get("/config/server/tasks/");
+ List<TaskInfo> result =
+ newGson().fromJson(r.getReader(),
+ new TypeToken<List<TaskInfo>>() {}.getType());
+ r.consume();
+ for (TaskInfo info : result) {
+ if ("Log File Compressor".equals(info.command)) {
+ return info.id;
+ }
+ }
+ return null;
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/KillTaskIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/KillTaskIT.java
new file mode 100644
index 0000000..90cb7cc
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/KillTaskIT.java
@@ -0,0 +1,64 @@
+// 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.acceptance.rest.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.server.config.ListTasks.TaskInfo;
+import com.google.gson.reflect.TypeToken;
+
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+public class KillTaskIT extends AbstractDaemonTest {
+
+ @Test
+ public void killTask() throws IOException {
+ RestResponse r = adminSession.get("/config/server/tasks/");
+ List<TaskInfo> result = newGson().fromJson(r.getReader(),
+ new TypeToken<List<TaskInfo>>() {}.getType());
+ r.consume();
+ int taskCount = result.size();
+ assertTrue(taskCount > 0);
+
+ r = adminSession.delete("/config/server/tasks/" + result.get(0).id);
+ assertEquals(HttpStatus.SC_NO_CONTENT, r.getStatusCode());
+ r.consume();
+
+ r = adminSession.get("/config/server/tasks/");
+ result = newGson().fromJson(r.getReader(),
+ new TypeToken<List<TaskInfo>>() {}.getType());
+ r.consume();
+ assertEquals(taskCount - 1, result.size());
+ }
+
+ @Test
+ public void killTask_NotFound() throws IOException {
+ RestResponse r = adminSession.get("/config/server/tasks/");
+ List<TaskInfo> result = newGson().fromJson(r.getReader(),
+ new TypeToken<List<TaskInfo>>() {}.getType());
+ r.consume();
+ assertTrue(result.size() > 0);
+
+ r = userSession.delete("/config/server/tasks/" + result.get(0).id);
+ assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode());
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListCachesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
new file mode 100644
index 0000000..db7fb7f
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
@@ -0,0 +1,103 @@
+// 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.acceptance.rest.config;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Ordering;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.server.config.ListCaches.CacheInfo;
+import com.google.gerrit.server.config.ListCaches.CacheType;
+import com.google.gson.reflect.TypeToken;
+
+import org.apache.http.HttpStatus;
+import org.eclipse.jgit.util.Base64;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+public class ListCachesIT extends AbstractDaemonTest {
+
+ @Test
+ public void listCaches() throws IOException {
+ RestResponse r = adminSession.get("/config/server/caches/");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ Map<String, CacheInfo> result =
+ newGson().fromJson(r.getReader(),
+ new TypeToken<Map<String, CacheInfo>>() {}.getType());
+
+ assertTrue(result.containsKey("accounts"));
+ CacheInfo accountsCacheInfo = result.get("accounts");
+ assertEquals(CacheType.MEM, accountsCacheInfo.type);
+ assertEquals(1, accountsCacheInfo.entries.mem.longValue());
+ assertNotNull(accountsCacheInfo.averageGet);
+ assertTrue(accountsCacheInfo.averageGet.endsWith("s"));
+ assertNull(accountsCacheInfo.entries.disk);
+ assertNull(accountsCacheInfo.entries.space);
+ assertTrue(accountsCacheInfo.hitRatio.mem >= 0);
+ assertTrue(accountsCacheInfo.hitRatio.mem <= 100);
+ assertNull(accountsCacheInfo.hitRatio.disk);
+
+ userSession.get("/config/server/version").consume();
+ r = adminSession.get("/config/server/caches/");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ result = newGson().fromJson(r.getReader(),
+ new TypeToken<Map<String, CacheInfo>>() {}.getType());
+ assertEquals(2, result.get("accounts").entries.mem.longValue());
+ }
+
+ @Test
+ public void listCaches_Forbidden() throws IOException {
+ RestResponse r = userSession.get("/config/server/caches/");
+ assertEquals(HttpStatus.SC_FORBIDDEN, r.getStatusCode());
+ }
+
+ @Test
+ public void listCacheNames() throws IOException {
+ RestResponse r = adminSession.get("/config/server/caches/?format=LIST");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ List<String> result =
+ newGson().fromJson(r.getReader(),
+ new TypeToken<List<String>>() {}.getType());
+ assertTrue(result.contains("accounts"));
+ assertTrue(result.contains("projects"));
+ assertTrue(Ordering.natural().isOrdered(result));
+ }
+
+ @Test
+ public void listCacheNamesTextList() throws IOException {
+ RestResponse r = adminSession.get("/config/server/caches/?format=TEXT_LIST");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ String result = new String(Base64.decode(r.getEntityContent()), UTF_8.name());
+ List<String> list = Arrays.asList(result.split("\n"));
+ assertTrue(list.contains("accounts"));
+ assertTrue(list.contains("projects"));
+ assertTrue(Ordering.natural().isOrdered(list));
+ }
+
+ @Test
+ public void listCaches_BadRequest() throws IOException {
+ RestResponse r = adminSession.get("/config/server/caches/?format=NONSENSE");
+ assertEquals(HttpStatus.SC_BAD_REQUEST, r.getStatusCode());
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListTasksIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListTasksIT.java
new file mode 100644
index 0000000..205a701
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListTasksIT.java
@@ -0,0 +1,65 @@
+// 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.acceptance.rest.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.server.config.ListTasks.TaskInfo;
+import com.google.gson.reflect.TypeToken;
+
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+public class ListTasksIT extends AbstractDaemonTest {
+
+ @Test
+ public void listTasks() throws IOException {
+ RestResponse r = adminSession.get("/config/server/tasks/");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ List<TaskInfo> result =
+ newGson().fromJson(r.getReader(),
+ new TypeToken<List<TaskInfo>>() {}.getType());
+ assertTrue(result.size() > 0);
+ boolean foundLogFileCompressorTask = false;
+ for (TaskInfo info : result) {
+ if ("Log File Compressor".equals(info.command)) {
+ foundLogFileCompressorTask = true;
+ }
+ assertNotNull(info.id);
+ Long.parseLong(info.id, 16);
+ assertNotNull(info.command);
+ assertNotNull(info.startTime);
+ }
+ assertTrue(foundLogFileCompressorTask);
+ }
+
+ @Test
+ public void listTasksWithoutViewQueueCapability() throws IOException {
+ RestResponse r = userSession.get("/config/server/tasks/");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ List<TaskInfo> result =
+ newGson().fromJson(r.getReader(),
+ new TypeToken<List<TaskInfo>>() {}.getType());
+
+ assertTrue(result.isEmpty());
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/BUCK
index 108cc8d..da34c1d 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/BUCK
@@ -6,6 +6,7 @@
':util',
'//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account:util',
],
+ labels = ['rest']
)
java_library(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK
index 91511be..fa8b10e 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK
@@ -5,8 +5,8 @@
deps = [
':branch',
':project',
- '//gerrit-acceptance-tests:lib',
],
+ labels = ['rest']
)
java_library(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BanCommitIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BanCommitIT.java
new file mode 100644
index 0000000..f4414a2
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BanCommitIT.java
@@ -0,0 +1,82 @@
+// 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.acceptance.rest.project;
+
+import static com.google.gerrit.acceptance.GitUtil.add;
+import static com.google.gerrit.acceptance.GitUtil.createCommit;
+import static com.google.gerrit.acceptance.GitUtil.pushHead;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Iterables;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.GitUtil.Commit;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.server.project.BanCommit;
+import com.google.gerrit.server.project.BanCommit.BanResultInfo;
+
+import org.apache.http.HttpStatus;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.transport.PushResult;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class BanCommitIT extends AbstractDaemonTest {
+
+ @Test
+ public void banCommit() throws IOException, GitAPIException {
+ add(git, "a.txt", "some content");
+ Commit c = createCommit(git, admin.getIdent(), "subject");
+
+ RestResponse r =
+ adminSession.put("/projects/" + project.get() + "/ban/",
+ BanCommit.Input.fromCommits(c.getCommit().getName()));
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ BanResultInfo info = newGson().fromJson(r.getReader(), BanResultInfo.class);
+ assertEquals(c.getCommit().getName(), Iterables.getOnlyElement(info.newlyBanned));
+ assertNull(info.alreadyBanned);
+ assertNull(info.ignored);
+
+ PushResult pushResult = pushHead(git, "refs/heads/master", false);
+ assertTrue(pushResult.getRemoteUpdate("refs/heads/master").getMessage()
+ .startsWith("contains banned commit"));
+ }
+
+ @Test
+ public void banAlreadyBannedCommit() throws IOException, GitAPIException {
+ RestResponse r =
+ adminSession.put("/projects/" + project.get() + "/ban/",
+ BanCommit.Input.fromCommits("a8a477efffbbf3b44169bb9a1d3a334cbbd9aa96"));
+ r.consume();
+
+ r = adminSession.put("/projects/" + project.get() + "/ban/",
+ BanCommit.Input.fromCommits("a8a477efffbbf3b44169bb9a1d3a334cbbd9aa96"));
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ BanResultInfo info = newGson().fromJson(r.getReader(), BanResultInfo.class);
+ assertEquals("a8a477efffbbf3b44169bb9a1d3a334cbbd9aa96", Iterables.getOnlyElement(info.alreadyBanned));
+ assertNull(info.newlyBanned);
+ assertNull(info.ignored);
+ }
+
+ @Test
+ public void banCommit_Forbidden() throws IOException {
+ RestResponse r =
+ userSession.put("/projects/" + project.get() + "/ban/",
+ BanCommit.Input.fromCommits("a8a477efffbbf3b44169bb9a1d3a334cbbd9aa96"));
+ assertEquals(HttpStatus.SC_FORBIDDEN, r.getStatusCode());
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
index a4bcdf2..23cd278 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java
@@ -14,18 +14,20 @@
package com.google.gerrit.acceptance.rest.project;
+import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static com.google.gerrit.server.project.Util.allow;
+import static com.google.gerrit.server.project.Util.block;
import static org.junit.Assert.assertEquals;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission;
-import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.reviewdb.client.Branch;
-import com.google.gerrit.server.config.AllProjectsNameProvider;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.project.ProjectCache;
import com.google.inject.Inject;
@@ -44,7 +46,7 @@
private ProjectCache projectCache;
@Inject
- private AllProjectsNameProvider allProjects;
+ private AllProjectsName allProjects;
private Branch.NameKey branch;
@@ -130,29 +132,26 @@
}
private void blockCreateReference() throws IOException, ConfigInvalidException {
- MetaDataUpdate md = metaDataUpdateFactory.create(allProjects.get());
- md.setMessage(String.format("Block %s", Permission.CREATE));
- ProjectConfig config = ProjectConfig.read(md);
- AccessSection s = config.getAccessSection("refs/*", true);
- Permission p = s.getPermission(Permission.CREATE, true);
- PermissionRule rule = new PermissionRule(config.resolve(
- SystemGroupBackend.getGroup(SystemGroupBackend.ANONYMOUS_USERS)));
- rule.setBlock();
- p.add(rule);
- config.commit(md);
- projectCache.evict(config.getProject());
+ ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ block(cfg, Permission.CREATE, ANONYMOUS_USERS, "refs/*");
+ saveProjectConfig(allProjects, cfg);
+ projectCache.evict(cfg.getProject());
}
private void grantOwner() throws IOException, ConfigInvalidException {
- MetaDataUpdate md = metaDataUpdateFactory.create(project);
- md.setMessage(String.format("Grant %s", Permission.OWNER));
- ProjectConfig config = ProjectConfig.read(md);
- AccessSection s = config.getAccessSection("refs/*", true);
- Permission p = s.getPermission(Permission.OWNER, true);
- PermissionRule rule = new PermissionRule(config.resolve(
- SystemGroupBackend.getGroup(SystemGroupBackend.REGISTERED_USERS)));
- p.add(rule);
- config.commit(md);
- projectCache.evict(config.getProject());
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ allow(cfg, Permission.OWNER, REGISTERED_USERS, "refs/*");
+ saveProjectConfig(project, cfg);
+ projectCache.evict(cfg.getProject());
+ }
+
+ private void saveProjectConfig(Project.NameKey p, ProjectConfig cfg)
+ throws IOException {
+ MetaDataUpdate md = metaDataUpdateFactory.create(p);
+ try {
+ cfg.commit(md);
+ } finally {
+ md.close();
+ }
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
index fe3d3af..d441f96 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
@@ -24,17 +24,20 @@
import com.google.common.collect.Sets;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.projects.ProjectApi;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
+import com.google.gerrit.extensions.common.InheritableBoolean;
+import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.common.SubmitType;
+import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.Project.InheritableBoolean;
-import com.google.gerrit.reviewdb.client.Project.SubmitType;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.group.SystemGroupBackend;
-import com.google.gerrit.server.project.CreateProject;
import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectJson.ProjectInfo;
import com.google.gerrit.server.project.ProjectState;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -65,6 +68,21 @@
@Inject
private GitRepositoryManager git;
+ @Inject
+ private GerritApi gApi;
+
+ @Test
+ public void testCreateProjectApi() throws RestApiException, IOException {
+ final String newProjectName = "newProject";
+ ProjectApi projectApi = gApi.projects().name(newProjectName).create();
+ ProjectInfo p = projectApi.get();
+ assertEquals(newProjectName, p.name);
+ ProjectState projectState = projectCache.get(new Project.NameKey(newProjectName));
+ assertNotNull(projectState);
+ assertProjectInfo(projectState.getProject(), p);
+ assertHead(newProjectName, "refs/heads/master");
+ }
+
@Test
public void testCreateProject() throws IOException {
final String newProjectName = "newProject";
@@ -80,7 +98,7 @@
@Test
public void testCreateProjectWithNameMismatch_BadRequest() throws IOException {
- CreateProject.Input in = new CreateProject.Input();
+ ProjectInput in = new ProjectInput();
in.name = "otherName";
RestResponse r = adminSession.put("/projects/someName", in);
assertEquals(HttpStatus.SC_BAD_REQUEST, r.getStatusCode());
@@ -89,7 +107,7 @@
@Test
public void testCreateProjectWithProperties() throws IOException {
final String newProjectName = "newProject";
- CreateProject.Input in = new CreateProject.Input();
+ ProjectInput in = new ProjectInput();
in.description = "Test description";
in.submitType = SubmitType.CHERRY_PICK;
in.useContributorAgreements = InheritableBoolean.TRUE;
@@ -115,16 +133,17 @@
RestResponse r = adminSession.put("/projects/" + parentName);
r.consume();
final String childName = "child";
- CreateProject.Input in = new CreateProject.Input();
+ ProjectInput in = new ProjectInput();
in.parent = parentName;
r = adminSession.put("/projects/" + childName, in);
Project project = projectCache.get(new Project.NameKey(childName)).getProject();
assertEquals(in.parent, project.getParentName());
}
+ @Test
public void testCreateChildProjectUnderNonExistingParent_UnprocessableEntity()
throws IOException {
- CreateProject.Input in = new CreateProject.Input();
+ ProjectInput in = new ProjectInput();
in.parent = "non-existing-project";
RestResponse r = adminSession.put("/projects/child", in);
assertEquals(HttpStatus.SC_UNPROCESSABLE_ENTITY, r.getStatusCode());
@@ -133,7 +152,7 @@
@Test
public void testCreateProjectWithOwner() throws IOException {
final String newProjectName = "newProject";
- CreateProject.Input in = new CreateProject.Input();
+ ProjectInput in = new ProjectInput();
in.owners = Lists.newArrayListWithCapacity(3);
in.owners.add("Anonymous Users"); // by name
in.owners.add(SystemGroupBackend.REGISTERED_USERS.get()); // by UUID
@@ -148,9 +167,10 @@
assertProjectOwners(expectedOwnerIds, projectState);
}
+ @Test
public void testCreateProjectWithNonExistingOwner_UnprocessableEntity()
throws IOException {
- CreateProject.Input in = new CreateProject.Input();
+ ProjectInput in = new ProjectInput();
in.owners = Collections.singletonList("non-existing-group");
RestResponse r = adminSession.put("/projects/newProject", in);
assertEquals(HttpStatus.SC_UNPROCESSABLE_ENTITY, r.getStatusCode());
@@ -159,7 +179,7 @@
@Test
public void testCreatePermissionOnlyProject() throws IOException {
final String newProjectName = "newProject";
- CreateProject.Input in = new CreateProject.Input();
+ ProjectInput in = new ProjectInput();
in.permissionsOnly = true;
adminSession.put("/projects/" + newProjectName, in);
assertHead(newProjectName, RefNames.REFS_CONFIG);
@@ -168,7 +188,7 @@
@Test
public void testCreateProjectWithEmptyCommit() throws IOException {
final String newProjectName = "newProject";
- CreateProject.Input in = new CreateProject.Input();
+ ProjectInput in = new ProjectInput();
in.createEmptyCommit = true;
adminSession.put("/projects/" + newProjectName, in);
assertEmptyCommit(newProjectName, "refs/heads/master");
@@ -177,7 +197,7 @@
@Test
public void testCreateProjectWithBranches() throws IOException {
final String newProjectName = "newProject";
- CreateProject.Input in = new CreateProject.Input();
+ ProjectInput in = new ProjectInput();
in.createEmptyCommit = true;
in.branches = Lists.newArrayListWithCapacity(3);
in.branches.add("refs/heads/test");
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/DeleteBranchIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/DeleteBranchIT.java
index 020fd43..0d6ec5b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/DeleteBranchIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/DeleteBranchIT.java
@@ -14,18 +14,20 @@
package com.google.gerrit.acceptance.rest.project;
+import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static com.google.gerrit.server.project.Util.allow;
+import static com.google.gerrit.server.project.Util.block;
import static org.junit.Assert.assertEquals;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission;
-import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.reviewdb.client.Branch;
-import com.google.gerrit.server.config.AllProjectsNameProvider;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.project.ProjectCache;
import com.google.inject.Inject;
@@ -45,7 +47,7 @@
private ProjectCache projectCache;
@Inject
- private AllProjectsNameProvider allProjects;
+ private AllProjectsName allProjects;
private Branch.NameKey branch;
@@ -125,30 +127,25 @@
}
private void blockForcePush() throws IOException, ConfigInvalidException {
- MetaDataUpdate md = metaDataUpdateFactory.create(allProjects.get());
- md.setMessage(String.format("Block force %s", Permission.PUSH));
- ProjectConfig config = ProjectConfig.read(md);
- AccessSection s = config.getAccessSection("refs/heads/*", true);
- Permission p = s.getPermission(Permission.PUSH, true);
- PermissionRule rule = new PermissionRule(config.resolve(
- SystemGroupBackend.getGroup(SystemGroupBackend.ANONYMOUS_USERS)));
- rule.setForce(true);
- rule.setBlock();
- p.add(rule);
- config.commit(md);
- projectCache.evict(config.getProject());
+ ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ block(cfg, Permission.PUSH, ANONYMOUS_USERS, "refs/heads/*").setForce(true);
+ saveProjectConfig(allProjects, cfg);
+ projectCache.evict(cfg.getProject());
}
private void grantOwner() throws IOException, ConfigInvalidException {
- MetaDataUpdate md = metaDataUpdateFactory.create(project);
- md.setMessage(String.format("Grant %s", Permission.OWNER));
- ProjectConfig config = ProjectConfig.read(md);
- AccessSection s = config.getAccessSection("refs/*", true);
- Permission p = s.getPermission(Permission.OWNER, true);
- PermissionRule rule = new PermissionRule(config.resolve(
- SystemGroupBackend.getGroup(SystemGroupBackend.REGISTERED_USERS)));
- p.add(rule);
- config.commit(md);
- projectCache.evict(config.getProject());
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ allow(cfg, Permission.OWNER, REGISTERED_USERS, "refs/*");
+ saveProjectConfig(project, cfg);
+ projectCache.evict(cfg.getProject());
+ }
+
+ private void saveProjectConfig(Project.NameKey p, ProjectConfig cfg) throws IOException {
+ MetaDataUpdate md = metaDataUpdateFactory.create(p);
+ try {
+ cfg.commit(md);
+ } finally {
+ md.close();
+ }
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java
index b037ff9..10d59d2d 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java
@@ -21,10 +21,10 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.acceptance.SshSession;
+import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectJson.ProjectInfo;
import com.google.inject.Inject;
import com.jcraft.jsch.JSchException;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetCommitIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetCommitIT.java
new file mode 100644
index 0000000..2aacf20
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetCommitIT.java
@@ -0,0 +1,111 @@
+// 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.acceptance.rest.project;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.extensions.common.CommitInfo;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.project.ListBranches.BranchInfo;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.inject.Inject;
+
+import org.apache.http.HttpStatus;
+import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class GetCommitIT extends AbstractDaemonTest {
+
+ @Inject
+ private ProjectCache projectCache;
+
+ @Inject
+ private AllProjectsName allProjects;
+
+ @Inject
+ private MetaDataUpdate.Server metaDataUpdateFactory;
+
+ @Test
+ public void getCommit() throws IOException {
+ RestResponse r =
+ adminSession.get("/projects/" + project.get() + "/branches/"
+ + IdString.fromDecoded(RefNames.REFS_CONFIG).encoded());
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ BranchInfo branchInfo =
+ newGson().fromJson(r.getReader(), BranchInfo.class);
+ r.consume();
+
+ r = adminSession.get("/projects/" + project.get() + "/commits/"
+ + branchInfo.revision);
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ CommitInfo commitInfo =
+ newGson().fromJson(r.getReader(), CommitInfo.class);
+ assertEquals(branchInfo.revision, commitInfo.commit);
+ assertEquals("Created project", commitInfo.subject);
+ assertEquals("Created project\n", commitInfo.message);
+ assertNotNull(commitInfo.author);
+ assertEquals("Administrator", commitInfo.author.name);
+ assertNotNull(commitInfo.committer);
+ assertEquals("Gerrit Code Review", commitInfo.committer.name);
+ assertTrue(commitInfo.parents.isEmpty());
+ }
+
+ @Test
+ public void getNonExistingCommit_NotFound() throws IOException {
+ RestResponse r = adminSession.get("/projects/" + project.get() + "/commits/"
+ + ObjectId.zeroId().name());
+ assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode());
+ }
+
+ @Test
+ public void getNonVisibleCommit_NotFound() throws IOException {
+ RestResponse r =
+ adminSession.get("/projects/" + project.get() + "/branches/"
+ + IdString.fromDecoded(RefNames.REFS_CONFIG).encoded());
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ BranchInfo branchInfo =
+ newGson().fromJson(r.getReader(), BranchInfo.class);
+ r.consume();
+
+ ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ cfg.getAccessSection("refs/*", false).removePermission(Permission.READ);
+ saveProjectConfig(cfg);
+ projectCache.evict(cfg.getProject());
+
+ r = adminSession.get("/projects/" + project.get() + "/commits/"
+ + branchInfo.revision);
+ assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode());
+ }
+
+ private void saveProjectConfig(ProjectConfig cfg) throws IOException {
+ MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
+ try {
+ cfg.commit(md);
+ } finally {
+ md.close();
+ }
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java
index 52bb623..e6fde73 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java
@@ -16,19 +16,18 @@
import static com.google.gerrit.acceptance.GitUtil.createProject;
import static com.google.gerrit.acceptance.rest.project.BranchAssert.assertBranches;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+import static com.google.gerrit.server.project.Util.block;
import static org.junit.Assert.assertEquals;
import com.google.common.collect.Lists;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission;
-import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.project.ListBranches.BranchInfo;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gson.reflect.TypeToken;
@@ -142,17 +141,10 @@
private void blockRead(Project.NameKey project, String ref)
throws RepositoryNotFoundException, IOException, ConfigInvalidException {
- MetaDataUpdate md = metaDataUpdateFactory.create(project);
- md.setMessage("Grant submit on " + ref);
- ProjectConfig config = ProjectConfig.read(md);
- AccessSection s = config.getAccessSection(ref, true);
- Permission p = s.getPermission(Permission.READ, true);
- PermissionRule rule = new PermissionRule(config.resolve(
- SystemGroupBackend.getGroup(SystemGroupBackend.REGISTERED_USERS)));
- rule.setBlock();
- p.add(rule);
- config.commit(md);
- projectCache.evict(config.getProject());
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ block(cfg, Permission.READ, REGISTERED_USERS, ref);
+ saveProjectConfig(project, cfg);
+ projectCache.evict(cfg.getProject());
}
private static List<BranchInfo> toBranchInfoList(RestResponse r)
@@ -168,4 +160,13 @@
PushOneCommit push = pushFactory.create(db, admin.getIdent());
return push.to(git, ref);
}
+
+ private void saveProjectConfig(Project.NameKey p, ProjectConfig cfg) throws IOException {
+ MetaDataUpdate md = metaDataUpdateFactory.create(p);
+ try {
+ cfg.commit(md);
+ } finally {
+ md.close();
+ }
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
index c61764b..466a239 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
@@ -21,9 +21,9 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllProjectsName;
-import com.google.gerrit.server.project.ProjectJson.ProjectInfo;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
@@ -53,7 +53,7 @@
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
List<ProjectInfo> projectInfoList = toProjectInfoList(r);
// Project 'p' was already created in the base class
- assertTrue(projectInfoList.size() == 1);
+ assertTrue(projectInfoList.size() == 2);
}
@Test
@@ -67,7 +67,11 @@
RestResponse r = GET("/projects/" + allProjects.get() + "/children/");
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
- assertProjects(Arrays.asList(existingProject, child1, child2), toProjectInfoList(r));
+ assertProjects(
+ Arrays.asList(
+ new Project.NameKey("All-Users"),
+ existingProject, child1, child2),
+ toProjectInfoList(r));
}
@Test
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java
new file mode 100644
index 0000000..923d752
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java
@@ -0,0 +1,236 @@
+// 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.acceptance.rest.project;
+
+import static com.google.gerrit.acceptance.GitUtil.createProject;
+import static com.google.gerrit.acceptance.rest.project.ProjectAssert.assertProjects;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
+import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gson.reflect.TypeToken;
+import com.google.inject.Inject;
+
+import com.jcraft.jsch.JSchException;
+
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+
+public class ListProjectsIT extends AbstractDaemonTest {
+
+ @Inject
+ private AllProjectsName allProjects;
+
+ @Inject
+ private AllUsersName allUsers;
+
+ @Test
+ public void listProjects() throws IOException, JSchException {
+ Project.NameKey someProject = new Project.NameKey("some-project");
+ createProject(sshSession, someProject.get());
+
+ RestResponse r = GET("/projects/");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ Map<String, ProjectInfo> result = toProjectInfoMap(r);
+ assertProjects(Arrays.asList(allUsers, someProject, project),
+ result.values());
+ }
+
+ @Test
+ public void listProjectsWithBranch() throws IOException, JSchException {
+ RestResponse r = GET("/projects/?b=master");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ Map<String, ProjectInfo> result = toProjectInfoMap(r);
+ assertNotNull(result.get(project.get()));
+ assertNotNull(result.get(project.get()).branches);
+ assertEquals(1, result.get(project.get()).branches.size());
+ assertNotNull(result.get(project.get()).branches.get("master"));
+ }
+
+ @Test
+ public void listProjectWithDescription() throws RestApiException, IOException {
+ ProjectInput projectInput = new ProjectInput();
+ projectInput.name = "some-project";
+ projectInput.description = "Description of some-project";
+ gApi.projects().name(projectInput.name).create(projectInput);
+
+ // description not be included in the results by default.
+ RestResponse r = GET("/projects/");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ Map<String, ProjectInfo> result = toProjectInfoMap(r);
+ assertNotNull(result.get(projectInput.name));
+ assertNull(result.get(projectInput.name).description);
+
+ r = GET("/projects/?d");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ result = toProjectInfoMap(r);
+ assertNotNull(result.get(projectInput.name));
+ assertEquals(projectInput.description,
+ result.get(projectInput.name).description);
+ }
+
+ @Test
+ public void listProjectsWithLimit() throws IOException, JSchException {
+ for (int i = 0; i < 5; i++) {
+ createProject(sshSession, new Project.NameKey("someProject" + i).get());
+ }
+
+ RestResponse r = GET("/projects/");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ Map<String, ProjectInfo> result = toProjectInfoMap(r);
+ assertEquals(7, result.size()); // 5 plus 2 existing projects: p and
+ // All-Users
+
+ r = GET("/projects/?n=2");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ result = toProjectInfoMap(r);
+ assertEquals(2, result.size());
+ }
+
+ @Test
+ public void listProjectsWithPrefix() throws IOException, JSchException {
+ Project.NameKey someProject = new Project.NameKey("some-project");
+ createProject(sshSession, someProject.get());
+ Project.NameKey someOtherProject =
+ new Project.NameKey("some-other-project");
+ createProject(sshSession, someOtherProject.get());
+ Project.NameKey projectAwesome = new Project.NameKey("project-awesome");
+ createProject(sshSession, projectAwesome.get());
+
+ RestResponse r = GET("/projects/?p=some");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ Map<String, ProjectInfo> result = toProjectInfoMap(r);
+ assertProjects(Arrays.asList(someProject, someOtherProject),
+ result.values());
+ }
+
+ @Test
+ public void listProjectsWithRegex() throws IOException, JSchException {
+ Project.NameKey someProject = new Project.NameKey("some-project");
+ createProject(sshSession, someProject.get());
+ Project.NameKey someOtherProject =
+ new Project.NameKey("some-other-project");
+ createProject(sshSession, someOtherProject.get());
+ Project.NameKey projectAwesome = new Project.NameKey("project-awesome");
+ createProject(sshSession, projectAwesome.get());
+
+ RestResponse r = GET("/projects/?r=.*some");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ Map<String, ProjectInfo> result = toProjectInfoMap(r);
+ assertProjects(Arrays.asList(projectAwesome), result.values());
+
+ r = GET("/projects/?r=[.*some");
+ assertEquals(HttpStatus.SC_BAD_REQUEST, r.getStatusCode());
+
+ r = GET("/projects/?r=.*");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ result = toProjectInfoMap(r);
+ assertProjects(Arrays.asList(someProject, someOtherProject, projectAwesome,
+ project, allUsers), result.values());
+ }
+
+ @Test
+ public void listProjectsWithSkip() throws IOException, JSchException {
+ for (int i = 0; i < 5; i++) {
+ createProject(sshSession, new Project.NameKey("someProject" + i).get());
+ }
+
+ RestResponse r = GET("/projects/");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ Map<String, ProjectInfo> result = toProjectInfoMap(r);
+ assertEquals(7, result.size()); // 5 plus 2 existing projects: p and
+ // All-Users
+
+ r = GET("/projects/?S=6");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ result = toProjectInfoMap(r);
+ assertEquals(1, result.size());
+ }
+
+ @Test
+ public void listProjectsWithSubstring() throws IOException, JSchException {
+ Project.NameKey someProject = new Project.NameKey("some-project");
+ createProject(sshSession, someProject.get());
+ Project.NameKey someOtherProject =
+ new Project.NameKey("some-other-project");
+ createProject(sshSession, someOtherProject.get());
+ Project.NameKey projectAwesome = new Project.NameKey("project-awesome");
+ createProject(sshSession, projectAwesome.get());
+
+ RestResponse r = GET("/projects/?m=some");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ Map<String, ProjectInfo> result = toProjectInfoMap(r);
+ assertProjects(
+ Arrays.asList(someProject, someOtherProject, projectAwesome),
+ result.values());
+ }
+
+ @Test
+ public void listProjectsWithTree() throws IOException, JSchException {
+ Project.NameKey someParentProject =
+ new Project.NameKey("some-parent-project");
+ createProject(sshSession, someParentProject.get());
+ Project.NameKey someChildProject =
+ new Project.NameKey("some-child-project");
+ createProject(sshSession, someChildProject.get(), someParentProject);
+
+ RestResponse r = GET("/projects/?tree");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ Map<String, ProjectInfo> result = toProjectInfoMap(r);
+ assertNotNull(result.get(someChildProject.get()));
+ assertEquals(someParentProject.get(),
+ result.get(someChildProject.get()).parent);
+ }
+
+ @Test
+ public void listProjectWithType() throws RestApiException, IOException {
+ RestResponse r = GET("/projects/?type=PERMISSIONS");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ Map<String, ProjectInfo> result = toProjectInfoMap(r);
+ assertEquals(1, result.size());
+ assertNotNull(result.get(allProjects.get()));
+
+ r = GET("/projects/?type=ALL");
+ assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+ result = toProjectInfoMap(r);
+ assertEquals(3, result.size());
+ assertProjects(Arrays.asList(allProjects, allUsers, project),
+ result.values());
+ }
+
+ private static Map<String, ProjectInfo> toProjectInfoMap(RestResponse r)
+ throws IOException {
+ Map<String, ProjectInfo> result =
+ newGson().fromJson(r.getReader(),
+ new TypeToken<Map<String, ProjectInfo>>() {}.getType());
+ return result;
+ }
+
+ private RestResponse GET(String endpoint) throws IOException {
+ return adminSession.get(endpoint);
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectAssert.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectAssert.java
index 788a54b..3354cb8 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectAssert.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectAssert.java
@@ -21,24 +21,26 @@
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
+import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.project.ProjectJson.ProjectInfo;
import com.google.gerrit.server.project.ProjectState;
-import java.util.List;
+import java.util.Collection;
import java.util.Set;
public class ProjectAssert {
public static void assertProjects(Iterable<Project.NameKey> expected,
- List<ProjectInfo> actual) {
+ Collection<ProjectInfo> actual) {
for (final Project.NameKey p : expected) {
ProjectInfo info = Iterables.find(actual, new Predicate<ProjectInfo>() {
@Override
public boolean apply(ProjectInfo info) {
- return new Project.NameKey(info.name).equals(p);
+ // 'name' is not set if returned in a map, use the id instead.
+ return new Project.NameKey(info.name != null ? info.name : Url
+ .decode(info.id)).equals(p);
}}, null);
assertNotNull("missing project: " + p, info);
actual.remove(info);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/BUCK
index 688e649..fce853b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/BUCK
@@ -2,7 +2,5 @@
acceptance_tests(
srcs = glob(['*IT.java']),
- deps = [
- '//gerrit-acceptance-tests:lib',
- ],
+ labels = ['server'],
)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/BUCK
index 688e649..fce853b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/BUCK
@@ -2,7 +2,5 @@
acceptance_tests(
srcs = glob(['*IT.java']),
- deps = [
- '//gerrit-acceptance-tests:lib',
- ],
+ labels = ['server'],
)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java
index f38ac89..2a20a2c 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java
@@ -15,8 +15,8 @@
package com.google.gerrit.acceptance.server.project;
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
+import static com.google.gerrit.server.project.Util.allow;
import static com.google.gerrit.server.project.Util.category;
-import static com.google.gerrit.server.project.Util.grant;
import static com.google.gerrit.server.project.Util.value;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -64,7 +64,7 @@
ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
AccountGroup.UUID anonymousUsers =
SystemGroupBackend.getGroup(ANONYMOUS_USERS).getUUID();
- grant(cfg, Permission.forLabel(Q.getName()), -1, 1, anonymousUsers,
+ allow(cfg, Permission.forLabel(Q.getName()), -1, 1, anonymousUsers,
"refs/heads/*");
saveProjectConfig(cfg);
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
index 6506040..bc311fd 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
@@ -30,14 +30,23 @@
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.testutil.ConfigSuite;
import com.google.inject.Inject;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Repository;
import org.junit.Before;
import org.junit.Test;
@NoHttpd
public class LabelTypeIT extends AbstractDaemonTest {
+ @ConfigSuite.Config
+ public static Config noteDbEnabled() {
+ Config cfg = new Config();
+ cfg.setBoolean("notedb", null, "write", true);
+ cfg.setBoolean("notedb", "patchSetApprovals", "read", true);
+ return cfg;
+ }
@Inject
private GitRepositoryManager repoManager;
@@ -61,6 +70,7 @@
codeReview.setCopyMaxScore(false);
codeReview.setCopyAllScoresOnTrivialRebase(false);
codeReview.setCopyAllScoresIfNoCodeChange(false);
+ codeReview.setDefaultValue((short)-1);
saveProjectConfig(cfg);
}
@@ -79,7 +89,7 @@
saveLabelConfig();
PushOneCommit.Result r = createChange();
revision(r).review(ReviewInput.reject());
- assertApproval(r, -2);
+ //assertApproval(r, -2);
r = amendChange(r.getChangeId());
assertApproval(r, -2);
}
@@ -317,6 +327,7 @@
private void doAssertApproval(int expected, ChangeInfo c) {
LabelInfo cr = c.labels.get("Code-Review");
+ assertEquals(-1, (int) cr.defaultValue);
assertEquals(1, cr.all.size());
assertEquals("Administrator", cr.all.get(0).name);
assertEquals(expected, cr.all.get(0).value.intValue());
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK
index aa9703c..74b26ba6 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK
@@ -3,4 +3,5 @@
acceptance_tests(
srcs = glob(['*IT.java']),
deps = ['//gerrit-acceptance-tests:lib'],
+ labels = ['ssh'],
)
diff --git a/gerrit-acceptance-tests/tests.defs b/gerrit-acceptance-tests/tests.defs
index 0131887..7bd2430 100644
--- a/gerrit-acceptance-tests/tests.defs
+++ b/gerrit-acceptance-tests/tests.defs
@@ -1,4 +1,4 @@
-# these need as workaround for the 'verify: false' bug in Jcraft SSH library
+# These are needed as workaround for the 'verify: false' bug in Jcraft SSH library
BOUNCYCASTLE = [
'//lib/bouncycastle:bcpkix',
'//lib/bouncycastle:bcpg',
@@ -7,6 +7,8 @@
def acceptance_tests(
srcs,
deps = [],
+ labels = [],
+ source_under_test = [],
vm_args = ['-Xmx256m']):
from os import environ, path
if not environ.get('NO_BOUNCYCASTLE'):
@@ -23,8 +25,8 @@
'//gerrit-httpd:httpd',
'//gerrit-sshd:sshd',
'//gerrit-server:server',
- ],
- labels = [
+ ] + source_under_test,
+ labels = labels + [
'acceptance',
'slow',
],
diff --git a/gerrit-antlr/BUCK b/gerrit-antlr/BUCK
index 57e7e1d..03c3c1e 100644
--- a/gerrit-antlr/BUCK
+++ b/gerrit-antlr/BUCK
@@ -17,8 +17,8 @@
java_library(
name = 'lib',
- srcs = [genfile('query_antlr.src.zip')],
- deps = PARSER_DEPS + [':query_antlr'],
+ srcs = [':query_antlr'],
+ deps = PARSER_DEPS,
)
# Hack necessary to expose ANTLR generated code as JAR to Eclipse.
@@ -28,9 +28,10 @@
deps = [':lib'],
out = 'query_parser.jar',
)
+
prebuilt_jar(
name = 'query_parser',
- binary_jar = genfile('query_parser.jar'),
- deps = PARSER_DEPS + [':query_link'],
+ binary_jar = ':query_link',
+ deps = PARSER_DEPS,
visibility = ['PUBLIC'],
)
diff --git a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
index 85a051b..65bb034 100644
--- a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
+++ b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
@@ -14,20 +14,22 @@
package com.google.gerrit.server.cache.h2;
-import com.google.common.base.Preconditions;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.server.cache.CacheBinding;
import com.google.gerrit.server.cache.PersistentCacheFactory;
import com.google.gerrit.server.cache.h2.H2CacheImpl.SqlStore;
import com.google.gerrit.server.cache.h2.H2CacheImpl.ValueHolder;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.plugins.Plugin;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
@@ -37,6 +39,7 @@
import java.io.File;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -48,17 +51,18 @@
private final DefaultCacheFactory defaultFactory;
private final Config config;
- private final File cacheDir;
+ private final File cacheDir;
private final List<H2CacheImpl<?, ?>> caches;
+ private final DynamicMap<Cache<?, ?>> cacheMap;
private final ExecutorService executor;
private final ScheduledExecutorService cleanup;
- private volatile boolean started;
@Inject
H2CacheFactory(
DefaultCacheFactory defaultCacheFactory,
@GerritServerConfig Config cfg,
- SitePaths site) {
+ SitePaths site,
+ DynamicMap<Cache<?, ?>> cacheMap) {
defaultFactory = defaultCacheFactory;
config = cfg;
@@ -79,6 +83,7 @@
}
caches = Lists.newLinkedList();
+ this.cacheMap = cacheMap;
if (cacheDir != null) {
executor = Executors.newFixedThreadPool(
@@ -100,7 +105,6 @@
@Override
public void start() {
- started = true;
if (executor != null) {
for (final H2CacheImpl<?, ?> cache : caches) {
executor.execute(new Runnable() {
@@ -141,26 +145,30 @@
log.warn("Interrupted waiting for disk cache to shutdown");
}
}
- for (H2CacheImpl<?, ?> cache : caches) {
- cache.stop();
+ synchronized (caches) {
+ for (H2CacheImpl<?, ?> cache : caches) {
+ cache.stop();
+ }
}
}
@SuppressWarnings({"unchecked", "cast"})
@Override
public <K, V> Cache<K, V> build(CacheBinding<K, V> def) {
- Preconditions.checkState(!started, "cache must be built before start");
long limit = config.getLong("cache", def.name(), "diskLimit", 128 << 20);
if (cacheDir == null || limit <= 0) {
return defaultFactory.build(def);
}
- SqlStore<K, V> store = newSqlStore(def.name(), def.keyType(), limit);
+ SqlStore<K, V> store = newSqlStore(def.name(), def.keyType(), limit,
+ def.expireAfterWrite(TimeUnit.SECONDS));
H2CacheImpl<K, V> cache = new H2CacheImpl<K, V>(
executor, store, def.keyType(),
(Cache<K, ValueHolder<V>>) defaultFactory.create(def, true).build());
- caches.add(cache);
+ synchronized (caches) {
+ caches.add(cache);
+ }
return cache;
}
@@ -169,14 +177,14 @@
public <K, V> LoadingCache<K, V> build(
CacheBinding<K, V> def,
CacheLoader<K, V> loader) {
- Preconditions.checkState(!started, "cache must be built before start");
long limit = config.getLong("cache", def.name(), "diskLimit", 128 << 20);
if (cacheDir == null || limit <= 0) {
return defaultFactory.build(def, loader);
}
- SqlStore<K, V> store = newSqlStore(def.name(), def.keyType(), limit);
+ SqlStore<K, V> store = newSqlStore(def.name(), def.keyType(), limit,
+ def.expireAfterWrite(TimeUnit.SECONDS));
Cache<K, ValueHolder<V>> mem = (Cache<K, ValueHolder<V>>)
defaultFactory.create(def, true)
.build((CacheLoader<K, V>) new H2CacheImpl.Loader<K, V>(
@@ -187,12 +195,27 @@
return cache;
}
+ @Override
+ public void onStop(Plugin plugin) {
+ synchronized (caches) {
+ for (Map.Entry<String, Provider<Cache<?, ?>>> entry :
+ cacheMap.byPlugin(plugin.getName()).entrySet()) {
+ Cache<?, ?> cache = entry.getValue().get();
+ if (caches.remove(cache)) {
+ ((H2CacheImpl<?, ?>) cache).stop();
+ }
+ }
+ }
+ }
+
private <V, K> SqlStore<K, V> newSqlStore(
String name,
TypeLiteral<K> keyType,
- long maxSize) {
+ long maxSize,
+ Long expireAfterWrite) {
File db = new File(cacheDir, name).getAbsoluteFile();
String url = "jdbc:h2:" + db.toURI().toString();
- return new SqlStore<K, V>(url, keyType, maxSize);
+ return new SqlStore<>(url, keyType, maxSize,
+ expireAfterWrite == null ? 0 : expireAfterWrite.longValue());
}
}
diff --git a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
index 4aca42b..5563988 100644
--- a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
+++ b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
@@ -11,6 +11,7 @@
import com.google.common.hash.Funnel;
import com.google.common.hash.Funnels;
import com.google.common.hash.PrimitiveSink;
+import com.google.gerrit.server.cache.PersistentCache;
import com.google.gerrit.server.util.TimeUtil;
import com.google.inject.TypeLiteral;
@@ -63,7 +64,8 @@
*
* @see H2CacheFactory
*/
-public class H2CacheImpl<K, V> extends AbstractLoadingCache<K, V> {
+public class H2CacheImpl<K, V> extends AbstractLoadingCache<K, V> implements
+ PersistentCache {
private static final Logger log = LoggerFactory.getLogger(H2CacheImpl.class);
private final Executor executor;
@@ -115,7 +117,7 @@
@Override
public void put(final K key, V val) {
- final ValueHolder<V> h = new ValueHolder<V>(val);
+ final ValueHolder<V> h = new ValueHolder<>(val);
h.created = TimeUtil.nowMs();
mem.put(key, h);
executor.execute(new Runnable() {
@@ -156,6 +158,7 @@
return mem.stats();
}
+ @Override
public DiskStats diskStats() {
return store.diskStats();
}
@@ -193,29 +196,6 @@
}, delay, TimeUnit.MILLISECONDS);
}
- public static class DiskStats {
- long size;
- long space;
- long hitCount;
- long missCount;
-
- public long size() {
- return size;
- }
-
- public long space() {
- return space;
- }
-
- public long hitCount() {
- return hitCount;
- }
-
- public long requestCount() {
- return hitCount + missCount;
- }
- }
-
static class ValueHolder<V> {
final V value;
long created;
@@ -246,7 +226,7 @@
}
}
- final ValueHolder<V> h = new ValueHolder<V>(loader.load(key));
+ final ValueHolder<V> h = new ValueHolder<>(loader.load(key));
h.created = TimeUtil.nowMs();
executor.execute(new Runnable() {
@Override
@@ -302,7 +282,7 @@
return (KeyType<K>) OTHER;
}
- static final KeyType<?> OTHER = new KeyType<Object>();
+ static final KeyType<?> OTHER = new KeyType<>();
static final KeyType<String> STRING = new KeyType<String>() {
@Override
String columnType() {
@@ -333,20 +313,23 @@
private final String url;
private final KeyType<K> keyType;
private final long maxSize;
+ private final long expireAfterWrite;
private final BlockingQueue<SqlHandle> handles;
private final AtomicLong hitCount = new AtomicLong();
private final AtomicLong missCount = new AtomicLong();
private volatile BloomFilter<K> bloomFilter;
private int estimatedSize;
- SqlStore(String jdbcUrl, TypeLiteral<K> keyType, long maxSize) {
+ SqlStore(String jdbcUrl, TypeLiteral<K> keyType, long maxSize,
+ long expireAfterWrite) {
this.url = jdbcUrl;
this.keyType = KeyType.create(keyType);
this.maxSize = maxSize;
+ this.expireAfterWrite = expireAfterWrite;
int cores = Runtime.getRuntime().availableProcessors();
int keep = Math.min(cores, 16);
- this.handles = new ArrayBlockingQueue<SqlHandle>(keep);
+ this.handles = new ArrayBlockingQueue<>(keep);
}
synchronized void open() {
@@ -428,7 +411,7 @@
try {
c = acquire();
if (c.get == null) {
- c.get = c.conn.prepareStatement("SELECT v FROM data WHERE k=?");
+ c.get = c.conn.prepareStatement("SELECT v, created FROM data WHERE k=?");
}
keyType.set(c.get, 1, key);
ResultSet r = c.get.executeQuery();
@@ -438,9 +421,16 @@
return null;
}
+ Timestamp created = r.getTimestamp(2);
+ if (expired(created)) {
+ invalidate(key);
+ missCount.incrementAndGet();
+ return null;
+ }
+
@SuppressWarnings("unchecked")
V val = (V) r.getObject(1);
- ValueHolder<V> h = new ValueHolder<V>(val);
+ ValueHolder<V> h = new ValueHolder<>(val);
h.clean = true;
hitCount.incrementAndGet();
touch(c, key);
@@ -458,6 +448,14 @@
}
}
+ private boolean expired(Timestamp created) {
+ if (expireAfterWrite == 0) {
+ return false;
+ }
+ long age = TimeUtil.nowMs() - created.getTime();
+ return 1000 * expireAfterWrite < age;
+ }
+
private void touch(SqlHandle c, K key) throws SQLException {
if (c.touch == null) {
c.touch =c.conn.prepareStatement("UPDATE data SET accessed=? WHERE k=?");
@@ -572,12 +570,14 @@
r = s.executeQuery("SELECT"
+ " k"
+ ",OCTET_LENGTH(k) + OCTET_LENGTH(v)"
+ + ",created"
+ " FROM data"
+ " ORDER BY accessed");
try {
while (maxSize < used && r.next()) {
K key = keyType.get(r, 1);
- if (mem.getIfPresent(key) != null) {
+ Timestamp created = r.getTimestamp(3);
+ if (mem.getIfPresent(key) != null && !expired(created)) {
touch(c, key);
} else {
invalidate(c, key);
@@ -599,9 +599,8 @@
}
DiskStats diskStats() {
- DiskStats d = new DiskStats();
- d.hitCount = hitCount.get();
- d.missCount = missCount.get();
+ long size = 0;
+ long space = 0;
SqlHandle c = null;
try {
c = acquire();
@@ -613,8 +612,8 @@
+ " FROM data");
try {
if (r.next()) {
- d.size = r.getLong(1);
- d.space = r.getLong(2);
+ size = r.getLong(1);
+ space = r.getLong(2);
}
} finally {
r.close();
@@ -628,7 +627,7 @@
} finally {
release(c);
}
- return d;
+ return new DiskStats(size, space, hitCount.get(), missCount.get());
}
private SqlHandle acquire() throws SQLException {
diff --git a/gerrit-common/BUCK b/gerrit-common/BUCK
index 9ed1624..3ba22c5 100644
--- a/gerrit-common/BUCK
+++ b/gerrit-common/BUCK
@@ -6,6 +6,11 @@
SRC + 'common/auth/SignInRequired.java',
]
+EXCLUDES = [
+ SRC + 'common/PluginData.java',
+ SRC + 'common/FileUtil.java',
+]
+
java_library(
name = 'annotations',
srcs = ANNOTATIONS,
@@ -14,15 +19,14 @@
gwt_module(
name = 'client',
- srcs = glob([SRC + 'common/**/*.java']),
- gwtxml = SRC + 'Common.gwt.xml',
+ srcs = glob([SRC + 'common/**/*.java'], excludes = EXCLUDES),
+ gwt_xml = SRC + 'Common.gwt.xml',
deps = [
+ ':annotations',
+ '//gerrit-extension-api:client',
'//gerrit-patch-jgit:client',
'//gerrit-prettify:client',
'//gerrit-reviewdb:client',
- ],
- compile_deps = [
- ':annotations',
'//lib:gwtjsonrpc',
'//lib:gwtorm',
'//lib/jgit:jgit',
@@ -35,11 +39,13 @@
srcs = glob([SRC + 'common/**/*.java'], excludes = ANNOTATIONS),
deps = [
':annotations',
+ '//gerrit-extension-api:api',
'//gerrit-patch-jgit:server',
'//gerrit-prettify:server',
'//gerrit-reviewdb:server',
'//lib:gwtjsonrpc',
'//lib:gwtorm',
+ '//lib:guava',
'//lib/jgit:jgit',
],
visibility = ['PUBLIC'],
@@ -50,6 +56,7 @@
srcs = glob(['src/test/java/**/*.java']),
deps = [
':client',
+ '//lib:guava',
'//lib:junit',
],
source_under_test = [':client'],
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/Die.java b/gerrit-common/src/main/java/com/google/gerrit/common/Die.java
similarity index 95%
rename from gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/Die.java
rename to gerrit-common/src/main/java/com/google/gerrit/common/Die.java
index 96e2ec8..6a1f304 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/Die.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/Die.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.pgm.util;
+package com.google.gerrit.common;
public class Die extends RuntimeException {
private static final long serialVersionUID = 1L;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/FileUtil.java b/gerrit-common/src/main/java/com/google/gerrit/common/FileUtil.java
new file mode 100644
index 0000000..bed10d6
--- /dev/null
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/FileUtil.java
@@ -0,0 +1,66 @@
+// 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.common;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.IO;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+
+public class FileUtil {
+ public static boolean modified(FileBasedConfig cfg) throws IOException {
+ byte[] curVers;
+ try {
+ curVers = IO.readFully(cfg.getFile());
+ } catch (FileNotFoundException notFound) {
+ return true;
+ }
+
+ byte[] newVers = Constants.encode(cfg.toText());
+ return !Arrays.equals(curVers, newVers);
+ }
+
+ public static void mkdir(final File path) {
+ if (!path.isDirectory() && !path.mkdir()) {
+ throw new Die("Cannot make directory " + path);
+ }
+ }
+
+ public static void chmod(final int mode, final File path) {
+ path.setReadable(false, false /* all */);
+ path.setWritable(false, false /* all */);
+ path.setExecutable(false, false /* all */);
+
+ path.setReadable((mode & 0400) == 0400, true /* owner only */);
+ path.setWritable((mode & 0200) == 0200, true /* owner only */);
+ if (path.isDirectory() || (mode & 0100) == 0100) {
+ path.setExecutable(true, true /* owner only */);
+ }
+
+ if ((mode & 0044) == 0044) {
+ path.setReadable(true, false /* all */);
+ }
+ if ((mode & 0011) == 0011) {
+ path.setExecutable(true, false /* all */);
+ }
+ }
+
+ private FileUtil() {
+ }
+}
\ No newline at end of file
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java b/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java
index e4199c2..c0382da 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java
@@ -44,6 +44,7 @@
public static final String ADMIN_PROJECTS = "/admin/projects/";
public static final String ADMIN_CREATE_PROJECT = "/admin/create-project/";
public static final String ADMIN_PLUGINS = "/admin/plugins/";
+ public static final String MY_GROUPS = "/groups/self";
public static String toChange(final ChangeInfo c) {
return toChange(c.getId());
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
new file mode 100644
index 0000000..fc5bb56
--- /dev/null
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java
@@ -0,0 +1,46 @@
+// 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.common;
+
+package com.google.gerrit.common;
+
+import com.google.common.base.Objects;
+
+import java.io.File;
+
+public class PluginData {
+ public final String name;
+ public final String version;
+ public final File pluginFile;
+
+ public PluginData(String name, String version, File pluginFile) {
+ this.name = name;
+ this.version = version;
+ this.pluginFile = pluginFile;
+ }
+
+ @Override
+ 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 super.equals(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name, version, pluginFile);
+ }
+}
\ No newline at end of file
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdUrls.java b/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdUrls.java
index 706f465..79c17f4 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdUrls.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdUrls.java
@@ -18,7 +18,6 @@
public static final String OPENID_IDENTIFIER = "openid_identifier";
public static final String LASTID_COOKIE = "gerrit.last_openid";
+ public static final String URL_LAUNCHPAD = "https://login.launchpad.net/+openid";
public static final String URL_YAHOO = "https://me.yahoo.com";
- public static final String URL_GOOGLE =
- "https://www.google.com/accounts/o8/id";
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfo.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfo.java
index 6b8c075..8614be5 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfo.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfo.java
@@ -21,6 +21,7 @@
protected Account.Id id;
protected String fullName;
protected String preferredEmail;
+ protected String username;
protected AccountInfo() {
}
@@ -45,6 +46,7 @@
id = a.getId();
fullName = a.getFullName();
preferredEmail = a.getPreferredEmail();
+ username = a.getUserName();
}
/** @return the unique local id of the account */
@@ -70,6 +72,11 @@
preferredEmail = email;
}
+ /** @return the username of the account holder */
+ public String getUsername() {
+ return username;
+ }
+
/**
* Formats an account name.
* <p>
@@ -87,7 +94,7 @@
}
/**
- * Formats an account as an name and an email address.
+ * Formats an account as a name and an email address.
* <p>
* Example output:
* <ul>
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetail.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetail.java
index 3342bc2..e067f06 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetail.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetail.java
@@ -14,10 +14,10 @@
package com.google.gerrit.common.data;
+import com.google.gerrit.extensions.common.SubmitType;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.ChangeMessage;
import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.client.Project;
import java.util.List;
import java.util.Set;
@@ -41,7 +41,7 @@
protected List<PatchSet> patchSets;
protected Set<PatchSet.Id> patchSetsWithDraftComments;
protected List<SubmitRecord> submitRecords;
- protected Project.SubmitType submitType;
+ protected SubmitType submitType;
protected SubmitTypeRecord submitTypeRecord;
protected boolean canSubmit;
protected List<ChangeMessage> messages;
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 38afaab..66309ea 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
@@ -22,6 +22,7 @@
import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gerrit.reviewdb.client.Project;
+import java.util.List;
import java.util.Set;
public class GerritConfig implements Cloneable {
@@ -33,7 +34,7 @@
protected String httpPasswordUrl;
protected String reportBugUrl;
protected String reportBugText;
- protected boolean gitBasicAuth;
+ protected boolean httpPasswordSettingsEnabled = true;
protected GitwebConfig gitweb;
protected boolean useContributorAgreements;
@@ -53,6 +54,7 @@
protected int suggestFrom;
protected int changeUpdateDelay;
protected AccountGeneralPreferences.ChangeScreen changeScreen;
+ protected List<String> archiveFormats;
protected int largeChangeSize;
protected boolean newFeatures;
@@ -112,12 +114,12 @@
reportBugText = t;
}
- public boolean isGitBasicAuth() {
- return gitBasicAuth;
+ public boolean isHttpPasswordSettingsEnabled() {
+ return httpPasswordSettingsEnabled;
}
- public void setGitBasicAuth(boolean gba) {
- gitBasicAuth = gba;
+ public void setHttpPasswordSettingsEnabled(boolean httpPasswordSettingsEnabled) {
+ this.httpPasswordSettingsEnabled = httpPasswordSettingsEnabled;
}
public String getEditFullNameUrl() {
@@ -291,6 +293,14 @@
this.largeChangeSize = largeChangeSize;
}
+ public List<String> getArchiveFormats() {
+ return archiveFormats;
+ }
+
+ public void setArchiveFormats(List<String> formats) {
+ archiveFormats = formats;
+ }
+
public boolean getNewFeatures() {
return newFeatures;
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelType.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelType.java
index c596c1e..5018df9 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelType.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelType.java
@@ -60,20 +60,6 @@
return name;
}
- public static String defaultAbbreviation(String name) {
- StringBuilder abbr = new StringBuilder();
- for (int i = 0; i < name.length(); i++) {
- char c = name.charAt(i);
- if (c >= 'A' && c <= 'Z') {
- abbr.append(c);
- }
- }
- if (abbr.length() == 0) {
- abbr.append(Character.toUpperCase(name.charAt(0)));
- }
- return abbr.toString();
- }
-
private static List<LabelValue> sortValues(List<LabelValue> values) {
values = new ArrayList<>(values);
if (values.size() <= 1) {
@@ -102,12 +88,12 @@
protected String name;
- protected String abbreviation;
protected String functionName;
protected boolean copyMinScore;
protected boolean copyMaxScore;
protected boolean copyAllScoresOnTrivialRebase;
protected boolean copyAllScoresIfNoCodeChange;
+ protected short defaultValue;
protected List<LabelValue> values;
protected short maxNegative;
@@ -125,8 +111,8 @@
this.name = checkName(name);
canOverride = true;
values = sortValues(valueList);
+ defaultValue = 0;
- abbreviation = defaultAbbreviation(name);
functionName = "MaxWithBlock";
maxNegative = Short.MIN_VALUE;
@@ -149,14 +135,6 @@
return psa.getLabelId().get().equalsIgnoreCase(name);
}
- public String getAbbreviation() {
- return abbreviation;
- }
-
- public void setAbbreviation(String abbreviation) {
- this.abbreviation = abbreviation;
- }
-
public String getFunctionName() {
return functionName;
}
@@ -200,6 +178,14 @@
return v.getValue() > 0 ? v : null;
}
+ public short getDefaultValue() {
+ return defaultValue;
+ }
+
+ public void setDefaultValue(short defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
public boolean isCopyMinScore() {
return copyMinScore;
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelTypes.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelTypes.java
index b47445e..18928f2 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelTypes.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelTypes.java
@@ -33,7 +33,7 @@
public LabelTypes(final List<? extends LabelType> approvals) {
labelTypes =
- Collections.unmodifiableList(new ArrayList<LabelType>(approvals));
+ Collections.unmodifiableList(new ArrayList<>(approvals));
}
public List<LabelType> getLabelTypes() {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java
index 0326e02..2379b4a 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java
@@ -48,7 +48,7 @@
private static final int labelAsIndex;
static {
- NAMES_LC = new ArrayList<String>();
+ NAMES_LC = new ArrayList<>();
NAMES_LC.add(OWNER.toLowerCase());
NAMES_LC.add(READ.toLowerCase());
NAMES_LC.add(ABANDON.toLowerCase());
@@ -229,7 +229,7 @@
private void initRules() {
if (rules == null) {
- rules = new ArrayList<PermissionRule>(4);
+ rules = new ArrayList<>(4);
}
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
index ea0c8d2..7041dcc 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
@@ -29,7 +29,6 @@
protected Set<String> ownerOf;
protected boolean isConfigVisible;
protected boolean canUpload;
- protected boolean canChangeParent;
protected LabelTypes labelTypes;
protected Map<String, String> capabilities;
protected Map<AccountGroup.UUID, GroupInfo> groupInfo;
@@ -110,14 +109,6 @@
this.canUpload = canUpload;
}
- public boolean canChangeParent() {
- return canChangeParent;
- }
-
- public void setCanChangeParent(boolean canChangeParent) {
- this.canChangeParent = canChangeParent;
- }
-
public LabelTypes getLabelTypes() {
return labelTypes;
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitTypeRecord.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitTypeRecord.java
index 4eea798..7b19f4c 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitTypeRecord.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitTypeRecord.java
@@ -14,7 +14,7 @@
package com.google.gerrit.common.data;
-import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.extensions.common.SubmitType;
/**
* Describes the submit type for a change.
@@ -31,7 +31,7 @@
RULE_ERROR
}
- public static SubmitTypeRecord OK(Project.SubmitType type) {
+ public static SubmitTypeRecord OK(SubmitType type) {
SubmitTypeRecord r = new SubmitTypeRecord();
r.status = Status.OK;
r.type = type;
@@ -39,7 +39,7 @@
}
public Status status;
- public Project.SubmitType type;
+ public SubmitType type;
public String errorMessage;
public String toString() {
diff --git a/gerrit-common/src/test/java/com/google/gerrit/common/data/ParameterizedStringTest.java b/gerrit-common/src/test/java/com/google/gerrit/common/data/ParameterizedStringTest.java
index 615f49f..b350a27 100644
--- a/gerrit-common/src/test/java/com/google/gerrit/common/data/ParameterizedStringTest.java
+++ b/gerrit-common/src/test/java/com/google/gerrit/common/data/ParameterizedStringTest.java
@@ -14,15 +14,17 @@
package com.google.gerrit.common.data;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.ImmutableMap;
+
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
public class ParameterizedStringTest {
@Test
public void testEmptyString() {
@@ -394,4 +396,32 @@
assertEquals("foo@example.com", p.bind(a)[0]);
assertEquals("foo@example.com", p.replace(a));
}
+
+ @Test
+ public void testReplaceSubmitTooltipWithVariables() {
+ ParameterizedString p = new ParameterizedString(
+ "Submit patch set ${patchSet} into ${branch}");
+ assertEquals(2, p.getParameterNames().size());
+ assertTrue(p.getParameterNames().contains("patchSet"));
+
+ Map<String, String> params = ImmutableMap.of(
+ "patchSet", "42",
+ "branch", "foo");
+ assertNotNull(p.bind(params));
+ assertEquals(2, p.bind(params).length);
+ assertEquals("42", p.bind(params)[0]);
+ assertEquals("foo", p.bind(params)[1]);
+ assertEquals("Submit patch set 42 into foo", p.replace(params));
+ }
+
+ @Test
+ public void testReplaceSubmitTooltipWithoutVariables() {
+ ParameterizedString p = new ParameterizedString(
+ "Submit patch set 40 into master");
+ Map<String, String> params = ImmutableMap.of(
+ "patchSet", "42",
+ "branch", "foo");
+ assertEquals(0, p.bind(params).length);
+ assertEquals("Submit patch set 40 into master", p.replace(params));
+ }
}
diff --git a/gerrit-extension-api/BUCK b/gerrit-extension-api/BUCK
index 0302afd..aad79d7 100644
--- a/gerrit-extension-api/BUCK
+++ b/gerrit-extension-api/BUCK
@@ -4,10 +4,13 @@
gwt_module(
name = 'client',
srcs = glob([
+ SRC + 'api/projects/ProjectState.java',
+ SRC + 'common/InheritableBoolean.java',
+ SRC + 'common/ListChangesOption.java',
+ SRC + 'common/SubmitType.java',
SRC + 'webui/GerritTopMenu.java',
- SRC + 'common/ListChangesOption.java'
]),
- gwtxml = SRC + 'Extensions.gwt.xml',
+ gwt_xml = SRC + 'Extensions.gwt.xml',
visibility = ['PUBLIC'],
)
@@ -28,10 +31,10 @@
visibility = ['PUBLIC'],
)
-java_library2(
+java_library(
name = 'api',
srcs = glob([SRC + '**/*.java']),
- compile_deps = ['//lib/guice:guice'],
+ provided_deps = ['//lib/guice:guice'],
visibility = ['PUBLIC'],
)
@@ -45,7 +48,7 @@
name = 'extension-api-javadoc',
title = 'Gerrit Review Extension API Documentation',
pkg = 'com.google.gerrit.extensions',
- paths = ['$SRCDIR/src/main/java'],
+ paths = ['src/main/java'],
srcs = SRCS,
deps = [
'//lib/guice:javax-inject',
diff --git a/gerrit-extension-api/pom.xml b/gerrit-extension-api/pom.xml
index a2e3b4c..8e99a3f 100644
--- a/gerrit-extension-api/pom.xml
+++ b/gerrit-extension-api/pom.xml
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-extension-api</artifactId>
- <version>2.9.5</version>
+ <version>2.10.8</version>
<packaging>jar</packaging>
<name>Gerrit Code Review - Extension API</name>
<description>API for Gerrit Extensions</description>
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/Extensions.gwt.xml b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/Extensions.gwt.xml
index df53ef1..757e046 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/Extensions.gwt.xml
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/Extensions.gwt.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<module>
- <source path='webui' />
+ <source path='api' />
<source path='common' />
+ <source path='webui' />
</module>
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/RootRelative.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/RootRelative.java
new file mode 100644
index 0000000..a812b53
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/RootRelative.java
@@ -0,0 +1,37 @@
+// 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.extensions.annotations;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.BindingAnnotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation applied to HttpServletRequest and HttpServletResponse
+ * when they are inherited from Gerrit instead of being injected by
+ * a plugin's ServletModule. This means that the path returned by
+ * 'javax.servlet.http.HttpServletRequest#getPathInfo()' is
+ * relative to the Gerrit root instead of a path within the plugin's
+ * URL space.
+ */
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RUNTIME)
+@BindingAnnotation
+public @interface RootRelative {
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
index 844807b..cc5807b 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
@@ -14,10 +14,34 @@
package com.google.gerrit.extensions.api;
+import com.google.gerrit.extensions.api.accounts.Accounts;
import com.google.gerrit.extensions.api.changes.Changes;
import com.google.gerrit.extensions.api.projects.Projects;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
public interface GerritApi {
+ public Accounts accounts();
public Changes changes();
public Projects projects();
+
+ /**
+ * A default implementation which allows source compatibility
+ * when adding new methods to the interface.
+ **/
+ public class NotImplemented implements GerritApi {
+ @Override
+ public Accounts accounts() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public Changes changes() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public Projects projects() {
+ throw new NotImplementedException();
+ }
+ }
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
new file mode 100644
index 0000000..d571cfd
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
@@ -0,0 +1,47 @@
+// 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.extensions.api.accounts;
+
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+public interface AccountApi {
+ AccountInfo get() throws RestApiException;
+
+ void starChange(String id) throws RestApiException;
+ void unstarChange(String id) throws RestApiException;
+
+ /**
+ * A default implementation which allows source compatibility
+ * when adding new methods to the interface.
+ **/
+ public class NotImplemented implements AccountApi {
+ @Override
+ public AccountInfo get() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void starChange(String id) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void unstarChange(String id) throws RestApiException {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java
new file mode 100644
index 0000000..749b12a
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java
@@ -0,0 +1,39 @@
+// 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.extensions.api.accounts;
+
+import com.google.gerrit.extensions.restapi.NotImplementedException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+public interface Accounts {
+ AccountApi id(String id) throws RestApiException;
+ AccountApi self() throws RestApiException;
+
+ /**
+ * A default implementation which allows source compatibility
+ * when adding new methods to the interface.
+ **/
+ public class NotImplemented implements Accounts {
+ @Override
+ public AccountApi id(String id) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public AccountApi self() throws RestApiException {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
index f0a9e4d..3382b76 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -16,6 +16,7 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ListChangesOption;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException;
import java.util.EnumSet;
@@ -45,4 +46,85 @@
ChangeInfo get() throws RestApiException;
/** {@code get} with {@link ListChangesOption} set to NONE. */
ChangeInfo info() throws RestApiException;
+
+ /**
+ * A default implementation which allows source compatibility
+ * when adding new methods to the interface.
+ **/
+ public class NotImplemented implements ChangeApi {
+ @Override
+ public String id() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public RevisionApi current() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public RevisionApi revision(int id) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public RevisionApi revision(String id) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void abandon() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void abandon(AbandonInput in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void restore() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void restore(RestoreInput in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ChangeApi revert() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ChangeApi revert(RevertInput in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void addReviewer(AddReviewerInput in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void addReviewer(String in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ChangeInfo get(EnumSet<ListChangesOption> options) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ChangeInfo get() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ChangeInfo info() throws RestApiException {
+ throw new NotImplementedException();
+ }
+ }
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
index 48e9fd3..201a0bd 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
@@ -14,11 +14,113 @@
package com.google.gerrit.extensions.api.changes;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.ListChangesOption;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+
public interface Changes {
ChangeApi id(int id) throws RestApiException;
ChangeApi id(String triplet) throws RestApiException;
ChangeApi id(String project, String branch, String id)
throws RestApiException;
+ ChangeApi create(ChangeInfo in) throws RestApiException;
+
+ QueryRequest query();
+ QueryRequest query(String query);
+
+ public abstract class QueryRequest {
+ private String query;
+ private int limit;
+ private int start;
+ private EnumSet<ListChangesOption> options = EnumSet.noneOf(ListChangesOption.class);
+
+ public abstract List<ChangeInfo> get() throws RestApiException;
+
+ public QueryRequest withQuery(String query) {
+ this.query = query;
+ return this;
+ }
+
+ public QueryRequest withLimit(int limit) {
+ this.limit = limit;
+ return this;
+ }
+
+ public QueryRequest withStart(int start) {
+ this.start = start;
+ return this;
+ }
+
+ public QueryRequest withOption(ListChangesOption options) {
+ this.options.add(options);
+ return this;
+ }
+
+ public QueryRequest withOptions(ListChangesOption... options) {
+ this.options.addAll(Arrays.asList(options));
+ return this;
+ }
+
+ public QueryRequest withOptions(EnumSet<ListChangesOption> options) {
+ this.options = options;
+ return this;
+ }
+
+ public String getQuery() {
+ return query;
+ }
+
+ public int getLimit() {
+ return limit;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public EnumSet<ListChangesOption> getOptions() {
+ return options;
+ }
+ }
+
+ /**
+ * A default implementation which allows source compatibility
+ * when adding new methods to the interface.
+ **/
+ public class NotImplemented implements Changes {
+ @Override
+ public ChangeApi id(int id) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ChangeApi id(String triplet) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ChangeApi id(String project, String branch, String id) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ChangeApi create(ChangeInfo in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public QueryRequest query() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public QueryRequest query(String query) {
+ throw new NotImplementedException();
+ }
+ }
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
index 993fa14..cf2d930 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
@@ -14,6 +14,7 @@
package com.google.gerrit.extensions.api.changes;
+import com.google.gerrit.extensions.common.Comment;
import com.google.gerrit.extensions.restapi.DefaultInput;
import java.util.LinkedHashMap;
@@ -26,7 +27,7 @@
public String message;
public Map<String, Short> labels;
- public Map<String, List<Comment>> comments;
+ public Map<String, List<CommentInput>> comments;
/**
* If true require all labels to be within the user's permitted ranges based
@@ -67,24 +68,7 @@
NONE, OWNER, OWNER_REVIEWERS, ALL
}
- public static enum Side {
- PARENT, REVISION
- }
-
- public static class Comment {
- public String id;
- public Side side;
- public int line;
- public String inReplyTo;
- public String message;
- public Range range;
-
- public static class Range {
- public int startLine;
- public int startCharacter;
- public int endLine;
- public int endCharacter;
- }
+ public static class CommentInput extends Comment {
}
public ReviewInput message(String msg) {
@@ -97,7 +81,7 @@
throw new IllegalArgumentException();
}
if (labels == null) {
- labels = new LinkedHashMap<String, Short>(4);
+ labels = new LinkedHashMap<>(4);
}
labels.put(name, value);
return this;
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
index 4f90be2..20bcea9 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
@@ -14,8 +14,11 @@
package com.google.gerrit.extensions.api.changes;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException;
+import java.util.Set;
+
public interface RevisionApi {
void delete() throws RestApiException;
void review(ReviewInput in) throws RestApiException;
@@ -26,4 +29,64 @@
void publish() throws RestApiException;
ChangeApi cherryPick(CherryPickInput in) throws RestApiException;
ChangeApi rebase() throws RestApiException;
+ boolean canRebase();
+
+ void setReviewed(String path, boolean reviewed) throws RestApiException;
+ Set<String> reviewed() throws RestApiException;
+
+ /**
+ * A default implementation which allows source compatibility
+ * when adding new methods to the interface.
+ **/
+ public class NotImplemented implements RevisionApi {
+ @Override
+ public void delete() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void review(ReviewInput in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void submit() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void submit(SubmitInput in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void publish() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ChangeApi cherryPick(CherryPickInput in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ChangeApi rebase() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public boolean canRebase() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void setReviewed(String path, boolean reviewed) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public Set<String> reviewed() throws RestApiException {
+ throw new NotImplementedException();
+ }
+ }
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
index 2f1533f..f88a2cb 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
@@ -14,8 +14,20 @@
package com.google.gerrit.extensions.api.projects;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException;
public interface BranchApi {
BranchApi create(BranchInput in) throws RestApiException;
+
+ /**
+ * A default implementation which allows source compatibility
+ * when adding new methods to the interface.
+ **/
+ public class NotImplemented implements BranchApi {
+ @Override
+ public BranchApi create(BranchInput in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+ }
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
index 1c7209d..d013c5d 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
@@ -14,6 +14,39 @@
package com.google.gerrit.extensions.api.projects;
+import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+
public interface ProjectApi {
+ ProjectApi create() throws RestApiException;
+ ProjectApi create(ProjectInput in) throws RestApiException;
+ ProjectInfo get();
BranchApi branch(String ref);
+
+ /**
+ * A default implementation which allows source compatibility
+ * when adding new methods to the interface.
+ **/
+ public class NotImplemented implements ProjectApi {
+ @Override
+ public ProjectApi create() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ProjectApi create(ProjectInput in) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ProjectInfo get() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public BranchApi branch(String ref) {
+ throw new NotImplementedException();
+ }
+ }
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectInput.java
new file mode 100644
index 0000000..74b2be87
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectInput.java
@@ -0,0 +1,43 @@
+// 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.extensions.api.projects;
+
+import com.google.gerrit.extensions.common.InheritableBoolean;
+import com.google.gerrit.extensions.common.SubmitType;
+
+import java.util.List;
+import java.util.Map;
+
+public class ProjectInput {
+ public String name;
+ public String parent;
+ public String description;
+ public boolean permissionsOnly;
+ public boolean createEmptyCommit;
+ public SubmitType submitType;
+ public List<String> branches;
+ public List<String> owners;
+ public InheritableBoolean useContributorAgreements;
+ public InheritableBoolean useSignedOffBy;
+ public InheritableBoolean useContentMerge;
+ public InheritableBoolean requireChangeId;
+ public String maxObjectSizeLimit;
+ public Map<String, Map<String, ConfigValue>> pluginConfigValues;
+
+ public static class ConfigValue {
+ public String value;
+ public List<String> values;
+ }
+}
\ No newline at end of file
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectState.java
similarity index 65%
copy from gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectState.java
index 72b0c8b..407b7c7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectState.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 The Android Open Source Project
+// 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.
@@ -12,14 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.schema;
+package com.google.gerrit.extensions.api.projects;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-
-public class Schema_58 extends SchemaVersion {
- @Inject
- Schema_58(Provider<Schema_57> prior) {
- super(prior);
- }
-}
+public enum ProjectState {
+ ACTIVE,
+ READ_ONLY,
+ HIDDEN
+}
\ No newline at end of file
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
index a3a4137..9c0cfd8 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
@@ -14,8 +14,75 @@
package com.google.gerrit.extensions.api.projects;
+import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException;
+import java.util.List;
+
public interface Projects {
ProjectApi name(String name) throws RestApiException;
+
+ ListRequest list();
+
+ public abstract class ListRequest {
+ private boolean description;
+ private String prefix;
+ private int limit;
+ private int start;
+
+ public abstract List<ProjectInfo> get() throws RestApiException;
+
+ public ListRequest withDescription(boolean description) {
+ this.description = description;
+ return this;
+ }
+
+ public ListRequest withPrefix(String prefix) {
+ this.prefix = prefix;
+ return this;
+ }
+
+ public ListRequest withLimit(int limit) {
+ this.limit = limit;
+ return this;
+ }
+
+ public ListRequest withStart(int start) {
+ this.start = start;
+ return this;
+ }
+
+ public boolean getDescription() {
+ return description;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public int getLimit() {
+ return limit;
+ }
+
+ public int getStart() {
+ return start;
+ }
+ }
+
+ /**
+ * A default implementation which allows source compatibility
+ * when adding new methods to the interface.
+ **/
+ public class NotImplemented implements Projects {
+ @Override
+ public ProjectApi name(String name) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ListRequest list() {
+ throw new NotImplementedException();
+ }
+ }
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthServiceProvider.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthServiceProvider.java
new file mode 100644
index 0000000..9be2630
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthServiceProvider.java
@@ -0,0 +1,65 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.extensions.auth.oauth;
+
+import com.google.gerrit.extensions.annotations.ExtensionPoint;
+
+import java.io.IOException;
+
+/* Contract that OAuth provider must implement */
+@ExtensionPoint
+public interface OAuthServiceProvider {
+
+ /**
+ * Returns the URL where you should redirect your users to authenticate
+ * your application.
+ *
+ * @return the OAuth service URL to redirect your users for authentication
+ */
+ String getAuthorizationUrl();
+
+ /**
+ * Retrieve the access token
+ *
+ * @param verifier verifier code
+ * @return access token
+ */
+ OAuthToken getAccessToken(OAuthVerifier verifier);
+
+ /**
+ * After establishing of secure communication channel, this method supossed to
+ * access the protected resoure and retrieve the username.
+ *
+ * @param token
+ * @return OAuth user information
+ * @throws IOException
+ */
+ OAuthUserInfo getUserInfo(OAuthToken token) throws IOException;
+
+ /**
+ * Returns the OAuth version of the service.
+ *
+ * @return oauth version as string
+ */
+ String getVersion();
+
+ /**
+ * Returns the name of this service. This name is resented the user to choose
+ * between multiple service providers
+ *
+ * @return name of the service
+ */
+ String getName();
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthToken.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthToken.java
new file mode 100644
index 0000000..901951e
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthToken.java
@@ -0,0 +1,41 @@
+// 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.extensions.auth.oauth;
+
+/* OAuth token */
+public class OAuthToken {
+
+ private final String token;
+ private final String secret;
+ private final String raw;
+
+ public OAuthToken(String token, String secret, String raw) {
+ this.token = token;
+ this.secret = secret;
+ this.raw = raw;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public String getSecret() {
+ return secret;
+ }
+
+ public String getRaw() {
+ return raw;
+ }
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthUserInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthUserInfo.java
new file mode 100644
index 0000000..388ce36
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthUserInfo.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.extensions.auth.oauth;
+
+public class OAuthUserInfo {
+
+ private final String externalId;
+ private final String userName;
+ private final String emailAddress;
+ private final String displayName;
+ private final String claimedIdentity;
+
+ public OAuthUserInfo(String externalId,
+ String userName,
+ String emailAddress,
+ String displayName,
+ String claimedIdentity) {
+ this.externalId = externalId;
+ this.userName = userName;
+ this.emailAddress = emailAddress;
+ this.displayName = displayName;
+ this.claimedIdentity = claimedIdentity;
+ }
+
+ public String getExternalId() {
+ return externalId;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public String getEmailAddress() {
+ return emailAddress;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public String getClaimedIdentity() {
+ return claimedIdentity;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthVerifier.java
similarity index 64%
copy from gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthVerifier.java
index 72b0c8b..33c45c5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/auth/oauth/OAuthVerifier.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 The Android Open Source Project
+// 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.
@@ -12,14 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.schema;
+package com.google.gerrit.extensions.auth.oauth;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
+/* OAuth verifier */
+public class OAuthVerifier {
-public class Schema_58 extends SchemaVersion {
- @Inject
- Schema_58(Provider<Schema_57> prior) {
- super(prior);
+ private final String value;
+
+ public OAuthVerifier(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
}
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java
index f85684e..653ec37 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java
@@ -39,4 +39,5 @@
public Map<String, LabelInfo> labels;
public Collection<ChangeMessageInfo> messages;
public Map<String, RevisionInfo> revisions;
+ public int _number;
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/Comment.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/Comment.java
new file mode 100644
index 0000000..b7ad9a7
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/Comment.java
@@ -0,0 +1,39 @@
+// 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.extensions.common;
+
+import java.sql.Timestamp;
+
+public abstract class Comment {
+ public String id;
+ public String path;
+ public Side side;
+ public int line;
+ public Range range;
+ public String inReplyTo;
+ public Timestamp updated;
+ public String message;
+
+ public static enum Side {
+ PARENT, REVISION
+ }
+
+ public static class Range {
+ public int startLine;
+ public int startCharacter;
+ public int endLine;
+ public int endCharacter;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/CommentInfo.java
similarity index 65%
copy from gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/CommentInfo.java
index 72b0c8b..cef1718 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/CommentInfo.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 The Android Open Source Project
+// 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.
@@ -12,14 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.schema;
+package com.google.gerrit.extensions.common;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-
-public class Schema_58 extends SchemaVersion {
- @Inject
- Schema_58(Provider<Schema_57> prior) {
- super(prior);
- }
+public class CommentInfo extends Comment {
+ public AccountInfo author;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/InheritableBoolean.java
similarity index 65%
copy from gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/InheritableBoolean.java
index 72b0c8b..676c4d3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/InheritableBoolean.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 The Android Open Source Project
+// 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.
@@ -12,14 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.schema;
+package com.google.gerrit.extensions.common;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-
-public class Schema_58 extends SchemaVersion {
- @Inject
- Schema_58(Provider<Schema_57> prior) {
- super(prior);
- }
-}
+public enum InheritableBoolean {
+ TRUE,
+ FALSE,
+ INHERIT
+}
\ No newline at end of file
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
index fd6008f..1e4edcd 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
@@ -25,6 +25,7 @@
public List<ApprovalInfo> all;
public Map<String, String> values;
public Short value;
+ public Short defaultValue;
public Boolean optional;
public Boolean blocking;
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ListChangesOption.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ListChangesOption.java
index c23e312..f9f8b62 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ListChangesOption.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ListChangesOption.java
@@ -49,7 +49,10 @@
DRAFT_COMMENTS(12),
/** Include download commands for the caller. */
- DOWNLOAD_COMMANDS(13);
+ DOWNLOAD_COMMANDS(13),
+
+ /** Include patch set weblinks. */
+ WEB_LINKS(14);
private final int value;
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ProjectInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ProjectInfo.java
new file mode 100644
index 0000000..bb07e44
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ProjectInfo.java
@@ -0,0 +1,30 @@
+// 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.extensions.common;
+
+import com.google.gerrit.extensions.api.projects.ProjectState;
+
+import java.util.List;
+import java.util.Map;
+
+public class ProjectInfo {
+ public String id;
+ public String name;
+ public String parent;
+ public String description;
+ public ProjectState state;
+ public Map<String, String> branches;
+ public List<WebLinkInfo> webLinks;
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java
index ea5b068..8f61aa2 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/RevisionInfo.java
@@ -14,6 +14,7 @@
package com.google.gerrit.extensions.common;
+import java.util.List;
import java.util.Map;
public class RevisionInfo {
@@ -25,4 +26,5 @@
public CommitInfo commit;
public Map<String, FileInfo> files;
public Map<String, ActionInfo> actions;
+ public List<WebLinkInfo> webLinks;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/SubmitType.java
similarity index 65%
copy from gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/SubmitType.java
index 72b0c8b..95a9693 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/SubmitType.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 The Android Open Source Project
+// 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.
@@ -12,14 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.schema;
+package com.google.gerrit.extensions.common;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-
-public class Schema_58 extends SchemaVersion {
- @Inject
- Schema_58(Provider<Schema_57> prior) {
- super(prior);
- }
-}
+public enum SubmitType {
+ FAST_FORWARD_ONLY,
+ MERGE_IF_NECESSARY,
+ REBASE_IF_NECESSARY,
+ MERGE_ALWAYS,
+ CHERRY_PICK
+}
\ No newline at end of file
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/WebLinkInfo.java
similarity index 66%
copy from gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/WebLinkInfo.java
index 72b0c8b..7695c8c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/WebLinkInfo.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 The Android Open Source Project
+// 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.
@@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.schema;
+package com.google.gerrit.extensions.common;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
+public class WebLinkInfo {
+ public String name;
+ public String url;
-public class Schema_58 extends SchemaVersion {
- @Inject
- Schema_58(Provider<Schema_57> prior) {
- super(prior);
+ public WebLinkInfo(String name, String url) {
+ this.name = name;
+ this.url = url;
}
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/UsageDataPublishedListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/UsageDataPublishedListener.java
new file mode 100644
index 0000000..365d056
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/UsageDataPublishedListener.java
@@ -0,0 +1,45 @@
+// 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.extensions.events;
+
+import com.google.gerrit.extensions.annotations.ExtensionPoint;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+/** Notified when usage data is published */
+@ExtensionPoint
+public interface UsageDataPublishedListener {
+
+ public interface Event {
+ MetaData getMetaData();
+ Timestamp getInstant();
+ List<Data> getData();
+ }
+
+ public interface Data {
+ long getValue();
+ String getProjectName();
+ }
+
+ public interface MetaData {
+ public String getName();
+ public String getUnitName();
+ public String getUnitSymbol();
+ public String getDescription();
+ }
+
+ void onUsageDataPublished(Event event);
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java
index aa1dc76..7edfaed 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java
@@ -78,7 +78,7 @@
Key<DynamicItem<T>> key = (Key<DynamicItem<T>>) Key.get(
Types.newParameterizedType(DynamicItem.class, member.getType()));
binder.bind(key)
- .toProvider(new DynamicItemProvider<T>(member, key))
+ .toProvider(new DynamicItemProvider<>(member, key))
.in(Scopes.SINGLETON);
}
@@ -111,10 +111,10 @@
DynamicItem(Key<DynamicItem<T>> key, Provider<T> provider, String pluginName) {
NamedProvider<T> in = null;
if (provider != null) {
- in = new NamedProvider<T>(provider, pluginName);
+ in = new NamedProvider<>(provider, pluginName);
}
this.key = key;
- this.ref = new AtomicReference<NamedProvider<T>>(in);
+ this.ref = new AtomicReference<>(in);
}
/**
@@ -148,19 +148,22 @@
* @return handle to remove the item at a later point in time.
*/
public RegistrationHandle set(Provider<T> impl, String pluginName) {
- final NamedProvider<T> item = new NamedProvider<T>(impl, pluginName);
- while (!ref.compareAndSet(null, item)) {
- NamedProvider<T> old = ref.get();
- if (old != null) {
+ final NamedProvider<T> item = new NamedProvider<>(impl, pluginName);
+ NamedProvider<T> old = null;
+ while (!ref.compareAndSet(old, item)) {
+ old = ref.get();
+ if (old != null && !"gerrit".equals(old.pluginName)) {
throw new ProvisionException(String.format(
"%s already provided by %s, ignoring plugin %s",
key.getTypeLiteral(), old.pluginName, pluginName));
}
}
+
+ final NamedProvider<T> defaultItem = old;
return new RegistrationHandle() {
@Override
public void remove() {
- ref.compareAndSet(item, null);
+ ref.compareAndSet(item, defaultItem);
}
};
}
@@ -177,25 +180,34 @@
*/
public ReloadableRegistrationHandle<T> set(Key<T> key, Provider<T> impl,
String pluginName) {
- final NamedProvider<T> item = new NamedProvider<T>(impl, pluginName);
- while (!ref.compareAndSet(null, item)) {
- NamedProvider<T> old = ref.get();
- if (old != null) {
+ final NamedProvider<T> item = new NamedProvider<>(impl, pluginName);
+ NamedProvider<T> old = null;
+ while (!ref.compareAndSet(old, item)) {
+ old = ref.get();
+ if (old != null
+ && !"gerrit".equals(old.pluginName)
+ && !pluginName.equals(old.pluginName)) {
+ // We allow to replace:
+ // 1. Gerrit core items, e.g. websession cache
+ // can be replaced by plugin implementation
+ // 2. Reload of current plugin
throw new ProvisionException(String.format(
"%s already provided by %s, ignoring plugin %s",
this.key.getTypeLiteral(), old.pluginName, pluginName));
}
}
- return new ReloadableHandle(key, item);
+ return new ReloadableHandle(key, item, old);
}
private class ReloadableHandle implements ReloadableRegistrationHandle<T> {
private final Key<T> key;
private final NamedProvider<T> item;
+ private final NamedProvider<T> defaultItem;
- ReloadableHandle(Key<T> key, NamedProvider<T> item) {
+ ReloadableHandle(Key<T> key, NamedProvider<T> item, NamedProvider<T> defaultItem) {
this.key = key;
this.item = item;
+ this.defaultItem = defaultItem;
}
@Override
@@ -205,14 +217,14 @@
@Override
public void remove() {
- ref.compareAndSet(item, null);
+ ref.compareAndSet(item, defaultItem);
}
@Override
public ReloadableHandle replace(Key<T> newKey, Provider<T> newItem) {
- NamedProvider<T> n = new NamedProvider<T>(newItem, item.pluginName);
+ NamedProvider<T> n = new NamedProvider<>(newItem, item.pluginName);
if (ref.compareAndSet(item, n)) {
- return new ReloadableHandle(newKey, n);
+ return new ReloadableHandle(newKey, n, defaultItem);
}
return null;
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItemProvider.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItemProvider.java
index 1074ee5..9b09d15 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItemProvider.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItemProvider.java
@@ -37,7 +37,7 @@
}
public DynamicItem<T> get() {
- return new DynamicItem<T>(key, find(injector, type), "gerrit");
+ return new DynamicItem<>(key, find(injector, type), "gerrit");
}
private static <T> Provider<T> find(Injector src, TypeLiteral<T> type) {
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java
index ea4a751..4251891 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java
@@ -81,14 +81,14 @@
Key<DynamicMap<T>> key = (Key<DynamicMap<T>>) Key.get(
Types.newParameterizedType(DynamicMap.class, member.getType()));
binder.bind(key)
- .toProvider(new DynamicMapProvider<T>(member))
+ .toProvider(new DynamicMapProvider<>(member))
.in(Scopes.SINGLETON);
}
final ConcurrentMap<NamePair, Provider<T>> items;
DynamicMap() {
- items = new ConcurrentHashMap<NamePair, Provider<T>>(
+ items = new ConcurrentHashMap<>(
16 /* initial size */,
0.75f /* load factor */,
1 /* concurrency level of 1, load/unload is single threaded */);
@@ -115,7 +115,7 @@
* @return sorted set of active plugins that supply at least one item.
*/
public SortedSet<String> plugins() {
- SortedSet<String> r = new TreeSet<String>();
+ SortedSet<String> r = new TreeSet<>();
for (NamePair p : items.keySet()) {
r.add(p.pluginName);
}
@@ -129,7 +129,7 @@
* @return items exported by a plugin, keyed by the export name.
*/
public SortedMap<String, Provider<T>> byPlugin(String pluginName) {
- SortedMap<String, Provider<T>> r = new TreeMap<String, Provider<T>>();
+ SortedMap<String, Provider<T>> r = new TreeMap<>();
for (Map.Entry<NamePair, Provider<T>> e : items.entrySet()) {
if (e.getKey().pluginName.equals(pluginName)) {
r.put(e.getKey().exportName, e.getValue());
@@ -206,4 +206,8 @@
return false;
}
}
+
+ public static <T> DynamicMap<T> emptyMap() {
+ return new DynamicMap<T>() {};
+ }
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMapProvider.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMapProvider.java
index c6e4701..2554673 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMapProvider.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMapProvider.java
@@ -34,7 +34,7 @@
public DynamicMap<T> get() {
PrivateInternals_DynamicMapImpl<T> m =
- new PrivateInternals_DynamicMapImpl<T>();
+ new PrivateInternals_DynamicMapImpl<>();
List<Binding<T>> bindings = injector.findBindingsByType(type);
if (bindings != null) {
for (Binding<T> b : bindings) {
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
index b2f19e5..628745a 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
@@ -72,7 +72,7 @@
Key<DynamicSet<T>> key = (Key<DynamicSet<T>>) Key.get(
Types.newParameterizedType(DynamicSet.class, member.getType()));
binder.bind(key)
- .toProvider(new DynamicSetProvider<T>(member))
+ .toProvider(new DynamicSetProvider<>(member))
.in(Scopes.SINGLETON);
}
@@ -136,7 +136,7 @@
private final CopyOnWriteArrayList<AtomicReference<Provider<T>>> items;
DynamicSet(Collection<AtomicReference<Provider<T>>> base) {
- items = new CopyOnWriteArrayList<AtomicReference<Provider<T>>>(base);
+ items = new CopyOnWriteArrayList<>(base);
}
@Override
@@ -194,8 +194,7 @@
* @return handle to remove the item at a later point in time.
*/
public RegistrationHandle add(final Provider<T> item) {
- final AtomicReference<Provider<T>> ref =
- new AtomicReference<Provider<T>>(item);
+ final AtomicReference<Provider<T>> ref = new AtomicReference<>(item);
items.add(ref);
return new RegistrationHandle() {
@Override
@@ -218,7 +217,7 @@
* without it ever leaving the collection.
*/
public ReloadableRegistrationHandle<T> add(Key<T> key, Provider<T> item) {
- AtomicReference<Provider<T>> ref = new AtomicReference<Provider<T>>(item);
+ AtomicReference<Provider<T>> ref = new AtomicReference<>(item);
items.add(ref);
return new ReloadableHandle(ref, key, item);
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java
index 21fa1b8..9ea96d4 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java
@@ -36,7 +36,7 @@
}
public DynamicSet<T> get() {
- return new DynamicSet<T>(find(injector, type));
+ return new DynamicSet<>(find(injector, type));
}
private static <T> List<AtomicReference<Provider<T>>> find(
@@ -47,16 +47,12 @@
if (cnt == 0) {
return Collections.emptyList();
}
- List<AtomicReference<Provider<T>>> r = newList(cnt);
+ List<AtomicReference<Provider<T>>> r = new ArrayList<>(cnt);
for (Binding<T> b : bindings) {
if (b.getKey().getAnnotation() != null) {
- r.add(new AtomicReference<Provider<T>>(b.getProvider()));
+ r.add(new AtomicReference<>(b.getProvider()));
}
}
return r;
}
-
- private static <T> List<AtomicReference<Provider<T>>> newList(int cnt) {
- return new ArrayList<AtomicReference<Provider<T>>>(cnt);
- }
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/PrivateInternals_DynamicTypes.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/PrivateInternals_DynamicTypes.java
index 8bc57ab..96538e1 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/PrivateInternals_DynamicTypes.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/PrivateInternals_DynamicTypes.java
@@ -31,7 +31,7 @@
/** <b>DO NOT USE</b> */
public class PrivateInternals_DynamicTypes {
public static Map<TypeLiteral<?>, DynamicItem<?>> dynamicItemsOf(Injector src) {
- Map<TypeLiteral<?>, DynamicItem<?>> m = newHashMap();
+ Map<TypeLiteral<?>, DynamicItem<?>> m = new HashMap<>();
for (Map.Entry<Key<?>, Binding<?>> e : src.getBindings().entrySet()) {
TypeLiteral<?> type = e.getKey().getTypeLiteral();
if (type.getRawType() == DynamicItem.class) {
@@ -47,7 +47,7 @@
}
public static Map<TypeLiteral<?>, DynamicSet<?>> dynamicSetsOf(Injector src) {
- Map<TypeLiteral<?>, DynamicSet<?>> m = newHashMap();
+ Map<TypeLiteral<?>, DynamicSet<?>> m = new HashMap<>();
for (Map.Entry<Key<?>, Binding<?>> e : src.getBindings().entrySet()) {
TypeLiteral<?> type = e.getKey().getTypeLiteral();
if (type.getRawType() == DynamicSet.class) {
@@ -63,7 +63,7 @@
}
public static Map<TypeLiteral<?>, DynamicMap<?>> dynamicMapsOf(Injector src) {
- Map<TypeLiteral<?>, DynamicMap<?>> m = newHashMap();
+ Map<TypeLiteral<?>, DynamicMap<?>> m = new HashMap<>();
for (Map.Entry<Key<?>, Binding<?>> e : src.getBindings().entrySet()) {
TypeLiteral<?> type = e.getKey().getTypeLiteral();
if (type.getRawType() == DynamicMap.class) {
@@ -85,7 +85,7 @@
return Collections.emptyList();
}
- List<RegistrationHandle> handles = new ArrayList<RegistrationHandle>(4);
+ List<RegistrationHandle> handles = new ArrayList<>(4);
try {
for (Map.Entry<TypeLiteral<?>, DynamicItem<?>> e : items.entrySet()) {
@SuppressWarnings("unchecked")
@@ -95,9 +95,7 @@
DynamicItem<Object> item = (DynamicItem<Object>) e.getValue();
for (Binding<Object> b : bindings(src, type)) {
- if (b.getKey().getAnnotation() != null) {
- handles.add(item.set(b.getKey(), b.getProvider(), pluginName));
- }
+ handles.add(item.set(b.getKey(), b.getProvider(), pluginName));
}
}
} catch (RuntimeException e) {
@@ -117,7 +115,7 @@
return Collections.emptyList();
}
- List<RegistrationHandle> handles = new ArrayList<RegistrationHandle>(4);
+ List<RegistrationHandle> handles = new ArrayList<>(4);
try {
for (Map.Entry<TypeLiteral<?>, DynamicSet<?>> e : sets.entrySet()) {
@SuppressWarnings("unchecked")
@@ -150,7 +148,7 @@
return Collections.emptyList();
}
- List<RegistrationHandle> handles = new ArrayList<RegistrationHandle>(4);
+ List<RegistrationHandle> handles = new ArrayList<>(4);
try {
for (Map.Entry<TypeLiteral<?>, DynamicMap<?>> e : maps.entrySet()) {
@SuppressWarnings("unchecked")
@@ -185,7 +183,7 @@
@Override
public void start() {
- handles = new ArrayList<RegistrationHandle>(4);
+ handles = new ArrayList<>(4);
Injector parent = self.getParent();
while (parent != null) {
handles.addAll(attachSets(self, dynamicSetsOf(parent)));
@@ -213,10 +211,6 @@
}
}
- private static <K,V> Map<K, V> newHashMap() {
- return new HashMap<K,V>();
- }
-
private static <T> List<Binding<T>> bindings(Injector src, TypeLiteral<T> type) {
return src.findBindingsByType(type);
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/Die.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/NotImplementedException.java
similarity index 65%
copy from gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/Die.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/NotImplementedException.java
index 96e2ec8..10d0a14 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/Die.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/NotImplementedException.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2009 The Android Open Source Project
+// 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.
@@ -12,16 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.pgm.util;
+package com.google.gerrit.extensions.restapi;
-public class Die extends RuntimeException {
+/** Method is not implemented in currently used implementation. */
+public class NotImplementedException extends UnsupportedOperationException {
private static final long serialVersionUID = 1L;
- public Die(final String why) {
- super(why);
- }
-
- public Die(final String why, final Throwable cause) {
- super(why, cause);
+ public NotImplementedException() {
+ super("Not implemented.");
}
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java
index 848004d..314c898 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java
@@ -21,12 +21,12 @@
/** HTTP 200 OK: pointless wrapper for type safety. */
public static <T> Response<T> ok(T value) {
- return new Impl<T>(200, value);
+ return new Impl<>(200, value);
}
/** HTTP 201 Created: typically used when a new resource is made. */
public static <T> Response<T> created(T value) {
- return new Impl<T>(201, value);
+ return new Impl<>(201, value);
}
/** HTTP 204 No Content: typically used when the resource is deleted. */
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiModule.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiModule.java
index b3a0e18..7708a5c 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiModule.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiModule.java
@@ -31,47 +31,47 @@
protected <R extends RestResource>
ReadViewBinder<R> get(TypeLiteral<RestView<R>> viewType) {
- return new ReadViewBinder<R>(view(viewType, GET, "/"));
+ return new ReadViewBinder<>(view(viewType, GET, "/"));
}
protected <R extends RestResource>
ModifyViewBinder<R> put(TypeLiteral<RestView<R>> viewType) {
- return new ModifyViewBinder<R>(view(viewType, PUT, "/"));
+ return new ModifyViewBinder<>(view(viewType, PUT, "/"));
}
protected <R extends RestResource>
ModifyViewBinder<R> post(TypeLiteral<RestView<R>> viewType) {
- return new ModifyViewBinder<R>(view(viewType, POST, "/"));
+ return new ModifyViewBinder<>(view(viewType, POST, "/"));
}
protected <R extends RestResource>
ModifyViewBinder<R> delete(TypeLiteral<RestView<R>> viewType) {
- return new ModifyViewBinder<R>(view(viewType, DELETE, "/"));
+ return new ModifyViewBinder<>(view(viewType, DELETE, "/"));
}
protected <R extends RestResource>
ReadViewBinder<R> get(TypeLiteral<RestView<R>> viewType, String name) {
- return new ReadViewBinder<R>(view(viewType, GET, name));
+ return new ReadViewBinder<>(view(viewType, GET, name));
}
protected <R extends RestResource>
ModifyViewBinder<R> put(TypeLiteral<RestView<R>> viewType, String name) {
- return new ModifyViewBinder<R>(view(viewType, PUT, name));
+ return new ModifyViewBinder<>(view(viewType, PUT, name));
}
protected <R extends RestResource>
ModifyViewBinder<R> post(TypeLiteral<RestView<R>> viewType, String name) {
- return new ModifyViewBinder<R>(view(viewType, POST, name));
+ return new ModifyViewBinder<>(view(viewType, POST, name));
}
protected <R extends RestResource>
ModifyViewBinder<R> delete(TypeLiteral<RestView<R>> viewType, String name) {
- return new ModifyViewBinder<R>(view(viewType, DELETE, name));
+ return new ModifyViewBinder<>(view(viewType, DELETE, name));
}
protected <P extends RestResource>
ChildCollectionBinder<P> child(TypeLiteral<RestView<P>> type, String name) {
- return new ChildCollectionBinder<P>(view(type, GET, name));
+ return new ChildCollectionBinder<>(view(type, GET, name));
}
protected <R extends RestResource>
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/PatchSetWebLink.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/PatchSetWebLink.java
new file mode 100644
index 0000000..b6086f2
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/PatchSetWebLink.java
@@ -0,0 +1,29 @@
+// 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.extensions.webui;
+
+import com.google.gerrit.extensions.annotations.ExtensionPoint;
+
+@ExtensionPoint
+public interface PatchSetWebLink extends WebLink {
+
+ /**
+ * URL to patch set in external service.
+ *
+ * @param projectName Name of the project
+ * @param commit Commit of the patch set
+ * @return url to patch set in external service.
+ */
+ String getPatchSetUrl(final String projectName, final String commit);
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/ProjectWebLink.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/ProjectWebLink.java
new file mode 100644
index 0000000..61e9982
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/ProjectWebLink.java
@@ -0,0 +1,29 @@
+// 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.extensions.webui;
+
+import com.google.gerrit.extensions.annotations.ExtensionPoint;
+
+@ExtensionPoint
+public interface ProjectWebLink extends WebLink {
+
+ /**
+ * URL to project in external service.
+ *
+ * @param projectName Name of the project
+ * @return url to project in external service.
+ */
+ String getProjectUrl(String projectName);
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/UiResult.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/UiResult.java
new file mode 100644
index 0000000..106db04
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/UiResult.java
@@ -0,0 +1,59 @@
+// 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.extensions.webui;
+
+import java.net.URI;
+
+/** Default result for {@link UiAction}s with no JavaScript. */
+public class UiResult {
+ /** Display an alert message to the user. */
+ public static UiResult alert(String message) {
+ UiResult r = new UiResult();
+ r.alert = message;
+ return r;
+ }
+
+ /** Launch URL in a new window. */
+ public static UiResult openUrl(URI uri) {
+ return openUrl(uri.toString());
+ }
+
+ /** Launch URL in a new window. */
+ public static UiResult openUrl(String url) {
+ UiResult r = new UiResult();
+ r.url = url;
+ r.openWindow = true;
+ return r;
+ }
+
+ /** Redirect the browser to a new URL. */
+ public static UiResult redirectUrl(String url) {
+ UiResult r = new UiResult();
+ r.url = url;
+ return r;
+ }
+
+ /** Alert the user with a message. */
+ protected String alert;
+
+ /** If present redirect browser to this URL. */
+ protected String url;
+
+ /** When true open {@link #url} in a new tab/window. */
+ protected Boolean openWindow;
+
+ private UiResult() {
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/WebLink.java
similarity index 65%
copy from gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/WebLink.java
index 72b0c8b..19d9ab7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/WebLink.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 The Android Open Source Project
+// 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.
@@ -11,15 +11,14 @@
// 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.extensions.webui;
-package com.google.gerrit.server.schema;
+public interface WebLink {
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-
-public class Schema_58 extends SchemaVersion {
- @Inject
- Schema_58(Provider<Schema_57> prior) {
- super(prior);
- }
+ /**
+ * The link-name displayed in UI.
+ *
+ * @return name of link.
+ */
+ String getLinkName();
}
diff --git a/gerrit-gwtexpui/BUCK b/gerrit-gwtexpui/BUCK
index 76d0741..e06bf17 100644
--- a/gerrit-gwtexpui/BUCK
+++ b/gerrit-gwtexpui/BUCK
@@ -3,7 +3,7 @@
gwt_module(
name = 'Clippy',
srcs = glob([SRC + 'clippy/client/*.java']),
- gwtxml = SRC + 'clippy/Clippy.gwt.xml',
+ gwt_xml = SRC + 'clippy/Clippy.gwt.xml',
resources = [
SRC + 'clippy/client/clippy.css',
SRC + 'clippy/client/clippy.swf',
@@ -11,8 +11,6 @@
deps = [
':SafeHtml',
':UserAgent',
- ],
- compile_deps = [
'//lib/gwt:user',
'//lib:LICENSE-clippy',
],
@@ -30,7 +28,7 @@
gwt_module(
name = 'GlobalKey',
srcs = glob([SRC + 'globalkey/client/*.java']),
- gwtxml = SRC + 'globalkey/GlobalKey.gwt.xml',
+ gwt_xml = SRC + 'globalkey/GlobalKey.gwt.xml',
resources = [
SRC + 'globalkey/client/KeyConstants.properties',
SRC + 'globalkey/client/key.css',
@@ -38,33 +36,33 @@
deps = [
':SafeHtml',
':UserAgent',
+ '//lib/gwt:user',
],
- compile_deps = ['//lib/gwt:user'],
visibility = ['PUBLIC'],
)
-java_library2(
+java_library(
name = 'linker_server',
srcs = glob([SRC + 'linker/server/*.java']),
- compile_deps = ['//lib:servlet-api-3_1'],
+ provided_deps = ['//lib:servlet-api-3_1'],
visibility = ['PUBLIC'],
)
gwt_module(
name = 'Progress',
srcs = glob([SRC + 'progress/client/*.java']),
- gwtxml = SRC + 'progress/Progress.gwt.xml',
+ gwt_xml = SRC + 'progress/Progress.gwt.xml',
resources = [SRC + 'progress/client/progress.css'],
- compile_deps = ['//lib/gwt:user'],
+ deps = ['//lib/gwt:user'],
visibility = ['PUBLIC'],
)
gwt_module(
name = 'SafeHtml',
srcs = glob([SRC + 'safehtml/client/*.java']),
- gwtxml = SRC + 'safehtml/SafeHtml.gwt.xml',
+ gwt_xml = SRC + 'safehtml/SafeHtml.gwt.xml',
resources = [SRC + 'safehtml/client/safehtml.css'],
- compile_deps = ['//lib/gwt:user'],
+ deps = ['//lib/gwt:user'],
visibility = ['PUBLIC'],
)
@@ -74,25 +72,25 @@
'src/test/java/com/google/gwtexpui/safehtml/client/**/*.java',
]),
deps = [
- ':SafeHtml_lib',
+ ':SafeHtml',
'//lib:junit',
'//lib/gwt:user',
'//lib/gwt:dev',
],
- source_under_test = [':SafeHtml_lib'],
+ source_under_test = [':SafeHtml'],
)
gwt_module(
name = 'UserAgent',
srcs = glob([SRC + 'user/client/*.java']),
- gwtxml = SRC + 'user/User.gwt.xml',
- compile_deps = ['//lib/gwt:user'],
+ gwt_xml = SRC + 'user/User.gwt.xml',
+ deps = ['//lib/gwt:user'],
visibility = ['PUBLIC'],
)
-java_library2(
+java_library(
name = 'server',
srcs = glob([SRC + 'server/*.java']),
- compile_deps = ['//lib:servlet-api-3_1'],
+ provided_deps = ['//lib:servlet-api-3_1'],
visibility = ['PUBLIC'],
)
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/css/rebind/CssLinker.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/css/rebind/CssLinker.java
index 0f6992d..af80b3c 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/css/rebind/CssLinker.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/css/rebind/CssLinker.java
@@ -44,8 +44,7 @@
final ArtifactSet returnTo = new ArtifactSet();
int index = 0;
- final HashMap<String, PublicResource> css =
- new HashMap<String, PublicResource>();
+ final HashMap<String, PublicResource> css = new HashMap<>();
for (final StandardStylesheetReference ssr : artifacts
.<StandardStylesheetReference> find(StandardStylesheetReference.class)) {
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java
index 15caa34..a0fee2b 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java
@@ -74,6 +74,12 @@
case KeyCodes.KEY_ESCAPE:
namedKey(b, KeyConstants.I.keyEsc());
break;
+ case KeyCodes.KEY_LEFT:
+ namedKey(b, KeyConstants.I.keyLeft());
+ break;
+ case KeyCodes.KEY_RIGHT:
+ namedKey(b, KeyConstants.I.keyRight());
+ break;
default:
b.openSpan();
b.setStyleName(KeyResources.I.css().helpKey());
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java
index 6600a18..e2fec27 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java
@@ -35,7 +35,7 @@
}
public KeyCommandSet(final String setName) {
- map = new HashMap<Integer, KeyCommand>();
+ map = new HashMap<>();
name = setName;
}
@@ -79,7 +79,7 @@
public void add(final KeyCommandSet set) {
if (sets == null) {
- sets = new ArrayList<KeyCommandSet>();
+ sets = new ArrayList<>();
}
assert !sets.contains(set);
sets.add(set);
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
index b4cb41e..d26ca8c 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
@@ -35,4 +35,6 @@
String keyShift();
String keyEnter();
String keyEsc();
+ String keyLeft();
+ String keyRight();
}
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
index 2e12b07..76a0318 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
@@ -13,3 +13,5 @@
keyShift = Shift
keyEnter = Enter
keyEsc = Esc
+keyLeft = Left
+keyRight = Right
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
index 67a5ef4..b015274 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
@@ -75,7 +75,7 @@
final FlowPanel body = new FlowPanel();
body.add(header);
- DOM.appendChild(body.getElement(), DOM.createElement("hr"));
+ body.getElement().appendChild(DOM.createElement("hr"));
body.add(lists);
focus = new FocusPanel(body);
@@ -133,8 +133,7 @@
* the same name, so that each set name appears at most once.
*/
private static Collection<KeyCommandSet> combinedSetsByName() {
- final LinkedHashMap<String, KeyCommandSet> byName =
- new LinkedHashMap<String, KeyCommandSet>();
+ LinkedHashMap<String, KeyCommandSet> byName = new LinkedHashMap<>();
for (final KeyCommandSet set : GlobalKey.active.all.getSets()) {
KeyCommandSet v = byName.get(set.getName());
if (v == null) {
@@ -171,7 +170,7 @@
lists.resizeRows(row + keys.size());
}
- Map<KeyCommand, Integer> rows = new HashMap<KeyCommand, Integer>();
+ Map<KeyCommand, Integer> rows = new HashMap<>();
FORMAT_KEYS: for (int i = 0; i < keys.size(); i++) {
final KeyCommand k = keys.get(i);
if (rows.containsKey(k)) {
@@ -234,7 +233,7 @@
}
private List<KeyCommand> sort(final KeyCommandSet set) {
- final List<KeyCommand> keys = new ArrayList<KeyCommand>(set.getKeys());
+ final List<KeyCommand> keys = new ArrayList<>(set.getKeys());
Collections.sort(keys, new Comparator<KeyCommand>() {
@Override
public int compare(KeyCommand arg0, KeyCommand arg1) {
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java
index 46d7f51..b08b29f 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java
@@ -23,7 +23,7 @@
private static final HashMap<String, Tag> TAGS;
static {
final Tag src = new SrcTag();
- TAGS = new HashMap<String, Tag>();
+ TAGS = new HashMap<>();
TAGS.put("a", new AnchorTag());
TAGS.put("form", new FormTag());
TAGS.put("img", src);
@@ -31,8 +31,8 @@
TAGS.put("frame", src);
}
- private final ArrayList<String> names = new ArrayList<String>();
- private final ArrayList<String> values = new ArrayList<String>();
+ private final ArrayList<String> names = new ArrayList<>();
+ private final ArrayList<String> values = new ArrayList<>();
private Tag tag = ANY;
private int live;
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/HighlightSuggestOracle.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/HighlightSuggestOracle.java
index ed4e6cb..216add1 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/HighlightSuggestOracle.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/HighlightSuggestOracle.java
@@ -45,7 +45,7 @@
final Response response) {
final String qpat = getQueryPattern(request.getQuery());
final boolean html = isHTML();
- final ArrayList<Suggestion> r = new ArrayList<Suggestion>();
+ final ArrayList<Suggestion> r = new ArrayList<>();
for (final Suggestion s : response.getSuggestions()) {
r.add(new BoldSuggestion(qpat, s, html));
}
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java
index 143ecef..a71120a 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java
@@ -122,8 +122,9 @@
/** Convert bare http:// and https:// URLs into <a href> tags. */
public SafeHtml linkify() {
final String part = "(?:" +
- "[a-zA-Z0-9$_.+!*',%;:@=?#/~-]" +
+ "[a-zA-Z0-9$_+!*'%;:@=?#/~-]" +
"|&(?!lt;|gt;)" +
+ "|[.,](?!(?:\\s|$))" +
")";
return replaceAll(
"(https?://" +
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/DialogVisibleEvent.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/DialogVisibleEvent.java
index 80a940a..74218b4 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/DialogVisibleEvent.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/DialogVisibleEvent.java
@@ -22,7 +22,7 @@
public static Type<DialogVisibleHandler> getType() {
if (TYPE == null) {
- TYPE = new Type<DialogVisibleHandler>();
+ TYPE = new Type<>();
}
return TYPE;
}
diff --git a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_LinkifyTest.java b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_LinkifyTest.java
index 749df17..75c3745 100644
--- a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_LinkifyTest.java
+++ b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_LinkifyTest.java
@@ -60,6 +60,38 @@
assertEquals("A <<a href=\"http://go.here/\" target=\"_blank\">http://go.here/</a>> B", n.asString());
}
+ @Test
+ public void testLinkify_TrailingPlainLetter() {
+ final SafeHtml o = html("A http://go.here/foo B");
+ final SafeHtml n = o.linkify();
+ assertNotSame(o, n);
+ assertEquals("A <a href=\"http://go.here/foo\" target=\"_blank\">http://go.here/foo</a> B", n.asString());
+ }
+
+ @Test
+ public void testLinkify_TrailingDot() {
+ final SafeHtml o = html("A http://go.here/. B");
+ final SafeHtml n = o.linkify();
+ assertNotSame(o, n);
+ assertEquals("A <a href=\"http://go.here/\" target=\"_blank\">http://go.here/</a>. B", n.asString());
+ }
+
+ @Test
+ public void testLinkify_TrailingComma() {
+ final SafeHtml o = html("A http://go.here/, B");
+ final SafeHtml n = o.linkify();
+ assertNotSame(o, n);
+ assertEquals("A <a href=\"http://go.here/\" target=\"_blank\">http://go.here/</a>, B", n.asString());
+ }
+
+ @Test
+ public void testLinkify_TrailingDotDot() {
+ final SafeHtml o = html("A http://go.here/.. B");
+ final SafeHtml n = o.linkify();
+ assertNotSame(o, n);
+ assertEquals("A <a href=\"http://go.here/.\" target=\"_blank\">http://go.here/.</a>. B", n.asString());
+ }
+
private static SafeHtml html(String text) {
return new SafeHtmlBuilder().append(text).toSafeHtml();
}
diff --git a/gerrit-gwtui-common/BUCK b/gerrit-gwtui-common/BUCK
index 76f2db8..f4c2358 100644
--- a/gerrit-gwtui-common/BUCK
+++ b/gerrit-gwtui-common/BUCK
@@ -3,8 +3,8 @@
gwt_module(
name = 'client',
srcs = glob([SRC + 'client/**/*.java']),
- gwtxml = SRC + 'GerritGwtUICommon.gwt.xml',
- compile_deps = ['//lib/gwt:user'],
+ gwt_xml = SRC + 'GerritGwtUICommon.gwt.xml',
+ deps = ['//lib/gwt:user'],
visibility = ['PUBLIC'],
)
@@ -14,11 +14,11 @@
visibility = ['PUBLIC'],
)
-java_library2(
+java_library(
name = 'client-lib2',
srcs = glob(['src/main/**/*.java']),
resources = glob(['src/main/**/*']),
- compile_deps = ['//lib/gwt:user'],
+ provided_deps = ['//lib/gwt:user'],
visibility = ['PUBLIC'],
)
diff --git a/gerrit-gwtui/BUCK b/gerrit-gwtui/BUCK
index e978323..89b7ef7 100644
--- a/gerrit-gwtui/BUCK
+++ b/gerrit-gwtui/BUCK
@@ -1,20 +1,22 @@
include_defs('//gerrit-gwtui/gwt.defs')
include_defs('//tools/gwt-constants.defs')
+from multiprocessing import cpu_count
+
+DEPS = [
+ '//gerrit-gwtexpui:CSS',
+ '//lib:gwtjsonrpc',
+]
genrule(
name = 'ui_optdbg',
cmd = 'cd $TMP;' +
- 'unzip -q $SRCDIR/ui_dbg.zip;' +
+ 'unzip -q $(location :ui_dbg);' +
'mv' +
' gerrit_ui/gerrit_ui.nocache.js' +
- ' gerrit_ui/gerrit_dbg.nocache.js;' +
- 'unzip -qo $SRCDIR/ui_opt.zip;' +
+ ' gerrit_ui/dbg_gerrit_ui.nocache.js;' +
+ 'unzip -qo $(location :ui_opt);' +
'mkdir -p $(dirname $OUT);' +
'zip -qr $OUT .',
- srcs = [
- genfile('ui_dbg.zip'),
- genfile('ui_opt.zip'),
- ],
deps = [
':ui_dbg',
':ui_opt',
@@ -23,28 +25,37 @@
visibility = ['PUBLIC'],
)
-gwt_application(
+gwt_binary(
name = 'ui_opt',
- module_target = MODULE,
- compiler_opts = GWT_COMPILER_OPTS,
- deps = APP_DEPS + [':ui_dbg'],
+ modules = [MODULE],
+ module_deps = [':ui_module'],
+ deps = DEPS + [':ui_dbg'],
+ local_workers = cpu_count(),
+ strict = True,
+ experimental_args = GWT_COMPILER_ARGS,
+ vm_args = GWT_JVM_ARGS,
)
-gwt_application(
+gwt_binary(
name = 'ui_dbg',
- module_target = MODULE,
- compiler_opts = DEBUG_OPTS + ['-strict'],
- deps = APP_DEPS,
+ modules = [MODULE],
+ style = 'PRETTY',
+ optimize = 0,
+ module_deps = [':ui_module'],
+ deps = DEPS,
+ local_workers = cpu_count(),
+ strict = True,
+ experimental_args = GWT_COMPILER_ARGS,
+ vm_args = GWT_JVM_ARGS,
visibility = ['//:eclipse'],
)
gwt_user_agent_permutations(
name = 'ui',
module_name = 'gerrit_ui',
- module_target = MODULE,
- compiler_opts = DEBUG_OPTS + ['-draftCompile'],
- browsers = BROWSERS,
- deps = APP_DEPS,
+ modules = [MODULE],
+ module_deps = [':ui_module'],
+ deps = DEPS,
visibility = ['//:'],
)
@@ -53,9 +64,11 @@
gwt_module(
name = 'ui_module',
srcs = glob(['src/main/java/**/*.java']),
- gwtxml = 'src/main/java/%s.gwt.xml' % MODULE.replace('.', '/'),
+ gwt_xml = 'src/main/java/%s.gwt.xml' % MODULE.replace('.', '/'),
resources = glob(['src/main/java/**/*'], excludes = DIFFY),
deps = [
+ ':diffy_logo',
+ ':freebie_application_icon_set',
'//gerrit-gwtexpui:Clippy',
'//gerrit-gwtexpui:GlobalKey',
'//gerrit-gwtexpui:Progress',
@@ -67,9 +80,6 @@
'//gerrit-patch-jgit:client',
'//gerrit-prettify:client',
'//gerrit-reviewdb:client',
- ],
- compile_deps = [
- ':diffy_logo',
'//gerrit-gwtexpui:CSS',
'//lib:gwtjsonrpc',
'//lib:gwtjsonrpc_src',
@@ -86,11 +96,18 @@
prebuilt_jar(
name = 'diffy_logo',
- binary_jar = genfile('diffy_images.jar'),
+ binary_jar = ':diffy_image_files_ln',
deps = [
'//lib:LICENSE-diffy',
'//lib:LICENSE-CC-BY3.0',
- ':diffy_image_files_ln',
+ ],
+)
+
+java_library(
+ name = 'freebie_application_icon_set',
+ deps = [
+ '//lib:LICENSE-freebie_application_icon_set',
+ '//lib:LICENSE-CC-BY3.0',
],
)
@@ -113,16 +130,16 @@
'src/main/java/com/google/gerrit/GerritGwtUI.gwt.xml',
],
deps = [
- ':ui_module_lib',
- '//gerrit-common:client_lib',
- '//gerrit-extension-api:client_lib',
+ ':ui_module',
+ '//gerrit-common:client',
+ '//gerrit-extension-api:client',
'//lib:junit',
'//lib/gwt:dev',
'//lib/gwt:user',
'//lib/gwt:gwt-test-utils',
'//lib/jgit:jgit',
],
- source_under_test = [':ui_module_lib'],
+ source_under_test = [':ui_module'],
vm_args = ['-Xmx512m'],
visibility = ['//tools/eclipse:classpath'],
)
diff --git a/gerrit-gwtui/gwt.defs b/gerrit-gwtui/gwt.defs
index e407854..0e10116 100644
--- a/gerrit-gwtui/gwt.defs
+++ b/gerrit-gwtui/gwt.defs
@@ -26,36 +26,35 @@
}
MODULE = 'com.google.gerrit.GerritGwtUI'
-DEBUG_OPTS = [
- '-style', 'PRETTY',
- '-optimize', '0',
-]
-
-APP_DEPS = [':ui_module']
-
def gwt_user_agent_permutations(
name,
module_name,
- module_target,
- compiler_opts = [],
+ modules,
+ style = 'PRETTY',
+ optimize = 0,
+ draft_compile = True,
+ module_deps = [],
deps = [],
- browsers = [],
+ browsers = BROWSERS,
visibility = []):
+ from multiprocessing import cpu_count
for ua in browsers:
impl = ua
if ua in ALIASES:
impl = ALIASES[ua]
xml = ''.join([
"<module rename-to='%s'>" % module_name,
- "<inherits name='%s'/>" % module_target,
+ "<inherits name='%s'/>" % modules[0],
"<set-property name='user.agent' value='%s'/>" % impl,
"<set-property name='locale' value='default'/>",
"</module>",
])
- gwt = '%s_%s.gwt.xml' % (module_target.replace('.', '/'), ua)
- jar = '%s_%s.gwtxml.jar' % (name, ua)
+ gwt = '%s_%s.gwt.xml' % (modules[0].replace('.', '/'), ua)
+ gwt_name = '%s_%s' % (name, ua)
+ jar = '%s.gwtxml.jar' % (gwt_name)
+
genrule(
- name = '%s_%s_gwtxml_gen' % (name, ua),
+ name = '%s_gwtxml_gen' % gwt_name,
cmd = 'cd $TMP;' +
('mkdir -p $(dirname %s);' % gwt) +
('echo "%s">%s;' % (xml, gwt)) +
@@ -63,15 +62,21 @@
out = jar,
)
prebuilt_jar(
- name = '%s_%s_gwtxml_lib' % (name, ua),
- binary_jar = genfile(jar),
- deps = [':%s_%s_gwtxml_gen' % (name, ua)],
+ name = '%s_gwtxml_lib' % gwt_name,
+ binary_jar = ':%s_gwtxml_gen' % gwt_name,
+ gwt_jar = ':%s_gwtxml_gen' % gwt_name,
)
- gwt_application(
- name = '%s_%s' % (name, ua),
- module_target = module_target + '_' + ua,
- compiler_opts = compiler_opts,
- deps = deps + [':%s_%s_gwtxml_lib' % (name, ua)],
+ gwt_binary(
+ name = gwt_name,
+ modules = [modules[0] + '_' + ua],
+ style = style,
+ optimize = optimize,
+ draft_compile = draft_compile,
+ module_deps = module_deps + [':%s_gwtxml_lib' % gwt_name],
+ deps = deps,
+ local_workers = cpu_count(),
+ strict = True,
+ experimental_args = GWT_COMPILER_ARGS,
+ vm_args = GWT_JVM_ARGS,
visibility = visibility,
)
-
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 666c3e2..2ad9a5e 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
@@ -21,6 +21,7 @@
import static com.google.gerrit.common.PageLinks.ADMIN_PROJECTS;
import static com.google.gerrit.common.PageLinks.DASHBOARDS;
import static com.google.gerrit.common.PageLinks.MINE;
+import static com.google.gerrit.common.PageLinks.MY_GROUPS;
import static com.google.gerrit.common.PageLinks.PROJECTS;
import static com.google.gerrit.common.PageLinks.QUERY;
import static com.google.gerrit.common.PageLinks.REGISTER;
@@ -55,6 +56,7 @@
import com.google.gerrit.client.admin.CreateGroupScreen;
import com.google.gerrit.client.admin.CreateProjectScreen;
import com.google.gerrit.client.admin.GroupListScreen;
+import com.google.gerrit.client.admin.MyGroupsListScreen;
import com.google.gerrit.client.admin.PluginListScreen;
import com.google.gerrit.client.admin.ProjectAccessScreen;
import com.google.gerrit.client.admin.ProjectBranchesScreen;
@@ -233,7 +235,12 @@
extension(token);
} else if (matchExact(MINE, token)) {
- Gerrit.display(token, mine(token));
+ String defaultScreenToken = Gerrit.getDefaultScreenToken();
+ if (defaultScreenToken != null && !MINE.equals(defaultScreenToken)) {
+ select(defaultScreenToken);
+ } else {
+ Gerrit.display(token, mine(token));
+ }
} else if (matchPrefix("/dashboard/", token)) {
dashboard(token);
@@ -253,6 +260,9 @@
} else if (matchPrefix("/admin/", token)) {
admin(token);
+ } else if (matchExact(MY_GROUPS, token)) {
+ Gerrit.display(token, new MyGroupsListScreen());
+
} else if (/* DEPRECATED URL */matchPrefix("/c2/", token)) {
changeScreen2 = true;
change(token);
@@ -440,6 +450,17 @@
return;
}
+ if (rest.equals("self")) {
+ if (Gerrit.isSignedIn()) {
+ Gerrit.display(token, new AccountDashboardScreen(Gerrit.getUserAccount().getId()));
+ } else {
+ Screen s = new AccountDashboardScreen(null);
+ s.setRequiresSignIn(true);
+ Gerrit.display(token, s);
+ }
+ return;
+ }
+
if (rest.startsWith("?")) {
Gerrit.display(token, new CustomDashboardScreen(rest.substring(1)));
return;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
index 4b6b092..5b51b48 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
@@ -180,21 +180,23 @@
public static AccountInfo asInfo(Account acct) {
if (acct == null) {
- return AccountInfo.create(0, null, null);
+ return AccountInfo.create(0, null, null, null);
}
return AccountInfo.create(
acct.getId() != null ? acct.getId().get() : 0,
acct.getFullName(),
- acct.getPreferredEmail());
+ acct.getPreferredEmail(),
+ acct.getUserName());
}
public static AccountInfo asInfo(com.google.gerrit.common.data.AccountInfo acct) {
if (acct == null) {
- return AccountInfo.create(0, null, null);
+ return AccountInfo.create(0, null, null, null);
}
return AccountInfo.create(
acct.getId() != null ? acct.getId().get() : 0,
acct.getFullName(),
- acct.getPreferredEmail());
+ acct.getPreferredEmail(),
+ acct.getUsername());
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
index b7857e4..27a4b53 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
@@ -18,8 +18,10 @@
import static com.google.gerrit.common.data.GlobalCapability.CREATE_PROJECT;
import static com.google.gerrit.common.data.GlobalCapability.VIEW_PLUGINS;
+import com.google.gerrit.client.account.AccountApi;
import com.google.gerrit.client.account.AccountCapabilities;
import com.google.gerrit.client.account.AccountInfo;
+import com.google.gerrit.client.account.Preferences;
import com.google.gerrit.client.admin.ProjectScreen;
import com.google.gerrit.client.api.ApiGlue;
import com.google.gerrit.client.api.PluginLoader;
@@ -30,14 +32,15 @@
import com.google.gerrit.client.extensions.TopMenuItem;
import com.google.gerrit.client.extensions.TopMenuList;
import com.google.gerrit.client.patches.PatchScreen;
+import com.google.gerrit.client.rpc.CallbackGroup;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.ui.LinkMenuBar;
import com.google.gerrit.client.ui.LinkMenuItem;
import com.google.gerrit.client.ui.MorphingTabPanel;
import com.google.gerrit.client.ui.PatchLink;
+import com.google.gerrit.client.ui.ProjectLinkMenuItem;
import com.google.gerrit.client.ui.Screen;
-import com.google.gerrit.client.ui.ScreenLoadEvent;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.data.GerritConfig;
import com.google.gerrit.common.data.GitwebConfig;
@@ -48,7 +51,6 @@
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
import com.google.gerrit.reviewdb.client.AuthType;
-import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
@@ -70,6 +72,7 @@
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.Location;
+import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FocusPanel;
@@ -104,6 +107,7 @@
private static GerritConfig myConfig;
private static HostPageData.Theme myTheme;
private static Account myAccount;
+ private static String defaultScreenToken;
private static AccountDiffPreference myAccountDiffPref;
private static String xGerritAuth;
@@ -211,6 +215,10 @@
}
}
+ public static void selectMenu(LinkMenuBar bar) {
+ menuLeft.selectTab(menuLeft.getWidgetIndex(bar));
+ }
+
/**
* Update the current history token after a screen change.
* <p>
@@ -265,6 +273,10 @@
return topMenu.isVisible();
}
+ public static String getDefaultScreenToken() {
+ return defaultScreenToken;
+ }
+
public static RootPanel getBottomMenu() {
return bottomMenu;
}
@@ -324,7 +336,8 @@
} else if (token.startsWith("/")) {
token = token.substring(1);
}
- return selfRedirect("/login/" + token);
+
+ return selfRedirect("login/") + URL.encodePathSegment("#/" + token);
}
public static String selfRedirect(String suffix) {
@@ -449,8 +462,6 @@
vs = "dev";
}
- btmmenu.add(new InlineLabel(C.keyHelp()));
- btmmenu.add(new InlineLabel(" | "));
btmmenu.add(new InlineHTML(M.poweredBy(vs)));
final String reportBugText = getConfig().getReportBugText();
@@ -461,6 +472,8 @@
a.setStyleName("");
btmmenu.add(new InlineLabel(" | "));
btmmenu.add(a);
+ btmmenu.add(new InlineLabel(" | "));
+ btmmenu.add(new InlineLabel(C.keyHelp()));
}
private void onModuleLoad2(HostPageData hpd) {
@@ -537,7 +550,7 @@
applyUserPreferences();
populateBottomMenu(bottomMenu, hpd);
- refreshMenuBar();
+ refreshMenuBar(false);
History.addValueChangeHandler(new ValueChangeHandler<String>() {
@Override
@@ -547,18 +560,27 @@
});
JumpKeys.register(body);
- String token = History.getToken();
- if (token.isEmpty()) {
- token = isSignedIn()
- ? PageLinks.MINE
- : PageLinks.toChangeQuery("status:open");
- }
-
saveDefaultTheme();
if (hpd.messages != null) {
new MessageOfTheDayBar(hpd.messages).show();
}
- PluginLoader.load(hpd.plugins, token);
+ CallbackGroup cbg = new CallbackGroup();
+ if (isSignedIn()) {
+ AccountApi.self().view("preferences").get(cbg.add(createMyMenuBarCallback()));
+ }
+ PluginLoader.load(hpd.plugins,
+ cbg.addFinal(new GerritCallback<VoidResult>() {
+ @Override
+ public void onSuccess(VoidResult result) {
+ String token = History.getToken();
+ if (token.isEmpty()) {
+ token = isSignedIn()
+ ? PageLinks.MINE
+ : PageLinks.toChangeQuery("status:open");
+ }
+ display(token);
+ }
+ }));
}
private void saveDefaultTheme() {
@@ -568,6 +590,10 @@
}
public static void refreshMenuBar() {
+ refreshMenuBar(true);
+ }
+
+ private static void refreshMenuBar(boolean populateMyMenu) {
menuLeft.clear();
menuRight.clear();
@@ -585,14 +611,12 @@
menuLeft.add(m, C.menuAll());
if (signedIn) {
- m = new LinkMenuBar();
- menuBars.put(GerritTopMenu.MY.menuName, m);
- addLink(m, C.menuMyChanges(), PageLinks.MINE);
- addLink(m, C.menuMyDrafts(), PageLinks.toChangeQuery("is:draft"));
- addLink(m, C.menuMyDraftComments(), PageLinks.toChangeQuery("has:draft"));
- addLink(m, C.menuMyWatchedChanges(), PageLinks.toChangeQuery("is:watched status:open"));
- addLink(m, C.menuMyStarredChanges(), PageLinks.toChangeQuery("is:starred"));
- menuLeft.add(m, C.menuMine());
+ LinkMenuBar myBar = new LinkMenuBar();
+ menuBars.put(GerritTopMenu.MY.menuName, myBar);
+ if (populateMyMenu) {
+ AccountApi.self().view("preferences").get(createMyMenuBarCallback());
+ }
+ menuLeft.add(myBar, C.menuMine());
menuLeft.selectTab(1);
} else {
menuLeft.selectTab(0);
@@ -609,22 +633,21 @@
addDiffLink(diffBar, C.menuDiffPatchSets(), PatchScreen.TopView.PATCH_SETS);
addDiffLink(diffBar, C.menuDiffFiles(), PatchScreen.TopView.FILES);
- final LinkMenuBar projectsBar = new LinkMenuBar() {
- @Override
- public void onScreenLoad(ScreenLoadEvent event) {
- if (event.getScreen() instanceof ProjectScreen) {
- menuLeft.selectTab(menuLeft.getWidgetIndex(this));
- }
- }
- };
+ final LinkMenuBar projectsBar = new LinkMenuBar();
menuBars.put(GerritTopMenu.PROJECTS.menuName, projectsBar);
addLink(projectsBar, C.menuProjectsList(), PageLinks.ADMIN_PROJECTS);
- addProjectLink(projectsBar, C.menuProjectsInfo(), ProjectScreen.INFO);
- addProjectLink(projectsBar, C.menuProjectsBranches(), ProjectScreen.BRANCH);
- addProjectLink(projectsBar, C.menuProjectsAccess(), ProjectScreen.ACCESS);
+ projectsBar.addItem(new ProjectLinkMenuItem(C.menuProjectsInfo(), ProjectScreen.INFO));
+ projectsBar.addItem(new ProjectLinkMenuItem(C.menuProjectsBranches(), ProjectScreen.BRANCH));
+ projectsBar.addItem(new ProjectLinkMenuItem(C.menuProjectsAccess(), ProjectScreen.ACCESS));
final LinkMenuItem dashboardsMenuItem =
- addProjectLink(projectsBar, C.menuProjectsDashboards(),
- ProjectScreen.DASHBOARDS);
+ new ProjectLinkMenuItem(C.menuProjectsDashboards(),
+ ProjectScreen.DASHBOARDS) {
+ protected boolean match(String token) {
+ return super.match(token) ||
+ (!getTargetHistoryToken().isEmpty() && ("/admin" + token).startsWith(getTargetHistoryToken()));
+ }
+ };
+ projectsBar.addItem(dashboardsMenuItem);
menuLeft.add(projectsBar, C.menuProjects());
if (signedIn) {
@@ -695,6 +718,15 @@
});
break;
+ case OAUTH:
+ menuRight.addItem(C.menuSignIn(), new Command() {
+ @Override
+ public void execute() {
+ doSignIn(History.getToken());
+ }
+ });
+ break;
+
case OPENID_SSO:
menuRight.addItem(C.menuSignIn(), new Command() {
public void execute() {
@@ -748,6 +780,27 @@
});
}
+ private static AsyncCallback<Preferences> createMyMenuBarCallback() {
+ return new GerritCallback<Preferences>() {
+ @Override
+ public void onSuccess(Preferences prefs) {
+ LinkMenuBar myBar = menuBars.get(GerritTopMenu.MY.menuName);
+ myBar.clear();
+ List<TopMenuItem> myMenuItems = Natives.asList(prefs.my());
+ String url = null;
+ if (!myMenuItems.isEmpty()) {
+ if (myMenuItems.get(0).getUrl().startsWith("#")) {
+ url = myMenuItems.get(0).getUrl().substring(1);
+ }
+ for (TopMenuItem item : myMenuItems) {
+ addExtensionLink(myBar, item);
+ }
+ }
+ defaultScreenToken = url;
+ }
+ };
+ }
+
public static void applyUserPreferences() {
if (myAccount != null) {
final AccountGeneralPreferences p = myAccount.getGeneralPreferences();
@@ -839,32 +892,6 @@
});
}
- private static LinkMenuItem addProjectLink(final LinkMenuBar m, final String text,
- final String panel) {
- LinkMenuItem i = new LinkMenuItem(text, "") {
- @Override
- public void onScreenLoad(ScreenLoadEvent event) {
- Screen screen = event.getScreen();
- Project.NameKey projectKey;
- if (screen instanceof ProjectScreen) {
- projectKey = ((ProjectScreen)screen).getProjectKey();
- } else {
- projectKey = ProjectScreen.getSavedKey();
- }
-
- if (projectKey != null) {
- setVisible(true);
- setTargetHistoryToken(Dispatcher.toProjectAdmin(projectKey, panel));
- } else {
- setVisible(false);
- }
- super.onScreenLoad(event);
- }
- };
- m.addItem(i);
- return i;
- }
-
private static void addDiffLink(final LinkMenuBar m, final String text,
final PatchScreen.Type type) {
m.addItem(new LinkMenuItem(text, "") {
@@ -890,15 +917,26 @@
}
private static void addExtensionLink(LinkMenuBar m, TopMenuItem item) {
- Anchor atag = anchor(item.getName(), isAbsolute(item.getUrl())
- ? item.getUrl()
- : selfRedirect(item.getUrl()));
-
- atag.setTarget(item.getTarget());
- if (item.getId() != null) {
- atag.getElement().setAttribute("id", item.getId());
+ if (item.getUrl().startsWith("#")
+ && (item.getTarget() == null || item.getTarget().isEmpty())) {
+ LinkMenuItem a =
+ new LinkMenuItem(item.getName(), item.getUrl().substring(1));
+ if (item.getId() != null) {
+ a.getElement().setAttribute("id", item.getId());
+ }
+ m.addItem(a);
+ } else {
+ Anchor atag = anchor(item.getName(), isAbsolute(item.getUrl())
+ ? item.getUrl()
+ : selfRedirect(item.getUrl()));
+ if (item.getTarget() != null && !item.getTarget().isEmpty()) {
+ atag.setTarget(item.getTarget());
+ }
+ if (item.getId() != null) {
+ atag.getElement().setAttribute("id", item.getId());
+ }
+ m.add(atag);
}
- m.add(atag);
}
private static boolean isAbsolute(String url) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
index 73c270b..5ba520c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
@@ -117,4 +117,9 @@
String projectAccessProposeForReviewHint();
String userCannotVoteToolTip();
+
+ String stringListPanelAdd();
+ String stringListPanelDelete();
+ String stringListPanelUp();
+ String stringListPanelDown();
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
index 63b8fe1..58a6d08 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
@@ -100,3 +100,8 @@
projectAccessProposeForReviewHint = You may propose these modifications to the project owners by clicking on 'Save for Review'.
userCannotVoteToolTip = User cannot vote in this category
+
+stringListPanelAdd = Add
+stringListPanelDelete = Delete
+stringListPanelUp = Up
+stringListPanelDown = Down
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
index 98b9534..42a8d74 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
@@ -85,7 +85,9 @@
String createGroupLink();
String createProjectPanel();
String dataCell();
+ String dataCellHidden();
String dataHeader();
+ String dataHeaderHidden();
String diffLinkCell();
String diffText();
String diffTextCONTEXT();
@@ -232,6 +234,7 @@
String sshHostKeyPanelKnownHostEntry();
String sshKeyPanelEncodedKey();
String sshKeyPanelInvalid();
+ String stringListPanelButtons();
String topMostCell();
String topmenu();
String topmenuMenuLeft();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java
index e50445d..2b78fa4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java
@@ -28,6 +28,12 @@
@Source("arrowRight.gif")
public ImageResource arrowRight();
+ @Source("arrowUp.png")
+ public ImageResource arrowUp();
+
+ @Source("arrowDown.png")
+ public ImageResource arrowDown();
+
@Source("editText.png")
public ImageResource edit();
@@ -70,6 +76,9 @@
@Source("warning.png")
public ImageResource warning();
+ @Source("listAdd.png")
+ public ImageResource listAdd();
+
@Source("merge.png")
public ImageResource merge();
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.java
index fa569b8..b6ea636 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.java
@@ -52,6 +52,8 @@
for (HostPageData.Message m : motd) {
b.openDiv();
b.append(SafeHtml.asis(m.html));
+ b.openElement("hr");
+ b.closeSelf();
b.closeDiv();
}
}
@@ -74,7 +76,7 @@
}
private static List<HostPageData.Message> filter(List<HostPageData.Message> in) {
- List<HostPageData.Message> show = new ArrayList<HostPageData.Message>();
+ List<HostPageData.Message> show = new ArrayList<>();
for (HostPageData.Message m : in) {
if (Cookies.getCookie(cookieName(m)) == null) {
show.add(m);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
index 0715aee..e92e613 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
@@ -81,6 +81,7 @@
suggestions.add("comment:");
suggestions.add("conflicts:");
suggestions.add("project:");
+ suggestions.add("projects:");
suggestions.add("parentproject:");
suggestions.add("branch:");
suggestions.add("topic:");
@@ -101,6 +102,7 @@
suggestions.add("is:owner");
suggestions.add("is:reviewer");
suggestions.add("is:open");
+ suggestions.add("is:pending");
suggestions.add("is:draft");
suggestions.add("is:closed");
suggestions.add("is:submitted");
@@ -110,12 +112,18 @@
suggestions.add("status:");
suggestions.add("status:open");
+ suggestions.add("status:pending");
suggestions.add("status:reviewed");
suggestions.add("status:submitted");
suggestions.add("status:closed");
suggestions.add("status:merged");
suggestions.add("status:abandoned");
+ suggestions.add("added:");
+ suggestions.add("deleted:");
+ suggestions.add("delta:");
+ suggestions.add("size:");
+
suggestions.add("AND");
suggestions.add("OR");
suggestions.add("NOT");
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/StringListPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/StringListPanel.java
new file mode 100644
index 0000000..bc36654
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/StringListPanel.java
@@ -0,0 +1,359 @@
+// 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;
+
+import com.google.gerrit.client.ui.NavigationTable;
+import com.google.gerrit.client.ui.OnEditEnabler;
+import com.google.gerrit.client.ui.SmallHeading;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.dom.client.KeyPressHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FocusWidget;
+import com.google.gwt.user.client.ui.HasEnabled;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.ImageResourceRenderer;
+import com.google.gwtexpui.globalkey.client.NpTextBox;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StringListPanel extends FlowPanel implements HasEnabled {
+ private final StringListTable t;
+ private HorizontalPanel titlePanel;
+ protected final HorizontalPanel buttonPanel;
+ private final Button deleteButton;
+ private Image info;
+ protected FocusWidget widget;
+
+ public StringListPanel(String title, List<String> fieldNames, FocusWidget w,
+ boolean autoSort) {
+ widget = w;
+ if (title != null) {
+ titlePanel = new HorizontalPanel();
+ SmallHeading titleLabel = new SmallHeading(title);
+ titlePanel.add(titleLabel);
+ add(titlePanel);
+ }
+
+ t = new StringListTable(fieldNames, autoSort);
+ add(t);
+
+ buttonPanel = new HorizontalPanel();
+ buttonPanel.setStyleName(Gerrit.RESOURCES.css().stringListPanelButtons());
+ deleteButton = new Button(Gerrit.C.stringListPanelDelete());
+ deleteButton.setEnabled(false);
+ deleteButton.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ widget.setEnabled(true);
+ t.deleteChecked();
+ }
+ });
+ buttonPanel.add(deleteButton);
+ add(buttonPanel);
+ }
+
+ public void display(List<List<String>> values) {
+ t.display(values);
+ }
+
+ public void setInfo(String msg) {
+ if (info == null && titlePanel != null) {
+ info = new Image(Gerrit.RESOURCES.info());
+ titlePanel.add(info);
+ }
+ if (info != null) {
+ info.setTitle(msg);
+ }
+ }
+
+ public List<List<String>> getValues() {
+ return t.getValues();
+ }
+
+ public List<String> getValues(int i) {
+ List<List<String>> allValuesList = getValues();
+ List<String> singleValueList = new ArrayList<>(allValuesList.size());
+ for (List<String> values : allValuesList) {
+ singleValueList.add(values.get(i));
+ }
+ return singleValueList;
+ }
+
+ private class StringListTable extends NavigationTable<List<String>> {
+ private final Button addButton;
+ private final List<NpTextBox> inputs;
+ private final boolean autoSort;
+
+ StringListTable(List<String> names, boolean autoSort) {
+ this.autoSort = autoSort;
+
+ addButton =
+ new Button(new ImageResourceRenderer().render(Gerrit.RESOURCES.listAdd()));
+ addButton.setTitle(Gerrit.C.stringListPanelAdd());
+ OnEditEnabler e = new OnEditEnabler(addButton);
+ inputs = new ArrayList<>();
+
+ FlexCellFormatter fmt = table.getFlexCellFormatter();
+ fmt.addStyleName(0, 0, Gerrit.RESOURCES.css().iconHeader());
+ fmt.addStyleName(0, 0, Gerrit.RESOURCES.css().leftMostCell());
+ for (int i = 0; i < names.size(); i++) {
+ fmt.addStyleName(0, i + 1, Gerrit.RESOURCES.css().dataHeader());
+ table.setText(0, i + 1, names.get(i));
+
+ NpTextBox input = new NpTextBox();
+ input.setVisibleLength(35);
+ input.addKeyPressHandler(new KeyPressHandler() {
+ @Override
+ public void onKeyPress(KeyPressEvent event) {
+ if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
+ widget.setEnabled(true);
+ add();
+ }
+ }
+ });
+ inputs.add(input);
+ fmt.addStyleName(1, i + 1, Gerrit.RESOURCES.css().dataHeader());
+ table.setWidget(1, i + 1, input);
+ e.listenTo(input);
+ }
+ addButton.setEnabled(false);
+
+ addButton.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ widget.setEnabled(true);
+ add();
+ }
+ });
+ fmt.addStyleName(1, 0, Gerrit.RESOURCES.css().iconHeader());
+ fmt.addStyleName(1, 0, Gerrit.RESOURCES.css().leftMostCell());
+ table.setWidget(1, 0, addButton);
+
+ if (!autoSort) {
+ fmt.addStyleName(0, names.size() + 1, Gerrit.RESOURCES.css().iconHeader());
+ fmt.addStyleName(0, names.size() + 2, Gerrit.RESOURCES.css().iconHeader());
+ fmt.addStyleName(1, names.size() + 1, Gerrit.RESOURCES.css().iconHeader());
+ fmt.addStyleName(1, names.size() + 2, Gerrit.RESOURCES.css().iconHeader());
+ }
+ }
+
+ void display(List<List<String>> values) {
+ for (int row = 2; row < table.getRowCount(); row++) {
+ table.removeRow(row--);
+ }
+ int row = 2;
+ for (List<String> v : values) {
+ populate(row, v);
+ row++;
+ }
+ updateNavigationLinks();
+ }
+
+ List<List<String>> getValues() {
+ List<List<String>> values = new ArrayList<>();
+ for (int row = 2; row < table.getRowCount(); row++) {
+ values.add(getRowItem(row));
+ }
+ return values;
+ }
+
+ @Override
+ protected List<String> getRowItem(int row) {
+ List<String> v = new ArrayList<>();
+ for (int i = 0; i < inputs.size(); i++) {
+ v.add(table.getText(row, i + 1));
+ }
+ return v;
+ }
+
+ private void populate(final int row, List<String> values) {
+ FlexCellFormatter fmt = table.getFlexCellFormatter();
+ fmt.addStyleName(row, 0, Gerrit.RESOURCES.css().iconCell());
+ fmt.addStyleName(row, 0, Gerrit.RESOURCES.css().leftMostCell());
+ CheckBox checkBox = new CheckBox();
+ checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
+ @Override
+ public void onValueChange(ValueChangeEvent<Boolean> event) {
+ enableDelete();
+ }
+ });
+ table.setWidget(row, 0, checkBox);
+ for (int i = 0; i < values.size(); i++) {
+ fmt.addStyleName(row, i + 1, Gerrit.RESOURCES.css().dataCell());
+ table.setText(row, i + 1, values.get(i));
+ }
+ if (!autoSort) {
+ fmt.addStyleName(row, values.size() + 1, Gerrit.RESOURCES.css().iconCell());
+ fmt.addStyleName(row, values.size() + 2, Gerrit.RESOURCES.css().dataCell());
+
+ Image down = new Image(Gerrit.RESOURCES.arrowDown());
+ down.setTitle(Gerrit.C.stringListPanelDown());
+ down.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ moveDown(row);
+ }
+ });
+ table.setWidget(row, values.size() + 1, down);
+
+ Image up = new Image(Gerrit.RESOURCES.arrowUp());
+ up.setTitle(Gerrit.C.stringListPanelUp());
+ up.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ moveUp(row);
+ }
+ });
+ table.setWidget(row, values.size() + 2, up);
+ }
+ }
+
+ @Override
+ protected void onCellSingleClick(Event event, int row, int column) {
+ if (column == inputs.size() + 1 && row >= 2
+ && row < table.getRowCount() - 2) {
+ moveDown(row);
+ } else if (column == inputs.size() + 2 && row > 2) {
+ moveUp(row);
+ }
+ }
+
+ void moveDown(int row) {
+ if (row < table.getRowCount() - 1) {
+ swap(row, row + 1);
+ }
+ }
+
+ void moveUp(int row) {
+ if (row > 2) {
+ swap(row - 1, row);
+ }
+ }
+
+ void swap(int row1, int row2) {
+ List<String> value = getRowItem(row1);
+ List<String> nextValue = getRowItem(row2);
+ populate(row1, nextValue);
+ populate(row2, value);
+ updateNavigationLinks();
+ widget.setEnabled(true);
+ }
+
+ private void updateNavigationLinks() {
+ if (!autoSort) {
+ for (int row = 2; row < table.getRowCount(); row++) {
+ table.getWidget(row, inputs.size() + 1).setVisible(
+ row < table.getRowCount() - 1);
+ table.getWidget(row, inputs.size() + 2).setVisible(row > 2);
+ }
+ }
+ }
+
+ void add() {
+ List<String> values = new ArrayList<>();
+ for (NpTextBox input : inputs) {
+ values.add(input.getValue().trim());
+ input.setValue("");
+ }
+ insert(values);
+ }
+
+ void insert(List<String> v) {
+ int insertPos = table.getRowCount();
+ if (autoSort) {
+ for (int row = 1; row < table.getRowCount(); row++) {
+ int compareResult = v.get(0).compareTo(table.getText(row, 1));
+ if (compareResult < 0) {
+ insertPos = row;
+ break;
+ } else if (compareResult == 0) {
+ return;
+ }
+ }
+ }
+ table.insertRow(insertPos);
+ populate(insertPos, v);
+ updateNavigationLinks();
+ }
+
+ void enableDelete() {
+ for (int row = 2; row < table.getRowCount(); row++) {
+ if (((CheckBox) table.getWidget(row, 0)).getValue()) {
+ deleteButton.setEnabled(true);
+ return;
+ }
+ }
+ deleteButton.setEnabled(false);
+ }
+
+ void deleteChecked() {
+ deleteButton.setEnabled(false);
+ for (int row = 2; row < table.getRowCount(); row++) {
+ if (((CheckBox) table.getWidget(row, 0)).getValue()) {
+ table.removeRow(row--);
+ }
+ }
+ updateNavigationLinks();
+ }
+
+ @Override
+ protected void onOpenRow(int row) {
+ }
+
+ @Override
+ protected Object getRowItemKey(List<String> item) {
+ return item.get(0);
+ }
+
+ void setEnabled(boolean enabled) {
+ addButton.setVisible(enabled);
+ for (NpTextBox input : inputs) {
+ input.setEnabled(enabled);
+ }
+ for (int row = 2; row < table.getRowCount(); row++) {
+ table.getWidget(row, 0).setVisible(enabled);
+ if (!autoSort) {
+ table.getWidget(row, inputs.size() + 1).setVisible(enabled);
+ table.getWidget(row, inputs.size() + 2).setVisible(enabled);
+ }
+ }
+ if (enabled) {
+ updateNavigationLinks();
+ }
+ }
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return deleteButton.isVisible();
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ t.setEnabled(enabled);
+ deleteButton.setVisible(enabled);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/WebLinkInfo.java
similarity index 61%
copy from gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
copy to gerrit-gwtui/src/main/java/com/google/gerrit/client/WebLinkInfo.java
index 72b0c8b..64b9cb8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_58.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/WebLinkInfo.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 The Android Open Source Project
+// 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.
@@ -12,14 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.schema;
+package com.google.gerrit.client;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
+import com.google.gwt.core.client.JavaScriptObject;
-public class Schema_58 extends SchemaVersion {
- @Inject
- Schema_58(Provider<Schema_57> prior) {
- super(prior);
+public class WebLinkInfo extends JavaScriptObject {
+
+ public final native String name() /*-{ return this.name; }-*/;
+ public final native String url() /*-{ return this.url; }-*/;
+
+ protected WebLinkInfo() {
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java
index b0a6160..f52eb31 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java
@@ -35,10 +35,21 @@
String useFlashClipboard();
String copySelfOnEmails();
String reversePatchSetOrder();
- String showUsernameInReviewCategory();
+ String reviewCategoryLabel();
+ String messageShowInReviewCategoryNone();
+ String messageShowInReviewCategoryName();
+ String messageShowInReviewCategoryEmail();
+ String messageShowInReviewCategoryUsername();
+ String messageShowInReviewCategoryAbbrev();
String buttonSaveChanges();
String showRelativeDateInChangeTable();
String showSizeBarInChangeTable();
+ String showLegacycidInChangeTable();
+ String myMenu();
+ String myMenuInfo();
+ String myMenuName();
+ String myMenuUrl();
+ String myMenuReset();
String changeScreenOldUi();
String changeScreenNewUi();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
index 63cb871..5d48bb8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
@@ -9,7 +9,14 @@
useFlashClipboard = Use Flash Clipboard Widget
copySelfOnEmails = CC Me On Comments I Write
reversePatchSetOrder = Display Patch Sets In Reverse Order (deprecated: Old Change Screen)
-showUsernameInReviewCategory = Display Person Name In Review Category
+
+reviewCategoryLabel = Display In Review Category
+messageShowInReviewCategoryNone = None (default)
+messageShowInReviewCategoryName = Show Name
+messageShowInReviewCategoryEmail = Show Email
+messageShowInReviewCategoryUsername = Show Username
+messageShowInReviewCategoryAbbrev = Show Abbreviated Name
+
maximumPageSizeFieldLabel = Maximum Page Size:
commentVisibilityLabel = Comment Visibility (deprecated: Old Change Screen):
changeScreenLabel = Change View:
@@ -19,6 +26,14 @@
buttonSaveChanges = Save Changes
showRelativeDateInChangeTable = Show Relative Dates In Changes Table
showSizeBarInChangeTable = Show Change Sizes As Colored Bars In Changes Table
+showLegacycidInChangeTable = Show Change Number In Changes Table
+myMenu = My Menu
+myMenuInfo = \
+ Menu items for the 'My' top level menu. \
+ The first menu item defines the default screen.
+myMenuName = Name
+myMenuUrl = URL
+myMenuReset = Reset
changeScreenOldUi = Old Screen
changeScreenNewUi = New Screen
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountInfo.java
index 26d551f..3ac626c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountInfo.java
@@ -21,6 +21,7 @@
public final native int _account_id() /*-{ return this._account_id || 0; }-*/;
public final native String name() /*-{ return this.name; }-*/;
public final native String email() /*-{ return this.email; }-*/;
+ public final native String username() /*-{ return this.username; }-*/;
/**
* @return true if the server supplied avatar information about this account.
@@ -46,8 +47,9 @@
/*-{ return this.avatars }-*/;
public static native AccountInfo create(int id, String name,
- String email) /*-{
- return {'_account_id': id, 'name': name, 'email': email};
+ String email, String username) /*-{
+ return {'_account_id': id, 'name': name, 'email': email,
+ 'username': username};
}-*/;
protected AccountInfo() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
index 5c66f3c..8a4666b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
@@ -40,6 +40,7 @@
p.manualReview(in.isManualReview());
p.renderEntireFile(in.isRenderEntireFile());
p.theme(in.getTheme());
+ p.hideEmptyPane(in.isHideEmptyPane());
return p;
}
@@ -59,6 +60,7 @@
p.setManualReview(manualReview());
p.setRenderEntireFile(renderEntireFile());
p.setTheme(theme());
+ p.setHideEmptyPane(hideEmptyPane());
}
public final void ignoreWhitespace(Whitespace i) {
@@ -84,6 +86,7 @@
public final native void expandAllComments(boolean e) /*-{ this.expand_all_comments = e }-*/;
public final native void manualReview(boolean r) /*-{ this.manual_review = r }-*/;
public final native void renderEntireFile(boolean r) /*-{ this.render_entire_file = r }-*/;
+ public final native void hideEmptyPane(boolean s) /*-{ this.hide_empty_pane = s }-*/;
public final void showLineNumbers(boolean s) { hideLineNumbers(!s); }
public final Whitespace ignoreWhitespace() {
@@ -111,6 +114,7 @@
public final native boolean expandAllComments() /*-{ return this.expand_all_comments || false }-*/;
public final native boolean manualReview() /*-{ return this.manual_review || false }-*/;
public final native boolean renderEntireFile() /*-{ return this.render_entire_file || false }-*/;
+ public final native boolean hideEmptyPane() /*-{ return this.hide_empty_pane || false }-*/;
public final boolean showLineNumbers() { return !hideLineNumbers(); }
public final boolean autoReview() { return !manualReview(); }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java
index 4703ef7..1f4d7ed 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java
@@ -59,7 +59,8 @@
});
add(deleteIdentity);
- if (Gerrit.getConfig().getAuthType() == AuthType.OPENID) {
+ if (Gerrit.getConfig().getAuthType() == AuthType.OPENID
+ || Gerrit.getConfig().getAuthType() == AuthType.OAUTH) {
Button linkIdentity = new Button(Util.C.buttonLinkIdentity());
linkIdentity.addClickHandler(new ClickHandler() {
@Override
@@ -243,15 +244,15 @@
//
return "";
- } else if (k.isScheme(OpenIdUrls.URL_GOOGLE)) {
+ } else if (k.isScheme("https://www.google.com/accounts/o8/id")) {
return OpenIdUtil.C.nameGoogle();
+ } else if (k.isScheme(OpenIdUrls.URL_LAUNCHPAD)) {
+ return OpenIdUtil.C.nameLaunchpad();
+
} else if (k.isScheme(OpenIdUrls.URL_YAHOO)) {
return OpenIdUtil.C.nameYahoo();
- } else if (k.isScheme(AccountExternalId.LEGACY_GAE)) {
- return OpenIdUtil.C.nameGoogle() + " (Imported from Google AppEngine)";
-
} else {
return k.getExternalId();
}
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 d8a0427..db1acbf 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
@@ -19,12 +19,17 @@
import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.StringListPanel;
+import com.google.gerrit.client.config.ConfigServerApi;
+import com.google.gerrit.client.extensions.TopMenuItem;
import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
import com.google.gerrit.client.ui.OnEditEnabler;
-import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.CommentVisibilityStrategy;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.ReviewCategoryStrategy;
+import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
@@ -34,24 +39,28 @@
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.ListBox;
-import com.google.gwtjsonrpc.common.VoidResult;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Date;
+import java.util.List;
public class MyPreferencesScreen extends SettingsScreen {
private CheckBox showSiteHeader;
private CheckBox useFlashClipboard;
private CheckBox copySelfOnEmails;
private CheckBox reversePatchSetOrder;
- private CheckBox showUsernameInReviewCategory;
private CheckBox relativeDateInChangeTable;
private CheckBox sizeBarInChangeTable;
+ private CheckBox legacycidInChangeTable;
private ListBox maximumPageSize;
private ListBox dateFormat;
private ListBox timeFormat;
+ private ListBox reviewCategoryStrategy;
private ListBox commentVisibilityStrategy;
private ListBox changeScreen;
private ListBox diffView;
+ private StringListPanel myMenus;
private Button save;
@Override
@@ -62,12 +71,28 @@
useFlashClipboard = new CheckBox(Util.C.useFlashClipboard());
copySelfOnEmails = new CheckBox(Util.C.copySelfOnEmails());
reversePatchSetOrder = new CheckBox(Util.C.reversePatchSetOrder());
- showUsernameInReviewCategory = new CheckBox(Util.C.showUsernameInReviewCategory());
maximumPageSize = new ListBox();
for (final short v : PAGESIZE_CHOICES) {
maximumPageSize.addItem(Util.M.rowsPerPage(v), String.valueOf(v));
}
+ reviewCategoryStrategy = new ListBox();
+ reviewCategoryStrategy.addItem(
+ Util.C.messageShowInReviewCategoryNone(),
+ AccountGeneralPreferences.ReviewCategoryStrategy.NONE.name());
+ reviewCategoryStrategy.addItem(
+ Util.C.messageShowInReviewCategoryName(),
+ AccountGeneralPreferences.ReviewCategoryStrategy.NAME.name());
+ reviewCategoryStrategy.addItem(
+ Util.C.messageShowInReviewCategoryEmail(),
+ AccountGeneralPreferences.ReviewCategoryStrategy.EMAIL.name());
+ reviewCategoryStrategy.addItem(
+ Util.C.messageShowInReviewCategoryUsername(),
+ AccountGeneralPreferences.ReviewCategoryStrategy.USERNAME.name());
+ reviewCategoryStrategy.addItem(
+ Util.C.messageShowInReviewCategoryAbbrev(),
+ AccountGeneralPreferences.ReviewCategoryStrategy.ABBREV.name());
+
commentVisibilityStrategy = new ListBox();
commentVisibilityStrategy.addItem(
com.google.gerrit.client.changes.Util.C.messageCollapseAll(),
@@ -138,8 +163,9 @@
relativeDateInChangeTable = new CheckBox(Util.C.showRelativeDateInChangeTable());
sizeBarInChangeTable = new CheckBox(Util.C.showSizeBarInChangeTable());
+ legacycidInChangeTable = new CheckBox(Util.C.showLegacycidInChangeTable());
- final Grid formGrid = new Grid(12, 2);
+ final Grid formGrid = new Grid(13, 2);
int row = 0;
formGrid.setText(row, labelIdx, "");
@@ -158,8 +184,8 @@
formGrid.setWidget(row, fieldIdx, reversePatchSetOrder);
row++;
- formGrid.setText(row, labelIdx, "");
- formGrid.setWidget(row, fieldIdx, showUsernameInReviewCategory);
+ formGrid.setText(row, labelIdx, Util.C.reviewCategoryLabel());
+ formGrid.setWidget(row, fieldIdx, reviewCategoryStrategy);
row++;
formGrid.setText(row, labelIdx, Util.C.maximumPageSizeFieldLabel());
@@ -178,6 +204,10 @@
formGrid.setText(row, labelIdx, "");
formGrid.setWidget(row, fieldIdx, sizeBarInChangeTable);
row++;
+
+ formGrid.setText(row, labelIdx, "");
+ formGrid.setWidget(row, fieldIdx, legacycidInChangeTable);
+ row++;
}
formGrid.setText(row, labelIdx, Util.C.commentVisibilityLabel());
@@ -202,6 +232,10 @@
doSave();
}
});
+
+ myMenus = new MyMenuPanel(save);
+ add(myMenus);
+
add(save);
final OnEditEnabler e = new OnEditEnabler(save);
@@ -209,12 +243,13 @@
e.listenTo(useFlashClipboard);
e.listenTo(copySelfOnEmails);
e.listenTo(reversePatchSetOrder);
- e.listenTo(showUsernameInReviewCategory);
e.listenTo(maximumPageSize);
e.listenTo(dateFormat);
e.listenTo(timeFormat);
e.listenTo(relativeDateInChangeTable);
e.listenTo(sizeBarInChangeTable);
+ e.listenTo(legacycidInChangeTable);
+ e.listenTo(reviewCategoryStrategy);
e.listenTo(commentVisibilityStrategy);
e.listenTo(changeScreen);
e.listenTo(diffView);
@@ -223,9 +258,11 @@
@Override
protected void onLoad() {
super.onLoad();
- Util.ACCOUNT_SVC.myAccount(new ScreenLoadCallback<Account>(this) {
- public void preDisplay(final Account result) {
- display(result.getGeneralPreferences());
+ AccountApi.self().view("preferences")
+ .get(new ScreenLoadCallback<Preferences>(this) {
+ @Override
+ public void preDisplay(Preferences prefs) {
+ display(prefs);
}
});
}
@@ -235,39 +272,52 @@
useFlashClipboard.setEnabled(on);
copySelfOnEmails.setEnabled(on);
reversePatchSetOrder.setEnabled(on);
- showUsernameInReviewCategory.setEnabled(on);
maximumPageSize.setEnabled(on);
dateFormat.setEnabled(on);
timeFormat.setEnabled(on);
relativeDateInChangeTable.setEnabled(on);
sizeBarInChangeTable.setEnabled(on);
+ legacycidInChangeTable.setEnabled(on);
+ reviewCategoryStrategy.setEnabled(on);
commentVisibilityStrategy.setEnabled(on);
changeScreen.setEnabled(on);
diffView.setEnabled(on);
}
- private void display(final AccountGeneralPreferences p) {
- showSiteHeader.setValue(p.isShowSiteHeader());
- useFlashClipboard.setValue(p.isUseFlashClipboard());
- copySelfOnEmails.setValue(p.isCopySelfOnEmails());
- reversePatchSetOrder.setValue(p.isReversePatchSetOrder());
- showUsernameInReviewCategory.setValue(p.isShowUsernameInReviewCategory());
- setListBox(maximumPageSize, DEFAULT_PAGESIZE, p.getMaximumPageSize());
+ private void display(Preferences p) {
+ showSiteHeader.setValue(p.showSiteHeader());
+ useFlashClipboard.setValue(p.useFlashClipboard());
+ copySelfOnEmails.setValue(p.copySelfOnEmail());
+ reversePatchSetOrder.setValue(p.reversePatchSetOrder());
+ setListBox(maximumPageSize, DEFAULT_PAGESIZE, p.changesPerPage());
setListBox(dateFormat, AccountGeneralPreferences.DateFormat.STD, //
- p.getDateFormat());
+ p.dateFormat());
setListBox(timeFormat, AccountGeneralPreferences.TimeFormat.HHMM_12, //
- p.getTimeFormat());
- relativeDateInChangeTable.setValue(p.isRelativeDateInChangeTable());
- sizeBarInChangeTable.setValue(p.isSizeBarInChangeTable());
+ p.timeFormat());
+ relativeDateInChangeTable.setValue(p.relativeDateInChangeTable());
+ sizeBarInChangeTable.setValue(p.sizeBarInChangeTable());
+ legacycidInChangeTable.setValue(p.legacycidInChangeTable());
+ setListBox(reviewCategoryStrategy,
+ AccountGeneralPreferences.ReviewCategoryStrategy.NONE,
+ p.reviewCategoryStrategy());
setListBox(commentVisibilityStrategy,
AccountGeneralPreferences.CommentVisibilityStrategy.EXPAND_RECENT,
- p.getCommentVisibilityStrategy());
+ p.commentVisibilityStrategy());
setListBox(changeScreen,
null,
- p.getChangeScreen());
+ p.changeScreen());
setListBox(diffView,
AccountGeneralPreferences.DiffView.SIDE_BY_SIDE,
- p.getDiffView());
+ p.d