Skip to main content

xtask/
release_commands.rs

1use anyhow::{bail, Context, Result};
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!("Usage: cargo xtask <check-release-versions|release-plan> [--base REF] [--head REF] [--mode pr|main] [--json]");
70                }
71                unknown => bail!("unknown release option: {unknown}"),
72            }
73            index += 1;
74        }
75        Ok(Self {
76            base,
77            head,
78            mode,
79            json,
80        })
81    }
82}
83
84fn parse_gate_mode(value: &str) -> Result<release_versions::GateMode> {
85    match value {
86        "pr" => Ok(release_versions::GateMode::Pr),
87        "main" => Ok(release_versions::GateMode::Main),
88        other => bail!("unknown release gate mode {other:?}; expected pr or main"),
89    }
90}
91
92fn parse_bump_level(value: &str) -> Result<release_versions::BumpLevel> {
93    match value {
94        "patch" => Ok(release_versions::BumpLevel::Patch),
95        "minor" => Ok(release_versions::BumpLevel::Minor),
96        "major" => Ok(release_versions::BumpLevel::Major),
97        other => bail!("unknown bump level {other:?}; expected patch, minor, or major"),
98    }
99}
100
101#[cfg(test)]
102#[path = "release_commands_tests.rs"]
103mod tests;