mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-08 03:10:26 +00:00
fix(build): refresh embedded git sha on branch commits
Track the active loose HEAD ref from CLI and server build scripts so local builds refresh FABRO_GIT_SHA after normal branch commits without watching packed-refs.
This commit is contained in:
parent
bfb633ba6e
commit
685cc18156
8 changed files with 198 additions and 46 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
|
@ -1618,6 +1618,10 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fabro-build-support"
|
||||
version = "0.228.0-nightly.0"
|
||||
|
||||
[[package]]
|
||||
name = "fabro-checkpoint"
|
||||
version = "0.228.0-nightly.0"
|
||||
|
|
@ -1657,6 +1661,7 @@ dependencies = [
|
|||
"fabro-agent",
|
||||
"fabro-api",
|
||||
"fabro-auth",
|
||||
"fabro-build-support",
|
||||
"fabro-checkpoint",
|
||||
"fabro-client",
|
||||
"fabro-config",
|
||||
|
|
@ -2134,6 +2139,7 @@ dependencies = [
|
|||
"fabro-agent",
|
||||
"fabro-api",
|
||||
"fabro-auth",
|
||||
"fabro-build-support",
|
||||
"fabro-config",
|
||||
"fabro-github",
|
||||
"fabro-graphviz",
|
||||
|
|
|
|||
13
lib/crates/build-support/Cargo.toml
Normal file
13
lib/crates/build-support/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "fabro-build-support"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
publish = false
|
||||
license.workspace = true
|
||||
description = "Build script support utilities for Fabro crates"
|
||||
|
||||
[lib]
|
||||
path = "git_metadata.rs"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
67
lib/crates/build-support/git_metadata.rs
Normal file
67
lib/crates/build-support/git_metadata.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct BuildGitMetadata {
|
||||
pub rerun_paths: Vec<PathBuf>,
|
||||
pub short_sha: String,
|
||||
}
|
||||
|
||||
pub fn collect_from(package_dir: &Path) -> BuildGitMetadata {
|
||||
let mut rerun_paths = Vec::new();
|
||||
|
||||
if let Some(head_path) = git_output(package_dir, ["rev-parse", "--git-path", "HEAD"]) {
|
||||
rerun_paths.push(PathBuf::from(head_path));
|
||||
}
|
||||
|
||||
if let Some(head_ref) = git_output(package_dir, ["symbolic-ref", "-q", "HEAD"]) {
|
||||
if let Some(ref_path) = git_output(package_dir, ["rev-parse", "--git-path", &head_ref]) {
|
||||
rerun_paths.push(PathBuf::from(ref_path));
|
||||
}
|
||||
}
|
||||
|
||||
let short_sha = git_output(package_dir, ["rev-list", "-1", "HEAD"])
|
||||
.map(|sha| {
|
||||
if sha.len() >= 7 {
|
||||
sha[..7].to_string()
|
||||
} else {
|
||||
sha
|
||||
}
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
BuildGitMetadata {
|
||||
rerun_paths,
|
||||
short_sha,
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "Build scripts read Cargo-provided PROFILE outside application runtime configuration."
|
||||
)]
|
||||
pub fn cargo_profile() -> String {
|
||||
std::env::var("PROFILE").unwrap_or_default()
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "Build scripts run outside Tokio and need synchronous git probes for embedded build metadata."
|
||||
)]
|
||||
fn git_output<const N: usize>(package_dir: &Path, args: [&str; N]) -> Option<String> {
|
||||
Command::new("git")
|
||||
.current_dir(package_dir)
|
||||
.args(args)
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|output| {
|
||||
if output.status.success() {
|
||||
String::from_utf8(output.stdout)
|
||||
.ok()
|
||||
.map(|output| output.trim().to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|output| !output.is_empty())
|
||||
}
|
||||
|
|
@ -108,10 +108,12 @@ core-foundation = { version = "0.9", optional = true }
|
|||
openssl = { version = "0.10", features = ["vendored"] }
|
||||
|
||||
[build-dependencies]
|
||||
fabro-build-support = { path = "../build-support" }
|
||||
chrono = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "2"
|
||||
fabro-build-support = { path = "../build-support" }
|
||||
fabro-server = { path = "../fabro-server", features = ["test-support"] }
|
||||
insta = { workspace = true, features = ["filters"] }
|
||||
paste = "1"
|
||||
|
|
|
|||
|
|
@ -1,31 +1,18 @@
|
|||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "Build scripts run outside Tokio and need a synchronous git probe for the embedded build SHA."
|
||||
)]
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=../../../.git/HEAD");
|
||||
use std::path::Path;
|
||||
|
||||
let sha = std::process::Command::new("git")
|
||||
.args(["rev-list", "-1", "HEAD"])
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|o| {
|
||||
if o.status.success() {
|
||||
String::from_utf8(o.stdout)
|
||||
.ok()
|
||||
.map(|s| s.trim().to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let short_sha = if sha.len() >= 7 { &sha[..7] } else { &sha };
|
||||
println!("cargo:rustc-env=FABRO_GIT_SHA={short_sha}");
|
||||
fn main() {
|
||||
let metadata = fabro_build_support::collect_from(Path::new("."));
|
||||
|
||||
for path in metadata.rerun_paths {
|
||||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
}
|
||||
|
||||
println!("cargo:rustc-env=FABRO_GIT_SHA={}", metadata.short_sha);
|
||||
|
||||
let build_date = chrono::Utc::now().format("%Y-%m-%d").to_string();
|
||||
println!("cargo:rustc-env=FABRO_BUILD_DATE={build_date}");
|
||||
|
||||
let profile = std::env::var("PROFILE").unwrap_or_default();
|
||||
let profile = fabro_build_support::cargo_profile();
|
||||
let profile_suffix = if profile == "release" {
|
||||
String::new()
|
||||
} else {
|
||||
|
|
|
|||
89
lib/crates/fabro-cli/tests/build_git_metadata.rs
Normal file
89
lib/crates/fabro-cli/tests/build_git_metadata.rs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
#[test]
|
||||
fn symbolic_branch_tracks_head_and_active_ref() {
|
||||
let repo = git_repo();
|
||||
|
||||
let metadata = fabro_build_support::collect_from(repo.path());
|
||||
|
||||
assert_eq!(metadata.rerun_paths, vec![
|
||||
PathBuf::from(".git/HEAD"),
|
||||
PathBuf::from(".git/refs/heads/main"),
|
||||
]);
|
||||
assert_eq!(metadata.short_sha.len(), 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn detached_head_tracks_only_head() {
|
||||
let repo = git_repo();
|
||||
git(repo.path(), ["checkout", "--detach", "HEAD"]);
|
||||
|
||||
let metadata = fabro_build_support::collect_from(repo.path());
|
||||
|
||||
assert_eq!(metadata.rerun_paths, vec![PathBuf::from(".git/HEAD")]);
|
||||
assert_eq!(metadata.short_sha.len(), 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_git_directory_has_no_metadata() {
|
||||
let dir = tempfile::tempdir().expect("temp dir should create");
|
||||
|
||||
let metadata = fabro_build_support::collect_from(dir.path());
|
||||
|
||||
assert!(metadata.rerun_paths.is_empty());
|
||||
assert!(metadata.short_sha.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn packed_refs_are_not_tracked() {
|
||||
let repo = git_repo();
|
||||
git(repo.path(), ["pack-refs", "--all", "--prune"]);
|
||||
|
||||
let metadata = fabro_build_support::collect_from(repo.path());
|
||||
|
||||
assert_eq!(metadata.rerun_paths, vec![
|
||||
PathBuf::from(".git/HEAD"),
|
||||
PathBuf::from(".git/refs/heads/main"),
|
||||
]);
|
||||
assert!(
|
||||
!metadata
|
||||
.rerun_paths
|
||||
.iter()
|
||||
.any(|path| path.ends_with("packed-refs"))
|
||||
);
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "This test creates a small synchronous Git fixture before exercising build metadata collection."
|
||||
)]
|
||||
fn git_repo() -> tempfile::TempDir {
|
||||
let repo = tempfile::tempdir().expect("temp repo should create");
|
||||
git(repo.path(), ["init"]);
|
||||
git(repo.path(), ["symbolic-ref", "HEAD", "refs/heads/main"]);
|
||||
git(repo.path(), ["config", "user.email", "fabro@example.test"]);
|
||||
git(repo.path(), ["config", "user.name", "Fabro Test"]);
|
||||
std::fs::write(repo.path().join("README.md"), "test\n").expect("readme should write");
|
||||
git(repo.path(), ["add", "README.md"]);
|
||||
git(repo.path(), ["commit", "-m", "initial"]);
|
||||
repo
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "This test fixture uses synchronous Git commands to set up repository states."
|
||||
)]
|
||||
fn git<const N: usize>(dir: &std::path::Path, args: [&str; N]) {
|
||||
let output = Command::new("git")
|
||||
.current_dir(dir)
|
||||
.args(args)
|
||||
.output()
|
||||
.expect("git should run");
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"git command failed\nstdout:\n{}\nstderr:\n{}",
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
}
|
||||
|
|
@ -94,6 +94,7 @@ zeroize.workspace = true
|
|||
strum.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
fabro-build-support = { path = "../build-support" }
|
||||
chrono = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
|||
|
|
@ -1,30 +1,17 @@
|
|||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "Build scripts run outside Tokio and need a synchronous git probe for the embedded build SHA."
|
||||
)]
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=../../../.git/HEAD");
|
||||
use std::path::Path;
|
||||
|
||||
let sha = std::process::Command::new("git")
|
||||
.args(["rev-list", "-1", "HEAD"])
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|o| {
|
||||
if o.status.success() {
|
||||
String::from_utf8(o.stdout)
|
||||
.ok()
|
||||
.map(|s| s.trim().to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let short_sha = if sha.len() >= 7 { &sha[..7] } else { &sha };
|
||||
println!("cargo:rustc-env=FABRO_GIT_SHA={short_sha}");
|
||||
fn main() {
|
||||
let metadata = fabro_build_support::collect_from(Path::new("."));
|
||||
|
||||
for path in metadata.rerun_paths {
|
||||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
}
|
||||
|
||||
println!("cargo:rustc-env=FABRO_GIT_SHA={}", metadata.short_sha);
|
||||
|
||||
let build_date = chrono::Utc::now().format("%Y-%m-%d").to_string();
|
||||
println!("cargo:rustc-env=FABRO_BUILD_DATE={build_date}");
|
||||
|
||||
let profile = std::env::var("PROFILE").unwrap_or_default();
|
||||
let profile = fabro_build_support::cargo_profile();
|
||||
println!("cargo:rustc-env=FABRO_BUILD_PROFILE={profile}");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue