1use gh_workflow::{Event, Expression, Push, Run, Step, Use, Workflow};
2
3use crate::tasks::workflows::{
4 run_bundling, run_tests, runners,
5 steps::{self, NamedJob, dependant_job, named, release_job},
6 vars,
7};
8
9pub(crate) fn release() -> Workflow {
10 let macos_tests = run_tests::run_platform_tests(runners::Platform::Mac);
11 let linux_tests = run_tests::run_platform_tests(runners::Platform::Linux);
12 let windows_tests = run_tests::run_platform_tests(runners::Platform::Windows);
13 let check_scripts = run_tests::check_scripts();
14
15 let create_draft_release = create_draft_release();
16
17 let bundle = ReleaseBundleJobs {
18 linux_arm64: bundle_linux_arm64(&[&linux_tests, &check_scripts]),
19 linux_x86_64: bundle_linux_x86_64(&[&linux_tests, &check_scripts]),
20 mac_arm64: bundle_mac_arm64(&[&macos_tests, &check_scripts]),
21 mac_x86_64: bundle_mac_x86_64(&[&macos_tests, &check_scripts]),
22 windows_arm64: bundle_windows_arm64(&[&windows_tests, &check_scripts]),
23 windows_x86_64: bundle_windows_x86_64(&[&windows_tests, &check_scripts]),
24 };
25
26 let upload_release_assets = upload_release_assets(&[&create_draft_release], &bundle);
27
28 let auto_release_preview = auto_release_preview(&[&upload_release_assets]);
29
30 named::workflow()
31 .on(Event::default().push(Push::default().tags(vec!["v*".to_string()])))
32 .concurrency(vars::one_workflow_per_non_main_branch())
33 .add_env(("CARGO_TERM_COLOR", "always"))
34 .add_env(("CARGO_INCREMENTAL", "0"))
35 .add_env(("RUST_BACKTRACE", "1"))
36 .add_env(("ZED_CLIENT_CHECKSUM_SEED", vars::ZED_CLIENT_CHECKSUM_SEED))
37 .add_env(("ZED_MINIDUMP_ENDPOINT", vars::ZED_SENTRY_MINIDUMP_ENDPOINT))
38 .add_job(macos_tests.name, macos_tests.job)
39 .add_job(linux_tests.name, linux_tests.job)
40 .add_job(windows_tests.name, windows_tests.job)
41 .add_job(check_scripts.name, check_scripts.job)
42 .add_job(create_draft_release.name, create_draft_release.job)
43 .add_job(bundle.linux_arm64.name, bundle.linux_arm64.job)
44 .add_job(bundle.linux_x86_64.name, bundle.linux_x86_64.job)
45 .add_job(bundle.mac_arm64.name, bundle.mac_arm64.job)
46 .add_job(bundle.mac_x86_64.name, bundle.mac_x86_64.job)
47 .add_job(bundle.windows_arm64.name, bundle.windows_arm64.job)
48 .add_job(bundle.windows_x86_64.name, bundle.windows_x86_64.job)
49 .add_job(upload_release_assets.name, upload_release_assets.job)
50 .add_job(auto_release_preview.name, auto_release_preview.job)
51}
52
53struct ReleaseBundleJobs {
54 linux_arm64: NamedJob,
55 linux_x86_64: NamedJob,
56 mac_arm64: NamedJob,
57 mac_x86_64: NamedJob,
58 windows_arm64: NamedJob,
59 windows_x86_64: NamedJob,
60}
61
62fn auto_release_preview(deps: &[&NamedJob; 1]) -> NamedJob {
63 fn create_sentry_release() -> Step<Use> {
64 named::uses(
65 "getsentry",
66 "action-release",
67 "526942b68292201ac6bbb99b9a0747d4abee354c", // v3
68 )
69 .add_env(("SENTRY_ORG", "zed-dev"))
70 .add_env(("SENTRY_PROJECT", "zed"))
71 .add_env(("SENTRY_AUTH_TOKEN", "${{ secrets.SENTRY_AUTH_TOKEN }}"))
72 .add_with(("environment", "production"))
73 }
74
75 named::job(
76 dependant_job(deps)
77 .runs_on(runners::LINUX_SMALL)
78 .cond(Expression::new(indoc::indoc!(
79 r#"
80 false
81 && startsWith(github.ref, 'refs/tags/v')
82 && endsWith(github.ref, '-pre') && !endsWith(github.ref, '.0-pre')
83 "# // todo(ci-release) enable
84 )))
85 .add_step(
86 steps::script(
87 r#"gh release edit "$GITHUB_REF_NAME" --repo=zed-industries/zed --draft=false"#,
88 )
89 .add_env(("GITHUB_TOKEN", "${{ secrets.GITHUB_TOKEN }}")),
90 )
91 .add_step(create_sentry_release()),
92 )
93}
94
95fn upload_release_assets(deps: &[&NamedJob], bundle_jobs: &ReleaseBundleJobs) -> NamedJob {
96 fn download_workflow_artifacts() -> Step<Use> {
97 named::uses(
98 "actions",
99 "download-artifact",
100 "018cc2cf5baa6db3ef3c5f8a56943fffe632ef53", // v6.0.0
101 )
102 .add_with(("path", "./artifacts/"))
103 }
104
105 fn prep_release_artifacts(bundle: &ReleaseBundleJobs) -> Step<Run> {
106 let assets = [
107 (&bundle.mac_x86_64.name, "zed", "Zed-x86_64.dmg"),
108 (&bundle.mac_arm64.name, "zed", "Zed-aarch64.dmg"),
109 (&bundle.windows_x86_64.name, "zed", "Zed-x86_64.exe"),
110 (&bundle.windows_arm64.name, "zed", "Zed-aarch64.exe"),
111 (&bundle.linux_arm64.name, "zed", "zed-linux-aarch64.tar.gz"),
112 (&bundle.linux_x86_64.name, "zed", "zed-linux-x86_64.tar.gz"),
113 (
114 &bundle.linux_x86_64.name,
115 "remote-server",
116 "zed-remote-server-linux-x86_64.gz",
117 ),
118 (
119 &bundle.linux_arm64.name,
120 "remote-server",
121 "zed-remote-server-linux-aarch64.gz",
122 ),
123 (
124 &bundle.mac_x86_64.name,
125 "remote-server",
126 "zed-remote-server-macos-x86_64.gz",
127 ),
128 (
129 &bundle.mac_arm64.name,
130 "remote-server",
131 "zed-remote-server-macos-aarch64.gz",
132 ),
133 ];
134
135 let mut script_lines = vec!["mkdir -p release-artifacts/\n".to_string()];
136 for (job_name, artifact_kind, release_artifact_name) in assets {
137 let artifact_path =
138 ["${{ needs.", job_name, ".outputs.", artifact_kind, " }}"].join("");
139 let mv_command = format!(
140 "mv ./artifacts/{artifact_path}/* release-artifacts/{release_artifact_name}"
141 );
142 script_lines.push(mv_command)
143 }
144
145 named::bash(&script_lines.join("\n"))
146 }
147
148 let mut deps = deps.to_vec();
149 deps.extend([
150 &bundle_jobs.linux_arm64,
151 &bundle_jobs.linux_x86_64,
152 &bundle_jobs.mac_arm64,
153 &bundle_jobs.mac_x86_64,
154 &bundle_jobs.windows_arm64,
155 &bundle_jobs.windows_x86_64,
156 ]);
157
158 named::job(
159 dependant_job(&deps)
160 .runs_on(runners::LINUX_MEDIUM)
161 .add_step(download_workflow_artifacts())
162 .add_step(steps::script("ls -lR ./artifacts"))
163 .add_step(prep_release_artifacts(bundle_jobs))
164 .add_step(
165 steps::script("gh release upload \"$GITHUB_REF_NAME\" --repo=zed-industries/zed release-artifacts/*")
166 .add_env(("GITHUB_TOKEN", "${{ secrets.GITHUB_TOKEN }}")),
167 ),
168 )
169}
170
171fn create_draft_release() -> NamedJob {
172 fn generate_release_notes() -> Step<Run> {
173 named::bash(
174 r#"node --redirect-warnings=/dev/null ./script/draft-release-notes "$RELEASE_VERSION" "$RELEASE_CHANNEL" > target/release-notes.md"#,
175 )
176 }
177
178 fn create_release() -> Step<Run> {
179 named::bash("script/create-draft-release target/release-notes.md")
180 .add_env(("GITHUB_TOKEN", "${{ secrets.GITHUB_TOKEN }}"))
181 }
182
183 named::job(
184 release_job(&[])
185 .runs_on(runners::LINUX_SMALL)
186 // We need to fetch more than one commit so that `script/draft-release-notes`
187 // is able to diff between the current and previous tag.
188 //
189 // 25 was chosen arbitrarily.
190 .add_step(
191 steps::checkout_repo()
192 .add_with(("fetch-depth", 25))
193 .add_with(("clean", false))
194 .add_with(("ref", "${{ github.ref }}")),
195 )
196 .add_step(steps::script("script/determine-release-channel")) // export RELEASE_CHANNEL and RELEASE_VERSION
197 .add_step(steps::script("mkdir -p target/"))
198 .add_step(generate_release_notes())
199 .add_step(create_release()),
200 )
201}
202
203fn bundle_mac_x86_64(deps: &[&NamedJob]) -> NamedJob {
204 named::job(run_bundling::bundle_mac_job(runners::Arch::X86_64, deps))
205}
206fn bundle_mac_arm64(deps: &[&NamedJob]) -> NamedJob {
207 named::job(run_bundling::bundle_mac_job(runners::Arch::ARM64, deps))
208}
209fn bundle_linux_x86_64(deps: &[&NamedJob]) -> NamedJob {
210 named::job(run_bundling::bundle_linux_job(runners::Arch::X86_64, deps))
211}
212fn bundle_linux_arm64(deps: &[&NamedJob]) -> NamedJob {
213 named::job(run_bundling::bundle_linux_job(runners::Arch::ARM64, deps))
214}
215fn bundle_windows_x86_64(deps: &[&NamedJob]) -> NamedJob {
216 named::job(run_bundling::bundle_windows_job(
217 runners::Arch::X86_64,
218 deps,
219 ))
220}
221fn bundle_windows_arm64(deps: &[&NamedJob]) -> NamedJob {
222 named::job(run_bundling::bundle_windows_job(runners::Arch::ARM64, deps))
223}