Day One: Getting Started with Bitbucket Pipelines

Bitbucket Pipelines Demo

By the end of this course, you should be able to put together a multi-step Bitbucket Pipeline to lint, scan, test and deploy your CF app. Check out this video for a demonstration of how Bitbucket works to run pipelines on git push.

Bitbucket Pipelines Config File

Bitbucket Pipelines is mainly configured through a bitbucket-pipelines.yml yaml file in the root of your repository. Remember that yaml files must be carefully indented using spaces, not tabs. Go ahead and create that file now using your favorite editor - we'll add to it as we go.

Every time you push to the Bitbucket repository, Bitbucket will read the configuration from this file and begin running the pipelines per your configuration.

Let's look at a basic configuration file for Bitbucket Pipelines.

This is an example of a pipeline I use on one of my own projects to lint my CFML. Take a good look, because all CI examples in this course will be based on this syntax!

OK? Now let's go through the file line by line until we understand what's going on.

Choosing a Docker Image

TL;DR: Use image: ortussolutions/commandbox:lucee5-alpine for Lucee apps and image: ortussolutions/commandbox:adobe{release}-alpine for ACF apps.

In Bitbucket Pipelines, every build runs in a Docker container, which enables us to tweak our CI build environment simply by choosing a Docker image which suits our needs. We "choose" a docker image by specifying an image and tag on line 1 of our configuration file - something like this: image: <imagename>:<tag>.

The <imagename> portion specifies which Docker image to use, by default pulling the image from the public Docker Hub. In most cases, unless you are a Docker power user looking for lighter/faster builds, I would recommend you use the Ortus Solutions docker image: image: ortussolutions/commandbox:<tag>.

The <tag> portion specifies an exact image version to use. There are many different versions depending on the CF engine or CommandBox configuration you need. For Lucee users, I recommend the lucee5-alpine tag specifying a Lucee 5 engine and the alpine version for a slightly smaller build. If you are running on ACF, use the tag to specify an ACF release such as adobe2016-alpine.

See the full list of ortussolutions/commandbox image tags here.

So the very first line in the bitbucket-pipelines.yml should look like this:

Configuring Branch Pipelines

Next we'll add a default pipeline to run when we push code on any branch. A pipeline defines a series of CI tasks which are run in sequence when a push or merge is made on the specified branch or branches. This course uses the default pipeline to execute on every push to the repository:

We can limit this pipeline to run on a specific branch or branches - for example, on Day Five of the course, we will set up a deployment pipeline to only run on pushes to the master branch. We can also use a "globbing pattern" to instruct Bitbucket to run our pipeline on any branch starting with feat/:

See Bitbucket's globbing patterns cheat sheet for more details on configuring a pipeline branch.

Bitbucket Pipeline Steps

The example config shows a step section with a name and a script section defining various commands to run. This step should contain every command necessary to perform a given task - in the example given, we first install the CFLint CommandBox module then run CFLint with certain parameters.

Any part of the build process can be organized into a separate step or pipeline, but each pipeline and each step starts with a fresh container so don't run box install testbox in one step and expect box testbox run to work in another step - the two commands must be run in the same step, because state is not maintained between pipelines or pipeline steps.

In this course, all pipeline tasks will be run on a single pipeline organized by step, but you should know that Bitbucket supports a maximum of 10 steps per pipeline. In later lessons we will create an additional step for each new CI task - that means we'll have a linting step, a Fixinator step, a testing step, and a deployment step. This will keep our file neat and organized, and allow us to re-run any step individually from Bitbucket:

The following is an example of a pipeline separated into multiple steps:

Bitbucket Pipelines Config Validator

This Bitbucket Pipelines config validator tool can help you check your bitbucket-pipelines.yml file before you bother committing and pushing. (And spending build minutes). If you're going to be playing with the examples in this course, I suggest you paste them in the validator before running them, at least for a while until you are more familiar with the config syntax.

Bitbucket Pipelines Speed Tips

With Bitbucket Pipelines, build time matters because build minutes cost money. Here's a few quick tips to keep your build times low:

Use "Pre-warmed" Alpine Docker Images

In CommandBox parlance, "pre-warmed" means that a specific version of the Lucee server is copied into the image, unpacked, and ready to start before you ever pull down the image to your local machine. For Docker newbies, this just bootstraps the Lucee server startup time with no effort on your part. To use a pre-warmed commandbox docker image, we'll use the lucee5-alpine image tag, which specifies a pre-warmed Lucee 5 server installed on Alpine Linux, which is a light Linux option for the Docker image base.

Build Your Own Docker Image

All of the examples in this course are based on the Ortus Solutions CommandBox Docker image. This image optimizes the CommandBox startup time, so every pipeline step using this image will run faster than they would after a manual install in the pipeline, for example.

To further speed up your pipelines, you might consider building your own Docker image to install fixinator, commandbox-cflint, and any other system modules you may use in a pipeline. This should speed up the install of those modules during the pipeline - although, to be fair, I haven't tried it myself. :)

Limit Clone Depth

Use the clone depth global option to limit the number of git commits to clone into the pipeline container. Unless you plan to be running git commands like git revert <commit> or git checkout <commit> during your build (I don’t!), you should be able to speed up your pipeline through this simple config tip.

Day One Wrap Up: Bitbucket Pipelines Base Configuration

Here's the final bitbucket-pipelines.yml configuration for Lesson One. Your configuration should look extremely similar to this, with your choice of CF engine on line 2.

Enabling Bitbucket Pipelines

Bitbucket Pipelines does not auto-enable just by committing and pushing a bitbucket-pipelines.yml file. To enable Bitbucket Pipelines for your repository, you'll need to:

  1. Navigate to your Bitbucket repo
  2. Under the "Pipelines" group, click "Settings"
  3. Click the toggle for "Enable Pipelines"

Once that is done, commit and push your bitbucket-pipelines.yml file up to the repository. You should be able to browse the repository's "Pipelines" section to see your latest commit trigger a pipelines build. Congrats! Your first pipeline is in place! This early in the course, your pipeline should build successfully - if not you may want to take a look at the Bitbucket Pipelines config validator.

And Lesson One comes to a close. Hope you've got a good handle on Bitbucket Pipelines basics! Any questions? Shoot me an email and I will be happy to give you a hand.

Complete and Continue