Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion .github/workflows/contract.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
stack_ref: ${{ steps.locked.outputs.stack_ref }}
core_api_ref: ${{ steps.locked.outputs.core_api_ref }}
fleetops_ref: ${{ steps.locked.outputs.fleetops_ref }}
fleetops_source_ref: ${{ steps.locked.outputs.fleetops_source_ref }}
steps:
- id: check
env:
Expand Down Expand Up @@ -54,6 +55,7 @@ jobs:
echo "stack_ref=$(read_lock '.sources.fleetbase_stack.commit')"
echo "core_api_ref=$(read_lock '.sources.fleetbase_stack.core_api_submodule')"
echo "fleetops_ref=$(read_lock '.sources.fleetbase_stack.fleetops_submodule')"
echo "fleetops_source_ref=$(read_lock '.sources.fleetops.commit')"
} >> "$GITHUB_OUTPUT"

contract:
Expand All @@ -70,6 +72,7 @@ jobs:
POSTMAN_REF: ${{ needs.gate.outputs.postman_ref }}
CORE_API_REF: ${{ needs.gate.outputs.core_api_ref }}
FLEETOPS_REF: ${{ needs.gate.outputs.fleetops_ref }}
FLEETOPS_SOURCE_REF: ${{ needs.gate.outputs.fleetops_source_ref }}
SOURCE_TOKEN: ${{ secrets._GITHUB_AUTH_TOKEN || github.token }}
POSTMAN_API_KEY: ${{ secrets.POSTMAN_API_KEY }}
steps:
Expand Down Expand Up @@ -135,13 +138,45 @@ jobs:
set -uo pipefail
for attempt in $(seq 1 30); do
if curl --fail --silent --max-time 5 http://localhost:8000/health | grep -q '"status"'; then
echo "API is healthy."
echo "API is healthy (attempt $attempt)."
exit 0
fi
sleep 5
done
echo "::error::API did not become healthy."
exit 1
# Mirror the canonical api-contract.yml overlay sequence before seeding:
# replace package, rebuild classmap, migrate, clear caches, reload Octane.
- name: Checkout locked Fleet-Ops source for overlay
if: env.FLEETOPS_SOURCE_REF != env.FLEETOPS_REF
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: fleetbase/fleetops
ref: ${{ env.FLEETOPS_SOURCE_REF }}
path: .fleetops-overlay
persist-credentials: false
- name: Overlay locked Fleet-Ops implementation
if: env.FLEETOPS_SOURCE_REF != env.FLEETOPS_REF
run: |
set -euo pipefail
test "$(git -C .fleetops-overlay rev-parse HEAD)" = "$FLEETOPS_SOURCE_REF"
test -f .fleetops-overlay/composer.json
# The target is one package inside this runner's disposable container.
docker compose exec -T application sh -c 'rm -rf /fleetbase/api/vendor/fleetbase/fleetops-api && mkdir -p /fleetbase/api/vendor/fleetbase/fleetops-api'
tar --exclude=.git -C .fleetops-overlay -cf - . | docker compose exec -T application sh -c 'tar -C /fleetbase/api/vendor/fleetbase/fleetops-api -xf -'
docker compose exec -T application chown -R www-data:www-data /fleetbase/api/vendor/fleetbase/fleetops-api
docker compose exec -T application su www-data -s /bin/sh -c 'cd /fleetbase/api && composer dump-autoload --optimize --no-scripts'
docker compose exec -T application su www-data -s /bin/sh -c 'cd /fleetbase/api && php artisan optimize:clear && php artisan migrate --force && php artisan octane:reload'
echo "Fleet-Ops source under test: $FLEETOPS_SOURCE_REF" >> "$GITHUB_STEP_SUMMARY"
for attempt in $(seq 1 20); do
if curl --fail --silent --max-time 5 http://localhost:8000/health | grep -q '"status"'; then
echo "API healthy after overlay (attempt $attempt)."
exit 0
fi
sleep 3
done
echo "::error::API did not recover after the locked Fleet-Ops overlay."
exit 1
- name: Mint a fresh SDK smoke credential
env:
CI_CUSTOMER_IDENTITY: ci-customer@fleetbase.local
Expand Down Expand Up @@ -196,6 +231,7 @@ jobs:
echo $! > .sdk/build/live-contract/bridge.pid
for attempt in $(seq 1 20); do
if curl --fail --silent http://127.0.0.1:9000/__sdk_contract_health | grep -q '"status":"ok"'; then
echo "SDK bridge is healthy (attempt $attempt)."
exit 0
fi
sleep 1
Expand Down
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

## [1.4.0] - 2026-09-12

### Added

