Setting up CI/CD pipelines
Contents
This guide describes how you create a CI/CD pipeline that builds, tests and deploys your XP apps with your favorite CI/CD service.
CI/CD images
Enonic builds images specifically made to be used in CI/CD pipelines. Those images can be used with different CI/CD providers to create pipelines. Each image contains the newest minor version of Enonic XP 7
, the newest version of the Enonic CLI
and some other essentials for build pipelines. The image name format is enonic/enonic-ci:<Minor Version><Optional Postfix>
. If you need Yarn or other Node tools, use the -node
postfix images for all versions to 7.13.
Starting on version 7.14, the -node
image has been made the base image while no image is made without these tools.
-
enonic/enonic-ci:7.12
-
enonic/enonic-ci:7.13
-
enonic/enonic-ci:7.12-node
-
enonic/enonic-ci:7.13-node
-
enonic/enonic-ci:7.14
You can see a full list of available images on Docker Hub.
Environmental variables
These variables are only needed if you plan to deploy your XP app in your pipeline. |
-
ENONIC_CLI_REMOTE_URL
is the address of the management port of the server you want to deploy to, i.ehttps://myserver.com:4848
orhttps://myserver.com:4443
. -
ENONIC_CLI_REMOTE_USER
is the user used to deploy. -
ENONIC_CLI_REMOTE_PASS
is the password of the respective user. -
CLIENT_CERT
is an optional variable used only for mTLS based app deployment with github action -
CLIENT_KEY
is an optional variable used only for mTLS based app deployment with github action -
APP_JAR
is an optional variable in githubaction to set path and name of the jar file to be deployed. When not given, github action looks for a .jar file under build/libs.
You can define multiple servers and based on some conditions pick the right server to deploy to. For now we will keep it simple, but if you want to see how that is done see section: Deploying with conditions.
CI/CD providers
Depending on your CI/CD provider the pipeline configuration may vary. In this section we will show how to do minimal configuration so that every time you commit to your repository your app will be built, tested and deployed.
Drone
-
Setup Drone for your project.
-
Set required environmental variables for your project for Drone.
-
Create pipeline file
.drone.yml
in your repository:kind: pipeline type: docker name: default steps: - name: build & test app image: enonic/enonic-ci:{version} commands: - /setup_sandbox.sh - enonic project build - name: deploy App image: enonic/enonic-ci:{version} environment: ENONIC_CLI_REMOTE_URL: from_secret: ENONIC_CLI_REMOTE_URL ENONIC_CLI_REMOTE_USER: from_secret: ENONIC_CLI_REMOTE_USER ENONIC_CLI_REMOTE_PASS: from_secret: ENONIC_CLI_REMOTE_PASS commands: - enonic app install --file build/libs/*.jar
-
Push file to repository:
git add .drone.yml git commit -m "Add Drone pipeline" git push
-
Wait for Drone to build, test and deploy your app to your server.
CircleCI
-
Setup CircleCI for your project.
-
Set required environmental variables for your project for CircleCI.
-
Create pipeline file
.circleci/config.yml
in your repository:version: 2.0 jobs: build: working_directory: ~/app docker: - image: enonic/enonic-ci:{version} steps: - checkout - run: name: Setup sandbox command: /setup_sandbox.sh - run: name: Build and Test App command: enonic project build - run: name: Deploy App command: enonic app install --file build/libs/*.jar
-
Push file to repository:
git add .circleci/config.yml git commit -m "Add CircleCI pipeline" git push
-
Wait for CircleCI to build, test and deploy your app to your server.
Github Actions
-
Setup Github Actions for your project.
-
Set required environmental variables for your project for Github Actions.
-
Create pipeline file
.github/workflows/enonic.yml
in your repository:name: Enonic CI Server deploy script on: [<triggering_event>] jobs: build: runs-on: ubuntu-latest steps: - id: build uses: enonic/release-tools/action-app-build@master - id: deploy uses: enonic/action-app-deploy@main with: url: ${{ secrets.ENONIC_CLI_REMOTE_URL }} username: ${{ secrets.ENONIC_CLI_REMOTE_USER }} password: ${{ secrets.ENONIC_CLI_REMOTE_PASS }} client_cert: ${{ secrets.CLIENT_CERT }} client_key: ${{ secrets.CLIENT_KEY }} app_jar: "<path and name of the app>"
-
Push file to repository:
git add .github/workflows/enonic.yml git commit -m "Add Github Actions pipeline" git push
-
Wait for Github Actions to build, test and deploy your app to your server.
Travis CI
-
Setup Travis CI for your project.
-
Set required environmental variables for your project for Travis CI.
-
Create pipeline file
.travis.yml
in your repository:Travis does not allow you to run custom images, so we will use their prebuilt images instead and deploy your app with curl. language: java jdk: - openjdk11 # No need to specify build/test step, Travis CI does that for us after_success: # We pipe the curl command to xargs echo to be able # to view the output in the Travis dashboard - | curl -X POST -f -s -S -o - \ -u $ENONIC_CLI_REMOTE_USER:$ENONIC_CLI_REMOTE_PASS \ -F "file=@$(find build/libs/ -name '*.jar')" \ $ENONIC_CLI_REMOTE_URL/app/install | xargs echo
-
Push file to repository:
git add .travis.yml git commit -m "Add Travis CI pipeline" git push
-
Wait for Travis CI to build, test and deploy your app to your server.
Jenkins
-
Setup Jenkins for your project.
-
Set required environmental variables for your project for Jenkins.
-
Create pipeline file
Jenkinsfile
in your repository:pipeline { agent { docker { image 'enonic/enonic-ci:{version}' } } environment { ENONIC_CLI_REMOTE_URL = credentials('jenkins-enonic-url') ENONIC_CLI_REMOTE_USER = credentials('jenkins-enonic-user') ENONIC_CLI_REMOTE_PASS = credentials('jenkins-enonic-pass') } stages { stage('Build and Test App') { steps { sh '/setup_sandbox.sh' sh 'enonic project build' } } stage('Deploy App') { steps { sh 'enonic app install --file build/libs/*.jar' } } } }
-
Push file to repository:
git add Jenkinsfile git commit -m "Add Jenkins pipeline" git push
-
Wait for Jenkins to build, test and deploy your app to your server.
Deploying with conditions
In this section we are going to take the pipeline a step further. Instead of building, testing and deploying on every commit, we will introduce some conditions.
Using Drone
Conditions
In this example our conditions will be:
-
Deploy to testing server on:
-
All pull requests to
master
branch
-
-
Deploy to staging server on:
-
All commits in
master
branch
-
-
Deploy to production server on:
-
All builds that are promoted to
production
-
Drone CLI
To setup secrets and do promotions it is easiest to use the Drone CLI. So start by installing the Drone CLI.
Now you have to get your access token for the Drone CLI. You can find it in your user profile on the drone server. If you are using the Drone Cloud service you can view it here.
To test your access token run the commands:
export DRONE_SERVER=https://cloud.drone.io
export DRONE_TOKEN=<your_access_token>
drone info
Creating secrets
Now create secrets for testing, staging and production servers. To do this run the commands:
ORG=<your_github_username_or_organization>
drone orgsecret add $ORG testing-url http://<xp_testing_server>:4848 --allow-pull-request
drone orgsecret add $ORG testing-user <xp_testing_user> --allow-pull-request
drone orgsecret add $ORG testing-pass <xp_testing_pass> --allow-pull-request
drone orgsecret add $ORG staging-url http://<xp_staging_server>:4848
drone orgsecret add $ORG staging-user <xp_staging_user>
drone orgsecret add $ORG staging-pass <xp_staging_pass>
drone orgsecret add $ORG production-url http://<xp_production_server>:4848
drone orgsecret add $ORG production-user <xp_production_user>
drone orgsecret add $ORG production-pass <xp_production_pass>
Create pipelines
Now we follow the same steps as before for Drone, but now our .drone.yml
looks a bit different:
kind: pipeline
type: docker
name: "Test Environment"
# Deploy to testing on pull requests to master branch
trigger:
branch:
- master
event:
include:
- pull_request
steps:
- name: build & test app
image: enonic/enonic-ci:{version}
commands:
- /setup_sandbox.sh
- enonic project build
- name: deploy
image: enonic/enonic-ci:{version}
environment:
ENONIC_CLI_REMOTE_URL:
from_secret: testing-url
ENONIC_CLI_REMOTE_USER:
from_secret: testing-user
ENONIC_CLI_REMOTE_PASS:
from_secret: testing-pass
commands:
- enonic app install --file build/libs/*.jar
---
kind: pipeline
type: docker
name: "Staging Environment"
# Deploy to staging push to master branch
trigger:
branch:
- master
event:
include:
- push
steps:
- name: build & test app
image: enonic/enonic-ci:{version}
commands:
- /setup_sandbox.sh
- enonic project build
- name: deploy
image: enonic/enonic-ci:{version}
environment:
ENONIC_CLI_REMOTE_URL:
from_secret: staging-url
ENONIC_CLI_REMOTE_USER:
from_secret: staging-user
ENONIC_CLI_REMOTE_PASS:
from_secret: staging-pass
commands:
- enonic app install --file build/libs/*.jar
---
kind: pipeline
type: docker
name: "Production Environment"
# Deploy to production on promoted builds
trigger:
target:
- production
steps:
- name: build & test app
image: enonic/enonic-ci:{version}
commands:
- /setup_sandbox.sh
- enonic project build
- name: deploy
image: enonic/enonic-ci:{version}
environment:
ENONIC_CLI_REMOTE_URL:
from_secret: production-url
ENONIC_CLI_REMOTE_USER:
from_secret: production-user
ENONIC_CLI_REMOTE_PASS:
from_secret: production-pass
commands:
- enonic app install --file build/libs/*.jar
Promoting builds to production
Once you are happy with a build that is running on the staging server, you can promote it to production. That is done by running the command:
drone build promote <your_github_username_or_organization/github_repo> <build_number> production
Using CircleCi
Conditions
In this example our conditions will be:
-
Build app on:
-
All commits
-
-
Deploy to testing server on:
-
All commits in branches called
feature-<SOMETHING>
-
-
Deploy to staging server on:
-
All commits in
master
branch -
All tags
-
-
Deploy to production server on:
-
All tags with format
vX.Y.Z
, but only after manual approval. Note that tags have to strictly follow this rule so tagv1.2.3-rc1
will for example not be deployed.
-
To do this we are going to use CircleCI and their workflow API.
Create contexts
Before we create the workflow, we first need to create 3 contexts in our organization. We will call them:
-
testing-server
-
staging-server
-
production-server
Each of these contexts should have those 3 Environmental variables to configure deployment to their respective servers.
Create workflow
Now we follow the same steps as before for CircleCI, but now our .circleci/config.yml
looks a bit different:
version: 2.1
executors:
xp-executor:
docker:
- image: enonic/enonic-ci:{version}
working_directory: ~/app
jobs:
build:
executor: xp-executor
steps:
- checkout
- run:
name: Setup sandbox
command: /setup_sandbox.sh
- run:
name: Build App
command: enonic project build
- persist_to_workspace:
root: ~/app/build
paths:
- libs
deploy:
executor: xp-executor
steps:
- attach_workspace:
at: ~/app/build
- run:
name: Deploy App
command: enonic app install --file build/libs/*.jar
workflows:
xp-ci-cd:
jobs:
- build: # Build and test all commits and tags (but not deploy)
filters:
tags:
only: /.*/
branches:
only: /.*/
- deploy: # Deploy feature-<SOMETHING> branches to test server
name: deploy-testing
context: testing-server
requires:
- build
filters:
branches:
only: /^feature-.*/
- deploy: # Deploy master branch and all tags to staging server
name: deploy-staging
context: staging-server
requires:
- build
filters:
tags:
only: /.*/
branches:
only: master
- deploy-prod-approval: # Require approval to deploy to production server
type: approval
requires:
- build
filters:
tags:
only: /^v[0-9]+\.[0-9]+\.[0-9]+$/
branches:
ignore: /.*/
- deploy: # Deploy tags with format vX.Y.Z to production server
name: deploy-production
context: production-server
requires:
- build
- deploy-prod-approval
filters:
tags:
only: /^v[0-9]+\.[0-9]+\.[0-9]+$/
branches:
ignore: /.*/
Now push this file to your repository and you are done. Now you have a fully functional CI/CD pipeline for your XP app.
To approve production deployments you have to open up your CircleCI project workflow page, pick running workflow that is on hold and approve the deploy-prod-approval job. |