1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | 'use strict';
|
10 |
|
11 | var chg = module.exports = {};
|
12 |
|
13 | var fs = require('fs');
|
14 | var shell = require('shelljs');
|
15 | var moment = require('moment');
|
16 |
|
17 | var changeLogFile = 'CHANGELOG.md';
|
18 | var unreleasedTitle = '## HEAD (Unreleased)\n';
|
19 | var noItems = '_(none)_';
|
20 | var divider = '--------------------\n\n';
|
21 |
|
22 | var ERR_NO_CHANGELOG = changeLogFile+' does not exist. Change to the directory where it does exist, or run `init` to create one in the current directory.';
|
23 |
|
24 | function noopCallback(){}
|
25 |
|
26 | function getChangeLog(){
|
27 | if (!fs.existsSync(changeLogFile)) {
|
28 | return null;
|
29 | }
|
30 | return fs.readFileSync(changeLogFile, 'utf8');
|
31 | }
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 | chg.init = function(options, callback){
|
47 | options = options || {};
|
48 | callback = callback || noopCallback;
|
49 |
|
50 | if (fs.existsSync(changeLogFile)){
|
51 | var err = new Error(changeLogFile + ' already exists');
|
52 | callback(err);
|
53 | return err;
|
54 | }
|
55 |
|
56 | var contents = 'CHANGELOG\n=========\n\n';
|
57 | contents += unreleasedTitle + noItems + '\n\n' + divider;
|
58 |
|
59 | fs.writeFileSync(changeLogFile, contents, 'utf8');
|
60 |
|
61 |
|
62 | callback(null, changeLogFile);
|
63 |
|
64 | return changeLogFile;
|
65 | };
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 | chg.delete = function(options, callback){
|
74 | options = options || {};
|
75 | callback = callback || noopCallback;
|
76 |
|
77 | if (!fs.existsSync(changeLogFile)) {
|
78 | var err = new Error(changeLogFile+' does not exist');
|
79 | callback(err);
|
80 | return err;
|
81 | }
|
82 |
|
83 | shell.rm(changeLogFile);
|
84 |
|
85 | callback(null, changeLogFile);
|
86 |
|
87 | return changeLogFile;
|
88 | };
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | chg.add = function(line, options, callback){
|
98 | var contents, sections, top;
|
99 |
|
100 | options = options || {};
|
101 | callback = callback || noopCallback;
|
102 |
|
103 |
|
104 | contents = getChangeLog();
|
105 | if (!contents) {
|
106 | var err = new Error(ERR_NO_CHANGELOG);
|
107 | callback(err);
|
108 | return err;
|
109 | }
|
110 |
|
111 |
|
112 | contents = contents.replace(unreleasedTitle + noItems + '\n', unreleasedTitle);
|
113 |
|
114 |
|
115 | sections = contents.split('\n'+divider);
|
116 |
|
117 | top = sections[0] + '* ' + line + '\n\n';
|
118 |
|
119 |
|
120 | contents = top + divider + sections[1];
|
121 | fs.writeFileSync(changeLogFile, contents, 'utf8');
|
122 |
|
123 |
|
124 | callback(null, line);
|
125 |
|
126 | return line;
|
127 | };
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 | chg.release = function(version, options, callback){
|
142 | var date, contents, changes, title, err;
|
143 |
|
144 | callback = callback || noopCallback;
|
145 | options = options || {};
|
146 | date = options.date || moment().format('YYYY-MM-DD');
|
147 | version = version || options.version || null;
|
148 |
|
149 | if (!version) {
|
150 | err = new Error('Version required');
|
151 | callback(err);
|
152 | return err;
|
153 | }
|
154 |
|
155 |
|
156 | contents = getChangeLog();
|
157 | if (!contents) {
|
158 | err = new Error(ERR_NO_CHANGELOG);
|
159 | callback(err);
|
160 | return err;
|
161 | }
|
162 |
|
163 |
|
164 | changes = contents.split(unreleasedTitle)[1];
|
165 |
|
166 | changes = changes.split('\n\n')[0];
|
167 |
|
168 | contents = contents.replace(changes, noItems);
|
169 |
|
170 |
|
171 | title = '##' + ' ' + version + ' ('+ date +')\n';
|
172 |
|
173 | contents = contents.replace(divider, divider + title + changes + '\n\n');
|
174 |
|
175 | fs.writeFileSync(changeLogFile, contents, 'utf8');
|
176 |
|
177 | var changeData = { title: title, changes: changes, changelog: contents };
|
178 | callback(null, changeData);
|
179 |
|
180 | return changeData;
|
181 | };
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 | chg.find = function(title, options, callback) {
|
194 | options = options || {};
|
195 | callback = callback || noopCallback;
|
196 |
|
197 | var err;
|
198 | if (!title) {
|
199 | err = new Error('Title required');
|
200 | callback(err);
|
201 | return err;
|
202 | }
|
203 |
|
204 | var contents = getChangeLog();
|
205 |
|
206 | if (!contents) {
|
207 | err = new Error(ERR_NO_CHANGELOG);
|
208 | callback(err);
|
209 | return err;
|
210 | }
|
211 |
|
212 |
|
213 | var regex = new RegExp('(## '+ title +'.*)\n((.+\n)+)');
|
214 | var result = regex.exec(contents);
|
215 |
|
216 | if (!result) {
|
217 | callback(null, {});
|
218 | return {};
|
219 | }
|
220 |
|
221 |
|
222 | var changeArray = result[2].split('\n');
|
223 |
|
224 | var resObj = {
|
225 | title: result[1],
|
226 | changesRaw: result[2],
|
227 | changes: changeArray
|
228 | };
|
229 |
|
230 | callback(null, resObj);
|
231 | return resObj;
|
232 | };
|