name: Build

on:
  workflow_dispatch:
    inputs:
      BASE_IMAGE_NAMESPACE:
        description: 'Base image namespace (Default: Your Github username)'
        required: false
        default: ''
      DOCKERHUB_IMAGE_NAMESPACE:
        description: 'Docker Hub image namespace (Default: Your Github username)'
        required: false
        default: ''
      GHCR_IMAGE_NAMESPACE:
        description: 'GitHub Container Registry image namespace (Default: Your Github username)'
        required: false
        default: ''
      SKIP_DOCKER_HUB:
        description: 'Set to true to skip pushing to Docker Hub (default: false)'
        required: false
        default: 'false'
      SKIP_GHCR:
        description: 'Set to true to skip pushing to GHCR (default: false)'
        required: false
        default: 'false'
      WEBCLIENT_SOURCE_LOCATION:
        description: 'Web Client API Repository'
        required: true
        default: 'https://github.com/lejianwen/rustdesk-api-web'
  push:
    tags:
      - 'v*.*.*'  # 当推送带有版本号的 tag（例如 v1.0.0）时触发工作流
      - 'test*'

env:
  LATEST_TAG: latest
  WEBCLIENT_SOURCE_LOCATION: ${{ github.event.inputs.WEBCLIENT_SOURCE_LOCATION || 'https://github.com/lejianwen/rustdesk-api-web' }}
  BASE_IMAGE_NAMESPACE: ${{ github.event.inputs.BASE_IMAGE_NAMESPACE || github.actor }}
  DOCKERHUB_IMAGE_NAMESPACE: ${{ github.event.inputs.DOCKERHUB_IMAGE_NAMESPACE || github.actor }}
  GHCR_IMAGE_NAMESPACE: ${{ github.event.inputs.GHCR_IMAGE_NAMESPACE || github.actor }}
  SKIP_DOCKER_HUB: ${{ github.event.inputs.SKIP_DOCKER_HUB || 'false' }}
  SKIP_GHCR: ${{ github.event.inputs.SKIP_GHCR }}
jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        job:
          - { platform: "amd64", goos: "linux" }
          - { platform: "arm64", goos: "linux" }
          - { platform: "amd64", goos: "windows" }

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Go environment
        uses: actions/setup-go@v4
        with:
          go-version: '1.22'  # 选择 Go 版本

      - name: Set up npm
        uses: actions/setup-node@v2
        with:
          node-version: '20'


      - name: build rustdesk-api-web
        run: |
          git clone ${{ env.WEBCLIENT_SOURCE_LOCATION }}
          cd rustdesk-api-web
          npm install
          npm run build
          mkdir ../resources/admin/ -p
          cp -ar dist/* ../resources/admin/

      - name: tidy
        run: go mod tidy

      - name: swag
        run: |
          go install github.com/swaggo/swag/cmd/swag@latest
          swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin
          swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api

      - name: Build for ${{ matrix.job.goos }}-${{ matrix.job.platform }}
        run: |
          mkdir release -p
          cp -ar resources release/
          cp -ar docs release/
          cp -ar conf release/
          mkdir -p release/data
          mkdir -p release/runtime
          if [ "${{ matrix.job.goos }}" = "windows" ]; then
            sudo apt-get install gcc-mingw-w64-x86-64 zip -y
            GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=x86_64-w64-mingw32-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain.exe ./cmd/apimain.go
            zip -r ${{ matrix.job.goos}}-${{ matrix.job.platform }}.zip ./release
          else
            if [ "${{ matrix.job.platform }}" = "arm64" ]; then
                wget https://musl.cc/aarch64-linux-musl-cross.tgz
                tar -xf aarch64-linux-musl-cross.tgz
                export PATH=$PATH:$PWD/aarch64-linux-musl-cross/bin
                GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=aarch64-linux-musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
            else
              sudo apt-get install musl musl-dev musl-tools -y
              GOOS=${{ matrix.job.goos }} GOARCH=${{ matrix.job.platform }} CC=musl-gcc CGO_LDFLAGS="-static" CGO_ENABLED=1 go build -ldflags "-s -w" -o ./release/apimain ./cmd/apimain.go
            fi
            tar -czf ${{ matrix.job.goos}}-${{ matrix.job.platform }}.tar.gz ./release
          fi

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
          path: |
            ${{ matrix.job.goos}}-${{ matrix.job.platform }}.tar.gz
            ${{ matrix.job.goos}}-${{ matrix.job.platform }}.zip
      - name: Upload to GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          files: |
            ${{ matrix.job.goos}}-${{ matrix.job.platform }}.tar.gz
            ${{ matrix.job.goos}}-${{ matrix.job.platform }}.zip
        #          tag_name: ${{ env.LATEST_TAG }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  docker:
    name: Push Docker Image
    needs: build
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        job:
          - { platform: "amd64", goos: "linux",  docker_platform: "linux/amd64" }
          - { platform: "arm64", goos: "linux",  docker_platform: "linux/arm64" }
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

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

      - name: Log in to Docker Hub
        if: ${{ env.SKIP_DOCKER_HUB == 'false' }}  # Only log in if SKIP_DOCKER_HUB is false
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_ACCESS_TOKEN }}

      - name: Log in to GitHub Container Registry
        if: ${{ env.SKIP_GHCR == 'false' }}  # Only log in if GHCR push is enabled
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract version from tag
        id: vars
        run: |
          if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
            echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
          else
            echo "TAG=latest" >> $GITHUB_ENV  # Default to 'latest' if not a tag
          fi

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api

      - name: Download binaries
        uses: actions/download-artifact@v4
        with:
          name: rustdesk-api-${{ matrix.job.goos }}-${{ matrix.job.platform }}
          path: ./

      - name: Unzip binaries
        run: |
          mkdir -p ${{ matrix.job.platform }}
          tar -xzf ${{ matrix.job.goos }}-${{ matrix.job.platform }}.tar.gz -C ${{ matrix.job.platform }}
          file ${{ matrix.job.platform }}/apimain

      - name: Build and push Docker image to Docker Hub ${{ matrix.job.platform }}
        if: ${{ env.SKIP_DOCKER_HUB == 'false' }}  # Only run this step if SKIP_DOCKER_HUB is false
        uses: docker/build-push-action@v5
        with:
          context: "."
          file: ./Dockerfile
          platforms: ${{ matrix.job.docker_platform }}
          push: true
          provenance: false
          build-args: |
            BUILDARCH=${{ matrix.job.platform }}
          tags: |
            ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.LATEST_TAG }}-${{ matrix.job.platform }},
            ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
          labels: ${{ steps.meta.outputs.labels }}

      - name: Build and push Docker image to GHCR ${{ matrix.job.platform }}
        if: ${{ env.SKIP_GHCR == 'false' }}  # Only run this step if SKIP_GHCR is false
        uses: docker/build-push-action@v5
        with:
          context: "."
          file: ./Dockerfile
          platforms: ${{ matrix.job.docker_platform }}
          push: true
          provenance: false
          build-args: |
            BUILDARCH=${{ matrix.job.platform }}
          tags: |
            ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.LATEST_TAG }}-${{ matrix.job.platform }},
            ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-${{ matrix.job.platform }}
          labels: ${{ steps.meta.outputs.labels }}

  #
  docker-manifest:
    name: Push Docker Manifest
    needs: docker
    runs-on: ubuntu-latest
    steps:
      - name: Extract version from tag
        id: vars
        run: |
          if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
            echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
          else
            echo "TAG=latest" >> $GITHUB_ENV  # Default to 'latest' if not a tag
          fi

      - name: Log in to Docker Hub
        if: ${{ env.SKIP_DOCKER_HUB == 'false' }}  # Only log in if Docker Hub push is enabled
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_ACCESS_TOKEN }}

      - name: Log in to GitHub Container Registry
        if: ${{ env.SKIP_GHCR == 'false' }}  # Only log in if GHCR push is enabled
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Create and push manifest Docker Hub (:version)
        if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
        uses: Noelware/docker-manifest-action@master
        with:
          base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
          extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
            ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
          push: true

      - name: Create and push manifest GHCR (:version)
        if: ${{ env.SKIP_GHCR == 'false' }}
        uses: Noelware/docker-manifest-action@master
        with:
          base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}
          extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-amd64,
            ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:${{ env.TAG }}-arm64
          push: true
          amend: true

      - name: Create and push manifest Docker Hub (:latest)
        if: ${{ env.SKIP_DOCKER_HUB == 'false' }}
        uses: Noelware/docker-manifest-action@master
        with:
          base-image: ${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest
          extra-images: ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:latest-amd64,
            ${{ env.DOCKERHUB_IMAGE_NAMESPACE }}/rustdesk-api:latest-arm64
          push: true

      - name: Create and push manifest GHCR (:latest)
        if: ${{ env.SKIP_GHCR == 'false' }}
        uses: Noelware/docker-manifest-action@master
        with:
          base-image: ghcr.io/${{ env.BASE_IMAGE_NAMESPACE }}/rustdesk-api:latest
          extra-images: ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:latest-amd64,
            ghcr.io/${{ env.GHCR_IMAGE_NAMESPACE }}/rustdesk-api:latest-arm64
          push: true
          amend: true