Skip to content

Conversation

@JLCarveth
Copy link

@JLCarveth JLCarveth commented Aug 29, 2025

Adds a deno bump-version subcommand similar to npm version

  • Ideally, deno init should be updated to include a default value for the version field in deno.json.
  • Right now the implementation uses the first version field it finds in either deno.json(c) or package.json, but perhaps we would instead prefer to check both files explicitly in case there are discrepancies.
  • TODO: Implement tests

Closes #30358

@bartlomieju bartlomieju added this to the 2.6.0 milestone Sep 10, 2025
@JLCarveth JLCarveth marked this pull request as ready for review September 12, 2025 18:07
@bartlomieju
Copy link
Member

Hey @JLCarveth we'll try to give you initial review this week. Is there anything that is blocking you at the moment?

@JLCarveth
Copy link
Author

Hey @JLCarveth we'll try to give you initial review this week. Is there anything that is blocking you at the moment?

Should I look into setting a default value for the version field in deno init?

@bartlomieju
Copy link
Member

@JLCarveth I'm not sure - deno init --lib already creates a structure with deno.json that has a version set - I think we're covered here.

@bartlomieju
Copy link
Member

@JLCarveth we just discussed this during the CLI meeting - overall this looks good, but we have a couple comments:

  • we're not sure about the name of the subcommand - we might want to use a verb here, like deno increase-version or deno bump-version
  • the Git integration seems extracurricular and maybe could be skipped (unless there's a strong prior art that it should be there?)

@JLCarveth
Copy link
Author

The Git integration was based on the npm behaviour: https://docs.npmjs.com/cli/v8/commands/npm-version#git-tag-version

If the team would prefer a simpler integration it could be removed

@JLCarveth
Copy link
Author

After thinking on it further, I agree that the git integration is not necessary. Adds more maintenance burden when a simple bash function can handle the git stuff. I'll remove that tomorrow

@bartlomieju
Copy link
Member

@JLCarveth sounds good, can you also rename the subcommand to bump-version please?

@bartlomieju
Copy link
Member

@JLCarveth I think we're ready to land this one - I'm thinking we could do it this week, without waiting for another minor release - how about we land this one as "unstable"? If so, let's add a small banner anytime this command is run that says: Warning deno bump-version is experimental as subject to change.

Comment on lines 3966 to 3967
<p(245)>deno bump-version patch --no-git-tag</> # Don't create git tag
<p(245)>deno bump-version patch --git-commit-all</> # Stage and commit all changes"
Copy link
Member

@dsherret dsherret Nov 4, 2025

Choose a reason for hiding this comment

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

Remove? Doesn't seem to be implemented (same with --dry-run)

if let Some(deno_json) = start_dir.maybe_deno_json() {
let config_path = deno_path_util::url_to_file_path(&deno_json.specifier)
.context("Failed to convert deno.json URL to path")?;
configs.push(ConfigUpdater::new(ConfigKind::DenoJson, config_path)?);
Copy link
Member

Choose a reason for hiding this comment

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

Is this ConfigKind necessary? Seems we could remove it?

return Ok(());
}
// Default to 1.0.0 if no version is found but increment is specified
Version::parse_standard("1.0.0")
Copy link
Member

@dsherret dsherret Nov 4, 2025

Choose a reason for hiding this comment

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

Maybe it should default to 0.1.0? If someone accidentally publishes a 0.1.0 version it's not too bad, but a 1.0.0 version can be bad. Plus, if someone has never published a version then most likely it's currently experimental, so 0.1.0 might make more sense.

@bartlomieju bartlomieju requested a review from dsherret November 5, 2025 08:12
Copy link
Member

@bartlomieju bartlomieju left a comment

Choose a reason for hiding this comment

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

Looks good from me. @dsherret are you okay with landing this as is?

Comment on lines 186 to 189
// Check for package.json
if let Some(pkg_json) = start_dir.maybe_pkg_json() {
configs.push(ConfigUpdater::new(pkg_json.path.clone())?);
}
Copy link
Member

@dsherret dsherret Nov 12, 2025

Choose a reason for hiding this comment

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

I'm not sure about this updating both deno.json and package.json at the same time.

I think probably this sub command should only update deno.json and then fallback to package.json when the deno.json doesn't exist (maybe also skipping it when the deno.json has no "name" and "version" field). Then in the future we can add an explicit flag for only updating the package.json (ex. deno bump-version --package-json minor or deno bump-version --npm minor)

Thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

I actually agree - we should do one or the other, not both at the same time. Defaulting to deno.json is fine, using package.json when no deno.json is fine and adding --package-json to force changing package.json is fine too for me.

@dsherret dsherret changed the title feat(cli): Implement support for an "npm version" equivalent in Deno CLI feat(cli): add deno bump-version subcommand Nov 12, 2025
@bartlomieju bartlomieju requested a review from dsherret November 17, 2025 14:30
@coderabbitai
Copy link

coderabbitai bot commented Dec 2, 2025

Walkthrough

Adds a new bump-version CLI subcommand and related types (VersionFlags, VersionIncrement) and a DenoSubcommand::BumpVersion variant. Implements tools::bump_version::bump_version_command to locate deno.json or package.json, read and parse the current version, compute increments (major, minor, patch, pre* variants), update the config in place, and log results. Exposes cli/tools::bump_version module. Adds integration tests covering increments, file selection, no-config failure, and no-increment behavior.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.04% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main feature: adding a deno bump-version subcommand, which aligns perfectly with the changeset's core objective.
Description check ✅ Passed The description explains the feature, mentions the related issue #30358, and notes implementation considerations about version field location and the TODO for tests.
Linked Issues check ✅ Passed The PR fully addresses issue #30358 by implementing a deno bump-version subcommand supporting semantic version bumping with Major/Minor/Patch/Prerelease strategies, file I/O, and error handling.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the bump-version feature: CLI args, subcommand dispatch, the command implementation, module exports, and integration tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
tests/integration/mod.rs (1)

49-50: Module placement breaks alphabetical order.

The other modules are alphabetically sorted. bump_version should be placed after bench (line 11) rather than after publish.

 #[path = "bench_tests.rs"]
 mod bench;
+#[path = "bump_version_tests.rs"]
+mod bump_version;
 #[path = "cache_tests.rs"]
 mod cache;

And remove lines 49-50.

cli/tools/bump_version.rs (1)

74-78: Consider insertion position for new version field.

Inserting at index 0 places version before name, which is unconventional. Typically name comes first in package manifests. Consider inserting after name if it exists, or at index 0 otherwise.

This is a minor stylistic concern - the current behavior is functional.

cli/args/flags.rs (1)

4137-4164: Clarify semantics of optional increment and de-duplicate parsing logic

Right now:

  • The positional increment is optional (no required_*), so deno bump-version can be invoked without an argument and VersionFlags { increment: None } is produced.
  • Valid strings are enforced twice: once in value_parser([...]) and again in the manual match in bump_version_parse.

If the design is that an increment is required (like npm version), consider making it explicit:

-    cmd.arg(
-      Arg::new("increment")
-        .help("Version increment type")
+    cmd.arg(
+      Arg::new("increment")
+        .help("Version increment type")
         .value_parser([
           "major",
           "minor",
           "patch",
           "premajor",
           "preminor",
           "prepatch",
           "prerelease",
         ])
-        .index(1),
+        .index(1)
+        .required_unless_present("help"),
     )

And to avoid the parser and bump_version_parse ever drifting, you can centralize the mapping:

-fn bump_version_parse(flags: &mut Flags, matches: &mut ArgMatches) {
-  let increment =
-    matches
-      .remove_one::<String>("increment")
-      .and_then(|s| match s.as_str() {
-        "major" => Some(VersionIncrement::Major),
-        "minor" => Some(VersionIncrement::Minor),
-        "patch" => Some(VersionIncrement::Patch),
-        "premajor" => Some(VersionIncrement::Premajor),
-        "preminor" => Some(VersionIncrement::Preminor),
-        "prepatch" => Some(VersionIncrement::Prepatch),
-        "prerelease" => Some(VersionIncrement::Prerelease),
-        _ => None,
-      });
+fn parse_version_increment(s: &str) -> VersionIncrement {
+  match s {
+    "major" => VersionIncrement::Major,
+    "minor" => VersionIncrement::Minor,
+    "patch" => VersionIncrement::Patch,
+    "premajor" => VersionIncrement::Premajor,
+    "preminor" => VersionIncrement::Preminor,
+    "prepatch" => VersionIncrement::Prepatch,
+    "prerelease" => VersionIncrement::Prerelease,
+    _ => unreachable!(),
+  }
+}
+
+fn bump_version_parse(flags: &mut Flags, matches: &mut ArgMatches) {
+  let increment = matches
+    .remove_one::<String>("increment")
+    .map(|s| parse_version_increment(&s));
@@
   flags.subcommand = DenoSubcommand::BumpVersion(VersionFlags { increment });
 }

Finally, it’d be good to add a small flags_from_vec test for deno bump-version (with and without increment) alongside the other CLI parsing tests, so the new wiring doesn’t regress silently.

Also applies to: 5442-5458

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d662fe and 2946674.

📒 Files selected for processing (6)
  • cli/args/flags.rs (7 hunks)
  • cli/main.rs (1 hunks)
  • cli/tools/bump_version.rs (1 hunks)
  • cli/tools/mod.rs (1 hunks)
  • tests/integration/bump_version_tests.rs (1 hunks)
  • tests/integration/mod.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
cli/tools/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

CLI tools should be implemented in cli/tools/<tool> or cli/tools/<tool>/mod.rs

Files:

  • cli/tools/mod.rs
  • cli/tools/bump_version.rs
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: For debugging Rust code, set breakpoints in IDE debuggers (VS Code with rust-analyzer, IntelliJ IDEA) or use lldb directly
Use eprintln!() or dbg!() macros for debug prints in Rust code

Files:

  • cli/tools/mod.rs
  • tests/integration/mod.rs
  • cli/tools/bump_version.rs
  • tests/integration/bump_version_tests.rs
  • cli/main.rs
  • cli/args/flags.rs
cli/main.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Main CLI entry point is in cli/main.rs and should handle command routing

Files:

  • cli/main.rs
cli/args/flags.rs

📄 CodeRabbit inference engine (CLAUDE.md)

CLI flag parsing should be defined in cli/args/flags.rs

Files:

  • cli/args/flags.rs
🧠 Learnings (4)
📚 Learning: 2025-11-24T16:19:37.808Z
Learnt from: CR
Repo: denoland/deno PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:19:37.808Z
Learning: Applies to cli/tools/**/*.rs : CLI tools should be implemented in `cli/tools/<tool>` or `cli/tools/<tool>/mod.rs`

Applied to files:

  • cli/tools/mod.rs
📚 Learning: 2025-11-24T16:19:37.808Z
Learnt from: CR
Repo: denoland/deno PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:19:37.808Z
Learning: Applies to cli/module_loader.rs : Module loading and resolution is handled in `cli/module_loader.rs`

Applied to files:

  • cli/tools/mod.rs
📚 Learning: 2025-11-24T16:19:37.808Z
Learnt from: CR
Repo: denoland/deno PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:19:37.808Z
Learning: Applies to src/**/*.rs : Unit tests should be inline with source code in each module

Applied to files:

  • tests/integration/mod.rs
📚 Learning: 2025-11-24T16:19:37.808Z
Learnt from: CR
Repo: denoland/deno PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:19:37.808Z
Learning: Applies to cli/args/flags.rs : CLI flag parsing should be defined in `cli/args/flags.rs`

Applied to files:

  • cli/args/flags.rs
🧬 Code graph analysis (2)
tests/integration/bump_version_tests.rs (2)
cli/tools/bump_version.rs (1)
  • new (30-46)
cli/main.rs (4)
  • output (80-80)
  • output (84-86)
  • output (90-92)
  • output (96-98)
cli/main.rs (1)
cli/tools/bump_version.rs (1)
  • bump_version_command (191-240)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: lint debug macos-x86_64
  • GitHub Check: test debug linux-aarch64
  • GitHub Check: test debug macos-x86_64
  • GitHub Check: test debug windows-x86_64
  • GitHub Check: test debug macos-aarch64
  • GitHub Check: test debug linux-x86_64
  • GitHub Check: test release linux-x86_64
  • GitHub Check: lint debug windows-x86_64
  • GitHub Check: build libs
  • GitHub Check: lint debug linux-x86_64
🔇 Additional comments (8)
cli/tools/mod.rs (1)

4-4: LGTM!

Module placement follows the alphabetical convention. Based on learnings, CLI tools should be in cli/tools/<tool> - this follows the expected pattern.

cli/main.rs (1)

442-448: LGTM!

The experimental warning follows the same pattern as deno bundle. The subcommand is correctly wired to the bump_version_command.

tests/integration/bump_version_tests.rs (1)

1-229: Solid test coverage.

Tests cover the key scenarios: increment types (patch/minor/major/prerelease), config file types (deno.json/package.json), edge cases (missing config, missing version field, read-only query). Structure preservation is also validated.

cli/tools/bump_version.rs (3)

95-171: Increment logic is correct.

The implementation follows standard semver incrementing rules. Pre-release identifiers are properly handled for all increment types.

One note: the function always succeeds, so the Result<Version, AnyError> return type could be simplified to just Version. However, keeping Result allows for future error cases without API changes.


173-189: Config file resolution follows the agreed approach.

Correctly prioritizes deno.json over package.json, with clear error messaging when neither exists. This aligns with the past review discussion.


191-240: Command implementation is clean.

The flow is logical: find config → get/default version → increment or display → commit. Default version is 0.1.0 as requested in past reviews.

cli/args/flags.rs (2)

136-151: VersionFlags / VersionIncrement and DenoSubcommand wiring look sound

The new VersionFlags/VersionIncrement types and the DenoSubcommand::BumpVersion(VersionFlags) variant follow the existing patterns for other subcommands (simple flag struct + enum variant) and don’t interfere with watch_flags, is_run, or needs_test. No issues here.

Also applies to: 552-589


1527-1535: bump-version is correctly exposed in help, dispatch, and root clap config

  • Help entry under “Dependency management” matches the new subcommand name and intent.
  • flags_from_vec_with_initial_cwd dispatches "bump-version" to bump_version_parse and clap_root registers bump_version_subcommand() with the same name, so the CLI routing is consistent end‑to‑end.
    No functional problems spotted.

Also applies to: 1711-1757, 2013-2019

<g>uninstall</> Uninstalls a dependency or an executable script in the installation root's bin directory
<g>outdated</> Find and update outdated dependencies
<g>remove</> Remove dependencies from the configuration file
<g>publish</> Publish the current working directory's package or workspace
Copy link
Member

Choose a reason for hiding this comment

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

Can you move this back? I don't believe this is dependency management?

Copy link
Member

Choose a reason for hiding this comment

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

I added this, I think it's fine

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
cli/args/flags.rs (3)

1556-1566: Help text could mention prerelease increments

You already accept premajor, preminor, prepatch, and prerelease via the CLI, but the top‑level help examples only show major|minor|patch. Consider adding one prerelease example or a brief mention so users discover those modes.


4226-4253: bump_version_subcommand definition is minimal and clear

Command name, description, and the positional increment argument are all wired correctly, and the value parser matches the supported increments. If you want the help output a bit clearer, you could add a value_name("INCREMENT"), but that’s optional.


5533-5549: bump_version_parse maps CLI to VersionFlags correctly; consider adding unit tests

The parse logic cleanly converts the optional increment string into Option<VersionIncrement> and sets flags.subcommand appropriately. To keep this file’s test coverage in line with other subcommands, consider adding a small test or two (for no‑arg and e.g. patch) in the tests module to assert the resulting Flags { subcommand: DenoSubcommand::BumpVersion(..) }.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2946674 and a5b909a.

📒 Files selected for processing (2)
  • cli/args/flags.rs (7 hunks)
  • cli/main.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: For debugging Rust code, set breakpoints in IDE debuggers (VS Code with rust-analyzer, IntelliJ IDEA) or use lldb directly
Use eprintln!() or dbg!() macros for debug prints in Rust code

Files:

  • cli/main.rs
  • cli/args/flags.rs

⚙️ CodeRabbit configuration file

Don't worry about coverage of Rust docstrings. Don't be nitpicky about it. Leave it to the author's judgement if such a documentation is necessary.

Files:

  • cli/main.rs
  • cli/args/flags.rs
cli/main.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Main CLI entry point is in cli/main.rs and should handle command routing

Files:

  • cli/main.rs
cli/args/flags.rs

📄 CodeRabbit inference engine (CLAUDE.md)

CLI flag parsing should be defined in cli/args/flags.rs

Files:

  • cli/args/flags.rs
🧠 Learnings (1)
📚 Learning: 2025-11-24T16:19:37.808Z
Learnt from: CR
Repo: denoland/deno PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:19:37.808Z
Learning: Applies to cli/args/flags.rs : CLI flag parsing should be defined in `cli/args/flags.rs`

Applied to files:

  • cli/args/flags.rs
🧬 Code graph analysis (1)
cli/main.rs (1)
cli/tools/bump_version.rs (1)
  • bump_version_command (191-240)
🔇 Additional comments (5)
cli/main.rs (1)

453-459: LGTM!

The new BumpVersion subcommand handler follows the established patterns in this file. The experimental warning is present as requested, and the function call correctly passes the Arc<Flags> and VersionFlags as expected by bump_version_command.

cli/args/flags.rs (4)

138-152: VersionFlags / VersionIncrement definitions look sound

The enum and flags struct cleanly model the supported increments and integrate well with the rest of the flags types; no issues here.


568-605: BumpVersion subcommand variant is correctly integrated into DenoSubcommand

Adding BumpVersion(VersionFlags) here is consistent with existing subcommands and keeps pattern‑matching straightforward.


1752-1788: bump-version dispatch wiring is correct

The new "bump-version" arm calling bump_version_parse matches the pattern of other non‑fallible parsers like remove/clean; control flow and error handling look fine.


2015-2051: clap_root registration of bump-version is consistent

Registering bump_version_subcommand() alongside other dependency‑management subcommands keeps the CLI surface coherent; no issues here.

@bartlomieju bartlomieju modified the milestones: 2.6.0, 2.7.0 Dec 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for an "npm version" equivalent in Deno CLI

3 participants