name: deploy-runner-images

on:
  push:
    tags: [boot-v*]
  workflow_dispatch:
    inputs:
      release_tag:
        description: "Release tag override (manual runs only)"
        required: false
        default: ""
      publish_release:
        description: "Publish artifacts to Forgejo release (true/false)"
        required: false
        default: "true"
      build_x86_64_netboot:
        description: "Build x86_64 netboot tarball (true/false)"
        required: false
        default: "true"
      build_x86_64_iso:
        description: "Build x86_64 installer ISO (true/false)"
        required: false
        default: "true"

concurrency:
  group: runner-image-deploy-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build-and-release:
    if: ${{ github.server_url != 'https://codeberg.org' }}
    runs-on: codeberg-medium-lazy
    steps:
      - name: Fetch source (no git required)
        env:
          GITHUB_TOKEN: ${{ github.token }}
        shell: bash
        run: |
          set -euo pipefail
          if [[ -z "${GITHUB_TOKEN:-}" ]]; then
            echo "error: missing github.token"
            exit 2
          fi
          if ! command -v curl >/dev/null 2>&1; then
            echo "error: curl is required"
            exit 2
          fi
          if ! command -v tar >/dev/null 2>&1; then
            echo "error: tar is required"
            exit 2
          fi
          if [[ -z "${GITHUB_SHA:-}" ]]; then
            echo "error: missing GITHUB_SHA"
            exit 2
          fi
          if [[ -z "${GITHUB_SERVER_URL:-}" ]]; then
            echo "error: missing GITHUB_SERVER_URL"
            exit 2
          fi
          if [[ -z "${GITHUB_REPOSITORY:-}" ]]; then
            echo "error: missing GITHUB_REPOSITORY"
            exit 2
          fi

          rm -rf .repo
          mkdir -p .repo
          curl -fsSL -H "Authorization: token ${GITHUB_TOKEN}" \
            "${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz?rev=${GITHUB_SHA}" \
            -o .repo/src.tgz
          tar -xzf .repo/src.tgz -C .repo --strip-components=1
          rm -f .repo/src.tgz

      - name: Bootstrap Nix
        shell: bash
        run: |
          set -euo pipefail
          if ! command -v nix >/dev/null 2>&1; then
            curl -fsSL https://nixos.org/nix/install -o /tmp/install-nix.sh
            sh /tmp/install-nix.sh --no-daemon --yes
          fi

          if [[ -f "$HOME/.nix-profile/etc/profile.d/nix.sh" ]]; then
            # shellcheck disable=SC1091
            . "$HOME/.nix-profile/etc/profile.d/nix.sh"
          fi
          if [[ -d "$HOME/.nix-profile/bin" ]]; then
            echo "PATH=$HOME/.nix-profile/bin:$PATH" >> "$GITHUB_ENV"
            export PATH="$HOME/.nix-profile/bin:$PATH"
          fi
          nix --version

      - name: Resolve build plan
        id: plan
        env:
          INPUT_RELEASE_TAG: ${{ github.event.inputs.release_tag }}
          INPUT_PUBLISH_RELEASE: ${{ github.event.inputs.publish_release }}
          INPUT_BUILD_X86_64_NETBOOT: ${{ github.event.inputs.build_x86_64_netboot }}
          INPUT_BUILD_X86_64_ISO: ${{ github.event.inputs.build_x86_64_iso }}
        shell: bash
        run: |
          set -euo pipefail

          bool_norm() {
            local raw
            raw="$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')"
            case "${raw}" in
              ''|true|1|yes|y|on) echo "true" ;;
              false|0|no|n|off) echo "false" ;;
              *)
                echo "error: invalid boolean value '${1}'" >&2
                exit 2
                ;;
            esac
          }

          short_sha="${GITHUB_SHA:0:12}"
          if [[ "${GITHUB_REF:-}" == refs/tags/* ]]; then
            release_tag="${GITHUB_REF#refs/tags/}"
          else
            release_tag="${INPUT_RELEASE_TAG:-}"
            if [[ -z "${release_tag}" ]]; then
              release_tag="boot-${short_sha}"
            fi
          fi

          if [[ ! "${release_tag}" =~ ^[A-Za-z0-9._-]+$ ]]; then
            echo "error: release tag contains unsupported characters: ${release_tag}" >&2
            exit 2
          fi

          publish_release="$(bool_norm "${INPUT_PUBLISH_RELEASE:-true}")"
          build_x86_64_netboot="$(bool_norm "${INPUT_BUILD_X86_64_NETBOOT:-true}")"
          build_x86_64_iso="$(bool_norm "${INPUT_BUILD_X86_64_ISO:-true}")"

          if [[ "${build_x86_64_netboot}" != "true" && "${build_x86_64_iso}" != "true" ]]; then
            echo "error: at least one image build must be enabled" >&2
            exit 2
          fi

          artifact_suffix="${short_sha}-${GITHUB_RUN_NUMBER:-0}-${GITHUB_RUN_ATTEMPT:-1}"

          echo "release_tag=${release_tag}" >> "$GITHUB_OUTPUT"
          echo "publish_release=${publish_release}" >> "$GITHUB_OUTPUT"
          echo "build_x86_64_netboot=${build_x86_64_netboot}" >> "$GITHUB_OUTPUT"
          echo "build_x86_64_iso=${build_x86_64_iso}" >> "$GITHUB_OUTPUT"
          echo "artifact_suffix=${artifact_suffix}" >> "$GITHUB_OUTPUT"

      - name: Build runner boot images
        env:
          BUILD_X86_64_NETBOOT: ${{ steps.plan.outputs.build_x86_64_netboot }}
          BUILD_X86_64_ISO: ${{ steps.plan.outputs.build_x86_64_iso }}
          ARTIFACT_SUFFIX: ${{ steps.plan.outputs.artifact_suffix }}
        shell: bash
        run: |
          set -euo pipefail
          cd .repo

          if [[ -f "$HOME/.nix-profile/etc/profile.d/nix.sh" ]]; then
            # shellcheck disable=SC1091
            . "$HOME/.nix-profile/etc/profile.d/nix.sh"
          fi
          export PATH="$HOME/.nix-profile/bin:$PATH"

          artifacts_dir="$PWD/.artifacts"
          rm -rf "${artifacts_dir}"
          mkdir -p "${artifacts_dir}"

          nix_args=(--accept-flake-config --extra-experimental-features "nix-command flakes")

          if [[ "${BUILD_X86_64_NETBOOT}" == "true" ]]; then
            nix build "${nix_args[@]}" \
              .#nixosConfigurations.ec-runner-x86_64-netboot.config.system.build.netboot \
              -o result-netboot-x86_64
            tar -C result-netboot-x86_64 \
              -czf "${artifacts_dir}/ec-runner-x86_64-netboot-${ARTIFACT_SUFFIX}.tar.gz" \
              kernel initrd netboot.ipxe
          fi

          if [[ "${BUILD_X86_64_ISO}" == "true" ]]; then
            nix build "${nix_args[@]}" \
              .#nixosConfigurations.ec-runner-x86_64-iso.config.system.build.isoImage \
              -o result-iso-x86_64
            iso_source=""
            if [[ -f result-iso-x86_64 ]]; then
              iso_source="result-iso-x86_64"
            else
              iso_source="$(find -L result-iso-x86_64 -type f -name '*.iso' | head -n 1 || true)"
            fi
            if [[ -z "${iso_source}" ]]; then
              echo "error: could not locate ISO output from result-iso-x86_64" >&2
              exit 2
            fi
            cp -f "${iso_source}" "${artifacts_dir}/ec-runner-x86_64-iso-${ARTIFACT_SUFFIX}.iso"
          fi

          if ! find "${artifacts_dir}" -maxdepth 1 -type f | grep -q .; then
            echo "error: no image artifacts were produced" >&2
            exit 2
          fi

          (
            cd "${artifacts_dir}"
            sha256sum -- * > SHA256SUMS.txt
            ls -lh
          )

      - name: Publish artifacts to Forgejo release
        if: ${{ steps.plan.outputs.publish_release == 'true' }}
        env:
          GITHUB_TOKEN: ${{ github.token }}
          RELEASE_TAG: ${{ steps.plan.outputs.release_tag }}
        shell: bash
        run: |
          set -euo pipefail
          cd .repo

          if [[ -z "${GITHUB_TOKEN:-}" ]]; then
            echo "error: missing github.token"
            exit 2
          fi
          if [[ -z "${GITHUB_SERVER_URL:-}" ]]; then
            echo "error: missing GITHUB_SERVER_URL"
            exit 2
          fi
          if [[ -z "${GITHUB_REPOSITORY:-}" ]]; then
            echo "error: missing GITHUB_REPOSITORY"
            exit 2
          fi

          api_base="${GITHUB_SERVER_URL%/}/api/v1/repos/${GITHUB_REPOSITORY}"
          release_json="$(curl -fsSL \
            -H "Authorization: token ${GITHUB_TOKEN}" \
            "${api_base}/releases/tags/${RELEASE_TAG}" 2>/dev/null || true)"

          if [[ -z "${release_json}" ]]; then
            payload="$(cat <<JSON
          {
            "tag_name": "${RELEASE_TAG}",
            "name": "Boot images ${RELEASE_TAG}",
            "body": "Automated runner boot image build from ${GITHUB_SHA}.",
            "draft": false,
            "prerelease": false
          }
          JSON
          )"
            release_json="$(curl -fsSL -X POST \
              -H "Authorization: token ${GITHUB_TOKEN}" \
              -H "content-type: application/json" \
              "${api_base}/releases" \
              -d "${payload}")"
          fi

          release_id=""
          if command -v python3 >/dev/null 2>&1; then
            release_id="$(python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' <<<"${release_json}" 2>/dev/null || true)"
          fi
          if [[ -z "${release_id}" ]]; then
            release_id="$(printf '%s' "${release_json}" \
              | sed -nE 's/.*"id"[[:space:]]*:[[:space:]]*([0-9]+).*/\1/p' \
              | head -n 1)"
          fi
          if [[ -z "${release_id}" ]]; then
            echo "error: failed to resolve release id for ${RELEASE_TAG}" >&2
            exit 2
          fi

          for asset_path in .artifacts/*; do
            [[ -f "${asset_path}" ]] || continue
            asset_name="$(basename "${asset_path}")"
            curl -fsSL -X POST \
              -H "Authorization: token ${GITHUB_TOKEN}" \
              -H "content-type: application/octet-stream" \
              --data-binary @"${asset_path}" \
              "${api_base}/releases/${release_id}/assets?name=${asset_name}" >/dev/null
            echo "uploaded: ${asset_name}"
          done
