cookbook-release 1.4.1 → 1.5.1

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
- SHA1:
3
- metadata.gz: ef4f876c9097c92b3f1531e562f575d0f607fec7
4
- data.tar.gz: 80314fba7113d9b8134aeb467c0973ad3cf3734f
2
+ SHA256:
3
+ metadata.gz: '0438ab5b35c35ac88fbc7f99b58e43882fe7fc2cb2d4299ed1d609cd0b702d4d'
4
+ data.tar.gz: 7390fd2694a610a5ac4fe0b81f4fdc6e7cbee9e4381d96f7b0ff9573f7c70cd0
5
5
  SHA512:
6
- metadata.gz: f0e4ec14d3d2759e8cd7f357d06a0e5ecdd30d6b90c8b16afdf486bb60dca6586f0de89b6dd69e66085a71f52eee9a75d57ba35d57df67f36b9d654c8102689d
7
- data.tar.gz: be592e21c15ec5022533001a738157d2afc91857238f3b9a3ee2b5c414c4a544c1ebae3bed21c197e6ca9c53b0b71bc381ef8a4dbe2ddcf9f80275e6817c5f2e
6
+ metadata.gz: 27ff8bf88d9e8453cfa5a46b45dd74e59ac5a8ba5e18b4b988b4acdf2a6b7d7b4e29c057ad73e402fcec7065b1662d5b8003496e100ce8592787da8441ab2a5f
7
+ data.tar.gz: 6e44f603a8aa0801968d3eea30574ef3b0c8751cb98c80b2d9f57f2511e80414d0f1cf978b4688105a58140c3e8123eb1437eeed355bb2507f85b5b53c181e23
data/.travis.yml CHANGED
@@ -1,13 +1,12 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.4.0
4
- before_install:
5
- - rvm @global do gem install bundler -v 1.15.4
3
+ - 2.4.0
6
4
  deploy:
7
5
  provider: rubygems
8
6
  api_key:
9
- secure: nrEzm2dqWjyaa5ewApSonF+2D+y3PYwt9xaQC04d1NtbhQYyzX6wti3oatpMJI2gkcuuLjKrNHH/aLbKOGv7+Jj5BUJGOLixxhRdJyLWde/6cKCYVgIYPxeUtSJrRgyHAS2o8TDPjhWCT5oRwSkmhd+5D2JKjVqAycetbIzKWWvqScO09z0bF66bbKSfO1s44JwKjnUUW7W9tzrPvMPouBBoFtQ+dQVgxYLajgmjprVvIwzlHxgq/zP8YwL8i7vyRJFiQXyveSxZfBagN2qrUM72HWBPLLW4AeAdLDHYWon88GDU0p+cy2mVeSe67fBPVDopAEGij7MNJCBWV1/SRRKQcEb2U823+1GSB13OvaOGTn9rYsJP5zLKu77ATbHPi22nMfWOAzdEJJ+uFu9XW4nwUO/j79zPC1mEsRZDJlDrmTc4XZQJRKkCUjSl/J53vbdy4JQfos8B2V15tzx1baswQVPZuNiwuP4dOupI34FohJSVXQrsOoWVWVEX5Tfod6s3kpivW6lzwM68I2qXFa/4H8RPU2m0eVpfQslOO8TaGnbodudbQ1LSi/d5W6XWrMVqWGH910JG3jlJgHn5J7yQlI4VqnOpCjGsx/5xincuJZ7hBhcu5q5zcAGem7TrYSNkrx6neBYKmpZBHOWalIGw8wI9uViEsGQ6fayFee8=
7
+ secure: ylfB0GIaZxPfZ6/dSJIPujfSt3vxqVFg16lqTBq/2AAZ0qwKTZi9qeM/QZDLMX28vCXmTsYxHGepmyvv0PvJaKvy7E6YBzIKz1Y1vsEZFeAFrgIQq9cDvc4wIX2eFjI7N1ChyaRgi+YYK4BSVfKjYqGBfXk5Wyh7uqNEuWE7FzABV+RxXoHcNi+AhYkCX3NF80qNukXRtiB7XTQj6CP4Wd+Dm25iOUwx8/zNMce8Z8V3j2ysvR4Vtm/soDsr/+Z+27wIdP0VqwElV1FxtR9km8MIJhmzSsnzcvgqJpRmMvO6HLZFzwqnLBzCoPYJqm3K+uQSSfll5LbaNtixlBzIusgtGgm1UjQy1YDGkPexJd5K5CuC/LW78Y7Zrl3CeT34RDlICoztEjhJxFry3EvFxPT03lVQx5z5Fc55/u0hy3mBCiHbxHxAPJLMOtehfv35bzOS7Jv3+otBm/8jn9dXO2pJJdwxL9W2wrzljWkly4yemwceMvtMYf+xnf1zdTnMYoqkYGGl0KutbFL69w78w7BwTFQIhcJOO+g27C6V8vHtqU0U5JOgE/QNg3yWhzhQjgCpzQhmuO+Bcs3Jq2T/OcqTfwM6gufNe+Gq2TdEfeH5Y0WcRtTKJBVVQ4XWFtgONE1C1hNBFLyh7GNZDQQVYBT3c/MXeV5Q++rVJYOdSrw=
10
8
  gem: cookbook-release
