├── .github
└── workflows
│ └── main.yml
├── CHANGELOG.md
├── README.md
├── composer.json
└── src
├── Parser.php
└── Retrievers
├── AbstractRetriever.php
├── ChangesRetriever.php
├── DescriptionRetriever.php
├── LineRetriever.php
└── ReleasesRetriever.php
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name:
2 | CI
3 | on: [push]
4 | jobs:
5 | php:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: actions/checkout@v1
9 | - name: Installing PHP
10 | uses: shivammathur/setup-php@master
11 | with:
12 | php-version: 7.4
13 | - name: Installing dependencies
14 | run: composer install --prefer-dist --ignore-platform-reqs
15 | - name: Tests
16 | run: composer test
17 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | A change log for the change log parser
3 |
4 | ## Unreleased
5 |
6 | ## 0.11.0 - 2019-12-23
7 |
8 | ### Changed
9 |
10 | - Allow `symfony/dom-crawler:5` and `symfony/css-selector:5`
11 | - Drop support for everything below PHP 7.4
12 |
13 | ## 0.10.1 - 2019-10-05
14 |
15 | ### Changed
16 |
17 | - [internal] Replaced Travis with GitHub actions
18 | - [internal] Updated to PHPSpec 6
19 |
20 | ### Security
21 |
22 | - Upgraded to `league/commonmark` to fix CVE-2019-10010
23 |
24 | ## 0.10.0 - 2018-02-25
25 |
26 | ### Changed
27 |
28 | - Drop support for PHP5, PHP 7.1.3 is now required
29 | - Upgrade dependencies to their latest versions
30 |
31 | ## 0.9.0 - 2016-01-01
32 |
33 | ### Changed
34 |
35 | - Updated symfony dependencies to 3.0
36 |
37 | ## 0.8.0 - 2015-12-25
38 |
39 | ### Changed
40 |
41 | - Updated symfony requirements to 2.8
42 |
43 | ## 0.7.1 - 2015-12-13
44 |
45 | ### Fixed
46 |
47 | - Fixed issue where the description returned the first release if no description was given
48 | - Better support for multi line descriptions.
49 | - Fixed issue where the parser crashed if a release had no date (for example and `unreleased` section)
50 |
51 | ## 0.7.0 - 2015-11-25
52 |
53 | * Updated the following dependencies to their latest versions: `league/commonmark:0.12.0`, `symfony/dom-crawler:2.7.7`, `symfony/css-selector:2.7.7`
54 | * PSR-4 autoloading
55 |
56 | ## 0.6.2 - 2015-04-15
57 |
58 | ### Fixed
59 |
60 | * Fix issue with empty lines being parsed
61 |
62 | ## 0.6.1 - 2015-01-09
63 |
64 | ### Fixed
65 |
66 | * Fixed an issue where a section would sometimes be empty
67 |
68 | ## 0.6.0 - 2014-12-28
69 |
70 | ### Added
71 |
72 | * added `.gitattributes` file to only include necessary content during a composer install
73 |
74 | ## 0.5.0 - 2014-12-25
75 |
76 | ### Changed
77 |
78 | * getChanges and getReleases now return arrays instead of JSON
79 |
80 | ## 0.4.0 - 2014-12-24
81 |
82 | _No notable changes_
83 |
84 | ## 0.3.0 - 2014-12-23
85 |
86 | ### Changed
87 |
88 | * Changed the underlying Markdown parser to [league/commonmark](https://github.com/thephpleague/commonmark)
89 |
90 | ## 0.2.0 - 2014-11-22
91 |
92 | ### Added
93 |
94 | * `getChanges` method to retrieve a single release
95 |
96 | ## 0.1.0 - 2014-11-22
97 |
98 | ### Added
99 |
100 | * `getReleases` method that retrieves the releases described in a change log
101 | * `toJson` method that creates a json representation of a change log.
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | > Parse changelogs like a pro
3 |
4 | This package makes it easy to parse change logs in the [keepachangelog.com](http://keepachangelog.com/) format
5 |
6 | ## Installation
7 |
8 | `composer require bramdevries/changelog`
9 |
10 | ## Usage
11 |
12 | ### Parsing an entire change log
13 |
14 | The following change log:
15 |
16 | ```md
17 |
18 | # Change Log
19 | A change log for the change log parser
20 |
21 | ## 0.2.0 - 2014-11-22
22 |
23 | ### Added
24 |
25 | * `getChanges` method to retrieve a single release
26 |
27 | ## 0.1.0 - 2014-11-22
28 |
29 | ### Added
30 |
31 | * `getReleases` method that retrieves the releases described in a change log
32 | * `toJson` method that creates a json representation of a change log.
33 |
34 | ```
35 |
36 | ```php
37 | $parser = new Changelog\Parser(file_get_contents('CHANGELOG.md');
38 | echo $parser->toJson();
39 | ```
40 |
41 | Will return
42 |
43 | ```json
44 | {
45 | "description": "A change log for the change log parser",
46 | "releases": [
47 | {
48 | "name": "0.0.1",
49 | "date": "2014-11-22",
50 | "changes": {
51 | "added": [
52 | "getReleases
method that retrieves the releases described in a change log",
53 | "toJson
method that creates a json representation of a change log."
54 | ]
55 | }
56 | }
57 | ]
58 | }
59 | ```
60 |
61 | ### Parsing a single release's changelog
62 |
63 | eg: If you want to parse a pull request in this format
64 |
65 | ```md
66 | ### Added
67 | - Addition 1
68 | - Addition 2
69 |
70 | ### Changed
71 | - Change 1
72 | - Change 2
73 |
74 | ### Removed
75 | - Removal 1
76 | - Removal 2
77 | ```
78 |
79 | ```php
80 | // Assuming $content contains the above markdown
81 | $parser = new Changelog\Parser($content);
82 | echo $parser->getChanges();
83 | ```
84 |
85 | returns
86 |
87 | ```json
88 | {
89 | "added": [
90 | "Addition 1",
91 | "Addition 2"
92 | ],
93 | "changed": [
94 | "Change 1",
95 | "Change 2"
96 | ],
97 | "removed": [
98 | "Removal 1",
99 | "Removal 2"
100 | ]
101 | }
102 | ```
103 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bramdevries/changelog",
3 | "license": "MIT",
4 | "description": "A http://keepachangelog.com/ parser for the common developer",
5 | "authors": [
6 | {
7 | "name": "Bram Devries",
8 | "email": "bram@madewithlove.be"
9 | }
10 | ],
11 | "require": {
12 | "php": ">=7.4",
13 | "symfony/dom-crawler": "~5",
14 | "symfony/css-selector": "~5",
15 | "league/commonmark": "^1.0"
16 | },
17 | "require-dev": {
18 | "phpspec/phpspec": "~6"
19 | },
20 | "autoload": {
21 | "psr-4": {
22 | "Changelog\\": "src"
23 | }
24 | },
25 | "scripts": {
26 | "test": [
27 | "phpspec run --format=pretty"
28 | ]
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Parser.php:
--------------------------------------------------------------------------------
1 | setContent($content);
29 | }
30 |
31 | /**
32 | * Retrieve all the releases from the change log
33 | *
34 | * @return array
35 | */
36 | public function getReleases()
37 | {
38 | return (new ReleasesRetriever($this->content->filter('h2')))->retrieve();
39 | }
40 |
41 | /**
42 | * @return array
43 | */
44 | public function getChanges()
45 | {
46 | return (new ChangesRetriever($this->content->filter('h3')))->retrieve();
47 | }
48 |
49 | /**
50 | * Set the content to parse
51 | *
52 | * @param $value
53 | */
54 | public function setContent($value)
55 | {
56 | $converter = new CommonMarkConverter;
57 | $this->content = new Crawler($converter->convertToHtml($value));
58 | }
59 |
60 | /**
61 | * @return string
62 | */
63 | public function getDescription()
64 | {
65 | return (new DescriptionRetriever($this->content->filter('h1 ~ p')))->retrieve();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Retrievers/AbstractRetriever.php:
--------------------------------------------------------------------------------
1 | nodes = [];
20 | $nodes->each(function ($node) {
21 | $this->nodes[] = $node;
22 | });
23 | }
24 |
25 | /**
26 | * @return array
27 | */
28 | public function retrieve()
29 | {
30 | return array_map([$this, 'parse'], $this->nodes);
31 | }
32 |
33 | /**
34 | * @param Crawler $node
35 | */
36 | abstract protected function parse(Crawler $node);
37 | }
--------------------------------------------------------------------------------
/src/Retrievers/ChangesRetriever.php:
--------------------------------------------------------------------------------
1 | html());
34 |
35 | if (!$key) {
36 | return [];
37 | }
38 |
39 | $lines = (new LineRetriever($node->nextAll()->first()->children('li')))->retrieve();
40 |
41 | return [
42 | 'section' => $key,
43 | 'changes' => $lines
44 | ];
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Retrievers/DescriptionRetriever.php:
--------------------------------------------------------------------------------
1 | text();
31 | }
32 | }
--------------------------------------------------------------------------------
/src/Retrievers/LineRetriever.php:
--------------------------------------------------------------------------------
1 | html());
17 | }
18 | }
--------------------------------------------------------------------------------
/src/Retrievers/ReleasesRetriever.php:
--------------------------------------------------------------------------------
1 | html());
17 |
18 | // Get the changes
19 | $nodes = $node->nextAll()->filterXPath('h3[preceding-sibling::h2[1][.="'.$node->html().'"]]');
20 |
21 | $changes = (new ChangesRetriever($nodes))->retrieve();
22 |
23 | return [
24 | 'name' => $title[0],
25 | 'date' => isset($title[1]) ? $title[1] : null,
26 | 'changes' => $changes,
27 | ];
28 | }
29 | }
--------------------------------------------------------------------------------