forked from activeadmin/activeadmin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrelease_manager.rb
220 lines (168 loc) · 5.1 KB
/
release_manager.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
class ReleaseManager
def initialize
assert_compatible_ruby!
assert_synced_versioning!
assert_clean_state!
end
def npm_push
npm_tag = npm_version.include?("-") ? "pre" : "latest"
system "npm", "publish", "--tag", npm_tag, exception: true
end
def prepare_prerelease
raise "Current release is not a prerelease. Use #prepare_prepatch, #prepare_preminor, or #prepare_premajor to start a new prerelease series" unless prerelease?(gem_version)
new_gem_prerelease = bump_gem_pre_version(:prerelease)
prepare_version(new_gem_prerelese)
end
def prepare_prepatch
new_gem_patch = bump_gem_version(:patch)
prepare_version(first_pre_for(new_gem_patch))
end
def prepare_patch
new_gem_patch = bump_gem_version(:patch)
prepare_version(new_gem_patch)
end
def prepare_preminor
new_gem_minor = bump_gem_version(:minor)
prepare_version(first_pre_for(new_gem_minor))
end
def prepare_minor
new_gem_minor = bump_gem_version(:minor)
prepare_version(new_gem_minor)
end
def prepare_premajor
new_gem_major = bump_gem_version(:major)
prepare_version(first_pre_for(new_gem_major))
end
def prepare_major
new_gem_major = bump_gem_version(:major)
prepare_version(new_gem_major)
end
private
def assert_compatible_ruby!
incompatible_ruby = Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.7.0")
raise "Unsupported ruby version. Use ruby 2.7.0 or higher to release" if incompatible_ruby
end
def assert_synced_versioning!
unsynced_versioning = npmify(gem_version) != npm_version
raise "Incompatible versions (gem: #{gem_version}, npm: #{npm_version})" if unsynced_versioning
end
def assert_clean_state!
clean_state = system("git", "diff", "--exit-code", *involved_files)
raise "Source control changes present in one of #{involved_files}. Commit or discard these first" unless clean_state
end
def npmify(version)
# See https://github.com/rails/rails/blob/0d0c30e534af7f80ec8b18eb946aaa613ca30444/tasks/release.rb#L26
version.gsub(/\./).with_index { |s, i| i == 2 ? "-" : s }
end
def bump_gem_pre_version
phase = :looking_for_prerelease_part
gem_version_segments.map do |segment|
if segment =~ /[a-z]/
phase = :bumping_pre_release
segment
else
if phase == :bumping_pre_release
phase = :done
segment + 1
else
segment
end
end
end.join(".")
end
def bump_gem_version(level)
gem_version_segments.map.with_index do |segment, index|
index_level = level_to_index(level)
if index < index_level
segment
elsif index == index_level
segment + 1
else
0
end
end.join(".")
end
def first_pre_for(version)
"#{version}.pre.1"
end
def level_to_index(level)
if level == :patch
2
elsif level == :minor
1
elsif level == :major
0
end
end
def prepare_version(version)
bump_gem(version)
bump_npm(version)
cut_changelog(version)
commit(version)
rescue
revert_changes
raise
end
def revert_changes
system "git", "checkout", "--", *involved_files, exception: true
end
def bump_npm(version)
system "npm", "version", npmify(version), "--no-git-tag-version", exception: true
end
def bump_gem(version)
bump_version_file(version)
bump_lockfiles(version)
end
def bump_version_file(version)
old_content = File.read(gem_version_file)
new_content = old_content.gsub!(/^ VERSION = '.*'$/, " VERSION = '#{version}'")
File.open(gem_version_file, "w") { |f| f.puts new_content }
end
def bump_lockfiles(version)
lockfiles.each do |lockfile|
old_content = File.read(lockfile)
new_content = old_content.gsub!(/^ activeadmin \(.*\)$/, " activeadmin (#{version})")
File.open(lockfile, "w") { |f| f.puts new_content }
end
end
def involved_files
[gem_version_file, *lockfiles, npm_version_file, changelog_file]
end
def lockfiles
["Gemfile.lock", *Dir.glob("gemfiles/rails_*/Gemfile.lock")]
end
def cut_changelog(version)
old_content = File.read(changelog_file).split("\n")
new_entry = "## #{version} [☰](https://github.com/activeadmin/activeadmin/compare/v#{gem_version}..#{version})"
new_content = [*old_content[0..3], new_entry, "", old_content[4..-1]].join("\n")
File.open(changelog_file, "w") { |f| f.puts(new_content) }
end
def commit(version)
system "git", "commit", "-am", "Get ready for #{version} release", exception: true
end
def gem_version_file
'lib/active_admin/version.rb'
end
def npm_version_file
'package.json'
end
def changelog_file
"CHANGELOG.md"
end
def npm_version
@npm_version ||=
begin
require "json"
JSON.parse(File.read(npm_version_file))["version"]
end
end
def gem_version
@gem_version ||= File.read(gem_version_file).match(/^ VERSION = '(.*)'$/)[1]
end
def prerelease?(version)
version.match?(/[a-z]/)
end
def gem_version_segments
@gem_version_segments ||= Gem::Version.new(gem_version).segments
end
end