We’ll describe how to integrate a Hugo project repo with Gitlab CI and deploy the built site on Gitlab Pages automatically. If you host your static site on another platform/server, the actions you’ll need to do might be slightly different. In all cases, the major thing is to specify how the
public folder of the project will be uploaded to the frontend server. These configurations are declarative and abide to the rules of the .gitlab-ci.yml specification.
Gitlab Pages is a free service to host one static web site per Gitlab project. The site will have a default domain consisting of our Gitlab username and project name:
Custom domains are supported.
Create .gitlab-ci.yml file
Gitlab CI recipes are declared in the
.gitlab-ci.yml located in the root folder of the project. We must create it, if it doesn’t exist.
Below are the file contents from my blog.
On line 1 we say what docker image we’d like to use as a base for the container that will be created for us and started by the Gitlab runners. I use a predefined container with a fixed Hugo version (0.54.0), as I’d like to have reproducible builds and be sure that the container will be baked with exactly the same Hugo version, that I’m using locally for development.
On line 3 we define a git resolving strategy for submodules in case our theme is downloaded as a git submodule. In my case, I have followed the tutorial and added the theme as a submodule.
Next we define two CI jobs.
On line 6 we start the definition of a job named
test. The name
test is an arbitrary string that we’ve chosen, it may be something else.
script part on line 7 contains the commands that will be executed inside the container shell. There may be multiple commands on each new line, but for our current needs we only run
This has the same effect as running the
hugo command locally inside the root folder of our project. The command will build our static web site and put it inside a
public folder (will create it if doesn’t exist). If the build completes successfully, the command will terminate with
exit code 0 and the job will pass ✅. It the build process fails, the command will terminate with
exit code > 0 and the CI job will fail ❌.
In reality, with the
test job just described, we haven’t really written any tests for our project (e.g. unit, intergration, etc.), but we implicitly say that if the build process of our static site succeeds, we consider the site OK and tested.
On line 9 we use the
except word to specify when the job should not be executed. The
master value says that the job should not be executed for a branch called
master. Instead, it will be executed for all other branches that we may have and push commits to.
The CI job
pages is more magical and subtle as it not only tests our site in the same way as we did in the
test job, but it also automatically deploys the site to Gitlab Pages, if the build process is successful.
On line 14 we run the
hugo command again, but this time with a flag to specify the environment configuration. The flag tells
hugo to look for
config.toml file inside the
/config/production/ folder. We need this so we can specify different variables for production. For example, the
baseURL variable may point to a real domain name like
https://myusername.gitlab.io/myproject, while the default
config.toml may set
baseURL = "http://localhost:1313".
The magic with the automatic deployment happens on line 15 with the word
artifacts. It says that the
public folder (which was generated during the run of
script), must not be deleted after the job is completed, but instead will be available afterwards. Whenever the Gitlab system finds this folder after the job completes, it will deploy it to the Gitlab Pages for our project. And bam… we have our site online.
When depoying to Gitlab Pages for the first time, the infrastructure needs 10-20 minutes to initialize the site and put it online. During this initial period we may see
404 Page Not Found error. We should wait for some time until the site goes live.
The last declaration in our
.gitlab-ci.yml file is the word
only. It defines another value which tells that the job should be executed only for commits in the
master branch. So whenever we merge a branch to
master or directly push commits to
master the site will be redeployed to Gitlab Pages.