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