From 43a7f96462baa263847d6f252be474ddf48ce15e Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 4 Nov 2025 11:29:35 -0700 Subject: [PATCH] Improve compare_perf.yml, cherry_pick.yml (#41606) Release Notes: - N/A --------- Co-authored-by: Nia Espera --- .github/workflows/cherry_pick.yml | 25 +++++++++ .github/workflows/compare_perf.yml | 53 ++++++++++++++++++- Cargo.lock | 4 +- Cargo.toml | 2 +- script/cherry-pick | 33 ++++++++++++ tooling/xtask/src/tasks/workflows.rs | 2 + .../xtask/src/tasks/workflows/cherry_pick.rs | 33 ++++++++++++ .../xtask/src/tasks/workflows/compare_perf.rs | 46 +++++++++++++--- tooling/xtask/src/tasks/workflows/steps.rs | 6 +++ tooling/xtask/src/tasks/workflows/vars.rs | 33 +++++++++++- 10 files changed, 224 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/cherry_pick.yml create mode 100755 script/cherry-pick create mode 100644 tooling/xtask/src/tasks/workflows/cherry_pick.rs diff --git a/.github/workflows/cherry_pick.yml b/.github/workflows/cherry_pick.yml new file mode 100644 index 0000000000000000000000000000000000000000..5a503c8c7f7bd503f5b13313c6115ba1cf9aa614 --- /dev/null +++ b/.github/workflows/cherry_pick.yml @@ -0,0 +1,25 @@ +# Generated from xtask::workflows::cherry_pick +# Rebuild with `cargo xtask workflows`. +name: cherry_pick +on: + workflow_dispatch: + inputs: + commit: + description: commit + required: true + type: string + branch: + description: branch + required: true + type: string +jobs: + run_cherry_pick: + runs-on: namespace-profile-2x4-ubuntu-2404 + steps: + - name: steps::checkout_repo + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + clean: false + - name: cherry_pick::run_cherry_pick::cherry_pick + run: ./scripts/cherry-pick ${{ inputs.branch }} ${{ inputs.commit }} + shell: bash -euxo pipefail {0} diff --git a/.github/workflows/compare_perf.yml b/.github/workflows/compare_perf.yml index 3f30ff1ec54afb88bc27557c89d189a8e1e21dff..3fc9e6201e9d350f29a2e089157a945bcba4d926 100644 --- a/.github/workflows/compare_perf.yml +++ b/.github/workflows/compare_perf.yml @@ -2,12 +2,61 @@ # Rebuild with `cargo xtask workflows`. name: compare_perf on: - workflow_dispatch: {} + workflow_dispatch: + inputs: + head: + description: head + required: true + type: string + base: + description: base + required: true + type: string jobs: run_perf: - runs-on: namespace-profile-2x4-ubuntu-2404 + runs-on: namespace-profile-16x32-ubuntu-2204 steps: - name: steps::checkout_repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: clean: false + - name: steps::setup_cargo_config + run: | + mkdir -p ./../.cargo + cp ./.cargo/ci-config.toml ./../.cargo/config.toml + shell: bash -euxo pipefail {0} + - name: steps::setup_linux + run: ./script/linux + shell: bash -euxo pipefail {0} + - name: steps::install_mold + run: ./script/install-mold + shell: bash -euxo pipefail {0} + - name: compare_perf::run_perf::install_hyperfine + run: cargo install hyperfine + shell: bash -euxo pipefail {0} + - name: steps::git_checkout + run: git fetch origin ${{ inputs.base }} && git checkout ${{ inputs.base }} + shell: bash -euxo pipefail {0} + - name: compare_perf::run_perf::cargo_perf_test + run: cargo perf-test -p gpui -- --json=${{ inputs.base }} + shell: bash -euxo pipefail {0} + - name: steps::git_checkout + run: git fetch origin ${{ inputs.head }} && git checkout ${{ inputs.head }} + shell: bash -euxo pipefail {0} + - name: compare_perf::run_perf::cargo_perf_test + run: cargo perf-test -p gpui -- --json=${{ inputs.head }} + shell: bash -euxo pipefail {0} + - name: compare_perf::run_perf::compare_runs + run: cargo perf-compare --save=results.md ${{ inputs.base }} ${{ inputs.head }} + shell: bash -euxo pipefail {0} + - name: '@actions/upload-artifact results.md' + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 + with: + name: results.md + path: results.md + if-no-files-found: error + - name: steps::cleanup_cargo_config + if: always() + run: | + rm -rf ./../.cargo + shell: bash -euxo pipefail {0} diff --git a/Cargo.lock b/Cargo.lock index 92bdac47be71486743420d6941721c6209045f04..b050f0ed51453954c7b2a2047f4075b8d98bab8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6961,7 +6961,7 @@ dependencies = [ [[package]] name = "gh-workflow" version = "0.8.0" -source = "git+https://github.com/zed-industries/gh-workflow?rev=0090c6b6ef82fff02bc8616645953e778d1acc08#0090c6b6ef82fff02bc8616645953e778d1acc08" +source = "git+https://github.com/zed-industries/gh-workflow?rev=3eaa84abca0778eb54272f45a312cb24f9a0b435#3eaa84abca0778eb54272f45a312cb24f9a0b435" dependencies = [ "async-trait", "derive_more 2.0.1", @@ -6978,7 +6978,7 @@ dependencies = [ [[package]] name = "gh-workflow-macros" version = "0.8.0" -source = "git+https://github.com/zed-industries/gh-workflow?rev=0090c6b6ef82fff02bc8616645953e778d1acc08#0090c6b6ef82fff02bc8616645953e778d1acc08" +source = "git+https://github.com/zed-industries/gh-workflow?rev=3eaa84abca0778eb54272f45a312cb24f9a0b435#3eaa84abca0778eb54272f45a312cb24f9a0b435" dependencies = [ "heck 0.5.0", "quote", diff --git a/Cargo.toml b/Cargo.toml index 7674b0bacc12e9f9ae78a3f299dc0f538e26bd35..ac6e310fe7d899486c5b5287f4ac07762751d9a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -508,7 +508,7 @@ fork = "0.2.0" futures = "0.3" futures-batch = "0.6.1" futures-lite = "1.13" -gh-workflow = { git = "https://github.com/zed-industries/gh-workflow", rev = "0090c6b6ef82fff02bc8616645953e778d1acc08" } +gh-workflow = { git = "https://github.com/zed-industries/gh-workflow", rev = "3eaa84abca0778eb54272f45a312cb24f9a0b435" } git2 = { version = "0.20.1", default-features = false } globset = "0.4" handlebars = "4.3" diff --git a/script/cherry-pick b/script/cherry-pick new file mode 100755 index 0000000000000000000000000000000000000000..2272b2b2bdaa1c0b7048047159d51352dbcc7dd4 --- /dev/null +++ b/script/cherry-pick @@ -0,0 +1,33 @@ +# #!/bin/bash +set -euxo pipefail + +if [ "$#" -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi + +BRANCH_NAME="$1" +COMMIT_SHA="$2" + +SHORT_SHA="${COMMIT_SHA:0:8}" +NEW_BRANCH="cherry-pick-${BRANCH_NAME}-${SHORT_SHA}" +git fetch origin +git checkout "$BRANCH_NAME" +git checkout -b "$NEW_BRANCH" + +git cherry-pick "$COMMIT_SHA" + +git push origin "$NEW_BRANCH" +COMMIT_TITLE=$(git log -1 --pretty=format:"%s" "$COMMIT_SHA") +COMMIT_BODY=$(git log -1 --pretty=format:"%b" "$COMMIT_SHA") + +# Check if commit title ends with (#number) +if [[ "$COMMIT_TITLE" =~ \(#([0-9]+)\)$ ]]; then + PR_NUMBER="${BASH_REMATCH[1]}" + PR_BODY="Cherry-pick of #${PR_NUMBER}"$'\n'$'\n'"----"$'\n'"${COMMIT_BODY}" +else + PR_BODY="Cherry-pick of ${COMMIT_SHA}"$'\n'$'\n'"----"$'\n'"${COMMIT_BODY}" +fi + +# Create a pull request +gh pr create --base "$BRANCH_NAME" --head "$NEW_BRANCH" --title "$COMMIT_TITLE (cherry-pick)" --body "$PR_BODY" diff --git a/tooling/xtask/src/tasks/workflows.rs b/tooling/xtask/src/tasks/workflows.rs index 538724bcd9648b89d303a6eff834d08ffb3bf18a..4cc1f5174a754df800fcae768bfe7ff1645032d3 100644 --- a/tooling/xtask/src/tasks/workflows.rs +++ b/tooling/xtask/src/tasks/workflows.rs @@ -3,6 +3,7 @@ use clap::Parser; use std::fs; use std::path::Path; +mod cherry_pick; mod compare_perf; mod danger; mod nix_build; @@ -28,6 +29,7 @@ pub fn run_workflows(_: GenerateWorkflowArgs) -> Result<()> { ("release_nightly.yml", release_nightly::release_nightly()), ("run_tests.yml", run_tests::run_tests()), ("release.yml", release::release()), + ("cherry_pick.yml", cherry_pick::cherry_pick()), ("compare_perf.yml", compare_perf::compare_perf()), ("run_unit_evals.yml", run_agent_evals::run_unit_evals()), ("run_agent_evals.yml", run_agent_evals::run_agent_evals()), diff --git a/tooling/xtask/src/tasks/workflows/cherry_pick.rs b/tooling/xtask/src/tasks/workflows/cherry_pick.rs new file mode 100644 index 0000000000000000000000000000000000000000..35c3f001e49d10f5fba6f23b243e499fe95cfa01 --- /dev/null +++ b/tooling/xtask/src/tasks/workflows/cherry_pick.rs @@ -0,0 +1,33 @@ +use gh_workflow::*; + +use crate::tasks::workflows::{ + runners, + steps::{self, NamedJob, named}, + vars::Input, +}; + +pub fn cherry_pick() -> Workflow { + let branch = Input::string("branch", None); + let commit = Input::string("commit", None); + let cherry_pick = run_cherry_pick(&branch, &commit); + named::workflow() + .on(Event::default().workflow_dispatch( + WorkflowDispatch::default() + .add_input(commit.name, commit.input()) + .add_input(branch.name, branch.input()), + )) + .add_job(cherry_pick.name, cherry_pick.job) +} + +fn run_cherry_pick(branch: &Input, commit: &Input) -> NamedJob { + fn cherry_pick(branch: &str, commit: &str) -> Step { + named::bash(&format!("./scripts/cherry-pick {branch} {commit}")) + } + + named::job( + Job::default() + .runs_on(runners::LINUX_SMALL) + .add_step(steps::checkout_repo()) + .add_step(cherry_pick(&branch.var(), &commit.var())), + ) +} diff --git a/tooling/xtask/src/tasks/workflows/compare_perf.rs b/tooling/xtask/src/tasks/workflows/compare_perf.rs index b46a3bb0ca1329906a8f0445e55c4edf5059cb95..b3a4b1e20d2353440a80c53afc2105d74710de91 100644 --- a/tooling/xtask/src/tasks/workflows/compare_perf.rs +++ b/tooling/xtask/src/tasks/workflows/compare_perf.rs @@ -1,22 +1,56 @@ use gh_workflow::*; +use crate::tasks::workflows::run_bundling::upload_artifact; +use crate::tasks::workflows::steps::FluentBuilder; use crate::tasks::workflows::{ runners, steps::{self, NamedJob, named}, + vars::Input, }; -/// Generates the danger.yml workflow pub fn compare_perf() -> Workflow { - let run_perf = run_perf(); + let head = Input::string("head", None); + let base = Input::string("base", None); + let run_perf = run_perf(&base, &head); named::workflow() - .on(Event::default().workflow_dispatch(WorkflowDispatch::default())) + .on(Event::default().workflow_dispatch( + WorkflowDispatch::default() + .add_input(head.name, head.input()) + .add_input(base.name, base.input()), + )) .add_job(run_perf.name, run_perf.job) } -pub fn run_perf() -> NamedJob { +pub fn run_perf(base: &Input, head: &Input) -> NamedJob { + fn cargo_perf_test(ref_name: String) -> Step { + // TODO: vim not gpui, and ideally allow args + named::bash(&format!("cargo perf-test -p gpui -- --json={ref_name}")) + } + + fn install_hyperfine() -> Step { + named::bash("cargo install hyperfine") + } + + fn compare_runs(head: String, base: String) -> Step { + // TODO: this should really be swapped... + named::bash(&format!( + "cargo perf-compare --save=results.md {base} {head}" + )) + } + named::job( Job::default() - .runs_on(runners::LINUX_SMALL) - .add_step(steps::checkout_repo()), + .runs_on(runners::LINUX_DEFAULT) + .add_step(steps::checkout_repo()) + .add_step(steps::setup_cargo_config(runners::Platform::Linux)) + .map(steps::install_linux_dependencies) + .add_step(install_hyperfine()) + .add_step(steps::git_checkout(&base.var())) + .add_step(cargo_perf_test(base.var())) + .add_step(steps::git_checkout(&head.var())) + .add_step(cargo_perf_test(head.var())) + .add_step(compare_runs(head.var(), base.var())) + .add_step(upload_artifact("results.md")) + .add_step(steps::cleanup_cargo_config(runners::Platform::Linux)), ) } diff --git a/tooling/xtask/src/tasks/workflows/steps.rs b/tooling/xtask/src/tasks/workflows/steps.rs index ddbb81a3c54733a2cda68fecd31fc7cb09718e35..f28f43232f952811efda166ada6267bdc31bb121 100644 --- a/tooling/xtask/src/tasks/workflows/steps.rs +++ b/tooling/xtask/src/tasks/workflows/steps.rs @@ -298,3 +298,9 @@ pub(crate) mod named { .join("::") } } + +pub fn git_checkout(ref_name: &str) -> Step { + named::bash(&format!( + "git fetch origin {ref_name} && git checkout {ref_name}" + )) +} diff --git a/tooling/xtask/src/tasks/workflows/vars.rs b/tooling/xtask/src/tasks/workflows/vars.rs index 9a7ffed5960f3b8f3f762a0977f78e17e86365e2..3dd16bb48decc4ae9fc978610364c814813eafbf 100644 --- a/tooling/xtask/src/tasks/workflows/vars.rs +++ b/tooling/xtask/src/tasks/workflows/vars.rs @@ -1,6 +1,6 @@ use std::cell::RefCell; -use gh_workflow::{Concurrency, Env, Expression}; +use gh_workflow::{Concurrency, Env, Expression, WorkflowDispatchInput}; use crate::tasks::workflows::{runners::Platform, steps::NamedJob}; @@ -107,7 +107,7 @@ impl PathCondition { name: job.name, job: job .job - .add_needs(set_by_step.clone()) + .add_need(set_by_step.clone()) .cond(Expression::new(format!( "needs.{}.outputs.{} == 'true'", &set_by_step, self.name @@ -116,6 +116,35 @@ impl PathCondition { } } +pub(crate) struct Input { + pub input_type: &'static str, + pub name: &'static str, + pub default: Option, +} + +impl Input { + pub fn string(name: &'static str, default: Option) -> Self { + Self { + input_type: "string", + name, + default, + } + } + + pub fn var(&self) -> String { + format!("${{{{ inputs.{} }}}}", self.name) + } + + pub fn input(&self) -> WorkflowDispatchInput { + WorkflowDispatchInput { + description: self.name.to_owned(), + required: self.default.is_none(), + input_type: self.input_type.to_owned(), + default: self.default.clone(), + } + } +} + pub mod assets { // NOTE: these asset names also exist in the zed.dev codebase. pub const MAC_AARCH64: &str = "Zed-aarch64.dmg";