mirror of
https://codeberg.org/simonrepp/hyper8.git
synced 2026-08-14 13:45:27 +02:00
Switch to unambiguous version detection, refine release notes link derivation
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2025 Simon Repp
|
||||
// SPDX-FileCopyrightText: 2025-2026 Simon Repp
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use indoc::formatdoc;
|
||||
@@ -9,7 +9,7 @@ use tauri::State;
|
||||
use hyper8_core::Theme;
|
||||
use hyper8_core::{AVAILABLE_LANGUAGES, SPLASH_SVG};
|
||||
use hyper8_core::util::html_escape_outside_attribute;
|
||||
use hyper8_version::{CHANGES_URL, VERSION_ADAPTIVE_PATCH};
|
||||
use hyper8_version::{RELEASE_NOTES, VERSION_ADAPTIVE_PATCH};
|
||||
|
||||
use crate::{EditorMode, LauncherState};
|
||||
|
||||
@@ -181,7 +181,7 @@ pub fn render(
|
||||
<header data-tauri-drag-region>
|
||||
{SPLASH_SVG}
|
||||
<button class="close">{close_icon}</button>
|
||||
<a href="{CHANGES_URL}" target="_blank">
|
||||
<a href="{RELEASE_NOTES}" target="_blank">
|
||||
{VERSION_ADAPTIVE_PATCH}
|
||||
</a>
|
||||
</header>
|
||||
@@ -196,7 +196,7 @@ pub fn render(
|
||||
<a href="https://hyper8.org/#donate" target="_blank">
|
||||
{t_donate}
|
||||
</a>
|
||||
<a href="{CHANGES_URL}" target="_blank">
|
||||
<a href="{RELEASE_NOTES}" target="_blank">
|
||||
{t_whats_new}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
+168
-63
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2024-2025 Simon Repp
|
||||
// SPDX-FileCopyrightText: 2024-2026 Simon Repp
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use std::env;
|
||||
@@ -6,79 +6,184 @@ use std::process::Command;
|
||||
|
||||
const CHANGES_INDEX_URL: &str = "https://hyper8.org/changes/";
|
||||
|
||||
/// For non-semantic versions we link to the release notes index page
|
||||
fn export_generic_release_notes() {
|
||||
let url = CHANGES_INDEX_URL;
|
||||
export_release_notes_variable(url);
|
||||
}
|
||||
|
||||
/// For regular semantic versions our convention is to link to release
|
||||
/// notes in the "[major].[minor].[patch]/" directory under the release
|
||||
/// notes index page
|
||||
fn export_semantic_release_notes(
|
||||
major: &str,
|
||||
minor: &str,
|
||||
patch: &str
|
||||
) {
|
||||
let url = format!("{CHANGES_INDEX_URL}{major}.{minor}.{patch}/");
|
||||
export_release_notes_variable(&url);
|
||||
}
|
||||
|
||||
fn export_semantic_version(
|
||||
major: &str,
|
||||
minor: &str,
|
||||
patch: &str
|
||||
) {
|
||||
let revision = git_revision();
|
||||
|
||||
let version_adaptive_patch = if patch == "0" {
|
||||
format!("{major}.{minor}")
|
||||
} else {
|
||||
format!("{major}.{minor}.{patch}")
|
||||
};
|
||||
|
||||
let version_with_patch = format!("{major}.{minor}.{patch}");
|
||||
let version_with_patch_and_revision = format!("{major}.{minor}.{patch} ({revision})");
|
||||
let version_without_patch = format!("{major}.{minor}");
|
||||
|
||||
export_version_variables(
|
||||
&version_adaptive_patch,
|
||||
&version_with_patch,
|
||||
&version_with_patch_and_revision,
|
||||
&version_without_patch
|
||||
);
|
||||
}
|
||||
|
||||
fn export_special_version(version: &str) {
|
||||
let revision = git_revision();
|
||||
|
||||
let version_with_revision = if version == revision {
|
||||
version.to_string()
|
||||
} else {
|
||||
format!("{version} ({revision})")
|
||||
};
|
||||
|
||||
export_version_variables(
|
||||
version,
|
||||
version,
|
||||
&version_with_revision,
|
||||
version
|
||||
);
|
||||
}
|
||||
|
||||
fn export_release_notes_variable(url: &str) {
|
||||
println!("cargo:rustc-env=HYPER8_RELEASE_NOTES={url}");
|
||||
}
|
||||
|
||||
fn export_version_variables(
|
||||
version_adaptive_patch: &str,
|
||||
version_with_patch: &str,
|
||||
version_with_patch_and_revision: &str,
|
||||
version_without_patch: &str
|
||||
) {
|
||||
println!("cargo:rustc-env=HYPER8_VERSION_ADAPTIVE_PATCH={version_adaptive_patch}");
|
||||
println!("cargo:rustc-env=HYPER8_VERSION_WITH_PATCH={version_with_patch}");
|
||||
println!("cargo:rustc-env=HYPER8_VERSION_WITH_PATCH_AND_REVISION={version_with_patch_and_revision}");
|
||||
println!("cargo:rustc-env=HYPER8_VERSION_WITHOUT_PATCH={version_without_patch}");
|
||||
}
|
||||
|
||||
// TODO: According to the canonical https://semver.org/ specification,
|
||||
// optional additional labels containing build/pre-release metadata may only
|
||||
// be separated by a narrower subset of characters than we allow (and use).
|
||||
// We might want to adopt these rules eventually.
|
||||
|
||||
/// Extracts and returns the major, minor and patch number and optional
|
||||
/// pre-release/build label from the passed version string if it follows
|
||||
/// a semantic format recognized by us, such as:
|
||||
/// - 1.2.3
|
||||
/// - 1.2.3~beta1
|
||||
/// - 1.2.3-preview1
|
||||
fn extract_semantic_version(version: &str) -> Option<(&str, &str, &str, Option<&str>)> {
|
||||
let (major, remainder) = version.split_once('.')?;
|
||||
let _ = major.parse::<u16>().ok()?;
|
||||
|
||||
let (minor, remainder) = remainder.split_once('.')?;
|
||||
let _ = minor.parse::<u16>().ok()?;
|
||||
|
||||
match remainder.split_once(|c| c == '~' || c == '-') {
|
||||
Some((patch, label)) => {
|
||||
let _ = patch.parse::<u16>().ok()?;
|
||||
Some((major, minor, patch, Some(label)))
|
||||
}
|
||||
None => {
|
||||
let _ = remainder.parse::<u16>().ok()?;
|
||||
Some((major, minor, remainder, None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn git_describe() -> Option<String> {
|
||||
let mut git = Command::new("git");
|
||||
|
||||
git.args(["describe"]);
|
||||
|
||||
if let Ok(output) = git.output() && output.status.success() {
|
||||
Some(String::from_utf8(output.stdout).unwrap())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Call git to determine the 7-digit short hash of the current revision.
|
||||
/// If git is not available, we fall back to "unknown revision".
|
||||
/// The output is stored in HYPER8_REVISION.
|
||||
fn compute_revision() {
|
||||
fn git_revision() -> String {
|
||||
let mut git = Command::new("git");
|
||||
|
||||
git.args(["rev-parse", "--short", "HEAD"]);
|
||||
|
||||
let revision = match git.output() {
|
||||
Ok(output) if output.status.success() => String::from_utf8(output.stdout).unwrap(),
|
||||
_ => String::from("unknown revision")
|
||||
};
|
||||
|
||||
println!("cargo:rustc-env=HYPER8_REVISION={revision}");
|
||||
if let Ok(output) = git.output() && output.status.success() {
|
||||
String::from_utf8(output.stdout).unwrap()
|
||||
} else {
|
||||
String::from("unknown revision")
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
compute_revision();
|
||||
compute_version();
|
||||
}
|
||||
|
||||
/// Provides three variables to the consecutive build step:
|
||||
/// - HYPER8_VERSION_ADAPTIVE_PATCH (With patch only if it is a patch release, e.g. "1.2.1")
|
||||
/// Provides variables to the consecutive build step:
|
||||
/// - HYPER8_RELEASE_NOTES (e.g. https://hyper8.org/changes/1.2.3/)
|
||||
/// - HYPER8_VERSION_ADAPTIVE_PATCH (With patch only if it is a patch release, e.g. "1.2.3")
|
||||
/// - HYPER8_VERSION_WITH_PATCH (Always with patch, e.g. "1.2.0")
|
||||
/// - HYPER8_VERSION_WITH_PATCH_AND_REVISION (Always with patch and revision, e.g. "1.2.3 (0abcdef)")
|
||||
/// - HYPER8_VERSION_WITHOUT_PATCH (Always without patch, e.g. "1.2")
|
||||
///
|
||||
/// If HYPER8_VERSION is used to override the version, all three variables
|
||||
/// will contain the full version, e.g. "2.0.0~pre1".
|
||||
fn compute_version() {
|
||||
let changes_url;
|
||||
let version_adaptive_patch;
|
||||
let version_with_patch;
|
||||
let version_without_patch;
|
||||
|
||||
if let Ok(override_version) = env::var("HYPER8_VERSION") {
|
||||
// An override version can be somewhat arbitrary, or refer to a
|
||||
// version for which there are no release notes available online yet,
|
||||
// so here we always fall back to the more general release notes
|
||||
// index page to avoid linking to a potentially unavailable page.
|
||||
changes_url = CHANGES_INDEX_URL.to_string();
|
||||
|
||||
version_adaptive_patch = override_version.clone();
|
||||
version_with_patch = override_version.clone();
|
||||
version_without_patch = override_version;
|
||||
} else {
|
||||
// For regular tag-based releases our convention currently is that
|
||||
// there is always a dedicated release notes page available for the
|
||||
// given tag at the major.minor.patch/ directory under the release
|
||||
// notes index page.
|
||||
changes_url = format!("{CHANGES_INDEX_URL}{}/", env!("CARGO_PKG_VERSION"));
|
||||
|
||||
version_adaptive_patch = if env!("CARGO_PKG_VERSION_PATCH") == "0" {
|
||||
concat!(
|
||||
env!("CARGO_PKG_VERSION_MAJOR"),
|
||||
'.',
|
||||
env!("CARGO_PKG_VERSION_MINOR")
|
||||
).to_string()
|
||||
} else {
|
||||
env!("CARGO_PKG_VERSION").to_string()
|
||||
};
|
||||
|
||||
version_with_patch = env!("CARGO_PKG_VERSION").to_string();
|
||||
|
||||
version_without_patch = concat!(
|
||||
env!("CARGO_PKG_VERSION_MAJOR"),
|
||||
'.',
|
||||
env!("CARGO_PKG_VERSION_MINOR")
|
||||
).to_string();
|
||||
}
|
||||
|
||||
/// If no semantic version is available we use various fallbacks to provide
|
||||
/// some kind of version information (e.g. only the git revision).
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-env-changed=HYPER8_VERSION");
|
||||
println!("cargo:rustc-env=HYPER8_CHANGES_URL={changes_url}");
|
||||
println!("cargo:rustc-env=HYPER8_VERSION_ADAPTIVE_PATCH={version_adaptive_patch}");
|
||||
println!("cargo:rustc-env=HYPER8_VERSION_WITH_PATCH={version_with_patch}");
|
||||
println!("cargo:rustc-env=HYPER8_VERSION_WITHOUT_PATCH={version_without_patch}");
|
||||
|
||||
if let Ok(version) = env::var("HYPER8_VERSION") {
|
||||
// Version was explicitly defined by environment variable
|
||||
|
||||
if let Some((major, minor, patch, label)) = extract_semantic_version(&version) {
|
||||
export_semantic_release_notes(major, minor, patch);
|
||||
|
||||
if label.is_none() {
|
||||
export_semantic_version(major, minor, patch);
|
||||
} else {
|
||||
export_special_version(&version);
|
||||
}
|
||||
} else {
|
||||
export_generic_release_notes();
|
||||
export_special_version(&version);
|
||||
}
|
||||
} else if git_describe().is_some_and(|name| name == env!("CARGO_PKG_VERSION")) {
|
||||
// Version is clearly implied by both the version declared in the
|
||||
// cargo manifest and the matching version in the tag of current
|
||||
// commit
|
||||
|
||||
let major = env!("CARGO_PKG_VERSION_MAJOR");
|
||||
let minor = env!("CARGO_PKG_VERSION_MINOR");
|
||||
let patch = env!("CARGO_PKG_VERSION_PATCH");
|
||||
|
||||
export_semantic_release_notes(major, minor, patch);
|
||||
export_semantic_version(major, minor, patch);
|
||||
} else {
|
||||
// We can not tell a version with any certainty, so we use the git
|
||||
// revision as a unique version identifier instead
|
||||
|
||||
let revision = git_revision();
|
||||
|
||||
export_generic_release_notes();
|
||||
export_special_version(&revision);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-17
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2025 Simon Repp
|
||||
// SPDX-FileCopyrightText: 2025-2026 Simon Repp
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
//! Build any hyper8 target (cli, docs, etc.) with the environment variable
|
||||
@@ -8,28 +8,22 @@
|
||||
//! For instance to build the docs for version "2.0.0~pre1":
|
||||
//! "HYPER8_VERSION=2.0.0~pre1 cargo run -p hyper8-docs -- [output_path]"
|
||||
|
||||
/// The link https://hyper8.org/changes/[major.minor.patch]/ for
|
||||
/// regular tag-based releases. If the version is being overridden using
|
||||
/// HYPER8_VERSION, it falls back to the more generic release notes index
|
||||
/// page (https://hyper8.org/changes/).
|
||||
pub const CHANGES_URL: &str = env!("HYPER8_CHANGES_URL");
|
||||
|
||||
/// 7-digit short commit hash or "unknown revision"
|
||||
pub const REVISION: &str = env!("HYPER8_REVISION");
|
||||
/// The link https://hyper8.org/changes/[major.minor.patch]/ if a semantic
|
||||
/// version is present either in the tag of the current commit (with a
|
||||
/// matching version present in the cargo manifest) or passed through the
|
||||
/// HYPER8_VERSION environment variable. If no semantic version is detected
|
||||
/// it falls back to the more generic release notes index page at
|
||||
/// https://hyper8.org/changes/.
|
||||
pub const RELEASE_NOTES: &str = env!("HYPER8_RELEASE_NOTES");
|
||||
|
||||
/// Adaptive version, e.g. "0.23" or "0.23.1" (leaves out patch for major/minor releases)
|
||||
pub const VERSION_ADAPTIVE_PATCH: &str = env!("HYPER8_VERSION_ADAPTIVE_PATCH");
|
||||
|
||||
/// E.g. Full version, "0.23.0" or "1.6.3"
|
||||
/// Full version, e.g. "0.23.0" or "1.6.3"
|
||||
pub const VERSION_WITH_PATCH: &str = env!("HYPER8_VERSION_WITH_PATCH");
|
||||
|
||||
/// E.g. "1.2.3 (0abcdef)"
|
||||
pub const VERSION_WITH_PATCH_AND_REVISION: &str = concat!(
|
||||
env!("HYPER8_VERSION_WITH_PATCH"),
|
||||
" (",
|
||||
env!("HYPER8_REVISION"),
|
||||
")"
|
||||
);
|
||||
/// Full version with 7-digit short commit hash, e.g. "1.2.3 (0abcdef)"
|
||||
pub const VERSION_WITH_PATCH_AND_REVISION: &str = env!("HYPER8_VERSION_WITH_PATCH_AND_REVISION");
|
||||
|
||||
/// Only the major and minor version, e.g. "0.23" or "1.6"
|
||||
pub const VERSION_WITHOUT_PATCH: &str = env!("HYPER8_VERSION_WITHOUT_PATCH");
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// SPDX-FileCopyrightText: 2024-2025 Simon Repp
|
||||
// SPDX-FileCopyrightText: 2024-2026 Simon Repp
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use indoc::formatdoc;
|
||||
|
||||
use hyper8_core::SPLASH_SVG;
|
||||
use hyper8_version::{CHANGES_URL, VERSION_ADAPTIVE_PATCH};
|
||||
use hyper8_version::{RELEASE_NOTES, VERSION_ADAPTIVE_PATCH};
|
||||
|
||||
use crate::SessionState;
|
||||
|
||||
@@ -31,7 +31,7 @@ pub fn splash_screen(session_state: &SessionState) -> String {
|
||||
<a class="donate" href="https://hyper8.org/#donate" target="_blank">
|
||||
{t_donate}
|
||||
</a>
|
||||
<a class="version" href="{CHANGES_URL}" target="_blank">
|
||||
<a class="version" href="{RELEASE_NOTES}" target="_blank">
|
||||
<span>{VERSION_ADAPTIVE_PATCH}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user