From f8d5fd84d7f1c848661a9b184b45dd93b5d80d9e Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Thu, 7 May 2026 05:01:06 -0500 Subject: [PATCH] ci: add nightly build artifacts (#1013) --- .github/workflows/nightly.yml | 111 ++++++++++++++++++++++++++++++++++ crates/cli/build.rs | 60 ++++++++++++++++++ crates/cli/src/lib.rs | 2 +- crates/tui/build.rs | 60 ++++++++++++++++++ crates/tui/src/main.rs | 4 +- 5 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/nightly.yml create mode 100644 crates/cli/build.rs create mode 100644 crates/tui/build.rs diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 00000000..6fe68721 --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,111 @@ +name: Nightly + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: nightly-${{ github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: -Dwarnings + DEEPSEEK_BUILD_SHA: ${{ github.sha }} + +jobs: + build: + name: Build ${{ matrix.artifact_name }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + binary: deepseek + artifact_name: deepseek-linux-x64 + - os: ubuntu-24.04-arm + target: aarch64-unknown-linux-gnu + binary: deepseek + artifact_name: deepseek-linux-arm64 + - os: macos-latest + target: x86_64-apple-darwin + binary: deepseek + artifact_name: deepseek-macos-x64 + - os: macos-latest + target: aarch64-apple-darwin + binary: deepseek + artifact_name: deepseek-macos-arm64 + - os: windows-latest + target: x86_64-pc-windows-msvc + binary: deepseek.exe + artifact_name: deepseek-windows-x64.exe + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + binary: deepseek-tui + artifact_name: deepseek-tui-linux-x64 + - os: ubuntu-24.04-arm + target: aarch64-unknown-linux-gnu + binary: deepseek-tui + artifact_name: deepseek-tui-linux-arm64 + - os: macos-latest + target: x86_64-apple-darwin + binary: deepseek-tui + artifact_name: deepseek-tui-macos-x64 + - os: macos-latest + target: aarch64-apple-darwin + binary: deepseek-tui + artifact_name: deepseek-tui-macos-arm64 + - os: windows-latest + target: x86_64-pc-windows-msvc + binary: deepseek-tui.exe + artifact_name: deepseek-tui-windows-x64.exe + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + - uses: Swatinem/rust-cache@v2 + - name: Install Linux system dependencies + if: runner.os == 'Linux' + run: | + for i in 1 2 3 4 5; do + sudo apt-get update && break + echo "apt-get update failed (attempt $i); retrying in 15s" + sleep 15 + done + sudo apt-get install -y libdbus-1-dev pkg-config + - name: Build + shell: bash + run: cargo build --release --locked --target ${{ matrix.target }} + - name: Stage artifact + id: stage + shell: bash + run: | + short_sha="${GITHUB_SHA::12}" + bin_path="target/${{ matrix.target }}/release/${{ matrix.binary }}" + if [ ! -f "${bin_path}" ]; then + echo "Binary not at ${bin_path}; searching target/ for ${{ matrix.binary }}:" + find target -name "${{ matrix.binary }}" -type f + exit 1 + fi + + mkdir -p nightly + cp "${bin_path}" "nightly/${{ matrix.artifact_name }}" + cat > nightly/nightly-build-info.txt <> "${GITHUB_OUTPUT}" + - uses: actions/upload-artifact@v4 + with: + name: ${{ steps.stage.outputs.name }} + path: nightly/* + retention-days: 14 diff --git a/crates/cli/build.rs b/crates/cli/build.rs new file mode 100644 index 00000000..b5e97c3b --- /dev/null +++ b/crates/cli/build.rs @@ -0,0 +1,60 @@ +use std::{path::PathBuf, process::Command}; + +fn main() { + println!("cargo:rerun-if-env-changed=DEEPSEEK_BUILD_SHA"); + println!("cargo:rerun-if-env-changed=GITHUB_SHA"); + + let package_version = env!("CARGO_PKG_VERSION"); + let build_version = build_sha() + .map(|sha| format!("{package_version} ({sha})")) + .unwrap_or_else(|| package_version.to_string()); + + println!("cargo:rustc-env=DEEPSEEK_BUILD_VERSION={build_version}"); +} + +fn build_sha() -> Option { + env_sha("DEEPSEEK_BUILD_SHA") + .or_else(|| env_sha("GITHUB_SHA")) + .or_else(git_sha) +} + +fn env_sha(name: &str) -> Option { + std::env::var(name).ok().and_then(short_sha) +} + +fn git_sha() -> Option { + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let top_level_output = Command::new("git") + .args(["-C"]) + .arg(&manifest_dir) + .args(["rev-parse", "--show-toplevel"]) + .output() + .ok()?; + if !top_level_output.status.success() { + return None; + } + let top_level = PathBuf::from(String::from_utf8_lossy(&top_level_output.stdout).trim()); + if !top_level.join("Cargo.toml").is_file() || !top_level.join("crates/tui").is_dir() { + return None; + } + + let output = Command::new("git") + .args(["-C"]) + .arg(top_level) + .args(["rev-parse", "--short=12", "HEAD"]) + .output() + .ok()?; + if !output.status.success() { + return None; + } + + short_sha(String::from_utf8_lossy(&output.stdout).to_string()) +} + +fn short_sha(value: String) -> Option { + let trimmed = value.trim(); + if trimmed.is_empty() { + return None; + } + Some(trimmed.chars().take(12).collect()) +} diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index c5ec1209..0bf6a2d1 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -53,7 +53,7 @@ impl From for ProviderKind { #[derive(Debug, Parser)] #[command( name = "deepseek", - version, + version = env!("DEEPSEEK_BUILD_VERSION"), bin_name = "deepseek", override_usage = "deepseek [OPTIONS] [PROMPT]\n deepseek [OPTIONS] [ARGS]" )] diff --git a/crates/tui/build.rs b/crates/tui/build.rs new file mode 100644 index 00000000..b5e97c3b --- /dev/null +++ b/crates/tui/build.rs @@ -0,0 +1,60 @@ +use std::{path::PathBuf, process::Command}; + +fn main() { + println!("cargo:rerun-if-env-changed=DEEPSEEK_BUILD_SHA"); + println!("cargo:rerun-if-env-changed=GITHUB_SHA"); + + let package_version = env!("CARGO_PKG_VERSION"); + let build_version = build_sha() + .map(|sha| format!("{package_version} ({sha})")) + .unwrap_or_else(|| package_version.to_string()); + + println!("cargo:rustc-env=DEEPSEEK_BUILD_VERSION={build_version}"); +} + +fn build_sha() -> Option { + env_sha("DEEPSEEK_BUILD_SHA") + .or_else(|| env_sha("GITHUB_SHA")) + .or_else(git_sha) +} + +fn env_sha(name: &str) -> Option { + std::env::var(name).ok().and_then(short_sha) +} + +fn git_sha() -> Option { + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let top_level_output = Command::new("git") + .args(["-C"]) + .arg(&manifest_dir) + .args(["rev-parse", "--show-toplevel"]) + .output() + .ok()?; + if !top_level_output.status.success() { + return None; + } + let top_level = PathBuf::from(String::from_utf8_lossy(&top_level_output.stdout).trim()); + if !top_level.join("Cargo.toml").is_file() || !top_level.join("crates/tui").is_dir() { + return None; + } + + let output = Command::new("git") + .args(["-C"]) + .arg(top_level) + .args(["rev-parse", "--short=12", "HEAD"]) + .output() + .ok()?; + if !output.status.success() { + return None; + } + + short_sha(String::from_utf8_lossy(&output.stdout).to_string()) +} + +fn short_sha(value: String) -> Option { + let trimmed = value.trim(); + if trimmed.is_empty() { + return None; + } + Some(trimmed.chars().take(12).collect()) +} diff --git a/crates/tui/src/main.rs b/crates/tui/src/main.rs index d55731eb..b7fff694 100644 --- a/crates/tui/src/main.rs +++ b/crates/tui/src/main.rs @@ -96,7 +96,7 @@ fn configure_windows_console_utf8() {} #[command( name = "deepseek", author, - version, + version = env!("DEEPSEEK_BUILD_VERSION"), about = "DeepSeek TUI/CLI for DeepSeek models", long_about = "Terminal-native TUI and CLI for DeepSeek models.\n\nRun 'deepseek' to start.\n\nNot affiliated with DeepSeek Inc." )] @@ -1529,7 +1529,7 @@ async fn run_doctor(config: &Config, workspace: &Path, config_path_override: Opt // Version info println!("{}", "Version Information:".bold()); - println!(" deepseek-tui: {}", env!("CARGO_PKG_VERSION")); + println!(" deepseek-tui: {}", env!("DEEPSEEK_BUILD_VERSION")); println!(" rust: {}", rustc_version()); println!();