feat(Drush): #3585531 Add commands to list, audit, and generate Canvas components

Overview

Adds Drush commands that mirror the component management screens at /admin/appearance/component and /admin/appearance/component/status. These give site builders and CI pipelines a scriptable way to inventory, audit, and regenerate Canvas components without the UI.

Commands

Command Alias Purpose
canvas:component:list canvas-component-list Inventory: every component config entity with its source, status, version count, and usage count.
canvas:component:status canvas-component-status Compatibility verdict per component: compatible, incompatible, or disabled.
canvas:component:generate canvas-component-generate Generate component config entities from discovered sources, and reconcile incompatibility reasons. Accepts --source to limit to one ComponentSource plugin.

list and status return RowsOfFields, so they honor --format (table, json, csv, …) and --fields.

canvas:component:status

  • Verdict, not just failures. Reports every component with a state column (compatible / incompatible / disabled). Disabled components are shown, not silently skipped. A manual disable maps to disabled, not incompatible.
  • Single-component lookup. Pass an ID to get one verdict: drush canvas:component:status sdc.byte_theme.card. An unknown ID errors.
  • CI gate. Exits non-zero when any reported component is incompatible, so it can fail a pipeline. A disabled component is a site-owner decision, not a failure, and does not affect the exit code.
drush canvas:component:list
drush canvas:component:list --format=json
drush canvas:component:status                       # whole-site verdict; non-zero if anything is incompatible
drush canvas:component:status sdc.byte_theme.card   # single component
drush canvas:component:generate --source=sdc

canvas:component:generate

Besides creating config entities, generate reconciles incompatibility reasons: it clears auto-disable reasons for components that now meet requirements and stores reasons for those that do not. A site owner's manual disable is preserved.

Implementation

  • src/Drush/Commands/CanvasCommands.php — discovered automatically by Drush 13 from the src/Drush/Commands directory. No drush.services.yml; dependency injection comes from AutowireTrait's static create() factory.
  • Reuses existing services: ComponentAudit, ComponentIncompatibilityReasonRepository, and ComponentSourceManager. The commands are thin wrappers over the same APIs the admin screens use.
  • status returns a CommandResult so it can carry both the formatted table and an exit code.
  • Bumps drush/drush to ^13.7 for the command attribute API.

Test coverage

tests/src/Kernel/Commands/CanvasCommandsTest.php (kernel, 11 tests):

  • list returns the expected columns and finds the test SDC component.
  • status reports state for every component, flags incompatibilities (non-zero exit), reports disabled components, resolves a single component by ID, and rejects an unknown ID.
  • generate recreates a deleted component, respects the --source filter, clears a stale auto-disable reason when a component is eligible again, and preserves a manual disable.

Verified manually against a DDEV site (Drupal 11.2, Drush 13.7): all commands are discovered after drush cr, the status exit code is 1 with incompatibilities present and 0 for a single compatible component, and an unknown ID exits non-zero.

AI Disclosure

Used Claude Code to draft the commands, kernel tests, and this description, to rebase the branch onto 1.x, to modernize command discovery to the src/Drush/Commands convention, and to extend status into a verdict tool. See: https://www.drupal.org/docs/develop/issues/issue-procedures-and-etiquette/policy-on-the-use-of-ai-when-contributing-to-drupal

Closes #3585531

Edited by Matt Glaman

Merge request reports

Loading