Passed
Push — master ( 1ffb2d...f18857 )
by Dmitriy
05:56 queued 02:52
created

GitController   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 70
dl 0
loc 122
ccs 0
cts 82
cp 0
rs 10
c 0
b 0
f 0
wmc 15

7 Methods

Rating   Name   Duplication   Size   Complexity  
A checkout() 0 13 2
A command() 0 26 5
A summary() 0 23 1
A serializeCommit() 0 8 2
A log() 0 14 1
A __construct() 0 4 1
A getGit() 0 18 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Debug\Api\Inspector\Controller;
6
7
use Gitonomy\Git\Commit;
8
use Gitonomy\Git\Reference\Branch;
9
use Gitonomy\Git\Repository;
10
use InvalidArgumentException;
11
use Psr\Http\Message\ResponseInterface;
12
use Psr\Http\Message\ServerRequestInterface;
13
use Throwable;
14
use Yiisoft\Aliases\Aliases;
15
use Yiisoft\DataResponse\DataResponseFactoryInterface;
16
use Yiisoft\VarDumper\VarDumper;
17
18
final class GitController
19
{
20
    public function __construct(
21
        private DataResponseFactoryInterface $responseFactory,
22
        private Aliases $aliases,
23
    ) {
24
    }
25
26
    public function summary(): ResponseInterface
27
    {
28
        $git = $this->getGit();
29
30
        $references = $git->getReferences();
31
        $name = trim($git->run('branch', ['--show-current']));
32
        $branch = $references->getBranch($name);
33
        $branches = $references->getBranches();
34
        $remoteNames = explode("\n", trim($git->run('remote')));
35
36
        $result = [
37
            'currentBranch' => $branch->getName(),
38
            'sha' => $branch->getCommitHash(),
39
            'remotes' => array_map(fn (string $name) => [
40
                'name' => $name,
41
                'url' => trim($git->run('remote', ['get-url', $name])),
42
            ], $remoteNames),
43
            'branches' => array_map(fn (Branch $branch) => $branch->getName(), $branches),
44
            'lastCommit' => $this->serializeCommit($branch->getCommit()),
45
            'status' => explode("\n", $git->run('status')),
46
        ];
47
        $response = VarDumper::create($result)->asPrimitives(255);
48
        return $this->responseFactory->createResponse($response);
49
    }
50
51
    public function log(): ResponseInterface
52
    {
53
        $git = $this->getGit();
54
55
        $references = $git->getReferences(false);
56
        $name = trim($git->run('branch', ['--show-current']));
57
        $branch = $references->getBranch($name);
58
        $result = [
59
            'currentBranch' => $branch->getName(),
60
            'sha' => $branch->getCommitHash(),
61
            'commits' => array_map([$this, 'serializeCommit'], $git->getLog(limit: 20)->getCommits()),
62
        ];
63
        $response = VarDumper::create($result)->asPrimitives(255);
64
        return $this->responseFactory->createResponse($response);
65
    }
66
67
    public function checkout(ServerRequestInterface $request): ResponseInterface
68
    {
69
        $git = $this->getGit();
70
71
        $parsedBody = \json_decode($request->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
72
        $branch = $parsedBody['branch'] ?? null;
73
74
        if ($branch === null) {
75
            throw new InvalidArgumentException('Branch should not be empty.');
76
        }
77
78
        $git->getWorkingCopy()->checkout($branch);
79
        return $this->responseFactory->createResponse([]);
80
    }
81
82
    public function command(ServerRequestInterface $request): ResponseInterface
83
    {
84
        $git = $this->getGit();
85
        $availableCommands = ['pull', 'fetch'];
86
87
        $command = $request->getQueryParams()['command'] ?? null;
88
89
        if ($command === null) {
90
            throw new InvalidArgumentException('Command should not be empty.');
91
        }
92
        if (!in_array($command, $availableCommands, true)) {
93
            throw new InvalidArgumentException(
94
                sprintf(
95
                    'Unknown command "%s". Available commands: "%s".',
96
                    $command,
97
                    implode('", "', $availableCommands),
98
                )
99
            );
100
        }
101
102
        if ($command === 'pull') {
103
            $git->run('pull', ['--rebase=false']);
104
        } elseif ($command === 'fetch') {
105
            $git->run('fetch', ['--tags']);
106
        }
107
        return $this->responseFactory->createResponse([]);
108
    }
109
110
    private function getGit(): Repository
111
    {
112
        $projectPath = $this->aliases->get('@root');
113
114
        while ($projectPath !== '/') {
115
            try {
116
                $git = new Repository($projectPath);
117
                $git->getWorkingCopy();
118
                return $git;
119
            } catch (Throwable) {
120
                $projectPath = dirname($projectPath);
121
            }
122
        }
123
124
        throw new InvalidArgumentException(
125
            sprintf(
126
                'Could find any repositories up from "%s" directory.',
127
                $projectPath,
128
            )
129
        );
130
    }
131
132
    private function serializeCommit(?Commit $commit): array
133
    {
134
        return $commit === null ? [] : [
135
            'sha' => $commit->getShortHash(),
136
            'message' => $commit->getSubjectMessage(),
137
            'author' => [
138
                'name' => $commit->getAuthorName(),
139
                'email' => $commit->getAuthorEmail(),
140
            ],
141
        ];
142
    }
143
}
144