Passed
Push — trunk ( aca09f...bd7f95 )
by Christian
14:04 queued 13s
created

FlexMigrator   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 205
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 126
dl 0
loc 205
rs 10
c 0
b 0
f 0
wmc 15

5 Methods

Rating   Name   Duplication   Size   Complexity  
A cleanup() 0 20 5
A patchRootComposerJson() 0 57 4
A copyNewTemplateFiles() 0 5 1
A addSymlinkRepository() 0 25 3
A migrateEnvFile() 0 12 2
1
<?php
2
declare(strict_types=1);
3
4
namespace Shopware\WebInstaller\Services;
5
6
use Shopware\Core\Framework\Log\Package;
7
use Symfony\Component\Filesystem\Filesystem;
8
9
/**
10
 * @internal
11
 *
12
 * @phpstan-type ComposerRepository array{type: string, url: string, options: array{symlink: bool}}
13
 */
14
#[Package('core')]
15
class FlexMigrator
16
{
17
    private const REMOVE_FILES = [
18
        '.dockerignore',
19
        'Dockerfile',
20
        'PLATFORM_COMMIT_SHA',
21
        'README.md',
22
        'config/services.xml',
23
        'config/services_test.xml',
24
        'easy-coding-standard.php',
25
        'license.txt',
26
        'phpstan.neon',
27
        'phpunit.xml.dist',
28
        'psalm.xml',
29
        'public/index.php',
30
        'src/TestBootstrap.php',
31
        'var/plugins.json',
32
    ];
33
34
    private const REMOVE_DIRECTORIES = [
35
        '.github',
36
        '.gitlab-ci',
37
        'gitlab-ci.yml',
38
        'bin',
39
        'config/etc',
40
        'config/services',
41
        'public/recovery',
42
        'files/update',
43
    ];
44
45
    private const ENV_DEFAULT = <<<EOT
46
###> symfony/lock ###
47
# Choose one of the stores below
48
# postgresql+advisory://db_user:db_password@localhost/db_name
49
LOCK_DSN=flock
50
###< symfony/lock ###
51
###> symfony/messenger ###
52
# Choose one of the transports below
53
# MESSENGER_TRANSPORT_DSN=doctrine://default
54
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
55
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
56
###< symfony/messenger ###
57
###> symfony/mailer ###
58
# MAILER_DSN=null://null
59
###< symfony/mailer ###
60
###> shopware/core ###
61
APP_ENV=prod
62
APP_URL=http://127.0.0.1:8000
63
APP_SECRET=7628a40c75b25f8a1f14b3812c3b250b
64
INSTANCE_ID=41322ddd2b70bd29ef65d402f025c785
65
BLUE_GREEN_DEPLOYMENT=0
66
DATABASE_URL=mysql://root:root@localhost/shopware
67
# With Shopware 6.4.17.0 the MAILER_DSN variable will be used in this template instead of MAILER_URL
68
MAILER_URL=null://null
69
###< shopware/core ###
70
###> shopware/elasticsearch ###
71
OPENSEARCH_URL=http://localhost:9200
72
SHOPWARE_ES_ENABLED=0
73
SHOPWARE_ES_INDEXING_ENABLED=0
74
SHOPWARE_ES_INDEX_PREFIX=sw
75
SHOPWARE_ES_THROW_EXCEPTION=1
76
###< shopware/elasticsearch ###
77
###> shopware/storefront ###
78
STOREFRONT_PROXY_URL=http://localhost
79
SHOPWARE_HTTP_CACHE_ENABLED=1
80
SHOPWARE_HTTP_DEFAULT_TTL=7200
81
###< shopware/storefront ###
82
EOT;
83
84
    /**
85
     * Delete all files and directories that are not needed anymore
86
     */
87
    public function cleanup(string $projectDir): void
88
    {
89
        $fs = new Filesystem();
90
91
        foreach (self::REMOVE_FILES as $file) {
92
            $path = $projectDir . '/' . $file;
93
            if ($fs->exists($path)) {
94
                $fs->remove($path);
95
            }
96
        }
97
98
        foreach (self::REMOVE_DIRECTORIES as $directory) {
99
            $path = $projectDir . '/' . $directory;
100
101
            if ($fs->exists($path)) {
102
                $fs->remove($path);
103
            }
104
        }
105
106
        $fs->mkdir($projectDir . '/bin');
107
    }
108
109
    public function patchRootComposerJson(string $projectDir): void
110
    {
111
        $composerJsonPath = $projectDir . '/composer.json';
112
113
        /** @var array{require: array<string, string>, config?: array{platform?: string, "allow-plugins": array<string, bool>, repositories?: ComposerRepository[]}} $composerJson */
114
        $composerJson = json_decode((string) file_get_contents($composerJsonPath), true, \JSON_THROW_ON_ERROR);
115
116
        $composerJson['require']['symfony/flex'] = '^2';
117
        $composerJson['require']['symfony/runtime'] = '^5.0|^6.0';
118
119
        // Remove old recovery
120
        unset($composerJson['require']['shopware/recovery']);
121
122
        if (!isset($composerJson['config'])) {
123
            $composerJson['config'] = [];
124
        }
125
126
        if (!isset($composerJson['config']['allow-plugins'])) {
127
            $composerJson['config']['allow-plugins'] = [];
128
        }
129
130
        $composerJson['config']['allow-plugins']['symfony/flex'] = true;
131
        $composerJson['config']['allow-plugins']['symfony/runtime'] = true;
132
133
        unset($composerJson['config']['platform']);
134
135
        $composerJson['scripts'] = [
136
            'auto-scripts' => [
137
                'assets:install' => 'symfony-cmd',
138
            ],
139
            'post-install-cmd' => [
140
                '@auto-scripts',
141
            ],
142
            'post-update-cmd' => [
143
                '@auto-scripts',
144
            ],
145
        ];
146
147
        $composerJson['extra']['symfony'] = [
148
            'allow-contrib' => true,
149
            'endpoint' => [
150
                'https://raw.githubusercontent.com/shopware/recipes/flex/main/index.json',
151
                'flex://defaults',
152
            ],
153
        ];
154
155
        $composerJson['require-dev'] = [
156
            'shopware/dev-tools' => '*',
157
        ];
158
159
        if (!isset($composerJson['repositories'])) {
160
            $composerJson['repositories'] = [];
161
        }
162
163
        $composerJson['repositories'] = $this->addSymlinkRepository($composerJson['repositories']);
164
165
        file_put_contents($composerJsonPath, json_encode($composerJson, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES));
166
    }
167
168
    public function copyNewTemplateFiles(string $projectDir): void
169
    {
170
        $fs = new Filesystem();
171
172
        $fs->mirror(__DIR__ . '/../Resources/flex-config/', $projectDir);
173
    }
174
175
    public function migrateEnvFile(string $projectDir): void
176
    {
177
        $envPath = $projectDir . '/.env';
178
179
        if (!file_exists($envPath)) {
180
            file_put_contents($envPath, self::ENV_DEFAULT);
181
182
            return;
183
        }
184
185
        rename($envPath, $envPath . '.local');
186
        file_put_contents($envPath, self::ENV_DEFAULT);
187
    }
188
189
    /**
190
     * @param ComposerRepository[] $repositories
191
     *
192
     * @return ComposerRepository[]
193
     */
194
    private function addSymlinkRepository(array $repositories): array
195
    {
196
        $existingRepos = array_column($repositories, 'url');
197
198
        if (!\in_array('custom/plugins/*', $existingRepos, true)) {
199
            $repositories[] = [
200
                'type' => 'path',
201
                'url' => 'custom/plugins/*',
202
                'options' => [
203
                    'symlink' => true,
204
                ],
205
            ];
206
        }
207
208
        if (!\in_array('custom/plugins/*/packages/*', $existingRepos, true)) {
209
            $repositories[] = [
210
                'type' => 'path',
211
                'url' => 'custom/plugins/*/packages/*',
212
                'options' => [
213
                    'symlink' => true,
214
                ],
215
            ];
216
        }
217
218
        return $repositories;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $repositories returns an array which contains values of type array<string,array<string,true>|string> which are incompatible with the documented value type Shopware\WebInstaller\Services\ComposerRepository.
Loading history...
219
    }
220
}
221