Files
evol-testbed/ci/USE_CI_IMAGE.md
T
2026-05-02 17:51:57 +03:00

9.7 KiB

Using the Clang 22 + Vulkan Gitea Actions CI Image

This guide explains how to build, publish, and use the prepared Docker image for Gitea Actions.

The prepared files are:

ci/Dockerfile
ci/README.md
ci/USE_CI_IMAGE.md
.dockerignore
.gitea/workflows/build-ci-image.yml
.gitea/workflows/build.yml

The image extends:

catthehacker/ubuntu:act-latest

It includes:

  • Clang/LLVM 22
  • clang-format-22
  • clang-tidy-22
  • lld-22
  • lldb-22
  • Meson
  • Ninja
  • Python 3 / pip / venv
  • Vulkan development packages/tools
  • build-essential
  • pkg-config
  • Git
  • Gitea/act-compatible tooling inherited from the base image

1. Decide your image name

Pick a container image path in your Gitea registry.

Example Gitea host:

git.neosisyphus.com

Organization:

evol3d

Image path:

git.neosisyphus.com/evol3d/evol-testbed

The pushed tags will be:

git.neosisyphus.com/evol3d/evol-testbed:latest
git.neosisyphus.com/evol3d/evol-testbed:clang22

2. Commit the prepared files

From the repository root:

git add ci/Dockerfile ci/README.md ci/USE_CI_IMAGE.md .dockerignore .gitea/workflows/build-ci-image.yml .gitea/workflows/build.yml
git commit -m "Add reusable Clang 22 Vulkan CI image"
git push

3. Create a Gitea access token

In the Gitea web UI:

  1. Open your user menu.
  2. Go to Settings.
  3. Go to Applications.
  4. Create a new access token.
  5. Give it package/container registry write permissions.

Depending on your Gitea version, the permission may be named one of:

package
packages
write:package
write:packages

Copy the token. It will be used as the registry password.


4. Add Gitea Actions variables

In your repository:

  1. Go to Settings.
  2. Go to Actions.
  3. Go to Variables.
  4. Add these variables:
REGISTRY_HOST=git.neosisyphus.com
REGISTRY_IMAGE=git.neosisyphus.com/evol3d/evol-testbed
CI_IMAGE=git.neosisyphus.com/evol3d/evol-testbed

Use your actual values.

REGISTRY_HOST

Only the hostname:

git.neosisyphus.com

Do not include https://.

Correct:

git.neosisyphus.com

Wrong:

https://git.neosisyphus.com

REGISTRY_IMAGE

The full image path without a tag:

git.neosisyphus.com/evol3d/evol-testbed

CI_IMAGE

Usually the same as REGISTRY_IMAGE:

git.neosisyphus.com/evol3d/evol-testbed

This is used by the normal build workflow.


5. Add Gitea Actions secrets

In your repository:

  1. Go to Settings.
  2. Go to Actions.
  3. Go to Secrets.
  4. Add:
REGISTRY_USERNAME
REGISTRY_PASSWORD

Example:

REGISTRY_USERNAME=myusername
REGISTRY_PASSWORD=<your-gitea-access-token>

Use your Gitea username for REGISTRY_USERNAME.

Use the token from step 3 for REGISTRY_PASSWORD.


6. Check the image build workflow

The image build workflow is:

.gitea/workflows/build-ci-image.yml

It logs into your registry, builds the image, and pushes two tags:

latest
clang22

The important commands are:

- name: Build CI image
  run: |
    docker build \
      --build-arg BASE_IMAGE=catthehacker/ubuntu:act-latest \
      --build-arg LLVM_VERSION=22 \
      --build-arg MESON_VERSION=latest \
      -t "${{ vars.REGISTRY_IMAGE }}:latest" \
      -t "${{ vars.REGISTRY_IMAGE }}:clang22" \
      -f ci/Dockerfile .

- name: Push CI image
  run: |
    docker push "${{ vars.REGISTRY_IMAGE }}:latest"
    docker push "${{ vars.REGISTRY_IMAGE }}:clang22"

7. Make sure your runner can build Docker images

The image-building workflow needs Docker.

On the runner host, check:

docker version

If that works, the host has Docker.

Your Gitea runner still needs permission to access Docker.

Option A: act_runner runs directly on the host

If your runner runs directly on the machine, make sure the runner user can use Docker.

Check the runner user, then add it to the Docker group if needed:

sudo usermod -aG docker <runner-user>
sudo systemctl restart act_runner

Test as that user:

docker ps

Option B: act_runner runs inside Docker

If act_runner itself runs inside a container, it needs the host Docker socket mounted:

-v /var/run/docker.sock:/var/run/docker.sock

Example:

docker run -d \
  --name gitea-act-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /opt/act-runner/config.yaml:/config.yaml \
  -v /opt/act-runner/data:/data \
  gitea/act_runner:latest

