Store current release channel name in a file in the zed crate

Max Brunsfeld created

Change summary

.github/workflows/ci.yml                   | 36 ++++++++++++++---------
.github/workflows/publish_collab_image.yml | 13 ++++----
Cargo.lock                                 |  1 
crates/auto_update/src/auto_update.rs      | 12 ++++++-
crates/client/Cargo.toml                   |  2 +
crates/client/src/client.rs                | 18 ++++++-----
crates/settings/src/settings.rs            |  8 +++++
crates/zed/RELEASE_CHANNEL                 |  1 
crates/zed/src/main.rs                     |  3 +
crates/zed/src/zed.rs                      | 22 ++++++++++++--
10 files changed, 80 insertions(+), 36 deletions(-)

Detailed changes

.github/workflows/ci.yml 🔗

@@ -79,22 +79,30 @@ jobs:
           clean: false
           submodules: 'recursive'
 
-      - name: Check that tag version matches package version
+      - name: Determine version and release channel
         if: ${{ startsWith(github.ref, 'refs/tags/v') }}
         run: |
           set -eu
-          crate_version=$(script/get-crate-version zed)
-          tag_version=$(echo $GITHUB_REF_NAME | sed -e 's/^v//' -e 's/-pre$//')
-          if [[ $tag_version != $crate_version ]]; then
-            echo "zed crate version $crate_version does not match git tag version $tag_version"
+
+          version=$(script/get-crate-version zed)
+          channel=$(cat crates/zed/RELEASE_CHANNEL)
+          echo "Publishing version: ${version} on release channel ${channel}"
+          echo "RELEASE_CHANNEL=${channel}" >> $GITHUB_ENV
+
+          expected_tag_name=""
+          case ${channel} in
+            stable)
+              expected_tag_name="v${version}";;
+            preview)
+              expected_tag_name="v${version}-pre";;
+            *)
+              echo "can't publish a release on channel ${channel}"
+              exit 1;;
+          esac
+          if [[ $GITHUB_REFNAME != $expected_tag_name ]]; then
+            echo "invalid release tag ${GITHUB_REFNAME}. expected ${expected_tag_name}"
             exit 1
           fi
-          echo "Publishing zed version: $crate_version"
-
-      - name: Enable the preview channel
-        if: ${{ startsWith(github.ref, 'refs/tags/v') && endsWith(github.ref, '-pre') }}
-        run: |
-          echo "ZED_PREVIEW_CHANNEL=1 >> $GITHUB_ENV
 
       - name: Create app bundle
         run: script/bundle
@@ -107,11 +115,11 @@ jobs:
           path: target/release/Zed.dmg
 
       - uses: softprops/action-gh-release@v1
-        name: Upload app bundle to release if release tag
-        if: ${{ startsWith(github.ref, 'refs/tags/v') }}
+        name: Upload app bundle to release
+        if: ${{ github.env.RELEASE_CHANNEL }}
         with:
           draft: true
-          prerelease: ${{ endsWith(github.ref, '-pre') }}
+          prerelease: ${{ github.env.RELEASE_CHANNEL == 'preview' }}
           files: target/release/Zed.dmg
           overwrite: true
           body: ""

.github/workflows/publish_collab_image.yml 🔗

@@ -28,17 +28,16 @@ jobs:
           clean: false
           submodules: 'recursive'
 
-      - name: Check that tag version matches package version
+      - name: Determine version
         run: |
           set -eu
-          crate_version=$(script/get-crate-version collab)
-          tag_version=$(echo $GITHUB_REF_NAME | sed -e 's/collab-v//')
-          if [[ $tag_version != $crate_version ]]; then
-            echo "collab crate version $crate_version does not match git tag version $tag_version"
+          version=$(script/get-crate-version collab)
+          if [[ $GITHUB_REF_NAME != "collab-v${version}" ]]; then
+            echo "release tag ${GITHUB_REF_NAME} does not match version ${version}"
             exit 1
           fi
