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: Checkout repo
530        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
531        with:
532          # We need to fetch more than one commit so that `script/draft-release-notes`
533          # is able to diff between the current and previous tag.
534          #
535          # 25 was chosen arbitrarily.
536          fetch-depth: 25
537          clean: false
538          ref: ${{ github.ref }}
539
540      - name: Limit target directory size
541        run: script/clear-target-dir-if-larger-than 100
542
543      - name: Determine version and release channel
544        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
545        run: |
546          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
547          script/determine-release-channel
548
549      - name: Draft release notes
550        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
551        run: |
552          mkdir -p target/
553          # Ignore any errors that occur while drafting release notes to not fail the build.
554          script/draft-release-notes "$RELEASE_VERSION" "$RELEASE_CHANNEL" > target/release-notes.md || true
555          script/create-draft-release target/release-notes.md
556        env:
557          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
558
559      - name: Create macOS app bundle
560        run: script/bundle-mac
561
562      - name: Rename binaries
563        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
564        run: |
565          mv target/aarch64-apple-darwin/release/Zed.dmg target/aarch64-apple-darwin/release/Zed-aarch64.dmg
566          mv target/x86_64-apple-darwin/release/Zed.dmg target/x86_64-apple-darwin/release/Zed-x86_64.dmg
567
568      - name: Upload app bundle (aarch64) to workflow run if main branch or specific label
569        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
570        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
571        with:
572          name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.dmg
573          path: target/aarch64-apple-darwin/release/Zed-aarch64.dmg
574
575      - name: Upload app bundle (x86_64) to workflow run if main branch or specific label
576        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
577        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
578        with:
579          name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.dmg
580          path: target/x86_64-apple-darwin/release/Zed-x86_64.dmg
581
582      - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
583        name: Upload app bundle to release
584        if: ${{ env.RELEASE_CHANNEL == 'preview' || env.RELEASE_CHANNEL == 'stable' }}
585        with:
586          draft: true
587          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
588          files: |
589            target/zed-remote-server-macos-x86_64.gz
590            target/zed-remote-server-macos-aarch64.gz
591            target/aarch64-apple-darwin/release/Zed-aarch64.dmg
592            target/x86_64-apple-darwin/release/Zed-x86_64.dmg
593        env:
594          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
595
596  bundle-linux-x86_x64:
597    timeout-minutes: 60
598    name: Linux x86_x64 release bundle
599    runs-on:
600      - namespace-profile-16x32-ubuntu-2004 # ubuntu 20.04 for minimal glibc
601    if: |
602      ( startsWith(github.ref, 'refs/tags/v')
603      || contains(github.event.pull_request.labels.*.name, 'run-bundling') )
604    needs: [linux_tests]
605    steps:
606      - name: Checkout repo
607        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
608        with:
609          clean: false
610
611      - name: Install Linux dependencies
612        run: ./script/linux && ./script/install-mold 2.34.0
613
614      - name: Determine version and release channel
615        if: startsWith(github.ref, 'refs/tags/v')
616        run: |
617          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
618          script/determine-release-channel
619
620      - name: Create Linux .tar.gz bundle
621        run: script/bundle-linux
622
623      - name: Upload Artifact to Workflow - zed (run-bundling)
624        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
625        if: contains(github.event.pull_request.labels.*.name, 'run-bundling')
626        with:
627          name: zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
628          path: target/release/zed-*.tar.gz
629
630      - name: Upload Artifact to Workflow - zed-remote-server (run-bundling)
631        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
632        if: contains(github.event.pull_request.labels.*.name, 'run-bundling')
633        with:
634          name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.gz
635          path: target/zed-remote-server-linux-x86_64.gz
636
637      - name: Upload Artifacts to release
638        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
639        if: ${{ !(contains(github.event.pull_request.labels.*.name, 'run-bundling')) }}
640        with:
641          draft: true
642          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
643          files: |
644            target/zed-remote-server-linux-x86_64.gz
645            target/release/zed-linux-x86_64.tar.gz
646        env:
647          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
648
649  bundle-linux-aarch64: # this runs on ubuntu22.04
650    timeout-minutes: 60
651    name: Linux arm64 release bundle
652    runs-on:
653      - namespace-profile-8x32-ubuntu-2004-arm-m4 # ubuntu 20.04 for minimal glibc
654    if: |
655      startsWith(github.ref, 'refs/tags/v')
656      || contains(github.event.pull_request.labels.*.name, 'run-bundling')
657    needs: [linux_tests]
658    steps:
659      - name: Checkout repo
660        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
661        with:
662          clean: false
663
664      - name: Install Linux dependencies
665        run: ./script/linux
666
667      - name: Determine version and release channel
668        if: startsWith(github.ref, 'refs/tags/v')
669        run: |
670          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
671          script/determine-release-channel
672
673      - name: Create and upload Linux .tar.gz bundles
674        run: script/bundle-linux
675
676      - name: Upload Artifact to Workflow - zed (run-bundling)
677        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
678        if: contains(github.event.pull_request.labels.*.name, 'run-bundling')
679        with:
680          name: zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
681          path: target/release/zed-*.tar.gz
682
683      - name: Upload Artifact to Workflow - zed-remote-server (run-bundling)
684        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
685        if: contains(github.event.pull_request.labels.*.name, 'run-bundling')
686        with:
687          name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.gz
688          path: target/zed-remote-server-linux-aarch64.gz
689
690      - name: Upload Artifacts to release
691        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
692        if: ${{ !(contains(github.event.pull_request.labels.*.name, 'run-bundling')) }}
693        with:
694          draft: true
695          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
696          files: |
697            target/zed-remote-server-linux-aarch64.gz
698            target/release/zed-linux-aarch64.tar.gz
699        env:
700          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
701
702  freebsd:
703    timeout-minutes: 60
704    runs-on: github-8vcpu-ubuntu-2404
705    if: |
706      ( startsWith(github.ref, 'refs/tags/v')
707      || contains(github.event.pull_request.labels.*.name, 'run-bundling') )
708    needs: [linux_tests]
709    name: Build Zed on FreeBSD
710    steps:
711      - uses: actions/checkout@v4
712      - name: Build FreeBSD remote-server
713        id: freebsd-build
714        uses: vmactions/freebsd-vm@c3ae29a132c8ef1924775414107a97cac042aad5 # v1.2.0
715        with:
716          usesh: true
717          release: 13.5
718          copyback: true
719          prepare: |
720            pkg install -y \
721              bash curl jq git \
722              rustup-init cmake-core llvm-devel-lite pkgconf protobuf # ibx11 alsa-lib rust-bindgen-cli
723          run: |
724            freebsd-version
725            sysctl hw.model
726            sysctl hw.ncpu
727            sysctl hw.physmem
728            sysctl hw.usermem
729            git config --global --add safe.directory /home/runner/work/zed/zed
730            rustup-init --profile minimal --default-toolchain none -y
731            . "$HOME/.cargo/env"
732            ./script/bundle-freebsd
733            mkdir -p out/
734            mv "target/zed-remote-server-freebsd-x86_64.gz" out/
735            rm -rf target/
736            cargo clean
737
738      - name: Upload Artifact to Workflow - zed-remote-server (run-bundling)
739        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
740        if: contains(github.event.pull_request.labels.*.name, 'run-bundling')
741        with:
742          name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-freebsd.gz
743          path: out/zed-remote-server-freebsd-x86_64.gz
744
745      - name: Upload Artifacts to release
746        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
747        if: ${{ !(contains(github.event.pull_request.labels.*.name, 'run-bundling')) }}
748        with:
749          draft: true
750          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
751          files: |
752            out/zed-remote-server-freebsd-x86_64.gz
753        env:
754          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
755
756  nix-build:
757    name: Build with Nix
758    uses: ./.github/workflows/nix.yml
759    needs: [job_spec]
760    if: github.repository_owner == 'zed-industries' &&
761      (contains(github.event.pull_request.labels.*.name, 'run-nix') ||
762      needs.job_spec.outputs.run_nix == 'true')
763    secrets: inherit
764    with:
765      flake-output: debug
766      # excludes the final package to only cache dependencies
767      cachix-filter: "-zed-editor-[0-9.]*-nightly"
768
769  bundle-windows-x64:
770    timeout-minutes: 120
771    name: Create a Windows installer
772    runs-on: [self-hosted, Windows, X64]
773    if: contains(github.event.pull_request.labels.*.name, 'run-bundling')
774    # if: (startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling'))
775    needs: [windows_tests]
776    env:
777      AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
778      AZURE_CLIENT_ID: ${{ secrets.AZURE_SIGNING_CLIENT_ID }}
779      AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SIGNING_CLIENT_SECRET }}
780      ACCOUNT_NAME: ${{ vars.AZURE_SIGNING_ACCOUNT_NAME }}
781      CERT_PROFILE_NAME: ${{ vars.AZURE_SIGNING_CERT_PROFILE_NAME }}
782      ENDPOINT: ${{ vars.AZURE_SIGNING_ENDPOINT }}
783      FILE_DIGEST: SHA256
784      TIMESTAMP_DIGEST: SHA256
785      TIMESTAMP_SERVER: "http://timestamp.acs.microsoft.com"
786    steps:
787      - name: Checkout repo
788        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
789        with:
790          clean: false
791
792      - name: Determine version and release channel
793        working-directory: ${{ env.ZED_WORKSPACE }}
794        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
795        run: |
796          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
797          script/determine-release-channel.ps1
798
799      - name: Build Zed installer
800        working-directory: ${{ env.ZED_WORKSPACE }}
801        run: script/bundle-windows.ps1
802
803      - name: Upload installer (x86_64) to Workflow - zed (run-bundling)
804        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
805        if: contains(github.event.pull_request.labels.*.name, 'run-bundling')
806        with:
807          name: ZedEditorUserSetup-x64-${{ github.event.pull_request.head.sha || github.sha }}.exe
808          path: ${{ env.SETUP_PATH }}
809
810      - name: Upload Artifacts to release
811        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
812        # Re-enable when we are ready to publish windows preview releases
813        if: ${{ !(contains(github.event.pull_request.labels.*.name, 'run-bundling')) && env.RELEASE_CHANNEL == 'preview' }} # upload only preview
814        with:
815          draft: true
816          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
817          files: ${{ env.SETUP_PATH }}
818        env:
819          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
820
821  auto-release-preview:
822    name: Auto release preview
823    if: |
824      startsWith(github.ref, 'refs/tags/v')
825      && endsWith(github.ref, '-pre') && !endsWith(github.ref, '.0-pre')
826    needs: [bundle-mac, bundle-linux-x86_x64, bundle-linux-aarch64, bundle-windows-x64]
827    runs-on:
828      - self-mini-macos
829    steps:
830      - name: gh release
831        run: gh release edit "$GITHUB_REF_NAME" --draft=false
832        env:
833          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}