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