version_sync/lib.rs
1//! `version-sync` provides macros for keeping version numbers in sync
2//! with your crate version.
3//!
4//! # Library Overview
5//!
6//! When making a release of a Rust project, you typically need to
7//! adjust some version numbers in your code and documentation. This
8//! crate gives you macros that covers some typical cases where
9//! version numbers need updating:
10//!
11//! * TOML examples in the `README.md` files that show how to add a
12//! dependency on your crate. See [`assert_markdown_deps_updated`].
13//!
14//! * A `Changelog.md` file that should at least mention the current
15//! version. See [`assert_contains_regex`] and
16//! [`assert_contains_substring`].
17//!
18//! * A `README.md` file which should only mention the current
19//! version. See [`assert_only_contains_regex`].
20//!
21//! * The [`html_root_url`] attribute that tells other crates where to
22//! find your documentation. See [`assert_html_root_url_updated`].
23//!
24//! Except for [`assert_contains_substring`], the macros are gated
25//! behind individual features, as detailed below.
26//!
27//! A typical configuration will use an integration test to verify
28//! that all version numbers are in sync. Create a
29//! `tests/version-numbers.rs` file with:
30//!
31//! ```rust
32//! #[test]
33//! # fn fake_hidden_test_case_1() {}
34//! # #[cfg(feature = "markdown_deps_updated")]
35//! fn test_readme_deps_updated() {
36//! version_sync::assert_markdown_deps_updated!("README.md");
37//! }
38//!
39//! #[test]
40//! # fn fake_hidden_test_case_2() {}
41//! fn test_readme_mentions_version() {
42//! version_sync::assert_contains_substring!("README.md", "Version {version}");
43//! }
44//!
45//! #[test]
46//! # fn fake_hidden_test_case_3() {}
47//! # #[cfg(feature = "html_root_url_updated")]
48//! fn test_html_root_url() {
49//! version_sync::assert_html_root_url_updated!("src/lib.rs");
50//! }
51//!
52//! # fn main() {
53//! # #[cfg(feature = "markdown_deps_updated")]
54//! # test_readme_deps_updated();
55//! # test_readme_mentions_version();
56//! # #[cfg(feature = "html_root_url_updated")]
57//! # test_html_root_url();
58//! # }
59//! ```
60//!
61//! When you run `cargo test`, your version numbers will be
62//! automatically checked.
63//!
64//! # Cargo Features
65//!
66//! In case you only need some of the macros above, you can disable
67//! them individually using Cargo features. The features are:
68//!
69//! * `markdown_deps_updated` enables [`assert_markdown_deps_updated`].
70//! * `html_root_url_updated` enables [`assert_html_root_url_updated`].
71//! * `contains_regex` enables [`assert_contains_regex`] and
72//! [`assert_only_contains_regex`].
73//!
74//! All of these features are enabled by default. If you disable all
75//! of them, you can still use [`assert_contains_substring`] to
76//! quickly check that a given file contains the current crate
77//! version.
78//!
79//! [`html_root_url`]: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#crate-sets-html_root_url-attribute-c-html-root
80
81#![doc(html_root_url = "https://docs.rs/version-sync/0.9.5")]
82#![forbid(unsafe_code)]
83#![deny(missing_docs)]
84
85mod contains_regex;
86mod contains_substring;
87mod helpers;
88mod html_root_url;
89mod markdown_deps;
90
91#[cfg(feature = "contains_regex")]
92pub use crate::contains_regex::{check_contains_regex, check_only_contains_regex};
93pub use crate::contains_substring::check_contains_substring;
94#[cfg(feature = "html_root_url_updated")]
95pub use crate::html_root_url::check_html_root_url;
96#[cfg(feature = "markdown_deps_updated")]
97pub use crate::markdown_deps::check_markdown_deps;
98
99/// Assert that dependencies on the current package are up to date.
100///
101/// The macro will call [`check_markdown_deps`] on the file name given
102/// in order to check that the TOML examples found all depend on a
103/// current version of your package. The package name is automatically
104/// taken from the `$CARGO_PKG_NAME` environment variable and the
105/// version is taken from `$CARGO_PKG_VERSION`. These environment
106/// variables are automatically set by Cargo when compiling your
107/// crate.
108///
109/// This macro is enabled by the `markdown_deps_updated` feature.
110///
111/// # Usage
112///
113/// The typical way to use this macro is from an integration test:
114///
115/// ```rust
116/// #[test]
117/// # fn fake_hidden_test_case() {}
118/// # // The above function ensures test_readme_deps is compiled.
119/// fn test_readme_deps() {
120/// version_sync::assert_markdown_deps_updated!("README.md");
121/// }
122///
123/// # fn main() {
124/// # test_readme_deps();
125/// # }
126/// ```
127///
128/// Tests are run with the current directory set to directory where
129/// your `Cargo.toml` file is, so this will find a `README.md` file
130/// next to your `Cargo.toml` file.
131///
132/// # Panics
133///
134/// If any TOML code block fails the check, `panic!` will be invoked.
135#[macro_export]
136#[cfg(feature = "markdown_deps_updated")]
137macro_rules! assert_markdown_deps_updated {
138 ($path:expr) => {
139 let pkg_name = env!("CARGO_PKG_NAME");
140 let pkg_version = env!("CARGO_PKG_VERSION");
141 if let Err(err) = $crate::check_markdown_deps($path, pkg_name, pkg_version) {
142 panic!("{}", err);
143 }
144 };
145}
146
147/// Assert that the `html_root_url` attribute is up to date.
148///
149/// Library crates can [set `html_root_url`][api-guidelines] to point
150/// to their documentation so that `cargo doc --no-deps` in other
151/// projects can generate correct links when referring the library.
152///
153/// The macro will call [`check_html_root_url`] on the file name given
154/// in order to check that the `html_root_url` is points to the
155/// current version of your package documentation on docs.rs. Use
156/// [`assert_contains_regex!`] instead if you don't host the
157/// documentation on docs.rs.
158///
159/// The package name is automatically taken from the `$CARGO_PKG_NAME`
160/// environment variable and the version is taken from
161/// `$CARGO_PKG_VERSION`. These environment variables are
162/// automatically set by Cargo when compiling your crate.
163///
164/// This macro is enabled by the `html_root_url_updated` feature.
165///
166/// # Usage
167///
168/// The typical way to use this macro is from an integration test:
169///
170/// ```rust
171/// #[test]
172/// # fn fake_hidden_test_case() {}
173/// # // The above function ensures test_html_root_url is compiled.
174/// fn test_html_root_url() {
175/// version_sync::assert_html_root_url_updated!("src/lib.rs");
176/// }
177///
178/// # fn main() {
179/// # test_html_root_url();
180/// # }
181/// ```
182///
183/// Tests are run with the current directory set to directory where
184/// your `Cargo.toml` file is, so this will find the `src/lib.rs`
185/// crate root.
186///
187/// # Panics
188///
189/// If the `html_root_url` fails the check, `panic!` will be invoked.
190///
191/// [api-guidelines]: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#crate-sets-html_root_url-attribute-c-html-root
192#[macro_export]
193#[cfg(feature = "html_root_url_updated")]
194macro_rules! assert_html_root_url_updated {
195 ($path:expr) => {
196 let pkg_name = env!("CARGO_PKG_NAME");
197 let pkg_version = env!("CARGO_PKG_VERSION");
198 if let Err(err) = $crate::check_html_root_url($path, pkg_name, pkg_version) {
199 panic!("{}", err);
200 }
201 };
202}
203
204/// Assert that versions numbers are up to date via substring matching.
205///
206/// This macro allows you verify that the current version number is
207/// mentioned in a particular file, such as a changelog file. You do
208/// this by specifying a template which will be matched against the
209/// content of the file.
210///
211/// The macro calls [`check_contains_substring`] on the file name
212/// given. The package name and current package version is
213/// automatically taken from the `$CARGO_PKG_NAME` and
214/// `$CARGO_PKG_VERSION` environment variables. These environment
215/// variables are automatically set by Cargo when compiling your
216/// crate.
217///
218/// # Usage
219///
220/// The typical way to use this macro is from an integration test:
221///
222/// ```rust
223/// #[test]
224/// # fn fake_hidden_test_case() {}
225/// # // The above function ensures test_readme_mentions_version is
226/// # // compiled.
227/// fn test_readme_mentions_version() {
228/// version_sync::assert_contains_substring!("README.md", "### Version {version}");
229/// }
230///
231/// # fn main() {
232/// # test_readme_mentions_version();
233/// # }
234/// ```
235///
236/// Tests are run with the current directory set to directory where
237/// your `Cargo.toml` file is, so this will find a `README.md` file
238/// next to your `Cargo.toml` file. It will then check that there is a
239/// heading mentioning the current version of your crate.
240///
241/// The template can contain placeholders which are replaced before
242/// the search begins:
243///
244/// * `{version}`: the current version number of your package.
245/// * `{name}`: the name of your package.
246///
247/// This way you can search for things like `"Latest version of {name}
248/// is: {version}"` and make sure you update your READMEs and
249/// changelogs consistently.
250///
251/// See [`assert_contains_regex`] if you want to search for a regular
252/// expression instead.
253///
254/// # Panics
255///
256/// If the substring cannot be found, `panic!` will be invoked and
257/// your integration test will fail.
258#[macro_export]
259macro_rules! assert_contains_substring {
260 ($path:expr, $format:expr) => {
261 let pkg_name = env!("CARGO_PKG_NAME");
262 let pkg_version = env!("CARGO_PKG_VERSION");
263 if let Err(err) = $crate::check_contains_substring($path, $format, pkg_name, pkg_version) {
264 panic!("{}", err);
265 }
266 };
267}
268
269/// Assert that versions numbers are up to date via a regex.
270///
271/// This macro allows you verify that the current version number is
272/// mentioned in a particular file, such as a changelog file. You do
273/// this by specifying a regular expression which will be matched
274/// against the contents of the file.
275///
276/// The macro calls [`check_contains_regex`] on the file name given.
277/// The package name and current package version is automatically
278/// taken from the `$CARGO_PKG_NAME` and `$CARGO_PKG_VERSION`
279/// environment variables. These environment variables are
280/// automatically set by Cargo when compiling your crate.
281///
282/// This macro is enabled by the `contains_regex` feature.
283///
284/// # Usage
285///
286/// The typical way to use this macro is from an integration test:
287///
288/// ```rust
289/// #[test]
290/// # fn fake_hidden_test_case() {}
291/// # // The above function ensures test_readme_mentions_version is
292/// # // compiled.
293/// fn test_readme_mentions_version() {
294/// version_sync::assert_contains_regex!("README.md", "^### Version {version}");
295/// }
296///
297/// # fn main() {
298/// # test_readme_mentions_version();
299/// # }
300/// ```
301///
302/// Tests are run with the current directory set to directory where
303/// your `Cargo.toml` file is, so this will find a `README.md` file
304/// next to your `Cargo.toml` file. It will then check that there is a
305/// heading mentioning the current version of your crate.
306///
307/// The regular expression can contain placeholders which are replaced
308/// before the regular expression search begins:
309///
310/// * `{version}`: the current version number of your package.
311/// * `{name}`: the name of your package.
312///
313/// This way you can search for things like `"Latest version of {name}
314/// is: {version}"` and make sure you update your READMEs and
315/// changelogs consistently.
316///
317/// # Panics
318///
319/// If the regular expression cannot be found, `panic!` will be
320/// invoked and your integration test will fail.
321#[macro_export]
322#[cfg(feature = "contains_regex")]
323macro_rules! assert_contains_regex {
324 ($path:expr, $format:expr) => {
325 let pkg_name = env!("CARGO_PKG_NAME");
326 let pkg_version = env!("CARGO_PKG_VERSION");
327 if let Err(err) = $crate::check_contains_regex($path, $format, pkg_name, pkg_version) {
328 panic!("{}", err);
329 }
330 };
331}
332
333/// Assert that all versions numbers are up to date via a regex.
334///
335/// This macro allows you verify that the current version number is
336/// mentioned in a particular file, such as a README file. You do this
337/// by specifying a regular expression which will be matched against
338/// the contents of the file.
339///
340/// The macro calls [`check_only_contains_regex`] on the file name
341/// given. The package name and current package version is
342/// automatically taken from the `$CARGO_PKG_NAME` and
343/// `$CARGO_PKG_VERSION` environment variables. These environment
344/// variables are automatically set by Cargo when compiling your
345/// crate.
346///
347/// This macro is enabled by the `contains_regex` feature.
348///
349/// # Usage
350///
351/// The typical way to use this macro is from an integration test:
352///
353/// ```rust
354/// #[test]
355/// # fn fake_hidden_test_case() {}
356/// # // The above function ensures test_readme_mentions_version is
357/// # // compiled.
358/// fn test_readme_links_are_updated() {
359/// version_sync::assert_only_contains_regex!("README.md", "docs.rs/{name}/{version}/");
360/// }
361///
362/// # fn main() {
363/// # test_readme_links_are_updated();
364/// # }
365/// ```
366///
367/// Tests are run with the current directory set to directory where
368/// your `Cargo.toml` file is, so this will find a `README.md` file
369/// next to your `Cargo.toml` file. It will then check that all links
370/// to docs.rs for your crate contain the current version of your
371/// crate.
372///
373/// The regular expression can contain placeholders which are replaced
374/// as follows:
375///
376/// * `{version}`: the version number of your package.
377/// * `{name}`: the name of your package.
378///
379/// The `{version}` placeholder will match compatible versions,
380/// meaning that `{version}` will match all of `1.2.3`, `1.2`, and `1`
381/// when your package is at version `1.2.3`.
382///
383/// # Panics
384///
385/// If the regular expression cannot be found or if some matches are
386/// not updated, `panic!` will be invoked and your integration test
387/// will fail.
388#[macro_export]
389#[cfg(feature = "contains_regex")]
390macro_rules! assert_only_contains_regex {
391 ($path:expr, $format:expr) => {
392 let pkg_name = env!("CARGO_PKG_NAME");
393 let pkg_version = env!("CARGO_PKG_VERSION");
394 if let Err(err) = $crate::check_only_contains_regex($path, $format, pkg_name, pkg_version) {
395 panic!("{}", err);
396 }
397 };
398}