Completed
Pull Request — master (#28)
by Robbie
12:24
created

CheckComposerUpdatesTask::getStability()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
1
<?php
2
3
use BringYourOwnIdeas\Maintenance\Util\ComposerLoader;
4
use BringYourOwnIdeas\UpdateChecker\UpdateChecker;
5
use Composer\Composer;
6
use Composer\Package\Link;
7
use Composer\Repository\ArrayRepository;
8
use Composer\Repository\BaseRepository;
9
use Composer\Repository\CompositeRepository;
10
11
/**
12
 * Task which does the actual checking of updates
13
 *
14
 * Originally from https://github.com/XploreNet/silverstripe-composerupdates
15
 *
16
 * @author Matt Dwen
17
 * @license MIT
18
 */
19
class CheckComposerUpdatesTask extends BuildTask
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
20
{
21
    /**
22
     * @var string
23
     */
24
    protected $title = 'Composer update checker';
25
26
    /**
27
     * @var string
28
     */
29
    protected $description = 'Checks if any composer dependencies can be updated.';
30
31
    private static $dependencies = [
0 ignored issues
show
Unused Code introduced by
The property $dependencies is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
32
        'ComposerLoader' => '%$BringYourOwnIdeas\\Maintenance\\Util\\ComposerLoader',
33
        'UpdateChecker' => '%$BringYourOwnIdeas\\UpdateChecker\\UpdateChecker',
34
    ];
35
36
    /**
37
     * The "types" of composer libraries that will be processed. Anything without these types will be ignored.
38
     *
39
     * @config
40
     * @var array
41
     */
42
    private static $allowed_types = [
0 ignored issues
show
Unused Code introduced by
The property $allowed_types is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
43
        'silverstripe-module',
44
        'silverstripe-vendormodule',
45
        'silverstripe-theme',
46
    ];
47
48
    /**
49
     * @var ComposerLoader
50
     */
51
    protected $composerLoader;
52
53
    /**
54
     * @var UpdateChecker
55
     */
56
    protected $updateChecker;
57
58
    /**
59
     * Runs the actual steps to verify if there are updates available
60
     *
61
     * @param SS_HTTPRequest $request
62
     */
63
    public function run($request)
64
    {
65
        $packages = $this->getPackages();
66
67
        // Run through the packages and check each for updates
68
        foreach ($packages as $packageData) {
69
            $this->getUpdateChecker()->checkForUpdates(
70
                $packageData['package'],
71
                $packageData['constraint']
72
            );
73
        }
74
75
        $this->message('The task finished running. You can find the updated information in the database now.');
76
    }
77
78
    /**
79
     * Retrieve an array of primary composer dependencies from composer.json.
80
     *
81
     * Packages are filtered by allowed type.
82
     *
83
     * @return array[]
84
     */
85
    protected function getPackages()
86
    {
87
        /** @var Composer $composer */
88
        $composer = $this->getComposerLoader()->getComposer();
89
90
        /** @var BaseRepository $repository */
91
        $repository = new CompositeRepository([
92
            new ArrayRepository([$composer->getPackage()]),
93
            $composer->getRepositoryManager()->getLocalRepository(),
94
        ]);
95
96
        $packages = [];
97
        foreach ($repository->getPackages() as $package) {
98
            // Filter out packages that are not "allowed types"
99
            if (!$this->isAllowedType($package->getType())) {
100
                continue;
101
            }
102
103
            // Find the constraint used for installation
104
            $constraint = $this->getInstalledConstraint($repository, $package->getName());
105
            $packages[$package->getName()] = [
106
                'constraint' => $constraint,
107
                'package' => $package,
108
            ];
109
        }
110
        return $packages;
111
    }
112
113
    /**
114
     * Find all dependency constraints for the given package in the current repository and return the strictest one
115
     *
116
     * @param BaseRepository $repository
117
     * @param string $packageName
118
     * @return string
119
     */
120
    protected function getInstalledConstraint(BaseRepository $repository, $packageName)
121
    {
122
        $constraints = [];
123
        foreach ($repository->getDependents($packageName) as $dependent) {
124
            /** @var Link $link */
125
            list (, $link) = $dependent;
126
            $constraints[] = $link->getPrettyConstraint();
127
        }
128
129
        usort($constraints, 'version_compare');
130
131
        return array_pop($constraints);
132
    }
133
134
    /**
135
     * Check whether the package type is "allowed", which will include it in reports. If the type is not allowed
136
     * then the package will be skipped.
137
     *
138
     * @param string $type
139
     * @return bool
140
     */
141
    protected function isAllowedType($type)
142
    {
143
        $allowedTypes = Config::inst()->get(__CLASS__, 'allowed_types');
144
145
        return in_array($type, $allowedTypes);
146
    }
147
148
    /**
149
     * prints a message during the run of the task
150
     *
151
     * @param string $text
152
     */
153
    protected function message($text)
154
    {
155
        if (!Director::is_cli()) {
156
            $text = '<p>' . $text . '</p>';
157
        }
158
159
        echo $text . PHP_EOL;
160
    }
161
162
    /**
163
     * @param ComposerLoader $composerLoader
164
     * @return $this
165
     */
166
    public function setComposerLoader(ComposerLoader $composerLoader)
167
    {
168
        $this->composerLoader = $composerLoader;
169
        return $this;
170
    }
171
172
    /**
173
     * @return ComposerLoader
174
     */
175
    public function getComposerLoader()
176
    {
177
        return $this->composerLoader;
178
    }
179
180
    /**
181
     * @param UpdateChecker $updateChecker
182
     * @return $this
183
     */
184
    public function setUpdateChecker(UpdateChecker $updateChecker)
185
    {
186
        $this->updateChecker = $updateChecker;
187
        return $this;
188
    }
189
190
    /**
191
     * @return UpdateChecker
192
     */
193
    public function getUpdateChecker()
194
    {
195
        return $this->updateChecker;
196
    }
197
}
198