Implement new versioning system

See `VERSIONING.md` for details.
This commit is contained in:
cloudhead 2024-03-25 10:47:19 +01:00
parent ada492f699
commit dbf47fe4e9
No known key found for this signature in database
39 changed files with 157 additions and 42 deletions

61
VERSIONING.md Normal file
View File

@ -0,0 +1,61 @@
# Versioning
This document describes the versioning scheme used by the Radicle Stack, ie.
the package that includes the Radicle CLI (`rad`), Radicle Node
(`radicle-node`) and other binaries. It is not relevant to the Rust *crate*
versions which follow [Semantic Versioning][semver].
[semver]: https://semver.org/
## Format
Versioning of the Radicle Stack is based on Git tags. During the build phase
(`build.rs`), we search for the most recent tag that starts with a `v`
character, eg. `v1.0.0`, and use that as the basis for computing the version.
If we're building code that is pointed to by that tag directly, that code will
inherit that version number, with the `v` character stripped. For example:
1.0.0
If on the other hand, the commit we are building has no version tag pointing to
it, we will use the most recent version tag by walking the history backwards
until we hit a tagged commit, and suffixing the version number with `-dev`,
plus the short hash of the commit. This indicates a development version that is
not released and not meant to be packaged or distributed. For example:
1.0.0-dev+5a3cd6d
Tags used for versioning are always annotated and signed, and follow the format:
"v" <major> "." <minor> "." <patch>
When the tag is parsed, we strip the `v` prefix, which results in a version
matching:
<major> "." <minor> "." <patch>
For pre-releases or release candidates, we add the `-rc` suffix, plus a number.
For example:
1.0.0-rc.2
These releases are meant to be packaged (they don't have `-dev` in them).
## Semantics
The Radicle version numbers do not follow strict rules, but these are the
guidelines we use:
1. Increment the `<major>` number when significant changes and/or improvements
are made to the Radicle Stack. This should happen rarely.
2. Increment the `<minor>` number when new features are added or existing
features are improved in a noticeable way.
3. Increment the `<patch>` number when bugs are fixed, docs are updated or
features are tweaked.
Unless clearly stated in the documentation, none of the user-facing commands
should be considered stable APIs, and may therefore break in `<minor>` or
`<major>` version updates. If command output is considered stable, and an
effort is made to maintain that stability, this will be stated in the command's
documentation.

View File

@ -1,7 +1,9 @@
use std::env; use std::env;
use std::process::Command; use std::process::Command;
fn main() { // TODO: Update to `cargo::` syntax after rust 1.77.
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Set a build-time `GIT_HEAD` env var which includes the commit id; // Set a build-time `GIT_HEAD` env var which includes the commit id;
// such that we can tell which code is running. // such that we can tell which code is running.
let hash = Command::new("git") let hash = Command::new("git")
@ -19,6 +21,57 @@ fn main() {
}) })
.unwrap_or(env::var("GIT_HEAD").unwrap_or("unknown".into())); .unwrap_or(env::var("GIT_HEAD").unwrap_or("unknown".into()));
let tags = Command::new("git")
.arg("tag")
.arg("--points-at")
.arg("HEAD")
.output()
.ok()
.and_then(|output| {
if output.status.success() {
String::from_utf8(output.stdout).ok()
} else {
None
}
})
.unwrap_or_default();
let tags = tags
.split_terminator('\n')
.filter_map(|s| s.strip_prefix('v'))
.collect::<Vec<_>>();
if tags.len() > 1 {
return Err("More than one version tag found for commit {hash}: {tags:?}".into());
}
// Used for `RADICLE_VERSION` env.
let version = if let Some(version) = tags.first() {
// There's a tag pointing at this `HEAD`.
// Eg. "1.0.43".
Some((*version).to_owned())
} else {
// If `HEAD` doesn't have a tag pointing to it, this is a development version,
// so find the closest tag starting with `v` and append `-dev` to the version.
// Eg. "1.0.43-dev".
Command::new("git")
.arg("describe")
.arg("--match=v*") // Match tags starting with `v`
.arg("--candidates=1") // Only one result
.arg("--abbrev=0") // Don't add the commit short-hash to the tag name
.arg("HEAD")
.output()
.ok()
.and_then(|output| {
if output.status.success() {
String::from_utf8(output.stdout).ok()
} else {
None
}
})
.map(|last| format!("{}-dev", last.trim()))
}
// If there are no tags found, we'll just call this a pre-release.
.unwrap_or(String::from("pre-release"));
// Set a build-time `GIT_COMMIT_TIME` env var which includes the commit time. // Set a build-time `GIT_COMMIT_TIME` env var which includes the commit time.
let commit_time = Command::new("git") let commit_time = Command::new("git")
.arg("show") .arg("show")
@ -35,7 +88,10 @@ fn main() {
}) })
.unwrap_or(0.to_string()); .unwrap_or(0.to_string());
println!("cargo:rustc-env=RADICLE_VERSION={version}");
println!("cargo:rustc-env=GIT_COMMIT_TIME={commit_time}"); println!("cargo:rustc-env=GIT_COMMIT_TIME={commit_time}");
println!("cargo:rustc-env=GIT_HEAD={hash}"); println!("cargo:rustc-env=GIT_HEAD={hash}");
println!("cargo:rustc-rerun-if-changed=.git/HEAD"); println!("cargo:rustc-rerun-if-changed=.git/HEAD");
Ok(())
} }

