Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
UpdateHistory
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
1 / 1
9
100.00% covered (success)
100.00%
1 / 1
 main
n/a
0 / 0
n/a
0 / 0
1
 addChangelogEntry
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
1 / 1
8
1<?php
2
3namespace Wikimedia\UpdateHistory;
4
5use RuntimeException;
6
7/**
8 * Update the HISTORY.md file just before/after a release.
9 * Run this with `composer update-history`.
10 */
11class UpdateHistory {
12    /**
13     * Main entry point.
14     * @param string $root Package root (where the HISTORY.md file is found).
15     * @param string $which One of 'patch', 'minor', or 'major'.
16     * @return int Exit code: zero on success, non-zero on failure.
17     * @codeCoverageIgnore
18     */
19    public static function main( string $root, string $which = 'patch' ): int {
20        $changeLogPath = "$root/HISTORY.md";
21        file_put_contents(
22            $changeLogPath,
23            self::addChangelogEntry( file_get_contents( $changeLogPath ) )
24        );
25        return 0;
26    }
27
28    /**
29     * @param string $changeLog Contents of the HISTORY.md file.
30     * @param string $which One of 'patch', 'minor', or 'major'.
31     *
32     * @return array|string|string[]|null
33     */
34    public static function addChangelogEntry( string $changeLog, string $which = 'patch' ) {
35        $changeLog = preg_replace_callback(
36            '/^(#+)( \S+)? (x\.x\.x|\d+\.\d+\.\d+)(.*)$/m',
37            static function ( $matches ) use ( $changeLog, $which ) {
38                $line = $matches[1] . ( $matches[2] ?? '' );
39                if ( $matches[3] !== 'x.x.x' ) {
40                    // Bump after a release
41                    return "$line x.x.x (not yet released)\n\n" . $matches[0];
42                }
43
44                // Find the previous version
45                if (
46                    preg_match(
47                        '/^#+' . preg_quote( $matches[2] ?? '', '/' ) .
48                        ' (\d+)\.(\d+)\.(\d+)/m', $changeLog, $m2
49                    ) !== 1
50                ) {
51                    throw new RuntimeException( "Last version not found!" );
52                }
53                // Do a release!
54                [ , $major, $minor, $patch ] = $m2;
55                switch ( $which ) {
56                    case 'patch':
57                        $patch++;
58                        break;
59                    case 'minor':
60                        $minor++;
61                        break;
62                    case 'major':
63                        $major++;
64                        break;
65                    default:
66                        throw new RuntimeException( "Unknown version bump type: $which" );
67                }
68                $nextVersion = "$major.$minor.$patch";
69                $date = date( 'Y-m-d' );
70                return "$line $nextVersion ($date)";
71            },
72            $changeLog,
73            1,
74            $count
75        );
76        if ( $count !== 1 ) {
77            throw new RuntimeException( "Changelog entry not found!" );
78        }
79        return $changeLog;
80    }
81}