1use crate::tasks::workflows::{
2 run_tests::run_tests_in,
3 runners::{Arch, Platform},
4 steps::{FluentBuilder, NamedJob},
5};
6
7use super::{runners, steps, steps::named, vars};
8use gh_workflow::*;
9use indoc::indoc;
10
11/// Generates the nix.yml workflow
12pub fn nix_build() -> Workflow {
13 let linux_x86 = build_nix(
14 Platform::Linux,
15 Arch::X86_64,
16 "debug",
17 Some("-zed-editor-[0-9.]*-nightly"),
18 &[],
19 );
20 let mac_arm = build_nix(
21 Platform::Mac,
22 Arch::ARM64,
23 "debug",
24 Some("-zed-editor-[0-9.]*-nightly"),
25 &[],
26 );
27
28 named::workflow()
29 .map(|workflow| {
30 run_tests_in(
31 &[
32 "nix/**",
33 "flake.*",
34 "Cargo.*",
35 "rust-toolchain.toml",
36 ".cargo/config.toml",
37 ],
38 workflow,
39 )
40 })
41 .add_event(Event::default().workflow_call(WorkflowCall::default()))
42 .add_job(linux_x86.name, linux_x86.job)
43 .add_job(mac_arm.name, mac_arm.job)
44}
45
46pub(crate) fn build_nix(
47 platform: Platform,
48 arch: Arch,
49 flake_output: &str,
50 cachix_filter: Option<&str>,
51 deps: &[&NamedJob],
52) -> NamedJob {
53 let runner = match platform {
54 Platform::Windows => unimplemented!(),
55 Platform::Linux => runners::LINUX_X86_BUNDLER,
56 Platform::Mac => runners::MAC_DEFAULT,
57 };
58 let mut job = Job::default()
59 .timeout_minutes(60u32)
60 .continue_on_error(true)
61 .cond(Expression::new(
62 "github.repository_owner == 'zed-industries'",
63 ))
64 .runs_on(runner)
65 .add_env(("ZED_CLIENT_CHECKSUM_SEED", vars::ZED_CLIENT_CHECKSUM_SEED))
66 .add_env(("ZED_MINIDUMP_ENDPOINT", vars::ZED_SENTRY_MINIDUMP_ENDPOINT))
67 .add_env((
68 "ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON",
69 vars::ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON,
70 ))
71 .add_env(("GIT_LFS_SKIP_SMUDGE", "1")) // breaks the livekit rust sdk examples which we don't actually depend on
72 .add_step(steps::checkout_repo());
73
74 if deps.len() > 0 {
75 job = job.needs(deps.iter().map(|d| d.name.clone()).collect::<Vec<String>>());
76 }
77
78 job = if platform == Platform::Linux {
79 job.add_step(install_nix())
80 .add_step(cachix_action(cachix_filter))
81 .add_step(build(&flake_output))
82 } else {
83 job.add_step(set_path())
84 .add_step(cachix_action(cachix_filter))
85 .add_step(build(&flake_output))
86 .add_step(limit_store())
87 };
88
89 NamedJob {
90 name: format!("build_nix_{platform}_{arch}"),
91 job,
92 }
93}
94
95// on our macs we manually install nix. for some reason the cachix action is running
96// under a non-login /bin/bash shell which doesn't source the proper script to add the
97// nix profile to PATH, so we manually add them here
98pub fn set_path() -> Step<Run> {
99 named::bash(indoc! {r#"
100 echo "/nix/var/nix/profiles/default/bin" >> "$GITHUB_PATH"
101 echo "/Users/administrator/.nix-profile/bin" >> "$GITHUB_PATH"
102 "#})
103}
104
105pub fn install_nix() -> Step<Use> {
106 named::uses(
107 "cachix",
108 "install-nix-action",
109 "02a151ada4993995686f9ed4f1be7cfbb229e56f", // v31
110 )
111 .add_with(("github_access_token", vars::GITHUB_TOKEN))
112}
113
114pub fn cachix_action(cachix_filter: Option<&str>) -> Step<Use> {
115 let mut step = named::uses(
116 "cachix",
117 "cachix-action",
118 "0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad", // v16
119 )
120 .add_with(("name", "zed"))
121 .add_with(("authToken", vars::CACHIX_AUTH_TOKEN))
122 .add_with(("cachixArgs", "-v"));
123 if let Some(cachix_filter) = cachix_filter {
124 step = step.add_with(("pushFilter", cachix_filter));
125 }
126 step
127}
128
129pub fn build(flake_output: &str) -> Step<Run> {
130 named::bash(&format!(
131 "nix build .#{} -L --accept-flake-config",
132 flake_output
133 ))
134}
135
136pub fn limit_store() -> Step<Run> {
137 named::bash(indoc! {r#"
138 if [ "$(du -sm /nix/store | cut -f1)" -gt 50000 ]; then
139 nix-collect-garbage -d || true
140 fi"#
141 })
142}