View File

@ -18,7 +18,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "auth", name: "auth",
description: "Manage identities and profiles", description: "Manage identities and profiles",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -10,7 +10,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "block", name: "block",
description: "Block repositories or nodes from being seeded or followed", description: "Block repositories or nodes from being seeded or followed",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -17,7 +17,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "checkout", name: "checkout",
description: "Checkout a repository into the local directory", description: "Checkout a repository into the local directory",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -12,7 +12,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "clean", name: "clean",
description: "Clean a repository", description: "Clean a repository",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -32,7 +32,7 @@ use crate::terminal::Element as _;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "clone", name: "clone",
description: "Clone a Radicle repository", description: "Clone a Radicle repository",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -16,7 +16,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "cob", name: "cob",
description: "Manage collaborative objects", description: "Manage collaborative objects",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -15,7 +15,7 @@ use crate::terminal::Element as _;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "config", name: "config",
description: "Manage your local Radicle configuration", description: "Manage your local Radicle configuration",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -14,14 +14,14 @@ use crate::terminal as term;
use crate::terminal::args::{Args, Help}; use crate::terminal::args::{Args, Help};
pub const NAME: &str = "rad"; pub const NAME: &str = "rad";
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = env!("RADICLE_VERSION");
pub const DESCRIPTION: &str = "Radicle command line interface"; pub const DESCRIPTION: &str = "Radicle command line interface";
pub const GIT_HEAD: &str = env!("GIT_HEAD"); pub const GIT_HEAD: &str = env!("GIT_HEAD");
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "debug", name: "debug",
description: "Write out information to help debug your Radicle node remotely", description: "Write out information to help debug your Radicle node remotely",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -16,7 +16,7 @@ use crate::terminal::highlight::Highlighter;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "diff", name: "diff",
description: "Show changes between commits", description: "Show changes between commits",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -12,7 +12,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "follow", name: "follow",
description: "Manage node follow policies", description: "Manage node follow policies",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -12,7 +12,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "fork", name: "fork",
description: "Create a fork of a repository", description: "Create a fork of a repository",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -8,7 +8,7 @@ use super::*;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "help", name: "help",
description: "CLI help", description: "CLI help",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: "Usage: rad help [--help]", usage: "Usage: rad help [--help]",
}; };

View File

@ -24,7 +24,7 @@ use crate::terminal::Interactive;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "id", name: "id",
description: "Manage repository identities", description: "Manage repository identities",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -25,7 +25,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "inbox", name: "inbox",
description: "Manage your Radicle notifications inbox", description: "Manage your Radicle notifications inbox",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -29,7 +29,7 @@ use crate::terminal::Interactive;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "init", name: "init",
description: "Initialize Radicle repositories", description: "Initialize Radicle repositories",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -23,7 +23,7 @@ use crate::terminal::Element;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "inspect", name: "inspect",
description: "Inspect a Radicle repository", description: "Inspect a Radicle repository",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -32,7 +32,7 @@ use crate::terminal::Element;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "issue", name: "issue",
description: "Manage issues", description: "Manage issues",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -10,7 +10,7 @@ use term::Element;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "ls", name: "ls",
description: "List repositories", description: "List repositories",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -23,7 +23,7 @@ pub mod routing;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "node", name: "node",
description: "Control and query the Radicle Node", description: "Control and query the Radicle Node",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -49,7 +49,7 @@ use crate::terminal::patch::Message;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "patch", name: "patch",
description: "Manage patches", description: "Manage patches",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -11,7 +11,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "path", name: "path",
description: "Display the Radicle home path", description: "Display the Radicle home path",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -13,7 +13,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "publish", name: "publish",
description: "Publish a repository to the network", description: "Publish a repository to the network",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -21,7 +21,7 @@ use crate::terminal::{Args, Context, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "remote", name: "remote",
description: "Manage a repository's remotes", description: "Manage a repository's remotes",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -16,7 +16,7 @@ use crate::{project, terminal as term};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "seed", name: "seed",
description: "Manage repository seeding policies", description: "Manage repository seeding policies",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -10,7 +10,7 @@ use crate::terminal::Element as _;
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "self", name: "self",
description: "Show information about your identity and device", description: "Show information about your identity and device",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -18,7 +18,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "stats", name: "stats",
description: "Displays aggregated repository and node metrics", description: "Displays aggregated repository and node metrics",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -24,7 +24,7 @@ use crate::terminal::{Table, TableOptions};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "sync", name: "sync",
description: "Sync repositories to the network", description: "Sync repositories to the network",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -10,7 +10,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "unfollow", name: "unfollow",
description: "Unfollow a peer", description: "Unfollow a peer",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -10,7 +10,7 @@ use crate::{project, terminal as term};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "unseed", name: "unseed",
description: "Remove repository seeding policies", description: "Remove repository seeding policies",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -13,7 +13,7 @@ use crate::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "wait", name: "wait",
description: "Wait for some state to be updated", description: "Wait for some state to be updated",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -10,12 +10,13 @@ use radicle_cli::terminal as term;
pub const NAME: &str = "rad"; pub const NAME: &str = "rad";
pub const PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); pub const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
pub const RADICLE_VERSION: &str = env!("RADICLE_VERSION");
pub const DESCRIPTION: &str = "Radicle command line interface"; pub const DESCRIPTION: &str = "Radicle command line interface";
pub const GIT_HEAD: &str = env!("GIT_HEAD"); pub const GIT_HEAD: &str = env!("GIT_HEAD");
pub const TIMESTAMP: &str = env!("GIT_COMMIT_TIME"); pub const TIMESTAMP: &str = env!("GIT_COMMIT_TIME");
pub const VERSION: Version = Version { pub const VERSION: Version = Version {
name: NAME, name: NAME,
version: PKG_VERSION, version: RADICLE_VERSION,
commit: GIT_HEAD, commit: GIT_HEAD,
timestamp: TIMESTAMP, timestamp: TIMESTAMP,
}; };

