Add callable workflow for extension repositories (#43082)

This starts the work on a workflow that can be invoked in extension CI
to test changes on extension repositories.

Release Notes:

- N/A

---------

Co-authored-by: Agus Zubiaga <agus@zed.dev>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
Finn Evers 2025-11-19 18:47:34 +01:00 committed by GitHub
parent 97b429953e
commit 2a2f5a9c7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 345 additions and 69 deletions

View file

@ -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

View file

@ -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

138
.github/workflows/extension_tests.yml vendored Normal file
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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()))?;

View file

@ -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)

View file

@ -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())

View file

@ -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<Run> {
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<Use>, 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<Run> {
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<Run> {
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
"#
})
}

View file

@ -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))

View file

@ -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::<Vec<_>>())

View file

@ -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::<Vec<String>>(),
)
.cond(Expression::new(
"github.repository_owner == 'zed-industries' && always()",
))
.cond(repository_owner_guard_expression(true))
.add_step(named::bash(&script));
named::job(job)

View file

@ -94,18 +94,18 @@ pub fn clear_target_dir_if_large(platform: Platform) -> Step<Run> {
}
}
pub(crate) fn clippy(platform: Platform) -> Step<Run> {
pub fn clippy(platform: Platform) -> Step<Run> {
match platform {
Platform::Windows => named::pwsh("./script/clippy.ps1"),
_ => named::bash("./script/clippy"),
}
}
pub(crate) fn cache_rust_dependencies_namespace() -> Step<Use> {
pub fn cache_rust_dependencies_namespace() -> Step<Use> {
named::uses("namespacelabs", "nscloud-cache-action", "v1").add_with(("cache", "rust"))
}
fn setup_linux() -> Step<Run> {
pub fn setup_linux() -> Step<Run> {
named::bash("./script/linux")
}
@ -131,7 +131,7 @@ pub fn script(name: &str) -> Step<Run> {
}
}
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<U>(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<Use> {
pub fn uses(owner: &str, repo: &str, ref_: &str) -> Step<Use> {
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<Run> {
pub fn bash(script: &str) -> Step<Run> {
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<Run> {
pub fn pwsh(script: &str) -> Step<Run> {
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<Run> {
pub fn run(platform: Platform, script: &str) -> Step<Run> {
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 = "<unknown>".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)

View file

@ -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<String>,