Skip to content

feat: Automatic version bumping from configured targets#707

Merged
BYK merged 17 commits intomasterfrom
feat/auto-version-bump-from-targets
Jan 30, 2026
Merged

feat: Automatic version bumping from configured targets#707
BYK merged 17 commits intomasterfrom
feat/auto-version-bump-from-targets

Conversation

@BYK
Copy link
Member

@BYK BYK commented Jan 12, 2026

Summary

When minVersion >= 2.21.0 and no custom preReleaseCommand is defined, Craft automatically bumps version numbers based on configured publish targets. This eliminates the need for a scripts/bump-version.sh script in most cases.

How It Works

  1. Craft examines configured targets in .craft.yml
  2. For each target that supports version bumping, it updates the appropriate project files
  3. Targets are processed in config order, deduplicated by type

Supported Targets

Target Detection Version Bump Method
npm package.json npm version --no-git-tag-version
pypi pyproject.toml hatch, poetry, setuptools-scm, or direct edit
crates Cargo.toml cargo set-version (cargo-edit)
gem *.gemspec Direct edit of gemspec + lib/**/version.rb
pub-dev pubspec.yaml Direct edit
hex mix.exs Direct edit
nuget *.csproj dotnet-setversion or direct XML edit

Python (pypi) Detection Priority

  1. [tool.hatch]hatch version <version>
  2. [tool.poetry]poetry version <version>
  3. [tool.setuptools_scm] → No-op (version from git tags)
  4. [project] with version → Direct TOML edit

Breaking Changes

None. Existing projects continue to work unchanged. The feature is gated behind minVersion: "2.21.0".

Fixes #76

When minVersion >= 2.19.0 and no preReleaseCommand is defined, Craft
automatically bumps version numbers based on configured publish targets.

Supported targets:
- npm: npm version --no-git-tag-version
- pypi: hatch, poetry, setuptools-scm, or direct pyproject.toml edit
- crates: cargo set-version (cargo-edit)
- gem: Direct edit of gemspec and lib/**/version.rb
- pub-dev: Direct edit of pubspec.yaml
- hex: Direct edit of mix.exs
- nuget: dotnet-setversion or direct XML edit

Fixes #76
@github-actions
Copy link
Contributor

github-actions bot commented Jan 12, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

  • Automatic version bumping from configured targets by BYK in #707

🤖 This preview updates automatically when you update the PR.

BYK added 5 commits January 12, 2026 22:39
For npm/yarn/pnpm monorepos, automatically detect and bump versions in
all workspace packages:

- npm 7+: Uses npm version --workspaces
- yarn/pnpm or npm < 7: Falls back to individual package bumping

