Completed
Push — master ( 56ef18...7cde6a )
by Andrii
02:06
created

History::addCommitLinks()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 7
cts 7
cp 1
rs 9.4285
nc 3
cc 3
eloc 4
nop 0
crap 3
1
<?php
2
3
/*
4
 * Changelog keeper
5
 *
6
 * @link      https://github.com/hiqdev/chkipper
7
 * @package   chkipper
8
 * @license   BSD-3-Clause
9
 * @copyright Copyright (c) 2016, HiQDev (http://hiqdev.com/)
10
 */
11
12
namespace hiqdev\chkipper\history;
13
14
/**
15
 * History class.
16
 *
17
 * @property array $headers: header => header
18
 * @property array $hashes:  hash => hash
19
 * @property array $links:   link => href
20
 * @property array $tags:    tag name => tag object
21
 *
22
 * @author Andrii Vasyliev <[email protected]>
23
 */
24
class History
25
{
26
    public $lastTag = 'Under development';
27
28
    public $initTag = 'Development started';
29
30
    protected $_project;
31
    protected $_headers = [];
32
    protected $_hashes  = [];
33
    protected $_links   = [];
34
    protected $_tags    = [];
35
36 1
    public function setProject($value)
37
    {
38 1
        $this->_project = $value;
39 1
    }
40
41 1
    public function getProject()
42
    {
43 1
        if ($this->_project === null) {
44
            $this->_project = $this->detectProject();
45
        }
46
47 1
        return $this->_project;
48
    }
49
50
    public function detectProject()
51
    {
52
        foreach ($this->getHeaders() as $line) {
53
            if (preg_match('/\b([a-z0-9._-]{2,}\/[a-z0-9._-]{2,})\b/i', $line, $m)) {
54
                return $m[1];
55
            }
56
        }
57
    }
58
59 2
    public function addHeader($str)
60
    {
61 2
        $this->_headers[$str] = $str;
62 2
    }
63
64 1
    public function addHeaders(array $headers)
65
    {
66 1
        foreach ($headers as $header) {
67 1
            $this->addHeader($header);
68 1
        }
69 1
    }
70
71 1
    public function setHeaders(array $headers)
72
    {
73 1
        $this->_headers = [];
74 1
        $this->addHeaders($headers);
75 1
    }
76
77 2
    public function getHeaders()
78
    {
79 2
        return $this->_headers;
80
    }
81
82 2
    public function hasLink($link)
83
    {
84 2
        return isset($this->_links[$link]);
85
    }
86
87
    public function removeLink($link)
88
    {
89
        unset($this->_links[$link]);
90
    }
91
92 3
    public function addLink($link, $href)
93
    {
94 3
        $this->_links[$link] = $href;
95 3
    }
96
97
    public function addLinks(array $links)
98
    {
99
        foreach ($links as $link => $href) {
100
            $this->addLink($link, $href);
101
        }
102
    }
103
104 1
    public function setLinks(array $links)
105
    {
106 1
        $this->_links = $links;
107 1
    }
108
109 2
    public function getLinks()
110
    {
111 2
        return $this->_links;
112
    }
113
114 2
    public function hasHash($hash)
115
    {
116 2
        return isset($this->_hashes[(string) $hash]);
117
    }
118
119 3
    public function addHash($hash)
120
    {
121 3
        $this->_hashes[(string) $hash] = $hash;
122 3
    }
123
124
    public function addHashes(array $hashes)
125
    {
126
        foreach ($hashes as $hash) {
127
            $this->addHash($hash);
128
        }
129
    }
130
131
    public function setHashes(array $hashes)
132
    {
133
        $this->_hashes = [];
134
        $this->addHashes($hashes);
135
    }
136
137 2
    public function getHashes()
138
    {
139 2
        return $this->_hashes;
140
    }
141
142 2
    public function getFirstTag()
143
    {
144 2
        return reset($this->_tags);
145
    }
146
147
    public function setFirstTag($name)
148
    {
149
        $this->getFirstTag()->setName($name);
150
    }
151
152 3
    public function countTags()
153
    {
154 3
        return count($this->_tags);
155
    }
156
157 3
    public function initTags()
158
    {
159 3
        if (!$this->countTags()) {
160 3
            $this->addTag(new Tag($this->lastTag));
161 3
        }
162 3
    }
163
164 2
    public function getTags()
165
    {
166 2
        return $this->_tags;
167
    }
168
169 1
    public function addTags(array $tags)
170
    {
171 1
        foreach ($tags as $name => $tag) {
172 1
            $this->addTag($tag);
173 1
        }
174 1
    }
175
176 1
    public function setTags(array $tags)
177
    {
178 1
        $this->_tags = [];
179 1
        $this->addTags($tags);
180 1
    }
181
182
    /**
183
     * Returns tag by name.
184
     * Creates if not exists.
185
     * Returns first tag when given empty name.
186
     * @param string|Tag $tag tag or tag name
187
     * @return Tag
188
     */
189 3
    public function findTag($tag)
190
    {
191 3
        if (!$tag) {
192 1
            $tag = reset($this->_tags) ?: $this->lastTag;
193 1
        }
194 3
        $name = $tag instanceof Tag ? $tag->getName() : $tag;
195 3
        if (!$this->hasTag($name)) {
196 3
            $this->_tags[$name] = new Tag($name);
197 3
        }
198
199 3
        return $this->_tags[$name];
200
    }
201
202 3
    public function hasTag($tag)
203
    {
204 3
        return isset($this->_tags[$tag]);
205
    }
206
207
    public function removeTag($name)
208
    {
209
        foreach ($this->_tags as $k => $tag) {
210
            if ($tag->getName() == $name) {
211
                unset($this->_tags[$k]);
212
213
                return;
214
            }
215
        }
216
    }
217
218 3
    public function addTag(Tag $tag)
219
    {
220 3
        return $this->findTag($tag->getName())->setDate($tag->getDate())->addNotes($tag->getNotes());
221
    }
222
223
    /**
224
     * Merges given history into the current.
225
     * @param History $history
226
     */
227
    public function merge(History $history)
228
    {
229
        $this->mergeTags($history->getTags());
230
        $this->addLinks($history->getLinks());
231
        $this->addHashes($history->getHashes());
232
    }
233
234
    /**
235
     * Merge given tags into the current history.
236
     * @param Tag[] $tags
237
     */
238
    public function mergeTags(array $tags)
239
    {
240
        foreach ($tags as $tag) {
241
            foreach ($tag->getNotes() as $note) {
242
                $note->removeCommits($this->getHashes());
243
            }
244
        }
245
        $olds = $this->getTags();
246
        $this->_tags = $tags;
247
        foreach ($olds as $tag) {
248
            $this->addTag($tag);
249
        }
250
    }
251
252
    /**
253
     * Normalizes the history.
254
     */
255 2
    public function normalize($options = [])
256
    {
257
        static $defaults = [
258
            'removeEmptyFirstTag' => [],
259
            'addInitTag'          => [],
260
            'addCommitLinks'      => [],
261
            'removeCommitLinks'   => [],
262 2
        ];
263 2
        $options = array_merge($defaults, $options);
264 2
        foreach ($options as $func => $args) {
265 2
            if (is_array($args)) {
266 2
                call_user_func_array([$this, $func], $args);
267 2
            }
268 2
        }
269 2
    }
270
271
    /**
272
     * Removes first tag if it is empty: has no notes and no commits.
273
     */
274 2
    public function removeEmptyFirstTag()
275
    {
276 2
        $tag = $this->getFirstTag();
277 2
        $notes = $tag->getNotes();
278 2
        if (count($notes) > 1) {
279
            return;
280
        }
281 2
        if (count($notes) > 0) {
282 2
            $note = reset($notes);
283 2
            if ($note->getNote() || count($note->getCommits()) > 0) {
284 2
                return;
285
            }
286
        }
287
        $this->removeTag($tag->getName());
288
    }
289
290
    /**
291
     * Adds init tag with oldest commit date.
292
     */
293 2
    public function addInitTag()
294
    {
295 2
        if (!$this->hasTag($this->initTag)) {
296 1
            $min = '';
297 1
            foreach ($this->getTags() as $tag) {
298 1
                foreach ($tag->getNotes() as $note) {
299 1
                    foreach ($note->getCommits() as $commit) {
300 1
                        $date = $commit->getDate();
301 1
                        if (!$min || strcmp($date, $min)<0) {
302 1
                            $min = $date;
303 1
                        }
304 1
                    }
305 1
                }
306 1
            }
307 1
            if ($min) {
308 1
                $this->addTag(new Tag($this->initTag, $min));
309 1
            }
310 1
        }
311 2
    }
312
313
    /**
314
     * Adds links for commits not having ones.
315
     */
316 2
    public function addCommitLinks()
317
    {
318 2
        foreach ($this->getHashes() as $hash) {
319 2
            if (!$this->hasLink($hash)) {
320 1
                $this->addLink($hash, $this->generateHashHref($hash));
321 1
            }
322 2
        }
323 2
    }
324
325 1
    public function generateHashHref($hash)
326
    {
327 1
        $project = $this->getProject();
328
329 1
        return "https://github.com/$project/commit/$hash";
330
    }
331
332
    /**
333
     * Removes commit links that are not present in the history.
334
     */
335 2
    public function removeCommitLinks($all = false)
336
    {
337 2
        foreach ($this->getLinks() as $link => $href) {
338 2
            if (preg_match('/^[0-9a-f]{7}$/', $link)) {
339 2
                if ($all || !$this->hasHash($link)) {
340
                    $this->removeLink($link);
341
                }
342 2
            }
343 2
        }
344 2
    }
345
}
346