- Inspection Forms and Inspections services, including form reads, typed-answer submission, inspection retrieval/listing, and vehicle inspection history.
- Caller-supplied idempotency headers and direct-array inspection examples, with compatibility preserved against 1.3.0 and earlier baselines.

### Changed

- Updated the locked Postman inventory to all 270 requests and the disposable contract seed to include published inspection forms.
- Test the explicitly locked Fleet-Ops implementation using the canonical package-overlay, migration, cache-clear, and worker-reload sequence before fixture seeding.

## [1.3.0] - 2026-09-10

### Added
Expand Down Expand Up @@ -107,7 +119,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Latest baseline whose public API is explicitly preserved by 1.1.0.


[Unreleased]: https://github.com/fleetbase/fleetbase-php/compare/1.3.0...HEAD
[Unreleased]: https://github.com/fleetbase/fleetbase-php/compare/1.4.0...HEAD
[1.4.0]: https://github.com/fleetbase/fleetbase-php/compare/1.3.0...1.4.0
[1.3.0]: https://github.com/fleetbase/fleetbase-php/compare/1.2.0...1.3.0
[1.2.0]: https://github.com/fleetbase/fleetbase-php/compare/1.1.2...1.2.0
[1.1.2]: https://github.com/fleetbase/fleetbase-php/compare/1.1.1...1.1.2
Expand Down
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![Downloads](https://img.shields.io/packagist/dt/fleetbase/fleetbase-php.svg)](https://packagist.org/packages/fleetbase/fleetbase-php)
[![License: AGPL-3.0-or-later](https://img.shields.io/badge/license-AGPL--3.0--or--later-blue.svg)](LICENSE)

The official PHP client for the [Fleetbase API](https://fleetbase.io/docs/api). It supports Fleetbase Cloud and self-hosted installations, covers all 264 locked Fleetbase and Core API requests, and retains the public API used by earlier SDK releases.
The official PHP client for the [Fleetbase API](https://fleetbase.io/docs/api). It supports Fleetbase Cloud and self-hosted installations, covers all 270 locked Fleetbase and Core API requests, and retains the public API used by earlier SDK releases.

Version 1.1.0 changed the license to `AGPL-3.0-or-later`. Published 1.0.x tags remain under the MIT license shipped with those releases. Review the [migration guide](docs/migration-guide.md) before upgrading.

Expand Down Expand Up @@ -54,7 +54,7 @@ echo $place->id;

Never commit an API key. Load it from your runtime secret manager or environment.

Existing property access remains supported (`$fleetbase->orders`). Explicit accessors such as `$fleetbase->orders()` are available for static analysis and dependency injection. Browse [all 264 generated PHP examples](docs/api-examples.md); CI executes each exact snippet against a hermetic transport.
Existing property access remains supported (`$fleetbase->orders`). Explicit accessors such as `$fleetbase->orders()` are available for static analysis and dependency injection. Browse [all 270 generated PHP examples](docs/api-examples.md); CI executes each exact snippet against a hermetic transport.

### Endpoint arguments

Expand Down Expand Up @@ -107,6 +107,28 @@ $fleetbase->trailers->detachTrailerFromVehicle($trailer->id);

Attach devices and equipment through their own services, using `attachDevice($deviceId, $data)` and `attachEquipment($equipmentId, $data)`. Standard trailer CRUD also supports `createTrailer`, `retrieveTrailer`, `queryTrailers`, `updateTrailer`, and `deleteTrailer`.

### Inspections

Version 1.4.0 adds the driver-facing inspection API:

```php
$forms = $fleetbase->inspectionForms->listInspectionForms(['vehicle' => $vehicleId]);
$form = $fleetbase->inspectionForms->retrieveInspectionForm($formId);
$inspection = $fleetbase->inspections->submitInspection([
'inspection_form' => $formId,
'driver' => $driverId,
'vehicle' => $vehicleId,
'custom_field_values' => [
['custom_field' => $fieldId, 'value_type' => 'object', 'value' => ['passed' => true]],
],
], ['headers' => ['Idempotency-Key' => $submissionKey]]);
$inspection = $fleetbase->inspections->retrieveInspection($inspectionId);
$inspections = $fleetbase->inspections->listInspections(['driver' => $driverId]);
$history = $fleetbase->vehicles->listVehicleInspections($vehicleId, ['limit' => 30]);
```

Read the form's `grouped_fields` to obtain field IDs and required answer types. Reuse the same caller-generated idempotency key when replaying one submission; generate a new key for a new inspection. The SDK passes the key through to the API and does not implement its own deduplication. Forms are published in the console, not created through this public API. Form authoring, submission updates/deletion, and public inspection-link management are not supported public endpoints.

## Configuration

The second constructor argument accepts client configuration. The third legacy argument retains the debug flag without printing requests or credentials.
Expand Down Expand Up @@ -295,7 +317,7 @@ composer test:coverage

Tests are hermetic by default and must not use production credentials or mutate a shared API. CI enforces PHP 7.4–8.5 with lowest/latest dependencies, PHPStan at max level, generated-contract drift, compatibility snapshots, exact 100% line and branch coverage, consumer fixtures, security checks, and archive inspection. See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution requirements.

The separate `Disposable API contract` workflow uses Fleetbase's canonical contract bootstrap: it pulls the published Fleetbase API image, runs the non-interactive installer with the same CI configuration used by Core API and Fleet-Ops, and invokes Fleetbase's shared Postman seed-and-mint action. Both official collections are routed through a local PHP SDK bridge, and CI then proves all 220 locked requests invoked their mapped SDK methods. This is an isolated runner-local Fleetbase instance, not a production or shared API.
The separate `Disposable API contract` workflow uses Fleetbase's canonical contract bootstrap: it pulls the published Fleetbase API image and runs the non-interactive installer with the same CI configuration used by Core API and Fleet-Ops. When the contract lock specifies a newer Fleet-Ops source, CI overlays that exact revision, rebuilds the autoloader, migrates and reloads workers before invoking Fleetbase's shared seed-and-mint action. Both official collections are routed through a local PHP SDK bridge, and CI then proves all 270 locked requests invoked their mapped SDK methods. This is an isolated runner-local Fleetbase instance, not a production or shared API; a source-overlay run does not prove those endpoints are deployed in a published image.

## Security and support

Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@
"@php tools/check-api-compatibility.php --baseline=contracts/public-api-1.0.2.json --current=build/contracts/public-api-current.json",
"@php tools/check-api-compatibility.php --baseline=contracts/public-api-1.0.3.json --current=build/contracts/public-api-current.json",
"@php tools/check-api-compatibility.php --baseline=contracts/public-api-1.1.0.json --current=build/contracts/public-api-current.json",
"@php tools/check-api-compatibility.php --baseline=contracts/public-api-1.2.0.json --current=build/contracts/public-api-current.json"
"@php tools/check-api-compatibility.php --baseline=contracts/public-api-1.2.0.json --current=build/contracts/public-api-current.json",
"@php tools/check-api-compatibility.php --baseline=contracts/public-api-1.3.0.json --current=build/contracts/public-api-current.json"
],
"check": [
"@lint",
Expand Down
20 changes: 10 additions & 10 deletions contracts/contract-lock.json
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
{
"schema_version": 1,
"generated_at": "2026-09-09",
"generated_at": "2026-09-12",
"sdk_baselines": {
"required_compatibility": {
"version": "1.0.2",
"git_ref": "1.0.2",
"commit": "569fe88e0359d567f30588820243d1d69ab418ec"
},
"latest_published": {
"version": "1.2.0",
"git_ref": "1.2.0",
"commit": "3e8cf88e080936b5cf3eb8c13dd2f88d040c75bd"
"version": "1.3.0",
"git_ref": "1.3.0",
"commit": "3a9467b306d5fcd93d6adb6b02dfaf5ad4cd0158"
}
},
"sources": {
"fleetbase_stack": {
"repository": "https://github.com/fleetbase/fleetbase",
"ref": "origin/main",
"commit": "2612278517a56e5389e98c8fd08648e583c87226",
"commit": "a5dea4be5f048c8543e69209ada166ce2efd0870",
"core_api_submodule": "4c763ce293d2e794f9260aca11fb4b52413a74ac",
"fleetops_submodule": "2980fb39cd4ff58442d287907849efea3a2805ba"
},
"postman": {
"repository": "https://github.com/fleetbase/postman",
"ref": "origin/main",
"commit": "7fe06b7c5e415a9aa292869e9037910896b049ad",
"commit": "d6a7cc530fa27d7cf19a0d3ef8594cf4e51a76bb",
"scope": [
"Fleetbase API",
"Fleetbase Core API"
],
"expected_requests": 264,
"expected_groups": 37
"expected_requests": 270,
"expected_groups": 38
},
"core_api": {
"repository": "https://github.com/fleetbase/core-api",
Expand All @@ -39,8 +39,8 @@
},
"fleetops": {
"repository": "https://github.com/fleetbase/fleetops",
"ref": "origin/main",
"commit": "2980fb39cd4ff58442d287907849efea3a2805ba"
"ref": "refs/pull/319/head",
"commit": "0d11583d0484ad04761ca0cd6a1025cec4aed91c"
}
}
}
Loading
Loading