This will be a short post aimed at beginners,
describing things you have to do to make sure your stack project
builds quickly on gitlab-ci. The simplest
.gitlab-ci.yml that you
could write that builds your project would be:
before-script: - apt-get update - curl -sSL https://get.haskellstack.org/ | sh build: script: - stack install - stack test
This approach is slow for several reasons:
- It has to install stack from scratch every time.
- It has to download all the dependencies your project needs in order to be built. That means downloading GHC, stack’s dependencies, and your project dependencies. Every time.
- It has to build your whole project and your test whole suite (right, every time, even if you don’t change it).
The three problems can be addressed very simply.
haskell docker image
There is a docker image you can use instead of the default one that gitlab-ci assigns to your build. That image is _/haskell, and it comes with stack preinstalled.
image: haskell build: script: - stack install - stack test
Cache your project dependencies
You can use gitlab-ci caching feature
to avoid rebuilding your project dependencies. Stack
keeps all the libraries you install in a directory called
STACK_ROOT. You can modify
what that directory is by using environment variables or command line flags, but you normally
don’t need to do it. The usual stack root is
~/.stack/. You could find what
on the gitlab-ci runner and then, state in the
.gitlab-ci.yml file that you want that
directory to be cached.
There is a problem though. Gitlab won’t cache paths that fall out of the
it builds your projects in. The right thing to do is to modify
STACK_ROOT so that it is inside
that directory, and then cache it.
image: haskell variables: STACK_ROOT: /builds/.stack build: script: - stack install - stack test cache: paths: - /builds/.stack
Cache your project build
If you just tweak a haskell module in your project, why should your whole thing
build from scratch? Your
project build does not get cached on
STACK_ROOT, but in a directory that is local to your
project’s. That directory is called
.stack-work. Cache that
too and you will be set.
The final yaml file would then be:
image: haskell variables: STACK_ROOT: /builds/.stack build: script: - stack install - stack test cache: paths: - /builds/.stack - .stack-work
So that’s all.