ci.yml

  1name: CI
  2
  3on:
  4  push:
  5    branches:
  6      - main
  7      - "v[0-9]+.[0-9]+.x"
  8    tags:
  9      - "v*"
 10
 11  pull_request:
 12    branches:
 13      - "**"
 14
 15concurrency:
 16  # Allow only one workflow per any non-`main` branch.
 17  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
 18  cancel-in-progress: true
 19
 20env:
 21  CARGO_TERM_COLOR: always
 22  CARGO_INCREMENTAL: 0
 23  RUST_BACKTRACE: 1
 24
 25jobs:
 26  job_spec:
 27    name: Decide which jobs to run
 28    if: github.repository_owner == 'zed-industries'
 29    outputs:
 30      run_tests: ${{ steps.filter.outputs.run_tests }}
 31      run_license: ${{ steps.filter.outputs.run_license }}
 32    runs-on:
 33      - ubuntu-latest
 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          # Specify anything which should skip full CI in this regex:
 52          # - docs/
 53          # - .github/ISSUE_TEMPLATE/
 54          # - .github/workflows/  (except .github/workflows/ci.yml)
 55          SKIP_REGEX='^(docs/|\.github/(ISSUE_TEMPLATE|workflows/(?!ci)))'
 56          if [[ $(git diff --name-only $COMPARE_REV ${{ github.sha }} | grep -vP "$SKIP_REGEX") ]]; then
 57            echo "run_tests=true" >> $GITHUB_OUTPUT
 58          else
 59            echo "run_tests=false" >> $GITHUB_OUTPUT
 60          fi
 61          if [[ $(git diff --name-only $COMPARE_REV ${{ github.sha }} | grep '^Cargo.lock') ]]; then
 62            echo "run_license=true" >> $GITHUB_OUTPUT
 63          else
 64            echo "run_license=false" >> $GITHUB_OUTPUT
 65          fi
 66
 67  migration_checks:
 68    name: Check Postgres and Protobuf migrations, mergability
 69    needs: [job_spec]
 70    if: |
 71      github.repository_owner == 'zed-industries' &&
 72      needs.job_spec.outputs.run_tests == 'true'
 73    timeout-minutes: 60
 74    runs-on:
 75      - self-hosted
 76      - test
 77    steps:
 78      - name: Checkout repo
 79        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
 80        with:
 81          clean: false
 82          fetch-depth: 0 # fetch full history
 83
 84      - name: Remove untracked files
 85        run: git clean -df
 86
 87      - name: Find modified migrations
 88        shell: bash -euxo pipefail {0}
 89        run: |
 90          export SQUAWK_GITHUB_TOKEN=${{ github.token }}
 91          . ./script/squawk
 92
 93      - name: Ensure fresh merge
 94        shell: bash -euxo pipefail {0}
 95        run: |
 96          if [ -z "$GITHUB_BASE_REF" ];
 97          then
 98            echo "BUF_BASE_BRANCH=$(git merge-base origin/main HEAD)" >> $GITHUB_ENV
 99          else
