name: Publish release

on:
  release:
    types: [created]

env:
  IS_TEST: false
  DOCKER_ORG_NAME: sanicframework
  DOCKER_IMAGE_NAME: sanic
  DOCKER_BASE_IMAGE_NAME: sanic-build
  DOCKER_IMAGE_DOCKERFILE: ./docker/Dockerfile
  DOCKER_BASE_IMAGE_DOCKERFILE: ./docker/Dockerfile-base

jobs:
  generate_info:
    name: Generate info
    runs-on: ubuntu-latest
    outputs:
      docker-tags: ${{ steps.generate_docker_info.outputs.tags }}
      pypi-version: ${{ steps.parse_version_tag.outputs.pypi-version }}
    steps:
      - name: Parse version tag
        id: parse_version_tag
        env:
          TAG_NAME: ${{ github.event.release.tag_name }}
        run: |
          tag_name="${{ env.TAG_NAME }}"

          if [[ ! "${tag_name}" =~ ^v([0-9]{2})\.([0-9]{1,2})\.([0-9]+)$ ]]; then
            echo "::error::Tag name must be in the format vYY.MM.MICRO"
            exit 1
          fi

          year_output="year=${BASH_REMATCH[1]}"
          month_output="month=${BASH_REMATCH[2]}"
          pypi_output="pypi-version=${tag_name#v}"

          echo "${year_output}"
          echo "${month_output}"
          echo "${pypi_output}"

          echo "${year_output}" >> $GITHUB_OUTPUT
          echo "${month_output}" >> $GITHUB_OUTPUT
          echo "${pypi_output}" >> $GITHUB_OUTPUT

      - name: Get latest release
        id: get_latest_release
        run: |
          latest_tag=$(
            curl -L \
              -H "Accept: application/vnd.github+json" \
              -H "Authorization: Bearer ${{ github.token }}" \
              -H "X-GitHub-Api-Version: 2022-11-28" \
              https://api.github.com/repos/${{ github.repository }}/releases/latest \
              | jq -r '.tag_name'
          )
          echo "latest_tag=$latest_tag" >> $GITHUB_OUTPUT

      - name: Generate Docker info
        id: generate_docker_info
        run: |
          tag_year="${{ steps.parse_version_tag.outputs.year }}"
          tag_month="${{ steps.parse_version_tag.outputs.month }}"
          latest_tag="${{ steps.get_latest_release.outputs.latest_tag }}"
          tag="${{ github.event.release.tag_name }}"

          tags="${tag_year}.${tag_month}"

          if [[ "${tag_month}" == "12" ]]; then
            tags+=",LTS"
            echo "::notice::Tag ${tag} is LTS version"
          else
            echo "::notice::Tag ${tag} is not LTS version"
          fi

          if [[ "${latest_tag}" == "${{ github.event.release.tag_name }}" ]]; then
            tags+=",latest"
            echo "::notice::Tag ${tag} is marked as latest"
          else
            echo "::notice::Tag ${tag} is not marked as latest"
          fi

          tags_output="tags=${tags}"

          echo "${tags_output}"
          echo "${tags_output}" >> $GITHUB_OUTPUT

  publish_package:
    name: Build and publish package
    runs-on: ubuntu-latest
    needs: generate_info
    steps:
    - name: Checkout repo
      uses: actions/checkout@v3

    - name: Setup Python
      uses: actions/setup-python@v4
      with:
        python-version: "3.11"

    - name: Install dependencies
      run: pip install build twine

    - name: Update package version
      run: |
        echo "__version__ = \"${{ needs.generate_info.outputs.pypi-version }}\"" > sanic/__version__.py

    - name: Build a binary wheel and a source tarball
      run: python -m build --sdist --wheel --outdir dist/ .

    - name: Publish to PyPi 🚀
      run: twine upload --non-interactive --disable-progress-bar dist/*
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ env.IS_TEST == 'true' && secrets.SANIC_TEST_PYPI_API_TOKEN || secrets.SANIC_PYPI_API_TOKEN }}
        TWINE_REPOSITORY: ${{ env.IS_TEST == 'true' && 'testpypi' || 'pypi' }}

  publish_docker:
    name: Publish Docker / Python ${{ matrix.python-version }}
    needs: [generate_info, publish_package]
    runs-on: ubuntu-latest
    strategy:
      fail-fast: true
      matrix:
        python-version: ["3.10", "3.11"]
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_ACCESS_USER }}
          password: ${{ secrets.DOCKER_ACCESS_TOKEN }}

      - name: Build and push base image
        uses: docker/build-push-action@v4
        with:
          push: ${{ env.IS_TEST == 'false' }}
          file: ${{ env.DOCKER_BASE_IMAGE_DOCKERFILE }}
          tags: ${{ env.DOCKER_ORG_NAME }}/${{ env.DOCKER_BASE_IMAGE_NAME }}:${{ matrix.python-version }}
          build-args: |
            PYTHON_VERSION=${{ matrix.python-version }}

      - name: Parse tags for this Python version
        id: parse_tags
        run: |
          IFS=',' read -ra tags <<< "${{ needs.generate_info.outputs.docker-tags }}"
          tag_args=""

          for tag in "${tags[@]}"; do
              tag_args+=",${{ env.DOCKER_ORG_NAME }}/${{ env.DOCKER_IMAGE_NAME }}:${tag}-py${{ matrix.python-version }}"
          done

          tag_args_output="tag_args=${tag_args:1}"

          echo "${tag_args_output}"
          echo "${tag_args_output}" >> $GITHUB_OUTPUT

      - name: Build and push Sanic image
        uses: docker/build-push-action@v4
        with:
          push: ${{ env.IS_TEST == 'false' }}
          file: ${{ env.DOCKER_IMAGE_DOCKERFILE }}
          tags: ${{ steps.parse_tags.outputs.tag_args }}
          build-args: |
            BASE_IMAGE_ORG=${{ env.DOCKER_ORG_NAME }}
            BASE_IMAGE_NAME=${{ env.DOCKER_BASE_IMAGE_NAME }}
            BASE_IMAGE_TAG=${{ matrix.python-version }}
            SANIC_PYPI_VERSION=${{ needs.generate_info.outputs.pypi-version }}
