Skip to content

mob.new_plugin: scaffold against current mob, not the abandoned ~> 0.6#26

Merged
GenericJam merged 1 commit into
masterfrom
fix-scaffold-mob-version
Jun 23, 2026
Merged

mob.new_plugin: scaffold against current mob, not the abandoned ~> 0.6#26
GenericJam merged 1 commit into
masterfrom
fix-scaffold-mob-version

Conversation

@GenericJam

Copy link
Copy Markdown
Owner

Problem

MobDev.Plugin.Scaffold hard-coded the mob requirement in two places: {:mob, "~> 0.6"} in the generated mix.exs and mob_version: "~> 0.6" in every tier's manifest. Published mob is 0.7.x, so a freshly scaffolded plugin can't activate:

installed :mob 0.7.x does not satisfy mob_version "~> 0.6"

and mix deps.get resolves a stale mob. The literal also lived in five separate template strings, so mix.exs and the manifest could drift apart with nothing catching a stale value before a user hit it.

Reported as #21, surfaced by mob_ci which dogfoods mob.new_plugin --tier 0..4 and had to hand-bump the generated fixtures. Confirmed by a consumer in the issue thread.

Fix

Derive the requirement instead of hard-coding it:

  • Scaffold.mob_requirement/1 (pure) maps a concrete version to "~> MAJOR.MINOR", or returns the compiled fallback on nil.
  • Scaffold.detect_mob_requirement/0 prefers the version of :mob actually resolved in the project (Application.spec(:mob, :vsn) after Application.load/1), falling back to a single @fallback_mob_requirement ("~> 0.7") when mob isn't loadable (standalone scaffolding). mix mob.new_plugin calls this and threads the result into Scaffold.files_for/3; the templates stay pure.
  • One literal (@fallback_mob_requirement); mix.exs and all manifests interpolate the threaded value so they can't disagree.
  • The ~> 0.6 example in the manifest validator's error message is bumped to ~> 0.7 for consistency (the mob_dev adopt-deps ~> 0.6 references are left alone — those pin mob_dev itself, which is 0.6.x).

Tests

New Scaffold describe block (#21): asserts the derivation, that every tier's mix.exs and manifest agree, that the default is not ~> 0.6, that files_for/3 honors an explicit requirement, and that a generated manifest validates against a mob version satisfying the default (derived from the requirement, so the check tracks future bumps). mix test test/mob_dev/plugin/scaffold_test.exs → 40 passed. mix format + mix credo --strict clean.

ADR: decisions/2026-06-22-scaffold-derives-mob-requirement.md. CHANGELOG entry under [Unreleased].

Note

When mob's major.minor moves again, @fallback_mob_requirement still needs a human bump — mob_dev doesn't depend on mob, so CI here can't compare against the latest published mob automatically. The test guards against silently shipping the old floor.

Closes #21

🤖 Generated with Claude Code

… 0.7)

MobDev.Plugin.Scaffold hard-coded {:mob, "~> 0.6"} in the generated
mix.exs and mob_version: "~> 0.6" in every tier's manifest, so a freshly
scaffolded plugin could not activate against published mob 0.7.x.

Derive the requirement instead: Scaffold.detect_mob_requirement/0 prefers
the mob actually resolved in the project, falling back to a single
@fallback_mob_requirement ("~> 0.7") constant. files_for/3 threads it into
both mix.exs and the manifest so they always agree. A Scaffold test pins
the default and validates a generated manifest against a matching mob
version, so the pin can't silently lag a future mob release.

Closes #21

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@GenericJam GenericJam merged commit 216f9fb into master Jun 23, 2026
3 checks passed
@GenericJam GenericJam deleted the fix-scaffold-mob-version branch June 23, 2026 04:00
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.

mix mob.new_plugin scaffolds plugins pinned to mob ~> 0.6 — won't activate against mob 0.7

1 participant