use gh_workflow::{ Concurrency, Container, Event, Expression, Job, Port, PullRequest, Push, Run, Step, Use, Workflow,};use indexmap::IndexMap;use indoc::formatdoc; use crate::tasks::workflows::{ steps::{CommonJobConditions, repository_owner_guard_expression, use_clang}, vars::{self, PathCondition},}; use super::{ runners::{self, Platform}, steps::{self, FluentBuilder, NamedJob, named, release_job},}; pub(crate) fn run_tests() -> Workflow { // Specify anything which should potentially skip full test suite in this regex: // - docs/ // - script/update_top_ranking_issues/ // - .github/ISSUE_TEMPLATE/ // - .github/workflows/ (except .github/workflows/ci.yml) let should_run_tests = PathCondition::inverted( "run_tests", r"^(docs/|script/update_top_ranking_issues/|\.github/(ISSUE_TEMPLATE|workflows/(?!run_tests)))", ); let should_check_docs = PathCondition::new("run_docs", r"^(docs/|crates/.*\.rs)"); let should_check_scripts = PathCondition::new( "run_action_checks", r"^\.github/(workflows/|actions/|actionlint.yml)|tooling/xtask|script/", ); let should_check_licences = PathCondition::new("run_licenses", r"^(Cargo.lock|script/.*licenses)"); let orchestrate = orchestrate(&[ &should_check_scripts, &should_check_docs, &should_check_licences, &should_run_tests, ]); let mut jobs = vec![ orchestrate, check_style(), should_run_tests.guard(clippy(Platform::Windows)), should_run_tests.guard(clippy(Platform::Linux)), should_run_tests.guard(clippy(Platform::Mac)), should_run_tests.guard(run_platform_tests(Platform::Windows)), should_run_tests.guard(run_platform_tests(Platform::Linux)), should_run_tests.guard(run_platform_tests(Platform::Mac)), should_run_tests.guard(doctests()), should_run_tests.guard(check_workspace_binaries()), should_run_tests.guard(check_wasm()), should_run_tests.guard(check_dependencies()), // could be more specific here? should_check_docs.guard(check_docs()), should_check_licences.guard(check_licenses()), should_check_scripts.guard(check_scripts()), ]; let tests_pass = tests_pass(&jobs); jobs.push(should_run_tests.guard(check_postgres_and_protobuf_migrations())); // could be more specific here? named::workflow() .add_event( Event::default() .push( Push::default() .add_branch("main") .add_branch("v[0-9]+.[0-9]+.x"), ) .pull_request(PullRequest::default().add_branch("**")), ) .concurrency( Concurrency::default() .group(concat!( "${{ github.workflow }}-${{ github.ref_name }}-", "${{ github.ref_name == 'main' && github.sha || 'anysha' }}" )) .cancel_in_progress(true), ) .add_env(("CARGO_TERM_COLOR", "always")) .add_env(("RUST_BACKTRACE", 1)) .add_env(("CARGO_INCREMENTAL", 0)) .map(|mut workflow| { for job in jobs { workflow = workflow.add_job(job.name, job.job) } workflow }) .add_job(tests_pass.name, tests_pass.job)} // Generates a bash script that checks changed files against regex patterns// and sets GitHub output variables accordinglypub fn orchestrate(rules: &[&PathCondition]) -> NamedJob { orchestrate_impl(rules, true)} pub fn orchestrate_without_package_filter(rules: &[&PathCondition]) -> NamedJob { orchestrate_impl(rules, false)} fn orchestrate_impl(rules: &[&PathCondition], include_package_filter: bool) -> NamedJob { let name = "orchestrate".to_owned(); let step_name = "filter".to_owned(); let mut script = String::new(); script.push_str(indoc::indoc! {r#" set -euo pipefail if [ -z "$GITHUB_BASE_REF" ]; then echo "Not in a PR context (i.e., push to main/stable/preview)" COMPARE_REV="$(git rev-parse HEAD~1)" else echo "In a PR context comparing to pull_request.base.ref" git fetch origin "$GITHUB_BASE_REF" --depth=350 COMPARE_REV="$(git merge-base "origin/${GITHUB_BASE_REF}" HEAD)" fi CHANGED_FILES="$(git diff --name-only "$COMPARE_REV" ${{ github.sha }})" check_pattern() { local output_name="$1" local pattern="$2" local grep_arg="$3" echo "$CHANGED_FILES" | grep "$grep_arg" "$pattern" && \ echo "${output_name}=true" >> "$GITHUB_OUTPUT" || \ echo "${output_name}=false" >> "$GITHUB_OUTPUT" } "#}); let mut outputs = IndexMap::new(); if include_package_filter { script.push_str(indoc::indoc! {r#" # Check for changes that require full rebuild (no filter) # Direct pushes to main/stable/preview always run full suite if [ -z "$GITHUB_BASE_REF" ]; then echo "Not a PR, running full test suite" echo "changed_packages=" >> "$GITHUB_OUTPUT" elif echo "$CHANGED_FILES" | grep -qP '^(rust-toolchain\.toml|\.cargo/|\.github/|Cargo\.(toml|lock)$)'; then echo "Toolchain, cargo config, or root Cargo files changed, will run all tests" echo "changed_packages=" >> "$GITHUB_OUTPUT" else # Extract changed directories from file paths CHANGED_DIRS=$(echo "$CHANGED_FILES" | \ grep -oP '^(crates|tooling)/\K[^/]+' | \ sort -u || true) # Build directory-to-package mapping using cargo metadata DIR_TO_PKG=$(cargo metadata --format-version=1 --no-deps 2>/dev/null | \ jq -r '.packages[] | select(.manifest_path | test("crates/|tooling/")) | "\(.manifest_path | capture("(crates|tooling)/(?<dir>[^/]+)") | .dir)=\(.name)"') # Map directory names to package names FILE_CHANGED_PKGS="" for dir in $CHANGED_DIRS; do pkg=$(echo "$DIR_TO_PKG" | grep "^${dir}=" | cut -d= -f2 | head -1) if [ -n "$pkg" ]; then FILE_CHANGED_PKGS=$(printf '%s\n%s' "$FILE_CHANGED_PKGS" "$pkg") else # Fall back to directory name if no mapping found FILE_CHANGED_PKGS=$(printf '%s\n%s' "$FILE_CHANGED_PKGS" "$dir") fi done FILE_CHANGED_PKGS=$(echo "$FILE_CHANGED_PKGS" | grep -v '^$' | sort -u || true) # If assets/ changed, add crates that depend on those assets if echo "$CHANGED_FILES" | grep -qP '^assets/'; then FILE_CHANGED_PKGS=$(printf '%s\n%s\n%s\n%s' "$FILE_CHANGED_PKGS" "settings" "storybook" "assets" | sort -u) fi # Combine all changed packages ALL_CHANGED_PKGS=$(echo "$FILE_CHANGED_PKGS" | grep -v '^$' || true) if [ -z "$ALL_CHANGED_PKGS" ]; then echo "No package changes detected, will run all tests" echo "changed_packages=" >> "$GITHUB_OUTPUT" else # Build nextest filterset with rdeps for each package FILTERSET=$(echo "$ALL_CHANGED_PKGS" | \ sed 's/.*/rdeps(&)/' | \ tr '\n' '|' | \ sed 's/|$//') echo "Changed packages filterset: $FILTERSET" echo "changed_packages=$FILTERSET" >> "$GITHUB_OUTPUT" fi fi "#}); outputs.insert( "changed_packages".to_owned(), format!("${{{{ steps.{}.outputs.changed_packages }}}}", step_name), ); } for rule in rules { assert!( rule.set_by_step .borrow_mut() .replace(name.clone()) .is_none() ); assert!( outputs .insert( rule.name.to_owned(), format!("${{{{ steps.{}.outputs.{} }}}}", step_name, rule.name) ) .is_none() ); let grep_arg = if rule.invert { "-qvP" } else { "-qP" }; script.push_str(&format!( "check_pattern \"{}\" '{}' {}\n", rule.name, rule.pattern, grep_arg )); } let job = Job::default() .runs_on(runners::LINUX_SMALL) .with_repository_owner_guard() .outputs(outputs) .add_step(steps::checkout_repo().with_deep_history_on_non_main()) .add_step(Step::new(step_name.clone()).run(script).id(step_name)); NamedJob { name, job }} pub fn tests_pass(jobs: &[NamedJob]) -> NamedJob { let mut script = String::from(indoc::indoc! {r#" set +x EXIT_CODE=0 check_result() { echo "* $1: $2" if [[ "$2" != "skipped" && "$2" != "success" ]]; then EXIT_CODE=1; fi } "#}); script.push_str( &jobs .iter() .map(|job| { format!( "check_result \"{}\" \"${{{{ needs.{}.result }}}}\"", job.name, job.name ) }) .collect::<Vec<_>>() .join("\n"), ); script.push_str("\n\nexit $EXIT_CODE\n"); let job = Job::default() .runs_on(runners::LINUX_SMALL) .needs( jobs.iter() .map(|j| j.name.to_string()) .collect::<Vec<String>>(), ) .cond(repository_owner_guard_expression(true)) .add_step(named::bash(&script)); named::job(job)} const TS_QUERY_LS_FILE: &str = "ts_query_ls-x86_64-unknown-linux-gnu.tar.gz";const CI_TS_QUERY_RELEASE: &str = "tags/v3.15.1"; pub(crate) fn fetch_ts_query_ls() -> Step<Use> { named::uses( "dsaltares", "fetch-gh-release-asset", "aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c", ) // v1.1.1 .add_with(("repo", "ribru17/ts_query_ls")) .add_with(("version", CI_TS_QUERY_RELEASE)) .add_with(("file", TS_QUERY_LS_FILE))} pub(crate) fn run_ts_query_ls() -> Step<Run> { named::bash(formatdoc!( r#"tar -xf {TS_QUERY_LS_FILE} ./ts_query_ls format --check . || {{ echo "Found unformatted queries, please format them with ts_query_ls." echo "For easy use, install the Tree-sitter query extension:" echo "zed://extension/tree-sitter-query" false }}"# ))} fn check_style() -> NamedJob { fn check_for_typos() -> Step<Use> { named::uses( "crate-ci", "typos", "2d0ce569feab1f8752f1dde43cc2f2aa53236e06", ) // v1.40.0 .with(("config", "./typos.toml")) } named::job( release_job(&[]) .runs_on(runners::LINUX_MEDIUM) .add_step(steps::checkout_repo()) .add_step(steps::cache_rust_dependencies_namespace()) .add_step(steps::setup_pnpm()) .add_step(steps::prettier()) .add_step(steps::cargo_fmt()) .add_step(steps::script("./script/check-todos")) .add_step(steps::script("./script/check-keymaps")) .add_step(check_for_typos()) .add_step(fetch_ts_query_ls()) .add_step(run_ts_query_ls()), )} fn check_dependencies() -> NamedJob { fn install_cargo_machete() -> Step<Use> { named::uses( "clechasseur", "rs-cargo", "8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386", // v2 ) .add_with(("command", "install")) .add_with(("args", "cargo-machete@0.7.0")) } fn run_cargo_machete() -> Step<Use> { named::uses( "clechasseur", "rs-cargo", "8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386", // v2 ) .add_with(("command", "machete")) } fn check_cargo_lock() -> Step<Run> { named::bash("cargo update --locked --workspace") } fn check_vulnerable_dependencies() -> Step<Use> { named::uses( "actions", "dependency-review-action", "67d4f4bd7a9b17a0db54d2a7519187c65e339de8", // v4 ) .if_condition(Expression::new("github.event_name == 'pull_request'")) .with(("license-check", false)) } named::job(use_clang( release_job(&[]) .runs_on(runners::LINUX_SMALL) .add_step(steps::checkout_repo()) .add_step(steps::cache_rust_dependencies_namespace()) .add_step(install_cargo_machete()) .add_step(run_cargo_machete()) .add_step(check_cargo_lock()) .add_step(check_vulnerable_dependencies()), ))} fn check_wasm() -> NamedJob { fn install_nightly_wasm_toolchain() -> Step<Run> { named::bash( "rustup toolchain install nightly --component rust-src --target wasm32-unknown-unknown", ) } fn cargo_check_wasm() -> Step<Run> { named::bash(concat!( "cargo +nightly -Zbuild-std=std,panic_abort ", "check --target wasm32-unknown-unknown -p gpui_platform", )) .add_env(( "CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUSTFLAGS", "-C target-feature=+atomics,+bulk-memory,+mutable-globals", )) } named::job( release_job(&[]) .runs_on(runners::LINUX_LARGE) .add_step(steps::checkout_repo()) .add_step(steps::setup_cargo_config(Platform::Linux)) .add_step(steps::cache_rust_dependencies_namespace()) .add_step(install_nightly_wasm_toolchain()) .add_step(steps::setup_sccache(Platform::Linux)) .add_step(cargo_check_wasm()) .add_step(steps::show_sccache_stats(Platform::Linux)) .add_step(steps::cleanup_cargo_config(Platform::Linux)), )} fn check_workspace_binaries() -> NamedJob { named::job(use_clang( release_job(&[]) .runs_on(runners::LINUX_LARGE) .add_step(steps::checkout_repo()) .add_step(steps::setup_cargo_config(Platform::Linux)) .add_step(steps::cache_rust_dependencies_namespace()) .map(steps::install_linux_dependencies) .add_step(steps::setup_sccache(Platform::Linux)) .add_step(steps::script("cargo build -p collab")) .add_step(steps::script("cargo build --workspace --bins --examples")) .add_step(steps::show_sccache_stats(Platform::Linux)) .add_step(steps::cleanup_cargo_config(Platform::Linux)), ))} pub(crate) fn clippy(platform: Platform) -> NamedJob { let runner = match platform { Platform::Windows => runners::WINDOWS_DEFAULT, Platform::Linux => runners::LINUX_DEFAULT, Platform::Mac => runners::MAC_DEFAULT, }; let mut job = release_job(&[]) .runs_on(runner) .add_step(steps::checkout_repo()) .add_step(steps::setup_cargo_config(platform)) .when( platform == Platform::Linux || platform == Platform::Mac, |this| this.add_step(steps::cache_rust_dependencies_namespace()), ) .when( platform == Platform::Linux, steps::install_linux_dependencies, ) .add_step(steps::setup_sccache(platform)) .add_step(steps::clippy(platform)) .add_step(steps::show_sccache_stats(platform)); if platform == Platform::Linux { job = use_clang(job); } NamedJob { name: format!("clippy_{platform}"), job, }} pub(crate) fn run_platform_tests(platform: Platform) -> NamedJob { run_platform_tests_impl(platform, true)} pub(crate) fn run_platform_tests_no_filter(platform: Platform) -> NamedJob { run_platform_tests_impl(platform, false)} fn run_platform_tests_impl(platform: Platform, filter_packages: bool) -> NamedJob { let runner = match platform { Platform::Windows => runners::WINDOWS_DEFAULT, Platform::Linux => runners::LINUX_DEFAULT, Platform::Mac => runners::MAC_DEFAULT, }; NamedJob { name: format!("run_tests_{platform}"), job: release_job(&[]) .runs_on(runner) .when(platform == Platform::Linux, |job| { job.add_service( "postgres", Container::new("postgres:15") .add_env(("POSTGRES_HOST_AUTH_METHOD", "trust")) .ports(vec![Port::Name("5432:5432".into())]) .options( "--health-cmd pg_isready \ --health-interval 500ms \ --health-timeout 5s \ --health-retries 10", ), ) }) .add_step(steps::checkout_repo()) .add_step(steps::setup_cargo_config(platform)) .when(platform == Platform::Mac, |this| { this.add_step(steps::cache_rust_dependencies_namespace()) }) .when(platform == Platform::Linux, |this| { use_clang(this.add_step(steps::cache_rust_dependencies_namespace())) }) .when( platform == Platform::Linux, steps::install_linux_dependencies, ) .add_step(steps::setup_node()) .when( platform == Platform::Linux || platform == Platform::Mac, |job| job.add_step(steps::cargo_install_nextest()), ) .add_step(steps::clear_target_dir_if_large(platform)) .add_step(steps::setup_sccache(platform)) .when(filter_packages, |job| { job.add_step( steps::cargo_nextest(platform).with_changed_packages_filter("orchestrate"),Lines 1–500 of 678. Load more
use gh_workflow::{ Concurrency, Container, Event, Expression, Job, Port, PullRequest, Push, Run, Step, Use, Workflow, }; use indexmap::IndexMap; use indoc::formatdoc; use crate::tasks::workflows::{ steps::{CommonJobConditions, repository_owner_guard_expression, use_clang}, vars::{self, PathCondition}, }; use super::{ runners::{self, Platform}, steps::{self, FluentBuilder, NamedJob, named, release_job}, }; pub(crate) fn run_tests() -> Workflow { // Specify anything which should potentially skip full test suite in this regex: // - docs/ // - script/update_top_ranking_issues/ // - .github/ISSUE_TEMPLATE/ // - .github/workflows/ (except .github/workflows/ci.yml) let should_run_tests = PathCondition::inverted( "run_tests", r"^(docs/|script/update_top_ranking_issues/|\.github/(ISSUE_TEMPLATE|workflows/(?!run_tests)))", ); let should_check_docs = PathCondition::new("run_docs", r"^(docs/|crates/.*\.rs)"); let should_check_scripts = PathCondition::new( "run_action_checks", r"^\.github/(workflows/|actions/|actionlint.yml)|tooling/xtask|script/", ); let should_check_licences = PathCondition::new("run_licenses", r"^(Cargo.lock|script/.*licenses)"); let orchestrate = orchestrate(&[ &should_check_scripts, &should_check_docs, &should_check_licences, &should_run_tests, ]); let mut jobs = vec![ orchestrate, check_style(), should_run_tests.guard(clippy(Platform::Windows)), should_run_tests.guard(clippy(Platform::Linux)), should_run_tests.guard(clippy(Platform::Mac)), should_run_tests.guard(run_platform_tests(Platform::Windows)), should_run_tests.guard(run_platform_tests(Platform::Linux)), should_run_tests.guard(run_platform_tests(Platform::Mac)), should_run_tests.guard(doctests()), should_run_tests.guard(check_workspace_binaries()), should_run_tests.guard(check_wasm()), should_run_tests.guard(check_dependencies()), // could be more specific here? should_check_docs.guard(check_docs()), should_check_licences.guard(check_licenses()), should_check_scripts.guard(check_scripts()), ]; let tests_pass = tests_pass(&jobs); jobs.push(should_run_tests.guard(check_postgres_and_protobuf_migrations())); // could be more specific here? named::workflow() .add_event( Event::default() .push( Push::default() .add_branch("main") .add_branch("v[0-9]+.[0-9]+.x"), ) .pull_request(PullRequest::default().add_branch("**")), ) .concurrency( Concurrency::default() .group(concat!( "${{ github.workflow }}-${{ github.ref_name }}-", "${{ github.ref_name == 'main' && github.sha || 'anysha' }}" )) .cancel_in_progress(true), ) .add_env(("CARGO_TERM_COLOR", "always")) .add_env(("RUST_BACKTRACE", 1)) .add_env(("CARGO_INCREMENTAL", 0)) .map(|mut workflow| { for job in jobs { workflow = workflow.add_job(job.name, job.job) } workflow }) .add_job(tests_pass.name, tests_pass.job) } // Generates a bash script that checks changed files against regex patterns // and sets GitHub output variables accordingly pub fn orchestrate(rules: &[&PathCondition]) -> NamedJob { orchestrate_impl(rules, true) } pub fn orchestrate_without_package_filter(rules: &[&PathCondition]) -> NamedJob { orchestrate_impl(rules, false) } fn orchestrate_impl(rules: &[&PathCondition], include_package_filter: bool) -> NamedJob { let name = "orchestrate".to_owned(); let step_name = "filter".to_owned(); let mut script = String::new(); script.push_str(indoc::indoc! {r#" set -euo pipefail if [ -z "$GITHUB_BASE_REF" ]; then echo "Not in a PR context (i.e., push to main/stable/preview)" COMPARE_REV="$(git rev-parse HEAD~1)" else echo "In a PR context comparing to pull_request.base.ref" git fetch origin "$GITHUB_BASE_REF" --depth=350 COMPARE_REV="$(git merge-base "origin/${GITHUB_BASE_REF}" HEAD)" fi CHANGED_FILES="$(git diff --name-only "$COMPARE_REV" ${{ github.sha }})" check_pattern() { local output_name="$1" local pattern="$2" local grep_arg="$3" echo "$CHANGED_FILES" | grep "$grep_arg" "$pattern" && \ echo "${output_name}=true" >> "$GITHUB_OUTPUT" || \ echo "${output_name}=false" >> "$GITHUB_OUTPUT" } "#}); let mut outputs = IndexMap::new(); if include_package_filter { script.push_str(indoc::indoc! {r#" # Check for changes that require full rebuild (no filter) # Direct pushes to main/stable/preview always run full suite if [ -z "$GITHUB_BASE_REF" ]; then echo "Not a PR, running full test suite" echo "changed_packages=" >> "$GITHUB_OUTPUT" elif echo "$CHANGED_FILES" | grep -qP '^(rust-toolchain\.toml|\.cargo/|\.github/|Cargo\.(toml|lock)$)'; then echo "Toolchain, cargo config, or root Cargo files changed, will run all tests" echo "changed_packages=" >> "$GITHUB_OUTPUT" else # Extract changed directories from file paths CHANGED_DIRS=$(echo "$CHANGED_FILES" | \ grep -oP '^(crates|tooling)/\K[^/]+' | \ sort -u || true) # Build directory-to-package mapping using cargo metadata DIR_TO_PKG=$(cargo metadata --format-version=1 --no-deps 2>/dev/null | \ jq -r '.packages[] | select(.manifest_path | test("crates/|tooling/")) | "\(.manifest_path | capture("(crates|tooling)/(?<dir>[^/]+)") | .dir)=\(.name)"') # Map directory names to package names FILE_CHANGED_PKGS="" for dir in $CHANGED_DIRS; do pkg=$(echo "$DIR_TO_PKG" | grep "^${dir}=" | cut -d= -f2 | head -1) if [ -n "$pkg" ]; then FILE_CHANGED_PKGS=$(printf '%s\n%s' "$FILE_CHANGED_PKGS" "$pkg") else # Fall back to directory name if no mapping found FILE_CHANGED_PKGS=$(printf '%s\n%s' "$FILE_CHANGED_PKGS" "$dir") fi done FILE_CHANGED_PKGS=$(echo "$FILE_CHANGED_PKGS" | grep -v '^$' | sort -u || true) # If assets/ changed, add crates that depend on those assets if echo "$CHANGED_FILES" | grep -qP '^assets/'; then FILE_CHANGED_PKGS=$(printf '%s\n%s\n%s\n%s' "$FILE_CHANGED_PKGS" "settings" "storybook" "assets" | sort -u) fi # Combine all changed packages ALL_CHANGED_PKGS=$(echo "$FILE_CHANGED_PKGS" | grep -v '^$' || true) if [ -z "$ALL_CHANGED_PKGS" ]; then echo "No package changes detected, will run all tests" echo "changed_packages=" >> "$GITHUB_OUTPUT" else # Build nextest filterset with rdeps for each package FILTERSET=$(echo "$ALL_CHANGED_PKGS" | \ sed 's/.*/rdeps(&)/' | \ tr '\n' '|' | \ sed 's/|$//') echo "Changed packages filterset: $FILTERSET" echo "changed_packages=$FILTERSET" >> "$GITHUB_OUTPUT" fi fi "#}); outputs.insert( "changed_packages".to_owned(), format!("${{{{ steps.{}.outputs.changed_packages }}}}", step_name), ); } for rule in rules { assert!( rule.set_by_step .borrow_mut() .replace(name.clone()) .is_none() ); assert!( outputs .insert( rule.name.to_owned(), format!("${{{{ steps.{}.outputs.{} }}}}", step_name, rule.name) ) .is_none() ); let grep_arg = if rule.invert { "-qvP" } else { "-qP" }; script.push_str(&format!( "check_pattern \"{}\" '{}' {}\n", rule.name, rule.pattern, grep_arg )); } let job = Job::default() .runs_on(runners::LINUX_SMALL) .with_repository_owner_guard() .outputs(outputs) .add_step(steps::checkout_repo().with_deep_history_on_non_main()) .add_step(Step::new(step_name.clone()).run(script).id(step_name)); NamedJob { name, job } } pub fn tests_pass(jobs: &[NamedJob]) -> NamedJob { let mut script = String::from(indoc::indoc! {r#" set +x EXIT_CODE=0 check_result() { echo "* $1: $2" if [[ "$2" != "skipped" && "$2" != "success" ]]; then EXIT_CODE=1; fi } "#}); script.push_str( &jobs .iter() .map(|job| { format!( "check_result \"{}\" \"${{{{ needs.{}.result }}}}\"", job.name, job.name ) }) .collect::<Vec<_>>() .join("\n"), ); script.push_str("\n\nexit $EXIT_CODE\n"); let job = Job::default() .runs_on(runners::LINUX_SMALL) .needs( jobs.iter() .map(|j| j.name.to_string()) .collect::<Vec<String>>(), ) .cond(repository_owner_guard_expression(true)) .add_step(named::bash(&script)); named::job(job) } const TS_QUERY_LS_FILE: &str = "ts_query_ls-x86_64-unknown-linux-gnu.tar.gz"; const CI_TS_QUERY_RELEASE: &str = "tags/v3.15.1"; pub(crate) fn fetch_ts_query_ls() -> Step<Use> { named::uses( "dsaltares", "fetch-gh-release-asset", "aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c", ) // v1.1.1 .add_with(("repo", "ribru17/ts_query_ls")) .add_with(("version", CI_TS_QUERY_RELEASE)) .add_with(("file", TS_QUERY_LS_FILE)) } pub(crate) fn run_ts_query_ls() -> Step<Run> { named::bash(formatdoc!( r#"tar -xf {TS_QUERY_LS_FILE} ./ts_query_ls format --check . || {{ echo "Found unformatted queries, please format them with ts_query_ls." echo "For easy use, install the Tree-sitter query extension:" echo "zed://extension/tree-sitter-query" false }}"# )) } fn check_style() -> NamedJob { fn check_for_typos() -> Step<Use> { named::uses( "crate-ci", "typos", "2d0ce569feab1f8752f1dde43cc2f2aa53236e06", ) // v1.40.0 .with(("config", "./typos.toml")) } named::job( release_job(&[]) .runs_on(runners::LINUX_MEDIUM) .add_step(steps::checkout_repo()) .add_step(steps::cache_rust_dependencies_namespace()) .add_step(steps::setup_pnpm()) .add_step(steps::prettier()) .add_step(steps::cargo_fmt()) .add_step(steps::script("./script/check-todos")) .add_step(steps::script("./script/check-keymaps")) .add_step(check_for_typos()) .add_step(fetch_ts_query_ls()) .add_step(run_ts_query_ls()), ) } fn check_dependencies() -> NamedJob { fn install_cargo_machete() -> Step<Use> { named::uses( "clechasseur", "rs-cargo", "8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386", // v2 ) .add_with(("command", "install")) .add_with(("args", "cargo-machete@0.7.0")) } fn run_cargo_machete() -> Step<Use> { named::uses( "clechasseur", "rs-cargo", "8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386", // v2 ) .add_with(("command", "machete")) } fn check_cargo_lock() -> Step<Run> { named::bash("cargo update --locked --workspace") } fn check_vulnerable_dependencies() -> Step<Use> { named::uses( "actions", "dependency-review-action", "67d4f4bd7a9b17a0db54d2a7519187c65e339de8", // v4 ) .if_condition(Expression::new("github.event_name == 'pull_request'")) .with(("license-check", false)) } named::job(use_clang( release_job(&[]) .runs_on(runners::LINUX_SMALL) .add_step(steps::checkout_repo()) .add_step(steps::cache_rust_dependencies_namespace()) .add_step(install_cargo_machete()) .add_step(run_cargo_machete()) .add_step(check_cargo_lock()) .add_step(check_vulnerable_dependencies()), )) } fn check_wasm() -> NamedJob { fn install_nightly_wasm_toolchain() -> Step<Run> { named::bash( "rustup toolchain install nightly --component rust-src --target wasm32-unknown-unknown", ) } fn cargo_check_wasm() -> Step<Run> { named::bash(concat!( "cargo +nightly -Zbuild-std=std,panic_abort ", "check --target wasm32-unknown-unknown -p gpui_platform", )) .add_env(( "CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUSTFLAGS", "-C target-feature=+atomics,+bulk-memory,+mutable-globals", )) } named::job( release_job(&[]) .runs_on(runners::LINUX_LARGE) .add_step(steps::checkout_repo()) .add_step(steps::setup_cargo_config(Platform::Linux)) .add_step(steps::cache_rust_dependencies_namespace()) .add_step(install_nightly_wasm_toolchain()) .add_step(steps::setup_sccache(Platform::Linux)) .add_step(cargo_check_wasm()) .add_step(steps::show_sccache_stats(Platform::Linux)) .add_step(steps::cleanup_cargo_config(Platform::Linux)), ) } fn check_workspace_binaries() -> NamedJob { named::job(use_clang( release_job(&[]) .runs_on(runners::LINUX_LARGE) .add_step(steps::checkout_repo()) .add_step(steps::setup_cargo_config(Platform::Linux)) .add_step(steps::cache_rust_dependencies_namespace()) .map(steps::install_linux_dependencies) .add_step(steps::setup_sccache(Platform::Linux)) .add_step(steps::script("cargo build -p collab")) .add_step(steps::script("cargo build --workspace --bins --examples")) .add_step(steps::show_sccache_stats(Platform::Linux)) .add_step(steps::cleanup_cargo_config(Platform::Linux)), )) } pub(crate) fn clippy(platform: Platform) -> NamedJob { let runner = match platform { Platform::Windows => runners::WINDOWS_DEFAULT, Platform::Linux => runners::LINUX_DEFAULT, Platform::Mac => runners::MAC_DEFAULT, }; let mut job = release_job(&[]) .runs_on(runner) .add_step(steps::checkout_repo()) .add_step(steps::setup_cargo_config(platform)) .when( platform == Platform::Linux || platform == Platform::Mac, |this| this.add_step(steps::cache_rust_dependencies_namespace()), ) .when( platform == Platform::Linux, steps::install_linux_dependencies, ) .add_step(steps::setup_sccache(platform)) .add_step(steps::clippy(platform)) .add_step(steps::show_sccache_stats(platform)); if platform == Platform::Linux { job = use_clang(job); } NamedJob { name: format!("clippy_{platform}"), job, } } pub(crate) fn run_platform_tests(platform: Platform) -> NamedJob { run_platform_tests_impl(platform, true) } pub(crate) fn run_platform_tests_no_filter(platform: Platform) -> NamedJob { run_platform_tests_impl(platform, false) } fn run_platform_tests_impl(platform: Platform, filter_packages: bool) -> NamedJob { let runner = match platform { Platform::Windows => runners::WINDOWS_DEFAULT, Platform::Linux => runners::LINUX_DEFAULT, Platform::Mac => runners::MAC_DEFAULT, }; NamedJob { name: format!("run_tests_{platform}"), job: release_job(&[]) .runs_on(runner) .when(platform == Platform::Linux, |job| { job.add_service( "postgres", Container::new("postgres:15") .add_env(("POSTGRES_HOST_AUTH_METHOD", "trust")) .ports(vec![Port::Name("5432:5432".into())]) .options( "--health-cmd pg_isready \ --health-interval 500ms \ --health-timeout 5s \ --health-retries 10", ), ) }) .add_step(steps::checkout_repo()) .add_step(steps::setup_cargo_config(platform)) .when(platform == Platform::Mac, |this| { this.add_step(steps::cache_rust_dependencies_namespace()) }) .when(platform == Platform::Linux, |this| { use_clang(this.add_step(steps::cache_rust_dependencies_namespace())) }) .when( platform == Platform::Linux, steps::install_linux_dependencies, ) .add_step(steps::setup_node()) .when( platform == Platform::Linux || platform == Platform::Mac, |job| job.add_step(steps::cargo_install_nextest()), ) .add_step(steps::clear_target_dir_if_large(platform)) .add_step(steps::setup_sccache(platform)) .when(filter_packages, |job| { job.add_step( steps::cargo_nextest(platform).with_changed_packages_filter("orchestrate"),