via workflow dispatch

Ben Kunkle created

Change summary

.github/workflows/after_release.yml                | 126 +--------------
.github/workflows/deploy_docs.yml                  |  26 ++
tooling/xtask/src/tasks/workflows/after_release.rs |  68 ++++++-
tooling/xtask/src/tasks/workflows/deploy_docs.rs   |  67 +++++--
4 files changed, 136 insertions(+), 151 deletions(-)

Detailed changes

.github/workflows/after_release.yml 🔗

@@ -11,10 +11,6 @@ on:
         description: tag_name
         required: true
         type: string
-      prerelease:
-        description: prerelease
-        required: true
-        type: boolean
       body:
         description: body
         type: string
@@ -36,114 +32,16 @@ jobs:
         VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
   deploy_docs:
     if: github.repository_owner == 'zed-industries'
-    name: Build and Deploy Docs
-    runs-on: namespace-profile-16x32-ubuntu-2204
-    env:
+    permissions:
+      contents: read
+    uses: zed-industries/zed/.github/workflows/deploy_docs.yml@main
+    secrets:
       DOCS_AMPLITUDE_API_KEY: ${{ secrets.DOCS_AMPLITUDE_API_KEY }}
-      MDBOOK_BOOK__SITE_URL: ${{ steps.resolve-channel.outputs.site_url }}
-      DOCS_CHANNEL: ${{ steps.resolve-channel.outputs.channel }}
-    steps:
-    - id: resolve-channel
-      name: deploy_docs::resolve_channel_step
-      run: |
-        if [ -z "$CHANNEL" ]; then
-            if [ "$GITHUB_REF" = "refs/heads/main" ]; then
-                CHANNEL="nightly"
-            else
-                echo "::error::channel input is required when ref is not main."
-                exit 1
-            fi
-        fi
-
-        case "$CHANNEL" in
-            "nightly")
-                SITE_URL="/docs/nightly/"
-                PROJECT_NAME="docs-nightly"
-                ;;
-            "preview")
-                SITE_URL="/docs/preview/"
-                PROJECT_NAME="docs-preview"
-                ;;
-            "stable")
-                SITE_URL="/docs/"
-                PROJECT_NAME="docs"
-                ;;
-            *)
-                echo "::error::Invalid docs channel '$CHANNEL'. Expected one of: nightly, preview, stable."
-                exit 1
-                ;;
-        esac
-
-        echo "channel=$CHANNEL" >> "$GITHUB_OUTPUT"
-        echo "site_url=$SITE_URL" >> "$GITHUB_OUTPUT"
-        echo "project_name=$PROJECT_NAME" >> "$GITHUB_OUTPUT"
-      env:
-        CHANNEL: ${{ (github.event.release.prerelease || inputs.prerelease) && 'preview' || 'stable' }}
-    - name: steps::checkout_repo
-      uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
-      with:
-        clean: false
-        ref: ${{ github.event.release.tag_name || inputs.tag_name }}
-    - name: steps::setup_cargo_config
-      run: |
-        mkdir -p ./../.cargo
-        cp ./.cargo/ci-config.toml ./../.cargo/config.toml
-    - name: steps::cache_rust_dependencies_namespace
-      uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9
-      with:
-        cache: rust
-        path: ~/.rustup
-    - name: steps::setup_linux
-      run: ./script/linux
-    - name: steps::download_wasi_sdk
-      run: ./script/download-wasi-sdk
-    - name: ./script/generate-action-metadata
-      run: ./script/generate-action-metadata
-    - name: deploy_docs::lychee_link_check
-      uses: lycheeverse/lychee-action@82202e5e9c2f4ef1a55a3d02563e1cb6041e5332
-      with:
-        args: --no-progress --exclude '^http' './docs/src/**/*'
-        fail: true
-        jobSummary: false
-    - name: deploy_docs::install_mdbook
-      uses: peaceiris/actions-mdbook@ee69d230fe19748b7abf22df32acaa93833fad08
-      with:
-        mdbook-version: 0.4.37
-    - name: deploy_docs::build_docs_book
-      run: |
-        mkdir -p target/deploy
-        mdbook build ./docs --dest-dir=../target/deploy/docs/
-    - name: deploy_docs::lychee_link_check
-      uses: lycheeverse/lychee-action@82202e5e9c2f4ef1a55a3d02563e1cb6041e5332
-      with:
-        args: --no-progress --exclude '^http' 'target/deploy/docs'
-        fail: true
-        jobSummary: false
-    - name: deploy_docs::docs_deploy_steps::deploy_to_cf_pages
-      uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65
-      with:
-        apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
-        accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
-        command: pages deploy target/deploy --project-name=${{ steps.resolve-channel.outputs.project_name }}
-    - name: deploy_docs::docs_deploy_steps::upload_install_script
-      uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65
-      with:
-        apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
-        accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
-        command: r2 object put -f script/install.sh zed-open-source-website-assets/install.sh
-    - name: deploy_docs::docs_deploy_steps::deploy_docs_worker
-      uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65
-      with:
-        apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
-        accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
-        command: deploy .cloudflare/docs-proxy/src/worker.js
-    - name: deploy_docs::docs_deploy_steps::upload_wrangler_logs
-      if: always()
-      uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
-      with:
-        name: wrangler_logs
-        path: /home/runner/.config/.wrangler/logs/
-    timeout-minutes: 60
+      CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+      CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+    with:
+      channel: ${{ endsWith(github.event.release.tag_name || inputs.tag_name, '-pre') && 'preview' || 'stable' }}
+      checkout_ref: ${{ github.event.release.tag_name || inputs.tag_name }}
   post_to_discord:
     needs:
     - rebuild_releases_page
