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