Skip to main content

xtask/
release_commands.rs

1use anyhow::{Context, Result, bail};
2use std::path::Path;
3
4use crate::release_versions;
5
6pub(crate) fn check(root: &Path, args: &[String]) -> Result<()> {
7    let options = ReleaseCommandOptions::parse(args)?;
8    release_versions::check(
9        root,
10        options.base.as_deref(),
11        &options.head,
12        options.mode,
13        options.json,
14    )
15}
16
17pub(crate) fn plan(root: &Path, args: &[String]) -> Result<()> {
18    let options = ReleaseCommandOptions::parse(args)?;
19    let plans = release_versions::plan(root, options.base.as_deref(), &options.head, options.mode)?;
20    release_versions::print_plans(&plans, options.json)
21}
22
23pub(crate) fn bump(root: &Path, args: &[String]) -> Result<()> {
24    if args.len() != 2 {
25        bail!("Usage: cargo xtask bump-version <component> <patch|minor|major>");
26    }
27    let level = parse_bump_level(&args[1])?;
28    release_versions::bump(root, &args[0], level)
29}
30
31#[derive(Debug, PartialEq, Eq)]
32struct ReleaseCommandOptions {
33    base: Option<String>,
34    head: String,
35    mode: release_versions::GateMode,
36    json: bool,
37}
38
39impl ReleaseCommandOptions {
40    fn parse(args: &[String]) -> Result<Self> {
41        let mut base = None;
42        let mut head = "HEAD".to_owned();
43        let mut mode = release_versions::GateMode::Pr;
44        let mut json = false;
45        let mut index = 0usize;
46        while index < args.len() {
47            match args[index].as_str() {
48                "--base" => {
49                    index += 1;
50                    base = Some(
51                        args.get(index)
52                            .context("--base requires a value")?
53                            .to_owned(),
54                    );
55                }
56                "--head" => {
57                    index += 1;
58                    head = args
59                        .get(index)
60                        .context("--head requires a value")?
61                        .to_owned();
62                }
63                "--mode" => {
64                    index += 1;
65                    mode = parse_gate_mode(args.get(index).context("--mode requires a value")?)?;
66                }
67                "--json" => json = true,
68                "--help" | "-h" => {
69                    bail!(
70                        "Usage: cargo xtask <check-release-versions|release-plan> [--base REF] [--head REF] [--mode pr|main] [--json]"
71                    );
72                }
73                unknown => bail!("unknown release option: {unknown}"),
74            }
75            index += 1;
76        }
77        Ok(Self {
78            base,
79            head,
80            mode,
81            json,
82        })
83    }
84}
85
86fn parse_gate_mode(value: &str) -> Result<release_versions::GateMode> {
87    match value {
88        "pr" => Ok(release_versions::GateMode::Pr),
89        "main" => Ok(release_versions::GateMode::Main),
90        other => bail!("unknown release gate mode {other:?}; expected pr or main"),
91    }
92}
93
94fn parse_bump_level(value: &str) -> Result<release_versions::BumpLevel> {
95    match value {
96        "patch" => Ok(release_versions::BumpLevel::Patch),
97        "minor" => Ok(release_versions::BumpLevel::Minor),
98        "major" => Ok(release_versions::BumpLevel::Major),
99        other => bail!("unknown bump level {other:?}; expected patch, minor, or major"),
100    }
101}
102
103#[cfg(test)]
104#[path = "release_commands_tests.rs"]
105mod tests;