11
9
  on:
12
10
  tags: true
13
11
  repo: criteo/cookbook-release
12
+ skip_cleanup: 'true'
@@ -6,7 +6,7 @@ require 'English'
6
6
 
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = 'cookbook-release'
9
- spec.version = '1.4.1'
9
+ spec.version = '1.5.1'
10
10
  spec.authors = ['Grégoire Seux']
11
11
  spec.email = 'g.seux@criteo.com'
12
12
  spec.summary = 'Provide primitives (and rake tasks) to release a cookbook'
@@ -22,8 +22,9 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency 'semantic'
23
23
  spec.add_dependency 'highline'
24
24
  spec.add_dependency 'mixlib-shellout'
25
- spec.add_dependency 'chef'
25
+ spec.add_dependency 'chef', '>= 12.18.31'
26
26
  spec.add_dependency 'git-ng' # see https://github.com/schacon/ruby-git/issues/307
27
+ spec.add_dependency 'unicode-emoji'
27
28
 
28
29
 
29
30
  spec.add_development_dependency 'rspec'
@@ -56,6 +56,12 @@ module CookbookRelease
56
56
  git = GitUtilities.new('sub_dir': args['sub_dir'])
57
57
  puts Changelog.new(git, opts).markdown_priority
58
58
  end
59
+
60
+ desc 'Display markdown changelog between branches with risky commits on top and non-node-only changes separated'
61
+ task 'changelog:markdown_priority_nodes', [:sub_dir] do |_, args|
62
+ git = GitUtilities.new('sub_dir': args['sub_dir'])
63
+ puts Changelog.new(git, opts).markdown_priority_nodes
64
+ end
59
65
  end
60
66
  end
61
67
 
@@ -4,11 +4,14 @@ module CookbookRelease
4
4
  DEFAULT_OPTS = {
5
5
  expand_major: true,
6
6
  expand_risky: true,
7
+ separate_nodes: true,
7
8
  short_sha: true
8
9
  }
9
10
 
10
11
  RISKY = 'RISKY/BREAKING (details below):'
11
12
  NO_RISKY = 'NO RISKY/BREAKING COMMITS. READ FULL CHANGELOG.'
13
+ NON_NODES_ONLY = 'Non-risky/major, Non-node-only commits'
14
+ NODES_ONLY = 'Commits impacting only nodes'
12
15
  FULL = 'Full changelog:'
13
16
  DETAILS = 'Details of risky commits:'
14
17
 
@@ -42,6 +45,7 @@ module CookbookRelease
42
45
  result << changelog.map do |c|
43
46
  full_body ||= @opts[:expand_major] && c.major?
44
47
  full_body ||= @opts[:expand_risky] && c.risky?
48
+ full_body ||= @opts[:separate_nodes] && c.nodes_only?
45
49
  full_body ||= @opts[:expand_commit] && (c[:subject] =~ @opts[:expand_commit] || c[:body] =~ @opts[:expand_commit])
46
50
  c.to_s_html(full_body)
47
51
  end.map { |c| " <p>#{c}</p>" }
@@ -81,6 +85,8 @@ module CookbookRelease
81
85
  changelog.map do |c|
82
86
  full_body ||= @opts[:expand_major] && c.major?
83
87
  full_body ||= @opts[:expand_risky] && c.risky?
88
+ full_body ||= @opts[:separate_nodes] && c.nodes_only?
89
+ full_body ||= @opts[:expand_commit] && (c[:subject] =~ @opts[:expand_commit] || c[:body] =~ @opts[:expand_commit])
84
90
  full_body ||= @opts[:expand_commit] && (c[:subject] =~ @opts[:expand_commit] || c[:body] =~ @opts[:expand_commit])
85
91
  c.to_s_markdown(full_body)
86
92
  end.join("\n")
@@ -103,8 +109,55 @@ module CookbookRelease
103
109
  result
104
110
  end
105
111
 