Private packages are skipped during workspace version bumping.
Tests cover:
- runAutomaticVersionBumps utility function
- NpmTarget.bumpVersion (including workspace detection)
- PypiTarget.bumpVersion (hatch, poetry, setuptools-scm, direct edit)
- CratesTarget.bumpVersion
- GemTarget.bumpVersion
- PubDevTarget.bumpVersion
- HexTarget.bumpVersion
- NugetTarget.bumpVersion
- Remove obvious comments (// Check if X exists)
- Simplify verbose multi-line comments to single lines
- Remove redundant JSDoc field descriptions
- Clean up try/catch blocks with explicit early returns
- Shorten verbose error messages
For npm/yarn/pnpm monorepos, Craft automatically detects and bumps versions in all workspace packages:

- **npm 7+**: Uses `npm version --workspaces` to bump all packages at once
- **yarn/pnpm or npm < 7**: Falls back to bumping each non-private package individually
Copy link
Member

Choose a reason for hiding this comment

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

where's my dear Bun? we can add it later, i think we could just look for Bun lockfiles bun.lockb / bun.lock, add BUN_BIN, USE_BUN env vars, and bun publishsupport.

Copy link
Member

Choose a reason for hiding this comment

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

it supports workspaces too https://bun.com/docs/pm/workspaces

@BYK
Copy link
Member Author

BYK commented Jan 30, 2026

Re: Gem monorepo support

Updated! The gem target now searches for .gemspec files up to 2 levels deep, respecting .gitignore patterns. This supports monorepo structures like:

  • sentry-ruby/sentry-ruby.gemspec (depth 1)
  • packages/gem-name/gem-name.gemspec (depth 2)

The implementation uses the ignore npm package for gitignore parsing and async fs/promises APIs.


Re: Bun support

Great suggestion! Bun support (lockfile detection via bun.lockb/bun.lock, BUN_BIN/USE_BUN env vars, bun publish, and workspace support) would be a valuable addition. I'll address this in a follow-up PR to keep this one focused on the automatic version bumping feature.

- Add 'ignore' package for gitignore-aware file traversal
- Add findFiles() utility that respects .gitignore patterns
- Update GemTarget.bumpVersion() to search up to 2 levels deep
- Convert gem target methods to async fs/promises APIs
- Add tests for monorepo support (sentry-ruby style)
@github-actions
Copy link
Contributor

github-actions bot commented Jan 30, 2026

PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-01-30 23:59 UTC

@BYK BYK marked this pull request as ready for review January 30, 2026 22:34
Addresses PR review comments to update the minimum version required for
automatic version bumping from targets to 2.21.0, which will be the
release version for this feature.
BYK added 6 commits January 30, 2026 22:59
Replace readdir with opendir and async for...of loop for more
memory-efficient directory traversal. The async iterator processes
entries one at a time rather than loading all entries into memory.

Addresses PR review feedback.
Add helper functions to centralize the common pattern of:
1. Resolving executable path (with optional env var override)
2. Checking if executable exists
3. Throwing helpful error if not found
4. Running the command with debug logging

New exports in system.ts:
- ExecutableConfig: interface for configuring executable resolution
- resolveExecutable(): resolve binary path from config
- runWithExecutable(): check and run executable in one call

Updated targets to use the new helper:
- pypi.ts: bumpWithHatch, bumpWithPoetry
- crates.ts: bumpVersion

Closes #738
Add support for trying multiple executables in order:
- findFirstExecutable(): finds first available from array of configs
- requireFirstExecutable(): same but throws if none found
- runWithExecutable(): now accepts single config or array

Updated npm.ts to use the new abstraction:
- Uses requireFirstExecutable([NPM_CONFIG, YARN_CONFIG])
- Returns index to determine which executable was found
- Replaces manual hasExecutable checks with cleaner pattern
…ling

- Mock runWithExecutable in tests since it calls hasExecutable internally
- Use module-scope mock functions for proper test configuration
- Remove explicit dir.close() since for-await-of handles cleanup automatically
vi.mock is hoisted to top of file, so mock functions must be created
with vi.hoisted() to be available during the mock factory execution.
@BYK
Copy link
Member Author

BYK commented Jan 30, 2026

@sentry review

@BYK
Copy link
Member Author

BYK commented Jan 30, 2026

@cursoragent review

@cursor
Copy link
Contributor

cursor bot commented Jan 30, 2026

Perfect! I've completed a comprehensive review of this PR. Let me provide you with my findings.

Code Review Summary

Overall Assessment ✅

This is a well-designed and thoroughly implemented feature that adds automatic version bumping for multiple package ecosystems. The code quality is excellent, with comprehensive tests and good documentation.

Strengths

  1. Architecture: Clean abstraction with the VersionBumpableTarget interface that targets implement as static methods
  2. Test Coverage: Comprehensive tests covering all target implementations and edge cases (788 tests pass)
  3. Error Handling: Good error messages with helpful hints (e.g., "Install cargo-edit: cargo install cargo-edit")
  4. Dry-run Support: All destructive operations properly respect dry-run mode
  5. Helper Abstraction: The runWithExecutable() helper eliminates code duplication across targets
  6. Monorepo Support:
    • npm/yarn workspace detection and bulk version bumping
    • Gem target searches for gemspec files up to 2 levels deep with gitignore support
  7. Documentation: Clear docs explaining the feature, detection priority, and supported targets

Key Implementation Details

Version Bump Flow:

  1. prepare.ts calls runAutomaticVersionBumps() when minVersion >= 2.21.0 and no custom preReleaseCommand
  2. Targets are deduplicated by type (multiple npm targets only bump package.json once)
  3. Each target's bumpVersion() static method:
    • Detects if the project uses that ecosystem
    • Returns false if detection fails (not applicable)
    • Returns true after successfully bumping
    • Throws on errors with helpful messages

Target Implementations:

  • npm: Uses npm version --no-git-tag-version with workspace support
  • pypi: Smart detection (hatch → poetry → setuptools_scm → direct edit)
  • crates: Uses cargo set-version from cargo-edit
  • gem: Direct file editing with monorepo support
  • nuget: Tries dotnet-setversion first, falls back to XML editing
  • pub-dev/hex: Direct YAML/Elixir file editing

Minor Issues Found (Non-blocking)

  1. Unused import in crates.ts (line 17):
import { logger } from '../logger';  // Only used in bumpVersion, not in main class
  1. Minor warning in system.ts (line 289):
catch (e) {  // 'e' defined but never used
  1. Documentation could mention:
    • What happens if version bump succeeds but later steps fail (git state)
    • Recommended approach for projects that need custom pre-processing

Addressed PR Comments

All previous PR feedback has been addressed:

  • AUTO_BUMP_MIN_VERSION constant used throughout
  • runWithExecutable() helper abstracts the executable pattern
  • opendir with async iterator for gem target
  • ✅ Gem monorepo support (2 levels deep, gitignore-aware)
  • minVersion: "2.21.0" updated in all examples

Recommendations

  1. Consider adding a warning when automatic bumping runs but finds no applicable targets (currently just logs at debug level)
  2. Document recovery: Add a note about what to do if version bump succeeds but prepare fails mid-way
  3. Future enhancement: Consider allowing per-target version bump customization for monorepos where different packages might need different versions

Testing

  • ✅ All 788 tests pass
  • ✅ Build succeeds
  • ✅ Linter passes (161 warnings are all pre-existing or minor unused vars)
  • ✅ E2E tests verify dry-run behavior

Final Verdict

APPROVED

This PR is ready to merge. The implementation is solid, well-tested, and follows the project's coding standards. The automatic version bumping feature will significantly improve the developer experience by eliminating the need for custom bump-version scripts in most cases.

The feature is properly gated behind minVersion: "2.21.0" ensuring backward compatibility, and the fallback to custom preReleaseCommand is well-designed.

Open in Cursor Open in Web

- Return detailed VersionBumpResult from runAutomaticVersionBumps
- Provide specific warnings for:
  - No targets support version bumping
  - Targets support it but didn't find applicable files
- Add recovery documentation for failed prepare after version bump
- Update tests for new return type
@BYK BYK merged commit d62ca92 into master Jan 30, 2026
16 checks passed
@BYK BYK deleted the feat/auto-version-bump-from-targets branch January 30, 2026 23:58
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.

Bump versions directly for known package managers

3 participants