name: 📦🚀 Build Installer - Linux RPM AMD64

on:
  workflow_dispatch:
    inputs:
      release_type:
        description: "Tagged release testing scenario"
        required: false
        type: choice
        default: ""
        options:
          - ""
          - 9.9.9-b1
          - 9.9.9-rc1
          - 9.9.9
  push:
    paths-ignore:
      - "**.md"
    branches:
      - "long_lived/**"
      - main
      - "release/**"
  release:
    types: [published]
  pull_request:
    paths-ignore:
      - "**.md"
    branches:
      - "**"

concurrency:
  group: ${{ github.event_name == 'pull_request' && format('{0}-{1}', github.workflow_ref, github.event.pull_request.number) || github.run_id }}
  cancel-in-progress: true

permissions:
  id-token: write
  contents: write

jobs:
  version:
    uses: ./.github/workflows/reflow-version.yml
    with:
      release_type: ${{ inputs.release_type }}

  build:
    name: Build amd64 RPM
    runs-on: ubuntu-latest
    needs:
      - version
    container:
      image: chianetwork/rocky8-builder:latest
    timeout-minutes: 40
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.10"]
        os:
          - arch-artifact-name: intel

    env:
      CHIA_INSTALLER_VERSION: ${{ needs.version.outputs.chia-installer-version }}
      POETRY_DYNAMIC_VERSIONING_OVERRIDE: "chia-blockchain=${{ needs.version.outputs.chia-installer-version }}"
      TAG_TYPE: ${{ needs.version.outputs.tag-type }}

    steps:
      - name: Add safe git directory
        uses: Chia-Network/actions/git-mark-workspace-safe@main

      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: recursive

      - uses: Chia-Network/actions/git-ssh-to-https@main

      - name: Cleanup any leftovers that exist from previous runs
        run: bash build_scripts/clean-runner.sh || true

      - name: Set Env
        uses: Chia-Network/actions/setjobenv@main
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Get latest madmax plotter
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          LATEST_MADMAX=$(gh api repos/Chia-Network/chia-plotter-madmax/releases/latest --jq 'select(.prerelease == false) | .tag_name')
          mkdir "$GITHUB_WORKSPACE"/madmax
          gh release download -R Chia-Network/chia-plotter-madmax "$LATEST_MADMAX" -p 'chia_plot-*-x86-64' -O "$GITHUB_WORKSPACE"/madmax/chia_plot
          gh release download -R Chia-Network/chia-plotter-madmax "$LATEST_MADMAX" -p 'chia_plot_k34-*-x86-64' -O "$GITHUB_WORKSPACE"/madmax/chia_plot_k34
          chmod +x "$GITHUB_WORKSPACE"/madmax/chia_plot
          chmod +x "$GITHUB_WORKSPACE"/madmax/chia_plot_k34

      - name: Fetch bladebit versions
        shell: bash
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # Fetch the latest version of each type
          LATEST_RELEASE=$(gh api repos/Chia-Network/bladebit/releases/latest --jq 'select(.prerelease == false) | .tag_name')
          LATEST_BETA=$(gh api repos/Chia-Network/bladebit/releases --jq 'map(select(.prerelease) | select(.tag_name | test("^v[0-9]+\\.[0-9]+\\.[0-9]+-beta[0-9]+$"))) | first | .tag_name')
          LATEST_RC=$(gh api repos/Chia-Network/bladebit/releases --jq 'map(select(.prerelease) | select(.tag_name | test("^v[0-9]+\\.[0-9]+\\.[0-9]+-rc[0-9]+$"))) | first | .tag_name')

          # Compare the versions and choose the newest that matches the requirements
          if [[ "$TAG_TYPE" == "beta" || -z "$TAG_TYPE" ]]; then
            # For beta or dev builds (indicated by the absence of a tag), use the latest version available
            LATEST_VERSION=$(printf "%s\n%s\n%s\n" "$LATEST_RELEASE" "$LATEST_BETA" "$LATEST_RC" | sed '/-/!s/$/_/' | sort -V | sed 's/_$//' | tail -n 1)
          elif [[ "$TAG_TYPE" == "rc" ]]; then
            # For RC builds, use the latest RC or full release if it's newer
            LATEST_VERSION=$(printf "%s\n%s\n" "$LATEST_RELEASE" "$LATEST_RC" | sed '/-/!s/$/_/' | sort -V | sed 's/_$//' | tail -n 1)
          else
            # For full releases, use the latest full release
            LATEST_VERSION="$LATEST_RELEASE"
          fi
          echo "LATEST_VERSION=$LATEST_VERSION" >> "$GITHUB_ENV"

      - name: Get latest bladebit plotter
        shell: bash
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # Download and extract the chosen version
          mkdir "$GITHUB_WORKSPACE"/bladebit
          cd "$GITHUB_WORKSPACE"/bladebit
          gh release download -R Chia-Network/bladebit "$LATEST_VERSION" -p 'bladebit*-centos-x86-64.tar.gz'
          find . -maxdepth 1 -name '*.tar.gz' -print0 | xargs -0 -I{} bash -c 'tar -xzf {} && rm {}'
          find . -maxdepth 1 -name 'bladebit*' -print0 | xargs -0 -I{} chmod +x {}
          cd "$OLDPWD"

      - uses: ./.github/actions/install
        with:
          python-version: ${{ matrix.python-version }}
          development: true
          constraints-file-artifact-name: constraints-file-${{ matrix.os.arch-artifact-name }}

      - uses: chia-network/actions/activate-venv@main

      - name: Prepare GUI cache
        id: gui-ref
        run: |
          gui_ref=$(git submodule status chia-blockchain-gui | sed -e 's/^ //g' -e 's/ chia-blockchain-gui.*$//g')
          echo "${gui_ref}"
          echo "GUI_REF=${gui_ref}" >> "$GITHUB_OUTPUT"
          echo "rm -rf ./chia-blockchain-gui"
          rm -rf ./chia-blockchain-gui

      - name: Cache GUI
        uses: actions/cache@v4
        id: cache-gui
        with:
          path: ./chia-blockchain-gui
          key: ${{ runner.os }}-rpm-chia-blockchain-gui-${{ steps.gui-ref.outputs.GUI_REF }}

      - if: steps.cache-gui.outputs.cache-hit != 'true'
        name: Build GUI
        continue-on-error: false
        run: |
          cd ./build_scripts
          bash build_linux_rpm-1-gui.sh

      - name: Build .rpm package
        run: |
          ldd --version
          cd ./build_scripts
          bash build_linux_rpm-2-installer.sh amd64

      - name: Upload fpm-generated rpm spec files
        uses: actions/upload-artifact@v4
        with:
          if-no-files-found: error
          name: spec
          path: |
            build_scripts/dist/cli.spec
            build_scripts/dist/gui.spec

      - name: Upload Linux artifacts
        uses: actions/upload-artifact@v4
        with:
          name: chia-installers-linux-rpm-${{ matrix.os.arch-artifact-name }}
          path: build_scripts/final_installer/

      - name: Remove working files to exclude from cache
        run: |
          rm -rf ./chia-blockchain-gui/packages/gui/daemon

  publish:
    name: 📦 Publish Installers
    uses: ./.github/workflows/reflow-publish-installer.yml
    with:
      concurrency-name: rpm
      chia-installer-version: ${{ needs.version.outputs.chia-installer-version }}
      chia-dev-version: ${{ needs.version.outputs.chia-dev-version }}
      configuration: ${{ toJSON( matrix.configuration ) }}
    secrets: inherit
    needs:
      - version
      - build
    strategy:
      fail-fast: false
      matrix:
        configuration:
          - python-version: ["3.10"]
            os:
              - matrix: redhat
                file-type:
                  name: RPM
                  extension: rpm
                glue-name: rpm
                artifact-platform-name: linux
                file-arch-name:
                  intel: x86_64
                file-suffix:
                  arm: ""
                  intel: ""
                names:
                  cli:
                    file: chia-blockchain-cli-{0}-1.{2}.rpm
                    def-file: chia-blockchain-cli-{1}-1.{2}.rpm
                    latest-dev-file: chia-blockchain-cli-1.{2}_latest_dev.rpm
                  gui:
                    file: chia-blockchain-{0}-1.{2}.rpm
                    def-file: chia-blockchain-{1}-1.{2}.rpm
                    latest-dev-file: chia-blockchain-1.{2}_latest_dev.rpm
            mode:
              - name: GUI
                matrix: gui
                glue-name: gui
              - name: CLI
                matrix: cli
                glue-name: cli
            arch:
              - name: ARM64
                matrix: arm
                artifact-name: arm
                glue-name: arm
              - name: Intel
                matrix: intel
                artifact-name: intel
                glue-name: intel
            exclude:
              - os:
                  matrix: redhat
                arch:
                  matrix: arm

  test:
    name: Test ${{ matrix.distribution.name }} ${{ matrix.mode.name }} ${{ matrix.state.name }}
    runs-on: ${{ matrix.os }}
    needs:
      - version
      - build
    container: ${{ matrix.distribution.url }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest]
        distribution:
          - name: amazonlinux:2023
            type: amazon
            url: "docker://amazonlinux:2023"
          - name: fedora:37
            type: fedora
            # (37, 3.11) https://packages.fedoraproject.org/search?query=python3&releases=Fedora+37&start=0
            url: "docker://fedora:37"
          - name: fedora:38
            type: fedora
            # (38, 3.11) https://packages.fedoraproject.org/search?query=python3&releases=Fedora+38&start=0
            url: "docker://fedora:38"
          - name: rockylinux:8
            type: rocky
            url: "docker://rockylinux:8"
          - name: rockylinux:9
            type: rocky
            url: "docker://rockylinux:9"
            # bypass this error for now: Problem: The operation would result in removing the following protected packages: systemd-udev
            noautoremove:
              gui: --noautoremove
          - name: build image
            type: rocky
            url: "docker://chianetwork/rocky8-builder:latest"
        mode:
          - name: GUI
            matrix: gui
            file: chia-blockchain-[0,1,2,3,4,5,6,7,8,9]*.rpm
            package: chia-blockchain
          - name: CLI
            matrix: cli
            file: chia-blockchain-cli-[0,1,2,3,4,5,6,7,8,9]*.rpm
            package: chia-blockchain-cli
        state:
          - name: Dirty
            matrix: dirty
          - name: Clean
            matrix: clean

    steps:
      - uses: Chia-Network/actions/clean-workspace@main

      - name: Download packages
        uses: actions/download-artifact@v4
        id: download
        with:
          name: chia-installers-linux-rpm-intel
          path: packages

      - name: Dirty the environment for the sake of testing
        if: matrix.state.matrix == 'dirty'
        run: |
          # this has been known to mess up the version detection, the empty directory should be removed
          mkdir --parents /opt/chia/chia_blockchain-0.1.dist-info
          # making sure that files are not removed
          touch /opt/chia/touched

      - name: Install package
        run: |
          ls -l "${{ steps.download.outputs.download-path }}"
          yum install -y numactl-libs "${{ steps.download.outputs.download-path }}"/${{ matrix.mode.file }}

      - name: List /opt/chia contents
        run: |
          find /opt/chia

      - name: Run chia dev installers test
        run: |
          chia dev installers test --require-no-madmax --expected-chia-version "${{ needs.version.outputs.chia-installer-version }}"

      - name: Verify /opt/chia present
        run: |
          if [ ! -e /opt/chia ]
          then
            ls -l /opt
            false
          fi

      - name: Remove package
        run: |
          yum remove -y ${{ matrix.distribution.noautoremove[matrix.mode.matrix] }} ${{ matrix.mode.package }}

      - name: Verify /opt/chia not present
        if: matrix.state.matrix == 'clean'
        run: |
          if [ -e /opt/chia ]
          then
            ls -lR /opt/chia
            false
          fi

      - name: Verify /opt/chia contains only touched file
        if: matrix.state.matrix == 'dirty'
        run: |
          ACTUAL=$(ls -a /opt/chia)
          EXPECTED=$(echo -e '.\n..\ntouched')
          echo "  actual: ${ACTUAL}"
          echo "expected: ${EXPECTED}"
          if [ "${ACTUAL}" != "${EXPECTED}" ]
          then
            echo "  !!! they do not match"
            ls -lR /opt/chia
            false
          else
            echo "  :] they match"
          fi
