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