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
statecolumn (compatible/incompatible/disabled). Disabled components are shown, not silently skipped. A manual disable maps todisabled, notincompatible. - 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. Adisabledcomponent 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=sdccanvas: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 thesrc/Drush/Commandsdirectory. Nodrush.services.yml; dependency injection comes fromAutowireTrait's staticcreate()factory.- Reuses existing services:
ComponentAudit,ComponentIncompatibilityReasonRepository, andComponentSourceManager. The commands are thin wrappers over the same APIs the admin screens use. statusreturns aCommandResultso it can carry both the formatted table and an exit code.- Bumps
drush/drushto^13.7for the command attribute API.
Test coverage
tests/src/Kernel/Commands/CanvasCommandsTest.php (kernel, 11 tests):
listreturns the expected columns and finds the test SDC component.statusreports state for every component, flags incompatibilities (non-zero exit), reports disabled components, resolves a single component by ID, and rejects an unknown ID.generaterecreates a deleted component, respects the--sourcefilter, 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