Hugo hosting in bitbucket

So you’ve decided to host a static website using hugo, and you prefer using Bitbucket ever since Microsoft bought Github1. Cool. That shouldn’t be too hard given that this is almost exactly why bitbucket’s pages were built for.

You don’t even need to search outside hugo’s documentation on how to make this work. It’s right there. There’s just one thing that I don’t like. It “forces” you to use Aerobatic.

Don’t get me wrong, aerobatic seems pretty cool but it’s overkill for a simple website hosted from bitbucket. It isn’t a dependency for a hugo deployment, we should be able to work around it.

Let’s see what we can do to make it work.

Configure hugo

First of all, we need to configure hugo.

hugo new site my-username.bitbucket.io
cd my-username.bitbucket.io
git init
touch .gitkeep
git add .gitkeep
git commit -m "Initial commit"

At this point, you might be wondering why I committed an empty file, and ignored the real files that we need. The reason for this will become apparent later. For now, just remember that we’re not committing things to master.

git checkout -b src
git add .
git commit -m "Adding hugo (https://gohugo.io)"

Now we have a default hugo installation that we can configure. Let’s pick a theme and configure the parameters of our website:

# I like to use the coder theme
git submodule add https://github.com/luizdepra/hugo-coder.git themes/hugo-coder

# Update the configuration
# Follow https://github.com/luizdepra/hugo-coder/wiki/Configurations#complete-example
# and remember to set baseURL to "https://my-username.bitbucket.io/"
vi config.toml

git add config.toml

git commit -m "Configure hugo, and add a dependency on the coder theme"

At this point, you’re done with hugo configuration. Next up, bitbucket specifics.

Configure bitbucket pipelines

As with the official guide, we’ll be using pipelines to build our website. Pipelines requires the existence of a file in our top level directory named bitbucket-pipelines.yml.

Create the file, with the following content:

image: beevelop/nodejs-python
pipelines:
  branches:
    src:
      - step:
          script:
            - apt-get update -y && apt-get install -y wget rsync git
            - wget https://github.com/gohugoio/hugo/releases/download/v0.54.0/hugo_extended_0.54.0_Linux-64bit.deb
            - dpkg -i hugo*.deb
            - rm hugo*.deb
            - git submodule init && git submodule update
            - hugo
            - git clean -df resources
            - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
            - git fetch
            - git checkout master
            - rsync -xcaPhvz public/ ./
            - rm -r public
            - git add . && git commit -m "[skip ci] generated from $BITBUCKET_COMMIT" && git push origin master:master

Note: bitbucket-pipelines.yml should be in the same directory as config.toml

Now, that seems to be quite complicated, so let’s take it line by line.

  1. First we ensure that wget, rsync and git are installed in the system.
  2. Then we fetch the extended version of hugo for linux… (The coder theme requires this version rather than the standard)
  3. …we install it…
  4. …and remove the installer. There’s no reason to keep the file any more.
  5. Then we ensure that the theme that is referenced in the configuration is present…
  6. …and proceed to build the website. At this point, we have everything we need under the public/ directory. The build process has also dropped some files in the resources/ directory, which we don’t really care about…
  7. …so we delete them. They are not tracked by git, so git clean will do the job.
  8. Then we tell git to retrieve all remote branches when running git fetch
  9. …and run git fetch. You guessed it. This is necessary, because by default there are no references to the master branch and we want to check it out.
  10. At this point we checkout the master branch. Remember, the generated sources are still under public/, and they won’t get overwritten while switching the branch, because that path is not tracked.
  11. Now we copy everything under public/ on the top level of the master branch. You can use cp over rsync, but that’s a matter of personal preference.
  12. Since we’ve copied everything that we need, delete the public/ directory.
  13. Last but not least, we commit everything and push the master branch.

Why all those steps, you might ask? Well, when we deploy our site to bitbucket pages, everything that is committed to our master branch will be publicly accessible. And while we don’t have any sensitive information committed, it’s still not a good idea to make all the files of your repository available to crawlers.

This way, we have our HTML files automatically committed to our master branch, which is used for hosting the page, and all our sources safely stored on a different branch. Obviously, this makes more sense if your bitbucket repository is set to private, but the separation is pretty cool either way.

Commit bitbucket-pipelines.yml, and push everything to bitbucket:

git add bitbucket-pipelines.yml
git commit -m "Configure bitbucket pipelines to build hugo"

git remote add origin git@bitbucket.org:my-username/my-username.bitbucket.io.git
git push -u origin master:master src:src

That’s it. The pipelines will pick up the files from your src branch, and build them on your master. After the build is complete, your website will be available at https://my-username.bitbucket.io

EOF