├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jscsrc ├── .jshintrc ├── .travis.yml ├── CHANGELOG.md ├── Gruntfile.js ├── README.md ├── package.json ├── tasks ├── conventional-changelog.js └── lib │ └── promise-from-streams.js └── test ├── fixtures ├── _CHANGELOG.md └── _CHANGELOG2.md └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | tmp 3 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "google", 3 | "maximumLineLength": null, 4 | "excludeFiles": ["node_modules/**"] 5 | } 6 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": true, 11 | "boss": true, 12 | "eqnull": true, 13 | "node": true 14 | } 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '5' 5 | - '4' 6 | - '3' 7 | - '2' 8 | - '1' 9 | - '0.12' 10 | - '0.10' 11 | before_script: 12 | - git config --global user.name 'Travis-CI' 13 | - git config --global user.email 'dummy@example.org' 14 | after_script: NODE_ENV=test grunt sendCoverallsInfo 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # [6.1.0](https://github.com/btford/grunt-conventional-changelog/compare/v6.0.1...v6.1.0) (2016-02-13) 3 | 4 | 5 | ### Features 6 | 7 | * **debug:** use conventional-changelog 1.1.0 and enable debug ([ecbaf63](https://github.com/btford/grunt-conventional-changelog/commit/ecbaf63)) 8 | 9 | 10 | 11 | 12 | ## [6.0.1](https://github.com/btford/grunt-conventional-changelog/compare/v6.0.0...v6.0.1) (2016-02-11) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * **log:** should say "Modified" how many files ([15f7955](https://github.com/btford/grunt-conventional-changelog/commit/15f7955)) 18 | 19 | 20 | 21 | 22 | # [6.0.0](https://github.com/btford/grunt-conventional-changelog/compare/v5.0.0...v6.0.0) (2016-02-11) 23 | 24 | 25 | ### Bug Fixes 26 | 27 | * **concat:** make sure the encoding is always buffer ([75fc4ee](https://github.com/btford/grunt-conventional-changelog/commit/75fc4ee)) 28 | * **error:** attach handler to the stream ([a54a194](https://github.com/btford/grunt-conventional-changelog/commit/a54a194)) 29 | 30 | ### Chores 31 | 32 | * **deps:** bump ([0320cba](https://github.com/btford/grunt-conventional-changelog/commit/0320cba)) 33 | 34 | 35 | ### BREAKING CHANGES 36 | 37 | * deps: Using conventional-changelog v1. 38 | 39 | 40 | 41 | 42 | # [5.0.0](https://github.com/btford/grunt-conventional-changelog/compare/v4.1.0...v5.0.0) (2015-09-30) 43 | 44 | 45 | ### Features 46 | 47 | * **deps:** bump ([bacd631](https://github.com/btford/grunt-conventional-changelog/commit/bacd631)) 48 | 49 | 50 | ### BREAKING CHANGES 51 | 52 | * deps: Use conventional-changelog^0.5.0 53 | 54 | 55 | 56 | 57 | # [4.1.0](https://github.com/btford/grunt-conventional-changelog/compare/v4.0.0...v4.1.0) (2015-08-15) 58 | 59 | 60 | **deps:** use conventional-changelog@0.4.0 61 | 62 | 63 | 64 | 65 | # [4.0.0](https://github.com/btford/grunt-conventional-changelog/compare/v3.0.0...v4.0.0) (2015-08-09) 66 | 67 | 68 | ### Features 69 | 70 | * **deps:** use conventional-changelog@0.3.0 ([cc51971](https://github.com/btford/grunt-conventional-changelog/commit/cc51971)) 71 | 72 | 73 | 74 | 75 | # 3.0.0 (2015-07-24) 76 | 77 | 78 | ### Features 79 | 80 | * **deps:** bump conventional-changelog to ^0.2.1 and use new api ([88212f8](https://github.com/btford/grunt-conventional-changelog/commit/88212f8)) 81 | 82 | 83 | 84 | 85 | ## 2.0.2 (2015-07-22) 86 | 87 | 88 | 89 | 90 | 91 | ## 2.0.1 (2015-07-20) 92 | 93 | 94 | ### Bug Fixes 95 | 96 | * **warn:** pass in warn ([04873db](https://github.com/btford/grunt-conventional-changelog/commit/04873db)) 97 | 98 | 99 | 100 | 101 | # 2.0.0 (2015-07-20) 102 | 103 | 104 | ### Features 105 | 106 | * **deprecated:** remove deprecated code ([631ce49](https://github.com/btford/grunt-conventional-changelog/commit/631ce49)) 107 | * **grunt:** make this a multi task ([4c6f3a0](https://github.com/btford/grunt-conventional-changelog/commit/4c6f3a0)) 108 | * **package:** add more keywords and fix description ([4cd34d7](https://github.com/btford/grunt-conventional-changelog/commit/4cd34d7)) 109 | * use conventional-changelog@0.1.0 ([c1a6ede](https://github.com/btford/grunt-conventional-changelog/commit/c1a6ede)), closes [#43](https://github.com/btford/grunt-conventional-changelog/issues/43) [#50](https://github.com/btford/grunt-conventional-changelog/issues/50) 110 | 111 | 112 | ### BREAKING CHANGES 113 | 114 | * conventional-changelog@0.1.0 is rewritten and so is this module. No backward compatibility. Checkout the docs for more info. 115 | 116 | 117 | 118 | 119 | ### 1.2.2 (2015-05-02) 120 | 121 | 122 | #### Bug Fixes 123 | 124 | * **dest:** do not ignore `options.dest` ([1dbf0a8c](https://github.com/btford/grunt-conventional-changelog/commit/1dbf0a8c), closes [#55](https://github.com/btford/grunt-conventional-changelog/issues/55)) 125 | * **grunt:** bump task should work properly ([488bb2eb](https://github.com/btford/grunt-conventional-changelog/commit/488bb2eb)) 126 | 127 | 128 | 129 | ### 1.2.1 (2015-04-03) 130 | 131 | 132 | #### Bump conventional-changelog to v0.0.17 133 | 134 | 135 | 136 | ## 1.2.0 (2015-03-31) 137 | 138 | 139 | #### Bug Fixes 140 | 141 | * **task:** fix that all editors can be started in config ([35a92b1d](https://github.com/btford/grunt-conventional-changelog/commit/35a92b1d), closes [#35](https://github.com/btford/grunt-conventional-changelog/issues/35)) 142 | 143 | 144 | #### Breaking Changes 145 | 146 | * This module no longer reads your package.json to find version and repository. This logic is moved to conventional-changelog. We want to make this one a pure grunt wrapper. 147 | 148 | ([0f9562ff](https://github.com/btford/grunt-conventional-changelog/commit/0f9562ff)) 149 | 150 | 151 | 152 | ## 1.1.0 (2014-02-11) 153 | 154 | 155 | #### Bug Fixes 156 | 157 | * make changelog work if no githubRepo specified ([890aac96](https://github.com/btford/grunt-conventional-changelog/commit/890aac9682dc4e4a46a7bd247f103e267c615d94)) 158 | * append if prepend set to false ([bdc56349](https://github.com/btford/grunt-conventional-changelog/commit/bdc563498d21de2be468c38ed3791825f4646146)) 159 | * Write whether file exists or not ([a2f663c0](https://github.com/btford/grunt-conventional-changelog/commit/a2f663c0c08bd7cbc6316389d89d6c327b0bd7db)) 160 | * **changelog:** cannot generate changelog for first tag () ([706a284b](https://github.com/btford/grunt-conventional-changelog/commit/706a284b531719f2bad7a0f9b4bbbd842af47909), closes [#27](https://github.com/btford/grunt-conventional-changelog/issues/27)) 161 | 162 | 163 | #### Features 164 | 165 | * parse multiple "Closes" definitions ([57e93d77](https://github.com/btford/grunt-conventional-changelog/commit/57e93d77de638d7701d6df837f216ca79ccf18fa)) 166 | * parse Closes/Fixes from subject ([8bcd7a39](https://github.com/btford/grunt-conventional-changelog/commit/8bcd7a39c2e32cad775af874d26ec91cb56a3a4e)) 167 | * replace with the changelog task from karma ([25a01c7c](https://github.com/btford/grunt-conventional-changelog/commit/25a01c7c7e55bcc2f87fb34e850b6c254f70ee7f)) 168 | * **validator:** 169 | * allow 100 characters in commit message () ([9982d897](https://github.com/btford/grunt-conventional-changelog/commit/9982d89753137d474b28d525bf323798dc7210f6), closes [#28](https://github.com/btford/grunt-conventional-changelog/issues/28)) 170 | * show list of available types on error ([4aee5b8e](https://github.com/btford/grunt-conventional-changelog/commit/4aee5b8ed457b95e2b084661aa52335f290216f5)) 171 | 172 | 173 | #### Breaking Changes 174 | 175 | * `options.github` no longer supported. Use the 176 | `repository` option instead. 177 | 178 | To migrate, change the following: 179 | 180 | ```js 181 | options: { 182 | github: 'me/project' 183 | } 184 | ``` 185 | 186 | To: 187 | 188 | ```js 189 | options: { 190 | repository: 'https://github.com/me/project' 191 | } 192 | ``` 193 | ([caa14d69](https://github.com/btford/grunt-conventional-changelog/commit/caa14d694ed14b0ec322e85533cf4e350136e501)) 194 | 195 | 196 | 197 | ## v1.0.0 (2013-07-17) 198 | 199 | 200 | #### Bug Fixes 201 | 202 | * append if prepend set to false ([bdc56349](https://github.com/btford/grunt-conventional-changelog/commit/bdc563498d21de2be468c38ed3791825f4646146)) 203 | * Write whether file exists or not ([a2f663c0](https://github.com/btford/grunt-conventional-changelog/commit/a2f663c0c08bd7cbc6316389d89d6c327b0bd7db)) 204 | 205 | 206 | #### Features 207 | 208 | * parse multiple "Closes" definitions ([57e93d77](https://github.com/btford/grunt-conventional-changelog/commit/57e93d77de638d7701d6df837f216ca79ccf18fa)) 209 | * parse Closes/Fixes from subject ([8bcd7a39](https://github.com/btford/grunt-conventional-changelog/commit/8bcd7a39c2e32cad775af874d26ec91cb56a3a4e)) 210 | * replace with the changelog task from karma ([25a01c7c](https://github.com/btford/grunt-conventional-changelog/commit/25a01c7c7e55bcc2f87fb34e850b6c254f70ee7f)) 211 | 212 | 213 | ### v0.1.2 (2013-06-23) 214 | 215 | 216 | #### Bug Fixes 217 | 218 | * **log:** correctly generate links to GitHub commits ([de15bde5](https://github.com/btford/grunt-conventional-changelog/commit/de15bde55e4ed11fc33c85c43f8ffdf7d01efe2f)) 219 | 220 | 221 | ### v0.1.1 (2013-06-11) 222 | 223 | 224 | #### Bug Fixes 225 | 226 | * **task:** Fix shelljs dependency problem ([2db8cf96](https://github.com/btford/grunt-conventional-changelog/commit/2db8cf969b2ac0aa4d2f9f6ab908b3f7f96f8cf2)) 227 | 228 | 229 | ## v0.1.0 (2013-05-30) 230 | 231 | 232 | #### Bug Fixes 233 | 234 | * **gruntfile:** load package.json ([8c4cb685](https://github.com/btford/grunt-conventional-changelog/commit/8c4cb685f161e1ed920138fd65d9d13be501ed33)) 235 | * **task:** 236 | * fix issue when no changelog exist yet ([c1a31f56](https://github.com/btford/grunt-conventional-changelog/commit/c1a31f566ee1fecc4f1ff3807d98d1a6aedf87a9)) 237 | * version regex now matches the commit messages created by `npm version` by defaul ([db3985d2](https://github.com/btford/grunt-conventional-changelog/commit/db3985d2069ba909b413fe7bcbb8521db2f8b7e2)) 238 | 239 | 240 | #### Features 241 | 242 | * **changelog:** 243 | * Allow 'enforce' option: Adds a git hook for commit conventions ([1cbe92cf](https://github.com/btford/grunt-conventional-changelog/commit/1cbe92cfa3f8f200ec42f7ef709c33813c230a03)) 244 | * allow 'version' option, to use instead of 'pkg.version' ([4a06569a](https://github.com/btford/grunt-conventional-changelog/commit/4a06569ad0c0024bde2d4b098ec839cd023ceeaa)) 245 | * **log:** 246 | * Add smart 'github' option for commit links ([6ac1083a](https://github.com/btford/grunt-conventional-changelog/commit/6ac1083a51a5b01e9c32f230254488e45f733b47)) 247 | * Add breaking changes section ([04ecfceb](https://github.com/btford/grunt-conventional-changelog/commit/04ecfceb57626ab7373eb66db25e1a465469d985)) 248 | * dogfooding - this task uses itself to generate its own changelogs ([746e9ffc](https://github.com/btford/grunt-conventional-changelog/commit/746e9ffca4dd8e90f359a424dca1cfad0a4e4ccf)) 249 | 250 | 251 | ### v0.0.12 (2013-04-06) 252 | 253 | 254 | #### Features 255 | 256 | * **log:** automatically split notes based on release version ([5545fe45](https://github.com/btford/grunt-conventional-changelog/commit/5545fe456f3376ae0d089face51a8b53bcad038d)) 257 | * **readme:** improve the readme ([0aeec479](https://github.com/btford/grunt-conventional-changelog/commit/0aeec479cfa68e04c33d81bd994a0445f7ddce26)) 258 | 259 | 260 | ### v0.0.11 (2013-04-05) 261 | 262 | 263 | #### Bug Fixes 264 | 265 | * **grunt:** add .jshintrc ([fd79b784](https://github.com/btford/grunt-conventional-changelog/commit/fd79b78483498e6e0cadedb9e4d4bb945fe5c644)) 266 | * **readme:** rename project, add license ([7320c25f](https://github.com/btford/grunt-conventional-changelog/commit/7320c25fa03b741047a584dbd1f024d62d98de9b)) 267 | * **release:** push to github and npm ([c794c502](https://github.com/btford/grunt-conventional-changelog/commit/c794c5023581796fc0853c3db5c36355ef897052)) 268 | 269 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = function(grunt) { 3 | grunt.initConfig({ 4 | pkg: grunt.file.readJSON('package.json'), 5 | clean: { 6 | test: 'tmp', 7 | coverage: 'coverage' 8 | }, 9 | jshint: { 10 | options: { 11 | jshintrc: '.jshintrc' 12 | }, 13 | all: [ 14 | '*.js', 15 | 'test/*.js', 16 | 'tasks/*.js' 17 | ] 18 | }, 19 | jscs: { 20 | options: { 21 | config: '.jscsrc' 22 | }, 23 | all: [ 24 | '*.js', 25 | 'test/*.js', 26 | 'tasks/*.js' 27 | ] 28 | }, 29 | copy: { 30 | noDestSingle: { 31 | src: 'test/fixtures/_CHANGELOG.md', 32 | dest: 'tmp/no-dest-single/_CHANGELOG.md' 33 | }, 34 | noDestMultiple: { 35 | expand: true, 36 | flatten: true, 37 | src: 'test/fixtures/*.md', 38 | dest: 'tmp/no-dest-multiple/' 39 | } 40 | }, 41 | nodeunit: { 42 | tests: ['test/*.js'] 43 | }, 44 | conventionalChangelog: { 45 | options: { 46 | changelogOpts: { 47 | preset: 'angular', 48 | outputUnreleased: true 49 | } 50 | }, 51 | append: { 52 | options: { 53 | changelogOpts: { 54 | preset: 'angular', 55 | append: true 56 | } 57 | }, 58 | src: 'test/fixtures/_CHANGELOG.md', 59 | dest: 'tmp/append.md' 60 | }, 61 | prepend: { 62 | src: 'test/fixtures/_CHANGELOG.md', 63 | dest: 'tmp/prepend.md' 64 | }, 65 | allBlocks: { 66 | options: { 67 | changelogOpts: { 68 | preset: 'angular', 69 | releaseCount: 0 70 | } 71 | }, 72 | src: 'test/fixtures/_CHANGELOG.md', 73 | dest: 'tmp/all-blocks.md' 74 | }, 75 | multiFiles: { 76 | expand: true, 77 | flatten: true, 78 | src: 'test/fixtures/*.md', 79 | dest: 'tmp/multiple-files/' 80 | }, 81 | multipleSrcToOneDest: { 82 | src: 'test/fixtures/*.md', 83 | dest: 'tmp/multiple-src-to-one-dest.md' 84 | }, 85 | noDestSingle: { 86 | src: 'tmp/no-dest-single/_CHANGELOG.md' 87 | }, 88 | noDestMultiple: { 89 | src: 'tmp/no-dest-multiple/*.md' 90 | }, 91 | noSrcAllBlocks: { 92 | options: { 93 | changelogOpts: { 94 | preset: 'angular', 95 | releaseCount: 0 96 | } 97 | }, 98 | dest: 'tmp/no-src-all-blocks.md' 99 | }, 100 | // This task should fail 101 | // noSrc: { 102 | // dest: 'tmp/no-src.md' 103 | // }, 104 | noFiles: {}, 105 | emptyOutput: { 106 | options: { 107 | writerOpts: { 108 | transform: function() { 109 | return false; 110 | } 111 | } 112 | } 113 | }, 114 | release: { 115 | src: 'CHANGELOG.md' 116 | } 117 | }, 118 | instrument: { 119 | files: 'tasks/**/*.js', 120 | options: { 121 | lazy: true, 122 | basePath: 'coverage/instrument/' 123 | } 124 | }, 125 | reloadTasks: { 126 | rootPath: 'coverage/instrument/tasks' 127 | }, 128 | storeCoverage: { 129 | options: { 130 | dir: 'coverage/reports' 131 | } 132 | }, 133 | makeReport: { 134 | src: 'coverage/reports/**/*.json', 135 | options: { 136 | type: 'lcov', 137 | dir: 'coverage', 138 | print: 'detail' 139 | } 140 | }, 141 | coveralls: { 142 | // Options relevant to all targets 143 | options: { 144 | // When true, grunt-coveralls will only print a warning rather than 145 | // an error, to prevent CI builds from failing unnecessarily (e.g. if 146 | // coveralls.io is down). Optional, defaults to false. 147 | force: false 148 | }, 149 | all: { 150 | // LCOV coverage file (can be string, glob or array) 151 | src: 'coverage/lcov.info', 152 | options: { 153 | // Any options for just this target 154 | } 155 | }, 156 | }, 157 | conventionalGithubReleaser: { 158 | release: { 159 | options: { 160 | auth: { 161 | type: 'oauth', 162 | token: process.env.CONVENTIONAL_GITHUB_RELEASER_TOKEN 163 | }, 164 | changelogOpts: { 165 | preset: 'angular' 166 | } 167 | } 168 | } 169 | }, 170 | bump: { 171 | options: { 172 | updateConfigs: ['pkg'], 173 | commitFiles: ['package.json', 'CHANGELOG.md'], 174 | commitMessage: 'chore: release v%VERSION%' 175 | } 176 | } 177 | }); 178 | 179 | require('load-grunt-tasks')(grunt); 180 | grunt.loadNpmTasks('grunt-istanbul'); 181 | grunt.loadTasks('tasks'); 182 | 183 | grunt.registerTask('lint', ['jshint', 'jscs']); 184 | grunt.registerTask('conventionalChangelog:test', [ 185 | 'conventionalChangelog:append', 186 | 'conventionalChangelog:prepend', 187 | 'conventionalChangelog:allBlocks', 188 | 'conventionalChangelog:multiFiles', 189 | 'conventionalChangelog:multipleSrcToOneDest', 190 | 'conventionalChangelog:noDestSingle', 191 | 'conventionalChangelog:noDestMultiple', 192 | 'conventionalChangelog:noSrcAllBlocks', 193 | // 'conventionalChangelog:noSrc', 194 | 'conventionalChangelog:noFiles' 195 | ]); 196 | grunt.registerTask('test', ['lint', 'clean:test', 'copy', 'conventionalChangelog:test', 'nodeunit']); 197 | grunt.registerTask('coverage', ['clean', 'instrument', 'reloadTasks', 'copy', 'conventionalChangelog:test', 'storeCoverage', 'makeReport']); 198 | grunt.registerTask('sendCoverallsInfo', ['coverage', 'coveralls', 'clean']); 199 | grunt.registerTask('default', ['lint', 'coverage', 'clean']); 200 | grunt.registerTask('release', 'bump, changelog and publish to npm.', function(type) { 201 | grunt.task.run([ 202 | 'bump:' + (type || 'patch') + ':bump-only', 203 | 'conventionalChangelog:release', 204 | 'bump-commit', 205 | 'conventionalGithubReleaser', 206 | 'npm-publish' 207 | ]); 208 | }); 209 | }; 210 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] [![Coverage Status][coveralls-image]][coveralls-url] 2 | 3 | > Generate a changelog using [conventional-changelog](https://github.com/ajoslin/conventional-changelog) 4 | 5 | *Issues with the output should be reported on the `conventional-changelog` [issue tracker](https://github.com/ajoslin/conventional-changelog/issues).* 6 | 7 | 8 | ## Install 9 | 10 | ``` 11 | $ npm install --save-dev grunt-conventional-changelog 12 | ``` 13 | 14 | 15 | ## Usage 16 | 17 | ```js 18 | grunt.loadNpmTasks('grunt-conventional-changelog'); 19 | 20 | grunt.initConfig({ 21 | conventionalChangelog: { 22 | options: { 23 | changelogOpts: { 24 | // conventional-changelog options go here 25 | preset: 'angular' 26 | }, 27 | context: { 28 | // context goes here 29 | }, 30 | gitRawCommitsOpts: { 31 | // git-raw-commits options go here 32 | }, 33 | parserOpts: { 34 | // conventional-commits-parser options go here 35 | }, 36 | writerOpts: { 37 | // conventional-changelog-writer options go here 38 | } 39 | }, 40 | release: { 41 | src: 'CHANGELOG.md' 42 | } 43 | } 44 | }); 45 | 46 | grunt.registerTask('default', ['conventionalChangelog']); 47 | ``` 48 | 49 | 50 | ## API 51 | 52 | See the [conventional-changelog](https://github.com/ajoslin/conventional-changelog) docs. 53 | 54 | There are some changes: 55 | 56 | ### changelogOpts 57 | 58 | #### warn 59 | 60 | It is `grunt.verbose.writeln`. 61 | 62 | 63 | ## Edit your changelog manually 64 | 65 | Sometimes after auto-generating the changelog you want to be able to review the generated changes or add some notes to the current release, you can polish your changelog manually without changing your workflow (you might use `grunt-release` in the workflow but need grunt to wait until you have finished polishing your changelog). 66 | 67 | Here are some examples of how to achieve this. 68 | 69 | ```js 70 | grunt.initConfig({ 71 | 72 | // grunt-shell 73 | shell: { 74 | changelog: { 75 | options: { 76 | stdinRawMode: true 77 | }, 78 | command: 'subl -w CHANGELOG.md', 79 | } 80 | }, 81 | 82 | // or grunt-spawn 83 | spawn: { 84 | changelog: { 85 | command: 'vim', 86 | pattern: 'CHANGELOG.md', 87 | commandArgs: ['{0}'], 88 | opts: { 89 | stdio: 'inherit' 90 | } 91 | } 92 | }, 93 | 94 | }); 95 | 96 | ... 97 | 98 | grunt.registerTask('publish', ['conventionalChangelog', 'shell:changelog', 'release']); 99 | 100 | // or 101 | 102 | grunt.registerTask('publish', ['conventionalChangelog', 'spawn:changelog', 'release']); 103 | ``` 104 | 105 | 106 | ## License 107 | 108 | MIT 109 | 110 | 111 | [npm-image]: https://badge.fury.io/js/grunt-conventional-changelog.svg 112 | [npm-url]: https://npmjs.org/package/grunt-conventional-changelog 113 | [travis-image]: https://travis-ci.org/btford/grunt-conventional-changelog.svg?branch=master 114 | [travis-url]: https://travis-ci.org/btford/grunt-conventional-changelog 115 | [daviddm-image]: https://david-dm.org/btford/grunt-conventional-changelog.svg?theme=shields.io 116 | [daviddm-url]: https://david-dm.org/btford/grunt-conventional-changelog 117 | [coveralls-image]: https://coveralls.io/repos/github/btford/grunt-conventional-changelog/badge.svg 118 | [coveralls-url]: https://coveralls.io/r/btford/grunt-conventional-changelog 119 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grunt-conventional-changelog", 3 | "version": "6.1.0", 4 | "description": "Generate a changelog using conventional-changelog", 5 | "engines": { 6 | "node": ">=0.10.0" 7 | }, 8 | "scripts": { 9 | "test": "grunt test" 10 | }, 11 | "author": "Brian Ford (http://briantford.com)", 12 | "repository": "btford/grunt-conventional-changelog", 13 | "keywords": [ 14 | "grunt", 15 | "gruntplugin", 16 | "conventional-changelog", 17 | "conventional", 18 | "changelog", 19 | "log" 20 | ], 21 | "contributors": [ 22 | { 23 | "name": "Brian Ford" 24 | }, 25 | { 26 | "name": "Vojta Jína" 27 | } 28 | ], 29 | "license": "MIT", 30 | "dependencies": { 31 | "chalk": "^1.1.0", 32 | "concat-stream": "^1.5.0", 33 | "conventional-changelog": "^1.1.0", 34 | "plur": "^2.0.0", 35 | "q": "^1.4.1" 36 | }, 37 | "devDependencies": { 38 | "grunt": "^0.4.5", 39 | "grunt-bump": "^0.7.0", 40 | "grunt-cli": "^0.1.13", 41 | "grunt-contrib-clean": "^0.7.0", 42 | "grunt-contrib-copy": "^0.8.0", 43 | "grunt-contrib-jshint": "^0.12.0", 44 | "grunt-contrib-nodeunit": "^0.4.1", 45 | "grunt-conventional-github-releaser": "^1.0.0", 46 | "grunt-coveralls": "^1.0.0", 47 | "grunt-istanbul": "^0.6.1", 48 | "grunt-jscs": "^2.0.0", 49 | "grunt-npm": "0.0.2", 50 | "load-grunt-tasks": "^3.2.0" 51 | }, 52 | "files": [ 53 | "tasks" 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /tasks/conventional-changelog.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var chalk = require('chalk'); 3 | var concat = require('concat-stream'); 4 | var conventionalChangelog = require('conventional-changelog'); 5 | var plur = require('plur'); 6 | var promiseFromStreams = require('./lib/promise-from-streams.js'); 7 | 8 | var DESC = 'Generate a changelog from git metadata'; 9 | 10 | module.exports = function(grunt) { 11 | grunt.registerMultiTask('conventionalChangelog', DESC, function() { 12 | var streams = []; 13 | var tally = 0; 14 | 15 | var done = this.async(); 16 | var files = this.files; 17 | var opts = this.options(); 18 | 19 | var changelogOpts = opts.changelogOpts; 20 | changelogOpts.warn = grunt.verbose.writeln; 21 | changelogOpts.debug = grunt.log.debug; 22 | var context = opts.context; 23 | var gitRawCommitsOpts = opts.gitRawCommitsOpts; 24 | var parserOpts = opts.parserOpts; 25 | var writerOpts = opts.writerOpts; 26 | 27 | function generate(src, dest) { 28 | return conventionalChangelog(changelogOpts, context, gitRawCommitsOpts, parserOpts, writerOpts) 29 | .on('error', function(err) { 30 | grunt.fail.fatal(err); 31 | }) 32 | .pipe(concat({ 33 | encoding: 'buffer' 34 | }, function(data) { 35 | if (changelogOpts.releaseCount === 0) { 36 | grunt.file.write(dest, data); 37 | } else { 38 | var contents = grunt.file.read(src, { 39 | encoding: null 40 | }); 41 | 42 | if (changelogOpts.append) { 43 | grunt.file.write(dest, Buffer.concat([contents, data])); 44 | } else { 45 | grunt.file.write(dest, Buffer.concat([data, contents])); 46 | } 47 | } 48 | 49 | tally++; 50 | })); 51 | } 52 | 53 | files.forEach(function(file) { 54 | var fileSrc = file.src; 55 | 56 | if (fileSrc) { 57 | if (file.dest) { 58 | if (fileSrc.length > 1) { 59 | grunt.log.warn('Only one src per dest is supported. The first file is used'); 60 | } 61 | 62 | streams.push(generate(fileSrc[0], file.dest)); 63 | } else { 64 | fileSrc.forEach(function(src) { 65 | streams.push(generate(src, src)); 66 | }); 67 | } 68 | } else { 69 | if (changelogOpts.releaseCount !== 0) { 70 | grunt.fail.fatal('With `changelogOpts.releaseCount !== 0` you need to specify a `file.src`'); 71 | } 72 | 73 | streams.push(generate(null, file.dest)); 74 | } 75 | }); 76 | 77 | promiseFromStreams(streams) 78 | .then(function() { 79 | if (tally) { 80 | grunt.log.write('Modified ' + chalk.cyan(tally.toString()) + plur(' file', tally)); 81 | } 82 | grunt.log.writeln(); 83 | 84 | done(); 85 | }, done); 86 | }); 87 | }; 88 | -------------------------------------------------------------------------------- /tasks/lib/promise-from-streams.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | 3 | function promiseFromStreams(streams) { 4 | return Q.all(streams.map(function(stream) { 5 | return Q.promise(function(resolve, reject) { 6 | stream.on('error', function(err) { 7 | reject(err); 8 | }); 9 | 10 | // This event fires when no more data will be provided. 11 | stream.on('end', resolve); 12 | 13 | // Emitted when the underlying resource (for example, the backing file 14 | // descriptor) has been closed. Not all streams will emit this. 15 | stream.on('close', resolve); 16 | 17 | // When the end() method has been called, and all data has been flushed 18 | // to the underlying system, this event is emitted. 19 | stream.on('finish', resolve); 20 | }); 21 | })); 22 | } 23 | 24 | module.exports = promiseFromStreams; 25 | -------------------------------------------------------------------------------- /test/fixtures/_CHANGELOG.md: -------------------------------------------------------------------------------- 1 | blablabla Some previous changelog. 2 | -------------------------------------------------------------------------------- /test/fixtures/_CHANGELOG2.md: -------------------------------------------------------------------------------- 1 | My changelog 2. 2 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var readFileSync = require('fs').readFileSync; 3 | 4 | /* 5 | ======== A Handy Little Nodeunit Reference ======== 6 | https://github.com/caolan/nodeunit 7 | 8 | Test methods: 9 | test.expect(numAssertions) 10 | test.done() 11 | Test assertions: 12 | test.ok(value, [message]) 13 | test.equal(actual, expected, [message]) 14 | test.notEqual(actual, expected, [message]) 15 | test.deepEqual(actual, expected, [message]) 16 | test.notDeepEqual(actual, expected, [message]) 17 | test.strictEqual(actual, expected, [message]) 18 | test.notStrictEqual(actual, expected, [message]) 19 | test.throws(block, [error], [message]) 20 | test.doesNotThrow(block, [error], [message]) 21 | test.ifError(value) 22 | */ 23 | 24 | exports.conventionalChangelog = { 25 | setUp: function(done) { 26 | this.allBlocks = readFileSync('tmp/all-blocks.md', 'utf-8'); 27 | this.append = readFileSync('tmp/append.md', 'utf-8'); 28 | this.multipleFiles1 = readFileSync('tmp/multiple-files/_CHANGELOG.md', 'utf-8'); 29 | this.multipleFiles2 = readFileSync('tmp/multiple-files/_CHANGELOG2.md', 'utf-8'); 30 | this.multipleSrcToOneDest = readFileSync('tmp/multiple-src-to-one-dest.md', 'utf-8'); 31 | this.noDestMultiple1 = readFileSync('tmp/no-dest-multiple/_CHANGELOG.md', 'utf-8'); 32 | this.noDestMultiple2 = readFileSync('tmp/no-dest-multiple/_CHANGELOG2.md', 'utf-8'); 33 | this.noDestSingle = readFileSync('tmp/no-dest-single/_CHANGELOG.md', 'utf-8'); 34 | this.noSrcAllBlocks = readFileSync('tmp/no-src-all-blocks.md', 'utf-8'); 35 | this.prepend = readFileSync('tmp/prepend.md', 'utf-8'); 36 | 37 | // setup here if necessary 38 | done(); 39 | }, 40 | allBlocks: function(test) { 41 | test.expect(1); 42 | test.ok(!this.allBlocks.match(/blablabla Some previous changelog/)); 43 | 44 | test.done(); 45 | }, 46 | append: function(test) { 47 | test.expect(1); 48 | test.ok(this.append.match(/^blablabla Some previous changelog[\w\W]+$/)); 49 | 50 | test.done(); 51 | }, 52 | multipleFiles: function(test) { 53 | test.expect(2); 54 | test.ok(this.multipleFiles1.match(/[\w\W]+blablabla Some previous changelog.\n$/)); 55 | test.ok(this.multipleFiles2.match(/^[\w\W]+My changelog 2.\n$/)); 56 | 57 | test.done(); 58 | }, 59 | multipleSrcToOneDest: function(test) { 60 | test.expect(1); 61 | test.ok(this.multipleSrcToOneDest.match(/[\w\W]+blablabla Some previous changelog.\n$/)); 62 | 63 | test.done(); 64 | }, 65 | noDestMultiple: function(test) { 66 | test.expect(2); 67 | test.ok(this.noDestMultiple1.match(/[\w\W]+blablabla Some previous changelog.\n$/)); 68 | test.ok(this.noDestMultiple2.match(/[\w\W]+My changelog 2.\n$/)); 69 | 70 | test.done(); 71 | }, 72 | noDestSingle: function(test) { 73 | test.expect(1); 74 | test.ok(this.noDestMultiple1.match(/[\w\W]+blablabla Some previous changelog.\n$/)); 75 | 76 | test.done(); 77 | }, 78 | noSrcAllBlocks: function(test) { 79 | test.expect(1); 80 | test.ok(!this.noSrcAllBlocks.match(/blablabla Some previous changelog/)); 81 | 82 | test.done(); 83 | }, 84 | prepend: function(test) { 85 | test.expect(1); 86 | test.ok(this.prepend.match(/[\w\W]+blablabla Some previous changelog.\n$/)); 87 | 88 | test.done(); 89 | } 90 | }; 91 | --------------------------------------------------------------------------------