ComposerCompatibilityCheckerStep3::runActualTask()   C
last analyzed

Complexity

Conditions 11
Paths 30

Size

Total Lines 91
Code Lines 70

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 70
c 1
b 0
f 0
dl 0
loc 91
rs 6.5077
cc 11
nc 30
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Sunnysideup\UpgradeToSilverstripe4\Tasks\IndividualTasks;
4
5
use Sunnysideup\UpgradeToSilverstripe4\Api\FileSystemFixes;
6
use Sunnysideup\UpgradeToSilverstripe4\Tasks\Task;
7
8
//use either of the following to create the info.json file required
9
//your project will also require a composer.json.default file
10
//this file is used to reset the project to the default state before attempting to install each library
11
//composer info --format=json > info.json
12
//composer info --direct --format=json > info.json
13
14
class ComposerCompatibilityCheckerStep3 extends Task
15
{
16
    protected $taskStep = 's10';
17
18
    protected $infoFileFileName = 'composer-requirements-info.json';
19
20
    protected $resultsFileAsJSON = 'composer-requirements-info.upgraded.json';
21
22
    protected $lessUpgradeIsBetter = false;
23
24
    private $outputArray = [];
25
26
    private $firstTimeReset = true;
27
28
    private $webRootLocation = '';
29
30
    public function getTitle()
31
    {
32
        if ($this->mu()->getIsModuleUpgrade()) {
0 ignored issues
show
Bug introduced by
The method getIsModuleUpgrade() does not exist on Sunnysideup\UpgradeToSilverstripe4\ModuleUpgrader. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

32
        if ($this->mu()->/** @scrutinizer ignore-call */ getIsModuleUpgrade()) {
Loading history...
Bug introduced by
It seems like getIsModuleUpgrade() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

32
        if ($this->mu()->/** @scrutinizer ignore-call */ getIsModuleUpgrade()) {
Loading history...
33
            return 'For moduls upgrades, this is not being used right now.';
34
        }
35
        return 'Check what composer requirements packages are best to use, using the '
36
            . $this->getJsonFileLocation() . ' file and placing results in '
37
            . $this->getJsonFileLocationJSONResults();
38
    }
39
40
    public function getDescription()
41
    {
42
        return '
43
            THIS IS STILL UNDER CONSTRUCTION!
44
            ';
45
    }
46
47
    /**
48
     * @param array $params
49
     */
50
    public function runActualTask($params = []): ?string
51
    {
52
        if ($this->mu()->getIsModuleUpgrade()) {
53
            return null;
54
        }
55
        $this->webRootLocation = $this->mu()->getWebRootDirLocation();
0 ignored issues
show
Bug introduced by
It seems like getWebRootDirLocation() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

55
        $this->webRootLocation = $this->mu()->/** @scrutinizer ignore-call */ getWebRootDirLocation();
Loading history...
Bug introduced by
The method getWebRootDirLocation() does not exist on Sunnysideup\UpgradeToSilverstripe4\ModuleUpgrader. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

55
        $this->webRootLocation = $this->mu()->/** @scrutinizer ignore-call */ getWebRootDirLocation();
Loading history...
56
57
        file_put_contents($this->getJsonFileLocationJSONResults(), '');
58
59
        $jsonFile = file_get_contents($this->getJsonFileLocation());
60
        $jsonData = json_decode($jsonFile, true);
61
62
        $libraries = $jsonData['installed'] ?? [];
63
64
        $this->resetProject();
65
        foreach ($libraries as $library) {
66
            $commit = '';
67
            $name = $library['name'];
68
            $version = $library['version'];
69
            if (strpos($version, 'dev-master') !== false) {
70
                $commit = $version;
71
                $version = str_replace(' ', '#', $version);
72
            }
73
            unset($libraryOutput);
74
            $libraryOutput = $this->mu()->execMe(
75
                $this->webRootLocation,
76
                'composer require ' . $name . " '" . $version . "' 2>&1 --no-interaction",
77
                'adding module'
78
            );
79
            $message = 'composer require ' . $name . ':' . $version . ' ... ';
80
            if (in_array('  [InvalidArgumentException]', $libraryOutput, true)) {
81
                $message .= "unsuccessful, could not find a matching version of package.\n";
82
                $this->mu()->colourPrint($message);
83
            } elseif (in_array('Installation failed, reverting ./composer.json to its original content.', $libraryOutput, true)) {
84
                $message .= "unsuccessful, searching for next best version.\n";
85
                $this->mu()->colourPrint($message);
86
                unset($show);
87
                $show = $this->mu()->execMe(
88
                    $this->webRootLocation,
89
                    'composer show -a ' . $name . ' --no-interaction 2>&1 ',
90
                    'show details of module'
91
                );
92
                $versionsString = $show[3];
93
                $versionsString = str_replace('versions : ', '', $versionsString);
94
                $currentVersionPos = strpos($versionsString, ', ' . $version);
95
                $versionsString = substr($versionsString, 0, $currentVersionPos);
96
                $newerVersions = explode(', ', $versionsString);
97
                if ($this->lessUpgradeIsBetter) {
98
                    $newerVersions = array_reverse($newerVersions);
99
                }
100
                $output = 0;
101
                $versionFound = false;
102
                foreach ($newerVersions as $newVersion) {
103
                    unset($output);
104
                    $output = $this->mu()->execMe(
105
                        $this->webRootLocation,
106
                        'composer require ' . $name . " '" . $newVersion . "' 2>&1 ",
107
                        'show details of module',
108
                        false
109
                    );
110
                    $message = 'composer require ' . $name . ':' . $newVersion . ' ...... ';
111
                    if (! in_array('Installation failed', $output, true)) {
112
                        $versionFound = true;
113
                        $message .= "successful!, it is the next best version.\n";
114
                        $this->mu()->colourPrint($message);
115
                        $this->addToOutputArray($name, $newVersion);
116
                        break;
117
                    }
118
                    $message .= "unsuccessful, searching for next best version.\n";
119
                    $this->mu()->colourPrint($message, false);
120
                }
121
122
                if (! $versionFound) {
123
                    $message = 'Could not find any compatible versions for:  ' . $name . "!'\n ";
124
                    $this->mu()->colourPrint($message);
125
                }
126
            } else {
127
                $message .= "successful!\n ";
128
                $this->mu()->colourPrint($message);
129
                $version = $commit ?: $version;
130
                $this->addToOutputArray($name, $version);
131
            }
132
        }
133
134
        file_put_contents(
135
            $this->getJsonFileLocationJSONResults(),
136
            json_encode($this->outputArray),
137
            FILE_APPEND | LOCK_EX
138
        );
139
140
        return null;
141
    }
142
143
    protected function resetProject()
144
    {
145
        $this->mu()->colourPrint('resetting project to composer.json.default', false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $colour of Sunnysideup\UpgradeToSil...Upgrader::colourPrint(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

145
        $this->mu()->colourPrint('resetting project to composer.json.default', /** @scrutinizer ignore-type */ false);
Loading history...
Bug introduced by
It seems like colourPrint() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

145
        $this->mu()->/** @scrutinizer ignore-call */ colourPrint('resetting project to composer.json.default', false);
Loading history...
146
        if ($this->firstTimeReset === true) {
147
            $this->mu()->execMe(
0 ignored issues
show
Bug introduced by
It seems like execMe() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

147
            $this->mu()->/** @scrutinizer ignore-call */ execMe(
Loading history...
148
                $this->webRootLocation,
149
                'cp composer.json composer.json.temp.default',
150
                'make temporary copy of composer.json'
151
            );
152
        }
153
        $fixer = FileSystemFixes::inst($this->mu())
0 ignored issues
show
Unused Code introduced by
The assignment to $fixer is dead and can be removed.
Loading history...
154
            ->removeDirOrFile($this->webRootLocation . '/composer.json');
155
        $this->mu()->execMe(
156
            $this->webRootLocation,
157
            'cp composer.json.temp.default composer.json',
158
            'back to default composer file'
159
        );
160
        if ($this->firstTimeReset === false) {
161
            $this->mu()->execMe(
162
                $this->webRootLocation,
163
                'composer update',
164
                'run composer update'
165
            );
166
        }
167
        $this->firstTimeReset = false;
168
    }
169
170
    protected function addToOutputArray($name, $version)
171
    {
172
        $pos = strpos($name, '/') + 1;
173
        $array['folder'] = substr($name, $pos);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$array was never initialized. Although not strictly required by PHP, it is generally a good practice to add $array = array(); before regardless.
Loading history...
174
        $array['tag'] = $version;
175
        $array['repo'] = null;
176
177
        $strings = $this->mu()->execMe(
178
            $this->webRootLocation,
179
            'composer show -a ' . $name . ' 2>&1 ',
180
            'run composer update'
181
        );
182
        $source = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $source is dead and can be removed.
Loading history...
183
184
        foreach ($strings as $string) {
185
            if (strpos($string, 'source') !== false) {
186
                $source = $string;
187
                preg_match_all('#\bhttps?://[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))#', $source, $match);
188
                if (! isset($match[0][0])) {
189
                    preg_match_all(
190
                        '#((git|ssh|http(s)?)|(git@[\w\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)(/)?#',
191
                        $source,
192
                        $match
193
                    );
194
                }
195
                if (isset($match[0][0])) {
196
                    $array['repo'] = $match[0][0];
197
                }
198
                break;
199
            }
200
        }
201
202
        array_push($this->outputArray, $array);
203
    }
204
205
    protected function getJsonFileLocation(): string
206
    {
207
        return $this->mu()->getWebRootDirLocation() . '/' . $this->infoFileFileName;
208
    }
209
210
    protected function getJsonFileLocationJSONResults(): string
211
    {
212
        return $this->mu()->getWebRootDirLocation() . '/' . $this->resultsFileAsJSON;
213
    }
214
215
    protected function hasCommitAndPush()
216
    {
217
        return false;
218
    }
219
}
220