name: CI

on:  # We are very liberal in terms of triggering builds. This should be revisited if we start seeing a lot of queueing
  - push
  - pull_request

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  build-jars:
    runs-on: ubuntu-latest
    name: build / jars
    steps:
      - name: Checkout sources
        uses: actions/checkout@v4
      - name: Build JARs
        run: make jar
      - name: Upload JARs
        uses: actions/upload-artifact@v4
        with:
          name: async-profiler-jars
          path: build/jar/*
          if-no-files-found: error

  build-linux-arm64:
    name: build / linux-arm64
    uses: ./.github/workflows/build.yml
    with:
      platform: linux-arm64
      runner: ubuntu-24.04-arm
      container-image: "arm:latest"

  build-linux-x64:
    name: build / linux-x64
    uses: ./.github/workflows/build.yml
    with:
      platform: linux-x64
      runner: ubuntu-latest
      container-image: x86:latest

  build-macos:
    name: build / macos
    uses: ./.github/workflows/build.yml
    with:
      platform: macos
      runner: macos-15

  integ-linux-x64:
    name: integ / linux-x64
    needs: build-linux-x64
    strategy:
      fail-fast: false
      matrix:
        test-platform: [linux-x64]
        java-version: [8, 11, 17, 21, 25]
        java-distribution: [corretto]
        container-image: [x86:latest]
        include:
          - test-platform: linux-x64-alpine
            container-image: alpine:corretto-11
            use-builtin-jdk: true
            java-distribution: corretto
            java-version: 11
          - test-platform: linux-x64-AL2
            container-image: amazonlinux:2
            # GHA provides Node.js by attaching a volume to the container. The container path is
            # '/__e/node20', and it's not writable unless we override it via 'container.volumes'.
            container-volumes: '["/tmp/node20:/__e/node20"]'
            java-version: 11
            java-distribution: corretto
          - test-platform: linux-x64-AL2023
            container-image: amazonlinux:2023
            java-version: 11
            java-distribution: corretto
          - test-platform: linux-x64-alpaquita
            container-image: alpaquita:x86_64-liberica-21
            use-builtin-jdk: true
            java-distribution: liberica
            java-version: 21
    uses: ./.github/workflows/integ.yml
    with:
      platform: linux-x64
      test-platform: ${{ matrix.test-platform }}
      runner: ubuntu-latest
      container-image: ${{ matrix.container-image }}
      container-volumes: ${{ matrix.container-volumes || '' }}
      java-version: ${{ matrix.java-version }}
      java-distribution: ${{ matrix.java-distribution }}
      use-builtin-jdk: ${{ matrix.use-builtin-jdk || false }}

  integ-linux-arm64:
    name: integ / linux-arm64
    needs: build-linux-arm64
    strategy:
      fail-fast: false
      matrix:
        test-platform: [linux-arm64]
        java-version: [8, 11, 17, 21, 25]
        java-distribution: [corretto]
        container-image: [arm:latest]
    uses: ./.github/workflows/integ.yml
    with:
      platform: linux-arm64
      test-platform: ${{ matrix.test-platform }}
      runner: ubuntu-24.04-arm
      container-image: ${{ matrix.container-image }}
      container-volumes: ${{ matrix.container-volumes || '' }}
      java-version: ${{ matrix.java-version }}
      java-distribution: ${{ matrix.java-distribution }}

  integ-macos:
    name: integ / macos
    needs: build-macos
    strategy:
      fail-fast: false
      matrix:
        include:
          - runner: macos-15
            test-platform: macos-arm64
            java-version: "11"
          - runner: macos-15
            test-platform: macos-arm64
            java-version: "21"
          - runner: macos-15-intel
            test-platform: macos-x64
            java-version: "17"
            architecture: x64
            retry-count: 1
    uses: ./.github/workflows/integ.yml
    with:
      platform: macos
      test-platform: ${{ matrix.test-platform }}
      runner: ${{ matrix.runner }}
      java-version: ${{ matrix.java-version }}
      architecture: ${{ matrix.architecture || '' }}
      retry-count: ${{ matrix.retry-count || 0 }}

  publish-only-on-push:
    if: github.event_name == 'push' && github.ref == 'refs/heads/master'
    permissions:
      contents: write
    name: publish (nightly)
    runs-on: ubuntu-latest
    needs: [build-jars, integ-linux-x64, integ-linux-arm64, integ-macos]
    steps:
      - name: Download async-profiler binaries and jars
        uses: actions/download-artifact@v4
        with:
          pattern: 'async-profiler-*'
          merge-multiple: 'true'
      - name: Delete previous release and publish new release
        uses: actions/github-script@v7
        with:
          result-encoding: string
          script: |
            const fs = require('fs').promises;
            const commonOptions = {
              owner: "async-profiler",
              repo: "async-profiler",
            };
            let previousRelease = undefined;
            try {
              previousRelease = await github.rest.repos.getReleaseByTag({
                ...commonOptions,
                tag: "nightly",
              });
            } catch (e) {
              console.log("No previous nightly release");
              // ignore, there was no previous nightly release
            }
            if (previousRelease !== undefined) {
              // delete previous release and nightly tag
              await github.rest.repos.deleteRelease({
                ...commonOptions,
                release_id: previousRelease.data.id,
              });
              await github.rest.git.deleteRef({...commonOptions, ref: "tags/nightly"});
            }
            // create draft release
            const newReleaseId = (await github.rest.repos.createRelease({
              ...commonOptions,
              tag_name: "nightly",
              target_commitish: "${{ github.sha }}",
              name: "Nightly builds",
              body: "Async-profiler binaries published automatically from the latest sources in `master` upon a successful build.",
              prerelease: true,
              draft: true,
            })).data.id;
            // upload binaries and jars to draft release
            for (const archiveName of await fs.readdir(process.cwd())) {
              await github.rest.repos.uploadReleaseAsset({
                ...commonOptions,
                release_id: newReleaseId,
                name: archiveName,
                data: await fs.readFile(archiveName),
              });
            }
            // publish release
            await github.rest.repos.updateRelease({
              ...commonOptions,
              release_id: newReleaseId,
              draft: false,
            });
