Skip to content

Commit a4a848a

Browse files
committed
Merge #2: Add a tool to check releases
129e58a Add bitcoincore-rpc to config file (Tobin C. Harding) 11e1fc5 Add a tool to check releases (Tobin C. Harding) Pull request description: Add a tool in Rust that can be used to do some release version checks. Currently supports two things: - Checking if the latest released version on crates.io is the same as in the config file. - Checking that a local crate uses the latest released dependencies (used to check that we have upgraded all deps before releasing a new version). Currently the output (colour ticks and crosses in my terminal): ```bash $ cargo run -- check-latest-dependencies ~/build/github.com/tcharding/rust-bitcoin/master bitcoin Checking latest dependencies for: crate: bitcoin version: "0.32.0-rc1" manifest: /home/tobin/build/github.com/tcharding/rust-bitcoin/master/bitcoin/Cargo.toml - serde ✓ 1.0.103 latest: 1.0.198 - base58ck ✓ 0.1.0 - base64 ✗ 0.21.3 latest: 0.22.0 - bech32 ✓ 0.11.0 - bitcoinconsensus ✗ 0.105.0+25.1 latest: 0.106.0+26.0 - bitcoin_hashes ✓ 0.14.0 - hex-conservative ✓ 0.2.0 - hex_lit ✓ 0.1.1 - bitcoin-internals ✓ 0.3.0 - bitcoin-io ✓ 0.1.1 latest: 0.1.2 - ordered ✓ 0.2.0 latest: 0.2.2 - secp256k1 ✓ 0.29.0 - bitcoin-units ✓ 0.1.0 latest: 0.1.1 ``` I'd like to extend it with all the ideas in rust-bitcoin/rust-bitcoin#2524 (comment). Close: #2524 ACKs for top commit: apoelstra: ACK 129e58a Tree-SHA512: d4dfe213a372f832d8464d1e21c6b4f001dcb52256c2086816b45c237aa414f54e490c843208b97546dae591007150a4a7f21d1a0716944af8f04a96998a21fe
2 parents 7ed1438 + 129e58a commit a4a848a

File tree

10 files changed

+1977
-0
lines changed

10 files changed

+1977
-0
lines changed

releases/Cargo.lock

Lines changed: 1314 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

releases/Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "releases"
3+
version = "0.1.0"
4+
authors = ["Tobin C. Harding <[email protected]>"]
5+
license = "CC0-1.0"
6+
repository = "https://github.com/rust-bitcoin/rust-bitcoin-maintainer-tools/"
7+
description = "Tool for checking various release related things."
8+
categories = []
9+
keywords = []
10+
readme = "README.md"
11+
edition = "2021"
12+
rust-version = "1.56.1"
13+
14+
[dependencies]
15+
anyhow = { version = "1.0.82", default-features = false, features = ["std"] }
16+
clap = { version = "4.5.4", default-features = false, features = ["std", "color", "help", "usage", "error-context", "suggestions", "derive", "cargo"] }
17+
crates_io_api = { version = "0.11.0", default-features = false, features = ["rustls"] }
18+
semver = { version = "1.0.22", default-features = false, features = ["std"] }
19+
serde_json = { version = "1.0.116", default-features = false, features = [] }
20+
serde = { version = "1.0.198", features = ["derive"] }
21+
tokio = { version = "1.37.0", features = ["rt", "macros"] }
22+
toml = { version = "0.8.12", default-features = false, features = ["display", "parse"] }

releases/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Releases Tool
2+
=============
3+
4+
This crate provides a tool for doing various release related checks.

