Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Deployment Bundle Laravel Package

integrated/deployment-bundle

A Laravel deployment bundle that gathers common release tooling into one installable package: zero-downtime deploys, environment and configuration checks, release hooks, and rollback helpers for simpler, repeatable production deployments.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is not on Packagist, has zero stars, zero dependents, and a description that promises more than any public evidence supports. Treat the repository as the documentation and read the source before you wire it into anything real. Budget an hour for a spike.

1. Resolve the package from Bitbucket. Composer cannot find integrated/deployment-bundle in the default registry. You need an explicit repositories entry plus credentials (an app password or SSH key, typically injected via COMPOSER_AUTH in CI):

{
    "repositories": [
        { "type": "vcs", "url": "https://bitbucket.org/eactive/integrated-deployment-bundle.git" }
    ],
    "require": {
        "integrated/deployment-bundle": "dev-master#<commit-sha>"
    }
}

Pin to a tag or commit hash, never a branch. With no dependents there is no ecosystem pressure discouraging BC breaks on master.

2. Register it — and check which framework it actually targets. The package name and Bundle suffix follow Symfony convention, but the marketing copy talks about Artisan commands. Resolve that first:

  • If composer.json declares extra.laravel.providers, Laravel package discovery registers it automatically and you are done.
  • If it declares extra.symfony.bundle-class or a DependencyInjection/Extension.php, it is a Symfony bundle. Add it manually in config/bundles.php:
return [
    // ...
    Integrated\DeploymentBundle\IntegratedDeploymentBundle::class => ['all' => true],
];

If neither exists, it is probably a framework-agnostic CLI — install it in a separate Composer project or a CI image rather than the app's composer.json, so its dependency graph never fights your application's lockfile.

3. Read these files first, in this order:

cat vendor/integrated/deployment-bundle/composer.json   # PHP/Laravel/Symfony constraints, autoload
ls  vendor/integrated/deployment-bundle/src
grep -rn "AsCommand\|console.command\|protected \$signature" vendor/integrated/deployment-bundle/src
cat vendor/integrated/deployment-bundle/src/DependencyInjection/Configuration.php

