gem_comet 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d7a15101d967116039e1422a45b92f8a19586185c72ebb8021fdfd80bb8ac5c
4
- data.tar.gz: 92f16b1fd992bf85f78338b3aa9d99f31e45e781cfdcc71fedde71aae5c6c3d6
3
+ metadata.gz: d4002b63773d5efc2b2c6cb8367b7f4fedc6222f8fc43ccee41eb83497e2deee
4
+ data.tar.gz: 6319c6d3b7ff584c6c80da5349639778aabdb580807cd2688508e2d3dded71b1
5
5
  SHA512:
6
- metadata.gz: 45c08cdafd4f92b80e9a8a1cf019f3a82aaead26237bc586edb1febc8c408fe2433e608bc67d7530e2346a8a41c1feefa03cda79782561a8c4f27520a0f076d8
7
- data.tar.gz: 1d9bd7f8d16acb80ec7bc3505a76270b0a4d8d09a32ec5326f5f617c9618e0557a586c87b56cefcc3a6e1b6a6f3882083e6efd7cc09aae48bd0474d1df0b7b73
6
+ metadata.gz: 590973c76a9a238d97550c5ec6b90f441ab8e3499c2fb5f297d6e8b7d5f50d086d2d98b5305cb5e6646fabf8a7467fb00f433dc3f2964dffa6e438f02b005d88
7
+ data.tar.gz: b3eb0b0b8cab1d370136b82ce34faa0e33a8905fbfc89cf1c9b04ed19663d378670b6c31af88a11d4ce64dad5b3cb6c4b665a01a67fdc6844867f592a10770d1
@@ -1,6 +1,7 @@
1
- version: 1
1
+ version: 1.1
2
2
 
3
3
  release:
4
4
  base_branch: master
5
5
  release_branch: release
6
6
  version_file_path: lib/gem_comet/version.rb
