Deploying Plugins
Place your plugin files under $JFROG_HOME/artifactory/var/etc/artifactory/plugins
.
Artifactory HA Plugins Directory
If you are working with a High Availability cluster your user plugins should be added to the primary node and they will be propagated to the entire cluster.
Any file name ending with .groovy
is loaded on startup. You can have multiple plugin files which are loaded in alphabetical order. Callbacks defined in plugins are called by the order they were loaded.
Reloading Plugins
By default, plugins are not reloaded after Artifactory has started-up. You can configure Artifactory to automatically detect plugin changes on disk or new plugin files and automatically reload them in runtime (plugin removals are not detected), or reload plugins using the REST API.
Auto Reload
To automatically reload plugins that have changed, set the number of seconds to check for plugin updates to a number greater than 0, by changing the following property in $JFROG_HOME/artifactory/var/etc/artifactory/artifactory.system.properties
, or by specifying the property with -D to the JVM running Artifactory:
artifactory.plugin.scripts.refreshIntervalSecs=0
NOTE! that deleting or renaming plugin files while auto-reloading is active is not fully supported and requires an Artifactory restart.
Disabling Plugin Reloading for Production
Ensure plugin auto-reloading is disabled in a production environment.
Reloading Plugins via REST API
You can reload plugins using the Reload Plugins REST API endpoint.
Plugins Lib Directory
If your plugin requires any external dependencies, you can place them under the $JFROG_HOME/artifactory/var/etc
/artifactory/plugins/lib
directory.
Removing Plugins
To remove a plugin, simply add the .force.delete
suffix to the original plugin file name. For example, rename my-plugin.groovy
to my-plugin.groovy.force.delete.
Removing Plugins from an Artifactory HA Cluster
To remove a plugin from a High Availability cluster, add the .force.delete
suffix to the original plugin file name.
The deletion event is then propagated to all other nodes in the cluster and Artifactory will delete the respective file from each cluster node automatically.
Retrieving Plugin Source Code
You can retrieve the Groovy source code of a user plugin using the Retrieve Plugin Code REST API endpoint
Writing Plugins
Artifactory plugins are written as Groovy scripts in regular files and have a simple DSL to wrap users code in closures inside well-known extension points.
Scripts have a couple of helper objects that are globally bound (see the plugin script template).
Naming conventions
Note that Groovy scripts must follow the same naming conventions as those specified for Java.
The Artifactory Public API (PAPI)
Scripts have access to the full classpath of Artifactory, however, the only API supported for plugins is the Artifactory Public API, defined in the
artifactory-papi.jar
.
The artifactory-papi.jar
can be found under WEB-INF/lib
folder inside the artifactory.war
.
Please see the Plugin Code Template and Sample Plugin below for more details.
IDE code completion
All major IDEs have good Groovy editing and debugging capabilities.
In order to make your developing experience complete, we provide support for our own DSL for IntelliJ IDEA. IntelliJ IDEA's Groovy DSL script for Artifactory User Plugins can be found in our GitHub repo.
Eclipse DSLD file is also available courtesy of
Globally Bound Variables
Variable Name | Variable Type | Comments |
---|---|---|
log | Writes to Artifactory log logger name is the name of the script file | |
repositories | Allows queries and operations on repositories and artifacts | |
security | Provides information about current security context, (e.g., current user and their permissions) | |
searches | org.artifactory.search.Searches | API for searching for artifacts and builds Since 2.3.4 |
builds | Allows CRUD operations on builds |
Closure Variables
Note! Declaring your own closure variables using the Groovy 'def ' keyword is considered best practice. Avoiding the "def" keyword is risky in terms of variable scoping, and will result in the variable being scoped globally, making it accessible from other closure executions.
Plugins Repository
Enhancing Artifactory with user plugins is community-driven effort.
If you are looking to go beyond Artifactory's out-of-the-box functionality take a look at already contributed plugins on GitHub, you might find what you are thinking about. If not, your contribution is very welcome!
Plugin Execution Points
The following table summarizes the available execution points. For more details about specific plugin look follow the section links.
Plugin Type | Code block name | When executed | Description |
Upload | |||
Event Callback (without return value) | beforeUploadRequest | On any download | Handle before upload request events, executed before Artifactory starts to handle the original client request, useful for overriding the actual repo path during the Artifactory upload process. |
Download | |||
Event Callback (with return values) | altResponse | On any download | Provide an alternative response, by setting a success/error status code value and an optional error message or by setting new values for the inputStream and size context variables (For succeeded resolutions). |
altAllResponses | On any download | Provide an alternative response, by setting response headers, a success/error status code value and an optional error message or by setting new values for the inputStream and size context variables. This applies for GET/HEAD requests, for successful resolutions or Not Modified responses. | |
altRemotePath | When reaching out to remote repositories | Provides an alternative download path under the same remote repository, by setting a new value to the path variable. | |
altRemoteContent | After fetching content from remote repositories | Provide an alternative download content, by setting new values for the inputStream and size context variables. | |
afterDownloadError | After failing during content fetching from remote repositories | Provide an alternative response, by setting a success/error status code value and an optional error message or by setting new values for the inputStream and size context variables (For failed resolutions). | |
Event Callback (without return value) | beforeRemoteDownload | Before fetching content from remote repositories | Handle before remote download events. |
afterRemoteDownload | After fetching content from remote repositories | Handle after remote download events. | |
beforeDownload | On any download | Handle before download events. | |
afterDownload | On any download | Handle after download events | |
beforeDownloadRequest | On any download | Handle before download request events, executed before Artifactory starts to handle the original client request, useful for intercepting expirable resources (other than the default ones like maven-metadata.xml). Limitation The repository ID of the actual repository from which the artifact was requested in the callback is unknown in the case of virtual repositories. Therefore, this The callback method does not work with the Docker Virtual repository. | |
Storage | |||
Event Callback (without return value) | before/after | Before / After selected storage operation | Handle events before and after Create, Delete, Move and Copy operations |
Jobs | |||
Scheduled execution | any valid Groovy (Java) literal as execution name | According to provided interval/delay or cron expression | Job runs are controlled by the provided interval or cron expression, which are mutually exclusive. The actual code to run as part of the job should be part of the job's closure. |
Executions | |||
User-driven execution | any valid Groovy (Java) literal as execution name | By REST call | External executions are invoked via REST requests. |
Realms | |||
Event Callback (without return value) | any valid Groovy (Java) literal as realm name with nested blocks: authenticate | During user authentication | Newly added realms are added before any built-in realms (Artifactory internal realm, LDAP, Crowd etc.). User authentication will be attempted against these realms first, by the order they are defined. |
Build | |||
Event Callback (without return value) | beforeSave | Before the build info is saved in Artifactory | Handle before build info save events |
afterSave | After the build info is saved in Artifactory | Handle after build info save events | |
Promotions | |||
User or build server driven execution | any valid Groovy (Java) literal as promotion name | By REST call | Promotes integration (a.k.a. snapshot) build to be a release invoking any code associated with it. |
Staging Strategy | |||
build server driven execution | any valid Groovy (Java) literal as staging strategy name | During build server driven staging build configuration | The strategy provides the build server with the following information:
|
Replication | |||
Event callback (with return value) | beforeFileReplication | Before file is replicated | Handle before file replication events. File replication can be skipped. |
beforeDirectoryReplication | Before directory is replicated | Handle before directory replication events. Directory replication can be skipped. | |
beforeDeleteReplication | Before file/directory is deleted | Handle before file or directory are deleted. | |
beforePropertyReplication | Before properties are replicated | Handle properties replication. |
Execution Context
The Download, Storage, Execution and Build plugin types are executed under the identity of the user request that triggered them.
It is possible to force a block of plugin code to execute under the "system" role, which is not bound to any authorization rules and can therefore perform actions that are otherwise forbidden for the original user.
To run under the "system" role wrap your code with the asSystem
closure:
... someCode ... asSystem { //This code runs as the system role } ... someOtherCode ...
Including AQL Queries
User plugins may include AQL queries opening up the full set of search capabilities that AQL has to offer. AQL queries are implemented within the Searches
object as shown in the example below.
import org.artifactory.repo.RepoPathFactory import org.artifactory.search.Searches import org.artifactory.search.aql.AqlResult executions { gemPropsPopulator() { def repoKey = "gem-local" ((Searches) searches).aql( "items.find({" + "\"repo\": \"" + repoKey + "\"," + "\"\$or\":[" + "{\"property.key\":{\"\$ne\":\"gem.name\"}}," + "{\"property.key\":{\"\$ne\":\"gem.version\"}}" + "]})" + ".include(\"path\", \"name\")") { AqlResult result -> result.each { ... ... ... } } } }
Plugin Template Source
General Info
Upload
Download
Storage
Jobs
Executions
Realms
Build
Promotions
Staging
Replication
Controlling Plugin Log Level
The default log level for user plugins is "warn". To change a plugin log level, add the following to $JFROG_HOME/artifactory/var/etc/artifactory/logback.xml
:
<logger name="my-plugin"> <level value="info"/> </logger>
The logger name is the name of the plugin file without the ".groovy
" extension (in the example above the plugin file name is my-plugin.groovy
). The logging levels can be either error, warn, info, debug or trace.
Open Source Plugins
Open Source plugins that may meet your needs or act as basic examples for various functions are available on our GitHub.