100            git checkout -B temp
101            git merge -q origin/$GITHUB_BASE_REF -m "merge main into temp"
102            echo "BUF_BASE_BRANCH=$GITHUB_BASE_REF" >> $GITHUB_ENV
103          fi
104
105      - uses: bufbuild/buf-setup-action@v1
106        with:
107          version: v1.29.0
108      - uses: bufbuild/buf-breaking-action@v1
109        with:
110          input: "crates/proto/proto/"
111          against: "https://github.com/${GITHUB_REPOSITORY}.git#branch=${BUF_BASE_BRANCH},subdir=crates/proto/proto/"
112
113  workspace_hack:
114    timeout-minutes: 60
115    name: Check workspace-hack crate
116    needs: [job_spec]
117    if: github.repository_owner == 'zed-industries'
118    runs-on:
119      - buildjet-8vcpu-ubuntu-2204
120    steps:
121      - name: Checkout repo
122        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
123      - name: Add Rust to the PATH
124        run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
125      - name: Install cargo-hakari
126        uses: clechasseur/rs-cargo@8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386 # v2
127        with:
128          command: install
129          args: cargo-hakari@0.9.35
130
131      - name: Check workspace-hack Cargo.toml is up-to-date
132        run: |
133          cargo hakari generate --diff || {
134            echo "To fix, run script/update-workspace-hack";
135            false
136          }
137      - name: Check all crates depend on workspace-hack
138        run: |
139          cargo hakari manage-deps --dry-run || {
140            echo "To fix, run script/update-workspace-hack"
141            false
142          }
143
144  style:
145    timeout-minutes: 60
146    name: Check formatting and spelling
147    needs: [job_spec]
148    if: github.repository_owner == 'zed-industries'
149    runs-on:
150      - buildjet-8vcpu-ubuntu-2204
151    steps:
152      - name: Checkout repo
153        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
154
155      - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
156        with:
157          version: 9
158
159      - name: Prettier Check on /docs
160        working-directory: ./docs
161        run: |
162          pnpm dlx prettier@${PRETTIER_VERSION} . --check || {
163            echo "To fix, run from the root of the zed repo:"
164            echo "  cd docs && pnpm dlx prettier@${PRETTIER_VERSION} . --write && cd .."
165            false
166          }
167        env:
168          PRETTIER_VERSION: 3.5.0
169
170      # To support writing comments that they will certainly be revisited.
171      - name: Check for todo! and FIXME comments
172        run: script/check-todos
173
174      - name: Run style checks
175        uses: ./.github/actions/check_style
176
177      - name: Check for typos
178        uses: crate-ci/typos@8e6a4285bcbde632c5d79900a7779746e8b7ea3f # v1.24.6
179        with:
180          config: ./typos.toml
181
182  macos_tests:
183    timeout-minutes: 60
184    name: (macOS) Run Clippy and tests
185    needs: [job_spec]
186    if: |
187      github.repository_owner == 'zed-industries' &&
188      needs.job_spec.outputs.run_tests == 'true'
189    runs-on:
190      - self-hosted
191      - test
192    steps:
193      - name: Checkout repo
194        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
195        with:
196          clean: false
197
198      - name: Configure CI
199        run: |
200          mkdir -p ./../.cargo
201          cp ./.cargo/ci-config.toml ./../.cargo/config.toml
202
203      - name: cargo clippy
204        run: ./script/clippy
205
206      - name: Install cargo-machete
207        uses: clechasseur/rs-cargo@8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386 # v2
208        with:
209          command: install
210          args: cargo-machete@0.7.0
211
212      - name: Check unused dependencies
213        uses: clechasseur/rs-cargo@8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386 # v2
214        with:
215          command: machete
216
217      - name: Check licenses
218        run: |
219          script/check-licenses
220          if [[ "${{ needs.job_spec.outputs.run_license }}" == "true" ]]; then
221            script/generate-licenses /tmp/zed_licenses_output
222          fi
223
224      - name: Check for new vulnerable dependencies
225        if: github.event_name == 'pull_request'
226        uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4
227        with:
228          license-check: false
229
230      - name: Run tests
231        uses: ./.github/actions/run_tests
232
233      - name: Build collab
234        run: cargo build -p collab
235
236      - name: Build other binaries and features
237        run: |
238          cargo build --workspace --bins --all-features
239          cargo check -p gpui --features "macos-blade"
240          cargo check -p workspace
241          cargo build -p remote_server
242          cargo check -p gpui --examples
243
244      # Since the macOS runners are stateful, so we need to remove the config file to prevent potential bug.
245      - name: Clean CI config file
246        if: always()
247        run: rm -rf ./../.cargo
248
249  linux_tests:
250    timeout-minutes: 60
251    name: (Linux) Run Clippy and tests
252    needs: [job_spec]
253    if: |
254      github.repository_owner == 'zed-industries' &&
255      needs.job_spec.outputs.run_tests == 'true'
256    runs-on:
257      - buildjet-16vcpu-ubuntu-2204
258    steps:
259      - name: Add Rust to the PATH
260        run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
261
262      - name: Checkout repo
263        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
264        with:
265          clean: false
266
267      - name: Cache dependencies
268        uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
269        with:
270          save-if: ${{ github.ref == 'refs/heads/main' }}
271          cache-provider: "buildjet"
272
273      - name: Install Linux dependencies
274        run: ./script/linux
275
276      - name: Configure CI
277        run: |
278          mkdir -p ./../.cargo
279          cp ./.cargo/ci-config.toml ./../.cargo/config.toml
280
281      - name: cargo clippy
282        run: ./script/clippy
283
284      - name: Run tests
285        uses: ./.github/actions/run_tests
286
287      - name: Build other binaries and features
288        run: |
289          cargo build -p zed
290          cargo check -p workspace
291          cargo check -p gpui --examples
292
293      # Even the Linux runner is not stateful, in theory there is no need to do this cleanup.
294      # But, to avoid potential issues in the future if we choose to use a stateful Linux runner and forget to add code
295      # to clean up the config file, I’ve included the cleanup code here as a precaution.
296      # While it’s not strictly necessary at this moment, I believe it’s better to err on the side of caution.
297      - name: Clean CI config file
298        if: always()
299        run: rm -rf ./../.cargo
300
301  build_remote_server:
302    timeout-minutes: 60
303    name: (Linux) Build Remote Server
304    needs: [job_spec]
305    if: |
306      github.repository_owner == 'zed-industries' &&
307      needs.job_spec.outputs.run_tests == 'true'
308    runs-on:
309      - buildjet-8vcpu-ubuntu-2204
310    steps:
311      - name: Add Rust to the PATH
312        run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
313
314      - name: Checkout repo
315        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
316        with:
317          clean: false
318
319      - name: Cache dependencies
320        uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
321        with:
322          save-if: ${{ github.ref == 'refs/heads/main' }}
323          cache-provider: "buildjet"
324
325      - name: Install Clang & Mold
326        run: ./script/remote-server && ./script/install-mold 2.34.0
327
328      - name: Configure CI
329        run: |
330          mkdir -p ./../.cargo
331          cp ./.cargo/ci-config.toml ./../.cargo/config.toml
332
333      - name: Build Remote Server
334        run: cargo build -p remote_server
335
336      - name: Clean CI config file
337        if: always()
338        run: rm -rf ./../.cargo
339
340  windows_clippy:
341    timeout-minutes: 60
342    name: (Windows) Run Clippy
343    needs: [job_spec]
344    if: |
345      github.repository_owner == 'zed-industries' &&
346      needs.job_spec.outputs.run_tests == 'true'
347    runs-on: windows-2025-16
348    steps:
349      # more info here:- https://github.com/rust-lang/cargo/issues/13020
350      - name: Enable longer pathnames for git
351        run: git config --system core.longpaths true
352
353      - name: Checkout repo
354        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
355        with:
356          clean: false
357
358      - name: Create Dev Drive using ReFS
359        run: ./script/setup-dev-driver.ps1
360
361      # actions/checkout does not let us clone into anywhere outside ${{ github.workspace }}, so we have to copy the clone...
362      - name: Copy Git Repo to Dev Drive
363        run: |
364          Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.ZED_WORKSPACE }}" -Recurse
365
366      - name: Cache dependencies
367        uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
368        with:
369          save-if: ${{ github.ref == 'refs/heads/main' }}
370          workspaces: ${{ env.ZED_WORKSPACE }}
371          cache-provider: "github"
372
373      - name: Configure CI
374        run: |
375          mkdir -p ${{ env.CARGO_HOME }} -ErrorAction Ignore
376          cp ./.cargo/ci-config.toml ${{ env.CARGO_HOME }}/config.toml
377
378      - name: cargo clippy
379        working-directory: ${{ env.ZED_WORKSPACE }}
380        run: ./script/clippy.ps1
381
382      - name: Check dev drive space
383        working-directory: ${{ env.ZED_WORKSPACE }}
384        # `setup-dev-driver.ps1` creates a 100GB drive, with CI taking up ~45GB of the drive.
385        run: ./script/exit-ci-if-dev-drive-is-full.ps1 95
386
387      # Since the Windows runners are stateful, so we need to remove the config file to prevent potential bug.
388      - name: Clean CI config file
389        if: always()
390        run: |
391          if (Test-Path "${{ env.CARGO_HOME }}/config.toml") {
392            Remove-Item -Path "${{ env.CARGO_HOME }}/config.toml"  -Force
393          }
394
395  # Windows CI takes twice as long as our other platforms and fast github hosted runners are expensive.
396  # But we still want to do CI, so let's only run tests on main and come back to this when we're
397  # ready to self host our Windows CI (e.g. during the push for full Windows support)
398  windows_tests:
399    timeout-minutes: 60
400    name: (Windows) Run Tests
401    needs: [job_spec]
402    if: |
403      github.repository_owner == 'zed-industries' &&
404      needs.job_spec.outputs.run_tests == 'true'
405    # Use bigger runners for PRs (speed); smaller for async (cost)
406    runs-on: ${{ github.event_name == 'pull_request' && 'windows-2025-32' || 'windows-2025-16' }}
407    steps:
408      # more info here:- https://github.com/rust-lang/cargo/issues/13020
409      - name: Enable longer pathnames for git
410        run: git config --system core.longpaths true
411
412      - name: Checkout repo
413        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
414        with:
415          clean: false
416
417      - name: Create Dev Drive using ReFS
418        run: ./script/setup-dev-driver.ps1
419
420      # actions/checkout does not let us clone into anywhere outside ${{ github.workspace }}, so we have to copy the clone...
421      - name: Copy Git Repo to Dev Drive
422        run: |
423          Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.ZED_WORKSPACE }}" -Recurse
424
425      - name: Cache dependencies
426        uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
427        with:
428          save-if: ${{ github.ref == 'refs/heads/main' }}
429          workspaces: ${{ env.ZED_WORKSPACE }}
430          cache-provider: "github"
431
432      - name: Configure CI
433        run: |
434          mkdir -p ${{ env.CARGO_HOME }} -ErrorAction Ignore
435          cp ./.cargo/ci-config.toml ${{ env.CARGO_HOME }}/config.toml
436
437      - name: Run tests
438        uses: ./.github/actions/run_tests_windows
439        with:
440          working-directory: ${{ env.ZED_WORKSPACE }}
441
442      - name: Build Zed
443        working-directory: ${{ env.ZED_WORKSPACE }}
444        run: cargo build
445
446      - name: Check dev drive space
447        working-directory: ${{ env.ZED_WORKSPACE }}
448        # `setup-dev-driver.ps1` creates a 100GB drive, with CI taking up ~45GB of the drive.
449        run: ./script/exit-ci-if-dev-drive-is-full.ps1 95
450
451      # Since the Windows runners are stateful, so we need to remove the config file to prevent potential bug.
452      - name: Clean CI config file
453        if: always()
454        run: |
455          if (Test-Path "${{ env.CARGO_HOME }}/config.toml") {
456            Remove-Item -Path "${{ env.CARGO_HOME }}/config.toml"  -Force
457          }
458
459  tests_pass:
460    name: Tests Pass
461    runs-on: ubuntu-latest
462    needs:
463      - job_spec
464      - style
465      - migration_checks
466      - workspace_hack
467      - linux_tests
468      - build_remote_server
469      - macos_tests
470      - windows_clippy
471      - windows_tests
472    if: always()
473    steps:
474      - name: Check all tests passed
475        run: |
476          # Check dependent jobs...
477          RET_CODE=0
478          # Always check style
479          [[ "${{ needs.style.result }}" != 'success' ]] && { RET_CODE=1; echo "style tests failed"; }
480
481          # Only check test jobs if they were supposed to run
482          if [[ "${{ needs.job_spec.outputs.run_tests }}" == "true" ]]; then
483            [[ "${{ needs.macos_tests.result }}"          != 'success' ]] && { RET_CODE=1; echo "macOS tests failed"; }
484            [[ "${{ needs.linux_tests.result }}"          != 'success' ]] && { RET_CODE=1; echo "Linux tests failed"; }
485            [[ "${{ needs.windows_tests.result }}"        != 'success' ]] && { RET_CODE=1; echo "Windows tests failed"; }
486            [[ "${{ needs.windows_clippy.result }}"       != 'success' ]] && { RET_CODE=1; echo "Windows clippy failed"; }
487            [[ "${{ needs.build_remote_server.result }}"  != 'success' ]] && { RET_CODE=1; echo "Remote server build failed"; }
488          fi
489          if [[ "$RET_CODE" -eq 0 ]]; then
490            echo "All tests passed successfully!"
491          fi
492          exit $RET_CODE
493
494  bundle-mac:
495    timeout-minutes: 120
496    name: Create a macOS bundle
497    runs-on:
498      - self-hosted
499      - bundle
500    if: |
501      startsWith(github.ref, 'refs/tags/v')
502      || contains(github.event.pull_request.labels.*.name, 'run-bundling')
503    needs: [macos_tests]
504    env:
505      MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
506      MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
507      APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
508      APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
509      APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
510      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
511      ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
512      DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
513      DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
514    steps:
515      - name: Install Node
516        uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
517        with:
518          node-version: "18"
519
520      - name: Checkout repo
521        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
522        with:
523          # We need to fetch more than one commit so that `script/draft-release-notes`
524          # is able to diff between the current and previous tag.
525          #
526          # 25 was chosen arbitrarily.
527          fetch-depth: 25
528          clean: false
529          ref: ${{ github.ref }}
530
531      - name: Limit target directory size
532        run: script/clear-target-dir-if-larger-than 100
533
534      - name: Determine version and release channel
535        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
536        run: |
537          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
538          script/determine-release-channel
539
540      - name: Draft release notes
541        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
542        run: |
543          mkdir -p target/
544          # Ignore any errors that occur while drafting release notes to not fail the build.
545          script/draft-release-notes "$RELEASE_VERSION" "$RELEASE_CHANNEL" > target/release-notes.md || true
546          script/create-draft-release target/release-notes.md
547        env:
548          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
549
550      - name: Create macOS app bundle
551        run: script/bundle-mac
552
553      - name: Rename binaries
554        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
555        run: |
556          mv target/aarch64-apple-darwin/release/Zed.dmg target/aarch64-apple-darwin/release/Zed-aarch64.dmg
557          mv target/x86_64-apple-darwin/release/Zed.dmg target/x86_64-apple-darwin/release/Zed-x86_64.dmg
558
559      - name: Upload app bundle (aarch64) to workflow run if main branch or specific label
560        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
561        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
562        with:
563          name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.dmg
564          path: target/aarch64-apple-darwin/release/Zed-aarch64.dmg
565
566      - name: Upload app bundle (x86_64) to workflow run if main branch or specific label
567        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
568        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
569        with:
570          name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.dmg
571          path: target/x86_64-apple-darwin/release/Zed-x86_64.dmg
572
573      - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
574        name: Upload app bundle to release
575        if: ${{ env.RELEASE_CHANNEL == 'preview' || env.RELEASE_CHANNEL == 'stable' }}
576        with:
577          draft: true
578          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
579          files: |
580            target/zed-remote-server-macos-x86_64.gz
581            target/zed-remote-server-macos-aarch64.gz
582            target/aarch64-apple-darwin/release/Zed-aarch64.dmg
583            target/x86_64-apple-darwin/release/Zed-x86_64.dmg
584        env:
585          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
586
587  bundle-linux-x86_x64:
588    timeout-minutes: 60
589    name: Linux x86_x64 release bundle
590    runs-on:
591      - buildjet-16vcpu-ubuntu-2004
592    if: |
593      startsWith(github.ref, 'refs/tags/v')
594      || contains(github.event.pull_request.labels.*.name, 'run-bundling')
595    needs: [linux_tests]
596    env:
597      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
598      ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
599      DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
600      DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
601    steps:
602      - name: Checkout repo
603        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
604        with:
605          clean: false
606
607      - name: Install Linux dependencies
608        run: ./script/linux && ./script/install-mold 2.34.0
609
610      - name: Determine version and release channel
611        if: startsWith(github.ref, 'refs/tags/v')
612        run: |
613          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
614          script/determine-release-channel
615
616      - name: Create Linux .tar.gz bundle
617        run: script/bundle-linux
618
619      - name: Upload Linux bundle to workflow run if main branch or specific label
620        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
621        if: |
622          github.ref == 'refs/heads/main'
623          || contains(github.event.pull_request.labels.*.name, 'run-bundling')
624        with:
625          name: zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
626          path: target/release/zed-*.tar.gz
627
628      - name: Upload Linux remote server to workflow run if main branch or specific label
629        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
630        if: |
631          github.ref == 'refs/heads/main'
632          || contains(github.event.pull_request.labels.*.name, 'run-bundling')
633        with:
634          name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.gz
635          path: target/zed-remote-server-linux-x86_64.gz
636
637      - name: Upload app bundle to release
638        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
639        with:
640          draft: true
641          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
642          files: |
643            target/zed-remote-server-linux-x86_64.gz
644            target/release/zed-linux-x86_64.tar.gz
645        env:
646          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
647
648  bundle-linux-aarch64: # this runs on ubuntu22.04
649    timeout-minutes: 60
650    name: Linux arm64 release bundle
651    runs-on:
652      - buildjet-16vcpu-ubuntu-2204-arm
653    if: |
654      startsWith(github.ref, 'refs/tags/v')
655      || contains(github.event.pull_request.labels.*.name, 'run-bundling')
656    needs: [linux_tests]
657    env:
658      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
659      ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
660      DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
661      DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
662    steps:
663      - name: Checkout repo
664        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
665        with:
666          clean: false
667
668      - name: Install Linux dependencies
669        run: ./script/linux
670
671      - name: Determine version and release channel
672        if: startsWith(github.ref, 'refs/tags/v')
673        run: |
674          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
675          script/determine-release-channel
676
677      - name: Create and upload Linux .tar.gz bundle
678        run: script/bundle-linux
679
680      - name: Upload Linux bundle to workflow run if main branch or specific label
681        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
682        if: |
683          github.ref == 'refs/heads/main'
684          || contains(github.event.pull_request.labels.*.name, 'run-bundling')
685        with:
686          name: zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
687          path: target/release/zed-*.tar.gz
688
689      - name: Upload Linux remote server to workflow run if main branch or specific label
690        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
691        if: |
692          github.ref == 'refs/heads/main'
693          || contains(github.event.pull_request.labels.*.name, 'run-bundling')
694        with:
695          name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.gz
696          path: target/zed-remote-server-linux-aarch64.gz
697
698      - name: Upload app bundle to release
699        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
700        with:
701          draft: true
702          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
703          files: |
704            target/zed-remote-server-linux-aarch64.gz
705            target/release/zed-linux-aarch64.tar.gz
706        env:
707          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
708
709  nix-build:
710    timeout-minutes: 60
711    name: Nix Build
712    continue-on-error: true
713    if: github.repository_owner == 'zed-industries' && contains(github.event.pull_request.labels.*.name, 'run-nix')
714    strategy:
715      fail-fast: false
716      matrix:
717        system:
718          - os: x86 Linux
719            runner: buildjet-16vcpu-ubuntu-2204
720            install_nix: true
721          - os: arm Mac
722            runner: [macOS, ARM64, test]
723            install_nix: false
724    runs-on: ${{ matrix.system.runner }}
725    env:
726      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
727      ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
728      GIT_LFS_SKIP_SMUDGE: 1 # breaks the livekit rust sdk examples which we don't actually depend on
729    steps:
730      - name: Checkout repo
731        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
732        with:
733          clean: false
734      - name: Set path
735        if: ${{ ! matrix.system.install_nix }}
736        run: |
737          echo "/nix/var/nix/profiles/default/bin" >> $GITHUB_PATH
738          echo "/Users/administrator/.nix-profile/bin" >> $GITHUB_PATH
739
740      - uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f # v31
741        if: ${{ matrix.system.install_nix }}
742        with:
743          github_access_token: ${{ secrets.GITHUB_TOKEN }}
744
745      - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
746        with:
747          name: zed-industries
748          authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
749          skipPush: true
750      - run: nix build .#debug
751      - name: Limit /nix/store to 50GB
752        run: "[ $(du -sm /nix/store | cut -f1) -gt 50000 ] && nix-collect-garbage -d"
753
754  auto-release-preview:
755    name: Auto release preview
756    if: |
757      startsWith(github.ref, 'refs/tags/v')
758      && endsWith(github.ref, '-pre') && !endsWith(github.ref, '.0-pre')
759    needs: [bundle-mac, bundle-linux-x86_x64, bundle-linux-aarch64]
760    runs-on:
761      - self-hosted
762      - bundle
763    steps:
764      - name: gh release
765        run: gh release edit $GITHUB_REF_NAME --draft=true
766        env:
767          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}