Vortos
Ops Kit

make:driver

Scaffold a driver, its conformance test, and an optional installable split package with vortos:make:driver.

make:driver

Writing a driver by hand means remembering the attribute, the capability descriptor skeleton, and the conformance test boilerplate every time. vortos:make:driver generates all of it from two arguments: the concern and the driver's key.

php bin/console vortos:make:driver deploy k8s \
  --port="App\Deploy\Target\DeployTargetInterface" \
  --tck="App\Deploy\Testing\DeployTargetConformanceTestCase"

This creates:

src/Deploy/Target/K8s/
├── K8sDriver.php
└── Tests/
    └── K8sDriverConformanceTest.php

Options

OptionDefaultPurpose
--portVortos\OpsKit\Driver\DriverInterfaceFQCN of the port interface the driver implements
--namespaceApp\<Concern>\DriverParent namespace for the generated class
--tckVortos\OpsKit\Testing\ConformanceTestCaseFQCN of the conformance base class the test extends
--tagvortos.<concern>.driverDI tag used by the concern's compiler pass
--dirderived from namespaceOutput directory
--order150extra.vortos.order written into a split package's composer.json
--splitoffAlso scaffold a full installable Composer package

Step-by-step

Generate the driver against your concern's actual port and TCK:

php bin/console vortos:make:driver backup s3-glacier \
  --port="App\Backup\Target\BackupTargetInterface" \
  --tck="App\Backup\Testing\BackupTargetConformanceTestCase"

Fill in capabilities() with what the driver honestly supports:

src/Backup/Target/S3Glacier/S3GlacierDriver.php
public function capabilities(): CapabilityDescriptor
{
    return CapabilityDescriptor::create(capabilities: [
        'point_in_time_restore' => false,
        'object_lock' => true,
    ]);
}

Implement the port's actual methods (deploy(), store(), notify() — whatever your port declares).

Wire registerForAutoconfiguration() in your concern's DI extension if this is the first driver for that port — the scaffolder prints the exact line to add:

$container->registerForAutoconfiguration(BackupTargetInterface::class)
    ->addTag('vortos.backup.target');

Run the generated conformance test. It already inherits the full TCK for that port — no test code to write beyond createDriver() and expectedKey(), which the scaffolder fills in for you:

./vendor/bin/phpunit src/Backup/Target/S3Glacier/Tests/S3GlacierDriverConformanceTest.php

Shipping a driver as its own package

Pass --split to scaffold a complete installable Composer package alongside the driver — useful when a driver depends on a provider SDK you don't want as a hard dependency of the core concern.

php bin/console vortos:make:driver analytics mixpanel --split
packages/Vortos/src/AnalyticsMixpanel/
├── composer.json
├── DependencyInjection/
│   ├── AnalyticsMixpanelPackage.php
│   └── AnalyticsMixpanelExtension.php
└── MixpanelDriver.php

The generated Extension calls setAutoconfigured(true) so the core concern's registerForAutoconfiguration() rule picks up the driver the moment the package is installed — there's no manual registration step on the consuming application's side. This is exactly the pattern AnalyticsPosthog and DeployK8s use.

Existing files are never overwritten

DriverScaffolder::write() skips any file that already exists rather than overwriting it. Re-running make:driver after hand-editing the generated class is safe.

On this page