refactor: remove flaky test #37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: build-docker-containers | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| update_readme: | |
| description: "Also sync DockerHub README" | |
| type: boolean | |
| default: false | |
| push: | |
| branches: | |
| - dev | |
| - master | |
| tags: | |
| - "v*" | |
| paths-ignore: | |
| - "**.md" | |
| - ".github/ISSUE_TEMPLATE/**" | |
| env: | |
| REGISTRY: ${{ vars.REGISTRY != '' && vars.REGISTRY || '' }} | |
| BUILD_AMD64: ${{ vars.BUILD_AMD64 != 'false' && 'true' || 'false' }} | |
| BUILD_ARM64: ${{ vars.BUILD_ARM64 != 'false' && 'true' || 'false' }} | |
| DOCKERHUB_SLUG: arabcoders/fbc_uploader | |
| GHCR_SLUG: ghcr.io/arabcoders/fbc_uploader | |
| PNPM_VERSION: 10 | |
| NODE_VERSION: 20 | |
| PYTHON_VERSION: "3.13" | |
| jobs: | |
| validate-build-config: | |
| name: Validate Build Configuration | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| steps: | |
| - name: Check if at least one architecture is enabled | |
| run: | | |
| if [ "${{ vars.BUILD_AMD64 }}" = "false" ] && [ "${{ vars.BUILD_ARM64 }}" = "false" ]; then | |
| echo "::error::Both BUILD_AMD64 and BUILD_ARM64 are disabled. At least one architecture must be enabled." | |
| exit 1 | |
| fi | |
| echo "Build configuration is valid" | |
| echo "BUILD_AMD64: ${{ vars.BUILD_AMD64 != 'false' && 'true' || 'false' }}" | |
| echo "BUILD_ARM64: ${{ vars.BUILD_ARM64 != 'false' && 'true' || 'false' }}" | |
| test: | |
| name: Run Tests & Prepare Frontend | |
| needs: [validate-build-config] | |
| permissions: | |
| contents: read | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install uv | |
| run: pip install uv | |
| - name: Install Python dependencies | |
| run: uv sync | |
| - name: Run Python linting | |
| run: uv run ruff check backend/ | |
| - name: Run Python tests | |
| run: uv run pytest backend/tests/ -v --tb=short | |
| - name: Install pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Install Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: pnpm | |
| cache-dependency-path: "frontend/pnpm-lock.yaml" | |
| - name: Install frontend dependencies | |
| working-directory: frontend | |
| env: | |
| NODE_ENV: development | |
| run: pnpm install --frozen-lockfile | |
| - name: Prepare frontend (nuxt prepare) | |
| working-directory: frontend | |
| env: | |
| NODE_ENV: development | |
| run: pnpm nuxt prepare | |
| - name: Run frontend linting | |
| working-directory: frontend | |
| run: pnpm run lint | |
| - name: Run frontend type checking | |
| working-directory: frontend | |
| run: pnpm run typecheck | |
| - name: Run frontend tests | |
| working-directory: frontend | |
| run: pnpm run test:ci | |
| - name: Remove dev dependencies | |
| working-directory: frontend | |
| env: | |
| NODE_ENV: production | |
| run: pnpm install --frozen-lockfile --prod --ignore-scripts | |
| - name: Build frontend | |
| working-directory: frontend | |
| env: | |
| NODE_ENV: production | |
| run: pnpm run generate | |
| - name: Upload frontend build | |
| uses: actions/upload-artifact@v4 | |
| if: env.REGISTRY == '' | |
| with: | |
| name: frontend-build | |
| path: frontend/exported/ | |
| retention-days: 1 | |
| docker-build-amd64: | |
| name: Build Container (amd64) | |
| runs-on: ubuntu-latest | |
| needs: [test, validate-build-config] | |
| if: vars.BUILD_AMD64 != 'false' | |
| permissions: | |
| packages: write | |
| contents: write | |
| env: | |
| ARCH: amd64 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download frontend build | |
| uses: actions/download-artifact@v4 | |
| if: env.REGISTRY == '' | |
| with: | |
| name: frontend-build | |
| path: frontend/exported/ | |
| - name: Update backend/app/version.py | |
| run: | | |
| VERSION="${GITHUB_REF##*/}" | |
| SHA=$(git rev-parse HEAD) | |
| DATE=$(date -u +"%Y%m%d") | |
| BRANCH=$(echo "${GITHUB_REF#refs/heads/}" | sed 's/\//-/g') | |
| echo "APP_VERSION=${VERSION}" >> "$GITHUB_ENV" | |
| echo "APP_SHA=${SHA}" >> "$GITHUB_ENV" | |
| echo "APP_DATE=${DATE}" >> "$GITHUB_ENV" | |
| echo "APP_BRANCH=${BRANCH}" >> "$GITHUB_ENV" | |
| sed -i \ | |
| -e "s/^APP_VERSION = \".*\"/APP_VERSION = \"${VERSION}\"/" \ | |
| -e "s/^APP_COMMIT_SHA = \".*\"/APP_COMMIT_SHA = \"${SHA}\"/" \ | |
| -e "s/^APP_BUILD_DATE = \".*\"/APP_BUILD_DATE = \"${DATE}\"/" \ | |
| -e "s/^APP_BRANCH = \".*\"/APP_BRANCH = \"${BRANCH}\"/" \ | |
| backend/app/version.py | |
| echo "Updated version info:" | |
| cat backend/app/version.py | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: | | |
| name=${{ env.DOCKERHUB_SLUG }},enable=${{ env.REGISTRY == '' }} | |
| name=${{ env.GHCR_SLUG }},enable=${{ env.REGISTRY == '' }} | |
| name=${{ env.REGISTRY }}/${{ github.repository }},enable=${{ env.REGISTRY != '' }} | |
| flavor: | | |
| latest=false | |
| suffix=-${{ env.ARCH }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=tag | |
| type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }} | |
| - name: Login to Private Registry | |
| uses: docker/login-action@v3 | |
| if: env.REGISTRY != '' | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GIT_TOKEN && secrets.GIT_TOKEN || secrets.GITHUB_TOKEN }} | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| if: env.REGISTRY == '' | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Login to DockerHub | |
| uses: docker/login-action@v3 | |
| if: env.REGISTRY == '' | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build and push | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| platforms: linux/${{ env.ARCH }} | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-to: type=gha,mode=max,scope=${{ github.workflow }} | |
| cache-from: type=gha,scope=${{ github.workflow }} | |
| provenance: true | |
| docker-build-arm64: | |
| name: Build Container (arm64) | |
| runs-on: ubuntu-latest | |
| needs: [test, validate-build-config] | |
| if: vars.BUILD_ARM64 != 'false' | |
| permissions: | |
| packages: write | |
| contents: write | |
| env: | |
| ARCH: arm64 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download frontend build | |
| uses: actions/download-artifact@v4 | |
| if: env.REGISTRY == '' | |
| with: | |
| name: frontend-build | |
| path: frontend/exported/ | |
| - name: Update backend/app/version.py | |
| run: | | |
| VERSION="${GITHUB_REF##*/}" | |
| SHA=$(git rev-parse HEAD) | |
| DATE=$(date -u +"%Y%m%d") | |
| BRANCH=$(echo "${GITHUB_REF#refs/heads/}" | sed 's/\//-/g') | |
| echo "APP_VERSION=${VERSION}" >> "$GITHUB_ENV" | |
| echo "APP_SHA=${SHA}" >> "$GITHUB_ENV" | |
| echo "APP_DATE=${DATE}" >> "$GITHUB_ENV" | |
| echo "APP_BRANCH=${BRANCH}" >> "$GITHUB_ENV" | |
| sed -i \ | |
| -e "s/^APP_VERSION = \".*\"/APP_VERSION = \"${VERSION}\"/" \ | |
| -e "s/^APP_COMMIT_SHA = \".*\"/APP_COMMIT_SHA = \"${SHA}\"/" \ | |
| -e "s/^APP_BUILD_DATE = \".*\"/APP_BUILD_DATE = \"${DATE}\"/" \ | |
| -e "s/^APP_BRANCH = \".*\"/APP_BRANCH = \"${BRANCH}\"/" \ | |
| backend/app/version.py | |
| echo "Updated version info:" | |
| cat backend/app/version.py | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: | | |
| name=${{ env.DOCKERHUB_SLUG }},enable=${{ env.REGISTRY == '' }} | |
| name=${{ env.GHCR_SLUG }},enable=${{ env.REGISTRY == '' }} | |
| name=${{ env.REGISTRY }}/${{ github.repository }},enable=${{ env.REGISTRY != '' }} | |
| flavor: | | |
| latest=false | |
| suffix=-${{ env.ARCH }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=tag | |
| type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }} | |
| - name: Login to Private Registry | |
| uses: docker/login-action@v3 | |
| if: env.REGISTRY != '' | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GIT_TOKEN && secrets.GIT_TOKEN || secrets.GITHUB_TOKEN }} | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| if: env.REGISTRY == '' | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Login to DockerHub | |
| uses: docker/login-action@v3 | |
| if: env.REGISTRY == '' | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build and push | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| platforms: linux/${{ env.ARCH }} | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-to: type=gha,mode=max,scope=${{ github.workflow }} | |
| cache-from: type=gha,scope=${{ github.workflow }} | |
| provenance: true | |
| docker-publish-manifest: | |
| name: Publish multi-arch manifest | |
| runs-on: ubuntu-latest | |
| needs: [docker-build-amd64, docker-build-arm64] | |
| if: | | |
| !cancelled() && | |
| (needs.docker-build-amd64.result == 'success' || needs.docker-build-arm64.result == 'success') | |
| permissions: | |
| packages: write | |
| contents: write | |
| steps: | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: | | |
| name=${{ env.DOCKERHUB_SLUG }},enable=${{ env.REGISTRY == '' }} | |
| name=${{ env.GHCR_SLUG }},enable=${{ env.REGISTRY == '' }} | |
| name=${{ env.REGISTRY }}/${{ github.repository }},enable=${{ env.REGISTRY != '' }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=tag | |
| type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }} | |
| - name: Login to Private Registry | |
| uses: docker/login-action@v3 | |
| if: env.REGISTRY != '' | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GIT_TOKEN && secrets.GIT_TOKEN || secrets.GITHUB_TOKEN }} | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| if: env.REGISTRY == '' | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Login to DockerHub | |
| uses: docker/login-action@v3 | |
| if: env.REGISTRY == '' | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Create and push manifest list | |
| shell: bash | |
| run: | | |
| IFS=$'\n' | |
| BUILD_AMD64="${{ env.BUILD_AMD64 }}" | |
| BUILD_ARM64="${{ env.BUILD_ARM64 }}" | |
| for tag in $(echo "${{ steps.meta.outputs.tags }}"); do | |
| echo "Creating manifest for ${tag}" | |
| IMAGES=() | |
| if [ "$BUILD_AMD64" = "true" ]; then | |
| IMAGES+=("${tag}-amd64") | |
| fi | |
| if [ "$BUILD_ARM64" = "true" ]; then | |
| IMAGES+=("${tag}-arm64") | |
| fi | |
| if [ ${#IMAGES[@]} -eq 0 ]; then | |
| echo "::error::No architectures enabled for manifest creation" | |
| exit 1 | |
| fi | |
| docker buildx imagetools create --tag "$tag" "${IMAGES[@]}" | |
| done | |
| - name: Update GitHub release notes | |
| if: startsWith(github.ref, 'refs/tags/v') && env.REGISTRY == '' | |
| uses: actions/github-script@v6 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const tag = context.ref.replace('refs/tags/', ''); | |
| const { data: releases } = await github.rest.repos.listReleases({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| }); | |
| const release = releases.find(r => r.tag_name === tag); | |
| if (!release) { | |
| core.setFailed(`Release with tag ${tag} not found`); | |
| return; | |
| } | |
| const baseTag = releases[1]?.tag_name || ''; | |
| if (!baseTag) { | |
| core.setFailed('Could not determine a base tag (no previous release found)'); | |
| return; | |
| } | |
| const { data: comparison } = await github.rest.repos.compareCommits({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| base: baseTag, | |
| head: tag, | |
| }); | |
| const commits = comparison.commits.filter(c => c.parents.length === 1); | |
| const changelog = commits | |
| .map(c => `- ${c.sha.substring(0, 7)} ${c.commit.message.split('\n')[0]}`) | |
| .join('\n'); | |
| if (!changelog) { | |
| core.setFailed('No commits found for the changelog'); | |
| return; | |
| } | |
| const existingBody = (release.body || '').trim(); | |
| const separator = `\n\n---\n\n## Commits since ${baseTag}\n\n`; | |
| const newBody = existingBody | |
| ? `${existingBody}${separator}${changelog}` | |
| : `## Commits since ${baseTag}\n\n${changelog}`; | |
| await github.rest.repos.updateRelease({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| release_id: release.id, | |
| body: newBody, | |
| }); | |
| dockerhub-sync-readme: | |
| name: DockerHub README sync | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| if: (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) || (github.event_name == 'workflow_dispatch' && github.event.inputs.update_readme == 'true') | |
| steps: | |
| - name: Sync README | |
| uses: docker://lsiodev/readme-sync:latest | |
| if: env.REGISTRY == '' | |
| env: | |
| DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} | |
| DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }} | |
| GIT_REPOSITORY: ${{ github.repository }} | |
| DOCKER_REPOSITORY: ${{ env.DOCKERHUB_SLUG }} | |
| GIT_BRANCH: master | |
| with: | |
| entrypoint: node | |
| args: /opt/docker-readme-sync/sync |