# 通用 Go + Vue 项目 CI（Gitea Actions）
#
# 单 job：可选 go test + Docker 多架构构建/推送
# 约定：go.mod、Dockerfile（详见 .gitea/README.md「Dockerfile 要求」）；前端（可选）在 web/
#
# 前置：act_runner（ubuntu-latest + docker.sock）、Secret REGISTRY_TOKEN
# Variables：REGISTRY、IMAGE_NAME、DOCKER_IMAGE_PREFIX、RUN_GO_TEST 等

name: CI

on:
  push:
    branches: [main, master]
    tags: ['v*']
  pull_request:

env:
  REGISTRY: ${{ vars.REGISTRY }}
  GITEA_ROOT_URL: ${{ vars.GITEA_ROOT_URL }}
  IMAGE_NAME: ${{ vars.IMAGE_NAME }}
  DOCKERFILE: ${{ vars.DOCKERFILE }}
  DOCKER_PLATFORMS: ${{ vars.DOCKER_PLATFORMS }}
  GO_TEST_SCOPE: ${{ vars.GO_TEST_SCOPE }}
  RUN_GO_TEST: ${{ vars.RUN_GO_TEST }}
  DOCKER_IMAGE_PREFIX: ${{ vars.DOCKER_IMAGE_PREFIX }}
  GOPROXY: ${{ vars.GOPROXY }}
  GOSUMDB: ${{ vars.GOSUMDB }}

