Showing preview only (1,094K chars total). Download the full file or copy to clipboard to get everything.
Repository: deployphp/deployer
Branch: master
Commit: 6e15e217ae5f
Files: 338
Total size: 1014.5 KB
Directory structure:
gitextract_pd_hfplz/
├── .gitattributes
├── .github/
│ ├── DISCUSSION_TEMPLATE/
│ │ └── bugs.yml
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ └── config.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── labeler.yml
│ └── workflows/
│ ├── check.yml
│ ├── docker.yml
│ ├── docs-sync.yml
│ ├── docs.yml
│ ├── labeler.yml
│ ├── lint.yml
│ ├── release.yml
│ ├── stale.yml
│ └── test.yml
├── .gitignore
├── .php-cs-fixer.dist.php
├── Dockerfile
├── LICENSE
├── README.md
├── SECURITY.md
├── bin/
│ ├── build
│ ├── dep
│ └── docgen
├── composer.json
├── contrib/
│ ├── bugsnag.php
│ ├── cachetool.php
│ ├── chatwork.php
│ ├── cimonitor.php
│ ├── cloudflare.php
│ ├── cpanel.php
│ ├── crontab.php
│ ├── directadmin.php
│ ├── discord.php
│ ├── grafana.php
│ ├── hangouts.php
│ ├── hipchat.php
│ ├── ispmanager.php
│ ├── mattermost.php
│ ├── ms-teams.php
│ ├── newrelic.php
│ ├── npm.php
│ ├── ntfy.php
│ ├── phinx.php
│ ├── php-fpm.php
│ ├── rabbit.php
│ ├── raygun.php
│ ├── rocketchat.php
│ ├── rollbar.php
│ ├── rsync.php
│ ├── sentry.php
│ ├── slack.php
│ ├── supervisord-monitor.php
│ ├── telegram.php
│ ├── webpack_encore.php
│ ├── workplace.php
│ ├── yammer.php
│ └── yarn.php
├── docs/
│ ├── KNOWN_BUGS.md
│ ├── UPGRADE.md
│ ├── api.md
│ ├── avoid-php-fpm-reloading.md
│ ├── basics.md
│ ├── ci-cd.md
│ ├── cli.md
│ ├── contrib/
│ │ ├── README.md
│ │ ├── bugsnag.md
│ │ ├── cachetool.md
│ │ ├── chatwork.md
│ │ ├── cimonitor.md
│ │ ├── cloudflare.md
│ │ ├── cpanel.md
│ │ ├── crontab.md
│ │ ├── directadmin.md
│ │ ├── discord.md
│ │ ├── grafana.md
│ │ ├── hangouts.md
│ │ ├── hipchat.md
│ │ ├── ispmanager.md
│ │ ├── mattermost.md
│ │ ├── ms-teams.md
│ │ ├── newrelic.md
│ │ ├── npm.md
│ │ ├── ntfy.md
│ │ ├── phinx.md
│ │ ├── php-fpm.md
│ │ ├── rabbit.md
│ │ ├── raygun.md
│ │ ├── rocketchat.md
│ │ ├── rollbar.md
│ │ ├── rsync.md
│ │ ├── sentry.md
│ │ ├── slack.md
│ │ ├── supervisord-monitor.md
│ │ ├── telegram.md
│ │ ├── webpack_encore.md
│ │ ├── workplace.md
│ │ ├── yammer.md
│ │ └── yarn.md
│ ├── getting-started.md
│ ├── hosts.md
│ ├── installation.md
│ ├── recipe/
│ │ ├── README.md
│ │ ├── cakephp.md
│ │ ├── codeigniter.md
│ │ ├── codeigniter4.md
│ │ ├── common.md
│ │ ├── composer.md
│ │ ├── contao.md
│ │ ├── craftcms.md
│ │ ├── deploy/
│ │ │ ├── check_remote.md
│ │ │ ├── cleanup.md
│ │ │ ├── clear_paths.md
│ │ │ ├── copy_dirs.md
│ │ │ ├── env.md
│ │ │ ├── info.md
│ │ │ ├── lock.md
│ │ │ ├── push.md
│ │ │ ├── release.md
│ │ │ ├── rollback.md
│ │ │ ├── setup.md
│ │ │ ├── shared.md
│ │ │ ├── symlink.md
│ │ │ ├── update_code.md
│ │ │ ├── vendors.md
│ │ │ └── writable.md
│ │ ├── drupal7.md
│ │ ├── drupal8.md
│ │ ├── flow_framework.md
│ │ ├── fuelphp.md
│ │ ├── joomla.md
│ │ ├── laravel.md
│ │ ├── magento.md
│ │ ├── magento2.md
│ │ ├── pimcore.md
│ │ ├── prestashop.md
│ │ ├── provision/
│ │ │ ├── databases.md
│ │ │ ├── nodejs.md
│ │ │ ├── php.md
│ │ │ ├── user.md
│ │ │ └── website.md
│ │ ├── provision.md
│ │ ├── shopware.md
│ │ ├── silverstripe.md
│ │ ├── spiral.md
│ │ ├── statamic.md
│ │ ├── sulu.md
│ │ ├── symfony.md
│ │ ├── typo3.md
│ │ ├── wordpress.md
│ │ ├── yii.md
│ │ └── zend_framework.md
│ ├── selector.md
│ ├── sidebar.js
│ ├── tasks.md
│ └── yaml.md
├── phpstan.neon
├── phpunit.xml
├── recipe/
│ ├── cakephp.php
│ ├── codeigniter.php
│ ├── codeigniter4.php
│ ├── common.php
│ ├── composer.php
│ ├── contao.php
│ ├── craftcms.php
│ ├── deploy/
│ │ ├── check_remote.php
│ │ ├── cleanup.php
│ │ ├── clear_paths.php
│ │ ├── copy_dirs.php
│ │ ├── env.php
│ │ ├── info.php
│ │ ├── lock.php
│ │ ├── push.php
│ │ ├── release.php
│ │ ├── rollback.php
│ │ ├── setup.php
│ │ ├── shared.php
│ │ ├── symlink.php
│ │ ├── update_code.php
│ │ ├── vendors.php
│ │ └── writable.php
│ ├── drupal7.php
│ ├── drupal8.php
│ ├── flow_framework.php
│ ├── fuelphp.php
│ ├── joomla.php
│ ├── laravel.php
│ ├── magento.php
│ ├── magento2.php
│ ├── pimcore.php
│ ├── prestashop.php
│ ├── provision/
│ │ ├── 404.html
│ │ ├── Caddyfile
│ │ ├── databases.php
│ │ ├── nodejs.php
│ │ ├── php.php
│ │ ├── user.php
│ │ └── website.php
│ ├── provision.php
│ ├── shopware.php
│ ├── silverstripe.php
│ ├── spiral.php
│ ├── statamic.php
│ ├── sulu.php
│ ├── symfony.php
│ ├── typo3.php
│ ├── wordpress.php
│ ├── yii.php
│ └── zend_framework.php
├── src/
│ ├── Collection/
│ │ └── Collection.php
│ ├── Command/
│ │ ├── BlackjackCommand.php
│ │ ├── CommandCommon.php
│ │ ├── ConfigCommand.php
│ │ ├── CustomOption.php
│ │ ├── InitCommand.php
│ │ ├── MainCommand.php
│ │ ├── RunCommand.php
│ │ ├── SelectCommand.php
│ │ ├── SshCommand.php
│ │ ├── TreeCommand.php
│ │ └── WorkerCommand.php
│ ├── Component/
│ │ ├── PharUpdate/
│ │ │ ├── Console/
│ │ │ │ ├── Command.php
│ │ │ │ └── Helper.php
│ │ │ ├── Exception/
│ │ │ │ ├── Exception.php
│ │ │ │ ├── ExceptionInterface.php
│ │ │ │ ├── FileException.php
│ │ │ │ ├── InvalidArgumentException.php
│ │ │ │ └── LogicException.php
│ │ │ ├── Manager.php
│ │ │ ├── Manifest.php
│ │ │ ├── Update.php
│ │ │ └── Version/
│ │ │ ├── Builder.php
│ │ │ ├── Comparator.php
│ │ │ ├── Dumper.php
│ │ │ ├── Exception/
│ │ │ │ ├── InvalidIdentifierException.php
│ │ │ │ ├── InvalidNumberException.php
│ │ │ │ ├── InvalidStringRepresentationException.php
│ │ │ │ └── VersionException.php
│ │ │ ├── Parser.php
│ │ │ ├── Validator.php
│ │ │ └── Version.php
│ │ └── Pimple/
│ │ ├── Container.php
│ │ └── Exception/
│ │ ├── ExpectedInvokableException.php
│ │ ├── FrozenServiceException.php
│ │ ├── InvalidServiceIdentifierException.php
│ │ └── UnknownIdentifierException.php
│ ├── Configuration.php
│ ├── Deployer.php
│ ├── Documentation/
│ │ ├── ApiGen.php
│ │ ├── DocConfig.php
│ │ ├── DocGen.php
│ │ ├── DocRecipe.php
│ │ └── DocTask.php
│ ├── Exception/
│ │ ├── ConfigurationException.php
│ │ ├── Exception.php
│ │ ├── GracefulShutdownException.php
│ │ ├── HttpieException.php
│ │ ├── RunException.php
│ │ ├── TimeoutException.php
│ │ └── WillAskUser.php
│ ├── Executor/
│ │ ├── Master.php
│ │ ├── Messenger.php
│ │ ├── Planner.php
│ │ ├── Response.php
│ │ ├── Server.php
│ │ └── Worker.php
│ ├── Host/
│ │ ├── Host.php
│ │ ├── HostCollection.php
│ │ ├── Localhost.php
│ │ └── Range.php
│ ├── Importer/
│ │ └── Importer.php
│ ├── Logger/
│ │ ├── Handler/
│ │ │ ├── FileHandler.php
│ │ │ ├── HandlerInterface.php
│ │ │ └── NullHandler.php
│ │ └── Logger.php
│ ├── ProcessRunner/
│ │ ├── Printer.php
│ │ └── ProcessRunner.php
│ ├── Selector/
│ │ └── Selector.php
│ ├── Ssh/
│ │ ├── IOArguments.php
│ │ ├── RunParams.php
│ │ └── SshClient.php
│ ├── Support/
│ │ ├── ObjectProxy.php
│ │ ├── Reporter.php
│ │ └── helpers.php
│ ├── Task/
│ │ ├── Context.php
│ │ ├── GroupTask.php
│ │ ├── ScriptManager.php
│ │ ├── Task.php
│ │ └── TaskCollection.php
│ ├── Utility/
│ │ ├── Httpie.php
│ │ └── Rsync.php
│ ├── functions.php
│ └── schema.json
└── tests/
├── bootstrap.php
├── fixtures/
│ ├── project/
│ │ └── uploaded.html
│ └── repository/
│ ├── README.md
│ ├── composer.json
│ └── uploads/
│ └── poem.txt
├── joy/
│ ├── HostDefaultConfigTest.php
│ ├── JoyTest.php
│ └── OnFuncTest.php
├── legacy/
│ ├── AbstractTest.php
│ ├── CurrentPathTest.php
│ ├── DeployTest.php
│ ├── EnvTest.php
│ ├── NamedArgumentsTest.php
│ ├── OncePerNodeTest.php
│ ├── OnceTest.php
│ ├── ParallelTest.php
│ ├── SelectTest.php
│ ├── UpdateCodeTest.php
│ ├── YamlTest.php
│ └── recipe/
│ ├── deploy.php
│ ├── deploy.yaml
│ ├── env.php
│ ├── once.php
│ ├── once_per_node.php
│ ├── parallel.php
│ ├── select.php
│ └── update_code.php
├── phpstan-baseline.neon
└── src/
├── Collection/
│ └── CollectionTest.php
├── Command/
│ └── BlackjackCommandTest.php
├── Component/
│ └── Pimple/
│ └── PimpleTest.php
├── Configuration/
│ └── ConfigurationTest.php
├── DeployerTest.php
├── FunctionsTest.php
├── Host/
│ ├── ConfigurationTest.php
│ ├── HostTest.php
│ └── RangeTest.php
├── Importer/
│ └── ImporterTest.php
├── Selector/
│ └── SelectorTest.php
├── Ssh/
│ └── IOArgumentsTest.php
├── Support/
│ ├── HelpersTest.php
│ └── ObjectProxyTest.php
└── Task/
├── ContextTest.php
├── ScriptManagerTest.php
└── TaskTest.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
/.gitattributes export-ignore
/.github/ export-ignore
/.gitignore export-ignore
/docs/ export-ignore
/phpcs.xml export-ignore
/phpstan.neon export-ignore
/phpunit.xml export-ignore
/tests/ export-ignore
================================================
FILE: .github/DISCUSSION_TEMPLATE/bugs.yml
================================================
body:
- type: markdown
attributes:
value: |
**Before opening a bug report, please search the existing discussions.**
- type: input
id: deployer-version
attributes:
label: Deployer Version
description: Which version of Deployer are you using? Please provide the full version.
placeholder: v8.0.0
validations:
required: true
- type: input
id: target-os
attributes:
label: Target OS
description: Which operating system are you using? Please provide the full version.
placeholder: Ubuntu 24.04
validations:
required: true
- type: dropdown
id: php-version
attributes:
label: Which PHP version are you using?
options:
- PHP 8.5
- PHP 8.4
- PHP 8.3
- PHP 8.2
- PHP 8.1
- PHP 8.0
- PHP 7.4
- PHP 7.3
- PHP 7.2
- PHP 7.1
- PHP 7.0
- PHP 5.6
- PHP 5.5
- PHP 5.4
- PHP 5.3
validations:
required: true
- type: textarea
id: deploy-src
attributes:
label: Content of deploy.php or deploy.yaml
description: Please, provide a minimal reproducible example of deploy.php or deploy.yaml file.
validations:
required: false
- type: textarea
attributes:
label: Steps to reproduce
description: Please provide the steps to reproduce the bug.
validations:
required: true
================================================
FILE: .github/FUNDING.yml
================================================
github: antonmedv
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Bug Report
url: https://github.com/deployphp/deployer/discussions/new?category=bugs
about: Submit a bug or an issue
- name: Feature request
url: https://github.com/deployphp/deployer/discussions/new?category=features
about: For ideas or feature requests
- name: Support questions & other
url: https://github.com/deployphp/deployer/discussions/new?category=help-needed
about: If you have a question or need help using the library
- name: General discussion
url: https://github.com/deployphp/deployer/discussions/new?category=general
about: Start a new discussion
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
- [ ] Bug fix #…?
- [ ] New feature?
- [ ] BC breaks?
- [ ] Tests added?
- [ ] Docs added?
Please, regenerate docs by running next command:
$ php bin/docgen
================================================
FILE: .github/labeler.yml
================================================
v7:
- base-branch: "7.x"
================================================
FILE: .github/workflows/check.yml
================================================
name: check
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
phpstan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Validate composer.json and composer.lock
run: composer validate
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress
- name: Run test suite
run: composer phpstan
code-style:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Validate composer.json and composer.lock
run: composer validate
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress
- name: Run php-cs-fixer
run: composer check
================================================
FILE: .github/workflows/docker.yml
================================================
name: docker
on:
release:
types: [ published ]
workflow_dispatch:
inputs:
version:
description: 'Version'
required: true
permissions:
id-token: write
attestations: write
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Get version
run: |
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV
if [ -n "$VERSION" ]; then
echo "RELEASE_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
fi
env:
VERSION: ${{ inputs.version }}
- name: Build phar
run: php -d phar.readonly=0 bin/build -v"$RELEASE_VERSION"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: deployphp/deployer
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha,format=long
type=sha
type=semver,pattern=v{{major}}.{{minor}}.{{patch}}
type=semver,pattern=v{{major}}.{{minor}}
type=semver,pattern=v{{major}}
type=ref,event=tag
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: deployphp
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
provenance: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
================================================
FILE: .github/workflows/docs-sync.yml
================================================
name: doc-sync
on:
push:
branches: [ master ]
permissions:
contents: write
jobs:
docgen-and-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress
- name: Run docgen
run: php bin/docgen
- name: Add & Commit
uses: EndBug/add-and-commit@v9
with:
default_author: github_actions
add: 'docs'
message: '[automatic] Update docs with bin/docgen'
================================================
FILE: .github/workflows/docs.yml
================================================
name: doc
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
docgen:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress
- name: Run docgen
run: php bin/docgen
- name: Check for uncommitted changes
run: |
status=$(git status --porcelain docs/);
[ -z "$status" ] || {
echo "Please, run bin/docgen and commit next files:";
echo $status;
exit 1;
}
================================================
FILE: .github/workflows/labeler.yml
================================================
name: labeler
on:
- pull_request_target
jobs:
labeler:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v6
================================================
FILE: .github/workflows/lint.yml
================================================
name: lint
on:
push:
branches: [ master ]
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
jobs:
lint:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: [ '8.2' ]
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
tools: cs2pr, parallel-lint
- name: Lint sources
run: composer exec --no-interaction -- parallel-lint bin/ contrib/ recipe/ src/ tests/ --checkstyle | cs2pr
================================================
FILE: .github/workflows/release.yml
================================================
name: release
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: 'Version'
required: true
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get version
run: |
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV
if [ -n "$VERSION" ]; then
echo "RELEASE_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
fi
env:
VERSION: ${{ inputs.version }}
- name: Build phar
run: php -d phar.readonly=0 bin/build -v"$RELEASE_VERSION"
- name: Sign phar
run: |
mkdir -p ~/.gnupg/
chmod 0700 ~/.gnupg/
echo "$GPG_SIGNING_KEY" > ~/.gnupg/private.key
gpg --import --no-tty --batch --yes ~/.gnupg/private.key
gpg -u anton@deployer.org --batch --pinentry-mode loopback --passphrase "${GPG_PASSPHRASE}" --detach-sign --output deployer.phar.asc deployer.phar
env:
GPG_SIGNING_KEY: |
${{ secrets.GPG_SIGNING_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
- name: Upload phar
run: gh release upload v"${RELEASE_VERSION}" deployer.phar
env:
GH_TOKEN: ${{ github.token }}
- name: Upload signature
run: gh release upload v"${RELEASE_VERSION}" deployer.phar.asc
env:
GH_TOKEN: ${{ github.token }}
================================================
FILE: .github/workflows/stale.yml
================================================
name: stale
on:
schedule:
- cron: "* * * * *"
workflow_dispatch:
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/stale@v9
with:
days-before-issue-stale: 0
days-before-issue-close: 0
ignore-updates: true
close-issue-message: |
This issue has been automatically closed. Please, open a discussion for bug reports and feature requests.
Read more: https://github.com/deployphp/deployer/discussions/3888
days-before-pr-stale: -1
days-before-pr-close: -1
operations-per-run: 1440
================================================
FILE: .github/workflows/test.yml
================================================
name: test
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
unit:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: [ '8.2', '8.3' ]
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, intl
coverage: xdebug
- name: Validate composer.json and composer.lock
run: composer validate
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress
- name: Run test suite
run: composer test
================================================
FILE: .gitignore
================================================
/vendor/
*.phar
.phpunit.result.cache
docker-compose.override.yml
.php-cs-fixer.cache
.idea/
================================================
FILE: .php-cs-fixer.dist.php
================================================
<?php
$finder = (new PhpCsFixer\Finder())
->in(__DIR__ . '/src')
->in(__DIR__ . '/recipe')
->in(__DIR__ . '/contrib')
->in(__DIR__ . '/tests');
return (new PhpCsFixer\Config())
->setRules([
'@PER-CS' => true,
// Due to historical reasons we have to keep this.
// Docs parser expects comment right after php tag.
'blank_line_after_opening_tag' => false,
// For PHP 7.4 compatibility.
'trailing_comma_in_multiline' => [
'elements' => ['arguments', 'array_destructuring', 'arrays']
],
])
->setFinder($finder);
================================================
FILE: Dockerfile
================================================
FROM php:8.4-cli-alpine
RUN apk add --no-cache bash git openssh-client rsync zip unzip libzip-dev \
RUN docker-php-ext-install mbstring mcrypt pcntl sockets curl zip
COPY --chmod=755 deployer.phar /bin/dep
WORKDIR /app
ENTRYPOINT ["/bin/dep"]
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright © 2013 Anton Medvedev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
<h1>
<a href="https://deployer.org">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://deployer.org/img/logo-white.svg" height="30">
<img src="https://deployer.org/img/logo.svg" alt="Deployer Logo" height="30">
</picture>
</a>
Deployer
</h1>
<p>The PHP deployment tool with support for popular frameworks out of the box.</p>
<p align="center"><br><br><a href="https://deployer.org"><img src="https://medv.io/assets/deployer/deployer.gif" alt="Deployer Screenshot" width="530"></a><br><br><br></p>
---
<p style="font-size: 21px; color:black;">
Browser testing via<br>
<a href="https://www.testmu.ai" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset=".github/testmu-black-logo.png" width="800">
<img src=".github/testmu-white-logo.png" alt="Testmu AI" width="800">
</picture>
</a>
</p>
---
<a href="https://github.com/deployphp/deployer/actions?query=workflow%3Atest"><img src="https://github.com/deployphp/deployer/workflows/test/badge.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/deployer/deployer"><img src="https://img.shields.io/packagist/v/deployer/deployer.svg?style=flat" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/deployer/deployer"><img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat" alt="License"></a>
See [deployer.org](https://deployer.org) for more information and documentation.
## Features
- Automatic server **provisioning**.
- **Zero downtime** deployments.
- Ready to use recipes for **most frameworks**.
## Additional resources
* [GitHub Action for Deployer](https://github.com/deployphp/action)
* [Deployer Docker Image](https://hub.docker.com/r/deployphp/deployer)
## License
[MIT](https://github.com/deployphp/deployer/blob/master/LICENSE)
<p align="center">
<a href="https://crow.watch/join/deployer">
<img src="https://github.com/user-attachments/assets/37c84073-6533-4746-951d-d879f90a7fd2" alt="Join Crow Watch" width="900" hight="600">
</a>
</p>
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Supported Versions
Deployer is generally backwards compatible with very few exceptions, so we
recommend users to always use the latest version to experience stability,
performance and security.
We generally backport security issues to a single previous major version,
unless this is not possible or feasible with a reasonable effort.
| Version | Supported |
|---------|--------------------|
| 8 | :white_check_mark: |
| 7 | :white_check_mark: |
| < 7 | :x: |
## Reporting a Vulnerability
If you believe you've discovered a serious vulnerability, please contact the
Expr core team at anton+security@medv.io. We will evaluate your report and if
necessary issue a fix and an advisory. If the issue was previously undisclosed,
we'll also mention your name in the credits.
================================================
FILE: bin/build
================================================
#!/usr/bin/env php
<?php
/* (c) Anton Medvedev <anton@medv.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (ini_get('phar.readonly') === '1') {
throw new \Exception('Writing to phar files is disabled. Change your `php.ini` or append `-d phar.readonly=false` to the shebang, if supported by your `env` executable.');
}
define('__ROOT__', realpath(__DIR__ . '/..'));
chdir(__ROOT__);
$opt = getopt('v:', ['nozip']);
$version = $opt['v'] ?? null;
if (empty($version)) {
echo "Please, specify version as \"-v8.0.0\".\n";
exit(1);
}
if (!preg_match('/^\d+\.\d+\.\d+(\-\w+(\.\d+)?)?$/', $version)) {
echo "Version must be \"7.0.0-beta.42\". Got \"$version\".\n";
exit(1);
}
echo `set -x; composer install --no-dev --prefer-dist --optimize-autoloader`;
$pharName = "deployer.phar";
$pharFile = __ROOT__ . '/' . $pharName;
if (file_exists($pharFile)) {
unlink($pharFile);
}
$ignore = [
'.anton',
'.git',
'Tests',
'tests',
'deploy.php',
'.php-cs-fixer.dist.php',
];
$phar = new \Phar($pharFile, 0, $pharName);
$phar->setSignatureAlgorithm(\Phar::SHA1);
$phar->startBuffering();
$iterator = new RecursiveDirectoryIterator(__ROOT__, FilesystemIterator::SKIP_DOTS);
$iterator = new RecursiveCallbackFilterIterator($iterator, function (SplFileInfo $fileInfo) use ($ignore) {
return !in_array($fileInfo->getBasename(), $ignore, true);
});
$iterator = new RecursiveIteratorIterator($iterator);
$iterator = new CallbackFilterIterator($iterator, function (SplFileInfo $fileInfo) {
//'bash', 'fish', 'zsh' is a completion templates
return in_array($fileInfo->getExtension(), ['php', 'exe', 'bash', 'fish', 'zsh'], true);
});
foreach ($iterator as $fileInfo) {
$file = str_replace(__ROOT__, '', $fileInfo->getRealPath());
echo "+ " . $file . "\n";
$phar->addFile($fileInfo->getRealPath(), $file);
if (!array_key_exists('nozip', $opt)) {
$phar[$file]->compress(Phar::GZ);
if (!$phar[$file]->isCompressed()) {
echo "Could not compress File: $file\n";
}
}
}
// Add Caddyfile
echo "+ /recipe/provision/Caddyfile\n";
$phar->addFile(realpath(__DIR__ . '/../recipe/provision/Caddyfile'), '/recipe/provision/Caddyfile');
// Add 404.html
echo "+ /recipe/provision/404.html\n";
$phar->addFile(realpath(__DIR__ . '/../recipe/provision/404.html'), '/recipe/provision/404.html');
// Add bin/dep file
echo "+ /bin/dep\n";
$depContent = file_get_contents(__ROOT__ . '/bin/dep');
$depContent = str_replace("#!/usr/bin/env php\n", '', $depContent);
$depContent = str_replace('__FILE__', 'str_replace("phar://", "", Phar::running())', $depContent);
$depContent = preg_replace("/run\('.+?'/", "run('$version'", $depContent);
$phar->addFromString('bin/dep', $depContent);
$phar->setStub(
<<<STUB
#!/usr/bin/env php
<?php
Phar::mapPhar('{$pharName}');
require 'phar://{$pharName}/bin/dep';
__HALT_COMPILER();
STUB
);
$phar->stopBuffering();
unset($phar);
echo "$pharName was created successfully.\n";
================================================
FILE: bin/dep
================================================
#!/usr/bin/env php
<?php
/* (c) Anton Medvedev <anton@medv.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
// Check PHP version
if (PHP_VERSION_ID < 80200) {
fwrite(STDERR, "PHP 8.2 or higher is required.\n");
exit(1);
}
// Detect deploy.php location
$deployFile = null;
foreach ($argv as $i => $arg) {
if (preg_match('/^(-f|--file)$/', $arg, $match) && $i + 1 < count($argv)) {
$deployFile = $argv[$i + 1];
break;
}
if (preg_match('/^--file=(?<file>.+)$/', $arg, $match)) {
$deployFile = $match['file'];
break;
}
if (preg_match('/^-f=?(?<file>.+)$/', $arg, $match)) {
$deployFile = $match['file'];
break;
}
}
if (!empty($deployFile)) {
$deployFile = realpath($deployFile);
}
$lookUp = function (string $name): ?string {
$dir = getcwd();
for ($i = 0; $i < 10; $i++) {
$path = "$dir/$name";
if (is_readable($path)) {
return $path;
}
$dir = dirname($dir);
}
return '';
};
if (empty($deployFile)) {
$deployFile = $lookUp('deploy.php');
}
if (empty($deployFile)) {
$deployFile = $lookUp('deploy.yaml');
}
if (empty($deployFile)) {
$deployFile = $lookUp('deploy.yml');
}
// Detect autoload location
$autoload = [
__DIR__ . '/../vendor/autoload.php', // The dep located at "deployer.phar/bin" or in development.
__DIR__ . '/../../../autoload.php', // The dep located at "vendor/deployer/deployer/bin".
__DIR__ . '/../autoload.php', // The dep located at "vendor/bin".
];
$includes = [
__DIR__ . '/..',
__DIR__ . '/../../../deployer/deployer',
__DIR__ . '/../deployer/deployer',
];
$includePath = false;
for ($i = 0; $i < count($autoload); $i++) {
if (file_exists($autoload[$i]) && is_dir($includes[$i])) {
require $autoload[$i];
$includePath = $includes[$i];
break;
}
}
if (empty($includePath)) {
fwrite(STDERR, "Error: The `autoload.php` file not found in:\n");
for ($i = 0; $i < count($autoload); $i++) {
$a = file_exists($autoload[$i]) ? 'true' : 'false';
$b = is_dir($includes[$i]) ? 'true' : 'false';
fwrite(STDERR, " - file_exists($autoload[$i]) = $a\n");
fwrite(STDERR, " is_dir($includes[$i]) = $b\n");
}
exit(1);
}
// Errors to exception
set_error_handler(function ($severity, $message, $filename, $lineno) {
if (error_reporting() == 0) {
return;
}
if (error_reporting() & $severity) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
});
// Enable recipe loading
set_include_path($includePath . PATH_SEPARATOR . get_include_path());
// Deployer constants
define('DEPLOYER', true);
define('DEPLOYER_BIN', __FILE__);
define('DEPLOYER_DEPLOY_FILE', $deployFile);
Deployer\Deployer::run('master', $deployFile);
================================================
FILE: bin/docgen
================================================
#!/usr/bin/env php
<?php
/* (c) Anton Medvedev <anton@medv.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Deployer;
use Deployer\Documentation\ApiGen;
use Deployer\Documentation\DocGen;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;
require __DIR__ . '/../vendor/autoload.php';
chdir(realpath(__DIR__ . '/..'));
$input = new ArgvInput();
$output = new ConsoleOutput();
$app = new Application('DocGen', '1.0.0');
$app->setDefaultCommand('all');
$api = function () use ($output) {
$parser = new ApiGen();
$parser->parse(file_get_contents(__DIR__ . '/../src/functions.php'));
$md = $parser->markdown();
file_put_contents(__DIR__ . '/../docs/api.md', $md);
$output->writeln('API Reference documentation updated.');
};
$recipes = function () use ($input, $output) {
$docgen = new DocGen(__DIR__ . '/..');
$docgen->parse(__DIR__ . '/../recipe');
$docgen->parse(__DIR__ . '/../contrib');
if ($input->getOption('json')) {
echo json_encode($docgen->recipes, JSON_PRETTY_PRINT);
return;
}
$docgen->gen(__DIR__ . '/../docs');
$output->writeln('Recipes documentation updated.');
};
$app->register('api')->setCode($api);
$app->register('recipes')->setCode($recipes)->addOption('json');
$app->register('all')->setCode(function () use ($recipes, $api) {
$api();
$recipes();
echo `git status`;
})->addOption('json');
$app->run($input, $output);
================================================
FILE: composer.json
================================================
{
"name": "deployer/deployer",
"description": "Deployment Tool",
"license": "MIT",
"homepage": "https://deployer.org",
"support": {
"docs": "https://deployer.org/docs",
"source": "https://github.com/deployphp/deployer",
"issues": "https://github.com/deployphp/deployer/issues"
},
"authors": [
{
"name": "Anton Medvedev",
"email": "anton@medv.io"
}
],
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/antonmedv"
}
],
"autoload": {
"psr-4": {
"Deployer\\": "src/"
},
"files": [
"src/functions.php",
"src/Support/helpers.php"
]
},
"scripts": {
"test": "pest",
"test:e2e": "pest --config tests/e2e/phpunit-e2e.xml",
"check": "php-cs-fixer check",
"fix": "php-cs-fixer fix",
"phpstan": "phpstan analyse -c phpstan.neon --memory-limit 1G",
"phpstan:baseline": "@phpstan --generate-baseline tests/phpstan-baseline.neon"
},
"bin": [
"bin/dep"
],
"require": {
"php": ">=8.2",
"symfony/console": "^7.2",
"symfony/process": "^7.2",
"symfony/yaml": "^7.2"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.68",
"pestphp/pest": "^3.3",
"phpstan/phpstan": "^1.4",
"phpunit/php-code-coverage": "^11.0",
"phpunit/phpunit": "^11.4"
},
"config": {
"sort-packages": true,
"process-timeout": 0,
"allow-plugins": {
"pestphp/pest-plugin": true,
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
================================================
FILE: contrib/bugsnag.php
================================================
<?php
/*
## Configuration
- *bugsnag_api_key* – the API Key associated with the project. Informs Bugsnag which project has been deployed. This is the only required field.
- *bugsnag_provider* – the name of your source control provider. Required when repository is supplied and only for on-premise services.
- *bugsnag_app_version* – the app version of the code you are currently deploying. Only set this if you tag your releases with semantic version numbers and deploy infrequently. (Optional.)
## Usage
Since you should only notify Bugsnag of a successful deployment, the `bugsnag:notify` task should be executed right at the end.
```php
after('deploy', 'bugsnag:notify');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
desc('Notifies Bugsnag of deployment');
task('bugsnag:notify', function () {
$data = [
'apiKey' => get('bugsnag_api_key'),
'releaseStage' => get('target'),
'repository' => get('repository'),
'provider' => get('bugsnag_provider', ''),
'branch' => get('branch'),
'revision' => runLocally('git log -n 1 --format="%h"'),
'appVersion' => get('bugsnag_app_version', ''),
];
Httpie::post('https://notify.bugsnag.com/deploy')
->jsonBody($data)
->send();
});
================================================
FILE: contrib/cachetool.php
================================================
<?php
/*
## Configuration
- **cachetool** *(optional)*: accepts a *string* or an *array* of strings with the unix socket or ip address to php-fpm. If `cachetool` is not given, then the application will look for a configuration file. The file must be named .cachetool.yml or .cachetool.yaml. CacheTool will look for this file on the current directory and in any parent directory until it finds one. If the paths above fail it will try to load /etc/cachetool.yml or /etc/cachetool.yaml configuration file.
```php
set('cachetool', '/var/run/php-fpm.sock');
// or
set('cachetool', '127.0.0.1:9000');
// or
set('cachetool', ['/var/run/php-fpm.sock', '/var/run/php-fpm-other.sock']);
```
You can also specify different cachetool settings for each host:
```php
host('staging')
->set('cachetool', '127.0.0.1:9000');
host('production')
->set('cachetool', '/var/run/php-fpm.sock');
```
By default, if no `cachetool` parameter is provided, this recipe will fallback to the global setting.
If your deployment user does not have permission to access the php-fpm.sock, you can alternatively use
the web adapter that creates a temporary php file and makes a web request to it with a configuration like
```php
set('cachetool_args', '--web --web-path=./public --web-url=https://{{hostname}}');
```
## Usage
Since APCu and OPcache deal with compiling and caching files, they should be executed right after the symlink is created for the new release:
```php
after('deploy:symlink', 'cachetool:clear:opcache');
// or
after('deploy:symlink', 'cachetool:clear:apcu');
```
## Read more
Read more information about cachetool on the website:
http://gordalina.github.io/cachetool/
*/
namespace Deployer;
set('cachetool', '');
/**
* URL to download cachetool from if it is not available
*
* CacheTool 9.x works with PHP >=8.1
* CacheTool 8.x works with PHP >=8.0
* CacheTool 7.x works with PHP >=7.3
*/
set('cachetool_url', 'https://github.com/gordalina/cachetool/releases/download/9.1.0/cachetool.phar');
set('cachetool_args', '');
set('bin/cachetool', function () {
if (!test('[ -f {{release_or_current_path}}/cachetool.phar ]')) {
run("cd {{release_or_current_path}} && curl -sLO {{cachetool_url}}");
}
return '{{release_or_current_path}}/cachetool.phar';
});
set('cachetool_options', function () {
$options = (array) get('cachetool');
$fullOptions = (string) get('cachetool_args');
$return = [];
if ($fullOptions !== '') {
$return = [$fullOptions];
} elseif (count($options) > 0) {
foreach ($options as $option) {
if (is_string($option) && $option !== '') {
$return[] = "--fcgi={$option}";
}
}
}
return $return ?: [''];
});
/**
* Clear opcache cache
*/
desc('Clears OPcode cache');
task('cachetool:clear:opcache', function () {
$options = get('cachetool_options');
foreach ($options as $option) {
run("cd {{release_or_current_path}} && {{bin/php}} {{bin/cachetool}} opcache:reset $option");
}
});
/**
* Clear APCu cache
*/
desc('Clears APCu system cache');
task('cachetool:clear:apcu', function () {
$options = get('cachetool_options');
foreach ($options as $option) {
run("cd {{release_or_current_path}} && {{bin/php}} {{bin/cachetool}} apcu:cache:clear $option");
}
});
/**
* Clear file status cache, including the realpath cache
*/
desc('Clears file status and realpath caches');
task('cachetool:clear:stat', function () {
$options = get('cachetool_options');
foreach ($options as $option) {
run("cd {{release_or_current_path}} && {{bin/php}} {{bin/cachetool}} stat:clear $option");
}
});
================================================
FILE: contrib/chatwork.php
================================================
<?php
/*
# Chatwork Recipe
## Installing
1. Create chatwork account by any manual in the internet
2. Take chatwork token (Like: b29a700e2d15bef3f26ae6a5c142d1ea) and set `chatwork_token` parameter
3. Take chatwork room id from url after clicked on the room, and set `chatwork_room_id` parameter
4. If you want, you can edit `chatwork_notify_text`, `chatwork_success_text` or `chatwork_failure_text`
5. Require chatwork recipe in your `deploy.php` file
```php
# https://deployer.org/recipes.html
require 'recipe/chatwork.php';
```
Add hook on deploy:
```php
before('deploy', 'chatwork:notify');
```
## Configuration
- `chatwork_token` – chatwork bot token, **required**
- `chatwork_room_id` — chatwork room to push messages to **required**
- `chatwork_notify_text` – notification message template
```
[info]
[title](*) Deployment Status: Deploying[/title]
Repo: {{repository}}
Branch: {{branch}}
Server: {{hostname}}
Release Path: {{release_path}}
Current Path: {{current_path}}
[/info]
```
- `chatwork_success_text` – success template, default:
```
[info]
[title](*) Deployment Status: Successfully[/title]
Repo: {{repository}}
Branch: {{branch}}
Server: {{hostname}}
Release Path: {{release_path}}
Current Path: {{current_path}}
[/info]"
```
- `chatwork_failure_text` – failure template, default:
```
[info]
[title](*) Deployment Status: Failed[/title]
Repo: {{repository}}
Branch: {{branch}}
Server: {{hostname}}
Release Path: {{release_path}}
Current Path: {{current_path}}
[/info]"
```
## Tasks
- `chatwork:notify` – send message to chatwork
- `chatwork:notify:success` – send success message to chatwork
- `chatwork:notify:failure` – send failure message to chatwork
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'chatwork:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'chatwork:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'chatwork:notify:failure');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
// Chatwork settings
set('chatwork_token', function () {
throw new \RuntimeException('Please configure "chatwork_token" parameter.');
});
set('chatwork_room_id', function () {
throw new \RuntimeException('Please configure "chatwork_room_id" parameter.');
});
set('chatwork_api', function () {
return 'https://api.chatwork.com/v2/rooms/' . get('chatwork_room_id') . '/messages';
});
// The Messages
set('chatwork_notify_text', "[info]\n[title](*) Deployment Status: Deploying[/title]\nRepo: {{repository}}\nBranch: {{branch}}\nServer: {{hostname}}\nRelease Path: {{release_path}}\nCurrent Path: {{current_path}}\n[/info]");
set('chatwork_success_text', "[info]\n[title](*) Deployment Status: Successfully[/title]\nRepo: {{repository}}\nBranch: {{branch}}\nServer: {{hostname}}\nRelease Path: {{release_path}}\nCurrent Path: {{current_path}}\n[/info]");
set('chatwork_failure_text', "[info]\n[title](*) Deployment Status: Failed[/title]\nRepo: {{repository}}\nBranch: {{branch}}\nServer: {{hostname}}\nRelease Path: {{release_path}}\nCurrent Path: {{current_path}}\n[/info]");
// Helpers
task('chatwork_send_message', function () {
Httpie::post(get('chatwork_api'))
->formBody(['body' => get('chatwork_message')])
->header("X-ChatWorkToken", get('chatwork_token'))
->send();
});
// Tasks
desc('Tests messages');
task('chatwork:test', function () {
set('chatwork_message', get('chatwork_notify_text'));
invoke('chatwork_send_message');
set('chatwork_message', get('chatwork_success_text'));
invoke('chatwork_send_message');
set('chatwork_message', get('chatwork_failure_text'));
invoke('chatwork_send_message');
})
->once();
desc('Notifies Chatwork');
task('chatwork:notify', function () {
if (!get('chatwork_token', false)) {
return;
}
if (!get('chatwork_room_id', false)) {
return;
}
set('chatwork_message', get('chatwork_notify_text'));
invoke('chatwork_send_message');
})
->once()
->hidden();
desc('Notifies Chatwork about deploy finish');
task('chatwork:notify:success', function () {
if (!get('chatwork_token', false)) {
return;
}
if (!get('chatwork_room_id', false)) {
return;
}
set('chatwork_message', get('chatwork_success_text'));
invoke('chatwork_send_message');
})
->once()
->hidden();
desc('Notifies Chatwork about deploy failure');
task('chatwork:notify:failure', function () {
if (!get('chatwork_token', false)) {
return;
}
if (!get('chatwork_room_id', false)) {
return;
}
set('chatwork_message', get('chatwork_failure_text'));
invoke('chatwork_send_message');
})
->once()
->hidden();
================================================
FILE: contrib/cimonitor.php
================================================
<?php
/*
Monitor your deployments on [CIMonitor](https://github.com/CIMonitor/CIMonitor).

Add tasks on deploy:
```php
before('deploy', 'cimonitor:notify');
after('deploy:success', 'cimonitor:notify:success');
after('deploy:failed', 'cimonitor:notify:failure');
```
## Configuration
- `cimonitor_webhook` – CIMonitor server webhook url, **required**
```
set('cimonitor_webhook', 'https://cimonitor.enrise.com/webhook/deployer');
```
- `cimonitor_title` – the title of application, default the username\reponame combination from `{{repository}}`
```
set('cimonitor_title', '');
```
- `cimonitor_user` – User object with name and email, default gets information from `git config`
```
set('cimonitor_user', function () {
return [
'name' => 'John Doe',
'email' => 'john@enrise.com',
];
});
```
Various cimonitor statusses are set, in case you want to change these yourselves. See the [CIMonitor documentation](https://cimonitor.readthedocs.io/en/latest/) for the usages of different states.
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'cimonitor:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'cimonitor:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'cimonitor:notify:failure');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
// Title of project based on git repo
set('cimonitor_title', function () {
$repo = get('repository');
$pattern = '/\w+\/\w+/';
return preg_match($pattern, $repo, $titles) ? $titles[0] : $repo;
});
set('cimonitor_user', function () {
return [
'name' => runLocally('git config --get user.name'),
'email' => runLocally('git config --get user.email'),
];
});
// CI monitor status states and job states
set('cimonitor_status_info', 'info');
set('cimonitor_status_warning', 'warning');
set('cimonitor_status_error', 'error');
set('cimonitor_status_success', 'success');
set('cimonitor_job_state_info', get('cimonitor_status_info'));
set('cimonitor_job_state_pending', 'pending');
set('cimonitor_job_state_running', 'running');
set('cimonitor_job_state_warning', get('cimonitor_status_warning'));
set('cimonitor_job_state_error', get('cimonitor_status_error'));
set('cimonitor_job_state_success', get('cimonitor_status_success'));
desc('Notifies CIMonitor');
task('cimonitor:notify', function () {
if (!get('cimonitor_webhook', false)) {
return;
}
$body = [
'state' => get('cimonitor_status_warning'),
'branch' => get('branch'),
'title' => get('cimonitor_title'),
'user' => get('cimonitor_user'),
'stages' => [get('stage', '')],
'jobs' => [
[
'name' => 'Deploying...',
'stage' => '',
'state' => get('cimonitor_job_state_running'),
],
],
];
Httpie::post(get('cimonitor_webhook'))->jsonBody($body)->send();
})
->once()
->hidden();
desc('Notifies CIMonitor about deploy finish');
task('cimonitor:notify:success', function () {
if (!get('cimonitor_webhook', false)) {
return;
}
$depstage = 'Deployed to ' . get('stage', '');
$body = [
'state' => get('cimonitor_status_success'),
'branch' => get('branch'),
'title' => get('cimonitor_title'),
'user' => get('cimonitor_user'),
'stages' => [$depstage],
'jobs' => [
[
'name' => 'Deploy',
'stage' => $depstage,
'state' => get('cimonitor_job_state_success'),
],
],
];
Httpie::post(get('cimonitor_webhook'))->jsonBody($body)->send();
})
->once()
->hidden();
desc('Notifies CIMonitor about deploy failure');
task('cimonitor:notify:failure', function () {
if (!get('cimonitor_webhook', false)) {
return;
}
$body = [
'state' => get('cimonitor_status_error'),
'branch' => get('branch'),
'title' => get('cimonitor_title'),
'user' => get('cimonitor_user'),
'stages' => [get('stage', '')],
'jobs' => [
[
'name' => 'Deploy',
'stage' => '',
'state' => get('cimonitor_job_state_error'),
],
],
];
Httpie::post(get('cimonitor_webhook'))->jsonBody($body)->send();
})
->once()
->hidden();
================================================
FILE: contrib/cloudflare.php
================================================
<?php
/*
### Configuration
- `cloudflare` – array with configuration for cloudflare
- `service_key` – Cloudflare Service Key. If this is not provided, use api_key and email.
- `api_key` – Cloudflare API key generated on the "My Account" page.
- `email` – Cloudflare Email address associated with your account.
- `api_token` – Cloudflare API Token generated on the "My Account" page.
- `domain` – The domain you want to clear (optional if zone_id is provided).
- `zone_id` – Cloudflare Zone ID (optional).
### Usage
Since the website should be built and some load is likely about to be applied to your server, this should be one of,
if not the, last tasks before cleanup
*/
namespace Deployer;
desc('Clears Cloudflare Cache');
task('deploy:cloudflare', function () {
$config = get('cloudflare', []);
// validate config and set headers
if (!empty($config['service_key'])) {
$headers = [
'X-Auth-User-Service-Key' => $config['service_key'],
];
} elseif (!empty($config['email']) && !empty($config['api_key'])) {
$headers = [
'X-Auth-Key' => $config['api_key'],
'X-Auth-Email' => $config['email'],
];
} elseif (!empty($config['api_token'])) {
$headers = [
'Authorization' => 'Bearer ' . $config['api_token'],
];
} else {
throw new \RuntimeException("Set a service key or email / api key");
}
$headers['Content-Type'] = 'application/json';
$makeRequest = function ($url, $opts = []) use ($headers) {
$ch = curl_init("https://api.cloudflare.com/client/v4/$url");
$parsedHeaders = [];
foreach ($headers as $key => $value) {
$parsedHeaders[] = "$key: $value";
}
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => $parsedHeaders,
CURLOPT_RETURNTRANSFER => true,
]);
curl_setopt_array($ch, $opts);
$res = curl_exec($ch);
if (curl_errno($ch)) {
throw new \RuntimeException("Error making curl request (result: $res)");
}
if (PHP_MAJOR_VERSION < 8) {
curl_close($ch);
}
return $res;
};
$zoneId = $config['zone_id'];
if (empty($zoneId)) {
if (empty($config['domain'])) {
throw new \RuntimeException("Set a domain");
}
// get the mysterious zone id from Cloud Flare
$zones = json_decode($makeRequest(
"zones?name={$config['domain']}",
), true);
if (!empty($zones['errors'])) {
throw new \RuntimeException('Problem with zone data');
} else {
$zoneId = current($zones['result'])['id'];
}
}
// make purge request
$makeRequest(
"zones/$zoneId/purge_cache",
[
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_POSTFIELDS => json_encode(
[
'purge_everything' => true,
],
),
],
);
});
================================================
FILE: contrib/cpanel.php
================================================
<?php
/*
### Description
This is a recipe that uses the [cPanel 2 API](https://documentation.cPanel.net/display/DD/Guide+to+cPanel+API+2).
Unfortunately the [UAPI](https://documentation.cPanel.net/display/DD/Guide+to+UAPI) that is recommended does not have support for creating addon domains.
The main idea behind is for staging purposes but I guess you can use it for other interesting concepts.
The idea is, every branch possibly has its own staging domain/subdomain (staging-neat-feature.project.com) and database db_neat-feature_project so it can be tested.
This recipe can make the domain/subdomain and database creation part of the deployment process so you don't have to manually create them through an interface.
### Configuration
The example uses a .env file and Dotenv for configuration, but you can set the parameters as you wish
```
set('cpanel', [
'host' => getenv('CPANEL_HOST'),
'port' => getenv('CPANEL_PORT'),
'username' => getenv('CPANEL_USERNAME'),
'auth_type' => getenv('CPANEL_AUTH_TYPE'),
'token' => getenv('CPANEL_TOKEN'),
'user' => getenv('CPANEL_USER'),
'db_user' => getenv('CPANEL_DB_USER'),
'db_user_privileges' => getenv('CPANEL_DB_PRIVILEGES'),
'timeout' => 500,
'allowInStage' => ['staging', 'beta', 'alpha'],
'create_domain_format' => '%s-%s-%s',
'create_domain_values' => ['staging', 'master', get('application')],
'subdomain_prefix' => substr(md5(get('application')), 0,4) . '-',
'subdomain_suffix' => getenv('SUDOMAIN_SUFFIX'),
'create_db_format' => '%s_%s-%s-%s',
'create_db_values' => ['apps', 'staging','master', get('application')],
]);
```
- `cpanel` – array with configuration for cPanel
- `username` – WHM account
- `user` – cPanel account that you want in charge of the domain
- `token` – WHM API token
- `create_domain_format` – Format for name creation of domain
- `create_domain_values` – The actual value reference for naming
- `subdomain_prefix` – cPanel has a weird way of dealing with addons and subdomains, you cannot create 2 addons with the same subdomain, so you need to change it in some way, example uses first 4 chars of md5(app_name)
- `subdomain_suffix` – cPanel has a weird way of dealing with addons and subdomains, so the suffix needs to be your main domain for that account for deletion purposes
- `addondir` – addon dir is different from the deploy path because cPanel "injects" /home/user/ into the path, so tilde cannot be used
- `allowInStage` – Define the stages that cPanel recipe actions are allowed in
#### .env file example
```
CPANEL_HOST=xxx.xxx.xxx.xxx
CPANEL_PORT=2087
CPANEL_USERNAME=root
CPANEL_TOKEN=xxxx
CPANEL_USER=xxx
CPANEL_AUTH_TYPE=hash
CPANEL_DB_USER=db_user
CPANEL_DB_PRIVILEGES="ALL PRIVILEGES"
SUDOMAIN_SUFFIX=.mymaindomain.com
```
### Tasks
- `cpanel:createaddondomain` Creates an addon domain
- `cpanel:deleteaddondomain` Removes an addon domain
- `cpanel:createdb` Creates a new database
### Usage
A complete example with configs, staging and deployment
```
<?php
namespace Deployer;
use Dotenv\Dotenv;
require 'vendor/autoload.php';
(Dotenv::create(__DIR__))->load(); // this is used just so an .env file can be used for credentials
require 'cpanel.php';
// Project name
set('application', 'myproject.com');
// Project repository
set('repository', 'git@github.com:myorg/myproject.com');
set('cpanel', [
'host' => getenv('CPANEL_HOST'),
'port' => getenv('CPANEL_PORT'),
'username' => getenv('CPANEL_USERNAME'),
'auth_type' => getenv('CPANEL_AUTH_TYPE'),
'token' => getenv('CPANEL_TOKEN'),
'user' => getenv('CPANEL_USER'),
'db_user' => getenv('CPANEL_DB_USER'),
'db_user_privileges' => getenv('CPANEL_DB_PRIVILEGES'),
'timeout' => 500,
'allowInStage' => ['staging', 'beta', 'alpha'],
'create_domain_format' => '%s-%s-%s',
'create_domain_values' => ['staging', 'master', get('application')],
'subdomain_prefix' => substr(md5(get('application')), 0,4) . '-',
'subdomain_suffix' => getenv('SUDOMAIN_SUFFIX'),
'create_db_format' => '%s_%s-%s-%s',
'create_db_values' => ['apps', 'staging','master', get('application')],
]);
host('myproject.com')
->stage('staging')
->set('cpanel_createdb', vsprintf(get('cpanel')['create_db_format'], get('cpanel')['create_db_values']))
->set('branch', 'dev-branch')
->set('deploy_path', '~/staging/' . vsprintf(get('cpanel')['create_domain_format'], get('cpanel')['create_domain_values']))
->set('addondir', 'staging/' . vsprintf(get('cpanel')['create_domain_format'], get('cpanel')['create_domain_values']));
// Tasks
task('build', function () {
run('cd {{release_path}} && build');
});
after('deploy:prepare', 'cpanel:createaddondomain');
after('deploy:prepare', 'cpanel:createdb');
```
*/
namespace Deployer;
use Deployer\Task\Context;
use Gufy\CpanelPhp\Cpanel;
/**
* @return Cpanel
* @throws Exception\Exception
*/
function getCpanel()
{
$config = get('cpanel', []);
$allowInStage = $config['allowInStage'];
$stage = input()->getArgument('stage');
if (!class_exists('\Gufy\CpanelPhp\Cpanel')) {
throw new \RuntimeException("<comment>Please install php package</comment> <info>gufy/cpanel-php</info> <comment>to use CPanel API</comment>");
}
if (!in_array($stage, $allowInStage)) {
throw new \RuntimeException(sprintf("Since it creates addon domains and databases, CPanel recipe is available only in the %s environments", implode($allowInStage)));
}
if (!is_array($config) ||
!isset($config['host']) ||
!isset($config['port']) ||
!isset($config['username']) ||
!isset($config['token']) ||
!isset($config['user'])) {
throw new \RuntimeException("<comment>Please configure CPanel config:</comment> <info>set('cpanel', array('host' => 'xxx.xxx.xxx.xxx:', 'port' => 2087 , 'username' => 'root', 'token' => 'asdfasdf', 'cpaneluser' => 'guy'));</info>");
}
$cpanel = new Cpanel([
'host' => 'https://' . $config['host'] . ':' . $config['port'],
'username' => $config['username'],
'auth_type' => $config['auth_type'],
'password' => $config['token'],
]);
$cpanel->setTimeout($config['timeout']);
return $cpanel;
}
function getDomainInfo()
{
$domain = vsprintf(get('cpanel')['create_domain_format'], get('cpanel')['create_domain_values']);
$cleanDomain = str_replace(['.', ',', ' ', '/', '-'], '', $domain);
$subDomain = get('cpanel')['subdomain_prefix'] . $cleanDomain;
return [
'domain' => $domain,
'subDomain' => $subDomain,
'subDomainWithSuffix' => $subDomain . get('cpanel')['subdomain_suffix'],
];
}
desc('Creates database though CPanel API');
task('cpanel:createdb', function () {
$cpanel = getCPanel();
$config = get('cpanel', []);
if (!askConfirmation(sprintf('This will try to create the database %s on the host though CPanel API, ok?', get('cpanel_createdb')), true)) {
return;
}
$createDbDataResult = $cpanel->cpanel('MysqlFE', 'createdb', $config['user'], ['db' => get('cpanel_createdb')]);
$addPrivilegesDataResult = $cpanel->cpanel('MysqlFE', 'setdbuserprivileges', $config['user'], ['privileges' => $config['db_user_privileges'], 'db' => get('cpanel_createdb'), 'dbuser' => $config['db_user']]);
$createDbData = json_decode($createDbDataResult, true);
$addPrivilegesData = json_decode($addPrivilegesDataResult, true);
if (isset($createDbData['cpanelresult']['error'])) {
writeln($createDbData['cpanelresult']['error']);
} else {
writeln('Successfully created database!');
}
if (isset($addPrivilegesData['cpanelresult']['error'])) {
writeln($addPrivilegesData['cpanelresult']['error']);
} else {
writeln('Successfully added privileges to database!');
}
});
desc('Creates addon domain though CPanel API');
task('cpanel:createaddondomain', function () {
$cpanel = getCPanel();
$config = get('cpanel', []);
$domain = getDomainInfo()['domain'];
$subDomain = getDomainInfo()['subDomain'];
if (!askConfirmation(sprintf('This will try to create the addon domain %s and point it to %s and subdomain %s, ok?', $domain, get('addondir'), $subDomain), true)) {
return;
}
writeln(sprintf('Creates addon domain %s and pointing it to %s', $domain, get('addondir')));
$addAddonDomainResult = $cpanel->cpanel('AddonDomain', 'addaddondomain', $config['user'], ['dir' => get('addondir'), 'newdomain' => $domain, 'subdomain' => $subDomain]);
$addAddonDomainData = json_decode($addAddonDomainResult, true);
if (isset($addAddonDomainResult['cpanelresult']['error'])) {
writeln($addAddonDomainData['cpanelresult']['error']);
} else {
writeln('Successfully created addon domain!');
writeln($addAddonDomainData['cpanelresult']['data'][0]['reason']);
}
});
desc('Deletes addon domain though CPanel API');
task('cpanel:deleteaddondomain', function () {
$cpanel = getCPanel();
$config = get('cpanel', []);
$domain = getDomainInfo()['domain'];
$subDomain = getDomainInfo()['subDomain'];
$subDomainWithSuffix = getDomainInfo()['subDomainWithSuffix'];
if (!askConfirmation(sprintf('This will delete the addon domain %s with corresponding subdomain %s, ok?', $domain, $subDomain), true)) {
return;
}
writeln(sprintf('Deleting addon domain %s', $domain));
$delAddonDomainResult = $cpanel->cpanel('AddonDomain', 'deladdondomain', $config['user'], ['domain' => $domain, 'subdomain' => $subDomainWithSuffix]);
$delAddonDomainResult = json_decode($delAddonDomainResult, true);
if (isset($delAddonDomainResult['cpanelresult']['error'])) {
writeln($delAddonDomainResult['cpanelresult']['error']);
} else {
writeln('Successfully deleted addon domain!');
writeln($delAddonDomainResult['cpanelresult']['data'][0]['reason']);
}
});
================================================
FILE: contrib/crontab.php
================================================
<?php
/*
Recipe for adding crontab jobs.
This recipe creates a new section in the crontab file with the configured jobs.
The section is identified by the *crontab:identifier* variable, by default the application name.
## Configuration
- *crontab:jobs* - An array of strings with crontab lines.
## Usage
```php
require 'contrib/crontab.php';
after('deploy:success', 'crontab:sync');
add('crontab:jobs', [
'* * * * * cd {{current_path}} && {{bin/php}} artisan schedule:run >> /dev/null 2>&1',
]);
```
*/
namespace Deployer;
use function Deployer\Support\escape_shell_argument;
// Get path to bin
set('bin/crontab', function () {
return which('crontab');
});
// Set the identifier used in the crontab, application name by default
set('crontab:identifier', function () {
return get('application', 'application');
});
// Use sudo to run crontab. When running crontab with sudo, you can use the `-u` parameter to change a crontab for a different user.
set('crontab:use_sudo', false);
desc('Sync crontab jobs');
task('crontab:sync', function () {
$cronJobsLocal = array_map(
fn($job) => parse($job),
get('crontab:jobs', []),
);
if (count($cronJobsLocal) == 0) {
writeln("Nothing to sync - configure crontab:jobs");
return;
}
$cronJobs = getRemoteCrontab();
$identifier = get('crontab:identifier');
$sectionStart = "###< $identifier";
$sectionEnd = "###> $identifier";
// find our cronjob section
$start = array_search($sectionStart, $cronJobs);
$end = array_search($sectionEnd, $cronJobs);
if ($start === false || $end === false) {
// Move the duplicates over when first generating the section
foreach ($cronJobs as $index => $cronJob) {
if (in_array($cronJob, $cronJobsLocal)) {
unset($cronJobs[$index]);
writeln("Crontab: Found existing job in crontab, moving it to the section");
}
}
// Create the section
$cronJobs[] = $sectionStart;
$cronJobs = [...$cronJobs, ...$cronJobsLocal];
$cronJobs[] = $sectionEnd;
writeln("Crontab: Found no section, created the section with configured jobs");
} else {
// Replace the existing section
array_splice($cronJobs, $start + 1, $end - $start - 1, $cronJobsLocal);
writeln("Crontab: Found existing section, replaced with configured jobs");
}
setRemoteCrontab($cronJobs);
});
desc('Remove crontab jobs');
task('crontab:remove', function () {
$cronJobsLocal = array_map(
fn($job) => parse($job),
get('crontab:jobs', []),
);
$cronJobs = getRemoteCrontab();
$identifier = get('crontab:identifier');
$sectionStart = "###< $identifier";
$sectionEnd = "###> $identifier";
// Find our cronjob section
$start = array_search($sectionStart, $cronJobs);
$end = array_search($sectionEnd, $cronJobs);
if ($start && $end) {
// Remove the existing section
array_splice($cronJobs, $start + 1, $end - $start - 1);
writeln("Crontab: Found existing section, removed jobs");
} elseif (count($cronJobsLocal) > 0) {
$foundJobs = false;
// Remove individual jobs if no section is present
foreach ($cronJobs as $index => $cronJob) {
if (in_array($cronJob, $cronJobsLocal)) {
unset($cronJobs[$index]);
$foundJobs = true;
}
}
if ($foundJobs) {
writeln("Crontab: Found existing jobs in crontab, removed jobs");
} else {
writeln("Crontab: No existing jobs in crontab, skipping");
return;
}
} else {
writeln("Crontab: Found no section and crontab:jobs is not configured, skipping");
return;
}
setRemoteCrontab($cronJobs);
});
function setRemoteCrontab(array $lines): void
{
$sudo = get('crontab:use_sudo') ? 'sudo' : '';
$tmpCrontabPath = sprintf('/tmp/%s', uniqid('crontab_save_'));
if (test("[ -f '$tmpCrontabPath' ]")) {
run("unlink '$tmpCrontabPath'");
}
foreach ($lines as $line) {
run("echo " . escape_shell_argument($line) . " >> $tmpCrontabPath");
}
run("$sudo {{bin/crontab}} " . $tmpCrontabPath);
run('unlink ' . $tmpCrontabPath);
}
function getRemoteCrontab(): array
{
$sudo = get('crontab:use_sudo') ? 'sudo' : '';
if (!test("$sudo {{bin/crontab}} -l >> /dev/null 2>&1")) {
return [];
}
return explode(PHP_EOL, run("$sudo {{bin/crontab}} -l"));
}
================================================
FILE: contrib/directadmin.php
================================================
<?php
/*
### Configuration
- `directadmin` – array with configuration for DirectAdmin
- `host` – DirectAdmin host
- `port` – DirectAdmin port (default: 2222, not required)
- `scheme` – DirectAdmin scheme (default: http, not required)
- `username` – DirectAdmin username
- `password` – DirectAdmin password (it is recommended to use login keys!)
- `db_user` – Database username (required when using directadmin:createdb or directadmin:deletedb)
- `db_name` – Database namse (required when using directadmin:createdb)
- `db_password` – Database password (required when using directadmin:createdb)
- `domain_name` – Domain to create, delete or edit (required when using directadmin:createdomain, directadmin:deletedomain, directadmin:symlink-private-html or directadmin:php-version)
- `domain_ssl` – Enable SSL, options: ON/OFF, default: ON (optional when using directadmin:createdb)
- `domain_cgi` – Enable CGI, options: ON/OFF, default: ON (optional when using directadmin:createdb)
- `domain_php` – Enable PHP, options: ON/OFF, default: ON (optional when using directadmin:createdb)
- `domain_php_version` – Domain PHP Version, default: 1 (required when using directadmin:php-version)
*/
namespace Deployer;
use Deployer\Task\Context;
use Deployer\Utility\Httpie;
/**
* getDirectAdminConfig
*
* @return array
*/
function getDirectAdminConfig()
{
$config = get('directadmin', []);
if (!is_array($config) ||
!isset($config['host']) ||
!isset($config['username']) ||
!isset($config['password'])) {
throw new \RuntimeException("Please set the following DirectAdmin config:" . PHP_EOL . "set('directadmin', ['host' => '127.0.0.1', 'port' => 2222, 'username' => 'admin', 'password' => 'password']);");
}
return $config;
}
/**
* DirectAdmin
*
* @param string $action
* @param array $data
*
* @return void
*/
function DirectAdmin(string $action, array $data = [])
{
$config = getDirectAdminConfig();
$scheme = $config['scheme'] ?? 'http';
$port = $config['port'] ?? 2222;
$result = Httpie::post(sprintf('%s://%s:%s/%s', $scheme, $config['host'], $port, $action))
->formBody($data)
->setopt(CURLOPT_USERPWD, $config['username'] . ':' . $config['password'])
->send();
parse_str($result, $resultData);
if ($resultData['error'] === '1') {
$resultData['details'] = trim($resultData['details']);
$resultData['details'] = str_replace(['\\n', '\\r'], '', $resultData['details']);
$resultData['details'] = strip_tags($resultData['details']);
writeln('<error>DirectAdmin message: ' . $resultData['details'] . '</error>');
}
}
desc('Creates a database on DirectAdmin');
task('directadmin:createdb', function () {
$config = getDirectAdminConfig();
if (!is_array($config) ||
!isset($config['db_name']) ||
!isset($config['db_user']) ||
!isset($config['db_password'])) {
throw new \RuntimeException("Please add the following DirectAdmin config:" . PHP_EOL . "add('directadmin', ['db_name' => 'test', 'db_user' => 'test', 'db_password' => '123456']);");
}
DirectAdmin('CMD_API_DATABASES', [
'action' => 'create',
'name' => $config['db_name'],
'user' => $config['db_user'],
'passwd' => $config['db_password'],
'passwd2' => $config['db_password'],
]);
});
desc('Deletes a database on DirectAdmin');
task('directadmin:deletedb', function () {
$config = getDirectAdminConfig();
if (!is_array($config) ||
!isset($config['db_user'])) {
throw new \RuntimeException("Please add the following DirectAdmin config:" . PHP_EOL . "add('directadmin', ['db_user' => 'test_database']);");
}
DirectAdmin('CMD_API_DATABASES', [
'action' => 'delete',
'select0' => $config['username'] . '_' . $config['db_user'],
]);
});
desc('Creates a domain on DirectAdmin');
task('directadmin:createdomain', function () {
$config = getDirectAdminConfig();
if (!is_array($config) ||
!isset($config['domain_name'])) {
throw new \RuntimeException("Please add the following DirectAdmin config:" . PHP_EOL . "add('directadmin', ['domain_name' => 'test.example.com']);");
}
DirectAdmin('CMD_API_DOMAIN', [
'action' => 'create',
'domain' => $config['domain_name'],
'ssl' => $config['domain_ssl'] ?? 'On',
'cgi' => $config['domain_cgi'] ?? 'ON',
'php' => $config['domain_php'] ?? 'ON',
]);
});
desc('Deletes a domain on DirectAdmin');
task('directadmin:deletedomain', function () {
$config = getDirectAdminConfig();
if (!is_array($config) ||
!isset($config['domain_name'])) {
throw new \RuntimeException("Please add the following DirectAdmin config:" . PHP_EOL . "add('directadmin', ['domain_name' => 'test.example.com']);");
}
DirectAdmin('CMD_API_DOMAIN', [
'delete' => 'anything',
'confirmed' => 'anything',
'select0' => $config['domain_name'],
]);
});
desc('Symlink your private_html to public_html');
task('directadmin:symlink-private-html', function () {
$config = getDirectAdminConfig();
if (!is_array($config) ||
!isset($config['domain_name'])) {
throw new \RuntimeException("Please add the following DirectAdmin config:" . PHP_EOL . "add('directadmin', ['domain_name' => 'test.example.com']);");
}
DirectAdmin('CMD_API_DOMAIN', [
'action' => 'private_html',
'domain' => $config['domain_name'],
'val' => 'symlink',
]);
});
desc('Changes the PHP version from a domain');
task('directadmin:php-version', function () {
$config = getDirectAdminConfig();
if (!is_array($config) ||
!isset($config['domain_name']) ||
!isset($config['domain_php_version'])) {
throw new \RuntimeException("Please add the following DirectAdmin config:" . PHP_EOL . "add('directadmin', ['domain_name' => 'test.example.com', 'domain_php_version' => 1]);");
}
DirectAdmin('CMD_API_DOMAIN', [
'action' => 'php_selector',
'domain' => $config['domain_name'],
'php1_select' => $config['domain_php_version'],
]);
});
================================================
FILE: contrib/discord.php
================================================
<?php
/*
## Installing
Add hook on deploy:
```php
before('deploy', 'discord:notify');
```
## Configuration
- `discord_channel` – Discord channel ID, **required**
- `discord_token` – Discord channel token, **required**
- `discord_notify_text` – notification message template, markdown supported, default:
```markdown
:information_source: **{{user}}** is deploying branch `{{branch}}` to _{{where}}_
```
- `discord_success_text` – success template, default:
```markdown
:white_check_mark: Branch `{{branch}}` deployed to _{{where}}_ successfully
```
- `discord_failure_text` – failure template, default:
```markdown
:no_entry_sign: Branch `{{branch}}` has failed to deploy to _{{where}}_
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'discord:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'discord:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'discord:notify:failure');
```
*/
namespace Deployer;
use Deployer\Task\Context;
use Deployer\Utility\Httpie;
set('discord_webhook', function () {
return 'https://discordapp.com/api/webhooks/{{discord_channel}}/{{discord_token}}/slack';
});
// Deploy messages
set('discord_notify_text', function () {
return [
'text' => parse(':information_source: **{{user}}** is deploying branch `{{what}}` to _{{where}}_'),
];
});
set('discord_success_text', function () {
return [
'text' => parse(':white_check_mark: Branch `{{what}}` deployed to _{{where}}_ successfully'),
];
});
set('discord_failure_text', function () {
return [
'text' => parse(':no_entry_sign: Branch `{{what}}` has failed to deploy to _{{where}}_'),
];
});
// The message
set('discord_message', 'discord_notify_text');
// Helpers
task('discord_send_message', function () {
$message = get(get('discord_message'));
Httpie::post(get('discord_webhook'))->jsonBody($message)->send();
});
// Tasks
desc('Tests messages');
task('discord:test', function () {
set('discord_message', 'discord_notify_text');
invoke('discord_send_message');
set('discord_message', 'discord_success_text');
invoke('discord_send_message');
set('discord_message', 'discord_failure_text');
invoke('discord_send_message');
})
->once();
desc('Notifies Discord');
task('discord:notify', function () {
set('discord_message', 'discord_notify_text');
invoke('discord_send_message');
})
->once()
->isHidden();
desc('Notifies Discord about deploy finish');
task('discord:notify:success', function () {
set('discord_message', 'discord_success_text');
invoke('discord_send_message');
})
->once()
->isHidden();
desc('Notifies Discord about deploy failure');
task('discord:notify:failure', function () {
set('discord_message', 'discord_failure_text');
invoke('discord_send_message');
})
->once()
->isHidden();
================================================
FILE: contrib/grafana.php
================================================
<?php
/*
## Configuration options
- **url** *(required)*: the URL to the creates annotation api endpoint.
- **token** *(required)*: authentication token. Can be created at Grafana Console.
- **time** *(optional)* – set deploy time of annotation. specify epoch milliseconds. (Defaults is set to the current time in epoch milliseconds.)
- **tags** *(optional)* – set tag of annotation.
- **text** *(optional)* – set text of annotation. (Defaults is set to "Deployed " + git log -n 1 --format="%h")
```php
// deploy.php
set('grafana', [
'token' => 'eyJrIj...',
'url' => 'http://grafana/api/annotations',
'tags' => ['deploy', 'production'],
]);
```
## Usage
If you want to create annotation about successful end of deployment.
```php
after('deploy:success', 'grafana:annotation');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
desc('Creates Grafana annotation of deployment');
task('grafana:annotation', function () {
$defaultConfig = [
'url' => null,
'token' => null,
'time' => round(microtime(true) * 1000),
'tags' => [],
'text' => null,
];
$config = array_merge($defaultConfig, (array) get('grafana'));
if (!is_array($config) || !isset($config['url']) || !isset($config['token'])) {
throw new \RuntimeException("Please configure Grafana: set('grafana', ['url' => 'https://localhost/api/annotations', token' => 'eyJrIjo...']);");
}
$params = [
'time' => $config['time'],
'isRegion' => false,
'tags' => $config['tags'],
'text' => $config['text'],
];
if (!isset($params['text'])) {
$params['text'] = 'Deployed ' . trim(runLocally('git log -n 1 --format="%h"'));
}
Httpie::post($config['url'])
->header('Authorization', 'Bearer ' . $config['token'])
->jsonBody($params)
->send();
});
================================================
FILE: contrib/hangouts.php
================================================
<?php
/*
Add hook on deploy:
```php
before('deploy', 'chat:notify');
```
## Configuration
- `chat_webhook` – chat incoming webhook url, **required**
- `chat_title` – the title of your notification card, default `{{application}}`
- `chat_subtitle` – the subtitle of your card, default `{{hostname}}`
- `chat_favicon` – an image for the header of your card, default `http://{{hostname}}/favicon.png`
- `chat_line1` – first line of the text in your card, default: `{{branch}}`
- `chat_line2` – second line of the text in your card, default: `{{stage}}`
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'chat:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'chat:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'chat:notify:failure');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
// Title of project
set('chat_title', function () {
return get('application', 'Project');
});
set('chat_subtitle', get('hostname'));
// If 'favicon' is set Google Hangouts Chat will decorate your card with an image.
set('favicon', 'http://{{hostname}}/favicon.png');
// Deploy messages
set('chat_line1', '{{branch}}');
set('chat_line2', '{{stage}}');
desc('Notifies Google Hangouts Chat');
task('chat:notify', function () {
if (!get('chat_webhook', false)) {
return;
}
$card = [
'header' => [
'title' => get('chat_title'),
'subtitle' => get('chat_subtitle'),
'imageUrl' => get('favicon'),
'imageStyle' => 'IMAGE',
],
'sections' => [
'widgets' => [
'keyValue' => [
'topLabel' => get('chat_line1'),
'content' => get('chat_line2'),
'contentMultiline' => false,
'bottomLabel' => 'started',
// Use 'iconUrl' to set a custom icon URL (png)
'icon' => 'CLOCK',
'button' => [
'textButton' => [
'text' => 'Visit site',
'onClick' => [
'openLink' => [
'url' => get('hostname'),
],
],
],
],
],
],
],
];
Httpie::post(get('chat_webhook'))->jsonBody(['cards' => $card])->send();
})
->once()
->hidden();
desc('Notifies Google Hangouts Chat about deploy finish');
task('chat:notify:success', function () {
if (!get('chat_webhook', false)) {
return;
}
$card = [
'header' => [
'title' => get('chat_title'),
'subtitle' => get('chat_subtitle'),
'imageUrl' => get('favicon'),
'imageStyle' => 'IMAGE',
],
'sections' => [
'widgets' => [
'keyValue' => [
'topLabel' => get('chat_line1'),
'content' => get('chat_line2'),
'contentMultiline' => false,
'bottomLabel' => 'succeeded',
// Use 'iconUrl' to set a custom icon URL (png)
'icon' => 'STAR',
'button' => [
'textButton' => [
'text' => 'Visit site',
'onClick' => [
'openLink' => [
'url' => get('hostname'),
],
],
],
],
],
],
],
];
Httpie::post(get('chat_webhook'))->jsonBody(['cards' => $card])->send();
})
->once()
->hidden();
desc('Notifies Google Hangouts Chat about deploy failure');
task('chat:notify:failure', function () {
if (!get('chat_webhook', false)) {
return;
}
$card = [
'header' => [
'title' => get('chat_title'),
'subtitle' => get('chat_subtitle'),
'imageUrl' => get('favicon'),
'imageStyle' => 'IMAGE',
],
'sections' => [
'widgets' => [
'keyValue' => [
'topLabel' => get('chat_line1'),
'content' => get('chat_line2'),
'contentMultiline' => false,
'bottomLabel' => 'failed',
// Use 'iconUrl' to set a custom icon URL (png)
// or use 'icon' and pick from this list:
// https://developers.google.com/hangouts/chat/reference/message-formats/cards#customicons
'button' => [
'textButton' => [
'text' => 'Visit site',
'onClick' => [
'openLink' => [
'url' => get('hostname'),
],
],
],
],
],
],
],
];
Httpie::post(get('chat_webhook'))->jsonBody(['cards' => $card])->send();
})
->once()
->hidden();
================================================
FILE: contrib/hipchat.php
================================================
<?php
/*
## Configuration
- `hipchat_token` – Hipchat V1 auth token
- `hipchat_room_id` – Room ID or name
- `hipchat_message` – Deploy message, default is `_{{user}}_ deploying `{{what}}` to *{{where}}*`
- `hipchat_from` – Default to target
- `hipchat_color` – Message color, default is **green**
- `hipchat_url` – The URL to the message endpoint, default is https://api.hipchat.com/v1/rooms/message
## Usage
Since you should only notify Hipchat room of a successful deployment, the `hipchat:notify` task should be executed right at the end.
```php
after('deploy', 'hipchat:notify');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
set('hipchat_color', 'green');
set('hipchat_from', '{{where}}');
set('hipchat_message', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
set('hipchat_url', 'https://api.hipchat.com/v1/rooms/message');
desc('Notifies Hipchat channel of deployment');
task('hipchat:notify', function () {
$params = [
'room_id' => get('hipchat_room_id'),
'from' => get('target'),
'message' => get('hipchat_message'),
'color' => get('hipchat_color'),
'auth_token' => get('hipchat_token'),
'notify' => 0,
'format' => 'json',
];
Httpie::get(get('hipchat_url'))
->query($params)
->send();
});
================================================
FILE: contrib/ispmanager.php
================================================
<?php
/*
* This recipe for work with ISPManager Lite panel by API.
*/
namespace Deployer;
use Deployer\Exception\Exception;
use Deployer\Utility\Httpie;
set('ispmanager_owner', 'www-root');
set('ispmanager_doc_root', '/var/www/' . get('ispmanager_owner') . '/data/');
// ISPManager default configuration
set('ispmanager', [
'api' => [
'dsn' => 'https://root:password@localhost:1500/ispmgr',
'secure' => true,
],
'createDomain' => null,
'updateDomain' => null,
'deleteDomain' => null,
'createDatabase' => null,
'deleteDatabase' => null,
'phpSelect' => null,
'createAlias' => null,
'deleteAlias' => null,
]);
// Vhost default configuration
set('vhost', [
'name' => '{{domain}}',
'php_enable' => 'on',
'aliases' => 'www.{{domain}}',
'home' => 'www/{{domain}}',
'owner' => get('ispmanager_owner'),
'email' => 'webmaster@{{domain}}',
'charset' => 'off',
'dirindex' => 'index.php uploaded.html',
'ssi' => 'on',
'php' => 'on',
'php_mode' => 'php_mode_mod',
'basedir' => 'on',
'php_apache_version' => 'native',
'cgi' => 'off',
'log_access' => 'on',
'log_error' => 'on',
]);
// Storage
set('ispmanager_session', '');
set('ispmanager_databases', [
'servers' => [],
'hosts' => [],
'dblist' => [],
]);
set('ispmanager_domains', []);
set('ispmanager_phplist', []);
set('ispmanager_aliaslist', []);
desc('Installs ispmanager');
task('ispmanager:init', function () {
$config = get('ispmanager');
if (!is_null($config['createDatabase']) || !is_null($config['deleteDatabase'])) {
invoke('ispmanager:db-server-list');
invoke('ispmanager:db-list');
}
if (!is_null($config['createDomain']) || !is_null($config['deleteDomain'])) {
invoke('ispmanager:domain-list');
}
if (!is_null($config['phpSelect'])) {
invoke('ispmanager:domain-list');
invoke('ispmanager:get-php-list');
}
if (!is_null($config['createAlias']) || !is_null($config['deleteAlias'])) {
invoke('ispmanager:domain-list');
}
});
desc('Takes database servers list');
task('ispmanager:db-server-list', function () {
$response = ispmanagerRequest('get', [
'func' => 'db.server',
]);
$hostList = [];
$serverList = [];
if (isset($response['doc']['elem']) && count($response['doc']['elem']) > 0) {
foreach ($response['doc']['elem'] as $dbServer) {
$serverList[$dbServer['name']['$']] = [
'host' => $dbServer['host']['$'],
'name' => $dbServer['name']['$'],
'version' => $dbServer['savedver']['$'],
];
if (!strpos($dbServer['host']['$'], ':')) {
$dbHost = $dbServer['host']['$'] . ':3306';
} else {
$dbHost = $dbServer['host']['$'];
}
$hostList[$dbHost] = [
'host' => $dbHost,
'name' => $dbServer['name']['$'],
'version' => $dbServer['savedver']['$'],
];
}
}
add('ispmanager_databases', [
'servers' => $serverList,
'hosts' => $hostList,
]);
});
desc('Takes databases list');
task('ispmanager:db-list', function () {
$response = ispmanagerRequest('get', [
'func' => 'db',
]);
$dbList = [];
if (isset($response['doc']['elem']) && count($response['doc']['elem']) > 0) {
foreach ($response['doc']['elem'] as $db) {
$dbList[$db['pair']['$']] = [
'name' => $db['name']['$'],
'server' => $db['server']['$'],
'location' => $db['pair']['$'],
];
}
}
add('ispmanager_databases', [
'dblist' => $dbList,
]);
});
desc('Takes domain list');
task('ispmanager:domain-list', function () {
$response = ispmanagerRequest('get', [
'func' => 'webdomain',
]);
$domainList = [];
if (isset($response['doc']['elem']) && count($response['doc']['elem']) > 0) {
foreach ($response['doc']['elem'] as $domain) {
$domainList[] = $domain['name']['$'];
}
}
add('ispmanager_domains', $domainList);
});
desc('Creates new database');
task('ispmanager:db-create', function () {
$config = get('ispmanager');
if (is_null($config['createDatabase'])) {
warning('Action for database create is not active');
return;
}
$dsnData = parse_url($config['createDatabase']['dsn']);
$dbInfo = get('ispmanager_databases');
$hostInfo = null;
foreach ($dbInfo['hosts'] as $hostData) {
if ($hostData['host'] == $dsnData['host'] . ':' . $dsnData['port']) {
$hostInfo = $hostData;
break;
}
}
if (is_null($hostInfo)) {
throw new Exception('Incorrect DB host');
}
$dbName = substr($dsnData['path'], 1);
$dbLocation = $dbName . '->' . $hostInfo['name'];
if (isset($dbInfo['dblist'][$dbLocation])) {
if (!isset($config['createDatabase']['skipIfExist']) || !$config['createDatabase']['skipIfExist']) {
throw new Exception('Database already exists!');
} else {
warning('Database already exists - skipping');
return;
}
}
$dbCreateRequest = [
'func' => 'db.edit',
'name' => $dbName,
'owner' => get('ispmanager_owner'),
'server' => $hostInfo['name'],
'charset' => $config['createDatabase']['charset'],
'sok' => 'ok',
];
if ($dsnData['user'] == '*') {
$dbCreateRequest['user'] = '*';
$dbCreateRequest['username'] = $dbName;
if ($dsnData['pass'] == '*') {
$dbCreateRequest['password'] = generatePassword(8);
} else {
$dbCreateRequest['password'] = $dsnData['pass'];
}
} else {
$dbCreateRequest['user'] = $dsnData['user'];
}
$response = ispmanagerRequest('post', $dbCreateRequest);
if (isset($response['doc']['error']['msg']['$'])) {
throw new Exception($response['doc']['error']['msg']['$']);
} else {
info('Database successfully created');
}
});
desc('Deletes database');
task('ispmanager:db-delete', function () {
$config = get('ispmanager');
if (is_null($config['deleteDatabase'])) {
warning('Action for database delete is not active');
return;
}
$dbInfo = get('ispmanager_databases');
$dsnData = parse_url($config['deleteDatabase']['dsn']);
$hostInfo = null;
foreach ($dbInfo['hosts'] as $hostData) {
if ($hostData['host'] == $dsnData['host'] . ':' . $dsnData['port']) {
$hostInfo = $hostData;
break;
}
}
if (is_null($hostInfo)) {
throw new Exception('Incorrect DB host');
}
$dbName = substr($dsnData['path'], 1);
$dbLocation = $dbName . '->' . $hostInfo['name'];
if (!isset($dbInfo['dblist'][$dbLocation])) {
if (!isset($config['deleteDatabase']['skipIfNotExist']) || !$config['deleteDatabase']['skipIfNotExist']) {
throw new Exception('Database not exist!');
} else {
warning('Database not exist - skipping');
return;
}
}
$dbDeleteRequest = [
'func' => 'db.delete',
'elid' => $dbLocation,
];
$response = ispmanagerRequest('post', $dbDeleteRequest);
if (isset($response['doc']['error']['msg']['$'])) {
throw new Exception($response['doc']['error']['msg']['$']);
} else {
info('Database successfully deleted');
}
});
desc('Creates new domain');
task('ispmanager:domain-create', function () {
$config = get('ispmanager');
if (is_null($config['createDomain'])) {
warning('Action for domain create is not active');
return;
}
if (!isset($config['createDomain']['name']) || $config['createDomain']['name'] == '') {
throw new Exception('Invalid domain name!');
}
// Check domain exists
$existDomains = get('ispmanager_domains');
if (in_array($config['createDomain']['name'], $existDomains)) {
if (!isset($config['createDomain']['skipIfExist']) || !$config['createDomain']['skipIfExist']) {
throw new Exception('Domain already exists!');
} else {
warning('Domain already exists - skipping');
return;
}
}
// Build vhost create request
$vhostTemplate = get('vhost');
$domainCreateRequest = [
'func' => 'webdomain.edit',
'sok' => 'ok',
];
foreach ($vhostTemplate as $key => $value) {
$domainCreateRequest[$key] = str_replace('{{domain}}', $config['createDomain']['name'], $vhostTemplate[$key]);
}
$response = ispmanagerRequest('post', $domainCreateRequest);
if (isset($response['doc']['error']['msg']['$'])) {
throw new Exception($response['doc']['error']['msg']['$']);
} else {
info('Domain successfully created');
}
});
desc('Gets allowed PHP modes and versions');
task('ispmanager:get-php-list', function () {
// Get www-root settings for fpm version
$response = ispmanagerRequest('get', [
'func' => 'user.edit',
'elid' => get('ispmanager_owner'),
'elname' => get('ispmanager_owner'),
]);
$userFPMVersion = $response['doc']['limit_php_fpm_version']['$'] ?? null;
$response = ispmanagerRequest('get', [
'func' => 'phpversions',
]);
$versions = [];
foreach ($response['doc']['elem'] as $phpVersion) {
$versions[$phpVersion['key']['$']] = [
'name' => $phpVersion['name']['$'],
'php_mode_mod' => false,
'php_mode_cgi' => false,
'php_mode_fcgi_apache' => false,
'php_mode_fcgi_nginxfpm' => false,
];
if (isset($phpVersion['default_apache']) && $phpVersion['default_apache']['$'] == 'on') {
$versions[$phpVersion['key']['$']]['php_mode_mod'] = true;
}
if (isset($phpVersion['cgi']) && $phpVersion['cgi']['$'] == 'on') {
$versions[$phpVersion['key']['$']]['php_mode_cgi'] = true;
}
if (isset($phpVersion['apache']) && $phpVersion['apache']['$'] == 'on') {
$versions[$phpVersion['key']['$']]['php_mode_fcgi_apache'] = true;
}
if (isset($phpVersion['fpm']) && $phpVersion['fpm']['$'] == 'on' && $phpVersion['key']['$'] == $userFPMVersion) {
$versions[$phpVersion['key']['$']]['php_mode_fcgi_nginxfpm'] = true;
}
}
add('ispmanager_phplist', $versions);
});
desc('Prints allowed PHP modes and versions');
task('ispmanager:print-php-list', function () {
invoke('ispmanager:get-php-list');
$versions = get('ispmanager_phplist');
writeln("PHP versions: ");
writeln(str_repeat('*', 32));
foreach ($versions as $versionKey => $versionData) {
writeln('PHP ' . $versionData['name'] . ' (ID: ' . $versionKey . ')');
writeln(str_repeat('*', 32));
if (!$versionData['php_mode_mod']) {
writeln('Apache module support (php_mode_mod) - <fg=red;options=bold>NO</>');
} else {
writeln('Apache module support (php_mode_mod) - <fg=green;options=bold>YES</>');
}
if (!$versionData['php_mode_cgi']) {
writeln('CGI support (php_mode_cgi) - <fg=red;options=bold>NO</>');
} else {
writeln('CGI support (php_mode_cgi) - <fg=green;options=bold>YES</>');
}
if (!$versionData['php_mode_fcgi_apache']) {
writeln('Apache fast-cgi support (php_mode_fcgi_apache) - <fg=red;options=bold>NO</>');
} else {
writeln('Apache fast-cgi support (php_mode_fcgi_apache) - <fg=green;options=bold>YES</>');
}
if (!$versionData['php_mode_fcgi_nginxfpm']) {
writeln('nginx fast-cgi support (php_mode_fcgi_nginxfpm) - <fg=red;options=bold>NO</>');
} else {
writeln('nginx fast-cgi support (php_mode_fcgi_nginxfpm) - <fg=green;options=bold>YES</>');
}
writeln(str_repeat('*', 32));
}
});
desc('Switches PHP version for domain');
task('ispmanager:domain-php-select', function () {
$config = get('ispmanager');
if (is_null($config['phpSelect'])) {
warning('Action for domain update is not active');
return;
}
if (!isset($config['phpSelect']['name']) || $config['phpSelect']['name'] == '') {
throw new Exception('Invalid domain name!');
}
$existDomains = get('ispmanager_domains');
if (!in_array($config['phpSelect']['name'], $existDomains)) {
throw new Exception('Domain not exist!');
}
if (!isset($config['phpSelect']['mode']) || !isset($config['phpSelect']['version'])) {
throw new Exception('Incorrect settings for select php version');
}
$phpVersions = get('ispmanager_phplist');
$newVersion = $config['phpSelect']['version'];
$newMode = $config['phpSelect']['mode'];
if (!isset($phpVersions[$newVersion])) {
throw new Exception('Incorrect php version');
}
$versionData = $phpVersions[$newVersion];
if (!isset($versionData[$newMode]) || !$versionData[$newMode]) {
throw new Exception('Incorrect php mode');
}
$domainUpdateRequest = [
'func' => 'webdomain.edit',
'elid' => $config['phpSelect']['name'],
'name' => $config['phpSelect']['name'],
'php_mode' => $newMode,
'sok' => 'ok',
];
if ($newMode == 'php_mode_mod') {
$domainUpdateRequest['php_apache_version'] = $newVersion;
} elseif ($newMode == 'php_mode_cgi') {
$domainUpdateRequest['php_cgi_version'] = $newVersion;
} elseif ($newMode == 'php_mode_fcgi_apache') {
$domainUpdateRequest['php_cgi_version'] = $newVersion;
$domainUpdateRequest['php_apache_version'] = $newVersion;
} elseif ($newMode == 'php_mode_fcgi_nginxfpm') {
$domainUpdateRequest['php_cgi_version'] = $newVersion;
$domainUpdateRequest['php_fpm_version'] = $newVersion;
} else {
throw new Exception('Unknown PHP mode!');
}
$response = ispmanagerRequest('post', $domainUpdateRequest);
if (isset($response['doc']['error']['msg']['$'])) {
throw new Exception($response['doc']['error']['msg']['$']);
} else {
info('PHP successfully selected');
}
});
desc('Creates new domain alias');
task('ispmanager:domain-alias-create', function () {
$config = get('ispmanager');
if (is_null($config['createAlias'])) {
warning('Action for alias create is not active');
return;
}
if (!isset($config['createAlias']['name']) || $config['createAlias']['name'] == '') {
throw new Exception('Invalid domain name!');
}
$existDomains = get('ispmanager_domains');
if (!in_array($config['createAlias']['name'], $existDomains)) {
throw new Exception('Domain not exist!');
}
if (!isset($config['createAlias']['alias']) || $config['createAlias']['alias'] == '') {
throw new Exception('Invalid alias name!');
}
// Get current domain data
$response = ispmanagerRequest('get', [
'func' => 'webdomain.edit',
'elid' => $config['createAlias']['name'],
'elname' => $config['createAlias']['name'],
]);
$existAliases = [];
if (isset($response['doc']['aliases']['$'])) {
$existAliases = explode(' ', $response['doc']['aliases']['$']);
}
$newAliasList = [];
$createAliasList = explode(' ', $config['createAlias']['alias']);
foreach ($createAliasList as $createAlias) {
if (in_array($createAlias, $existAliases)) {
if (!isset($config['createAlias']['skipIfExist']) || !$config['createAlias']['skipIfExist']) {
throw new Exception('Alias already exists!');
} else {
warning('Alias ' . $createAlias . ' already exists - skipping');
continue;
}
}
$newAliasList[] = $createAlias;
}
$saveAliases = array_merge($existAliases, $newAliasList);
$domainUpdateRequest = [
'func' => 'webdomain.edit',
'elid' => $config['createAlias']['name'],
'name' => $config['createAlias']['name'],
'aliases' => implode(' ', $saveAliases),
'sok' => 'ok',
];
$response = ispmanagerRequest('post', $domainUpdateRequest);
if (isset($response['doc']['error']['msg']['$'])) {
throw new Exception($response['doc']['error']['msg']['$']);
} else {
info('Alias successfully created');
}
});
desc('Deletes domain alias');
task('ispmanager:domain-alias-delete', function () {
$config = get('ispmanager');
if (is_null($config['deleteAlias'])) {
warning('Action for alias create is not active');
return;
}
if (!isset($config['deleteAlias']['name']) || $config['deleteAlias']['name'] == '') {
throw new Exception('Invalid domain name!');
}
$existDomains = get('ispmanager_domains');
if (!in_array($config['deleteAlias']['name'], $existDomains)) {
throw new Exception('Domain not exist!');
}
if (!isset($config['deleteAlias']['alias']) || $config['deleteAlias']['alias'] == '') {
throw new Exception('Invalid alias name!');
}
// Get current domain data
$response = ispmanagerRequest('get', [
'func' => 'webdomain.edit',
'elid' => $config['createAlias']['name'],
'elname' => $config['createAlias']['name'],
]);
$existAliases = [];
if (isset($response['doc']['aliases']['$'])) {
$existAliases = explode(' ', $response['doc']['aliases']['$']);
}
$deleteAliasList = explode(' ', $config['deleteAlias']['alias']);
foreach ($deleteAliasList as $deleteAlias) {
if (!in_array($deleteAlias, $existAliases)) {
if (!isset($config['deleteAlias']['skipIfNotExist']) || !$config['deleteAlias']['skipIfNotExist']) {
throw new Exception('Alias not exist!');
} else {
warning('Alias ' . $deleteAlias . ' not exist - skipping');
continue;
}
}
if (($index = array_search($deleteAlias, $existAliases)) !== false) {
unset($existAliases[$index]);
}
}
$domainUpdateRequest = [
'func' => 'webdomain.edit',
'elid' => $config['deleteAlias']['name'],
'name' => $config['deleteAlias']['name'],
'aliases' => implode(' ', $existAliases),
'sok' => 'ok',
];
$response = ispmanagerRequest('post', $domainUpdateRequest);
if (isset($response['doc']['error']['msg']['$'])) {
throw new Exception($response['doc']['error']['msg']['$']);
} else {
info('Alias successfully deleted');
}
});
desc('Deletes domain');
task('ispmanager:domain-delete', function () {
$config = get('ispmanager');
if (is_null($config['deleteDomain'])) {
warning('Action for domain delete is not active');
return;
}
if (!isset($config['deleteDomain']['name']) || $config['deleteDomain']['name'] == '') {
throw new Exception('Invalid domain name!');
}
// Check domain exists
$existDomains = get('ispmanager_domains');
if (!in_array($config['deleteDomain']['name'], $existDomains)) {
if (!isset($config['deleteDomain']['skipIfNotExist']) || !$config['deleteDomain']['skipIfNotExist']) {
throw new Exception('Domain not exist!');
} else {
warning('Domain not exist - skipping');
return;
}
}
// Build request
$domainDeleteRequest = [
'func' => 'webdomain.delete.confirm',
'elid' => $config['deleteDomain']['name'],
'sok' => 'ok',
];
if (!isset($config['deleteDomain']['removeDir']) || !$config['deleteDomain']['removeDir']) {
$domainDeleteRequest['remove_directory'] = 'off';
} else {
$domainDeleteRequest['remove_directory'] = 'on';
}
$response = ispmanagerRequest('post', $domainDeleteRequest);
if (isset($response['doc']['error']['msg']['$'])) {
throw new Exception($response['doc']['error']['msg']['$']);
} else {
info('Domain successfully deleted');
}
});
desc('Auto task processing');
task('ispmanager:process', function () {
$config = get('ispmanager');
if (!is_null($config['createDatabase'])) {
invoke('ispmanager:db-create');
}
if (!is_null($config['deleteDatabase'])) {
invoke('ispmanager:db-delete');
}
if (!is_null($config['createDomain'])) {
invoke('ispmanager:domain-create');
}
if (!is_null($config['deleteDomain'])) {
invoke('ispmanager:domain-delete');
}
if (!is_null($config['phpSelect'])) {
invoke('ispmanager:domain-php-select');
}
if (!is_null($config['createAlias'])) {
invoke('ispmanager:domain-alias-create');
}
if (!is_null($config['deleteAlias'])) {
invoke('ispmanager:domain-alias-delete');
}
});
function ispmanagerRequest($method, $requestData)
{
$config = get('ispmanager');
$dsnData = parse_url($config['api']['dsn']);
$requestUrl = $dsnData['scheme'] . '://' . $dsnData['host'] . ':' . $dsnData['port'] . $dsnData['path'];
if ($config['api']['secure'] && get('ispmanager_session') == '') {
ispmanagerAuthRequest($requestUrl, $dsnData['user'], $dsnData['pass']);
}
if ($method == 'post') {
return Httpie::post($requestUrl)
->formBody(prepareRequest($requestData))
->setopt(CURLOPT_SSL_VERIFYPEER, false)
->setopt(CURLOPT_SSL_VERIFYHOST, false)
->getJson();
} elseif ($method == 'get') {
return Httpie::get($requestUrl)
->query(prepareRequest($requestData))
->setopt(CURLOPT_SSL_VERIFYPEER, false)
->setopt(CURLOPT_SSL_VERIFYHOST, false)
->getJson();
} else {
throw new Exception('Unknown request method');
}
}
function ispmanagerAuthRequest($url, $login, $pass)
{
$authRequestData = [
'func' => 'auth',
'username' => $login,
'password' => $pass,
];
$responseData = Httpie::post($url)
->setopt(CURLOPT_SSL_VERIFYPEER, false)
->setopt(CURLOPT_SSL_VERIFYHOST, false)
->formBody(prepareRequest($authRequestData))
->getJson();
if (isset($responseData['doc']['auth']['$id'])) {
set('ispmanager_session', $responseData['doc']['auth']['$id']);
} else {
throw new Exception('Error while create auth session');
}
}
function prepareRequest($requestData)
{
$config = get('ispmanager');
$dsnData = parse_url($config['api']['dsn']);
if (!isset($requestData['out'])) {
$requestData['out'] = 'json';
}
if (!$config['api']['secure']) {
$requestData['authinfo'] = $dsnData['user'] . ':' . $dsnData['pass'];
} else {
if (get('ispmanager_session') != '') {
$requestData['auth'] = get('ispmanager_session');
}
}
return $requestData;
}
function generatePassword($lenght)
{
return substr(md5(uniqid()), 0, $lenght);
}
// Callbacks before actions under domains
before('ispmanager:domain-alias-create', 'ispmanager:init');
before('ispmanager:domain-alias-delete', 'ispmanager:init');
before('ispmanager:domain-create', 'ispmanager:init');
before('ispmanager:domain-delete', 'ispmanager:init');
before('ispmanager:domain-php-select', 'ispmanager:init');
// Callbacks before actions under databases
before('ispmanager:db-create', 'ispmanager:init');
before('ispmanager:db-delete', 'ispmanager:init');
================================================
FILE: contrib/mattermost.php
================================================
<?php
/*
## Installing
Create a Mattermost incoming webhook, through the administration panel.
Add hook on deploy:
```
before('deploy', 'mattermost:notify');
```
## Configuration
- `mattermost_webhook` - incoming mattermost webook **required**
```
set('mattermost_webook', 'https://{your-mattermost-site}/hooks/xxx-generatedkey-xxx');
```
- `mattermost_channel` - overrides the channel the message posts in
```
set('mattermost_channel', 'town-square');
```
- `mattermost_username` - overrides the username the message posts as
```
set('mattermost_username', 'deployer');
```
- `mattermost_icon_url` - overrides the profile picture the message posts with
```
set('mattermost_icon_url', 'https://domain.com/your-icon.png');
```
- `mattermost_text` - notification message
```
set('mattermost_text', '_{{user}}_ deploying `{{what}}` to **{{where}}**');
```
- `mattermost_success_text` – success template, default:
```
set('mattermost_success_text', 'Deploy to **{{where}}** successful {{mattermost_success_emoji}}');
```
- `mattermost_failure_text` – failure template, default:
```
set('mattermost_failure_text', 'Deploy to **{{where}}** failed {{mattermost_failure_emoji}}');
```
- `mattermost_success_emoji` – emoji added at the end of success text
- `mattermost_failure_emoji` – emoji added at the end of failure text
For detailed information about Mattermost hooks see: https://developers.mattermost.com/integrate/incoming-webhooks/
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'mattermost:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'mattermost:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'mattermost:notify:failure');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
set('mattermost_webhook', null);
set('mattermost_channel', null);
set('mattermost_username', 'deployer');
set('mattermost_icon_url', null);
set('mattermost_success_emoji', ':white_check_mark:');
set('mattermost_failure_emoji', ':x:');
set('mattermost_text', '_{{user}}_ deploying `{{what}}` to **{{where}}**');
set('mattermost_success_text', 'Deploy to **{{where}}** successful {{mattermost_success_emoji}}');
set('mattermost_failure_text', 'Deploy to **{{where}}** failed {{mattermost_failure_emoji}}');
desc('Notifies mattermost');
task('mattermost:notify', function () {
if (null === get('mattermost_webhook')) {
return;
}
$body = [
'text' => get('mattermost_text'),
'username' => get('mattermost_username'),
];
if (get('mattermost_channel')) {
$body['channel'] = get('mattermost_channel');
}
if (get('mattermost_icon_url')) {
$body['icon_url'] = get('mattermost_icon_url');
}
Httpie::post(get('mattermost_webhook'))->jsonBody($body)->send();
});
desc('Notifies mattermost about deploy finish');
task('mattermost:notify:success', function () {
if (null === get('mattermost_webhook')) {
return;
}
$body = [
'text' => get('mattermost_success_text'),
'username' => get('mattermost_username'),
];
if (get('mattermost_channel')) {
$body['channel'] = get('mattermost_channel');
}
if (get('mattermost_icon_url')) {
$body['icon_url'] = get('mattermost_icon_url');
}
Httpie::post(get('mattermost_webhook'))->jsonBody($body)->send();
});
desc('Notifies mattermost about deploy failure');
task('mattermost:notify:failure', function () {
if (null === get('mattermost_webhook')) {
return;
}
$body = [
'text' => get('mattermost_failure_text'),
'username' => get('mattermost_username'),
];
if (get('mattermost_channel')) {
$body['channel'] = get('mattermost_channel');
}
if (get('mattermost_icon_url')) {
$body['icon_url'] = get('mattermost_icon_url');
}
Httpie::post(get('mattermost_webhook'))->jsonBody($body)->send();
});
================================================
FILE: contrib/ms-teams.php
================================================
<?php
/*
## Installing
Require ms-teams recipe in your `deploy.php` file:
Setup:
1. Open MS Teams
2. Navigate to Teams section
3. Select existing or create new team
4. Select existing or create new channel
5. Hover over channel to get three dots, click, in menu select "Connectors"
6. Search for and configure "Incoming Webhook"
7. Confirm/create and copy your Webhook URL
8. Setup deploy.php
Add in header:
```php
require 'contrib/ms-teams.php';
set('teams_webhook', 'https://outlook.office.com/webhook/...');
```
Add in content:
```php
before('deploy', 'teams:notify');
after('deploy:success', 'teams:notify:success');
after('deploy:failed', 'teams:notify:failure');
```
9.) Sip your coffee
## Configuration
- `teams_webhook` – teams incoming webhook url, **required**
```
set('teams_webhook', 'https://outlook.office.com/webhook/...');
```
- `teams_title` – the title of application, default `{{application}}`
- `teams_text` – notification message template, markdown supported
```
set('teams_text', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
```
- `teams_success_text` – success template, default:
```
set('teams_success_text', 'Deploy to *{{where}}* successful');
```
- `teams_failure_text` – failure template, default:
```
set('teams_failure_text', 'Deploy to *{{where}}* failed');
```
- `teams_color` – color's attachment
- `teams_success_color` – success color's attachment
- `teams_failure_color` – failure color's attachment
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'teams:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'teams:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'teams:notify:failure');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
// Title of project
set('teams_title', function () {
return get('application', 'Project');
});
// Allow Continue on Failure
set('teams_failure_continue', false);
// Deploy message
set('teams_text', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
set('teams_success_text', 'Deploy to *{{where}}* successful');
set('teams_failure_text', 'Deploy to *{{where}}* failed');
// Color of attachment
set('teams_color', '#4d91f7');
set('teams_success_color', '#00c100');
set('teams_failure_color', '#ff0909');
desc('Notifies Teams');
task('teams:notify', function () {
if (!get('teams_webhook', false)) {
warning('No MS Teams webhook configured');
return;
}
try {
Httpie::post(get('teams_webhook'))->jsonBody([
"themeColor" => get('teams_color'),
'text' => get('teams_text'),
])->send();
} catch (\Exception $e) {
if (get('teams_failure_continue', false)) {
warning('Error sending Teams Notification: ' . $e->getMessage());
} else {
throw $e;
}
}
})
->once()
->hidden();
desc('Notifies Teams about deploy finish');
task('teams:notify:success', function () {
if (!get('teams_webhook', false)) {
warning('No MS Teams webhook configured');
return;
}
try {
Httpie::post(get('teams_webhook'))->jsonBody([
"themeColor" => get('teams_success_color'),
'text' => get('teams_success_text'),
])->send();
} catch (\Exception $e) {
if (get('teams_failure_continue', false)) {
warning('Error sending Teams Notification: ' . $e->getMessage());
} else {
throw $e;
}
}
})
->once()
->hidden();
desc('Notifies Teams about deploy failure');
task('teams:notify:failure', function () {
if (!get('teams_webhook', false)) {
warning('No MS Teams webhook configured');
return;
}
try {
Httpie::post(get('teams_webhook'))->jsonBody([
"themeColor" => get('teams_failure_color'),
'text' => get('teams_failure_text'),
])->send();
} catch (\Exception $e) {
if (get('teams_failure_continue', false)) {
warning('Error sending Teams Notification: ' . $e->getMessage());
} else {
throw $e;
}
}
})
->once()
->hidden();
================================================
FILE: contrib/newrelic.php
================================================
<?php
/*
## Configuration
- `newrelic_app_id` – newrelic's app id
- `newrelic_api_key` – newrelic's api key
- `newrelic_description` – message to send
- `newrelic_endpoint` – newrelic's REST API endpoint
## Usage
Since you should only notify New Relic of a successful deployment, the `newrelic:notify` task should be executed right at the end.
```php
after('deploy', 'newrelic:notify');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
set('newrelic_app_id', function () {
throw new \Exception('Please, configure "newrelic_app_id" parameter.');
});
set('newrelic_description', function () {
return runLocally('git log -n 1 --format="%an: %s" | tr \'"\' "\'"');
});
set('newrelic_revision', function () {
return runLocally('git log -n 1 --format="%h"');
});
set('newrelic_endpoint', 'api.newrelic.com');
desc('Notifies New Relic of deployment');
task('newrelic:notify', function () {
if (($appId = get('newrelic_app_id')) && ($apiKey = get('newrelic_api_key')) && ($endpoint = get('newrelic_endpoint'))) {
$data = [
'user' => get('user'),
'revision' => get('newrelic_revision'),
'description' => get('newrelic_description'),
];
Httpie::post("https://$endpoint/v2/applications/$appId/deployments.json")
->header("X-Api-Key", $apiKey)
->query(['deployment' => $data])
->send();
}
})
->once()
->hidden();
================================================
FILE: contrib/npm.php
================================================
<?php
/*
## Configuration
- `bin/npm` *(optional)*: set npm binary, automatically detected otherwise.
## Usage
```php
after('deploy:update_code', 'npm:install');
```
*/
namespace Deployer;
set('bin/npm', function () {
return which('npm');
});
// Uses `npm ci` command. This command is similar to npm install,
// except it's meant to be used in automated environments such as
// test platforms, continuous integration, and deployment -- or
// any situation where you want to make sure you're doing a clean
// install of your dependencies.
desc('Installs npm packages');
task('npm:install', function () {
run("cd {{release_path}} && {{bin/npm}} ci");
});
================================================
FILE: contrib/ntfy.php
================================================
<?php
/*
## Installing
Require ntfy.sh recipe in your `deploy.php` file:
Setup:
1. Setup deploy.php
Add in header:
```php
require 'contrib/ntfy.php';
set('ntfy_topic', 'ntfy.sh/mytopic');
```
Add in content:
```php
before('deploy', 'ntfy:notify');
after('deploy:success', 'ntfy:notify:success');
after('deploy:failed', 'ntfy:notify:failure');
```
9.) Sip your coffee
## Configuration
- `ntfy_server` – ntfy server url, default `ntfy.sh`
```
set('ntfy_server', 'ntfy.sh');
```
- `ntfy_topic` – ntfy topic, **required**
```
set('ntfy_topic', 'mysecrettopic');
```
- `ntfy_title` – the title of the message, default `{{application}}`
- `ntfy_text` – notification message template
```
set('ntfy_text', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
```
- `ntfy_tags` – notification message tags / emojis (comma separated)
```
set('ntfy_tags', `information_source`);
```
- `ntfy_priority` – notification message priority (integer)
```
set('ntfy_priority', 5);
```
- `ntfy_success_text` – success template, default:
```
set('ntfy_success_text', 'Deploy to *{{where}}* successful');
```
- `ntfy_success_tags` – success tags / emojis (comma separated)
```
set('ntfy_success_tags', `white_check_mark,champagne`);
```
- `ntfy_success_priority` – success notification message priority
- `ntfy_failure_text` – failure template, default:
```
set('ntfy_failure_text', 'Deploy to *{{where}}* failed');
```
- `ntfy_failure_tags` – failure tags / emojis (comma separated)
```
set('ntfy_failure_tags', `warning,skull`);
```
- `ntfy_failure_priority` – failure notification message priority
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'ntfy:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'ntfy:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'ntfy:notify:failure');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
set('ntfy_server', 'ntfy.sh');
// Title of project
set('ntfy_title', function () {
return get('application', 'Project');
});
// Deploy message
set('ntfy_text', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
set('ntfy_success_text', 'Deploy to *{{where}}* successful');
set('ntfy_failure_text', 'Deploy to *{{where}}* failed');
// Message tags
set('ntfy_tags', '');
set('ntfy_success_tags', '');
set('ntfy_failure_tags', '');
desc('Notifies ntfy server');
task('ntfy:notify', function () {
if (!get('ntfy_topic', false)) {
warning('No ntfy topic configured');
return;
}
Httpie::post(get('ntfy_server'))->jsonBody([
"topic" => get('ntfy_topic'),
"title" => get('ntfy_title'),
"message" => get('ntfy_text'),
"tags" => explode(",", get('ntfy_tags')),
"priority" => get('ntfy_priority'),
])->send();
})
->once()
->hidden();
desc('Notifies ntfy server about deploy finish');
task('ntfy:notify:success', function () {
if (!get('ntfy_topic', false)) {
warning('No ntfy topic configured');
return;
}
Httpie::post(get('ntfy_server'))->jsonBody([
"topic" => get('ntfy_topic'),
"title" => get('ntfy_title'),
"message" => get('ntfy_success_text'),
"tags" => explode(",", get('ntfy_success_tags')),
"priority" => get('ntfy_success_priority'),
])->send();
})
->once()
->hidden();
desc('Notifies ntfy server about deploy failure');
task('ntfy:notify:failure', function () {
if (!get('ntfy_topic', false)) {
warning('No ntfy topic configured');
return;
}
Httpie::post(get('ntfy_server'))->jsonBody([
"topic" => get('ntfy_topic'),
"title" => get('ntfy_title'),
"message" => get('ntfy_failure_text'),
"tags" => explode(",", get('ntfy_failure_tags')),
"priority" => get('ntfy_failure_priority'),
])->send();
})
->once()
->hidden();
================================================
FILE: contrib/phinx.php
================================================
<?php
/*
## Configuration options
All options are in the config parameter `phinx` specified as an array (instead of the `phinx_path` variable).
All parameters are *optional*, but you can specify them with a dictionary (to change all parameters)
or by deployer dot notation (to change one option).
### Phinx params
- `phinx.environment`
- `phinx.date`
- `phinx.configuration` N.B. current directory is the project directory
- `phinx.target`
- `phinx.seed`
- `phinx.parser`
- `phinx.remove-all` (pass empty string as value)
### Phinx path params
- `phinx_path` Specify phinx path (by default phinx is searched for in $PATH, ./vendor/bin and ~/.composer/vendor/bin)
### Example of usage
```php
$phinx_env_vars = [
'environment' => 'development',
'configuration' => './migration/.phinx.yml',
'target' => '20120103083322',
'remove-all' => '',
];
set('phinx_path', '/usr/local/phinx/bin/phinx');
set('phinx', $phinx_env_vars);
after('cleanup', 'phinx:migrate');
// or set it for a specific server
host('dev')
->user('user')
->set('deploy_path', '/var/www')
->set('phinx', $phinx_env_vars)
->set('phinx_path', '');
```
## Suggested Usage
You can run all tasks before or after any
tasks (but you need to specify external configs for phinx).
If you use internal configs (which are in your project) you need
to run it after the `deploy:update_code` task is completed.
## Read more
For further reading see [phinx.org](https://phinx.org). Complete descriptions of all possible options can be found on the [commands page](http://docs.phinx.org/en/latest/commands.html).
*/
namespace Deployer;
use Deployer\Exception\RunException;
/*
* Phinx recipe for Deployer
*
* @author Alexey Boyko <ket4yiit@gmail.com>
* @contributor Security-Database <info@security-database.com>
* @copyright 2016 Alexey Boyko
* @license MIT https://github.com/deployphp/recipes/blob/master/LICENSE
*
* @link https://github.com/deployphp/recipes
*
* @see http://deployer.org
* @see https://phinx.org
*/
/**
* Path to Phinx
*/
set('bin/phinx', function () {
try {
$phinxPath = which('phinx');
} catch (RunException $e) {
$phinxPath = null;
}
if ($phinxPath !== null) {
return "phinx";
} elseif (test('[ -f {{release_path}}/vendor/bin/phinx ]')) {
return "{{release_path}}/vendor/bin/phinx";
} elseif (test('[ -f ~/.composer/vendor/bin/phinx ]')) {
return '~/.composer/vendor/bin/phinx';
} else {
throw new \RuntimeException('Cannot find phinx. Please specify path to phinx manually');
}
});
/**
* Make Phinx command
*
* @param string $cmdName Name of command
* @param array $conf Command options(config)
*
* @return string Phinx command to execute
*/
function phinx_get_cmd($cmdName, $conf)
{
$phinx = get('phinx_path') ?: get('bin/phinx');
$phinxCmd = "$phinx $cmdName";
$options = '';
foreach ($conf as $name => $value) {
$options .= " --$name $value";
}
$phinxCmd .= $options;
return $phinxCmd;
}
/**
* Returns options array that allowed for command
*
* @param array $allowedOptions List of allowed options
*
* @return array Array of options
*/
function phinx_get_allowed_config($allowedOptions)
{
$opts = [];
try {
foreach (get('phinx') as $key => $val) {
if (in_array($key, $allowedOptions)) {
$opts[$key] = $val;
}
}
} catch (\RuntimeException $e) {
}
return $opts;
}
desc('Migrats database with phinx');
task('phinx:migrate', function () {
$ALLOWED_OPTIONS = [
'configuration',
'date',
'environment',
'target',
'parser',
];
$conf = phinx_get_allowed_config($ALLOWED_OPTIONS);
cd('{{release_path}}');
$phinxCmd = phinx_get_cmd('migrate', $conf);
run($phinxCmd);
cd('{{deploy_path}}');
});
desc('Rollbacks database migrations with phinx');
task('phinx:rollback', function () {
$ALLOWED_OPTIONS = [
'configuration',
'date',
'environment',
'target',
'parser',
];
$conf = phinx_get_allowed_config($ALLOWED_OPTIONS);
cd('{{release_path}}');
$phinxCmd = phinx_get_cmd('rollback', $conf);
run($phinxCmd);
cd('{{deploy_path}}');
});
desc('Seeds database with phinx');
task('phinx:seed', function () {
$ALLOWED_OPTIONS = [
'configuration',
'environment',
'parser',
'seed',
];
$conf = phinx_get_allowed_config($ALLOWED_OPTIONS);
cd('{{release_path}}');
$phinxCmd = phinx_get_cmd('seed:run', $conf);
run($phinxCmd);
cd('{{deploy_path}}');
});
desc('Sets a migrations breakpoint with phinx');
task('phinx:breakpoint', function () {
$ALLOWED_OPTIONS = [
'configuration',
'environment',
'remove-all',
'target',
];
$conf = phinx_get_allowed_config($ALLOWED_OPTIONS);
cd('{{release_path}}');
$phinxCmd = phinx_get_cmd('breakpoint', $conf);
run($phinxCmd);
cd('{{deploy_path}}');
});
================================================
FILE: contrib/php-fpm.php
================================================
<?php
/*
:::caution
Do **not** reload php-fpm. Some user requests could fail or not complete in the
process of reloading.
Instead, configure your server [properly](avoid-php-fpm-reloading). If you're using Deployer's provision
recipe, it's already configured the right way and no php-fpm reload is needed.
:::
## Configuration
- `php_fpm_version` – The PHP-fpm version. For example: `8.0`.
- `php_fpm_service` – The full name of the PHP-fpm service. Defaults to `php{{php_fpm_version}}-fpm`.
- `php_fpm_command` – The command to run to reload PHP-fpm. Defaults to `sudo systemctl reload {{php_fpm_service}}`.
## Usage
Start by explicitely providing the current version of PHP-version using the `php_fpm_version`.
Alternatively, you may use any of the options above to configure how PHP-fpm should reload.
Then, add the `php-fpm:reload` task at the end of your deployments by using the `after` method like so.
```php
set('php_fpm_version', '8.0');
after('deploy', 'php-fpm:reload');
```
*/
namespace Deployer;
// Automatically detects by using {{bin/php}}.
set('php_fpm_version', function () {
return run('{{bin/php}} -r "printf(\'%d.%d\', PHP_MAJOR_VERSION, PHP_MINOR_VERSION);"');
});
set('php_fpm_service', 'php{{php_fpm_version}}-fpm');
desc('Reloads the php-fpm service');
task('php-fpm:reload', function () {
warning('Avoid reloading php-fpm [deployer.org/docs/8.x/avoid-php-fpm-reloading]');
run('sudo systemctl reload {{php_fpm_service}}');
});
================================================
FILE: contrib/rabbit.php
================================================
<?php
/*
### Installing
```php
// deploy.php
require 'recipe/rabbit.php';
```
### Configuration options
- **rabbit** *(required)*: accepts an *array* with the connection information to [rabbitmq](http://www.rabbitmq.com) server token and team name.
You can provide also other configuration options:
- *host* - default is localhost
- *port* - default is 5672
- *username* - default is *guest*
- *password* - default is *guest*
- *channel* - no default value, need to be specified via config
- *message* - default is **Deployment to '$host' on *$prod* was successful\n$releasePath**
- *vhost* - default is
```php
// deploy.php
set('rabbit', [
'host' => 'localhost',
'port' => '5672',
'username' => 'guest',
'password' => 'guest',
'channel' => 'notify-channel',
'vhost' => '/my-app'
]);
```
### Suggested Usage
Since you should only notify RabbitMQ channel of a successful deployment, the `deploy:rabbit` task should be executed right at the end.
```php
// deploy.php
before('deploy:end', 'deploy:rabbit');
```
*/
namespace Deployer;
use Deployer\Task\Context;
use PhpAmqpLib\Connection\AMQPConnection;
use PhpAmqpLib\Message\AMQPMessage;
desc('Notifies RabbitMQ channel about deployment');
task('deploy:rabbit', function () {
if (!class_exists('PhpAmqpLib\Connection\AMQPConnection')) {
throw new \RuntimeException("<comment>Please install php package</comment> <info>videlalvaro/php-amqplib</info> <comment>to use rabbitmq</comment>");
}
$config = get('rabbit', []);
if (!isset($config['message'])) {
$releasePath = get('release_path');
$host = Context::get()->getHost();
$stage = get('stage', false);
$stageInfo = ($stage) ? sprintf(' on *%s*', $stage) : '';
$message = "Deployment to '%s'%s was successful\n(%s)";
$config['message'] = sprintf(
$message,
$host->getHostname(),
$stageInfo,
$releasePath,
);
}
$defaultConfig = [
'host' => 'localhost',
'port' => 5672,
'username' => 'guest',
'password' => 'guest',
'vhost' => '/',
];
$config = array_merge($defaultConfig, $config);
if (!is_array($config) ||
!isset($config['channel']) ||
!isset($config['host']) ||
!isset($config['port']) ||
!isset($config['username']) ||
!isset($config['password']) ||
!isset($config['vhost'])) {
throw new \RuntimeException("<comment>Please configure rabbit config:</comment> <info>set('rabbit', array('channel' => 'channel', 'host' => 'host', 'port' => 'port', 'username' => 'username', 'password' => 'password'));</info>");
}
$connection = new AMQPConnection($config['host'], $config['port'], $config['username'], $config['password'], $config['vhost']);
$channel = $connection->channel();
$msg = new AMQPMessage($config['message']);
$channel->basic_publish($msg, $config['channel'], $config['channel']);
$channel->close();
$connection->close();
});
================================================
FILE: contrib/raygun.php
================================================
<?php
/*
## Configuration
- `raygun_api_key` – the API key of your Raygun application
- `raygun_version` – the version of your application that this deployment is releasing
- `raygun_owner_name` – the name of the person creating this deployment
- `raygun_email` – the email of the person creating this deployment
- `raygun_comment` – the deployment notes
- `raygun_scm_identifier` – the commit that this deployment was built off
- `raygun_scm_type` - the source control system you use
## Usage
To notify Raygun of a successful deployment, you can use the 'raygun:notify' task after a deployment.
```php
after('deploy', 'raygun:notify');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
desc('Notifies Raygun of deployment');
task('raygun:notify', function () {
$data = [
'apiKey' => get('raygun_api_key'),
'version' => get('raygun_version'),
'ownerName' => get('raygun_owner_name'),
'emailAddress' => get('raygun_email'),
'comment' => get('raygun_comment'),
'scmIdentifier' => get('raygun_scm_identifier'),
'scmType' => get('raygun_scm_type'),
];
Httpie::post('https://app.raygun.io/deployments')
->jsonBody($data)
->send();
});
================================================
FILE: contrib/rocketchat.php
================================================
<?php
/*
## Installing
Create a RocketChat incoming webhook, through the administration panel.
Add hook on deploy:
```
before('deploy', 'rocketchat:notify');
```
## Configuration
- `rocketchat_webhook` - incoming rocketchat webook **required**
```
set('rocketchat_webhook', 'https://rocketchat.yourcompany.com/hooks/XXXXX');
```
- `rocketchat_title` - the title of the application, defaults to `{{application}}`
- `rocketchat_text` - notification message
```
set('rocketchat_text', '_{{user}}_ deploying {{what}} to {{where}}');
```
- `rocketchat_success_text` – success template, default:
```
set('rocketchat_success_text', 'Deploy to *{{where}}* successful');
```
- `rocketchat_failure_text` – failure template, default:
```
set('rocketchat_failure_text', 'Deploy to *{{where}}* failed');
```
- `rocketchat_color` – color's attachment
- `rocketchat_success_color` – success color's attachment
- `rocketchat_failure_color` – failure color's attachment
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'rocketchat:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'rocketchat:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'rocketchat:notify:failure');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
set('rockchat_title', function () {
return get('application', 'Project');
});
set('rocketchat_icon_emoji', ':robot:');
set('rocketchat_icon_url', null);
set('rocketchat_channel', null);
set('rocketchat_room_id', null);
set('rocketchat_username', null);
set('rocketchat_webhook', null);
set('rocketchat_color', '#000000');
set('rocketchat_success_color', '#00c100');
set('rocketchat_failure_color', '#ff0909');
set('rocketchat_text', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
set('rocketchat_success_text', 'Deploy to *{{where}}* successful');
set('rocketchat_failure_text', 'Deploy to *{{where}}* failed');
desc('Notifies RocketChat');
task('rocketchat:notify', function () {
if (null === get('rocketchat_webhook')) {
return;
}
$body = [
'text' => get('rockchat_title'),
'username' => get('rocketchat_username'),
'attachments' => [[
'text' => get('rocketchat_text'),
'color' => get('rocketchat_color'),
]],
];
if (get('rocketchat_channel')) {
$body['channel'] = get('rocketchat_channel');
}
if (get('rocketchat_room_id')) {
$body['roomId'] = get('rocketchat_room_id');
}
if (get('rocketchat_icon_url')) {
$body['avatar'] = get('rocketchat_icon_url');
} elseif (get('rocketchat_icon_emoji')) {
$body['emoji'] = get('rocketchat_icon_emoji');
}
Httpie::post(get('rocketchat_webhook'))->jsonBody($body)->send();
});
desc('Notifies RocketChat about deploy finish');
task('rocketchat:notify:success', function () {
if (null === get('rocketchat_webhook')) {
return;
}
$body = [
'text' => get('rockchat_title'),
'username' => get('rocketchat_username'),
'attachments' => [[
'text' => get('rocketchat_success_text'),
'color' => get('rocketchat_success_color'),
]],
];
if (get('rocketchat_channel')) {
$body['channel'] = get('rocketchat_channel');
}
if (get('rocketchat_room_id')) {
$body['roomId'] = get('rocketchat_room_id');
}
if (get('rocketchat_icon_url')) {
$body['avatar'] = get('rocketchat_icon_url');
} elseif (get('rocketchat_icon_emoji')) {
$body['emoji'] = get('rocketchat_icon_emoji');
}
Httpie::post(get('rocketchat_webhook'))->jsonBody($body)->send();
});
desc('Notifies RocketChat about deploy failure');
task('rocketchat:notify:failure', function () {
if (null === get('rocketchat_webhook')) {
return;
}
$body = [
'text' => get('rockchat_title'),
'username' => get('rocketchat_username'),
'attachments' => [[
'color' => get('rocketchat_failure_color'),
'text' => get('rocketchat_failure_text'),
]],
];
if (get('rocketchat_channel')) {
$body['channel'] = get('rocketchat_channel');
}
if (get('rocketchat_room_id')) {
$body['roomId'] = get('rocketchat_room_id');
}
if (get('rocketchat_icon_url')) {
$body['avatar'] = get('rocketchat_icon_url');
} elseif (get('rocketchat_icon_emoji')) {
$body['emoji'] = get('rocketchat_icon_emoji');
}
Httpie::post(get('rocketchat_webhook'))->jsonBody($body)->send();
});
================================================
FILE: contrib/rollbar.php
================================================
<?php
/*
## Configuration
- `rollbar_token` – access token to rollbar api
- `rollbar_comment` – comment about deploy, default to
```php
set('rollbar_comment', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
```
- `rollbar_username` – rollbar user name
## Usage
Since you should only notify Rollbar channel of a successful deployment, the `rollbar:notify` task should be executed right at the end.
```php
after('deploy', 'rollbar:notify');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
set('rollbar_comment', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
desc('Notifies Rollbar of deployment');
task('rollbar:notify', function () {
if (!get('rollbar_token', false)) {
return;
}
$params = [
'access_token' => get('rollbar_token'),
'environment' => get('where'),
'revision' => runLocally('git log -n 1 --format="%h"'),
'local_username' => get('user'),
'rollbar_username' => get('rollbar_username'),
'comment' => get('rollbar_comment'),
];
Httpie::post('https://api.rollbar.com/api/1/deploy/')
->formBody($params)
->send();
})
->once();
================================================
FILE: contrib/rsync.php
================================================
<?php
/*
:::warning
This must not be confused with `/src/Utility/Rsync.php`, deployer's built-in rsync. Their configuration options are also very different, read carefully below.
:::
## Configuration options
- **rsync**: Accepts an array with following rsync options (all are optional and defaults are ok):
- *exclude*: accepts an *array* with patterns to be excluded from sending to server
- *exclude-file*: accepts a *string* containing absolute path to file, which contains exclude patterns
- *include*: accepts an *array* with patterns to be included in sending to server
- *include-file*: accepts a *string* containing absolute path to file, which contains include patterns
- *filter*: accepts an *array* of rsync filter rules
- *filter-file*: accepts a *string* containing merge-file filename.
- *filter-perdir*: accepts a *string* containing merge-file filename to be scanned and merger per each directory in rsync list on files to send
- *flags*: accepts a *string* of flags to set when calling rsync command. Please **avoid** flags that accept params, and use *options* instead.
- *options*: accepts an *array* of options to set when calling rsync command. **DO NOT** prefix options with `--` as it's automatically added.
- *timeout*: accepts an *int* defining timeout for rsync command to run locally.
### Sample Configuration:
Following is default configuration. By default rsync ignores only git dir and `deploy.php` file.
```php
// deploy.php
set('rsync',[
'exclude' => [
'.git',
'deploy.php',
],
'exclude-file' => false,
'include' => [],
'include-file' => false,
'filter' => [],
'filter-file' => false,
'filter-perdir'=> false,
'flags' => 'rz', // Recursive, with compress
'options' => ['delete'],
'timeout' => 60,
]);
```
If You have multiple excludes, You can put them in file and reference that instead. If You use `deploy:rsync_warmup` You could set additional options that could speed-up and/or affect way things are working. For example:
```php
// deploy.php
set('rsync',[
'exclude' => ['excludes_file'],
'exclude-file' => '/tmp/localdeploys/excludes_file', //Use absolute path to avoid possible rsync problems
'include' => [],
'include-file' => false,
'filter' => [],
'filter-file' => false,
'filter-perdir' => false,
'flags' => 'rzcE', // Recursive, with compress, check based on checksum rather than time/size, preserve Executable flag
'options' => ['delete', 'delete-after', 'force'], //Delete after successful transfer, delete even if deleted dir is not empty
'timeout' => 3600, //for those huge repos or crappy connection
]);
```
### Parameter
- **rsync_src**: per-host rsync source. This can be server, stage or whatever-dependent. By default it's set to current directory
- **rsync_dest**: per-host rsync destination. This can be server, stage or whatever-dependent. by default it's equivalent to release deploy destination.
### Sample configurations:
This is default configuration:
```php
set('rsync_src', __DIR__);
set('rsync_dest','{{release_path}}');
```
If You use local deploy recipe You can set src to local release:
```php
host('hostname')
->hostname('10.10.10.10')
->port(22)
->set('deploy_path','/your/remote/path/app')
->set('rsync_src', '/your/local/path/app')
->set('rsync_dest','{{release_path}}');
```
## Usage
- `rsync` task
Set `rsync_src` to locally cloned repository and rsync to `rsync_dest`. Then set this task instead of `deploy:update_code` in Your `deploy` task if Your hosting provider does not allow git.
- `rsync:warmup` task
If Your deploy task looks like:
```php
task('deploy', [
'deploy:prepare',
'deploy:release',
'rsync',
'deploy:vendors',
'deploy:symlink',
])->desc('Deploy your project');
```
And Your `rsync_dest` is set to `{{release_path}}` then You could add this task to run before `rsync` task or after `deploy:release`, whatever is more convenient.
*/
namespace Deployer;
use Deployer\Host\Localhost;
use Deployer\Task\Context;
set('rsync', [
'exclude' => [
'.git',
'deploy.php',
],
'exclude-file' => false,
'include' => [],
'include-file' => false,
'filter' => [],
'filter-file' => false,
'filter-perdir' => false,
'flags' => 'rz',
'options' => ['delete'],
'timeout' => 300,
]);
set('rsync_src', __DIR__);
set('rsync_dest', '{{release_path}}');
set('rsync_excludes', function () {
$config = get('rsync');
$excludes = $config['exclude'];
$excludeFile = $config['exclude-file'];
$excludesRsync = '';
foreach ($excludes as $exclude) {
$excludesRsync .= ' --exclude=' . escapeshellarg($exclude);
}
if (!empty($excludeFile) && file_exists($excludeFile) && is_file($excludeFile) && is_readable($excludeFile)) {
$excludesRsync .= ' --exclude-from=' . escapeshellarg($excludeFile);
}
return $excludesRsync;
});
set('rsync_includes', function () {
$config = get('rsync');
$includes = $config['include'];
$includeFile = $config['include-file'];
$includesRsync = '';
foreach ($includes as $include) {
$includesRsync .= ' --include=' . escapeshellarg($include);
}
if (!empty($includeFile) && file_exists($includeFile) && is_file($includeFile) && is_readable($includeFile)) {
$includesRsync .= ' --include-from=' . escapeshellarg($includeFile);
}
return $includesRsync;
});
set('rsync_filter', function () {
$config = get('rsync');
$filters = $config['filter'];
$filterFile = $config['filter-file'];
$filterPerDir = $config['filter-perdir'];
$filtersRsync = '';
foreach ($filters as $filter) {
$filtersRsync .= " --filter='$filter'";
}
if (!empty($filterFile)) {
$filtersRsync .= " --filter='merge $filterFile'";
}
if (!empty($filterPerDir)) {
$filtersRsync .= " --filter='dir-merge $filterPerDir'";
}
return $filtersRsync;
});
set('rsync_options', function () {
$config = get('rsync');
$options = $config['options'];
$optionsRsync = [];
foreach ($options as $option) {
$optionsRsync[] = "--$option";
}
return implode(' ', $optionsRsync);
});
desc('Warmups remote Rsync target');
task('rsync:warmup', function () {
$config = get('rsync');
$source = "{{current_path}}";
$destination = "{{deploy_path}}/release";
if (test("[ -d $(echo $source) ]")) {
run("rsync -{$config['flags']} {{rsync_options}}{{rsync_excludes}}{{rsync_includes}}{{rsync_filter}} $source/ $destination/");
} else {
writeln("<comment>No way to warmup rsync.</comment>");
}
});
desc('Rsync local->remote');
task('rsync', function () {
$config = get('rsync');
$src = get('rsync_src');
while (is_callable($src)) {
$src = $src();
}
if (!trim($src)) {
// if $src is not set here rsync is going to do a directory listing
// exiting with code 0, since only doing a directory listing clearly
// is not what we want to achieve we need to throw an exception
throw new \RuntimeException('You need to specify a source path.');
}
$dst = get('rsync_dest');
while (is_callable($dst)) {
$dst = $dst();
}
if (!trim($dst)) {
// if $dst is not set here we are going to sync to root
// and even worse - depending on rsync flags and permission -
// might end up deleting everything we have write permission to
throw new \RuntimeException('You need to specify a destination path.');
}
$rsyncFlags = (is_string($config['flags']) && trim($config['flags']) !== '') ? "-{$config['flags']}" : '';
$host = Context::get()->getHost();
if ($host instanceof Localhost) {
runLocally("rsync {$rsyncFlags} {{rsync_options}}{{rsync_includes}}{{rsync_excludes}}{{rsync_filter}} '$src/' '$dst/'", timeout: $config['timeout']);
return;
}
$sshArguments = $host->connectionOptionsString();
runLocally("rsync {$rsyncFlags} -e 'ssh $sshArguments' {{rsync_options}}{{rsync_includes}}{{rsync_excludes}}{{rsync_filter}} '$src/' '{$host->connectionString()}:$dst/'", timeout: $config['timeout']);
});
================================================
FILE: contrib/sentry.php
================================================
<?php
/*
### Configuration options
- **organization** *(required)*: the slug of the organization the release belongs to.
- **projects** *(required)*: array of slugs of the projects to create a release for.
- **token** *(required)*: authentication token. Can be created at [https://sentry.io/settings/account/api/auth-tokens/]
- **version** *(required)* – a version identifier for this release.
Can be a version number, a commit hash etc. (Defaults is set to git log -n 1 --format="%h".)
- **version_prefix** *(optional)* - a string prefixed to version.
Releases are global per organization so indipentent projects needs to prefix version number with unique string to avoid conflicts
- **environment** *(optional)* - the environment you’re deploying to. By default framework's environment is used.
For example for symfony, *symfony_env* configuration is read otherwise defaults to 'prod'.
- **ref** *(optional)* – an optional commit reference. This is useful if a tagged version has been provided.
- **refs** *(optional)* - array to indicate the start and end commits for each repository included in a release.
Head commits must include parameters *repository* and *commit*) (the HEAD sha).
They can optionally include *previousCommit* (the sha of the HEAD of the previous release),
which should be specified if this is the first time you’ve sent commit data.
- **commits** *(optional)* - array commits data to be associated with the release.
Commits must include parameters *id* (the sha of the commit), and can optionally include *repository*,
*message*, *author_name*, *author_email* and *timestamp*. By default will send all new commits,
unless it's a first release, then only first 200 will be sent.
- **url** *(optional)* – a URL that points to the release. This can be the path to an online interface to the sourcecode for instance.
- **date_released** *(optional)* – date that indicates when the release went live. If not provided the current time is assumed.
- **sentry_server** *(optional)* – sentry server (if you host it yourself). defaults to hosted sentry service.
- **date_deploy_started** *(optional)* - date that indicates when the deploy started. Defaults to current time.
- **date_deploy_finished** *(optional)* - date that indicates when the deploy ended. If not provided, the current time is used.
- **deploy_name** *(optional)* - name of the deploy
- **git_version_command** *(optional)* - the command that retrieves the git version information (Defaults is set to git log -n 1 --format="%h", other options are git describe --tags --abbrev=0)
```php
// deploy.php
set('sentry', [
'organization' => 'exampleorg',
'projects' => [
'exampleproj'
],
'token' => 'd47828...',
'version' => '0.0.1',
]);
```
### Suggested Usage
Since you should only notify Sentry of a successful deployment, the deploy:sentry task should be executed right at the end.
```php
// deploy.php
after('deploy', 'deploy:sentry');
```
*/
namespace Deployer;
use Closure;
use DateTime;
use Deployer\Exception\ConfigurationException;
use Deployer\Utility\Httpie;
desc('Notifies Sentry of deployment');
task(
'deploy:sentry',
static function () {
$now = date('c');
$defaultConfig = [
'version' => getReleaseGitRef(),
'version_prefix' => null,
'refs' => [],
'ref' => null,
'commits' => getGitCommitsRefs(),
'url' => null,
'date_released' => $now,
'date_deploy_started' => $now,
'date_deploy_finished' => $now,
'sentry_server' => 'https://sentry.io',
'previous_commit' => null,
'environment' => get('symfony_env', 'prod'),
'deploy_name' => null,
];
$config = array_merge($defaultConfig, (array) get('sentry'));
array_walk(
$config,
static function (&$value) use ($config) {
if (is_callable($value)) {
$value = $value($config);
}
},
);
if (
!isset($config['organization'], $config['token'], $config['version'])
|| (empty($config['projects']) || !is_array($config['projects']))
) {
throw new \RuntimeException(
<<<EXAMPLE
Required data missing. Please configure sentry:
set(
'sentry',
[
'organization' => 'exampleorg',
'projects' => [
'exampleproj',
'exampleproje2'
],
'token' => 'd47828...',
]
);"
EXAMPLE,
);
}
$releaseData = array_filter(
[
'version' => ($config['version_prefix'] ?? '') . $config['version'],
'refs' => $config['refs'],
'ref' => $config['ref'],
'url' => $config['url'],
'commits' => array_slice($config['commits'] ?? [], 0), // reset keys to serialize as array in json
'dateReleased' => $config['date_released'],
'projects' => $config['projects'],
'previousCommit' => $config['previous_commit'],
],
);
$releasesApiUrl = $config['sentry_server'] . '/api/0/organizations/' . $config['organization'] . '/releases/';
$response = Httpie::post(
$releasesApiUrl,
)
->setopt(CURLOPT_TIMEOUT, 10)
->header('Authorization', sprintf('Bearer %s', $config['token']))
->jsonBody($releaseData)
->getJson();
if (!isset($response['version'], $response['projects'])) {
throw new \RuntimeException(sprintf('Unable to create a release: %s', print_r($response, true)));
}
writeln(
sprintf(
'<info>Sentry:</info> Release of version <comment>%s</comment> ' .
'for projects: <comment>%s</comment> created successfully.',
$response['version'],
implode(', ', array_column($response['projects'], 'slug')),
),
);
$deployData = array_filter(
[
'environment' => $config['environment'],
'name' => $config['deploy_name'],
'url' => $config['url'],
'dateStarted' => $config['date_deploy_started'],
'dateFinished' => $config['date_deploy_finished'],
],
);
$response = Httpie::post(
$releasesApiUrl . $response['version'] . '/deploys/',
)
->setopt(CURLOPT_TIMEOUT, 10)
->header('Authorization', sprintf('Bearer %s', $config['token']))
->jsonBody($deployData)
->getJson();
if (!isset($response['id'], $response['environment'])) {
throw new \RuntimeException(sprintf('Unable to create a deployment: %s', print_r($response, true)));
}
writeln(
sprintf(
'<info>Sentry:</info> Deployment <comment>%s</comment> ' .
'for environment <comment>%s</comment> created successfully',
$response['id'],
$response['environment'],
),
);
},
);
function getPreviousReleaseRevision()
{
switch (get('update_code_strategy')) {
case 'local_archive':
case 'archive':
if (has('previous_release')) {
return run('cat {{previous_release}}/REVISION');
}
return null;
case 'clone':
if (has('previous_release')) {
cd('{{previous_release}}');
return trim(run('git rev-parse HEAD'));
}
return null;
default:
throw new ConfigurationException(parse("Unknown `update_code_strategy` option: {{update_code_strategy}}."));
}
}
function getCurrentReleaseRevision()
{
switch (get('update_code_strategy')) {
case 'local_archive':
case 'archive':
return run('cat {{release_path}}/REVISION');
case 'clone':
cd('{{release_path}}');
return trim(run('git rev-parse HEAD'));
default:
throw new ConfigurationException(parse("Unknown `update_code_strategy` option: {{update_code_strategy}}."));
}
}
function getReleaseGitRef(): Closure
{
return static function ($config = []): string {
$strategy = get('update_code_strategy');
if ($strategy === 'archive') {
cd('{{deploy_path}}/.dep/repo');
} else {
cd('{{release_path}}');
}
if (isset($config['git_version_command'])) {
return trim(run($config['git_version_command']));
}
if ($strategy !== 'clone') {
return run('cat {{current_path}}/REVISION');
}
return trim(run('git log -n 1 --format="%h"'));
};
}
function getGitCommitsRefs(): Closure
{
return static function ($config = []): array {
$previousReleaseRevision = getPreviousReleaseRevision();
$currentReleaseRevision = getCurrentReleaseRevision() ?: 'HEAD';
if ($previousReleaseRevision === null) {
$commitRange = $currentReleaseRevision;
} else {
$commitRange = $previousReleaseRevision . '..' . $currentReleaseRevision;
}
try {
if (get('update_code_strategy') === 'archive') {
cd('{{deploy_path}}/.dep/repo');
} else {
cd('{{release_path}}');
}
$result = run(sprintf('git rev-list --pretty="%s" %s', 'format:%H#%an#%ae#%at#%s', $commitRange));
$lines = array_filter(
// limit number of commits for first release with many commits
array_map('trim', array_slice(explode("\n", $result), 0, 200)),
static function (string $line): bool {
return !empty($line) && strpos($line, 'commit') !== 0;
},
);
return array_map(
static function (string $line): array {
[$ref, $authorName, $authorEmail, $timestamp, $message] = explode('#', $line, 5);
return [
'id' => $ref,
'author_name' => $authorName,
'author_email' => $authorEmail,
'message' => $message,
'timestamp' => date(\DateTime::ATOM, (int) $timestamp),
];
},
$lines,
);
} catch (\Deployer\Exception\RunException $e) {
writeln($e->getMessage());
return [];
}
};
}
================================================
FILE: contrib/slack.php
================================================
<?php
/*
## Installing
<a href="https://slack.com/oauth/authorize?&client_id=113734341365.225973502034&scope=incoming-webhook"><img alt="Add to Slack" height="40" width="139" src="https://platform.slack-edge.com/img/add_to_slack.png" srcset="https://platform.slack-edge.com/img/add_to_slack.png 1x, https://platform.slack-edge.com/img/add_to_slack@2x.png 2x" /></a>
Add hook on deploy:
```php
before('deploy', 'slack:notify');
```
## Configuration
- `slack_webhook` – slack incoming webhook url, **required**
```
set('slack_webhook', 'https://hooks.slack.com/...');
```
- `slack_channel` - channel to send notification to. The default is the channel configured in the webhook
- `slack_title` – the title of application, default `{{application}}`
- `slack_text` – notification message template, markdown supported
```
set('slack_text', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
```
- `slack_success_text` – success template, default:
```
set('slack_success_text', 'Deploy to *{{where}}* successful');
```
- `slack_failure_text` – failure template, default:
```
set('slack_failure_text', 'Deploy to *{{where}}* failed');
```
- `slack_color` – color's attachment
- `slack_success_color` – success color's attachment
- `slack_failure_color` – failure color's attachment
- `slack_fields` - set attachments fields for pretty output in Slack, default:
```
set('slack_fields', []);
```
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'slack:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'slack:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'slack:notify:failure');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
// Channel to publish to, when false the default channel the webhook will be used
set('slack_channel', false);
// Title of project
set('slack_title', function () {
return get('application', 'Project');
});
// Deploy message
set('slack_text', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
set('slack_success_text', 'Deploy to *{{where}}* successful');
set('slack_failure_text', 'Deploy to *{{where}}* failed');
set('slack_rollback_text', '_{{user}}_ rolled back changes on *{{where}}*');
set('slack_fields', []);
// Color of attachment
set('slack_color', '#4d91f7');
set('slack_success_color', '#00c100');
set('slack_failure_color', '#ff0909');
set('slack_rollback_color', '#eba211');
function checkSlackAnswer($result)
{
if ('invalid_token' === $result) {
warning('Invalid Slack token');
return false;
}
return true;
}
desc('Notifies Slack');
task('slack:notify', function () {
if (!get('slack_webhook', false)) {
warning('No Slack webhook configured');
return;
}
$attachment = [
'title' => get('slack_title'),
'text' => get('slack_text'),
'color' => get('slack_color'),
'mrkdwn_in' => ['text'],
];
$result = Httpie::post(get('slack_webhook'))->jsonBody(['channel' => get('slack_channel'), 'attachments' => [$attachment]])->send();
checkSlackAnswer($result);
})
->once()
->hidden();
desc('Notifies Slack about deploy finish');
task('slack:notify:success', function () {
if (!get('slack_webhook', false)) {
warning('No Slack webhook configured');
return;
}
$attachment = [
'title' => get('slack_title'),
'text' => get('slack_success_text'),
'color' => get('slack_success_color'),
'fields' => get('slack_fields'),
'mrkdwn_in' => ['text'],
];
$result = Httpie::post(get('slack_webhook'))->jsonBody(['channel' => get('slack_channel'), 'attachments' => [$attachment]])->send();
checkSlackAnswer($result);
})
->once()
->hidden();
desc('Notifies Slack about deploy failure');
task('slack:notify:failure', function () {
if (!get('slack_webhook', false)) {
warning('No Slack webhook configured');
return;
}
$attachment = [
'title' => get('slack_title'),
'text' => get('slack_failure_text'),
'color' => get('slack_failure_color'),
'mrkdwn_in' => ['text'],
];
$result = Httpie::post(get('slack_webhook'))->jsonBody(['channel' => get('slack_channel'), 'attachments' => [$attachment]])->send();
checkSlackAnswer($result);
})
->once()
->hidden();
desc('Notifies Slack about rollback');
task('slack:notify:rollback', function () {
if (!get('slack_webhook', false)) {
warning('No Slack webhook configured');
return;
}
$attachment = [
'title' => get('slack_title'),
'text' => get('slack_rollback_text'),
'color' => get('slack_rollback_color'),
'mrkdwn_in' => ['text'],
];
$result = Httpie::post(get('slack_webhook'))->jsonBody(['channel' => get('slack_channel'), 'attachments' => [$attachment]])->send();
checkSlackAnswer($result);
})
->once()
->hidden();
================================================
FILE: contrib/supervisord-monitor.php
================================================
<?php
/*
### Description
This is a recipe that uses the [Supervisord server monitoring project](https://github.com/mlazarov/supervisord-monitor).
With this recipe the possibility is created to restart a supervisord process through the Supervisor Monitor webtool, by using cURL. This workaround is particular usefull when the deployment user has unsuficient rights to restart a daemon process from the cli.
### Configuration
```
set('supervisord', [
'uri' => 'https://youruri.xyz/supervisor',
'basic_auth_user' => 'username',
'basic_auth_password' => 'password',
'process_name' => 'process01',
]);
```
or
```
set('supervisord_uri', 'https://youruri.xyz/supervisor');
set('supervisord_basic_auth_user', 'username');
set('supervisord_basic_auth_password', 'password');
set('supervisord_process_name', 'process01');
```
- `supervisord` – array with configuration for Supervisord
- `uri` – URI to the Supervisord monitor page
- `basic_auth_user` – Basic auth username to access the URI
- `basic_auth_password` – Basic auth password to access the URI
- `process_name` – the process name, as visible in the Supervisord monitor page. Multiple processes can be listed here, comma separated
### Task
- `supervisord-monitor:restart` Restarts given processes
- `supervisord-monitor:stop` Stops given processes
- `supervisord-monitor:start` Starts given processes
### Usage
A complete example with configs, staging and deployment
```
<?php
namespace Deployer;
use Dotenv\Dotenv;
require 'vendor/autoload.php';
require 'supervisord_monitor.php';
// Project name
set('application', 'myproject.com');
// Project repository
set('repository', 'git@github.com:myorg/myproject.com');
set('supervisord', [
'uri' => 'https://youruri.xyz/supervisor',
'basic_auth_user' => 'username',
'basic_auth_password' => 'password',
'process_name' => 'process01',
]);
host('staging.myproject.com')
->set('branch', 'develop')
->set('labels', ['stage' => 'staging']);
host('myproject.com')
->set('branch', 'main')
->set('labels', ['stage' => 'production']);
// Tasks
task('build', function () {
run('cd {{release_path}} && build');
});
task('deploy', [
'build',
'supervisord',
]);
task('supervisord', ['supervisord-monitor:restart'])
->select('stage=production');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
function supervisordCheckConfig()
{
$config = get('supervisord', []);
foreach ($config as $key => $value) {
if ($value) {
set('supervisord_' . $key, $value);
}
}
if (!get('supervisord_uri') ||
!get('supervisord_basic_auth_user') ||
!get('supervisord_basic_auth_password') ||
!get('supervisord_process_name')) {
throw new \RuntimeException("<comment>Please configure Supervisord config:</comment> <info>set('supervisord', array('uri' => 'yourdomain.xyz/supervisor', 'basic_auth_user' => 'abc' , 'basic_auth_password' => 'xyz', 'process_name' => 'process01,process02'));</info> or <info>set('supervisord_uri', 'yourdomain.xyz/supervisor'); set('supervisord_basic_auth_user', 'abc'); etc</info>");
}
}
function supervisordGetBasicAuthToken()
{
return 'Basic ' . base64_encode(get('supervisord_basic_auth_user') . ':' . get('supervisord_basic_auth_password'));
}
function supervisordIsAuthenticated()
{
supervisordCheckConfig();
$authResponseInfo = [];
Httpie::post(get('supervisord_uri'))->header('Authorization', supervisordGetBasicAuthToken())->send($authResponseInfo);
return $authResponseInfo['http_code'] === 200;
}
function supervisordControlAction($name, $action = 'stop')
{
$stopResponseInfo = [];
Httpie::post(get('supervisord_uri') . '/control/' . $action . '/localhost/' . $name)->header('Authorization', supervisordGetBasicAuthToken())->send($stopResponseInfo);
return $stopResponseInfo['http_code'] === 200;
}
task('supervisord-monitor:restart', function () {
if (supervisordIsAuthenticated()) {
$names = explode(',', get('supervisord_process_name'));
foreach ($names as $name) {
$name = trim($name);
if (supervisordControlAction($name, 'stop')) {
writeln('Daemon [' . $name . '] stopped');
if (supervisordControlAction($name, 'start')) {
writeln('Daemon [' . $name . '] started');
}
}
}
} else {
writeln('Authentication failed');
}
});
task('supervisord-monitor:stop', function () {
if (supervisordIsAuthenticated()) {
$names = explode(',', get('supervisord_process_name'));
foreach ($names as $name) {
$name = trim($name);
if (supervisordControlAction($name, 'stop')) {
writeln('Daemon [' . $name . '] stopped');
}
}
} else {
writeln('Authentication failed');
}
});
task('supervisord-monitor:start', function () {
if (supervisordIsAuthenticated()) {
$names = explode(',', get('supervisord_process_name'));
foreach ($names as $name) {
$name = trim($name);
if (supervisordControlAction($name, 'start')) {
writeln('Daemon [' . $name . '] started');
}
}
} else {
writeln('Authentication failed');
}
});
================================================
FILE: contrib/telegram.php
================================================
<?php
/*
## Installing
1. Create telegram bot with [BotFather](https://t.me/BotFather) and grab the token provided
2. Send `/start` to your bot and open https://api.telegram.org/bot{$TELEGRAM_TOKEN_HERE}/getUpdates
3. Take chat_id from response
Add hook on deploy:
```php
before('deploy', 'telegram:notify');
```
## Configuration
- `telegram_token` – telegram bot token, **required**
- `telegram_chat_id` — chat ID to push messages to
- `telegram_proxy` - proxy connection string in [CURLOPT_PROXY](https://curl.haxx.se/libcurl/c/CURLOPT_PROXY.html) form like:
```
http://proxy:80
socks5://user:password@host:3128
```
- `telegram_title` – the title of application, default `{{application}}`
- `telegram_text` – notification message template
```
_{{user}}_ deploying `{{what}}` to *{{where}}*
```
- `telegram_success_text` – success template, default:
```
Deploy to *{{where}}* successful
```
- `telegram_failure_text` – failure template, default:
```
Deploy to *{{where}}* failed
```
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'telegram:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'telegram:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'telegram:notify:failure');
*/
namespace Deployer;
use Deployer\Utility\Httpie;
// Title of project
set('telegram_title', function () {
return get('application', 'Project');
});
// Telegram settings
set('telegram_token', function () {
throw new \Exception('Please, configure "telegram_token" parameter.');
});
set('telegram_chat_id', function () {
throw new \Exception('Please, configure "telegram_chat_id" parameter.');
});
set('telegram_url', function () {
return 'https://api.telegram.org/bot' . get('telegram_token') . '/sendmessage';
});
// Deploy message
set('telegram_text', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
set('telegram_success_text', 'Deploy to *{{where}}* successful');
set('telegram_failure_text', 'Deploy to *{{where}}* failed');
desc('Notifies Telegram');
task('telegram:notify', function () {
if (!get('telegram_token', false)) {
warning('No Telegram token configured');
return;
}
if (!get('telegram_chat_id', false)) {
warning('No Telegram chat id configured');
return;
}
$telegramUrl = get('telegram_url') . '?' . http_build_query(
[
'chat_id' => get('telegram_chat_id'),
'text' => get('telegram_text'),
'parse_mode' => 'Markdown',
],
);
$httpie = Httpie::get($telegramUrl);
if (get('telegram_proxy', '') !== '') {
$httpie = $httpie->setopt(CURLOPT_PROXY, get('telegram_proxy'));
}
$httpie->send();
})
->once()
->hidden();
desc('Notifies Telegram about deploy finish');
task('telegram:notify:success', function () {
if (!get('telegram_token', false)) {
warning('No Telegram token configured');
return;
}
if (!get('telegram_chat_id', false)) {
warning('No Telegram chat id configured');
return;
}
$telegramUrl = get('telegram_url') . '?' . http_build_query(
[
'chat_id' => get('telegram_chat_id'),
'text' => get('telegram_success_text'),
'parse_mode' => 'Markdown',
],
);
$httpie = Httpie::get($telegramUrl);
if (get('telegram_proxy', '') !== '') {
$httpie = $httpie->setopt(CURLOPT_PROXY, get('telegram_proxy'));
}
$httpie->send();
})
->once()
->hidden();
desc('Notifies Telegram about deploy failure');
task('telegram:notify:failure', function () {
if (!get('telegram_token', false)) {
warning('No Telegram token configured');
return;
}
if (!get('telegram_chat_id', false)) {
warning('No Telegram chat id configured');
return;
}
$telegramUrl = get('telegram_url') . '?' . http_build_query(
[
'chat_id' => get('telegram_chat_id'),
'text' => get('telegram_failure_text'),
'parse_mode' => 'Markdown',
],
);
$httpie = Httpie::get($telegramUrl);
if (get('telegram_proxy', '') !== '') {
$httpie = $httpie->setopt(CURLOPT_PROXY, get('telegram_proxy'));
}
$httpie->send();
})
->once()
->hidden();
================================================
FILE: contrib/webpack_encore.php
================================================
<?php
/*
## Configuration
- **webpack_encore/package_manager** *(optional)*: set yarn or npm. We try to find if yarn or npm is available and used.
## Usage
```php
// For Yarn
after('deploy:update_code', 'yarn:install');
// For npm
after('deploy:update_code', 'npm:install');
after('deploy:update_code', 'webpack_encore:build');
```
*/
namespace Deployer;
require_once __DIR__ . '/npm.php';
require_once __DIR__ . '/yarn.php';
set('webpack_encore/package_manager', function () {
if (test('[ -f {{release_path}}/yarn.lock ]')) {
return 'yarn';
}
return 'npm';
});
set('webpack_encore/env', 'production');
desc('Runs webpack encore build');
task('webpack_encore:build', function () {
$packageManager = get('webpack_encore/package_manager');
if (!in_array($packageManager, ['npm', 'yarn'], true)) {
throw new \Exception(sprintf('Package Manager "%s" is not supported', $packageManager));
}
run("cd {{release_path}} && {{bin/$packageManager}} run encore {{webpack_encore/env}}");
});
================================================
FILE: contrib/workplace.php
================================================
<?php
/*
This recipes works with Custom Integrations and Publishing Bots.
Add hook on deploy:
```
before('deploy', 'workplace:notify');
```
## Configuration
- `workplace_webhook` - incoming workplace webhook **required**
```
// With custom integration
set('workplace_webhook', 'https://graph.facebook.com/<GROUP_ID>/feed?access_token=<ACCESS_TOKEN>');
// With publishing bot
set('workplace_webhook', 'https://graph.facebook.com/v3.0/group/feed?access_token=<ACCESS_TOKEN>');
// Use markdown on message
set('workplace_webhook', 'https://graph.facebook.com/<GROUP_ID>/feed?access_token=<ACCESS_TOKEN>&formatting=MARKDOWN');
```
- `workplace_text` - notification message
```
set('workplace_text', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
```
- `workplace_success_text` – success template, default:
```
set('workplace_success_text', 'Deploy to *{{where}}* successful');
```
- `workplace_failure_text` – failure template, default:
```
set('workplace_failure_text', 'Deploy to *{{where}}* failed');
```
- `workplace_edit_post` – whether to create a new post for deploy result, or edit the first one created, default creates a new post:
```
set('workplace_edit_post', false);
```
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'workplace:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'workplace:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'workplace:notify:failure');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
// Deploy message
set('workplace_text', '_{{user}}_ deploying `{{what}}` to *{{where}}*');
set('workplace_success_text', 'Deploy to *{{where}}* successful');
set('workplace_failure_text', 'Deploy to *{{where}}* failed');
// By default, create a new post for every message
set('workplace_edit_post', false);
desc('Notifies Workplace');
task('workplace:notify', function () {
if (!get('workplace_webhook', false)) {
return;
}
$url = get('workplace_webhook') . '&message=' . urlencode(get('workplace_text'));
$response = Httpie::post($url)->getJson();
if (get('workplace_edit_post', false)) {
// Endpoint will be something like: https//graph.facebook.com/<POST_ID>?<QUERY_PARAMS>
$url = sprintf(
'%s://%s/%s?%s',
parse_url(get('workplace_webhook'), PHP_URL_SCHEME),
parse_url(get('workplace_webhook'), PHP_URL_HOST),
$response['id'],
parse_url(get('workplace_webhook'), PHP_URL_QUERY),
);
// Replace the webhook with a url that points to the created post
set('workplace_webhook', $url);
}
})
->once()
->hidden();
desc('Notifies Workplace about deploy finish');
task('workplace:notify:success', function () {
if (!get('workplace_webhook', false)) {
return;
}
$url = get('workplace_webhook') . '&message=' . urlencode(get('workplace_success_text'));
Httpie::post($url)->send();
})
->once()
->hidden();
desc('Notifies Workplace about deploy failure');
task('workplace:notify:failure', function () {
if (!get('workplace_webhook', false)) {
return;
}
$url = get('workplace_webhook') . '&message=' . urlencode(get('workplace_failure_text'));
Httpie::post($url)->send();
})
->once()
->hidden();
================================================
FILE: contrib/yammer.php
================================================
<?php
/*
Add hook on deploy:
```php
before('deploy', 'yammer:notify');
```
## Configuration
- `yammer_url` – The URL to the message endpoint, default is https://www.yammer.com/api/v1/messages.json
- `yammer_token` *(required)* – Yammer auth token
- `yammer_group_id` *(required)* - Group ID
- `yammer_title` – the title of application, default `{{application}}`
- `yammer_body` – notification message template, default:
```
<em>{{user}}</em> deploying {{what}} to <strong>{{where}}</strong>
```
- `yammer_success_body` – success template, default:
```
Deploy to <strong>{{where}}</strong> successful
```
- `yammer_failure_body` – failure template, default:
```
Deploy to <strong>{{where}}</strong> failed
```
## Usage
If you want to notify only about beginning of deployment add this line only:
```php
before('deploy', 'yammer:notify');
```
If you want to notify about successful end of deployment add this too:
```php
after('deploy:success', 'yammer:notify:success');
```
If you want to notify about failed deployment add this too:
```php
after('deploy:failed', 'yammer:notify:failure');
```
*/
namespace Deployer;
use Deployer\Utility\Httpie;
set('yammer_url', 'https://www.yammer.com/api/v1/messages.json');
// Title of project
set('yammer_title', function () {
return get('application', 'Project');
});
// Deploy message
set('yammer_body', '<em>{{user}}</em> deploying {{what}} to <strong>{{where}}</strong>');
set('yammer_success_body', 'Deploy to <strong>{{where}}</strong> successful');
set('yammer_failure_body', 'Deploy to <strong>{{where}}</strong> failed');
desc('Notifies Yammer');
task('yammer:notify', function () {
$params = [
'is_rich_text' => 'true',
'message_type' => 'announcement',
'group_id' => get('yammer_group_id'),
'title' => get('yammer_title'),
'body' => get('yammer_body'),
];
Httpie::post(get('yammer_url'))
->header('Authorization', 'Bearer ' . get('yammer_token'))
->header('Content-type', 'application/json')
->jsonBody($params)
->send();
})
->once()
->hidden();
desc('Notifies Yammer about deploy finish');
task('yammer:notify:success', function () {
$params = [
'is_rich_text' => 'true',
'message_type' => 'announcement',
'group_id' => get('yammer_group_id'),
'title' => get('yammer_title'),
'body' => get('yammer_success_body'),
];
Httpie::post(get('yammer_url'))
->header('Authorization', 'Bearer ' . get('yammer_token'))
->header('Content-type', 'application/json')
->jsonBody($params)
->send();
})
->once()
->hidden();
desc('Notifies Yammer about deploy failure');
task('yammer:notify:failure', function () {
$params = [
'is_rich_text' => 'true',
'message_type' => 'announcement',
'group_id' => get('yammer_group_id'),
'title' => get('yammer_title'),
'body' => get('yammer_failure_body'),
];
Httpie::post(get('yammer_url'))
->header('Authorization', 'Bearer ' . get('yammer_token'))
->header('Content-type', 'application/json')
->jsonBody($params)
->send();
})
->once()
->hidden();
================================================
FILE: contrib/yarn.php
================================================
<?php
/*
## Configuration
- **bin/yarn** *(optional)*: set Yarn binary, automatically detected otherwise.
## Usage
```php
after('deploy:update_code', 'yarn:install');
```
*/
namespace Deployer;
set('bin/yarn', function () {
return which('yarn');
});
// In there is a {{previous_release}}, node_modules will be copied from it before installing deps with yarn.
desc('Installs Yarn packages');
task('yarn:install', function () {
if (has('previous_release')) {
if (test('[ -d {{previous_release}}/node_modules ]')) {
run('cp -R {{previous_release}}/node_modules {{release_path}}');
}
}
run("cd {{release_path}} && {{bin/yarn}}");
});
================================================
FILE: docs/KNOWN_BUGS.md
================================================
# Known Bugs
## Ubuntu 14.04, Coreutils 8.21
There are known bugs with relative symlinks `ln --relative`, which may cause the rollback command to fail.
Add the following line to your _deploy.php_ file:
```php
set('use_relative_symlink', false);
```
## OpenSSH_7.2p2
ControlPersist causes stderr to be left open until the master connection times out.
- https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=714526
- https://bugzilla.mindrot.org/show_bug.cgi?id=1988
## cURL 7.29.0
Certificate verification fails with multiple https urls.
- https://bugzilla.redhat.com/show_bug.cgi?id=1241172
## Rsync (3.1.3)
Artifact upload with `rsync` is interrupted after the first chunk of data upload.
```
The command "rsync -azP -e 'ssh -A -p *** -o UserKnownHostsFile=/dev/null
-o StrictHostKeyChecking=no' 'artifacts/artifact.tar.gz' 'deploy@ssh.XXX.io:/srv/releases/2009076181'" failed.
Exit Code: 255(Unknown error)
Output:
================
sending incremental file list
artifact.tar.gz
32,768 0% 0.00kB/s 0:00:00
Error Output:
================
client_loop: send disconnect: Broken pipe
rsync: [sender] write error: Broken pipe (32)
```
In order to resolve (workaround) the issue, you need to add `--bwlimit=4096` to the list of options.
Example:
```php
task('artifact:upload', function () {
upload(get('artifact_path'), '{{release_path}}', ['options' => ['--bwlimit=4096']]);
});
```
The issue was also described in the [Github Action](https://github.com/deployphp/action/issues/35).
================================================
FILE: docs/UPGRADE.md
================================================
# Upgrade a major version
## Upgrade from 7.x to 8.x
- `run()` and `runLocally()` doesn't accept `options` parameter anymore. Use named arguments instead.
- `no_throw` is now `nothrow`.
- `real_time_output` is now `forceOutput`.
- `idle_timeout` is now `idleTimeout`.
## Upgrade from 6.x to 7.x
### Step 1: Update deploy.php
1. Change config `hostname` to `alias`.
2. Change config `real_hostname` to `hostname`.
3. Change config `user` to `remote_user`.
4. Update `host()` definitions:
1. Add `set` prefix to all setters: `identityFile` -> `setIdentityFile` or `set('identity_file')`
2. Update `host(...)->addSshOption('UserKnownHostsFile', '/dev/null')` to `host(...)->setSshArguments(['-o UserKnownHostsFile=/dev/null']);`
3. Replace _stage_ with labels, i.e.
```php
host('deployer.org')
->set('labels', ['stage' => 'prod']);
```
When deploying instead of `dep deploy prod` use `dep deploy stage=prod`.
4. `alias()` is deleted, `host()` itself sets alias and hostname, to override hostname use `setHostname()`.
5. Update `task()` definitions.
1. Replace `onRoles()` with `select()`:
```php
task(...)
->select('stage=prod');
```
2. Don't use string-based task definition, it's not available anymore. Don't forget to set correct working directory.
```php
# from
task('deploy:npm-install', 'npm clean-install');
# to
task('deploy:npm-install', function() {
cd('{{release_path}}');
run('npm clean-install');
});
```
3. Remove `shallow()` tasks options.
6. Third party recipes now live inside main Deployer repo in _contrib_:
```php
require 'contrib/rsync.php';
```
7. Replace `inventory()` with `import()`. It now can import hosts, configs, tasks:
```yaml
import: recipe/common.php
config:
application: deployer
shared_dirs:
- uploads
- storage/logs/
- storage/db
shared_files:
- .env
- config/test.yaml
keep_releases: 3
http_user: false
hosts:
prod:
local: true
tasks:
deploy:
- deploy:prepare
- deploy:vendors
- deploy:publish
deploy:vendors:
- run: "cd {{release_path}} && echo {{bin/composer}} {{composer_options}} 2>&1"
```
8. Rename task `success` to `deploy:success` and `cleanup` to `deploy:cleanup`.
9. Verbosity functions (`isDebug()`, etc) got deleted. Use `output()->isDebug()` instead.
10. `runLocally()` commands are executed relative to the recipe file directory. This behaviour can be overridden via an environment variable:
```
DEPLOYER_ROOT=. vendor/bin/dep taskname
```
11. Replace `local()` tasks with combination of `once()` and `runLocally()` func.
12. Replace `locateBinaryPath()` with `which()` func.
13. Replace `default_stage` with `default_selector`, and adjust the value accordingly (for example: "prod" to "stage=prod").
14. Replace `onHosts()` and `onStage()` with [labels & selectors](selector.md).
15. Replace `setPrivate()` with [`hidden()`](tasks.md#hidden).
16. Configuration property `writable_recursive` defaults to `false`. This behaviour can be overridden with:
```php
set('writable_recursive', true);
```
17. `.git` directory is not present in release directory anymore. The previous behavior can be restored with:
```php
set('update_code_strategy', 'clone');
```
### Step 2: Deploy
Since the release history numbering is not compatible between v6 and v7, you need to specify the `release_name` manually for the first time. Otherwise you start with release 1.
1. Find out next release name (ssh to the host, `ls` releases dir, find the biggest number). Example: `42`.
2. Deploy with release_name:
```
dep deploy -o release_name=43
```
:::note
In case a rollback is needed, manually change the `current` symlink:
```
ln -nfs releases/42 current
```
:::
:::note
In case there are multiple hosts with different release names, you should create a `{{deploy_path}}/.dep/latest_release` file in each host with the current release number of that particular host.
:::
## Upgrade from 5.x to 6.x
1. Changed branch option priority
If you have host definition with `branch(...)` parameter, adding `--branch` option will not override it any more.
If no `branch(...)` parameter persists, branch will be fetched from current local git branch.
```php
host('prod')
->set('branch', 'production')
```
In order to return to old behavior add checking of `--branch` option.
```php
host('prod')
->set('branch', function () {
return input()->getOption('branch') ?: 'production';
})
```
2. Add `deploy:info` task to the beginning to `deploy` task.
3. `run` returns string instead of `Deployer\Type\Result`
Now `run` and `runLocally` returns `string` instead of `Deployer\Type\Result`.
Replace method calls as:
- `run('command')->toString()` → `run('command')`
- `run('if command; then echo "true"; fi;')->toBool()` → `test('command')`
4. `env_vars` renamed to `env`
- `set('env_vars', 'FOO=bar');` → `set('env', ['FOO' => 'bar']);`
If your are using Symfony recipe, then you need to change `env` setting:
- `set('env', 'prod');` → `set('symfony_env', 'prod');`
## Upgrade from 4.x to 5.x
1. Servers to Hosts
- `server($hostname)` to `host($hostname)`, and `server($name, $hostname)` to `host($name)->hostname($hostname)`
- `localServer($name)` to `localhost()`
- `cluster($name, $nodes, $port)` to `hosts(...$hodes)`
- `serverList($file)` to `inventory($file)`
If you need to deploy to same server use [host aliases](https://deployer.org/docs/hosts#host-aliases):
```php
host('domain.com/green', 'domain.com/blue')
->set('deploy_path', '~/{{hostname}}')
...
```
Or you can define different hosts with same hostname:
```php
host('production')
->hostname('domain.com')
->set('deploy_path', '~/production')
...
host('beta')
->hostname('domain.com')
->set('deploy_path', '~/beta')
...
```
2. Configuration options
- Rename `{{server.name}}` to `{{hostname}}`
3. DotArray syntax
In v5 access to nested arrays in config via dot notation was removed.
If you was using it, consider to move to plain config options.
Refactor this:
```php
set('a', ['b' => 1]);
// ...
get('a.b');
```
To:
```php
set('a_b', 1);
// ...
get('a_b');
```
4. Credentials
Best practice in new v5 is to omit credentials for connection in `deploy.php` and write them in `~/.ssh/config` instead.
- `identityFile($publicKeyFile,, $privateKeyFile, $passPhrase)` to `identityFile($privateKeyFile)`
- `pemFile($pemFile)` to `identityFile($pemFile)`
- `forwardAgent()` to `forwardAgent(true)`
5. Tasks constraints
- `onlyOn` to `onHosts`
- `onlyOnStage` to `onStage`
## Upgrade from 3.x to 4.x
1. Namespace for functions
Add to beginning of _deploy.php_ next line:
```php
use function Deployer\{server, task, run, set, get, add, before, after};
```
If you are using PHP version less than 5.6, you can use this:
```php
namespace Deployer;
```
2. `env()` to `set()`/`get()`
Rename all calls `env($name, $value)` to `set($name, $value)`.
Rename all rvalue `env($name)` to `get($name)`.
Rename all `server(...)->env(...)` to `server(...)->set(...)`.
3. Moved _NonFatalException_
Rename `Deployer\Task\NonFatalException` to `Deployer\Exception\NonFatalException`.
4. Prior release cleanup
Due to changes in release management, the new cleanup task will ignore any prior releases deployed with 3.x. These will need to be manually removed after migrating to and successfully releasing via 4.x.
## Upgrade from 2.x to 3.x
1. ### `->path('...')`
Replace your server paths configuration:
```php
server(...)
->path(...);
```
to:
```php
server(...)
->env('deploy_path', '...');
```
================================================
FILE: docs/api.md
================================================
<!-- DO NOT EDIT THIS FILE! -->
<!-- Instead edit src/functions.php -->
<!-- Then run bin/docgen -->
# API Reference
## host()
```php
host(string ...$hostname): Host|ObjectProxy
```
Defines a host or hosts.
```php
host('example.org');
host('prod.example.org', 'staging.example.org');
```
Inside task can be used to get `Host` instance of an alias.
```php
task('test', function () {
$port = host('example.org')->get('port');
});
```
## localhost()
```php
localhost(string ...$hostnames): Localhost|ObjectProxy
```
Define a local host.
Deployer will not connect to this host, but will execute commands locally instead.
```php
localhost('ci'); // Alias and hostname will be "ci".
```
## currentHost()
```php
currentHost(): Host
```
Returns current host.
## select()
```php
select(string $selector): array
```
Returns hosts based on provided selector.
```php
on(select('stage=prod, role=db'), function (Host $host) {
...
});
```
## selectedHosts()
```php
selectedHosts(): array
```
Returns array of hosts selected by user via CLI.
## import()
```php
import(string $file): void
```
Import other php or yaml recipes.
```php
import('recipe/common.php');
```
```php
import(__DIR__ . '/config/hosts.yaml');
```
## desc()
```php
desc(?string $title = null): ?string
```
Set task description.
## task()
```php
task(string $name, callable|array|null $body = null): Task
```
Define a new task and save to tasks list.
Alternatively get a defined task.
| Argument | Type | Comment |
|---|---|---|
| `$name` | `string` | Name of current task. |
| `$body` | `callable` or `array` or `null` | Callable task, array of other tasks names or nothing to get a defined tasks |
## before()
```php
before(string $task, string|callable $do): ?Task
```
Call that task before specified task runs.
| Argument | Type | Comment |
|---|---|---|
| `$task` | `string` | The task before $that should be run. |
| `$do` | `string` or `callable` | The task to be run. |
## after()
```php
after(string $task, string|callable $do): ?Task
```
Call that task after specified task runs.
| Argument | Type | Comment |
|---|---|---|
| `$task` | `string` | The task after $that should be run. |
| `$do` | `string` or `callable` | The task to be run. |
## fail()
```php
fail(string $task, string|callable $do): ?Task
```
Setup which task run on failure of $task.
When called multiple times for a task, previous fail() definitions will be overridden.
| Argument | Type | Comment |
|---|---|---|
| `$task` | `string` | The task which need to fail so $that should be run. |
| `$do` | `string` or `callable` | The task to be run. |
## option()
```php
option(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null): void
```
Add users options.
| Argument | Type | Comment |
|---|---|---|
| `$name` | `string` | The option name |
| `$shortcut` | `string` or `array` or `null` | The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts |
| `$mode` | `int` or `null` | The option mode: One of the VALUE_* constants |
| `$description` | `string` | A description text |
| `$default` | `string` or `string[]` or `int` or `bool` or `null` | The default value (must be null for self::VALUE_NONE) |
## cd()
```php
cd(string $path): void
```
Change the current working directory.
```php
cd('~/myapp');
run('ls'); // Will run `ls` in ~/myapp.
```
## become()
```php
become(string $user): \Closure
```
Change the current user.
Usage:
```php
$restore = become('deployer');
// do something
$restore(); // revert back to the previous user
```
## within()
```php
within(string $path, callable $callback): mixed
```
Execute a callback within a specific directory and revert back to the initial working directory.
## run()
```php
run(
string $command,
?string $cwd = null,
?array $env = null,
#[\SensitiveParameter]
?string $secret = null,
?bool $nothrow = false,
?bool $forceOutput = false,
?int $timeout = null,
?int $idleTimeout = null,
): string
```
Executes given command on remote host.
Examples:
```php
run('echo hello world');
run('cd {{deploy_path}} && git status');
run('password %secret%', secret: getenv('CI_SECRET'));
run('curl medv.io', timeout: 5);
```
```php
$path = run('readlink {{deploy_path}}/current');
run("echo $path");
```
| Argument | Type | Comment |
|---|---|---|
| `$command` | `string` | Command to run on remote host. |
| `$cwd` | `string` or `null` | Sets the process working directory. If not set {{working_path}} will be used. |
| `$timeout` | `int` or `null` | Sets the process timeout (max. runtime). The timeout in seconds (default: 300 sec; see {{default_timeout}}, `null` to disable). |
| `$idleTimeout` | `int` or `null` | Sets the process idle timeout (max. time since last output) in seconds. |
| `$secret` | `string` or `null` | Placeholder `%secret%` can be used in command. Placeholder will be replaced with this value and will not appear in any logs. |
| `$env` | `array` or `null` | Array of environment variables: `run('echo $KEY', env: ['key' => 'value']);` |
| `$forceOutput` | `bool` or `null` | Print command output in real-time. |
| `$nothrow` | `bool` or `null` | Don't throw an exception of non-zero exit code. |
## runLocally()
```php
runLocally(
string $command,
?string $cwd = null,
?int $timeout = null,
?int $idleTimeout = null,
#[\SensitiveParameter]
?string $secret = null,
?array $env = null,
?bool $forceOutput = false,
?bool $nothrow = false,
?string $shell = null,
): string
```
Execute commands on a local machine.
Examples:
```php
$user = runLocally('git config user.name');
runLocally("echo $user");
```
| Argument | Type | Comment |
|---|---|---|
| `$command` | `string` | Command to run on localhost. |
| `$cwd` | `string` or `null` | Sets the process working directory. If not set {{working_path}} will be used. |
| `$timeout` | `int` or `null` | Sets the process timeout (max. runtime). The timeout in seconds (default: 300 sec, `null` to disable). |
| `$idleTimeout` | `int` or `null` | Sets the process idle timeout (max. time since last output) in seconds. |
| `$secret` | `string` or `null` | Placeholder `%secret%` can be used in command. Placeholder will be replaced with this value and will not appear in any logs. |
| `$env` | `array` or `null` | Array of environment variables: `runLocally('echo $KEY', env: ['key' => 'value']);` |
| `$forceOutput` | `bool` or `null` | Print command output in real-time. |
| `$nothrow` | `bool` or `null` | Don't throw an exception of non-zero exit code. |
| `$shell` | `string` or `null` | Shell to run in. Default is `bash -s`. |
## test()
```php
test(string $command): bool
```
Run test command.
Example:
```php
if (test('[ -d {{release_path}} ]')) {
...
}
```
## testLocally()
```php
testLocally(string $command): bool
```
Run test command locally.
Example:
testLocally('[ -d {{local_release_path}} ]')
## on()
```php
on($hosts, callable $callback): void
```
Iterate other hosts, allowing to call run a func in callback.
```php
on(select('stage=prod, role=db'), function ($host) {
...
});
```
```php
on(host('example.org'), function ($host) {
...
});
```
```php
on(Deployer::get()->hosts, function ($host) {
...
});
```
## invoke()
```php
invoke(string $taskName): void
```
Runs a task.
```php
invoke('deploy:symlink');
```
## upload()
```php
upload($source, string $destination, array $config = []): void
```
gitextract_pd_hfplz/
├── .gitattributes
├── .github/
│ ├── DISCUSSION_TEMPLATE/
│ │ └── bugs.yml
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ └── config.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── labeler.yml
│ └── workflows/
│ ├── check.yml
│ ├── docker.yml
│ ├── docs-sync.yml
│ ├── docs.yml
│ ├── labeler.yml
│ ├── lint.yml
│ ├── release.yml
│ ├── stale.yml
│ └── test.yml
├── .gitignore
├── .php-cs-fixer.dist.php
├── Dockerfile
├── LICENSE
├── README.md
├── SECURITY.md
├── bin/
│ ├── build
│ ├── dep
│ └── docgen
├── composer.json
├── contrib/
│ ├── bugsnag.php
│ ├── cachetool.php
│ ├── chatwork.php
│ ├── cimonitor.php
│ ├── cloudflare.php
│ ├── cpanel.php
│ ├── crontab.php
│ ├── directadmin.php
│ ├── discord.php
│ ├── grafana.php
│ ├── hangouts.php
│ ├── hipchat.php
│ ├── ispmanager.php
│ ├── mattermost.php
│ ├── ms-teams.php
│ ├── newrelic.php
│ ├── npm.php
│ ├── ntfy.php
│ ├── phinx.php
│ ├── php-fpm.php
│ ├── rabbit.php
│ ├── raygun.php
│ ├── rocketchat.php
│ ├── rollbar.php
│ ├── rsync.php
│ ├── sentry.php
│ ├── slack.php
│ ├── supervisord-monitor.php
│ ├── telegram.php
│ ├── webpack_encore.php
│ ├── workplace.php
│ ├── yammer.php
│ └── yarn.php
├── docs/
│ ├── KNOWN_BUGS.md
│ ├── UPGRADE.md
│ ├── api.md
│ ├── avoid-php-fpm-reloading.md
│ ├── basics.md
│ ├── ci-cd.md
│ ├── cli.md
│ ├── contrib/
│ │ ├── README.md
│ │ ├── bugsnag.md
│ │ ├── cachetool.md
│ │ ├── chatwork.md
│ │ ├── cimonitor.md
│ │ ├── cloudflare.md
│ │ ├── cpanel.md
│ │ ├── crontab.md
│ │ ├── directadmin.md
│ │ ├── discord.md
│ │ ├── grafana.md
│ │ ├── hangouts.md
│ │ ├── hipchat.md
│ │ ├── ispmanager.md
│ │ ├── mattermost.md
│ │ ├── ms-teams.md
│ │ ├── newrelic.md
│ │ ├── npm.md
│ │ ├── ntfy.md
│ │ ├── phinx.md
│ │ ├── php-fpm.md
│ │ ├── rabbit.md
│ │ ├── raygun.md
│ │ ├── rocketchat.md
│ │ ├── rollbar.md
│ │ ├── rsync.md
│ │ ├── sentry.md
│ │ ├── slack.md
│ │ ├── supervisord-monitor.md
│ │ ├── telegram.md
│ │ ├── webpack_encore.md
│ │ ├── workplace.md
│ │ ├── yammer.md
│ │ └── yarn.md
│ ├── getting-started.md
│ ├── hosts.md
│ ├── installation.md
│ ├── recipe/
│ │ ├── README.md
│ │ ├── cakephp.md
│ │ ├── codeigniter.md
│ │ ├── codeigniter4.md
│ │ ├── common.md
│ │ ├── composer.md
│ │ ├── contao.md
│ │ ├── craftcms.md
│ │ ├── deploy/
│ │ │ ├── check_remote.md
│ │ │ ├── cleanup.md
│ │ │ ├── clear_paths.md
│ │ │ ├── copy_dirs.md
│ │ │ ├── env.md
│ │ │ ├── info.md
│ │ │ ├── lock.md
│ │ │ ├── push.md
│ │ │ ├── release.md
│ │ │ ├── rollback.md
│ │ │ ├── setup.md
│ │ │ ├── shared.md
│ │ │ ├── symlink.md
│ │ │ ├── update_code.md
│ │ │ ├── vendors.md
│ │ │ └── writable.md
│ │ ├── drupal7.md
│ │ ├── drupal8.md
│ │ ├── flow_framework.md
│ │ ├── fuelphp.md
│ │ ├── joomla.md
│ │ ├── laravel.md
│ │ ├── magento.md
│ │ ├── magento2.md
│ │ ├── pimcore.md
│ │ ├── prestashop.md
│ │ ├── provision/
│ │ │ ├── databases.md
│ │ │ ├── nodejs.md
│ │ │ ├── php.md
│ │ │ ├── user.md
│ │ │ └── website.md
│ │ ├── provision.md
│ │ ├── shopware.md
│ │ ├── silverstripe.md
│ │ ├── spiral.md
│ │ ├── statamic.md
│ │ ├── sulu.md
│ │ ├── symfony.md
│ │ ├── typo3.md
│ │ ├── wordpress.md
│ │ ├── yii.md
│ │ └── zend_framework.md
│ ├── selector.md
│ ├── sidebar.js
│ ├── tasks.md
│ └── yaml.md
├── phpstan.neon
├── phpunit.xml
├── recipe/
│ ├── cakephp.php
│ ├── codeigniter.php
│ ├── codeigniter4.php
│ ├── common.php
│ ├── composer.php
│ ├── contao.php
│ ├── craftcms.php
│ ├── deploy/
│ │ ├── check_remote.php
│ │ ├── cleanup.php
│ │ ├── clear_paths.php
│ │ ├── copy_dirs.php
│ │ ├── env.php
│ │ ├── info.php
│ │ ├── lock.php
│ │ ├── push.php
│ │ ├── release.php
│ │ ├── rollback.php
│ │ ├── setup.php
│ │ ├── shared.php
│ │ ├── symlink.php
│ │ ├── update_code.php
│ │ ├── vendors.php
│ │ └── writable.php
│ ├── drupal7.php
│ ├── drupal8.php
│ ├── flow_framework.php
│ ├── fuelphp.php
│ ├── joomla.php
│ ├── laravel.php
│ ├── magento.php
│ ├── magento2.php
│ ├── pimcore.php
│ ├── prestashop.php
│ ├── provision/
│ │ ├── 404.html
│ │ ├── Caddyfile
│ │ ├── databases.php
│ │ ├── nodejs.php
│ │ ├── php.php
│ │ ├── user.php
│ │ └── website.php
│ ├── provision.php
│ ├── shopware.php
│ ├── silverstripe.php
│ ├── spiral.php
│ ├── statamic.php
│ ├── sulu.php
│ ├── symfony.php
│ ├── typo3.php
│ ├── wordpress.php
│ ├── yii.php
│ └── zend_framework.php
├── src/
│ ├── Collection/
│ │ └── Collection.php
│ ├── Command/
│ │ ├── BlackjackCommand.php
│ │ ├── CommandCommon.php
│ │ ├── ConfigCommand.php
│ │ ├── CustomOption.php
│ │ ├── InitCommand.php
│ │ ├── MainCommand.php
│ │ ├── RunCommand.php
│ │ ├── SelectCommand.php
│ │ ├── SshCommand.php
│ │ ├── TreeCommand.php
│ │ └── WorkerCommand.php
│ ├── Component/
│ │ ├── PharUpdate/
│ │ │ ├── Console/
│ │ │ │ ├── Command.php
│ │ │ │ └── Helper.php
│ │ │ ├── Exception/
│ │ │ │ ├── Exception.php
│ │ │ │ ├── ExceptionInterface.php
│ │ │ │ ├── FileException.php
│ │ │ │ ├── InvalidArgumentException.php
│ │ │ │ └── LogicException.php
│ │ │ ├── Manager.php
│ │ │ ├── Manifest.php
│ │ │ ├── Update.php
│ │ │ └── Version/
│ │ │ ├── Builder.php
│ │ │ ├── Comparator.php
│ │ │ ├── Dumper.php
│ │ │ ├── Exception/
│ │ │ │ ├── InvalidIdentifierException.php
│ │ │ │ ├── InvalidNumberException.php
│ │ │ │ ├── InvalidStringRepresentationException.php
│ │ │ │ └── VersionException.php
│ │ │ ├── Parser.php
│ │ │ ├── Validator.php
│ │ │ └── Version.php
│ │ └── Pimple/
│ │ ├── Container.php
│ │ └── Exception/
│ │ ├── ExpectedInvokableException.php
│ │ ├── FrozenServiceException.php
│ │ ├── InvalidServiceIdentifierException.php
│ │ └── UnknownIdentifierException.php
│ ├── Configuration.php
│ ├── Deployer.php
│ ├── Documentation/
│ │ ├── ApiGen.php
│ │ ├── DocConfig.php
│ │ ├── DocGen.php
│ │ ├── DocRecipe.php
│ │ └── DocTask.php
│ ├── Exception/
│ │ ├── ConfigurationException.php
│ │ ├── Exception.php
│ │ ├── GracefulShutdownException.php
│ │ ├── HttpieException.php
│ │ ├── RunException.php
│ │ ├── TimeoutException.php
│ │ └── WillAskUser.php
│ ├── Executor/
│ │ ├── Master.php
│ │ ├── Messenger.php
│ │ ├── Planner.php
│ │ ├── Response.php
│ │ ├── Server.php
│ │ └── Worker.php
│ ├── Host/
│ │ ├── Host.php
│ │ ├── HostCollection.php
│ │ ├── Localhost.php
│ │ └── Range.php
│ ├── Importer/
│ │ └── Importer.php
│ ├── Logger/
│ │ ├── Handler/
│ │ │ ├── FileHandler.php
│ │ │ ├── HandlerInterface.php
│ │ │ └── NullHandler.php
│ │ └── Logger.php
│ ├── ProcessRunner/
│ │ ├── Printer.php
│ │ └── ProcessRunner.php
│ ├── Selector/
│ │ └── Selector.php
│ ├── Ssh/
│ │ ├── IOArguments.php
│ │ ├── RunParams.php
│ │ └── SshClient.php
│ ├── Support/
│ │ ├── ObjectProxy.php
│ │ ├── Reporter.php
│ │ └── helpers.php
│ ├── Task/
│ │ ├── Context.php
│ │ ├── GroupTask.php
│ │ ├── ScriptManager.php
│ │ ├── Task.php
│ │ └── TaskCollection.php
│ ├── Utility/
│ │ ├── Httpie.php
│ │ └── Rsync.php
│ ├── functions.php
│ └── schema.json
└── tests/
├── bootstrap.php
├── fixtures/
│ ├── project/
│ │ └── uploaded.html
│ └── repository/
│ ├── README.md
│ ├── composer.json
│ └── uploads/
│ └── poem.txt
├── joy/
│ ├── HostDefaultConfigTest.php
│ ├── JoyTest.php
│ └── OnFuncTest.php
├── legacy/
│ ├── AbstractTest.php
│ ├── CurrentPathTest.php
│ ├── DeployTest.php
│ ├── EnvTest.php
│ ├── NamedArgumentsTest.php
│ ├── OncePerNodeTest.php
│ ├── OnceTest.php
│ ├── ParallelTest.php
│ ├── SelectTest.php
│ ├── UpdateCodeTest.php
│ ├── YamlTest.php
│ └── recipe/
│ ├── deploy.php
│ ├── deploy.yaml
│ ├── env.php
│ ├── once.php
│ ├── once_per_node.php
│ ├── parallel.php
│ ├── select.php
│ └── update_code.php
├── phpstan-baseline.neon
└── src/
├── Collection/
│ └── CollectionTest.php
├── Command/
│ └── BlackjackCommandTest.php
├── Component/
│ └── Pimple/
│ └── PimpleTest.php
├── Configuration/
│ └── ConfigurationTest.php
├── DeployerTest.php
├── FunctionsTest.php
├── Host/
│ ├── ConfigurationTest.php
│ ├── HostTest.php
│ └── RangeTest.php
├── Importer/
│ └── ImporterTest.php
├── Selector/
│ └── SelectorTest.php
├── Ssh/
│ └── IOArgumentsTest.php
├── Support/
│ ├── HelpersTest.php
│ └── ObjectProxyTest.php
└── Task/
├── ContextTest.php
├── ScriptManagerTest.php
└── TaskTest.php
SYMBOL INDEX (739 symbols across 127 files)
FILE: contrib/cpanel.php
function getCpanel (line 146) | function getCpanel()
function getDomainInfo (line 182) | function getDomainInfo()
FILE: contrib/crontab.php
function setRemoteCrontab (line 129) | function setRemoteCrontab(array $lines): void
function getRemoteCrontab (line 147) | function getRemoteCrontab(): array
FILE: contrib/directadmin.php
function getDirectAdminConfig (line 31) | function getDirectAdminConfig()
function DirectAdmin (line 53) | function DirectAdmin(string $action, array $data = [])
FILE: contrib/ispmanager.php
function ispmanagerRequest (line 697) | function ispmanagerRequest($method, $requestData)
function ispmanagerAuthRequest (line 725) | function ispmanagerAuthRequest($url, $login, $pass)
function prepareRequest (line 746) | function prepareRequest($requestData)
function generatePassword (line 766) | function generatePassword($lenght)
FILE: contrib/phinx.php
function phinx_get_cmd (line 107) | function phinx_get_cmd($cmdName, $conf)
function phinx_get_allowed_config (line 131) | function phinx_get_allowed_config($allowedOptions)
FILE: contrib/sentry.php
function getPreviousReleaseRevision (line 187) | function getPreviousReleaseRevision()
function getCurrentReleaseRevision (line 209) | function getCurrentReleaseRevision()
function getReleaseGitRef (line 225) | function getReleaseGitRef(): Closure
function getGitCommitsRefs (line 248) | function getGitCommitsRefs(): Closure
FILE: contrib/slack.php
function checkSlackAnswer (line 90) | function checkSlackAnswer($result)
FILE: contrib/supervisord-monitor.php
function supervisordCheckConfig (line 94) | function supervisordCheckConfig()
function supervisordGetBasicAuthToken (line 111) | function supervisordGetBasicAuthToken()
function supervisordIsAuthenticated (line 116) | function supervisordIsAuthenticated()
function supervisordControlAction (line 126) | function supervisordControlAction($name, $action = 'stop')
FILE: recipe/codeigniter4.php
function spark (line 46) | function spark($command, $options = [])
function codeigniter4_version_compare (line 83) | function codeigniter4_version_compare($version, $comparator)
FILE: recipe/craftcms.php
function craft (line 37) | function craft($command, $options = [])
FILE: recipe/laravel.php
function artisan (line 39) | function artisan($command, $options = [])
function laravel_version_compare (line 77) | function laravel_version_compare($version, $comparator)
FILE: recipe/magento2.php
function magentoDeployAssetsSplit (line 230) | function magentoDeployAssetsSplit(string $area)
FILE: recipe/shopware.php
function getPlugins (line 122) | function getPlugins(): array
FILE: recipe/spiral.php
function command (line 26) | function command(string $command, array $options = []): \Closure
function rr (line 43) | function rr(string $command, array $options = []): \Closure
FILE: src/Collection/Collection.php
class Collection (line 16) | class Collection implements Countable, IteratorAggregate
method all (line 20) | public function all(): array
method get (line 25) | public function get(string $name): mixed
method has (line 33) | public function has(string $name): bool
method set (line 38) | public function set(string $name, mixed $object)
method remove (line 43) | public function remove(string $name): void
method count (line 51) | public function count(): int
method select (line 56) | public function select(callable $callback): array
method getIterator (line 72) | #[\ReturnTypeWillChange]
method notFound (line 78) | protected function notFound(string $name): \InvalidArgumentException
FILE: src/Command/BlackjackCommand.php
class BlackjackCommand (line 21) | class BlackjackCommand extends Command
method __construct (line 35) | public function __construct()
method execute (line 41) | protected function execute(Input $input, Output $output): int
method newDeck (line 232) | private function newDeck(): array
method handValue (line 247) | public static function handValue(array $hand): int
method print (line 305) | private function print(string $text = "")
method printHand (line 310) | private function printHand(array $hand, int $offset = 1)
method printWhiskey (line 348) | private function printWhiskey(int $whiskeyLevel)
FILE: src/Command/CommandCommon.php
type CommandCommon (line 16) | trait CommandCommon
method telemetry (line 24) | protected function telemetry(array $data = []): void
FILE: src/Command/ConfigCommand.php
class ConfigCommand (line 22) | class ConfigCommand extends SelectCommand
method __construct (line 24) | public function __construct(Deployer $deployer)
method configure (line 30) | protected function configure()
method execute (line 37) | protected function execute(Input $input, Output $output): int
FILE: src/Command/CustomOption.php
type CustomOption (line 15) | trait CustomOption
method applyOverrides (line 21) | protected function applyOverrides(array $hosts, array $options)
method castValueToPhpType (line 41) | protected function castValueToPhpType($value)
FILE: src/Command/InitCommand.php
class InitCommand (line 22) | class InitCommand extends Command
method configure (line 26) | protected function configure()
method execute (line 34) | protected function execute(InputInterface $input, OutputInterface $out...
method php (line 161) | private function php(string $template, string $project, string $reposi...
method yaml (line 194) | private function yaml(string $template, string $project, string $repos...
method getAdditionalConfigs (line 224) | private function getAdditionalConfigs(string $template): string
method recipes (line 241) | private function recipes(): array
FILE: src/Command/MainCommand.php
class MainCommand (line 24) | class MainCommand extends SelectCommand
method __construct (line 29) | public function __construct(string $name, ?string $description, Deploy...
method configure (line 37) | protected function configure()
method execute (line 88) | protected function execute(Input $input, Output $output): int
method checkUpdates (line 160) | private function checkUpdates()
method showBanner (line 169) | private function showBanner()
method complete (line 186) | public function complete(CompletionInput $input, CompletionSuggestions...
FILE: src/Command/RunCommand.php
class RunCommand (line 27) | class RunCommand extends SelectCommand
method __construct (line 31) | public function __construct(Deployer $deployer)
method configure (line 37) | protected function configure()
method execute (line 59) | protected function execute(Input $input, Output $output): int
FILE: src/Command/SelectCommand.php
class SelectCommand (line 27) | abstract class SelectCommand extends Command
method __construct (line 34) | public function __construct(string $name, Deployer $deployer)
method configure (line 40) | protected function configure()
method selectHosts (line 48) | protected function selectHosts(Input $input, Output $output): array
method complete (line 97) | public function complete(CompletionInput $input, CompletionSuggestions...
FILE: src/Command/SshCommand.php
class SshCommand (line 28) | class SshCommand extends Command
method __construct (line 37) | public function __construct(Deployer $deployer)
method configure (line 44) | protected function configure()
method execute (line 53) | protected function execute(InputInterface $input, OutputInterface $out...
method complete (line 107) | public function complete(CompletionInput $input, CompletionSuggestions...
FILE: src/Command/TreeCommand.php
class TreeCommand (line 22) | class TreeCommand extends Command
method __construct (line 45) | public function __construct(Deployer $deployer)
method configure (line 53) | protected function configure()
method execute (line 62) | protected function execute(Input $input, Output $output): int
method buildTree (line 73) | private function buildTree(string $taskName)
method createTreeFromTaskName (line 78) | private function createTreeFromTaskName(string $taskName, string $post...
method addTaskToTree (line 133) | private function addTaskToTree(string $taskName, bool $isLast = false)
method outputTree (line 143) | private function outputTree(string $taskName)
method complete (line 173) | public function complete(CompletionInput $input, CompletionSuggestions...
FILE: src/Command/WorkerCommand.php
class WorkerCommand (line 22) | class WorkerCommand extends MainCommand
method __construct (line 24) | public function __construct(Deployer $deployer)
method configure (line 30) | protected function configure()
method execute (line 39) | protected function execute(InputInterface $input, OutputInterface $out...
FILE: src/Component/PharUpdate/Console/Command.php
class Command (line 19) | class Command extends Base
method __construct (line 46) | public function __construct(string $name, bool $disable = false)
method setManifestUri (line 58) | public function setManifestUri(string $uri)
method setRunningFile (line 68) | public function setRunningFile(string $file): void
method configure (line 76) | protected function configure()
method execute (line 105) | protected function execute(InputInterface $input, OutputInterface $out...
FILE: src/Component/PharUpdate/Console/Helper.php
class Helper (line 16) | class Helper extends Base
method getManager (line 25) | public function getManager(string $uri): Manager
method getName (line 30) | public function getName(): string
FILE: src/Component/PharUpdate/Exception/Exception.php
class Exception (line 12) | class Exception extends \Exception implements ExceptionInterface
method create (line 19) | public static function create(string $format, $value = null): self
method lastError (line 31) | public static function lastError(): self
FILE: src/Component/PharUpdate/Exception/ExceptionInterface.php
type ExceptionInterface (line 12) | interface ExceptionInterface {}
FILE: src/Component/PharUpdate/Exception/FileException.php
class FileException (line 12) | class FileException extends Exception {}
FILE: src/Component/PharUpdate/Exception/InvalidArgumentException.php
class InvalidArgumentException (line 12) | class InvalidArgumentException extends Exception {}
FILE: src/Component/PharUpdate/Exception/LogicException.php
class LogicException (line 12) | class LogicException extends Exception {}
FILE: src/Component/PharUpdate/Manager.php
class Manager (line 16) | class Manager
method __construct (line 37) | public function __construct(Manifest $manifest)
method getManifest (line 47) | public function getManifest(): Manifest
method getRunningFile (line 57) | public function getRunningFile(): string
method setRunningFile (line 74) | public function setRunningFile(string $file): void
method update (line 95) | public function update($version, bool $major = false, bool $pre = fals...
FILE: src/Component/PharUpdate/Manifest.php
class Manifest (line 16) | class Manifest
method __construct (line 30) | public function __construct(array $updates = [])
method findRecent (line 42) | public function findRecent(Version $version, bool $major = false, bool...
method getUpdates (line 75) | public function getUpdates(): array
method load (line 85) | public static function load(string $json): self
method loadFile (line 95) | public static function loadFile(string $file): self
method create (line 107) | private static function create(array $decoded): self
FILE: src/Component/PharUpdate/Update.php
class Update (line 20) | class Update
method __construct (line 74) | public function __construct(
method copyTo (line 96) | public function copyTo(string $file): void
method deleteFile (line 136) | public function deleteFile(): void
method getFile (line 172) | public function getFile(): ?string
method getName (line 226) | public function getName(): string
method getPublicKey (line 234) | public function getPublicKey(): string
method getSha1 (line 242) | public function getSha1(): string
method getUrl (line 250) | public function getUrl(): string
method getVersion (line 258) | public function getVersion(): Version
method isNewer (line 270) | public function isNewer(Version $version): bool
FILE: src/Component/PharUpdate/Version/Builder.php
class Builder (line 15) | class Builder extends Version
method clearBuild (line 20) | public function clearBuild(): void
method clearPreRelease (line 28) | public function clearPreRelease(): void
method create (line 38) | public static function create(): Builder
method getVersion (line 48) | public function getVersion(): Version
method importComponents (line 66) | public function importComponents(array $components): self
method importString (line 108) | public function importString(string $version): self
method importVersion (line 120) | public function importVersion(Version $version): self
method incrementMajor (line 138) | public function incrementMajor(int $amount = 1): self
method incrementMinor (line 155) | public function incrementMinor(int $amount = 1): self
method incrementPatch (line 170) | public function incrementPatch(int $amount = 1): self
method setBuild (line 186) | public function setBuild(array $identifiers): self
method setMajor (line 208) | public function setMajor(int $number): self
method setMinor (line 228) | public function setMinor(int $number): self
method setPatch (line 248) | public function setPatch(int $number): self
method setPreRelease (line 268) | public function setPreRelease(array $identifiers): self
FILE: src/Component/PharUpdate/Version/Comparator.php
class Comparator (line 12) | class Comparator
method compareTo (line 41) | public static function compareTo(Version $left, Version $right)
method isEqualTo (line 75) | public static function isEqualTo(Version $left, Version $right)
method isGreaterThan (line 89) | public static function isGreaterThan(Version $left, Version $right)
method isLessThan (line 103) | public static function isLessThan(Version $left, Version $right)
method compareIdentifiers (line 120) | public static function compareIdentifiers(array $left, array $right)
FILE: src/Component/PharUpdate/Version/Dumper.php
class Dumper (line 12) | class Dumper
method toComponents (line 21) | public static function toComponents(Version $version)
method toString (line 39) | public static function toString(Version $version)
FILE: src/Component/PharUpdate/Version/Exception/InvalidIdentifierException.php
class InvalidIdentifierException (line 12) | class InvalidIdentifierException extends VersionException
method __construct (line 26) | public function __construct(string $identifier)
method getIdentifier (line 43) | public function getIdentifier(): string
FILE: src/Component/PharUpdate/Version/Exception/InvalidNumberException.php
class InvalidNumberException (line 12) | class InvalidNumberException extends VersionException
method __construct (line 26) | public function __construct($number)
method getNumber (line 43) | public function getNumber()
FILE: src/Component/PharUpdate/Version/Exception/InvalidStringRepresentationException.php
class InvalidStringRepresentationException (line 12) | class InvalidStringRepresentationException extends VersionException
method __construct (line 26) | public function __construct(string $version)
method getVersion (line 43) | public function getVersion(): string
FILE: src/Component/PharUpdate/Version/Exception/VersionException.php
class VersionException (line 14) | class VersionException extends Exception {}
FILE: src/Component/PharUpdate/Version/Parser.php
class Parser (line 14) | class Parser
method toBuilder (line 48) | public static function toBuilder(string $version): Builder
method toComponents (line 65) | public static function toComponents(string $version): array
method toVersion (line 105) | public static function toVersion(string $version): Version
FILE: src/Component/PharUpdate/Version/Validator.php
class Validator (line 12) | class Validator
method isIdentifier (line 31) | public static function isIdentifier(string $identifier): bool
method isNumber (line 43) | public static function isNumber(int $number): bool
method isVersion (line 55) | public static function isVersion(string $version): bool
FILE: src/Component/PharUpdate/Version/Version.php
class Version (line 12) | class Version
method __construct (line 58) | public function __construct(
method getBuild (line 77) | public function getBuild(): array
method getMajor (line 87) | public function getMajor(): int
method getMinor (line 97) | public function getMinor(): int
method getPatch (line 107) | public function getPatch(): int
method getPreRelease (line 117) | public function getPreRelease(): array
method isStable (line 127) | public function isStable(): bool
method __toString (line 137) | public function __toString(): string
FILE: src/Component/Pimple/Container.php
class Container (line 23) | class Container implements \ArrayAccess
method __construct (line 57) | public function __construct(array $values = [])
method offsetSet (line 82) | #[\ReturnTypeWillChange]
method offsetGet (line 103) | #[\ReturnTypeWillChange]
method offsetExists (line 140) | #[\ReturnTypeWillChange]
method offsetUnset (line 152) | #[\ReturnTypeWillChange]
method factory (line 173) | public function factory(callable $callable)
method protect (line 195) | public function protect(callable $callable)
method raw (line 215) | public function raw(string $id)
method extend (line 244) | public function extend(string $id, callable $callable)
method keys (line 285) | public function keys()
FILE: src/Component/Pimple/Exception/ExpectedInvokableException.php
class ExpectedInvokableException (line 20) | class ExpectedInvokableException extends \InvalidArgumentException imple...
FILE: src/Component/Pimple/Exception/FrozenServiceException.php
class FrozenServiceException (line 20) | class FrozenServiceException extends \RuntimeException implements Contai...
method __construct (line 25) | public function __construct(string $id)
FILE: src/Component/Pimple/Exception/InvalidServiceIdentifierException.php
class InvalidServiceIdentifierException (line 20) | class InvalidServiceIdentifierException extends \InvalidArgumentExceptio...
method __construct (line 25) | public function __construct(string $id)
FILE: src/Component/Pimple/Exception/UnknownIdentifierException.php
class UnknownIdentifierException (line 20) | class UnknownIdentifierException extends \InvalidArgumentException imple...
method __construct (line 25) | public function __construct(string $id)
FILE: src/Configuration.php
class Configuration (line 20) | class Configuration implements \ArrayAccess
method __construct (line 25) | public function __construct(?Configuration $parent = null)
method update (line 30) | public function update(array $values): void
method bind (line 35) | public function bind(Configuration $parent): void
method set (line 40) | public function set(string $name, mixed $value): void
method has (line 45) | public function has(string $name): bool
method hasOwn (line 57) | public function hasOwn(string $name): bool
method add (line 62) | public function add(string $name, array $array): void
method get (line 75) | public function get(string $name, mixed $default = null): mixed
method fetch (line 103) | protected function fetch(string $name): mixed
method parse (line 114) | public function parse(mixed $value): mixed
method keys (line 126) | public function keys(): array
method offsetExists (line 135) | #[\ReturnTypeWillChange]
method offsetGet (line 145) | #[\ReturnTypeWillChange]
method offsetSet (line 155) | #[\ReturnTypeWillChange]
method offsetUnset (line 164) | #[\ReturnTypeWillChange]
method load (line 170) | public function load(): void
method save (line 186) | public function save(): void
method persist (line 202) | public function persist(): array
FILE: src/Deployer.php
class Deployer (line 73) | class Deployer extends Container
method __construct (line 77) | public function __construct(Application $console)
method get (line 185) | public static function get(): self
method init (line 190) | public function init(): void
method addTaskCommands (line 213) | public function addTaskCommands(): void
method __get (line 223) | public function __get(string $name): mixed
method __set (line 232) | public function __set(string $name, mixed $value): void
method getConsole (line 237) | public function getConsole(): Application
method getHelper (line 242) | public function getHelper(string $name): Console\Helper\HelperInterface
method run (line 247) | public static function run(string $version, ?string $deployFile): void
method printException (line 301) | public static function printException(OutputInterface $output, Throwab...
method isWorker (line 322) | public static function isWorker(): bool
method masterCall (line 330) | public static function masterCall(Host $host, string $func, mixed ...$...
method isPharArchive (line 347) | public static function isPharArchive(): bool
FILE: src/Documentation/ApiGen.php
class ApiGen (line 13) | class ApiGen
method parse (line 20) | public function parse(string $source): void
method markdown (line 91) | public function markdown(): string
FILE: src/Documentation/DocConfig.php
class DocConfig (line 13) | class DocConfig
FILE: src/Documentation/DocGen.php
class DocGen (line 18) | class DocGen
method __construct (line 29) | public function __construct(string $root)
method parse (line 34) | public function parse(string $source): void
method gen (line 48) | public function gen(string $destination): ?string
method generateRecipesIndex (line 321) | public function generateRecipesIndex(string $destination)
method generateContribIndex (line 336) | public function generateContribIndex(string $destination)
function trim_comment (line 352) | function trim_comment(string $line): string
function indent (line 357) | function indent(string $text): string
function php_to_md (line 364) | function php_to_md(string $file): string
function title (line 369) | function title(string $s): string
function anchor (line 374) | function anchor(string $s): string
function remove_text_emoji (line 379) | function remove_text_emoji(string $text): string
function add_tailing_dot (line 384) | function add_tailing_dot(string $sentence): string
function recipe_to_md_link (line 395) | function recipe_to_md_link(string $recipe): string
function is_framework_recipe (line 402) | function is_framework_recipe(DocRecipe $recipe): bool
function framework_brand_name (line 408) | function framework_brand_name(string $brandName): string
FILE: src/Documentation/DocRecipe.php
class DocRecipe (line 13) | class DocRecipe
method __construct (line 40) | public function __construct(string $recipeName, string $recipePath)
method parse (line 49) | public function parse(string $content)
FILE: src/Documentation/DocTask.php
class DocTask (line 13) | class DocTask
method mdLink (line 40) | public function mdLink(): string
FILE: src/Exception/ConfigurationException.php
class ConfigurationException (line 13) | class ConfigurationException extends \RuntimeException {}
FILE: src/Exception/Exception.php
class Exception (line 15) | class Exception extends \Exception
method __construct (line 30) | public function __construct(string $message = "", int $code = 0, ?Thro...
method setTaskSourceLocation (line 45) | public static function setTaskSourceLocation(string $filepath): void
method getTaskFilename (line 50) | public function getTaskFilename(): string
method getTaskLineNumber (line 55) | public function getTaskLineNumber(): int
method setTaskFilename (line 60) | public function setTaskFilename(string $taskFilename): void
method setTaskLineNumber (line 65) | public function setTaskLineNumber(int $taskLineNumber): void
FILE: src/Exception/GracefulShutdownException.php
class GracefulShutdownException (line 24) | class GracefulShutdownException extends Exception
FILE: src/Exception/HttpieException.php
class HttpieException (line 13) | class HttpieException extends \RuntimeException {}
FILE: src/Exception/RunException.php
class RunException (line 16) | class RunException extends Exception
method __construct (line 39) | public function __construct(
method getHost (line 56) | public function getHost(): Host
method getCommand (line 61) | public function getCommand(): string
method getExitCode (line 66) | public function getExitCode(): int
method getExitCodeText (line 71) | public function getExitCodeText(): string
method getOutput (line 76) | public function getOutput(): string
method getErrorOutput (line 81) | public function getErrorOutput(): string
FILE: src/Exception/TimeoutException.php
class TimeoutException (line 13) | class TimeoutException extends Exception
method __construct (line 15) | public function __construct(
FILE: src/Exception/WillAskUser.php
class WillAskUser (line 13) | class WillAskUser extends Exception
method __construct (line 15) | public function __construct(string $message)
FILE: src/Executor/Master.php
function spinner (line 27) | function spinner(string $message = ''): string
class Master (line 33) | class Master
method __construct (line 41) | public function __construct(
method run (line 58) | public function run(array $tasks, array $hosts, ?Planner $plan = null)...
method runTask (line 147) | private function runTask(Task $task, array $hosts): int
method createProcess (line 244) | protected function createProcess(Host $host, Task $task, int $port): P...
method allFinished (line 265) | protected function allFinished(array $processes): bool
method gatherOutput (line 278) | protected function gatherOutput(array $processes, callable $callback):...
method cumulativeExitCode (line 296) | protected function cumulativeExitCode(array $processes): int
FILE: src/Executor/Messenger.php
class Messenger (line 22) | class Messenger
method __construct (line 44) | public function __construct(Input $input, Output $output, Logger $logger)
method startTask (line 51) | public function startTask(Task $task): void
method endTask (line 69) | public function endTask(Task $task, bool $error = false): void
method endOnHost (line 102) | public function endOnHost(Host $host): void
method renderException (line 109) | public function renderException(Throwable $exception, Host $host): void
FILE: src/Executor/Planner.php
class Planner (line 18) | class Planner
method __construct (line 34) | public function __construct(OutputInterface $output, array $hosts)
method commit (line 50) | public function commit(array $hosts, Task $task): void
method render (line 66) | public function render()
FILE: src/Executor/Response.php
class Response (line 13) | class Response
method __construct (line 18) | public function __construct(int $status, mixed $body)
method getStatus (line 24) | public function getStatus(): int
method getBody (line 29) | public function getBody(): mixed
FILE: src/Executor/Server.php
class Server (line 17) | class Server
method __construct (line 40) | public function __construct($host, $port, OutputInterface $output)
method checkRequiredExtensionsExists (line 48) | public static function checkRequiredExtensionsExists(): void
method run (line 58) | public function run(): void
method createServerSocket (line 97) | private function createServerSocket()
method updatePort (line 111) | private function updatePort(): void
method acceptNewConnections (line 122) | private function acceptNewConnections(): void
method handleClientRequests (line 133) | private function handleClientRequests(): void
method readClientRequest (line 150) | private function readClientRequest($clientSocket)
method parseRequest (line 161) | private function parseRequest($request)
method sendResponse (line 188) | private function sendResponse($clientSocket, Response $response)
method closeClientSocket (line 199) | private function closeClientSocket($clientSocket, $key): void
method afterRun (line 205) | public function afterRun(Closure $param): void
method ticker (line 210) | public function ticker(Closure $param): void
method router (line 215) | public function router(Closure $param)
method stop (line 220) | public function stop(): void
FILE: src/Executor/Worker.php
class Worker (line 22) | class Worker
method __construct (line 26) | public function __construct(Deployer $deployer)
method execute (line 31) | public function execute(Task $task, Host $host): int
FILE: src/Host/Host.php
class Host (line 22) | class Host
method __construct (line 29) | public function __construct(string $hostname)
method __toString (line 40) | public function __toString(): string
method config (line 45) | public function config(): Configuration
method set (line 53) | public function set(string $name, $value): self
method add (line 65) | public function add(string $name, array $value): self
method has (line 71) | public function has(string $name): bool
method hasOwn (line 76) | public function hasOwn(string $name): bool
method get (line 85) | public function get(string $name, $default = null)
method getAlias (line 90) | public function getAlias(): ?string
method setTag (line 95) | public function setTag(string $tag): self
method getTag (line 101) | public function getTag(): ?string
method setHostname (line 106) | public function setHostname(string $hostname): self
method getHostname (line 112) | public function getHostname(): ?string
method setRemoteUser (line 117) | public function setRemoteUser(string $user): self
method getRemoteUser (line 123) | public function getRemoteUser(): ?string
method setPort (line 132) | public function setPort($port): self
method getPort (line 141) | public function getPort()
method setConfigFile (line 146) | public function setConfigFile(string $file): self
method getConfigFile (line 152) | public function getConfigFile(): ?string
method setIdentityFile (line 157) | public function setIdentityFile(string $file): self
method getIdentityFile (line 163) | public function getIdentityFile(): ?string
method setForwardAgent (line 168) | public function setForwardAgent(bool $on): self
method getForwardAgent (line 174) | public function getForwardAgent(): ?bool
method setSshMultiplexing (line 179) | public function setSshMultiplexing(bool $on): self
method getSshMultiplexing (line 185) | public function getSshMultiplexing(): ?bool
method setShell (line 190) | public function setShell(string $command): self
method getShell (line 196) | public function getShell(): ?string
method setShellPath (line 201) | public function setShellPath(string $path): self
method getShellPath (line 207) | public function getShellPath(): ?string
method setDeployPath (line 212) | public function setDeployPath(string $path): self
method getDeployPath (line 218) | public function getDeployPath(): ?string
method setLabels (line 223) | public function setLabels(array $labels): self
method addLabels (line 229) | public function addLabels(array $labels): self
method getLabels (line 236) | public function getLabels(): ?array
method setSshArguments (line 241) | public function setSshArguments(array $args): self
method getSshArguments (line 247) | public function getSshArguments(): ?array
method setSshControlPath (line 252) | public function setSshControlPath(string $path): self
method getSshControlPath (line 258) | public function getSshControlPath(): string
method generateControlPath (line 263) | private function generateControlPath(): string
method connectionString (line 281) | public function connectionString(): string
method connectionOptionsString (line 289) | public function connectionOptionsString(): string
method connectionOptionsArray (line 297) | public function connectionOptionsArray(): array
FILE: src/Host/HostCollection.php
class HostCollection (line 19) | class HostCollection extends Collection
method notFound (line 21) | protected function notFound(string $name): \InvalidArgumentException
FILE: src/Host/Localhost.php
class Localhost (line 13) | class Localhost extends Host
method __construct (line 15) | public function __construct(string $hostname = 'localhost')
FILE: src/Host/Range.php
class Range (line 13) | class Range
method expand (line 17) | public static function expand(array $hostnames): array
method format (line 36) | private static function format(string $i, bool $zeroBased): string
FILE: src/Importer/Importer.php
class Importer (line 34) | class Importer
method import (line 48) | public static function import($paths)
method hosts (line 87) | protected static function hosts(array $hosts)
method config (line 103) | protected static function config(array $config)
method tasks (line 110) | protected static function tasks(array $tasks)
method after (line 220) | protected static function after(array $after)
method before (line 233) | protected static function before(array $before)
FILE: src/Logger/Handler/FileHandler.php
class FileHandler (line 13) | class FileHandler implements HandlerInterface
method __construct (line 20) | public function __construct(string $filePath)
method log (line 25) | public function log(string $message): void
FILE: src/Logger/Handler/HandlerInterface.php
type HandlerInterface (line 13) | interface HandlerInterface
method log (line 15) | public function log(string $message): void;
FILE: src/Logger/Handler/NullHandler.php
class NullHandler (line 13) | class NullHandler implements HandlerInterface
method log (line 15) | public function log(string $message): void {}
FILE: src/Logger/Logger.php
class Logger (line 17) | class Logger
method __construct (line 24) | public function __construct(HandlerInterface $handler)
method log (line 29) | public function log(string $message): void
method callback (line 34) | public function callback(Host $host): \Closure
method printBuffer (line 41) | public function printBuffer(Host $host, string $type, string $buffer):...
method writeln (line 48) | public function writeln(Host $host, string $type, string $line): void
FILE: src/ProcessRunner/Printer.php
class Printer (line 16) | class Printer
method __construct (line 20) | public function __construct(OutputInterface $output)
method command (line 25) | public function command(Host $host, string $type, string $command): void
method callback (line 38) | public function callback(Host $host, bool $forceOutput): callable
method printBuffer (line 50) | public function printBuffer(string $type, Host $host, string $buffer):...
method writeln (line 57) | public function writeln(string $type, Host $host, string $line): void
FILE: src/ProcessRunner/ProcessRunner.php
class ProcessRunner (line 25) | class ProcessRunner
method __construct (line 30) | public function __construct(Printer $pop, Logger $logger)
method run (line 36) | public function run(Host $host, string $command, RunParams $params): s...
FILE: src/Selector/Selector.php
class Selector (line 18) | class Selector
method __construct (line 25) | public function __construct(HostCollection $hosts)
method select (line 33) | public function select(string $selectExpression)
method apply (line 47) | public static function apply(?array $conditions, Host $host): bool
method compare (line 83) | private static function compare(string $op, $a, ?string $b): bool
method parse (line 104) | public static function parse(string $expression): array
FILE: src/Ssh/IOArguments.php
class IOArguments (line 17) | class IOArguments
method collect (line 19) | public static function collect(InputInterface $input, OutputInterface ...
method verbosity (line 58) | private static function verbosity(int $verbosity): string
FILE: src/Ssh/RunParams.php
class RunParams (line 5) | class RunParams
method __construct (line 7) | public function __construct(
method with (line 20) | public function with(
FILE: src/Ssh/SshClient.php
class SshClient (line 24) | class SshClient
method __construct (line 30) | public function __construct(OutputInterface $output, Printer $pop, Log...
method run (line 37) | public function run(Host $host, string $command, RunParams $params): s...
FILE: src/Support/ObjectProxy.php
class ObjectProxy (line 13) | class ObjectProxy
method __construct (line 20) | public function __construct(array $objects)
method __call (line 25) | public function __call(string $name, array $arguments): self
FILE: src/Support/Reporter.php
class Reporter (line 19) | class Reporter
method report (line 21) | public static function report(array $stats): void
FILE: src/Support/helpers.php
function array_flatten (line 13) | function array_flatten(array $array): array
function array_merge_alternate (line 29) | function array_merge_alternate(array $original, array $override): array
function env_stringify (line 57) | function env_stringify(array $array): string
function is_closure (line 68) | function is_closure(mixed $var): bool
function array_all (line 76) | function array_all(array $array, callable $predicate): bool
function normalize_line_endings (line 89) | function normalize_line_endings(string $string): string
function parse_home_dir (line 97) | function parse_home_dir(string $path): string
function find_line_number (line 114) | function find_line_number(string $source, string $string): int
function colorize_host (line 124) | function colorize_host(string $alias): string
function escape_shell_argument (line 211) | function escape_shell_argument(string $argument): string
function deployer_root (line 216) | function deployer_root(): string
FILE: src/Task/Context.php
class Context (line 19) | class Context
method __construct (line 28) | public function __construct(Host $host)
method push (line 33) | public static function push(Context $context): void
method has (line 38) | public static function has(): bool
method get (line 43) | public static function get(): Context
method pop (line 51) | public static function pop(): ?Context
method required (line 64) | public static function required(string $callerName): void
method getConfig (line 71) | public function getConfig(): Configuration
method getHost (line 76) | public function getHost(): Host
FILE: src/Task/GroupTask.php
class GroupTask (line 15) | class GroupTask extends Task
method __construct (line 27) | public function __construct(string $name, array $group)
method run (line 33) | public function run(Context $context): void
method getGroup (line 45) | public function getGroup(): array
method setGroup (line 50) | public function setGroup(array $group): void
FILE: src/Task/ScriptManager.php
class ScriptManager (line 17) | class ScriptManager
method __construct (line 32) | public function __construct(TaskCollection $tasks)
method getTasks (line 42) | public function getTasks(string $name, ?string $startFrom = null, arra...
method doGetTasks (line 81) | public function doGetTasks(string $name): array
method getHooksEnabled (line 117) | public function getHooksEnabled(): bool
method setHooksEnabled (line 122) | public function setHooksEnabled(bool $hooksEnabled): void
FILE: src/Task/Task.php
class Task (line 15) | class Task
method __construct (line 73) | public function __construct(string $name, ?callable $callback = null)
method setCallback (line 82) | public function setCallback(callable $callback): void
method run (line 87) | public function run(Context $context): void
method getName (line 102) | public function getName(): string
method __toString (line 107) | public function __toString(): string
method getDescription (line 112) | public function getDescription(): ?string
method desc (line 117) | public function desc(string $description): self
method getSourceLocation (line 123) | public function getSourceLocation(): string
method setSourceLocation (line 128) | public function setSourceLocation(string $path): void
method saveSourceLocation (line 133) | public function saveSourceLocation(): void
method once (line 144) | public function once(bool $once = true): self
method isOnce (line 150) | public function isOnce(): bool
method oncePerNode (line 159) | public function oncePerNode(bool $once = true): self
method isOncePerNode (line 165) | public function isOncePerNode(): bool
method hidden (line 173) | public function hidden(bool $hidden = true): self
method isHidden (line 179) | public function isHidden(): bool
method addBefore (line 187) | public function addBefore(string $task): self
method addAfter (line 196) | public function addAfter(string $task): self
method getBefore (line 202) | public function getBefore(): array
method getAfter (line 207) | public function getAfter(): array
method getLimit (line 212) | public function getLimit(): ?int
method limit (line 217) | public function limit(?int $limit): self
method select (line 223) | public function select(string $selector): self
method getSelector (line 232) | public function getSelector(): ?array
method addSelector (line 237) | public function addSelector(?array $newSelector): void
method isVerbose (line 248) | public function isVerbose(): bool
method verbose (line 253) | public function verbose(bool $verbose = true): self
method isEnabled (line 259) | public function isEnabled(): bool
method disable (line 264) | public function disable(): self
method enable (line 270) | public function enable(): self
FILE: src/Task/TaskCollection.php
class TaskCollection (line 19) | class TaskCollection extends Collection
method notFound (line 21) | protected function notFound(string $name): \InvalidArgumentException
method add (line 26) | public function add(Task $task): void
FILE: src/Utility/Httpie.php
class Httpie (line 15) | class Httpie
method __construct (line 24) | public function __construct()
method get (line 34) | public static function get(string $url): Httpie
method post (line 42) | public static function post(string $url): Httpie
method patch (line 50) | public static function patch(string $url): Httpie
method put (line 59) | public static function put(string $url): Httpie
method delete (line 67) | public static function delete(string $url): Httpie
method query (line 75) | public function query(array $params): self
method header (line 81) | public function header(string $header, string $value): self
method body (line 87) | public function body(string $body): self
method jsonBody (line 96) | public function jsonBody(array $data): self
method formBody (line 106) | public function formBody(array $data): self
method setopt (line 119) | public function setopt(int $key, $value): self
method nothrow (line 125) | public function nothrow(bool $on = true): self
method send (line 131) | public function send(?array &$info = null): string
method getJson (line 173) | public function getJson(): mixed
FILE: src/Utility/Rsync.php
class Rsync (line 23) | class Rsync
method __construct (line 34) | public function __construct(Printer $pop, OutputInterface $output)
method call (line 47) | public function call(Host $host, $source, string $destination, array $...
FILE: src/functions.php
function host (line 53) | function host(string ...$hostname): Host|ObjectProxy
function localhost (line 90) | function localhost(string ...$hostnames): Localhost|ObjectProxy
function currentHost (line 112) | function currentHost(): Host
function select (line 128) | function select(string $selector): array
function selectedHosts (line 138) | function selectedHosts(): array
function import (line 158) | function import(string $file): void
function desc (line 166) | function desc(?string $title = null): ?string
function task (line 186) | function task(string $name, callable|array|null $body = null): Task
function before (line 238) | function before(string $task, string|callable $do): ?Task
function after (line 258) | function after(string $task, string|callable $do): ?Task
function fail (line 279) | function fail(string $task, string|callable $do): ?Task
function option (line 301) | function option(string $name, $shortcut = null, ?int $mode = null, strin...
function cd (line 316) | function cd(string $path): void
function become (line 336) | function become(string $user): \Closure
function within (line 351) | function within(string $path, callable $callback): mixed
function run (line 392) | function run(
function runLocally (line 482) | function runLocally(
function test (line 523) | function test(string $command): bool
function testLocally (line 536) | function testLocally(string $command): bool
function on (line 564) | function on($hosts, callable $callback): void
function invoke (line 596) | function invoke(string $taskName): void
function upload (line 628) | function upload($source, string $destination, array $config = []): void
function download (line 649) | function download(string $source, string $destination, array $config = [...
function info (line 666) | function info(string $message): void
function warning (line 674) | function warning(string $message): void
function writeln (line 688) | function writeln(string $message, int $options = 0): void
function parse (line 697) | function parse(string $value): string
function set (line 707) | function set(string $name, $value): void
function add (line 721) | function add(string $name, array $array): void
function get (line 737) | function get(string $name, $default = null)
function has (line 749) | function has(string $name): bool
function ask (line 758) | function ask(string $message, ?string $default = null, ?array $autocompl...
function askChoice (line 793) | function askChoice(string $message, array $availableChoices, $default = ...
function askConfirmation (line 832) | function askConfirmation(string $message, bool $default = false): bool
function askHiddenResponse (line 860) | function askHiddenResponse(string $message): string
function input (line 889) | function input(): InputInterface
function output (line 894) | function output(): OutputInterface
function commandExist (line 904) | function commandExist(string $command): bool
function commandSupportsOption (line 912) | function commandSupportsOption(string $command, string $option): bool
function which (line 924) | function which(string $name): string
function remoteEnv (line 948) | function remoteEnv(): array
function error (line 962) | function error(string $message): Exception
function timestamp (line 970) | function timestamp(): string
function fetch (line 982) | function fetch(string $url, string $method = 'get', array $headers = [],...
FILE: tests/joy/HostDefaultConfigTest.php
class HostDefaultConfigTest (line 13) | class HostDefaultConfigTest extends JoyTest
method recipe (line 15) | protected function recipe(): string
method testOnFunc (line 29) | public function testOnFunc()
FILE: tests/joy/JoyTest.php
class JoyTest (line 18) | abstract class JoyTest extends TestCase
method setUpBeforeClass (line 30) | public static function setUpBeforeClass(): void
method tearDownAfterClass (line 36) | public static function tearDownAfterClass(): void
method cleanUp (line 41) | protected static function cleanUp()
method init (line 48) | protected function init(string $recipe)
method dep (line 60) | protected function dep(string $task, array $args = []): int
method recipe (line 76) | abstract protected function recipe(): string;
FILE: tests/joy/OnFuncTest.php
class OnFuncTest (line 11) | class OnFuncTest extends JoyTest
method recipe (line 13) | protected function recipe(): string
method testOnFunc (line 38) | public function testOnFunc()
FILE: tests/legacy/AbstractTest.php
class AbstractTest (line 18) | abstract class AbstractTest extends TestCase
method setUpBeforeClass (line 30) | public static function setUpBeforeClass(): void
method tearDownAfterClass (line 36) | public static function tearDownAfterClass(): void
method cleanUp (line 41) | protected static function cleanUp()
method init (line 48) | protected function init(string $recipe)
method dep (line 60) | protected function dep(string $recipe, string $task)
FILE: tests/legacy/CurrentPathTest.php
class CurrentPathTest (line 12) | class CurrentPathTest extends AbstractTest
method testDeployWithDifferentCurrentPath (line 16) | public function testDeployWithDifferentCurrentPath()
FILE: tests/legacy/DeployTest.php
class DeployTest (line 12) | class DeployTest extends AbstractTest
method testDeploy (line 16) | public function testDeploy()
method testDeploySelectHosts (line 44) | public function testDeploySelectHosts()
method testKeepReleases (line 55) | public function testKeepReleases()
method testRollback (line 82) | public function testRollback()
method testFail (line 95) | public function testFail()
method testCleanup (line 112) | public function testCleanup()
method testIsUnlockedExitsWithOneWhenDeployIsLocked (line 125) | public function testIsUnlockedExitsWithOneWhenDeployIsLocked()
method testIsUnlockedExitsWithZeroWhenDeployIsNotLocked (line 135) | public function testIsUnlockedExitsWithZeroWhenDeployIsNotLocked()
FILE: tests/legacy/EnvTest.php
class EnvTest (line 10) | class EnvTest extends AbstractTest
method testOnce (line 14) | public function testOnce()
FILE: tests/legacy/OncePerNodeTest.php
class OncePerNodeTest (line 10) | class OncePerNodeTest extends AbstractTest
method testOnce (line 14) | public function testOnce()
FILE: tests/legacy/OnceTest.php
class OnceTest (line 10) | class OnceTest extends AbstractTest
method testOnce (line 14) | public function testOnce()
FILE: tests/legacy/ParallelTest.php
class ParallelTest (line 12) | class ParallelTest extends AbstractTest
method setUpBeforeClass (line 16) | public static function setUpBeforeClass(): void
method tearDownAfterClass (line 22) | public static function tearDownAfterClass(): void
method testWorker (line 28) | public function testWorker()
method testServer (line 41) | public function testServer()
method testOption (line 58) | public function testOption()
method testCachedHostConfig (line 81) | public function testCachedHostConfig()
method testHostConfigFromCallback (line 98) | public function testHostConfigFromCallback()
FILE: tests/legacy/SelectTest.php
class SelectTest (line 12) | class SelectTest extends AbstractTest
method testSelect (line 16) | public function testSelect()
FILE: tests/legacy/UpdateCodeTest.php
class UpdateCodeTest (line 12) | class UpdateCodeTest extends AbstractTest
method testDeployWithDifferentUpdateCodeTask (line 16) | public function testDeployWithDifferentUpdateCodeTask()
FILE: tests/legacy/YamlTest.php
class YamlTest (line 12) | class YamlTest extends AbstractTest
method testDeploy (line 16) | public function testDeploy()
FILE: tests/src/Collection/CollectionTest.php
class CollectionTest (line 14) | class CollectionTest extends TestCase
method collections (line 16) | public static function collections()
method testCollection (line 28) | public function testCollection($collection)
method testException (line 47) | public function testException($collection)
FILE: tests/src/Command/BlackjackCommandTest.php
class BlackjackCommandTest (line 6) | class BlackjackCommandTest extends TestCase
method testHandValue (line 8) | public function testHandValue()
FILE: tests/src/Component/Pimple/PimpleTest.php
class PimpleTest (line 22) | class PimpleTest extends TestCase
method testWithString (line 24) | public function testWithString()
method testWithClosure (line 32) | public function testWithClosure()
method testServicesShouldBeDifferent (line 42) | public function testServicesShouldBeDifferent()
method testShouldPassContainerAsParameter (line 58) | public function testShouldPassContainerAsParameter()
method testIsset (line 72) | public function testIsset()
method testConstructorInjection (line 88) | public function testConstructorInjection()
method testOffsetGetValidatesKeyIsPresent (line 96) | public function testOffsetGetValidatesKeyIsPresent()
method testLegacyOffsetGetValidatesKeyIsPresent (line 108) | public function testLegacyOffsetGetValidatesKeyIsPresent()
method testOffsetGetHonorsNullValues (line 117) | public function testOffsetGetHonorsNullValues()
method testUnset (line 124) | public function testUnset()
method testShare (line 140) | public function testShare($service)
method testProtect (line 157) | public function testProtect($service)
method testGlobalFunctionNameAsParameterValue (line 165) | public function testGlobalFunctionNameAsParameterValue()
method testRaw (line 172) | public function testRaw()
method testRawHonorsNullValues (line 181) | public function testRawHonorsNullValues()
method testRawValidatesKeyIsPresent (line 188) | public function testRawValidatesKeyIsPresent()
method testLegacyRawValidatesKeyIsPresent (line 200) | public function testLegacyRawValidatesKeyIsPresent()
method testExtend (line 212) | public function testExtend($service)
method testExtendDoesNotLeakWithFactories (line 239) | public function testExtendDoesNotLeakWithFactories()
method testExtendValidatesKeyIsPresent (line 263) | public function testExtendValidatesKeyIsPresent()
method testLegacyExtendValidatesKeyIsPresent (line 275) | public function testLegacyExtendValidatesKeyIsPresent()
method testKeys (line 284) | public function testKeys()
method settingAnInvokableObjectShouldTreatItAsFactory (line 294) | public function settingAnInvokableObjectShouldTreatItAsFactory()
method settingNonInvokableObjectShouldTreatItAsParameter (line 303) | public function settingNonInvokableObjectShouldTreatItAsParameter()
method testFactoryFailsForInvalidServiceDefinitions (line 314) | public function testFactoryFailsForInvalidServiceDefinitions($service)
method testLegacyFactoryFailsForInvalidServiceDefinitions (line 325) | public function testLegacyFactoryFailsForInvalidServiceDefinitions($se...
method testProtectFailsForInvalidServiceDefinitions (line 335) | public function testProtectFailsForInvalidServiceDefinitions($service)
method testLegacyProtectFailsForInvalidServiceDefinitions (line 346) | public function testLegacyProtectFailsForInvalidServiceDefinitions($se...
method testExtendFailsForKeysNotContainingServiceDefinitions (line 356) | public function testExtendFailsForKeysNotContainingServiceDefinitions(...
method testLegacyExtendFailsForKeysNotContainingServiceDefinitions (line 370) | public function testLegacyExtendFailsForKeysNotContainingServiceDefini...
method testExtendingProtectedClosureDeprecation (line 384) | public function testExtendingProtectedClosureDeprecation()
method testExtendFailsForInvalidServiceDefinitions (line 401) | public function testExtendFailsForInvalidServiceDefinitions($service)
method testLegacyExtendFailsForInvalidServiceDefinitions (line 413) | public function testLegacyExtendFailsForInvalidServiceDefinitions($ser...
method testExtendFailsIfFrozenServiceIsNonInvokable (line 421) | public function testExtendFailsIfFrozenServiceIsNonInvokable()
method testExtendFailsIfFrozenServiceIsInvokable (line 435) | public function testExtendFailsIfFrozenServiceIsInvokable()
method badServiceDefinitionProvider (line 452) | public static function badServiceDefinitionProvider()
method serviceDefinitionProvider (line 463) | public static function serviceDefinitionProvider()
method testDefiningNewServiceAfterFreeze (line 476) | public function testDefiningNewServiceAfterFreeze()
method testOverridingServiceAfterFreeze (line 490) | public function testOverridingServiceAfterFreeze()
method testLegacyOverridingServiceAfterFreeze (line 509) | public function testLegacyOverridingServiceAfterFreeze()
method testRemovingServiceAfterFreeze (line 525) | public function testRemovingServiceAfterFreeze()
method testExtendingService (line 540) | public function testExtendingService()
method testExtendingServiceAfterOtherServiceFreeze (line 555) | public function testExtendingServiceAfterOtherServiceFreeze()
class Invokable (line 573) | class Invokable
method __invoke (line 575) | public function __invoke($value = null)
class NonInvokable (line 584) | class NonInvokable
method __call (line 586) | public function __call($a, $b) {}
class Service (line 589) | class Service
FILE: tests/src/Configuration/ConfigurationTest.php
class ConfigurationTest (line 9) | class ConfigurationTest extends TestCase
method testParse (line 11) | public function testParse()
method testUnset (line 20) | public function testUnset()
method testGet (line 28) | public function testGet()
method testGetDefault (line 41) | public function testGetDefault()
method testGetException (line 49) | public function testGetException()
method testGetParent (line 59) | public function testGetParent()
method testGetParentParent (line 78) | public function testGetParentParent()
method testGetParentWhatDependsOnChild (line 90) | public function testGetParentWhatDependsOnChild()
method testGetFromCallback (line 104) | public function testGetFromCallback()
method testAdd (line 113) | public function testAdd()
method testAddEmpty (line 121) | public function testAddEmpty()
method testAddDefaultToNotArray (line 128) | public function testAddDefaultToNotArray()
method testAddToParent (line 138) | public function testAddToParent()
method testAddToParentCallback (line 149) | public function testAddToParentCallback()
method testPersist (line 162) | public function testPersist()
FILE: tests/src/DeployerTest.php
class DeployerTest (line 15) | class DeployerTest extends TestCase
method setUp (line 19) | protected function setUp(): void
method tearDown (line 27) | protected function tearDown(): void
method testInstance (line 32) | public function testInstance()
FILE: tests/src/FunctionsTest.php
class FunctionsTest (line 23) | class FunctionsTest extends TestCase
method setUp (line 30) | protected function setUp(): void
method tearDown (line 44) | protected function tearDown(): void
method testHost (line 51) | public function testHost()
method testLocalhost (line 65) | public function testLocalhost()
method testTask (line 71) | public function testTask()
method testBefore (line 86) | public function testBefore()
method testAfter (line 97) | public function testAfter()
method testRunLocally (line 108) | public function testRunLocally()
method testWithinSetsWorkingPaths (line 114) | public function testWithinSetsWorkingPaths()
method testWithinRestoresWorkingPathInCaseOfException (line 127) | public function testWithinRestoresWorkingPathInCaseOfException()
method testWithinReturningValue (line 143) | public function testWithinReturningValue()
method testWithinWithVoidFunction (line 152) | public function testWithinWithVoidFunction()
method taskToNames (line 161) | private function taskToNames($tasks)
FILE: tests/src/Host/ConfigurationTest.php
class ConfigurationTest (line 14) | class ConfigurationTest extends TestCase
method testConfiguration (line 16) | public function testConfiguration()
method testAddParams (line 44) | public function testAddParams()
method testAddParamsToNotArray (line 79) | public function testAddParamsToNotArray()
FILE: tests/src/Host/HostTest.php
class HostTest (line 13) | class HostTest extends TestCase
method testHost (line 15) | public function testHost()
method testConfigurationAccessor (line 38) | public function testConfigurationAccessor()
method testHostAlias (line 52) | public function testHostAlias()
method testHostWithParams (line 59) | public function testHostWithParams()
method testHostWithUserFromConfig (line 70) | public function testHostWithUserFromConfig()
FILE: tests/src/Host/RangeTest.php
class RangeTest (line 12) | class RangeTest extends TestCase
method testExpand (line 14) | public function testExpand()
FILE: tests/src/Importer/ImporterTest.php
class ImporterTest (line 10) | class ImporterTest extends TestCase
method setUp (line 15) | public function setUp(): void
method tearDown (line 22) | public function tearDown(): void
method testCanOneOverrideStaticMethod (line 28) | public function testCanOneOverrideStaticMethod(): void
method testImporterIgnoresYamlHiddenKeys (line 50) | public function testImporterIgnoresYamlHiddenKeys(): void
FILE: tests/src/Selector/SelectorTest.php
class SelectorTest (line 9) | class SelectorTest extends TestCase
method testSelectHosts (line 11) | public function testSelectHosts()
FILE: tests/src/Ssh/IOArgumentsTest.php
class IOArgumentsTest (line 12) | class IOArgumentsTest extends TestCase
method testCollect (line 14) | public function testCollect()
FILE: tests/src/Support/HelpersTest.php
class HelpersTest (line 12) | class HelpersTest extends TestCase
method testArrayFlatten (line 14) | public function testArrayFlatten()
method testArrayMergeAlternate (line 19) | public function testArrayMergeAlternate()
method testParseHomeDir (line 55) | public function testParseHomeDir()
method testEscapeShellArgument (line 63) | public function testEscapeShellArgument()
FILE: tests/src/Support/ObjectProxyTest.php
class ObjectProxyTest (line 12) | class ObjectProxyTest extends TestCase
method testObjectProxy (line 14) | public function testObjectProxy()
FILE: tests/src/Task/ContextTest.php
class ContextTest (line 16) | class ContextTest extends TestCase
method testContext (line 18) | public function testContext()
FILE: tests/src/Task/ScriptManagerTest.php
class ScriptManagerTest (line 12) | class ScriptManagerTest extends TestCase
method testGetTasks (line 14) | public function testGetTasks()
method testOnce (line 34) | public function testOnce()
method testSelectsCombine (line 57) | public function testSelectsCombine()
method testThrowsExceptionIfTaskCollectionEmpty (line 85) | public function testThrowsExceptionIfTaskCollectionEmpty()
method testThrowsExceptionIfTaskDontExists (line 93) | public function testThrowsExceptionIfTaskDontExists()
FILE: tests/src/Task/TaskTest.php
class TaskTest (line 16) | class TaskTest extends TestCase
method tearDown (line 18) | protected function tearDown(): void
method testTask (line 23) | public function testTask()
method testInit (line 56) | public function testInit()
method testGroupInvoke (line 88) | public function testGroupInvoke(): void
class StubTask (line 107) | class StubTask
method __invoke (line 111) | public function __invoke()
Condensed preview — 338 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,100K chars).
[
{
"path": ".gitattributes",
"chars": 203,
"preview": "/.gitattributes export-ignore\n/.github/ export-ignore\n/.gitignore export-ignore\n/docs/ export-ignore\n/phpcs.xml export-i"
},
{
"path": ".github/DISCUSSION_TEMPLATE/bugs.yml",
"chars": 1458,
"preview": "body:\n - type: markdown\n attributes:\n value: |\n **Before opening a bug report, please search the existin"
},
{
"path": ".github/FUNDING.yml",
"chars": 18,
"preview": "github: antonmedv\n"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 653,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Bug Report\n url: https://github.com/deployphp/deployer/discussio"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 170,
"preview": "- [ ] Bug fix #…?\n- [ ] New feature?\n- [ ] BC breaks?\n- [ ] Tests added?\n- [ ] Docs added?\n\n Please, regenerate doc"
},
{
"path": ".github/labeler.yml",
"chars": 24,
"preview": "v7:\n- base-branch: \"7.x\""
},
{
"path": ".github/workflows/check.yml",
"chars": 1898,
"preview": "name: check\n\non:\n push:\n branches: [ master ]\n pull_request:\n branches: [ master ]\n\njobs:\n phpstan:\n runs-on"
},
{
"path": ".github/workflows/docker.yml",
"chars": 1802,
"preview": "name: docker\n\non:\n release:\n types: [ published ]\n workflow_dispatch:\n inputs:\n version:\n descriptio"
},
{
"path": ".github/workflows/docs-sync.yml",
"chars": 1112,
"preview": "name: doc-sync\n\non:\n push:\n branches: [ master ]\n\npermissions:\n contents: write\n\njobs:\n docgen-and-commit:\n run"
},
{
"path": ".github/workflows/docs.yml",
"chars": 1166,
"preview": "name: doc\n\non:\n push:\n branches: [ master ]\n pull_request:\n branches: [ master ]\n\njobs:\n docgen:\n runs-on: u"
},
{
"path": ".github/workflows/labeler.yml",
"chars": 195,
"preview": "name: labeler\n\non:\n- pull_request_target\n\njobs:\n labeler:\n permissions:\n contents: read\n pull-requests: wr"
},
{
"path": ".github/workflows/lint.yml",
"chars": 584,
"preview": "name: lint\n\non:\n push:\n branches: [ master ]\n pull_request:\n types: [opened, synchronize, reopened, ready_for_re"
},
{
"path": ".github/workflows/release.yml",
"chars": 1484,
"preview": "name: release\n\non:\n release:\n types: [published]\n workflow_dispatch:\n inputs:\n version:\n description"
},
{
"path": ".github/workflows/stale.yml",
"chars": 668,
"preview": "name: stale\non:\n schedule:\n - cron: \"* * * * *\"\n workflow_dispatch:\n\njobs:\n close-issues:\n runs-on: ubuntu-late"
},
{
"path": ".github/workflows/test.yml",
"chars": 1141,
"preview": "name: test\n\non:\n push:\n branches: [ master ]\n pull_request:\n branches: [ master ]\n\njobs:\n unit:\n runs-on: ub"
},
{
"path": ".gitignore",
"chars": 93,
"preview": "/vendor/\n*.phar\n.phpunit.result.cache\ndocker-compose.override.yml\n.php-cs-fixer.cache\n.idea/\n"
},
{
"path": ".php-cs-fixer.dist.php",
"chars": 607,
"preview": "<?php\n\n$finder = (new PhpCsFixer\\Finder())\n ->in(__DIR__ . '/src')\n ->in(__DIR__ . '/recipe')\n ->in(__DIR__ . '"
},
{
"path": "Dockerfile",
"chars": 248,
"preview": "FROM php:8.4-cli-alpine\n\nRUN apk add --no-cache bash git openssh-client rsync zip unzip libzip-dev \\\n\nRUN docker-php-ext"
},
{
"path": "LICENSE",
"chars": 1079,
"preview": "The MIT License (MIT)\n\nCopyright © 2013 Anton Medvedev\n\nPermission is hereby granted, free of charge, to any person obta"
},
{
"path": "README.md",
"chars": 2124,
"preview": "<h1>\n <a href=\"https://deployer.org\">\n <picture>\n <source media=\"(prefers-color-scheme: dark)\" srcs"
},
{
"path": "SECURITY.md",
"chars": 835,
"preview": "# Security Policy\n\n## Supported Versions\n\nDeployer is generally backwards compatible with very few exceptions, so we\nrec"
},
{
"path": "bin/build",
"chars": 3089,
"preview": "#!/usr/bin/env php\n<?php\n/* (c) Anton Medvedev <anton@medv.io>\n *\n * For the full copyright and license information, ple"
},
{
"path": "bin/dep",
"chars": 2927,
"preview": "#!/usr/bin/env php\n<?php\n/* (c) Anton Medvedev <anton@medv.io>\n *\n * For the full copyright and license information, ple"
},
{
"path": "bin/docgen",
"chars": 1612,
"preview": "#!/usr/bin/env php\n<?php\n/* (c) Anton Medvedev <anton@medv.io>\n *\n * For the full copyright and license information, ple"
},
{
"path": "composer.json",
"chars": 1751,
"preview": "{\n \"name\": \"deployer/deployer\",\n \"description\": \"Deployment Tool\",\n \"license\": \"MIT\",\n \"homepage\": \"https://"
},
{
"path": "contrib/bugsnag.php",
"chars": 1298,
"preview": "<?php\n/*\n\n## Configuration\n\n- *bugsnag_api_key* – the API Key associated with the project. Informs Bugsnag which project"
},
{
"path": "contrib/cachetool.php",
"chars": 3709,
"preview": "<?php\n/*\n\n## Configuration\n\n- **cachetool** *(optional)*: accepts a *string* or an *array* of strings with the unix sock"
},
{
"path": "contrib/chatwork.php",
"chars": 4959,
"preview": "<?php\n/*\n# Chatwork Recipe\n\n## Installing\n 1. Create chatwork account by any manual in the internet\n 2. Take chatwork "
},
{
"path": "contrib/cimonitor.php",
"chars": 4601,
"preview": "<?php\n/*\nMonitor your deployments on [CIMonitor](https://github.com/CIMonitor/CIMonitor).\n\n;\n```\n\n## Configuration\n\n- `discor"
},
{
"path": "contrib/grafana.php",
"chars": 1868,
"preview": "<?php\n/*\n\n## Configuration options\n\n- **url** *(required)*: the URL to the creates annotation api endpoint.\n- **token** "
},
{
"path": "contrib/hangouts.php",
"chars": 5454,
"preview": "<?php\n/*\n\nAdd hook on deploy:\n\n```php\nbefore('deploy', 'chat:notify');\n```\n\n## Configuration\n\n- `chat_webhook` – chat in"
},
{
"path": "contrib/hipchat.php",
"chars": 1308,
"preview": "<?php\n/*\n## Configuration\n\n- `hipchat_token` – Hipchat V1 auth token\n- `hipchat_room_id` – Room ID or name\n- `hipchat_me"
},
{
"path": "contrib/ispmanager.php",
"chars": 23772,
"preview": "<?php\n/*\n * This recipe for work with ISPManager Lite panel by API.\n */\n\nnamespace Deployer;\n\nuse Deployer\\Exception\\Exc"
},
{
"path": "contrib/mattermost.php",
"chars": 4134,
"preview": "<?php\n/*\n## Installing\n\nCreate a Mattermost incoming webhook, through the administration panel.\n\nAdd hook on deploy:\n\n``"
},
{
"path": "contrib/ms-teams.php",
"chars": 4322,
"preview": "<?php\n/*\n## Installing\n\nRequire ms-teams recipe in your `deploy.php` file:\n\nSetup:\n1. Open MS Teams\n2. Navigate to Teams"
},
{
"path": "contrib/newrelic.php",
"chars": 1446,
"preview": "<?php\n/*\n## Configuration\n\n- `newrelic_app_id` – newrelic's app id\n- `newrelic_api_key` – newrelic's api key\n- `newrelic"
},
{
"path": "contrib/npm.php",
"chars": 669,
"preview": "<?php\n/*\n## Configuration\n\n- `bin/npm` *(optional)*: set npm binary, automatically detected otherwise.\n\n## Usage\n\n```php"
},
{
"path": "contrib/ntfy.php",
"chars": 4085,
"preview": "<?php\n/*\n## Installing\n\nRequire ntfy.sh recipe in your `deploy.php` file:\n\nSetup:\n1. Setup deploy.php\n Add in header:"
},
{
"path": "contrib/phinx.php",
"chars": 5092,
"preview": "<?php\n/*\n\n## Configuration options\n\nAll options are in the config parameter `phinx` specified as an array (instead of th"
},
{
"path": "contrib/php-fpm.php",
"chars": 1478,
"preview": "<?php\n/*\n\n:::caution\nDo **not** reload php-fpm. Some user requests could fail or not complete in the\nprocess of reloadin"
},
{
"path": "contrib/rabbit.php",
"chars": 3079,
"preview": "<?php\n/*\n### Installing\n\n```php\n// deploy.php\n\nrequire 'recipe/rabbit.php';\n```\n\n### Configuration options\n\n- **rabbit**"
},
{
"path": "contrib/raygun.php",
"chars": 1238,
"preview": "<?php\n/*\n\n## Configuration\n\n- `raygun_api_key` – the API key of your Raygun application\n- `raygun_version` – the version"
},
{
"path": "contrib/rocketchat.php",
"chars": 4731,
"preview": "<?php\n/*\n## Installing\n\nCreate a RocketChat incoming webhook, through the administration panel.\n\nAdd hook on deploy:\n\n``"
},
{
"path": "contrib/rollbar.php",
"chars": 1166,
"preview": "<?php\n/*\n\n## Configuration\n\n- `rollbar_token` – access token to rollbar api\n- `rollbar_comment` – comment about deploy, "
},
{
"path": "contrib/rsync.php",
"chars": 8406,
"preview": "<?php\n/*\n:::warning\nThis must not be confused with `/src/Utility/Rsync.php`, deployer's built-in rsync. Their configurat"
},
{
"path": "contrib/sentry.php",
"chars": 10979,
"preview": "<?php\n/*\n\n### Configuration options\n\n- **organization** *(required)*: the slug of the organization the release belongs t"
},
{
"path": "contrib/slack.php",
"chars": 5089,
"preview": "<?php\n/*\n## Installing\n\n<a href=\"https://slack.com/oauth/authorize?&client_id=113734341365.225973502034&scope=incoming-w"
},
{
"path": "contrib/supervisord-monitor.php",
"chars": 5361,
"preview": "<?php\n/*\n### Description\nThis is a recipe that uses the [Supervisord server monitoring project](https://github.com/mlaza"
},
{
"path": "contrib/telegram.php",
"chars": 4467,
"preview": "<?php\n/*\n## Installing\n 1. Create telegram bot with [BotFather](https://t.me/BotFather) and grab the token provided\n 2"
},
{
"path": "contrib/webpack_encore.php",
"chars": 1037,
"preview": "<?php\n/*\n\n## Configuration\n\n- **webpack_encore/package_manager** *(optional)*: set yarn or npm. We try to find if yarn o"
},
{
"path": "contrib/workplace.php",
"chars": 3499,
"preview": "<?php\n/*\nThis recipes works with Custom Integrations and Publishing Bots.\n\n\nAdd hook on deploy:\n\n```\nbefore('deploy', 'w"
},
{
"path": "contrib/yammer.php",
"chars": 3242,
"preview": "<?php\n/*\n\nAdd hook on deploy:\n\n```php\nbefore('deploy', 'yammer:notify');\n```\n\n## Configuration\n\n- `yammer_url` – The URL"
},
{
"path": "contrib/yarn.php",
"chars": 681,
"preview": "<?php\n/*\n## Configuration\n\n- **bin/yarn** *(optional)*: set Yarn binary, automatically detected otherwise.\n\n## Usage\n\n``"
},
{
"path": "docs/KNOWN_BUGS.md",
"chars": 1514,
"preview": "# Known Bugs\n\n## Ubuntu 14.04, Coreutils 8.21\n\nThere are known bugs with relative symlinks `ln --relative`, which may ca"
},
{
"path": "docs/UPGRADE.md",
"chars": 8073,
"preview": "# Upgrade a major version\n\n## Upgrade from 7.x to 8.x\n\n- `run()` and `runLocally()` doesn't accept `options` parameter a"
},
{
"path": "docs/api.md",
"chars": 11014,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit src/functions.php -->\n<!-- Then run bin/docgen -->\n\n# API Reference\n\n#"
},
{
"path": "docs/avoid-php-fpm-reloading.md",
"chars": 1565,
"preview": "# Avoid PHP-FPM Reloading\n\nDeployer symlinks _current_ to latest release dir.\n\n```\ncurrent -> releases/3/\nreleases/\n "
},
{
"path": "docs/basics.md",
"chars": 5986,
"preview": "# Basics\n\nDeployer operates around two main concepts: [**hosts**](hosts.md) and [**tasks**](tasks.md). These are defined"
},
{
"path": "docs/ci-cd.md",
"chars": 4637,
"preview": "# CI/CD\n\n## GitHub Actions\n\nUse official [GitHub Action for Deployer](https://github.com/deployphp/action).\n\nCreate `.gi"
},
{
"path": "docs/cli.md",
"chars": 5054,
"preview": "# CLI Usage\n\nWe recommend adding the following alias to your .bashrc file:\n\n```bash\nalias dep='vendor/bin/dep'\n```\n\nIt i"
},
{
"path": "docs/contrib/README.md",
"chars": 1557,
"preview": "# All Contrib Recipes\n\n* [Bugsnag Recipe](/docs/contrib/bugsnag.md)\n* [Cachetool Recipe](/docs/contrib/cachetool.md)\n* ["
},
{
"path": "docs/contrib/bugsnag.md",
"chars": 1041,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/bugsnag.php -->\n<!-- Then run bin/docgen -->\n\n# Bugsnag Recipe"
},
{
"path": "docs/contrib/cachetool.md",
"chars": 5332,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/cachetool.php -->\n<!-- Then run bin/docgen -->\n\n# Cachetool Re"
},
{
"path": "docs/contrib/chatwork.md",
"chars": 4825,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/chatwork.php -->\n<!-- Then run bin/docgen -->\n\n# Chatwork Reci"
},
{
"path": "docs/contrib/cimonitor.md",
"chars": 4558,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/cimonitor.php -->\n<!-- Then run bin/docgen -->\n\n# Cimonitor Re"
},
{
"path": "docs/contrib/cloudflare.md",
"chars": 1754,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/cloudflare.php -->\n<!-- Then run bin/docgen -->\n\n# Cloudflare "
},
{
"path": "docs/contrib/cpanel.md",
"chars": 5527,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/cpanel.php -->\n<!-- Then run bin/docgen -->\n\n# Cpanel Recipe\n\n"
},
{
"path": "docs/contrib/crontab.md",
"chars": 1723,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/crontab.php -->\n<!-- Then run bin/docgen -->\n\n# Crontab Recipe"
},
{
"path": "docs/contrib/directadmin.md",
"chars": 2581,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/directadmin.php -->\n<!-- Then run bin/docgen -->\n\n# Directadmi"
},
{
"path": "docs/contrib/discord.md",
"chars": 3335,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/discord.php -->\n<!-- Then run bin/docgen -->\n\n# Discord Recipe"
},
{
"path": "docs/contrib/grafana.md",
"chars": 1170,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/grafana.php -->\n<!-- Then run bin/docgen -->\n\n# Grafana Recipe"
},
{
"path": "docs/contrib/hangouts.md",
"chars": 2601,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/hangouts.php -->\n<!-- Then run bin/docgen -->\n\n# Hangouts Reci"
},
{
"path": "docs/contrib/hipchat.md",
"chars": 1648,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/hipchat.php -->\n<!-- Then run bin/docgen -->\n\n# Hipchat Recipe"
},
{
"path": "docs/contrib/ispmanager.md",
"chars": 4915,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/ispmanager.php -->\n<!-- Then run bin/docgen -->\n\n# Ispmanager "
},
{
"path": "docs/contrib/mattermost.md",
"chars": 4281,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/mattermost.php -->\n<!-- Then run bin/docgen -->\n\n# Mattermost "
},
{
"path": "docs/contrib/ms-teams.md",
"chars": 3987,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/ms-teams.php -->\n<!-- Then run bin/docgen -->\n\n# Ms-teams Reci"
},
{
"path": "docs/contrib/newrelic.md",
"chars": 1516,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/newrelic.php -->\n<!-- Then run bin/docgen -->\n\n# Newrelic Reci"
},
{
"path": "docs/contrib/npm.md",
"chars": 1096,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/npm.php -->\n<!-- Then run bin/docgen -->\n\n# Npm Recipe\n\n```php"
},
{
"path": "docs/contrib/ntfy.md",
"chars": 3927,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/ntfy.php -->\n<!-- Then run bin/docgen -->\n\n# Ntfy Recipe\n\n```p"
},
{
"path": "docs/contrib/phinx.md",
"chars": 2955,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/phinx.php -->\n<!-- Then run bin/docgen -->\n\n# Phinx Recipe\n\n``"
},
{
"path": "docs/contrib/php-fpm.md",
"chars": 2894,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/php-fpm.php -->\n<!-- Then run bin/docgen -->\n\n# Php-fpm Recipe"
},
{
"path": "docs/contrib/rabbit.md",
"chars": 1409,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/rabbit.php -->\n<!-- Then run bin/docgen -->\n\n# Rabbit Recipe\n\n"
},
{
"path": "docs/contrib/raygun.md",
"chars": 995,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/raygun.php -->\n<!-- Then run bin/docgen -->\n\n# Raygun Recipe\n\n"
},
{
"path": "docs/contrib/rocketchat.md",
"chars": 4327,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/rocketchat.php -->\n<!-- Then run bin/docgen -->\n\n# Rocketchat "
},
{
"path": "docs/contrib/rollbar.md",
"chars": 1022,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/rollbar.php -->\n<!-- Then run bin/docgen -->\n\n# Rollbar Recipe"
},
{
"path": "docs/contrib/rsync.md",
"chars": 6107,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/rsync.php -->\n<!-- Then run bin/docgen -->\n\n# Rsync Recipe\n\n``"
},
{
"path": "docs/contrib/sentry.md",
"chars": 3134,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/sentry.php -->\n<!-- Then run bin/docgen -->\n\n# Sentry Recipe\n\n"
},
{
"path": "docs/contrib/slack.md",
"chars": 4557,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/slack.php -->\n<!-- Then run bin/docgen -->\n\n# Slack Recipe\n\n``"
},
{
"path": "docs/contrib/supervisord-monitor.md",
"chars": 3044,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/supervisord-monitor.php -->\n<!-- Then run bin/docgen -->\n\n# Su"
},
{
"path": "docs/contrib/telegram.md",
"chars": 3474,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/telegram.php -->\n<!-- Then run bin/docgen -->\n\n# Telegram Reci"
},
{
"path": "docs/contrib/webpack_encore.md",
"chars": 1523,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/webpack_encore.php -->\n<!-- Then run bin/docgen -->\n\n# Webpack"
},
{
"path": "docs/contrib/workplace.md",
"chars": 3171,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/workplace.php -->\n<!-- Then run bin/docgen -->\n\n# Workplace Re"
},
{
"path": "docs/contrib/yammer.md",
"chars": 2806,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/yammer.php -->\n<!-- Then run bin/docgen -->\n\n# Yammer Recipe\n\n"
},
{
"path": "docs/contrib/yarn.md",
"chars": 943,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit contrib/yarn.php -->\n<!-- Then run bin/docgen -->\n\n# Yarn Recipe\n\n```p"
},
{
"path": "docs/getting-started.md",
"chars": 5226,
"preview": "# Getting Started\n\nThis tutorial will guide you through:\n\n- Setting up a new host with the [provision](recipe/provision."
},
{
"path": "docs/hosts.md",
"chars": 6211,
"preview": "# Hosts\n\nIn Deployer, you define hosts using the [host()](api.md#host) function.\n\n### Defining a Host\n\n```php\nhost('exam"
},
{
"path": "docs/installation.md",
"chars": 3011,
"preview": "# Installation\n\nThere are two ways to install Deployer: globally or locally. Global installation is recommended for most"
},
{
"path": "docs/recipe/README.md",
"chars": 1305,
"preview": "# All Recipes\n\n* [Cakephp Recipe](/docs/recipe/cakephp.md)\n* [Codeigniter 4 Recipe](/docs/recipe/codeigniter4.md)\n* [Cod"
},
{
"path": "docs/recipe/cakephp.md",
"chars": 4182,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/cakephp.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a"
},
{
"path": "docs/recipe/codeigniter.md",
"chars": 3634,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/codeigniter.php -->\n<!-- Then run bin/docgen -->\n\n# How to Depl"
},
{
"path": "docs/recipe/codeigniter4.md",
"chars": 9079,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/codeigniter4.php -->\n<!-- Then run bin/docgen -->\n\n# How to Dep"
},
{
"path": "docs/recipe/common.md",
"chars": 6357,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/common.php -->\n<!-- Then run bin/docgen -->\n\n# Common Recipe\n\n`"
},
{
"path": "docs/recipe/composer.md",
"chars": 625,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/composer.php -->\n<!-- Then run bin/docgen -->\n\n# Composer Recip"
},
{
"path": "docs/recipe/contao.md",
"chars": 6675,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/contao.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a "
},
{
"path": "docs/recipe/craftcms.md",
"chars": 3666,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/craftcms.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy "
},
{
"path": "docs/recipe/deploy/check_remote.md",
"chars": 558,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/check_remote.php -->\n<!-- Then run bin/docgen -->\n\n# Che"
},
{
"path": "docs/recipe/deploy/cleanup.md",
"chars": 599,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/cleanup.php -->\n<!-- Then run bin/docgen -->\n\n# Cleanup "
},
{
"path": "docs/recipe/deploy/clear_paths.md",
"chars": 834,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/clear_paths.php -->\n<!-- Then run bin/docgen -->\n\n# Clea"
},
{
"path": "docs/recipe/deploy/copy_dirs.md",
"chars": 623,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/copy_dirs.php -->\n<!-- Then run bin/docgen -->\n\n# Copy D"
},
{
"path": "docs/recipe/deploy/env.md",
"chars": 526,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/env.php -->\n<!-- Then run bin/docgen -->\n\n# Env Recipe\n\n"
},
{
"path": "docs/recipe/deploy/info.md",
"chars": 1006,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/info.php -->\n<!-- Then run bin/docgen -->\n\n# Info Recipe"
},
{
"path": "docs/recipe/deploy/lock.md",
"chars": 658,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/lock.php -->\n<!-- Then run bin/docgen -->\n\n# Lock Recipe"
},
{
"path": "docs/recipe/deploy/push.md",
"chars": 523,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/push.php -->\n<!-- Then run bin/docgen -->\n\n# Push Recipe"
},
{
"path": "docs/recipe/deploy/release.md",
"chars": 2839,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/release.php -->\n<!-- Then run bin/docgen -->\n\n# Release "
},
{
"path": "docs/recipe/deploy/rollback.md",
"chars": 1306,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/rollback.php -->\n<!-- Then run bin/docgen -->\n\n# Rollbac"
},
{
"path": "docs/recipe/deploy/setup.md",
"chars": 371,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/setup.php -->\n<!-- Then run bin/docgen -->\n\n# Setup Reci"
},
{
"path": "docs/recipe/deploy/shared.md",
"chars": 1057,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/shared.php -->\n<!-- Then run bin/docgen -->\n\n# Shared Re"
},
{
"path": "docs/recipe/deploy/symlink.md",
"chars": 665,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/symlink.php -->\n<!-- Then run bin/docgen -->\n\n# Symlink "
},
{
"path": "docs/recipe/deploy/update_code.md",
"chars": 2543,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/update_code.php -->\n<!-- Then run bin/docgen -->\n\n# Upda"
},
{
"path": "docs/recipe/deploy/vendors.md",
"chars": 1240,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/vendors.php -->\n<!-- Then run bin/docgen -->\n\n# Vendors "
},
{
"path": "docs/recipe/deploy/writable.md",
"chars": 2617,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/deploy/writable.php -->\n<!-- Then run bin/docgen -->\n\n# Writabl"
},
{
"path": "docs/recipe/drupal7.md",
"chars": 4268,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/drupal7.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a"
},
{
"path": "docs/recipe/drupal8.md",
"chars": 3949,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/drupal8.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a"
},
{
"path": "docs/recipe/flow_framework.md",
"chars": 4538,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/flow_framework.php -->\n<!-- Then run bin/docgen -->\n\n# How to D"
},
{
"path": "docs/recipe/fuelphp.md",
"chars": 3280,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/fuelphp.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a"
},
{
"path": "docs/recipe/joomla.md",
"chars": 3575,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/joomla.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a "
},
{
"path": "docs/recipe/laravel.md",
"chars": 15224,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/laravel.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a"
},
{
"path": "docs/recipe/magento.md",
"chars": 4189,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/magento.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a"
},
{
"path": "docs/recipe/magento2.md",
"chars": 25994,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/magento2.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy "
},
{
"path": "docs/recipe/pimcore.md",
"chars": 3315,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/pimcore.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a"
},
{
"path": "docs/recipe/prestashop.md",
"chars": 3775,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/prestashop.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deplo"
},
{
"path": "docs/recipe/provision/databases.md",
"chars": 1675,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/provision/databases.php -->\n<!-- Then run bin/docgen -->\n\n# Dat"
},
{
"path": "docs/recipe/provision/nodejs.md",
"chars": 561,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/provision/nodejs.php -->\n<!-- Then run bin/docgen -->\n\n# Nodejs"
},
{
"path": "docs/recipe/provision/php.md",
"chars": 893,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/provision/php.php -->\n<!-- Then run bin/docgen -->\n\n# Php Recip"
},
{
"path": "docs/recipe/provision/user.md",
"chars": 774,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/provision/user.php -->\n<!-- Then run bin/docgen -->\n\n# User Rec"
},
{
"path": "docs/recipe/provision/website.md",
"chars": 1242,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/provision/website.php -->\n<!-- Then run bin/docgen -->\n\n# Websi"
},
{
"path": "docs/recipe/provision.md",
"chars": 3442,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/provision.php -->\n<!-- Then run bin/docgen -->\n\n# Provision Rec"
},
{
"path": "docs/recipe/shopware.md",
"chars": 10212,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/shopware.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy "
},
{
"path": "docs/recipe/silverstripe.md",
"chars": 4705,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/silverstripe.php -->\n<!-- Then run bin/docgen -->\n\n# How to Dep"
},
{
"path": "docs/recipe/spiral.md",
"chars": 8192,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/spiral.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a "
},
{
"path": "docs/recipe/statamic.md",
"chars": 7240,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/statamic.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy "
},
{
"path": "docs/recipe/sulu.md",
"chars": 3364,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/sulu.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a Su"
},
{
"path": "docs/recipe/symfony.md",
"chars": 5600,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/symfony.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a"
},
{
"path": "docs/recipe/typo3.md",
"chars": 10005,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/typo3.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a T"
},
{
"path": "docs/recipe/wordpress.md",
"chars": 3628,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/wordpress.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy"
},
{
"path": "docs/recipe/yii.md",
"chars": 3792,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/yii.php -->\n<!-- Then run bin/docgen -->\n\n# How to Deploy a Yii"
},
{
"path": "docs/recipe/zend_framework.md",
"chars": 3015,
"preview": "<!-- DO NOT EDIT THIS FILE! -->\n<!-- Instead edit recipe/zend_framework.php -->\n<!-- Then run bin/docgen -->\n\n# How to D"
},
{
"path": "docs/selector.md",
"chars": 4589,
"preview": "# Selector\n\nDeployer uses the selector to choose hosts. Each host can have a set of labels.\nLabels are key-value pairs.\n"
},
{
"path": "docs/sidebar.js",
"chars": 330,
"preview": "module.exports = [\n \"installation\",\n \"getting-started\",\n \"basics\",\n {\n type: \"category\",\n label: \"Main Concept"
},
{
"path": "docs/tasks.md",
"chars": 2388,
"preview": "# Tasks\n\nDefine a task by using the [task](api.md#task) function. Also, you can give a description\nfor a task with the ["
},
{
"path": "docs/yaml.md",
"chars": 769,
"preview": "# YAML\n\nDeployer supports recipes written in YAML. For validating the structure, Deployer uses\nthe JSON Schema declared "
},
{
"path": "phpstan.neon",
"chars": 415,
"preview": "includes:\n - tests/phpstan-baseline.neon\n\nparameters:\n level: 5\n paths:\n - src\n - recipe\n "
},
{
"path": "phpunit.xml",
"chars": 935,
"preview": "<?xml version=\"1.0\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" bootstrap=\"tests/bootstrap.php\" col"
},
{
"path": "recipe/cakephp.php",
"chars": 1000,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['cakephp']);\n\n/**\n * CakePHP 4 Projec"
},
{
"path": "recipe/codeigniter.php",
"chars": 425,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['codeigniter']);\n\n// CodeIgniter shar"
},
{
"path": "recipe/codeigniter4.php",
"chars": 5785,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['codeigniter4']);\n\n// Default Configu"
},
{
"path": "recipe/common.php",
"chars": 4747,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire __DIR__ . '/provision.php';\nrequire __DIR__ . '/deploy/check_remote.php';\nrequire __"
},
{
"path": "recipe/composer.php",
"chars": 215,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['composer']);\n\ndesc('Deploys your pro"
},
{
"path": "recipe/contao.php",
"chars": 3853,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/symfony.php';\n\nadd('recipes', ['contao']);\n\n// The public path is t"
},
{
"path": "recipe/craftcms.php",
"chars": 3451,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['craftcms']);\n\nset('log_files', 'stor"
},
{
"path": "recipe/deploy/check_remote.php",
"chars": 1714,
"preview": "<?php\n\nnamespace Deployer;\n\nuse Deployer\\Exception\\Exception;\nuse Deployer\\Exception\\GracefulShutdownException;\n\n// Canc"
},
{
"path": "recipe/deploy/cleanup.php",
"chars": 547,
"preview": "<?php\n\nnamespace Deployer;\n\n// Use sudo in deploy:cleanup task for rm command.\nset('cleanup_use_sudo', false);\n\ndesc('Cl"
},
{
"path": "recipe/deploy/clear_paths.php",
"chars": 603,
"preview": "<?php\n\nnamespace Deployer;\n\n// List of paths to remove from {{release_path}}.\nset('clear_paths', []);\n\n// Use sudo for d"
},
{
"path": "recipe/deploy/copy_dirs.php",
"chars": 1219,
"preview": "<?php\n\nnamespace Deployer;\n\n// List of dirs to copy between releases.\n// For example you can copy `node_modules` to spee"
},
{
"path": "recipe/deploy/env.php",
"chars": 284,
"preview": "<?php\n\nnamespace Deployer;\n\nset('dotenv_example', '.env.example');\n\ndesc('Configure .env file');\ntask('deploy:env', func"
},
{
"path": "recipe/deploy/info.php",
"chars": 1067,
"preview": "<?php\n\nnamespace Deployer;\n\n// Defines \"what\" text for the 'deploy:info' task.\n// Uses one of the following sources:\n// "
},
{
"path": "recipe/deploy/lock.php",
"chars": 1055,
"preview": "<?php\n\nnamespace Deployer;\n\nuse Deployer\\Exception\\GracefulShutdownException;\n\ndesc('Locks deploy');\ntask('deploy:lock',"
},
{
"path": "recipe/deploy/push.php",
"chars": 663,
"preview": "<?php\n\nnamespace Deployer;\n\n// Creates patch of local changes and pushes them on host.\n// And applies to current_path. P"
},
{
"path": "recipe/deploy/release.php",
"chars": 6915,
"preview": "<?php\n\nnamespace Deployer;\n\nuse Deployer\\Exception\\Exception;\nuse Symfony\\Component\\Console\\Helper\\Table;\n\nuse function "
},
{
"path": "recipe/deploy/rollback.php",
"chars": 2700,
"preview": "<?php\n\nnamespace Deployer;\n\nuse Deployer\\Exception\\Exception;\n\n/*\n * Rollback candidate will be automatically chosen by "
},
{
"path": "recipe/deploy/setup.php",
"chars": 737,
"preview": "<?php\n\nnamespace Deployer;\n\ndesc('Prepares host for deploy');\ntask('deploy:setup', function () {\n run(\n <<<EOF"
},
{
"path": "recipe/deploy/shared.php",
"chars": 3195,
"preview": "<?php\n\nnamespace Deployer;\n\nuse Deployer\\Exception\\Exception;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n// "
},
{
"path": "recipe/deploy/symlink.php",
"chars": 668,
"preview": "<?php\n\nnamespace Deployer;\n\n// Use mv -T if available. Will check automatically.\nset('use_atomic_symlink', function () {"
},
{
"path": "recipe/deploy/update_code.php",
"chars": 4833,
"preview": "<?php\n\nnamespace Deployer;\n\nuse Deployer\\Exception\\ConfigurationException;\nuse Symfony\\Component\\Console\\Input\\InputOpti"
},
{
"path": "recipe/deploy/vendors.php",
"chars": 1778,
"preview": "<?php\n\nnamespace Deployer;\n\nset('composer_action', 'install');\nset('composer_options', '--verbose --prefer-dist --no-pro"
},
{
"path": "recipe/deploy/writable.php",
"chars": 6556,
"preview": "<?php\n\nnamespace Deployer;\n\n// Used to make a writable directory by a server.\n// Used in `chown` and `acl` modes of {{wr"
},
{
"path": "recipe/drupal7.php",
"chars": 2031,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['drupal7']);\n\ntask('deploy', [\n 'd"
},
{
"path": "recipe/drupal8.php",
"chars": 554,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['drupal8']);\n\ntask('deploy', [\n 'd"
},
{
"path": "recipe/flow_framework.php",
"chars": 1043,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['flow_framework']);\n\n// Flow-Framewor"
},
{
"path": "recipe/fuelphp.php",
"chars": 327,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['fuelphp']);\n\n// FuelPHP 1.x shared d"
},
{
"path": "recipe/joomla.php",
"chars": 302,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['joomla']);\n\nset('shared_files', ['co"
},
{
"path": "recipe/laravel.php",
"chars": 9056,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['laravel']);\n\nset('shared_dirs', ['st"
},
{
"path": "recipe/magento.php",
"chars": 1103,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['magento']);\n\n/**\n * Magento Configur"
},
{
"path": "recipe/magento2.php",
"chars": 21348,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\nrequire_once __DIR__ . '/../contrib/cachetool.php';\n\nu"
},
{
"path": "recipe/pimcore.php",
"chars": 805,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/symfony.php';\n\nadd('recipes', ['pimcore']);\n\nadd('shared_dirs', ['p"
},
{
"path": "recipe/prestashop.php",
"chars": 824,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire_once __DIR__ . '/common.php';\n\nadd('recipes', ['prestashop']);\n\nset('shared_files', "
},
{
"path": "recipe/provision/404.html",
"chars": 2233,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width"
},
{
"path": "recipe/provision/Caddyfile",
"chars": 456,
"preview": "{{domain}} {\n root * {{deploy_path}}/current/{{public_path}}\n encode zstd gzip\n file_server\n php_fastcgi * unix//run"
},
{
"path": "recipe/provision/databases.php",
"chars": 2966,
"preview": "<?php\n\nnamespace Deployer;\n\nset('db_type', function () {\n $supportedDbTypes = [\n 'none',\n 'mysql',\n "
},
{
"path": "recipe/provision/nodejs.php",
"chars": 1123,
"preview": "<?php\n\nnamespace Deployer;\n\nuse function Deployer\\Support\\escape_shell_argument;\n\nset('node_version', '--lts');\n\ndesc('I"
},
{
"path": "recipe/provision/php.php",
"chars": 3708,
"preview": "<?php\n\nnamespace Deployer;\n\nset('php_version', function () {\n $defaultPhpVersion = file_exists('composer.json')\n "
},
{
"path": "recipe/provision/user.php",
"chars": 2876,
"preview": "<?php\n\nnamespace Deployer;\n\nuse function Deployer\\Support\\parse_home_dir;\n\nset('sudo_password', function () {\n return"
},
{
"path": "recipe/provision/website.php",
"chars": 2166,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Deployer;\n\nset('domain', function () {\n return ask(' Domain: ', get('hostn"
},
{
"path": "recipe/provision.php",
"chars": 6430,
"preview": "<?php\n\nnamespace Deployer;\n\nrequire __DIR__ . '/provision/databases.php';\nrequire __DIR__ . '/provision/nodejs.php';\nreq"
},
{
"path": "recipe/shopware.php",
"chars": 6201,
"preview": "<?php\n/**\n * ## Usage\n *\n * Add `repository` to your _deploy.php_ file:\n *\n * ```php\n * set('repository', 'git@github.co"
}
]
// ... and 138 more files (download for full content)
About this extraction
This page contains the full source code of the deployphp/deployer GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 338 files (1014.5 KB), approximately 271.2k tokens, and a symbol index with 739 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.