Skip to content

Liber Tertius · Chapter 3 · Keeping a project current

Add, trace and remove modules

Adding is one command and removing is three, because removal edits grim.json before it asks anything and never touches the lock. A commit between the two halves is what makes every step reversible.

≈10 min 7 steps A clean working tree A running stack
Source

Before you start

Commit what you are working on. Of everything these commands write, git tracks two files, grim.json and grim.lock. With a clean tree, git diff on those two is the full record of a change, and git checkout is the way back.

Bring the stack up. Adding a module ends with the autoloader and the migrations in the app container. With the container down both are skipped, and the steps still show a tick.

$ git status --short
$ grim up

The ritual, in order

Seven steps. The first and the third only read. The second and the fifth are the ones that write, and the commit of step four stands between them on purpose.

  1. Find the module

    Look before you build. grim search matches one word against names and descriptions in the catalogue, and grim module:info reads a single entry from GitHub.

    $ grim search orders
    $ grim module:info cart-orders --readme

    The Name column holds the short name, and that is what every later command takes. Read two rows of the entry: Archived has to say no, and Latest release is the newest release anywhere, which can be on a train ahead of yours. With no word in mind, grim list:available prints the whole catalogue.

  2. Add it

    grim require picks the newest release on the train in grim.lock, installs the module with everything it requires, and writes grim.json and the lock.

    $ grim require cart-orders
    
    Requiring module: cart-orders
    
      ✓ [1/7] Resolving dependencies (2s)
      ✓ [2/7] Installing modules (6s)
    
      ✓ [7/7] Running migrations (3s)
    
    $ git diff grim.json grim.lock

    The Packages added table under the steps names only what you asked for. The diff names everything. grim.json gains one line, "cart-orders": "~2.4". The lock gains the module and each of its dependencies. The whole project is resolved again on the train, so a module you already had can move to a newer patch release in the same run. That shows in the diff too.

  3. Trace what came along

    A module you did not name is now in src/. grim why prints the chain from grim.json down to it.

    $ grim why payments
    
    payments  v2.4.0
    
    shop (project)
    └─ cart-orders  (grim.json)
       └─ payments  (requires)

    Only the module you named was switched on in storage/config/modules-enabled.php. A dependency is installed and locked, and it is not in that list. When the app needs it switched on, add its line by hand, in the shape of the ones already there: Modules\Payments\PaymentsProvider::class,.

  4. Test, then commit the pair

    grim.json says what you asked for and grim.lock says what you got. They belong in one commit, once grim test agrees.

    $ grim test
    $ git add grim.json grim.lock
    $ git commit -m "feat: add cart-orders"

    This commit is also the safety net of the next step.

  5. Remove a module

    Ask first who else needs it, then let grim remove drop it. Skip its --dry-run: the dry run looks for orphans without taking the module out first, so it lists less than the real run deletes.

    $ grim why cart-orders
    $ grim remove cart-orders
    ✓ Removed cart-orders from grim.json
    
    Orphan modules (not required by grim.json):
      • cart-orders  (1.2 MB)
      • payments  (412.0 KB)
      Delete 2 orphan module(s)? [y/N]

    grim.json is already saved when the question appears. Read the list: it holds every module nothing reaches any more, including leftovers that are older than this removal. Answer y and the directories under src/ go, together with their lines in modules-enabled.php. Answer no and the edit of grim.json stays. git checkout grim.json takes it back.

    cart-orders stays installed — still reachable transitively means another module requires it. It left grim.json and stays on disk, which is correct.

    An installed module is a git checkout, and edits inside it exist nowhere else. --force skips the question and the check for uncommitted changes, and the work is deleted with the directory.

  6. Sweep what is left

    grim prune is the same cleanup without the edit. Run its dry run after a removal you answered no to, after a merge that dropped a line from grim.json, or simply to see that nothing is left.

    $ grim prune --dry-run
    No orphan modules — every installed module is reachable from grim.json.

    Unlike the dry run of remove, this one is exact: it reads grim.json as it is on disk. When it lists modules, grim prune without the flag asks and deletes.

  7. Write the lock again, then commit

    Neither remove nor prune touches grim.lock, so it still names what you deleted. grim install resolves grim.json again and writes it. --no-composer keeps that to files and lock.

    $ grim install --no-composer
    $ grim test
    $ git add grim.json grim.lock
    $ git commit -m "chore: remove cart-orders"

    git diff grim.json grim.lock before the commit shows the same two files, this time with lines leaving.

What you have now

A grim.json that lists what the project asks for, a lock that matches it, and a src/ with nothing in it that the two do not explain.

"requires": {
    "cart": "~2.4",
    "cart-orders": "~2.4"
}

The database is the exception. Removing a module deletes its code and leaves the tables its migrations created. Drop them yourself when the data is no longer wanted. A module fix on the same train is Take one module fix mid-train.

When it does not work

“Module 'cart-orders' has no available versions (required by grim.json)”

The module has no release on the project's train. Nothing was written. Wait for its release on your train, or move the project with Move a project to a new train when the module is only released ahead of you.

“1 package cannot be installed:”

The run stops before anything is cloned, and the lines below say why: archived, or not visible to your GitHub account. Nothing was installed. is meant literally. An archived module that became part of core is already in the project.

A class of the new module is not found

The stack was down while you ran grim require, so the autoloader and the migrations were skipped behind a green tick. Catch up by hand.

$ grim up
$ grim composer dump-autoload
$ grim artisan migrate

“'payments' is not listed in grim.json requires.”

You can only remove what you required. payments is somebody's dependency, and grim why payments shows whose. It goes when the module that needs it goes.

“⚠ 1 module has uncommitted changes that would be lost.”

The clean orphans are deleted and the edited one stays. Commit and push from inside src/<Module>/, then run grim prune.