name: ci on: push: branches: [ main ] tags: [ 'v*' ] pull_request: jobs: test: runs-on: ubuntu-latest services: mariadb: image: mariadb:11 env: MARIADB_DATABASE: gitea_codex MARIADB_USER: gitea_codex MARIADB_PASSWORD: gitea_codex MARIADB_ROOT_PASSWORD: rootpass ports: - 3306:3306 options: >- --health-cmd "mariadb-admin ping -h 127.0.0.1 -uroot -prootpass" --health-interval 5s --health-timeout 5s --health-retries 20 env: GITEA_BASE_URL: https://gitea.reversed.dev GITEA_TOKEN: test GITEA_BOT_USERNAME: codex-bot GITEA_WEBHOOK_SECRET: testsecret OPENAI_API_KEY: test-openai ALLOWED_REPOS: org/repo COOLDOWN_SECONDS: 60 WEBHOOK_MODE: repo DB_HOST: mariadb DB_PORT: 3306 DB_NAME: gitea_codex DB_USER: gitea_codex DB_PASSWORD: gitea_codex TEST_DATABASE_URL: mysql+pymysql://gitea_codex:gitea_codex@mariadb:3306/gitea_codex?charset=utf8mb4 WORKDIR: /tmp/work MAX_DIFF_BYTES: 200000 MAX_REVIEW_MINUTES: 10 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: '3.12' - name: Install deps run: | python -m pip install --upgrade pip pip install -e .[dev] - name: Wait for MariaDB run: | python - <<'PY' import os import time import pymysql host = os.environ["DB_HOST"] port = int(os.environ["DB_PORT"]) user = os.environ["DB_USER"] password = os.environ["DB_PASSWORD"] database = os.environ["DB_NAME"] for _ in range(60): try: conn = pymysql.connect( host=host, port=port, user=user, password=password, database=database, connect_timeout=2, read_timeout=2, write_timeout=2, ) conn.close() print("MariaDB is ready") raise SystemExit(0) except Exception as exc: print(f"Waiting for MariaDB: {exc}") time.sleep(2) print("MariaDB did not become ready in time") raise SystemExit(1) PY - name: Run Alembic migrations run: alembic upgrade head - name: Run tests run: pytest publish: runs-on: ubuntu-latest needs: test if: gitea.event_name == 'push' env: REGISTRY: gitea.reversed.dev IMAGE_NAME: space/gitea-codex steps: - uses: actions/checkout@v4 - uses: docker/setup-buildx-action@v3 - name: Derive package metadata id: meta shell: bash run: | set -euo pipefail owner="${IMAGE_NAME%%/*}" repo="${IMAGE_NAME##*/}" if [ -z "${owner}" ] || [ -z "${repo}" ]; then echo "::error::Failed to derive owner/repo from IMAGE_NAME=${IMAGE_NAME}" exit 1 fi echo "owner=${owner}" >> "${GITHUB_OUTPUT}" echo "repo=${repo}" >> "${GITHUB_OUTPUT}" - name: Login to Gitea container registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.REGISTRY_USERNAME }} password: ${{ secrets.REGISTRY_PASSWORD }} - name: Build and push tags shell: bash env: CI_SHA: ${{ gitea.sha }} CI_REF_NAME: ${{ gitea.ref_name }} run: | set -euo pipefail IMAGE="${REGISTRY}/${IMAGE_NAME}" SHA_TAG="sha-${CI_SHA::12}" REF_TAG="${CI_REF_NAME}" docker buildx build --push \ -t "${IMAGE}:${SHA_TAG}" \ -t "${IMAGE}:${REF_TAG}" \ . if [ "${CI_REF_NAME}" = "main" ]; then docker buildx build --push -t "${IMAGE}:latest" . fi - name: Publish image summary shell: bash env: CI_SHA: ${{ gitea.sha }} CI_REF_NAME: ${{ gitea.ref_name }} run: | set -euo pipefail IMAGE="${REGISTRY}/${IMAGE_NAME}" echo "Published image tags:" >> "${GITHUB_STEP_SUMMARY}" echo "- ${IMAGE}:${CI_REF_NAME}" >> "${GITHUB_STEP_SUMMARY}" echo "- ${IMAGE}:sha-${CI_SHA::12}" >> "${GITHUB_STEP_SUMMARY}" if [ "${CI_REF_NAME}" = "main" ]; then echo "- ${IMAGE}:latest" >> "${GITHUB_STEP_SUMMARY}" fi - name: Link package to repository shell: bash env: REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} PACKAGE_OWNER: ${{ steps.meta.outputs.owner }} PACKAGE_NAME: ${{ steps.meta.outputs.repo }} REPO_NAME: ${{ steps.meta.outputs.repo }} run: | set -euo pipefail token="${REGISTRY_PASSWORD:-${REGISTRY_TOKEN:-}}" if [ -z "$token" ]; then echo "::error::Registry token/password is empty. Set REGISTRY_PASSWORD or REGISTRY_TOKEN." exit 1 fi python3 - <<'PY' import json import os import sys import urllib.error import urllib.parse import urllib.request owner = os.environ["PACKAGE_OWNER"] package = os.environ["PACKAGE_NAME"] repo = os.environ["REPO_NAME"] token = os.environ["REGISTRY_PASSWORD"] or os.environ["REGISTRY_TOKEN"] base = "https://gitea.reversed.dev/api/v1" headers = { "Authorization": f"token {token}", "Accept": "application/json", } latest_url = f"{base}/packages/{urllib.parse.quote(owner)}/container/{urllib.parse.quote(package)}/-/latest" req = urllib.request.Request(latest_url, headers=headers) with urllib.request.urlopen(req) as resp: current = json.load(resp) linked_repo = (current.get("repository") or {}).get("name") if linked_repo == repo: print(f"package already linked to {owner}/{repo}") sys.exit(0) link_url = f"{base}/packages/{urllib.parse.quote(owner)}/container/{urllib.parse.quote(package)}/-/link/{urllib.parse.quote(repo)}" link_req = urllib.request.Request(link_url, data=b"", method="POST", headers=headers) try: with urllib.request.urlopen(link_req) as resp: print(f"linked package to {owner}/{repo}, status={resp.status}") except urllib.error.HTTPError as exc: body = exc.read().decode(errors="replace") print(f"link failed: status={exc.code} body={body}") raise PY