112
+ def markdown_priority_nodes
113
+ result = []
114
+ result << append_risky(changelog)
115
+ result << append_by_impact(changelog)
116
+ result << append_risky_details(changelog)
117
+ result
118
+ end
119
+
106
120
  private
107
121
 
122
+ # @param changelog [Array<Commit>]
123
+ # @return [String] a string describing the changelog
124
+ def append_by_impact(changelog)
125
+ not_nodes_only_commits = changelog.reject { |c| c.nodes_only? || c.risky? || c.major? }
126
+ nodes_only_commits = changelog.select(&:nodes_only?)
127
+ output = []
128
+ if not_nodes_only_commits.any?
129
+ txt = not_nodes_only_commits.map { |c| c.to_s_markdown(false) }.join("\n")
130
+ output << "*#{NON_NODES_ONLY}*\n#{txt}\n"
131
+ end
132
+ if nodes_only_commits.any?
133
+ txt = nodes_only_commits.map { |c| c.to_s_markdown(false) }.join("\n")
134
+ output << "*#{NODES_ONLY}*\n#{txt}\n"
135
+ end
136
+ output.join
137
+ end
138
+
139
+ # @param changelog [Array<Commit>]
140
+ # @return [String] a string describing the changelog
141
+ def append_risky_details(changelog)
142
+ risky_commits = changelog.select { |c| c.risky? || c.major? }
143
+ if risky_commits.any?
144
+ "\n#{DETAILS}\n" + risky_commits.map { |c| c.to_s_markdown(true) }.join("\n")
145
+ else
146
+ ''
147
+ end
148
+ end
149
+
150
+ # @param changelog [Array<Commit>]
151
+ # @return [String] a string describing the changelog
152
+ def append_risky(changelog)
153
+ risky_commits = changelog.select { |c| c.risky? || c.major? }
154
+ if risky_commits.any?
155
+ "*#{RISKY}*\n" << risky_commits.map { |c| c.to_s_markdown(false) }.join("\n") << "\n"
156
+ else
157
+ "*#{NO_RISKY}*\n\n"
158
+ end
159
+ end
160
+
108
161
  def changelog
109
162
  ref = ENV['RELEASE_BRANCH'] || 'origin/master'
110
163
  @git.compute_changelog(ref, @opts[:short_sha])
@@ -1,3 +1,6 @@
1
+ require 'forwardable'
2
+ require 'unicode/emoji'
3
+
1
4
  module CookbookRelease
2
5
  class Commit
3
6
  extend Forwardable
@@ -34,6 +37,10 @@ module CookbookRelease
34
37
  !!(self[:subject] =~ /\[risky\]/i)
35
38
  end
36
39
 
40
+ def nodes_only?
41
+ self[:nodes_only]
42
+ end
43
+
37
44
  def color
38
45
  case true
39
46
  when major?
@@ -75,11 +82,20 @@ module CookbookRelease
75
82
  else
76
83
  result << "_#{self[:author]} <#{self[:email]}>_"
77
84
  end
78
- result << " `#{self[:subject]}`"
85
+ result << ' '
86
+ result << backtick_string(self[:subject])
79
87
  result << "\n```\n#{strip_change_id(self[:body])}```" if full && self[:body]
80
88
  result
81
89
  end
82
90
 
