name: pkg for platform
run-name: pkging ${{ fromJSON(inputs.pkg).project }} (${{ inputs.name }})

on:
  workflow_call:
    inputs:
      name:
        description: brewkit platform unique ID
        type: string
      tinyname:
        description: >
          GitHub Actions has a non resizable sidebar so we need a shorter name
          or it’s much harder to differentiate the different jobs.
        type: string
        default: ${{ inputs.name }}
      os:
        type: string
      container:
        required: false
        type: string
      pkg:
        description: eg. `example.com@1.2.3`
        type: string
      dry-run:
        description: dry runs do not modify bottle storage
        type: boolean
        default: false
      test-os:
        description: a JSON array of runner-names
        type: string
      test-container:
        description: >
          A JSON array of docker image names or `[null]`.
          Indeed! You cannot leave this as `null` or undefined.
          Sorry, GHA is not flexible enough to efficiently work around this.
        type: string
      complain:
        type: boolean
        default: false
      invalidate-cloudfront:
        type: boolean
        default: true
    secrets:
      APPLE_CERTIFICATE_P12: { required: false }
      APPLE_CERTIFICATE_P12_PASSWORD: { required: false }
      APPLE_IDENTITY: { required: false }
      GPG_KEY_ID: { required: true }
      GPG_PRIVATE_KEY: { required: true }
      AWS_ACCESS_KEY_ID: { required: false }
      AWS_S3_BUCKET: { required: true }
      AWS_SECRET_ACCESS_KEY: { required: true }
      AWS_CF_DISTRIBUTION_ID: { required: true }

env:
  BREWKIT_PKGJSON: ${{ inputs.pkg }}

