after_release.rs

  1use gh_workflow::*;
  2
  3use crate::tasks::workflows::{
  4    release::{self, notify_on_failure},
  5    runners,
  6    steps::{CommonJobConditions, NamedJob, checkout_repo, dependant_job, named},
  7    vars::{self, StepOutput, WorkflowInput},
  8};
  9
 10const TAG_NAME: &str = "${{ github.event.release.tag_name || inputs.tag_name }}";
 11const IS_PRERELEASE: &str = "${{ github.event.release.prerelease || inputs.prerelease }}";
 12const RELEASE_BODY: &str = "${{ github.event.release.body || inputs.body }}";
 13
 14pub fn after_release() -> Workflow {
 15    let tag_name = WorkflowInput::string("tag_name", None);
 16    let prerelease = WorkflowInput::bool("prerelease", None);
 17    let body = WorkflowInput::string("body", Some(String::new()));
 18
 19    let refresh_zed_dev = rebuild_releases_page();
 20    let post_to_discord = post_to_discord(&[&refresh_zed_dev]);
 21    let publish_winget = publish_winget();
 22    let create_sentry_release = create_sentry_release();
 23    let notify_on_failure = notify_on_failure(&[
 24        &refresh_zed_dev,
 25        &post_to_discord,
 26        &publish_winget,
 27        &create_sentry_release,
 28    ]);
 29
 30    named::workflow()
 31        .on(Event::default()
 32            .release(Release::default().types(vec![ReleaseType::Published]))
 33            .workflow_dispatch(
 34                WorkflowDispatch::default()
 35                    .add_input(tag_name.name, tag_name.input())
 36                    .add_input(prerelease.name, prerelease.input())
 37                    .add_input(body.name, body.input()),
 38            ))
 39        .add_job(refresh_zed_dev.name, refresh_zed_dev.job)
 40        .add_job(post_to_discord.name, post_to_discord.job)
 41        .add_job(publish_winget.name, publish_winget.job)
 42        .add_job(create_sentry_release.name, create_sentry_release.job)
 43        .add_job(notify_on_failure.name, notify_on_failure.job)
 44}
 45
 46fn rebuild_releases_page() -> NamedJob {
 47    fn refresh_cloud_releases() -> Step<Run> {
 48        named::bash(format!(
 49            "curl -fX POST https://cloud.zed.dev/releases/refresh?expect_tag={TAG_NAME}"
 50        ))
 51    }
 52
 53    fn redeploy_zed_dev() -> Step<Run> {
 54        named::bash("npm exec --yes -- vercel@37 --token=\"$VERCEL_TOKEN\" --scope zed-industries redeploy https://zed.dev")
 55            .add_env(("VERCEL_TOKEN", vars::VERCEL_TOKEN))
 56    }
 57
 58    named::job(
 59        Job::default()
 60            .runs_on(runners::LINUX_SMALL)
 61            .with_repository_owner_guard()
 62            .add_step(refresh_cloud_releases())
 63            .add_step(redeploy_zed_dev()),
 64    )
 65}
 66
 67fn post_to_discord(deps: &[&NamedJob]) -> NamedJob {
 68    fn get_release_url() -> Step<Run> {
 69        named::bash(format!(
 70            r#"if [ "{IS_PRERELEASE}" == "true" ]; then
 71    URL="https://zed.dev/releases/preview"
 72else
 73    URL="https://zed.dev/releases/stable"
 74fi
 75
 76echo "URL=$URL" >> "$GITHUB_OUTPUT"
 77"#
 78        ))
 79        .id("get-release-url")
 80    }
 81
 82    fn get_content() -> Step<Use> {
 83        named::uses(
 84            "2428392",
 85            "gh-truncate-string-action",
 86            "b3ff790d21cf42af3ca7579146eedb93c8fb0757", // v1.4.1
 87        )
 88        .id("get-content")
 89        .add_with((
 90            "stringToTruncate",
 91            format!(
 92                "📣 Zed [{TAG_NAME}](<${{{{ steps.get-release-url.outputs.URL }}}}>)  was just released!\n\n{RELEASE_BODY}\n"
 93            ),
 94        ))
 95        .add_with(("maxLength", 2000))
 96        .add_with(("truncationSymbol", "..."))
 97    }
 98
 99    fn discord_webhook_action() -> Step<Use> {
100        named::uses(
101            "tsickert",
102            "discord-webhook",
103            "c840d45a03a323fbc3f7507ac7769dbd91bfb164", // v5.3.0
104        )
105        .add_with(("webhook-url", vars::DISCORD_WEBHOOK_RELEASE_NOTES))
106        .add_with(("content", "${{ steps.get-content.outputs.string }}"))
107    }
108    let job = dependant_job(deps)
109        .runs_on(runners::LINUX_SMALL)
110        .with_repository_owner_guard()
111        .add_step(get_release_url())
112        .add_step(get_content())
113        .add_step(discord_webhook_action());
114    named::job(job)
115}
116
117fn publish_winget() -> NamedJob {
118    fn set_package_name() -> (Step<Run>, StepOutput) {
119        let script = format!(
120            r#"if ("{IS_PRERELEASE}" -eq "true") {{
121    $PACKAGE_NAME = "ZedIndustries.Zed.Preview"
122}} else {{
123    $PACKAGE_NAME = "ZedIndustries.Zed"
124}}
125
126echo "PACKAGE_NAME=$PACKAGE_NAME" >> $env:GITHUB_OUTPUT
127"#
128        );
129        let step = named::pwsh(&script).id("set-package-name");
130
131        let output = StepOutput::new(&step, "PACKAGE_NAME");
132        (step, output)
133    }
134
135    fn winget_releaser(package_name: &StepOutput) -> Step<Use> {
136        named::uses(
137            "vedantmgoyal9",
138            "winget-releaser",
139            "19e706d4c9121098010096f9c495a70a7518b30f", // v2
140        )
141        .add_with(("identifier", package_name.to_string()))
142        .add_with(("release-tag", TAG_NAME))
143        .add_with(("max-versions-to-keep", 5))
144        .add_with(("token", vars::WINGET_TOKEN))
145    }
146
147    let (set_package_name, package_name) = set_package_name();
148
149    named::job(
150        Job::default()
151            .runs_on(runners::WINDOWS_DEFAULT)
152            .add_step(set_package_name)
153            .add_step(winget_releaser(&package_name)),
154    )
155}
156
157fn create_sentry_release() -> NamedJob {
158    let job = Job::default()
159        .runs_on(runners::LINUX_SMALL)
160        .with_repository_owner_guard()
161        .add_step(checkout_repo())
162        .add_step(release::create_sentry_release());
163    named::job(job)
164}