ci.yml

  1name: CI
  2
  3on:
  4  push:
  5    branches:
  6      - main
  7      - "v[0-9]+.[0-9]+.x"
  8    tags:
  9      - "v*"
 10  pull_request:
 11    branches:
 12      - "**"
 13  merge_group:
 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  RUSTFLAGS: "-D warnings"
 25
 26jobs:
 27  check_docs_only:
 28    runs-on: ubuntu-latest
 29    outputs:
 30      docs_only: ${{ steps.check_changes.outputs.docs_only }}
 31    steps:
 32      - uses: actions/checkout@v4
 33        with:
 34          fetch-depth: 0
 35      - name: Check for non-docs changes
 36        id: check_changes
 37        run: |
 38          if git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | grep -qvE '^docs/'; then
 39            echo "docs_only=false" >> $GITHUB_OUTPUT
 40          else
 41            echo "docs_only=true" >> $GITHUB_OUTPUT
 42          fi
 43
 44  migration_checks:
 45    name: Check Postgres and Protobuf migrations, mergability
 46    if: github.repository_owner == 'zed-industries'
 47    timeout-minutes: 60
 48    runs-on:
 49      - self-hosted
 50      - test
 51    steps:
 52      - name: Checkout repo
 53        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
 54        with:
 55          clean: false
 56          fetch-depth: 0 # fetch full history
 57
 58      - name: Remove untracked files
 59        run: git clean -df
 60
 61      - name: Find modified migrations
 62        shell: bash -euxo pipefail {0}
 63        run: |
 64          export SQUAWK_GITHUB_TOKEN=${{ github.token }}
 65          . ./script/squawk
 66
 67      - name: Ensure fresh merge
 68        shell: bash -euxo pipefail {0}
 69        run: |
 70          if [ -z "$GITHUB_BASE_REF" ];
 71          then
 72            echo "BUF_BASE_BRANCH=$(git merge-base origin/main HEAD)" >> $GITHUB_ENV
 73          else
 74            git checkout -B temp
 75            git merge -q origin/$GITHUB_BASE_REF -m "merge main into temp"
 76            echo "BUF_BASE_BRANCH=$GITHUB_BASE_REF" >> $GITHUB_ENV
 77          fi
 78
 79      - uses: bufbuild/buf-setup-action@v1
 80        with:
 81          version: v1.29.0
 82      - uses: bufbuild/buf-breaking-action@v1
 83        with:
 84          input: "crates/proto/proto/"
 85          against: "https://github.com/${GITHUB_REPOSITORY}.git#branch=${BUF_BASE_BRANCH},subdir=crates/proto/proto/"
 86
 87  style:
 88    timeout-minutes: 60
 89    name: Check formatting and spelling
 90    if: github.repository_owner == 'zed-industries'
 91    runs-on:
 92      - buildjet-8vcpu-ubuntu-2204
 93    steps:
 94      - name: Checkout repo
 95        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
 96
 97      - name: Run style checks
 98        uses: ./.github/actions/check_style
 99