91
+ def backtick_string(input)
92
+ s = input.gsub(/( )?(#{Unicode::Emoji::REGEX})( )?/, '` \2 `')
93
+ .gsub(/( )?``( )?/, '')
94
+ s += '`' unless s =~ /`$/
95
+ s = '`' + s unless s =~ /^`/
96
+ s
97
+ end
98
+
83
99
  private
84
100
 
85
101
  def strip_change_id(body)
@@ -23,6 +23,12 @@ module CookbookRelease
23
23
  File.directory?(::File.join(dir, '.git'))
24
24
  end
25
25
 
26
+ def self.find_root(dir = Dir.pwd)
27
+ cmd = Mixlib::ShellOut.new("git rev-parse --show-toplevel", cwd: dir)
28
+ cmd.run_command
29
+ cmd.error? ? nil : cmd.stdout.chomp
30
+ end
31
+
26
32
  def reset_command(new_version)
27
33
  remote = choose_remote
28
34
  "git tag -d #{new_version} ; git push #{remote} :#{new_version}"
@@ -43,11 +49,13 @@ module CookbookRelease
43
49
  def _compute_last_release
44
50
  tag = Mixlib::ShellOut.new([
45
51
  'git describe',
52
+ "--abbrev=0",
46
53
  "--tags",
47
54
  "--match \"#{@tag_prefix}[0-9]*\.[0-9]*\.[0-9]*\""
48
55
  ].join(" "), @shellout_opts)
49
56
  tag.run_command
50
- tag.stdout.split('-').first
57
+ rel = tag.stdout.sub(/^#{@tag_prefix}/, '').chomp
58
+ rel.empty? ? nil : rel
51
59
  end
52
60
 
53
61
  def has_any_release?
@@ -64,7 +72,8 @@ module CookbookRelease
64
72
  end
65
73
 
66
74
  def compute_changelog(since, short_sha = true)
67
- @g.log(500).object(@sub_dir).between(since, 'HEAD').map do |commit|
75
+ ref = "#{@tag_prefix}#{since}"
76
+ @g.log(500).object(@sub_dir).between(ref, 'HEAD').map do |commit|
68
77
  message = commit.message.lines.map(&:chomp).compact.delete_if(&:empty?)
69
78
  Commit.new(
70
79
  author: commit.author.name,
@@ -72,7 +81,10 @@ module CookbookRelease
72
81
  subject: message.delete_at(0),
73
82
  hash: short_sha ? commit.sha[0,7] : commit.sha,
74
83
  body: message.empty? ? nil : message.join("\n"),
75
- is_merge_commit: commit.parents.length > 1
84
+ is_merge_commit: commit.parents.length > 1,
85
+ nodes_only: @g.diff(commit.sha, "#{commit.sha}~1").name_status.reject do |path, change_type|
86
+ path.include?('nodes/') && ['A', 'D'].include?(change_type) # basic node additions or deletions only
87
+ end.count.zero?
76
88
  )
77
89
  end.reject { |commit| commit[:is_merge_commit] }
78
90
  end
@@ -5,13 +5,20 @@ module CookbookRelease
5
5
  def self.current_version(file)
6
6
  dir = File.dirname(file)
7
7
  version_file = File.join(dir, '.cookbook_version')
8
+ git_root = GitUtilities.find_root(dir)
8
9
 
9
- if !GitUtilities.git?(dir)
10
+ if !GitUtilities.git?(dir) && git_root.nil?
10
11
  return File.read(version_file) if File.exist?(version_file)
11
12
  raise "Can't determine version in a non-git environment without #{version_file}"
12
13
  end
13
14
 
14
- r = Release.new(GitUtilities.new(cwd: dir))
15
+ git = if git_root == dir
16
+ GitUtilities.new(cwd: dir)
17
+ else
18
+ GitUtilities.new(cwd: git_root, tag_prefix: "#{File.basename(dir)}-", sub_dir: dir)
19
+ end
20
+
21
+ r = Release.new(git)
15
22
  begin
16
23
  r.new_version.first
17
24
  rescue ExistingRelease
@@ -55,5 +55,40 @@ describe CookbookRelease::Changelog do
55
55
  expect(changelog.markdown).to start_with('*654321* @j.doe `[Risky] hello`')
56
56
  end
57
57
  end
58
+ context 'Separates risky and non-risky+non-nodes' do
59
+ let(:commits) do
60
+ [
61
+ CookbookRelease::Commit.new(
62
+ hash: '654321',
63
+ subject: 'hello',
64
+ author: 'John Doe',
65
+ email: 'j.doe@nobody.com',
66
+ body: 'New Men Just Want to Watch the World Burn',
67
+ nodes_only: false),
68
+ CookbookRelease::Commit.new(
69
+ hash: '654321',
70
+ subject: '[Risky] hello',
71
+ author: 'John Doe',
72
+ email: 'j.doe@nobody.com',
73
+ body: 'Some Men Just Want to Watch the World Turn',
74
+ nodes_only: true),
75
+ CookbookRelease::Commit.new(
76
+ hash: '654321',
77
+ subject: 'hello only nodes',
78
+ author: 'John Doe',
79
+ email: 'j.doe@nobody.com',
80
+ body: 'Old Men Just Want to Watch the World Learn',
81
+ nodes_only: true)
82
+ ]
83
+ end
84
+
85
+ it 'expands the body with non-risky+non-nodes' do
86
+ expect(git).to receive(:compute_changelog).and_return(commits).at_least(:once)
87
+ changelog = CookbookRelease::Changelog.new(git, expand_risky: true, nodes_only: true)
88
+ expect(changelog.markdown_priority_nodes.join('')).to include(
89
+ "\n*Non-risky/major, Non-node-only commits*\n*654321* _John Doe <j.doe@nobody.com>_ `hello`\n*Commits impacting only nodes"
90
+ )
91
+ end
92
+ end
58
93
  end
59
94
  end
data/spec/commit_spec.rb CHANGED
@@ -23,4 +23,16 @@ describe CookbookRelease::Commit do
23
23
  expect(minor_change) .not_to be_patch
24
24
  end
25
25
  end
26
+
27
+ describe '.to_s_markdown' do
28
+ it 'surrounds subject with backticks' do
29
+ commit = CookbookRelease::Commit.new(subject: 'This is a fix', hash: 'abcdef', author: 'Linus', email: 'linus@linux.org')
30
+ expect(commit.to_s_markdown(false)).to match(/`#{commit[:subject]}`/)
31
+ end
32
+
33
+ it 'properly handle emojis' do
34
+ commit = CookbookRelease::Commit.new(subject: 'This is a fix 🔧 and I love 🪐🚀', hash: 'abcdef', author: 'Linus', email: 'linus@linux.org')
35
+ expect(commit.to_s_markdown(false)).to match(/`This is a fix` 🔧 `and I love` 🪐🚀/)
36
+ end
37
+ end
26
38
  end
data/spec/git_spec.rb CHANGED
@@ -44,6 +44,12 @@ describe CookbookRelease::GitUtilities do
44
44
  expect(CookbookRelease::GitUtilities.git?(tmp)).to be(true)
45
45
  FileUtils.rm_rf(tmp)
46
46
  end
47
+
48
+ it 'finds repo\'s root from subdir' do
49
+ subdir = 'cookbooks/mycookbook'
50
+ FileUtils.mkdir_p(subdir)
51
+ expect(CookbookRelease::GitUtilities.find_root(subdir)).to eq(Dir.pwd)
52
+ end
47
53
  end
48
54
 
49
55
  describe '.clean_index(?|!)' do
@@ -150,8 +156,8 @@ git tag 12.34.56
150
156
 
151
157
  it 'parse correctly commits' do
152
158
  cmds = <<-EOH
153
- git commit --allow-empty -m "subject" -m "body" -m "line2"
154
- git commit --allow-empty -m "without body"
159
+ git commit --allow-empty --no-verify -m "subject" -m "body" -m "line2"
160
+ git commit --allow-empty --no-verify -m "without body"
155
161
  EOH
156
162
  cmds.split("\n").each do |cmd|
157
163
  cmd = Mixlib::ShellOut.new(cmd)
@@ -183,5 +189,32 @@ git tag 12.34.56
183
189
  changelog = git.compute_changelog('HEAD~1', false)
184
190
  expect(changelog[0][:hash].size).to eq(40)
185
191
  end
192
+
193
+ it 'detects node-only commits' do
194
+ cmds = <<-EOH
195
+ mkdir -p nodes/preprod
196
+ echo "hello first" > nodes/preprod/tata.rb
197
+ git add nodes/preprod/tata.rb
198
+ git commit -m "hello there"
199
+ echo "hello second" > nodes/preprod/tata.rb
200
+ git add nodes/preprod/tata.rb
201
+ git commit -m "hello there modify"
202
+ mkdir -p toto
203
+ echo "hello" > toto/titi.rb
204
+ git add toto/titi.rb
205
+ git commit -m "subject" -m "body" -m "line2"
206
+ EOH
207
+ cmds.split("\n").each do |cmd|
208
+ cmd = Mixlib::ShellOut.new(cmd)
209
+ cmd.run_command
210
+ cmd.error!
211
+ end
212
+
213
+ git = CookbookRelease::GitUtilities.new
214
+ changelog = git.compute_changelog('HEAD~3')
215
+ expect(changelog[0][:nodes_only]).to be false # Add a non-"nodes" file
216
+ expect(changelog[1][:nodes_only]).to be false # Modify a "nodes" file
217
+ expect(changelog[2][:nodes_only]).to be true # Add a "nodes" file
218
+ end
186
219
  end
187
220
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cookbook-release
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Grégoire Seux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-30 00:00:00.000000000 Z
11
+ date: 2021-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: semantic
@@ -54,6 +54,20 @@ dependencies:
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: chef
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 12.18.31
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 12.18.31
69
+ - !ruby/object:Gem::Dependency
70
+ name: git-ng
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - ">="
@@ -67,7 +81,7 @@ dependencies:
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: git-ng
84
+ name: unicode-emoji
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - ">="
@@ -181,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
195
  version: '0'
182
196
  requirements: []
183
197
  rubyforge_project:
184
- rubygems_version: 2.6.13
198
+ rubygems_version: 2.7.6.2
185
199
  signing_key:
186
200
  specification_version: 4
187
201
  summary: Provide primitives (and rake tasks) to release a cookbook