diff --git a/.github/download_build.sh b/.github/download_build.sh new file mode 100755 index 0000000000..4a2f53fae1 --- /dev/null +++ b/.github/download_build.sh @@ -0,0 +1,38 @@ +#!/bin/bash -e + +[ $# -ne 3 ] && { echo "Usage: $0 " >&2; exit 1; } +VERSION="$1" +BUILD_NAME="$2" +DEST_FILE="$3" +[ -z "$BUILDKITE_TOKEN" ] && { echo "BUILDKITE_TOKEN not set." >&2; exit 1; } + +API_BASE="https://api.buildkite.com/v2" +ORG="julialang" + +if [ "$VERSION" = "master" ]; then + PIPELINE="julia-master" + BRANCH="master" + BRANCH_FILTER='.branch == "master"' +else + PIPELINE="julia-release-${VERSION//./-dot-}" + BRANCH="release-$VERSION" + BRANCH_FILTER="(.branch == \"release-$VERSION\") or (.branch | startswith(\"v$VERSION\"))" +fi + +ARTIFACTS_URL=$(curl -s -H "Authorization: Bearer $BUILDKITE_TOKEN" \ + "$API_BASE/organizations/$ORG/pipelines/$PIPELINE/builds?per_page=10&branch=$BRANCH" | \ + jq -r "first(.[] | select($BRANCH_FILTER) | .jobs[] | select(.step_key == \"$BUILD_NAME\" and .exit_status == 0) | .artifacts_url)") +if [ -z "$ARTIFACTS_URL" ] || [ "$ARTIFACTS_URL" = "null" ]; then + echo "No successful build found." + exit 1 +fi + +ARTIFACT_URL=$(curl -s -H "Authorization: Bearer $BUILDKITE_TOKEN" "$ARTIFACTS_URL" | \ + jq -r '.[0].download_url') +if [ -z "$ARTIFACT_URL" ] || [ "$ARTIFACT_URL" = "null" ]; then + echo "No artifact found." + exit 1 +fi + +curl -s -L -H "Authorization: Bearer $BUILDKITE_TOKEN" -o "$DEST_FILE" "$ARTIFACT_URL" +echo "Artifact downloaded as $DEST_FILE" diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 946f9e172d..3799f76339 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -34,7 +34,7 @@ concurrency: jobs: test: timeout-minutes: 120 - name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ matrix.libEnzyme }} libEnzyme - assertions=${{ matrix.assertions }} llvm_args=${{ matrix.llvm_args }} - ${{ github.event_name }} + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ matrix.libEnzyme }} libEnzyme - llvm_args=${{ matrix.llvm_args }} - ${{ github.event_name }} runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -52,8 +52,6 @@ jobs: - '' arch: - default - assertions: - - false libEnzyme: [local, packaged] exclude: - os: windows-latest @@ -64,58 +62,17 @@ jobs: arch: x86 libEnzyme: packaged version: '1.10' - assertions: false - - os: ubuntu-24.04 - arch: default - libEnzyme: packaged - version: '1.10' - assertions: true - - os: ubuntu-24.04 - arch: default - libEnzyme: packaged - version: '1.11' - assertions: true - - os: ubuntu-24.04 - arch: default - libEnzyme: packaged - version: '1.12' - assertions: true - - os: ubuntu-24.04 - arch: default - libEnzyme: packaged - version: '1.13' - assertions: true - - os: ubuntu-24.04 - arch: default - libEnzyme: packaged - version: '1.10' - assertions: true - llvm_args: '--opaque-pointers' - os: ubuntu-24.04 arch: default libEnzyme: packaged version: '1.11' - assertions: false llvm_args: '--opaque-pointers' steps: - uses: actions/checkout@v6 - uses: julia-actions/setup-julia@v3 - if: ${{ ! matrix.assertions }} with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: actions/checkout@v6 - if: ${{ matrix.assertions }} - with: - repository: 'JuliaLang/julia' - ref: release-${{ matrix.version }} - path: 'julia' - - name: Compile Julia - if: ${{ matrix.assertions }} - run: | - sed -i.bak 's/exit 2/exit 0/g' julia/deps/tools/jlchecksum - make -C julia -j $(nproc) FORCE_ASSERTIONS=1 LLVM_ASSERTIONS=1 JULIA_PRECOMPILE=0 - echo $PWD/julia/usr/bin >> $GITHUB_PATH - uses: julia-actions/cache@v3 - name: add EnzymeCore EnzymeTestUtils shell: julia --color=yes --project=. {0} @@ -164,7 +121,7 @@ jobs: id: run_tests # TODO restore coverage post https://github.com/JuliaGPU/GPUCompiler.jl/pull/711 with: - coverage: ${{ matrix.version != '1.11' || !matrix.assertions }} + coverage: true test_args: ${{ env.runtest_test_args }} env: JULIA_PKG_SERVER_REGISTRY_PREFERENCE: eager diff --git a/.github/workflows/GetAsserts.yml b/.github/workflows/GetAsserts.yml new file mode 100644 index 0000000000..a6eae2fd41 --- /dev/null +++ b/.github/workflows/GetAsserts.yml @@ -0,0 +1,46 @@ +name: GetAsserts + +# This workflow downloads Julia assert builds using the BUILDKITE_TOKEN secret. +# It never checks out PR code, so the secret cannot be exfiltrated. +# The builds are passed as artifacts to the TestAsserts workflow. + +on: + push: + branches: [main, master] + tags: ["*"] + pull_request_target: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + download: + name: Download Julia ${{ matrix.version }} (${{ matrix.build }}) + runs-on: ubuntu-latest + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + version: ['master', '1.11', '1.12', '1.13'] + build: ['x86_64-linux-gnuassert'] + steps: + # Only checks out the base branch (never PR code) + - uses: actions/checkout@v6 + + - name: Download Julia + env: + BUILDKITE_TOKEN: ${{ secrets.BUILDKITE_TOKEN }} + run: | + ./.github/download_build.sh "${{ matrix.version }}" "build_${{ matrix.build }}" julia.tar.gz + + - name: Upload Julia build + uses: actions/upload-artifact@v7 + with: + name: julia-${{ matrix.version }}-${{ matrix.build }} + path: julia.tar.gz + retention-days: 1 diff --git a/.github/workflows/TestAsserts.yml b/.github/workflows/TestAsserts.yml new file mode 100644 index 0000000000..fe5de59ea0 --- /dev/null +++ b/.github/workflows/TestAsserts.yml @@ -0,0 +1,136 @@ +name: TestAsserts + +# This workflow runs tests using assert builds downloaded by GetAsserts. +# It does not use any secrets (BUILDKITE_TOKEN access is confined to GetAsserts). + +on: + workflow_run: + workflows: ["GetAsserts"] + types: + - completed + +permissions: + contents: read + # needed to report check runs since workflow_run can't report back to PRs natively + checks: write + +concurrency: + group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }} + cancel-in-progress: true + +jobs: + test: + name: Julia ${{ matrix.version }} ${{ matrix.llvm_args }} (assert) - Linux + runs-on: ubuntu-latest + timeout-minutes: 120 + if: github.event.workflow_run.conclusion == 'success' + strategy: + fail-fast: false + matrix: + include: + - version: 'master' + build: 'x86_64-linux-gnuassert' + llvm_args: '' + - version: '1.11' + build: 'x86_64-linux-gnuassert' + llvm_args: '--opaque-pointers' + - version: '1.11' + build: 'x86_64-linux-gnuassert' + llvm_args: '' + - version: '1.12' + build: 'x86_64-linux-gnuassert' + llvm_args: '' + - version: '1.13' + build: 'x86_64-linux-gnuassert' + llvm_args: '' + steps: + - name: Report in-progress + uses: actions/github-script@v9 + with: + script: | + await github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head_sha: '${{ github.event.workflow_run.head_sha }}', + name: 'Julia ${{ matrix.version }} ${{ matrix.llvm_args }} (assert) - Linux', + status: 'in_progress', + details_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, + }); + + - name: Download Julia build + uses: actions/download-artifact@v8 + with: + name: julia-${{ matrix.version }}-${{ matrix.build }} + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ github.token }} + + - name: Install Julia + run: | + tar -xf julia.tar.gz -C ../ + rm julia.tar.gz + echo $PWD/../julia-*/bin >> $GITHUB_PATH + + - uses: actions/checkout@v6 + with: + ref: ${{ github.event.workflow_run.head_sha }} + fetch-depth: 0 + + - uses: julia-actions/cache@v3 + - uses: julia-actions/julia-buildpkg@v1 + + - name: Run tests + run: julia --project -e 'using Pkg; Pkg.test(; coverage=true)' + env: + JULIA_LLVM_ARGS: ${{ matrix.llvm_args }} + + - name: Report check run + if: always() + uses: actions/github-script@v9 + with: + script: | + await github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head_sha: '${{ github.event.workflow_run.head_sha }}', + name: 'Julia ${{ matrix.version }} ${{ matrix.llvm_args }} (assert) - Linux', + status: 'completed', + conclusion: '${{ job.status }}', + details_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, + output: { + title: 'Assert build test ${{ job.status }}', + summary: 'Tested against `${{ matrix.build }}` build of Julia ${{ matrix.version }}.' + } + }); + + report-failure: + name: Report download failure + runs-on: ubuntu-latest + if: github.event.workflow_run.conclusion == 'failure' + steps: + - name: Report check runs + uses: actions/github-script@v9 + with: + script: | + // Keep in sync with the matrix above + const entries = [ + {version: 'master', llvm_args: ''}, + {version: '1.11', llvm_args: '--opaque-pointers'}, + {version: '1.11', llvm_args: ''}, + {version: '1.12', llvm_args: ''}, + {version: '1.13', llvm_args: ''}, + ]; + await Promise.all(entries.map(({version, llvm_args}) => + github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head_sha: '${{ github.event.workflow_run.head_sha }}', + name: `Julia ${version} ${llvm_args} (assert) - Linux`, + status: 'completed', + conclusion: 'failure', + details_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${{ github.event.workflow_run.id }}`, + output: { + title: 'Assert build download failed', + summary: 'The GetAsserts workflow failed to download the Julia build.' + } + }) + ));