1use std::path::Path;
2
3use crate::tasks::workflows::{
4 release::ReleaseBundleJobs,
5 runners::{Arch, Platform, ReleaseChannel},
6 steps::{FluentBuilder, NamedJob, dependant_job, named},
7 vars::{assets, bundle_envs},
8};
9
10use super::{runners, steps};
11use gh_workflow::*;
12
13pub fn run_bundling() -> Workflow {
14 let bundle = ReleaseBundleJobs {
15 linux_aarch64: bundle_linux(Arch::AARCH64, None, &[]),
16 linux_x86_64: bundle_linux(Arch::X86_64, None, &[]),
17 mac_aarch64: bundle_mac(Arch::AARCH64, None, &[]),
18 mac_x86_64: bundle_mac(Arch::X86_64, None, &[]),
19 windows_aarch64: bundle_windows(Arch::AARCH64, None, &[]),
20 windows_x86_64: bundle_windows(Arch::X86_64, None, &[]),
21 };
22 named::workflow()
23 .on(Event::default().pull_request(
24 PullRequest::default().types([PullRequestType::Labeled, PullRequestType::Synchronize]),
25 ))
26 .concurrency(
27 Concurrency::new(Expression::new(
28 "${{ github.workflow }}-${{ github.head_ref || github.ref }}",
29 ))
30 .cancel_in_progress(true),
31 )
32 .add_env(("CARGO_TERM_COLOR", "always"))
33 .add_env(("RUST_BACKTRACE", "1"))
34 .map(|mut workflow| {
35 for job in bundle.into_jobs() {
36 workflow = workflow.add_job(job.name, job.job);
37 }
38 workflow
39 })
40}
41
42fn bundle_job(deps: &[&NamedJob]) -> Job {
43 dependant_job(deps)
44 .when(deps.len() == 0, |job|
45 job.cond(Expression::new(
46 "(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
47 (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))",
48 )))
49 .timeout_minutes(60u32)
50}
51
52pub(crate) fn bundle_mac(
53 arch: Arch,
54 release_channel: Option<ReleaseChannel>,
55 deps: &[&NamedJob],
56) -> NamedJob {
57 pub fn bundle_mac(arch: Arch) -> Step<Run> {
58 named::bash(&format!("./script/bundle-mac {arch}-apple-darwin"))
59 }
60 let platform = Platform::Mac;
61 let artifact_name = match arch {
62 Arch::X86_64 => assets::MAC_X86_64,
63 Arch::AARCH64 => assets::MAC_AARCH64,
64 };
65 let remote_server_artifact_name = match arch {
66 Arch::X86_64 => assets::REMOTE_SERVER_MAC_X86_64,
67 Arch::AARCH64 => assets::REMOTE_SERVER_MAC_AARCH64,
68 };
69 NamedJob {
70 name: format!("bundle_mac_{arch}"),
71 job: bundle_job(deps)
72 .runs_on(runners::MAC_DEFAULT)
73 .envs(bundle_envs(platform))
74 .add_step(steps::checkout_repo())
75 .when_some(release_channel, |job, release_channel| {
76 job.add_step(set_release_channel(platform, release_channel))
77 })
78 .add_step(steps::setup_node())
79 .add_step(steps::setup_sentry())
80 .add_step(steps::clear_target_dir_if_large(runners::Platform::Mac))
81 .add_step(bundle_mac(arch))
82 .add_step(upload_artifact(&format!(
83 "target/{arch}-apple-darwin/release/{artifact_name}"
84 )))
85 .add_step(upload_artifact(&format!(
86 "target/{remote_server_artifact_name}"
87 ))),
88 }
89}
90
91pub fn upload_artifact(path: &str) -> Step<Use> {
92 let name = Path::new(path).file_name().unwrap().to_str().unwrap();
93 Step::new(format!("@actions/upload-artifact {}", name))
94 .uses(
95 "actions",
96 "upload-artifact",
97 "330a01c490aca151604b8cf639adc76d48f6c5d4", // v5
98 )
99 // N.B. "name" is the name for the asset. The uploaded
100 // file retains its filename.
101 .add_with(("name", name))
102 .add_with(("path", path))
103 .add_with(("if-no-files-found", "error"))
104}
105
106pub(crate) fn bundle_linux(
107 arch: Arch,
108 release_channel: Option<ReleaseChannel>,
109 deps: &[&NamedJob],
110) -> NamedJob {
111 let platform = Platform::Linux;
112 let artifact_name = match arch {
113 Arch::X86_64 => assets::LINUX_X86_64,
114 Arch::AARCH64 => assets::LINUX_AARCH64,
115 };
116 let remote_server_artifact_name = match arch {
117 Arch::X86_64 => assets::REMOTE_SERVER_LINUX_X86_64,
118 Arch::AARCH64 => assets::REMOTE_SERVER_LINUX_AARCH64,
119 };
120 NamedJob {
121 name: format!("bundle_linux_{arch}"),
122 job: bundle_job(deps)
123 .runs_on(arch.linux_bundler())
124 .envs(bundle_envs(platform))
125 .add_step(steps::checkout_repo())
126 .when_some(release_channel, |job, release_channel| {
127 job.add_step(set_release_channel(platform, release_channel))
128 })
129 .add_step(steps::setup_sentry())
130 .map(steps::install_linux_dependencies)
131 .add_step(steps::script("./script/bundle-linux"))
132 .add_step(upload_artifact(&format!("target/release/{artifact_name}")))
133 .add_step(upload_artifact(&format!(
134 "target/{remote_server_artifact_name}"
135 ))),
136 }
137}
138
139pub(crate) fn bundle_windows(
140 arch: Arch,
141 release_channel: Option<ReleaseChannel>,
142 deps: &[&NamedJob],
143) -> NamedJob {
144 let platform = Platform::Windows;
145 pub fn bundle_windows(arch: Arch) -> Step<Run> {
146 let step = match arch {
147 Arch::X86_64 => named::pwsh("script/bundle-windows.ps1 -Architecture x86_64"),
148 Arch::AARCH64 => named::pwsh("script/bundle-windows.ps1 -Architecture aarch64"),
149 };
150 step.working_directory("${{ env.ZED_WORKSPACE }}")
151 }
152 let artifact_name = match arch {
153 Arch::X86_64 => assets::WINDOWS_X86_64,
154 Arch::AARCH64 => assets::WINDOWS_AARCH64,
155 };
156 NamedJob {
157 name: format!("bundle_windows_{arch}"),
158 job: bundle_job(deps)
159 .runs_on(runners::WINDOWS_DEFAULT)
160 .envs(bundle_envs(platform))
161 .add_step(steps::checkout_repo())
162 .when_some(release_channel, |job, release_channel| {
163 job.add_step(set_release_channel(platform, release_channel))
164 })
165 .add_step(steps::setup_sentry())
166 .add_step(bundle_windows(arch))
167 .add_step(upload_artifact(&format!("target/{artifact_name}"))),
168 }
169}
170
171fn set_release_channel(platform: Platform, release_channel: ReleaseChannel) -> Step<Run> {
172 match release_channel {
173 ReleaseChannel::Nightly => set_release_channel_to_nightly(platform),
174 }
175}
176
177fn set_release_channel_to_nightly(platform: Platform) -> Step<Run> {
178 match platform {
179 Platform::Linux | Platform::Mac => named::bash(indoc::indoc! {r#"
180 set -eu
181 version=$(git rev-parse --short HEAD)
182 echo "Publishing version: ${version} on release channel nightly"
183 echo "nightly" > crates/zed/RELEASE_CHANNEL
184 "#}),
185 Platform::Windows => named::pwsh(indoc::indoc! {r#"
186 $ErrorActionPreference = "Stop"
187 $version = git rev-parse --short HEAD
188 Write-Host "Publishing version: $version on release channel nightly"
189 "nightly" | Set-Content -Path "crates/zed/RELEASE_CHANNEL"
190 "#})
191 .working_directory("${{ env.ZED_WORKSPACE }}"),
192 }
193}