Skip to content

codex-v2

codex-v2 #225

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
types: [opened, synchronize]
branches: [main, develop]
env:
CI_IMAGE: ghcr.io/${{ github.repository }}-ci
CI_IMAGE_TAG: ghcr.io/${{ github.repository }}-ci:latest
CI_CONTAINER: ${{ github.event.repository.name }}-ci
IMAGE: ghcr.io/${{ github.repository }}
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# ---------------------------------------------------------------------------
# Lint, test, and build the Python wheel (amd64 only)
# ---------------------------------------------------------------------------
test:
name: Lint, Test & Build Dist
runs-on: ubuntu-24.04
if: |
github.ref_name == 'main' && github.event_name == 'push' ||
github.base_ref == 'main' ||
(github.base_ref == 'develop' && (github.head_ref == 'pre-release' || startsWith(github.head_ref, 'v')))
permissions:
contents: read
packages: write
checks: write
steps:
- name: Checkout
uses: actions/checkout@v6
with:
# Only fetch full history for the main push gate
fetch-depth: ${{ (github.ref_name == 'main' && github.event_name == 'push') && 0 || 1 }}
- name: Check for Redundant Tests & Existing Dist
id: gate
if: github.ref_name == 'main' && github.event_name == 'push'
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bin/ci-download-dist-if-identical.sh
- name: Set up Docker Buildx
if: steps.gate.outputs.dist_found != 'true'
uses: docker/setup-buildx-action@v4
- name: Log in to GHCR
if: steps.gate.outputs.dist_found != 'true'
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build dist-builder image
id: build-ci
if: steps.gate.outputs.dist_found != 'true'
uses: docker/build-push-action@v7
with:
context: .
target: codex-ci
load: true
tags: ${{ env.CI_IMAGE_TAG }}
cache-from: type=registry,ref=${{ env.CI_IMAGE }}:cache
cache-to: type=registry,ref=${{ env.CI_IMAGE }}:cache,mode=max
- name: Start Services
id: start-services
if: steps.build-ci.outcome == 'success'
run: |
mkdir -p dist test-results
docker compose up -d ci
- name: Lint
id: lint
if: steps.start-services.outcome == 'success'
run: docker exec ${{ env.CI_CONTAINER }} make lint
- name: Build for Tests & Dist
id: build-for-tests
if: steps.lint.outcome == 'success'
run: docker exec ${{ env.CI_CONTAINER }} make build-choices build-frontend collectstatic
- name: Tests
id: tests
if: steps.build-for-tests.outcome == 'success'
run: docker exec ${{ env.CI_CONTAINER }} make test-frontend django-check test-python -o build-choices
- name: Upload Test Results
id: upload-tests
if: "!cancelled() && steps.tests.outcome != 'skipped'"
uses: actions/upload-artifact@v7
with:
name: test-results
path: "**/test-results/pytest/*.xml"
- name: Publish Test Report
if: "!cancelled() && steps.upload-tests.outcome == 'success'"
uses: mikepenz/action-junit-report@v6
with:
report_paths: "**/test-results/pytest/*.xml"
- name: Build Distribution
id: build-dist
if: steps.tests.outcome == 'success'
run: docker exec ${{ env.CI_CONTAINER }} make build-only
- name: Stop Services
if: steps.start-services.outcome == 'success'
run: |
touch .env.package # hack because down is too promiscuous
docker compose down
- name: Upload dist artifact
if: "!cancelled() && steps.gate.outputs.dist_found == 'true' || steps.build-dist.outcome =='success'"
uses: actions/upload-artifact@v7
with:
name: python-dist
path: dist/
retention-days: 2
- name: Discord notification (Test Results)
if: "!cancelled() && false"
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}
title: Lint & Test
description: "Tests for ${{ github.ref_name }} #${{ github.run_number }} ${{ job.status == 'success' && 'passed' || 'FAILED' }}"
color: ${{ job.status == 'success' && '0x28a745' || '0xd73a49' }}
url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
# ---------------------------------------------------------------------------
# Build per-arch Docker images natively
# ---------------------------------------------------------------------------
build:
name: Build Image (${{ matrix.arch }})
needs: test
if: github.event_name == 'push' ||
(github.base_ref == 'develop' && github.head_ref == 'pre-release')
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Download dist artifact
uses: actions/download-artifact@v8
with:
name: python-dist
path: dist/
- name: Set Build Context
run: |
VERSION=$(grep -Po '(?<=^version = ")[^"]+' pyproject.toml)
echo "CODEX_VERSION=${VERSION}" >> "$GITHUB_ENV"
echo "CODEX_WHEEL=$(find dist -name '*.whl' -print0 | xargs basename)" >> "$GITHUB_ENV"
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/${{ matrix.arch }}
push: true
build-args: |
CODEX_VERSION=${{ env.CODEX_VERSION }}
CODEX_WHEEL=${{ env.CODEX_WHEEL }}
tags: ${{ env.IMAGE }}:${{ env.CODEX_VERSION }}-${{ matrix.arch }}
cache-from: type=gha,scope=build-${{ matrix.arch }}
cache-to: type=gha,scope=build-${{ matrix.arch }},mode=max
# ---------------------------------------------------------------------------
# Create multi-arch manifest and publish
# ---------------------------------------------------------------------------
deploy:
name: Deploy
needs: build
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Setup uv
uses: astral-sh/[email protected]
- name: Download dist artifact
uses: actions/download-artifact@v8
with:
name: python-dist
path: dist/
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push manifest
run: |
VERSION=$(uv version --short)
TAG_ARGS=("-t" "${IMAGE}:${VERSION}")
# Positive regex check for Final versions (e.g., 1.2.3)
if [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
TAG_ARGS+=("-t" "${IMAGE}:latest")
fi
docker buildx imagetools create \
--annotation "index:org.opencontainers.image.title=Codex" \
--annotation "index:org.opencontainers.image.description=Codex Comic Server" \
--annotation "index:org.opencontainers.image.version=${VERSION}" \
--annotation "index:org.opencontainers.image.authors=AJ Slater <[email protected]>" \
--annotation "index:org.opencontainers.image.url=https://codex-reader.app" \
--annotation "index:org.opencontainers.image.source=https://github.com/ajslater/codex" \
--annotation "index:org.opencontainers.image.licenses=GPL-3.0-only" \
"${TAG_ARGS[@]}" \
"${IMAGE}:${VERSION}-amd64" \
"${IMAGE}:${VERSION}-arm64"
- name: Publish to PyPI
run: uv publish dist/*
env:
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
- name: Discord notification (Deploy Results)
if: "!cancelled() && false"
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}
title: Deploy
description: "Deploy ${{ github.ref_name }} #${{ github.run_number }} ${{ job.status == 'success' && 'succeeded' || 'FAILED' }}"
color: ${{ job.status == 'success' && '0x28a745' || '0xd73a49' }}
url: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"