-          echo "Publishing collab version: $crate_version"
-          echo "COLLAB_VERSION=$crate_version" >> $GITHUB_ENV
+          echo "Publishing collab version: ${version}"
+          echo "COLLAB_VERSION=${version}" >> $GITHUB_ENV
 
       - name: Build docker image
         run: docker build . --tag registry.digitalocean.com/zed/collab:v${COLLAB_VERSION}

Cargo.lock 🔗

@@ -959,6 +959,7 @@ dependencies = [
  "rand 0.8.5",
  "rpc",
  "serde",
+ "settings",
  "smol",
  "sum_tree",
  "tempfile",

crates/auto_update/src/auto_update.rs 🔗

@@ -1,13 +1,14 @@
 mod update_notification;
 
 use anyhow::{anyhow, Context, Result};
-use client::{http::HttpClient, PREVIEW_CHANNEL, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL};
+use client::{http::HttpClient, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL};
 use gpui::{
     actions, platform::AppVersion, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
     MutableAppContext, Task, WeakViewHandle,
 };
 use lazy_static::lazy_static;
 use serde::Deserialize;
+use settings::ReleaseChannel;
 use smol::{fs::File, io::AsyncReadExt, process::Command};
 use std::{env, ffi::OsString, path::PathBuf, sync::Arc, time::Duration};
 use update_notification::UpdateNotification;
@@ -174,7 +175,14 @@ impl AutoUpdater {
             )
         });
 
-        let preview_param = if *PREVIEW_CHANNEL { "&preview=1" } else { "" };
+        let preview_param = cx.read(|cx| {
+            if cx.has_global::<ReleaseChannel>() {
+                if *cx.global::<ReleaseChannel>() == ReleaseChannel::Preview {
+                    return "&preview=1";
+                }
+            }
+            ""
+        });
 
         let mut response = client
             .get(

crates/client/Cargo.toml 🔗

@@ -35,9 +35,11 @@ tiny_http = "0.8"
 uuid = { version = "1.1.2", features = ["v4"] }
 url = "2.2"
 serde = { version = "*", features = ["derive"] }
+settings = { path = "../settings" }
 tempfile = "3"
 
 [dev-dependencies]
 collections = { path = "../collections", features = ["test-support"] }
 gpui = { path = "../gpui", features = ["test-support"] }
 rpc = { path = "../rpc", features = ["test-support"] }
+settings = { path = "../settings", features = ["test-support"] }

crates/client/src/client.rs 🔗

@@ -30,6 +30,7 @@ use postage::watch;
 use rand::prelude::*;
 use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, RequestMessage};
 use serde::Deserialize;
