blob: 77652464758a6c8fe927b16ce7fcaaa9b4a541dd [file] [log] [blame]
Deniz Türkoglueb78b602012-05-07 14:02:36 -07001Gerrit Code Review - Plugin Development
2=======================================
3
Edwin Kempinaf275322012-07-16 11:04:01 +02004The Gerrit server functionality can be extended by installing plugins.
5This page describes how plugins for Gerrit can be developed.
6
7Depending on how tightly the extension code is coupled with the Gerrit
8server code, there is a distinction between `plugins` and `extensions`.
9
Edwin Kempinf5a77332012-07-18 11:17:53 +020010[[plugin]]
Edwin Kempin948de0f2012-07-16 10:34:35 +020011A `plugin` in Gerrit is tightly coupled code that runs in the same
Shawn O. Pearceda4919a2012-05-10 16:54:28 -070012JVM as Gerrit. It has full access to all server internals. Plugins
13are tightly coupled to a specific major.minor server version and
14may require source code changes to compile against a different
15server version.
16
Edwin Kempinf5a77332012-07-18 11:17:53 +020017[[extension]]
Edwin Kempin948de0f2012-07-16 10:34:35 +020018An `extension` in Gerrit runs inside of the same JVM as Gerrit
Shawn O. Pearceda4919a2012-05-10 16:54:28 -070019in the same way as a plugin, but has limited visibility to the
Edwin Kempinfd19bfb2012-07-16 10:44:17 +020020server's internals. The limited visibility reduces the extension's
21dependencies, enabling it to be compatible across a wider range
Shawn O. Pearceda4919a2012-05-10 16:54:28 -070022of server versions.
23
24Most of this documentation refers to either type as a plugin.
Deniz Türkoglueb78b602012-05-07 14:02:36 -070025
Edwin Kempinf878c4b2012-07-18 09:34:25 +020026[[getting-started]]
27Getting started
28---------------
Deniz Türkoglueb78b602012-05-07 14:02:36 -070029
Edwin Kempinf878c4b2012-07-18 09:34:25 +020030To get started with the development of a plugin there are two
31recommended ways:
Dave Borowitz5cc8f662012-05-21 09:51:36 -070032
Edwin Kempinf878c4b2012-07-18 09:34:25 +020033. use the Gerrit Plugin Maven archetype to create a new plugin project:
34+
35With the Gerrit Plugin Maven archetype you can create a skeleton for a
36plugin project.
37+
38----
39mvn archetype:generate -DarchetypeGroupId=com.google.gerrit \
40 -DarchetypeArtifactId=gerrit-plugin-archetype \
41 -DarchetypeVersion=2.5-SNAPSHOT \
42 -DgroupId=com.google.gerrit \
43 -DartifactId=testPlugin
44----
45+
46Maven will ask for additional properties and then create the plugin in
47the current directory. To change the default property values answer 'n'
48when Maven asks to confirm the properties configuration. It will then
49ask again for all properties including those with predefined default
50values.
51
52. clone the sample helloworld plugin:
53+
54This is a Maven project that adds an SSH command to Gerrit to print
55out a hello world message. It can be taken as an example to develop
56an own plugin.
57+
Dave Borowitz5cc8f662012-05-21 09:51:36 -070058----
59$ git clone https://gerrit.googlesource.com/plugins/helloworld
60----
Edwin Kempinf878c4b2012-07-18 09:34:25 +020061+
62When starting from this example one should take care to adapt the
63`Gerrit-ApiVersion` in the `pom.xml` to the version of Gerrit for which
64the plugin is developed. If the plugin is developed for a released
65Gerrit version (no `SNAPSHOT` version) then the URL for the
66`gerrit-api-repository` in the `pom.xml` needs to be changed to
Shawn Pearced5005002013-06-21 11:01:45 -070067`https://gerrit-api.storage.googleapis.com/release/`.
Dave Borowitz5cc8f662012-05-21 09:51:36 -070068
Edwin Kempinf878c4b2012-07-18 09:34:25 +020069[[API]]
70API
71---
72
73There are two different API formats offered against which plugins can
74be developed:
Deniz Türkoglueb78b602012-05-07 14:02:36 -070075
Shawn O. Pearceda4919a2012-05-10 16:54:28 -070076gerrit-extension-api.jar::
77 A stable but thin interface. Suitable for extensions that need
78 to be notified of events, but do not require tight coupling to
79 the internals of Gerrit. Extensions built against this API can
80 expect to be binary compatible across a wide range of server
81 versions.
Deniz Türkoglueb78b602012-05-07 14:02:36 -070082
Shawn O. Pearceda4919a2012-05-10 16:54:28 -070083gerrit-plugin-api.jar::
84 The complete internals of the Gerrit server, permitting a
85 plugin to tightly couple itself and provide additional
86 functionality that is not possible as an extension. Plugins
87 built against this API are expected to break at the source
88 code level between every major.minor Gerrit release. A plugin
89 that compiles against 2.5 will probably need source code level
90 changes to work with 2.6, 2.7, and so on.
Deniz Türkoglueb78b602012-05-07 14:02:36 -070091
92Manifest
93--------
94
Shawn O. Pearceda4919a2012-05-10 16:54:28 -070095Plugins may provide optional description information with standard
96manifest fields:
Nasser Grainawie033b262012-05-09 17:54:21 -070097
Shawn O. Pearceda4919a2012-05-10 16:54:28 -070098====
99 Implementation-Title: Example plugin showing examples
100 Implementation-Version: 1.0
101 Implementation-Vendor: Example, Inc.
102 Implementation-URL: http://example.com/opensource/plugin-foo/
103====
Nasser Grainawie033b262012-05-09 17:54:21 -0700104
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700105ApiType
106~~~~~~~
Nasser Grainawie033b262012-05-09 17:54:21 -0700107
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700108Plugins using the tightly coupled `gerrit-plugin-api.jar` must
109declare this API dependency in the manifest to gain access to server
Edwin Kempin948de0f2012-07-16 10:34:35 +0200110internals. If no `Gerrit-ApiType` is specified the stable `extension`
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700111API will be assumed. This may cause ClassNotFoundExceptions when
112loading a plugin that needs the plugin API.
Nasser Grainawie033b262012-05-09 17:54:21 -0700113
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700114====
115 Gerrit-ApiType: plugin
116====
117
118Explicit Registration
119~~~~~~~~~~~~~~~~~~~~~
120
121Plugins that use explicit Guice registration must name the Guice
122modules in the manifest. Up to three modules can be named in the
Edwin Kempin948de0f2012-07-16 10:34:35 +0200123manifest. `Gerrit-Module` supplies bindings to the core server;
124`Gerrit-SshModule` supplies SSH commands to the SSH server (if
125enabled); `Gerrit-HttpModule` supplies servlets and filters to the HTTP
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700126server (if enabled). If no modules are named automatic registration
127will be performed by scanning all classes in the plugin JAR for
128`@Listen` and `@Export("")` annotations.
129
130====
131 Gerrit-Module: tld.example.project.CoreModuleClassName
132 Gerrit-SshModule: tld.example.project.SshModuleClassName
133 Gerrit-HttpModule: tld.example.project.HttpModuleClassName
134====
135
Edwin Kempinf7295742012-07-16 15:03:46 +0200136[[reload_method]]
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700137Reload Method
138~~~~~~~~~~~~~
139
140If a plugin holds an exclusive resource that must be released before
141loading the plugin again (for example listening on a network port or
Edwin Kempin948de0f2012-07-16 10:34:35 +0200142acquiring a file lock) the manifest must declare `Gerrit-ReloadMode`
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700143to be `restart`. Otherwise the preferred method of `reload` will
144be used, as it enables the server to hot-patch an updated plugin
145with no down time.
146
147====
148 Gerrit-ReloadMode: restart
149====
150
151In either mode ('restart' or 'reload') any plugin or extension can
152be updated without restarting the Gerrit server. The difference is
153how Gerrit handles the upgrade:
154
155restart::
156 The old plugin is completely stopped. All registrations of SSH
157 commands and HTTP servlets are removed. All registrations of any
158 extension points are removed. All registered LifecycleListeners
159 have their `stop()` method invoked in reverse order. The new
160 plugin is started, and registrations are made from the new
161 plugin. There is a brief window where neither the old nor the
162 new plugin is connected to the server. This means SSH commands
163 and HTTP servlets will return not found errors, and the plugin
164 will not be notified of events that occurred during the restart.
165
166reload::
167 The new plugin is started. Its LifecycleListeners are permitted
168 to perform their `start()` methods. All SSH and HTTP registrations
169 are atomically swapped out from the old plugin to the new plugin,
170 ensuring the server never returns a not found error. All extension
171 point listeners are atomically swapped out from the old plugin to
172 the new plugin, ensuring no events are missed (however some events
173 may still route to the old plugin if the swap wasn't complete yet).
174 The old plugin is stopped.
175
Edwin Kempinf7295742012-07-16 15:03:46 +0200176To reload/restart a plugin the link:cmd-plugin-reload.html[plugin reload]
177command can be used.
178
Luca Milanesio737285d2012-09-25 14:26:43 +0100179[[init_step]]
180Init step
181~~~~~~~~~
182
183Plugins can contribute their own "init step" during the Gerrit init
184wizard. This is useful for guiding the Gerrit administrator through
185the settings needed by the plugin to work propertly.
186
187For instance plugins to integrate Jira issues to Gerrit changes may
188contribute their own "init step" to allow configuring the Jira URL,
189credentials and possibly verify connectivity to validate them.
190
191====
192 Gerrit-InitStep: tld.example.project.MyInitStep
193====
194
195MyInitStep needs to follow the standard Gerrit InitStep syntax
David Pursehouse92463562013-06-24 10:16:28 +0900196and behavior: writing to the console using the injected ConsoleUI
Luca Milanesio737285d2012-09-25 14:26:43 +0100197and accessing / changing configuration settings using Section.Factory.
198
199In addition to the standard Gerrit init injections, plugins receive
200the @PluginName String injection containing their own plugin name.
201
202Bear in mind that the Plugin's InitStep class will be loaded but
203the standard Gerrit runtime environment is not available and the plugin's
204own Guice modules were not initialized.
205This means the InitStep for a plugin is not executed in the same way that
206the plugin executes within the server, and may mean a plugin author cannot
207trivially reuse runtime code during init.
208
209For instance a plugin that wants to verify connectivity may need to statically
210call the constructor of their connection class, passing in values obtained
211from the Section.Factory rather than from an injected Config object.
212
213Plugins InitStep are executing during the "Gerrit Plugin init" phase, after
214the extraction of the plugins embedded in Gerrit.war into $GERRIT_SITE/plugins
215and before the DB Schema initialization or upgrade.
216Plugins InitStep cannot refer to Gerrit DB Schema or any other Gerrit runtime
217objects injected at startup.
218
219====
Sasa Zivkov69f99fb2013-06-24 16:54:15 +0200220 public class MyInitStep implements InitStep {
221 private final ConsoleUI ui;
222 private final Section.Factory sections;
223 private final String pluginName;
Luca Milanesio737285d2012-09-25 14:26:43 +0100224
Sasa Zivkov69f99fb2013-06-24 16:54:15 +0200225 @Inject
226 public GitBlitInitStep(final ConsoleUI ui, Section.Factory sections, @PluginName String pluginName) {
227 this.ui = ui;
228 this.sections = sections;
229 this.pluginName = pluginName;
230 }
231
232 @Override
233 public void run() throws Exception {
234 ui.header("\nMy plugin");
235
236 Section mySection = getSection("myplugin", null);
237 mySection.string("Link name", "linkname", "MyLink");
238 }
Luca Milanesio737285d2012-09-25 14:26:43 +0100239 }
Luca Milanesio737285d2012-09-25 14:26:43 +0100240====
241
Edwin Kempinf5a77332012-07-18 11:17:53 +0200242[[classpath]]
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700243Classpath
244---------
245
246Each plugin is loaded into its own ClassLoader, isolating plugins
247from each other. A plugin or extension inherits the Java runtime
248and the Gerrit API chosen by `Gerrit-ApiType` (extension or plugin)
249from the hosting server.
250
251Plugins are loaded from a single JAR file. If a plugin needs
252additional libraries, it must include those dependencies within
253its own JAR. Plugins built using Maven may be able to use the
254link:http://maven.apache.org/plugins/maven-shade-plugin/[shade plugin]
255to package additional dependencies. Relocating (or renaming) classes
256should not be necessary due to the ClassLoader isolation.
Deniz Türkoglueb78b602012-05-07 14:02:36 -0700257
Edwin Kempinf5a77332012-07-18 11:17:53 +0200258[[ssh]]
Deniz Türkoglueb78b602012-05-07 14:02:36 -0700259SSH Commands
260------------
261
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700262Plugins may provide commands that can be accessed through the SSH
263interface (extensions do not have this option).
Deniz Türkoglueb78b602012-05-07 14:02:36 -0700264
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700265Command implementations must extend the base class SshCommand:
Deniz Türkoglueb78b602012-05-07 14:02:36 -0700266
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700267====
268 import com.google.gerrit.sshd.SshCommand;
Deniz Türkoglueb78b602012-05-07 14:02:36 -0700269
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700270 class PrintHello extends SshCommand {
271 protected abstract void run() {
272 stdout.print("Hello\n");
273 }
274 }
275====
Nasser Grainawie033b262012-05-09 17:54:21 -0700276
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700277If no Guice modules are declared in the manifest, SSH commands may
Edwin Kempin948de0f2012-07-16 10:34:35 +0200278use auto-registration by providing an `@Export` annotation:
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700279
280====
281 import com.google.gerrit.extensions.annotations.Export;
282 import com.google.gerrit.sshd.SshCommand;
283
284 @Export("print")
285 class PrintHello extends SshCommand {
286 protected abstract void run() {
287 stdout.print("Hello\n");
288 }
289 }
290====
291
292If explicit registration is being used, a Guice module must be
293supplied to register the SSH command and declared in the manifest
294with the `Gerrit-SshModule` attribute:
295
296====
297 import com.google.gerrit.sshd.PluginCommandModule;
298
299 class MyCommands extends PluginCommandModule {
300 protected void configureCommands() {
301 command("print").to(PrintHello.class);
302 }
303 }
304====
305
306For a plugin installed as name `helloworld`, the command implemented
307by PrintHello class will be available to users as:
308
309----
Keunhong Parka09a6f12012-07-10 14:45:02 -0600310$ ssh -p 29418 review.example.com helloworld print
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700311----
312
David Ostrovsky7066cc02013-06-15 14:46:23 +0200313[[capabilities]]
314Plugin Owned Capabilities
315-------------------------
316
317Plugins may provide their own capabilities and restrict usage of SSH
318commands to the users who are granted those capabilities.
319
320Plugins define the capabilities by overriding the `CapabilityDefinition`
321abstract class:
322
323====
324 public class PrintHelloCapability extends CapabilityDefinition {
325 @Override
326 public String getDescription() {
327 return "Print Hello";
328 }
329 }
330====
331
332If no Guice modules are declared in the manifest, UI commands may
333use auto-registration by providing an `@Export` annotation:
334
335====
336 @Export("printHello")
337 public class PrintHelloCapability extends CapabilityDefinition {
338 ...
339====
340
341Otherwise the capability must be bound in a plugin module:
342
343====
344 public class HelloWorldModule extends AbstractModule {
345 @Override
346 protected void configure() {
347 bind(CapabilityDefinition.class)
348 .annotatedWith(Exports.named("printHello"))
349 .to(PrintHelloCapability.class);
350 }
351 }
352====
353
354With a plugin-owned capability defined in this way, it is possible to restrict
355usage of an SSH command or UiAction to members of the group that were granted
356this capability in the usual way, using the `RequiresCapability` annotation:
357
358====
359 @RequiresCapability("printHello")
Shawn Pearce5b70c222013-08-12 19:49:41 -0700360 @CommandMetaData(name="print", description="Print greeting in different languages")
David Ostrovsky7066cc02013-06-15 14:46:23 +0200361 public final class PrintHelloWorldCommand extends SshCommand {
362 ...
363====
364
365Or with UiAction:
366
367====
368 @RequiresCapability("printHello")
369 public class SayHelloAction extends UiAction<RevisionResource>
370 implements RestModifyView<RevisionResource, SayHelloAction.Input> {
371 ...
372====
373
374Capability scope was introduced to differentiate between plugin-owned
375capabilities and core capabilities. Per default the scope of
376@RequiresCapability annotation is `CapabilityScope.CONTEXT`, that means:
377+
378* when `@RequiresCapability` is used within a plugin the scope of the
379capability is assumed to be that plugin.
380+
381* If `@RequiresCapability` is used within the core Gerrit Code Review server
382(and thus is outside of a plugin) the scope is the core server and will use
383the `GlobalCapability` known to Gerrit Code Review server.
384
385If a plugin needs to use a core capability name (e.g. "administrateServer")
386this can be specified by setting `scope = CapabilityScope.CORE`:
387
388====
389 @RequiresCapability(value = "administrateServer", scope =
390 CapabilityScope.CORE)
391 ...
392====
393
Edwin Kempinf5a77332012-07-18 11:17:53 +0200394[[http]]
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700395HTTP Servlets
396-------------
397
398Plugins or extensions may register additional HTTP servlets, and
399wrap them with HTTP filters.
400
401Servlets may use auto-registration to declare the URL they handle:
402
403====
404 import com.google.gerrit.extensions.annotations.Export;
405 import com.google.inject.Singleton;
406 import javax.servlet.http.HttpServlet;
407 import javax.servlet.http.HttpServletRequest;
408 import javax.servlet.http.HttpServletResponse;
409
410 @Export("/print")
411 @Singleton
412 class HelloServlet extends HttpServlet {
413 protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
414 res.setContentType("text/plain");
415 res.setCharacterEncoding("UTF-8");
416 res.getWriter().write("Hello");
417 }
418 }
419====
420
Edwin Kempin8aa650f2012-07-18 11:25:48 +0200421The auto registration only works for standard servlet mappings like
422`/foo` or `/foo/*`. Regex style bindings must use a Guice ServletModule
423to register the HTTP servlets and declare it explicitly in the manifest
424with the `Gerrit-HttpModule` attribute:
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700425
426====
427 import com.google.inject.servlet.ServletModule;
428
429 class MyWebUrls extends ServletModule {
430 protected void configureServlets() {
431 serve("/print").with(HelloServlet.class);
432 }
433 }
434====
435
436For a plugin installed as name `helloworld`, the servlet implemented
437by HelloServlet class will be available to users as:
438
439----
440$ curl http://review.example.com/plugins/helloworld/print
441----
Nasser Grainawie033b262012-05-09 17:54:21 -0700442
Edwin Kempinf5a77332012-07-18 11:17:53 +0200443[[data-directory]]
Edwin Kempin41f63912012-07-17 12:33:55 +0200444Data Directory
445--------------
446
447Plugins can request a data directory with a `@PluginData` File
448dependency. A data directory will be created automatically by the
449server in `$site_path/data/$plugin_name` and passed to the plugin.
450
451Plugins can use this to store any data they want.
452
453====
454 @Inject
455 MyType(@PluginData java.io.File myDir) {
456 new FileInputStream(new File(myDir, "my.config"));
457 }
458====
459
Edwin Kempinf5a77332012-07-18 11:17:53 +0200460[[documentation]]
Nasser Grainawie033b262012-05-09 17:54:21 -0700461Documentation
462-------------
463
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700464If a plugin does not register a filter or servlet to handle URLs
465`/Documentation/*` or `/static/*`, the core Gerrit server will
466automatically export these resources over HTTP from the plugin JAR.
467
David Pursehouse6853b5a2013-07-10 11:38:03 +0900468Static resources under the `static/` directory in the JAR will be
Dave Borowitzb893ac82013-03-27 10:03:55 -0400469available as `/plugins/helloworld/static/resource`. This prefix is
470configurable by setting the `Gerrit-HttpStaticPrefix` attribute.
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700471
David Pursehouse6853b5a2013-07-10 11:38:03 +0900472Documentation files under the `Documentation/` directory in the JAR
Dave Borowitzb893ac82013-03-27 10:03:55 -0400473will be available as `/plugins/helloworld/Documentation/resource`. This
474prefix is configurable by setting the `Gerrit-HttpDocumentationPrefix`
475attribute.
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700476
477Documentation may be written in
478link:http://daringfireball.net/projects/markdown/[Markdown] style
479if the file name ends with `.md`. Gerrit will automatically convert
480Markdown to HTML if accessed with extension `.html`.
Nasser Grainawie033b262012-05-09 17:54:21 -0700481
Edwin Kempinf5a77332012-07-18 11:17:53 +0200482[[macros]]
Edwin Kempinc78777d2012-07-16 15:55:11 +0200483Within the Markdown documentation files macros can be used that allow
484to write documentation with reasonably accurate examples that adjust
485automatically based on the installation.
486
487The following macros are supported:
488
489[width="40%",options="header"]
490|===================================================
491|Macro | Replacement
492|@PLUGIN@ | name of the plugin
493|@URL@ | Gerrit Web URL
494|@SSH_HOST@ | SSH Host
495|@SSH_PORT@ | SSH Port
496|===================================================
497
498The macros will be replaced when the documentation files are rendered
499from Markdown to HTML.
500
501Macros that start with `\` such as `\@KEEP@` will render as `@KEEP@`
502even if there is an expansion for `KEEP` in the future.
503
Edwin Kempinf5a77332012-07-18 11:17:53 +0200504[[auto-index]]
Shawn O. Pearce795167c2012-05-12 11:20:18 -0700505Automatic Index
506~~~~~~~~~~~~~~~
507
508If a plugin does not handle its `/` URL itself, Gerrit will
509redirect clients to the plugin's `/Documentation/index.html`.
510Requests for `/Documentation/` (bare directory) will also redirect
511to `/Documentation/index.html`.
512
513If neither resource `Documentation/index.html` or
514`Documentation/index.md` exists in the plugin JAR, Gerrit will
515automatically generate an index page for the plugin's documentation
516tree by scanning every `*.md` and `*.html` file in the Documentation/
517directory.
518
519For any discovered Markdown (`*.md`) file, Gerrit will parse the
520header of the file and extract the first level one title. This
521title text will be used as display text for a link to the HTML
522version of the page.
523
524For any discovered HTML (`*.html`) file, Gerrit will use the name
525of the file, minus the `*.html` extension, as the link text. Any
526hyphens in the file name will be replaced with spaces.
527
David Pursehouse6853b5a2013-07-10 11:38:03 +0900528If a discovered file is named `about.md` or `about.html`, its
529content will be inserted in an 'About' section at the top of the
530auto-generated index page. If both `about.md` and `about.html`
531exist, only the first discovered file will be used.
532
Shawn O. Pearce795167c2012-05-12 11:20:18 -0700533If a discovered file name beings with `cmd-` it will be clustered
David Pursehouse6853b5a2013-07-10 11:38:03 +0900534into a 'Commands' section of the generated index page.
535
David Pursehousefe529152013-08-14 16:35:06 +0900536If a discovered file name beings with `servlet-` it will be clustered
537into a 'Servlets' section of the generated index page.
538
539If a discovered file name beings with `rest-api-` it will be clustered
540into a 'REST APIs' section of the generated index page.
541
David Pursehouse6853b5a2013-07-10 11:38:03 +0900542All other files are clustered under a 'Documentation' section.
Shawn O. Pearce795167c2012-05-12 11:20:18 -0700543
544Some optional information from the manifest is extracted and
545displayed as part of the index page, if present in the manifest:
546
547[width="40%",options="header"]
548|===================================================
549|Field | Source Attribute
550|Name | Implementation-Title
551|Vendor | Implementation-Vendor
552|Version | Implementation-Version
553|URL | Implementation-URL
554|API Version | Gerrit-ApiVersion
555|===================================================
556
Edwin Kempinf5a77332012-07-18 11:17:53 +0200557[[deployment]]
Nasser Grainawie033b262012-05-09 17:54:21 -0700558Deployment
559----------
560
Edwin Kempinf7295742012-07-16 15:03:46 +0200561Compiled plugins and extensions can be deployed to a running Gerrit
562server using the link:cmd-plugin-install.html[plugin install] command.
Shawn O. Pearceda4919a2012-05-10 16:54:28 -0700563
564Plugins can also be copied directly into the server's
565directory at `$site_path/plugins/$name.jar`. The name of
566the JAR file, minus the `.jar` extension, will be used as the
567plugin name. Unless disabled, servers periodically scan this
568directory for updated plugins. The time can be adjusted by
569link:config-gerrit.html#plugins.checkFrequency[plugins.checkFrequency].
Deniz Türkoglueb78b602012-05-07 14:02:36 -0700570
Edwin Kempinf7295742012-07-16 15:03:46 +0200571For disabling plugins the link:cmd-plugin-remove.html[plugin remove]
572command can be used.
573
Brad Larsond5e87c32012-07-11 12:18:49 -0500574Disabled plugins can be re-enabled using the
575link:cmd-plugin-enable.html[plugin enable] command.
576
Deniz Türkoglueb78b602012-05-07 14:02:36 -0700577GERRIT
578------
579Part of link:index.html[Gerrit Code Review]