Monorepo   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 47
c 1
b 0
f 0
dl 0
loc 100
rs 10
wmc 18

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 3
A isDebug() 0 3 1
A getLogger() 0 3 1
B resolveRepository() 0 50 11
A getRepository() 0 3 1
A getRepositories() 0 3 1
1
<?php declare(strict_types=1);
2
3
/*
4
 * This file is part of Biurad opensource projects.
5
 *
6
 * @copyright 2022 Biurad Group (https://biurad.com/)
7
 * @license   https://opensource.org/licenses/BSD-3-Clause License
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Biurad\Monorepo;
14
15
use Biurad\Git\Repository;
16
use Psr\Log\LoggerInterface;
17
use Symfony\Component\Console\Logger\ConsoleLogger;
18
use Symfony\Component\Console\Output\ConsoleOutput;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Symfony\Component\Process\Process;
21
22
/**
23
 * Monorepo Manager Class.
24
 *
25
 * @author Divine Niiquaye Ibok <[email protected]>
26
 */
27
class Monorepo
28
{
29
    private Repository $repository;
30
    private ?LoggerInterface $logger = null;
31
    private bool $debug;
32
33
    /**
34
     * @param array<int,array<int,string>> $repositories
35
     */
36
    public function __construct(public Config $config, int $verbosity, private array $repositories)
37
    {
38
        $verMap = [
39
            'error' => ConsoleOutput::VERBOSITY_VERY_VERBOSE,
40
            'debug' => ConsoleOutput::VERBOSITY_VERBOSE,
41
        ];
42
        $this->repository = new Repository(
43
            $this->config['path'],
44
            [],
45
            $this->debug = false !== \getenv('APP_DEBUG'),
46
            $this->logger = \interface_exists(LoggerInterface::class) ? new ConsoleLogger(new ConsoleOutput($verbosity), $verMap) : null
47
        );
48
49
        if (0 !== $this->repository->getConfig('gc.auto')) {
50
            $this->repository->run('config', ['gc.auto', 0]);
51
        }
52
    }
53
54
    public function resolveRepository(OutputInterface $output, callable $resolver, callable $checker = null): int
55
    {
56
        $result = 0;
57
58
        foreach ($this->repositories as [$url, $remote, $path, $merge]) {
59
            if (null !== $checker && !$checker([$url, $remote, $path, $merge])) {
60
                continue;
61
            }
62
63
            if (\file_exists($clonePath = \rtrim($this->config['cache'], '\/').'/'.$remote)) {
64
                if ($this->config['reclone']) {
65
                    $output->writeln(\sprintf('Deleting previous clone of <info>%s</info>', $remote));
66
                    Process::fromShellCommandline(('\\' === \DIRECTORY_SEPARATOR ? 'rd /s /q "' : 'rm -rf "').$clonePath.'"')->run();
67
                } else {
68
                    $this->repository->run('pull', ['--all'], cwd: $clonePath);
69
                }
70
            }
71
72
            $output->writeln(\sprintf('<info>Cloning %s into %s</info>', $url, $clonePath));
73
            @\mkdir($clonePath, recursive: true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

73
            /** @scrutinizer ignore-unhandled */ @\mkdir($clonePath, recursive: true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
74
            $this->repository->run('clone', ['-q', '--bare', $url, $clonePath]);
75
76
            if (0 !== $this->repository->getExitCode()) {
77
                $output->writeln(\sprintf('<error>Failed to clone %s</error>', $url));
78
79
                return WorkflowCommand::FAILURE;
80
            }
81
82
            if (null === $this->repository->getConfig('remote.'.$remote.'.url')) {
83
                $output->writeln(\sprintf('<info>Adding remote %s</info>', $remote));
84
                $this->repository->run('remote', ['add', $remote, $clonePath]);
85
            } else {
86
                $output->writeln(\sprintf('<info>Updating remote %s</info>', $remote));
87
                $this->repository->run('remote', ['set-url', $remote, $clonePath]);
88
            }
89
90
            $result = $resolver([$url, $remote, $path, $clonePath, $merge]);
91
            $this->repository->run('remote', ['remove', $remote]);
92
            $output->writeln('');
93
94
            if (null === $result) {
95
                continue;
96
            }
97
98
            if ($result > 0) {
99
                return $result;
100
            }
101
        }
102
103
        return $result;
104
    }
105
106
    public function getRepository(): Repository
107
    {
108
        return $this->repository;
109
    }
110
111
    /**
112
     * @return array<int,array<int,string>>
113
     */
114
    public function getRepositories(): array
115
    {
116
        return $this->repositories;
117
    }
118
119
    public function getLogger(): LoggerInterface
120
    {
121
        return $this->logger;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->logger could return the type null which is incompatible with the type-hinted return Psr\Log\LoggerInterface. Consider adding an additional type-check to rule them out.
Loading history...
122
    }
123
124
    public function isDebug(): bool
125
    {
126
        return $this->debug;
127
    }
128
}
129