release_nightly.rs

  1use crate::tasks::workflows::{
  2    nix_build::build_nix,
  3    runners::{Arch, Platform},
  4    steps::NamedJob,
  5    vars::{mac_bundle_envs, windows_bundle_envs},
  6};
  7
  8use super::{runners, steps, steps::named, vars};
  9use gh_workflow::*;
 10use indexmap::IndexMap;
 11
 12/// Generates the release_nightly.yml workflow
 13pub fn release_nightly() -> Workflow {
 14    let env: IndexMap<_, _> = [
 15        ("CARGO_TERM_COLOR", "always"),
 16        ("CARGO_INCREMENTAL", "0"),
 17        ("RUST_BACKTRACE", "1"),
 18        ("ZED_CLIENT_CHECKSUM_SEED", vars::ZED_CLIENT_CHECKSUM_SEED),
 19        ("ZED_MINIDUMP_ENDPOINT", vars::ZED_SENTRY_MINIDUMP_ENDPOINT),
 20        (
 21            "DIGITALOCEAN_SPACES_ACCESS_KEY",
 22            vars::DIGITALOCEAN_SPACES_ACCESS_KEY,
 23        ),
 24        (
 25            "DIGITALOCEAN_SPACES_SECRET_KEY",
 26            vars::DIGITALOCEAN_SPACES_SECRET_KEY,
 27        ),
 28    ]
 29    .into_iter()
 30    .map(|(key, value)| (key.into(), value.into()))
 31    .collect();
 32
 33    let style = check_style();
 34    let tests = run_tests(Platform::Mac);
 35    let windows_tests = run_tests(Platform::Windows);
 36    let bundle_mac = bundle_mac_nightly(&[&style, &tests]);
 37    let linux_x86 = bundle_linux_nightly(Arch::X86_64, &[&style, &tests]);
 38    let linux_arm = bundle_linux_nightly(Arch::ARM64, &[&style, &tests]);
 39    let windows_x86 = bundle_windows_nightly(Arch::X86_64, &[&style, &windows_tests]);
 40    let windows_arm = bundle_windows_nightly(Arch::ARM64, &[&style, &windows_tests]);
 41
 42    let nix_linux_x86 = build_nix(
 43        Platform::Linux,
 44        Arch::X86_64,
 45        "default",
 46        None,
 47        &[&style, &tests],
 48    );
 49    let nix_mac_arm = build_nix(
 50        Platform::Mac,
 51        Arch::ARM64,
 52        "default",
 53        None,
 54        &[&style, &tests],
 55    );
 56    let update_nightly_tag = update_nightly_tag_job(&[
 57        &bundle_mac,
 58        &linux_x86,
 59        &linux_arm,
 60        &windows_x86,
 61        &windows_arm,
 62    ]);
 63
 64    named::workflow()
 65        .on(Event::default()
 66            // Fire every day at 7:00am UTC (Roughly before EU workday and after US workday)
 67            .schedule([Schedule::new("0 7 * * *")])
 68            .push(Push::default().add_tag("nightly")))
 69        .envs(env)
 70        .add_job(style.name, style.job)
 71        .add_job(tests.name, tests.job)
 72        .add_job(windows_tests.name, windows_tests.job)
 73        .add_job(bundle_mac.name, bundle_mac.job)
 74        .add_job(linux_x86.name, linux_x86.job)
 75        .add_job(linux_arm.name, linux_arm.job)
 76        .add_job(windows_x86.name, windows_x86.job)
 77        .add_job(windows_arm.name, windows_arm.job)
 78        .add_job(nix_linux_x86.name, nix_linux_x86.job)
 79        .add_job(nix_mac_arm.name, nix_mac_arm.job)
 80        .add_job(update_nightly_tag.name, update_nightly_tag.job)
 81}
 82
 83fn check_style() -> NamedJob {
 84    let job = release_job(&[])
 85        .runs_on(runners::MAC_DEFAULT)
 86        .add_step(
 87            steps::checkout_repo()
 88                .add_with(("clean", false))
 89                .add_with(("fetch-depth", 0)),
 90        )
 91        .add_step(steps::cargo_fmt())
 92        .add_step(steps::script("./script/clippy"));
 93
 94    named::job(job)
 95}
 96
 97fn release_job(deps: &[&NamedJob]) -> Job {
 98    let job = Job::default()
 99        .cond(Expression::new(
100            "github.repository_owner == 'zed-industries'",
101        ))
102        .timeout_minutes(60u32);
103    if deps.len() > 0 {
104        job.needs(deps.iter().map(|j| j.name.clone()).collect::<Vec<_>>())
105    } else {
106        job
107    }
108}
109
110fn run_tests(platform: Platform) -> NamedJob {
111    let runner = match platform {
112        Platform::Windows => runners::WINDOWS_DEFAULT,
113        Platform::Linux => runners::LINUX_DEFAULT,
114        Platform::Mac => runners::MAC_DEFAULT,
115    };
116    NamedJob {
117        name: format!("run_tests_{platform}"),
118        job: release_job(&[])
119            .runs_on(runner)
120            .add_step(steps::checkout_repo())
121            .add_step(steps::setup_cargo_config(platform))
122            .add_step(steps::setup_node())
123            .add_step(steps::cargo_install_nextest(platform))
124            .add_step(steps::clear_target_dir_if_large(platform))
125            .add_step(steps::cargo_nextest(platform))
126            .add_step(steps::cleanup_cargo_config(platform)),
127    }
128}
129
130fn bundle_mac_nightly(deps: &[&NamedJob]) -> NamedJob {
131    let platform = Platform::Mac;
132    let job = release_job(deps)
133        .runs_on(runners::MAC_DEFAULT)
134        .envs(mac_bundle_envs())
135        .add_step(steps::checkout_repo())
136        .add_step(steps::setup_node())
137        .add_step(steps::setup_sentry())
138        .add_step(steps::clear_target_dir_if_large(platform))
139        .add_step(set_release_channel_to_nightly(platform))
140        .add_step(steps::script("./script/bundle-mac"))
141        .add_step(upload_zed_nightly(platform, Arch::ARM64));
142    named::job(job)
143}
144
145fn bundle_linux_nightly(arch: Arch, deps: &[&NamedJob]) -> NamedJob {
146    let platform = Platform::Linux;
147    let mut job = release_job(deps)
148        .runs_on(arch.linux_bundler())
149        .add_step(steps::checkout_repo())
150        .add_step(steps::setup_sentry())
151        .add_step(add_rust_to_path())
152        .add_step(steps::script("./script/linux"));
153
154    // todo(ci) can we do this on arm too?
155    if arch == Arch::X86_64 {
156        job = job.add_step(steps::script("./script/install-mold"));
157    }
158    job = job
159        .add_step(steps::clear_target_dir_if_large(platform))
160        .add_step(set_release_channel_to_nightly(platform))
161        .add_step(steps::script("./script/bundle-linux"))
162        .add_step(upload_zed_nightly(platform, arch));
163    NamedJob {
164        name: format!("bundle_linux_nightly_{arch}"),
165        job,
166    }
167}
168
169fn bundle_windows_nightly(arch: Arch, deps: &[&NamedJob]) -> NamedJob {
170    let platform = Platform::Windows;
171    NamedJob {
172        name: format!("bundle_windows_nightly_{arch}"),
173        job: release_job(deps)
174            .runs_on(runners::WINDOWS_DEFAULT)
175            .envs(windows_bundle_envs())
176            .add_step(steps::checkout_repo())
177            .add_step(steps::setup_sentry())
178            .add_step(set_release_channel_to_nightly(platform))
179            .add_step(build_zed_installer(arch))
180            .add_step(upload_zed_nightly_windows(arch)),
181    }
182}
183
184fn update_nightly_tag_job(deps: &[&NamedJob]) -> NamedJob {
185    NamedJob {
186        name: "update_nightly_tag".to_owned(),
187        job: release_job(deps)
188            .runs_on(runners::LINUX_CHEAP)
189            .add_step(steps::checkout_repo().add_with(("fetch-depth", 0)))
190            .add_step(update_nightly_tag())
191            .add_step(create_sentry_release()),
192    }
193}
194
195fn set_release_channel_to_nightly(platform: Platform) -> Step<Run> {
196    match platform {
197        Platform::Linux | Platform::Mac => named::bash(indoc::indoc! {r#"
198            set -eu
199            version=$(git rev-parse --short HEAD)
200            echo "Publishing version: ${version} on release channel nightly"
201            echo "nightly" > crates/zed/RELEASE_CHANNEL
202        "#}),
203        Platform::Windows => named::pwsh(indoc::indoc! {r#"
204            $ErrorActionPreference = "Stop"
205            $version = git rev-parse --short HEAD
206            Write-Host "Publishing version: $version on release channel nightly"
207            "nightly" | Set-Content -Path "crates/zed/RELEASE_CHANNEL"
208        "#})
209        .working_directory("${{ env.ZED_WORKSPACE }}"),
210    }
211}
212
213fn add_rust_to_path() -> Step<Run> {
214    named::bash(r#"echo "$HOME/.cargo/bin" >> "$GITHUB_PATH""#)
215}
216
217fn upload_zed_nightly(platform: Platform, arch: Arch) -> Step<Run> {
218    match platform {
219        Platform::Linux => named::bash("script/upload-nightly linux-targz"),
220        Platform::Mac => named::bash("script/upload-nightly macos"),
221        Platform::Windows => {
222            let cmd = match arch {
223                Arch::X86_64 => "script/upload-nightly.ps1 -Architecture x86_64",
224                Arch::ARM64 => "script/upload-nightly.ps1 -Architecture aarch64",
225            };
226            named::pwsh(cmd).working_directory("${{ env.ZED_WORKSPACE }}")
227        }
228    }
229}
230
231fn build_zed_installer(arch: Arch) -> Step<Run> {
232    let cmd = match arch {
233        Arch::X86_64 => "script/bundle-windows.ps1 -Architecture x86_64",
234        Arch::ARM64 => "script/bundle-windows.ps1 -Architecture aarch64",
235    };
236    named::pwsh(cmd).working_directory("${{ env.ZED_WORKSPACE }}")
237}
238
239fn upload_zed_nightly_windows(arch: Arch) -> Step<Run> {
240    let cmd = match arch {
241        Arch::X86_64 => "script/upload-nightly.ps1 -Architecture x86_64",
242        Arch::ARM64 => "script/upload-nightly.ps1 -Architecture aarch64",
243    };
244    named::pwsh(cmd).working_directory("${{ env.ZED_WORKSPACE }}")
245}
246
247fn update_nightly_tag() -> Step<Run> {
248    named::bash(indoc::indoc! {r#"
249        if [ "$(git rev-parse nightly)" = "$(git rev-parse HEAD)" ]; then
250          echo "Nightly tag already points to current commit. Skipping tagging."
251          exit 0
252        fi
253        git config user.name github-actions
254        git config user.email github-actions@github.com
255        git tag -f nightly
256        git push origin nightly --force
257    "#})
258}
259
260fn create_sentry_release() -> Step<Use> {
261    named::uses(
262        "getsentry",
263        "action-release",
264        "526942b68292201ac6bbb99b9a0747d4abee354c", // v3
265    )
266    .add_env(("SENTRY_ORG", "zed-dev"))
267    .add_env(("SENTRY_PROJECT", "zed"))
268    .add_env(("SENTRY_AUTH_TOKEN", vars::SENTRY_AUTH_TOKEN))
269    .add_with(("environment", "production"))
270}