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