Skip to content


Quick start

Get a fresh copy of the abra source code from here.

Install direnv, run cp .envrc.sample .envrc, then run direnv allow in this directory. This will set coopcloud repos as private due to this bug.. Or you can run go env -w but I'm not sure how persistent this is.

Install Go >= 1.16 and then:

  • make build to build
  • ./abra to run commands
  • make test will run tests
  • make install will install it to $GOPATH/bin
  • go get <package> and go mod tidy to add a new dependency

Our Drone CI configuration runs a number of checks on each pushed commit. See the Makefile for more handy targets.

Please use the conventional commit format for your commits so we can automate our change log.

Unit tests

Run tests

Run the entire suite.

make test

Filter tests

Run a specific test.

go test ./pkg/recipe -v -run TestGetVersionLabelLocalDoesNotUseTimeoutLabel

Integration tests

Install dependencies

We use bats, you can install the required dependencies with the following. You also need a working installation of Docker and Go (not covered in this section).

apt install bats-file bats-assert bats-support jq make git

Unfortunately, the latest bats version in Debian stable does not have the "filter tests by tags" feature, which is very handy for running a subset of the tests. For this, we need to install bats from source. It's easy.

apt purge -y bats
git clone
cd bats-core
sudo ./ /usr/local

Run tests

Then you can run the integration test suite with the following.

export ABRA_DIR="$HOME/.abra_test"
bats -Tp tests/integration # DO NOT run this just yet, read below...

ABRA_TEST_DOMAIN should also have a DNS A record for * which points to the same server so that the test suite can deploy apps freely. It's advised that you re-use the same server and therefore the same Traefik deployment for running your integration tests. The test suite does not deploy Traefik for you. Then you'll have more stable results.

You probably don't want to run the entire test suite though, it takes a while. Try the following for starters.

bats -Tp tests/integration/autocomplete.bats

Tagging tests

When a test actually deploys something to a server, we tag it with the following:

# bats test_tags=slow
@test "..." {

Then we can use filters (see below) to pick out a subset of tests which do/do not use a live server. Feel free to come up with your own tags. See the bats-core docs for more.

Filter tests

You can run a specific file.

bats -Tp tests/integration/autocomplete.bats

For example, if you want to check that all abra recipe ... tests remain working.

bats -Tp tests/integration/recipe_*

You can filter on test names to run specific kinds of tests.

bats -Tp tests/integration --filter "validate app argument"

You can filter on tags.

bats -Tp tests/integration --filter-tags "\!slow" # only fast tests
bats -Tp tests/integration --filter-tags "slow"   # only slow tests

You can also only run the previously failed tests.

bats -TP tests/integration --filter-status failed

Debug tests

If you're running into issues and want to debug stuff, you can pass -x to bats to trace all commands run in the test. You can add echo '...' >&3 debug statements to your test to output stuff also.

Using the abra public API

Warning, there is currently no stability promise for the abra public API! Most of the internals are exposed in order to allow a free hand for developers to try build stuff. If people start to build things then we can start the discussion on what is useful to have open/closed and keep stable etc. Please let us know if you depend on the APIs!

The documentation is here. Here's a brief example to get you going:

package main

import (

    abraClient ""
    dockerClient ""

func getClient(serverName string) (*dockerClient.Client, error) {
    cl, err := abraClient.New(serverName)
    if err != nil {
        return nil, fmt.Errorf("getClient: %s", err)
    return cl, nil

func main() {
    cl, err := getClient("")
    if err != nil {

    // do stuff with the client...

Some tools that are making use of the API so far are:


If there's no official release for the architecture you use, you can cross-compile abra very easily. Clone the source code from here and then:

  • enter the abra directory
  • run git tag -l to see the list of tags, choose the latest one
  • run git checkout <tag>, where <tag> is the latest version
  • run GOOS=<os> GOARCH=<arch> [GOARM=<arm>] make build. You only have to use GOARM if you're building for ARM, this specifies the ARM version (5,6,7 etc). See this for a list of all supported OS'es and architectures.

Building in Docker

If you are living under a curse of constant Go environment problems, it might be easier to build abra using Docker:

sudo setenforce 0  # SELinux probably won't allow Docker to access files
docker run -it -v $PWD:/abra golang:1.19.6 bash
cd /abra
. .envrc
git config --global --add /abra  # work around funky file permissions
make build

Release management

We use goreleaser to help us automate releases. We use semver for versioning all releases of the tool. While we are still in the public beta release phase, we will maintain a 0.y.z-beta format. Change logs are generated from our commit logs. We are still working this out and aim to refine our release praxis as we go.

For developers, while using this -beta format, the y part is the "major" version part. So, if you make breaking changes, you increment that and not the x part. So, if you're on 0.1.0-beta, then you'd go to 0.1.1-beta for a backwards compatible change and 0.2.0-beta for a backwards incompatible change.

Making a new release

  • Run the integration test suite and the unit tests (make test) (takes a while!)
  • Change ABRA_VERSION in scripts/installer/installer to match the new tag (use semver)
  • Commit that change (e.g. git commit -m 'chore: publish next tag x.y.z-beta')
  • Make a new tag (e.g. git tag -a x.y.z-beta)
  • Push the new tag (e.g. git push && git push --tags)
  • Wait until the build finishes on
  • Deploy the new installer script (e.g. cd ./scripts/installer && make)
  • Check the release worked, (e.g. abra upgrade; abra -v)

Fork maintenance


We maintain a fork of godotenv because we need inline comment parsing for environment files. You can upgrade the version here by running go get<commit> where <commit> is the latest commit you want to pin to. At time of writing, go get is the command you want to run to maintain the above functionality.


A number of modules in pkg/upstream are copy/pasta'd from the upstream docker/docker/client. We had to do this because upstream are not exposing their API as public.

Due to coop-cloud/organising#358.