releases/releases.json

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
{
2+
"org": "gihub.com/rust-bitcoin",
3+
"latests": [
4+
{ "package": "bitcoincore-rpc", "version": "0.18.0" },
5+
{ "package": "bitcoincore-rpc-json", "version": "0.18.0"},
6+
{ "package": "miniscript", "version": "11.0.0" },
7+
{ "package": "bitcoin", "version": "0.32.0" },
8+
{ "package": "base58ck", "version": "0.1.0" },
9+
{ "package": "bech32", "version": "0.11.0" },
10+
{ "package": "bitcoin_hashes", "version": "0.14.0" },
11+
{ "package": "hex-conservative", "version": "0.2.0" },
12+
{ "package": "hex_lit", "version": "0.1.1" },
13+
{ "package": "bitcoin-internals", "version": "0.3.0" },
14+
{ "package": "bitcoin-io", "version": "0.1.2" },
15+
{ "package": "secp256k1", "version": "0.29.0" },
16+
{ "package": "units", "version": "0.1.0" },
17+
{ "package": "ordered", "version": "0.2.2" },
18+
{ "package": "bitcoinconsensus", "version": "0.106.0+26.0" }
19+
],
20+
"releases": [
21+
{ "package": "bitcoincore-rpc", "version": "0.18.0", "dependencies":
22+
[
23+
{ "package": "bitcoincore-rpc-json", "version": "0.18.0"},
24+
{ "package": "log", "version": "0.4.5"},
25+
{ "package": "jsonrpc", "version": "0.14.0"},
26+
{ "package": "serde", "version": "1.0.156" },
27+
{ "package": "serde_json", "version": "1.0.96" }
28+
]
29+
},
30+
{ "package": "bitcoincore-rpc", "version": "0.18.0", "dependencies":
31+
[
32+
{ "package": "serde", "version": "1.0.156" },
33+
{ "package": "serde_json", "version": "1.0.96" },
34+
{ "package": "bitcoin", "version": "0.31.0" }
35+
]
36+
},
37+
{ "package": "miniscript", "version": "11.0.0", "dependencies":
38+
[
39+
{ "package": "bitcoin", "version": "0.31.0" },
40+
{ "package": "bitcoin-internals", "version": "0.2.0" },
41+
{ "package": "bech32", "version": "0.10.0-beta" },
42+
{ "package": "serde", "version": "1.0.103" }
43+
]
44+
},
45+
{ "package": "bitcoin", "version": "0.32.0-rc1", "dependencies":
46+
[
47+
{ "package": "base58ck", "version": "0.1.0" },
48+
{ "package": "bech32", "version": "0.11.0" },
49+
{ "package": "bitcoin_hashes", "version": "0.14.0" },
50+
{ "package": "hex-conservative", "version": "0.2.0" },
51+
{ "package": "hex_lit", "version": "0.1.1" },
52+
{ "package": "bitcoin-internals", "version": "0.3.0" },
53+
{ "package": "bitcoin-io", "version": "0.1.1" },
54+
{ "package": "secp256k1", "version": "0.29.0" },
55+
{ "package": "units", "version": "0.1.0" },
56+
{ "package": "base64", "version": "0.21.3" },
57+
{ "package": "ordered", "version": "0.2.0" },
58+
{ "package": "bitcoinconsensus", "version": "0.105.0" },
59+
{ "package": "serde", "version": "1.0.103" }
60+
]
61+
},
62+
{ "package": "bitcoin", "version": "0.31.2", "dependencies":
63+
[
64+
{ "package": "bitcoin-internals", "version": "0.2.0" },
65+
{ "package": "hex-conservative", "version": "0.1.1" },
66+
{ "package": "bech32", "version": "0.10.0-beta" },
67+
{ "package": "bitcoin_hashes", "version": "0.13.0" },
68+
{ "package": "secp256k1", "version": "0.28.0" },
69+
{ "package": "bitcoinconsensus", "version": "0.20.2-0.5.0" },
70+
{ "package": "hex_lit", "version": "0.1.1" },
71+
{ "package": "base64", "version": "0.21.3" },
72+
{ "package": "core2", "version": "0.3.2" },
73+
{ "package": "serde", "version": "1.0.103" }
74+
]
75+
},
76+
{ "package": "base58ck", "version": "0.1.0", "dependencies":
77+
[
78+
{ "package": "bitcoin_hashes", "version": "0.14.0" },
79+
{ "package": "bitcoin-internals", "version": "0.3.0" }
80+
]
81+
},
82+
{ "package": "bitcoin_hashes", "version": "0.13.0", "dependencies":
83+
[
84+
{ "package": "bitcoin-internals", "version": "0.2.0" },
85+
{ "package": "hex-conservative", "version": "0.1.1" },
86+
{ "package": "schemars", "version": "0.8.3" },
87+
{ "package": "serde", "version": "1.0.0" },
88+
{ "package": "core2", "version": "0.3.2" }
89+
]
90+
},
91+
{ "package": "bitcoin-internals", "version": "0.2.0", "dependencies":
92+
[
93+
{ "package": "serde", "version": "1.0.103" }
94+
]
95+
},
96+
{ "package": "bech32", "version": "0.10.0-beta", "dependencies": [] },
97+
{ "package": "secp256k1", "version": "0.28.0", "dependencies":
98+
[
99+
{ "package": "secp256k1-sys", "version": "0.9.0" },
100+
{ "package": "bitcoin_hashes", "version": "0.13.0" },
101+
{ "package": "rand", "version": "0.8.0" }
102+
]
103+
},
104+
{ "package": "secp256k1-sys", "version": "0.9.0", "dependencies": [] },
105+
{ "package": "hex-conservative", "version": "0.1.1", "dependencies":
106+
[
107+
{ "package": "core2", "version": "0.3.2" }
108+
]
109+
},
110+
{ "package": "bitcoinconsensus", "version": "0.20.2-0.5.0", "dependencies":
111+
[
112+
{ "package": "libc", "version": "0.2.0" }
113+
]
114+
}
115+
]
116+
}

