name: ci run-name: >- ci (${{ github.event_name }}${{ github.event_name == 'pull_request' && format(' #{0}', github.event.pull_request.number) || '' }}) # Entry point of every build. It decides what the run is (daily / rc / stable / branch), then calls # one reusable workflow per OS and a final one that publishes the GitHub release. # # push to nx2 touching VERSION stable or rc release, aborted when that tag already exists # schedule daily build of nx2, aborted when nothing changed since the last one # workflow_dispatch branch build of the chosen ref (or a forced daily, from nx2) # pull_request + ci:build label branch build of a same-repo PR, rebuilt on each push on: push: branches: - nx2 paths: - VERSION - CHANGELOG.md schedule: - cron: "0 3 * * *" workflow_dispatch: inputs: kind: description: What to build (daily is only allowed from nx2) type: choice options: [branch, daily] default: branch platforms: description: Which OS builds to run type: choice options: [all, linux, windows, macos] default: all pgo: description: Also build the PGO variants type: choice options: [none, both] default: none publish: description: Publish the binaries as a GitHub pre-release (otherwise only workflow artifacts) type: boolean default: true pull_request: types: [labeled, synchronize, reopened] permissions: contents: read # A running release or daily build is never cancelled: it finishes and publishes, and one newer run # queues behind it. Branch builds are rolling, so a newer push replaces the one in progress. concurrency: # Manual and scheduled daily builds share a group; PR and manual branch builds share a group # for the source branch so they cannot race while replacing the same rolling release. group: ci-${{ (github.event_name == 'pull_request' && (github.event.pull_request.head.repo.full_name != github.repository || (github.event.action == 'labeled' && github.event.label.name != 'ci:build'))) && format('ignored-{0}', github.run_id) || (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.kind == 'daily')) && 'daily-nx2' || (github.event_name == 'pull_request' && format('branch-{0}', github.event.pull_request.head.ref)) || (github.event_name == 'workflow_dispatch' && format('branch-{0}', github.ref_name)) || format('release-{0}', github.ref) }} cancel-in-progress: ${{ github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.kind != 'daily') }} jobs: prepare: name: Prepare scheme if: >- github.event_name != 'pull_request' || ( github.event.pull_request.head.repo.full_name == github.repository && contains(github.event.pull_request.labels.*.name, 'ci:build') && (github.event.action != 'labeled' || github.event.label.name == 'ci:build') ) runs-on: ubuntu-24.04 permissions: contents: read pull-requests: read outputs: kind: ${{ steps.scheme.outputs.kind }} tag: ${{ steps.scheme.outputs.tag }} title: ${{ steps.scheme.outputs.title }} version: ${{ steps.scheme.outputs.version }} refspec: ${{ steps.scheme.outputs.refspec }} sha: ${{ steps.scheme.outputs.sha }} skip: ${{ steps.scheme.outputs.skip }} prerelease: ${{ steps.scheme.outputs.prerelease }} nightly: ${{ steps.scheme.outputs.nightly }} publish: ${{ steps.scheme.outputs.publish }} prev_tag: ${{ steps.scheme.outputs.prev_tag }} branch: ${{ steps.scheme.outputs.branch }} steps: # Run the scheme helper from the trusted default branch. The target commit is fetched as # git data only; PR code must not control outputs that feed the write-enabled release job. - name: Check out trusted CI scripts uses: actions/checkout@v7 with: ref: ${{ github.event.repository.default_branch }} fetch-depth: 0 - name: Resolve build commit id: target shell: bash env: TARGET_SHA: ${{ github.event.pull_request.head.sha || github.sha }} run: | set -euo pipefail if [ "$GITHUB_EVENT_NAME" = schedule ]; then git fetch --no-tags origin nx2:refs/remotes/origin/nx2 sha=$(git rev-parse refs/remotes/origin/nx2) else git fetch --no-tags origin "$TARGET_SHA" sha="$TARGET_SHA" fi git cat-file -e "$sha^{commit}" # The VERSION file belongs to the source commit for a version-triggered push. if [ "$GITHUB_EVENT_NAME" = push ]; then git show "$sha:VERSION" > VERSION git show "$sha:CHANGELOG.md" > CHANGELOG.md fi echo "sha=$sha" >> "$GITHUB_OUTPUT" - name: Prepare scheme id: scheme shell: bash env: GH_TOKEN: ${{ github.token }} INPUT_KIND: ${{ inputs.kind }} INPUT_PUBLISH: ${{ inputs.publish }} PR_HEAD_REF: ${{ github.event.pull_request.head.ref }} PR_TITLE: ${{ github.event.pull_request.title }} BUILD_SHA: ${{ steps.target.outputs.sha }} run: bash tools/ci/prepare.sh linux: name: Linux needs: prepare if: >- needs.prepare.outputs.skip != 'true' && (inputs.platforms == '' || inputs.platforms == 'all' || inputs.platforms == 'linux') uses: ./.github/workflows/build-linux.yml with: sha: ${{ needs.prepare.outputs.sha }} version: ${{ needs.prepare.outputs.version }} refspec: ${{ needs.prepare.outputs.refspec }} tag: ${{ needs.prepare.outputs.tag }} release: ${{ needs.prepare.outputs.kind == 'stable' || needs.prepare.outputs.kind == 'rc' }} nightly: ${{ needs.prepare.outputs.nightly == 'true' }} pgo: ${{ inputs.pgo || (needs.prepare.outputs.kind == 'branch' && 'none' || 'both') }} windows: name: Windows needs: prepare if: >- needs.prepare.outputs.skip != 'true' && (inputs.platforms == '' || inputs.platforms == 'all' || inputs.platforms == 'windows') uses: ./.github/workflows/build-windows.yml with: sha: ${{ needs.prepare.outputs.sha }} version: ${{ needs.prepare.outputs.version }} refspec: ${{ needs.prepare.outputs.refspec }} tag: ${{ needs.prepare.outputs.tag }} release: ${{ needs.prepare.outputs.kind == 'stable' || needs.prepare.outputs.kind == 'rc' }} nightly: ${{ needs.prepare.outputs.nightly == 'true' }} pgo: ${{ inputs.pgo || (needs.prepare.outputs.kind == 'branch' && 'none' || 'both') }} macos: name: macOS needs: prepare if: >- needs.prepare.outputs.skip != 'true' && (inputs.platforms == '' || inputs.platforms == 'all' || inputs.platforms == 'macos') uses: ./.github/workflows/build-macos.yml with: sha: ${{ needs.prepare.outputs.sha }} version: ${{ needs.prepare.outputs.version }} refspec: ${{ needs.prepare.outputs.refspec }} tag: ${{ needs.prepare.outputs.tag }} release: ${{ needs.prepare.outputs.kind == 'stable' || needs.prepare.outputs.kind == 'rc' }} nightly: ${{ needs.prepare.outputs.nightly == 'true' }} runner: ${{ vars.MACOS_RUNNER || 'macos-15' }} # Publishes only when every OS that ran succeeded (skipped OSes don't count). release: name: Publish release needs: [prepare, linux, windows, macos] if: >- always() && needs.prepare.result == 'success' && needs.prepare.outputs.skip != 'true' && needs.prepare.outputs.publish == 'true' && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') permissions: contents: write uses: ./.github/workflows/release.yml secrets: DISCORD_WEBHOOK_URL: ${{ github.event_name != 'pull_request' && secrets.DISCORD_WEBHOOK_URL || '' }} with: kind: ${{ needs.prepare.outputs.kind }} tag: ${{ needs.prepare.outputs.tag }} title: ${{ needs.prepare.outputs.title }} prerelease: ${{ needs.prepare.outputs.prerelease == 'true' }} sha: ${{ needs.prepare.outputs.sha }} prev_tag: ${{ needs.prepare.outputs.prev_tag }} branch: ${{ needs.prepare.outputs.branch }} macos_runner: ${{ vars.MACOS_RUNNER || 'macos-15' }}