Configuration.php (or the config/*.php file with mergeConfigFrom) is the authoritative option list. READMEs on low-traffic Bitbucket bundles drift constantly; the config tree does not.

4. Publish the config and list the commands.

php artisan vendor:publish --provider="Integrated\DeploymentBundle\DeploymentServiceProvider"
php artisan config:show deployment        # Laravel 11+; or config:dump-reference
php artisan list | grep -i deploy

First use case — a staging dry run. Do not let this package be the first thing a CI job runs against a real environment. Point it at a throwaway staging host, run the release command with maximum verbosity (-vvv), and watch what it actually executes:

php artisan deploy:release -vvv --env=staging

Confirm from the output that every step the description advertises (readiness checks, asset build, migrations, cache warm-up) genuinely fires, and note the order. That ordered list is the thing you will be maintaining.

Implementation Patterns

Keep the config shape in code and the values in the environment. Deployment config carries hostnames, paths and sometimes credentials. Commit config/deployment.php with the structure and %env()%/env() references only:

return [
    'releases_path'  => env('DEPLOY_RELEASES_PATH', '/var/www/app/releases'),
    'current_path'   => env('DEPLOY_CURRENT_PATH', '/var/www/app/current'),
    'keep_releases'  => (int) env('DEPLOY_KEEP_RELEASES', 5),
    'hooks' => [
        'pre_deploy'   => [\App\Deployment\BuildAssets::class],
        'post_deploy'  => [\App\Deployment\ReloadFpm::class],
    ],
    'checks' => [
        'php_version'   => '8.2',
        'writable_paths' => ['storage', 'bootstrap/cache'],
    ],
];

Never commit a populated deployment.php per-environment file. On config caching, remember php artisan config:cache freezes values — if the deploy command reads env at runtime, config:cache must run after the deploy, or the env must be present in the FPM pool, not just the deploy shell.

Wrap each deploy step in your own hook class rather than inlining shell. The bundle's extension point is its hook list. Own that boundary:

namespace App\Deployment;

class BuildAssets
{
    public function __invoke($context): void
    {
        $this->run('npm ci --omit=dev');
        $this->run('npm run build');
    }
}

Two payoffs: you can unit-test the hook in isolation, and if the bundle is abandoned you can re-point the same hooks at a hand-written Artisan command in an afternoon.

Model the release layout explicitly. Most bundles of this kind assume a releases/<timestamp> + current symlink + shared/ directory convention. Verify it against Configuration.php and make your .env, storage/, and public/uploads all resolve into shared/. If the bundle symlinks current but does not create the shared symlinks, do it in a pre_deploy hook — storage:link on a fresh release directory is the single most common cause of a "successful" deploy that 500s on first request.

Run migrations inside the release, never in place. Migrations must execute against the new release's code while the current symlink still points at the old release. If the bundle's ordering does that, good. If it symlinks first and migrates second, you have a live window where old workers run against a new schema — reorder via hooks. Always pass --force in a non-interactive context, and never let a deploy run migrate:fresh because an environment name was mistyped:

$this->artisan('migrate', ['--force' => true]);

Warm the cache deliberately, then reload the runtime. The correct tail of a deploy is:

php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
# then, outside the bundle:
php artisan queue:restart
systemctl reload php8.2-fpm   # or: kill -USR2 $(cat /run/php-fpm.pid)

queue:restart is easy to forget and produces the worst failure mode — new code is live, but long-running workers keep executing the old code for hours. opcache is worse: without an FPM reload, a symlink swap can leave you serving a stale bytecode cache. Neither is reliably the bundle's job; both belong in your post_deploy hook.

Drive it from CI, not from a laptop. The bundle should be one step in a pipeline triggered by a tagged release, with the deploy user's SSH key mounted as a CI secret:

- name: Deploy
  run: |
    ssh deploy@app-staging "cd /var/www/app && php artisan deploy:release -vvv"

Pass the target commit or release id if the bundle supports it; if it just deploys "whatever is in the working tree," your pipeline must ensure the host checks out the exact SHA before invoking it. A deploy tool that cannot be told what to deploy is a deploy tool that will eventually deploy the wrong thing.

Rehearse rollback before you need it. Run a release, introduce a trivial regression, then roll back on staging and confirm: the symlink flips, the previous release is still intact, keep_releases retains what you expect, and the rollback does not attempt to reverse migrations (almost none do). Write the migration-down strategy into your runbook separately.

Gotchas and Tips

The framework mismatch is the risk, not a detail. If this is a Symfony bundle, its console commands are bin/console commands, not php artisan commands, and its Configuration.php/Extension classes have no Laravel equivalent. Confirm which before you spend a sprint. If it is Symfony-only, the pragmatic pattern is to run it as a standalone tool in CI against the target host and keep it out of the app's composer.json entirely.

Zero dependents means zero field-testing. There is no issue tracker history, no Stack Overflow corpus, no one to ask. Every behavior you rely on, you must verify on staging yourself. Write those verifications down; the next developer will not have your memory.

Dependency conflicts are the quiet killer. A deployment tool sharing your application's composer.lock can pin a Symfony component or symfony/console version that blocks a routine framework upgrade two months later. If you hit any resolution conflict — or just want insurance — install the bundle in a dedicated Composer project on the deploy host or in a CI image, and invoke it through a wrapper script.

Hook idempotency is not guaranteed. Assume every hook may run twice after a partial failure. Guard destructive steps:

if (is_link($this->currentPath()) && readlink($this->currentPath()) === $releasePath) {
    return; // already swapped
}

Partial deploys are the failure mode to design against. If the symlink flips but config:cache fails, you are serving cached config from the old release against new code. Wrap the tail of the deploy so a failed cache warm-up automatically reverts the symlink, or at minimum exits non-zero loudly so CI marks the release failed.

Non-interactive environment is not the same environment. The deploy shell often lacks the FPM pool's environment variables, its PATH, and its APP_ENV. Anything reading env() inside a hook at deploy time can see a different value than at request time. Prefer values baked into config/ and cached, and validate with a readiness check that compares the two.

Readiness checks are only useful if they are specific. "PHP version matches" and "storage is writable" catch real problems. "Database connection works" usually just duplicates what the migration will tell you. Write one check for the thing that bit you last quarter — disk space, a required extension, a missing shared directory, a certificate expiry — and keep the list short enough that people still read it.

Beware secrets in config dumps. config:show and config:dump-reference will happily print anything the bundle stores in the config tree. Before you paste that output into a ticket, scan it for hostnames, keys and tokens.

Verbosity is your debugger. When a step silently does nothing, -vvv plus the Symfony/Laravel process output is the fastest path. If the bundle swallows subprocess output, that is itself a reason to fork it — a deploy tool that hides npm run build failures is actively dangerous.

Fork it deliberately, early. With no maintainer visible, plan for ownership from day one: pin the commit, keep hooks in your own namespace, and keep the config in your repo. If the package turns out to be solid, you have lost almost nothing. If it turns out to be abandoned, you convert your hook classes into an internal Artisan command and drop the dependency — which is exactly the outcome a one-week spike should have been testing for.

Log every deploy to somewhere durable. Release id, commit SHA, operator, start/end times, steps run, outcome. The bundle's release history is convenient for rollback but insufficient for post-incident review; ship those records to your log aggregator as part of the post_deploy hook.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console