Without the socket mount, the workflow cannot run docker build.


8. Run the image build workflow

There are two ways.

Method 1: push changes

The workflow triggers when these files change:

ci/Dockerfile
.dockerignore
.gitea/workflows/build-ci-image.yml

So this is enough:

git push

Method 2: manual workflow dispatch

If your Gitea version supports workflow_dispatch:

  1. Go to your repository.
  2. Open Actions.
  3. Select build-ci-image.
  4. Click Run workflow.

9. Confirm the image was pushed

In Gitea:

  1. Open the repository or organization.
  2. Go to Packages.
  3. Look for:
evol-testbed

Confirm these tags exist:

latest
clang22

10. Use the image in your normal build workflow

The prepared normal workflow is:

.gitea/workflows/build.yml

It uses:

container:
  image: ${{ vars.CI_IMAGE }}:clang22

If you set:

CI_IMAGE=git.neosisyphus.com/evol3d/evol-testbed

then the workflow uses:

git.neosisyphus.com/evol3d/evol-testbed:clang22

The key workflow shape is:

name: build

on:
  push:
  pull_request:

jobs:
  linux:
    runs-on: ubuntu-latest

    container:
      image: ${{ vars.CI_IMAGE }}:clang22

    steps:
      - uses: actions/checkout@v4

      - name: Check CI toolchain
        run: |
          clang --version
          clang++ --version
          meson --version
          ninja --version
          python3 --version
          vulkaninfo --summary || true

      - name: Configure
        run: |
          meson setup build

      - name: Build
        run: |
          meson compile -C build

Commit and push:

git add .gitea/workflows/build.yml
git commit -m "Use Clang 22 Vulkan CI image"
git push

11. If vars.CI_IMAGE does not work in container.image

Some Gitea/act versions may not expand variables in container.image.

If the build fails because the image name is invalid, replace this:

container:
  image: ${{ vars.CI_IMAGE }}:clang22

with the literal image name:

container:
  image: git.neosisyphus.com/evol3d/evol-testbed:clang22

Then commit and push:

git add .gitea/workflows/build.yml
git commit -m "Use literal CI image path"
git push

12. If the image is private

Your runner must be able to pull it.

Log in on the runner host:

docker login git.neosisyphus.com

Use your Gitea username and token.

If act_runner runs as a system service, log in as the same user that runs act_runner, or configure Docker credentials for that user.

Then restart the runner:

sudo systemctl restart act_runner

If your runner itself is Dockerized, make sure Docker credentials are available to the runner setup.


13. Test the image manually on the runner

On the runner host:

docker pull git.neosisyphus.com/evol3d/evol-testbed:clang22

Run it:

docker run --rm -it git.neosisyphus.com/evol3d/evol-testbed:clang22 bash

Inside the container:

clang --version
clang++ --version
meson --version
ninja --version
python3 --version
vulkaninfo --summary

Expected results:

  • clang should be version 22.
  • meson should print a version.
  • ninja should print a version.
  • vulkaninfo --summary may fail if the CI machine has no GPU/display/runtime Vulkan driver. That is usually okay for compile-only CI as long as Vulkan headers/tools are installed.

Exit:

exit

14. Use it in other projects

Once the image exists, any project can use it:

name: build

on:
  push:
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest

    container:
      image: git.neosisyphus.com/evol3d/evol-testbed:clang22

    steps:
      - uses: actions/checkout@v4

      - run: |
          meson setup build
          meson compile -C build

No more installing LLVM/Vulkan/Meson every CI run.


15. Updating the image later

Edit:

ci/Dockerfile

Then:

git add ci/Dockerfile
git commit -m "Update CI image"
git push

The image workflow will rebuild and push:

latest
clang22

Your normal builds will use the updated image next time they run.


Instead of only using:

clang22

consider immutable tags:

clang22-v1
clang22-v2
clang22-2026-05

Example build command tag:

-t "${{ vars.REGISTRY_IMAGE }}:clang22-v1"

Then use:

container:
  image: git.neosisyphus.com/evol3d/evol-testbed:clang22-v1

This avoids surprise breakage when clang22 or latest changes.


17. Quick checklist

1. Commit ci/Dockerfile and workflows.
2. Create Gitea token with package/container write access.
3. Add Actions variables:
   - REGISTRY_HOST
   - REGISTRY_IMAGE
   - CI_IMAGE
4. Add Actions secrets:
   - REGISTRY_USERNAME
   - REGISTRY_PASSWORD
5. Make sure the runner can run docker build.
6. Run build-ci-image workflow.
7. Confirm image appears in Gitea Packages.
8. Use image in .gitea/workflows/build.yml.
9. Push normal project code.
10. Build should run inside the prebuilt Clang/Vulkan image.

The most important final workflow line is:

container:
  image: git.neosisyphus.com/evol3d/evol-testbed:clang22