Skip to main content

atuin_common/
docs.rs

1//! Links into the versioned documentation site.
2//!
3//! docs.atuin.sh is versioned with mike, and the three kinds of version it
4//! publishes are not equally durable (see `.github/actions/docs-deploy-*`):
5//!
6//! TODO(markovejnovic): This file is debt and slop. Probably doesn't belong in atuin-common even.
7
8/// The docs.atuin.sh version segment matching this build.
9pub const VERSION: &str = version_segment(env!("CARGO_PKG_VERSION"));
10
11/// A URL for `path` (e.g. `guide/sync/#login`) in this build's documentation.
12#[must_use]
13pub fn url(path: &str) -> String {
14    format!("https://docs.atuin.sh/{VERSION}/{path}")
15}
16
17const fn version_segment(version: &str) -> &str {
18    let bytes = version.as_bytes();
19
20    let mut i = 0;
21    while i < bytes.len() {
22        if bytes[i] == b'-' {
23            return "main";
24        }
25        i += 1;
26    }
27
28    let mut end = 0;
29    let mut dots = 0;
30    while end < bytes.len() {
31        if bytes[end] == b'.' {
32            dots += 1;
33            if dots == 2 {
34                break;
35            }
36        }
37        end += 1;
38    }
39
40    match std::str::from_utf8(bytes.split_at(end).0) {
41        Ok(segment) => segment,
42        Err(_) => "main",
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use rstest::rstest;
49
50    use super::*;
51
52    #[rstest]
53    #[case::stable_patch_zero("18.17.0", "18.17")]
54    #[case::stable_patch_one("18.17.1", "18.17")]
55    #[case::stable_major_bump("19.0.0", "19.0")]
56    #[case::stable_large("100.200.300", "100.200")]
57    // Pinning these to `18.18.0-beta.2` would 404 once 18.18.0 shipped and
58    // the preview was pruned.
59    #[case::prerelease_beta("18.18.0-beta.2", "main")]
60    #[case::prerelease_beta_older("18.16.0-beta.1", "main")]
61    #[case::prerelease_rc("19.0.0-rc.1", "main")]
62    fn version_segment_maps_release_to_docs_segment(#[case] version: &str, #[case] expected: &str) {
63        assert_eq!(version_segment(version), expected);
64    }
65
66    #[rstest]
67    fn this_build_resolves_to_a_published_version() {
68        // Either `X.Y` or `main`; never a full version, and never empty.
69        assert!(!VERSION.is_empty());
70        assert!(VERSION == "main" || VERSION.split('.').count() == 2);
71        assert!(!VERSION.contains('-'));
72    }
73
74    #[rstest]
75    fn urls_are_absolute_and_versioned() {
76        assert_eq!(
77            url("guide/sync/#login"),
78            format!("https://docs.atuin.sh/{VERSION}/guide/sync/#login")
79        );
80    }
81}