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
 14concurrency:
 15  # Allow only one workflow per any non-`main` branch.
 16  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
 17  cancel-in-progress: true
 18
 19env:
 20  CARGO_TERM_COLOR: always
 21  CARGO_INCREMENTAL: 0
 22  RUST_BACKTRACE: 1
 23
 24jobs:
 25  style:
 26    name: Check formatting and spelling
 27    runs-on:
 28      - self-hosted
 29      - test
 30    steps:
 31      - name: Checkout repo
 32        uses: actions/checkout@v4
 33        with:
 34          clean: false
 35          fetch-depth: 0
 36
 37      - name: Remove untracked files
 38        run: git clean -df
 39
 40      - name: Set up default .cargo/config.toml
 41        run: cp ./.cargo/ci-config.toml ~/.cargo/config.toml
 42
 43      - name: Check spelling
 44        run: |
 45          if ! which typos > /dev/null; then
 46            cargo install typos-cli
 47          fi
 48          typos
 49
 50      - name: Run style checks
 51        uses: ./.github/actions/check_style
 52
 53      - name: Check unused dependencies
 54        uses: bnjbvr/cargo-machete@main
 55
 56      - name: Check license generation
 57        run: script/generate-licenses /tmp/zed_licenses_output
 58
 59      - name: Ensure fresh merge
 60        shell: bash -euxo pipefail {0}
 61        run: |
 62          if [ -z "$GITHUB_BASE_REF" ];
 63          then
 64            echo "BUF_BASE_BRANCH=$(git merge-base origin/main HEAD)" >> $GITHUB_ENV
 65          else
 66            git checkout -B temp
 67            git merge -q origin/$GITHUB_BASE_REF -m "merge main into temp"
 68            echo "BUF_BASE_BRANCH=$GITHUB_BASE_REF" >> $GITHUB_ENV
 69          fi
 70
 71      - uses: bufbuild/buf-setup-action@v1
 72        with:
 73          version: v1.29.0
 74      - uses: bufbuild/buf-breaking-action@v1
 75        with:
 76          input: "crates/rpc/proto/"
 77          against: "https://github.com/${GITHUB_REPOSITORY}.git#branch=${BUF_BASE_BRANCH},subdir=crates/rpc/proto/"
 78
 79  macos_tests:
 80    name: (macOS) Run Clippy and tests
 81    runs-on:
 82      - self-hosted
 83      - test
 84    steps:
 85      - name: Checkout repo
 86        uses: actions/checkout@v4
 87        with:
 88          clean: false
 89
 90      - name: cargo clippy
 91        run: cargo xtask clippy
 92
 93      - name: Run tests
 94        uses: ./.github/actions/run_tests
 95
 96      - name: Build collab
 97        run: cargo build -p collab
 98
 99      - name: Build other binaries and features
