name: build-mosh-binaries

# Trigger philosophy (mirrors build.yml):
#  - Pushes that touch the mosh build pipeline + PRs run the matrix
#    so we can validate workflow / script changes without tagging.
#    Artifacts upload as workflow artifacts only; *no* release.
#  - Manual `workflow_dispatch` with `release_tag` publishes the
#    binaries + SHA256SUMS to the dedicated binary repository
#    (`binaricat/Netcatty-mosh-bin` by default).
#
# `paths` keeps unrelated commits (UI, bridges, etc) from rebuilding
# or refreshing mosh binaries on every push.
on:
  workflow_dispatch:
    inputs:
      mosh_ref:
        description: "mosh upstream git ref (tag/branch/commit) — see https://github.com/mobile-shell/mosh"
        type: string
        default: "mosh-1.4.0"
      release_tag:
        description: "Optional release tag to attach binaries to (e.g. mosh-bin-1.4.0-1). Empty = artifacts only."
        type: string
        default: ""
      release_repo:
        description: "Repository that stores mosh-client binary releases."
        type: string
        default: "binaricat/Netcatty-mosh-bin"
  push:
    branches:
      - "**"
    paths:
      - ".gitattributes"
      - ".github/workflows/build-mosh-binaries.yml"
      - "electron-builder.config.cjs"
      - "package.json"
      - "scripts/build-mosh/**"
      - "scripts/fetch-mosh-binaries.cjs"
      - "scripts/mosh-extra-resources.cjs"
  pull_request:
    paths:
      - ".gitattributes"
      - ".github/workflows/build-mosh-binaries.yml"
      - "electron-builder.config.cjs"
      - "package.json"
      - "scripts/build-mosh/**"
      - "scripts/fetch-mosh-binaries.cjs"
      - "scripts/mosh-extra-resources.cjs"