releases/rustfmt.toml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
ignore = []
2+
hard_tabs = false
3+
tab_spaces = 4
4+
newline_style = "Auto"
5+
indent_style = "Block"
6+
7+
max_width = 100 # This is number of characters.
8+
# `use_small_heuristics` is ignored if the granular width config values are explicitly set.
9+
use_small_heuristics = "Max" # "Max" == All granular width settings same as `max_width`.
10+
# # Granular width configuration settings. These are percentages of `max_width`.
11+
# fn_call_width = 60
12+
# attr_fn_like_width = 70
13+
# struct_lit_width = 18
14+
# struct_variant_width = 35
15+
# array_width = 60
16+
# chain_width = 60
17+
# single_line_if_else_max_width = 50
18+
19+
wrap_comments = false
20+
format_code_in_doc_comments = false
21+
comment_width = 100 # Default 80
22+
normalize_comments = false
23+
normalize_doc_attributes = false
24+
format_strings = false
25+
format_macro_matchers = false
26+
format_macro_bodies = true
27+
hex_literal_case = "Preserve"
28+
empty_item_single_line = true
29+
struct_lit_single_line = true
30+
fn_single_line = true # Default false
31+
where_single_line = false
32+
imports_indent = "Block"
33+
imports_layout = "Mixed"
34+
imports_granularity = "Module" # Default "Preserve"
35+
group_imports = "StdExternalCrate" # Default "Preserve"
36+
reorder_imports = true
37+
reorder_modules = true
38+
reorder_impl_items = false
39+
type_punctuation_density = "Wide"
40+
space_before_colon = false
41+
space_after_colon = true
42+
spaces_around_ranges = false
43+
binop_separator = "Front"
44+
remove_nested_parens = true
45+
combine_control_expr = true
46+
overflow_delimited_expr = false
47+
struct_field_align_threshold = 0
48+
enum_discrim_align_threshold = 0
49+
match_arm_blocks = false # Default true
50+
match_arm_leading_pipes = "Never"
51+
force_multiline_blocks = false
52+
fn_params_layout = "Tall"
53+
brace_style = "SameLineWhere"
54+
control_brace_style = "AlwaysSameLine"
55+
trailing_semicolon = true
56+
trailing_comma = "Vertical"
57+
match_block_trailing_comma = false
58+
blank_lines_upper_bound = 1
59+
blank_lines_lower_bound = 0
60+
edition = "2021"
61+
version = "One"
62+
inline_attribute_width = 0
63+
format_generated_files = true
64+
merge_derives = true
65+
use_try_shorthand = false
66+
use_field_init_shorthand = false
67+
force_explicit_abi = true
68+
condense_wildcard_suffixes = false
69+
color = "Auto"
70+
unstable_features = false
71+
disable_all_formatting = false
72+
skip_children = false
73+
hide_parse_errors = false
74+
error_on_line_overflow = false
75+
error_on_unformatted = false
76+
emit_mode = "Files"
77+
make_backup = false

releases/src/api.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! Interact with the crates.io API.
4+
5+
pub fn latest_release(package: &str) -> Release { todo!() }

releases/src/json.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//! Types that represent the JSON schema and provide deserialization.
2+
//!
3+
//! We deserialize to Rust std types then convert to more strictly typed types manually.
4+
5+
#![allow(dead_code)] // This is just the JSON schemar, all fields exist.
6+
7+
use serde::Deserialize;
8+
9+
/// The `releases.json` config file.
10+
#[derive(Debug, Deserialize)]
11+
pub struct Config {
12+
/// The github organisation this config file relates to.
13+
pub org: String,
14+
/// List of the latest releases.
15+
pub latests: Vec<CrateVersion>,
16+
/// List of all releases we run checks against.
17+
pub releases: Vec<CrateNode>,
18+
}
19+
20+
/// As specific version of a crate.
21+
#[derive(Debug, Deserialize)]
22+
pub struct CrateVersion {
23+
/// The crate's package name on crates.io
24+
pub package: String,
25+
/// The dependencies semantic version number.
26+
pub version: String,
27+
}
28+
29+
/// A version of one of the crates along with a list of its dependencies (and their versions) - used
30+
/// to make a dependency graph.
31+
#[derive(Debug, Deserialize)]
32+
pub struct CrateNode {
33+
/// The crate's package name on crates.io
34+
pub package: String,
35+
/// The release's semantic version number.
36+
pub version: String,
37+
/// List of this releases dependencies.
38+
pub dependencies: Vec<CrateVersion>,
39+
}

