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: cargo clippy
120        if: needs.check_docs_only.outputs.docs_only == 'false'
121        run: ./script/clippy
122
123      - name: Check unused dependencies
124        if: needs.check_docs_only.outputs.docs_only == 'false'
125        uses: bnjbvr/cargo-machete@main
126
127      - name: Check licenses
128        if: needs.check_docs_only.outputs.docs_only == 'false'
129        run: |
130          script/check-licenses
131          script/generate-licenses /tmp/zed_licenses_output
132
133      - name: Check for new vulnerable dependencies
134        if: github.event_name == 'pull_request' && needs.check_docs_only.outputs.docs_only == 'false'
135        uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4
136        with:
137          license-check: false
138
139      - name: Run tests
140        if: needs.check_docs_only.outputs.docs_only == 'false'
141        uses: ./.github/actions/run_tests
142
143      - name: Build collab
144        if: needs.check_docs_only.outputs.docs_only == 'false'
145        run: cargo build -p collab
146
147      - name: Build other binaries and features
148        if: needs.check_docs_only.outputs.docs_only == 'false'
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: Cache dependencies
173        if: needs.check_docs_only.outputs.docs_only == 'false'
174        uses: swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2
175        with:
176          save-if: ${{ github.ref == 'refs/heads/main' }}
177          cache-provider: "buildjet"
178
179      - name: Install Linux dependencies
180        if: needs.check_docs_only.outputs.docs_only == 'false'
181        run: ./script/linux
182
183      - name: cargo clippy
184        if: needs.check_docs_only.outputs.docs_only == 'false'
185        run: ./script/clippy
186
187      - name: Run tests
188        if: needs.check_docs_only.outputs.docs_only == 'false'
189        uses: ./.github/actions/run_tests
190
191      - name: Build other binaries and features
192        if: needs.check_docs_only.outputs.docs_only == 'false'
193        run: |
194          cargo build -p zed
195          cargo check -p workspace
196
197  build_remote_server:
198    timeout-minutes: 60
199    name: (Linux) Build Remote Server
200    if: github.repository_owner == 'zed-industries'
201    runs-on:
202      - buildjet-16vcpu-ubuntu-2204
203    needs: check_docs_only
204    steps:
205      - name: Add Rust to the PATH
206        run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
207
208      - name: Checkout repo
209        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
210        with:
211          clean: false
212
213      - name: Cache dependencies
214        if: needs.check_docs_only.outputs.docs_only == 'false'
215        uses: swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2
216        with:
217          save-if: ${{ github.ref == 'refs/heads/main' }}
218          cache-provider: "buildjet"
219
220      - name: Install Clang & Mold
221        if: needs.check_docs_only.outputs.docs_only == 'false'
222        run: ./script/remote-server && ./script/install-mold 2.34.0
223
224      - name: Build Remote Server
225        if: needs.check_docs_only.outputs.docs_only == 'false'
226        run: cargo build -p remote_server
227
228  # todo(windows): Actually run the tests
229  windows_tests:
230    timeout-minutes: 60
231    name: (Windows) Run Clippy and tests
232    if: github.repository_owner == 'zed-industries'
233    runs-on: hosted-windows-1
234    needs: check_docs_only
235    steps:
236      # more info here:- https://github.com/rust-lang/cargo/issues/13020
237      - name: Enable longer pathnames for git
238        run: git config --system core.longpaths true
239      - name: Checkout repo
240        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
241        with:
242          clean: false
243
244      - name: Cache dependencies
245        if: needs.check_docs_only.outputs.docs_only == 'false'
246        uses: swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2
247        with:
248          save-if: ${{ github.ref == 'refs/heads/main' }}
249          cache-provider: "github"
250
251      - name: cargo clippy
252        if: needs.check_docs_only.outputs.docs_only == 'false'
253        # Windows can't run shell scripts, so we need to use `cargo xtask`.
254        run: cargo xtask clippy
255
256      - name: Build Zed
257        if: needs.check_docs_only.outputs.docs_only == 'false'
258        run: cargo build
259
260  bundle-mac:
261    timeout-minutes: 60
262    name: Create a macOS bundle
263    runs-on:
264      - self-hosted
265      - bundle
266    if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
267    needs: [macos_tests]
268    env:
269      MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
270      MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
271      APPLE_NOTARIZATION_USERNAME: ${{ secrets.APPLE_NOTARIZATION_USERNAME }}
272      APPLE_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }}
273      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
274      ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
275      DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
276      DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
277    steps:
278      - name: Install Node
279        uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
280        with:
281          node-version: "18"
282
283      - name: Checkout repo
284        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
285        with:
286          # We need to fetch more than one commit so that `script/draft-release-notes`
287          # is able to diff between the current and previous tag.
288          #
289          # 25 was chosen arbitrarily.
290          fetch-depth: 25
291          clean: false
292          ref: ${{ github.ref }}
293
294      - name: Limit target directory size
295        run: script/clear-target-dir-if-larger-than 100
296
297      - name: Determine version and release channel
298        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
299        run: |
300          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
301          script/determine-release-channel
302
303      - name: Draft release notes
304        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
305        run: |
306          mkdir -p target/
307          # Ignore any errors that occur while drafting release notes to not fail the build.
308          script/draft-release-notes "$RELEASE_VERSION" "$RELEASE_CHANNEL" > target/release-notes.md || true
309          script/create-draft-release target/release-notes.md
310        env:
311          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
312
313      - name: Generate license file
314        run: script/generate-licenses
315
316      - name: Create macOS app bundle
317        run: script/bundle-mac
318
319      - name: Rename binaries
320        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
321        run: |
322          mv target/aarch64-apple-darwin/release/Zed.dmg target/aarch64-apple-darwin/release/Zed-aarch64.dmg
323          mv target/x86_64-apple-darwin/release/Zed.dmg target/x86_64-apple-darwin/release/Zed-x86_64.dmg
324
325      - name: Upload app bundle (aarch64) to workflow run if main branch or specific label
326        uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
327        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
328        with:
329          name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.dmg
330          path: target/aarch64-apple-darwin/release/Zed-aarch64.dmg
331
332      - name: Upload app bundle (x86_64) 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 }}-x86_64.dmg
337          path: target/x86_64-apple-darwin/release/Zed-x86_64.dmg
338
339      - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
340        name: Upload app bundle to release
341        if: ${{ env.RELEASE_CHANNEL == 'preview' || env.RELEASE_CHANNEL == 'stable' }}
342        with:
343          draft: true
344          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
345          files: |
346            target/zed-remote-server-macos-x86_64.gz
347            target/zed-remote-server-macos-aarch64.gz
348            target/aarch64-apple-darwin/release/Zed-aarch64.dmg
349            target/x86_64-apple-darwin/release/Zed-x86_64.dmg
350        env:
351          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
352
353  bundle-linux:
354    timeout-minutes: 60
355    name: Create a Linux bundle
356    runs-on:
357      - buildjet-16vcpu-ubuntu-2004
358    if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
359    needs: [linux_tests]
360    env:
361      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
362      ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
363    steps:
364      - name: Checkout repo
365        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
366        with:
367          clean: false
368
369      - name: Install Linux dependencies
370        run: ./script/linux && ./script/install-mold 2.34.0
371
372      - name: Determine version and release channel
373        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
374        run: |
375          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
376          script/determine-release-channel
377
378      - name: Create Linux .tar.gz bundle
379        run: script/bundle-linux
380
381      - name: Upload Linux bundle to workflow run if main branch or specific label
382        uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
383        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
384        with:
385          name: zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
386          path: target/release/zed-*.tar.gz
387
388      - name: Upload app bundle to release
389        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
390        with:
391          draft: true
392          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
393          files: |
394            target/zed-remote-server-linux-x86_64.gz
395            target/release/zed-linux-x86_64.tar.gz
396        env:
397          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
398
399  bundle-linux-aarch64: # this runs on ubuntu22.04
400    timeout-minutes: 60
401    name: Create arm64 Linux bundle
402    runs-on:
403      - buildjet-16vcpu-ubuntu-2204-arm
404    if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
405    needs: [linux_tests]
406    env:
407      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
408      ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
409    steps:
410      - name: Checkout repo
411        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
412        with:
413          clean: false
414
415      - name: Install Linux dependencies
416        run: ./script/linux
417
418      - name: Determine version and release channel
419        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
420        run: |
421          # This exports RELEASE_CHANNEL into env (GITHUB_ENV)
422          script/determine-release-channel
423
424      - name: Create and upload Linux .tar.gz bundle
425        run: script/bundle-linux
426
427      - name: Upload Linux bundle to workflow run if main branch or specific label
428        uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
429        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
430        with:
431          name: zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
432          path: target/release/zed-*.tar.gz
433
434      - name: Upload app bundle to release
435        uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
436        with:
437          draft: true
438          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
439          files: |
440            target/zed-remote-server-linux-aarch64.gz
441            target/release/zed-linux-aarch64.tar.gz
442        env:
443          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
444
445  auto-release-preview:
446    name: Auto release preview
447    if: ${{ startsWith(github.ref, 'refs/tags/v') && endsWith(github.ref, '-pre') && !endsWith(github.ref, '.0-pre') }}
448    needs: [bundle-mac, bundle-linux, bundle-linux-aarch64]
449    runs-on:
450      - self-hosted
451      - bundle
452    steps:
453      - name: gh release
454        run: gh release edit $GITHUB_REF_NAME --draft=false
455        env:
456          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}