Issues (779)

GitCommands/Command/GitLogCommand.php (4 issues)

1
<?php
2
3
/*
4
 * This file is part of the GitCommandBundle package.
5
 *
6
 * (c) Paul Schweppe <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace VersionControl\GitCommandBundle\GitCommands\Command;
13
14
use Exception;
15
use RuntimeException;
16
use VersionControl\GitCommandBundle\Entity\GitLog;
17
18
/**
19
 * @author Paul Schweppe <[email protected]>
20
 */
21
class GitLogCommand extends AbstractGitCommand
22
{
23
    /**
24
     * @var string Log format
25
     */
26
    protected $format = '%H | %h | %T | %t | %P | %p | %an | %ae | %ad | %ar | %cn | %ce | %cd | %cr | %s';
27
28
    /**
29
     * Limit the number of commits return from command.
30
     *
31
     * @var int
32
     */
33
    protected $logCount = 9999999;
34
35
    /**
36
     * Pagination: Number of results to return.
37
     *
38
     * @var int
39
     */
40
    protected $limit = 30;
41
42
    /**
43
     * Pagintation: Current Page.
44
     *
45
     * @var int
46
     */
47
    protected $page = 0;
48
49
    /**
50
     * Pagintation: Total Number of results.
51
     *
52
     * @var int
53
     */
54
    protected $totalCount = 0;
55
56
    /**
57
     * Pagintation: Total Number of pages.
58
     *
59
     * @var int
60
     */
61
    protected $totalPages = 0;
62
63
    /**
64
     * Git log command.
65
     *
66
     * @var string
67
     */
68
    protected $logCommand;
69
70
    /**
71
     * Filter log by commit hash. Only returns logs with this hash. Should be only one result.
72
     *
73
     * @var string
74
     */
75
    protected $commitHash;
76
77
    /**
78
     * Filter log by branch name. Only returns commits form this branch.
79
     *
80
     * @var string
81
     */
82
    protected $branch;
83
84
    /**
85
     * Filter log by path. File name should include the path relative to git folder. Only returns commits
86
     * that effect this file.
87
     *
88
     * @var string
89
     */
90
    protected $path;
91
92
    /**
93
     * Enables the --not --remotes flags. Returns commits that have not been
94
     * pushed to a remote server.
95
     *
96
     * @var bool
97
     */
98
    protected $notRemote;
99
100
    /**
101
     * Enables the --decorate flag. The --decorate flag makes git log display all of the
102
     * references (e.g., branches, tags, etc) that point to each commit.
103
     *
104
     * This lets you know that the top commit is also checked out (denoted by HEAD) and
105
     * that it is also the tip of the master branch. The second commit has another branch
106
     * pointing to it called feature, and finally the 4th commit is tagged as v0.9.
107
     *
108
     * Branches, tags, HEAD, and the commit history are almost all of the information contained
109
     * in your Git repository, so this gives you a more complete view of the logical
110
     * structure of your repository.
111
     *
112
     * @var bool
113
     */
114
    protected $showReferences;
115
116
    /**
117
     * Array of log lines.
118
     *
119
     * @var array|string
120
     */
121
    protected $logData = array();
122
123
    /**
124
     * Filter By Message.
125
     *
126
     * To filter commits by their commit message, use the --grep flag.
127
     *
128
     * @var string
129
     */
130
    protected $filterByMessage;
131
132
    /**
133
     * Filter by Date After
134
     * If you’re looking for a commit from a specific time frame, you can use
135
     * the --after or --before flags for filtering commits by date.
136
     * These both accept a variety of date formats as a parameter.
137
     *      git log --after="2014-7-1"
138
     *      git log --after="yesterday"
139
     *      git log --after="2014-7-1" --before="2014-7-4".
140
     *
141
     * @var string
142
     */
143
    protected $filterByDateAfter;
144
145
    /**
146
     * Filter by Date After
147
     * If you’re looking for a commit from a specific time frame, you can use
148
     * the --after or --before flags for filtering commits by date.
149
     * These both accept a variety of date formats as a parameter.
150
     *      git log --after="2014-7-1"
151
     *      git log --after="yesterday"
152
     *      git log --after="2014-7-1" --before="2014-7-4".
153
     *
154
     * @var string
155
     */
156
    protected $filterByDateBefore;
157
158
    /**
159
     * Filter By Author
160
     * When you’re only looking for commits created by a particular user, use the --author flag.
161
     * This accepts a regular expression, and returns all commits whose author matches that
162
     * pattern. If you know exactly who you’re looking for, you can use a plain old string
163
     * instead of a regular expression: --author="John".
164
     *
165
     * @var string
166
     */
167
    protected $filterByAuthor;
168
169
    /**
170
     * Filter By Content
171
     * Used to search for commits that introduce or remove a particular line of source code.
172
     * This is called a pickaxe, and it takes the form of -S"<string>". For example, if you
173
     * want to know when the string Hello, World! was added to any file in the project,
174
     * you would use the following command:
175
     *      git log -S"Hello, World!".
176
     *
177
     * @var string
178
     */
179
    protected $filterByContent;
180
181
    /**
182
     * @return string
183
     */
184
    public function getLogCommand(): string
185
    {
186
        $this->logCommand = 'git --no-pager log -m "--pretty=format:\'' . $this->format . '\'"';
187
        if ($this->logCount) {
188
            $this->logCommand .= ' -' . (int)$this->logCount . ' ';
189
        }
190
191
        if ($this->showReferences === true) {
192
            $this->logCommand .= ' --decorate ';
193
        }
194
195
        if ($this->commitHash && $this->branch == false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $this->branch of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
196
            $this->logCommand .= ' ' . escapeshellarg($this->commitHash);
197
        }
198
199
        //Filters
200
        if ($this->filterByMessage) {
201
            $this->logCommand .= ' --grep=' . escapeshellarg($this->filterByMessage) . ' -i';
202
        }
203
204
        if ($this->filterByDateAfter) {
205
            $this->logCommand .= ' --after=' . escapeshellarg($this->filterByDateAfter);
206
        }
207
208
        if ($this->filterByDateBefore) {
209
            $this->logCommand .= ' --before=' . escapeshellarg($this->filterByDateBefore);
210
        }
211
212
        if ($this->filterByAuthor) {
213
            $this->logCommand .= ' --author=' . escapeshellarg($this->filterByAuthor);
214
        }
215
216
        if ($this->filterByContent) {
217
            $this->logCommand .= ' -S' . escapeshellarg($this->filterByContent);
218
        }
219
220
        if ($this->branch) {
221
            $this->logCommand .= ' ' . escapeshellarg(trim($this->branch));
222
        } elseif (!$this->commitHash) {
223
            $this->logCommand .= ' --all';
224
        }
225
226
        if ($this->notRemote) {
227
            $this->logCommand .= ' --not --remotes';
228
        }
229
230
        // To prevent confusion with options and branch names, paths may need to be prefixed with "-- " to separate
231
        // them from options or refnames.
232
        $this->logCommand .= ' --';
233
234
        //Show only commits that affect any of the specified paths.
235
        if ($this->path) {
236
            $this->logCommand .= ' ' . escapeshellarg(trim($this->path));
237
        }
238
239
        return $this->logCommand;
240
    }
241
242
    /**
243
     * Executes the git log command.
244
     *
245
     * @return GitLogCommand
246
     * @throws Exception
247
     */
248
    public function execute(): GitLogCommand
249
    {
250
        try {
251
            $logCommand = $this->getLogCommand();
252
            $this->logData = $this->command->runCommand($logCommand);
253
        } catch (RuntimeException $e) {
254
            if ($this->getObjectCount() !== 0) {
255
                throw new RuntimeException('Error in getting log: ' . $e->getMessage());
256
            }
257
            $this->logData = '';
258
        }
259
260
        return $this;
261
    }
262
263
    /**
264
     * Gets the results. Runs any pagination on the log data that is need and
265
     * converts the log lines into GitLog objects.
266
     *
267
     * @return array of GitLog objects
268
     */
269
    public function getResults(): array
270
    {
271
        $logs = array();
272
        if (is_array($this->logData)) {
273
            return [];
274
        }
275
276
        $lines = $this->splitOnNewLine($this->logData);
277
278
        if (is_array($lines)) {
0 ignored issues
show
The condition is_array($lines) is always true.
Loading history...
279
            $paginatedLines = $this->paginate($lines);
280
            foreach ($paginatedLines as $line) {
281
                if (trim($line)) {
282
                    $logs[] = new GitLog($line);
283
                }
284
            }
285
        }
286
287
        return $logs;
288
    }
289
290
    /**
291
     * Gets the first result. Does not run pagination.
292
     * Used mostly for commit hash data
293
     * converts the log lines into GitLog objects.
294
     *
295
     * @return GitLog
296
     */
297
    public function getFirstResult(): GitLog
298
    {
299
        $log = null;
300
        $lines = $this->splitOnNewLine($this->logData);
0 ignored issues
show
It seems like $this->logData can also be of type array; however, parameter $text of VersionControl\GitComman...mmand::splitOnNewLine() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

300
        $lines = $this->splitOnNewLine(/** @scrutinizer ignore-type */ $this->logData);
Loading history...
301
302
        if (is_array($lines) && count($lines) > 0) {
303
            $line = trim($lines[0]);
304
            $log = new GitLog($line);
305
        }
306
307
        return $log;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $log could return the type null which is incompatible with the type-hinted return VersionControl\GitCommandBundle\Entity\GitLog. Consider adding an additional type-check to rule them out.
Loading history...
308
    }
309
310
    /**
311
     * Paginates log lines using array_slice.
312
     *
313
     * @param array $lines
314
     *
315
     * @return array of lines
316
     */
317
    protected function paginate($lines): array
318
    {
319
        $this->totalCount = count($lines);
320
        $this->totalPages = ceil($this->totalCount / $this->limit);
321
322
        $page = min($this->page, $this->totalPages);
323
        $splitOn = $page * $this->limit;
324
325
        return array_slice($lines, $splitOn, $this->limit);
326
    }
327
328
    public function getLogCount(): int
329
    {
330
        return $this->logCount;
331
    }
332
333
    public function getLimit(): int
334
    {
335
        return $this->limit;
336
    }
337
338
    public function getPage(): int
339
    {
340
        return $this->page;
341
    }
342
343
    public function getTotalCount(): int
344
    {
345
        return $this->totalCount;
346
    }
347
348
    public function getTotalPages(): int
349
    {
350
        return $this->totalPages;
351
    }
352
353
    public function getCommitHash(): string
354
    {
355
        return $this->commitHash;
356
    }
357
358
    public function getBranch(): string
359
    {
360
        return $this->branch;
361
    }
362
363
    public function getNotRemote(): bool
364
    {
365
        return $this->notRemote;
366
    }
367
368
    public function getShowReferences(): bool
369
    {
370
        return $this->showReferences;
371
    }
372
373
    public function getFilterByMessage(): string
374
    {
375
        return $this->filterByMessage;
376
    }
377
378
    public function getFilterByDateAfter(): string
379
    {
380
        return $this->filterByDateAfter;
381
    }
382
383
    public function getFilterByDateBefore(): string
384
    {
385
        return $this->filterByDateBefore;
386
    }
387
388
    public function getFilterByAuthor(): string
389
    {
390
        return $this->filterByAuthor;
391
    }
392
393
    public function getFilterByContent(): string
394
    {
395
        return $this->filterByContent;
396
    }
397
398
    public function setLogCount($logCount)
399
    {
400
        $this->logCount = $logCount;
401
402
        return $this;
403
    }
404
405
    public function setLimit($limit)
406
    {
407
        $this->limit = $limit;
408
409
        return $this;
410
    }
411
412
    public function setPage($page)
413
    {
414
        $this->page = $page;
415
416
        return $this;
417
    }
418
419
    public function setTotalCount($totalCount)
420
    {
421
        $this->totalCount = $totalCount;
422
423
        return $this;
424
    }
425
426
    public function setTotalPages($totalPages)
427
    {
428
        $this->totalPages = $totalPages;
429
430
        return $this;
431
    }
432
433
    public function setCommitHash($commitHash)
434
    {
435
        $this->commitHash = $commitHash;
436
437
        return $this;
438
    }
439
440
    public function setBranch($branch)
441
    {
442
        if ($branch !== '(No Branch)') {
443
            $this->branch = $branch;
444
        }
445
446
        return $this;
447
    }
448
449
    public function setNotRemote($notRemote)
450
    {
451
        $this->notRemote = $notRemote;
452
453
        return $this;
454
    }
455
456
    public function setShowReferences($showReferences)
457
    {
458
        $this->showReferences = $showReferences;
459
460
        return $this;
461
    }
462
463
    public function setFilterByMessage($filterByMessage)
464
    {
465
        $this->filterByMessage = $filterByMessage;
466
467
        return $this;
468
    }
469
470
    public function setFilterByDateAfter($filterByDateAfter)
471
    {
472
        $this->filterByDateAfter = $filterByDateAfter;
473
474
        return $this;
475
    }
476
477
    public function setFilterByDateBefore($filterByDateBefore)
478
    {
479
        $this->filterByDateBefore = $filterByDateBefore;
480
481
        return $this;
482
    }
483
484
    public function setFilterByAuthor($filterByAuthor)
485
    {
486
        $this->filterByAuthor = $filterByAuthor;
487
488
        return $this;
489
    }
490
491
    /**
492
     * @param string $filterByContent
493
     *
494
     * @return GitLogCommand
495
     */
496
    public function setFilterByContent($filterByContent): GitLogCommand
497
    {
498
        $this->filterByContent = $filterByContent;
499
500
        return $this;
501
    }
502
503
    /**
504
     * @return string
505
     */
506
    public function getPath(): string
507
    {
508
        return $this->path;
509
    }
510
511
    /**
512
     * @param $path
513
     *
514
     * @return GitLogCommand
515
     */
516
    public function setPath($path): self
517
    {
518
        $this->path = $path;
519
520
        return $this;
521
    }
522
}
523