ci.yml

  1name: CI
  2
  3on:
  4  push:
  5    tags:
  6      - "v*"
  7
  8concurrency:
  9  # Allow only one workflow per any non-`main` branch.
 10  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
 11  cancel-in-progress: true
 12
 13env:
 14  CARGO_TERM_COLOR: always
 15  CARGO_INCREMENTAL: 0
 16  RUST_BACKTRACE: 1
 17  DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
 18  DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
 19  ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
 20  ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
 21
 22jobs:
 23  job_spec:
 24    name: Decide which jobs to run
 25    if: github.repository_owner == 'zed-industries'
 26    outputs:
 27      run_tests: ${{ steps.filter.outputs.run_tests }}
 28      run_license: ${{ steps.filter.outputs.run_license }}
 29      run_docs: ${{ steps.filter.outputs.run_docs }}
 30      run_nix: ${{ steps.filter.outputs.run_nix }}
 31      run_actionlint: ${{ steps.filter.outputs.run_actionlint }}
 32    runs-on:
 33      - namespace-profile-2x4-ubuntu-2404
 34    steps:
 35      - name: Checkout repo
 36        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
 37        with:
 38          # 350 is arbitrary; ~10days of history on main (5secs); full history is ~25secs
 39          fetch-depth: ${{ github.ref == 'refs/heads/main' && 2 || 350 }}
 40      - name: Fetch git history and generate output filters
 41        id: filter
 42        run: |
 43          if [ -z "$GITHUB_BASE_REF" ]; then
 44            echo "Not in a PR context (i.e., push to main/stable/preview)"
 45            COMPARE_REV="$(git rev-parse HEAD~1)"
 46          else
 47            echo "In a PR context comparing to pull_request.base.ref"
 48            git fetch origin "$GITHUB_BASE_REF" --depth=350
 49            COMPARE_REV="$(git merge-base "origin/${GITHUB_BASE_REF}" HEAD)"
 50          fi
 51          CHANGED_FILES="$(git diff --name-only "$COMPARE_REV" ${{ github.sha }})"
 52
 53          # Specify anything which should potentially skip full test suite in this regex:
 54          # - docs/
 55          # - script/update_top_ranking_issues/
 56          # - .github/ISSUE_TEMPLATE/
 57          # - .github/workflows/  (except .github/workflows/ci.yml)
 58          SKIP_REGEX='^(docs/|script/update_top_ranking_issues/|\.github/(ISSUE_TEMPLATE|workflows/(?!ci)))'
 59
 60          echo "$CHANGED_FILES" | grep -qvP "$SKIP_REGEX" && \
 61            echo "run_tests=true" >> "$GITHUB_OUTPUT" || \
 62            echo "run_tests=false" >> "$GITHUB_OUTPUT"
 63
 64          echo "$CHANGED_FILES" | grep -qP '^docs/' && \
 65            echo "run_docs=true" >> "$GITHUB_OUTPUT" || \
 66            echo "run_docs=false" >> "$GITHUB_OUTPUT"
 67
 68          echo "$CHANGED_FILES" | grep -qP '^\.github/(workflows/|actions/|actionlint.yml)' && \
 69            echo "run_actionlint=true" >> "$GITHUB_OUTPUT" || \
 70            echo "run_actionlint=false" >> "$GITHUB_OUTPUT"
 71
 72          echo "$CHANGED_FILES" | grep -qP '^(Cargo.lock|script/.*licenses)' && \
 73            echo "run_license=true" >> "$GITHUB_OUTPUT" || \
 74            echo "run_license=false" >> "$GITHUB_OUTPUT"
 75
 76          echo "$CHANGED_FILES" | grep -qP '^(nix/|flake\.|Cargo\.|rust-toolchain.toml|\.cargo/config.toml)' && \
 77            echo "$GITHUB_REF_NAME" | grep -qvP '^v[0-9]+\.[0-9]+\.[0-9x](-pre)?$' && \
 78            echo "run_nix=true" >> "$GITHUB_OUTPUT" || \
 79            echo "run_nix=false" >> "$GITHUB_OUTPUT"
 80
 81  migration_checks:
 82    name: Check Postgres and Protobuf migrations, mergability
 83    needs: [job_spec]
 84    if: |
 85      github.repository_owner == 'zed-industries' &&
 86      needs.job_spec.outputs.run_tests == 'true'
 87    timeout-minutes: 60
 88    runs-on:
 89      - self-mini-macos
 90    steps:
 91      - name: Checkout repo
 92        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
 93        with:
 94          clean: false
 95          fetch-depth: 0 # fetch full history
 96
 97      - name: Remove untracked files
 98        run: git clean -df
 99
