BlogHome

Bevy <3 Github Actions

2023-04-08

In this post, I want to show how I did manage to automate building and publishing my game written with Bevy to GitHub Pages using GitHub Actions. Few years ago I was working on some side project game- Slavic Castles. It was written in Rust, using Quicksilver framework. Lately I wanted to return to work on it, but it seems like the framework is dead. Bevy seems like a most used Rust game framework, so I've decided to give it a shot. It worked out well and I want to share with anyone interested how they can easily add some form of CI/CD to their Bevy projects.

Bevy and WASM

Bevy engine itself is a too big topic to cover, so I will assume that the reader has a basic knowledge about it. One minor thing that I can add that not everyone knows is the fact that you can easily make bevy canvas in WebGL match browser size, in main.rs when adding DefaultPlugin add this:

        .add_plugins(DefaultPlugins.set(WindowPlugin {
            primary_window: Some(Window {
                fit_canvas_to_parent: true,
                ..default()
            }),
            ..default()
        }))

And in index.html make sure that this style rule is present:

        html,
        body {
            margin: 0;
            height: 100%;
        }

For more info about building for web there is great page on Bevy cheatbook. Just make sure to install this tool, it should be mentioned there but is not:

cargo install wasm-bindgen-cli

GitHub Actions

Assuming that game is hosted on GitHub it can be easily be builded using GitHub Actions. You will need to create first .github/actions folders in the main directory of the repo. Inside that directory, we will create YAML file named rust.yml. Here it is where the magic happens. Below I will explain each part of the file but I want to recommend reading the docs about it.

Beggining of the file:

name: build

on:
  push:
    branches:
      - 'main'
      - 'master'

env:
  CARGO_TERM_COLOR: always

Three things - give name to workflow, specifies when it should be run(in this case on pushing to branches main and master) and we are setting env variable.

jobs: # here we are specifing all of the jobs
  build: # name of the job
    runs-on: ubuntu-latest # system, linux is the cheapest
    timeout-minutes: 30 
    steps:
      - uses: actions/checkout@v3
      - uses: actions/cache@v3
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ github.ref || github.run_id }}
      - uses: dtolnay/rust-toolchain@stable
      - name: Install alsa and udev
        run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev

In the second part we are starting the job, restoring cache (so the next build is going to be faster) installing all the dependencies and preparing for most important part:

      - name: Build
        run: cargo build --release --target wasm32-unknown-unknown && wasm-bindgen --out-dir ./out/ --target web ./target/wasm32-unknown-unknown/release/bevy_wasm_ci_example.wasm  
      - name: Copy
        run: cp -R assets out/ && cp index.html out/index.html
      - name: Push
        uses: s0/git-publish-subdir-action@develop
        env:
          SQUASH_HISTORY: true
          REPO: self
          BRANCH: gh-pages # The branch name where you want to push the assets
          FOLDER: out # The directory where your assets are generated
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # GitHub will automatically add this - you don't need to bother getting a token
          MESSAGE: "Build: ({sha}) {msg}" # The commit message

Here we building our game to WASM, copying all of the assets, index.html (remember to create one!) and pushing it to branch named gh-pages. If you did all of that and pushed the code to remote you should have this beatiful error:

Error: Process exited with code: 128:
remote: Permission to {USERNAME}/{REPO_NAME}.git denied to github-actions[bot].

That is because we need to make sure inside repository Settings -> Actions -> General we have selected Read and write permissions.

Then we can go to Settings -> Pages you can specify gh-pages as source branch for GitHub Pages. Now the game should be available on domain {username}.github.io/{repo_name}. For me it would be this address.

The End

I guess this is more than enough to automate building and deploying Bevy games to web. For anyone interested the example project is available here.

This work is licensed under CC BY-NC-SA 4.0.