From 3fe9753d8964a58965a3eccf86a70fff23d1c0b3 Mon Sep 17 00:00:00 2001 From: Finn Evers Date: Fri, 24 Apr 2026 10:27:25 +0200 Subject: [PATCH] ci: Improve messaging around compliance failures (#54636) Release Notes: - N/A --- .github/workflows/release.yml | 21 ++++-- tooling/xtask/src/tasks/workflows/release.rs | 79 ++++++++++++++------ 2 files changed, 74 insertions(+), 26 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4f39b4ed52..c705a7279b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -643,7 +643,6 @@ jobs: validate_release_assets: needs: - upload_release_assets - - compliance_check runs-on: namespace-profile-2x4-ubuntu-2404 steps: - name: release::validate_release_assets @@ -664,6 +663,12 @@ jobs: echo "All expected assets are present in the release." env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + release_compliance_check: + needs: + - upload_release_assets + - compliance_check + runs-on: namespace-profile-8x16-ubuntu-2204 + steps: - name: steps::checkout_repo uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd with: @@ -712,6 +717,7 @@ jobs: auto_release_preview: needs: - validate_release_assets + - release_compliance_check if: startsWith(github.ref, 'refs/tags/v') && endsWith(github.ref, '-pre') && !endsWith(github.ref, '.0-pre') runs-on: namespace-profile-2x4-ubuntu-2404 steps: @@ -730,6 +736,7 @@ jobs: - create_draft_release - upload_release_assets - validate_release_assets + - release_compliance_check - auto_release_preview - run_tests_mac - run_tests_linux @@ -750,9 +757,7 @@ jobs: - id: generate-webhook-message name: release::generate_slack_message run: | - MESSAGE=$(TAG="$GITHUB_REF_NAME" - - if [ "$DRAFT_RESULT" == "failure" ]; then + MESSAGE=$(if [ "$DRAFT_RESULT" == "failure" ]; then echo "❌ Draft release creation failed for $TAG: $RUN_URL" else RELEASE_URL=$(gh release view "$TAG" --repo=zed-industries/zed --json url -q '.url') @@ -787,8 +792,11 @@ jobs: echo "❌ Tests for $TAG failed: $RUN_URL" fi fi + elif [ "$COMPLIANCE_RESULT" == "failure" ]; then + # We already notify within that job + echo "" elif [ "$VALIDATE_RESULT" == "failure" ]; then - echo "❌ Release asset validation failed for $TAG (missing assets): $RUN_URL" + echo "❌ Release validation failed for $TAG: missing assets: $RUN_URL" elif [ "$AUTO_RELEASE_RESULT" == "success" ]; then echo "✅ Release $TAG was auto-released successfully: $RELEASE_URL" elif [ "$AUTO_RELEASE_RESULT" == "failure" ]; then @@ -804,8 +812,10 @@ jobs: DRAFT_RESULT: ${{ needs.create_draft_release.result }} UPLOAD_RESULT: ${{ needs.upload_release_assets.result }} VALIDATE_RESULT: ${{ needs.validate_release_assets.result }} + COMPLIANCE_RESULT: ${{ needs.release_compliance_check.result }} AUTO_RELEASE_RESULT: ${{ needs.auto_release_preview.result }} RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + TAG: ${{ github.ref_name }} RESULT_RUN_TESTS_MAC: ${{ needs.run_tests_mac.result }} RESULT_RUN_TESTS_LINUX: ${{ needs.run_tests_linux.result }} RESULT_RUN_TESTS_WINDOWS: ${{ needs.run_tests_windows.result }} @@ -820,6 +830,7 @@ jobs: RESULT_BUNDLE_WINDOWS_AARCH64: ${{ needs.bundle_windows_aarch64.result }} RESULT_BUNDLE_WINDOWS_X86_64: ${{ needs.bundle_windows_x86_64.result }} - name: release::send_slack_message + if: steps.generate-webhook-message.outputs.message != '' run: 'curl -X POST -H ''Content-type: application/json'' --data "$(jq -n --arg text "$SLACK_MESSAGE" ''{"text": $text}'')" "$SLACK_WEBHOOK"' env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_WORKFLOW_FAILURES }} diff --git a/tooling/xtask/src/tasks/workflows/release.rs b/tooling/xtask/src/tasks/workflows/release.rs index 76895a37e3..045960de57 100644 --- a/tooling/xtask/src/tasks/workflows/release.rs +++ b/tooling/xtask/src/tasks/workflows/release.rs @@ -58,12 +58,14 @@ pub(crate) fn release() -> Workflow { }; let upload_release_assets = upload_release_assets(&[&create_draft_release], &bundle); - let validate_release_assets = validate_release_assets( + let validate_release_assets = validate_release_assets(&[&upload_release_assets]); + let release_compliance = release_compliance_check( &[&upload_release_assets, &non_blocking_compliance_run], job_output, ); - let auto_release_preview = auto_release_preview(&[&validate_release_assets]); + let auto_release_preview = + auto_release_preview(&[&validate_release_assets, &release_compliance]); let test_jobs = [ &macos_tests, @@ -78,6 +80,7 @@ pub(crate) fn release() -> Workflow { &create_draft_release, &upload_release_assets, &validate_release_assets, + &release_compliance, &auto_release_preview, &test_jobs, &bundle, @@ -108,6 +111,7 @@ pub(crate) fn release() -> Workflow { }) .add_job(upload_release_assets.name, upload_release_assets.job) .add_job(validate_release_assets.name, validate_release_assets.job) + .add_job(release_compliance.name, release_compliance.job) .add_job(auto_release_preview.name, auto_release_preview.job) .add_job(push_slack_notification.name, push_slack_notification.job) } @@ -308,7 +312,7 @@ fn compliance_check() -> (NamedJob, JobOutput) { (compliance_job, check_result) } -fn validate_release_assets(deps: &[&NamedJob], context_check_result: JobOutput) -> NamedJob { +fn validate_release_assets(deps: &[&NamedJob]) -> NamedJob { let expected_assets: Vec = assets::all().iter().map(|a| format!("\"{a}\"")).collect(); let expected_assets_json = format!("[{}]", expected_assets.join(", ")); @@ -330,9 +334,16 @@ fn validate_release_assets(deps: &[&NamedJob], context_check_result: JobOutput) "#, }; + named::job( + dependant_job(deps).runs_on(runners::LINUX_SMALL).add_step( + named::bash(&validation_script).add_env(("GITHUB_TOKEN", vars::GITHUB_TOKEN)), + ), + ) +} + +fn release_compliance_check(deps: &[&NamedJob], non_blocking_outcome: JobOutput) -> NamedJob { let job = dependant_job(deps) - .runs_on(runners::LINUX_SMALL) - .add_step(named::bash(&validation_script).add_env(("GITHUB_TOKEN", vars::GITHUB_TOKEN))) + .runs_on(runners::LINUX_LARGE) .add_step( steps::checkout_repo() .with_full_history() @@ -340,15 +351,14 @@ fn validate_release_assets(deps: &[&NamedJob], context_check_result: JobOutput) ) .add_step(steps::cache_rust_dependencies_namespace()); - named::job( - add_compliance_steps( - job, - ComplianceContext::Release { - non_blocking_outcome: context_check_result, - }, - ) - .0, - ) + let (job, _) = add_compliance_steps( + job, + ComplianceContext::Release { + non_blocking_outcome, + }, + ); + + named::job(job) } fn auto_release_preview(deps: &[&NamedJob]) -> NamedJob { @@ -441,6 +451,7 @@ pub(crate) fn push_release_update_notification( create_draft_release_job: &NamedJob, upload_assets_job: &NamedJob, validate_assets_job: &NamedJob, + compliance_job: &NamedJob, auto_release_preview: &NamedJob, test_jobs: &[&NamedJob], bundle_jobs: &ReleaseBundleJobs, @@ -468,11 +479,16 @@ pub(crate) fn push_release_update_notification( "VALIDATE_RESULT".into(), format!("${{{{ needs.{}.result }}}}", validate_assets_job.name), ), + ( + "COMPLIANCE_RESULT".into(), + format!("${{{{ needs.{}.result }}}}", compliance_job.name), + ), ( "AUTO_RELEASE_RESULT".into(), format!("${{{{ needs.{}.result }}}}", auto_release_preview.name), ), ("RUN_URL".into(), CURRENT_ACTION_RUN_URL.to_string()), + ("TAG".into(), Context::github().ref_name().to_string()), ] .into_iter() .chain( @@ -493,8 +509,6 @@ pub(crate) fn push_release_update_notification( .join("\n "); let notification_script = formatdoc! {r#" - TAG="$GITHUB_REF_NAME" - if [ "$DRAFT_RESULT" == "failure" ]; then echo "❌ Draft release creation failed for $TAG: $RUN_URL" else @@ -518,8 +532,11 @@ pub(crate) fn push_release_update_notification( echo "❌ Tests for $TAG failed: $RUN_URL" fi fi + elif [ "$COMPLIANCE_RESULT" == "failure" ]; then + # We already notify within that job + echo "" elif [ "$VALIDATE_RESULT" == "failure" ]; then - echo "❌ Release asset validation failed for $TAG (missing assets): $RUN_URL" + echo "❌ Release validation failed for $TAG: missing assets: $RUN_URL" elif [ "$AUTO_RELEASE_RESULT" == "success" ]; then echo "✅ Release $TAG was auto-released successfully: $RELEASE_URL" elif [ "$AUTO_RELEASE_RESULT" == "failure" ]; then @@ -535,6 +552,7 @@ pub(crate) fn push_release_update_notification( create_draft_release_job, upload_assets_job, validate_assets_job, + compliance_job, auto_release_preview, ]; all_deps.extend(test_jobs.iter().copied()); @@ -574,15 +592,29 @@ pub(crate) enum MessageType { }, } +enum MessageSource { + String(String), + StepOutput(StepOutput), +} + +impl MessageSource { + fn message(self) -> String { + match self { + MessageSource::String(string) => string, + MessageSource::StepOutput(output) => output.to_string(), + } + } +} + fn notify_slack(message: MessageType) -> Vec> { match message { - MessageType::Static(message) => vec![send_slack_message(message)], + MessageType::Static(message) => vec![send_slack_message(MessageSource::String(message))], MessageType::Evaluated { script, env } => { let (generate_step, generated_message) = generate_slack_message(script, env); vec![ generate_step, - send_slack_message(generated_message.to_string()), + send_slack_message(MessageSource::StepOutput(generated_message)), ] } } @@ -610,10 +642,15 @@ fn generate_slack_message( (generate_step, output) } -fn send_slack_message(message: String) -> Step { +fn send_slack_message(message_source: MessageSource) -> Step { named::bash( r#"curl -X POST -H 'Content-type: application/json' --data "$(jq -n --arg text "$SLACK_MESSAGE" '{"text": $text}')" "$SLACK_WEBHOOK""# ) + .map(|this| match &message_source { + MessageSource::String(_) => this, + MessageSource::StepOutput(output) => this + .if_condition(Expression::new(format!("{message} != ''", message = output.expr()))), + }) .add_env(("SLACK_WEBHOOK", vars::SLACK_WEBHOOK_WORKFLOW_FAILURES)) - .add_env(("SLACK_MESSAGE", message)) + .add_env(("SLACK_MESSAGE", message_source.message())) }