🏡 index : quine-global-labs/mirror-ublue-os-packages.git

name: Build packages in CI

on:
  merge_group:
  pull_request:

jobs:
  changed_files:
    runs-on: ubuntu-latest
    name: Get changed files
    outputs:
      all_changed_files: ${{ steps.changed-package-files.outputs.all_changed_files }}
      any_changed: ${{ steps.changed-package-files.outputs.any_changed }}
      specs: ${{ steps.packages.outputs.specs }}
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

      - name: Get directories with spec files
        id: specdirs
        run: |
          set -x
          FILESLIST="./files.txt"
          # The extra xargs there is so that the changed-files action can find all the files
          find . -type f -iname '*.spec' -exec 'dirname' '{}' ';' 2>/dev/null | xargs -I{} echo "{}/**" > $FILESLIST
          echo "fileslist=$FILESLIST" >> $GITHUB_OUTPUT

      - name: Get all changed files from package directores
        id: changed-package-files
        uses: step-security/changed-files@2e07db73e5ccdb319b9a6c7766bd46d39d304bad # v47
        with:
          files_from_source_file: ${{ steps.specdirs.outputs.fileslist }}

      - name: Get all packages that need to be rebuilt
        id: packages
        if: steps.changed-package-files.outputs.any_changed == 'true'
        env:
          ALL_CHANGED_FILES: ${{ steps.changed-package-files.outputs.all_changed_files }}
        run: |
          set -x

          # This is a mess and must be removed at some point, but the general idea is that when you have arbitrary files like:
          # ALL_CHANGED_FILES="packages/chungus/bungus.spec ucore/sanoid.spec staging/gnome-shell/39/gnome-shell.spec"
          # If its a spec dont do anything, just add it to ALL_SPECS
          # If its not a spec try to find an adjencent spec: get its dirname, check if there are any specs, go back 1 directory (...) until you get to 1 folder deep into GITHUB_WORKDIR

          SPEC_DIRS=()
          while IFS= read -r -d $'\0'; do
            SPEC_DIRS+=("$(realpath "--relative-to=${GITHUB_WORKSPACE}" "$(dirname "${REPLY}")")")
          done < <(find . -type f -iname '*.spec' -print0)

          ALL_SPECS=()
          for file in ${ALL_CHANGED_FILES} ; do
            if [ "${file##*.}" == "spec" ] ; then
              ALL_SPECS+=("$(realpath --relative-to="${GITHUB_WORKSPACE}" "${file}")")
              continue
            fi
            # We need this else PRs editing random files wont get the specs building due to not bumping them directly
            # This way we still get the checks although we kinda need the bumped spec on the COPR (will be enforced after build)
            cd "$(dirname "${file}")"
            while : ; do
              pwd
              while IFS=  read -r -d $'\0'; do
                ALL_SPECS+=("$(realpath --relative-to="${GITHUB_WORKSPACE}" "${REPLY}")")
              done < <(find . -maxdepth 1 -type f -iname "*.spec" -print0)
              [[ " ${SPEC_DIRS[*]} " =~ [[:space:]]$(realpath --relative-to="${GITHUB_WORKSPACE}" ${PWD})[[:space:]] ]] && break
              cd ..
            done
            cd "${GITHUB_WORKSPACE}"
          done

          # This is kind of a hack so that we get only unique specs
          IFS=" " read -r -a ALL_SPECS <<< "$(tr ' ' '\n' <<< "${ALL_SPECS[@]}" | sort -u | tr '\n' ' ')"

          MATRIX="{\"specs\":[]}"
          for spec in "${ALL_SPECS[@]}" ; do
            [ -e "$spec" ] && MATRIX=$(jq -c ".specs += [\"$spec\"]" <<< $MATRIX)
          done

          echo "specs=$(jq -r -c '.specs' <<< "${MATRIX}")" >> $GITHUB_OUTPUT

  build_packages:
    runs-on: ${{ matrix.platform == 'amd64' && 'ubuntu-26.04' || 'ubuntu-26.04-arm' }}
    needs: changed_files
    name: Build RPM package
    if: needs.changed_files.outputs.any_changed == 'true'
    strategy:
      fail-fast: false
      matrix:
        platform: ["arm64","amd64"]
        # These are our target environments
        # FIXME: renovate rule for this would be awesome
        chroot: ["fedora-44", "fedora-45", "epel-10"]
        spec: ${{ fromJson(needs.changed_files.outputs.specs) }}
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

      - name: Show container tooling versions
        run: |
          podman --version
          buildah --version
          podman info

      - name: Setup Just
        uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4

      - name: Build ${{ matrix.spec }}
        id: build_package
        env:
          CHROOT: ${{ matrix.chroot }}
          SPEC_FILE: ${{ matrix.spec }}
        run: |
          set -x
          just=$(which just)

          mkdir -p containers
          MOCK_DIR=./mock
          CONTAINERS_DIR=./containers
          SOURCES_DIR=.
          export CONTAINERS_DIR
          # FIXME: this is a quick and dirty workaround, please make this pretty
          UBLUE_OS_ORG="ublue-os"
          COPR_NAMESPACE="${UBLUE_OS_ORG}/$(basename $(dirname $(dirname $SPEC_FILE)))"
          export MOCK_COPRS="https://download.copr.fedorainfracloud.org/results/${COPR_NAMESPACE}/${CHROOT}-$(arch)"
          if ! $just build ${SPEC_FILE} -r ${CHROOT}-$(arch) ; then
            echo "Retrying with a network connection"
            $just build ${SPEC_FILE} -r ${CHROOT}-$(arch) --enable-network
          fi
          SKIPPED_ARCH=false
          if [ -e "$SOURCES_DIR/arch_skipped" ] ; then
            SKIPPED_ARCH=true
          fi
          sudo chown -R $(id -u):$(id -g) $MOCK_DIR
          echo "mock_dir=$MOCK_DIR" >> "$GITHUB_OUTPUT"
          echo "containers_dir=$CONTAINERS_DIR" >> "$GITHUB_OUTPUT"
          echo "sources_dir=$SOURCES_DIR" >> "$GITHUB_OUTPUT"
          echo "skipped_arch=$SKIPPED_ARCH" >> "$GITHUB_OUTPUT"
          echo "package=$(basename "${{ matrix.spec }}" ".spec")" >> "$GITHUB_OUTPUT"

      - name: Upload to Job Artifacts
        if: steps.build_package.outputs.skipped_arch == 'false'
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
        with:
          name: ${{ matrix.chroot }}-${{ matrix.platform }}-${{ steps.build_package.outputs.package }}
          if-no-files-found: error
          path: |
            ${{ steps.build_package.outputs.mock_dir }}/**/*.rpm

  check:
    name: Check all builds successful
    if: always()
    runs-on: ubuntu-latest
    needs: [build_packages]
    steps:
      - name: Check Jobs
        env:
          JOBS: ${{ toJson(needs) }}
        run: |
          echo "Job status:"
          echo $JOBS | jq -r 'to_entries[] | " - \(.key): \(.value.result)"'

          for i in $(echo $JOBS | jq -r 'to_entries[] | .value.result'); do
            if [ "$i" != "success" ] && [ "$i" != "skipped" ]; then
              echo ""
              echo "Status check not okay!"
              exit 1
            fi
          done