# 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: ```text ci/Dockerfile ci/README.md ci/USE_CI_IMAGE.md .dockerignore .gitea/workflows/build-ci-image.yml .gitea/workflows/build.yml ``` The image extends: ```text 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: ```text git.neosisyphus.com ``` Organization: ```text evol3d ``` Image path: ```text git.neosisyphus.com/evol3d/evol-testbed ``` The pushed tags will be: ```text git.neosisyphus.com/evol3d/evol-testbed:latest git.neosisyphus.com/evol3d/evol-testbed:clang22 ``` --- ## 2. Commit the prepared files From the repository root: ```bash 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: ```text 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: ```text 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: ```text git.neosisyphus.com ``` Do not include `https://`. Correct: ```text git.neosisyphus.com ``` Wrong: ```text https://git.neosisyphus.com ``` ### `REGISTRY_IMAGE` The full image path without a tag: ```text git.neosisyphus.com/evol3d/evol-testbed ``` ### `CI_IMAGE` Usually the same as `REGISTRY_IMAGE`: ```text 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: ```text REGISTRY_USERNAME REGISTRY_PASSWORD ``` Example: ```text REGISTRY_USERNAME=myusername REGISTRY_PASSWORD= ``` 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: ```text .gitea/workflows/build-ci-image.yml ``` It logs into your registry, builds the image, and pushes two tags: ```text latest clang22 ``` The important commands are: ```yaml - 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: ```bash 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: ```bash sudo usermod -aG docker sudo systemctl restart act_runner ``` Test as that user: ```bash docker ps ``` ### Option B: `act_runner` runs inside Docker If `act_runner` itself runs inside a container, it needs the host Docker socket mounted: ```bash -v /var/run/docker.sock:/var/run/docker.sock ``` Example: ```bash 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: ```text ci/Dockerfile .dockerignore .gitea/workflows/build-ci-image.yml ``` So this is enough: ```bash 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: ```text evol-testbed ``` Confirm these tags exist: ```text latest clang22 ``` --- ## 10. Use the image in your normal build workflow The prepared normal workflow is: ```text .gitea/workflows/build.yml ``` It uses: ```yaml container: image: ${{ vars.CI_IMAGE }}:clang22 ``` If you set: ```text CI_IMAGE=git.neosisyphus.com/evol3d/evol-testbed ``` then the workflow uses: ```text git.neosisyphus.com/evol3d/evol-testbed:clang22 ``` The key workflow shape is: ```yaml 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: ```bash 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: ```yaml container: image: ${{ vars.CI_IMAGE }}:clang22 ``` with the literal image name: ```yaml container: image: git.neosisyphus.com/evol3d/evol-testbed:clang22 ``` Then commit and push: ```bash 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: ```bash 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: ```bash 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: ```bash docker pull git.neosisyphus.com/evol3d/evol-testbed:clang22 ``` Run it: ```bash docker run --rm -it git.neosisyphus.com/evol3d/evol-testbed:clang22 bash ``` Inside the container: ```bash 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: ```bash exit ``` --- ## 14. Use it in other projects Once the image exists, any project can use it: ```yaml 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: ```text ci/Dockerfile ``` Then: ```bash git add ci/Dockerfile git commit -m "Update CI image" git push ``` The image workflow will rebuild and push: ```text latest clang22 ``` Your normal builds will use the updated image next time they run. --- ## 16. Recommended: version image tags Instead of only using: ```text clang22 ``` consider immutable tags: ```text clang22-v1 clang22-v2 clang22-2026-05 ``` Example build command tag: ```yaml -t "${{ vars.REGISTRY_IMAGE }}:clang22-v1" ``` Then use: ```yaml container: image: git.neosisyphus.com/evol3d/evol-testbed:clang22-v1 ``` This avoids surprise breakage when `clang22` or `latest` changes. --- ## 17. Quick checklist ```text 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: ```yaml container: image: git.neosisyphus.com/evol3d/evol-testbed:clang22 ```