When Travis CI was acquired by Idera, it didn’t take long to cease its support for open source projects. This affected this blog since I overengineered it to learn some dev-ops skills. As result, I was forced to migrate the continuous integration (CI) tool from Travis to CircleCI. While I was at it, I took advantage and included a docker image for the build instead of declaring the dependencies installation as part of the CI build.
I am indebted to z0li who provided a guide I was able to follow through here. The Docker image, config.yml and deploy scripts were modified from z0li’s post.
1.Docker Image
This is the base Docker image upon which the blog is built. It still contains htmlproofer even though I am not using it at the moment. It is something either I’ll adopt or drop in the future. It also contains, of course, hugo version 0.68.1 which is the last one I troubleshooted the cocoa theme for as detailed in my previous post.
FROM ruby:2.6-alpine3.9
ENV HUGO_VERSION=0.68.1
RUN apk add --no-cache make gcc libc-dev bash libcurl ruby-nokogiri \
openssh-client rsync git && \
gem install --no-document html-proofer
RUN mkdir /tmp/hugo && \
cd /tmp/hugo && \
wget https://github.com/spf13/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz && \
tar xzvf hugo_${HUGO_VERSION}_Linux-64bit.tar.gz && \
mv /tmp/hugo/hugo /usr/local/bin/ && \
rm -rf /tmp/hugo
CMD [ "hugo", "version" ]
2. config.yml
This is where most of the action happens, the config.yml file required by CircleCI.
version: 2.1
jobs:
build:
docker:
- image: gtpedrosa/hugo-build:latest
working_directory: /src
steps:
- add_ssh_keys:
fingerprints:
- "x4TBLAoCPktmU+ECc3aoxBPuymLldWBEaFpnR8yFDdE"
- checkout
- run: git submodule update --init
- run: hugo -v -s /src -d /src/public
- deploy:
name: push to master branch
command: sh /src/scripts/deploy_ci.sh
Notice:
- docker: it pulls the image previously uploaded to dockerhub and linked to my github repo.
- working_directory: specify the location to work from
- add_ssh_keys: include necessary credentials so circleci communicates to github
- checkout: special command to checkout the gtpedriosa.github.io repo
- first run: update submodules, in this case, the hugo theme used and fork that I mantain, but designed by Nishanth Shanmugham
- second run: after pulling the code it runs hugo and saves the html in the usual public folder
- deploy: calls deploy script where the rest of action happens, which I’ll document in the following section.
3. deploy_ci.sh
Admitedly, I made inumerous mistakes in this transition. And learned a lot by trial and error, so here’s the full file:
#!/bin/bash
set -e
echo "* checking out the master branch:"
git clone --single-branch --branch master git@github.com:gtpedrosa/gtpedrosa.github.io.git master
echo "* synchronizing the files:"
rsync -arv /src/public/ master --delete --exclude ".git"
cp README.md master/
echo "* pushing to master:"
cd master
echo "cd OK"
git config user.name "CircleCI"
git config user.email "guilherme.pedrosa@gmail.com"
echo "git config OK"
git add -A
echo "git add OK"
git commit -m "Automated deployment job ${CIRCLE_BRANCH} #${CIRCLE_BUILD_NUM} [skip ci]" --allow-empty
echo "git commit OK"
git push origin master
echo "* done"
Now, let’s break it down in three parts and make some comments.
set -e
The first excerpt causes the execution of the script to fail if an error is raised, instead of the default behavior of ignoring it. Therefore, any issues in the deployment will cause the build to fail.
echo "* checking out the master branch:"
git clone --single-branch --branch master git@github.com:gtpedrosa/gtpedrosa.github.io.git master
echo "* synchronizing the files:"
rsync -arv /src/public/ master --delete --exclude ".git"
cp README.md master/
The html files in the master branch are cloned in this second part. The generated html pages from the hugo run (refer to the second run statement in the config.yml file) are synced to the folder where the html files were cloned. Notice where they are coming from in the rsync argument. This is basically where the new posts are added to the previous ones.
echo "* pushing to master:"
cd master
echo "cd OK"
git config user.name "CircleCI"
git config user.email "guilherme.pedrosa@gmail.com"
echo "git config OK"
git add -A
echo "git add OK"
git commit -m "Automated deployment job ${CIRCLE_BRANCH} #${CIRCLE_BUILD_NUM} [skip ci]" --allow-empty
echo "git commit OK"
git push origin master
echo "* done"
Lastly, the changes are commited and pushed to master. This will update the ghpages site automatically. One detail to note is the [skip ci] tag. From the documentation:
By default, CircleCI automatically triggers a pipeline whenever you push changes to your project. You can override this behavior by adding a [ci skip] or [skip ci] tag within the first 250 characters of the body or title of the commit.
If you ommit it, another job will be triggered and fail. This is messing up with the badge in the readme of the repository at this exact moment.
Also, any issue in the build can be debugged in the newly spun environment by sshing in an interactive shell. I really appreciated this to understand where I messed up with my paths.
Well, I hope this breakdown distilled some of the learnings in the process.
Hey, be the first who comment this article.