Write Plugins

📘

Note

JFrog Workers is the newer, recommended way to easily extend the JFrog Platform (not just Artifactory) in a Cloud-native way. While plugins are supported, we strongly suggest using JFrog Workers whenever possible.

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 artifactory-papi.jar.

You can find the artifactory-papi.jar under WEB-INF/lib folder inside artifactory.war.

For more information, see Plugin Code Template.

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 James Carnegie.

Globally Bound Variables

Variable NameVariable TypeComments
logorg.slf4j.Logger

Writes to Artifactory log

logger name is the name of the script file

repositoriesorg.artifactory.repo.Repositories

Allows queries and operations on repositories

and artifacts

securityorg.artifactory.security.Security

Provides information about current security context,

(e.g., current user and their permissions)

searchesorg.artifactory.search.Searches

API for searching for artifacts and builds

Since 2.3.4

buildsorg.artifactory.build.Builds

Allows CRUD operations on builds

Since 2.6

⚠️

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 plugins, follow the section links.

Plugin TypeCode block nameWhen executedDescription
Upload
Event Callback (without return value)
beforeUploadRequest
On any uploadHandle 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 downloadProvide 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 downloadProvide 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 repositoriesProvides an alternative download path under the same remote repository, by setting a new value to the path variable.
altRemoteContent
After fetching content from remote repositoriesProvide an alternative download content, by setting new values for the inputStream and size context variables.
afterDownloadError
After failing during content fetching from remote repositoriesProvide 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 repositoriesHandle before remote download events.
afterRemoteDownload
After fetching content from remote repositoriesHandle after remote download events.
beforeDownload
On any downloadHandle before download events.
afterDownload
On any downloadHandle after download events. It is triggered after download execution, not download completion.
beforeDownloadRequest
On any downloadHandle 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
Create, Delete, Move, Copy,
PropertyCreate, PropertyDelete
Before / After selected storage operationHandle events before and after Create, Delete, Move and Copy operations
📘

Note

Artifactory works with transactions. During a transaction, the change may not yet committed to the database. Hence, the previous information may still exist in your database and you may see the outdated information show up after execution in rare cases.

Jobs
Scheduled executionany valid Groovy (Java) literal as execution nameAccording to provided interval/delay or cron expressionJob 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 executionany valid Groovy (Java) literal as execution nameBy REST callExternal executions are invoked via REST requests.
Realms
Event Callback (without return value)any valid Groovy (Java) literal as realm name with nested blocks:
authenticate
userExists
During user authenticationNewly 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.
📘

Note

Artifactory version 7.71.x or above, add the security.authentication.user-plugin: trueto your access.config.yml file to enable the plugin realm authentication.

For more information, refer to the Supported Access Configurations documentation.

Build
Event Callback (without return value)
beforeSave
Before the build info is saved in ArtifactoryHandle before build info save events
afterSave
After the build info is saved in ArtifactoryHandle after build info save events
Promotions
User or build server driven executionany valid Groovy (Java) literal as promotion nameBy REST callPromotes integration (a.k.a. snapshot) build to be a release invoking any code associated with it.
Staging Strategy
build server driven executionany valid Groovy (Java) literal as staging strategy name.During build server driven staging build configurationThe strategy provides the build server with the following information:
  • How the artifacts in the staged build should be versioned;
  • How the artifacts in the next integration build should be versioned;
  • Should the build server create a release branch/tag/stream in VCS and how it should be called;
  • To which repository in Artifactory the built artifacts should be submitted.
Replication
Event callback (with return value)beforeFileReplicationBefore file is replicatedHandle before file replication events. File replication can be skipped.
beforeDirectoryReplicationBefore directory is replicatedHandle before directory replication events. Directory replication can be skipped.
beforeDeleteReplicationBefore file/directory is deletedHandle before file or directory are deleted.
beforePropertyReplicationBefore properties are replicatedHandle properties replication.

User Plugin 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 {
                ...
                ...
                ...
               }
       }
   }
}

Did this page help you?