-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(bootstrap): creating initial structure
- Loading branch information
Rafael Pedrola
committed
Nov 15, 2013
1 parent
89ee30f
commit dea45d6
Showing
76 changed files
with
7,033 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node changelog.js 1.0.0 changelog.md "My App" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
#!/usr/bin/env node | ||
|
||
// TODO(vojta): pre-commit hook for validating messages | ||
// TODO(vojta): report errors, currently Q silence everything which really sucks | ||
|
||
var child = require('child_process'); | ||
var fs = require('fs'); | ||
var util = require('util'); | ||
var q = require('qq'); | ||
var _s = require('underscore-string'); | ||
|
||
var GIT_LOG_CMD = 'git log development --grep="%s" -E --format=%s %s..HEAD'; | ||
//var GIT_LOG_CMD = 'git log --grep="%s" -E --format=%s %s..HEAD'; | ||
var GIT_TAG_CMD = 'git describe --tags --abbrev=0'; | ||
|
||
var PROVIDER = 'BitBucket'; | ||
var HEADER_TPL = '<a name="%s">%s</a>\n# %s (%s)\n\n'; | ||
var LINK_ISSUE = '[#%s](https://bitbucket.org/adesisnetlife/repsol-proyecto-f-nix-intranet/issues/%s)'; | ||
var LINK_COMMIT = '[%s](https://bitbucket.org/adesisnetlife/repsol-proyecto-f-nix-intranet/commits/%s)'; | ||
|
||
var EMPTY_COMPONENT = '$$'; | ||
|
||
var warn = function() { | ||
console.log('WARNING:', util.format.apply(null, arguments)); | ||
}; | ||
|
||
|
||
var parseRawCommit = function(raw) { | ||
if (!raw) return null; | ||
|
||
var lines = raw.split('\n'); | ||
var msg = {}, match; | ||
|
||
msg.hash = lines.shift(); | ||
msg.subject = lines.shift(); | ||
|
||
msg.closes = []; | ||
msg.breaks = []; | ||
|
||
lines.forEach(function(line) { | ||
match = line.match(/(?:Closes|Fixes)\s#(\d+)/); | ||
if (match) msg.closes.push(parseInt(match[1])); | ||
}); | ||
|
||
match = raw.match(/BREAKING CHANGE:([\s\S]*)/); | ||
if (match) { | ||
msg.breaking = match[1]; | ||
} | ||
|
||
|
||
msg.body = lines.join('\n'); | ||
match = msg.subject.match(/^(.*)\((.*)\)\:\s(.*)$/); | ||
console.log(match); | ||
if (!match || !match[1] || !match[3]) { | ||
warn('Incorrect message: %s %s', msg.hash, msg.subject); | ||
return null; | ||
} | ||
|
||
msg.type = match[1]; | ||
msg.component = match[2]; | ||
msg.subject = match[3]; | ||
|
||
return msg; | ||
}; | ||
|
||
|
||
var linkToIssue = function(issue) { | ||
return util.format(LINK_ISSUE, issue, issue); | ||
}; | ||
|
||
|
||
var linkToCommit = function(hash) { | ||
return util.format(LINK_COMMIT, hash.substr(0, 8), hash); | ||
}; | ||
|
||
|
||
var currentDate = function() { | ||
var now = new Date(); | ||
var pad = function(i) { | ||
return ('0' + i).substr(-2); | ||
}; | ||
|
||
return util.format('%d-%s-%s', now.getFullYear(), pad(now.getMonth() + 1), pad(now.getDate())); | ||
}; | ||
|
||
|
||
var printSection = function(stream, title, section, printCommitLinks) { | ||
printCommitLinks = printCommitLinks === undefined ? true : printCommitLinks; | ||
var components = Object.getOwnPropertyNames(section).sort(); | ||
|
||
if (!components.length) return; | ||
|
||
stream.write(util.format('\n## %s\n\n', title)); | ||
|
||
components.forEach(function(name) { | ||
var prefix = '-'; | ||
var nested = section[name].length > 1; | ||
|
||
if (name !== EMPTY_COMPONENT) { | ||
if (nested) { | ||
stream.write(util.format('- **%s:**\n', name)); | ||
prefix = ' -'; | ||
} else { | ||
prefix = util.format('- **%s:**', name); | ||
} | ||
} | ||
|
||
section[name].forEach(function(commit) { | ||
if (printCommitLinks) { | ||
stream.write(util.format('%s %s\n (%s', prefix, commit.subject, linkToCommit(commit.hash))); | ||
if (commit.closes.length) { | ||
stream.write(',\n ' + commit.closes.map(linkToIssue).join(', ')); | ||
} | ||
stream.write(')\n'); | ||
} else { | ||
stream.write(util.format('%s %s', prefix, commit.subject)); | ||
} | ||
}); | ||
}); | ||
|
||
stream.write('\n'); | ||
}; | ||
|
||
|
||
var readGitLog = function(grep, from) { | ||
var deferred = q.defer(); | ||
|
||
// TODO(vojta): if it's slow, use spawn and stream it instead | ||
|
||
child.exec(util.format(GIT_LOG_CMD, grep, '%H%n%s%n%b%n==END==', from), function(code, stdout, stderr) { | ||
|
||
var commits = []; | ||
|
||
stdout.split('\n==END==\n').forEach(function(rawCommit) { | ||
|
||
var commit = parseRawCommit(rawCommit); | ||
if (commit) commits.push(commit); | ||
}); | ||
|
||
deferred.resolve(commits); | ||
}); | ||
|
||
return deferred.promise; | ||
}; | ||
|
||
|
||
var writeChangelog = function(stream, commits, version, appName) { | ||
var sections = { | ||
fix: {}, | ||
feat: {}, | ||
breaks: {}, | ||
problems: {}, | ||
docs: {} | ||
}; | ||
|
||
sections.breaks[EMPTY_COMPONENT] = []; | ||
|
||
commits.forEach(function(commit) { | ||
var section = sections[commit.type]; | ||
var component = commit.component || EMPTY_COMPONENT; | ||
|
||
if (section) { | ||
section[component] = section[component] || []; | ||
section[component].push(commit); | ||
} | ||
|
||
if (commit.breaking) { | ||
sections.breaks[component] = sections.breaks[component] || []; | ||
sections.breaks[component].push({ | ||
subject: util.format("due to %s,\n %s", linkToCommit(commit.hash), commit.breaking), | ||
hash: commit.hash, | ||
closes: [] | ||
}); | ||
}; | ||
}); | ||
|
||
stream.write(util.format(HEADER_TPL, version, appName, version, currentDate())); | ||
printSection(stream, 'Documentation', sections.docs); | ||
printSection(stream, 'Bug Fixes', sections.fix); | ||
printSection(stream, 'Features', sections.feat); | ||
printSection(stream, 'Breaking Changes', sections.breaks, false); | ||
printSection(stream, 'Client Problems', sections.problems, false); | ||
} | ||
|
||
|
||
var getPreviousTag = function() { | ||
|
||
var deferred = q.defer(); | ||
console.log(GIT_TAG_CMD); | ||
child.exec(GIT_TAG_CMD, function(code, stdout, stderr) { | ||
if (code) deferred.reject('Cannot get the previous tag.'); | ||
else deferred.resolve(stdout.replace('\n', '')); | ||
}); | ||
|
||
return deferred.promise; | ||
}; | ||
|
||
|
||
var generate = function(version, file, appName) { | ||
|
||
getPreviousTag().then(function(tag) { | ||
|
||
console.log('Reading git log since', tag); | ||
readGitLog('^fix|^feat|^docs|BREAKING', tag).then(function(commits) { | ||
console.log('Parsed', commits.length, 'commits'); | ||
console.log('Generating changelog to', file || 'stdout', '(', version, ')'); | ||
writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version, appName); | ||
}); | ||
}); | ||
}; | ||
|
||
|
||
// publish for testing | ||
exports.parseRawCommit = parseRawCommit; | ||
|
||
// hacky start if not run by jasmine :-D | ||
if (process.argv.join('').indexOf('jasmine-node') === -1) { | ||
//node changelog.js 1.0.0 changelog.md "My App" | ||
if (process.argv[5] != undefined) { | ||
if (process.argv[5] == 'GitHub' || process.argv[5] == 'BitBucket') { | ||
PROVIDER = process.argv[5]; | ||
} | ||
} | ||
generate(process.argv[2], process.argv[3], process.argv[4]); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#!/usr/bin/env bash | ||
|
||
function catch_errors() { | ||
echo "ERROR. That's life." | ||
exit 1 | ||
} | ||
|
||
trap catch_errors ERR | ||
|
||
TMP_FILE='changelog.tmp' | ||
CHANGELOG_FILE='CHANGELOG.md' | ||
|
||
echo "Getting current version..." | ||
VERSION=`./version.js --current` | ||
|
||
echo "Generating changelog..." | ||
./changelog.js $VERSION $TMP_FILE | ||
|
||
cat $CHANGELOG_FILE >> $TMP_FILE | ||
mv -f $TMP_FILE $CHANGELOG_FILE | ||
|
||
|
||
echo "Updating version..." | ||
./version.js --remove-snapshot | ||
|
||
echo "CONFIRM TO COMMIT" | ||
read WHATEVER | ||
|
||
|
||
echo "Creating commit..." | ||
git commit version.yaml CHANGELOG.md -m "chore(relase): cutting the v$VERSION release" | ||
|
||
echo "Creating tag..." | ||
git tag "v$VERSION" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
describe('changelog.js', function() { | ||
var ch = require('./changelog'); | ||
|
||
describe('parseRawCommit', function() { | ||
it('should parse raw commit', function() { | ||
var msg = ch.parseRawCommit( | ||
'9b1aff905b638aa274a5fc8f88662df446d374bd\n' + | ||
'feat(scope): broadcast $destroy event on scope destruction\n' + | ||
'perf testing shows that in chrome this change adds 5-15% overhead\n' + | ||
'when destroying 10k nested scopes where each scope has a $destroy listener\n'); | ||
|
||
expect(msg.type).toBe('feat'); | ||
expect(msg.hash).toBe('9b1aff905b638aa274a5fc8f88662df446d374bd'); | ||
expect(msg.subject).toBe('broadcast $destroy event on scope destruction'); | ||
expect(msg.body).toBe('perf testing shows that in chrome this change adds 5-15% overhead\n' + | ||
'when destroying 10k nested scopes where each scope has a $destroy listener\n') | ||
expect(msg.component).toBe('scope'); | ||
}); | ||
|
||
|
||
it('should parse closed issues', function() { | ||
var msg = ch.parseRawCommit( | ||
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' + | ||
'feat(ng-list): Allow custom separator\n' + | ||
'bla bla bla\n\n' + | ||
'Closes #123\nCloses #25\n'); | ||
|
||
expect(msg.closes).toEqual([123, 25]); | ||
}); | ||
|
||
|
||
it('should parse breaking changes', function() { | ||
var msg = ch.parseRawCommit( | ||
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' + | ||
'feat(ng-list): Allow custom separator\n' + | ||
'bla bla bla\n\n' + | ||
'BREAKING CHANGE: first breaking change\nsomething else\n' + | ||
'another line with more info\n'); | ||
|
||
expect(msg.breaking).toEqual(' first breaking change\nsomething else\nanother line with more info\n'); | ||
}); | ||
}); | ||
}); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.