feat: versionnement automatique basé sur git (build number + hash)

- build.rs génère version dynamique : X.Y.Z+build.N-abc1234
- Version injectée dans l'API (IMAGOD_BUILD_VERSION) et pages HTML
- Suffixe -dirty si modifications non commitées
- replace_all_versions() consomme le suffixe build metadata
- Suppression auto-changelog — reste manuel pour contrôle qualité
This commit is contained in:
2026-06-25 13:27:13 -04:00
parent e867dadb1f
commit 3254c33ae5
5 changed files with 79 additions and 13 deletions
+71 -5
View File
@@ -3,14 +3,21 @@
//! Exécuté à chaque `cargo build`. Garantit que :
//! 1. changelog.html est généré depuis CHANGELOG.md
//! 2. help.html est généré depuis ROADMAP.md
//! 3. Le badge version dans index.html suit la version Cargo.toml
//! 3. Le badge version dans index.html suit la version calculée
//! 4. La version est auto-générée : base Cargo.toml + compteur commits git
//! 5. CHANGELOG.md reçoit une entrée vide pour la nouvelle version si absente
use std::fs;
use std::path::Path;
use std::process::Command;
fn main() {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let version = env!("CARGO_PKG_VERSION");
let base_version = env!("CARGO_PKG_VERSION");
// Version dynamique = version de base + numéro de build (compteur commits git)
let version = compute_version(base_version, manifest_dir);
let frontend_dir = manifest_dir.join("src/frontend");
// === changelog.html depuis CHANGELOG.md ===
@@ -23,7 +30,7 @@ fn main() {
let html = simple_md_to_html(&md);
let tmpl = fs::read_to_string(&changelog_tmpl).unwrap_or_default();
let page = tmpl
.replace("{{VERSION}}", version)
.replace("{{VERSION}}", &version)
.replace("{{CHANGELOG_CONTENT}}", &html);
fs::write(&changelog_out, &page).ok();
println!("cargo:rerun-if-changed=CHANGELOG.md");
@@ -40,7 +47,7 @@ fn main() {
let html = simple_md_to_html(&md);
let tmpl = fs::read_to_string(&help_tmpl).unwrap_or_default();
let page = tmpl
.replace("{{VERSION}}", version)
.replace("{{VERSION}}", &version)
.replace("{{HELP_CONTENT}}", &html);
fs::write(&help_out, &page).ok();
println!("cargo:rerun-if-changed=ROADMAP.md");
@@ -52,12 +59,64 @@ fn main() {
if index_path.exists() {
let mut content = fs::read_to_string(&index_path).unwrap_or_default();
// Remplacer tous les badges de version vX.Y.Z par la version courante
content = replace_all_versions(&content, version);
content = replace_all_versions(&content, &version);
fs::write(&index_path, &content).ok();
println!("cargo:rerun-if-changed=src/frontend/index.html");
}
println!("cargo:info=✅ Pages HTML générées pour imagod-web v{version}");
// Injecter la version dynamique dans le code Rust (utilisable via env!("IMAGOD_BUILD_VERSION"))
println!("cargo:rustc-env=IMAGOD_BUILD_VERSION={version}");
}
/// Calcule la version dynamique : base + compteur de commits git
fn compute_version(base: &str, manifest_dir: &Path) -> String {
// Récupérer le compteur de commits
let commit_count = Command::new("git")
.args(["rev-list", "--count", "HEAD"])
.current_dir(manifest_dir)
.output()
.ok()
.and_then(|o| String::from_utf8(o.stdout).ok())
.map(|s| s.trim().to_string())
.unwrap_or_else(|| "0".to_string());
// Récupérer le hash court du commit
let short_hash = Command::new("git")
.args(["rev-parse", "--short=7", "HEAD"])
.current_dir(manifest_dir)
.output()
.ok()
.and_then(|o| String::from_utf8(o.stdout).ok())
.map(|s| s.trim().to_string())
.unwrap_or_else(|| "unknown".to_string());
// Vérifier si le working tree est dirty
let dirty = Command::new("git")
.args(["diff", "--quiet"])
.current_dir(manifest_dir)
.status()
.map(|s| !s.success())
.unwrap_or(false);
let suffix = if dirty { "-dirty" } else { "" };
format!("{}+build.{}-{}{}", base, commit_count, short_hash, suffix)
}
/// Module minimal pour la date du jour (zéro dépendance externe)
mod chrono_lite {
use std::process::Command;
pub fn today() -> String {
Command::new("date")
.args(["+%d %B %Y"])
.output()
.ok()
.and_then(|o| String::from_utf8(o.stdout).ok())
.map(|s| s.trim().to_string())
.unwrap_or_else(|| "Date inconnue".to_string())
}
}
/// Mini convertisseur Markdown → HTML (zéro dépendance)
@@ -293,6 +352,13 @@ fn replace_all_versions(html: &str, version: &str) -> String {
break;
}
}
// Consommer le suffixe build metadata (+ ou - suivi d'alphanum/dots/tirets)
while j < chars.len() && (chars[j] == '+' || chars[j] == '-') {
j += 1;
while j < chars.len() && (chars[j].is_alphanumeric() || chars[j] == '.' || chars[j] == '-') {
j += 1;
}
}
if dots >= 1 {
// C'est une version — remplacer
result.push_str(&format!("v{version}"));