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