100        run: cargo build --workspace --bins --all-features; cargo check -p gpui --features "macos-blade"
101
102  # todo(linux): Actually run the tests
103  linux_tests:
104    name: (Linux) Run Clippy and tests
105    runs-on:
106      - self-hosted
107      - deploy
108    steps:
109      - name: Add Rust to the PATH
110        run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
111
112      - name: Checkout repo
113        uses: actions/checkout@v4
114        with:
115          clean: false
116
117      - name: cargo clippy
118        run: cargo xtask clippy
119
120      - name: Build Zed
121        run: cargo build -p zed
122
123  # todo(windows): Actually run the tests
124  windows_tests:
125    name: (Windows) Run Clippy and tests
126    runs-on: hosted-windows-1
127    steps:
128      - name: Checkout repo
129        uses: actions/checkout@v4
130        with:
131          clean: false
132
133      - name: Cache dependencies
134        uses: swatinem/rust-cache@v2
135        with:
136          save-if: ${{ github.ref == 'refs/heads/main' }}
137
138      - name: cargo clippy
139        run: cargo xtask clippy
140
141      - name: Build Zed
142        run: cargo build -p zed
143
144  bundle-mac:
145    name: Create a macOS bundle
146    runs-on:
147      - self-hosted
148      - bundle
149    if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
150    needs: [macos_tests]
151    env:
152      MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
153      MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
154      APPLE_NOTARIZATION_USERNAME: ${{ secrets.APPLE_NOTARIZATION_USERNAME }}
155      APPLE_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }}
156      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
157      DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
158      DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
159    steps:
160      - name: Install Node
161        uses: actions/setup-node@v4
162        with:
163          node-version: "18"
164
165      - name: Checkout repo
166        uses: actions/checkout@v4
167        with:
168          # We need to fetch more than one commit so that `script/draft-release-notes`
169          # is able to diff between the current and previous tag.
170          #
171          # 25 was chosen arbitrarily.
172          fetch-depth: 25
173          clean: false
174
175      - name: Limit target directory size
176        run: script/clear-target-dir-if-larger-than 100
177
178      - name: Determine version and release channel
179        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
180        run: |
181          set -eu
182
183          version=$(script/get-crate-version zed)
184          channel=$(cat crates/zed/RELEASE_CHANNEL)
185          echo "Publishing version: ${version} on release channel ${channel}"
186          echo "RELEASE_CHANNEL=${channel}" >> $GITHUB_ENV
187
188          expected_tag_name=""
189          case ${channel} in
190            stable)
191              expected_tag_name="v${version}";;
192            preview)
193              expected_tag_name="v${version}-pre";;
194            nightly)
195              expected_tag_name="v${version}-nightly";;
196            *)
197              echo "can't publish a release on channel ${channel}"
198              exit 1;;
199          esac
200          if [[ $GITHUB_REF_NAME != $expected_tag_name ]]; then
201            echo "invalid release tag ${GITHUB_REF_NAME}. expected ${expected_tag_name}"
202            exit 1
203          fi
204          mkdir -p target/
205          # Ignore any errors that occur while drafting release notes to not fail the build.
206          script/draft-release-notes "$version" "$channel" > target/release-notes.md || true
207
208      - name: Generate license file
209        run: script/generate-licenses
210
211      - name: Create macOS app bundle
212        run: script/bundle-mac
213
214      - name: Rename single-architecture binaries
215        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
216        run: |
217          mv target/aarch64-apple-darwin/release/Zed.dmg target/aarch64-apple-darwin/release/Zed-aarch64.dmg
218          mv target/x86_64-apple-darwin/release/Zed.dmg target/x86_64-apple-darwin/release/Zed-x86_64.dmg
219
220      - name: Upload app bundle (universal) to workflow run if main branch or specific label
221        uses: actions/upload-artifact@v4
222        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
223        with:
224          name: Zed_${{ github.event.pull_request.head.sha || github.sha }}.dmg
225          path: target/release/Zed.dmg
226      - name: Upload app bundle (aarch64) to workflow run if main branch or specific label
227        uses: actions/upload-artifact@v4
228        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
229        with:
230          name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.dmg
231          path: target/aarch64-apple-darwin/release/Zed-aarch64.dmg
232
233      - name: Upload app bundle (x86_64) to workflow run if main branch or specific label
234        uses: actions/upload-artifact@v4
235        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
236        with:
237          name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.dmg
238          path: target/x86_64-apple-darwin/release/Zed-x86_64.dmg
239
240      - uses: softprops/action-gh-release@v1
241        name: Upload app bundle to release
242        if: ${{ env.RELEASE_CHANNEL == 'preview' || env.RELEASE_CHANNEL == 'stable' }}
243        with:
244          draft: true
245          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
246          files: |
247            target/aarch64-apple-darwin/release/Zed-aarch64.dmg
248            target/x86_64-apple-darwin/release/Zed-x86_64.dmg
249            target/release/Zed.dmg
250          body_file: target/release-notes.md
251        env:
252          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
253
254  bundle-linux:
255    name: Create a Linux bundle
256    runs-on:
257      - self-hosted
258      - deploy
259    if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
260    needs: [linux_tests]
261    env:
262      ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
263    steps:
264      - name: Add Rust to the PATH
265        run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
266
267      - name: Checkout repo
268        uses: actions/checkout@v4
269        with:
270          clean: false
271
272      - name: Limit target directory size
273        run: script/clear-target-dir-if-larger-than 100
274
275      - name: Determine version and release channel
276        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
277        run: |
278          set -eu
279
280          version=$(script/get-crate-version zed)
281          channel=$(cat crates/zed/RELEASE_CHANNEL)
282          echo "Publishing version: ${version} on release channel ${channel}"
283          echo "RELEASE_CHANNEL=${channel}" >> $GITHUB_ENV
284
285          expected_tag_name=""
286          case ${channel} in
287            stable)
288              expected_tag_name="v${version}";;
289            preview)
290              expected_tag_name="v${version}-pre";;
291            nightly)
292              expected_tag_name="v${version}-nightly";;
293            *)
294              echo "can't publish a release on channel ${channel}"
295              exit 1;;
296          esac
297          if [[ $GITHUB_REF_NAME != $expected_tag_name ]]; then
298            echo "invalid release tag ${GITHUB_REF_NAME}. expected ${expected_tag_name}"
299            exit 1
300          fi
301
302      - name: Generate license file
303        run: script/generate-licenses
304
305      - name: Create and upload Linux .tar.gz bundle
306        run: script/bundle-linux
307
308      - name: Upload Linux bundle to workflow run if main branch or specific label
309        uses: actions/upload-artifact@v4
310        if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
311        with:
312          name: zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
313          path: zed-*.tar.gz
314
315      - name: Upload app bundle to release
316        uses: softprops/action-gh-release@v1
317        if: ${{ env.RELEASE_CHANNEL == 'preview' }}
318        with:
319          draft: true
320          prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
321          files: target/release/zed-linux-x86_64.tar.gz
322          body: ""
323        env:
324          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}