name: 🚀 CI/CD

on:
  push:

jobs:
  test_and_build:
    runs-on: ubuntu-latest
    container:
      image: wakemeops/ubuntu:20.04
    steps:
      - name: Install Poetry, Python 3.11 and other dependencies
        uses: upciti/wakemeops-action@v1
        with:
          packages: |
            debhelper
            fakeroot
            build-essential
            python3.11-build-standalone
            poetry

      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Load Cached Python Dependencies
        uses: actions/cache@v3
        with:
          path: .venv
          key: python-dependencies-${{ hashFiles('**/poetry.lock') }}

      - name: Install Python Dependencies
        run: |
          ln -s /usr/lib/python-build-standalone/3.11/bin/python3.11 /usr/bin/python
          poetry install

      - name: Run ruff format
        run: poetry run ruff format --diff src tests

      - name: Run ruff
        run: poetry run ruff src tests

      - name: Run mypy
        run: poetry run mypy --show-error-codes src

      - name: Run pytest
        run: poetry run pytest --cov=src --cov-report=term-missing tests

      - name: Generate coverage report
        shell: bash
        run: poetry run coverage xml

      - uses: codecov/codecov-action@v3
        with:
          files: ./coverage.xml

      - name: Build single binary application
        run: |
          export TCL_LIBRARY=/usr/lib/python-build-standalone/3.11/lib/tcl8.6/
          poetry install --extras pyinstaller
          [[ "$GITHUB_REF" == *"tags"* ]] && VERSION=$GITHUB_REF_NAME || VERSION=0.0.0
          poetry version $VERSION
          sed -i "s/__version__ = \"0\"/__version__ = \"$VERSION\"/g" src/ops2deb/__init__.py
          poetry run pyinstaller --onefile src/ops2deb/__main__.py --name ops2deb -s
          dist/ops2deb version
          mv dist/ops2deb ops2deb_linux_amd64
        shell: bash

      - name: Upload build artifact
        uses: actions/upload-artifact@v3
        with:
          name: ops2deb_linux_amd64
          path: ops2deb_linux_amd64
          retention-days: 2

      - name: Build distributions
        run: |
          rm -rf dist/
          poetry run poetry build

      - name: Upload build artifacts
        uses: actions/upload-artifact@v3
        with:
          name: distributions
          path: dist/*
          retention-days: 2

  publish_release:
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/')
    needs: [test_and_build]
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Install clog-cli
        uses: upciti/wakemeops-action@v1
        with:
          packages: clog-cli

      - name: Build Release Changelog
        run: |
          clog --setversion $(git tag --sort=creatordate | tail -n1) \
               --from $(git tag --sort=creatordate | tail -n2 | head -n1) \
               -o changelog.md \
               -r https://github.com/upciti/ops2deb

      - name: Download build artifact
        uses: actions/download-artifact@v3
        with:
          name: ops2deb_linux_amd64

      - name: Create Release
        uses: softprops/action-gh-release@v2
        with:
          body_path: changelog.md
          files: ops2deb_linux_amd64

  publish_pypi:
    runs-on: ubuntu-22.04
    if: startsWith(github.ref, 'refs/tags')
    needs: [test_and_build]
    steps:
      - name: Download build artifacts
        uses: actions/download-artifact@v3
        with:
          name: distributions
          path: dist

      - name: Publish distribution 📦 to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.PYPI_API_TOKEN }}

  publish_images:
    runs-on: ubuntu-latest
    needs: [test_and_build]
    if: github.event.repository.fork == false && startsWith(github.ref, 'refs/tags')
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Download build artifact
        uses: actions/download-artifact@v3
        with:
          name: ops2deb_linux_amd64

      - name: Set execute permission
        run: chmod +x ops2deb_linux_amd64

      - name: Login to GitHub Container Registry
        if: startsWith(github.ref, 'refs/tags')
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Docker meta for slim images
        id: metaslim
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/upciti/ops2deb
          flavor: suffix=-slim,onlatest=true
          tags: |
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=semver,pattern={{major}}
            type=ref,event=branch

      - name: Build slim Docker image
        uses: docker/build-push-action@v6
        with:
          context: .
          build-args: |
            OPS2DEB_PATH=ops2deb_linux_amd64
          target: slim
          tags: ${{ steps.metaslim.outputs.tags }}
          labels: ${{ steps.metaslim.outputs.labels }}

      - name: Check Docker image
        run: docker run --rm -i ghcr.io/${{ github.event.repository.full_name }}:latest-slim --help

      - name: Docker meta for big images
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/upciti/ops2deb
          tags: |
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=semver,pattern={{major}}
            type=ref,event=branch

      - name: Build Docker image
        uses: docker/build-push-action@v6
        with:
          context: .
          build-args: |
            OPS2DEB_PATH=ops2deb_linux_amd64
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

      - name: Publish Docker image
        if: startsWith(github.ref, 'refs/tags')
        run: |
          docker push --all-tags ghcr.io/${{ github.event.repository.full_name }}