Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AL-1612 - Added an initialization check to env:clone-content for the target environment in order to prevent workflow error #1930

Merged
merged 5 commits into from
Jan 22, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ All notable changes to this project will be documented in this file. This projec
- Lock::serialize() 'locked' attribute has changed from string to boolean. (#1923)
- `Pantheon\Terminus\Friends\RowsOfFieldsTrait` has become `Pantheon\Terminus\Commands\StructuredDataTrait`. (#1923)
- `Backup::getUrl()` has been changed to `Backup::getArchiveURL()`. (#1923)
- Changed Environment::cloneDatabase() to accept an Environment object. (#1930)
- Changed Environment::cloneFiles() to accept an Environment object. (#1930)
- The target environment used in `env:clone-content` is now checked for initialization prior to cloning. (#1930)

### Deprecated
- `service-level:set` is now deprecated. Please use `plan:set`. (#1901)
Expand Down
110 changes: 84 additions & 26 deletions src/Commands/Env/CloneContentCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
use League\Container\ContainerAwareTrait;
use Pantheon\Terminus\Commands\TerminusCommand;
use Pantheon\Terminus\Exceptions\TerminusException;
use Pantheon\Terminus\Models\Environment;
use Pantheon\Terminus\Models\Workflow;
use Pantheon\Terminus\ProgressBars\WorkflowProgressBar;
use Pantheon\Terminus\Site\SiteAwareInterface;
use Pantheon\Terminus\Site\SiteAwareTrait;
Expand All @@ -19,6 +21,16 @@ class CloneContentCommand extends TerminusCommand implements ContainerAwareInter
use ContainerAwareTrait;
use SiteAwareTrait;

/**
* @var Environment
*/
private $source_env;
/**
* @var Environment
*/
private $target_env;


/**
* Clones database/files from one environment to another environment.
*
Expand All @@ -41,43 +53,89 @@ class CloneContentCommand extends TerminusCommand implements ContainerAwareInter
public function cloneContent($site_env, $target_env, array $options = ['db-only' => false, 'files-only' => false,])
{
if (!empty($options['db-only']) && !empty($options['files-only'])) {
throw new TerminusException("You cannot specify both --db-only and --files-only");
throw new TerminusException('You cannot specify both --db-only and --files-only');
}

list($site, $env) = $this->getUnfrozenSiteEnv($site_env);
$from_name = $env->getName();
$target = $site->getEnvironments()->get($target_env);
$to_name = $target->getName();
list($site, $this->source_env) = $this->getUnfrozenSiteEnv($site_env);
$this->target_env = $site->getEnvironments()->get($target_env);

$tr = ['from' => $from_name, 'to' => $to_name, 'site' => $site->getName(),];
if (!$env->isInitialized()) {
throw new TerminusException(
"{site}'s {from} environment cannot be cloned because it has not been initialized. Please run `env:deploy {site}.{from}` to initialize it.",
$tr
);
}
if (!$this->confirm('Are you sure you want to clone content from {from} to {to} on {site}?', $tr)) {
$this->checkForInitialization($this->source_env);
$this->checkForInitialization($this->target_env);
if (!$this->confirm(
'Are you sure you want to clone content from {from} to {to} on {site}?',
[
'from' => $this->source_env->getName(),
'site' => $site->getName(),
'to' => $this->target_env->getName(),
]
)) {
return;
}

if (empty($options['db-only'])) {
$workflow = $target->cloneFiles($from_name);
$this->log()->notice(
"Cloning files from {from_name} environment to {target_env} environment",
compact(['from_name', 'target_env'])
);
$this->getContainer()->get(WorkflowProgressBar::class, [$this->output, $workflow,])->cycle();
$this->log()->notice($workflow->getMessage());
$this->cloneFiles();
}

if (empty($options['files-only'])) {
$workflow = $target->cloneDatabase($from_name);
$this->log()->notice(
"Cloning database from {from_name} environment to {target_env} environment",
compact(['from_name', 'target_env'])
$this->cloneDatabase();
}
}

/**
* Checks to see whether the indicated environment is initialized and stops the process if it isn't
*
* @param Environment $env
* @throws TerminusException Thrown if the passed-in environment is not initialized
*/
private function checkForInitialization(Environment $env)
{
if (!$env->isInitialized()) {
throw new TerminusException(
"{site}'s {env} environment cannot be cloned because it has not been initialized. Please run `env:deploy {site}.{env}` to initialize it.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this language is too specific since the check is used for both the source and the destination?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. I think I do want to change this.

['env' => $env->getName(), 'site' => $env->getSite()->getName(),]
);
$this->getContainer()->get(WorkflowProgressBar::class, [$this->output, $workflow,])->cycle();
$this->log()->notice($workflow->getMessage());
}
}

/**
* Emits the cloning notice and clones runs the database cloning
*/
private function cloneDatabase()
{
$this->emitNotice('database');
$this->runClone($this->target_env->cloneDatabase($this->source_env));
}

/**
* Emits the cloning notice and clones runs the files cloning
*/
private function cloneFiles()
{
$this->emitNotice('files');
$this->runClone($this->target_env->cloneFiles($this->source_env));
}

/**
* Emits the cloning notice
*
* @param string $element
*/
private function emitNotice($element)
{
$this->log()->notice(
"Cloning ${element} from {source} environment to {target} environment",
['source' => $this->source_env->getName(), 'target' => $this->target_env->getName(),]
);
}

/**
* Runs the clone workflow with a progress bar
*
* @param Workflow $workflow
*/
private function runClone(Workflow $workflow)
{
$this->getContainer()->get(WorkflowProgressBar::class, [$this->output, $workflow,])->cycle();
$this->log()->notice($workflow->getMessage());
}
}
12 changes: 6 additions & 6 deletions src/Models/Environment.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,24 +143,24 @@ public function clearCache()
/**
* Clones database from this environment to another
*
* @param string $from_env Name of the environment to clone
* @param Environment $from_env An object representing the environment to clone
* @return Workflow
*/
public function cloneDatabase($from_env)
public function cloneDatabase(Environment $from_env)
{
$params = ['from_environment' => $from_env,];
$params = ['from_environment' => $from_env->getName(),];
return $this->getWorkflows()->create('clone_database', compact('params'));
}

/**
* Clones files from this environment to another
*
* @param string $from_env Name of the environment to clone
* @param Environment $from_env An object representing the environment to clone
* @return Workflow
*/
public function cloneFiles($from_env)
public function cloneFiles(Environment $from_env)
{
$params = ['from_environment' => $from_env,];
$params = ['from_environment' => $from_env->getName(),];
return $this->getWorkflows()->create('clone_files', compact('params'));
}

Expand Down
12 changes: 10 additions & 2 deletions tests/features/env-clone.feature
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,18 @@ Feature: Cloning site content
Cloned database from "test" to "dev"
"""

@vcr env-clone-uninitialized.yml
Scenario: Attempting to clone an uninitialized environment
@vcr env-clone-from-uninitialized.yml
Scenario: Attempting to clone from an uninitialized environment
When I run "terminus env:clone-content [[test_site_name]].test dev --db-only --yes"
Then I should get:
"""
[[test_site_name]]'s test environment cannot be cloned because it has not been initialized. Please run `env:deploy [[test_site_name]].test` to initialize it.
"""

@vcr env-clone-to-uninitialized.yml
Scenario: Attempting to clone to an uninitialized environment
When I run "terminus env:clone-content [[test_site_name]].test live --db-only --yes"
Then I should get:
"""
[[test_site_name]]'s live environment cannot be cloned because it has not been initialized. Please run `env:deploy [[test_site_name]].live` to initialize it.
"""
Loading