releases/src/lib.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! Tool to check various release related things.
4+
5+
// Coding conventions.
6+
#![warn(missing_docs)]
7+
8+
use std::fmt;
9+
10+
use anyhow::bail;
11+
use semver::Version;
12+
13+
pub mod json;
14+
15+
/// The state of the rust-bitcoin org that this tool aims to run checks on.
16+
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
17+
pub struct Config {
18+
/// List of the latest releases.
19+
pub latests: Vec<CrateVersion>,
20+
/// The releases we want to check.
21+
pub releases: Vec<CrateNode>,
22+
}
23+
24+
impl Config {
25+
/// Returns the latest release of the given crate.
26+
pub fn latest(&self, package: &str) -> anyhow::Result<Version> {
27+
let mut want = None;
28+
for latest in self.latests.iter() {
29+
if latest.package == package {
30+
want = Some(latest.version.clone());
31+
}
32+
}
33+
if want.is_none() {
34+
bail!("package {} is not listed in latest section of config file", package);
35+
}
36+
37+
let mut found = Version::parse("0.0.0").expect("valid zero version");
38+
let mut release = None;
39+
for r in self.releases.iter() {
40+
if r.package == package && r.version > found {
41+
found = r.version.clone();
42+
release = Some(r);
43+
}
44+
}
45+
match release {
46+
Some(r) => {
47+
if r.version != want.expect("checked above") {
48+
bail!("the latest version in the releases section for {} does not match the verison in the latest section", package);
49+
}
50+
Ok(r.version.clone())
51+
}
52+
None => bail!("we don't have a release in the config file for {}", package),
53+
}
54+
}
55+
}
56+
57+
impl TryFrom<json::Config> for Config {
58+
type Error = semver::Error;
59+
60+
fn try_from(json: json::Config) -> Result<Self, Self::Error> {
61+
let latests: Result<Vec<_>, _> = json.latests.into_iter().map(TryFrom::try_from).collect();
62+
let releases: Result<Vec<_>, _> =
63+
json.releases.into_iter().map(TryFrom::try_from).collect();
64+
Ok(Self { latests: latests?, releases: releases? })
65+
}
66+
}
67+
68+
/// As specific version of a crate.
69+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
70+
pub struct CrateVersion {
71+
/// The crate's package name on crates.io
72+
pub package: String,
73+
/// The dependencies semantic version number.
74+
pub version: Version,
75+
}
76+
77+
impl TryFrom<json::CrateVersion> for CrateVersion {
78+
type Error = semver::Error;
79+
80+
fn try_from(json: json::CrateVersion) -> Result<Self, Self::Error> {
81+
Ok(Self { package: json.package, version: Version::parse(&json.version)? })
82+
}
83+
}
84+
85+
/// A version of one of the crates that lives in the github.com/rust-bitcoin org.
86+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
87+
pub struct CrateNode {
88+
/// The crate this release is for.
89+
pub package: String,
90+
/// The release's semantic version number.
91+
pub version: Version,
92+
/// List of this releases dependencies.
93+
pub dependencies: Vec<CrateVersion>,
94+
}
95+
96+
impl fmt::Display for CrateNode {
97+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98+
write!(f, "{} {}", self.package, self.version)
99+
}
100+
}
101+
102+
impl TryFrom<json::CrateNode> for CrateNode {
103+
type Error = semver::Error;
104+
105+
fn try_from(json: json::CrateNode) -> Result<Self, Self::Error> {
106+
let mut dependencies = vec![];
107+
for d in json.dependencies {
108+
let converted = CrateVersion::try_from(d)?;
109+
dependencies.push(converted);
110+
}
111+
112+
Ok(Self { package: json.package, version: Version::parse(&json.version)?, dependencies })
113+
}
114+
}

0 commit comments

Comments
 (0)