diff --git a/.github/actions/check_formatting/action.yml b/.github/actions/check_formatting/action.yml new file mode 100644 index 0000000000..7fef26407b --- /dev/null +++ b/.github/actions/check_formatting/action.yml @@ -0,0 +1,15 @@ +name: 'Check formatting' +description: 'Checks code formatting use cargo fmt' + +runs: + using: "composite" + steps: + - name: Install Rust + shell: bash -euxo pipefail {0} + run: | + rustup set profile minimal + rustup update stable + + - name: cargo fmt + shell: bash -euxo pipefail {0} + run: cargo fmt --all -- --check diff --git a/.github/actions/run_tests/action.yml b/.github/actions/run_tests/action.yml new file mode 100644 index 0000000000..de5eadb61a --- /dev/null +++ b/.github/actions/run_tests/action.yml @@ -0,0 +1,34 @@ +name: "Run tests" +description: "Runs the tests" + +runs: + using: "composite" + steps: + - name: Install Rust + shell: bash -euxo pipefail {0} + run: | + rustup set profile minimal + rustup update stable + rustup target add wasm32-wasi + cargo install cargo-nextest + + - name: Install Node + uses: actions/setup-node@v3 + with: + node-version: "18" + + - name: Limit target directory size + shell: bash -euxo pipefail {0} + run: script/clear-target-dir-if-larger-than 70 + + - name: Run check + env: + RUSTFLAGS: -D warnings + shell: bash -euxo pipefail {0} + run: cargo check --tests --workspace + + - name: Run tests + env: + RUSTFLAGS: -D warnings + shell: bash -euxo pipefail {0} + run: cargo nextest run --workspace --no-fail-fast diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 60dc4c1f52..65475a41b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,19 +23,14 @@ jobs: - self-hosted - test steps: - - name: Install Rust - run: | - rustup set profile minimal - rustup update stable - - name: Checkout repo uses: actions/checkout@v3 with: clean: false submodules: "recursive" - - name: cargo fmt - run: cargo fmt --all -- --check + - name: Run rustfmt + uses: ./.github/actions/check_formatting tests: name: Run tests @@ -43,35 +38,15 @@ jobs: - self-hosted - test needs: rustfmt - env: - RUSTFLAGS: -D warnings steps: - - name: Install Rust - run: | - rustup set profile minimal - rustup update stable - rustup target add wasm32-wasi - cargo install cargo-nextest - - - name: Install Node - uses: actions/setup-node@v3 - with: - node-version: "18" - - name: Checkout repo uses: actions/checkout@v3 with: clean: false submodules: "recursive" - - name: Limit target directory size - run: script/clear-target-dir-if-larger-than 70 - - - name: Run check - run: cargo check --workspace - - name: Run tests - run: cargo nextest run --workspace --no-fail-fast + uses: ./.github/actions/run_tests - name: Build collab run: cargo build -p collab @@ -130,6 +105,8 @@ jobs: expected_tag_name="v${version}";; preview) expected_tag_name="v${version}-pre";; + nightly) + expected_tag_name="v${version}-nightly";; *) echo "can't publish a release on channel ${channel}" exit 1;; @@ -154,7 +131,9 @@ jobs: - uses: softprops/action-gh-release@v1 name: Upload app bundle to release - if: ${{ env.RELEASE_CHANNEL }} + # TODO kb seems that zed.dev relies on GitHub releases for release version tracking. + # Find alternatives for `nightly` or just go on with more releases? + if: ${{ env.RELEASE_CHANNEL == 'preview' || env.RELEASE_CHANNEL == 'stable' }} with: draft: true prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }} diff --git a/.github/workflows/release_nightly.yml b/.github/workflows/release_nightly.yml new file mode 100644 index 0000000000..447e928866 --- /dev/null +++ b/.github/workflows/release_nightly.yml @@ -0,0 +1,98 @@ +name: Release Nightly + +on: + schedule: + # Fire every night at 1:00am + - cron: "0 1 * * *" + push: + tags: + - "nightly" + +env: + CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 0 + RUST_BACKTRACE: 1 + +jobs: + rustfmt: + name: Check formatting + runs-on: + - self-hosted + - test + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + clean: false + submodules: "recursive" + + - name: Run rustfmt + uses: ./.github/actions/check_formatting + + tests: + name: Run tests + runs-on: + - self-hosted + - test + needs: rustfmt + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + clean: false + submodules: "recursive" + + - name: Run tests + uses: ./.github/actions/run_tests + + bundle: + name: Bundle app + runs-on: + - self-hosted + - bundle + needs: tests + env: + MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }} + MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} + APPLE_NOTARIZATION_USERNAME: ${{ secrets.APPLE_NOTARIZATION_USERNAME }} + APPLE_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }} + DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }} + DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }} + steps: + - name: Install Rust + run: | + rustup set profile minimal + rustup update stable + rustup target add aarch64-apple-darwin + rustup target add x86_64-apple-darwin + rustup target add wasm32-wasi + + - name: Install Node + uses: actions/setup-node@v3 + with: + node-version: "18" + + - name: Checkout repo + uses: actions/checkout@v3 + with: + clean: false + submodules: "recursive" + + - name: Limit target directory size + run: script/clear-target-dir-if-larger-than 70 + + - name: Set release channel to nightly + run: | + set -eu + version=$(git rev-parse --short HEAD) + echo "Publishing version: ${version} on release channel nightly" + echo "nightly" > crates/zed/RELEASE_CHANNEL + + - name: Generate license file + run: script/generate-licenses + + - name: Create app bundle + run: script/bundle -2 + + - name: Upload Zed Nightly + run: script/upload-nightly diff --git a/Cargo.lock b/Cargo.lock index ec9198fc9d..fc045354f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -724,6 +724,30 @@ dependencies = [ "workspace", ] +[[package]] +name = "auto_update2" +version = "0.1.0" +dependencies = [ + "anyhow", + "client2", + "db2", + "gpui2", + "isahc", + "lazy_static", + "log", + "menu2", + "project2", + "serde", + "serde_derive", + "serde_json", + "settings2", + "smol", + "tempdir", + "theme2", + "util", + "workspace2", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -11571,6 +11595,7 @@ dependencies = [ "async-recursion 0.3.2", "async-tar", "async-trait", + "auto_update2", "backtrace", "call2", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 8aeaf6a85d..7c51d32d05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "crates/audio", "crates/audio2", "crates/auto_update", + "crates/auto_update2", "crates/breadcrumbs", "crates/call", "crates/call2", diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs index 0d537b882a..cf285ac7cf 100644 --- a/crates/auto_update/src/auto_update.rs +++ b/crates/auto_update/src/auto_update.rs @@ -118,14 +118,18 @@ fn view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) { let auto_updater = auto_updater.read(cx); let server_url = &auto_updater.server_url; let current_version = auto_updater.current_version; - let latest_release_url = if cx.has_global::() - && *cx.global::() == ReleaseChannel::Preview - { - format!("{server_url}/releases/preview/{current_version}") - } else { - format!("{server_url}/releases/stable/{current_version}") - }; - cx.platform().open_url(&latest_release_url); + if cx.has_global::() { + match cx.global::() { + ReleaseChannel::Dev => {} + ReleaseChannel::Nightly => {} + ReleaseChannel::Preview => cx + .platform() + .open_url(&format!("{server_url}/releases/preview/{current_version}")), + ReleaseChannel::Stable => cx + .platform() + .open_url(&format!("{server_url}/releases/stable/{current_version}")), + } + } } } @@ -224,22 +228,19 @@ impl AutoUpdater { ) }); - let preview_param = cx.read(|cx| { + let mut url_string = format!( + "{server_url}/api/releases/latest?token={ZED_SECRET_CLIENT_TOKEN}&asset=Zed.dmg" + ); + cx.read(|cx| { if cx.has_global::() { - if *cx.global::() == ReleaseChannel::Preview { - return "&preview=1"; + if let Some(param) = cx.global::().release_query_param() { + url_string += "&"; + url_string += param; } } - "" }); - let mut response = client - .get( - &format!("{server_url}/api/releases/latest?token={ZED_SECRET_CLIENT_TOKEN}&asset=Zed.dmg{preview_param}"), - Default::default(), - true, - ) - .await?; + let mut response = client.get(&url_string, Default::default(), true).await?; let mut body = Vec::new(); response diff --git a/crates/auto_update2/Cargo.toml b/crates/auto_update2/Cargo.toml new file mode 100644 index 0000000000..20eb129746 --- /dev/null +++ b/crates/auto_update2/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "auto_update2" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "src/auto_update.rs" +doctest = false + +[dependencies] +db = { package = "db2", path = "../db2" } +client = { package = "client2", path = "../client2" } +gpui = { package = "gpui2", path = "../gpui2" } +menu = { package = "menu2", path = "../menu2" } +project = { package = "project2", path = "../project2" } +settings = { package = "settings2", path = "../settings2" } +theme = { package = "theme2", path = "../theme2" } +workspace = { package = "workspace2", path = "../workspace2" } +util = { path = "../util" } +anyhow.workspace = true +isahc.workspace = true +lazy_static.workspace = true +log.workspace = true +serde.workspace = true +serde_derive.workspace = true +serde_json.workspace = true +smol.workspace = true +tempdir.workspace = true diff --git a/crates/auto_update2/src/auto_update.rs b/crates/auto_update2/src/auto_update.rs new file mode 100644 index 0000000000..06b4e45066 --- /dev/null +++ b/crates/auto_update2/src/auto_update.rs @@ -0,0 +1,392 @@ +mod update_notification; + +use anyhow::{anyhow, Context, Result}; +use client::{Client, TelemetrySettings, ZED_APP_PATH, ZED_APP_VERSION, ZED_SECRET_CLIENT_TOKEN}; +use db::kvp::KEY_VALUE_STORE; +use db::RELEASE_CHANNEL; +use gpui::{ + actions, AppContext, AsyncAppContext, Context as _, Model, ModelContext, SemanticVersion, Task, + ViewContext, VisualContext, +}; +use isahc::AsyncBody; +use serde::Deserialize; +use serde_derive::Serialize; +use smol::io::AsyncReadExt; + +use settings::{Settings, SettingsStore}; +use smol::{fs::File, process::Command}; +use std::{ffi::OsString, sync::Arc, time::Duration}; +use update_notification::UpdateNotification; +use util::channel::{AppCommitSha, ReleaseChannel}; +use util::http::HttpClient; +use workspace::Workspace; + +const SHOULD_SHOW_UPDATE_NOTIFICATION_KEY: &str = "auto-updater-should-show-updated-notification"; +const POLL_INTERVAL: Duration = Duration::from_secs(60 * 60); + +actions!(Check, DismissErrorMessage, ViewReleaseNotes); + +#[derive(Serialize)] +struct UpdateRequestBody { + installation_id: Option>, + release_channel: Option<&'static str>, + telemetry: bool, +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum AutoUpdateStatus { + Idle, + Checking, + Downloading, + Installing, + Updated, + Errored, +} + +pub struct AutoUpdater { + status: AutoUpdateStatus, + current_version: SemanticVersion, + http_client: Arc, + pending_poll: Option>>, + server_url: String, +} + +#[derive(Deserialize)] +struct JsonRelease { + version: String, + url: String, +} + +struct AutoUpdateSetting(bool); + +impl Settings for AutoUpdateSetting { + const KEY: Option<&'static str> = Some("auto_update"); + + type FileContent = Option; + + fn load( + default_value: &Option, + user_values: &[&Option], + _: &mut AppContext, + ) -> Result { + Ok(Self( + Self::json_merge(default_value, user_values)?.ok_or_else(Self::missing_default)?, + )) + } +} + +pub fn init(http_client: Arc, server_url: String, cx: &mut AppContext) { + AutoUpdateSetting::register(cx); + + cx.observe_new_views(|wokrspace: &mut Workspace, _cx| { + wokrspace.register_action(|_, action: &Check, cx| check(action, cx)); + }) + .detach(); + + if let Some(version) = *ZED_APP_VERSION { + let auto_updater = cx.build_model(|cx| { + let updater = AutoUpdater::new(version, http_client, server_url); + + let mut update_subscription = AutoUpdateSetting::get_global(cx) + .0 + .then(|| updater.start_polling(cx)); + + cx.observe_global::(move |updater, cx| { + if AutoUpdateSetting::get_global(cx).0 { + if update_subscription.is_none() { + update_subscription = Some(updater.start_polling(cx)) + } + } else { + update_subscription.take(); + } + }) + .detach(); + + updater + }); + cx.set_global(Some(auto_updater)); + //todo!(action) + // cx.add_global_action(view_release_notes); + // cx.add_action(UpdateNotification::dismiss); + } +} + +pub fn check(_: &Check, cx: &mut AppContext) { + if let Some(updater) = AutoUpdater::get(cx) { + updater.update(cx, |updater, cx| updater.poll(cx)); + } +} + +fn _view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) { + if let Some(auto_updater) = AutoUpdater::get(cx) { + let auto_updater = auto_updater.read(cx); + let server_url = &auto_updater.server_url; + let current_version = auto_updater.current_version; + if cx.has_global::() { + match cx.global::() { + ReleaseChannel::Dev => {} + ReleaseChannel::Nightly => {} + ReleaseChannel::Preview => { + cx.open_url(&format!("{server_url}/releases/preview/{current_version}")) + } + ReleaseChannel::Stable => { + cx.open_url(&format!("{server_url}/releases/stable/{current_version}")) + } + } + } + } +} + +pub fn notify_of_any_new_update(cx: &mut ViewContext) -> Option<()> { + let updater = AutoUpdater::get(cx)?; + let version = updater.read(cx).current_version; + let should_show_notification = updater.read(cx).should_show_update_notification(cx); + + cx.spawn(|workspace, mut cx| async move { + let should_show_notification = should_show_notification.await?; + if should_show_notification { + workspace.update(&mut cx, |workspace, cx| { + workspace.show_notification(0, cx, |cx| { + cx.build_view(|_| UpdateNotification::new(version)) + }); + updater + .read(cx) + .set_should_show_update_notification(false, cx) + .detach_and_log_err(cx); + })?; + } + anyhow::Ok(()) + }) + .detach(); + + None +} + +impl AutoUpdater { + pub fn get(cx: &mut AppContext) -> Option> { + cx.default_global::>>().clone() + } + + fn new( + current_version: SemanticVersion, + http_client: Arc, + server_url: String, + ) -> Self { + Self { + status: AutoUpdateStatus::Idle, + current_version, + http_client, + server_url, + pending_poll: None, + } + } + + pub fn start_polling(&self, cx: &mut ModelContext) -> Task> { + cx.spawn(|this, mut cx| async move { + loop { + this.update(&mut cx, |this, cx| this.poll(cx))?; + cx.background_executor().timer(POLL_INTERVAL).await; + } + }) + } + + pub fn poll(&mut self, cx: &mut ModelContext) { + if self.pending_poll.is_some() || self.status == AutoUpdateStatus::Updated { + return; + } + + self.status = AutoUpdateStatus::Checking; + cx.notify(); + + self.pending_poll = Some(cx.spawn(|this, mut cx| async move { + let result = Self::update(this.upgrade()?, cx.clone()).await; + this.update(&mut cx, |this, cx| { + this.pending_poll = None; + if let Err(error) = result { + log::error!("auto-update failed: error:{:?}", error); + this.status = AutoUpdateStatus::Errored; + cx.notify(); + } + }) + .ok() + })); + } + + pub fn status(&self) -> AutoUpdateStatus { + self.status + } + + pub fn dismiss_error(&mut self, cx: &mut ModelContext) { + self.status = AutoUpdateStatus::Idle; + cx.notify(); + } + + async fn update(this: Model, mut cx: AsyncAppContext) -> Result<()> { + let (client, server_url, current_version) = this.read_with(&cx, |this, _| { + ( + this.http_client.clone(), + this.server_url.clone(), + this.current_version, + ) + })?; + + let mut url_string = format!( + "{server_url}/api/releases/latest?token={ZED_SECRET_CLIENT_TOKEN}&asset=Zed.dmg" + ); + cx.update(|cx| { + if cx.has_global::() { + if let Some(param) = cx.global::().release_query_param() { + url_string += "&"; + url_string += param; + } + } + })?; + + let mut response = client.get(&url_string, Default::default(), true).await?; + + let mut body = Vec::new(); + response + .body_mut() + .read_to_end(&mut body) + .await + .context("error reading release")?; + let release: JsonRelease = + serde_json::from_slice(body.as_slice()).context("error deserializing release")?; + + let should_download = match *RELEASE_CHANNEL { + ReleaseChannel::Nightly => cx + .try_read_global::(|sha, _| release.version != sha.0) + .unwrap_or(true), + _ => release.version.parse::()? <= current_version, + }; + + if !should_download { + this.update(&mut cx, |this, cx| { + this.status = AutoUpdateStatus::Idle; + cx.notify(); + })?; + return Ok(()); + } + + this.update(&mut cx, |this, cx| { + this.status = AutoUpdateStatus::Downloading; + cx.notify(); + })?; + + let temp_dir = tempdir::TempDir::new("zed-auto-update")?; + let dmg_path = temp_dir.path().join("Zed.dmg"); + let mount_path = temp_dir.path().join("Zed"); + let running_app_path = ZED_APP_PATH + .clone() + .map_or_else(|| cx.update(|cx| cx.app_path())?, Ok)?; + let running_app_filename = running_app_path + .file_name() + .ok_or_else(|| anyhow!("invalid running app path"))?; + let mut mounted_app_path: OsString = mount_path.join(running_app_filename).into(); + mounted_app_path.push("/"); + + let mut dmg_file = File::create(&dmg_path).await?; + + let (installation_id, release_channel, telemetry) = cx.update(|cx| { + let installation_id = cx.global::>().telemetry().installation_id(); + let release_channel = cx + .has_global::() + .then(|| cx.global::().display_name()); + let telemetry = TelemetrySettings::get_global(cx).metrics; + + (installation_id, release_channel, telemetry) + })?; + + let request_body = AsyncBody::from(serde_json::to_string(&UpdateRequestBody { + installation_id, + release_channel, + telemetry, + })?); + + let mut response = client.get(&release.url, request_body, true).await?; + smol::io::copy(response.body_mut(), &mut dmg_file).await?; + log::info!("downloaded update. path:{:?}", dmg_path); + + this.update(&mut cx, |this, cx| { + this.status = AutoUpdateStatus::Installing; + cx.notify(); + })?; + + let output = Command::new("hdiutil") + .args(&["attach", "-nobrowse"]) + .arg(&dmg_path) + .arg("-mountroot") + .arg(&temp_dir.path()) + .output() + .await?; + if !output.status.success() { + Err(anyhow!( + "failed to mount: {:?}", + String::from_utf8_lossy(&output.stderr) + ))?; + } + + let output = Command::new("rsync") + .args(&["-av", "--delete"]) + .arg(&mounted_app_path) + .arg(&running_app_path) + .output() + .await?; + if !output.status.success() { + Err(anyhow!( + "failed to copy app: {:?}", + String::from_utf8_lossy(&output.stderr) + ))?; + } + + let output = Command::new("hdiutil") + .args(&["detach"]) + .arg(&mount_path) + .output() + .await?; + if !output.status.success() { + Err(anyhow!( + "failed to unmount: {:?}", + String::from_utf8_lossy(&output.stderr) + ))?; + } + + this.update(&mut cx, |this, cx| { + this.set_should_show_update_notification(true, cx) + .detach_and_log_err(cx); + this.status = AutoUpdateStatus::Updated; + cx.notify(); + })?; + Ok(()) + } + + fn set_should_show_update_notification( + &self, + should_show: bool, + cx: &AppContext, + ) -> Task> { + cx.background_executor().spawn(async move { + if should_show { + KEY_VALUE_STORE + .write_kvp( + SHOULD_SHOW_UPDATE_NOTIFICATION_KEY.to_string(), + "".to_string(), + ) + .await?; + } else { + KEY_VALUE_STORE + .delete_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY.to_string()) + .await?; + } + Ok(()) + }) + } + + fn should_show_update_notification(&self, cx: &AppContext) -> Task> { + cx.background_executor().spawn(async move { + Ok(KEY_VALUE_STORE + .read_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY)? + .is_some()) + }) + } +} diff --git a/crates/auto_update2/src/update_notification.rs b/crates/auto_update2/src/update_notification.rs new file mode 100644 index 0000000000..b77682c9ae --- /dev/null +++ b/crates/auto_update2/src/update_notification.rs @@ -0,0 +1,87 @@ +use gpui::{div, Div, EventEmitter, ParentComponent, Render, SemanticVersion, ViewContext}; +use menu::Cancel; +use workspace::notifications::NotificationEvent; + +pub struct UpdateNotification { + _version: SemanticVersion, +} + +impl EventEmitter for UpdateNotification {} + +impl Render for UpdateNotification { + type Element = Div; + + fn render(&mut self, _cx: &mut gpui::ViewContext) -> Self::Element { + div().child("Updated zed!") + // let theme = theme::current(cx).clone(); + // let theme = &theme.update_notification; + + // let app_name = cx.global::().display_name(); + + // MouseEventHandler::new::(0, cx, |state, cx| { + // Flex::column() + // .with_child( + // Flex::row() + // .with_child( + // Text::new( + // format!("Updated to {app_name} {}", self.version), + // theme.message.text.clone(), + // ) + // .contained() + // .with_style(theme.message.container) + // .aligned() + // .top() + // .left() + // .flex(1., true), + // ) + // .with_child( + // MouseEventHandler::new::(0, cx, |state, _| { + // let style = theme.dismiss_button.style_for(state); + // Svg::new("icons/x.svg") + // .with_color(style.color) + // .constrained() + // .with_width(style.icon_width) + // .aligned() + // .contained() + // .with_style(style.container) + // .constrained() + // .with_width(style.button_width) + // .with_height(style.button_width) + // }) + // .with_padding(Padding::uniform(5.)) + // .on_click(MouseButton::Left, move |_, this, cx| { + // this.dismiss(&Default::default(), cx) + // }) + // .aligned() + // .constrained() + // .with_height(cx.font_cache().line_height(theme.message.text.font_size)) + // .aligned() + // .top() + // .flex_float(), + // ), + // ) + // .with_child({ + // let style = theme.action_message.style_for(state); + // Text::new("View the release notes", style.text.clone()) + // .contained() + // .with_style(style.container) + // }) + // .contained() + // }) + // .with_cursor_style(CursorStyle::PointingHand) + // .on_click(MouseButton::Left, |_, _, cx| { + // crate::view_release_notes(&Default::default(), cx) + // }) + // .into_any_named("update notification") + } +} + +impl UpdateNotification { + pub fn new(version: SemanticVersion) -> Self { + Self { _version: version } + } + + pub fn _dismiss(&mut self, _: &Cancel, cx: &mut ViewContext) { + cx.emit(NotificationEvent::Dismiss); + } +} diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index 9f63d0e2be..a14088cc50 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -987,9 +987,17 @@ impl Client { self.establish_websocket_connection(credentials, cx) } - async fn get_rpc_url(http: Arc, is_preview: bool) -> Result { - let preview_param = if is_preview { "?preview=1" } else { "" }; - let url = format!("{}/rpc{preview_param}", *ZED_SERVER_URL); + async fn get_rpc_url( + http: Arc, + release_channel: Option, + ) -> Result { + let mut url = format!("{}/rpc", *ZED_SERVER_URL); + if let Some(preview_param) = + release_channel.and_then(|channel| channel.release_query_param()) + { + url += "?"; + url += preview_param; + } let response = http.get(&url, Default::default(), false).await?; // Normally, ZED_SERVER_URL is set to the URL of zed.dev website. @@ -1024,11 +1032,11 @@ impl Client { credentials: &Credentials, cx: &AsyncAppContext, ) -> Task> { - let use_preview_server = cx.read(|cx| { + let release_channel = cx.read(|cx| { if cx.has_global::() { - *cx.global::() != ReleaseChannel::Stable + Some(*cx.global::()) } else { - false + None } }); @@ -1041,7 +1049,7 @@ impl Client { let http = self.http.clone(); cx.background().spawn(async move { - let mut rpc_url = Self::get_rpc_url(http, use_preview_server).await?; + let mut rpc_url = Self::get_rpc_url(http, release_channel).await?; let rpc_host = rpc_url .host_str() .zip(rpc_url.port_or_known_default()) @@ -1191,7 +1199,7 @@ impl Client { // Use the collab server's admin API to retrieve the id // of the impersonated user. - let mut url = Self::get_rpc_url(http.clone(), false).await?; + let mut url = Self::get_rpc_url(http.clone(), None).await?; url.set_path("/user"); url.set_query(Some(&format!("github_login={login}"))); let request = Request::get(url.as_str()) diff --git a/crates/client/src/telemetry.rs b/crates/client/src/telemetry.rs index fd93aaeec8..ad2b29c388 100644 --- a/crates/client/src/telemetry.rs +++ b/crates/client/src/telemetry.rs @@ -20,7 +20,7 @@ pub struct Telemetry { #[derive(Default)] struct TelemetryState { metrics_id: Option>, // Per logged-in user - installation_id: Option>, // Per app installation (different for dev, preview, and stable) + installation_id: Option>, // Per app installation (different for dev, nightly, preview, and stable) session_id: Option>, // Per app launch app_version: Option>, release_channel: Option<&'static str>, diff --git a/crates/client2/src/client2.rs b/crates/client2/src/client2.rs index 93ec7f329b..b4279b023e 100644 --- a/crates/client2/src/client2.rs +++ b/crates/client2/src/client2.rs @@ -923,9 +923,17 @@ impl Client { self.establish_websocket_connection(credentials, cx) } - async fn get_rpc_url(http: Arc, is_preview: bool) -> Result { - let preview_param = if is_preview { "?preview=1" } else { "" }; - let url = format!("{}/rpc{preview_param}", *ZED_SERVER_URL); + async fn get_rpc_url( + http: Arc, + release_channel: Option, + ) -> Result { + let mut url = format!("{}/rpc", *ZED_SERVER_URL); + if let Some(preview_param) = + release_channel.and_then(|channel| channel.release_query_param()) + { + url += "?"; + url += preview_param; + } let response = http.get(&url, Default::default(), false).await?; // Normally, ZED_SERVER_URL is set to the URL of zed.dev website. @@ -960,9 +968,7 @@ impl Client { credentials: &Credentials, cx: &AsyncAppContext, ) -> Task> { - let use_preview_server = cx - .try_read_global(|channel: &ReleaseChannel, _| *channel != ReleaseChannel::Stable) - .unwrap_or(false); + let release_channel = cx.try_read_global(|channel: &ReleaseChannel, _| *channel); let request = Request::builder() .header( @@ -973,7 +979,7 @@ impl Client { let http = self.http.clone(); cx.background_executor().spawn(async move { - let mut rpc_url = Self::get_rpc_url(http, use_preview_server).await?; + let mut rpc_url = Self::get_rpc_url(http, release_channel).await?; let rpc_host = rpc_url .host_str() .zip(rpc_url.port_or_known_default()) @@ -1120,7 +1126,7 @@ impl Client { // Use the collab server's admin API to retrieve the id // of the impersonated user. - let mut url = Self::get_rpc_url(http.clone(), false).await?; + let mut url = Self::get_rpc_url(http.clone(), None).await?; url.set_path("/user"); url.set_query(Some(&format!("github_login={login}"))); let request = Request::get(url.as_str()) diff --git a/crates/client2/src/telemetry.rs b/crates/client2/src/telemetry.rs index 3723f7b906..cf5b3b765b 100644 --- a/crates/client2/src/telemetry.rs +++ b/crates/client2/src/telemetry.rs @@ -20,7 +20,7 @@ pub struct Telemetry { struct TelemetryState { metrics_id: Option>, // Per logged-in user - installation_id: Option>, // Per app installation (different for dev, preview, and stable) + installation_id: Option>, // Per app installation (different for dev, nightly, preview, and stable) session_id: Option>, // Per app launch release_channel: Option<&'static str>, app_metadata: AppMetadata, diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index b5083b97c2..ca96ba210e 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -492,6 +492,10 @@ impl AppContext { self.platform.open_url(url); } + pub fn app_path(&self) -> Result { + self.platform.app_path() + } + pub fn path_for_auxiliary_executable(&self, name: &str) -> Result { self.platform.path_for_auxiliary_executable(name) } diff --git a/crates/util/src/channel.rs b/crates/util/src/channel.rs index 47c6a570a1..55f13df084 100644 --- a/crates/util/src/channel.rs +++ b/crates/util/src/channel.rs @@ -1,6 +1,5 @@ -use std::env; - use lazy_static::lazy_static; +use std::env; lazy_static! { pub static ref RELEASE_CHANNEL_NAME: String = if cfg!(debug_assertions) { @@ -9,18 +8,22 @@ lazy_static! { } else { include_str!("../../zed/RELEASE_CHANNEL").to_string() }; - pub static ref RELEASE_CHANNEL: ReleaseChannel = match RELEASE_CHANNEL_NAME.as_str() { + pub static ref RELEASE_CHANNEL: ReleaseChannel = match RELEASE_CHANNEL_NAME.as_str().trim() { "dev" => ReleaseChannel::Dev, + "nightly" => ReleaseChannel::Nightly, "preview" => ReleaseChannel::Preview, "stable" => ReleaseChannel::Stable, _ => panic!("invalid release channel {}", *RELEASE_CHANNEL_NAME), }; } +pub struct AppCommitSha(pub String); + #[derive(Copy, Clone, PartialEq, Eq, Default)] pub enum ReleaseChannel { #[default] Dev, + Nightly, Preview, Stable, } @@ -29,6 +32,7 @@ impl ReleaseChannel { pub fn display_name(&self) -> &'static str { match self { ReleaseChannel::Dev => "Zed Dev", + ReleaseChannel::Nightly => "Zed Nightly", ReleaseChannel::Preview => "Zed Preview", ReleaseChannel::Stable => "Zed", } @@ -37,6 +41,7 @@ impl ReleaseChannel { pub fn dev_name(&self) -> &'static str { match self { ReleaseChannel::Dev => "dev", + ReleaseChannel::Nightly => "nightly", ReleaseChannel::Preview => "preview", ReleaseChannel::Stable => "stable", } @@ -45,6 +50,7 @@ impl ReleaseChannel { pub fn url_scheme(&self) -> &'static str { match self { ReleaseChannel::Dev => "zed-dev://", + ReleaseChannel::Nightly => "zed-nightly://", ReleaseChannel::Preview => "zed-preview://", ReleaseChannel::Stable => "zed://", } @@ -53,15 +59,27 @@ impl ReleaseChannel { pub fn link_prefix(&self) -> &'static str { match self { ReleaseChannel::Dev => "https://zed.dev/dev/", + // TODO kb need to add server handling + ReleaseChannel::Nightly => "https://zed.dev/nightly/", ReleaseChannel::Preview => "https://zed.dev/preview/", ReleaseChannel::Stable => "https://zed.dev/", } } + + pub fn release_query_param(&self) -> Option<&'static str> { + match self { + Self::Dev => None, + Self::Nightly => Some("nightly=1"), + Self::Preview => Some("preview=1"), + Self::Stable => None, + } + } } pub fn parse_zed_link(link: &str) -> Option<&str> { for release in [ ReleaseChannel::Dev, + ReleaseChannel::Nightly, ReleaseChannel::Preview, ReleaseChannel::Stable, ] { diff --git a/crates/workspace2/src/notifications.rs b/crates/workspace2/src/notifications.rs index 7277cc6fc4..b1df74c61a 100644 --- a/crates/workspace2/src/notifications.rs +++ b/crates/workspace2/src/notifications.rs @@ -15,6 +15,8 @@ pub enum NotificationEvent { pub trait Notification: EventEmitter + Render {} +impl + Render> Notification for V {} + pub trait NotificationHandle: Send { fn id(&self) -> EntityId; fn to_any(&self) -> AnyView; @@ -164,7 +166,7 @@ impl Workspace { } pub mod simple_message_notification { - use super::{Notification, NotificationEvent}; + use super::NotificationEvent; use gpui::{AnyElement, AppContext, Div, EventEmitter, Render, TextStyle, ViewContext}; use serde::Deserialize; use std::{borrow::Cow, sync::Arc}; @@ -359,7 +361,6 @@ pub mod simple_message_notification { // } impl EventEmitter for MessageNotification {} - impl Notification for MessageNotification {} } pub trait NotifyResultExt { diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 028653696a..ab8d5b7efe 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -170,6 +170,15 @@ osx_minimum_system_version = "10.15.7" osx_info_plist_exts = ["resources/info/*"] osx_url_schemes = ["zed-dev"] +[package.metadata.bundle-nightly] +# TODO kb different icon? +icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"] +identifier = "dev.zed.Zed-Nightly" +name = "Zed Nightly" +osx_minimum_system_version = "10.15.7" +osx_info_plist_exts = ["resources/info/*"] +osx_url_schemes = ["zed-nightly"] + [package.metadata.bundle-preview] icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"] identifier = "dev.zed.Zed-Preview" @@ -178,7 +187,6 @@ osx_minimum_system_version = "10.15.7" osx_info_plist_exts = ["resources/info/*"] osx_url_schemes = ["zed-preview"] - [package.metadata.bundle-stable] icon = ["resources/app-icon@2x.png", "resources/app-icon.png"] identifier = "dev.zed.Zed" diff --git a/crates/zed/contents/nightly/embedded.provisionprofile b/crates/zed/contents/nightly/embedded.provisionprofile new file mode 100644 index 0000000000..8979e1fb9f Binary files /dev/null and b/crates/zed/contents/nightly/embedded.provisionprofile differ diff --git a/crates/zed/src/only_instance.rs b/crates/zed/src/only_instance.rs index a8c4b30816..85dbd3684a 100644 --- a/crates/zed/src/only_instance.rs +++ b/crates/zed/src/only_instance.rs @@ -17,6 +17,7 @@ fn address() -> SocketAddr { ReleaseChannel::Dev => 43737, ReleaseChannel::Preview => 43738, ReleaseChannel::Stable => 43739, + ReleaseChannel::Nightly => 43740, }; SocketAddr::V4(SocketAddrV4::new(LOCALHOST, port)) @@ -25,6 +26,7 @@ fn address() -> SocketAddr { fn instance_handshake() -> &'static str { match *util::channel::RELEASE_CHANNEL { ReleaseChannel::Dev => "Zed Editor Dev Instance Running", + ReleaseChannel::Nightly => "Zed Editor Nightly Instance Running", ReleaseChannel::Preview => "Zed Editor Preview Instance Running", ReleaseChannel::Stable => "Zed Editor Stable Instance Running", } diff --git a/crates/zed2/Cargo.toml b/crates/zed2/Cargo.toml index 2f39b8f96b..087af56170 100644 --- a/crates/zed2/Cargo.toml +++ b/crates/zed2/Cargo.toml @@ -11,14 +11,14 @@ path = "src/zed2.rs" doctest = false [[bin]] -name = "Zed2" +name = "zed2" path = "src/main.rs" [dependencies] ai = { package = "ai2", path = "../ai2"} # audio = { path = "../audio" } # activity_indicator = { path = "../activity_indicator" } -# auto_update = { path = "../auto_update" } +auto_update = { package = "auto_update2", path = "../auto_update2" } # breadcrumbs = { path = "../breadcrumbs" } call = { package = "call2", path = "../call2" } # channel = { path = "../channel" } @@ -166,6 +166,14 @@ osx_minimum_system_version = "10.15.7" osx_info_plist_exts = ["resources/info/*"] osx_url_schemes = ["zed-dev"] +[package.metadata.bundle-nightly] +icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"] +identifier = "dev.zed.Zed-Dev" +name = "Zed Nightly" +osx_minimum_system_version = "10.15.7" +osx_info_plist_exts = ["resources/info/*"] +osx_url_schemes = ["zed-dev"] + [package.metadata.bundle-preview] icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"] identifier = "dev.zed.Zed-Preview" diff --git a/crates/zed2/build.rs b/crates/zed2/build.rs index 14bf9999fb..619f248029 100644 --- a/crates/zed2/build.rs +++ b/crates/zed2/build.rs @@ -1,3 +1,5 @@ +use std::process::Command; + fn main() { println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.15.7"); @@ -21,4 +23,14 @@ fn main() { // Register exported Objective-C selectors, protocols, etc println!("cargo:rustc-link-arg=-Wl,-ObjC"); + + // Populate git sha environment variable if git is available + if let Ok(output) = Command::new("git").args(["rev-parse", "HEAD"]).output() { + if output.status.success() { + println!( + "cargo:rustc-env=ZED_COMMIT_SHA={}", + String::from_utf8_lossy(&output.stdout).trim() + ); + } + } } diff --git a/crates/zed2/contents/nightly/embedded.provisionprofile b/crates/zed2/contents/nightly/embedded.provisionprofile new file mode 100644 index 0000000000..8979e1fb9f Binary files /dev/null and b/crates/zed2/contents/nightly/embedded.provisionprofile differ diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index 3140ad5414..6c402514d2 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -43,7 +43,7 @@ use std::{ use theme::ActiveTheme; use util::{ async_maybe, - channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL}, + channel::{parse_zed_link, AppCommitSha, ReleaseChannel, RELEASE_CHANNEL}, http::{self, HttpClient}, paths, ResultExt, }; @@ -113,6 +113,10 @@ fn main() { app.run(move |cx| { cx.set_global(*RELEASE_CHANNEL); + if let Some(build_sha) = option_env!("ZED_COMMIT_SHA") { + cx.set_global(AppCommitSha(build_sha.into())) + } + cx.set_global(listener.clone()); load_embedded_fonts(cx); @@ -183,7 +187,7 @@ fn main() { cx.set_global(Arc::downgrade(&app_state)); // audio::init(Assets, cx); - // auto_update::init(http.clone(), client::ZED_SERVER_URL.clone(), cx); + auto_update::init(http.clone(), client::ZED_SERVER_URL.clone(), cx); workspace::init(app_state.clone(), cx); // recent_projects::init(cx); diff --git a/crates/zed2/src/only_instance.rs b/crates/zed2/src/only_instance.rs index a8c4b30816..85dbd3684a 100644 --- a/crates/zed2/src/only_instance.rs +++ b/crates/zed2/src/only_instance.rs @@ -17,6 +17,7 @@ fn address() -> SocketAddr { ReleaseChannel::Dev => 43737, ReleaseChannel::Preview => 43738, ReleaseChannel::Stable => 43739, + ReleaseChannel::Nightly => 43740, }; SocketAddr::V4(SocketAddrV4::new(LOCALHOST, port)) @@ -25,6 +26,7 @@ fn address() -> SocketAddr { fn instance_handshake() -> &'static str { match *util::channel::RELEASE_CHANNEL { ReleaseChannel::Dev => "Zed Editor Dev Instance Running", + ReleaseChannel::Nightly => "Zed Editor Nightly Instance Running", ReleaseChannel::Preview => "Zed Editor Preview Instance Running", ReleaseChannel::Stable => "Zed Editor Stable Instance Running", } diff --git a/crates/zed2/src/zed2.rs b/crates/zed2/src/zed2.rs index e46f0b14c2..97223f1174 100644 --- a/crates/zed2/src/zed2.rs +++ b/crates/zed2/src/zed2.rs @@ -23,7 +23,7 @@ use std::{borrow::Cow, ops::Deref, sync::Arc}; use terminal_view::terminal_panel::TerminalPanel; use util::{ asset_str, - channel::ReleaseChannel, + channel::{AppCommitSha, ReleaseChannel}, paths::{self, LOCAL_SETTINGS_RELATIVE_PATH}, ResultExt, }; @@ -162,7 +162,7 @@ pub fn initialize_workspace(app_state: Arc, cx: &mut AppContext) { // status_bar.add_right_item(cursor_position, cx); }); - // auto_update::notify_of_any_new_update(cx.weak_handle(), cx); + auto_update::notify_of_any_new_update(cx); // vim::observe_keystrokes(cx); @@ -432,9 +432,16 @@ pub fn initialize_workspace(app_state: Arc, cx: &mut AppContext) { } fn about(_: &mut Workspace, _: &About, cx: &mut gpui::ViewContext) { + use std::fmt::Write as _; + let app_name = cx.global::().display_name(); let version = env!("CARGO_PKG_VERSION"); - let prompt = cx.prompt(PromptLevel::Info, &format!("{app_name} {version}"), &["OK"]); + let mut message = format!("{app_name} {version}"); + if let Some(sha) = cx.try_global::() { + write!(&mut message, "\n\n{}", sha.0).unwrap(); + } + + let prompt = cx.prompt(PromptLevel::Info, &message, &["OK"]); cx.foreground_executor() .spawn(async { prompt.await.ok(); diff --git a/script/bump-nightly b/script/bump-nightly new file mode 100755 index 0000000000..92cdd191eb --- /dev/null +++ b/script/bump-nightly @@ -0,0 +1,11 @@ +#!/bin/bash + +branch=$(git rev-parse --abbrev-ref HEAD) +if [ "$branch" != "main" ]; then + echo "You must be on main to run this script" + exit 1 +fi + +git pull --ff-only origin main +git tag -f nightly +git push -f origin nightly diff --git a/script/bump-zed-minor-versions b/script/bump-zed-minor-versions index 8dcf7e334e..9e03d8a70c 100755 --- a/script/bump-zed-minor-versions +++ b/script/bump-zed-minor-versions @@ -43,8 +43,8 @@ if [[ $patch != 0 ]]; then echo "patch version on main should be zero" exit 1 fi -if [[ $(cat crates/zed/RELEASE_CHANNEL) != dev ]]; then - echo "release channel on main should be dev" +if [[ $(cat crates/zed/RELEASE_CHANNEL) != dev && $(cat crates/zed/RELEASE_CHANNEL) != nightly ]]; then + echo "release channel on main should be dev or nightly" exit 1 fi if git show-ref --quiet refs/tags/${preview_tag_name}; then @@ -59,6 +59,7 @@ if ! git show-ref --quiet refs/heads/${prev_minor_branch_name}; then echo "previous branch ${minor_branch_name} doesn't exist" exit 1 fi +# TODO kb anything else for RELEASE_CHANNEL == nightly needs to be done below? if [[ $(git show ${prev_minor_branch_name}:crates/zed/RELEASE_CHANNEL) != preview ]]; then echo "release channel on branch ${prev_minor_branch_name} should be preview" exit 1 diff --git a/script/bump-zed-patch-version b/script/bump-zed-patch-version index de0c0f7d66..e00e747aa3 100755 --- a/script/bump-zed-patch-version +++ b/script/bump-zed-patch-version @@ -9,8 +9,11 @@ case $channel in preview) tag_suffix="-pre" ;; + nightly) + tag_suffix="-nightly" + ;; *) - echo "this must be run on a stable or preview release branch" >&2 + echo "this must be run on either of stable|preview|nightly release branches" >&2 exit 1 ;; esac diff --git a/script/bundle b/script/bundle index 8c0b3fef87..19505a05d8 100755 --- a/script/bundle +++ b/script/bundle @@ -9,6 +9,7 @@ local_arch=false local_only=false overwrite_local_app=false bundle_name="" +zed_crate="zed" # This must match the team in the provsiioning profile. APPLE_NOTORIZATION_TEAM="MQ55VZLNZQ" @@ -25,13 +26,11 @@ Options: -o Open the resulting DMG or the app itself in local mode. -f Overwrite the local app bundle if it exists. -h Display this help and exit. + -2 Build zed 2 instead of zed 1. " } -# If -o option is specified, the folder of the resulting dmg will be opened in finder -# If -d is specified, Zed will be compiled in debug mode and the application's path printed -# If -od or -do is specified Zed will be bundled in debug and the application will be run. -while getopts 'dlfoh' flag +while getopts 'dlfoh2' flag do case "${flag}" in o) open_result=true;; @@ -51,6 +50,7 @@ do target_dir="debug" ;; f) overwrite_local_app=true;; + 2) zed_crate="zed2";; h) help_info exit 0 @@ -83,16 +83,19 @@ local_target_triple=${host_line#*: } if [ "$local_arch" = true ]; then echo "Building for local target only." - cargo build ${build_flag} --package zed + cargo build ${build_flag} --package ${zed_crate} cargo build ${build_flag} --package cli else echo "Compiling zed binaries" - cargo build ${build_flag} --package zed --package cli --target aarch64-apple-darwin --target x86_64-apple-darwin + cargo build ${build_flag} --package ${zed_crate} --package cli --target aarch64-apple-darwin --target x86_64-apple-darwin fi echo "Creating application bundle" pushd crates/zed channel=$( "${app_path}/Contents/Resources/zed.entitlements" + cat crates/${zed_crate}/resources/zed.entitlements | sed '/com.apple.developer.associated-domains/,+1d' > "${app_path}/Contents/Resources/zed.entitlements" codesign --force --deep --entitlements "${app_path}/Contents/Resources/zed.entitlements" --sign ${MACOS_SIGNING_KEY:- -} "${app_path}" -v fi diff --git a/script/deploy b/script/deploy index d32d387339..b6da3f8f84 100755 --- a/script/deploy +++ b/script/deploy @@ -4,12 +4,17 @@ set -eu source script/lib/deploy-helpers.sh if [[ $# < 2 ]]; then - echo "Usage: $0 " + echo "Usage: $0 (nightly is not yet supported)" exit 1 fi environment=$1 version=$2 +if [[ ${environment} == "nightly" ]]; then + echo "nightly is not yet supported" + exit 1 +fi + export_vars_for_environment ${environment} image_id=$(image_id_for_version ${version}) diff --git a/script/deploy-migration b/script/deploy-migration index a6b1574c04..340e6cef1f 100755 --- a/script/deploy-migration +++ b/script/deploy-migration @@ -4,12 +4,17 @@ set -eu source script/lib/deploy-helpers.sh if [[ $# < 2 ]]; then - echo "Usage: $0 " + echo "Usage: $0 (nightly is not yet supported)" exit 1 fi environment=$1 version=$2 +if [[ ${environment} == "nightly" ]]; then + echo "nightly is not yet supported" + exit 1 +fi + export_vars_for_environment ${environment} image_id=$(image_id_for_version ${version}) @@ -23,4 +28,4 @@ envsubst < crates/collab/k8s/migrate.template.yml | kubectl apply -f - pod=$(kubectl --namespace=${environment} get pods --selector=job-name=${ZED_MIGRATE_JOB_NAME} --output=jsonpath='{.items[0].metadata.name}') echo "Job pod:" $pod -kubectl --namespace=${environment} logs -f ${pod} \ No newline at end of file +kubectl --namespace=${environment} logs -f ${pod} diff --git a/script/upload-nightly b/script/upload-nightly new file mode 100755 index 0000000000..073976a335 --- /dev/null +++ b/script/upload-nightly @@ -0,0 +1,37 @@ +#!/bin/bash + +# Based on the template in: https://docs.digitalocean.com/reference/api/spaces-api/ +set -ux + +# Step 1: Define the parameters for the Space you want to upload to. +SPACE="zed-nightly-host" # Find your endpoint in the control panel, under Settings. +REGION="nyc3" # Must be "us-east-1" when creating new Spaces. Otherwise, use the region in your endpoint (e.g. nyc3). + +# Step 2: Define a function that uploads your object via cURL. +function uploadToSpaces +{ + file_to_upload="$1" + file_name="$2" + space_path="nightly" + date=$(date +"%a, %d %b %Y %T %z") + acl="x-amz-acl:private" + content_type="application/octet-stream" + storage_type="x-amz-storage-class:STANDARD" + string="PUT\n\n${content_type}\n${date}\n${acl}\n${storage_type}\n/${SPACE}/${space_path}/${file_name}" + signature=$(echo -en "${string}" | openssl sha1 -hmac "${DIGITALOCEAN_SPACES_SECRET_KEY}" -binary | base64) + + curl -vv -s -X PUT -T "$file_to_upload" \ + -H "Host: ${SPACE}.${REGION}.digitaloceanspaces.com" \ + -H "Date: $date" \ + -H "Content-Type: $content_type" \ + -H "$storage_type" \ + -H "$acl" \ + -H "Authorization: AWS ${DIGITALOCEAN_SPACES_ACCESS_KEY}:$signature" \ + "https://${SPACE}.${REGION}.digitaloceanspaces.com/${space_path}/${file_name}" +} + +sha=$(git rev-parse HEAD) +echo ${sha} > target/latest-sha + +uploadToSpaces "target/release/Zed.dmg" "Zed.dmg" +uploadToSpaces "target/latest-sha" "latest-sha" diff --git a/script/what-is-deployed b/script/what-is-deployed index f97e216f4a..b6a68dd3b3 100755 --- a/script/what-is-deployed +++ b/script/what-is-deployed @@ -4,11 +4,16 @@ set -eu source script/lib/deploy-helpers.sh if [[ $# < 1 ]]; then - echo "Usage: $0 " + echo "Usage: $0 (nightly is not yet supported)" exit 1 fi environment=$1 +if [[ ${environment} == "nightly" ]]; then + echo "nightly is not yet supported" + exit 1 +fi + export_vars_for_environment ${environment} target_zed_kube_cluster