Spec: GitHub Actions Integration
Issue: MAR-40 Date: 2026-04-24 Status: In Review
Overview
Shipper provides workflow examples in the CLI repository and a composite action in shippercli/actions/.github/actions/shipper. The action sets up its own PHP and Composer runtime, installs the CLI and requested provider packages together in an isolated tool directory, and runs Shipper against the checked-out application.
The application does not need Shipper in its composer.json, composer.lock, or vendor directory.
Composite Action Inputs
| Input | Required | Default | Description |
|---|---|---|---|
command |
Yes | - | validate, plan, apply, status, logs, rollback, or destroy |
project |
No | - | Project name from shipper.yml |
profile |
No | - | Profile name such as production, staging, or preview |
force |
No | false |
Skip confirmation prompts |
release |
No | - | Provider release identifier for rollback |
lines |
No | - | Maximum log lines |
working-directory |
No | . |
Directory containing shipper.yml |
php-version |
No | 8.3 |
PHP used for the isolated Shipper installation |
cli-version |
No | ^1.0 |
Composer constraint for shippercli/cli |
providers |
Yes | - | Provider packages, one per line with an optional constraint |
Action Behavior
- Sets up PHP and Composer independently of the application.
- Canonicalizes and validates the provider package list.
- Installs
shippercli/cliand all providers in one isolated Composer tool directory. - Caches that tool installation by OS, PHP version, CLI constraint, and provider list.
- Confirms requested packages are visible as
shipper-pluginpackages through Composer'sInstalledVersions. - Runs
vendor/bin/shipper --version, allowlists the requested command, and passes inputs through environment variables and a bash argument array. - Runs from
working-directorywithout modifying the application's Composer files.
Reference
Pin consumers to a release tag or commit SHA, not main:
- uses: actions/checkout@v4
- uses: shippercli/actions/.github/actions/shipper@c2c276e12f831ba2c3377a063d579fede5cc5ecc
with:
command: apply
project: api
profile: production
force: true
cli-version: '^1.0'
providers: |
shippercli/provider-cpanel:^1.0
env:
CPANEL_API_TOKEN: ${{ secrets.CPANEL_API_TOKEN }}
Multiple published providers share one install. The package names below are illustrative:
providers: |
vendor/provider-one:^1.0
vendor/provider-two:^1.0
Functional Requirements
FR-001 - Isolated Composer installation
The action installs the CLI and providers outside the application checkout and runs that installation's vendor/bin/shipper.
FR-002 - Provider discovery
Every requested package must be installed with Composer type shipper-plugin and visible to Composer\\InstalledVersions in the CLI process.
FR-003 - Safe argument handling
Inputs are passed through env:; commands are allowlisted and arguments are built as a bash array. The action does not evaluate free-form shell input.
FR-004 - Cache isolation The cache key represents the action toolchain only and never hashes the application's lockfile.
FR-005 - Exit code propagation
The action writes exit-code to GITHUB_OUTPUT and returns the CLI exit code.
Edge Cases
- Empty provider lists fail before installation.
- Invalid package names and non-plugin packages fail with a clear error.
- Conflicting or unavailable Composer constraints fail the single Composer install.
- Unsupported commands fail before the CLI is invoked.
- A missing CLI binary or failed
--versioncheck fails the action. - Duplicate provider lines are deduplicated before installation and cache hashing.
Acceptance Criteria
- CLI and providers are installed together outside the application checkout.
- The action runs
$SHIPPER_HOME/vendor/bin/shipper, never a downloaded PHAR. - Application Composer files and
vendorare not modified. - Requested providers are confirmed through
InstalledVersions::getInstalledPackagesByType('shipper-plugin'). - Inputs use environment variables and argv;
commandis allowlisted. - Cache identity includes OS, PHP, CLI constraint, and canonical providers.
- Examples require
providersand pinshippercli/actionsto a tag or SHA. - Preview workflows pass
GITHUB_PR_NUMBERandGITHUB_HEAD_REF.
Open Questions
- Should the action publish immutable major tags such as
v1automatically when av1.x.yrelease is created? - Should reusable workflow examples be retained after consumers have migrated to the composite action?