+use settings::ReleaseChannel;
 use std::{
     any::TypeId,
     collections::HashMap,
@@ -50,9 +51,6 @@ pub use rpc::*;
 pub use user::*;
 
 lazy_static! {
-    pub static ref PREVIEW_CHANNEL: bool = std::env::var("ZED_PREVIEW_CHANNEL")
-        .map_or(false, |var| !var.is_empty())
-        || option_env!("ZED_PREVIEW_CHANNEL").map_or(false, |var| !var.is_empty());
     pub static ref ZED_SERVER_URL: String =
         std::env::var("ZED_SERVER_URL").unwrap_or_else(|_| "https://zed.dev".to_string());
     pub static ref IMPERSONATE_LOGIN: Option<String> = std::env::var("ZED_IMPERSONATE")
@@ -970,6 +968,14 @@ impl Client {
         credentials: &Credentials,
         cx: &AsyncAppContext,
     ) -> Task<Result<Connection, EstablishConnectionError>> {
+        let is_preview = cx.read(|cx| {
+            if cx.has_global::<ReleaseChannel>() {
+                *cx.global::<ReleaseChannel>() == ReleaseChannel::Preview
+            } else {
+                false
+            }
+        });
+
         let request = Request::builder()
             .header(
                 "Authorization",
@@ -991,11 +997,7 @@ impl Client {
             match rpc_url.scheme() {
                 "https" => {
                     rpc_url.set_scheme("wss").unwrap();
-                    rpc_url.set_query(if *PREVIEW_CHANNEL {
-                        Some("preview=1")
-                    } else {
-                        None
-                    });
+                    rpc_url.set_query(if is_preview { Some("preview=1") } else { None });
                     let request = request.uri(rpc_url.as_str()).body(())?;
                     let (stream, _) =
                         async_tungstenite::async_tls::client_async_tls(request, stream).await?;

crates/settings/src/settings.rs 🔗

@@ -54,6 +54,14 @@ pub struct FeatureFlags {
     pub experimental_themes: bool,
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Default)]
+pub enum ReleaseChannel {
+    #[default]
+    Dev,
+    Preview,
+    Stable,
+}
+
 impl FeatureFlags {
     pub fn keymap_files(&self) -> Vec<&'static str> {
         vec![]

crates/zed/src/main.rs 🔗

@@ -39,7 +39,7 @@ use settings::watched_json::{watch_keymap_file, watch_settings_file, WatchedJson
 use theme::ThemeRegistry;
 use util::{ResultExt, TryFutureExt};
 use workspace::{self, AppState, ItemHandle, NewFile, OpenPaths, Workspace};
-use zed::{self, build_window_options, initialize_workspace, languages, menus};
+use zed::{self, build_window_options, initialize_workspace, languages, menus, RELEASE_CHANNEL};
 
 fn main() {
     let http = http::client();
@@ -97,6 +97,7 @@ fn main() {
 
         let (settings_file_content, keymap_file) = cx.background().block(config_files).unwrap();
 
+        cx.set_global(*RELEASE_CHANNEL);
         cx.set_global(HomeDir(zed::paths::HOME.to_path_buf()));
 
         //Setup settings global before binding actions

crates/zed/src/zed.rs 🔗

@@ -9,11 +9,11 @@ use anyhow::{anyhow, Context, Result};
 use assets::Assets;
 use breadcrumbs::Breadcrumbs;
 pub use client;
-use client::PREVIEW_CHANNEL;
 use collab_ui::{CollabTitlebarItem, ToggleCollaborationMenu};
 use collections::VecDeque;
 pub use editor;
 use editor::{Editor, MultiBuffer};
+use lazy_static::lazy_static;
 
 use gpui::{
     actions,
@@ -29,7 +29,7 @@ use project_panel::ProjectPanel;
 use search::{BufferSearchBar, ProjectSearchBar};
 use serde::Deserialize;
 use serde_json::to_string_pretty;
-use settings::{keymap_file_json_schema, settings_file_json_schema, Settings};
+use settings::{keymap_file_json_schema, settings_file_json_schema, ReleaseChannel, Settings};
 use std::{env, path::Path, str, sync::Arc};
 use util::ResultExt;
 pub use workspace;
@@ -69,6 +69,16 @@ actions!(
 );
 
 const MIN_FONT_SIZE: f32 = 6.0;
+const RELEASE_CHANNEL_NAME: &str = include_str!("../RELEASE_CHANNEL");
+
+lazy_static! {
+    pub static ref RELEASE_CHANNEL: ReleaseChannel = match RELEASE_CHANNEL_NAME {
+        "dev" => ReleaseChannel::Dev,
+        "preview" => ReleaseChannel::Preview,
+        "stable" => ReleaseChannel::Preview,
+        _ => panic!("invalid release channel {RELEASE_CHANNEL_NAME}"),
+    };
+}
 
 pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
     cx.add_action(about);
@@ -378,11 +388,15 @@ fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) {
 }
 
 fn about(_: &mut Workspace, _: &About, cx: &mut gpui::ViewContext<Workspace>) {
-    let channel = if *PREVIEW_CHANNEL { "Preview " } else { "" };
+    let app_name = match *cx.global::<ReleaseChannel>() {
+        ReleaseChannel::Dev => "Zed Dev",
+        ReleaseChannel::Preview => "Zed Preview",
+        ReleaseChannel::Stable => "Zed",
+    };
     let version = env!("CARGO_PKG_VERSION");
     cx.prompt(
         gpui::PromptLevel::Info,
-        &format!("Zed {channel}{version}"),
+        &format!("{app_name} {version}"),
         &["OK"],
     );
 }