Skip to content

Board the newest train

$ grim update --dry-run

A project does not update module by module. Core, every module and every theme are released together on one version line, a train, named by its MAJOR.MINOR. grim update moves all of them onto the newest train that the core constraint in grim.json allows, then writes grim.lock again, whole.

Given a module name it does the smaller thing: that one module, to its newest release on the train the project is already locked to. It will not cross into a newer train for one module, because a module from one train against the core of another is exactly the combination trains exist to rule out.

Usage

$ grim update --dry-run     # the plan, nothing changed
$ grim update               # the whole project, onto the newest train
$ grim update cart          # one module, inside the locked train

Run it from the project directory, logged in with grim auth:login, in a project that already has a grim.lock. Run the dry run first, every time. It is the only place you see which files are about to be removed from the project before they are.

Arguments and options

Move the project onto the newest release train matching grim.json

Usage

grim update [--dry-run] [-f|--force] [--] [<module>]

Arguments

Argument Description
module Update a single module, inside the locked train (optional)

Options

Option Description
--dry-run Show the plan without applying it
-f, --force Reinstall units already at their target version, and overwrite untracked files on checkout without prompting

What it actually does

In this order, and every step is printed as it happens.

  1. Checks every package can be had. An archived module, a private one you have no access to, or one that does not exist stops the whole update before anything is fetched, and says which.
  2. Picks the train. Resolves core from grim.json to a grim-core release and takes its MAJOR.MINOR. That is the train for everything else.
  3. Prints the plan. A headline such as Train 2.4 → 2.5 available (core 2.5.0), then one row per unit that moves: current version, target, and the constraint that allowed it. With nothing to move it prints Everything is up to date on train 2.5. and stops.
  4. Lands core. Core is copied into the project. Your grim.json, grim.lock, .env, .gitignore and storage/ are never overwritten.
  5. Removes what core stopped shipping. Files the previous grim-core release carried and the new one does not are deleted, and each is named. See what gets removed.
  6. Checks out modules and themes. Each is a git checkout, moved to its new tag.
  7. Writes grim.lock. The train, the core version and commit, and every module and theme with its version and commit. config/modules-available.php is regenerated from it.
  8. Catches the container up. When core moved: composer install and php artisan migrate --force in the running app container. If the environment is down it says so and leaves that to the next grim up.
  9. Offers to prune. Modules left on disk that nothing in grim.json needs any more are listed, with a prompt to remove them now.

A single-module update skips steps 4, 5 and 8. It never touches core, and the rest of the lock is carried over as it was.

What gets removed

Core is copied, not checked out, so a file that left core upstream would otherwise stay in every project for good: a deleted test that keeps failing, a deleted class that keeps autoloading. Update removes the difference between the old core release and the new one, with these exceptions.

Case What happens
Unchanged since the old release Removed, and named: Removed <path>. The dry run prints Would remove <path>.
Edited locally Kept, with a warning. An edited copy of a file upstream dropped is more likely deliberate than drift.
Instance state grim.json, grim.lock, .env and storage/ are never touched.
Files grim manages The infrastructure files grim upgrade writes, and config/modules-available.php, are left alone.
A module that left core Nothing is deleted. You are told to add it to grim.json or run grim remove.

When the old core tree cannot be read, for example because the lock records no release version of core, the train still lands and update prints that nothing was removed. It does not guess.

Pitfalls

~2.0 is not a pinned train

Composer reads a two-part tilde as >=2.0 <3.0.0, so "core": "~2.0" follows every train of major 2. To stay on one train, write "core": "2.4.*". Either way, no module ever drifts off the train core landed on.

Update does not touch Docker files

docker-compose.yml, docker/ and the Dockerfiles come from the templates of the grim you have installed, not from core. After grim self-update, run grim upgrade to bring them in line.

A single module refuses to move

Train 2.5 available; run `grim update` (train) means a newer train exists and the project is not on it. Update the whole project first; single-module updates only work inside the train in grim.lock.

A unit has no release on the new train

⚠ module cart has no release on train 2.5 (~2.0) — left as it is. in the plan means everything else moves and that unit stays on its old version. Wait for its release on the train, or loosen its constraint in grim.json if the constraint is what rules it out.

A checkout that would overwrite untracked files inside a module stops and asks. --force answers yes for you, so read the list before reaching for it.

After it finishes

Run the suite, then look at what changed before committing the new lock.

$ grim test
$ git diff --stat

The whole move, with the review and the restart around it, is the recipe Move a project to a new train.

Recipes that use it

The idea underneath