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