Adding a Jekyll Pipeline in Azure DevOps
Christopher Tobin
November 09, 2019
GitHub Pages has served me pretty well so far. I’ve been using it to host this website and I’ve found it to be a really incredible tool. I decided to take this a step further by integrating some devops tools into the mix with Azure DevOps. Azure DevOps is pretty awesome. It’s a one-stop-shop for managing code, backlog items, bugs, builds, deployments, tests, and just about anything else related to software development and project management.
Azure DevOps enables us to hook up to a GitHub repository and create a build pipeline. We are able to build just about anything, and deploy it anywhere if we do things properly. While Azure DevOps doesn’t have any built-in templates for building Jekyll applications, creating one from scratch is pretty simple.
Creating the Pipeline
We’ll first need to login to Azure DevOps and create a new pipeline. After selecting Pipelines
from the menu on the left of the page, we’ll be presented with a button that will allow us to create a New Pipeline
. We’ll be asked to select where our code lies. For our purposes we’ll be selecting GitHub. After authenticating with GitHub, we’ll be able to select which repository we want to hook up to Azure DevOps. An editor will be opened that will allow us to configure the build pipeline with the yml
syntax. Note that yml
is very particular about the spacing and indentation for the different elements in the file, so pay extra close attention that everything is indented properly. It is very easy to make a syntax error working with these files.
Configuring the pipeline from here is actually super simple. We’ll first want to specify what branch this pipeline will apply to. I’ve set this pipeline here to trigger only for commits on the master
branch. I’ve also chosen to execute this pipeline on an ubuntu
server. There are also options for using a Mac or Windows vm to execute the pipeline on if that is desired.
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
Now that we have that out of the way, we can get to the fun part where we actually configure the different steps we want to execute in our build pipeline. For the first step we have to tell the pipeline what language we should use during the build process. Because we are building a Jekyll application, we’ll be selecting Ruby. As of this post, Jekyll requires a minimum Ruby version of 2.4.0. Any version of Ruby can be used here, but it should be at least 2.4.0.
steps:
- task: UseRubyVersion@0
inputs:
versionSpec: '>= 2.4'
Our next steps will execute some scripts on the command line. We’ll first install bundler so that we can install all of the dependencies that are needed for our project. We can also give these steps a friendly name so that the build logs make a bit more sense. Note that during the build process, the bundle install
step tends to take a couple of minutes to run.
steps:
- task: UseRubyVersion@0
inputs:
versionSpec: '>= 2.4'
- script: gem install bundler
displayName: 'Install Bundler'
- script: 'bundle install'
displayName: 'Install Jekyll and Dependencies'
Now comes the magic! With bundler and all of our dependencies installed, we are now able to actually build the Jekyll site. Executing the simple bundle exec jekyll build
command will suffice here. By default this will generate the site in a _site
folder which we’ll look for in one of the later steps.
- script: 'bundle exec jekyll build'
displayName: 'Build Jekyll Site'
We’re almost there! Our last step will be to take the output from bundle exec jekyll serve
and publish an artifact so that it can be used in a deployment step later on. The first step in this process is to copy the files from the _site
folder to the $(Build.ArtifactStagingDirectory)
folder. This is a default folder location for artifacts that we can reference later. We then take this _site
folder and publish an artifact I’m naming _site
. Although I’ve named this artifact the same name as the folder, it most certainly doesn’t have to be.
- task: CopyFiles@2
displayName: 'Copy Files to: $(Build.ArtifactStagingDirectory)'
inputs:
SourceFolder: '_site'
TargetFolder: '$(Build.ArtifactStagingDirectory)'
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: _site'
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: '_site'
Final Pipeline
Putting it all together and we have a build pipeline! We can now commit this file to our repository and it will be read whenever there is a commit on the master
branch. Pretty cool huh?
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseRubyVersion@0
inputs:
versionSpec: '>= 2.4'
- script: gem install bundler
displayName: 'Install Bundler'
- script: 'bundle install'
displayName: 'Install Jekyll and Dependencies'
- script: 'bundle exec jekyll build'
displayName: 'Build Jekyll Site'
- task: CopyFiles@2
displayName: 'Copy Files to: $(Build.ArtifactStagingDirectory)'
inputs:
SourceFolder: '_site'
TargetFolder: '$(Build.ArtifactStagingDirectory)'
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: _site'
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: '_site'