Issues (186)

Build/update-changelog.php (1 issue)

1
<?php
2
3
/*
4
 * Copyright (C)
5
 * Nathan Boiron <[email protected]>
6
 * Romain Canon <[email protected]>
7
 *
8
 * This file is part of the TYPO3 NotiZ project.
9
 * It is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU General Public License, either
11
 * version 3 of the License, or any later version.
12
 *
13
 * For the full copyright and license information, see:
14
 * http://www.gnu.org/licenses/gpl-3.0.html
15
 */
16
17
/**
18
 * Run the following command in shell:
19
 *
20
 * $ php Build/update-changelog.php x.y.z
21
 *
22
 * Then update the `CHANGELOG.md` file, do modifications if needed, then commit.
23
 */
24
class UpdateChangelog
25
{
26
    const CHANGELOG_FILE = 'CHANGELOG.md';
27
28
    protected $version;
29
    protected $currentDate;
30
    protected $lastGitTag;
31
32
    /**
33
     * Must have the new version number as parameter.
34
     *
35
     * @param string $version
36
     */
37
    public function __construct($version)
38
    {
39
        $this->version = $version;
40
41
        // Format "02 February 2018"
42
        $this->currentDate = date('d F Y');
43
44
        // Fetches last tag that was added in git
45
        $this->lastGitTag = trim(shell_exec('git describe --tags --abbrev=0'));
46
    }
47
48
    /**
49
     * Will update the changelog file with the latest commits, ordered as
50
     * follow:
51
     *
52
     * - New features
53
     * - Bugs fixed
54
     * - Important/breaking changes
55
     * - Other less important commits
56
     */
57
    public function run()
58
    {
59
        $features = $this->getLogs('FEATURE');
60
        $bugfix = $this->getLogs('BUGFIX');
61
        $important = $this->getLogs('!!!');
62
        $others = $this->getInvertedLogs('FEATURE', 'BUGFIX', '!!!');
63
64
        $currentChangelog = file_get_contents(self::CHANGELOG_FILE);
65
66
        $changelog = $this->getChangelog($features, $bugfix, $important, $others);
67
        $changelog = preg_replace('/\n/', "\n$changelog", $currentChangelog, 1);
68
69
        file_put_contents(self::CHANGELOG_FILE, $changelog);
70
    }
71
72
    /**
73
     * @param string $features
74
     * @param string $bugfix
75
     * @param string $important
76
     * @param string $others
77
     * @return string
78
     */
79
    protected function getChangelog($features, $bugfix, $important, $others)
80
    {
81
        $changelog = "
82
## v$this->version - $this->currentDate
83
84
> ℹ️ *Click on a changelog entry to see more details.*";
85
86
        if ($features) {
87
            $changelog .= "
88
89
### New features
90
$features";
91
        }
92
93
        if ($bugfix) {
94
            $changelog .= "
95
### Bugs fixed
96
$bugfix";
97
        }
98
99
        if ($important) {
100
            $changelog .= "
101
### Important
102
103
**⚠ Please pay attention to the changes below as they might break your TYPO3 installation:**
104
$important";
105
        }
106
107
        if ($others) {
108
            $changelog .= "
109
### Others
110
$others";
111
        }
112
113
        return $changelog;
114
    }
115
116
    /**
117
     * @param string[] $types
118
     * @return string
119
     */
120
    protected function getLogs(...$types)
121
    {
122
        $command = $this->getLogsCommand(...$types);
123
124
        return $this->formatLogs($command);
125
    }
126
127
    /**
128
     * @param string[] $types
129
     * @return string
130
     */
131
    protected function getInvertedLogs(...$types)
132
    {
133
        $command = $this->getLogsCommand(...$types);
134
        $command .= ' --invert-grep';
135
136
        return $this->formatLogs($command);
137
    }
138
139
    /**
140
     * @param string[] $types
141
     * @return string
142
     */
143
    protected function getLogsCommand(...$types)
144
    {
145
        $command = "git log HEAD...$this->lastGitTag" .
146
            ' --date=format:"%d %b %Y"';
147
148
        foreach ($types as $type) {
149
            $command .= ' --grep="^\[' . $type . '\]"';
150
        }
151
152
        return $command;
153
    }
154
155
    /**
156
     * @param $command
157
     * @return string
158
     */
159
    protected function formatLogs($command)
160
    {
161
        $title = $this->getGitLog($command, '%s');
162
        $revisionShort = $this->getGitLog($command, '%h');
163
        $revision = $this->getGitLog($command, '%H');
164
        $body = $this->getGitLog($command, '%b');
165
        $author = $this->getGitLog($command, '%an');
166
        $authorEmail = $this->getGitLog($command, '%ae');
167
        $date = $this->getGitLog($command, '%ad');
168
169
        $count = count($title);
170
171
        if ($count === 0) {
172
            return '';
173
        }
174
175
        $result = '';
176
177
        for ($i = 0; $i < count($title); $i++) {
178
            $detailedTitle = $this->replaceCodeSections($title[$i]);
179
            $pullRequest = null;
180
181
            $detailedBody = preg_replace('/\n/', "\n> ", $body[$i]);
182
            $detailedBody = $this->addLinkToGitHubIssues($detailedBody);
183
184
            // Add a link to detected GitHub issues number.
185
            if (preg_match('/#([0-9]+)/', $title[$i], $pullRequestResult)) {
186
                $detailedTitle = preg_replace('/ *\(#([0-9]+)\)/', '', $detailedTitle);
187
                $detailedTitle = preg_replace('/ *#([0-9]+)/', '', $detailedTitle);
188
                $pullRequest = ' / [#' . $pullRequestResult[1] . '](https://github.com/CuyZ/NotiZ/issues/' . $pullRequestResult[1] . ')';
189
            }
190
191
            $result .= <<<HTML
192
193
<details>
194
<summary>$detailedTitle</summary>
195
196
> *by [$author[$i]](mailto:$authorEmail[$i])* on *$date[$i] / [$revisionShort[$i]](https://github.com/CuyZ/NotiZ/commit/$revision[$i])$pullRequest*
197
198
> $detailedBody
199
</details>
200
201
HTML;
202
        }
203
204
        return $result;
205
    }
206
207
    /**
208
     * @param string $command
209
     * @param string $format
210
     * @return array
211
     */
212
    protected function getGitLog($command, $format)
213
    {
214
        $result = shell_exec($command . '  --pretty=tformat:"' . $format . '>>>NEXT<<<"');
215
        $result = explode('>>>NEXT<<<', $result);
216
        $result = array_map('trim', $result);
217
        array_pop($result);
218
        $result = array_map([$this, 'sanitizeLog'], $result);
219
220
        return $result;
221
    }
222
223
    /**
224
     * @param string $text
225
     * @return string
226
     */
227
    protected function sanitizeLog($text)
228
    {
229
        // Replace redundant line breaks.
230
        $text = preg_replace('/\n\n\n+/m', "\n\n", $text);
231
232
        // Removes the commit prefix.
233
        $text = preg_replace('/^\[!!!\](.*)$/', '$1', $text);
234
        $text = preg_replace('/^\[[^ \]]+\] (.*)$/', '$1', $text);
235
236
        return $text;
237
    }
238
239
    /**
240
     * Add a link to all detected GitHub issues number.
241
     *
242
     * @param string $text
243
     * @return string
244
     */
245
    protected function addLinkToGitHubIssues($text)
246
    {
247
        return preg_replace('/#([0-9]+)/', '[#$1](https:\/\/github.com\/CuyZ\/NotiZ\/issues\/$1)', $text);
248
    }
249
250
    /**
251
     * @param string $text
252
     * @return string
253
     */
254
    protected function replaceCodeSections($text)
255
    {
256
        return preg_replace('/`([^`]*)`/', '<code>$1</code>', $text);
257
    }
258
}
259
260
unset($argv[0]);
261
(new UpdateChangelog(...$argv))->run();
0 ignored issues
show
$argv is expanded, but the parameter $version of UpdateChangelog::__construct() does not expect variable arguments. ( Ignorable by Annotation )

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

261
(new UpdateChangelog(/** @scrutinizer ignore-type */ ...$argv))->run();
Loading history...
262