Refactor your build
Renaming a project, bumping every dependency, lifting shared configuration into a template, moving a project under a different folder — these are routine refactors in any non-trivial codebase. In most build tools they're hand-edits across N files, because the build is a program and a program can't safely rewrite itself. In bleep they're commands.
Each one reads bleep.yaml, computes a new bleep.yaml, writes it
back. Run it, look at git diff, code-review, push.
Bumping dependencies
bleep build update-deps
Bumps every dependency in the build to its newest available version.
Coursier resolves the catalogue; bleep walks it and emits a new
bleep.yaml with the new version pinned everywhere it appeared.
Optional --steward flag follows
Scala Steward's
slightly-more-conservative bump strategy. --prerelease opens the
pool to non-stable releases.
bleep build update-deps
git diff bleep.yaml # review
git commit -am "bump dependencies"
bleep build update-dep org.foo::bar
Same shape, but for one dependency (or every dependency from one
organisation). Useful when you've decided to bump cats-core today
and leave the rest alone.
bleep build update-dep org.typelevel::cats-core
bleep build update-dep org.typelevel # every typelevel dep
Project topology
bleep build project-rename old new
Renames a project across the whole build. Every other project that
declared dependsOn: old is updated to dependsOn: new. Templates
that mentioned old by name are updated. The folder on disk gets
renamed too. The diff is the rename plus its propagation; nothing
gets missed.
bleep build project-rename my-old-name my-new-name
The kind of refactor that's terrifying in Maven (because a missed reference is a runtime classpath surprise) is mechanical here.
bleep build project-merge-into a b
Merges project a into project b. Sources move, dependencies
union, configuration merges. Project a disappears from
bleep.yaml and from disk. Use when you've been carrying two
modules that should always have been one.
bleep build project-merge-into legacy-utils utils
bleep build projects-move libs/ a b c
Relocates one or more projects under a different parent folder on
disk and updates the folder: field on each. The names don't
change; only where they live.
bleep build projects-move libs/ formatter parser printer
Templates
bleep build templates-reapply
Re-merges templates into projects. Run this after editing a
template definition (e.g. bumped Scala version in
template-common) to propagate the change into every project that
extends that template — without you having to track them down.
# edit template-common's scala.version
bleep build templates-reapply
git diff bleep.yaml
The diff shows you exactly which projects picked up the change.
bleep build templates-generate-new
Throws away the existing templates and infers fresh ones from the
projects' shared shape. Useful right after
bleep import-maven on a
50-module monorepo where every module had its own copy of the same
compiler options — bleep finds the common shape, lifts it
into a template, makes every project extend it.
bleep build templates-generate-new
Layout and housekeeping
bleep build move-files-into-bleep-layout
Migrates a freshly-imported sbt-shaped layout (src/main/scala,
src/test/scala) to the bleep-native shape (src/scala, with the
test project as a sibling). Drops the sbt-scope and folder
fields once the move is done.
bleep import # produces sbt-shaped layout
bleep build move-files-into-bleep-layout # convert
bleep build create-directories
Creates every source / resource directory the projects expect on disk. Useful right after scaffolding a new project, or after a refactor that introduced a new project that doesn't have its folders yet.
bleep build create-directories
bleep build normalize
Sort keys, deduplicate lists, drop empty values, collapse single-element lists to scalars. Idempotent. Run any time the file has drifted from canonical form — or wire it into a pre-commit hook so it never does.
bleep build normalize
Why this works
A bleep.yaml survives a tool round-trip cleanly because:
- The schema is closed and exhaustive — every field has a name in the Scala model, no escape hatches.
- The encoder is idempotent:
encode(decode(yaml)) == normalize(yaml). Every refactor command emits canonical-form YAML. - Every refactor operates on the same in-memory model the build itself uses. There is no second representation to drift against.
The diffs are small, readable, and code-reviewable. The compactness is for humans; the transparency is for tools.
See also
- Inspect the build — the read-only side of the same model: ask questions, get JSON, pipe anywhere.
bleep buildreference — every subcommand with its full flag set, auto-generated.- Templates & Inheritance
— what
templates-reapplyactually re-applies.