jobs:
  docker:
    runs-on: ubuntu-latest
    container:
      image: catthehacker/ubuntu:act-22.04
    steps:
      - name: Checkout
        uses: https://gitea.com/actions/checkout@v4

      - name: Run Go tests
        if: vars.RUN_GO_TEST != 'false'
        shell: bash
        run: |
          set -euo pipefail
          export GOPROXY="${GOPROXY:-https://goproxy.cn,direct}"
          export GOSUMDB="${GOSUMDB:-sum.golang.google.cn}"

          GO_VERSION=$(grep '^go ' go.mod | awk '{print $2}')
          ARCH=$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')
          TAR="go${GO_VERSION}.linux-${ARCH}.tar.gz"

          if ! command -v go >/dev/null 2>&1 || ! go version | grep -q "go${GO_VERSION} "; then
            downloaded=0
            for url in \
              "https://mirrors.aliyun.com/golang/${TAR}" \
              "https://golang.google.cn/dl/${TAR}" \
              "https://go.dev/dl/${TAR}"; do
              echo "trying ${url}"
              if curl -fsSL --connect-timeout 20 --retry 3 --retry-delay 5 --max-time 600 \
                "$url" -o /tmp/go.tgz; then
                downloaded=1
                break
              fi
            done
            [ "$downloaded" -eq 1 ] || { echo "failed to download Go ${GO_VERSION}" >&2; exit 1; }
            rm -rf /usr/local/go
            tar -C /usr/local -xzf /tmp/go.tgz
            export PATH="/usr/local/go/bin:${PATH}"
          fi
          go version
          go test "${GO_TEST_SCOPE:-./...}"

      - name: Setup Docker
        run: |
          set -eux
          if ! command -v docker >/dev/null 2>&1; then
            apt-get update
            DEBIAN_FRONTEND=noninteractive apt-get install -y docker.io
          fi
          if [ ! -S /var/run/docker.sock ]; then
            echo "ERROR: /var/run/docker.sock 未挂载到 job 容器。" >&2
            echo "请在 act_runner config.yaml 中配置：" >&2
            echo "  container.options: -v /var/run/docker.sock:/var/run/docker.sock" >&2
            echo "  container.valid_volumes: [/var/run/docker.sock]" >&2
            exit 1
          fi
          docker info

      - name: Resolve registry
        id: reg
        if: gitea.event_name == 'push'
        shell: bash
        env:
          GITEA_SERVER_URL: ${{ gitea.server_url }}
        run: |
          set -euo pipefail

          url_to_host() {
            echo "$1" | sed -e 's|^https://||' -e 's|^http://||' -e 's|/.*||'
          }

          is_internal_host() {
            local host="${1%%:*}"
            case "$host" in
              localhost|127.*|10.*|192.168.*) return 0 ;;
              172.*)
                local second
                second=$(echo "$host" | cut -d. -f2)
                [ "$second" -ge 16 ] && [ "$second" -le 31 ]
                return
                ;;
              *) return 1 ;;
            esac
          }

          registry="${REGISTRY:-}"
          if [ -z "$registry" ] && [ -n "${GITEA_ROOT_URL:-}" ]; then
            registry=$(url_to_host "${GITEA_ROOT_URL}")
          fi
          if [ -z "$registry" ]; then
            registry=$(url_to_host "${GITEA_SERVER_URL}")
          fi

          if is_internal_host "$registry"; then
            echo "ERROR: Registry 主机 '${registry}' 是内网地址。" >&2
            echo "请设置 Variable REGISTRY=公网 Gitea 域名（如 git.example.com）。" >&2
            exit 1
          fi

          echo "registry host: ${registry}"

          auth_header=""
          if auth_header=$(curl -fsS -D - "https://${registry}/v2/" -o /dev/null 2>&1 | grep -i '^www-authenticate:'); then
            if echo "$auth_header" | grep -qiE '127\.0\.0\.1|172\.(1[6-9]|2[0-9]|3[01])\.|localhost|:13827'; then
              echo "ERROR: Registry token realm 指向内网地址：${auth_header}" >&2
              exit 1
            fi
          fi

          echo "host=${registry}" >> "${GITHUB_OUTPUT}"

      - name: Log in to Container Registry
        if: gitea.event_name == 'push'
        shell: bash
        run: |
          set -euo pipefail
          echo "${{ secrets.REGISTRY_TOKEN }}" | \
            docker login "${{ steps.reg.outputs.host }}" -u "${{ gitea.actor }}" --password-stdin

      - name: Build image
        shell: bash
        env:
          GITEA_SHA: ${{ gitea.sha }}
          GITEA_REF: ${{ gitea.ref }}
          GITEA_REPOSITORY: ${{ gitea.repository }}
          GITEA_REPOSITORY_OWNER: ${{ gitea.repository_owner }}
          GITEA_EVENT_NAME: ${{ gitea.event_name }}
          REGISTRY_HOST: ${{ steps.reg.outputs.host }}
        run: |
          set -euo pipefail

          dockerfile="${DOCKERFILE:-Dockerfile}"

          if [ "${DOCKER_IMAGE_PREFIX:-}" = "hub" ] || [ "${DOCKER_IMAGE_PREFIX:-}" = "docker.io" ]; then
            image_prefix=""
          elif [ -z "${DOCKER_IMAGE_PREFIX:-}" ] || [ "${DOCKER_IMAGE_PREFIX}" = "1panel" ]; then
            image_prefix="docker.1panel.live/library/"
          elif [ "${DOCKER_IMAGE_PREFIX}" = "daocloud" ]; then
            image_prefix="docker.m.daocloud.io/library/"
          else
            image_prefix="${DOCKER_IMAGE_PREFIX}"
            [[ "${image_prefix}" == */ ]] || image_prefix="${image_prefix}/"
          fi
          echo "using IMAGE_PREFIX=${image_prefix:-<docker.io>}"
          build_args=(
            --build-arg "IMAGE_PREFIX=${image_prefix}"
            --build-arg "GOPROXY=${GOPROXY:-https://goproxy.cn,direct}"
            --build-arg "GOSUMDB=${GOSUMDB:-sum.golang.google.cn}"
          )

          builder_id="gitea-buildx-${GITEA_REPOSITORY//\//-}"

          if [ "${GITEA_EVENT_NAME}" = "push" ]; then
            install_binfmt() {
              for img in \
                "docker.1panel.live/tonistiigi/binfmt:latest" \
                "docker.m.daocloud.io/tonistiigi/binfmt:latest" \
                "tonistiigi/binfmt:latest"; do
                echo "trying binfmt image: ${img}"
                if docker run --privileged --rm "${img}" --install all; then
                  return 0
                fi
              done
              return 1
            }
            install_binfmt || true

            registry="${REGISTRY_HOST}"
            image_name="${IMAGE_NAME:-$(echo "${GITEA_REPOSITORY##*/}" | tr '[:upper:]' '[:lower:]')}"
            platforms="${DOCKER_PLATFORMS:-linux/amd64,linux/arm64}"
            image="${registry}/${GITEA_REPOSITORY_OWNER}/${image_name}"
            tags="${image}:sha-${GITEA_SHA:0:7}"
            case "${GITEA_REF}" in
              refs/heads/main|refs/heads/master)
                tags="${tags},${image}:latest"
                ;;
              refs/tags/v*)
                tags="${tags},${image}:${GITEA_REF#refs/tags/}"
                ;;
            esac

            docker buildx create --name "${builder_id}" --use 2>/dev/null || docker buildx use "${builder_id}"
            docker buildx inspect --bootstrap

            tag_args=()
            IFS=',' read -r -a tag_list <<< "$tags"
            for t in "${tag_list[@]}"; do
              tag_args+=(-t "$t")
            done

            docker buildx build \
              --platform "${platforms}" \
              -f "${dockerfile}" \
              "${build_args[@]}" \
              "${tag_args[@]}" \
              --push \
              .
          else
            # PR：仅单架构构建验证 Dockerfile，不推送
            docker buildx create --name "${builder_id}" --use 2>/dev/null || docker buildx use "${builder_id}"
            docker buildx inspect --bootstrap
            docker buildx build \
              --platform linux/amd64 \
              -f "${dockerfile}" \
              "${build_args[@]}" \
              --load \
              .
          fi
