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::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;
// such that we can tell which code is running.
let hash = Command::new("git")
@ -19,6 +21,57 @@ fn main() {
})
.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.
let commit_time = Command::new("git")
.arg("show")
@ -35,7 +88,10 @@ fn main() {
})
.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_HEAD={hash}");
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 {
name: "auth",
description: "Manage identities and profiles",
version: env!("CARGO_PKG_VERSION"),
version: env!("RADICLE_VERSION"),
usage: r#"
Usage

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,14 +14,14 @@ use crate::terminal as term;
use crate::terminal::args::{Args, Help};
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 GIT_HEAD: &str = env!("GIT_HEAD");
pub const HELP: Help = Help {
name: "debug",
description: "Write out information to help debug your Radicle node remotely",
version: env!("CARGO_PKG_VERSION"),
version: env!("RADICLE_VERSION"),
usage: r#"
Usage

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,12 +10,13 @@ use radicle_cli::terminal as term;
pub const NAME: &str = "rad";
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 GIT_HEAD: &str = env!("GIT_HEAD");
pub const TIMESTAMP: &str = env!("GIT_COMMIT_TIME");
pub const VERSION: Version = Version {
name: NAME,
version: PKG_VERSION,
version: RADICLE_VERSION,
commit: GIT_HEAD,
timestamp: TIMESTAMP,
};

View File

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

View File

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

View File

@ -10,7 +10,7 @@ async fn main() -> anyhow::Result<()> {
// SAFETY: The logger is only initialized once.
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 {
Ok(()) => {}

View File

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

View File

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

View File

@ -12,9 +12,6 @@ pub struct Version<'a> {
impl<'a> Version<'a> {
/// 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.
pub fn write(&self, mut w: impl std::io::Write) -> Result<(), io::Error> {
let Version {