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