jobs:
  build:
    name: build ${{inputs.tinyname}}
    runs-on: ${{ fromJSON(inputs.os) }}
    container: ${{ inputs.container }}
    permissions: {}
    outputs:
      project: ${{ steps.build.outputs.project }}
      version: ${{ steps.build.outputs.version }}
      platform: ${{ steps.build.outputs.platform }}
      arch: ${{ steps.build.outputs.arch }}
    env:
      PKGX_PANTRY_PATH: ${{ github.workspace }}
    steps:
      - uses: actions/checkout@v4

      - uses: pkgxdev/setup@v2
        with:
          PKGX_DIR: /opt

      - uses: ./.github/actions/setup
        with:
          p12-file-base64: ${{ secrets.APPLE_CERTIFICATE_P12 }}
          p12-password: ${{ secrets.APPLE_CERTIFICATE_P12_PASSWORD }}
          APPLE_IDENTITY: ${{ secrets.APPLE_IDENTITY }}

      - uses: pkgxdev/brewkit/build@v1
        with:
          pkg: ${{ inputs.pkg }}
        id: build

      - uses: styfle/cancel-workflow-action@0.12.0
        if: steps.build.outputs.noop

      - uses: pkgxdev/brewkit/audit@v1
        with:
          pkg: ${{ inputs.pkg }}

      - uses: pkgxdev/brewkit/upload-build-artifact@v1

  test:
    name: test ${{inputs.tinyname}} ${{ matrix.container || ''}} ${{ matrix.container || '' }} ${{ join(matrix.os, '+') }}
    needs: build
    strategy:
      matrix:
        os: ${{ fromJSON(inputs.test-os) }}
        container: ${{ fromJSON(inputs.test-container) }}
    permissions: {}
    runs-on: ${{ matrix.os }}
    container: ${{ matrix.container }}
    env:
      PKGX_PANTRY_PATH: ${{ github.workspace }}
    steps:
      - uses: pkgxdev/setup@v2
      - uses: actions/checkout@v4
      - uses: pkgxdev/brewkit/download-build-artifact@v1
        with:
          pkg: ${{ inputs.pkg }}
      - uses: pkgxdev/brewkit/test@v1
        with:
          pkg: ${{ inputs.pkg }}

  bottle:
    name: bottle (${{inputs.tinyname}}.${{matrix.compression}})
    needs: [build, test]
    permissions: {}
    strategy:
      matrix:
        compression: [xz, gz]
    runs-on: ubuntu-latest
    env:
      AWS: ${{ inputs.dry-run && 'echo' || 'aws' }}
      PREFIX: ${{ needs.build.outputs.project }}/${{ needs.build.outputs.platform }}/${{ needs.build.outputs.arch }}/v${{ needs.build.outputs.version }}.tar.${{ matrix.compression }}
    steps:
      - uses: pkgxdev/setup@v2

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - name: import GPG key
        run: echo $GPG_PRIVATE_KEY |
          base64 -d |
          pkgx gpg --import --batch --yes
        env:
          GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}

      - uses: pkgxdev/brewkit/download-build-artifact@v1
        id: dl
        with:
          pkg: ${{ inputs.pkg }}
          platform: ${{ inputs.name }}
          extract: false

      - uses: pkgxdev/brewkit/bottle@v1
        id: bottle
        with:
          file: ${{ steps.dl.outputs.filename }}
          compression: ${{ matrix.compression }}

      - name: gpg
        run: pkgx gpg
          --detach-sign
          --armor
          --output ${{ steps.bottle.outputs.filename }}.asc
          --local-user ${{ secrets.GPG_KEY_ID }}
          ${{ steps.bottle.outputs.filename }}

      - name: sha
        run: pkgx
          sha256sum
          ${{ steps.bottle.outputs.filename }} > ${{ steps.bottle.outputs.filename }}.sha256sum

      - name: s3 put
        run: |
          $AWS s3 cp ${{ steps.bottle.outputs.filename }}           $URL
          $AWS s3 cp ${{ steps.bottle.outputs.filename }}.asc       $URL.asc
          $AWS s3 cp ${{ steps.bottle.outputs.filename }}.sha256sum $URL.sha256sum

          echo "cf-paths=/$PREFIX /$PREFIX.asc /$PREFIX.sha256sum" >> $GITHUB_OUTPUT
        env:
          URL: s3://${{ secrets.AWS_S3_BUCKET }}/${{ env.PREFIX }}
        id: put

      - name: s3 put file listing
        if: ${{ matrix.compression == 'gz' }}
        id: files
        run: |
          PREFIX=$(dirname $PREFIX)
          tar tf ${{ steps.bottle.outputs.filename }} \
            | grep -v '/$' \
            | grep -v '^venv/' \
            > $FILENAME
          $AWS s3 cp $FILENAME s3://${{ secrets.AWS_S3_BUCKET }}/$PREFIX/$FILENAME
          echo "cf-paths=/$PREFIX/$FILENAME" >> $GITHUB_OUTPUT
        env:
          FILENAME: v${{ needs.build.outputs.version }}.files.txt

      - name: invalidate cloudfront
        run: $AWS cloudfront create-invalidation
          --distribution-id ${{ secrets.AWS_CF_DISTRIBUTION_ID }}
          --paths
          ${{ steps.put.outputs.cf-paths }} ${{ steps.files.outputs.cf-paths }}
        if: inputs.invalidate-cloudfront

  publish:
    name: publish ${{inputs.tinyname}} ${{ inputs.dry-run && '(dry-run)' }}
    runs-on: ubuntu-latest
    needs: [bottle, build]
    permissions: {}
    env:
      AWS: ${{ inputs.dry-run && 'echo' || 'aws' }}
      DIRNAME: ${{ needs.build.outputs.project }}/${{ needs.build.outputs.platform }}/${{ needs.build.outputs.arch }}
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - uses: pkgxdev/setup@v2

      - name: generate versions.txt
        run: |
          if ! aws s3 cp \
            s3://${{ secrets.AWS_S3_BUCKET }}/$DIRNAME/versions.txt \
            ./remote-versions.txt; then
            touch remote-versions.txt
          fi
          echo "$SCRIPT" > script.ts
          pkgx deno run -A script.ts ./remote-versions.txt ${{ needs.build.outputs.version }} > versions.txt
        env:
          SCRIPT: |
            import SemVer, { compare } from "https://raw.githubusercontent.com/pkgxdev/libpkgx/main/src/utils/semver.ts"
            const versions = new Set(Deno.readTextFileSync(Deno.args[0]).trim().split("\n").filter(x => x))
            versions.add(Deno.args[1])
            const out = [...versions].map(x => new SemVer(x)).sort(compare).join("\n")
            await Deno.stdout.write(new TextEncoder().encode(out.trim()))

      - name: s3 put
        run: $AWS s3 cp versions.txt s3://${{ secrets.AWS_S3_BUCKET }}/$DIRNAME/versions.txt

      - name: invalidate cloudfront
        run: $AWS cloudfront create-invalidation
          --distribution-id ${{ secrets.AWS_CF_DISTRIBUTION_ID }}
          --paths
          /$DIRNAME/versions.txt
        if: inputs.invalidate-cloudfront

  complain:
    needs: bottle
    if: failure() && !inputs.dry-run && inputs.complain
    runs-on: ubuntu-latest
    permissions:
      issues: write
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/complain
        with:
          pkg: ${{ fromJSON(inputs.pkg).project }}=${{ fromJSON(inputs.pkg).version.value }}
