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}