name: Build Offline Nginx Ingress Installer

on:
  push:
    paths:
      - 'scripts/ingress-installer.sh'
      - 'scripts/resolve_nginx_ingress_versions.sh'
      - '.github/workflows/offline-package-nginx-ingress.yaml'
  workflow_dispatch:
    inputs:
      tag:
        description: "Release tag to use/sync (e.g., v0.133.0). Leave empty to use offline-nginx-ingress-<run_number>"
        required: false
        type: string
      image_tag:
        description: "Override image tag for nginx/nginx-ingress (e.g., 5.1.1). Leave empty to auto-resolve"
        required: false
        type: string
      chart_version:
        description: "Override helm chart version for nginx-stable/nginx-ingress (e.g., 1.2.3). Leave empty to auto-resolve"
        required: false
        type: string
      major_whitelist:
        description: "Allowed major versions for image tag (regex alternation). Default: 5 (i.e., ^5\\.)"
        required: false
        type: string
        default: "5"

permissions:
  contents: write   # 需要创建/上传 Release 资产

concurrency:
  group: build-offline-nginx-ingress
  cancel-in-progress: false

jobs:
  build-offline-installer:
    strategy:
      matrix:
        arch: [amd64, arm64]
    runs-on: ubuntu-latest
    outputs:
      image_tag: ${{ steps.resolve.outputs.image_tag }}
      chart_version: ${{ steps.resolve.outputs.chart_version }}
      artifact-name: ${{ steps.upload-artifact.outputs.artifact-name }}
    steps:
      - uses: actions/checkout@v4

      - name: Install deps (curl, jq, helm)
        run: |
          set -euo pipefail
          sudo apt-get update -y
          sudo apt-get install -y curl jq
          curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
          helm version

      - name: Add helm repo
        run: |
          set -euo pipefail
          helm repo add nginx-stable https://helm.nginx.com/stable
          helm repo update

      - name: Resolve latest versions
        id: resolve
        env:
          OVERRIDE_IMAGE_TAG: ${{ github.event.inputs.image_tag }}
          OVERRIDE_CHART_VERSION: ${{ github.event.inputs.chart_version }}
          MAJOR_WHITELIST: ${{ github.event.inputs.major_whitelist }}
        run: |
          set -euo pipefail
          bash scripts/resolve_nginx_ingress_versions.sh

      - name: Prepare directories
        run: |
          set -euo pipefail
          mkdir -p offline-installer/{images,charts,scripts,bin}

      # 复制并“盖章”版本号到安装脚本
      - name: Stage installer script and stamp resolved image tag
        env:
          IMG_TAG: ${{ steps.resolve.outputs.image_tag }}
        run: |
          set -euo pipefail
          cp scripts/ingress-installer.sh offline-installer/scripts/
          # 替换默认的 NGINX_IC_IMAGE 与 OCI_NGINX_REF 中的 2.4.0 为解析到的 ${IMG_TAG}
          sed -i -E "s|(NGINX_IC_IMAGE:=nginx/nginx-ingress:)[0-9]+\.[0-9]+\.[0-9]+|\1${IMG_TAG}|" offline-installer/scripts/ingress-installer.sh
          sed -i -E "s|(OCI_NGINX_REF:=nginx-ingress-)[0-9]+\.[0-9]+\.[0-9]+|\1${IMG_TAG}|" offline-installer/scripts/ingress-installer.sh
          chmod +x offline-installer/scripts/ingress-installer.sh

      - name: Download nerdctl binary for ${{ matrix.arch }}
        run: |
          set -euo pipefail
          wget https://github.com/containerd/nerdctl/releases/download/v2.0.3/nerdctl-2.0.3-linux-${{ matrix.arch }}.tar.gz \
            -O offline-installer/nerdctl.tar.gz

      - name: Pull & export required images (nginx/nginx-ingress:${{ steps.resolve.outputs.image_tag }})
        env:
          IMG_TAG: ${{ steps.resolve.outputs.image_tag }}
        run: |
          set -euo pipefail
          docker pull "nginx/nginx-ingress:${IMG_TAG}"
          docker pull "registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407"

          docker save "nginx/nginx-ingress:${IMG_TAG}" \
            -o offline-installer/images/nginx-ingress.tar

          docker save "registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407" \
            -o offline-installer/images/kube-webhook-certgen.tar

      - name: Download Helm Chart (nginx-stable/nginx-ingress ${{ steps.resolve.outputs.chart_version }})
        env:
          CHART_VERSION: ${{ steps.resolve.outputs.chart_version }}
        run: |
          set -euo pipefail
          helm pull nginx-stable/nginx-ingress --version="${CHART_VERSION}" --untar --untardir offline-installer/charts

      - name: Package offline installer
        run: |
          set -euo pipefail
          cd offline-installer
          tar czvf ../offline-setup-nginx-ingress-${{ matrix.arch }}.tar.gz ./
          cd ..

      - name: Upload artifact
        id: upload-artifact
        uses: actions/upload-artifact@v4
        with:
          name: offline-setup-nginx-ingress-${{ matrix.arch }}
          path: offline-setup-nginx-ingress-${{ matrix.arch }}.tar.gz

  test-offline-installer:
    needs: build-offline-installer
    strategy:
      matrix:
        arch: [amd64]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Download offline installer artifact for ${{ matrix.arch }}
        uses: actions/download-artifact@v4
        with:
          name: offline-setup-nginx-ingress-${{ matrix.arch }}
          path: offline-test

      - name: Setup K3s and KUBECONFIG for user
        run: |
          set -euo pipefail
          curl -sfL https://get.k3s.io | sudo sh -
          mkdir -p $HOME/.kube
          sudo cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
          sudo chown $USER:$USER $HOME/.kube/config
          sudo mkdir -p /root/.kube
          sudo cp /etc/rancher/k3s/k3s.yaml /root/.kube/config
          kubectl get nodes
          kubectl version --client=true

      - name: Install Helm
        run: |
          set -euo pipefail
          curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

      - name: Load offline installer package
        run: |
          set -euo pipefail
          cd offline-test
          tar -xzvf offline-setup-nginx-ingress-${{ matrix.arch }}.tar.gz
          sudo tar xzvf nerdctl.tar.gz -C /usr/local/bin/
          docker load -i images/nginx-ingress.tar
          docker load -i images/kube-webhook-certgen.tar
          cd ..

      - name: Run offline installer in K3S cluster
        run: |
          set -euo pipefail
          cd offline-test
          sudo bash scripts/ingress-installer.sh
          sleep 10
          sudo helm list -A
          sudo kubectl -n ingress get pods

  publish-release:
    needs: test-offline-installer
    runs-on: ubuntu-latest
    env:
      TAG_NAME: ${{ github.event.inputs.tag != '' && github.event.inputs.tag || format('offline-nginx-ingress-{0}', github.run_number) }}
      RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
      RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
      VPS_HOST: ${{ secrets.VPS_HOST }}
      REMOTE_ROOT: /data/update-server/nginx-ingress
    steps:
      - uses: actions/checkout@v4

      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        with:
          tag_name: ${{ env.TAG_NAME }}
          release_name: Build ${{ env.TAG_NAME }}
          draft: false
          prerelease: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Download amd64 artifact
        uses: actions/download-artifact@v4
        with:
          name: offline-setup-nginx-ingress-amd64
          path: release-artifacts

      - name: Download arm64 artifact
        uses: actions/download-artifact@v4
        with:
          name: offline-setup-nginx-ingress-arm64
          path: release-artifacts

      - name: Upload offline installers to GitHub Release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ env.TAG_NAME }}
          files: |
            release-artifacts/offline-setup-nginx-ingress-amd64.tar.gz
            release-artifacts/offline-setup-nginx-ingress-arm64.tar.gz
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      # === Rsync 到远端 ===
      - name: Ensure deps (rsync, ssh)
        run: |
          set -euo pipefail
          sudo apt-get update -y
          sudo apt-get install -y rsync openssh-client

      - name: Init SSH
        run: |
          set -euo pipefail
          mkdir -p ~/.ssh
          echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts

      - name: Rsync release assets to remote
        run: |
          set -euo pipefail
          REMOTE_DIR="${REMOTE_ROOT}/${TAG_NAME}"
          ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" "mkdir -p '${REMOTE_DIR}'"
          echo "Rsync -> ${VPS_HOST}:${REMOTE_DIR}/"
          rsync -av -e "ssh -i ~/.ssh/id_rsa" \
            release-artifacts/offline-setup-nginx-ingress-amd64.tar.gz \
            release-artifacts/offline-setup-nginx-ingress-arm64.tar.gz \
            "${RSYNC_SSH_USER}@${VPS_HOST}:${REMOTE_DIR}/"

  retention:
    name: Remote retention (keep latest 3)
    needs: publish-release
    runs-on: ubuntu-latest
    env:
      RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
      RSYNC_SSH_USER: ${{ secrets.RSYNC_SSH_USER }}
      VPS_HOST: ${{ secrets.VPS_HOST }}
      REMOTE_ROOT: /data/update-server/nginx-ingress
    steps:
      - name: Init SSH
        run: |
          set -euo pipefail
          mkdir -p ~/.ssh
          echo "$RSYNC_SSH_KEY" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts

      - name: Prune old versions on remote (keep 3)
        run: |
          set -euo pipefail
          ssh -i ~/.ssh/id_rsa "${RSYNC_SSH_USER}@${VPS_HOST}" bash -lc '
            set -euo pipefail
            cd "'"${REMOTE_ROOT}"'" || exit 0
            keep=3
            # 同时兼容两类目录命名：offline-nginx-ingress-* 和 v<semver>
            mapfile -t all < <(ls -1 | grep -E "^(offline-nginx-ingress-|v[0-9]+\.)" | sort -V -r || true)
            if [ "${#all[@]}" -le "$keep" ]; then
              echo "Nothing to prune. Count=${#all[@]}"
              exit 0
            fi
            to_delete=("${all[@]:keep}")
            echo "Pruning old versions: ${to_delete[*]}"
            for d in "${to_delete[@]}"; do
              rm -rf -- "$d"
            done
          '
