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