7
+ changelog_file_path: CHANGELOG.md
@@ -0,0 +1,26 @@
1
+ # Change log
2
+
3
+ ## 0.2.0 (Oct 14, 2019)
4
+
5
+ ### Feature
6
+
7
+ * Auto generate change log ([#22](https://github.com/ryz310/gem_comet/pull/22))
8
+
9
+ ## 0.1.1 (Oct 13, 2019)
10
+
11
+ ### Bugfix
12
+
13
+ * Fix version number validation ([#16](https://github.com/ryz310/gem_comet/pull/16))
14
+
15
+ ### Misc
16
+
17
+ * Re-generate .rubocop_todo.yml with RuboCop v0.73.0 ([#3](https://github.com/ryz310/gem_comet/pull/3))
18
+ * Re-generate .rubocop_todo.yml with RuboCop v0.74.0 ([#5](https://github.com/ryz310/gem_comet/pull/5))
19
+ * Re-generate .rubocop_todo.yml with RuboCop v0.75.0 ([#13](https://github.com/ryz310/gem_comet/pull/13))
20
+ * ryz310/dependabot/bundler/rake-tw-13.0 ([#9](https://github.com/ryz310/gem_comet/pull/9))
21
+ * ryz310/dependabot/bundler/rubocop-performance-1.5.0 ([#14](https://github.com/ryz310/gem_comet/pull/14))
22
+ * ryz310/dependabot/bundler/rspec-3.9.0 ([#17](https://github.com/ryz310/gem_comet/pull/17))
23
+
24
+ ## 0.1.0 (Jul 16, 2019)
25
+
26
+ Initial release :rocket:
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gem_comet (0.1.1)
4
+ gem_comet (0.2.0)
5
5
  pr_comet (~> 0.3.0)
6
6
  thor
7
7
  type_struct
data/README.md CHANGED
@@ -2,29 +2,49 @@
2
2
 
3
3
  # GemComet
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/gem_comet`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+ The `gem_comet` is a command line tool which to update and release your gem.
6
+ Install as following:
6
7
 
7
- TODO: Delete this and the text above, and describe your gem
8
+ ```
9
+ $ gem install 'gem_comet'
10
+ ```
8
11
 
9
- ## Installation
12
+ Initialize `gem_comet` as following:
10
13
 
11
- Add this line to your application's Gemfile:
14
+ ```
15
+ $ gem_comet init
16
+ ```
12
17
 
13
- ```ruby
14
- gem 'gem_comet'
18
+ Then, edit the created file: `.gem_comet.yml` as following.
19
+
20
+ ```yaml
21
+ version: 1
22
+
23
+ release:
24
+ base_branch: master
25
+ release_branch: release
26
+ version_file_path: { Path of the version file. e.g. lib/gem_comet/version.rb }
15
27
  ```
16
28
 
17
- And then execute:
29
+ ## Usage
30
+
31
+ ### Display changelogs
18
32
 
19
- $ bundle
33
+ Displays changelogs from last release to HEAD commit.
20
34
 
21
- Or install it yourself as:
35
+ ```
36
+ $ gem_comet changelog
37
+ ```
22
38
 
23
- $ gem install gem_comet
39
+ ### Release
24
40
 
25
- ## Usage
41
+ Creates update PR and release PR.
42
+
43
+ ```
44
+ $ gem_comet release { The version number you want to release. e.g. "1.2.3" }
45
+ ```
26
46
 
27
- TODO: Write usage instructions here
47
+ Then, you should check pull requests on your GitHub repository page. You will see two pull requests: "Update v1.2.3" and "Release v1.2.3". First, you should check "Update v1.2.3" and merge. Next, you should check "Release v1.2.3" and merge. The "Release v1.2.3" destination is the release branch. You should set up CI that to deploy the gem automatically.
28
48
 
29
49
  ## Development
30
50
 
@@ -2,11 +2,15 @@
2
2
 
3
3
  require 'thor'
4
4
  require 'type_struct'
5
+ require 'type_struct/ext'
5
6
  require 'pr_comet'
6
7
  require 'yaml'
7
8
  require 'gem_comet/version'
8
9
  require 'gem_comet/service_abstract'
9
10
  require 'gem_comet/config'
11
+ require 'gem_comet/version_editor'
12
+ require 'gem_comet/changelog_editor'
13
+ require 'gem_comet/changelog_generator'
10
14
  require 'gem_comet/release'
11
15
  require 'gem_comet/release/update_pr'
12
16
  require 'gem_comet/release/release_pr'
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GemComet
4
+ # Edits CHANGELOG.md file of gem
5
+ class ChangelogEditor
6
+ HEADER = "# Change log\n"
7
+
8
+ attr_reader :changelog_file_path
9
+
10
+ def initialize
11
+ @changelog_file_path = Config.call.release.changelog_file_path
12
+ end
13
+
14
+ # Appends the content to CHANGELOG.md.
15
+ #
16
+ # @param content [String] Character string you want to append
17
+ def append!(content:)
18
+ return if changelog_file_path.nil?
19
+
20
+ changelog_file = File.read(changelog_file_path)
21
+ position = changelog_file.index(HEADER) + HEADER.length
22
+ changelog_file.insert(position, content)
23
+ File.write(changelog_file_path, changelog_file)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GemComet
4
+ # Generates changelog from git log
5
+ class ChangelogGenerator < ServiceAbstract
6
+ attr_reader :last_label, :new_version
7
+
8
+ # @param current_version [String] Current version of your gem
9
+ # @param new_version [String] Next version of your gem
10
+ def initialize(current_version:, new_version: nil)
11
+ @last_label = "v#{current_version}"
12
+ @new_version = new_version || 'NEW'
13
+ end
14
+
15
+ private
16
+
17
+ MERGE_COMMIT_TITLE = /Merge pull request #(\d+) from (.+)/.freeze
18
+
19
+ # Returns changelogs as markdown format from current version to HEAD commit.
20
+ #
21
+ # @return [String] Changelogs as markdown format
22
+ def call
23
+ <<~MARKDOWN
24
+
25
+ ## #{new_version} (#{Date.today.strftime('%b %d, %Y')})
26
+
27
+ ### Feature
28
+ ### Bugfix
29
+ ### Breaking Change
30
+ ### Misc
31
+
32
+ #{changelogs.reverse.join("\n")}
33
+
34
+ MARKDOWN
35
+ end
36
+
37
+ # Returns array of changelogs as markdown format.
38
+ #
39
+ # @return [Array<String>] Array of changelogs as markdown format
40
+ def changelogs
41
+ merge_commits.map do |merge_commit|
42
+ next unless merge_commit.match?(MERGE_COMMIT_TITLE)
43
+
44
+ pull_request_number = extract_pull_request_number(merge_commit)
45
+ pull_request_url = get_pull_request_url(pull_request_number)
46
+ description = extract_description(merge_commit) || extract_branch_name(merge_commit)
47
+
48
+ "* #{description} ([##{pull_request_number}](#{pull_request_url}))"
49
+ end.compact
50
+ end
51
+
52
+ # Extracts PR number from merge commit string.
53
+ #
54
+ # @param merge_commit [String] The target string
55
+ # @return [Integer] The pull request number
56
+ def extract_pull_request_number(merge_commit)
57
+ MERGE_COMMIT_TITLE.match(merge_commit).captures.first.to_i
58
+ end
59
+
60
+ # Get the PR URL. (e.g. https://github.com/ryz310/gem_comet/pull/1)
61
+ #
62
+ # @param pull_request_number [Integer] The target pull request number
63
+ # @return [String] Returns the URL
64
+ def get_pull_request_url(pull_request_number)
65
+ "#{origin_url}/pull/#{pull_request_number}"
66
+ end
67
+
68
+ # Extracts commit desciption from merge commit string.
69
+ #
70
+ # @param merge_commit [String] The target string
71
+ # @return [String] The commit description
72
+ # @return [nil] Returns `nil` if not exists
73
+ def extract_description(merge_commit)
74
+ description = merge_commit.lines.last
75
+ description&.chomp&.strip unless description.match?(MERGE_COMMIT_TITLE)
76
+ end
77
+
78
+ # Extracts the PR branch name from merge commit string.
79
+ #
80
+ # @param merge_commit [String] The target string
81
+ # @return [String] Branch name
82
+ def extract_branch_name(merge_commit)
83
+ MERGE_COMMIT_TITLE.match(merge_commit).captures.last.chomp.strip
84
+ end
85
+
86
+ # Parces the merge commit log, which to separate by each commit.
87
+ #
88
+ # @return [Array<String>] Array of git commit log
89
+ def merge_commits
90
+ merge_commit_log.split(/^commit \w{40}\n/).reject(&:empty?).map(&:chomp)
91
+ end
92
+
93
+ # Returns only merge commit logs via git command.
94
+ #
95
+ # @return [String] Get only merge commit logs
96
+ def merge_commit_log
97
+ @merge_commit_log ||= `git log --merges #{last_label}..HEAD`
98
+ end
99
+
100
+ # Returns the git origin URL via git command.
101
+ #
102
+ # @return [String] The origin URL
103
+ def origin_url
104
+ @origin_url ||= `git remote get-url --push origin`.sub('.git', '').chomp
105
+ end
106
+ end
107
+ end
@@ -13,6 +13,7 @@ module GemComet
13
13
  def init
14
14
  template '../../template/.gem_comet.yml.erb', '.gem_comet.yml',
15
15
  version: GemComet::Config::CURRENT_VERSION
16
+ template '../../template/CHANGELOG.md.erb', 'CHANGELOG.md'
16
17
  end
17
18
 
18
19
  desc 'release VERSION', 'Creates update PR and release PR'
@@ -20,6 +21,12 @@ module GemComet
20
21
  Release.call(version: version)
21
22
  end
22
23
 
24
+ desc 'changelog', 'Displays changelogs from last release to HEAD commit'
25
+ def changelog
26
+ version_editor = VersionEditor.new
27
+ puts ChangelogGenerator.call(current_version: version_editor.current_version)
28
+ end
29
+
23
30
  desc 'version', 'Shows current version'
24
31
  def version
25
32
  puts GemComet::VERSION
@@ -3,32 +3,32 @@
3
3
  module GemComet
4
4
  # Loads the config file
5
5
  class Config < ServiceAbstract
6
- CURRENT_VERSION = 1
6
+ using TypeStruct::Union::Ext
7
7
 
8
- V1 = TypeStruct.new(
9
- version: CURRENT_VERSION,
8
+ CONFIG_FILE_PATH = '.gem_comet.yml'
9
+ CURRENT_VERSION = 1.1
10
+
11
+ V1_1 = TypeStruct.new(
12
+ version: 1.0...2.0,
10
13
  release: TypeStruct.new(
11
14
  base_branch: String,
12
15
  release_branch: String,
13
- version_file_path: String
16
+ version_file_path: String,
17
+ changelog_file_path: String | nil
14
18
  )
15
19
  )
16
20
 
17
- private
18
-
19
- attr_reader :file_path
21
+ def initialize; end
20
22
 
21
- def initialize(file_path:)
22
- @file_path = file_path
23
- end
23
+ private
24
24
 
25
25
  def call
26
- V1.from_hash(YAML.safe_load(File.open(file_path)))
26
+ V1_1.from_hash(YAML.safe_load(File.open(CONFIG_FILE_PATH)))
27
27
  rescue Errno::ENOENT
28
28
  raise 'Not initialized. Please run `$ gem_comet init`.'
29
29
  rescue TypeStruct::MultiTypeError => e
30
30
  puts e.message
31
- raise "Unexpected file format. Please check your '#{file_path}'."
31
+ raise "Unexpected file format. Please check your '#{CONFIG_FILE_PATH}'."
32
32
  end
33
33
  end
34
34
  end
@@ -3,19 +3,17 @@
3
3
  module GemComet
4
4
  # Creates pull requests for gem release and that preparation
5
5
  class Release < ServiceAbstract
6
- CONFIG_FILE_PATH = '.gem_comet.yml'
7
-
8
- private
9
-
10
- attr_reader :version, :config
11
-
12
6
  def initialize(version:)
13
7
  verify_version_number(version)
14
8
 
15
9
  @version = version
16
- @config = Config.call(file_path: CONFIG_FILE_PATH)
10
+ @config = Config.call
17
11
  end
18
12
 
13
+ private
14
+
15
+ attr_reader :version, :config
16
+
19
17
  def call
20
18
  UpdatePR.call(update_pr_args)
21
19
  ReleasePR.call(release_pr_args)
@@ -24,8 +22,7 @@ module GemComet
24
22
  def update_pr_args
25
23
  {
26
24
  version: version,
27
- base_branch: config.release.base_branch,
28
- version_file_path: config.release.version_file_path
25
+ base_branch: config.release.base_branch
29
26
  }
30
27
  end
31
28
 
@@ -4,30 +4,37 @@ module GemComet
4
4
  class Release
5
5
  # Creates a pull request for release preparation
6
6
  class UpdatePR < ServiceAbstract
7
- private
8
-
9
- attr_reader :version, :pr_comet, :version_file_path
10
-
11
- def initialize(version:, base_branch:, version_file_path:)
7
+ def initialize(version:, base_branch:)
12
8
  @version = version
13
9
  @pr_comet = PrComet.new(base: base_branch, branch: "update/v#{version}")
14
- @version_file_path = version_file_path
10
+ @version_editor = VersionEditor.new
11
+ @changelog_editor = ChangelogEditor.new
15
12
  end
16
13
 
14
+ private
15
+
16
+ attr_reader :version, :pr_comet, :version_editor, :changelog_editor
17
+
17
18
  def call
19
+ update_changelog
18
20
  update_version_file
19
21
  bundle_update
20
22
  create_pull_request
21
23
  end
22
24
 
25
+ def update_changelog
26
+ pr_comet.commit ':comet: Update CHANGELOG.md' do
27
+ changelog = ChangelogGenerator.call(
28
+ current_version: version_editor.current_version,
29
+ new_version: version
30
+ )
31
+ changelog_editor.append!(content: changelog)
32
+ end
33
+ end
34
+
23
35
  def update_version_file
24
36
  pr_comet.commit ':comet: Update version number' do
25
- version_file = File.read(version_file_path)
26
- version_file.sub!(
27
- /VERSION\s*=\s*(['"])(.+?)(['"])/,
28
- "VERSION = \\1#{version}\\3"
29
- )
30
- File.write(version_file_path, version_file)
37
+ version_editor.update!(new_version: version)
31
38
  end
32
39
  end
33
40
 
@@ -3,6 +3,8 @@
3
3
  module GemComet
4
4
  # The abstract class for service classes
5
5
  class ServiceAbstract
6
+ private_class_method :new
7
+
6
8
  def self.call(*args)
7
9
  new(*args).send(:call)
8
10
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GemComet
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GemComet
4
+ # Edits version file of the gem
5
+ class VersionEditor
6
+ attr_reader :version_file_path
7
+
8
+ VERSION_NUMBER_PATTERN = /VERSION\s*=\s*(['"])(.+?)(['"])/.freeze
9
+
10
+ def initialize
11
+ @version_file_path = Config.call.release.version_file_path
12
+ end
13
+
14
+ # Reads the current version number of gem
15
+ #
16
+ # @return [String] The current version number
17
+ def current_version
18
+ version_file = File.read(version_file_path)
19
+ VERSION_NUMBER_PATTERN.match(version_file).captures[1]
20
+ end
21
+
22
+ # Updates the version number of gem
23
+ #
24
+ # @param new_version [String] The next version number
25
+ def update!(new_version:)
26
+ version_file = File.read(version_file_path)
27
+ version_file.sub!(VERSION_NUMBER_PATTERN, "VERSION = \\1#{new_version}\\3")
28
+ File.write(version_file_path, version_file)
29
+ end
30
+ end
31
+ end
@@ -9,3 +9,4 @@ release:
9
9
  base_branch: master
10
10
  release_branch: release
11
11
  version_file_path: '{Path of your version file}'
12
+ changelog_file_path: CHANGELOG.md # optional
@@ -0,0 +1 @@
1
+ # Change log
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem_comet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ryz310
@@ -207,6 +207,7 @@ files:
207
207
  - ".rspec"
208
208
  - ".rubocop.yml"
209
209
  - ".rubocop_todo.yml"
210
+ - CHANGELOG.md
210
211
  - CODE_OF_CONDUCT.md
211
212
  - Gemfile
212
213
  - Gemfile.lock
@@ -218,6 +219,8 @@ files:
218
219
  - exe/gem_comet
219
220
  - gem_comet.gemspec
220
221
  - lib/gem_comet.rb
222
+ - lib/gem_comet/changelog_editor.rb
223
+ - lib/gem_comet/changelog_generator.rb
221
224
  - lib/gem_comet/cli.rb
222
225
  - lib/gem_comet/config.rb
223
226
  - lib/gem_comet/release.rb
@@ -225,7 +228,9 @@ files:
225
228
  - lib/gem_comet/release/update_pr.rb
226
229
  - lib/gem_comet/service_abstract.rb
227
230
  - lib/gem_comet/version.rb
231
+ - lib/gem_comet/version_editor.rb
228
232
  - template/.gem_comet.yml.erb
233
+ - template/CHANGELOG.md.erb
229
234
  homepage: https://github.com/ryz310/gem_comet
230
235
  licenses:
231
236
  - MIT