# Cancel superseded branch / PR builds.
concurrency:
  group: build-mosh-binaries-${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  MOSH_REF: ${{ inputs.mosh_ref || 'mosh-1.4.0' }}

jobs:
  # ------------------------------------------------------------------
  # Linux x64 (manylinux2014 / glibc 2.17, broad distro compatibility).
  # Static-links the heavy third-party deps where possible; the resulting
  # mosh-client still depends on baseline Linux system libraries.
  # ------------------------------------------------------------------
  build-linux-x64:
    name: build-linux-x64
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build mosh-client (linux-x64)
        run: |
          # Run only the compiler inside manylinux2014. JavaScript actions
          # need the host runner's newer glibc.
          docker run --rm \
            -e MOSH_REF="${MOSH_REF}" \
            -e OUT_DIR=/work/out \
            -e ARCH=x64 \
            -v "${GITHUB_WORKSPACE}:/work" \
            -w /work \
            quay.io/pypa/manylinux2014_x86_64 \
            bash scripts/build-mosh/build-linux.sh
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: mosh-client-linux-x64
          path: out/

  build-linux-arm64:
    name: build-linux-arm64
    runs-on: ubuntu-24.04-arm
    steps:
      - uses: actions/checkout@v4
      - name: Build mosh-client (linux-arm64)
        run: |
          # Run only the compiler inside manylinux2014. JavaScript actions
          # need the host runner's newer glibc.
          docker run --rm \
            -e MOSH_REF="${MOSH_REF}" \
            -e OUT_DIR=/work/out \
            -e ARCH=arm64 \
            -v "${GITHUB_WORKSPACE}:/work" \
            -w /work \
            quay.io/pypa/manylinux2014_aarch64 \
            bash scripts/build-mosh/build-linux.sh
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: mosh-client-linux-arm64
          path: out/

  # ------------------------------------------------------------------
  # macOS universal2 (arm64 + x86_64 lipo).
  # Min deployment target: macOS 11 (Big Sur) — covers arm64 hardware.
  # Static-links OpenSSL, protobuf, ncurses for both arches.
  # ------------------------------------------------------------------
  build-macos-universal:
    name: build-macos-universal
    runs-on: macos-15-intel
    steps:
      - uses: actions/checkout@v4
      - name: Build mosh-client (darwin-universal)
        env:
          MOSH_REF: ${{ env.MOSH_REF }}
          OUT_DIR: ${{ github.workspace }}/out
          MACOSX_DEPLOYMENT_TARGET: "11.0"
        run: bash scripts/build-mosh/build-macos.sh
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: mosh-client-darwin-universal
          path: out/

  # ------------------------------------------------------------------
  # Windows x64 pinned standalone client.
  # Do not compile this in CI: the upstream Cygwin build can clear the
  # terminal and never render output on Windows. Ship the SHA256-pinned
  # FluentTerminal standalone binary verified by fetch-windows.sh.
  # ------------------------------------------------------------------
  fetch-windows-x64:
    name: fetch-windows-x64
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Fetch pinned mosh-client.exe (win32-x64)
        run: |
          set -euo pipefail
          export OUT_DIR="${GITHUB_WORKSPACE}/out"
          mkdir -p "$OUT_DIR"
          bash scripts/build-mosh/fetch-windows.sh
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: mosh-client-win32-x64
          path: out/

  # ------------------------------------------------------------------
  # Windows arm64 — intentionally not built.
  # The pinned upstream source only provides x64. arm64 Windows builds
  # should be added only after we have a tested standalone arm64 client.
  # ------------------------------------------------------------------

  # ------------------------------------------------------------------
  # Aggregate + optional release to the dedicated binary repository.
  # ------------------------------------------------------------------
  release:
    name: release
    needs:
      - build-linux-x64
      - build-linux-arm64
      - build-macos-universal
      - fetch-windows-x64
    runs-on: ubuntu-latest
    if: github.event_name == 'workflow_dispatch' && inputs.release_tag != ''
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts
      - name: Stage release files
        run: |
          set -euo pipefail
          mkdir -p release
          for d in artifacts/*/; do
            find "$d" -maxdepth 1 -type f -exec cp {} release/ \;
          done
          (cd release && find . -maxdepth 1 -type f ! -name SHA256SUMS -printf '%P\n' | sort | xargs sha256sum > SHA256SUMS)
          ls -la release
          cat release/SHA256SUMS
      - name: Determine tag
        id: tag
        env:
          RELEASE_TAG: ${{ inputs.release_tag }}
        run: |
          tag="${RELEASE_TAG}"
          if [[ ! "$tag" =~ ^mosh-bin-[A-Za-z0-9._-]+$ ]]; then
            echo "Invalid mosh binary release tag: $tag" >&2
            exit 1
          fi
          printf 'name=%s\n' "$tag" >> "$GITHUB_OUTPUT"
      - name: Create / update release
        env:
          GH_TOKEN: ${{ secrets.MOSH_BIN_RELEASE_TOKEN }}
          RELEASE_REPO: ${{ inputs.release_repo }}
          RELEASE_TAG: ${{ steps.tag.outputs.name }}
        run: |
          set -euo pipefail
          if [[ -z "${GH_TOKEN:-}" ]]; then
            echo "::error::MOSH_BIN_RELEASE_TOKEN is required to publish into ${RELEASE_REPO}."
            exit 1
          fi
          {
            printf '%s\n' 'Pre-built `mosh-client` binaries consumed by `scripts/fetch-mosh-binaries.cjs` during `npm run pack`.'
            printf 'Linux/macOS artifacts are built from `mobile-shell/mosh` upstream ref `%s`.\n' "${MOSH_REF}"
            printf '%s\n\n' 'Windows x64 is the SHA256-pinned FluentTerminal standalone `mosh-client.exe` fallback.'
            printf 'Source workflow: %s/%s/actions/runs/%s\n' "${GITHUB_SERVER_URL}" "${GITHUB_REPOSITORY}" "${GITHUB_RUN_ID}"
            printf 'Source commit: `%s`\n\n' "${GITHUB_SHA}"
            printf '%s\n' 'All artifacts are GPL-3.0; see `resources/mosh/README.md` for source provenance.'
          } > release-notes.md
          if gh release view "${RELEASE_TAG}" --repo "${RELEASE_REPO}" >/dev/null 2>&1; then
            gh release edit "${RELEASE_TAG}" \
              --repo "${RELEASE_REPO}" \
              --title "${RELEASE_TAG}" \
              --notes-file release-notes.md
            gh release upload "${RELEASE_TAG}" release/* \
              --repo "${RELEASE_REPO}" \
              --clobber
          else
            gh release create "${RELEASE_TAG}" release/* \
              --repo "${RELEASE_REPO}" \
              --title "${RELEASE_TAG}" \
              --notes-file release-notes.md
          fi
