Test Failed
Pull Request — master (#38)
by Stephen
14:18
created

CruiseInstall::handle()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 20
c 2
b 0
f 0
dl 0
loc 30
rs 9.2888
cc 5
nc 4
nop 0
1
<?php
2
3
namespace Sfneal\Cruise\Commands;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Contracts\Console\PromptsForMissingInput;
7
use Illuminate\Process\Pipe;
8
use Illuminate\Support\Facades\Artisan;
9
use Illuminate\Support\Facades\Process;
10
11
use function Laravel\Prompts\select;
12
use function Laravel\Prompts\text;
13
14
class CruiseInstall extends Command implements PromptsForMissingInput
15
{
16
    /**
17
     * The name and signature of the console command.
18
     *
19
     * @var string
20
     */
21
    protected $signature = 'cruise:install
22
                            {docker_id : Your docker ID you will be using with your laravel application}
23
                            {docker_image : Your laravel applications docker image name}
24
                            {front_end_compiler : Front-end asset bundler}';
25
26
    /**
27
     * The console command description.
28
     *
29
     * @var string
30
     */
31
    protected $description = 'Install the cruise package and publish files';
32
33
    /**
34
     * Execute the console command.
35
     */
36
    public function handle(): int
37
    {
38
        Artisan::call('vendor:publish', ['--tag' => 'cruise-config']);
39
        $this->info('Published cruise config files config/cruise.php');
40
41
        Artisan::call('vendor:publish', ['--tag' => 'docker']);
42
        $this->info('Published docker assets to the application root');
43
44
        $this->publishDockerAssets();
45
46
        $this->renameDockerImages($this->argument('docker_id'), $this->argument('docker_image'));
47
48
        $this->addComposerScript('start-dev');
49
        $this->addComposerScript('start-dev-db');
50
        $this->addComposerScript('start-dev-node');
51
        $this->addComposerScript('start-test');
52
        $this->addComposerScript('stop');
53
        $this->addComposerScript('build');
54
        $this->info('Published composer scripts for starting/stopping docker services');
55
56
        if (! file_exists(base_path('.env.dev')) && file_exists(base_path('.env'))) {
57
            copy(base_path('.env'), base_path('.env.dev'));
58
            $this->info('Published missing .env.dev file');
59
        }
60
        if (! file_exists(base_path('.env.dev.db')) && file_exists(base_path('.env'))) {
61
            copy(base_path('.env.dev'), base_path('.env.dev.db'));
62
            $this->info('Published missing .env.dev.db file');
63
        }
64
65
        return self::SUCCESS;
66
    }
67
68
    private function publishDockerAssets(): void
69
    {
70
        if ($this->argument('front_end_compiler') == 'Webpack') {
71
            Artisan::call('vendor:publish', ['--tag' => 'docker-webpack']);
72
        }
73
        if ($this->argument('front_end_compiler') == 'Vite') {
74
            Artisan::call('vendor:publish', ['--tag' => 'docker-vite']);
75
        }
76
        $this->info("Published {$this->argument('front_end_compiler')} Dockerfiles & docker-compose.yml's");
77
    }
78
79
    private function addComposerScript(string $script): void
80
    {
81
        $script_path = 'vendor/sfneal/cruise/scripts/runners';
82
83
        $process = Process::run([
84
            'composer', 'config', "scripts.$script", "sh $script_path/$script.sh", '--working-dir='.base_path(),
85
        ]);
86
87
        if ($process->successful()) {
88
            $this->info("Added 'composer $script' command to composer.json");
89
        }
90
    }
91
92
    private function renameDockerImages(string $docker_id, string $image_name): void
93
    {
94
        $og_full_image_name = trim(Process::path(base_path())
95
            ->run("grep -A 10 'services:' docker-compose.yml | grep -A 1 'app:' | grep 'image:' | awk '{print $2}' | grep -o '^[^:]*'")
96
            ->output());
97
98
        // Linux process
99
        $process = Process::pipe(function (Pipe $pipe) use ($og_full_image_name, $docker_id, $image_name) {
100
            [$og_docker_id, $og_image_name] = explode('/', $og_full_image_name);
101
102
            $docker_compose_files = [
103
                'docker-compose.yml',
104
                'docker-compose-dev.yml',
105
                'docker-compose-dev-db.yml',
106
                'docker-compose-dev-node.yml',
107
                'docker-compose-tests.yml',
108
            ];
109
110
            foreach ($docker_compose_files as $docker_file) {
111
                // Should work on Linux
112
                $pipe->path(base_path())->command("sed -i'' 's|$og_docker_id|$docker_id|g' ".$docker_file);
113
                $pipe->path(base_path())->command(trim("sed -i'' 's|$og_image_name|$image_name|g' ".$docker_file));
114
            }
115
        });
116
117
        // Mac process - ugly hack
118
        if (! $process->successful()) {
119
            $process = Process::pipe(function (Pipe $pipe) use ($og_full_image_name, $docker_id, $image_name) {
120
                [$og_docker_id, $og_image_name] = explode('/', $og_full_image_name);
121
122
                $docker_compose_files = [
123
                    'docker-compose.yml',
124
                    'docker-compose-dev.yml',
125
                    'docker-compose-dev-db.yml',
126
                    'docker-compose-dev-node.yml',
127
                    'docker-compose-tests.yml',
128
                ];
129
130
                foreach ($docker_compose_files as $docker_file) {
131
                    // Should work on Macs
132
                    $pipe->path(base_path())->command("sed -i '' 's|$og_docker_id|$docker_id|g' ".$docker_file);
133
                    $pipe->path(base_path())->command(trim("sed -i '' 's|$og_image_name|$image_name|g' ".$docker_file));
134
135
                    // I don't care if it works on Windows!
136
                }
137
            });
138
        }
139
140
        if ($process->successful()) {
141
            $this->info("Renamed docker images from {$og_full_image_name} to {$docker_id}/{$image_name}");
142
        } else {
143
            $this->info("Failed to rename docker images from {$og_full_image_name} to {$docker_id}/{$image_name}");
144
        }
145
    }
146
147
    /**
148
     * Prompt for missing input arguments using the returned questions.
149
     *
150
     * @return array<string, string>
151
     */
152
    protected function promptForMissingArgumentsUsing(): array
153
    {
154
        return [
155
            'docker_id' => function () {
156
                return text(
157
                    label: 'Enter your Docker ID:',
158
                    placeholder: 'E.g. mydockerid',
159
                    required: true,
160
                );
161
            },
162
            'docker_image' => function () {
163
                return text(
164
                    label: 'Enter your Docker image name (recommend using application name):',
165
                    placeholder: 'E.g. myapplication',
166
                    required: true,
167
                );
168
            },
169
            'front_end_compiler' => function () {
170
                return select(
171
                    label: 'Select Front-end asset compiler',
172
                    options: ['Webpack', 'Vite'],
173
                    default: 'Vite',
174
                );
175
            },
176
        ];
177
    }
178
}
179