How to setup one-click deployment to Itch.io


On r/RogueLikeDev I noticed that there was an FAQ Friday where developers were talking about packaging and distribution. Having worked with many software teams over the years, and maintained various infrastructures I knew how crucial this was to get right. With this in mind, I decided one of the things I would focus on early in Coffee Break RL’s development was a solid release system.


As I’m a big fan of open-source, I use GitLab was my code repository and Continuous Integration (CI) environment. This gave a great starting point for planning my game’s deployment. I’d also seen that the 7drl (7 day RogueLike) challenge hosted it’s games on Itch.io. This gave the second half of my deployment system: Continuous Deployment (CD).

The primary benefit of having a CI/CD infrastructure in place is that I don’t have to worry about deploying my game. I know that it will always have been tested (to some degree) before I release it, and given how strict Rust’s compiler is, it is unlikely that I will run into any runtime errors (though this is not a guarantee by any means!).

GitLab uses a configuration file called: .gitlab-ci.yml to control it’s CI/CD environment. If you want to take a look at Coffee Break RL’s gitlab-ci file, you can find it here. This file essentially consists of the following sections:

  • Define the stages of deployment (e.g. Test/Build/Deploy)
  • Define any global variables or parameters
  • Define the scripts that run within each stage

We can define the stages by simply adding the following code to our .gitlab-ci.yml file:

# Define stages
stages:
  - test
  - build
  - deploy

This gives us three stages: test, build, deploy (testing happens at compilation for Rust).
We can now add any variables that we might need:

# Set any required environment variables here
variables:
  RUST_BACKTRACE: "FULL"
# Do any pre-flight requirements here, such as updating $PATH installing dependencies
before_script:
  - export PATH="/root/.cargo/bin:$PATH"

Here we are setting a local environmental variable: RUST_BACKTRACE to “FULL” making sure our compiler will provide a full trace back to any errors it finds. We have also exported to the path to the cargo binary. This will run before every script in our gitlab-ci.yml file.

Finally we can create the scripts that will actually run:

build:linux:
  stage: build
  allow_failure: true
  image: "rustdocker/rust:stable"
  script:
    # Edit /root/.profile to deal with incorrect error messages
    - sed -i '$d' /root/.profile; sed -i '$d' /root/.profile; sed -i '$d' /root/.profile
    - cat /root/.profile
    - echo "test -t 0 && mesg n || true" >> /root/.profile
    - sed -i -e '$a\' /root/.profile
    - cat /root/.profile
    # Update system
    - sudo apt-get -y update; sudo apt-get -y dist-upgrade</p>
    # Install dependencies</p>
    - sudo apt-get -y install python3
    - sudo apt-get -y install cmake 
    - sudo apt-get -y install libexpat1-dev
    - sudo apt-get -y install libfreetype6-dev
    - sudo apt-get -y install libasound2-dev
    - sudo apt-get -y install libxcb-shm0
    - sudo apt-get -y install libx11-xcb-dev
    - sudo apt-get -y install libxcb-render-util0-dev
    - sudo apt-get -y install libxcb-shape0-dev
    - sudo apt-get -y install libxcb-xfixes0-dev
    # Build
    - rustc --version && cargo --version
    - cargo build --release
    # Clean up
    - mv target/release/coffeebreakrl ./
  artifacts:
    paths:
      - coffeebreakrl
      - resources
      - texture
      - font
      - README.md
      - LICENSE.md
    expire_in: 1 month

Wow that seems like a lot! Let’s break that down:

build:linux:
  stage: build
  allow_failure: true
  image: "rustdocker/rust:stable"

These first few lines are just defining the name of the script (build:linux in this case); what stage the script is part of (the build stage); we’re going to allow this script to fail (this can be useful if you want the rest of your CI/CD system to run); and finally we’re telling GitLab which Docker image we want to run our script in. If you’re not familiar with Docker, this is essentially just a pre configured environment we can use. In this case, it’s a Debian operating system with the stable version of Rust installed on top.

The next bit of code:

script:
    # Edit /root/.profile to deal with incorrect error messages
    - sed -i '$d' /root/.profile; sed -i '$d' /root/.profile; sed -i '$d' /root/.profile
    - cat /root/.profile
    - echo "test -t 0 && mesg n || true" >> /root/.profile
    - sed -i -e '$a\' /root/.profile
    - cat /root/.profile
    # Update system
    - sudo apt-get -y update; sudo apt-get -y dist-upgrade
    # Install dependencies
    - sudo apt-get -y install python3
    - sudo apt-get -y install cmake
    - sudo apt-get -y install libexpat1-dev
    - sudo apt-get -y install libfreetype6-dev
    - sudo apt-get -y install libasound2-dev
    - sudo apt-get -y install libxcb-shm0
    - sudo apt-get -y install libx11-xcb-dev
    - sudo apt-get -y install libxcb-render-util0-dev
    - sudo apt-get -y install libxcb-shape0-dev
    - sudo apt-get -y install libxcb-xfixes0-dev
    # Build
    - rustc --version && cargo --version
    - cargo build --release
    # Clean up
    - mv target/release/coffeebreakrl ./

is simply bash script that will execute. I won’t go through what it’s doing here (it’s fairly well commented), but be aware that if you are using a Docker image that doesn’t have bash (such as Windows) you’ll need to use a scripting language native to that operating system.

Finally:

artifacts:
    paths:
      - coffeebreakrl
      - resources
      - texture
      - font
      - README.md
      - LICENSE.md
    expire_in: 1 month

This section just tells GitLab that we’d like to keep the files/directories listed in the ‘paths’ section for 1 month. We can download these via an API or from GitLab directly. We’ll be using these for pushing builds to Itch.io. A minimal example gitlab-ci.yml file can be found here.


So now that we’ve seen what GitLab can do, let’s talk about Itch.io. Itch.io uses Butler for pushing build via an API. This is really quite a slick method dealing with it. To use Butler:

  1. Download your flavor of Butler here
  2. Run “butler login” locally to generate an API key which can be found in your account settings on Itch.io (it should have Wharf next to it)
  3. Add the API key to your GitLab repo, as per this guide (note this guide is awesome and really helped me out!)
  4. You’re done!

You can kick a CI/CD job in GitLab by pushing a commit to your repository. If you’d like to see a more complex system with different branches and manual release buttons, check out Coffee Break RL’s gitlab-ci.yml file.

Until next time, keep on coding!

Get Coffee Break RL

Download NowName your own price

Leave a comment

Log in with itch.io to leave a comment.