Skip to content

Commit 4ed7b4b

Browse files
committed
Initial commit
1 parent c3eb72e commit 4ed7b4b

File tree

5 files changed

+242
-1
lines changed

5 files changed

+242
-1
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/.idea
2+
/vendor/
3+
composer.lock

README.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,41 @@
1-
# laravel-migrate-to-branch
1+
# Laravel migrate:to-branch
2+
3+
This is a Laravel Artisan command to rollback migrations before switching to a given branch.
4+
5+
Imagine the scenario where you are working on a feature branch with some new migrations that have
6+
been run on the database. Now you want to switch back to the develop branch but you need to
7+
rollback the migrations to the state they were on the develop branch. This command makes this process
8+
easier by working out which migrations need rolled back and then running the `migrate:rollback` command
9+
for you.
10+
11+
**Note:** This command needs run _before_ you switch branches.
12+
13+
## Install
14+
15+
Require the library by running:
16+
17+
```
18+
composer require gilbitron/laravel-migrate-to-branch
19+
```
20+
21+
Next you need to add the following to your `providers` array in `config/app.php`:
22+
23+
```
24+
Gilbitron\Laravel\MigrateToBranchServiceProvider::class
25+
```
26+
27+
## Usage
28+
29+
Before switching to a different branch run the following command using the name of the destination branch:
30+
31+
```
32+
php artisan migrate:to-branch {branch}
33+
```
34+
35+
If you want to see which migrations need rolled back without actually running the `migrate:rollback` command
36+
you can use the `--dry-run` flag.
37+
38+
## Credits
39+
40+
Laravel "migrate:to-branch" was created by [Gilbert Pellegrom](https://gilbert.pellegrom.me) from
41+
[Dev7studios](https://dev7studios.co). Released under the MIT license.

composer.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "gilbitron/laravel-migrate-to-branch",
3+
"description": "A Laravel Artisan command to rollback migrations before switching to a given branch",
4+
"type": "library",
5+
"license": "MIT",
6+
"authors": [
7+
{
8+
"name": "Gilbert Pellegrom",
9+
"email": "gilbert@pellegrom.me"
10+
}
11+
],
12+
"require": {
13+
"laravel/framework": "5.*"
14+
},
15+
"autoload": {
16+
"psr-4": {
17+
"Gilbitron\\Laravel\\": "src/"
18+
}
19+
}
20+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<?php
2+
3+
namespace Gilbitron\Laravel\Console\Commands;
4+
5+
use Illuminate\Database\Console\Migrations\BaseCommand;
6+
use Illuminate\Support\Collection;
7+
8+
class MigrateToBranch extends BaseCommand
9+
{
10+
/**
11+
* The name and signature of the console command.
12+
*
13+
* @var string
14+
*/
15+
protected $signature = 'migrate:to-branch {branch : The name of the branch}
16+
{--database= : The database connection to use}
17+
{--path= : The path of migrations files to be executed}
18+
{--dry-run : Output the migrations that need rolled back}';
19+
20+
/**
21+
* The console command description.
22+
*
23+
* @var string
24+
*/
25+
protected $description = 'Rollback migrations before switching to a given branch';
26+
27+
/**
28+
* The migrator instance.
29+
*
30+
* @var \Illuminate\Database\Migrations\Migrator
31+
*/
32+
protected $migrator;
33+
34+
/**
35+
* Create a new command instance.
36+
*/
37+
public function __construct()
38+
{
39+
parent::__construct();
40+
41+
// For some reason dependency injecting this class doesn't work
42+
$this->migrator = app('migrator');
43+
}
44+
45+
/**
46+
* Execute the console command.
47+
*
48+
* @return mixed
49+
*/
50+
public function handle()
51+
{
52+
$destBranch = $this->argument('branch');
53+
$currentBranch = trim(shell_exec('git rev-parse --abbrev-ref HEAD'));
54+
55+
if ($destBranch == $currentBranch) {
56+
$this->error('Already on branch ' . $destBranch);
57+
return;
58+
}
59+
60+
$rollbackMigrations = $this->getMigrationsToRollBack($currentBranch, $destBranch);
61+
$ranMigrations = $this->getRanMigrations();
62+
63+
$steps = $rollbackMigrations->reject(function ($migration) use ($ranMigrations) {
64+
return !in_array($migration, $ranMigrations->toArray());
65+
});
66+
67+
if ($steps->count()) {
68+
if ($this->option('dry-run')) {
69+
$this->info('Rollback required! ' . $steps->count() . ' migrations need rolled back:');
70+
71+
$steps->each(function ($item) {
72+
$this->line(' - ' . $item);
73+
});
74+
75+
$this->info('Run the following command: php artisan migrate:rollback --step=' . $steps->count());
76+
} else {
77+
$this->call('migrate:rollback', [
78+
'--step' => $steps->count(),
79+
]);
80+
}
81+
} else {
82+
$this->info('No migrations need rolled back');
83+
}
84+
}
85+
86+
/**
87+
* Get migrations to roll back
88+
*
89+
* @param string $currentBranch
90+
* @param string $destBranch
91+
* @return Collection
92+
*/
93+
protected function getMigrationsToRollBack($currentBranch, $destBranch)
94+
{
95+
$command = 'cd ' . base_path() . ' && git diff --name-status ';
96+
$command .= $currentBranch . '..' . $destBranch;
97+
$command .= ' -- database/migrations';
98+
99+
/*
100+
* Format:
101+
* A database/migrations/2017_06_02_105859_example1_migration.php
102+
* D database/migrations/2017_06_02_105859_example2_migration.php
103+
*/
104+
$output = trim(shell_exec($command));
105+
$migrations = explode("\n", $output);
106+
107+
return collect($migrations)->reject(function ($migration) {
108+
// We only need migrations that don't exist in the dest branch
109+
return !starts_with($migration, 'D');
110+
})->map(function ($migration) {
111+
return basename($migration, '.php');
112+
});
113+
}
114+
115+
/**
116+
* Get migrations that have been run
117+
*
118+
* @return Collection
119+
*/
120+
protected function getRanMigrations()
121+
{
122+
$this->migrator->setConnection($this->option('database'));
123+
124+
if (!$this->migrator->repositoryExists()) {
125+
return collect();
126+
}
127+
128+
$ran = $this->migrator->getRepository()->getRan();
129+
130+
return collect($this->getAllMigrationFiles())->reject(function ($migration) use ($ran) {
131+
$migrationName = $this->migrator->getMigrationName($migration);
132+
133+
return !in_array($migrationName, $ran);
134+
})->keys();
135+
}
136+
137+
/**
138+
* Get an array of all of the migration files.
139+
*
140+
* @return array
141+
*/
142+
protected function getAllMigrationFiles()
143+
{
144+
return $this->migrator->getMigrationFiles($this->getMigrationPaths());
145+
}
146+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace Gilbitron\Laravel;
4+
5+
use Illuminate\Support\ServiceProvider;
6+
7+
class MigrateToBranchServiceProvider extends ServiceProvider
8+
{
9+
protected $commands = [
10+
\Gilbitron\Laravel\Console\Commands\MigrateToBranch::class,
11+
];
12+
13+
/**
14+
* Bootstrap the application services.
15+
*
16+
* @return void
17+
*/
18+
public function boot()
19+
{
20+
//
21+
}
22+
23+
/**
24+
* Register the application services.
25+
*
26+
* @return void
27+
*/
28+
public function register()
29+
{
30+
$this->commands($this->commands);
31+
}
32+
}

0 commit comments

Comments
 (0)