Continous Delivery with Godot

When you create a game there is the possibility that you want to provide it on multiple systems like Linux, Windows, MacOS, Android, iPhone (iOS) or web. Specially when your game engine comes with the functionality to export to multiple systems it kind of offers itself to use this feature so your game can be reached by more people. But this can lead to a hell of exporting work, specially when you want to test those exports in between of the development process. Thanks to the magic of CI/CD and docker this problem can be minimized.

Godot is rich with exporting possibilities like Linux, Windows, MacOS, Android, iPhone and web.

Let’s assume we want to export our Godot game to Linux, Windows, MacOS and web and we want to provide all of them on the itch.io page. The full process for that can take about 15 min and since those platforms can differ strongly (like web games still contain problems with game controller input) we are forced to test those functionalities multiple times in our development process, so we can be sure that they work the same as the others. In the first step tests in form of continuous integrations (CI) can help to cover possible problems.

This is where the Docker image godot-ci comes in place, which provides a godot environment where we can run our project in an enclosed system. To use this image in a CI/CD manner we can use most of the git repository sites out there. Like with Github, Gitlab or Gitea (with the drone plugin) you can write a YAML file which contains the test steps. Those steps can then be execute automatically when you push your code changes to origin/master. And to activate this YAML file you only have to place it in your repository root directory.

Let’s start with a Gitlab YAML example. This Example can differ from the other platforms (Github, GItea/Drone) since they use different CI/CD systems. But overall the process is mostly the same. First we describe which Docker image should be used. If we want to use our godot-ci image we can write the following line in the YAML file:

image: barichello/godot-ci:3.2.3

For the next step we can describe the stages which we want to use. In Gitlab all jobs in a stage can run simultaneously while the jobs between the stages run consecutively.

image: barichello/godot-ci:3.2.3

stages:
  - export
  - deploy

This will give us the following structure in Gitlab CI. The jobs are not included, since we haven’t described them yet. But in the picture you can see in what order the jobs can run:

Pipeline view in Gitlab: The Steps in your YAML file are visual displayed in the overview.

Now we need to describe the jobs. Let’s start with a linux build. For that we create the part linux and add the attribute stage: export:

image: barichello/godot-ci:3.2.3

stages:
  - export
  - deploy

linux:
  stage: export

With that the job gets placed in the export stage, which will be run before any jobs in the stage deploy. To keep our YAML file flexible for other projects, we can add an environment value to provide the name of our project in just one line:

image: barichello/godot-ci:3.2.3

stages:
  - export
  - deploy

variables:               
  EXPORT_NAME: test-project

linux:
  stage: export

Now we can use this variable for the script part, where we define the commands to export the game for Linux:

image: barichello/godot-ci:3.2.3

stages:
  - export
  - deploy

variables:               
  EXPORT_NAME: test-project

linux:
  stage: export
  script:
    - mkdir -v -p build/linux
    - cd $EXPORT_NAME
    - godot -v --export "Linux/X11" ../build/linux/$EXPORT_NAME.x86_64

As you can see on the last line, thanks to the godot-ci image we can directly call the Godot engine which is included in the image. Now there is one Problem: If we run this job it would generate the Linux export but the files are not accessible for us. To get access to the file on Gitlab CI we add the following lines:

image: barichello/godot-ci:3.2.3

stages:
  - export
  - deploy

variables:               
  EXPORT_NAME: test-project

linux:
  stage: export
  script:
    - mkdir -v -p build/linux
    - cd $EXPORT_NAME
    - godot -v --export "Linux/X11" ../build/linux/$EXPORT_NAME.x86_64
  artifacts:
    name: $EXPORT_NAME-$CI_JOB_NAME
    paths:
      - build/linux

This will generate a zip file which can be downloaded in the CI view of Gitlab. At this point we can add now all other export jobs:

image: barichello/godot-ci:3.2.3

stages:
  - export
  - deploy

variables:               
  EXPORT_NAME: test-project

linux:
  stage: export
  script:
    - mkdir -v -p build/linux
    - cd $EXPORT_NAME
    - godot -v --export "Linux/X11" ../build/linux/$EXPORT_NAME.x86_64
  artifacts:
    name: $EXPORT_NAME-$CI_JOB_NAME
    paths:
      - build/linux

windows:
  stage: export
  script:
    - mkdir -v -p build/windows
    - cd $EXPORT_NAME
    - godot -v --export "Windows Desktop" ../build/windows/$EXPORT_NAME.exe
  artifacts:
    name: $EXPORT_NAME-$CI_JOB_NAME
    paths:
      - build/windows

mac:
  stage: export
  script:
    - mkdir -v -p build/mac
    - cd $EXPORT_NAME
    - godot -v --export "Mac OSX" ../build/mac/$EXPORT_NAME.zip
  artifacts:
    name: $EXPORT_NAME-$CI_JOB_NAME
    paths:
      - build/mac

web:
  stage: export
  script:
    - mkdir -v -p build/web
    - cd $EXPORT_NAME
    - godot -v --export "HTML5" ../build/web/index.html
  artifacts:
    name: $EXPORT_NAME-$CI_JOB_NAME
    paths:
      - build/web

With that our CI/CD jobs will create an export for Linux, Windows, Mac and web every time we push new code to the repository. This is very handy isn’t it? Now if you want, you can also include an Android export thanks to a little contribution of myself and others:

Github commits for Android support to show my narcissistic side.

You can find more information how to add Android export on the Github-Page of the image. But one part is still missing: Deployment. We still want to automatically deploy our game on our itch.io page. For that wen can add the following lines in our YAML file:

image: barichello/godot-ci:3.2.3

...

web:
  stage: export
  script:
    - mkdir -v -p build/web
    - cd $EXPORT_NAME
    - godot -v --export "HTML5" ../build/web/index.html
  artifacts:
    name: $EXPORT_NAME-$CI_JOB_NAME
    paths:
      - build/web

# Itch.io Deploy
itchio:linux:
  stage: deploy
  script:
    - butler push ./build/linux $ITCHIO_USERNAME/$ITCHIO_GAME:linux
  dependencies:
    - linux

itchio:windows:
  stage: deploy
  script:
    - butler push ./build/windows $ITCHIO_USERNAME/$ITCHIO_GAME:windows
  dependencies:
    - windows

itchio:macosx:
  stage: deploy
  script:
    - butler push ./build/mac $ITCHIO_USERNAME/$ITCHIO_GAME:mac
  dependencies:
    - mac

For the deploying process on itch.io we use the command line tool butler from itch.io. In this example you have to provide the values for the variables ITCHIO_USERNAME and ITCHIO_GAME which you also can implement like the EXPORT_NAME environment variable before.

With that you implemented a CI/CD system for your game. Every time you push to your repository, the game will be automatically deployed on your itch.io page in just some seconds. And if you want to add test steps for you project you can simply add another stage before the export like this:

...

stages:
  - test
  - export
  - deploy

# just try to run godot and see if there occurs an error
run-test:
  - stage: test
  - script: godot -q

input-test:
  - stage: test
  - script: godot -s res://scripts/my-cool-input-tests.gd

Leave a Reply

Your email address will not be published. Required fields are marked *