diff --git a/jenkins-pipeline-examples/README.md b/jenkins-pipeline-examples/README.md new file mode 100644 index 000000000..91248f624 --- /dev/null +++ b/jenkins-pipeline-examples/README.md @@ -0,0 +1,161 @@ +# Jenkins Pipeline - Working With Artifactory + +## Introduction +The Pipeline Jenkins Plugin allows you to create a script that defines your build steps. +For those not familiar with Jenkins Pipeline, check out the [Pipeline Tutorial](https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md) or the [Getting Started With Pipeline](https://jenkins.io/doc/pipeline/) documentation. +We recently added support for Artifactory operations as part of the Pipeline script DSL. +You have the added option of downloading dependencies, uploading artifacts, and publishing build-info to Artifactory from a Pipeline script. +Pipeline support for Artifactory is provided by the [Jenkins Artifactory Plugin](https://github.com/JFrogDev/jenkins-artifactory-plugin). +The official release of the Jenkins Artifactory Plugin with Pipeline support has not been published yet, +but will become available within the coming weeks. +In the meantime, we encourage you to try out the plugin snapshot. + +## Installing the Plugin Snapshot +1. Ensure that the Pipeline Plugin is installed on your Jenkins instance. +2. Download the the Artifactory Plugin snapshot from [this link](https://bintray.com/jfrog/jfrog-jars/download_file?file_path=artifactory.hpi). +3. To install the Artifactory Plugin you downloaded, follow these steps: + * Go to ‘Manage Jenkins’ --> ‘Manage Plugins’ --> ‘Advanced’ tab. + * In the ‘Upload Plugin’ section, select the path to the artifactory.hpi file and click ‘Upload’. + * Restart Jenkins. + +## Using the Artifactory DSL +### Creating an Artifactory Server Instance +To upload or download files to and from your Artifactory server, first you need to +create an Artifactory server instance in your Pipeline script. +If your Artifactory server is pre-defined in Jenkins, all you need is the server ID. +To obtain or set your Artifactory server ID, go to Manage --> Configure System. +Then, you can create your Artifactory server instance by adding the following line to your script: +``` +def server = Artifactory.server('my-server-id') +``` +You also have the option of creating an Artifactory instance, even if the server is not pre-defined in Jenkins. To create an Artifactory instance, add the following line to your script: +``` +def server = Artifactory.newServer('artifactory-url', 'username', 'password') +``` +We recommend using variables, rather than plain text, to specify the Artifactory server details. + +### Uploading and Downloading Files To and From Artifactory +Once you have created an Artifactory server instance, you are ready to download files from an Artifactory server. First, you need to create a spec, +which is a json string. +The spec defines the files that you want to download and the target path for the files. +See the example below: +``` +def downloadSpec = '{ + "files": [ + { + "pattern": "bazinga-repo/*.zip", + "target": "bazinga/" + } + ] +}' +``` +The above spec defines the following: +Downloads all zip files in the *bazinga-repo* Artifactory repository into the +*bazinga* directory on your Jenkins agent file-system. +Notice that *files* is a list, therefore, your spec can include a list of patterns and targets. +The following step is to use the spec to download the files. To download the files, add the following line: +``` +server.download(downloadSpec) +``` +Piece of cake, right? + +The process of uploading files is similar to downloading files. First, create a spec and then use this spec to upload files to the Artifactory server: +``` +def uploadSpec = '{ + "files": [ + { + "pattern": "bazinga/*froggy*.zip", + "target": "bazinga-repo/froggy-files" + } + ] +}' +server.upload(uploadSpec) +``` +The code shown above uploads all zip files that include *froggy* in their names into the *froggy-files* foldder in the *bazinga-repo* Artifactory repository. + +### Publishing Build-Info to Artifactory +Both the download and upload methods return a build-info object, which can be published +to Artifactory. Below is an example code sample: +``` +def buildInfo1 = server.download(downloadSpec) +def buildInfo2 = server.upload(uploadSpec) +buildInfo1.append(buildInfo2) +server.publishBuildInfo(buildInfo1) +``` +Below is a second example: +``` +def buildInfo = Artifactory.newBuildInfo() +server.download(artifactoryDownloadDsl, buildInfo) +server.upload(artifactoryDownloadDsl, buildInfo) +server.publishBuildInfo(buildInfo1) +``` + +## Advanced Upload Options +### Using Placeholders When Uploading +The upload spec allows for flexibility in how you define the target path by using wildcard or regular expressions with placeholders. +Any wildcard enclosed in parenthesis in the source path can be matched with a corresponding placeholder in the target path to determine the name of the artifact once uploaded. +In the following example, for each .tgz file in the source directory, a corresponding directory with the same name +is created in the target repository and the file is created in the corresponding directory. +For example, a file called froggy.tgz is uploaded to my-local-rep/froggy/froggy.tgz. +``` +def uploadSpec = '{ + "files": [ + { + "pattern": "(*).tgz", + "target": "my-local-repo/{1}/" + "recursive": "false" + } + ] +}' +``` +### Using Regular Expressions +You have the option of using a regular expression rather than wildcard patterns to define the upload pattern. Add *"regexp": "true"* to the spec. +See the example below: +``` +def uploadSpec = '{ + "files": [ + { + "pattern": "(.*).tgz", + "target": "my-local-repo/{1}/" + "recursive": "false" + "regexp": "true" + } + ] +}' +``` + +## The Download Spec Schema +You can also use [AQL](https://www.jfrog.com/confluence/display/RTF/Artifactory+Query+Language) instead of wildcard patterns: +``` +{ + "files": [ + { + "pattern" or "aql": "[Mandatory]", + "target": "[Mandatory]", + "props": "[Optional]", + "recursive": "[Optional, Default: true]", + "flat" : "[Optional, Default: false]" + } + ] +} +``` +## The Upload Spec Schema +``` +{ + "files": [ + { + "pattern": "[Mandatory]", + "target": "[Mandatory]", + "props": "[Optional]", + "recursive": "[Optional, Default: 'true']", + "flat" : "[Optional, Default: 'true']", + "regexp": "[Optional, Default: 'false']" + } + ] +} +``` +## Examples +The examples below are meant to help you get started using the Artifactory DSL in your Pipeline scripts. + +* The [props-example](https://github.com/jfrogdev/project-examples/tree/master/jenkins-pipeline-examples/props-example]) download and upload files to Artifactory with properties. The props-example also uses a placeholder when uploading. +* The [aql-example](https://github.com/jfrogdev/project-examples/tree/master/jenkins-pipeline-examples/aql-example]) uses [AQL](https://www.jfrog.com/confluence/display/RTF/Artifactory+Query+Language) in its download spec. diff --git a/jenkins-pipeline-examples/aql-example/Jenkinsfile b/jenkins-pipeline-examples/aql-example/Jenkinsfile new file mode 100644 index 000000000..75bf9ec82 --- /dev/null +++ b/jenkins-pipeline-examples/aql-example/Jenkinsfile @@ -0,0 +1,22 @@ +node { + git url: 'https://github.com/jfrogdev/project-examples.git' + def filePathPrefix = 'aql-example/' + + // Get Artifactory server instance, defined in the Artifactory Plugin administration page. + def server = Artifactory.server SERVER_ID + + def buildInfo = Artifactory.newBuildInfo() + // You can set the build name and number. + buildInfo.setName 'holyFrog' + buildInfo.setNumber '42' + + // Read the upload spec which was downloaded from github. + def uploadSpec = readFile "${filePathPrefix}upload.json" + // Upload to Artifactory. + server.upload uploadSpec, buildInfo + + // The download file contains pattern for downloading artifacts to the root directory by setting recursive=false + def downloadSpec = readFile "${filePathPrefix}download.json" + server.download downloadSpec, buildInfo + server.publishBuildInfo buildInfo +} diff --git a/jenkins-pipeline-examples/aql-example/download.json b/jenkins-pipeline-examples/aql-example/download.json new file mode 100644 index 000000000..8135b4578 --- /dev/null +++ b/jenkins-pipeline-examples/aql-example/download.json @@ -0,0 +1,38 @@ +{ + "files": [ + { + "aql": { + "items.find": { + "repo": "libs-snapshot-local", + "$or": [ + { + "$and": [ + { + "path": { + "$match": "." + }, + "name": { + "$match": "​*Pipeline.zip" + } + } + ] + }, + { + "$and": [ + { + "path": { + "$match": "*​" + }, + "name": { + "$match": "*Pipeline.zip" + } + } + ] + } + ] + } + }, + "target": "Bazinga/Artifactory/" + } + ] +} diff --git a/jenkins-pipeline-examples/aql-example/upload.json b/jenkins-pipeline-examples/aql-example/upload.json new file mode 100644 index 000000000..c94019756 --- /dev/null +++ b/jenkins-pipeline-examples/aql-example/upload.json @@ -0,0 +1,14 @@ +{ + "files": [ + { + "pattern": "files/*Artifactory*.zip", + "target": "libs-snapshot-local/", + "recursive": "false" + }, + { + "pattern": "files/*ArtifactoryPipelineNoFlat.zip", + "target": "libs-snapshot-local", + "flat" :"false" + } + ] +} diff --git a/jenkins-pipeline-examples/files/ArtifactoryPipeline.zip b/jenkins-pipeline-examples/files/ArtifactoryPipeline.zip new file mode 100644 index 000000000..15cb0ecb3 Binary files /dev/null and b/jenkins-pipeline-examples/files/ArtifactoryPipeline.zip differ diff --git a/jenkins-pipeline-examples/files/ArtifactoryPipelineNoProps.zip b/jenkins-pipeline-examples/files/ArtifactoryPipelineNoProps.zip new file mode 100644 index 000000000..15cb0ecb3 Binary files /dev/null and b/jenkins-pipeline-examples/files/ArtifactoryPipelineNoProps.zip differ diff --git a/jenkins-pipeline-examples/files/recursiveArtifacts/InnerArtifactoryPipeline.zip b/jenkins-pipeline-examples/files/recursiveArtifacts/InnerArtifactoryPipeline.zip new file mode 100644 index 000000000..15cb0ecb3 Binary files /dev/null and b/jenkins-pipeline-examples/files/recursiveArtifacts/InnerArtifactoryPipeline.zip differ diff --git a/jenkins-pipeline-examples/files/recursiveArtifacts/InnerArtifactoryPipelineNoFlat.zip b/jenkins-pipeline-examples/files/recursiveArtifacts/InnerArtifactoryPipelineNoFlat.zip new file mode 100644 index 000000000..15cb0ecb3 Binary files /dev/null and b/jenkins-pipeline-examples/files/recursiveArtifacts/InnerArtifactoryPipelineNoFlat.zip differ diff --git a/jenkins-pipeline-examples/props-example/Jenkinsfile b/jenkins-pipeline-examples/props-example/Jenkinsfile new file mode 100644 index 000000000..936d98d9d --- /dev/null +++ b/jenkins-pipeline-examples/props-example/Jenkinsfile @@ -0,0 +1,22 @@ +node { + git url: 'https://github.com/jfrogdev/project-examples.git' + def filePathPrefix = 'jenkins-pipeline-examples/props-example/' + + // Get Artifactory server instance, defined in the Artifactory Plugin administration page. + def server = Artifactory.server SERVER_ID + + // Read the upload spec which was downloaded from github. + def uploadSpec = readFile "${filePathPrefix}upload.json" + // Upload to Artifactory. + def buildInfo1 = server.upload uploadSpec + + // Read the upload spec and upload files to Artifactory. + def downloadSpec = readFile "${filePathPrefix}download.json" + def buildInfo2 = server.download downloadSpec + + // Merge the upload and download build-info objects. + buildInfo1.append buildInfo2 + + // Publish the build to Artifactory + server.publishBuildInfo buildInfo1 +} diff --git a/jenkins-pipeline-examples/props-example/download.json b/jenkins-pipeline-examples/props-example/download.json new file mode 100644 index 000000000..eead2385e --- /dev/null +++ b/jenkins-pipeline-examples/props-example/download.json @@ -0,0 +1,9 @@ +{ + "files": [ + { + "pattern": "libs-snapshot-local/*(Pipeline).zip", + "target": "Bazinga/{1}/", + "props": "p1=v1;p2=v2" + } + ] +} \ No newline at end of file diff --git a/jenkins-pipeline-examples/props-example/upload.json b/jenkins-pipeline-examples/props-example/upload.json new file mode 100644 index 000000000..ab1e8b764 --- /dev/null +++ b/jenkins-pipeline-examples/props-example/upload.json @@ -0,0 +1,13 @@ +{ + "files": [ + { + "pattern": "jenkins-pipeline-examples/files/ArtifactoryPipeline.zip", + "target": "libs-snapshot-local", + "props": "p1=v1;p2=v2" + }, + { + "pattern": "jenkins-pipeline-examples/files/ArtifactoryPipelineNoProps.zip", + "target": "libs-snapshot-local" + } + ] +}