Forgejo is a lightweight version control hub that provides git hosting, project management, release management and packages. It’s very powerful and very efficient (written in Go and uses minimal memory).

Gitea and Forejo

Forgejo is a fork of Gitea which was created in 2022 after Gitea changed the direction of their project to align with more commercial interests. Forgejo offers most of the same features as Gitea but focuses on public good.

Actions

Forgejo have recently introduced a CI actions feature which is compatible with github’s actions.

In order for a lot of the actions to work, it can be helpful to have a number of labels set up for the runner like so:

  labels:
    - 'docker:docker://node:20-bookworm'
    - 'node20:docker://node:20-bookworm'
    - 'lxc:lxc://debian:bullseye'
    - 'bullseye:lxc://debian:bullseye'
    - 'self-hosted:host://-self-hosted'
    - 'ubuntu-22.04:docker:// ghcr.io/catthehacker/ubuntu:act-22.04' 
    - 'ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-22.04'

setup-python does not work with the recommended node:20-bookworm container so it is better to use the ubuntu act containers when working with Python. These ubuntu act image have a number of prerequisite tools and libraries built in.

Docker-in-Docker

If you want to build a docker image inside your runner, the only way I’ve found to make it work is to pass the internal IP address of the dind container that you are using to run the model directly.

On the host system run:

$ docker ps | grep dind
# output from this command will be...
<container_id>   docker:dind   "dockerd-entrypoint.…"   ...   docker_dind
 

Then run:

 docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker_dind

If your container is called something other than docker_dind use that here instead. You should see an IP address like 172.21.0.123.

Let’s set up a new action secret in our repo for the DIND_HOST with the value tcp://172.21.0.123:2375.

Then, in our action YAML, we can pass the secret as our DOCKER_HOST env var:

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      DOCKER_HOST: ${{ secrets.DIND_HOST }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
 
      - name: Log in to Docker Hub
        uses: docker/login-action@v2
        with:
          registry:  ${{ secrets.DOCKER_REGISTRY }}
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
 
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
 
      - name: Build and push
        uses: docker/build-push-action@v4

Services in Actions

You can now run services inside actions just like in Github:

jobs:
  build:
    runs-on: ubuntu-latest
      mysql:
        image: mariadb
        env:
          MARIADB_ROOT_PASSWORD: "password"

Resources

Python Packages

Best strategy with PDM seems to be:

  1. use pdm build
  2. upload package with twine:
    twine upload \
       --repository-url https://gitea.example.org/api/packages/<username>/pypi \
       -u <username> \
       -p <password> \
       dist/something-0.1.0-py3-none-any.whl