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