Skip to content

Latest commit

 

History

History
174 lines (115 loc) · 10.3 KB

README.md

File metadata and controls

174 lines (115 loc) · 10.3 KB

Build Status codecov Download Stack Overflow

artifactory-rest

alt tag

java client, based on jclouds, to interact with Artifactory's REST API.

Motivation

Shortly after writing the etcd-rest library I had a use-case for automating various functions against Artifactory. This included, but was not limited to: querying for groups of artifacts, deleting groups of artifacts, adding properties to groups of artifacts, etc. Furthermore I needed to do this in DevOps/CICD fashion: meaning I wanted to be able to configure it (endpoint, credentials, token, http properties, etc) and build the client by inferring these values from System Proprties, Environment Variables, or a combination of the 2. I started looking at the artifactory-java-client and could immediately tell it was not going to suffice. This is not a shot at them but more an admission that they simply designed things in a different way than what I required. Nevertheless I continued forward and thought maybe I could write some sort of wrapper to do what I needed. After playing for a bit, and getting my first initial PR together, I had the painful feeling that getting a change in, whilst writing tests, was just too much work. It's for this reason I noted the above etcd-rest library as it is built on top of jclouds, has an easy to use and understand client interface, has a built in model for writing mock and integration tests, makes adding new code amount to little more than wiring up a new interface method with a handful of annotations, and could do everything I wanted.

It's with this in mind that I created the artifactory-rest library and its sister project the gradle-artifactory-rest-plugin. These are both DevOps/CICD focused, are easy to use, and easy to contribute back to. All boiler plate http code has been abstracted away leaving the developer to focus solely on wiring up a new endpoint (interface method) with the appropriate annotations.

On jclouds, apis and endpoints

Being built on top of jclouds means things are broken up into Apis. Apis are just Interfaces that are analagous to a resource provided by the server-side program (e.g. /api/repositories, /api/search, /api/storage, etc..). The methods within these Interfaces are analagous to an endpoint provided by these resources (e.g. GET /api/repositories/my-repo, POST /api/search/aql, DELETE /api/storage/my-repo/my-item, etc..). The user only needs to be concerned with which Api they need and then calling its various methods. These methods, much like any java library, return domain objects (e.g. POJO's) modeled after the json returned by artifactory.

Interacting with the remote service becomes transparent and allows developers to focus on getting things done rather than the internals of the API itself, or how to build a client, or how to parse the json.

On new features

New Api's or endpoints are generally added as needed and/or requested. If there is something you want to see just open an ISSUE and ask or send in a PullRequest. However, putting together a PullRequest for a new feature is generally the faster route to go as it's much easier to review a PullRequest than to create one ourselves. There is no problem doing so of course but if you need something done now than a PullRequest is your best bet otherwise you may have to patiently wait for one of our contributors to take up the work.

Latest Release

Can be sourced from maven like so:

<dependency>
  <groupId>io.github.cdancy</groupId>
  <artifactId>artifactory-rest</artifactId>
  <version>X.Y.Z</version>
  <classifier>sources|tests|javadoc|all</classifier> (Optional)
</dependency>

Documentation

javadocs can be found via github pages here

Examples on how to build a ArtifactoryClient

When using Basic (e.g. username and password) authentication:

ArtifactoryClient client = ArtifactoryClient.builder()
.endPoint("http://127.0.0.1:8080/artifactory") // Optional and can be sourced from system/env. Falls back to http://127.0.0.1:8080/artifactory
.credentials("admin:password") // Optional and can be sourced from system/env and can be Base64 encoded.
.build();

Version version = client.api().systemApi().version();

When using Bearer (e.g. jfrog token) authentication:

ArtifactoryClient client = ArtifactoryClient.builder()
.endPoint("http://127.0.0.1:8080/artifactory") // Optional and can be sourced from system/env. Falls back to http://127.0.0.1:8080/artifactory
.token("123456789abcdef") // Optional and can be sourced from system/env.
.build();

Version version = client.api().systemApi().version();

When using Anonymous authentication or sourcing from system/environment (as described below):

ArtifactoryClient client = ArtifactoryClient.builder()
.endPoint("http://127.0.0.1:8080/artifactory") // Optional and can be sourced from system/env. Falls back to http://127.0.0.1:8080/artifactory
.build();

Version version = client.api().systemApi().version();

On System Property and Environment Variable setup

Client's do NOT need to supply the endPoint or authentication as part of instantiating the ArtifactoryClient object. Instead one can supply them through System Properties, Environment Variables, or a combination of the 2. System Properties will be searched first and if not found we will attempt to query the Environment Variables. If neither turns up anything than anonymous access is assumed.

Setting the endpoint can be done like so (searched in order):

`System.setProperty("artifactory.rest.endpoint", "http://my-artifactory-instance:12345/artifactory")`
`export ARTIFACTORY_REST_ENDPOINT=http://my-artifactory-instance:12345/artifactory`

Setting the credentials, which represents Basic authentication and is optionally Base64 encoded, can be done like so (searched in order):

`System.setProperty("artifactory.rest.credentials", "username:password")`
`export ARTIFACTORY_REST_CREDENTIALS=username:password`

Setting the token, which represents Bearer authentication, can be done like so (searched in order):

`System.setProperty("artifactory.rest.token", "abcdefg1234567")`
`export ARTIFACTORY_REST_TOKEN=abcdefg1234567`

On Overrides

Because we are built on top of jclouds we can take advantage of overriding various internal HTTP properties by passing in a Properties object or, and in following with the spirit of this library, configuring them through System Properties of Environment Variables. The properties a given client can configure can be found HERE.

When configuring through a Properties object you must pass in the keys exactly as they are named within jclouds:

Properties props = new Properties();
props.setProperty("jclouds.so-timeout", "60000");
props.setProperty("jclouds.connection-timeout", "120000");

ArtifactoryClient client = ArtifactoryClient.builder()
.overrides(props)
.build();

Version version = client.api().systemApi().version();

When configuring through System Properties you must prepend the jclouds name with artifactory.rest.:

System.setProperty("artifactory.rest.jclouds.so-timeout", "60000");
System.setProperty("artifactory.rest.jclouds.connection-timeout", "120000");

ArtifactoryClient client = ArtifactoryClient.builder()
.build();

Version version = client.api().systemApi().version();

When configuring through Environment Variables you must CAPITALIZE all characters, replace any . with _, and prepend the jclouds name with ARTIFACTORY_REST_:

export ARTIFACTORY_REST_JCLOUDS_SO-TIMEOUT=60000
export ARTIFACTORY_REST_JCLOUDS_CONNECTION-TIMEOUT=120000

ArtifactoryClient client = ArtifactoryClient.builder()
.build();

Version version = client.api().systemApi().version();

It should be noted that when using this feature a merge happens behind the scenes between all possible ways one can pass in overrides. Meaning if you pass in a Properties object, and there are System Properties and Environment Variables set, then all 3 will be merged into a single Properties object which in turn will be passed along to jclouds. When it comes to precedence passed in Properties take precedence over System Properties which in turn take precedence over Environment Variables.

Examples

The mock and live tests provide many examples that you can use in your own code. If there are any questions feel free to open an issue and ask.

Components

  • jclouds - used as the backend for communicating with Artifactory's REST API
  • AutoValue - used to create immutable value types both to and from the artifactory program

Testing

Running mock tests can be done like so:

./gradlew mockTest

Running integration tests can be done like so (requires Artifactory instance):

./gradlew integTest

Various properties exist for you to configure how the integTest task can be run should the defaults not suffice.

Additional Resources