Passed
Push — master ( 3de4a6...1995be )
by Dmitriy
04:46 queued 01:29
created

GitController   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 15
eloc 69
c 1
b 0
f 0
dl 0
loc 121
ccs 0
cts 81
cp 0
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A checkout() 0 12 2
A log() 0 14 1
A __construct() 0 4 1
A serializeCommit() 0 8 2
A getGit() 0 18 3
A command() 0 26 5
A summary() 0 23 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Debug\Api\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)->asJson(false, 255);
48
        return $this->responseFactory->createResponse(json_decode($response, null, 512, JSON_THROW_ON_ERROR));
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)->asJson(false, 255);
64
        return $this->responseFactory->createResponse(json_decode($response, null, 512, JSON_THROW_ON_ERROR));
65
    }
66
67
    public function checkout(ServerRequestInterface $request): ResponseInterface
68
    {
69
        $git = $this->getGit();
70
71
        $branch = $request->getParsedBody()['branch'] ?? null;
72
73
        if ($branch === null) {
74
            throw new InvalidArgumentException('Branch should not be empty.');
75
        }
76
77
        $git->getWorkingCopy()->checkout($branch);
78
        return $this->responseFactory->createResponse([]);
79
    }
80
81
    public function command(ServerRequestInterface $request): ResponseInterface
82
    {
83
        $git = $this->getGit();
84
        $availableCommands = ['pull', 'fetch'];
85
86
        $command = $request->getQueryParams()['command'] ?? null;
87
88
        if ($command === null) {
89
            throw new InvalidArgumentException('Command should not be empty.');
90
        }
91
        if (!in_array($command, $availableCommands, true)) {
92
            throw new InvalidArgumentException(
93
                sprintf(
94
                    'Unknown command "%s". Available commands: "%s".',
95
                    $command,
96
                    implode('", "', $availableCommands),
97
                )
98
            );
99
        }
100
101
        if ($command === 'pull') {
102
            $git->run('pull', ['--rebase=false']);
103
        } elseif ($command === 'fetch') {
104
            $git->run('fetch', ['--tags']);
105
        }
106
        return $this->responseFactory->createResponse([]);
107
    }
108
109
    private function getGit(): Repository
110
    {
111
        $projectPath = $this->aliases->get('@root');
112
113
        while ($projectPath !== '/') {
114
            try {
115
                $git = new Repository($projectPath);
116
                $git->getWorkingCopy();
117
                return $git;
118
            } catch (Throwable) {
119
                $projectPath = dirname($projectPath);
120
            }
121
        }
122
123
        throw new InvalidArgumentException(
124
            sprintf(
125
                'Could find any repositories up from "%s" directory.',
126
                $projectPath,
127
            )
128
        );
129
    }
130
131
    private function serializeCommit(?Commit $commit): array
132
    {
133
        return $commit === null ? [] : [
134
            'sha' => $commit->getShortHash(),
135
            'message' => $commit->getSubjectMessage(),
136
            'author' => [
137
                'name' => $commit->getAuthorName(),
138
                'email' => $commit->getAuthorEmail(),
139
            ],
140
        ];
141
    }
142
}
143