100      - name: Check for typos
101        uses: crate-ci/typos@8e6a4285bcbde632c5d79900a7779746e8b7ea3f # v1.24.6
102        with:
103          config: ./typos.toml
104
105  macos_tests:
106    timeout-minutes: 60
107    name: (macOS) Run Clippy and tests
108    if: github.repository_owner == 'zed-industries'
109    runs-on:
110      - self-hosted
111      - test
112    needs: check_docs_only
113    steps:
114      - name: Checkout repo
115        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
116        with:
117          clean: false
118
119      - name: Skip for docs-only changes
120        if: needs.check_docs_only.outputs.docs_only == 'true'
121        run: |
122          echo "Skipping for docs-only changes"
123          exit 0
124
125      - name: cargo clippy
126        run: ./script/clippy
127
128      - name: Check unused dependencies
129        uses: bnjbvr/cargo-machete@main
130
131      - name: Check licenses
132        run: |
133          script/check-licenses
134          script/generate-licenses /tmp/zed_licenses_output
135
136      - name: Check for new vulnerable dependencies
137        if: github.event_name == 'pull_request'
138        uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4
139        with:
140          license-check: false
141
142      - name: Run tests
143        uses: ./.github/actions/run_tests
144
145      - name: Build collab
146        run: cargo build -p collab
147
148      - name: Build other binaries and features
149        run: |
150          cargo build --workspace --bins --all-features
151          cargo check -p gpui --features "macos-blade"
152          cargo check -p workspace
153          cargo build -p remote_server
154          script/check-rust-livekit-macos
155
156  linux_tests:
157    timeout-minutes: 60
158    name: (Linux) Run Clippy and tests
159    if: github.repository_owner == 'zed-industries'
160    runs-on:
161      - buildjet-16vcpu-ubuntu-2204
162    needs: check_docs_only
163    steps:
164      - name: Add Rust to the PATH
165        run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
166
167      - name: Checkout repo
168        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
169        with:
170          clean: false
171
172      - name: Skip for docs-only changes
173        if: needs.check_docs_only.outputs.docs_only == 'true'
174        run: |
175          echo "Skipping for docs-only changes"
176          exit 0
177
178      - name: Cache dependencies
179        uses: swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2
180        with:
181          save-if: ${{ github.ref == 'refs/heads/main' }}
182          cache-provider: "buildjet"
183
184      - name: Install Linux dependencies
185        run: ./script/linux
186
187      - name: cargo clippy
188        run: ./script/clippy
189
190      - name: Run tests
191        uses: ./.github/actions/run_tests
192
193      - name: Build other binaries and features
194        run: |
195          cargo build -p zed
196          cargo check -p workspace
197
198  build_remote_server:
199    timeout-minutes: 60
200    name: (Linux) Build Remote Server
201    if: github.repository_owner == 'zed-industries'
202    runs-on:
203      - buildjet-16vcpu-ubuntu-2204
204    needs: check_docs_only
205    steps:
206      - name: Add Rust to the PATH
207        run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
208
209      - name: Checkout repo
210        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
211        with:
212          clean: false
213
214      - name: Skip for docs-only changes
215        if: needs.check_docs_only.outputs.docs_only == 'true'
216        run: |
217          echo "Skipping for docs-only changes"
218          exit 0
219
220      - name: Cache dependencies
221        uses: swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2
222        with:
223          save-if: ${{ github.ref == 'refs/heads/main' }}
224          cache-provider: "buildjet"
225
226      - name: Install Clang & Mold
227        run: ./script/remote-server && ./script/install-mold 2.34.0
228
229      - name: Build Remote Server
230        run: cargo build -p remote_server
231
232  # todo(windows): Actually run the tests
233  windows_tests:
234    timeout-minutes: 60
235    name: (Windows) Run Clippy and tests
236    if: github.repository_owner == 'zed-industries'
237    runs-on: hosted-windows-1
238    needs: check_docs_only
239    steps:
240      # more info here:- https://github.com/rust-lang/cargo/issues/13020
241      - name: Enable longer pathnames for git
242        run: git config --system core.longpaths true
243      - name: Checkout repo
244        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
245        with:
246          clean: false
247
248      - name: Skip for docs-only changes
249        if: needs.check_docs_only.outputs.docs_only == 'true'
250        run: |
251          echo "Skipping for docs-only changes"
252          exit 0
253
254      - name: Cache dependencies
255        uses: swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2
256        with:
257          save-if: ${{ github.ref == 'refs/heads/main' }}
258          cache-provider: "github"
259
260      - name: cargo clippy
261        # Windows can't run shell scripts, so we need to use `cargo xtask`.
262        run: cargo xtask clippy
263
264      - name: Build Zed
265        run: cargo build
266
267  bundle-mac:
268    timeout-minutes: 60
269    name: Create a macOS bundle
270    runs-on:
271      - self-hosted
272      - bundle
273    if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
274    needs: [macos_tests]
275    env:
276      MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
277      MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
278      APPLE_NOTARIZATION_USERNAME: ${{ secrets.APPLE_NOTARIZATION_USERNAME }}
279      APPLE_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }}
280      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
281      ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
282      DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
283      DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
284    steps:
285      - name: Install Node
286        uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
287        with:
288          node-version: "18"
289
290      - name: Checkout repo
291        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
292        with:
293          # We need to fetch more than one commit so that `script/draft-release-notes`
294          # is able to diff between the current and previous tag.
295          #
296          # 25 was chosen arbitrarily.
297          fetch-depth: 25
298          clean: false
299          ref: ${{ github.ref }}
300
301      - name: Limit target directory size
302        run: script/clear-target-dir-if-larger-than 100
303
304      - name: Determine version and release channel
305        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
306        run: |
307          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
308          script/determine-release-channel
309
310      - name: Draft release notes
311        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
312        run: |
313          mkdir -p target/
314          # Ignore any errors that occur while drafting release notes to not fail the build.
315          script/draft-release-notes "$RELEASE_VERSION" "$RELEASE_CHANNEL" > target/release-notes.md || true
316          script/create-draft-release target/release-notes.md
317        env:
318          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
319
320      - name: Generate license file
321        run: script/generate-licenses
322
323      - name: Create macOS app bundle
324        run: script/bundle-mac
325
326      - name: Rename binaries
327        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
328        run: |
329          mv target/aarch64-apple-darwin/release/Zed.dmg target/aarch64-apple-darwin/release/Zed-aarch64.dmg
330          mv target/x86_64-apple-darwin/release/Zed.dmg target/x86_64-apple-darwin/release/Zed-x86_64.dmg
331
332      - name: Upload app bundle (aarch64) to workflow run if main branch or specific label
333        uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
334        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
335        with:
336          name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.dmg
337          path: target/aarch64-apple-darwin/release/Zed-aarch64.dmg
338
339      - name: Upload app bundle (x86_64) to workflow run if main branch or specific label
340        uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
341        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
342        with:
343          name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.dmg
344          path: target/x86_64-apple-darwin/release/Zed-x86_64.dmg
345
346      - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
347        name: Upload app bundle to release
348        if: ${{ env.RELEASE_CHANNEL == 'preview' || env.RELEASE_CHANNEL == 'stable' }}
349        with:
350          draft: true
351          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
352          files: |
353            target/zed-remote-server-macos-x86_64.gz
354            target/zed-remote-server-macos-aarch64.gz
355            target/aarch64-apple-darwin/release/Zed-aarch64.dmg
356            target/x86_64-apple-darwin/release/Zed-x86_64.dmg
357        env:
358          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
359
360  bundle-linux:
361    timeout-minutes: 60
362    name: Create a Linux bundle
363    runs-on:
364      - buildjet-16vcpu-ubuntu-2004
365    if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
366    needs: [linux_tests]
367    env:
368      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
369      ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
370    steps:
371      - name: Checkout repo
372        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
373        with:
374          clean: false
375
376      - name: Install Linux dependencies
377        run: ./script/linux && ./script/install-mold 2.34.0
378
379      - name: Determine version and release channel
380        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
381        run: |
382          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
383          script/determine-release-channel
384
385      - name: Create Linux .tar.gz bundle
386        run: script/bundle-linux
387
388      - name: Upload Linux bundle to workflow run if main branch or specific label
389        uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
390        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
391        with:
392          name: zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
393          path: target/release/zed-*.tar.gz
394
395      - name: Upload app bundle to release
396        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
397        with:
398          draft: true
399          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
400          files: |
401            target/zed-remote-server-linux-x86_64.gz
402            target/release/zed-linux-x86_64.tar.gz
403        env:
404          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
405
406  bundle-linux-aarch64: # this runs on ubuntu22.04
407    timeout-minutes: 60
408    name: Create arm64 Linux bundle
409    runs-on:
410      - buildjet-16vcpu-ubuntu-2204-arm
411    if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
412    needs: [linux_tests]
413    env:
414      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
415      ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
416    steps:
417      - name: Checkout repo
418        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
419        with:
420          clean: false
421
422      - name: Install Linux dependencies
423        run: ./script/linux
424
425      - name: Determine version and release channel
426        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
427        run: |
428          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
429          script/determine-release-channel
430
431      - name: Create and upload Linux .tar.gz bundle
432        run: script/bundle-linux
433
434      - name: Upload Linux bundle to workflow run if main branch or specific label
435        uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
436        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
437        with:
438          name: zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
439          path: target/release/zed-*.tar.gz
440
441      - name: Upload app bundle to release
442        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
443        with:
444          draft: true
445          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
446          files: |
447            target/zed-remote-server-linux-aarch64.gz
448            target/release/zed-linux-aarch64.tar.gz
449        env:
450          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
451
452  auto-release-preview:
453    name: Auto release preview
454    if: ${{ startsWith(github.ref, 'refs/tags/v') && endsWith(github.ref, '-pre') && !endsWith(github.ref, '.0-pre') }}
455    needs: [bundle-mac, bundle-linux, bundle-linux-aarch64]
456    runs-on:
457      - self-hosted
458      - bundle
459    steps:
460      - name: gh release
461        run: gh release edit $GITHUB_REF_NAME --draft=false
462        env:
463          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}