diff --git a/.github/workflows/after_release.yml b/.github/workflows/after_release.yml index f9412672b3dd0fc5e029b3e0dc0c7a93d8582aa2..2e75659de0bdf51f4586ef57770fd54dc4eeb074 100644 --- a/.github/workflows/after_release.yml +++ b/.github/workflows/after_release.yml @@ -7,7 +7,7 @@ on: - published jobs: rebuild_releases_page: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: namespace-profile-2x4-ubuntu-2404 steps: - name: after_release::rebuild_releases_page::refresh_cloud_releases @@ -21,7 +21,7 @@ jobs: post_to_discord: needs: - rebuild_releases_page - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: namespace-profile-2x4-ubuntu-2404 steps: - id: get-release-url @@ -71,7 +71,7 @@ jobs: max-versions-to-keep: 5 token: ${{ secrets.WINGET_TOKEN }} create_sentry_release: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: namespace-profile-2x4-ubuntu-2404 steps: - name: steps::checkout_repo diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml index 054767e5f1fd86c2a5b8fa2112802e797ec10f6e..9d6054eb3e7546088d29dd9c6316a3494ea6fb17 100644 --- a/.github/workflows/danger.yml +++ b/.github/workflows/danger.yml @@ -12,7 +12,7 @@ on: - main jobs: danger: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: namespace-profile-2x4-ubuntu-2404 steps: - name: steps::checkout_repo diff --git a/.github/workflows/extension_tests.yml b/.github/workflows/extension_tests.yml new file mode 100644 index 0000000000000000000000000000000000000000..89289fbea20999ada413ef1801bb428f03c82c6b --- /dev/null +++ b/.github/workflows/extension_tests.yml @@ -0,0 +1,138 @@ +# Generated from xtask::workflows::extension_tests +# Rebuild with `cargo xtask workflows`. +name: extension_tests +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: '1' + CARGO_INCREMENTAL: '0' + ZED_EXTENSION_CLI_SHA: 7cfce605704d41ca247e3f84804bf323f6c6caaf +on: + workflow_call: + inputs: + run_tests: + description: Whether the workflow should run rust tests + required: true + type: boolean +jobs: + orchestrate: + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') + runs-on: namespace-profile-2x4-ubuntu-2404 + steps: + - name: steps::checkout_repo + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + clean: false + fetch-depth: ${{ github.ref == 'refs/heads/main' && 2 || 350 }} + - id: filter + name: filter + run: | + 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" + } + + check_pattern "check_rust" '^(Cargo.lock|Cargo.toml|.*\.rs)$' -qP + check_pattern "check_extension" '^.*\.scm$' -qP + shell: bash -euxo pipefail {0} + outputs: + check_rust: ${{ steps.filter.outputs.check_rust }} + check_extension: ${{ steps.filter.outputs.check_extension }} + check_rust: + needs: + - orchestrate + if: needs.orchestrate.outputs.check_rust == 'true' + runs-on: namespace-profile-16x32-ubuntu-2204 + steps: + - name: steps::checkout_repo + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + clean: false + - name: steps::cache_rust_dependencies_namespace + uses: namespacelabs/nscloud-cache-action@v1 + with: + cache: rust + - name: steps::cargo_fmt + run: cargo fmt --all -- --check + shell: bash -euxo pipefail {0} + - name: extension_tests::run_clippy + run: cargo clippy --release --all-targets --all-features -- --deny warnings + shell: bash -euxo pipefail {0} + - name: steps::cargo_install_nextest + if: inputs.run_tests + uses: taiki-e/install-action@nextest + - name: steps::cargo_nextest + if: inputs.run_tests + run: cargo nextest run --workspace --no-fail-fast --failure-output immediate-final + shell: bash -euxo pipefail {0} + timeout-minutes: 3 + check_extension: + needs: + - orchestrate + if: needs.orchestrate.outputs.check_extension == 'true' + runs-on: namespace-profile-2x4-ubuntu-2404 + steps: + - name: steps::checkout_repo + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + clean: false + - id: cache-zed-extension-cli + name: extension_tests::cache_zed_extension_cli + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 + with: + path: zed-extension + key: zed-extension-${{ env.ZED_EXTENSION_CLI_SHA }} + - name: extension_tests::download_zed_extension_cli + if: steps.cache-zed-extension-cli.outputs.cache-hit != 'true' + run: | + wget --quiet "https://zed-extension-cli.nyc3.digitaloceanspaces.com/$ZED_EXTENSION_CLI_SHA/x86_64-unknown-linux-gnu/zed-extension" + chmod +x zed-extension + shell: bash -euxo pipefail {0} + - name: extension_tests::check + run: | + mkdir -p /tmp/ext-scratch + mkdir -p /tmp/ext-output + ./zed-extension --source-dir . --scratch-dir /tmp/ext-scratch --output-dir /tmp/ext-output + shell: bash -euxo pipefail {0} + timeout-minutes: 1 + tests_pass: + needs: + - orchestrate + - check_rust + - check_extension + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') && always() + runs-on: namespace-profile-2x4-ubuntu-2404 + steps: + - name: run_tests::tests_pass + run: | + set +x + EXIT_CODE=0 + + check_result() { + echo "* $1: $2" + if [[ "$2" != "skipped" && "$2" != "success" ]]; then EXIT_CODE=1; fi + } + + check_result "orchestrate" "${{ needs.orchestrate.result }}" + check_result "check_rust" "${{ needs.check_rust.result }}" + check_result "check_extension" "${{ needs.check_extension.result }}" + + exit $EXIT_CODE + shell: bash -euxo pipefail {0} +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }} + cancel-in-progress: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d591ebc509fb9347daf41614c7b53f09a5ec0312..90d105880f94ee428f01746ed627f5c6f7d4e246 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ on: - v* jobs: run_tests_mac: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: self-mini-macos steps: - name: steps::checkout_repo @@ -42,7 +42,7 @@ jobs: shell: bash -euxo pipefail {0} timeout-minutes: 60 run_tests_linux: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: namespace-profile-16x32-ubuntu-2204 steps: - name: steps::checkout_repo @@ -89,7 +89,7 @@ jobs: shell: bash -euxo pipefail {0} timeout-minutes: 60 run_tests_windows: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: self-32vcpu-windows-2022 steps: - name: steps::checkout_repo @@ -121,7 +121,7 @@ jobs: shell: pwsh timeout-minutes: 60 check_scripts: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: namespace-profile-2x4-ubuntu-2404 steps: - name: steps::checkout_repo @@ -150,7 +150,7 @@ jobs: shell: bash -euxo pipefail {0} timeout-minutes: 60 create_draft_release: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: namespace-profile-2x4-ubuntu-2404 steps: - name: steps::checkout_repo diff --git a/.github/workflows/release_nightly.yml b/.github/workflows/release_nightly.yml index 0604aad15531fc7f013b4790ba1e0efa9c21eb52..bb327f2c5527d353c9aad01c3e26edcf5baac78c 100644 --- a/.github/workflows/release_nightly.yml +++ b/.github/workflows/release_nightly.yml @@ -12,7 +12,7 @@ on: - cron: 0 7 * * * jobs: check_style: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: self-mini-macos steps: - name: steps::checkout_repo @@ -28,7 +28,7 @@ jobs: shell: bash -euxo pipefail {0} timeout-minutes: 60 run_tests_windows: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: self-32vcpu-windows-2022 steps: - name: steps::checkout_repo @@ -361,7 +361,7 @@ jobs: needs: - check_style - run_tests_windows - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: namespace-profile-32x64-ubuntu-2004 env: ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }} @@ -392,7 +392,7 @@ jobs: needs: - check_style - run_tests_windows - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: self-mini-macos env: ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }} @@ -434,7 +434,7 @@ jobs: - bundle_mac_x86_64 - bundle_windows_aarch64 - bundle_windows_x86_64 - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: namespace-profile-4x8-ubuntu-2204 steps: - name: steps::checkout_repo diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 2322f5d7659366ec312bc76b7501afdab86ff5dc..883be0c1905507639664e6d1f35b4c7e48d0928e 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -15,7 +15,7 @@ on: - v[0-9]+.[0-9]+.x jobs: orchestrate: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: namespace-profile-2x4-ubuntu-2404 steps: - name: steps::checkout_repo @@ -59,7 +59,7 @@ jobs: run_nix: ${{ steps.filter.outputs.run_nix }} run_tests: ${{ steps.filter.outputs.run_tests }} check_style: - if: github.repository_owner == 'zed-industries' + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') runs-on: namespace-profile-4x8-ubuntu-2204 steps: - name: steps::checkout_repo @@ -538,7 +538,7 @@ jobs: - check_scripts - build_nix_linux_x86_64 - build_nix_mac_aarch64 - if: github.repository_owner == 'zed-industries' && always() + if: (github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions') && always() runs-on: namespace-profile-2x4-ubuntu-2404 steps: - name: run_tests::tests_pass diff --git a/tooling/xtask/src/tasks/workflows.rs b/tooling/xtask/src/tasks/workflows.rs index 374a22f3ea9c65dcfc9743f77448a5c29117cedf..31ca9590f1d6c8c935da4056930db470913656c9 100644 --- a/tooling/xtask/src/tasks/workflows.rs +++ b/tooling/xtask/src/tasks/workflows.rs @@ -7,6 +7,7 @@ mod after_release; mod cherry_pick; mod compare_perf; mod danger; +mod extension_tests; mod nix_build; mod release_nightly; mod run_bundling; @@ -39,6 +40,7 @@ pub fn run_workflows(_: GenerateWorkflowArgs) -> Result<()> { ), ("run_agent_evals.yml", run_agent_evals::run_agent_evals()), ("after_release.yml", after_release::after_release()), + ("extension_tests.yml", extension_tests::extension_tests()), ]; fs::create_dir_all(dir) .with_context(|| format!("Failed to create directory: {}", dir.display()))?; diff --git a/tooling/xtask/src/tasks/workflows/after_release.rs b/tooling/xtask/src/tasks/workflows/after_release.rs index d626faf52098a41c531eab0f13f4d727ea7a7cf9..c99173bfe7183b5a3440804a18e0133270744654 100644 --- a/tooling/xtask/src/tasks/workflows/after_release.rs +++ b/tooling/xtask/src/tasks/workflows/after_release.rs @@ -3,7 +3,7 @@ use gh_workflow::*; use crate::tasks::workflows::{ release::{self, notify_on_failure}, runners, - steps::{NamedJob, checkout_repo, dependant_job, named}, + steps::{CommonJobConditions, NamedJob, checkout_repo, dependant_job, named}, vars::{self, StepOutput}, }; @@ -43,9 +43,7 @@ fn rebuild_releases_page() -> NamedJob { named::job( Job::default() .runs_on(runners::LINUX_SMALL) - .cond(Expression::new( - "github.repository_owner == 'zed-industries'", - )) + .with_repository_owner_guard() .add_step(refresh_cloud_releases()) .add_step(redeploy_zed_dev()), ) @@ -95,9 +93,7 @@ fn post_to_discord(deps: &[&NamedJob]) -> NamedJob { } let job = dependant_job(deps) .runs_on(runners::LINUX_SMALL) - .cond(Expression::new( - "github.repository_owner == 'zed-industries'", - )) + .with_repository_owner_guard() .add_step(get_release_url()) .add_step(get_content()) .add_step(discord_webhook_action()); @@ -145,9 +141,7 @@ fn publish_winget() -> NamedJob { fn create_sentry_release() -> NamedJob { let job = Job::default() .runs_on(runners::LINUX_SMALL) - .cond(Expression::new( - "github.repository_owner == 'zed-industries'", - )) + .with_repository_owner_guard() .add_step(checkout_repo()) .add_step(release::create_sentry_release()); named::job(job) diff --git a/tooling/xtask/src/tasks/workflows/danger.rs b/tooling/xtask/src/tasks/workflows/danger.rs index eed2cba732292e5851468766084e846f366b3edc..8b3bf0ac3a855f096da096dcf8f8204bd7aaac42 100644 --- a/tooling/xtask/src/tasks/workflows/danger.rs +++ b/tooling/xtask/src/tasks/workflows/danger.rs @@ -1,6 +1,6 @@ use gh_workflow::*; -use crate::tasks::workflows::steps::{NamedJob, named}; +use crate::tasks::workflows::steps::{CommonJobConditions, NamedJob, named}; use super::{runners, steps}; @@ -42,9 +42,7 @@ fn danger_job() -> NamedJob { NamedJob { name: "danger".to_string(), job: Job::default() - .cond(Expression::new( - "github.repository_owner == 'zed-industries'", - )) + .with_repository_owner_guard() .runs_on(runners::LINUX_SMALL) .add_step(steps::checkout_repo()) .add_step(steps::setup_pnpm()) diff --git a/tooling/xtask/src/tasks/workflows/extension_tests.rs b/tooling/xtask/src/tasks/workflows/extension_tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..4ee094fd37608c2427037effac3a6afa182014ba --- /dev/null +++ b/tooling/xtask/src/tasks/workflows/extension_tests.rs @@ -0,0 +1,129 @@ +use gh_workflow::*; +use indoc::indoc; + +use crate::tasks::workflows::{ + run_tests::{orchestrate, tests_pass}, + runners, + steps::{self, CommonJobConditions, FluentBuilder, NamedJob, named}, + vars::{PathCondition, StepOutput, one_workflow_per_non_main_branch}, +}; + +const RUN_TESTS_INPUT: &str = "run_tests"; +const ZED_EXTENSION_CLI_SHA: &str = "7cfce605704d41ca247e3f84804bf323f6c6caaf"; + +// This is used by various extensions repos in the zed-extensions org to run automated tests. +pub(crate) fn extension_tests() -> Workflow { + let should_check_rust = PathCondition::new("check_rust", r"^(Cargo.lock|Cargo.toml|.*\.rs)$"); + let should_check_extension = PathCondition::new("check_extension", r"^.*\.scm$"); + + let orchestrate = orchestrate(&[&should_check_rust, &should_check_extension]); + + let jobs = [ + orchestrate, + should_check_rust.guard(check_rust()), + should_check_extension.guard(check_extension()), + ]; + + let tests_pass = tests_pass(&jobs); + + named::workflow() + .add_event( + Event::default().workflow_call(WorkflowCall::default().add_input( + RUN_TESTS_INPUT, + WorkflowCallInput { + description: "Whether the workflow should run rust tests".into(), + required: true, + input_type: "boolean".into(), + default: None, + }, + )), + ) + .concurrency(one_workflow_per_non_main_branch()) + .add_env(("CARGO_TERM_COLOR", "always")) + .add_env(("RUST_BACKTRACE", 1)) + .add_env(("CARGO_INCREMENTAL", 0)) + .add_env(("ZED_EXTENSION_CLI_SHA", ZED_EXTENSION_CLI_SHA)) + .map(|workflow| { + jobs.into_iter() + .chain([tests_pass]) + .fold(workflow, |workflow, job| { + workflow.add_job(job.name, job.job) + }) + }) +} + +fn run_clippy() -> Step { + named::bash("cargo clippy --release --all-targets --all-features -- --deny warnings") +} + +fn check_rust() -> NamedJob { + let job = Job::default() + .with_repository_owner_guard() + .runs_on(runners::LINUX_DEFAULT) + .timeout_minutes(3u32) + .add_step(steps::checkout_repo()) + .add_step(steps::cache_rust_dependencies_namespace()) + .add_step(steps::cargo_fmt()) + .add_step(run_clippy()) + .add_step( + steps::cargo_install_nextest() + .if_condition(Expression::new(format!("inputs.{RUN_TESTS_INPUT}"))), + ) + .add_step( + steps::cargo_nextest(runners::Platform::Linux) + .if_condition(Expression::new(format!("inputs.{RUN_TESTS_INPUT}"))), + ); + + named::job(job) +} + +fn check_extension() -> NamedJob { + let (cache_download, cache_hit) = cache_zed_extension_cli(); + let job = Job::default() + .with_repository_owner_guard() + .runs_on(runners::LINUX_SMALL) + .timeout_minutes(1u32) + .add_step(steps::checkout_repo()) + .add_step(cache_download) + .add_step(download_zed_extension_cli(cache_hit)) + .add_step(check()); + + named::job(job) +} + +pub fn cache_zed_extension_cli() -> (Step, StepOutput) { + let step = named::uses( + "actions", + "cache", + "0057852bfaa89a56745cba8c7296529d2fc39830", + ) + .id("cache-zed-extension-cli") + .with( + Input::default() + .add("path", "zed-extension") + .add("key", "zed-extension-${{ env.ZED_EXTENSION_CLI_SHA }}"), + ); + let output = StepOutput::new(&step, "cache-hit"); + (step, output) +} + +pub fn download_zed_extension_cli(cache_hit: StepOutput) -> Step { + named::bash( + indoc! { + r#" + wget --quiet "https://zed-extension-cli.nyc3.digitaloceanspaces.com/$ZED_EXTENSION_CLI_SHA/x86_64-unknown-linux-gnu/zed-extension" + chmod +x zed-extension + "#, + } + ).if_condition(Expression::new(format!("{} != 'true'", cache_hit.expr()))) +} + +pub fn check() -> Step { + named::bash(indoc! { + r#" + mkdir -p /tmp/ext-scratch + mkdir -p /tmp/ext-output + ./zed-extension --source-dir . --scratch-dir /tmp/ext-scratch --output-dir /tmp/ext-output + "# + }) +} diff --git a/tooling/xtask/src/tasks/workflows/nix_build.rs b/tooling/xtask/src/tasks/workflows/nix_build.rs index 3c6818106335aac712bbf4c282107e735cd5c631..ff98852d191ae8b0edf29c6cdf52985b16034221 100644 --- a/tooling/xtask/src/tasks/workflows/nix_build.rs +++ b/tooling/xtask/src/tasks/workflows/nix_build.rs @@ -1,6 +1,6 @@ use crate::tasks::workflows::{ runners::{Arch, Platform}, - steps::NamedJob, + steps::{CommonJobConditions, NamedJob}, }; use super::{runners, steps, steps::named, vars}; @@ -71,9 +71,7 @@ pub(crate) fn build_nix( let mut job = Job::default() .timeout_minutes(60u32) .continue_on_error(true) - .cond(Expression::new( - "github.repository_owner == 'zed-industries'", - )) + .with_repository_owner_guard() .runs_on(runner) .add_env(("ZED_CLIENT_CHECKSUM_SEED", vars::ZED_CLIENT_CHECKSUM_SEED)) .add_env(("ZED_MINIDUMP_ENDPOINT", vars::ZED_SENTRY_MINIDUMP_ENDPOINT)) diff --git a/tooling/xtask/src/tasks/workflows/release_nightly.rs b/tooling/xtask/src/tasks/workflows/release_nightly.rs index c916013c0bc6f5ad89d56f382f3484097edcbed3..73cdbe3f3ee1f19a20643189b37c378d307af86a 100644 --- a/tooling/xtask/src/tasks/workflows/release_nightly.rs +++ b/tooling/xtask/src/tasks/workflows/release_nightly.rs @@ -7,7 +7,7 @@ use crate::tasks::workflows::{ run_bundling::{bundle_linux, bundle_mac, bundle_windows}, run_tests::run_platform_tests, runners::{Arch, Platform, ReleaseChannel}, - steps::{FluentBuilder, NamedJob}, + steps::{CommonJobConditions, FluentBuilder, NamedJob}, }; use super::{runners, steps, steps::named, vars}; @@ -83,9 +83,7 @@ fn check_style() -> NamedJob { fn release_job(deps: &[&NamedJob]) -> Job { let job = Job::default() - .cond(Expression::new( - "github.repository_owner == 'zed-industries'", - )) + .with_repository_owner_guard() .timeout_minutes(60u32); if deps.len() > 0 { job.needs(deps.iter().map(|j| j.name.clone()).collect::>()) diff --git a/tooling/xtask/src/tasks/workflows/run_tests.rs b/tooling/xtask/src/tasks/workflows/run_tests.rs index 826881ab8a1e248450a2f3c4a3a62f4d449a8117..31ebddc8b3dfff2bd93de7be4bce39cbb0a6195c 100644 --- a/tooling/xtask/src/tasks/workflows/run_tests.rs +++ b/tooling/xtask/src/tasks/workflows/run_tests.rs @@ -4,7 +4,10 @@ use gh_workflow::{ use indexmap::IndexMap; use crate::tasks::workflows::{ - nix_build::build_nix, runners::Arch, steps::BASH_SHELL, vars::PathCondition, + nix_build::build_nix, + runners::Arch, + steps::{BASH_SHELL, CommonJobConditions, repository_owner_guard_expression}, + vars::PathCondition, }; use super::{ @@ -107,7 +110,7 @@ pub(crate) fn run_tests() -> Workflow { // Generates a bash script that checks changed files against regex patterns // and sets GitHub output variables accordingly -fn orchestrate(rules: &[&PathCondition]) -> NamedJob { +pub fn orchestrate(rules: &[&PathCondition]) -> NamedJob { let name = "orchestrate".to_owned(); let step_name = "filter".to_owned(); let mut script = String::new(); @@ -162,9 +165,7 @@ fn orchestrate(rules: &[&PathCondition]) -> NamedJob { let job = Job::default() .runs_on(runners::LINUX_SMALL) - .cond(Expression::new( - "github.repository_owner == 'zed-industries'", - )) + .with_repository_owner_guard() .outputs(outputs) .add_step(steps::checkout_repo().add_with(( "fetch-depth", @@ -180,7 +181,7 @@ fn orchestrate(rules: &[&PathCondition]) -> NamedJob { NamedJob { name, job } } -pub(crate) fn tests_pass(jobs: &[NamedJob]) -> NamedJob { +pub fn tests_pass(jobs: &[NamedJob]) -> NamedJob { let mut script = String::from(indoc::indoc! {r#" set +x EXIT_CODE=0 @@ -214,9 +215,7 @@ pub(crate) fn tests_pass(jobs: &[NamedJob]) -> NamedJob { .map(|j| j.name.to_string()) .collect::>(), ) - .cond(Expression::new( - "github.repository_owner == 'zed-industries' && always()", - )) + .cond(repository_owner_guard_expression(true)) .add_step(named::bash(&script)); named::job(job) diff --git a/tooling/xtask/src/tasks/workflows/steps.rs b/tooling/xtask/src/tasks/workflows/steps.rs index 969dd35db07dc6ed315e0fa3e3ae2b69934e8b95..c5edbdf8439675b4264388001322c12f4f3026e9 100644 --- a/tooling/xtask/src/tasks/workflows/steps.rs +++ b/tooling/xtask/src/tasks/workflows/steps.rs @@ -94,18 +94,18 @@ pub fn clear_target_dir_if_large(platform: Platform) -> Step { } } -pub(crate) fn clippy(platform: Platform) -> Step { +pub fn clippy(platform: Platform) -> Step { match platform { Platform::Windows => named::pwsh("./script/clippy.ps1"), _ => named::bash("./script/clippy"), } } -pub(crate) fn cache_rust_dependencies_namespace() -> Step { +pub fn cache_rust_dependencies_namespace() -> Step { named::uses("namespacelabs", "nscloud-cache-action", "v1").add_with(("cache", "rust")) } -fn setup_linux() -> Step { +pub fn setup_linux() -> Step { named::bash("./script/linux") } @@ -131,7 +131,7 @@ pub fn script(name: &str) -> Step { } } -pub(crate) struct NamedJob { +pub struct NamedJob { pub name: String, pub job: Job, } @@ -145,11 +145,26 @@ pub(crate) struct NamedJob { // } // } +pub fn repository_owner_guard_expression(trigger_always: bool) -> Expression { + Expression::new(format!( + "(github.repository_owner == 'zed-industries' || github.repository_owner == 'zed-extensions'){}", + trigger_always.then_some(" && always()").unwrap_or_default() + )) +} + +pub trait CommonJobConditions: Sized { + fn with_repository_owner_guard(self) -> Self; +} + +impl CommonJobConditions for Job { + fn with_repository_owner_guard(self) -> Self { + self.cond(repository_owner_guard_expression(false)) + } +} + pub(crate) fn release_job(deps: &[&NamedJob]) -> Job { dependant_job(deps) - .cond(Expression::new( - "github.repository_owner == 'zed-industries'", - )) + .with_repository_owner_guard() .timeout_minutes(60u32) } @@ -169,7 +184,7 @@ impl FluentBuilder for Workflow {} /// Copied from GPUI to avoid adding GPUI as dependency /// todo(ci) just put this in gh-workflow #[allow(unused)] -pub(crate) trait FluentBuilder { +pub trait FluentBuilder { /// Imperatively modify self with the given closure. fn map(self, f: impl FnOnce(Self) -> U) -> U where @@ -223,34 +238,34 @@ pub(crate) trait FluentBuilder { // (janky) helper to generate steps with a name that corresponds // to the name of the calling function. -pub(crate) mod named { +pub mod named { use super::*; /// Returns a uses step with the same name as the enclosing function. /// (You shouldn't inline this function into the workflow definition, you must /// wrap it in a new function.) - pub(crate) fn uses(owner: &str, repo: &str, ref_: &str) -> Step { + pub fn uses(owner: &str, repo: &str, ref_: &str) -> Step { Step::new(function_name(1)).uses(owner, repo, ref_) } /// Returns a bash-script step with the same name as the enclosing function. /// (You shouldn't inline this function into the workflow definition, you must /// wrap it in a new function.) - pub(crate) fn bash(script: &str) -> Step { + pub fn bash(script: &str) -> Step { Step::new(function_name(1)).run(script).shell(BASH_SHELL) } /// Returns a pwsh-script step with the same name as the enclosing function. /// (You shouldn't inline this function into the workflow definition, you must /// wrap it in a new function.) - pub(crate) fn pwsh(script: &str) -> Step { + pub fn pwsh(script: &str) -> Step { Step::new(function_name(1)).run(script).shell(PWSH_SHELL) } /// Runs the command in either powershell or bash, depending on platform. /// (You shouldn't inline this function into the workflow definition, you must /// wrap it in a new function.) - pub(crate) fn run(platform: Platform, script: &str) -> Step { + pub fn run(platform: Platform, script: &str) -> Step { match platform { Platform::Windows => Step::new(function_name(1)).run(script).shell(PWSH_SHELL), Platform::Linux | Platform::Mac => { @@ -260,7 +275,7 @@ pub(crate) mod named { } /// Returns a Workflow with the same name as the enclosing module. - pub(crate) fn workflow() -> Workflow { + pub fn workflow() -> Workflow { Workflow::default().name( named::function_name(1) .split("::") @@ -272,7 +287,7 @@ pub(crate) mod named { /// Returns a Job with the same name as the enclosing function. /// (note job names may not contain `::`) - pub(crate) fn job(job: Job) -> NamedJob { + pub fn job(job: Job) -> NamedJob { NamedJob { name: function_name(1).split("::").last().unwrap().to_owned(), job, @@ -282,7 +297,7 @@ pub(crate) mod named { /// Returns the function name N callers above in the stack /// (typically 1). /// This only works because xtask always runs debug builds. - pub(crate) fn function_name(i: usize) -> String { + pub fn function_name(i: usize) -> String { let mut name = "".to_string(); let mut count = 0; backtrace::trace(|frame| { @@ -297,6 +312,7 @@ pub(crate) mod named { }); false }); + name.split("::") .skip_while(|s| s != &"workflows") .skip(1) diff --git a/tooling/xtask/src/tasks/workflows/vars.rs b/tooling/xtask/src/tasks/workflows/vars.rs index 1b3a0ec72ab7ad9a3a6c4446f5e08743d0212a2b..bbb98af757dd9b794ae7c57d6ddb4f1d3d10019d 100644 --- a/tooling/xtask/src/tasks/workflows/vars.rs +++ b/tooling/xtask/src/tasks/workflows/vars.rs @@ -11,8 +11,8 @@ macro_rules! secret { } macro_rules! var { - ($secret_name:ident) => { - pub const $secret_name: &str = concat!("${{ vars.", stringify!($secret_name), " }}"); + ($var_name:ident) => { + pub const $var_name: &str = concat!("${{ vars.", stringify!($var_name), " }}"); }; } @@ -76,7 +76,7 @@ pub fn bundle_envs(platform: Platform) -> Env { } } -pub(crate) fn one_workflow_per_non_main_branch() -> Concurrency { +pub fn one_workflow_per_non_main_branch() -> Concurrency { Concurrency::default() .group("${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}") .cancel_in_progress(true) @@ -89,7 +89,7 @@ pub(crate) fn allow_concurrent_runs() -> Concurrency { } // Represents a pattern to check for changed files and corresponding output variable -pub(crate) struct PathCondition { +pub struct PathCondition { pub name: &'static str, pub pattern: &'static str, pub invert: bool, @@ -147,6 +147,10 @@ impl StepOutput { .expect("Steps that produce outputs must have an ID"), } } + + pub fn expr(&self) -> String { + format!("steps.{}.outputs.{}", self.step_id, self.name) + } } impl serde::Serialize for StepOutput { @@ -164,7 +168,7 @@ impl std::fmt::Display for StepOutput { } } -pub(crate) struct Input { +pub struct Input { pub input_type: &'static str, pub name: &'static str, pub default: Option,