release-notes 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 691d3c472f9792ce0e682085a84f2207f6a4fdda
4
+ data.tar.gz: bb273e2057859b3a70ffcf692ed6f442152df7d9
5
+ SHA512:
6
+ metadata.gz: e056b89f89730bb42537f613e7dcb23363ee4ff25c74aecb54711882935cd2f29912b0a86ef4e3a4af7ea11d5012c55c371033f661b0248ec224b2bd0fb9601b
7
+ data.tar.gz: ed86f0d78b8f71c11e8f39766a3e92f403da70c6711e933b375d1c84c061bfffc903c325ea9b494395b817eff227bf5a36933256cf5bab09538c78ebe44a91c1
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ RELEASE_NOTES.md
12
+ release-notes.tmp.md
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.4.0
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.0
5
+ before_install: gem install bundler -v 1.12.5
6
+ env:
7
+ global:
8
+ secure: ovawk+NnGZGW+hOeC3iPMZ9jKY5FvaxfHLj6XX4Vfe12cq0cdGYirW6pk2uKdJZdE0pC5q4sFv1ZTgcNSTySuNpQ9Gkp4xjcGEVr5JSdmVse8DuxttwkeSPt94DemyMK3f0A3dWN8OJF7/NQbacPeUuXryxmusCqJMlWccVYGeSQQNJ21mFfl2pCf6Z9qls4Q3rzXc4hsVQ5G1B/j9YcMjax0EwXI4cEq/6JadK4OmXrGkCw6M/wvBEqNyhLz+R/gcYiJZqYUETdncRuNiH8N6JKiaCnZUFkGY4bggpOvz29lj3JEQV9jY+3UBeqxuYj3glT7buEuf6//ARedY7IDlupkiDNuSpIKJhzIKAgitc/g+cnUflQV8PiImAEseO0OpoAJ7Bsa688EgyvMgo/kYwjHqZetvlUksQI+XyZ+o7/88LF2Qz4pbuBtdFC4DaKaeqQN5afIHSPtxhYwFA/n+GmY4jymj5ZWod9zZasVdlDgCQzgH5M1W7nEGun8mRW93wf8+3wAx+fXVbB67aDbqJFBJfH6zm/aBCN16kGkHUibRxUyb0F52woBQLUcOIr9Kbujp02D7IK3Z7PFz+DtHfA8aYRXxRDIHxx0tw91UxQzBinsq27kH8EWDmEKMHJeZlMRR4X4ijd6+KFoKUobXFblCeVeO0HCIBxpfTc39w=
9
+ after_success:
10
+ - bundle exec codeclimate-test-reporter
data/.yardopts ADDED
@@ -0,0 +1,6 @@
1
+ --protected
2
+ --private
3
+ --hide-api private
4
+ --exclude templates
5
+ --markup markdown
6
+ --markup-provider redcarpet
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at dvmonroe6@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in release-notes.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'aruba', '~> 0.14.2'
8
+ gem 'codeclimate-test-reporter', require: false
9
+ gem 'pry-byebug', '~> 3.4.2'
10
+ gem 'rspec', '~> 3.6.0'
11
+ gem 'simplecov', require: false
12
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Drew Monroe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # Release::Notes
2
+
3
+ [![Build Status](https://travis-ci.org/dvmonroe/release-notes.svg?branch=master)](https://travis-ci.org/dvmonroe/release-notes)
4
+ [![Code Climate](https://codeclimate.com/github/dvmonroe/release-notes/badges/gpa.svg)](https://codeclimate.com/github/dvmonroe/release-notes)
5
+ [![Test Coverage](https://codeclimate.com/github/dvmonroe/release-notes/badges/coverage.svg)](https://codeclimate.com/github/dvmonroe/release-notes/coverage)
6
+ [![Inline docs](http://inch-ci.org/github/dvmonroe/release-notes.svg?branch=master)](http://inch-ci.org/github/dvmonroe/release-notes)
7
+
8
+ Release notes for the stakeholders.
9
+
10
+ Release::Notes is a small wrapper around your project's git log. The gem is
11
+ intended to help increase visability to all team members and stakeholders with
12
+ automated documentation of important changes made to your code base for a given production
13
+ deployment based on tags and labels in your commit messages.
14
+
15
+ Release::Notes is different than a changelog. It's meant for situations where other
16
+ team members (non-devs) in your organization need to know about key changes
17
+ to the production software. If your looking for a comprehnsive changelog that
18
+ reflects resolved github issues or logging all merges to your project, I would
19
+ suggest you look at something else like
20
+ [github-changelog-generator](https://github.com/skywinder/github-changelog-generator).
21
+
22
+ Not looking for a tested gem or prefer the rawness of a bash script? Checkout the similar
23
+ [bash implementation](https://gist.github.com/dvmonroe/300226a1ed4435fb38d72e72e1bbc5a0)
24
+
25
+ ## Getting Started
26
+
27
+ Add this line to your application's Gemfile:
28
+
29
+ ```ruby
30
+ gem 'release-notes'
31
+ ```
32
+
33
+ And then execute:
34
+
35
+ ```sh
36
+ $ bundle
37
+ ```
38
+
39
+ Or install it yourself as:
40
+
41
+ ```sh
42
+ $ gem install release-notes
43
+ ```
44
+
45
+ After you install Release::Notes, if you're using with rails, you can run the generator:
46
+
47
+ ```sh
48
+ $ rails generate release:notes:install
49
+ ```
50
+
51
+ This Release::Notes generator creates an initializer file to allow further configuration.
52
+
53
+ If you're not in a rails project you can create the file yourself.
54
+
55
+
56
+ ## Configure
57
+
58
+ Override any of these defaults in `config/initializers/release_notes.rb`:
59
+
60
+ ```ruby
61
+ Release::Notes.configure do |config|
62
+ config.output_file = './RELEASE_NOTES.md'
63
+ config.temp_file = './release-notes.tmp.md'
64
+ config.include_merges = false
65
+ config.ignore_case = true
66
+ config.log_format = '- %s'
67
+ config.extended_regex = true
68
+ config.bug_labels = %w[Fix Update]
69
+ config.feature_labels = %w[Add Create]
70
+ config.misc_labels = %w[Refactor]
71
+ config.bug_title = '**Fixed bugs:**'
72
+ config.feature_title = '**Implemented enhancements:**'
73
+ config.misc_title = '**Miscellaneous:**'
74
+ config.link_to_labels = %w[]
75
+ config.link_to_humanize = %w[]
76
+ config.link_to_sites = %w[]
77
+ config.timezone = 'America/New_York'
78
+ end
79
+ ```
80
+
81
+ For more information about each individual setting checkout Release::Notes's
82
+ [config docs](http://www.rubydoc.info/github/dvmonroe/release-notes/master/Release/Notes/Configuration).
83
+
84
+ ## Usage
85
+
86
+ ### TL;DR
87
+
88
+ ```sh
89
+ bundle exec update_release_notes:run
90
+ ```
91
+
92
+ ### Git Worklow
93
+
94
+ Release::Notes works best with a rebase workflow and requires tagging. General rebase benefits include:
95
+
96
+ * One clear commit per feature, bug or miscellaneous addition to the codebase
97
+ * Commits in logical time manner
98
+
99
+ By default configuration, Release::Notes ignores merges. Along with rebasing, by deafult,
100
+ Release::Notes relies mainly on the subject of a commit. Therefore, it's important to craft concise and
101
+ meaningful commit subjects with longer bodies as needed for larger feature additions or bug fixes.
102
+
103
+ For more information about a rebase workflow or crafting solid commit messages
104
+ check out the following links
105
+
106
+ * [Commit Messages](http://chris.beams.io/posts/git-commit/)
107
+ * [Git Rebase Workflow](https://git-scm.com/book/en/v2/Git-Branching-Rebasing)
108
+
109
+ ### Deploying with Capistrano
110
+
111
+ If using Rails, a rake task is included and would be best utilized within your deploy script.
112
+
113
+ If not on rails, but using rake, you can easily craft your own rake task. At the very least calling
114
+
115
+ ```ruby
116
+ Release::Notes::Update.new.run
117
+ ```
118
+ is the only instance that needs to be instantiated and invoked.
119
+
120
+ A sample capistrano production file might look something like this:
121
+
122
+ ```ruby
123
+ # config/deploy/production.rb
124
+ server 'the_name_for_my_server', user: 'deploy', roles: %w{app web}
125
+
126
+ set :application, 'my_app'
127
+ set :deploy_to, '/var/www/my_app'
128
+
129
+
130
+ namespace :deploy do
131
+ before :starting, :update_release_notes
132
+
133
+ task :update_release_notes do
134
+ sh 'RAILS_ENV=development bin/rake "update_release_notes:run"'
135
+ # run a second task that generates an auto commit
136
+ # this would be created by you
137
+ sh 'RAILS_ENV=development bin/rake "release_notes:commit"'
138
+ end
139
+ end
140
+ ```
141
+
142
+ Useful information can be found here regarding the
143
+ [capistrano flow](http://capistranorb.com/documentation/getting-started/flow/).
144
+
145
+ As you can see above, it's suggested that after generating your release notes you would
146
+ run an automated commit with a rake task like:
147
+
148
+ ```ruby
149
+ # lib/tasks/commit.rake
150
+ `git commit -am "Release to production #{Time.zone.now}"`
151
+ `git push origin master`
152
+ ```
153
+
154
+ From there, make sure you tag your release after the deploy script runs so that your tag
155
+ includes this last commit.
156
+
157
+ ## Note
158
+
159
+ * Your project must tag releases(release-notes uses the tag date to output the changes)
160
+ (PR's to make this more flexible are welcome)
161
+ * Linking is opinionated and will link to a URI structure of `#{site-url}/#{issue_number}`. It
162
+ will ouput something like: `[HONEYBADGER #33150353](https://app.honeybadger.io/projects/9999/faults/33150353)`.
163
+ This also means that your link_to_labels have to be something like `['HB #']` (PR's to make this more flexible are welcome)
164
+
165
+ ## Development
166
+
167
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
168
+
169
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
170
+
171
+ ## Contributing
172
+
173
+ Bug reports and pull requests are welcome on GitHub at https://github.com/dvmonroe/release-notes. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
174
+
175
+
176
+ ## License
177
+
178
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
179
+
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ Dir.glob('lib/tasks/*.rake').each { |r| import r }
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'release/notes'
6
+ require 'pry-byebug'
7
+
8
+ # You can add fixtures and/or initialization code here to make experimenting
9
+ # with your gem easier. You can also use a different console, if you like.
10
+
11
+ # (If you use this, don't forget to add pry to your Gemfile!)
12
+ # require "pry"
13
+ # Pry.start
14
+
15
+ require 'irb'
16
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ require 'rails/generators/base'
3
+
4
+ module Release
5
+ module Notes
6
+ module Generators
7
+ class InstallGenerator < Rails::Generators::Base
8
+ source_root File.expand_path('../templates', __FILE__)
9
+
10
+ def create_release_notes_initializer
11
+ copy_file 'release_notes.rb', 'config/initializers/release_notes.rb'
12
+ end
13
+
14
+ def display_readme
15
+ readme 'README'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ *******************************************************************************
2
+
3
+ Next step:
4
+
5
+ 1. Configure release and tag options :
6
+
7
+ # config/initializers/release_notes.rb
8
+ config.by_tag_date = false
9
+
10
+
11
+ *******************************************************************************
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ Release::Notes.configure do |config|
4
+ # config.output_file = './RELEASE_NOTES.md'
5
+ # config.temp_file = './release-notes.tmp.md'
6
+ # config.include_merges = false
7
+ # config.ignore_case = true
8
+ # config.log_format = '- %s'
9
+ # config.extended_regex = true
10
+ # config.bug_labels = %w[Fix Update]
11
+ # config.feature_labels = %w[Add Create]
12
+ # config.misc_labels = %w[Refactor]
13
+ # config.bug_title = '**Fixed bugs:**'
14
+ # config.feature_title = '**Implemented enhancements:**'
15
+ # config.misc_title = '**Miscellaneous:**'
16
+ # config.link_to_labels = %w[]
17
+ # config.link_to_humanize = %w[]
18
+ # config.link_to_sites = %w[]
19
+ # config.timezone = 'America/New_York'
20
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/time'
5
+
6
+ require 'release/notes/date_format'
7
+ require 'release/notes/link'
8
+ require 'release/notes/pretty_print'
9
+
10
+ require 'release/notes/version'
11
+ require 'release/notes/configuration'
12
+ require 'release/notes/git'
13
+ require 'release/notes/system'
14
+ require 'release/notes/with_configuration'
15
+
16
+ require 'release/notes/write'
17
+ require 'release/notes/log'
18
+
19
+ require 'release/notes/railtie' if defined?(Rails)
20
+
21
+ module Release
22
+ module Notes
23
+ class Update
24
+ attr_reader :logger
25
+
26
+ def initialize
27
+ @options = Release::Notes.configuration
28
+ @logger = Release::Notes::Log.new @options
29
+ end
30
+
31
+ def run
32
+ logger.perform
33
+ end
34
+ end
35
+
36
+ def self.root
37
+ File.expand_path('../..', __FILE__)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Release
4
+ module Notes
5
+ class Configuration
6
+ # The absolute path of your generated log.
7
+ # Defaults to `./RELEASE_NOTES.md`.
8
+ # @return [String]
9
+ attr_accessor :output_file
10
+
11
+ # The absolute path of the temporary generated log.
12
+ # Defaults to `./release-notes.tmp.md`.
13
+ # @return [String]
14
+ attr_accessor :temp_file
15
+
16
+ # Determines whether to print commits with more than one parent.
17
+ # Defaults to `false`. For more, see
18
+ # [Git Log Docs](https://git-scm.com/docs/git-log)
19
+ # @return [Boolean]
20
+ attr_accessor :include_merges
21
+
22
+ # Match the regular expression limiting patterns without regard to letter case
23
+ # when printing your git log.
24
+ # Defaults to `true`. For more, see
25
+ # [Git Log Docs](https://git-scm.com/docs/git-log)
26
+ # @return [Boolean]
27
+ attr_accessor :ignore_case
28
+
29
+ # Consider the limiting patterns to be extended regular expressions patterns
30
+ # when printing your git log.
31
+ # Defaults to `true`. For more, see
32
+ # [Git Log Docs](https://git-scm.com/docs/git-log)
33
+ # @return [Boolean]
34
+ attr_accessor :extended_regex
35
+
36
+ # Allows you to specify what information you want to print from your git log
37
+ # Defaults to `%s` for subject. For more, see
38
+ # [Git Log Docs](https://git-scm.com/docs/git-log)
39
+ # @return [String]
40
+ attr_accessor :log_format
41
+
42
+ # Controls the labels grepped for in your commit subjects that will
43
+ # be add under you bug title
44
+ # Defaults to `%w(Fix Update)`.
45
+ # @return [Array]
46
+ attr_accessor :bug_labels
47
+
48
+ # Controls the labels grepped for in your commit subjects that will
49
+ # be add under you feature title
50
+ # Defaults to `%w(Add Create)`.
51
+ # @return [Array]
52
+ attr_accessor :feature_labels
53
+
54
+ # Controls the labels grepped for in your commit subjects that will
55
+ # be add under you miscellaneous title
56
+ # Defaults to `%w(Refactor)`.
57
+ # @return [Array]
58
+ attr_accessor :misc_labels
59
+
60
+ # Controls the title used in your generated log for all bugs listed
61
+ # Defaults to `**Fixed bugs:**`.
62
+ # @return [String]
63
+ attr_accessor :bug_title
64
+
65
+ # Controls the title used in your generated log for all features listed
66
+ # Defaults to `**Implemented enhancements:**`.
67
+ # @return [String]
68
+ attr_accessor :feature_title
69
+
70
+ # Controls the title used in your generated log for all misc commits listed
71
+ # Defaults to `**Miscellaneous:**`.
72
+ # @return [String]
73
+ attr_accessor :misc_title
74
+
75
+ # The labels grepped for in your commit subject that you want to linkify.
76
+ # The index within the array must match the index for the site
77
+ # in `:link_to_humanize` and `:link_to_sites`.
78
+ # Defaults to `[]`.
79
+ # @return [Array]
80
+ attr_accessor :link_to_labels
81
+
82
+ # The humanized output that you'd like to represent the associated `:link_to_label`
83
+ # The index within the array must match the index for the site
84
+ # in `:link_to_label` and `:link_to_sites`.
85
+ # Defaults to `[]`.
86
+ # @return [Array]
87
+ attr_accessor :link_to_humanize
88
+
89
+ # The url for the site that you'd like to represent the associated `:link_to_label`
90
+ # The index within the array must match the index for the site
91
+ # in `:link_to_label` and `:link_to_humanize`.
92
+ # Defaults to `[]`.
93
+ # @return [Array]
94
+ attr_accessor :link_to_sites
95
+
96
+ # Sets the timezone that should be used for setting the date.
97
+ # Defaults to `America/New_York`. For more, see
98
+ # [ActiveSupport Time Zones](http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html)
99
+ # @return [String]
100
+ attr_accessor :timezone
101
+
102
+ # Controls whether your commit subject labels should be removed from the final
103
+ # ouput of your message on the generated log.
104
+ # Defaults to `true`.
105
+ # @return [Boolean]
106
+ attr_accessor :prettify_messages
107
+
108
+ def initialize
109
+ @output_file = './RELEASE_NOTES.md'
110
+ @temp_file = './release-notes.tmp.md'
111
+ @include_merges = false
112
+ @ignore_case = true
113
+ @extended_regex = true
114
+ @log_format = '- %s'
115
+ @bug_labels = %w[Fix Update]
116
+ @feature_labels = %w[Add Create]
117
+ @misc_labels = %w[Refactor]
118
+ @bug_title = '**Fixed bugs:**'
119
+ @feature_title = '**Implemented enhancements:**'
120
+ @misc_title = '**Miscellaneous:**'
121
+ @link_to_labels = %w[]
122
+ @link_to_humanize = %w[]
123
+ @link_to_sites = %w[]
124
+ @timezone = 'America/New_York'
125
+ @prettify_messages = true
126
+ end
127
+
128
+ # @return [String]
129
+ def include_merges?
130
+ @include_merges ? '' : '--no-merges'
131
+ end
132
+
133
+ # @return [String]
134
+ def regex_type
135
+ @extended_regex ? '-E' : ''
136
+ end
137
+
138
+ # @return [String]
139
+ def grep_insensitive?
140
+ @ignore_case ? '-i' : ''
141
+ end
142
+
143
+ # @return [String]
144
+ def bugs
145
+ @bugs ||= generate_regex(@bug_labels)
146
+ end
147
+
148
+ # @return [String]
149
+ def features
150
+ @features ||= generate_regex(@feature_labels)
151
+ end
152
+
153
+ # @return [String]
154
+ def misc
155
+ @misc ||= generate_regex(@misc_labels)
156
+ end
157
+
158
+ # @return [String]
159
+ def all_labels
160
+ @all_labels ||= generate_regex(@bug_labels + @feature_labels + @misc_labels)
161
+ end
162
+
163
+ # @return [Boolean]
164
+ def release_notes_exist?
165
+ File.exist? output_file
166
+ end
167
+
168
+ # @return [Boolean]
169
+ def link_commits?
170
+ link_to_labels.present? && link_to_humanize.present? &&
171
+ link_to_sites.present?
172
+ end
173
+
174
+ # @return [Boolean]
175
+ def prettify_messages?
176
+ @prettify_messages
177
+ end
178
+
179
+ private
180
+
181
+ # @api private
182
+ # Using over Regexp.union
183
+ def generate_regex(arr)
184
+ arr.join('|').insert(0, '(').insert(-1, ')')
185
+ end
186
+ end
187
+
188
+ # @return [Release::Notes::Configuration] Release::Notes's current configuration
189
+ def self.configuration
190
+ @configuration ||= Configuration.new
191
+ end
192
+
193
+ # Set Release::Notes's configuration
194
+ # @param config [Release::Notes::Configuration]
195
+ def self.configuration=(config)
196
+ @configuration = config
197
+ end
198
+
199
+ # Modify Release::Notes's current configuration
200
+ # @yieldparam [Release::Notes] config current Release::Notes config
201
+ # ```
202
+ # Release::Notes.configure do |config|
203
+ # config.routes = false
204
+ # end
205
+ # ```
206
+ def self.configure
207
+ yield configuration
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Release
4
+ module Notes
5
+ class DateFormat
6
+ attr_reader :config, :time_now
7
+ delegate :timezone, to: :config
8
+
9
+ def initialize(config)
10
+ @config = config
11
+ Time.zone = timezone
12
+
13
+ @time_now = Time.zone.now
14
+ end
15
+
16
+ def date_humanized(date: nil)
17
+ date = date.present? ? Time.zone.parse(date) : time_now
18
+ date.strftime('%B %d, %Y %r %Z')
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Release
4
+ module Notes
5
+ module Git
6
+ module_function
7
+
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ delegate :log_format, :grep_insensitive?, :regex_type, :include_merges?, to: :config
12
+
13
+ def log(**opts)
14
+ "git log '#{opts[:tag_from]}'..'#{opts[:tag_to]}' --grep='#{opts[:label]}'" \
15
+ " #{regex_type} #{grep_insensitive?}" \
16
+ " #{include_merges?} --format='#{log_format}'"
17
+ end
18
+ end
19
+
20
+ def last_tag
21
+ 'git describe --abbrev=0 --tags'
22
+ end
23
+
24
+ def tag_date(tag)
25
+ "git log -1 --format=%ai #{tag}"
26
+ end
27
+
28
+ def read_all_tags
29
+ 'git tags | sort -u -r'
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Release
4
+ module Notes
5
+ module Link
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ delegate :link_to_labels, :link_to_sites, :link_to_humanize, to: :config
10
+
11
+ def link_lines(lines:)
12
+ new_lines = ''
13
+ lines.split("\n").each do |line|
14
+ unless link_to_labels.any? { |la| line.include? la }
15
+ new_lines += "#{line}\n"
16
+ next
17
+ end
18
+ link_to_labels.each_with_index do |label, i|
19
+ next unless line.include? label
20
+ words = line.split(/\s/)
21
+ words.each do |word|
22
+ next unless (word =~ /^#.*/)&.zero?
23
+ new_lines += "#{replace(line, word, label, i)}\n"
24
+ end
25
+ end
26
+ end
27
+ new_lines
28
+ end
29
+
30
+ private
31
+
32
+ # @api private
33
+ def replace(line, issue_number, label, index)
34
+ identifier = "#{label.split(/\s/)[0]} #{issue_number}"
35
+ humanized = "#{link_to_humanize[index]} #{issue_number}"
36
+ linked = "[#{humanized}](#{link_to_sites[index]})"
37
+
38
+ line.gsub! identifier, linked
39
+ line
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Release
4
+ module Notes
5
+ class Log
6
+ include System
7
+ include WithConfiguration
8
+
9
+ attr_reader :config, :writer, :date_formatter
10
+ attr_reader :all_tags
11
+
12
+ delegate :all_labels, :features, :bugs, :misc, :feature_title,
13
+ :bug_title, :misc_title, :release_notes_exist?, to: :config
14
+
15
+ delegate :date_humanized, :format_tag_date, to: :date_formatter
16
+ delegate :digest, to: :writer
17
+
18
+ def initialize(config)
19
+ @config = config
20
+
21
+ setup_writer
22
+ setup_date_formatter
23
+ end
24
+
25
+ def perform
26
+ if release_notes_exist?
27
+ # Find the last tag and group all commits
28
+ # under a date header at the time this is run
29
+ find_last_tag_and_log
30
+ else
31
+ # Find all tags and get the logs between each tag
32
+ # run this the first time if nothing exists
33
+ find_all_tags_and_log_all
34
+ end
35
+ writer.write_new_file
36
+ end
37
+
38
+ private
39
+
40
+ def all_tags
41
+ @all_tags ||= System.all_tags.split("\n")
42
+ # return Error.new(msg: :missing_tags) unless all_tags.present?
43
+ end
44
+
45
+ # @api private
46
+ def copy_single_tag_of_activity(tag_from:, tag_to: nil)
47
+ tag_to ||= 'HEAD'
48
+ [features, bugs, misc].each_with_index do |regex, i|
49
+ log = system_call(tag_from: tag_from, tag_to: tag_to, label: regex)
50
+ digest(date: nil, title: titles[i], log_message: log) if log.present?
51
+ end
52
+ end
53
+
54
+ # @api private
55
+ def find_last_tag_and_log
56
+ last_tag = system_last_tag.delete!("\n")
57
+ return false unless system_call(tag_from: last_tag, label: all_labels).present?
58
+
59
+ # output the date right now
60
+ digest date: date_humanized
61
+ copy_single_tag_of_activity(tag_from: last_tag)
62
+ end
63
+
64
+ # @api private
65
+ def setup_writer
66
+ @writer = Release::Notes::Write.new config
67
+ end
68
+
69
+ # @api private
70
+ def setup_date_formatter
71
+ @date_formatter = Release::Notes::DateFormat.new config
72
+ end
73
+
74
+ # @api private
75
+ def find_all_tags_and_log_all
76
+ all_tags.each_with_index do |ta, i|
77
+ previous_tag = all_tags[i + 1]
78
+ next unless previous_tag.present? &&
79
+ system_call(tag_from: previous_tag, tag_to: ta, label: all_labels).present?
80
+
81
+ digest date: date_humanized(date: System.tag_date(tag: ta))
82
+ copy_single_tag_of_activity(tag_from: previous_tag, tag_to: ta)
83
+ end
84
+ end
85
+
86
+ # @api private
87
+ def system_call(**opts)
88
+ with_config(config: config) do
89
+ system_log(opts)
90
+ end
91
+ end
92
+
93
+ # @api private
94
+ def titles
95
+ [feature_title, bug_title, misc_title]
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Release
4
+ module Notes
5
+ module PrettyPrint
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ delegate :all_labels, to: :config
10
+
11
+ def prettify(line:)
12
+ line.gsub(labels_regex, '').strip
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ # @api private
19
+ def labels_regex
20
+ Regexp.new all_labels, Regexp::IGNORECASE
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Release
4
+ module Notes
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ load 'tasks/update_release_notes.rake'
8
+ end
9
+
10
+ generators do
11
+ require 'generators/release/notes/install/install_generator.rb'
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Release
4
+ module Notes
5
+ module System
6
+ module_function
7
+
8
+ extend ActiveSupport::Concern
9
+ include Git
10
+
11
+ included do
12
+ def system_log(**opts)
13
+ `#{log(opts)}`
14
+ end
15
+ end
16
+
17
+ def all_tags
18
+ `#{Git.read_all_tags}`
19
+ end
20
+
21
+ def system_last_tag
22
+ `#{Git.last_tag}`
23
+ end
24
+
25
+ def tag_date(tag: nil)
26
+ tag ||= system_last_tag
27
+ `#{Git.tag_date(tag)}`
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Release
4
+ module Notes
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Release
4
+ module Notes
5
+ module WithConfiguration
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attr_reader :config, :date_formatter
10
+
11
+ def with_config(**opts, &_block)
12
+ @confg = opts.fetch(:config, {})
13
+ yield
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Release
4
+ module Notes
5
+ class Write
6
+ include Link
7
+ include PrettyPrint
8
+ include WithConfiguration
9
+
10
+ attr_accessor :config
11
+
12
+ delegate :output_file, :temp_file, :link_commits?, :all_labels,
13
+ :prettify_messages?, :release_notes_exist?, to: :config
14
+
15
+ def initialize(config)
16
+ @config = config
17
+ # create a new temp file regardless if it exists
18
+ new_temp_file_template
19
+ end
20
+
21
+ def digest(date: nil, title: nil, log_message: nil)
22
+ File.open(temp_file, 'a') do |fi|
23
+ fi << "\n\n## #{date}\n" if date
24
+ fi << "\n#{title}\n\n" if title && !date
25
+ fi << "#{title}\n\n" if title && date
26
+
27
+ break unless log_message
28
+ # link messages if needed
29
+ msg = link_message log_message
30
+ # remove tags if needed
31
+ msg = with_config(config: config) { prettify(line: msg) } if prettify_messages?
32
+ fi << "#{msg}\n"
33
+ end
34
+ end
35
+
36
+ # append old file to new temp file
37
+ # overwrite output file with tmp file
38
+ def write_new_file
39
+ copy_over_notes if release_notes_exist?
40
+
41
+ FileUtils.cp(temp_file, output_file)
42
+ FileUtils.rm temp_file
43
+ end
44
+
45
+ private
46
+
47
+ # @api private
48
+ def copy_over_notes
49
+ File.open(temp_file, 'a') do |f|
50
+ f << "\n"
51
+ IO.readlines(output_file)[2..-1].each { |line| f << line }
52
+ end
53
+ end
54
+
55
+ # @api private
56
+ def link_message(log_message)
57
+ return log_message unless link_commits?
58
+ with_config(config: config) do
59
+ link_lines(lines: log_message)
60
+ end
61
+ end
62
+
63
+ # @api private
64
+ def new_temp_file_template
65
+ File.new(temp_file, 'w')
66
+ File.open(temp_file, 'a') do |fi|
67
+ fi << "# Release Notes\n----------------------"
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :update_release_notes do
4
+ task run: :environment do
5
+ Release::Notes::Update.new.run
6
+ end
7
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'release/notes/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "release-notes"
8
+ spec.version = Release::Notes::VERSION
9
+ spec.authors = ["Drew Monroe"]
10
+ spec.email = ["dvmonroe6@gmail.com"]
11
+
12
+ spec.summary = "Release notes for stakeholders"
13
+ spec.description = spec.summary
14
+ spec.homepage = "http://github.com/dvmonroe/release-notes"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency 'activesupport'
23
+ spec.add_development_dependency 'bundler', '~> 1.12'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: release-notes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Drew Monroe
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-05-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.12'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.12'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: Release notes for stakeholders
56
+ email:
57
+ - dvmonroe6@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".ruby-version"
65
+ - ".travis.yml"
66
+ - ".yardopts"
67
+ - CODE_OF_CONDUCT.md
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - bin/console
73
+ - bin/setup
74
+ - lib/generators/release/notes/install/install_generator.rb
75
+ - lib/generators/release/notes/install/templates/README
76
+ - lib/generators/release/notes/install/templates/release_notes.rb
77
+ - lib/release/notes.rb
78
+ - lib/release/notes/configuration.rb
79
+ - lib/release/notes/date_format.rb
80
+ - lib/release/notes/git.rb
81
+ - lib/release/notes/link.rb
82
+ - lib/release/notes/log.rb
83
+ - lib/release/notes/pretty_print.rb
84
+ - lib/release/notes/railtie.rb
85
+ - lib/release/notes/system.rb
86
+ - lib/release/notes/version.rb
87
+ - lib/release/notes/with_configuration.rb
88
+ - lib/release/notes/write.rb
89
+ - lib/tasks/update_release_notes.rake
90
+ - release-notes.gemspec
91
+ homepage: http://github.com/dvmonroe/release-notes
92
+ licenses:
93
+ - MIT
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.6.10
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Release notes for stakeholders
115
+ test_files: []