name: 03. Release

on:
  release:
    types: [published]
  workflow_dispatch:
    inputs:
      target:
        description: 'Select where to publish'
        required: true
        type: choice
        default: 'testpypi'
        options:
        - none
        - testpypi
        - pypi
        - both
      build_sdist:
        description: 'Whether to build source distribution'
        required: false
        type: boolean
        default: true
      build_wheels:
        description: 'Whether to build wheel distribution'
        required: false
        type: boolean
        default: true
      os_json:
        description: 'JSON string of runner labels to build on (Manual only; ubuntu-24.04=x86_64, ubuntu-24.04-arm=aarch64, macos-14=arm64, macos-15-intel=x86_64, windows-latest=x86_64)'
        required: false
        type: string
        default: '["ubuntu-24.04", "ubuntu-24.04-arm", "macos-14", "macos-15-intel", "windows-latest"]'
      python_json:
        description: 'JSON string of Python versions (Manual only)'
        required: false
        type: string
        default: '["3.10"]'

permissions:
  contents: write
  id-token: write
  actions: read

jobs:
  build:
    # Skip this workflow for CLI releases (tags starting with cli-)
    if: "!startsWith(github.event.release.tag_name, 'cli-')"
    uses: ./.github/workflows/_build.yml
    with:
      os_json: ${{ inputs.os_json || '["ubuntu-24.04", "ubuntu-24.04-arm", "macos-14", "macos-15-intel", "windows-latest"]' }}
      python_json: ${{ inputs.python_json || '["3.10"]' }}
      build_sdist: ${{ github.event_name == 'release' || inputs.build_sdist != false }}
      build_wheels: ${{ github.event_name == 'release' || inputs.build_wheels != false }}

  permission-check:
    name: Check write permission
    needs: [build]
    runs-on: ubuntu-24.04
    permissions:
      contents: read
    outputs:
      allowed: ${{ steps.check.outputs.allowed }}
    steps:
    - name: Verify actor permission
      id: check
      uses: actions/github-script@v8
      with:
        script: |
          // Only check permission for manual dispatch
          if (context.eventName !== 'workflow_dispatch') {
            core.setOutput('allowed', 'true');
            return;
          }
          const { owner, repo } = context.repo;
          const actor = context.actor;
          const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
            owner,
            repo,
            username: actor,
          });
          const perm = data.permission;
          core.info(`Actor ${actor} permission: ${perm}`);
          const allowed = ['admin', 'maintain', 'write'].includes(perm);
          core.setOutput('allowed', allowed ? 'true' : 'false');
          if (!allowed) {
            core.setFailed(`User ${actor} does not have write permission`);
          }

  publish-testpypi:
    name: Publish to TestPyPI
    needs: [build, permission-check]
    if: >-
      needs.permission-check.outputs.allowed == 'true' &&
      (inputs.target == 'testpypi' || inputs.target == 'both')
    runs-on: ubuntu-24.04
    environment:
      name: testpypi
      url: https://test.pypi.org/p/openviking
    permissions:
      id-token: write
      actions: read
    steps:
    - name: Download all the dists (Same Run)
      uses: actions/download-artifact@v8
      with:
        pattern: python-package-distributions-*
        path: dist/
        merge-multiple: true

    - name: Publish distribution to TestPyPI
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        repository-url: https://test.pypi.org/legacy/
        skip-existing: true
        verbose: true

    - name: Display published version
      run: |
        # Get version from the first wheel file found
        VERSION=$(ls dist/*.whl | head -n 1 | xargs basename | cut -d- -f2)
        echo "Published to TestPyPI (or already existed) with version: $VERSION"
        echo "::notice::Published to TestPyPI (or already existed) with version: $VERSION"

  publish-pypi:
    name: Publish to PyPI
    needs: [build, permission-check]
    if: >-
      needs.permission-check.outputs.allowed == 'true' &&
      (github.event_name == 'release' || inputs.target == 'pypi' || inputs.target == 'both')
    runs-on: ubuntu-24.04
    environment:
      name: pypi
      url: https://pypi.org/p/openviking
    permissions:
      id-token: write
      actions: read
    steps:
    - name: Download all the dists (Same Run)
      uses: actions/download-artifact@v8
      with:
        pattern: python-package-distributions-*
        path: dist/
        merge-multiple: true

    - name: Publish distribution to PyPI
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        skip-existing: true
        verbose: true

    - name: Display published version
      run: |
        # Get version from the first wheel file found
        VERSION=$(ls dist/*.whl | head -n 1 | xargs basename | cut -d- -f2)
        echo "Published to PyPI (or already existed) with version: $VERSION"
        echo "::notice::Published to PyPI (or already existed) with version: $VERSION"

  docker:
    name: Build and Push Docker Image
    needs: [build, permission-check]
    if: >-
      needs.permission-check.outputs.allowed == 'true' &&
      github.event_name == 'release'
    runs-on: ubuntu-24.04
    permissions:
      contents: read
      packages: write
      attestations: write
      id-token: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          submodules: recursive

      - name: Log in to the Container registry
        uses: docker/login-action@v4
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v6
        with:
          images: ghcr.io/${{ github.repository }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v4

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

      - name: Build and push Docker image
        uses: docker/build-push-action@v7
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          build-args: |
            OPENVIKING_VERSION=${{ github.event.release.tag_name }}
