xtask/npm/
nightly.rs

1use std::process::{Command, Stdio};
2
3use anyhow::{ensure, Context, Result};
4use chrono::Utc;
5use clap::Args;
6use semver::{Prerelease, Version};
7
8use crate::{
9    npm::util::{bump_swc_cli, set_version},
10    util::{repository_root, wrap},
11};
12
13#[derive(Debug, Args)]
14pub(super) struct NightlyCmd {}
15
16impl NightlyCmd {
17    pub fn run(self) -> Result<()> {
18        wrap(|| {
19            let date = Utc::now().format("%Y%m%d").to_string();
20
21            let root_pkg_json = repository_root()?.join("./packages/core/package.json");
22            let content = serde_json::from_reader::<_, serde_json::Value>(
23                std::fs::File::open(root_pkg_json)
24                    .context("failed to open ./packages/core/package.json")?,
25            )?;
26            let prev_version = Version::parse(content["version"].as_str().unwrap())?;
27
28            let version = find_first_nightly(&prev_version, &date)?;
29
30            println!("Publishing nightly version {version}");
31
32            set_version(&version).context("failed to set version")?;
33            bump_swc_cli().context("failed to bump swc-cli")?;
34
35            // ./scripts/publish.sh $version
36            let status = Command::new("sh")
37                .arg("./scripts/publish.sh")
38                .arg(format!("{version}"))
39                .status()
40                .context("failed to publish")?;
41
42            ensure!(status.success(), "failed to publish");
43
44            Ok(())
45        })
46        .context("failed to publish nightly version")
47    }
48}
49
50fn find_first_nightly(prev_version: &semver::Version, date: &str) -> Result<Version> {
51    let mut ver = prev_version.clone();
52
53    if prev_version.pre.is_empty() {
54        ver.patch += 1;
55    }
56
57    for i in 1.. {
58        ver.pre = Prerelease::new(&format!("nightly-{date}.{i}"))?;
59
60        if ver <= *prev_version {
61            continue;
62        }
63
64        let tag = format!("v{ver}");
65
66        let output = Command::new("git")
67            .arg("tag")
68            .arg("-l")
69            .stderr(Stdio::inherit())
70            .output()
71            .context("git tag -l failed")
72            .map(|v| v.stdout)
73            .and_then(|s| String::from_utf8(s).context("git tag -l returned non-utf8"))?;
74
75        if !output.contains(&tag) {
76            return Ok(ver);
77        }
78    }
79
80    unreachable!("failed to find a free nightly version")
81}