Completed
Push — develop ( ab9f70...4afa03 )
by
unknown
02:16
created

MainCommand::init()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 9.9332
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
/**
4
 * GitElephant - An abstraction layer for git written in PHP
5
 * Copyright (C) 2013  Matteo Giachino
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see [http://www.gnu.org/licenses/].
19
 */
20
21
namespace GitElephant\Command;
22
23
use GitElephant\Objects\Author;
24
use GitElephant\Objects\Branch;
25
use GitElephant\Objects\TreeishInterface;
26
use GitElephant\Repository;
27
28
/**
29
 * Main command generator (init, status, add, commit, checkout)
30
 *
31
 * @author Matteo Giachino <[email protected]>
32
 */
33
class MainCommand extends BaseCommand
34
{
35
    public const GIT_INIT = 'init';
36
    public const GIT_STATUS = 'status';
37
    public const GIT_ADD = 'add';
38
    public const GIT_COMMIT = 'commit';
39
    public const GIT_CHECKOUT = 'checkout';
40
    public const GIT_MOVE = 'mv';
41
    public const GIT_REMOVE = 'rm';
42
    public const GIT_RESET = 'reset';
43
44
    /**
45
     * constructor
46
     *
47
     * @param \GitElephant\Repository $repo The repository object this command
48
     *                                      will interact with
49
     */
50 104
    public function __construct(Repository $repo = null)
51
    {
52 104
        parent::__construct($repo);
53 104
    }
54
55
    /**
56
     * Init the repository
57
     *
58
     * @param bool $bare
59
     *
60
     * @throws \RuntimeException
61
     * @return MainCommand
62
     */
63 99
    public function init($bare = false): string
64
    {
65 99
        $this->clearAll();
66 99
        if ($bare) {
67 5
            $this->addCommandArgument('--bare');
68
        }
69 99
        $this->addCommandName(self::GIT_INIT);
70
71 99
        return $this->getCommand();
72
    }
73
74
    /**
75
     * Get the repository status
76
     *
77
     * @param bool $porcelain
78
     *
79
     * @throws \RuntimeException
80
     * @return string
81
     */
82 12
    public function status($porcelain = false): string
83
    {
84 12
        $this->clearAll();
85 12
        $this->addCommandName(self::GIT_STATUS);
86 12
        if ($porcelain) {
87 9
            $this->addCommandArgument('--porcelain');
88
        } else {
89 3
            $this->addConfigs(['color.status' => 'false']);
90
        }
91
92 12
        return $this->getCommand();
93
    }
94
95
    /**
96
     * Add a node to the stage
97
     *
98
     * @param string $what what should be added to the repository
99
     *
100
     * @throws \RuntimeException
101
     * @return string
102
     */
103 94
    public function add($what = '.'): string
104
    {
105 94
        $this->clearAll();
106 94
        $this->addCommandName(self::GIT_ADD);
107 94
        $this->addCommandArgument('--all');
108 94
        $this->addCommandSubject($what);
109
110 94
        return $this->getCommand();
111
    }
112
113
    /**
114
     * Remove a node from the stage and put in the working tree
115
     *
116
     * @param string $what what should be removed from the stage
117
     *
118
     * @throws \RuntimeException
119
     * @return string
120
     */
121 2
    public function unstage($what): string
122
    {
123 2
        $this->clearAll();
124 2
        $this->addCommandName(self::GIT_RESET);
125 2
        $this->addCommandArgument('HEAD');
126 2
        $this->addPath($what);
127
128 2
        return $this->getCommand();
129
    }
130
131
    /**
132
     * Commit
133
     *
134
     * @param string        $message  the commit message
135
     * @param bool          $stageAll commit all changes
136
     * @param string|Author $author   override the author for this commit
137
     *
138
     * @throws \RuntimeException
139
     * @throws \InvalidArgumentException
140
     * @return string
141
     */
142 94
    public function commit($message, $stageAll = false, $author = null, $allowEmpty = false): string
143
    {
144 94
        $this->clearAll();
145
146 94
        if (trim($message) === '' || is_null($message)) {
147
            throw new \InvalidArgumentException(sprintf('You can\'t commit without message'));
148
        }
149 94
        $this->addCommandName(self::GIT_COMMIT);
150
151 94
        if ($stageAll) {
152 88
            $this->addCommandArgument('-a');
153
        }
154
155 94
        if ($author !== null) {
156 1
            $this->addCommandArgument('--author');
157 1
            $this->addCommandArgument($author);
0 ignored issues
show
Bug introduced by
It seems like $author defined by parameter $author on line 142 can also be of type object<GitElephant\Objects\Author>; however, GitElephant\Command\Base...d::addCommandArgument() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
158
        }
159
160 94
        if ($allowEmpty) {
161 1
            $this->addCommandArgument('--allow-empty');
162
        }
163
164 94
        $this->addCommandArgument('-m');
165 94
        $this->addCommandSubject($message);
166
167 94
        return $this->getCommand();
168
    }
169
170
    /**
171
     * Checkout a treeish reference
172
     *
173
     * @param string|Branch $ref the reference to checkout
174
     *
175
     * @throws \RuntimeException
176
     * @return string
177
     */
178 23
    public function checkout($ref): string
179
    {
180 23
        $this->clearAll();
181
182 23
        $what = $ref;
183 23
        if ($ref instanceof Branch) {
184 2
            $what = $ref->getName();
185 22
        } elseif ($ref instanceof TreeishInterface) {
186
            $what = $ref->getSha();
187
        }
188
189 23
        $this->addCommandName(self::GIT_CHECKOUT);
190 23
        $this->addCommandArgument('-q');
191 23
        $this->addCommandSubject($what);
192
193 23
        return $this->getCommand();
194
    }
195
196
    /**
197
     * Move a file/directory
198
     *
199
     * @param string|Object $from source path
200
     * @param string|Object $to   destination path
201
     *
202
     * @throws \RuntimeException
203
     * @throws \InvalidArgumentException
204
     * @return string
205
     */
206 1
    public function move($from, $to): string
207
    {
208 1
        $this->clearAll();
209
210 1
        $from = trim($from);
211 1
        if (!$this->validatePath($from)) {
212
            throw new \InvalidArgumentException('Invalid source path');
213
        }
214
215 1
        $to = trim($to);
216 1
        if (!$this->validatePath($to)) {
217
            throw new \InvalidArgumentException('Invalid destination path');
218
        }
219
220 1
        $this->addCommandName(self::GIT_MOVE);
221 1
        $this->addCommandSubject($from);
222 1
        $this->addCommandSubject2($to);
223
224 1
        return $this->getCommand();
225
    }
226
227
    /**
228
     * Remove a file/directory
229
     *
230
     * @param string|Object $path      the path to remove
231
     * @param bool          $recursive recurse
232
     * @param bool          $force     force
233
     *
234
     * @throws \RuntimeException
235
     * @throws \InvalidArgumentException
236
     * @return string
237
     */
238 1
    public function remove($path, $recursive, $force): string
239
    {
240 1
        $this->clearAll();
241
        
242 1
        $path = trim($path);
243 1
        if (!$this->validatePath($path)) {
244
            throw new \InvalidArgumentException('Invalid path');
245
        }
246
247 1
        $this->addCommandName(self::GIT_REMOVE);
248
249 1
        if ($recursive) {
250
            $this->addCommandArgument('-r');
251
        }
252
253 1
        if ($force) {
254
            $this->addCommandArgument('-f');
255
        }
256
        
257 1
        $this->addPath($path);
258
259 1
        return $this->getCommand();
260
    }
261
262
    /**
263
     * Validates a path
264
     *
265
     * @param string $path path
266
     *
267
     * @return bool
268
     */
269 2
    protected function validatePath($path): bool
270
    {
271 2
        if (empty($path)) {
272
            return false;
273
        }
274
275
        // we are always operating from root directory
276
        // so forbid relative paths
277 2
        if (false !== strpos($path, '..')) {
278
            return false;
279
        }
280
281 2
        return true;
282
    }
283
}
284