From 1b2e38bb339a716aa48380cdf7c528b07b13b3bf Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 4 Nov 2025 16:28:29 -0700 Subject: [PATCH] More tweaks to CI pipeline (#41941) Closes #ISSUE Release Notes: - N/A *or* Added/Fixed/Improved ... --- .github/workflows/cherry_pick.yml | 16 +++++++- .github/workflows/compare_perf.yml | 20 +++++++++- script/cherry-pick | 15 +++---- .../xtask/src/tasks/workflows/cherry_pick.rs | 40 +++++++++++++++---- .../xtask/src/tasks/workflows/compare_perf.rs | 33 +++++++++------ tooling/xtask/src/tasks/workflows/steps.rs | 2 +- tooling/xtask/src/tasks/workflows/vars.rs | 38 +++++++++++++++--- 7 files changed, 128 insertions(+), 36 deletions(-) diff --git a/.github/workflows/cherry_pick.yml b/.github/workflows/cherry_pick.yml index 5a503c8c7f7bd503f5b13313c6115ba1cf9aa614..69a46558396bd04db9f43e5d401c74d14b07fc88 100644 --- a/.github/workflows/cherry_pick.yml +++ b/.github/workflows/cherry_pick.yml @@ -12,6 +12,10 @@ on: description: branch required: true type: string + channel: + description: channel + required: true + type: string jobs: run_cherry_pick: runs-on: namespace-profile-2x4-ubuntu-2404 @@ -20,6 +24,16 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: clean: false + - id: get-app-token + name: cherry_pick::run_cherry_pick::authenticate_as_zippy + uses: actions/create-github-app-token@bef1eaf1c0ac2b148ee2a0a74c65fbe6db0631f1 + with: + app-id: ${{ secrets.ZED_ZIPPY_APP_ID }} + private-key: ${{ secrets.ZED_ZIPPY_APP_PRIVATE_KEY }} - name: cherry_pick::run_cherry_pick::cherry_pick - run: ./scripts/cherry-pick ${{ inputs.branch }} ${{ inputs.commit }} + run: ./script/cherry-pick ${{ inputs.branch }} ${{ inputs.commit }} ${{ inputs.channel }} shell: bash -euxo pipefail {0} + env: + GIT_COMMITTER_NAME: Zed Zippy + GIT_COMMITTER_EMAIL: hi@zed.dev + GITHUB_TOKEN: ${{ steps.get-app-token.outputs.token }} diff --git a/.github/workflows/compare_perf.yml b/.github/workflows/compare_perf.yml index 3fc9e6201e9d350f29a2e089157a945bcba4d926..40dc2fb2129dfa355c18e0ecfd0aa3ae6afba9ea 100644 --- a/.github/workflows/compare_perf.yml +++ b/.github/workflows/compare_perf.yml @@ -12,6 +12,10 @@ on: description: base required: true type: string + crate_name: + description: crate_name + type: string + default: '' jobs: run_perf: runs-on: namespace-profile-16x32-ubuntu-2204 @@ -38,13 +42,25 @@ jobs: 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 }} + run: |2- + + if [ -n "${{ inputs.crate_name }}" ]; then + cargo perf-test -p ${{ inputs.crate_name }} -- --json=${{ inputs.base }}; + else + cargo perf-test -p vim -- --json=${{ inputs.base }}; + fi 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 }} + run: |2- + + if [ -n "${{ inputs.crate_name }}" ]; then + cargo perf-test -p ${{ inputs.crate_name }} -- --json=${{ inputs.head }}; + else + cargo perf-test -p vim -- --json=${{ inputs.head }}; + fi shell: bash -euxo pipefail {0} - name: compare_perf::run_perf::compare_runs run: cargo perf-compare --save=results.md ${{ inputs.base }} ${{ inputs.head }} diff --git a/script/cherry-pick b/script/cherry-pick index 2272b2b2bdaa1c0b7048047159d51352dbcc7dd4..1cf94e87e1a41bab38bbe018cdee4f04a0391276 100755 --- a/script/cherry-pick +++ b/script/cherry-pick @@ -1,33 +1,34 @@ # #!/bin/bash set -euxo pipefail -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " +if [ "$#" -ne 3 ]; then + echo "Usage: $0 " exit 1 fi BRANCH_NAME="$1" COMMIT_SHA="$2" +CHANNEL="$3" 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 checkout -B "$NEW_BRANCH" git cherry-pick "$COMMIT_SHA" -git push origin "$NEW_BRANCH" +git push origin -f "$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}" + PR_BODY="Cherry-pick of #${PR_NUMBER} to ${CHANNEL}"$'\n'$'\n'"----"$'\n'"${COMMIT_BODY}" else - PR_BODY="Cherry-pick of ${COMMIT_SHA}"$'\n'$'\n'"----"$'\n'"${COMMIT_BODY}" + PR_BODY="Cherry-pick of ${COMMIT_SHA} to ${CHANNEL}"$'\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" +gh pr create --base "$BRANCH_NAME" --head "$NEW_BRANCH" --title "$COMMIT_TITLE (cherry-pick to $CHANNEL)" --body "$PR_BODY" diff --git a/tooling/xtask/src/tasks/workflows/cherry_pick.rs b/tooling/xtask/src/tasks/workflows/cherry_pick.rs index 35c3f001e49d10f5fba6f23b243e499fe95cfa01..1a8407f2ec403648946dc091d3d1763b982d8452 100644 --- a/tooling/xtask/src/tasks/workflows/cherry_pick.rs +++ b/tooling/xtask/src/tasks/workflows/cherry_pick.rs @@ -3,31 +3,57 @@ use gh_workflow::*; use crate::tasks::workflows::{ runners, steps::{self, NamedJob, named}, - vars::Input, + vars::{self, Input, StepOutput}, }; 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); + let channel = Input::string("channel", None); + let cherry_pick = run_cherry_pick(&branch, &commit, &channel); named::workflow() .on(Event::default().workflow_dispatch( WorkflowDispatch::default() .add_input(commit.name, commit.input()) - .add_input(branch.name, branch.input()), + .add_input(branch.name, branch.input()) + .add_input(channel.name, channel.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}")) +fn run_cherry_pick(branch: &Input, commit: &Input, channel: &Input) -> NamedJob { + fn authenticate_as_zippy() -> (Step, StepOutput) { + let step = named::uses( + "actions", + "create-github-app-token", + "bef1eaf1c0ac2b148ee2a0a74c65fbe6db0631f1", + ) // v2 + .add_with(("app-id", vars::ZED_ZIPPY_APP_ID)) + .add_with(("private-key", vars::ZED_ZIPPY_APP_PRIVATE_KEY)) + .id("get-app-token"); + let output = StepOutput::new(&step, "token"); + (step, output) } + fn cherry_pick( + branch: &Input, + commit: &Input, + channel: &Input, + token: &StepOutput, + ) -> Step { + named::bash(&format!("./script/cherry-pick {branch} {commit} {channel}")) + .add_env(("GIT_COMMITTER_NAME", "Zed Zippy")) + .add_env(("GIT_COMMITTER_EMAIL", "hi@zed.dev")) + .add_env(("GITHUB_TOKEN", token)) + } + + let (authenticate, token) = authenticate_as_zippy(); + named::job( Job::default() .runs_on(runners::LINUX_SMALL) .add_step(steps::checkout_repo()) - .add_step(cherry_pick(&branch.var(), &commit.var())), + .add_step(authenticate) + .add_step(cherry_pick(branch, commit, channel, &token)), ) } diff --git a/tooling/xtask/src/tasks/workflows/compare_perf.rs b/tooling/xtask/src/tasks/workflows/compare_perf.rs index b3a4b1e20d2353440a80c53afc2105d74710de91..b1d6e0c60bd6b49893de8877e7d1fd51e5967679 100644 --- a/tooling/xtask/src/tasks/workflows/compare_perf.rs +++ b/tooling/xtask/src/tasks/workflows/compare_perf.rs @@ -11,28 +11,35 @@ use crate::tasks::workflows::{ pub fn compare_perf() -> Workflow { let head = Input::string("head", None); let base = Input::string("base", None); - let run_perf = run_perf(&base, &head); + let crate_name = Input::string("crate_name", Some("".to_owned())); + let run_perf = run_perf(&base, &head, &crate_name); named::workflow() .on(Event::default().workflow_dispatch( WorkflowDispatch::default() .add_input(head.name, head.input()) - .add_input(base.name, base.input()), + .add_input(base.name, base.input()) + .add_input(crate_name.name, crate_name.input()), )) .add_job(run_perf.name, run_perf.job) } -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}")) +pub fn run_perf(base: &Input, head: &Input, crate_name: &Input) -> NamedJob { + fn cargo_perf_test(ref_name: &Input, crate_name: &Input) -> Step { + named::bash(&format!( + " + if [ -n \"{crate_name}\" ]; then + cargo perf-test -p {crate_name} -- --json={ref_name}; + else + cargo perf-test -p vim -- --json={ref_name}; + fi" + )) } fn install_hyperfine() -> Step { named::bash("cargo install hyperfine") } - fn compare_runs(head: String, base: String) -> Step { - // TODO: this should really be swapped... + fn compare_runs(head: &Input, base: &Input) -> Step { named::bash(&format!( "cargo perf-compare --save=results.md {base} {head}" )) @@ -45,11 +52,11 @@ pub fn run_perf(base: &Input, head: &Input) -> NamedJob { .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(steps::git_checkout(base)) + .add_step(cargo_perf_test(base, crate_name)) + .add_step(steps::git_checkout(head)) + .add_step(cargo_perf_test(head, crate_name)) + .add_step(compare_runs(head, base)) .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 f28f43232f952811efda166ada6267bdc31bb121..6e7d6130abb3fbdb04389c9d226f067397dcf41d 100644 --- a/tooling/xtask/src/tasks/workflows/steps.rs +++ b/tooling/xtask/src/tasks/workflows/steps.rs @@ -299,7 +299,7 @@ pub(crate) mod named { } } -pub fn git_checkout(ref_name: &str) -> Step { +pub fn git_checkout(ref_name: &dyn std::fmt::Display) -> 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 3dd16bb48decc4ae9fc978610364c814813eafbf..640efdf6c12553fe5494b88ec5816b498016f6ec 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, WorkflowDispatchInput}; +use gh_workflow::{Concurrency, Env, Expression, Step, WorkflowDispatchInput}; use crate::tasks::workflows::{runners::Platform, steps::NamedJob}; @@ -34,6 +34,8 @@ secret!(ZED_CLIENT_CHECKSUM_SEED); secret!(ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON); secret!(ZED_SENTRY_MINIDUMP_ENDPOINT); secret!(SLACK_APP_ZED_UNIT_EVALS_BOT_TOKEN); +secret!(ZED_ZIPPY_APP_ID); +secret!(ZED_ZIPPY_APP_PRIVATE_KEY); // todo(ci) make these secrets too... var!(AZURE_SIGNING_ACCOUNT_NAME); @@ -116,6 +118,30 @@ impl PathCondition { } } +pub(crate) struct StepOutput { + name: &'static str, + step_id: String, +} + +impl StepOutput { + pub fn new(step: &Step, name: &'static str) -> Self { + Self { + name, + step_id: step + .value + .id + .clone() + .expect("Steps that produce outputs must have an ID"), + } + } +} + +impl std::fmt::Display for StepOutput { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "${{{{ steps.{}.outputs.{} }}}}", self.step_id, self.name) + } +} + pub(crate) struct Input { pub input_type: &'static str, pub name: &'static str, @@ -131,10 +157,6 @@ impl Input { } } - pub fn var(&self) -> String { - format!("${{{{ inputs.{} }}}}", self.name) - } - pub fn input(&self) -> WorkflowDispatchInput { WorkflowDispatchInput { description: self.name.to_owned(), @@ -145,6 +167,12 @@ impl Input { } } +impl std::fmt::Display for Input { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "${{{{ inputs.{} }}}}", self.name) + } +} + pub mod assets { // NOTE: these asset names also exist in the zed.dev codebase. pub const MAC_AARCH64: &str = "Zed-aarch64.dmg";