├── .rsync_exclude.txt.dist
├── Command
└── DeployCommand.php
├── DependencyInjection
├── Configuration.php
└── DeployExtension.php
├── DeployBundle.php
├── README.md
└── composer.json
/.rsync_exclude.txt.dist:
--------------------------------------------------------------------------------
1 | # IDEs files
2 | .buildpath
3 | .project
4 | .settings
5 | nbproject
6 |
7 | # VCS files
8 | .gitignore
9 | .travis.yml
10 |
11 | /app/config/*_dev.yml
12 | /app/config/parameters.yml
13 | /app/logs
14 | /app/cache
15 | web/*
16 | vendor
17 |
--------------------------------------------------------------------------------
/Command/DeployCommand.php:
--------------------------------------------------------------------------------
1 | - http://www.iliveinperego.com/
5 | *
6 | * For the full copyright and license information, please view the LICENSE
7 | * file that was distributed with this source code.
8 | */
9 |
10 | namespace Hpatoio\DeployBundle\Command;
11 |
12 | use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
13 | use Symfony\Component\Console\Input\InputArgument;
14 | use Symfony\Component\Console\Input\InputInterface;
15 | use Symfony\Component\Console\Input\InputOption;
16 | use Symfony\Component\Console\Output\OutputInterface;
17 | use Symfony\Component\Console\Formatter\OutputFormatterStyle;
18 | use Symfony\Component\Process\Process;
19 |
20 | class DeployCommand extends ContainerAwareCommand
21 | {
22 | /**
23 | * @see Command
24 | */
25 | protected function configure()
26 | {
27 | $this
28 | ->setName('project:deploy')
29 | ->setDescription('Deploy your project via rsync')
30 | ->addArgument('env', InputArgument::REQUIRED, 'The environment where you want to deploy the project')
31 | ->addOption('go', null, InputOption::VALUE_NONE, 'Do the deployment')
32 | ->addOption('rsync-options', null, InputOption::VALUE_NONE, 'Options to pass to the rsync executable')
33 | ->addOption('force-vendor', null, InputOption::VALUE_NONE, 'Force sync of vendor dir.')
34 | ;
35 | }
36 |
37 | /**
38 | * @see Command
39 | */
40 | protected function execute(InputInterface $input, OutputInterface $output)
41 | {
42 |
43 | $config_root_path = $this->getContainer()->get('kernel')->getRootDir()."/config/";
44 | $output->getFormatter()->setStyle('notice', new OutputFormatterStyle('red', 'yellow'));
45 | $available_env = $this->getContainer()->getParameter('deploy.config');
46 |
47 | $env = $input->getArgument('env');
48 |
49 | if (!in_array($env, array_keys($available_env))) {
50 | throw new \InvalidArgumentException(sprintf('\'%s\' is no a valid environment. Valid environments: %s', $env, implode(",",array_keys($available_env))));
51 | }
52 |
53 | foreach ($available_env[$env] as $key => $value) {
54 | $$key = $value;
55 | }
56 |
57 | $ssh = 'ssh -p '.$port.'';
58 |
59 | if ($input->getOption('rsync-options'))
60 | $rsync_options = $input->getOption('rsync-options');
61 |
62 | if ($input->getOption('force-vendor'))
63 | $rsync_options .= " --include 'vendor' ";
64 |
65 | $exclude_file_found = false;
66 |
67 | if (file_exists($config_root_path.'rsync_exclude.txt')) {
68 | $rsync_options .= sprintf(' --exclude-from="%srsync_exclude.txt"', $config_root_path);
69 | $exclude_file_found = true;
70 | }
71 |
72 | if (file_exists($config_root_path."rsync_exclude_{$env}.txt")) {
73 | $rsync_options .= sprintf(" --exclude-from=\"%srsync_exclude_{$env}.txt\"", $config_root_path);
74 | $exclude_file_found = true;
75 | }
76 |
77 | if (!$exclude_file_found) {
78 | $output->writeln(sprintf('No rsync_exclude file found, nothing excluded. If you want an rsync_exclude.txt template get it here http://bit.ly/rsehdbsf2', $config_root_path."rsync_exclude.txt"));
79 | $output->writeln("");
80 | }
81 |
82 | $dryRun = $input->getOption('go') ? '' : '--dry-run';
83 |
84 | $user = ($user !='') ? $user."@" : "";
85 |
86 | $command = "rsync $dryRun $rsync_options -e \"$ssh\" ./ $user$host:$dir";
87 |
88 | $output->writeln(sprintf('%s on %s server with %s command',
89 | ($dryRun) ? 'Fake deploying' : 'Deploying',
90 | $input->getArgument('env'),
91 | $command));
92 |
93 | $process = new Process($command);
94 | $process->setTimeout(($timeout == 0) ? null : $timeout);
95 |
96 | $output->writeln("\nSTART deploy\n--------------------------------------------");
97 |
98 | $process->run(function ($type, $buffer) use ($output) {
99 | if ('err' === $type) {
100 | $output->write( 'ERR > '.$buffer);
101 | } else {
102 | $output->write($buffer);
103 | }
104 | });
105 |
106 | $output->writeln("\nEND deploy\n--------------------------------------------\n");
107 |
108 | if ($dryRun) {
109 |
110 | $output->writeln('This was a simulation, --go was not specified. Post deploy operation not run.');
111 | $output->writeln(sprintf('Run the command with --go for really copy the files to %s server.', $env));
112 |
113 | } else {
114 |
115 | $output->writeln(sprintf("Deployed on %s server!\n", $env));
116 |
117 | if ( isset($post_deploy_operations) && count($post_deploy_operations) > 0 ) {
118 |
119 | $post_deploy_commands = implode("; ", $post_deploy_operations);
120 |
121 | $output->writeln(sprintf("Running post deploy commands on %s server!\n", $env));
122 |
123 | $command = "$ssh $user$host 'cd \"$dir\";".$post_deploy_commands."'";
124 |
125 | $process = new Process($command);
126 | $process->setTimeout(($timeout == 0) ? null : $timeout);
127 | $process->run(function ($type, $buffer) use ($output) {
128 | if ('err' === $type) {
129 | $output->write( 'ERR > '.$buffer);
130 | } else {
131 | $output->write($buffer);
132 | }
133 | });
134 |
135 | $output->writeln("\nDone");
136 |
137 | }
138 |
139 | }
140 |
141 | $output->writeln("");
142 |
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/DependencyInjection/Configuration.php:
--------------------------------------------------------------------------------
1 | - http://www.iliveinperego.com/
5 | *
6 | * For the full copyright and license information, please view the LICENSE
7 | * file that was distributed with this source code.
8 | */
9 |
10 | namespace Hpatoio\DeployBundle\DependencyInjection;
11 |
12 | use Symfony\Component\Config\Definition\Builder\TreeBuilder;
13 | use Symfony\Component\Config\Definition\ConfigurationInterface;
14 |
15 | /**
16 | * This is the class that validates and merges configuration from your app/config files
17 | *
18 | * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
19 | */
20 | class Configuration implements ConfigurationInterface
21 | {
22 | /**
23 | * {@inheritDoc}
24 | */
25 | public function getConfigTreeBuilder()
26 | {
27 |
28 | $treeBuilder = new TreeBuilder();
29 | $rootNode = $treeBuilder->root('deploy');
30 |
31 | // Here you should define the parameters that are allowed to
32 | // configure your bundle. See the documentation linked above for
33 | // more information on that topic.
34 |
35 | $rootNode->isRequired()
36 | ->requiresAtLeastOneElement()
37 | ->useAttributeAsKey('name')
38 | ->prototype('array')
39 | ->children()
40 | ->scalarNode('rsync_options')
41 | ->defaultValue('-azC --force --delete --progress -h --checksum')
42 | ->info('Default options used by the rsync command. You can override this value by passing --rsync-options on the command line.')
43 | ->example('-azC --force --delete --progress -h --checksum')
44 | ->end()
45 | ->scalarNode('host')
46 | ->isRequired()
47 | ->cannotBeEmpty()
48 | ->info('Name or IP of the remote server')
49 | ->end()
50 | ->scalarNode('dir')
51 | ->defaultValue('')
52 | ->info('Remote root for your project. NB: this is not the document root. Usually a level before.')
53 | ->end()
54 | ->scalarNode('user')
55 | ->defaultValue('')
56 | ->info('The user on the destination server. If none is specified your local user is used.')
57 | ->end()
58 | ->scalarNode('port')
59 | ->defaultValue('22')
60 | ->info('TCP port.')
61 | ->end()
62 | ->scalarNode('timeout')
63 | ->defaultValue('60')
64 | ->info('Process timeout in seconds. Set it to 0 for no timeout.')
65 | ->end()
66 | ->variableNode('post_deploy_operations')
67 | ->info('Shell commands to run after deploy on the remote machine.')
68 | ->end();
69 |
70 | return $treeBuilder;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/DependencyInjection/DeployExtension.php:
--------------------------------------------------------------------------------
1 | - http://www.iliveinperego.com/
5 | *
6 | * For the full copyright and license information, please view the LICENSE
7 | * file that was distributed with this source code.
8 | */
9 |
10 | namespace Hpatoio\DeployBundle\DependencyInjection;
11 |
12 | use Symfony\Component\HttpKernel\DependencyInjection\Extension;
13 | use Symfony\Component\DependencyInjection\ContainerBuilder;
14 |
15 | class DeployExtension extends Extension
16 | {
17 |
18 | /**
19 | * {@inheritDoc}
20 | */
21 | public function load(array $configs, ContainerBuilder $container)
22 | {
23 | $configuration = new Configuration();
24 | $config = $this->processConfiguration($configuration, $configs);
25 |
26 | $container->setParameter('deploy.config', $config);
27 |
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/DeployBundle.php:
--------------------------------------------------------------------------------
1 | - http://www.iliveinperego.com/
5 | *
6 | * For the full copyright and license information, please view the LICENSE
7 | * file that was distributed with this source code.
8 | */
9 |
10 | namespace Hpatoio\DeployBundle;
11 |
12 | use Symfony\Component\HttpKernel\Bundle\Bundle;
13 |
14 | class DeployBundle extends Bundle
15 | {
16 | }
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | DeployBundle
2 | =================
3 |
4 | [](https://packagist.org/packages/hpatoio/deploy-bundle)
5 | [](https://packagist.org/packages/hpatoio/deploy-bundle)
6 | [](https://insight.sensiolabs.com/projects/b4556cd7-652f-4a58-9126-eb2c1abd6c89)
7 |
8 | ## Installation
9 | Run the command:
10 |
11 | ```bash
12 | $ composer require hpatoio/deploy-bundle ~1.5
13 | ```
14 |
15 | **N.B.** This project follow [semantic versioning](http://semver.org/). Latest stable branch is `1.5`.
16 |
17 |
18 | ### Enable the bundle in your project
19 | ```php
20 | // app/AppKernel.php
21 | public function registerBundles()
22 | {
23 | $bundles = array(
24 | // ...
25 | new Hpatoio\DeployBundle\DeployBundle(),
26 | // ...
27 | );
28 | }
29 | ```
30 | ## Configuration
31 | Configuration is all about defining environments. You can define as many environments as you want, the only mandatory value is `host`. The deploy is made via rsync so default value are used if none are specified.
32 | Remember that to get the configuration reference for this bundle you can run:
33 | ```bash
34 | bin/console config:dump-reference DeployBundle
35 | ```
36 |
37 | Configuration example:
38 | ```yaml
39 | # app/config/config.yml
40 | deploy:
41 | prod:
42 | rsync-options: '-azC --force --delete --progress -h --checksum'
43 | host: my.destination.env
44 | dir: /path/to/project/root
45 | user: root
46 | port: 22
47 | timeout: 120 # Connection timeout in seconds. 0 for no timeout.
48 | uat:
49 | host: 192.168.1.10
50 | user: root2
51 | dir: /path/to/project/root
52 | port: 22022
53 | post_deploy_operations:
54 | - bin/console cache:clear --env=prod
55 | - bin/console assets:install --env=prod
56 | - bin/console assetic:dump --env=prod
57 | ```
58 |
59 | Most of the keys don't need explanation except:
60 |
61 | #### post_deploy_operations
62 | You can add a list of command you want run on the remote server after the deploy. In the configuration above you can see the common command you run after a deploy (clear the cache, publish assets etc)
63 | These commands are run as a shell command on the remote server. So you can enter whichever shell command you want (cp, rm etc)
64 |
65 | Please don't confuse Symfony environment with deploy environment. As you can see in the configuration above we run `post_deploy_operations` for Symfony environment `prod` on deploy environment `uat`
66 |
67 | #### rsync-options
68 | If you add the key `rsync-options` to your environment you will override the default options used for rsync. So the system is using:
69 |
70 | * "-azC --force --delete --progress -h --checksum" if nothing is specified
71 | * the value for the key `rsync-options` if specified it in `config.yml` for the target environment
72 | * the value of the command line option `--rsync-options`
73 |
74 | ### Rsync Exclude
75 | Create a `rsync_exclude.txt` file under `app/config` to exclude files from deploy. [here](https://github.com/hpatoio/DeployBundle/blob/master/.rsync_exclude.txt.dist) a good starting point.
76 |
77 | You can also create a per-environment rsync_exclude. Just create a file in `app/config` with name `rsync_exclude_{env}.txt`. For more details you can read here #3 and here #7
78 |
79 | ## Force vendor syncronization
80 | Usually `vendor` dir is excluded from rsync. If you need tou sync it you can add `--force-vendor`. (see later for an example)
81 |
82 | ## Use
83 | Deployment is easy:
84 | ```shell
85 | php bin/console project:deploy --go prod
86 | ```
87 | Feel a bit unsure ? Simulate the deploy
88 | ```shell
89 | php bin/console project:deploy prod
90 | ```
91 | Need to update vendor ? Use the option --force-vendor (Usually vendor is excluded from rsync)
92 | ```shell
93 | php bin/console project:deploy --go --force-vendor prod
94 | ```
95 | Custom parameters for rsync
96 | ```shell
97 | php bin/console project:deploy --rsync-options="-azChdl" prod
98 | ```
99 | License
100 | -------------
101 | DeployBundle is licensed under the CC-BY-SA-3.0 - see [here](http://www.spdx.org/licenses/CC-BY-SA-3.0) for details
102 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hpatoio/deploy-bundle",
3 | "type": "symfony-bundle",
4 | "description": "Easy deploy via rsync. Porting of Symfony 1 project:deploy command.",
5 | "keywords": ["deploy","command"],
6 | "homepage": "http://github.com/hpatoio/DeployBundle",
7 | "license": "CC-BY-SA-3.0",
8 | "authors": [
9 | {
10 | "name": "Simone Fumagalli",
11 | "homepage": "http://www.iliveinperego.com/",
12 | "email": "simone@iliveinperego.com",
13 | "role": "Developer"
14 | }
15 | ],
16 | "require": {
17 | "php": ">=5.3.2",
18 | "symfony/framework-bundle": "~2.0|~3.0"
19 | },
20 | "autoload": {
21 | "psr-0": { "Hpatoio\\DeployBundle": "" }
22 | },
23 | "target-dir": "Hpatoio/DeployBundle"
24 | }
25 |
--------------------------------------------------------------------------------