Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
92eb8e7
feat(global-cli): add monorepo release workflow with publish safety c…
ubugeeei Mar 28, 2026
650a278
refactor
ubugeeei Mar 28, 2026
013da0a
test: more conventional commit perser tests
ubugeeei Mar 28, 2026
e5e927a
refactor: first publishing guidance template
ubugeeei Mar 28, 2026
ba8f778
more docs
ubugeeei Mar 28, 2026
6af54bb
remove tokio
ubugeeei Mar 28, 2026
4ea6d8b
refactor
ubugeeei Mar 28, 2026
ab737c2
refactor
ubugeeei Mar 28, 2026
a7c8da2
refactor
ubugeeei Mar 28, 2026
ad2b473
refactor
ubugeeei Mar 28, 2026
0ec06d9
feat(release): harden vp release flow
ubugeeei Mar 28, 2026
eb0557b
fix(release): keep repo manifests unchanged
ubugeeei Mar 28, 2026
c61cbe0
fix(release): restore CI buildability
ubugeeei Mar 28, 2026
3e079f6
fix(release): resolve remaining compile errors
ubugeeei Mar 28, 2026
7fb661a
fix(release): use standard success exit statuses
ubugeeei Mar 28, 2026
100eae4
fix(release): drop unused runner helper
ubugeeei Mar 28, 2026
c40d266
fix(release): handle invalid tags in tests
ubugeeei Mar 28, 2026
5045471
test(versioning): align invalid patch expectation
ubugeeei Mar 28, 2026
a02c430
fix(release): keep publish workflow template parseable
ubugeeei Mar 28, 2026
28f157b
chore(global): drop checked-in binaries
ubugeeei Mar 28, 2026
155e4b6
fix ci
ubugeeei Mar 29, 2026
c43ffa0
Merge branch 'main' of github.com:voidzero-dev/vite-plus into feat/pu…
ubugeeei Mar 29, 2026
c3c9209
Merge branch 'main' into feat/publish-support
ubugeeei Mar 29, 2026
fe917e2
fix ci
ubugeeei Mar 29, 2026
982d328
Merge branch 'feat/publish-support' of github.com:voidzero-dev/vite-p…
ubugeeei Mar 29, 2026
3d305ba
fix ci
ubugeeei Mar 29, 2026
6c0dba0
Merge branch 'main' of github.com:voidzero-dev/vite-plus into feat/pu…
ubugeeei Mar 30, 2026
66122e2
fix vp release tagging and verification
ubugeeei Mar 30, 2026
1f1fdb1
fix ci
ubugeeei Mar 30, 2026
39f0ef9
Merge remote-tracking branch 'origin/main' into feat/publish-support
ubugeeei Mar 31, 2026
6bf799a
fix: align rolldown workspace deps
ubugeeei Mar 31, 2026
1c029a1
fix: stabilize windows script test and fixture format
ubugeeei Mar 31, 2026
4c07242
test: isolate env exec runtime cache
ubugeeei Mar 31, 2026
c983d41
Merge branch 'main' into feat/publish-support
ubugeeei Mar 31, 2026
ced4ce5
Merge branch 'main' into feat/publish-support
ubugeeei Mar 31, 2026
54e4fde
Merge branch 'main' into feat/publish-support
ubugeeei Apr 1, 2026
d0c32a7
Merge branch 'main' of github.com:voidzero-dev/vite-plus into feat/pu…
ubugeeei Apr 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ Vite+ is the unified entry point for local web development. It combines [Vite](h
- **`vp build`:** Build applications for production with Vite + Rolldown
- **`vp run`:** Execute monorepo tasks with caching and dependency-aware scheduling
- **`vp pack`:** Build libraries for npm publishing or standalone app binaries
- **`vp release`:** Version and publish workspace packages with native publish preflight during `--dry-run`, release checks before real publishes by default, retry-friendly exact version overrides via `--version`, optional changelog generation via `--changelog`, prerelease channels like `--preid alpha` / `beta` / `rc`, and `--projects` order respected between independent packages
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything here should only be one line with 6-7 words or so.

- **`vp create` / `vp migrate`:** Scaffold new projects and migrate existing ones

All of this is configured from your project root and works across Vite's framework ecosystem.
Vite+ is fully open-source under the MIT license.

`vp release` detects likely checks from `build`, `pack`, `prepack`, `prepublishOnly`, `prepare`, and `vitePlus.release.checkScripts`. Real releases run those checks before publishing unless you pass `--no-run-checks`; dry-runs stay lightweight by default and can opt in with `--run-checks`. `--dry-run` also runs the native publisher in dry-run mode from a temporary release manifest state when the git worktree is clean. Use `--yes` for CI or other non-interactive runs, and `--version <x.y.z>` when retrying a partial publish at an exact version.

Real releases always create git tags after a successful publish. When every released package shares the same target version, `vp release` also creates a repository-level `v<version>` tag so GitHub Releases and repo-wide release notes can follow the same watermark. Preview-only flags such as `--skip-publish` and `--no-git-tag` are therefore limited to `--dry-run`.

Comment on lines +28 to +31
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the right place for the release docs.

## Getting Started

Install Vite+ globally as `vp`:
Expand Down Expand Up @@ -120,6 +125,7 @@ Use `vp migrate` to migrate to Vite+. It merges tool-specific config files such

- **build** - Build for production
- **pack** - Build libraries
- **release** - Version and publish workspace packages, with optional changelog generation
- **preview** - Preview production build

#### Manage Dependencies
Expand Down
2 changes: 2 additions & 0 deletions crates/vite_global_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ tracing = { workspace = true }
owo-colors = { workspace = true }
oxc_resolver = { workspace = true }
crossterm = { workspace = true }
glob = { workspace = true }
petgraph = { workspace = true }
vite_error = { workspace = true }
vite_install = { workspace = true }
vite_js_runtime = { workspace = true }
Expand Down
107 changes: 107 additions & 0 deletions crates/vite_global_cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,74 @@ pub enum Commands {
args: Vec<String>,
},

/// Version workspace packages locally, then publish them from trusted-publishing CI with readiness checks and optional changelog generation
Release {
/// Preview the release plan without changing files or publishing
#[arg(long)]
dry_run: bool,

/// During dry-runs, omit publish simulation and show only versioning/changelog actions
#[arg(long)]
skip_publish: bool,

/// Treat this release as the first one and ignore existing release tags
#[arg(long)]
first_release: bool,

/// Generate root and per-package changelogs
#[arg(long, overrides_with = "no_changelog")]
changelog: bool,

/// Skip changelog generation
#[arg(long, overrides_with = "changelog")]
no_changelog: bool,

/// Override the computed release version. Useful when retrying a partial publish.
#[arg(long, value_name = "VERSION")]
version: Option<String>,

/// Publish a prerelease using the provided identifier (for example: alpha, beta, rc)
#[arg(long, value_name = "TAG")]
preid: Option<String>,

/// Legacy TOTP code for npm 2FA publish flows. Prefer trusted publishing or passkey/security-key auth when possible.
#[arg(long, value_name = "OTP")]
otp: Option<String>,

/// Release only matching workspace packages. When multiple values are provided,
/// their order is used as a tie-breaker between independent packages.
#[arg(long, value_name = "PATTERN", value_delimiter = ',')]
projects: Option<Vec<String>>,

/// Create git tags for released packages
#[arg(long, overrides_with = "no_git_tag")]
git_tag: bool,

/// Skip git tag creation in preview mode
#[arg(long, overrides_with = "git_tag")]
no_git_tag: bool,

/// Create a git commit for release changes
#[arg(long, overrides_with = "no_git_commit")]
git_commit: bool,

/// Skip the release commit
#[arg(long, overrides_with = "git_commit")]
no_git_commit: bool,

/// Run detected release checks before publishing. Real releases do this by default.
#[arg(long, overrides_with = "no_run_checks")]
run_checks: bool,

/// Skip release checks before publishing
#[arg(long, overrides_with = "run_checks")]
no_run_checks: bool,

/// Skip the final confirmation prompt
#[arg(long, short = 'y', alias = "force")]
yes: bool,
},

/// Run tasks
#[command(disable_help_flag = true)]
Run {
Expand Down Expand Up @@ -2032,6 +2100,45 @@ pub async fn run_command_with_options(
commands::delegate::execute(cwd, "pack", &args).await
}

Commands::Release {
dry_run,
skip_publish,
first_release,
changelog,
no_changelog,
version,
preid,
otp,
projects,
git_tag: _,
no_git_tag,
git_commit: _,
no_git_commit,
run_checks,
no_run_checks,
yes,
} => {
let run_checks = if dry_run { run_checks } else { !no_run_checks || run_checks };
commands::release::execute(
cwd,
commands::release::ReleaseOptions {
dry_run,
skip_publish,
first_release,
changelog: changelog && !no_changelog,
version,
preid,
otp,
projects,
git_tag: !no_git_tag,
git_commit: !no_git_commit,
run_checks,
yes,
},
)
.await
}

Commands::Run { args } => {
if help::maybe_print_unified_delegate_help("run", &args, render_options.show_header) {
return Ok(ExitStatus::default());
Expand Down
6 changes: 6 additions & 0 deletions crates/vite_global_cli/src/command_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ const COMMANDS: &[CommandEntry] = &[
append_help: false,
},
CommandEntry { label: "pack", command: "pack", summary: "Build library.", append_help: false },
CommandEntry {
label: "release",
command: "release",
summary: "Version and publish workspace packages with readiness checks, confirmation, and optional changelog generation.",
append_help: false,
},
CommandEntry {
label: "preview",
command: "preview",
Expand Down
36 changes: 35 additions & 1 deletion crates/vite_global_cli/src/commands/env/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,43 @@ fn exit_status(code: i32) -> ExitStatus {

#[cfg(test)]
mod tests {
use std::ffi::OsString;

use serial_test::serial;
use tempfile::TempDir;

use super::*;

struct VpHomeGuard {
original_vp_home: Option<OsString>,
_temp_dir: TempDir,
}

impl VpHomeGuard {
fn new() -> Self {
let temp_dir = TempDir::new().unwrap();
let original_vp_home = std::env::var_os(env_vars::VP_HOME);
// SAFETY: This test helper is only used from serial tests and restores the
// process-global environment before dropping.
unsafe {
std::env::set_var(env_vars::VP_HOME, temp_dir.path());
}
Self { original_vp_home, _temp_dir: temp_dir }
}
}

impl Drop for VpHomeGuard {
fn drop(&mut self) {
// SAFETY: We restore the original process-global environment captured in new().
unsafe {
match &self.original_vp_home {
Some(value) => std::env::set_var(env_vars::VP_HOME, value),
None => std::env::remove_var(env_vars::VP_HOME),
}
}
}
}

#[tokio::test]
async fn test_execute_missing_command() {
let result = execute(Some("20.18.0"), None, &[]).await;
Expand All @@ -208,10 +241,11 @@ mod tests {
#[tokio::test]
#[serial]
async fn test_execute_node_version() {
let _guard = VpHomeGuard::new();
// Run 'node --version' with a specific Node.js version
let command = vec!["node".to_string(), "--version".to_string()];
let result = execute(Some("20.18.0"), None, &command).await;
assert!(result.is_ok());
assert!(result.is_ok(), "{result:?}");
let status = result.unwrap();
assert!(status.success());
}
Expand Down
1 change: 1 addition & 0 deletions crates/vite_global_cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ pub mod install;
pub mod link;
pub mod outdated;
pub mod pm;
pub mod release;
pub mod remove;
pub mod unlink;
pub mod update;
Expand Down
1 change: 1 addition & 0 deletions crates/vite_global_cli/src/commands/pm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ pub async fn execute_pm_subcommand(
tag: tag.as_deref(),
access: access.as_deref(),
otp: otp.as_deref(),
provenance: None,
no_git_checks,
publish_branch: publish_branch.as_deref(),
report_summary,
Expand Down
Loading
Loading