@@ -153,7 +51,7 @@ jobs:
     - id: get-release-url
       name: after_release::post_to_discord::get_release_url
       run: |
-        if [ "${{ github.event.release.prerelease || inputs.prerelease }}" == "true" ]; then
+        if [ "${{ endsWith(github.event.release.tag_name || inputs.tag_name, '-pre') }}" == "true" ]; then
             URL="https://zed.dev/releases/preview"
         else
             URL="https://zed.dev/releases/stable"
@@ -200,7 +98,7 @@ jobs:
     - id: set-package-name
       name: after_release::publish_winget::set_package_name
       run: |
-        if ("${{ github.event.release.prerelease || inputs.prerelease }}" -eq "true") {
+        if ("${{ endsWith(github.event.release.tag_name || inputs.tag_name, '-pre') }}" -eq "true") {
             $PACKAGE_NAME = "ZedIndustries.Zed.Preview"
         } else {
             $PACKAGE_NAME = "ZedIndustries.Zed"
@@ -234,10 +132,10 @@ jobs:
   notify_on_failure:
     needs:
     - rebuild_releases_page
-    - deploy_docs
     - post_to_discord
     - publish_winget
     - create_sentry_release
+    - deploy_docs
     if: failure()
     runs-on: namespace-profile-2x4-ubuntu-2404
     steps:

.github/workflows/deploy_docs.yml 🔗

@@ -2,14 +2,34 @@
 # Rebuild with `cargo xtask workflows`.
 name: deploy_docs
 on:
+  workflow_call:
+    inputs:
+      channel:
+        description: channel
+        type: string
+        default: ''
+      checkout_ref:
+        description: checkout_ref
+        type: string
+        default: ''
+    secrets:
+      DOCS_AMPLITUDE_API_KEY:
+        description: DOCS_AMPLITUDE_API_KEY
+        required: true
+      CLOUDFLARE_API_TOKEN:
+        description: CLOUDFLARE_API_TOKEN
+        required: true
+      CLOUDFLARE_ACCOUNT_ID:
+        description: CLOUDFLARE_ACCOUNT_ID
+        required: true
   workflow_dispatch:
     inputs:
       channel:
         description: 'Docs channel to deploy: nightly, preview, or stable'
         type: string
         default: ''
-      commit_sha:
-        description: Exact commit SHA to checkout and deploy. Defaults to event SHA when omitted.
+      checkout_ref:
+        description: Git ref to checkout and deploy. Defaults to event SHA when omitted.
         type: string
         default: ''
 jobs:
@@ -62,7 +82,7 @@ jobs:
       uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
       with:
         clean: false
-        ref: ${{ inputs.commit_sha != '' && inputs.commit_sha || github.sha }}
+        ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || github.sha }}
     - name: steps::setup_cargo_config
       run: |
         mkdir -p ./../.cargo

