From 46aeb4694a64e9470c858ad3a7ffa76838edd8cc Mon Sep 17 00:00:00 2001 From: bybrooklyn Date: Sat, 28 Mar 2026 21:09:10 -0400 Subject: [PATCH] Stamp nightly builds with commit-based runtime version --- .github/workflows/build.yml | 57 ++++++++++++++++++----------------- .github/workflows/ci.yml | 21 +++++++------ .github/workflows/docker.yml | 15 +++++---- .github/workflows/docs.yml | 15 +++++---- .github/workflows/nightly.yml | 11 ++++--- .github/workflows/release.yml | 5 ++- .idea/.name | 1 + build.rs | 8 +++++ src/lib.rs | 1 + src/main.rs | 18 +++++++++-- src/media/pipeline.rs | 2 +- src/server/system.rs | 6 ++-- src/telemetry.rs | 2 +- src/version.rs | 13 ++++++++ 14 files changed, 114 insertions(+), 61 deletions(-) create mode 100644 .idea/.name create mode 100644 src/version.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f043cd4..f1a7b7a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,6 +49,7 @@ on: env: IMAGE_NAME: ghcr.io/bybrooklyn/alchemist + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" jobs: build-docs: @@ -56,14 +57,14 @@ jobs: timeout-minutes: 20 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 - name: Set up Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 cache: npm cache-dependency-path: package-lock.json @@ -89,7 +90,7 @@ jobs: zip -r "../${ARCHIVE}" . - name: Upload docs artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: alchemist-website path: alchemist-website-${{ steps.ver.outputs.version }}.zip @@ -102,7 +103,7 @@ jobs: working-directory: web steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 @@ -112,7 +113,7 @@ jobs: bun-version: latest - name: Restore Bun dependency cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | web/node_modules @@ -134,7 +135,7 @@ jobs: run: bun run build - name: Upload frontend artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: web-dist-${{ github.run_id }} path: web/dist @@ -158,12 +159,12 @@ jobs: SCCACHE_CACHE_SIZE: 2G steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 - name: Download frontend artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: web-dist-${{ github.run_id }} path: web/dist @@ -212,7 +213,7 @@ jobs: sha256sum "$ARCHIVE" > "$ARCHIVE.sha256" - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ matrix.artifact_name }} path: | @@ -229,12 +230,12 @@ jobs: SCCACHE_CACHE_SIZE: 2G steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 - name: Download frontend artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: web-dist-${{ github.run_id }} path: web/dist @@ -274,7 +275,7 @@ jobs: > "alchemist-windows-x86_64.exe.sha256" - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: alchemist-windows-x86_64 path: | @@ -299,12 +300,12 @@ jobs: SCCACHE_CACHE_SIZE: 2G steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 - name: Download frontend artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: web-dist-${{ github.run_id }} path: web/dist @@ -344,7 +345,7 @@ jobs: shasum -a 256 "$ARCHIVE" > "$ARCHIVE.sha256" - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ matrix.artifact_name }} path: | @@ -370,12 +371,12 @@ jobs: cache_ref: ghcr.io/bybrooklyn/alchemist:buildcache-arm64 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 - name: Download Linux artifact - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: ${{ matrix.artifact_name }} path: artifacts/${{ matrix.arch }} @@ -392,13 +393,13 @@ jobs: chmod +x "${CONTEXT_DIR}/alchemist" - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -406,7 +407,7 @@ jobs: - name: Build and push by digest id: build - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: runtime-context/${{ matrix.arch }} file: runtime-context/${{ matrix.arch }}/Dockerfile @@ -430,7 +431,7 @@ jobs: touch "digests/${digest#sha256:}" - name: Upload digest artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: docker-digests-${{ matrix.arch }} path: digests/* @@ -443,17 +444,17 @@ jobs: if: inputs.push_docker steps: - name: Download digests - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: pattern: docker-digests-* merge-multiple: true path: digests - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -485,12 +486,12 @@ jobs: if: inputs.publish_release steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: pattern: alchemist-* merge-multiple: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cbbb179..5b1be83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,9 @@ concurrency: permissions: contents: read +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + jobs: rust-check: runs-on: ubuntu-latest @@ -32,7 +35,7 @@ jobs: SCCACHE_CACHE_SIZE: 2G steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 @@ -67,7 +70,7 @@ jobs: SCCACHE_CACHE_SIZE: 2G steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 @@ -94,7 +97,7 @@ jobs: - name: Upload artifacts on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: rust-test-artifacts path: target/debug/ @@ -108,7 +111,7 @@ jobs: working-directory: web steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 @@ -118,7 +121,7 @@ jobs: bun-version: latest - name: Restore Bun dependency cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | web/node_modules @@ -152,7 +155,7 @@ jobs: working-directory: web-e2e steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 @@ -176,7 +179,7 @@ jobs: bun-version: latest - name: Restore Bun dependency cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | web/node_modules @@ -188,7 +191,7 @@ jobs: bun-web-${{ runner.os }}- - name: Restore Playwright browser cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ hashFiles('web-e2e/package.json', 'web-e2e/bun.lock') }} @@ -212,7 +215,7 @@ jobs: - name: Upload artifacts on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: e2e-reliability-artifacts path: web-e2e/test-results/ diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index cd5df28..947d043 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -23,13 +23,16 @@ permissions: contents: read packages: write +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + jobs: docker: runs-on: ubuntu-latest timeout-minutes: 90 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 @@ -41,14 +44,14 @@ jobs: - name: Set up QEMU if: github.event_name == 'workflow_dispatch' - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Log in to GHCR if: github.event_name != 'pull_request' - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -56,7 +59,7 @@ jobs: - name: Build (PR preview — no push) if: github.event_name == 'pull_request' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: . platforms: linux/amd64 @@ -70,7 +73,7 @@ jobs: - name: Build and push (manual dispatch) if: github.event_name == 'workflow_dispatch' - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: . platforms: linux/amd64,linux/arm64 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d9d88db..fbab7c0 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -38,20 +38,23 @@ permissions: pages: write id-token: write +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + jobs: build-docs: runs-on: ubuntu-latest timeout-minutes: 20 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 - name: Set up Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 cache: npm cache-dependency-path: package-lock.json @@ -65,7 +68,7 @@ jobs: run: npm run build - name: Upload built site artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: docs-site-${{ github.run_id }} path: build @@ -73,7 +76,7 @@ jobs: - name: Upload GitHub Pages artifact if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master' - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@v4 with: path: build @@ -87,4 +90,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v5 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 537b1b1..f3bf946 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -14,6 +14,9 @@ permissions: contents: write packages: write +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + jobs: ci-gate: runs-on: ubuntu-latest @@ -24,7 +27,7 @@ jobs: SCCACHE_CACHE_SIZE: 2G steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 @@ -59,7 +62,7 @@ jobs: release_name: ${{ steps.meta.outputs.release_name }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 @@ -71,7 +74,7 @@ jobs: SHORT_SHA=$(git rev-parse --short=7 "${GITHUB_SHA}") { echo "short_sha=${SHORT_SHA}" - echo "version_suffix=-nightly+${SHORT_SHA}" + echo "version_suffix=nightly+${SHORT_SHA}" echo "release_name=Nightly — ${SHORT_SHA} ($(date -u +%Y-%m-%d))" } >> "$GITHUB_OUTPUT" @@ -81,7 +84,7 @@ jobs: timeout-minutes: 5 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ed97dca..2494e17 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,6 +14,9 @@ permissions: contents: write packages: write +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + jobs: release-meta: runs-on: ubuntu-latest @@ -25,7 +28,7 @@ jobs: docker_tags: ${{ steps.docker.outputs.tags }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 1 diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..83fc3ea --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +telemetry.rs \ No newline at end of file diff --git a/build.rs b/build.rs index d2cafa2..41b4b25 100644 --- a/build.rs +++ b/build.rs @@ -4,6 +4,14 @@ use std::path::Path; fn main() { println!("cargo:rerun-if-changed=web/dist"); + println!("cargo:rerun-if-env-changed=ALCHEMIST_VERSION"); + + if let Some(version) = env::var_os("ALCHEMIST_VERSION") { + println!( + "cargo:rustc-env=ALCHEMIST_BUILD_VERSION={}", + version.to_string_lossy() + ); + } if env::var_os("CARGO_FEATURE_EMBED_WEB").is_none() { return; diff --git a/src/lib.rs b/src/lib.rs index 49683dc..8ca186e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ pub mod server; pub mod settings; pub mod system; pub mod telemetry; +pub mod version; pub mod wizard; pub use config::QualityProfile; diff --git a/src/main.rs b/src/main.rs index 643bd20..3b69c92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use alchemist::db::EventChannels; use alchemist::error::Result; use alchemist::system::hardware; +use alchemist::version; use alchemist::{Agent, Transcoder, config, db, runtime}; use clap::Parser; use std::path::{Path, PathBuf}; @@ -14,7 +15,7 @@ use tokio::sync::RwLock; use tokio::sync::broadcast; #[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] +#[command(author, version = version::current(), about, long_about = None)] struct Args { /// Run in CLI mode (process directories and exit) #[arg(long)] @@ -139,7 +140,7 @@ async fn run() -> Result<()> { ); info!(""); info!(""); - let version = env!("CARGO_PKG_VERSION"); + let version = alchemist::version::current(); let build_info = option_env!("BUILD_INFO") .or(option_env!("GIT_SHA")) .or(option_env!("VERGEN_GIT_SHA")) @@ -668,6 +669,19 @@ async fn run() -> Result<()> { Ok(()) } +#[cfg(test)] +mod version_cli_tests { + use super::*; + use clap::CommandFactory; + + #[test] + fn clap_command_uses_runtime_version_source() { + let command = Args::command(); + let version = command.get_version().unwrap_or_default(); + assert_eq!(version, version::current()); + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/media/pipeline.rs b/src/media/pipeline.rs index c03198b..6b15254 100644 --- a/src/media/pipeline.rs +++ b/src/media/pipeline.rs @@ -1228,7 +1228,7 @@ impl Pipeline { let hw_snapshot = self.hardware_state.snapshot().await; let hw = hw_snapshot.as_ref(); let event = TelemetryEvent { - app_version: env!("CARGO_PKG_VERSION").to_string(), + app_version: crate::version::current().to_string(), event_type: params.event_type.to_string(), status: params.status.map(str::to_string), failure_reason: params.failure_reason.map(str::to_string), diff --git a/src/server/system.rs b/src/server/system.rs index 04df10f..d5e1136 100644 --- a/src/server/system.rs +++ b/src/server/system.rs @@ -165,7 +165,7 @@ pub(crate) async fn get_system_info_handler( State(state): State>, ) -> impl IntoResponse { let config = state.config.read().await; - let version = env!("CARGO_PKG_VERSION").to_string(); + let version = crate::version::current().to_string(); let os_version = format!("{} {}", std::env::consts::OS, std::env::consts::ARCH); let is_docker = std::path::Path::new("/.dockerenv").exists(); @@ -210,7 +210,7 @@ pub(crate) async fn health_handler(State(state): State>) -> impl I axum::Json(serde_json::json!({ "status": "ok", - "version": env!("CARGO_PKG_VERSION"), + "version": crate::version::current(), "uptime": format!("{}h {}m {}s", hours, minutes, seconds), "uptime_seconds": uptime.as_secs() })) @@ -296,7 +296,7 @@ pub(crate) async fn telemetry_payload_handler(State(state): State> (sys.cpus().len(), sys.total_memory() / 1024 / 1024) }; - let version = env!("CARGO_PKG_VERSION").to_string(); + let version = crate::version::current().to_string(); let os_version = format!("{} {}", std::env::consts::OS, std::env::consts::ARCH); let is_docker = std::path::Path::new("/.dockerenv").exists(); let uptime_seconds = state.start_time.elapsed().as_secs(); diff --git a/src/telemetry.rs b/src/telemetry.rs index 03d3c32..fa0dca8 100644 --- a/src/telemetry.rs +++ b/src/telemetry.rs @@ -129,7 +129,7 @@ fn telemetry_client() -> &'static reqwest::Client { CLIENT.get_or_init(|| { reqwest::Client::builder() .timeout(Duration::from_secs(TELEMETRY_TIMEOUT_SECS)) - .user_agent(format!("alchemist/{}", env!("CARGO_PKG_VERSION"))) + .user_agent(format!("alchemist/{}", crate::version::current())) .build() .unwrap_or_else(|_| reqwest::Client::new()) }) diff --git a/src/version.rs b/src/version.rs new file mode 100644 index 0000000..6e8d09f --- /dev/null +++ b/src/version.rs @@ -0,0 +1,13 @@ +pub fn current() -> &'static str { + option_env!("ALCHEMIST_BUILD_VERSION").unwrap_or(env!("CARGO_PKG_VERSION")) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn current_version_is_non_empty() { + assert!(!current().trim().is_empty()); + } +}