View File

@ -34,7 +34,7 @@ use crate::api::error::Error;
use crate::cache::Cache; use crate::cache::Cache;
use crate::Options; use crate::Options;
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = env!("RADICLE_VERSION");
/// Identifier for sessions /// Identifier for sessions
type SessionId = String; type SessionId = String;

View File

@ -16,7 +16,7 @@ use radicle_cli::terminal::args::{Args, Error, Help};
pub const HELP: Help = Help { pub const HELP: Help = Help {
name: "web", name: "web",
description: "Run the HTTP daemon and connect the web explorer to it", description: "Run the HTTP daemon and connect the web explorer to it",
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
usage: r#" usage: r#"
Usage Usage

View File

@ -10,7 +10,7 @@ async fn main() -> anyhow::Result<()> {
// SAFETY: The logger is only initialized once. // SAFETY: The logger is only initialized once.
httpd::logger::init().unwrap(); httpd::logger::init().unwrap();
tracing::info!("version {}-{}", env!("CARGO_PKG_VERSION"), env!("GIT_HEAD")); tracing::info!("version {}-{}", env!("RADICLE_VERSION"), env!("GIT_HEAD"));
match httpd::run(options).await { match httpd::run(options).await {
Ok(()) => {} Ok(()) => {}

View File

@ -15,7 +15,7 @@ use radicle_node::Runtime;
pub const VERSION: Version = Version { pub const VERSION: Version = Version {
name: env!("CARGO_PKG_NAME"), name: env!("CARGO_PKG_NAME"),
commit: env!("GIT_HEAD"), commit: env!("GIT_HEAD"),
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
timestamp: env!("GIT_COMMIT_TIME"), timestamp: env!("GIT_COMMIT_TIME"),
}; };
@ -100,7 +100,7 @@ fn execute() -> anyhow::Result<()> {
logger::init(options.log)?; logger::init(options.log)?;
log::info!(target: "node", "Starting node.."); log::info!(target: "node", "Starting node..");
log::info!(target: "node", "Version {} ({})", env!("CARGO_PKG_VERSION"), env!("GIT_HEAD")); log::info!(target: "node", "Version {} ({})", env!("RADICLE_VERSION"), env!("GIT_HEAD"));
log::info!(target: "node", "Unlocking node keystore.."); log::info!(target: "node", "Unlocking node keystore..");
let passphrase = profile::env::passphrase(); let passphrase = profile::env::passphrase();

View File

@ -6,7 +6,7 @@ use radicle::version::Version;
pub const VERSION: Version = Version { pub const VERSION: Version = Version {
name: "git-remote-rad", name: "git-remote-rad",
commit: env!("GIT_HEAD"), commit: env!("GIT_HEAD"),
version: env!("CARGO_PKG_VERSION"), version: env!("RADICLE_VERSION"),
timestamp: env!("GIT_COMMIT_TIME"), timestamp: env!("GIT_COMMIT_TIME"),
}; };

View File

@ -12,9 +12,6 @@ pub struct Version<'a> {
impl<'a> Version<'a> { impl<'a> Version<'a> {
/// Write program version as string. /// Write program version as string.
///
/// The program version follows [semantic versioning](https://semver.org).
///
/// Adjust with caution, third party applications parse the string for version info. /// Adjust with caution, third party applications parse the string for version info.
pub fn write(&self, mut w: impl std::io::Write) -> Result<(), io::Error> { pub fn write(&self, mut w: impl std::io::Write) -> Result<(), io::Error> {
let Version { let Version {