keepachangelog 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +6 -1
- data/Gemfile.lock +2 -2
- data/features/help.feature +2 -3
- data/features/{parse.feature → markdown.feature} +4 -4
- data/features/yaml.feature +17 -0
- data/lib/keepachangelog/cli.rb +22 -6
- data/lib/keepachangelog/markdown_printer.rb +90 -0
- data/lib/keepachangelog/parser.rb +33 -61
- data/lib/keepachangelog/parser/markdown.rb +68 -0
- data/lib/keepachangelog/parser/yaml.rb +110 -0
- data/package.json +1 -1
- data/spec/markdown_printer_spec.rb +19 -0
- data/spec/parser/markdown_spec.rb +109 -0
- data/spec/parser/yaml_spec.rb +50 -0
- data/spec/parser_spec.rb +0 -118
- data/spec/spec_helper.rb +2 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: beb911086da3260f5c4f06ff2f57b219ddb19a06
|
4
|
+
data.tar.gz: d08ff76239c9a49db9ee5f46f33d3f4df75498bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5fb6c397a7f820740f5f86206f6e37211afbfc564afd4cf17c0f7de4907b6ff57faf50333abec10ccde44b4d18f04a72d0c1d096d148d0e9c54b7f033bc33fce
|
7
|
+
data.tar.gz: 0237365f64e45fd84ee99b74fd9c0b68f57621f063e0d2c7abf249525c7149f256ade2bb9ceb5b5c979d4ba05ff064f590f8d26377d147a65c8c75c263ea31a3
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,11 +4,16 @@ Alla ändringar till detta projekt dokumenteras i denna fil.
|
|
4
4
|
Formatet är baserat på [Keep a Changelog](http://keepachangelog.com/)
|
5
5
|
och detta projekt följer [Semantic Versioning](http://semver.org/).
|
6
6
|
|
7
|
+
## [0.2.0] - 2017-03-27
|
8
|
+
- Förmåga att läsa in Changelog i YAML-format.
|
9
|
+
- Förmåga att skriva till Markdown-format.
|
10
|
+
|
7
11
|
## [0.1.0] - 2017-03-27
|
8
12
|
### Nytt
|
9
13
|
- Ruby gem som exponerar verktyget via Ruby och CLI.
|
10
14
|
- Förmåga att konvertera Changelog till JSON.
|
11
15
|
- Förmåga att konvertera Changelog till YAML.
|
12
16
|
|
13
|
-
[Unreleased]: https://git.basalt.se/chbr/keepachangelog/compare/0.
|
17
|
+
[Unreleased]: https://git.basalt.se/chbr/keepachangelog/compare/0.2.0...HEAD
|
18
|
+
[0.2.0]: https://git.basalt.se/chbr/keepachangelog/compare/0.1.0...0.2.0
|
14
19
|
[0.1.0]: https://git.basalt.se/chbr/keepachangelog/compare/77986bc...0.1.0
|
data/Gemfile.lock
CHANGED
data/features/help.feature
CHANGED
@@ -8,6 +8,5 @@ Feature: Show help
|
|
8
8
|
Then the output should contain "Keepachangelog commands"
|
9
9
|
|
10
10
|
Scenario: Getting help about a command
|
11
|
-
When I successfully run `keepachangelog help
|
12
|
-
Then the output should contain "
|
13
|
-
And the output should contain "Usage"
|
11
|
+
When I successfully run `keepachangelog help markdown`
|
12
|
+
Then the output should contain "Usage"
|
@@ -10,10 +10,10 @@ Feature: List transformators
|
|
10
10
|
### New
|
11
11
|
- Feature A
|
12
12
|
"""
|
13
|
-
When I successfully run `keepachangelog
|
13
|
+
When I successfully run `keepachangelog markdown`
|
14
14
|
Then the output should contain:
|
15
15
|
"""
|
16
|
-
|
16
|
+
{"versions":{"Unreleased":{"url":null,"date":null,"changes":{"New":["Feature A"]}}}}
|
17
17
|
"""
|
18
18
|
|
19
19
|
Scenario: Running without command
|
@@ -26,7 +26,7 @@ Feature: List transformators
|
|
26
26
|
When I successfully run `keepachangelog`
|
27
27
|
Then the output should contain:
|
28
28
|
"""
|
29
|
-
|
29
|
+
{"versions":{"Unreleased":{"url":null,"date":null,"changes":{"New":["Feature A"]}}}}
|
30
30
|
"""
|
31
31
|
|
32
32
|
Scenario: Changelog has a non-default filename
|
@@ -39,5 +39,5 @@ Feature: List transformators
|
|
39
39
|
When I successfully run `keepachangelog --path=HISTORY.md`
|
40
40
|
Then the output should contain:
|
41
41
|
"""
|
42
|
-
|
42
|
+
{"versions":{"Unreleased":{"url":null,"date":null,"changes":{"New":["Feature A"]}}}}
|
43
43
|
"""
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: List transformators
|
2
|
+
|
3
|
+
Parse a changelog by running `keepachangelog parse` or just simply
|
4
|
+
`keepachangelog`.
|
5
|
+
|
6
|
+
Scenario: Running with command
|
7
|
+
Given a file "changelog/1.0.0/1.yml" with:
|
8
|
+
"""
|
9
|
+
---
|
10
|
+
title: Feature A
|
11
|
+
type: New
|
12
|
+
"""
|
13
|
+
When I successfully run `keepachangelog yaml`
|
14
|
+
Then the output should contain:
|
15
|
+
"""
|
16
|
+
{"versions":{"1.0.0":{"changes":{"New":["Feature A"]}}}}
|
17
|
+
"""
|
data/lib/keepachangelog/cli.rb
CHANGED
@@ -18,22 +18,38 @@ module Keepachangelog
|
|
18
18
|
shell.say Keepachangelog.version
|
19
19
|
end
|
20
20
|
|
21
|
-
desc '
|
21
|
+
desc 'markdown', 'Parse a changelog in markdown'
|
22
22
|
option :format, type: :string,
|
23
23
|
desc: 'The output format',
|
24
24
|
default: 'json',
|
25
25
|
banner: 'json|yaml',
|
26
26
|
aliases: '-f'
|
27
27
|
option :path, type: :string,
|
28
|
-
desc: 'Path to the
|
28
|
+
desc: 'Path to the Changelog file',
|
29
29
|
default: 'CHANGELOG.md',
|
30
30
|
aliases: '-p'
|
31
|
-
def
|
32
|
-
require 'keepachangelog/parser'
|
33
|
-
p =
|
31
|
+
def markdown
|
32
|
+
require 'keepachangelog/parser/markdown'
|
33
|
+
p = MarkdownParser.load(options[:path])
|
34
34
|
shell.say p.send("to_#{options[:format]}")
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
desc 'yaml', 'Parse a folder of YAML files'
|
38
|
+
option :format, type: :string,
|
39
|
+
desc: 'The output format',
|
40
|
+
default: 'json',
|
41
|
+
banner: 'json|yaml',
|
42
|
+
aliases: '-f'
|
43
|
+
option :path, type: :string,
|
44
|
+
desc: 'Path to the yaml folder',
|
45
|
+
default: 'changelog',
|
46
|
+
aliases: '-p'
|
47
|
+
def yaml
|
48
|
+
require 'keepachangelog/parser/yaml'
|
49
|
+
p = YamlParser.load(options[:path])
|
50
|
+
shell.say p.send("to_#{options[:format]}")
|
51
|
+
end
|
52
|
+
|
53
|
+
default_task :markdown
|
38
54
|
end
|
39
55
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Keepachangelog
|
2
|
+
class MarkdownPrinter
|
3
|
+
attr_accessor :options
|
4
|
+
attr_accessor :versions
|
5
|
+
|
6
|
+
def initialize(versions, options = {})
|
7
|
+
self.options = options
|
8
|
+
self.versions = versions
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
[
|
13
|
+
"# #{options[:title] || default_title}",
|
14
|
+
clean_intro(options[:intro]) || default_intro,
|
15
|
+
'',
|
16
|
+
versions.reverse_each.map do |k, v|
|
17
|
+
version(k, v)
|
18
|
+
end,
|
19
|
+
anchors
|
20
|
+
].flatten.join("\n")
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def clean_intro(text)
|
26
|
+
text.to_s.strip.gsub("\n", "\n\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
def version(header, content)
|
30
|
+
[
|
31
|
+
version_header(header),
|
32
|
+
content['changes'].map { |k, v| section(k, v) }
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
def section(header, content)
|
37
|
+
[
|
38
|
+
"### #{header}",
|
39
|
+
content.map { |c| change(c) },
|
40
|
+
''
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
def anchors
|
45
|
+
v = versions.keys.sort.reverse
|
46
|
+
(0..v.length - 1).map { |i| anchor(v, i) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def anchor(v, i)
|
50
|
+
from_v = i == v.length - 1 ? first_commit : v[i + 1]
|
51
|
+
to_v = v[i] == 'Unreleased' ? 'HEAD' : v[i]
|
52
|
+
"[#{v[i]}]: #{options[:url]}/compare/#{from_v}..#{to_v}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def change(content)
|
56
|
+
"- #{content}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def default_title
|
60
|
+
'Change log'
|
61
|
+
end
|
62
|
+
|
63
|
+
def default_intro
|
64
|
+
"All notable changes to this project will be documented in this file.
|
65
|
+
|
66
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
67
|
+
and this project adheres to [Semantic Versioning](http://semver.org/)."
|
68
|
+
end
|
69
|
+
|
70
|
+
def first_commit
|
71
|
+
`git rev-parse --short $(git rev-list --max-parents=0 HEAD) 2>/dev/null`
|
72
|
+
.strip
|
73
|
+
end
|
74
|
+
|
75
|
+
def version_date(version)
|
76
|
+
date = `git log -1 --format=%aI #{version} 2>/dev/null`.strip
|
77
|
+
DateTime.parse(date).strftime('%Y-%m-%d')
|
78
|
+
rescue
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def version_header(version)
|
83
|
+
header = version
|
84
|
+
header = "[#{header}]" if options[:url]
|
85
|
+
date = version_date(version)
|
86
|
+
header += " - #{date}" if date
|
87
|
+
"## #{header}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -1,82 +1,54 @@
|
|
1
|
+
require 'keepachangelog/markdown_printer'
|
2
|
+
|
1
3
|
module Keepachangelog
|
2
4
|
class Parser
|
3
5
|
attr_accessor :parsed_content
|
4
6
|
|
5
|
-
def initialize
|
6
|
-
self.parsed_content =
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.load(filename = 'CHANGELOG.md')
|
10
|
-
content = File.open(filename, &:read)
|
11
|
-
new(content)
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.parse(content)
|
15
|
-
new(content)
|
7
|
+
def initialize
|
8
|
+
self.parsed_content = { 'versions' => {} }
|
16
9
|
end
|
17
10
|
|
11
|
+
# Changelog in JSON format
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
# ```json
|
15
|
+
# {"1.0.0": { "changes": { "New": ["Feature A"] } } }
|
16
|
+
# ```
|
18
17
|
def to_json
|
19
18
|
parsed_content.to_json
|
20
19
|
end
|
21
20
|
|
21
|
+
# Changelog in YAML format
|
22
|
+
#
|
23
|
+
# Example:
|
24
|
+
# ```yaml
|
25
|
+
# ---
|
26
|
+
# 0.1.0:
|
27
|
+
# changes:
|
28
|
+
# New:
|
29
|
+
# - Feature A
|
30
|
+
# ```
|
22
31
|
def to_yaml
|
23
32
|
parsed_content.to_yaml
|
24
33
|
end
|
25
34
|
|
35
|
+
# Changelog as a Ruby string
|
36
|
+
#
|
37
|
+
# Example:
|
38
|
+
# ```ruby
|
39
|
+
# {"0.1.0"=>{"changes"=>{"New"=>["Feature A"]}}
|
40
|
+
# ```
|
26
41
|
def to_s
|
27
42
|
parsed_content.to_s
|
28
43
|
end
|
29
44
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
def clean(content)
|
40
|
-
content.sub(/^.*?\n\s*## /, '## ')
|
41
|
-
end
|
42
|
-
|
43
|
-
def parse_version(content, anchors)
|
44
|
-
header_pattern = /\[(?<name>.*)\]( - (?<date>\d\d\d\d-\d\d-\d\d))?/
|
45
|
-
sections = content.split(/\n\s*### /)
|
46
|
-
header = sections[0].match header_pattern
|
47
|
-
{
|
48
|
-
'version' => header[:name],
|
49
|
-
'url' => get_url(header[:name], anchors),
|
50
|
-
'date' => header[:date],
|
51
|
-
'changes' => sections[1..-1].map { |s| parse_section s }.to_h
|
52
|
-
}
|
53
|
-
end
|
54
|
-
|
55
|
-
def get_url(version, anchors)
|
56
|
-
anchors.keys.include?(version) ? anchors[version] : nil
|
57
|
-
end
|
58
|
-
|
59
|
-
def parse_section(content)
|
60
|
-
lines = content.split("\n")
|
61
|
-
bullets = lines[1..-1]
|
62
|
-
.select { |s| s.strip.start_with?('- ') }
|
63
|
-
.map { |s| clean_bullet(s) }
|
64
|
-
[lines[0], bullets]
|
65
|
-
end
|
66
|
-
|
67
|
-
def clean_bullet(string)
|
68
|
-
string.strip.gsub(/^\s*- /, '').gsub(/\(.*#\d+\)\.?$/, '').strip
|
69
|
-
end
|
70
|
-
|
71
|
-
def extract_anchors!(content)
|
72
|
-
anchor_pattern = /\n\s*\[(.*)\]: (.*)\s*\n/
|
73
|
-
anchors = content.scan anchor_pattern
|
74
|
-
cleaned_content = ''
|
75
|
-
while cleaned_content.to_s != content.to_s
|
76
|
-
cleaned_content = content.gsub anchor_pattern, "\n"
|
77
|
-
content.replace(cleaned_content)
|
78
|
-
end
|
79
|
-
anchors.map { |x| [x[0], x[1]] }.to_h
|
45
|
+
# Changelog as Markdown
|
46
|
+
def to_md
|
47
|
+
md = MarkdownPrinter.new(parsed_content['versions'],
|
48
|
+
title: parsed_content['title'],
|
49
|
+
intro: parsed_content['intro'],
|
50
|
+
url: parsed_content['url'])
|
51
|
+
md.to_s
|
80
52
|
end
|
81
53
|
end
|
82
54
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Keepachangelog
|
2
|
+
# Parser for Markdown content
|
3
|
+
class MarkdownParser < Parser
|
4
|
+
# Parse raw markdown content
|
5
|
+
def self.parse(content = '')
|
6
|
+
new.parse(content)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Parse a file with markdown content
|
10
|
+
def self.load(filename = 'CHANGELOG.md')
|
11
|
+
parse File.open(filename, &:read)
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse(content)
|
15
|
+
content = "\n" + clean(content).strip + "\n"
|
16
|
+
anchors = extract_anchors! content
|
17
|
+
versions = content.split(/\n\s*## /)[1..-1]
|
18
|
+
{
|
19
|
+
'versions' => versions.map { |v| parse_version v, anchors }.to_h
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def clean(content)
|
26
|
+
content.sub(/^.*?\n\s*## /, '## ')
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_version(content, anchors)
|
30
|
+
header_pattern = /\[(?<name>.*)\]( - (?<date>\d\d\d\d-\d\d-\d\d))?/
|
31
|
+
sections = content.split(/\n\s*### /)
|
32
|
+
header = sections[0].match header_pattern
|
33
|
+
[header[:name],
|
34
|
+
{
|
35
|
+
'url' => get_url(header[:name], anchors),
|
36
|
+
'date' => header[:date],
|
37
|
+
'changes' => sections[1..-1].map { |s| parse_section s }.to_h
|
38
|
+
}]
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_url(version, anchors)
|
42
|
+
anchors.keys.include?(version) ? anchors[version] : nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_section(content)
|
46
|
+
lines = content.split("\n")
|
47
|
+
bullets = lines[1..-1]
|
48
|
+
.select { |s| s.strip.start_with?('- ') }
|
49
|
+
.map { |s| clean_bullet(s) }
|
50
|
+
[lines[0], bullets]
|
51
|
+
end
|
52
|
+
|
53
|
+
def clean_bullet(string)
|
54
|
+
string.strip.gsub(/^\s*- /, '').gsub(/\(.*#\d+\)\.?$/, '').strip
|
55
|
+
end
|
56
|
+
|
57
|
+
def extract_anchors!(content)
|
58
|
+
anchor_pattern = /\n\s*\[(.*)\]: (.*)\s*\n/
|
59
|
+
anchors = content.scan anchor_pattern
|
60
|
+
cleaned_content = ''
|
61
|
+
while cleaned_content.to_s != content.to_s
|
62
|
+
cleaned_content = content.gsub anchor_pattern, "\n"
|
63
|
+
content.replace(cleaned_content)
|
64
|
+
end
|
65
|
+
anchors.map { |x| [x[0], x[1]] }.to_h
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Keepachangelog
|
2
|
+
# Parser for YAML content
|
3
|
+
#
|
4
|
+
# The YAML files describing the Changelog are expected to be in a folder
|
5
|
+
# structure where each version is its own folder and each Merge Request
|
6
|
+
# or Pull Request is in its own YAML-file.
|
7
|
+
#
|
8
|
+
# ```
|
9
|
+
# changelog
|
10
|
+
# ├── 0.1.0
|
11
|
+
# │ └── 1-first-merge-request.yaml
|
12
|
+
# ├── 0.2.0
|
13
|
+
# │ └── 3-another-cool-mr.yaml
|
14
|
+
# ├── 0.3.0
|
15
|
+
# │ ├── 8-fixing-some-stuff.yaml
|
16
|
+
# │ └── 9-add-new-feature.yaml
|
17
|
+
# └── unreleased
|
18
|
+
# └── 11-minor-patch.yaml
|
19
|
+
# ```
|
20
|
+
#
|
21
|
+
# Each YAML file is expected to be in the following format:
|
22
|
+
#
|
23
|
+
# ```yaml
|
24
|
+
# ---
|
25
|
+
# title: The ability to perform Foo while Bar is active
|
26
|
+
# merge_request: 11
|
27
|
+
# issue: 42
|
28
|
+
# author: @chbr
|
29
|
+
# type: New
|
30
|
+
# ```
|
31
|
+
#
|
32
|
+
# - `title` is a single sentence without punctiation that describes the
|
33
|
+
# change
|
34
|
+
# - `merge_request` is the ID of the MR or PR (optional)
|
35
|
+
# - `issue` is the ID of the issue (optional)
|
36
|
+
# - `author` is the username of the author (optional)
|
37
|
+
# - `type` is the type of change, for example *New*, *Changed*, *Fixed*,
|
38
|
+
# *Removed* or *Security*.
|
39
|
+
class YamlParser < Parser
|
40
|
+
# Parse raw yaml content of a single file
|
41
|
+
def self.parse(content, version = 'unreleased')
|
42
|
+
new.parse(content, version)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Parse a folder with YAML files
|
46
|
+
def self.load(path = 'changelog')
|
47
|
+
p = new
|
48
|
+
p.load(path)
|
49
|
+
p
|
50
|
+
end
|
51
|
+
|
52
|
+
# Parse raw yaml content of a single file
|
53
|
+
def parse(content, version)
|
54
|
+
initialize_version version
|
55
|
+
yaml = YAML.safe_load content
|
56
|
+
return {} unless yaml
|
57
|
+
add_change yaml, version
|
58
|
+
end
|
59
|
+
|
60
|
+
# Parse a folder with YAML files
|
61
|
+
def load(path = 'changelog')
|
62
|
+
read_meta("#{path}/meta.yaml")
|
63
|
+
Dir.glob("#{path}/*").each { |f| parse_version(f) }
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def read_meta(path)
|
69
|
+
return unless File.exist?(path)
|
70
|
+
content = File.open(path, &:read)
|
71
|
+
yaml = YAML.safe_load content
|
72
|
+
return unless yaml
|
73
|
+
parsed_content['title'] = yaml['title']
|
74
|
+
parsed_content['url'] = yaml['url']
|
75
|
+
parsed_content['intro'] = yaml['intro']
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_change(yaml, version)
|
79
|
+
changes = parsed_content['versions'][version]['changes']
|
80
|
+
changes[yaml['type']] = (changes[yaml['type']] || []) +
|
81
|
+
[generate_line(yaml)]
|
82
|
+
parsed_content
|
83
|
+
end
|
84
|
+
|
85
|
+
def parse_version(folder)
|
86
|
+
version = File.basename(folder)
|
87
|
+
return if version == 'meta.yaml'
|
88
|
+
initialize_version version
|
89
|
+
files = Dir.glob("#{folder}/**/*.yaml") +
|
90
|
+
Dir.glob("#{folder}/**/*.yml")
|
91
|
+
files.sort.each { |f| parse_file(f, version) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def parse_file(filename, version)
|
95
|
+
parse File.open(filename, &:read), version
|
96
|
+
end
|
97
|
+
|
98
|
+
def generate_line(yaml)
|
99
|
+
line = yaml['title']
|
100
|
+
line += " (!#{yaml['merge_request']})" if yaml['merge_request']
|
101
|
+
line += " (##{yaml['issue']})" if yaml['issue']
|
102
|
+
line += " (#{yaml['author']})" if yaml['author']
|
103
|
+
line
|
104
|
+
end
|
105
|
+
|
106
|
+
def initialize_version(version)
|
107
|
+
parsed_content['versions'][version] = { 'changes' => {} }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/package.json
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Keepachangelog
|
4
|
+
describe MarkdownPrinter do
|
5
|
+
describe '.to_s' do
|
6
|
+
it 'should print markdown document' do
|
7
|
+
versions = {
|
8
|
+
'1.0.0' => {
|
9
|
+
'changes' => { 'New' => ['Feature A'] }
|
10
|
+
}
|
11
|
+
}
|
12
|
+
p = MarkdownPrinter.new(versions, title: 'My Title')
|
13
|
+
md = p.to_s
|
14
|
+
expect(md).to match('# My Title')
|
15
|
+
expect(md).to match('## 1.0.0')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Keepachangelog
|
4
|
+
describe MarkdownParser do
|
5
|
+
describe '.parse' do
|
6
|
+
it 'should parse empty content' do
|
7
|
+
cl = MarkdownParser.parse('')
|
8
|
+
expect(cl).to eq('versions' => {})
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should parse single version' do
|
12
|
+
content = "
|
13
|
+
## [1.2.3] - 2017-01-01
|
14
|
+
### New
|
15
|
+
- Feature A
|
16
|
+
### Fixed
|
17
|
+
- Feature B
|
18
|
+
[1.2.3]: http://test.io
|
19
|
+
"
|
20
|
+
cl = MarkdownParser.parse(content)
|
21
|
+
expect(cl).to eq(
|
22
|
+
'versions' => {
|
23
|
+
'1.2.3' => {
|
24
|
+
'url' => 'http://test.io',
|
25
|
+
'date' => '2017-01-01',
|
26
|
+
'changes' => {
|
27
|
+
'New' => ['Feature A'],
|
28
|
+
'Fixed' => ['Feature B']
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should parse multiple versions' do
|
36
|
+
content = "
|
37
|
+
## [2.0.0] - 2017-01-01
|
38
|
+
### New
|
39
|
+
- Feature A
|
40
|
+
## [1.0.0]
|
41
|
+
### Fixed
|
42
|
+
- Feature B
|
43
|
+
[1.0.0]: http://test.io
|
44
|
+
"
|
45
|
+
cl = MarkdownParser.parse(content)
|
46
|
+
expect(cl).to eq(
|
47
|
+
'versions' => {
|
48
|
+
'2.0.0' => {
|
49
|
+
'url' => nil,
|
50
|
+
'date' => '2017-01-01',
|
51
|
+
'changes' => { 'New' => ['Feature A'] }
|
52
|
+
},
|
53
|
+
'1.0.0' => {
|
54
|
+
'url' => 'http://test.io',
|
55
|
+
'date' => nil,
|
56
|
+
'changes' => { 'Fixed' => ['Feature B'] }
|
57
|
+
}
|
58
|
+
}
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should parse version without sections' do
|
63
|
+
content = "
|
64
|
+
## [3.0.0]
|
65
|
+
## [2.0.0] - 2017-01-01
|
66
|
+
### New
|
67
|
+
- Feature A
|
68
|
+
## [1.0.0]
|
69
|
+
"
|
70
|
+
cl = MarkdownParser.parse(content)
|
71
|
+
expect(cl).to eq(
|
72
|
+
'versions' => {
|
73
|
+
'3.0.0' => {
|
74
|
+
'url' => nil, 'date' => nil, 'changes' => {}
|
75
|
+
},
|
76
|
+
'2.0.0' => {
|
77
|
+
'url' => nil,
|
78
|
+
'date' => '2017-01-01',
|
79
|
+
'changes' => { 'New' => ['Feature A'] }
|
80
|
+
},
|
81
|
+
'1.0.0' => {
|
82
|
+
'url' => nil, 'date' => nil, 'changes' => {}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '.load' do
|
90
|
+
it 'should parse content of file' do
|
91
|
+
content = 'test changelog'
|
92
|
+
allow(File).to receive(:open).and_call_original
|
93
|
+
expect(File).to receive(:open).with('test.md')
|
94
|
+
.and_yield(StringIO.new(content))
|
95
|
+
expect(MarkdownParser).to receive(:parse).with(content)
|
96
|
+
MarkdownParser.load('test.md')
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should throw on non-existent file' do
|
100
|
+
expect do
|
101
|
+
MarkdownParser.load('invalid-file')
|
102
|
+
end.to raise_exception(
|
103
|
+
Errno::ENOENT,
|
104
|
+
'No such file or directory @ rb_sysopen - invalid-file'
|
105
|
+
)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Keepachangelog
|
4
|
+
describe YamlParser do
|
5
|
+
describe '.parse' do
|
6
|
+
it 'should parse empty content' do
|
7
|
+
cl = YamlParser.parse('')
|
8
|
+
expect(cl).to eq({})
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should parse single version' do
|
12
|
+
content = "
|
13
|
+
---
|
14
|
+
title: Feature A
|
15
|
+
type: New
|
16
|
+
"
|
17
|
+
cl = YamlParser.parse(content, '1.2.3')
|
18
|
+
expect(cl).to eq(
|
19
|
+
'versions' => {
|
20
|
+
'1.2.3' => {
|
21
|
+
'changes' => {
|
22
|
+
'New' => ['Feature A']
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '.load' do
|
31
|
+
it 'should parse content of folder' do
|
32
|
+
content = 'test changelog'
|
33
|
+
allow(File).to receive(:open).and_call_original
|
34
|
+
allow(File).to receive(:open).with('changelog/1.0.0/1.yml')
|
35
|
+
.and_yield(StringIO.new(content))
|
36
|
+
expect(Dir).to receive(:glob).with('changelog/*')
|
37
|
+
.and_return(['changelog/1.0.0'])
|
38
|
+
expect(Dir).to receive(:glob).with('changelog/1.0.0/**/*.yml')
|
39
|
+
.and_return(['changelog/1.0.0/1.yml'])
|
40
|
+
expect(Dir).to receive(:glob).with('changelog/1.0.0/**/*.yaml')
|
41
|
+
.and_return([])
|
42
|
+
|
43
|
+
expect_any_instance_of(YamlParser).to \
|
44
|
+
receive(:parse).with('test changelog', '1.0.0')
|
45
|
+
|
46
|
+
YamlParser.load
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/spec/parser_spec.rb
CHANGED
@@ -2,124 +2,6 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Keepachangelog
|
4
4
|
describe Parser do
|
5
|
-
describe '#parse' do
|
6
|
-
it 'should parse empty content' do
|
7
|
-
content = ''
|
8
|
-
p = Parser.new(content)
|
9
|
-
expect(p.parsed_content).to eq([])
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'should parse single version' do
|
13
|
-
content = "
|
14
|
-
## [1.2.3] - 2017-01-01
|
15
|
-
### New
|
16
|
-
- Feature A
|
17
|
-
### Fixed
|
18
|
-
- Feature B
|
19
|
-
[1.2.3]: http://test.io
|
20
|
-
"
|
21
|
-
p = Parser.new(content)
|
22
|
-
expect(p.parsed_content).to eq(
|
23
|
-
[
|
24
|
-
{
|
25
|
-
'version' => '1.2.3',
|
26
|
-
'url' => 'http://test.io',
|
27
|
-
'date' => '2017-01-01',
|
28
|
-
'changes' => {
|
29
|
-
'New' => ['Feature A'],
|
30
|
-
'Fixed' => ['Feature B']
|
31
|
-
}
|
32
|
-
}
|
33
|
-
]
|
34
|
-
)
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'should parse multiple versions' do
|
38
|
-
content = "
|
39
|
-
## [2.0.0] - 2017-01-01
|
40
|
-
### New
|
41
|
-
- Feature A
|
42
|
-
## [1.0.0]
|
43
|
-
### Fixed
|
44
|
-
- Feature B
|
45
|
-
[1.0.0]: http://test.io
|
46
|
-
"
|
47
|
-
p = Parser.new(content)
|
48
|
-
expect(p.parsed_content).to eq(
|
49
|
-
[
|
50
|
-
{
|
51
|
-
'version' => '2.0.0',
|
52
|
-
'url' => nil,
|
53
|
-
'date' => '2017-01-01',
|
54
|
-
'changes' => { 'New' => ['Feature A'] }
|
55
|
-
},
|
56
|
-
{
|
57
|
-
'version' => '1.0.0',
|
58
|
-
'url' => 'http://test.io',
|
59
|
-
'date' => nil,
|
60
|
-
'changes' => { 'Fixed' => ['Feature B'] }
|
61
|
-
}
|
62
|
-
]
|
63
|
-
)
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'should parse version without sections' do
|
67
|
-
content = "
|
68
|
-
## [3.0.0]
|
69
|
-
## [2.0.0] - 2017-01-01
|
70
|
-
### New
|
71
|
-
- Feature A
|
72
|
-
## [1.0.0]
|
73
|
-
"
|
74
|
-
p = Parser.new(content)
|
75
|
-
expect(p.parsed_content).to eq(
|
76
|
-
[
|
77
|
-
{
|
78
|
-
'version' => '3.0.0', 'url' => nil, 'date' => nil,
|
79
|
-
'changes' => {}
|
80
|
-
},
|
81
|
-
{
|
82
|
-
'version' => '2.0.0',
|
83
|
-
'url' => nil,
|
84
|
-
'date' => '2017-01-01',
|
85
|
-
'changes' => { 'New' => ['Feature A'] }
|
86
|
-
},
|
87
|
-
{
|
88
|
-
'version' => '1.0.0', 'url' => nil, 'date' => nil,
|
89
|
-
'changes' => {}
|
90
|
-
}
|
91
|
-
]
|
92
|
-
)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
describe '.load' do
|
97
|
-
it 'should parse content of file' do
|
98
|
-
content = 'test changelog'
|
99
|
-
allow(File).to receive(:open).and_call_original
|
100
|
-
expect(File).to receive(:open).with('test.md')
|
101
|
-
.and_yield(StringIO.new(content))
|
102
|
-
expect(Parser).to receive(:new).with(content)
|
103
|
-
Parser.load('test.md')
|
104
|
-
end
|
105
|
-
|
106
|
-
it 'should throw on non-existent file' do
|
107
|
-
expect do
|
108
|
-
Parser.load('invalid-file')
|
109
|
-
end.to raise_exception(
|
110
|
-
Errno::ENOENT,
|
111
|
-
'No such file or directory @ rb_sysopen - invalid-file'
|
112
|
-
)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
describe '.parse' do
|
117
|
-
it 'should call on .new' do
|
118
|
-
expect(Parser).to receive(:new).with('test')
|
119
|
-
Parser.parse('test')
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
5
|
describe '.to_json' do
|
124
6
|
it 'should cast parsed content into json' do
|
125
7
|
p = Parser.new
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: keepachangelog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Basalt AB
|
@@ -144,15 +144,22 @@ files:
|
|
144
144
|
- bin/setup
|
145
145
|
- exe/keepachangelog
|
146
146
|
- features/help.feature
|
147
|
-
- features/
|
147
|
+
- features/markdown.feature
|
148
148
|
- features/support/aruba.rb
|
149
149
|
- features/version.feature
|
150
|
+
- features/yaml.feature
|
150
151
|
- keepachangelog.gemspec
|
151
152
|
- lib/keepachangelog.rb
|
152
153
|
- lib/keepachangelog/cli.rb
|
154
|
+
- lib/keepachangelog/markdown_printer.rb
|
153
155
|
- lib/keepachangelog/parser.rb
|
156
|
+
- lib/keepachangelog/parser/markdown.rb
|
157
|
+
- lib/keepachangelog/parser/yaml.rb
|
154
158
|
- lib/keepachangelog/version.rb
|
155
159
|
- package.json
|
160
|
+
- spec/markdown_printer_spec.rb
|
161
|
+
- spec/parser/markdown_spec.rb
|
162
|
+
- spec/parser/yaml_spec.rb
|
156
163
|
- spec/parser_spec.rb
|
157
164
|
- spec/spec_helper.rb
|
158
165
|
- spec/version_spec.rb
|