100      - name: Find modified migrations
101        shell: bash -euxo pipefail {0}
102        run: |
103          export SQUAWK_GITHUB_TOKEN=${{ github.token }}
104          . ./script/squawk
105
106      - name: Ensure fresh merge
107        shell: bash -euxo pipefail {0}
108        run: |
109          if [ -z "$GITHUB_BASE_REF" ];
110          then
111            echo "BUF_BASE_BRANCH=$(git merge-base origin/main HEAD)" >> "$GITHUB_ENV"
112          else
113            git checkout -B temp
114            git merge -q "origin/$GITHUB_BASE_REF" -m "merge main into temp"
115            echo "BUF_BASE_BRANCH=$GITHUB_BASE_REF" >> "$GITHUB_ENV"
116          fi
117
118      - uses: bufbuild/buf-setup-action@v1
119        with:
120          version: v1.29.0
121      - uses: bufbuild/buf-breaking-action@v1
122        with:
123          input: "crates/proto/proto/"
124          against: "https://github.com/${GITHUB_REPOSITORY}.git#branch=${BUF_BASE_BRANCH},subdir=crates/proto/proto/"
125
126  style:
127    timeout-minutes: 60
128    name: Check formatting and spelling
129    needs: [job_spec]
130    if: github.repository_owner == 'zed-industries'
131    runs-on:
132      - namespace-profile-4x8-ubuntu-2204
133    steps:
134      - name: Checkout repo
135        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
136
137      - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
138        with:
139          version: 9
140
141      - name: Prettier Check on /docs
142        working-directory: ./docs
143        run: |
144          pnpm dlx "prettier@${PRETTIER_VERSION}" . --check || {
145            echo "To fix, run from the root of the Zed repo:"
146            echo "  cd docs && pnpm dlx prettier@${PRETTIER_VERSION} . --write && cd .."
147            false
148          }
149        env:
150          PRETTIER_VERSION: 3.5.0
151
152      - name: Prettier Check on default.json
153        run: |
154          pnpm dlx "prettier@${PRETTIER_VERSION}" assets/settings/default.json --check || {
155            echo "To fix, run from the root of the Zed repo:"
156            echo "  pnpm dlx prettier@${PRETTIER_VERSION} assets/settings/default.json --write"
157            false
158          }
159        env:
160          PRETTIER_VERSION: 3.5.0
161
162      # To support writing comments that they will certainly be revisited.
163      - name: Check for todo! and FIXME comments
164        run: script/check-todos
165
166      - name: Check modifier use in keymaps
167        run: script/check-keymaps
168
169      - name: Run style checks
170        uses: ./.github/actions/check_style
171
172      - name: Check for typos
173        uses: crate-ci/typos@80c8a4945eec0f6d464eaf9e65ed98ef085283d1 # v1.38.1
174        with:
175          config: ./typos.toml
176
177  check_docs:
178    timeout-minutes: 60
179    name: Check docs
180    needs: [job_spec]
181    if: |
182      github.repository_owner == 'zed-industries' &&
183      (needs.job_spec.outputs.run_tests == 'true' || needs.job_spec.outputs.run_docs == 'true')
184    runs-on:
185      - namespace-profile-8x16-ubuntu-2204
186    steps:
187      - name: Checkout repo
188        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
189        with:
190          clean: false
191
192      - name: Configure CI
193        run: |
194          mkdir -p ./../.cargo
195          cp ./.cargo/ci-config.toml ./../.cargo/config.toml
196
197      - name: Build docs
198        uses: ./.github/actions/build_docs
199
200  actionlint:
201    runs-on: namespace-profile-2x4-ubuntu-2404
202    if: github.repository_owner == 'zed-industries' && needs.job_spec.outputs.run_actionlint == 'true'
203    needs: [job_spec]
204    steps:
205      - uses: actions/checkout@v4
206      - name: Download actionlint
207        id: get_actionlint
208        run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
209        shell: bash
210      - name: Check workflow files
211        run: ${{ steps.get_actionlint.outputs.executable }} -color
212        shell: bash
213
214  macos_tests:
215    timeout-minutes: 60
216    name: (macOS) Run Clippy and tests
217    needs: [job_spec]
218    if: |
219      github.repository_owner == 'zed-industries' &&
220      needs.job_spec.outputs.run_tests == 'true'
221    runs-on:
222      - self-mini-macos
223    steps:
224      - name: Checkout repo
225        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
226        with:
227          clean: false
228
229      - name: Configure CI
230        run: |
231          mkdir -p ./../.cargo
232          cp ./.cargo/ci-config.toml ./../.cargo/config.toml
233
234      - name: Check that Cargo.lock is up to date
235        run: |
236          cargo update --locked --workspace
237
238      - name: cargo clippy
239        run: ./script/clippy
240
241      - name: Install cargo-machete
242        uses: clechasseur/rs-cargo@8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386 # v2
243        with:
244          command: install
245          args: cargo-machete@0.7.0
246
247      - name: Check unused dependencies
248        uses: clechasseur/rs-cargo@8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386 # v2
249        with:
250          command: machete
251
252      - name: Check licenses
253        run: |
254          script/check-licenses
255          if [[ "${{ needs.job_spec.outputs.run_license }}" == "true" ]]; then
256            script/generate-licenses /tmp/zed_licenses_output
257          fi
258
259      - name: Check for new vulnerable dependencies
260        if: github.event_name == 'pull_request'
261        uses: actions/dependency-review-action@67d4f4bd7a9b17a0db54d2a7519187c65e339de8 # v4
262        with:
263          license-check: false
264
265      - name: Run tests
266        uses: ./.github/actions/run_tests
267
268      - name: Build collab
269        # we should do this on a linux x86 machinge
270        run: cargo build -p collab
271
272      - name: Build other binaries and features
273        run: |
274          cargo build --workspace --bins --examples
275
276      # Since the macOS runners are stateful, so we need to remove the config file to prevent potential bug.
277      - name: Clean CI config file
278        if: always()
279        run: rm -rf ./../.cargo
280
281  linux_tests:
282    timeout-minutes: 60
283    name: (Linux) Run Clippy and tests
284    needs: [job_spec]
285    if: |
286      github.repository_owner == 'zed-industries' &&
287      needs.job_spec.outputs.run_tests == 'true'
288    runs-on:
289      - namespace-profile-16x32-ubuntu-2204
290    steps:
291      - name: Add Rust to the PATH
292        run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
293
294      - name: Checkout repo
295        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
296        with:
297          clean: false
298
299      - name: Cache dependencies
300        uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
301        with:
302          save-if: ${{ github.ref == 'refs/heads/main' }}
303          # cache-provider: "buildjet"
304
305      - name: Install Linux dependencies
306        run: ./script/linux
307
308      - name: Configure CI
309        run: |
310          mkdir -p ./../.cargo
311          cp ./.cargo/ci-config.toml ./../.cargo/config.toml
312
313      - name: cargo clippy
314        run: ./script/clippy
315
316      - name: Run tests
317        uses: ./.github/actions/run_tests
318
319      - name: Build other binaries and features
320        run: |
321          cargo build -p zed
322          cargo check -p workspace
323          cargo check -p gpui --examples
324
325      # Even the Linux runner is not stateful, in theory there is no need to do this cleanup.
326      # But, to avoid potential issues in the future if we choose to use a stateful Linux runner and forget to add code
327      # to clean up the config file, I’ve included the cleanup code here as a precaution.
328      # While it’s not strictly necessary at this moment, I believe it’s better to err on the side of caution.
329      - name: Clean CI config file
330        if: always()
331        run: rm -rf ./../.cargo
332
333  doctests:
334    # Nextest currently doesn't support doctests, so run them separately and in parallel.
335    timeout-minutes: 60
336    name: (Linux) Run doctests
337    needs: [job_spec]
338    if: |
339      github.repository_owner == 'zed-industries' &&
340      needs.job_spec.outputs.run_tests == 'true'
341    runs-on:
342      - namespace-profile-16x32-ubuntu-2204
343    steps:
344      - name: Add Rust to the PATH
345        run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
346
347      - name: Checkout repo
348        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
349        with:
350          clean: false
351
352      - name: Cache dependencies
353        uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
354        with:
355          save-if: ${{ github.ref == 'refs/heads/main' }}
356          # cache-provider: "buildjet"
357
358      - name: Install Linux dependencies
359        run: ./script/linux
360
361      - name: Configure CI
362        run: |
363          mkdir -p ./../.cargo
364          cp ./.cargo/ci-config.toml ./../.cargo/config.toml
365
366      - name: Run doctests
367        run: cargo test --workspace --doc --no-fail-fast
368
369      - name: Clean CI config file
370        if: always()
371        run: rm -rf ./../.cargo
372
373  build_remote_server:
374    timeout-minutes: 60
375    name: (Linux) Build Remote Server
376    needs: [job_spec]
377    if: |
378      github.repository_owner == 'zed-industries' &&
379      needs.job_spec.outputs.run_tests == 'true'
380    runs-on:
381      - namespace-profile-16x32-ubuntu-2204
382    steps:
383      - name: Add Rust to the PATH
384        run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
385
386      - name: Checkout repo
387        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
388        with:
389          clean: false
390
391      - name: Cache dependencies
392        uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
393        with:
394          save-if: ${{ github.ref == 'refs/heads/main' }}
395          # cache-provider: "buildjet"
396
397      - name: Install Clang & Mold
398        run: ./script/remote-server && ./script/install-mold 2.34.0
399
400      - name: Configure CI
401        run: |
402          mkdir -p ./../.cargo
403          cp ./.cargo/ci-config.toml ./../.cargo/config.toml
404
405      - name: Build Remote Server
406        run: cargo build -p remote_server
407
408      - name: Clean CI config file
409        if: always()
410        run: rm -rf ./../.cargo
411
412  windows_tests:
413    timeout-minutes: 60
414    name: (Windows) Run Clippy and tests
415    needs: [job_spec]
416    if: |
417      github.repository_owner == 'zed-industries' &&
418      needs.job_spec.outputs.run_tests == 'true'
419    runs-on: [self-32vcpu-windows-2022]
420    steps:
421      - name: Environment Setup
422        run: |
423          $RunnerDir = Split-Path -Parent $env:RUNNER_WORKSPACE
424          Write-Output `
425            "RUSTUP_HOME=$RunnerDir\.rustup" `
426            "CARGO_HOME=$RunnerDir\.cargo" `
427            "PATH=$RunnerDir\.cargo\bin;$env:PATH" `
428          >> $env:GITHUB_ENV
429
430      - name: Checkout repo
431        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
432        with:
433          clean: false
434
435      - name: Configure CI
436        run: |
437          New-Item -ItemType Directory -Path "./../.cargo" -Force
438          Copy-Item -Path "./.cargo/ci-config.toml" -Destination "./../.cargo/config.toml"
439
440      - name: cargo clippy
441        run: |
442          .\script\clippy.ps1
443
444      - name: Run tests
445        uses: ./.github/actions/run_tests_windows
446
447      - name: Build Zed
448        run: cargo build
449
450      - name: Limit target directory size
451        run: ./script/clear-target-dir-if-larger-than.ps1 250
452
453      - name: Clean CI config file
454        if: always()
455        run: Remove-Item -Recurse -Path "./../.cargo" -Force -ErrorAction SilentlyContinue
456
457  tests_pass:
458    name: Tests Pass
459    runs-on: namespace-profile-2x4-ubuntu-2404
460    needs:
461      - job_spec
462      - style
463      - check_docs
464      - actionlint
465      - migration_checks
466      # run_tests: If adding required tests, add them here and to script below.
467      - linux_tests
468      - build_remote_server
469      - macos_tests
470      - windows_tests
471    if: |
472      github.repository_owner == 'zed-industries' &&
473      always()
474    steps:
475      - name: Check all tests passed
476        run: |
477          # Check dependent jobs...
478          RET_CODE=0
479          # Always check style
480          [[ "${{ needs.style.result }}"      != 'success' ]] && { RET_CODE=1; echo "style tests failed"; }
481
482          if [[ "${{ needs.job_spec.outputs.run_docs }}" == "true" ]]; then
483            [[ "${{ needs.check_docs.result }}" != 'success' ]] && { RET_CODE=1; echo "docs checks failed"; }
484          fi
485
486          if [[ "${{ needs.job_spec.outputs.run_actionlint }}" == "true" ]]; then
487            [[ "${{ needs.actionlint.result }}" != 'success' ]] && { RET_CODE=1; echo "actionlint checks failed"; }
488          fi
489
490          # Only check test jobs if they were supposed to run
491          if [[ "${{ needs.job_spec.outputs.run_tests }}" == "true" ]]; then
492            [[ "${{ needs.macos_tests.result }}"          != 'success' ]] && { RET_CODE=1; echo "macOS tests failed"; }
493            [[ "${{ needs.linux_tests.result }}"          != 'success' ]] && { RET_CODE=1; echo "Linux tests failed"; }
494            [[ "${{ needs.windows_tests.result }}"        != 'success' ]] && { RET_CODE=1; echo "Windows tests failed"; }
495            [[ "${{ needs.build_remote_server.result }}"  != 'success' ]] && { RET_CODE=1; echo "Remote server build failed"; }
496            # This check is intentionally disabled. See: https://github.com/zed-industries/zed/pull/28431
497            # [[ "${{ needs.migration_checks.result }}"     != 'success' ]] && { RET_CODE=1; echo "Migration Checks failed"; }
498          fi
499          if [[ "$RET_CODE" -eq 0 ]]; then
500            echo "All tests passed successfully!"
501          fi
502          exit $RET_CODE
503
504  bundle-mac:
505    timeout-minutes: 120
506    name: Create a macOS bundle
507    runs-on:
508      - self-mini-macos
509    if: startsWith(github.ref, 'refs/tags/v')
510    needs: [macos_tests]
511    env:
512      MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
513      MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
514      APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
515      APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
516      APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
517    steps:
518      - name: Install Node
519        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
520        with:
521          node-version: "18"
522
523      - name: Setup Sentry CLI
524        uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b #v2
525        with:
526          token: ${{ SECRETS.SENTRY_AUTH_TOKEN }}
527
528      - name: Checkout repo
529        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
530        with:
531          # We need to fetch more than one commit so that `script/draft-release-notes`
532          # is able to diff between the current and previous tag.
533          #
534          # 25 was chosen arbitrarily.
535          fetch-depth: 25
536          clean: false
537          ref: ${{ github.ref }}
538
539      - name: Limit target directory size
540        run: script/clear-target-dir-if-larger-than 300
541
542      - name: Determine version and release channel
543        run: |
544          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
545          script/determine-release-channel
546
547      - name: Draft release notes
548        run: |
549          mkdir -p target/
550          # Ignore any errors that occur while drafting release notes to not fail the build.
551          script/draft-release-notes "$RELEASE_VERSION" "$RELEASE_CHANNEL" > target/release-notes.md || true
552          script/create-draft-release target/release-notes.md
553        env:
554          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
555
556      - name: Create macOS app bundle (aarch64)
557        run: script/bundle-mac aarch64-apple-darwin
558
559      - name: Create macOS app bundle (x64)
560        run: script/bundle-mac x86_64-apple-darwin
561
562      - name: Rename binaries
563        run: |
564          mv target/aarch64-apple-darwin/release/Zed.dmg target/aarch64-apple-darwin/release/Zed-aarch64.dmg
565          mv target/x86_64-apple-darwin/release/Zed.dmg target/x86_64-apple-darwin/release/Zed-x86_64.dmg
566
567      - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
568        name: Upload app bundle to release
569        if: ${{ env.RELEASE_CHANNEL == 'preview' || env.RELEASE_CHANNEL == 'stable' }}
570        with:
571          draft: true
572          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
573          files: |
574            target/zed-remote-server-macos-x86_64.gz
575            target/zed-remote-server-macos-aarch64.gz
576            target/aarch64-apple-darwin/release/Zed-aarch64.dmg
577            target/x86_64-apple-darwin/release/Zed-x86_64.dmg
578        env:
579          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
580
581  bundle-linux-x86_x64:
582    timeout-minutes: 60
583    name: Linux x86_x64 release bundle
584    runs-on:
585      - namespace-profile-16x32-ubuntu-2004 # ubuntu 20.04 for minimal glibc
586    if: |
587      ( startsWith(github.ref, 'refs/tags/v') )
588    needs: [linux_tests]
589    steps:
590      - name: Checkout repo
591        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
592        with:
593          clean: false
594
595      - name: Install Linux dependencies
596        run: ./script/linux && ./script/install-mold 2.34.0
597
598      - name: Setup Sentry CLI
599        uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b #v2
600        with:
601          token: ${{ SECRETS.SENTRY_AUTH_TOKEN }}
602
603      - name: Determine version and release channel
604        run: |
605          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
606          script/determine-release-channel
607
608      - name: Create Linux .tar.gz bundle
609        run: script/bundle-linux
610
611      - name: Upload Artifacts to release
612        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
613        with:
614          draft: true
615          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
616          files: |
617            target/zed-remote-server-linux-x86_64.gz
618            target/release/zed-linux-x86_64.tar.gz
619        env:
620          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
621
622  bundle-linux-aarch64: # this runs on ubuntu22.04
623    timeout-minutes: 60
624    name: Linux arm64 release bundle
625    runs-on:
626      - namespace-profile-8x32-ubuntu-2004-arm-m4 # ubuntu 20.04 for minimal glibc
627    if: |
628      startsWith(github.ref, 'refs/tags/v')
629    needs: [linux_tests]
630    steps:
631      - name: Checkout repo
632        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
633        with:
634          clean: false
635
636      - name: Install Linux dependencies
637        run: ./script/linux
638
639      - name: Setup Sentry CLI
640        uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b #v2
641        with:
642          token: ${{ SECRETS.SENTRY_AUTH_TOKEN }}
643
644      - name: Determine version and release channel
645        run: |
646          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
647          script/determine-release-channel
648
649      - name: Create and upload Linux .tar.gz bundles
650        run: script/bundle-linux
651
652      - name: Upload Artifacts to release
653        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
654        with:
655          draft: true
656          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
657          files: |
658            target/zed-remote-server-linux-aarch64.gz
659            target/release/zed-linux-aarch64.tar.gz
660        env:
661          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
662
663  freebsd:
664    timeout-minutes: 60
665    runs-on: github-8vcpu-ubuntu-2404
666    if: |
667      false && ( startsWith(github.ref, 'refs/tags/v') )
668    needs: [linux_tests]
669    name: Build Zed on FreeBSD
670    steps:
671      - uses: actions/checkout@v4
672      - name: Build FreeBSD remote-server
673        id: freebsd-build
674        uses: vmactions/freebsd-vm@c3ae29a132c8ef1924775414107a97cac042aad5 # v1.2.0
675        with:
676          usesh: true
677          release: 13.5
678          copyback: true
679          prepare: |
680            pkg install -y \
681              bash curl jq git \
682              rustup-init cmake-core llvm-devel-lite pkgconf protobuf # ibx11 alsa-lib rust-bindgen-cli
683          run: |
684            freebsd-version
685            sysctl hw.model
686            sysctl hw.ncpu
687            sysctl hw.physmem
688            sysctl hw.usermem
689            git config --global --add safe.directory /home/runner/work/zed/zed
690            rustup-init --profile minimal --default-toolchain none -y
691            . "$HOME/.cargo/env"
692            ./script/bundle-freebsd
693            mkdir -p out/
694            mv "target/zed-remote-server-freebsd-x86_64.gz" out/
695            rm -rf target/
696            cargo clean
697
698      - name: Upload Artifact to Workflow - zed-remote-server (run-bundling)
699        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
700        if: contains(github.event.pull_request.labels.*.name, 'run-bundling')
701        with:
702          name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-freebsd.gz
703          path: out/zed-remote-server-freebsd-x86_64.gz
704
705      - name: Upload Artifacts to release
706        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
707        if: ${{ !(contains(github.event.pull_request.labels.*.name, 'run-bundling')) }}
708        with:
709          draft: true
710          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
711          files: |
712            out/zed-remote-server-freebsd-x86_64.gz
713        env:
714          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
715
716  nix-build:
717    name: Build with Nix
718    uses: ./.github/workflows/nix_build.yml
719    needs: [job_spec]
720    if: github.repository_owner == 'zed-industries' &&
721      (contains(github.event.pull_request.labels.*.name, 'run-nix') ||
722      needs.job_spec.outputs.run_nix == 'true')
723    secrets: inherit
724
725  bundle-windows-x64:
726    timeout-minutes: 120
727    name: Create a Windows installer for x86_64
728    runs-on: [self-32vcpu-windows-2022]
729    if: |
730      ( startsWith(github.ref, 'refs/tags/v') )
731    needs: [windows_tests]
732    env:
733      AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
734      AZURE_CLIENT_ID: ${{ secrets.AZURE_SIGNING_CLIENT_ID }}
735      AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SIGNING_CLIENT_SECRET }}
736      ACCOUNT_NAME: ${{ vars.AZURE_SIGNING_ACCOUNT_NAME }}
737      CERT_PROFILE_NAME: ${{ vars.AZURE_SIGNING_CERT_PROFILE_NAME }}
738      ENDPOINT: ${{ vars.AZURE_SIGNING_ENDPOINT }}
739      FILE_DIGEST: SHA256
740      TIMESTAMP_DIGEST: SHA256
741      TIMESTAMP_SERVER: "http://timestamp.acs.microsoft.com"
742    steps:
743      - name: Checkout repo
744        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
745        with:
746          clean: false
747
748      - name: Setup Sentry CLI
749        uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b #v2
750        with:
751          token: ${{ SECRETS.SENTRY_AUTH_TOKEN }}
752
753      - name: Determine version and release channel
754        working-directory: ${{ env.ZED_WORKSPACE }}
755        run: |
756          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
757          script/determine-release-channel.ps1
758
759      - name: Build Zed installer
760        working-directory: ${{ env.ZED_WORKSPACE }}
761        run: script/bundle-windows.ps1
762
763      - name: Upload Artifacts to release
764        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
765        with:
766          draft: true
767          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
768          files: ${{ env.SETUP_PATH }}
769        env:
770          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
771
772  bundle-windows-aarch64:
773    timeout-minutes: 120
774    name: Create a Windows installer for aarch64
775    runs-on: [self-32vcpu-windows-2022]
776    if: |
777      ( startsWith(github.ref, 'refs/tags/v') )
778    needs: [windows_tests]
779    env:
780      AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
781      AZURE_CLIENT_ID: ${{ secrets.AZURE_SIGNING_CLIENT_ID }}
782      AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SIGNING_CLIENT_SECRET }}
783      ACCOUNT_NAME: ${{ vars.AZURE_SIGNING_ACCOUNT_NAME }}
784      CERT_PROFILE_NAME: ${{ vars.AZURE_SIGNING_CERT_PROFILE_NAME }}
785      ENDPOINT: ${{ vars.AZURE_SIGNING_ENDPOINT }}
786      FILE_DIGEST: SHA256
787      TIMESTAMP_DIGEST: SHA256
788      TIMESTAMP_SERVER: "http://timestamp.acs.microsoft.com"
789    steps:
790      - name: Checkout repo
791        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
792        with:
793          clean: false
794
795      - name: Setup Sentry CLI
796        uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b #v2
797        with:
798          token: ${{ SECRETS.SENTRY_AUTH_TOKEN }}
799
800      - name: Determine version and release channel
801        working-directory: ${{ env.ZED_WORKSPACE }}
802        run: |
803          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
804          script/determine-release-channel.ps1
805
806      - name: Build Zed installer
807        working-directory: ${{ env.ZED_WORKSPACE }}
808        run: script/bundle-windows.ps1 -Architecture aarch64
809
810      - name: Upload Artifacts to release
811        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
812        with:
813          draft: true
814          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
815          files: ${{ env.SETUP_PATH }}
816        env:
817          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
818
819  auto-release-preview:
820    name: Auto release preview
821    if: |
822      false
823      && startsWith(github.ref, 'refs/tags/v')
824      && endsWith(github.ref, '-pre') && !endsWith(github.ref, '.0-pre')
825    needs: [bundle-mac, bundle-linux-x86_x64, bundle-linux-aarch64, bundle-windows-x64, bundle-windows-aarch64]
826    runs-on:
827      - self-mini-macos
828    steps:
829      - name: gh release
830        run: gh release edit "$GITHUB_REF_NAME" --draft=false
831        env:
832          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
833
834      - name: Create Sentry release
835        uses: getsentry/action-release@526942b68292201ac6bbb99b9a0747d4abee354c # v3
836        env:
837          SENTRY_ORG: zed-dev
838          SENTRY_PROJECT: zed
839          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
840        with:
841          environment: production