tooling/xtask/src/tasks/workflows/after_release.rs 🔗

@@ -1,7 +1,6 @@
 use gh_workflow::*;
 
 use crate::tasks::workflows::{
-    deploy_docs,
     release::{self, notify_on_failure},
     runners,
     steps::{CommonJobConditions, NamedJob, checkout_repo, dependant_job, named},
@@ -9,28 +8,32 @@ use crate::tasks::workflows::{
 };
 
 const TAG_NAME: &str = "${{ github.event.release.tag_name || inputs.tag_name }}";
-const IS_PRERELEASE: &str = "${{ github.event.release.prerelease || inputs.prerelease }}";
+const IS_PRERELEASE: &str =
+    "${{ endsWith(github.event.release.tag_name || inputs.tag_name, '-pre') }}";
 const RELEASE_BODY: &str = "${{ github.event.release.body || inputs.body }}";
-const DOCS_CHANNEL: &str =
-    "${{ (github.event.release.prerelease || inputs.prerelease) && 'preview' || 'stable' }}";
+const DOCS_CHANNEL: &str = "${{ endsWith(github.event.release.tag_name || inputs.tag_name, '-pre') && 'preview' || 'stable' }}";
 
 pub fn after_release() -> Workflow {
     let tag_name = WorkflowInput::string("tag_name", None);
-    let prerelease = WorkflowInput::bool("prerelease", None);
     let body = WorkflowInput::string("body", Some(String::new()));
 
     let refresh_zed_dev = rebuild_releases_page();
-    let deploy_docs = deploy_docs::release_docs_job(DOCS_CHANNEL, TAG_NAME);
+    let deploy_docs = deploy_docs();
     let post_to_discord = post_to_discord(&[&refresh_zed_dev]);
     let publish_winget = publish_winget();
     let create_sentry_release = create_sentry_release();
-    let notify_on_failure = notify_on_failure(&[
-        &refresh_zed_dev,
-        &deploy_docs,
-        &post_to_discord,
-        &publish_winget,
-        &create_sentry_release,
-    ]);
+    let notify_on_failure = {
+        let notify_on_failure = notify_on_failure(&[
+            &refresh_zed_dev,
+            &post_to_discord,
+            &publish_winget,
+            &create_sentry_release,
+        ]);
+        NamedJob {
+            name: notify_on_failure.name,
+            job: notify_on_failure.job.add_need(deploy_docs.name.clone()),
+        }
+    };
 
     named::workflow()
         .on(Event::default()
@@ -38,7 +41,6 @@ pub fn after_release() -> Workflow {
             .workflow_dispatch(
                 WorkflowDispatch::default()
                     .add_input(tag_name.name, tag_name.input())
-                    .add_input(prerelease.name, prerelease.input())
                     .add_input(body.name, body.input()),
             ))
         .add_job(refresh_zed_dev.name, refresh_zed_dev.job)
@@ -49,6 +51,44 @@ pub fn after_release() -> Workflow {
         .add_job(notify_on_failure.name, notify_on_failure.job)
 }
 
+fn deploy_docs() -> NamedJob<UsesJob> {
+    let job = Job::default()
+        .cond(Expression::new(
+            "github.repository_owner == 'zed-industries'",
+        ))
+        .permissions(Permissions::default().contents(Level::Read))
+        .uses(
+            "zed-industries",
+            "zed",
+            ".github/workflows/deploy_docs.yml",
+            "main",
+        )
+        .with(
+            Input::default()
+                .add("channel", DOCS_CHANNEL)
+                .add("checkout_ref", TAG_NAME),
+        )
+        .secrets(indexmap::IndexMap::from([
+            (
+                "DOCS_AMPLITUDE_API_KEY".to_owned(),
+                vars::DOCS_AMPLITUDE_API_KEY.to_owned(),
+            ),
+            (
+                "CLOUDFLARE_API_TOKEN".to_owned(),
+                vars::CLOUDFLARE_API_TOKEN.to_owned(),
+            ),
+            (
+                "CLOUDFLARE_ACCOUNT_ID".to_owned(),
+                vars::CLOUDFLARE_ACCOUNT_ID.to_owned(),
+            ),
+        ]));
+
+    NamedJob {
+        name: "deploy_docs".to_owned(),
+        job,
+    }
+}
+
 fn rebuild_releases_page() -> NamedJob {
     fn refresh_cloud_releases() -> Step<Run> {
         named::bash(format!(

tooling/xtask/src/tasks/workflows/deploy_docs.rs 🔗

@@ -1,4 +1,7 @@
-use gh_workflow::{Event, Expression, Job, Run, Step, Use, Workflow, WorkflowDispatch};
+use gh_workflow::{
+    Event, Expression, Job, Run, Step, Use, Workflow, WorkflowCall, WorkflowCallSecret,
+    WorkflowDispatch,
+};
 
 use crate::tasks::workflows::{
     runners,
@@ -239,23 +242,16 @@ fn docs_job(channel_expr: impl Into<String>, checkout_ref: Option<String>) -> Na
     }
 }
 
-pub(crate) fn release_docs_job(
-    channel_expr: impl Into<String>,
-    checkout_ref: impl Into<String>,
-) -> NamedJob {
-    docs_job(channel_expr, Some(checkout_ref.into()))
-}
-
 pub(crate) fn deploy_docs_job(
     channel_input: &WorkflowInput,
-    commit_sha_input: &WorkflowInput,
+    checkout_ref_input: &WorkflowInput,
 ) -> NamedJob {
     docs_job(
         channel_input.expr(),
         Some(format!(
             "${{{{ {} != '' && {} || github.sha }}}}",
-            commit_sha_input.expr(),
-            commit_sha_input.expr()
+            checkout_ref_input.expr(),
+            checkout_ref_input.expr()
         )),
     )
 }
@@ -263,16 +259,47 @@ pub(crate) fn deploy_docs_job(
 pub(crate) fn deploy_docs() -> Workflow {
     let channel = WorkflowInput::string("channel", Some(String::new()))
         .description("Docs channel to deploy: nightly, preview, or stable");
-    let commit_sha = WorkflowInput::string("commit_sha", Some(String::new())).description(
-        "Exact commit SHA to checkout and deploy. Defaults to event SHA when omitted.",
-    );
-    let deploy_docs = deploy_docs_job(&channel, &commit_sha);
+    let checkout_ref = WorkflowInput::string("checkout_ref", Some(String::new()))
+        .description("Git ref to checkout and deploy. Defaults to event SHA when omitted.");
+    let deploy_docs = deploy_docs_job(&channel, &checkout_ref);
 
     named::workflow()
-        .on(Event::default().workflow_dispatch(
-            WorkflowDispatch::default()
-                .add_input(channel.name, channel.input())
-                .add_input(commit_sha.name, commit_sha.input()),
-        ))
+        .add_event(
+            Event::default().workflow_dispatch(
+                WorkflowDispatch::default()
+                    .add_input(channel.name, channel.input())
+                    .add_input(checkout_ref.name, checkout_ref.input()),
+            ),
+        )
+        .add_event(
+            Event::default().workflow_call(
+                WorkflowCall::default()
+                    .add_input(channel.name, channel.call_input())
+                    .add_input(checkout_ref.name, checkout_ref.call_input())
+                    .secrets([
+                        (
+                            "DOCS_AMPLITUDE_API_KEY".to_owned(),
+                            WorkflowCallSecret {
+                                description: "DOCS_AMPLITUDE_API_KEY".to_owned(),
+                                required: true,
+                            },
+                        ),
+                        (
+                            "CLOUDFLARE_API_TOKEN".to_owned(),
+                            WorkflowCallSecret {
+                                description: "CLOUDFLARE_API_TOKEN".to_owned(),
+                                required: true,
+                            },
+                        ),
+                        (
+                            "CLOUDFLARE_ACCOUNT_ID".to_owned(),
+                            WorkflowCallSecret {
+                                description: "CLOUDFLARE_ACCOUNT_ID".to_owned(),
+                                required: true,
+                            },
+                        ),
+                    ]),
+            ),
+        )
         .add_job(deploy_docs.name, deploy_docs.job)
 }