1414use JTMcC \AtomicDeployments \Models \Enums \DeploymentStatus ;
1515
1616use Illuminate \Support \Pluralizer ;
17+ use Illuminate \Support \Facades \File ;
1718
1819class AtomicDeployments
1920{
2021
2122 protected ?AtomicDeployment $ model = null ;
2223
2324 protected bool $ dryRun ;
25+ protected array $ migrate ;
2426
2527 protected string $ buildPath ;
2628 protected string $ deploymentLink ;
@@ -34,15 +36,22 @@ class AtomicDeployments
3436 * @param string $deploymentLink
3537 * @param string $deploymentsPath
3638 * @param string $buildPath
39+ * @param array $migrate
3740 * @param bool $dryRun
3841 *
3942 * @throws ExecuteFailedException
4043 */
41- public function __construct (string $ deploymentLink , string $ deploymentsPath , string $ buildPath , bool $ dryRun = false )
44+ public function __construct (
45+ string $ deploymentLink ,
46+ string $ deploymentsPath ,
47+ string $ buildPath ,
48+ array $ migrate = [],
49+ bool $ dryRun = false )
4250 {
4351 $ this ->deploymentLink = $ deploymentLink ;
4452 $ this ->deploymentsPath = $ deploymentsPath ;
4553 $ this ->buildPath = $ buildPath ;
54+ $ this ->migrate = $ migrate ;
4655 $ this ->dryRun = $ dryRun ;
4756
4857 register_shutdown_function ([$ this , 'shutdown ' ]);
@@ -57,7 +66,7 @@ public function __construct(string $deploymentLink, string $deploymentsPath, str
5766 * @param Closure|null $success
5867 * @param Closure|null $failed
5968 */
60- public function deploy (?Closure $ success = null , ?Closure $ failed = null )
69+ public function deploy (?Closure $ success = null , ?Closure $ failed = null ): void
6170 {
6271 try {
6372
@@ -80,6 +89,7 @@ public function deploy(?Closure $success = null, ?Closure $failed = null)
8089 $ this ->createDeploymentDirectory ();
8190 $ this ->confirmRequiredDirectoriesExist ();
8291 $ this ->copyDeploymentContents ();
92+ $ this ->copyMigrationContents ();
8393 $ this ->linkDeployment ($ this ->deploymentLink , $ this ->deploymentPath );
8494 $ this ->confirmSymbolicLink ($ this ->deploymentPath );
8595 $ this ->updateDeploymentStatus (DeploymentStatus::SUCCESS );
@@ -104,7 +114,7 @@ public function deploy(?Closure $success = null, ?Closure $failed = null)
104114 *
105115 * @param int $status
106116 */
107- public function updateDeploymentStatus (int $ status )
117+ public function updateDeploymentStatus (int $ status ): void
108118 {
109119 if ($ this ->isDryRun ()) {
110120 Output::warn ('Dry run - Skipping deployment status update ' );
@@ -132,7 +142,7 @@ public function updateDeploymentStatus(int $status)
132142 *
133143 * @throws ExecuteFailedException
134144 */
135- public function confirmSymbolicLink (string $ deploymentPath )
145+ public function confirmSymbolicLink (string $ deploymentPath ): bool
136146 {
137147 Output::info ('Confirming deployment link is correct ' );
138148 $ currentDeploymentPath = $ this ->getCurrentDeploymentPath ();
@@ -154,7 +164,7 @@ public function confirmSymbolicLink(string $deploymentPath)
154164 /**
155165 * @throws InvalidPathException
156166 */
157- public function confirmRequiredDirectoriesExist ()
167+ public function confirmRequiredDirectoriesExist (): void
158168 {
159169 if ($ this ->isDryRun ()) {
160170 Output::warn ('Dry run - Skipping required directory exists check for: ' );
@@ -176,7 +186,7 @@ public function createDeploymentDirectory(): void
176186 {
177187 Output::info ("Creating directory at {$ this ->deploymentPath }" );
178188
179- if (strpos ($ this ->deploymentPath , $ this ->buildPath ) !== false ) {
189+ if (strpos ($ this ->deploymentPath , $ this ->buildPath ) !== false ) {
180190 throw new InvalidPathException ('Deployments folder cannot be subdirectory of build folder ' );
181191 }
182192
@@ -204,11 +214,63 @@ public function copyDeploymentContents(): void
204214 return ;
205215 }
206216
207- Exec::rsyncDir ("{$ this ->buildPath }/ " , "{$ this ->deploymentPath }/ " );
217+ Exec::rsync ("{$ this ->buildPath }/ " , "{$ this ->deploymentPath }/ " );
208218 Output::info ('Copying complete ' );
209219 }
210220
211221
222+ /**
223+ * @throws ExecuteFailedException
224+ */
225+ public function copyMigrationContents (): void
226+ {
227+ if (!empty ($ this ->initialDeploymentPath ) && count ($ this ->migrate )) {
228+
229+ if ($ this ->isDryRun ()) {
230+ Output::warn ('Dry run - skipping migrations ' );
231+ }
232+
233+ collect ($ this ->migrate )->each (function ($ pattern ) {
234+
235+ if (!$ this ->isDryRun ()) {
236+ Output::info ("Running migration for pattern {$ pattern }" );
237+ }
238+
239+ $ rootFrom = rtrim ($ this ->initialDeploymentPath , DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR ;
240+ $ rootTo = rtrim ($ this ->deploymentPath , DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR ;
241+
242+ foreach (File::glob ($ rootFrom . $ pattern ) as $ from ) {
243+
244+ $ dir = $ from ;
245+
246+ if (!File::isDirectory ($ dir )) {
247+ $ dir = File::dirname ($ dir );
248+ }
249+
250+ $ dir = str_replace ($ rootFrom , $ rootTo , $ dir );
251+ $ to = str_replace ($ rootFrom , $ rootTo , $ from );
252+
253+ if ($ this ->isDryRun ()) {
254+ Output::warn ("Dry run - migrate: \r\n - {$ from }\r\n - {$ to }" );
255+ Output::line ();
256+ continue ;
257+ }
258+
259+ File::ensureDirectoryExists ($ dir , 0755 , true );
260+
261+ Exec::rsync ($ from , $ to );
262+
263+ }
264+
265+ if (!$ this ->isDryRun ()) {
266+ Output::info ("Finished migration for pattern {$ pattern }" );
267+ }
268+
269+ });
270+ }
271+ }
272+
273+
212274 /**
213275 * Create Symbolic link for live deployment
214276 * Will overwrite previous link
@@ -249,10 +311,10 @@ public function setDeploymentDirectory(string $name): void
249311 *
250312 * @throws ExecuteFailedException
251313 */
252- public function getCurrentDeploymentPath ()
314+ public function getCurrentDeploymentPath (): string
253315 {
254316 $ result = Exec::readlink ($ this ->deploymentLink );
255- if ($ result === $ this ->deploymentLink ) {
317+ if ($ result === $ this ->deploymentLink ) {
256318 return '' ;
257319 }
258320 return $ result ;
@@ -276,7 +338,7 @@ public function setDeploymentPath(): void
276338 *
277339 * @see getCurrentDeploymentPath() to get the path currently in use
278340 */
279- public function getDeploymentPath ()
341+ public function getDeploymentPath (): string
280342 {
281343 return $ this ->deploymentsPath ;
282344 }
@@ -333,7 +395,7 @@ public function rollback(): void
333395 * @throws ExecuteFailedException
334396 * @throws InvalidPathException
335397 */
336- public function cleanBuilds ($ limit )
398+ public function cleanBuilds ($ limit ): void
337399 {
338400 Output::alert ('Running Build Cleanup ' );
339401 Output::info ("Max deployment directories allowed set to {$ limit }" );
@@ -368,23 +430,30 @@ public function cleanBuilds($limit)
368430 }
369431
370432
371- public function isDryRun () {
433+ /**
434+ * @return bool
435+ */
436+ public function isDryRun (): bool
437+ {
372438 return $ this ->dryRun ;
373439 }
374-
440+
375441
376442 /**
377443 * @throws ExecuteFailedException
378444 */
379- public function failed ()
445+ public function failed (): void
380446 {
381447 $ this ->rollback ();
382448 $ this ->updateDeploymentStatus (DeploymentStatus::FAILED );
383449 DeploymentFailed::dispatch ($ this , $ this ->model );
384450 }
385451
386-
387- public function shutdown ()
452+
453+ /**
454+ * @throws ExecuteFailedException
455+ */
456+ public function shutdown (): void
388457 {
389458 if ($ error = error_get_last ()) {
390459 Output::error ("Error detected during shutdown, requesting rollback " );
0 commit comments