• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JBZoo / Composer-Graph / 6259329790

16 Aug 2023 06:35PM UTC coverage: 91.029%. Remained the same
6259329790

push

github

web-flow
Upgrade `jbzoo/cli:^7.1.1` (#18)

345 of 379 relevant lines covered (91.03%)

71.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.14
/src/Commands/Build.php
1
<?php
2

3
/**
4
 * JBZoo Toolbox - Composer-Graph.
5
 *
6
 * This file is part of the JBZoo Toolbox project.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT
11
 * @copyright  Copyright (C) JBZoo.com, All rights reserved.
12
 * @see        https://github.com/JBZoo/Composer-Graph
13
 */
14

15
declare(strict_types=1);
16

17
namespace JBZoo\ComposerGraph\Commands;
18

19
use JBZoo\Cli\CliCommand;
20
use JBZoo\Cli\Codes;
21
use JBZoo\Cli\OutLvl;
22
use JBZoo\ComposerGraph\Collection;
23
use JBZoo\ComposerGraph\ComposerGraph;
24
use JBZoo\Data\JSON;
25
use JBZoo\MermaidPHP\Graph;
26
use Symfony\Component\Console\Input\InputOption;
27

28
use function JBZoo\Data\json;
29

30
/**
31
 * @psalm-suppress PropertyNotSetInConstructor
32
 */
33
class Build extends CliCommand
34
{
35
    /**
36
     * {@inheritDoc}
37
     */
38
    protected function configure(): void
39
    {
40
        $required = InputOption::VALUE_REQUIRED;
96✔
41
        $none     = InputOption::VALUE_NONE;
96✔
42

43
        if (!\defined('\IS_PHPUNIT_TEST')) {
96✔
44
            \define('\IS_PHPUNIT_TEST', false);
×
45
        }
46

47
        $this
48✔
48
            ->setName('build')
96✔
49
            ->addOption(
96✔
50
                'root',
48✔
51
                'r',
48✔
52
                $required,
48✔
53
                'The path has to contain ' .
48✔
54
                '"composer.json" and "composer.lock" files',
48✔
55
                './',
48✔
56
            )
48✔
57
            ->addOption('output', 'o', $required, 'Path to html output.', './build/composer-graph.html')
96✔
58
            ->addOption(
96✔
59
                'format',
48✔
60
                'f',
48✔
61
                $required,
48✔
62
                'Output format. Available options: <info>' . \implode(',', [
96✔
63
                    ComposerGraph::FORMAT_HTML,
48✔
64
                    ComposerGraph::FORMAT_MERMAID,
48✔
65
                ]) . '</info>',
48✔
66
                ComposerGraph::FORMAT_HTML,
48✔
67
            )
48✔
68
            ->addOption(
96✔
69
                'direction',
48✔
70
                'D',
48✔
71
                $required,
48✔
72
                'Direction of graph. Available options: <info>' . \implode(',', [
96✔
73
                    Graph::LEFT_RIGHT,
48✔
74
                    Graph::TOP_BOTTOM,
48✔
75
                    Graph::BOTTOM_TOP,
48✔
76
                    Graph::RIGHT_LEFT,
48✔
77
                ]) . '</info>',
48✔
78
                Graph::LEFT_RIGHT,
48✔
79
            )
48✔
80
            ->addOption('show-php', 'p', $none, 'Show PHP-node')
96✔
81
            ->addOption('show-ext', 'e', $none, 'Show all ext-* nodes (PHP modules)')
96✔
82
            ->addOption('show-dev', 'd', $none, 'Show all dev dependencies')
96✔
83
            ->addOption('show-suggests', 's', $none, 'Show not installed suggests packages')
96✔
84
            ->addOption('show-link-versions', 'l', $none, 'Show version requirements in links')
96✔
85
            ->addOption('show-package-versions', 'P', $none, 'Show version of packages')
96✔
86
            ->addOption(
96✔
87
                'abc-order',
48✔
88
                'O',
48✔
89
                $none,
48✔
90
                'Strict ABC ordering nodes in graph. ' .
48✔
91
                "It's fine tuning, sometimes it useful.",
48✔
92
            );
48✔
93

94
        parent::configure();
96✔
95
    }
96

97
    /**
98
     * {@inheritDoc}
99
     */
100
    protected function executeAction(): int
101
    {
102
        $format = $this->getOptString('format');
96✔
103

104
        [$composerJson, $composerLock] = $this->getJsonData();
96✔
105
        $vendorDir                     = $this->findVendorDir($composerJson);
96✔
106

107
        $composerGraph = new ComposerGraph(
96✔
108
            new Collection($composerJson, $composerLock, $vendorDir),
96✔
109
            [
48✔
110
                'direction'    => $this->getOptString('direction'),
96✔
111
                'php'          => $this->getOptBool('show-php'),
96✔
112
                'ext'          => $this->getOptBool('show-ext'),
96✔
113
                'dev'          => $this->getOptBool('show-dev'),
96✔
114
                'suggest'      => $this->getOptBool('show-suggests'),
96✔
115
                'link-version' => $this->getOptBool('show-link-versions'),
96✔
116
                'lib-version'  => $this->getOptBool('show-package-versions'),
96✔
117
                'format'       => $format,
48✔
118
                'output-path'  => $this->getOptString('output'),
96✔
119
                'abc-order'    => $this->getOptBool('abc-order'),
96✔
120
            ],
48✔
121
        );
48✔
122

123
        $result = $composerGraph->build();
96✔
124
        if ($format === ComposerGraph::FORMAT_HTML) {
96✔
125
            $this->_("Report is ready: <info>{$result}</info>");
96✔
126
        } else {
127
            $this->_($result);
96✔
128
        }
129

130
        return Codes::OK;
96✔
131
    }
132

133
    private function getRootPath(): string
134
    {
135
        $origRootPath = $this->getOptString('root');
96✔
136
        $realRootPath = \realpath($origRootPath);
96✔
137

138
        // Validate root path
139
        if ($realRootPath === false || !\is_dir($realRootPath)) {
96✔
140
            throw new Exception("Root path is not directory or not found: {$origRootPath}");
×
141
        }
142

143
        return $realRootPath;
96✔
144
    }
145

146
    /**
147
     * @return JSON[]
148
     */
149
    private function getJsonData(): array
150
    {
151
        $realRootPath = $this->getRootPath();
96✔
152

153
        // Validate "composer.json" path and file
154
        $composerJsonPath = "{$realRootPath}/composer.json";
96✔
155
        if (!\file_exists($composerJsonPath)) {
96✔
156
            throw new Exception("The file \"{$composerJsonPath}\" not found");
×
157
        }
158

159
        $composerJson = json($composerJsonPath);
96✔
160
        if (\count($composerJson) <= 1) {
96✔
161
            throw new Exception("The file \"{$composerJsonPath}\" is empty");
×
162
        }
163

164
        $this->_("Composer JSON file found: <info>{$composerJsonPath}</info>", OutLvl::DEBUG);
96✔
165

166
        // Validate "composer.lock" path and file
167
        $composerLockPath = "{$realRootPath}/composer.lock";
96✔
168
        if (!\file_exists($composerLockPath)) {
96✔
169
            throw new Exception("The file \"{$composerLockPath}\" not found");
×
170
        }
171

172
        $composerLock = json($composerLockPath);
96✔
173
        if (\count($composerLock) <= 1) {
96✔
174
            throw new Exception("The file \"{$composerLockPath}\" is empty");
×
175
        }
176

177
        $this->_("Composer LOCK file found: <info>{$composerLockPath}</info>", OutLvl::DEBUG);
96✔
178

179
        return [$composerJson, $composerLock];
96✔
180
    }
181

182
    private function findVendorDir(JSON $composerJson): ?string
183
    {
184
        $realRootPath = $this->getRootPath();
96✔
185

186
        $vendorDir = $composerJson->find('config.vendor-dir') ?? 'vendor';
96✔
187

188
        $realVendorDir = \realpath("{$realRootPath}/{$vendorDir}");
96✔
189
        if (
190
            $realVendorDir !== false
96✔
191
            && \is_dir($realVendorDir)
96✔
192
        ) {
193
            return $realVendorDir;
×
194
        }
195

196
        return null;
96✔
197
    }
198
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc