devist 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/devist +155 -0
- data/lib/devist.rb +94 -0
- data/lib/devist/compiler.rb +50 -0
- data/lib/devist/export/html/_default.html.erb +277 -0
- data/lib/devist/export/html/_polar.html.erb +281 -0
- data/lib/devist/extractor.rb +26 -0
- data/lib/devist/models/project.rb +12 -0
- data/lib/devist/models/tags.rb +32 -0
- data/lib/devist/models/version.rb +25 -0
- data/lib/devist/parser.rb +101 -0
- metadata +55 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 56284ad08775f7a152ddc16b24b1f3250f87a4c1
|
4
|
+
data.tar.gz: 809589a83532dde27f85530ec0e81892efe8cae0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bf5cf1693998e7b3b00c53690872e00437478a5548ff2aa1d55df70ec9bed643bb7586fccb44c6cb07bf06c8907f99268be0f7237a583f9f87e3744237964b94
|
7
|
+
data.tar.gz: 61f38f87748e6530c838715817abd9757e37c1d87e7541d96eebd44739f3ab102529ce78f5dadb02572027345ba5e4a6d6a517736ec653fada95c52dd007e514
|
data/bin/devist
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'devist'
|
4
|
+
|
5
|
+
##############################################################
|
6
|
+
#
|
7
|
+
# bin/devist
|
8
|
+
#
|
9
|
+
# Main action point. Devist binary.
|
10
|
+
# stacklog/devist @ github
|
11
|
+
#
|
12
|
+
# Halis Duraki <duraki.halis@nsoft.ba>
|
13
|
+
#
|
14
|
+
##############################################################
|
15
|
+
|
16
|
+
# bin/devist.rb
|
17
|
+
# This file is a part of the devist package.
|
18
|
+
# Halis Duraki <duraki.halis@nsoft.ba>
|
19
|
+
#
|
20
|
+
# This is the main entry point of the Devist. It creates a
|
21
|
+
# binary and parse and execute actions based on given CLI
|
22
|
+
# arguments.
|
23
|
+
class DevistBinary
|
24
|
+
|
25
|
+
# Print banner image.
|
26
|
+
def print_logo
|
27
|
+
puts <<EOL
|
28
|
+
__ _ __
|
29
|
+
____/ /__ _ __(_)____/ /_
|
30
|
+
/ __ / _ \\ | / / / ___/ __/
|
31
|
+
/ /_/ / __/ |/ / (__ ) /_
|
32
|
+
\\__,_/\\___/|___/_/____/\\__/
|
33
|
+
- Release notes generator.
|
34
|
+
https://github.com/stacklog/devist
|
35
|
+
|
36
|
+
Use --help for details.
|
37
|
+
|
38
|
+
EOL
|
39
|
+
end
|
40
|
+
|
41
|
+
# Print help menu.
|
42
|
+
def print_help
|
43
|
+
puts <<EOL
|
44
|
+
Use devist to generate beautiful release notes. All you need to have is CHANGELOG.md with
|
45
|
+
.devist line at the end of the file.
|
46
|
+
|
47
|
+
$ devist | run devist
|
48
|
+
$ devist --help | usage / this menu
|
49
|
+
$ devist --v | show current version
|
50
|
+
$ devist --new | create changelog template
|
51
|
+
|
52
|
+
-
|
53
|
+
$ devist file_name theme_name
|
54
|
+
|
55
|
+
Example:
|
56
|
+
$ devist changelog
|
57
|
+
$ devist changelog polar
|
58
|
+
EOL
|
59
|
+
end
|
60
|
+
|
61
|
+
# Entry point. Main.
|
62
|
+
def ep (arguments)
|
63
|
+
@arguments = arguments
|
64
|
+
|
65
|
+
print_logo
|
66
|
+
|
67
|
+
# Recieved filename + theme as args
|
68
|
+
if @arguments.count.equal?(2)
|
69
|
+
return theme
|
70
|
+
end
|
71
|
+
|
72
|
+
# Check other arguments
|
73
|
+
case @arguments[0]
|
74
|
+
when '--help'
|
75
|
+
print_help
|
76
|
+
when '--v'
|
77
|
+
version
|
78
|
+
when '--new'
|
79
|
+
create # Create new changelog (fresh project)
|
80
|
+
else
|
81
|
+
default # Try to export with filename and default theme
|
82
|
+
return
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Generate with default theme.
|
87
|
+
def default
|
88
|
+
file_name = @arguments[0]
|
89
|
+
|
90
|
+
unless file_name.nil?
|
91
|
+
decompile(file_name)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Generate by specifying theme.
|
96
|
+
def theme
|
97
|
+
file_name = @arguments[0]
|
98
|
+
theme_name = @arguments[1]
|
99
|
+
|
100
|
+
unless file_name.nil?
|
101
|
+
decompile(file_name, theme_name)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Display devist version.
|
106
|
+
def version
|
107
|
+
v = `git rev-parse HEAD`
|
108
|
+
d = `git log -1 --format=%cd`
|
109
|
+
print " * devist version: #{v[0, 7]} - #{d[0, 10]}\n"
|
110
|
+
end
|
111
|
+
|
112
|
+
# Create new changelog.
|
113
|
+
def create
|
114
|
+
print " * Generating CHANGELOG.md ...\n"
|
115
|
+
|
116
|
+
if File.file?(Dir.pwd + '/CHANGELOG.md')
|
117
|
+
print " * File CHANGELOG.md already exists. Backup it, remove, and try again.\n"
|
118
|
+
print " * You may try to run 'devist changelog' to try generate the export.\n"
|
119
|
+
abort
|
120
|
+
end
|
121
|
+
|
122
|
+
new = File.new(Dir.pwd + '/CHANGELOG.md', 'w')
|
123
|
+
print " * Output .devist as a way of thinkering ...\n"
|
124
|
+
thinkering(new)
|
125
|
+
print " -\n"
|
126
|
+
print " ** All done! Continue editing CHANGELOG.md.\n"
|
127
|
+
end
|
128
|
+
|
129
|
+
# Fill new changelog.
|
130
|
+
def thinkering(new)
|
131
|
+
new.puts('@project: MyProject ')
|
132
|
+
new.puts('@author: Your Name <email@address.com> ')
|
133
|
+
new.puts('@homepage: https://example.com ')
|
134
|
+
new.puts('')
|
135
|
+
new.puts("### Version 1.0.0 of #{Time.now.strftime("%d %b %Y")}")
|
136
|
+
new.puts('+ #added: something goes here')
|
137
|
+
new.puts('')
|
138
|
+
new.puts('.devist')
|
139
|
+
new.close
|
140
|
+
end
|
141
|
+
|
142
|
+
# Decompile ep.
|
143
|
+
def decompile(file_name, theme_name = 'default')
|
144
|
+
print " * devist will try to generate export for file '#{file_name}' with theme '#{theme_name}'\n"
|
145
|
+
|
146
|
+
@devist = Devist.new(file_name, theme_name)
|
147
|
+
@devist.decompile
|
148
|
+
@devist.recompile
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
# Create new bin/ep with argv
|
154
|
+
devistbin = DevistBinary.new
|
155
|
+
devistbin.ep(ARGV)
|
data/lib/devist.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# devist.rb
|
2
|
+
# This file is a part of the devist package.
|
3
|
+
# Halis Duraki <duraki.halis@nsoft.ba>
|
4
|
+
#
|
5
|
+
# This is the place where the ep action is being taken.
|
6
|
+
# Devist check if setup is ok and proceed with parsing
|
7
|
+
# and creating the static export.
|
8
|
+
class Devist
|
9
|
+
|
10
|
+
#
|
11
|
+
# @project: stacklog/devist
|
12
|
+
# @author: Halis Duraki <duraki.halis@nsoft.ba>
|
13
|
+
# @homepage: https://github.com/stacklog/devist
|
14
|
+
#
|
15
|
+
|
16
|
+
attr_reader :parser, :compiler
|
17
|
+
|
18
|
+
# Default files to look for
|
19
|
+
@@default_search = %w[CHANGELOG RELEASES NEWS]
|
20
|
+
|
21
|
+
# Init
|
22
|
+
def initialize(filename, theme = 'default')
|
23
|
+
|
24
|
+
@parser = Parser.new
|
25
|
+
@filename = filename + ".md"
|
26
|
+
@themename = "_" + theme + ".html.erb"
|
27
|
+
|
28
|
+
# Theme directory is absolute dirpath + subs
|
29
|
+
theme_dir = __dir__ + "/devist/export/html/"
|
30
|
+
|
31
|
+
# Check if both theme and filename exists
|
32
|
+
if File.file?(@filename)
|
33
|
+
print " * File '#{@filename}' exists; continuing ...\n"
|
34
|
+
else
|
35
|
+
print " * File '#{@filename}' does NOT exists; exit ...\n"
|
36
|
+
print " > Do you want to allow devist to search the file for you? (y\/N) "
|
37
|
+
devist_as = STDIN.gets.chomp
|
38
|
+
|
39
|
+
# Search for changelogs automatically
|
40
|
+
if devist_as.downcase.eql?("y")
|
41
|
+
print " * Searching for changelog data ...\n"
|
42
|
+
available
|
43
|
+
|
44
|
+
if @@available.count > 0
|
45
|
+
print " * Try to run with filename #{@@available_list}\n"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
|
52
|
+
if File.file?(theme_dir + @themename)
|
53
|
+
print " * Theme '#{@themename}' exists; continuing ...\n"
|
54
|
+
else
|
55
|
+
print " * Theme '#{@themename}' does NOT exists; exit ...\n"
|
56
|
+
exit
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
# Auto-search for available changelog
|
62
|
+
def available
|
63
|
+
@@available = []
|
64
|
+
@@available_list = String.new
|
65
|
+
|
66
|
+
@@default_search.each do |filename|
|
67
|
+
filename.concat(".md")
|
68
|
+
if File.file?(filename)
|
69
|
+
@@available_list.concat(filename + " ")
|
70
|
+
@@available.push(filename)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
print " * Found #{@@available.count} results.\n"
|
75
|
+
|
76
|
+
@@available.count
|
77
|
+
end
|
78
|
+
|
79
|
+
# Decompile .md file.
|
80
|
+
def decompile
|
81
|
+
@parser.parse_data(@filename)
|
82
|
+
@parser.project
|
83
|
+
end
|
84
|
+
|
85
|
+
# Recompile .md file.
|
86
|
+
def recompile
|
87
|
+
@compiler = Compiler.new(@parser.project, @parser.changelog, @themename)
|
88
|
+
@compiler.compile_data
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
require 'devist/parser'
|
94
|
+
require 'devist/compiler'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
# compiler.rb
|
4
|
+
# This file is a part of the devist package.
|
5
|
+
# Halis Duraki <duraki.halis@nsoft.ba>
|
6
|
+
#
|
7
|
+
# This is the main compiler class. It takes arguments
|
8
|
+
# project (model), changelog (model), and theme name.
|
9
|
+
# Object offers a version listing plus save operation
|
10
|
+
# and binding to the theme erb.
|
11
|
+
class Devist::Compiler
|
12
|
+
|
13
|
+
# Init.
|
14
|
+
def initialize(project, changelog, theme)
|
15
|
+
@project = project
|
16
|
+
@changelog = changelog
|
17
|
+
@theme = theme
|
18
|
+
end
|
19
|
+
|
20
|
+
# Save compiled.
|
21
|
+
def save
|
22
|
+
print " -\n"
|
23
|
+
print " * Trying to compile set ...\n"
|
24
|
+
|
25
|
+
print " * Creating new export from erb ...\n"
|
26
|
+
asset = "#{__dir__}/export/html/#{@theme}"
|
27
|
+
erb = ERB.new(File.open(asset).read, 0, '>')
|
28
|
+
|
29
|
+
print " * Injecting parsed results to the erb ...\n"
|
30
|
+
erb.result binding
|
31
|
+
|
32
|
+
print " * Writing compiled data to changelog file ...\n"
|
33
|
+
File.open("#{Dir.pwd}/changelog.html", 'w') do |f|
|
34
|
+
f.write erb.result binding
|
35
|
+
end
|
36
|
+
|
37
|
+
print " -\n"
|
38
|
+
print " ** All done! Check changelog.html file in your browser :)\n"
|
39
|
+
end
|
40
|
+
|
41
|
+
# Compile data.
|
42
|
+
def compile_data
|
43
|
+
@changelog.each do |version|
|
44
|
+
print " * Found version #{version.version}; registered ...\n"
|
45
|
+
end
|
46
|
+
|
47
|
+
save
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,277 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
|
4
|
+
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
5
|
+
<meta content="<%= @project.author %>/<%= @project.name %>" name="description" />
|
6
|
+
<meta content="width=device-width, initial-scale=1, user-scalable=no" name="viewport" />
|
7
|
+
|
8
|
+
<!-- Stylesheets -->
|
9
|
+
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/6.0.0/normalize.min.css' rel="stylesheet" type="text/css" />
|
10
|
+
<link href='https://fonts.googleapis.com/css?family=Abel|Roboto:400|Roboto+Condensed:400|Roboto+Mono:400' rel='stylesheet' type='text/css'>
|
11
|
+
|
12
|
+
<!-- Title -->
|
13
|
+
<title><%= @project.author.gsub(/\<.*?>/,"").chomp.strip! + '/' + @project.name %> - devist notes</title>
|
14
|
+
|
15
|
+
<body>
|
16
|
+
<header><h2>Release Notes - <%= @project.name %></h2></header>
|
17
|
+
<nav class="side-nav">
|
18
|
+
<ul style="background: none; color: #555; padding: 0; margin: 0;">
|
19
|
+
<li><a class="side-nav-item" href="<%= @project.homepage %>"><%= @project.author.gsub(/\<.*?\>/,"").chomp.strip! + '/' + @project.name %></a> </li>
|
20
|
+
<li><a style="font-size:12px;" class="side-nav-item " href="https://github.com/stacklog/devist">Created with devist</a></li>
|
21
|
+
</ul>
|
22
|
+
</nav>
|
23
|
+
|
24
|
+
<section class="container">
|
25
|
+
|
26
|
+
<% @changelog.each do |version| %>
|
27
|
+
|
28
|
+
<div id="<%= version.version %>">
|
29
|
+
<a href="#<%= version.version %>"><h3>Version <%= version.version %></h3></a>
|
30
|
+
<p><%= version.date.to_s %></p>
|
31
|
+
|
32
|
+
<ul>
|
33
|
+
|
34
|
+
<% version.tags.get[0].each do |added| %>
|
35
|
+
<li><span class="label label--add">added</span> <%= added.chomp %></li>
|
36
|
+
<% end %>
|
37
|
+
|
38
|
+
<% version.tags.get[1].each do |fixed| %>
|
39
|
+
<li><span class="label label--fixed">fixed</span> <%= fixed.chomp %></li>
|
40
|
+
<% end %>
|
41
|
+
|
42
|
+
<% version.tags.get[2].each do |removed| %>
|
43
|
+
<li><span class="label label--removed">removed</span> <%= removed.chomp %></li>
|
44
|
+
<% end %>
|
45
|
+
|
46
|
+
<% version.tags.get[3].each do |improved| %>
|
47
|
+
<li><span class="label label--improve">improved</span> <%= improved.chomp %></li>
|
48
|
+
<% end %>
|
49
|
+
|
50
|
+
</ul>
|
51
|
+
</div>
|
52
|
+
|
53
|
+
|
54
|
+
<% end %>
|
55
|
+
|
56
|
+
</section>
|
57
|
+
|
58
|
+
|
59
|
+
</body>
|
60
|
+
|
61
|
+
<!-- Custom style -->
|
62
|
+
<style>
|
63
|
+
|
64
|
+
:root {
|
65
|
+
background: #292929;
|
66
|
+
color: #bbb;
|
67
|
+
}
|
68
|
+
|
69
|
+
.label {
|
70
|
+
background: rgba(41, 41, 41, 0.27);
|
71
|
+
padding: 3px;
|
72
|
+
border-radius: 5px;
|
73
|
+
}
|
74
|
+
|
75
|
+
code {
|
76
|
+
border-color: rgba(255,255,255,0);;
|
77
|
+
}
|
78
|
+
|
79
|
+
h2 {
|
80
|
+
color: #555;
|
81
|
+
}
|
82
|
+
|
83
|
+
header {
|
84
|
+
padding-top: 4.5rem;
|
85
|
+
}
|
86
|
+
|
87
|
+
kbd {
|
88
|
+
background: rgba(255,255,255,.1);
|
89
|
+
border-color: rgba(0,0,0,.35);;
|
90
|
+
}
|
91
|
+
|
92
|
+
nav {
|
93
|
+
position: fixed;
|
94
|
+
left: 1.8rem;
|
95
|
+
top: 1.8rem;
|
96
|
+
}
|
97
|
+
|
98
|
+
section.container {
|
99
|
+
margin-bottom: 7.2rem;
|
100
|
+
max-width: 30rem;
|
101
|
+
}
|
102
|
+
|
103
|
+
section.container li {
|
104
|
+
text-align: left;
|
105
|
+
text-transform: capitalize;
|
106
|
+
}
|
107
|
+
|
108
|
+
section.container ul {
|
109
|
+
background: rgba(255,255,255,.05);
|
110
|
+
border-radius: .225rem;
|
111
|
+
margin: .9rem 0 2.7rem;
|
112
|
+
padding: 1rem 1.5rem;
|
113
|
+
}
|
114
|
+
|
115
|
+
.side-nav-item.current:after {
|
116
|
+
content: ' -';
|
117
|
+
}
|
118
|
+
|
119
|
+
nav {
|
120
|
+
font-family: "Roboto Condensed", sans-serif;
|
121
|
+
font-size: 1.2rem;
|
122
|
+
text-align: left;
|
123
|
+
}
|
124
|
+
|
125
|
+
.label--add {
|
126
|
+
color: #da139a;
|
127
|
+
text-transform: capitalize;
|
128
|
+
}
|
129
|
+
|
130
|
+
.label--improve {
|
131
|
+
color: #79b;
|
132
|
+
text-transform: capitalize;
|
133
|
+
}
|
134
|
+
|
135
|
+
.label--removed {
|
136
|
+
color: #9e6565;
|
137
|
+
text-transform: capitalize;
|
138
|
+
}
|
139
|
+
|
140
|
+
.label--fixed {
|
141
|
+
color: #7b9;
|
142
|
+
text-transform: capitalize;
|
143
|
+
}
|
144
|
+
|
145
|
+
p {
|
146
|
+
color: #555;
|
147
|
+
}
|
148
|
+
|
149
|
+
/* grid
|
150
|
+
------------------------------ */
|
151
|
+
|
152
|
+
.container {
|
153
|
+
margin: 0 auto;
|
154
|
+
max-width: 60rem;
|
155
|
+
position: relative;
|
156
|
+
width: 100%;
|
157
|
+
}
|
158
|
+
|
159
|
+
.row {
|
160
|
+
display: flex;
|
161
|
+
flex-direction: row;
|
162
|
+
margin: 0 -1.0rem;
|
163
|
+
}
|
164
|
+
|
165
|
+
.row .column {
|
166
|
+
margin-bottom: 2.7rem;
|
167
|
+
padding: 0 1.0rem;
|
168
|
+
width: 100%;
|
169
|
+
}
|
170
|
+
|
171
|
+
:root {
|
172
|
+
font-family: 'Roboto', sans-serif;
|
173
|
+
font-size: 15px;
|
174
|
+
height: 100%;
|
175
|
+
text-align: center;
|
176
|
+
}
|
177
|
+
|
178
|
+
::selection,
|
179
|
+
::-moz-selection {
|
180
|
+
background: rgba(0,0,0,.1);
|
181
|
+
}
|
182
|
+
|
183
|
+
a {
|
184
|
+
color: inherit;
|
185
|
+
text-decoration: none;
|
186
|
+
}
|
187
|
+
|
188
|
+
body {
|
189
|
+
line-height: 1.8rem;
|
190
|
+
height: 100%;
|
191
|
+
width: 100%;
|
192
|
+
}
|
193
|
+
|
194
|
+
code {
|
195
|
+
border: 1px solid #fff;
|
196
|
+
border-bottom: 2px solid #fff;
|
197
|
+
border-radius: 3px;
|
198
|
+
color: #ba9;
|
199
|
+
font-family: "Roboto Mono", monospace;
|
200
|
+
font-size: .85rem;
|
201
|
+
line-height: 0;
|
202
|
+
padding: .2rem .3rem .1rem;
|
203
|
+
white-space: nowrap;
|
204
|
+
}
|
205
|
+
|
206
|
+
h1, h2, h3 {
|
207
|
+
line-height: inherit;
|
208
|
+
font-size: inherit;
|
209
|
+
font-weight: normal;
|
210
|
+
margin: 0;
|
211
|
+
}
|
212
|
+
|
213
|
+
h1 {
|
214
|
+
font-family: "Abel", sans-serif;
|
215
|
+
}
|
216
|
+
|
217
|
+
h2 {
|
218
|
+
font-family: "Abel", sans-serif;
|
219
|
+
font-size: 1.8rem;
|
220
|
+
font-weight: 300;
|
221
|
+
margin-bottom: 4.5rem;
|
222
|
+
}
|
223
|
+
|
224
|
+
h3 {
|
225
|
+
font-family: "Roboto Condensed", sans-serif;
|
226
|
+
font-size: 1.2rem;
|
227
|
+
}
|
228
|
+
|
229
|
+
hr {
|
230
|
+
border: none;
|
231
|
+
border-bottom: 1px solid #444;
|
232
|
+
}
|
233
|
+
|
234
|
+
kbd {
|
235
|
+
background: #fff;
|
236
|
+
border: 1px solid #ddd;
|
237
|
+
border-bottom: 2px solid #ddd;
|
238
|
+
border-radius: 3px;
|
239
|
+
font-family: "Roboto Mono", monospace;
|
240
|
+
font-size: .85rem;
|
241
|
+
line-height: 0;
|
242
|
+
padding: .2rem .3rem .1rem;
|
243
|
+
text-transform: capitalize;
|
244
|
+
white-space: nowrap;
|
245
|
+
}
|
246
|
+
|
247
|
+
p {
|
248
|
+
margin: 0;
|
249
|
+
}
|
250
|
+
|
251
|
+
p a {
|
252
|
+
text-decoration: underline;
|
253
|
+
}
|
254
|
+
|
255
|
+
ul {
|
256
|
+
list-style: none;
|
257
|
+
margin: 0;
|
258
|
+
padding: 0;
|
259
|
+
}
|
260
|
+
|
261
|
+
/* navigation
|
262
|
+
------------------------------ */
|
263
|
+
|
264
|
+
.nav-item {
|
265
|
+
display: inline-block;
|
266
|
+
}
|
267
|
+
|
268
|
+
.nav-item:before {
|
269
|
+
content: '\00a0 | \00a0';
|
270
|
+
}
|
271
|
+
|
272
|
+
.nav-item:first-child:before {
|
273
|
+
content: '';
|
274
|
+
}
|
275
|
+
|
276
|
+
</style>
|
277
|
+
</html>
|
@@ -0,0 +1,281 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
|
4
|
+
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
5
|
+
<meta content="<%= @project.author.delete(' ') %>/<%= @project.name %>" name="description" />
|
6
|
+
<meta content="width=device-width, initial-scale=1, user-scalable=no" name="viewport" />
|
7
|
+
|
8
|
+
<!-- Stylesheets -->
|
9
|
+
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/6.0.0/normalize.min.css' rel="stylesheet" type="text/css" />
|
10
|
+
<link href='https://fonts.googleapis.com/css?family=Abel|Roboto:400|Roboto+Condensed:400|Roboto+Mono:400' rel='stylesheet' type='text/css'>
|
11
|
+
|
12
|
+
<!-- Title -->
|
13
|
+
<title><%= @project.author.gsub(/\<.*?>/,"").chomp.strip! + '/' + @project.name %> - devist notes</title>
|
14
|
+
|
15
|
+
<body>
|
16
|
+
<header><h2>Release Notes - <%= @project.name %></h2></header>
|
17
|
+
<nav class="side-nav">
|
18
|
+
<ul style="background: none; color: #555; padding: 0; margin: 0;">
|
19
|
+
<li><a class="side-nav-item" href="<%= @project.homepage %>"><%= @project.author.gsub(/\<.*?\>/,"").chomp.strip! + '/' + @project.name %></a> </li>
|
20
|
+
<li><a style="font-size:12px;" class="side-nav-item " href="https://github.com/stacklog/devist">Created with devist</a></li>
|
21
|
+
</ul>
|
22
|
+
</nav>
|
23
|
+
|
24
|
+
<section class="container">
|
25
|
+
|
26
|
+
<% @changelog.each do |version| %>
|
27
|
+
|
28
|
+
<div id="<%= version.version %>">
|
29
|
+
<a href="#<%= version.version %>"><h3>Version <%= version.version %></h3></a>
|
30
|
+
<p><%= version.date.to_s %></p>
|
31
|
+
|
32
|
+
<ul>
|
33
|
+
|
34
|
+
<% version.tags.get[0].each do |added| %>
|
35
|
+
<li><span class="label label--add">added</span> <%= added.chomp %></li>
|
36
|
+
<% end %>
|
37
|
+
|
38
|
+
<% version.tags.get[1].each do |fixed| %>
|
39
|
+
<li><span class="label label--fixed">fixed</span> <%= fixed.chomp %></li>
|
40
|
+
<% end %>
|
41
|
+
|
42
|
+
<% version.tags.get[2].each do |removed| %>
|
43
|
+
<li><span class="label label--removed">removed</span> <%= removed.chomp %></li>
|
44
|
+
<% end %>
|
45
|
+
|
46
|
+
<% version.tags.get[3].each do |improved| %>
|
47
|
+
<li><span class="label label--improve">improved</span> <%= improved.chomp %></li>
|
48
|
+
<% end %>
|
49
|
+
|
50
|
+
</ul>
|
51
|
+
</div>
|
52
|
+
|
53
|
+
<% end %>
|
54
|
+
|
55
|
+
</section>
|
56
|
+
|
57
|
+
|
58
|
+
</body>
|
59
|
+
|
60
|
+
<!-- Custom style -->
|
61
|
+
<style>
|
62
|
+
|
63
|
+
:root {
|
64
|
+
background: #ffefef;
|
65
|
+
color: #777575;
|
66
|
+
}
|
67
|
+
|
68
|
+
.label {
|
69
|
+
background: rgba(41, 41, 41, 0.81);
|
70
|
+
padding: 3px;
|
71
|
+
border-radius: 5px;
|
72
|
+
}
|
73
|
+
|
74
|
+
code {
|
75
|
+
border-color: rgba(255,255,255,0);;
|
76
|
+
}
|
77
|
+
|
78
|
+
h2 {
|
79
|
+
color: #635b5b;
|
80
|
+
}
|
81
|
+
|
82
|
+
header {
|
83
|
+
padding-top: 4.5rem;
|
84
|
+
}
|
85
|
+
|
86
|
+
kbd {
|
87
|
+
background: rgba(255,255,255,.1);
|
88
|
+
border-color: rgba(0,0,0,.35);;
|
89
|
+
}
|
90
|
+
|
91
|
+
nav {
|
92
|
+
position: fixed;
|
93
|
+
left: 1.8rem;
|
94
|
+
top: 1.8rem;
|
95
|
+
}
|
96
|
+
|
97
|
+
section.container {
|
98
|
+
margin-bottom: 7.2rem;
|
99
|
+
max-width: 30rem;
|
100
|
+
}
|
101
|
+
|
102
|
+
section.container li {
|
103
|
+
text-align: left;
|
104
|
+
text-transform: capitalize;
|
105
|
+
}
|
106
|
+
|
107
|
+
section.container ul {
|
108
|
+
background: rgba(230, 230, 230, 0.48);
|
109
|
+
border-radius: .225rem;
|
110
|
+
margin: .9rem 0 2.7rem;
|
111
|
+
padding: 1rem 1.5rem;
|
112
|
+
}
|
113
|
+
|
114
|
+
.side-nav-item.current:after {
|
115
|
+
content: ' -';
|
116
|
+
}
|
117
|
+
|
118
|
+
nav {
|
119
|
+
font-family: "Roboto Condensed", sans-serif;
|
120
|
+
font-size: 1.2rem;
|
121
|
+
text-align: left;
|
122
|
+
}
|
123
|
+
|
124
|
+
.label--add {
|
125
|
+
color: #cfd0c5;
|
126
|
+
text-transform: capitalize;
|
127
|
+
}
|
128
|
+
|
129
|
+
.label--improve {
|
130
|
+
color: #79b;
|
131
|
+
text-transform: capitalize;
|
132
|
+
}
|
133
|
+
|
134
|
+
.label--removed {
|
135
|
+
color: #e46f6f;
|
136
|
+
text-transform: capitalize;
|
137
|
+
}
|
138
|
+
|
139
|
+
.label--fixed {
|
140
|
+
color: #7b9;
|
141
|
+
text-transform: capitalize;
|
142
|
+
}
|
143
|
+
|
144
|
+
p {
|
145
|
+
color: #555;
|
146
|
+
}
|
147
|
+
|
148
|
+
/* grid
|
149
|
+
------------------------------ */
|
150
|
+
|
151
|
+
.container {
|
152
|
+
margin: 0 auto;
|
153
|
+
max-width: 60rem;
|
154
|
+
position: relative;
|
155
|
+
width: 100%;
|
156
|
+
}
|
157
|
+
|
158
|
+
.row {
|
159
|
+
display: flex;
|
160
|
+
flex-direction: row;
|
161
|
+
margin: 0 -1.0rem;
|
162
|
+
}
|
163
|
+
|
164
|
+
.row .column {
|
165
|
+
margin-bottom: 2.7rem;
|
166
|
+
padding: 0 1.0rem;
|
167
|
+
width: 100%;
|
168
|
+
}
|
169
|
+
|
170
|
+
:root {
|
171
|
+
font-family: 'Roboto', sans-serif;
|
172
|
+
font-size: 15px;
|
173
|
+
height: 100%;
|
174
|
+
text-align: center;
|
175
|
+
}
|
176
|
+
|
177
|
+
::selection,
|
178
|
+
::-moz-selection {
|
179
|
+
background: rgba(0,0,0,.1);
|
180
|
+
}
|
181
|
+
|
182
|
+
a {
|
183
|
+
color: inherit;
|
184
|
+
text-decoration: none;
|
185
|
+
}
|
186
|
+
|
187
|
+
body {
|
188
|
+
line-height: 1.8rem;
|
189
|
+
height: 100%;
|
190
|
+
width: 100%;
|
191
|
+
}
|
192
|
+
|
193
|
+
code {
|
194
|
+
border: 1px solid #fff;
|
195
|
+
border-bottom: 2px solid #fff;
|
196
|
+
border-radius: 3px;
|
197
|
+
color: #ba9;
|
198
|
+
font-family: "Roboto Mono", monospace;
|
199
|
+
font-size: .85rem;
|
200
|
+
line-height: 0;
|
201
|
+
padding: .2rem .3rem .1rem;
|
202
|
+
white-space: nowrap;
|
203
|
+
}
|
204
|
+
|
205
|
+
h1, h2, h3 {
|
206
|
+
line-height: inherit;
|
207
|
+
font-size: inherit;
|
208
|
+
font-weight: normal;
|
209
|
+
margin: 0;
|
210
|
+
}
|
211
|
+
|
212
|
+
h1 {
|
213
|
+
font-family: "Abel", sans-serif;
|
214
|
+
}
|
215
|
+
|
216
|
+
h2 {
|
217
|
+
font-family: "Abel", sans-serif;
|
218
|
+
font-size: 1.8rem;
|
219
|
+
font-weight: 300;
|
220
|
+
margin-bottom: 4.5rem;
|
221
|
+
}
|
222
|
+
|
223
|
+
h3 {
|
224
|
+
color: black;
|
225
|
+
font-family: "Roboto Condensed", sans-serif;
|
226
|
+
font-size: 1.2rem;
|
227
|
+
}
|
228
|
+
|
229
|
+
hr {
|
230
|
+
border: none;
|
231
|
+
border-bottom: 1px solid #444;
|
232
|
+
}
|
233
|
+
|
234
|
+
kbd {
|
235
|
+
background: #fff;
|
236
|
+
border: 1px solid #ddd;
|
237
|
+
border-bottom: 2px solid #ddd;
|
238
|
+
border-radius: 3px;
|
239
|
+
font-family: "Roboto Mono", monospace;
|
240
|
+
font-size: .85rem;
|
241
|
+
line-height: 0;
|
242
|
+
padding: .2rem .3rem .1rem;
|
243
|
+
text-transform: capitalize;
|
244
|
+
white-space: nowrap;
|
245
|
+
}
|
246
|
+
|
247
|
+
p {
|
248
|
+
margin: 0;
|
249
|
+
}
|
250
|
+
|
251
|
+
p a {
|
252
|
+
text-decoration: underline;
|
253
|
+
}
|
254
|
+
|
255
|
+
ul {
|
256
|
+
list-style: none;
|
257
|
+
margin: 0;
|
258
|
+
padding: 0;
|
259
|
+
}
|
260
|
+
|
261
|
+
il {
|
262
|
+
color: #644190;
|
263
|
+
}
|
264
|
+
|
265
|
+
/* navigation
|
266
|
+
------------------------------ */
|
267
|
+
|
268
|
+
.nav-item {
|
269
|
+
display: inline-block;
|
270
|
+
}
|
271
|
+
|
272
|
+
.nav-item:before {
|
273
|
+
content: '\00a0 | \00a0';
|
274
|
+
}
|
275
|
+
|
276
|
+
.nav-item:first-child:before {
|
277
|
+
content: '';
|
278
|
+
}
|
279
|
+
|
280
|
+
</style>
|
281
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# extractor.rb
|
2
|
+
# This file is a part of the devist package.
|
3
|
+
# Halis Duraki <duraki.halis@nsoft.ba>
|
4
|
+
#
|
5
|
+
# The extractor class extracts all necessary elements
|
6
|
+
# from the line, or changelog revision. All methods
|
7
|
+
# shall be static.
|
8
|
+
class Devist::Extractor
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def extract_version(line)
|
13
|
+
line[/n (.*) of/, 1]
|
14
|
+
end
|
15
|
+
|
16
|
+
def extract_change(line)
|
17
|
+
line.split(': ')[-1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def extract_info(line)
|
21
|
+
line.split(': ')[-1]
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# project.rb
|
2
|
+
# This file is a part of the devist package.
|
3
|
+
# Halis Duraki <duraki.halis@nsoft.ba>
|
4
|
+
#
|
5
|
+
# Create a project instance model. This allows us to reuse
|
6
|
+
# project name, author and homepage whenever we want. The
|
7
|
+
# object is not necessary to be created.
|
8
|
+
class Devist::Project
|
9
|
+
|
10
|
+
attr_accessor :name, :author, :homepage
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# tags.rb:Marray
|
2
|
+
#
|
3
|
+
# This is the helper class that allows us to
|
4
|
+
# recreate a multidimensional array.
|
5
|
+
class Marray < Array
|
6
|
+
def [](i)
|
7
|
+
super.nil? ? self[i] = Marray.new : super
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# tags.rb
|
12
|
+
# This file is a part of the devist package.
|
13
|
+
# Halis Duraki <duraki.halis@nsoft.ba>
|
14
|
+
#
|
15
|
+
# Model class `tags` is dynamic object that have parent
|
16
|
+
# `version` and is made of version tag info.
|
17
|
+
class Devist::Tag
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@list = %w[added fixed removed improved]
|
21
|
+
@change = Marray.new(@list.count)
|
22
|
+
end
|
23
|
+
|
24
|
+
def add (type, change)
|
25
|
+
@change[@list.index(type)][@change[@list.index(type)].count] = change
|
26
|
+
end
|
27
|
+
|
28
|
+
def get
|
29
|
+
@change
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# version.rb
|
2
|
+
# This file is a part of the devist package.
|
3
|
+
# Halis Duraki <duraki.halis@nsoft.ba>
|
4
|
+
#
|
5
|
+
# Model class `version` is dynamic object that creates a
|
6
|
+
# new changelog version instance with appropriate tag(s)
|
7
|
+
# data.
|
8
|
+
class Devist::Version
|
9
|
+
|
10
|
+
attr_accessor :version, :date, :tags
|
11
|
+
|
12
|
+
def initialize(version, date)
|
13
|
+
@version = version
|
14
|
+
@date = date
|
15
|
+
@tags = Devist::Tag.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# Create a new tag.
|
19
|
+
def tag (type, change)
|
20
|
+
@tags.add(type, change)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'devist/models/tags'
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
# parser.rb
|
4
|
+
# This file is a part of the devist package.
|
5
|
+
# Halis Duraki <duraki.halis@nsoft.ba>
|
6
|
+
#
|
7
|
+
# Parser will allow a building routine for the given
|
8
|
+
# changelog by investigating every line in the file.
|
9
|
+
# The Parser created project info, and build changelog,
|
10
|
+
# but it also check if the given file is proper devist
|
11
|
+
# format.
|
12
|
+
class Devist::Parser
|
13
|
+
|
14
|
+
attr_reader :project, :changelog
|
15
|
+
|
16
|
+
# Project builder.
|
17
|
+
def build_info(line)
|
18
|
+
case line
|
19
|
+
when /@project:+/
|
20
|
+
@project.name = Devist::Extractor.extract_info(line)
|
21
|
+
print " * Extracting project name ... [#{@project.name.chomp.strip!}]\n"
|
22
|
+
when /@author:.+/
|
23
|
+
@project.author = Devist::Extractor.extract_info(line)
|
24
|
+
print " * Extracting project author ... [#{@project.author.chomp.strip!}]\n"
|
25
|
+
when /@homepage:.+/
|
26
|
+
@project.homepage = Devist::Extractor.extract_info(line)
|
27
|
+
print " * Extracting project homepage ... [#{@project.homepage.chomp.strip!}]\n"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Changelog builder.
|
32
|
+
def build_changelog(line)
|
33
|
+
build_version(line)
|
34
|
+
build_tags(line)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Build tags.
|
38
|
+
def build_tags(line)
|
39
|
+
case line
|
40
|
+
when /#added.+/
|
41
|
+
@changelog[@version].tag 'added', Devist::Extractor.extract_change(line)
|
42
|
+
when /#fixed.+/
|
43
|
+
@changelog[@version].tag 'fixed', Devist::Extractor.extract_change(line)
|
44
|
+
when /#removed.+/
|
45
|
+
@changelog[@version].tag 'removed', Devist::Extractor.extract_change(line)
|
46
|
+
when /#improved.+/
|
47
|
+
@changelog[@version].tag 'improved', Devist::Extractor.extract_change(line)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Build version.
|
52
|
+
def build_version(line)
|
53
|
+
case line
|
54
|
+
when /### Version+/
|
55
|
+
@date = Date.parse(line) # Extract version date
|
56
|
+
@version += 1 # Increment version
|
57
|
+
@changelog[@version] = Devist::Version.new (Devist::Extractor.extract_version line), @date
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Is file devist configured.
|
62
|
+
def devist?(file_name)
|
63
|
+
is_devist = File.open(file_name).to_a
|
64
|
+
|
65
|
+
if is_devist.last.equal?("")
|
66
|
+
is_devist.pop is_devist.last
|
67
|
+
end
|
68
|
+
|
69
|
+
print " * Checking if changelog is devist configured ...\n"
|
70
|
+
if is_devist.last.chomp != '.devist'
|
71
|
+
print " * The file is not configured for devist. Are you missing .devist at the end of the file?\n"
|
72
|
+
print " * Skipping ...\n"
|
73
|
+
end
|
74
|
+
|
75
|
+
print " * Found .devist signature.\n"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Line parser.
|
79
|
+
def parse_data(file_name)
|
80
|
+
@project = Devist::Project.new
|
81
|
+
@changelog = []
|
82
|
+
@version = -1 # Start from 0
|
83
|
+
|
84
|
+
devist?(file_name) # Check if file is configured for usage
|
85
|
+
|
86
|
+
print " * Building model from file data ...\n"
|
87
|
+
|
88
|
+
File.foreach(file_name) do |line|
|
89
|
+
build_info(line) # Build project info
|
90
|
+
build_changelog(line) # Build changelog data
|
91
|
+
end
|
92
|
+
|
93
|
+
@changelog
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
require 'devist/extractor'
|
99
|
+
require 'devist/models/project'
|
100
|
+
require 'devist/models/tags'
|
101
|
+
require 'devist/models/version'
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: devist
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Halis Duraki
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-05-08 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A Ruby gem that will help you export your Markdown changelog into beautiful
|
14
|
+
HTML pages.
|
15
|
+
email: duraki.halis@nosft.ba
|
16
|
+
executables:
|
17
|
+
- devist
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- bin/devist
|
22
|
+
- lib/devist.rb
|
23
|
+
- lib/devist/compiler.rb
|
24
|
+
- lib/devist/export/html/_default.html.erb
|
25
|
+
- lib/devist/export/html/_polar.html.erb
|
26
|
+
- lib/devist/extractor.rb
|
27
|
+
- lib/devist/models/project.rb
|
28
|
+
- lib/devist/models/tags.rb
|
29
|
+
- lib/devist/models/version.rb
|
30
|
+
- lib/devist/parser.rb
|
31
|
+
homepage: https://github.com/stacklog/devist
|
32
|
+
licenses:
|
33
|
+
- MIT
|
34
|
+
metadata: {}
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 2.5.1
|
52
|
+
signing_key:
|
53
|
+
specification_version: 4
|
54
|
+
summary: Generate beautiful changelogs!
|
55
|
+
test_files: []
|