diff --git a/src/Component.php b/src/Component.php index 03e7bf8..60e169f 100644 --- a/src/Component.php +++ b/src/Component.php @@ -8,6 +8,7 @@ use Keboola\AppProjectMigrate\JobRunner\JobRunnerFactory; use Keboola\Component\BaseComponent; use Keboola\Component\UserException; +use Keboola\EncryptionApiClient\Migrations; use Keboola\StorageApi\Client as StorageClient; use Keboola\StorageApi\ClientException as StorageClientException; use Keboola\StorageApi\Components; @@ -51,6 +52,10 @@ protected function run(): void ); } + if ($config->shouldMigrateSecrets() && !$config->getSourceManageToken()) { + throw new UserException('#sourceManageToken must be set.', 422); + } + Utils::checkMigrationApps($sourceProjectClient, $destProjectClient); if (!Utils::checkIfProjectEmpty($destProjectClient, new Components($destProjectClient))) { @@ -71,11 +76,16 @@ protected function run(): void $sourceJobRunner = JobRunnerFactory::create($sourceProjectClient, $logger); $destJobRunner = JobRunnerFactory::create($destProjectClient, $logger); + $migrationsClient = new Migrations($config->getSourceManageToken() ?? '', [ + 'url' => $sourceProjectClient->getServiceUrl('encryption'), + ]); $migrate = new Migrate( $config, $sourceJobRunner, $destJobRunner, + $sourceProjectClient, + $migrationsClient, $destProjectClient->getApiUrl(), $destProjectClient->getTokenString(), $logger, diff --git a/src/Migrate.php b/src/Migrate.php index 88d156d..db49e5e 100644 --- a/src/Migrate.php +++ b/src/Migrate.php @@ -4,12 +4,11 @@ namespace Keboola\AppProjectMigrate; -use Closure; use Keboola\AppProjectMigrate\JobRunner\JobRunner; use Keboola\AppProjectMigrate\JobRunner\SyrupJobRunner; use Keboola\Component\UserException; use Keboola\EncryptionApiClient\Exception\ClientException as EncryptionClientException; -use Keboola\EncryptionApiClient\Migrations; +use Keboola\EncryptionApiClient\Migrations as MigrationsClient; use Keboola\StorageApi\Client as StorageClient; use Keboola\StorageApi\Components; use Keboola\StorageApi\DevBranches; @@ -24,6 +23,10 @@ class Migrate private JobRunner $destJobRunner; + private StorageClient $sourceProjectStorageClient; + + private MigrationsClient $migrationsClient; + private string $sourceProjectUrl; private string $sourceProjectToken; @@ -32,18 +35,12 @@ class Migrate private string $destinationProjectToken; - private ?string $sourceManageApiToken; - private LoggerInterface $logger; private bool $directDataMigration; private bool $migrateSecrets; - private Closure $sourceClientFactory; - - private Closure $migrationsClientFactory; - public const OBSOLETE_COMPONENTS = [ 'orchestrator', 'gooddata-writer', @@ -53,17 +50,20 @@ public function __construct( Config $config, JobRunner $sourceJobRunner, JobRunner $destJobRunner, + StorageClient $sourceProjectStorageClient, + MigrationsClient $migrationsClient, string $destinationProjectUrl, string $destinationProjectToken, LoggerInterface $logger ) { $this->sourceJobRunner = $sourceJobRunner; $this->destJobRunner = $destJobRunner; + $this->sourceProjectStorageClient = $sourceProjectStorageClient; + $this->migrationsClient = $migrationsClient; $this->sourceProjectUrl = $config->getSourceProjectUrl(); $this->sourceProjectToken = $config->getSourceProjectToken(); $this->destinationProjectUrl = $destinationProjectUrl; $this->destinationProjectToken = $destinationProjectToken; - $this->sourceManageApiToken = $config->getSourceManageToken(); $this->directDataMigration = $config->directDataMigration(); $this->migrateSecrets = $config->shouldMigrateSecrets(); $this->logger = $logger; @@ -100,16 +100,6 @@ public function run(): void } } - public function setSourceClientFactory(callable $factory): void - { - $this->sourceClientFactory = Closure::fromCallable($factory); - } - - public function setMigrationsClientFactory(callable $factory): void - { - $this->migrationsClientFactory = Closure::fromCallable($factory); - } - private function generateBackupCredentials(): array { $this->logger->info('Creating backup credentials'); @@ -162,22 +152,17 @@ private function migrateSecrets(): void { $this->logger->info('Migrating secrets in configurations', ['secrets']); - $sourceClient = $this->createSourceClient(); - - $sourceDevBranches = new DevBranches($sourceClient); + $sourceDevBranches = new DevBranches($this->sourceProjectStorageClient); $sourceBranches = $sourceDevBranches->listBranches(); $defaultSourceBranch = current(array_filter($sourceBranches, fn($b) => $b['isDefault'] === true)); - $sourceComponentsApi = new Components($sourceClient); + $sourceComponentsApi = new Components($this->sourceProjectStorageClient); $components = $sourceComponentsApi->listComponents(); if (!$components) { $this->logger->info('There are no components to migrate.', ['secrets']); return; } - $encryptionApiUrl = $sourceClient->getServiceUrl('encryption'); - $migrations = $this->createMigrationsClient($encryptionApiUrl); - foreach ($components as $component) { if (in_array($component['id'], self::OBSOLETE_COMPONENTS, true)) { $this->logger->info( @@ -188,7 +173,7 @@ private function migrateSecrets(): void } foreach ($component['configurations'] as $config) { - $response = $migrations + $response = $this->migrationsClient ->migrateConfiguration( $this->sourceProjectToken, Utils::getStackFromProjectUrl($this->destinationProjectUrl), @@ -203,27 +188,6 @@ private function migrateSecrets(): void } } - private function createSourceClient(): StorageClient - { - if (isset($this->sourceClientFactory)) { - return (fn(): StorageClient => ($this->sourceClientFactory)())(); - } - return new StorageClient(['token' => $this->sourceProjectToken, 'url' => $this->sourceProjectUrl ]); - } - - private function createMigrationsClient(string $encryptionApiUrl): Migrations - { - if (isset($this->migrationsClientFactory)) { - return (fn(): Migrations => ($this->migrationsClientFactory)($encryptionApiUrl))(); - } - if (!$this->sourceManageApiToken) { - throw new UserException('#sourceManageToken must be set', 422); - } - return new Migrations($this->sourceManageApiToken, [ - 'url' => $encryptionApiUrl, - ]); - } - private function migrateDataOfTablesDirectly(): void { $this->logger->info('Migrate data of tables directly.'); diff --git a/tests/phpunit/MigrateTest.php b/tests/phpunit/MigrateTest.php index 0fa0eee..8810ce2 100644 --- a/tests/phpunit/MigrateTest.php +++ b/tests/phpunit/MigrateTest.php @@ -133,17 +133,6 @@ public function testMigrateSuccess( $logsHandler = new TestHandler(); $logger = new Logger('tests', [$logsHandler]); - /** @var JobRunner $sourceJobRunnerMock */ - /** @var JobRunner $destJobRunnerMock */ - $migrate = new Migrate( - $config, - $sourceJobRunnerMock, - $destJobRunnerMock, - 'https://dest-stack/', - 'dest-token', - $logger, - ); - $sourceClientMock = $this->createMock(StorageClient::class); $sourceClientMock ->method('apiGet') @@ -211,8 +200,18 @@ public function testMigrateSuccess( $migrationsClientMock->expects(self::never())->method('migrateConfiguration'); } - $migrate->setSourceClientFactory(fn() => $sourceClientMock); - $migrate->setMigrationsClientFactory(fn() => $migrationsClientMock); + /** @var JobRunner $sourceJobRunnerMock */ + /** @var JobRunner $destJobRunnerMock */ + $migrate = new Migrate( + $config, + $sourceJobRunnerMock, + $destJobRunnerMock, + $sourceClientMock, + $migrationsClientMock, + 'https://dest-stack/', + 'dest-token', + $logger, + ); $migrate->run(); @@ -249,6 +248,8 @@ public function testShouldFailOnSnapshotError(): void { $sourceJobRunnerMock = $this->createMock(SyrupJobRunner::class); $destJobRunnerMock = $this->createMock(SyrupJobRunner::class); + $sourceClientMock = $this->createMock(StorageClient::class); + $migrationsClientMock = $this->createMock(Migrations::class); // generate credentials $this->mockAddMethodGenerateS3ReadCredentials($sourceJobRunnerMock); @@ -286,6 +287,8 @@ public function testShouldFailOnSnapshotError(): void $config, $sourceJobRunnerMock, $destJobRunnerMock, + $sourceClientMock, + $migrationsClientMock, 'xxx-b', 'yyy-b', new NullLogger(), @@ -295,12 +298,14 @@ public function testShouldFailOnSnapshotError(): void public function testShouldFailOnRestoreError(): void { - $sourceClientMock = $this->createMock(SyrupJobRunner::class); - $destClientMock = $this->createMock(SyrupJobRunner::class); + $sourceJobRunnerMock = $this->createMock(SyrupJobRunner::class); + $destJobRunnerMock = $this->createMock(SyrupJobRunner::class); + $sourceClientMock = $this->createMock(StorageClient::class); + $migrationsClientMock = $this->createMock(Migrations::class); - $this->mockAddMethodGenerateS3ReadCredentials($sourceClientMock); + $this->mockAddMethodGenerateS3ReadCredentials($sourceJobRunnerMock); $this->mockAddMethodBackupProject( - $sourceClientMock, + $sourceJobRunnerMock, [ 'id' => '222', 'status' => 'success', @@ -308,7 +313,7 @@ public function testShouldFailOnRestoreError(): void false ); - $destClientMock + $destJobRunnerMock ->method('runJob') ->willReturn([ 'id' => '222', @@ -335,8 +340,10 @@ public function testShouldFailOnRestoreError(): void $migrate = new Migrate( $config, + $sourceJobRunnerMock, + $destJobRunnerMock, $sourceClientMock, - $destClientMock, + $migrationsClientMock, 'xxx-b', 'yyy-b', new NullLogger(), @@ -346,12 +353,14 @@ public function testShouldFailOnRestoreError(): void public function testCatchSyrupClientException(): void { - $sourceClientMock = $this->createMock(SyrupJobRunner::class); - $destinationClientMock = $this->createMock(SyrupJobRunner::class); + $sourceJobRunnerMock = $this->createMock(SyrupJobRunner::class); + $destJobRunnerMock = $this->createMock(SyrupJobRunner::class); + $sourceClientMock = $this->createMock(StorageClient::class); + $migrationsClientMock = $this->createMock(Migrations::class); - $this->mockAddMethodGenerateS3ReadCredentials($sourceClientMock); + $this->mockAddMethodGenerateS3ReadCredentials($sourceJobRunnerMock); $this->mockAddMethodBackupProject( - $sourceClientMock, + $sourceJobRunnerMock, [ 'id' => '222', 'status' => 'success', @@ -359,7 +368,7 @@ public function testCatchSyrupClientException(): void false ); - $destinationClientMock + $destJobRunnerMock ->method('runJob') ->willThrowException( new ClientException('Test ClientException', 401) @@ -380,8 +389,10 @@ public function testCatchSyrupClientException(): void $migrate = new Migrate( $config, + $sourceJobRunnerMock, + $destJobRunnerMock, $sourceClientMock, - $destinationClientMock, + $migrationsClientMock, 'xxx-b', 'yyy-b', new NullLogger(),