releasinator 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.releasinator.rb +18 -2
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +1 -1
- data/README.md +64 -6
- data/lib/command_processor.rb +7 -3
- data/lib/config_hash.rb +6 -0
- data/lib/downstream.rb +201 -0
- data/lib/downstream_repo.rb +10 -0
- data/lib/git_util.rb +33 -0
- data/lib/releasinator/version.rb +1 -1
- data/lib/tasks/releasinator.rake +57 -230
- data/lib/validator.rb +93 -55
- data/lib/validator_changelog.rb +37 -18
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 142b9a1c28929a601de19ffd0cbf8a9676c787b7
|
4
|
+
data.tar.gz: 2db14160b8162e371cb3490e972c8c0a7d2f3782
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8e8f8e57c25244bc78e3bdbe23df9c33e1c54c2f64f2139cce64aecb9a3697df99245c8ef06cf71429f9af35dc41fe81d6cfcc581156c8dc3b1f8ab1ef88805
|
7
|
+
data.tar.gz: ad2d9f1ed2ad1487443486446d3c85dc5cb368a64884aacf67779e8d4c51bb8e57f0f3c9ff1cf5a8722f47957a9c58955c94310c003d6d9a89a7993da51b6f68
|
data/.releasinator.rb
CHANGED
@@ -15,14 +15,30 @@ def validate_version_match()
|
|
15
15
|
Printer.success("Ruby gem spec version #{spec_version} matches latest changelog version.")
|
16
16
|
end
|
17
17
|
|
18
|
+
def validate_ruby_gem_credentials()
|
19
|
+
file_path = Dir.home() + "/.gem/credentials"
|
20
|
+
if !File.exist?(file_path)
|
21
|
+
Printer.fail("Please create " + file_path.bold + " with the proper credentials.")
|
22
|
+
abort()
|
23
|
+
else
|
24
|
+
Printer.success(file_path.bold + " found.")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
18
28
|
configatron.custom_validation_methods = [
|
19
|
-
method(:validate_version_match)
|
29
|
+
method(:validate_version_match),
|
30
|
+
method(:validate_ruby_gem_credentials)
|
20
31
|
]
|
21
32
|
|
22
33
|
|
23
34
|
def build_method
|
24
35
|
# run tests first
|
25
|
-
|
36
|
+
# detect non-zero failures/errors, since ruby command won't exit properly if unit tests called exit/abort
|
37
|
+
output = CommandProcessor.command("ruby test/ts_allTests.rb | cat", live_output=true)
|
38
|
+
if !output.match /assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications$/
|
39
|
+
Printer.fail("There were unit test failures.")
|
40
|
+
abort()
|
41
|
+
end
|
26
42
|
|
27
43
|
output_dir = "build"
|
28
44
|
CommandProcessor.command("gem build releasinator.gemspec")
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,15 @@
|
|
1
1
|
Releasinator release notes
|
2
2
|
==========================
|
3
3
|
|
4
|
+
0.3.0
|
5
|
+
-----
|
6
|
+
* Add new `validate:releasinator_version` task.
|
7
|
+
* Add new `@validator.validate_in_path(executable)` function for use by any config.
|
8
|
+
* Fix version validation to be more permissive when a suffix is provided.
|
9
|
+
* Add missing dependencies on `validate:changelog`.
|
10
|
+
* Remove default rake task, so that releasing is explicit with the `release` task.
|
11
|
+
* Clean up and correct some file validations.
|
12
|
+
* Fix some bugs.
|
4
13
|
|
5
14
|
0.2.1
|
6
15
|
-----
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Releasinator
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/releasinator)
|
4
|
+
|
3
5
|
## Problem
|
4
6
|
|
5
7
|
When automating an SDK release process, many teams and languages have different ideas. The release process is a hurdle that makes it hard for new project members to ramp up. One shouldn't have to read a `release_process.md` to release an open source SDK.
|
@@ -21,8 +23,64 @@ The releasinator corrects this by enforcing standard must-have release files, be
|
|
21
23
|
|
22
24
|
### Usage
|
23
25
|
|
24
|
-
1.
|
25
|
-
2.
|
26
|
+
1. Add releasinator dependency to `Gemfile` or `.gemspec`
|
27
|
+
2. add a `Rakefile` with the following contents:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
spec = Gem::Specification.find_by_name 'releasinator'
|
31
|
+
load "#{spec.gem_dir}/lib/tasks/releasinator.rake"
|
32
|
+
```
|
33
|
+
|
34
|
+
3. Run `rake <command>` to use the newly added rake tasks
|
35
|
+
|
36
|
+
### Tasks
|
37
|
+
|
38
|
+
```
|
39
|
+
release
|
40
|
+
|
41
|
+
--> config
|
42
|
+
|
43
|
+
--> validate:all
|
44
|
+
--> validate:git_version
|
45
|
+
--> validate:gitignore
|
46
|
+
--> validate:git
|
47
|
+
--> validate:branch
|
48
|
+
--> validate:submodules
|
49
|
+
--> validate:readme
|
50
|
+
--> validate:changelog
|
51
|
+
--> validate:license
|
52
|
+
--> validate:contributing
|
53
|
+
--> validate:issue_template
|
54
|
+
--> validate:github_permissions_local
|
55
|
+
--> validate:github_permissions_downstream[downstream_repo_index]
|
56
|
+
--> validate:custom
|
57
|
+
|
58
|
+
--> local:build
|
59
|
+
--> local:checklist
|
60
|
+
--> local:confirm
|
61
|
+
--> local:prepare
|
62
|
+
--> local:tag
|
63
|
+
|
64
|
+
--> pm:all
|
65
|
+
--> pm:publish
|
66
|
+
--> pm:wait
|
67
|
+
|
68
|
+
--> downstream:all
|
69
|
+
--> downstream:reset[downstream_repo_index]
|
70
|
+
--> downstream:prepare[downstream_repo_index]
|
71
|
+
--> downstream:build[downstream_repo_index]
|
72
|
+
--> downstream:package[downstream_repo_index]
|
73
|
+
--> downstream:push[downstream_repo_index]
|
74
|
+
|
75
|
+
--> local:push
|
76
|
+
|
77
|
+
--> docs:all
|
78
|
+
--> docs:build
|
79
|
+
--> docs:package
|
80
|
+
--> docs:push
|
81
|
+
|
82
|
+
```
|
83
|
+
|
26
84
|
|
27
85
|
## Conventions
|
28
86
|
|
@@ -60,10 +118,6 @@ The releasinator enforces certain conventions. If a filename doesn't exactly ma
|
|
60
118
|
* Compiling with the right version of the platform.
|
61
119
|
* Upstream library dependencies are the latest available.
|
62
120
|
|
63
|
-
#### Package manager credential management
|
64
|
-
1. Validate permissions to publish to package manager
|
65
|
-
2. If permissions are needed, retrieve them from the secret credential repo, and run any subsequent repo steps.
|
66
|
-
|
67
121
|
#### Performs internal-only tasks:
|
68
122
|
|
69
123
|
1. ✓ Confirm user has completed all manual tasks (aka pre-release checklist).
|
@@ -102,6 +156,10 @@ The releasinator enforces certain conventions. If a filename doesn't exactly ma
|
|
102
156
|
11. TODO add those same release notes within the release notes of the downstream repo.
|
103
157
|
11. Assemble a draft of news, and publish (where possible, i.e. send email, tweet, whatever).
|
104
158
|
|
159
|
+
#### Package manager credential management (TODO)
|
160
|
+
1. Validate permissions to publish to package manager
|
161
|
+
2. If permissions are needed, retrieve them from the secret credential repo, and run any subsequent repo steps.
|
162
|
+
|
105
163
|
## Contributing
|
106
164
|
|
107
165
|
Please read our [contributing guidelines](CONTRIBUTING.md) prior to submitting a Pull Request.
|
data/lib/command_processor.rb
CHANGED
@@ -6,6 +6,7 @@ module Releasinator
|
|
6
6
|
def self.command(command, live_output=false)
|
7
7
|
puts Time.now.utc.iso8601 + ": " + "#{Dir.pwd}".bold + " exec:" + " #{command}".bold
|
8
8
|
if live_output
|
9
|
+
|
9
10
|
puts "...with live output (forked process)".bold
|
10
11
|
|
11
12
|
return_code = nil
|
@@ -18,7 +19,11 @@ module Releasinator
|
|
18
19
|
end
|
19
20
|
end
|
20
21
|
io.close
|
21
|
-
|
22
|
+
output = ""
|
23
|
+
r.each_line do |line|
|
24
|
+
puts line.strip.white
|
25
|
+
output << line
|
26
|
+
end
|
22
27
|
|
23
28
|
Process.wait(pid)
|
24
29
|
fork_exitstatus = $?.exitstatus
|
@@ -33,9 +38,8 @@ module Releasinator
|
|
33
38
|
Printer.fail("Process failed with exitstatus:#{exitstatus}")
|
34
39
|
abort()
|
35
40
|
end
|
36
|
-
|
37
|
-
output
|
38
41
|
end
|
42
|
+
output
|
39
43
|
end
|
40
44
|
|
41
45
|
# waits for the input command to return non-empty output.
|
data/lib/config_hash.rb
CHANGED
data/lib/downstream.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
require_relative 'command_processor'
|
2
|
+
require_relative 'downstream_repo'
|
3
|
+
require_relative 'git_util'
|
4
|
+
require_relative 'printer'
|
5
|
+
require_relative 'publisher'
|
6
|
+
|
7
|
+
module Releasinator
|
8
|
+
class Downstream
|
9
|
+
|
10
|
+
def initialize(releasinator_config, validator, current_release)
|
11
|
+
@releasinator_config = releasinator_config
|
12
|
+
@validator = validator
|
13
|
+
@current_release = current_release
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_github_permissions(args)
|
17
|
+
if @releasinator_config.has_key?(:downstream_repos)
|
18
|
+
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
19
|
+
@validator.validate_github_permissions(downstream_repo.url)
|
20
|
+
end
|
21
|
+
else
|
22
|
+
Printer.success("Not validating permissions of downstream repos. None found.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def reset(args)
|
27
|
+
if @releasinator_config.has_key?(:downstream_repos)
|
28
|
+
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
29
|
+
puts "resetting downstream_repo[#{index}]: #{downstream_repo.url}" if @releasinator_config[:verbose]
|
30
|
+
Dir.mkdir(DOWNSTREAM_REPOS) unless File.exist?(DOWNSTREAM_REPOS)
|
31
|
+
Dir.chdir(DOWNSTREAM_REPOS) do
|
32
|
+
CommandProcessor.command("git clone --origin origin #{downstream_repo.url} #{downstream_repo.name}") unless File.exist?(downstream_repo.name)
|
33
|
+
|
34
|
+
Dir.chdir(downstream_repo.name) do
|
35
|
+
GitUtil.reset_repo(downstream_repo.branch)
|
36
|
+
|
37
|
+
if downstream_repo.options.has_key? :new_branch_name
|
38
|
+
new_branch_name = get_new_branch_name(downstream_repo.options[:new_branch_name], @current_release.version)
|
39
|
+
GitUtil.delete_branch new_branch_name
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
Printer.success("Done resetting downstream repos.")
|
45
|
+
else
|
46
|
+
Printer.success("Not resetting downstream repos. None found.")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def prepare(args)
|
51
|
+
if @releasinator_config.has_key?(:downstream_repos)
|
52
|
+
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
53
|
+
puts "preparing downstream_repo[#{index}]: #{downstream_repo.url}" if @releasinator_config[:verbose]
|
54
|
+
|
55
|
+
root_dir = Dir.pwd.strip
|
56
|
+
copy_from_dir = root_dir + "/" + get_base_dir()
|
57
|
+
|
58
|
+
Dir.chdir(DOWNSTREAM_REPOS) do
|
59
|
+
Dir.chdir(downstream_repo.name) do
|
60
|
+
|
61
|
+
if downstream_repo.options.has_key? :new_branch_name
|
62
|
+
new_branch_name = get_new_branch_name(downstream_repo.options[:new_branch_name], @current_release.version)
|
63
|
+
CommandProcessor.command("git checkout -b #{new_branch_name}")
|
64
|
+
end
|
65
|
+
|
66
|
+
if downstream_repo.full_file_sync
|
67
|
+
# remove old everything
|
68
|
+
CommandProcessor.command("rm -rf *")
|
69
|
+
|
70
|
+
# update all sdk files
|
71
|
+
CommandProcessor.command("rsync -av --exclude='#{DOWNSTREAM_REPOS}' --exclude='.git/' #{copy_from_dir}/* .")
|
72
|
+
CommandProcessor.command("rsync -av --exclude='#{DOWNSTREAM_REPOS}' --exclude='.git/' #{copy_from_dir}/.[!.]* .")
|
73
|
+
end
|
74
|
+
|
75
|
+
# copy custom files
|
76
|
+
if downstream_repo.options.has_key? :files_to_copy
|
77
|
+
downstream_repo.options[:files_to_copy].each do |copy_file|
|
78
|
+
copy_the_file(root_dir, copy_file, @current_release.version)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if downstream_repo.options.has_key? :post_copy_methods
|
83
|
+
downstream_repo.options[:post_copy_methods].each do |method|
|
84
|
+
method.call(@current_release.version)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if GitUtil.is_clean_git?
|
89
|
+
Printer.fail("Nothing changed in #{downstream_repo.name}!")
|
90
|
+
abort()
|
91
|
+
end
|
92
|
+
# add everything to git and commit
|
93
|
+
CommandProcessor.command("git add .")
|
94
|
+
CommandProcessor.command("git add -u .")
|
95
|
+
if downstream_repo.options.has_key? :new_branch_name
|
96
|
+
commit_message = "Update #{@releasinator_config[:product_name]} to #{@current_release.version}"
|
97
|
+
else
|
98
|
+
commit_message = "Release #{@current_release.version}"
|
99
|
+
end
|
100
|
+
CommandProcessor.command("git commit -am \"#{commit_message}\"")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
Printer.success("Done preparing downstream repos.")
|
105
|
+
else
|
106
|
+
Printer.success("Not preparing downstream repos. None found.")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def build(args)
|
111
|
+
if @releasinator_config.has_key?(:downstream_repos)
|
112
|
+
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
113
|
+
puts "building downstream_repo[#{index}]: #{downstream_repo.url}" if @releasinator_config[:verbose]
|
114
|
+
Dir.chdir(DOWNSTREAM_REPOS) do
|
115
|
+
Dir.chdir(downstream_repo.name) do
|
116
|
+
# build any files to verify release
|
117
|
+
if downstream_repo.options.has_key? :build_methods
|
118
|
+
downstream_repo.options[:build_methods].each do |method|
|
119
|
+
method.call
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
Printer.success("Done building downstream repos.")
|
126
|
+
else
|
127
|
+
Printer.success("Not building downstream repos. None found.")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def package(args)
|
132
|
+
if @releasinator_config.has_key?(:downstream_repos)
|
133
|
+
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
134
|
+
puts "packaging downstream_repo[#{index}]: #{downstream_repo.url}" if @releasinator_config[:verbose]
|
135
|
+
Dir.chdir(DOWNSTREAM_REPOS) do
|
136
|
+
Dir.chdir(downstream_repo.name) do
|
137
|
+
# don't tag those where new branches are created
|
138
|
+
GitUtil.tag(@current_release.version, @current_release.changelog) unless downstream_repo.options.has_key? :new_branch_name
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
Printer.success("Done packaging downstream repos.")
|
143
|
+
else
|
144
|
+
Printer.success("Not packaging downstream repos. None found.")
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def push(args)
|
149
|
+
if @releasinator_config.has_key?(:downstream_repos)
|
150
|
+
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
151
|
+
puts "pushing downstream_repo[#{index}]: #{downstream_repo.url}" if @releasinator_config[:verbose]
|
152
|
+
Dir.chdir(DOWNSTREAM_REPOS) do
|
153
|
+
Dir.chdir(downstream_repo.name) do
|
154
|
+
if downstream_repo.options.has_key? :new_branch_name
|
155
|
+
new_branch_name = get_new_branch_name(downstream_repo.options[:new_branch_name], @current_release.version)
|
156
|
+
CommandProcessor.command("git push -u origin #{new_branch_name}")
|
157
|
+
Publisher.new(@releasinator_config).publish_pull_request(downstream_repo.url, @current_release, @releasinator_config[:product_name], downstream_repo.branch, new_branch_name)
|
158
|
+
else
|
159
|
+
GitUtil.push_branch("master")
|
160
|
+
GitUtil.push_tag(@current_release.version)
|
161
|
+
Publisher.new(@releasinator_config).publish_draft(downstream_repo.url, @current_release) unless ! downstream_repo.release_to_github
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
Printer.success("Done pushing downstream repos.")
|
167
|
+
else
|
168
|
+
Printer.success("Not pushing downstream repos. None found.")
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def get_downstream_repos(downstream_repo_index)
|
175
|
+
repos_to_iterate_over = {}
|
176
|
+
if downstream_repo_index
|
177
|
+
index = Integer(downstream_repo_index) rescue false
|
178
|
+
if !index
|
179
|
+
Printer.fail("downstream_repo_index:#{downstream_repo_index} not a valid integer")
|
180
|
+
abort()
|
181
|
+
end
|
182
|
+
downstream_repo_max_index = @releasinator_config[:downstream_repos].size - 1
|
183
|
+
if index < 0
|
184
|
+
Printer.fail("Index out of bounds downstream_repo_index: #{index} < 0")
|
185
|
+
abort()
|
186
|
+
end
|
187
|
+
if index > downstream_repo_max_index
|
188
|
+
Printer.fail("Index out of bounds downstream_repo_index: #{index} >= #{downstream_repo_max_index}")
|
189
|
+
abort()
|
190
|
+
end
|
191
|
+
# keep original index for printing
|
192
|
+
repos_to_iterate_over[@releasinator_config[:downstream_repos][index]] = index
|
193
|
+
else
|
194
|
+
@releasinator_config[:downstream_repos].each_with_index do |downstream_repo, index|
|
195
|
+
repos_to_iterate_over[downstream_repo] = index
|
196
|
+
end
|
197
|
+
end
|
198
|
+
repos_to_iterate_over
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
data/lib/downstream_repo.rb
CHANGED
@@ -14,5 +14,15 @@ module Releasinator
|
|
14
14
|
# :post_copy_methods
|
15
15
|
# :build_methods
|
16
16
|
end
|
17
|
+
|
18
|
+
def full_file_sync
|
19
|
+
return @options[:full_file_sync] if @options.has_key? :full_file_sync
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def release_to_github
|
24
|
+
return @options[:release_to_github] if @options.has_key? :release_to_github
|
25
|
+
false
|
26
|
+
end
|
17
27
|
end
|
18
28
|
end
|
data/lib/git_util.rb
CHANGED
@@ -2,6 +2,30 @@ require_relative 'command_processor'
|
|
2
2
|
|
3
3
|
module Releasinator
|
4
4
|
class GitUtil
|
5
|
+
def self.reset_repo(branch_name)
|
6
|
+
# resets the repo to a clean state
|
7
|
+
checkout(branch_name)
|
8
|
+
fetch()
|
9
|
+
CommandProcessor.command("git reset --hard origin/#{branch_name}")
|
10
|
+
CommandProcessor.command("git clean -x -d -f")
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.fetch()
|
14
|
+
CommandProcessor.command("git fetch origin --prune --recurse-submodules -j9")
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.push_branch(branch_name)
|
18
|
+
checkout(branch_name)
|
19
|
+
fetch()
|
20
|
+
# always merge to include any extra commits added during release process
|
21
|
+
CommandProcessor.command("git merge origin/#{branch_name} --no-edit")
|
22
|
+
CommandProcessor.command("git push origin #{branch_name}")
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.push_tag(tag_name)
|
26
|
+
CommandProcessor.command("git push origin #{tag_name}")
|
27
|
+
end
|
28
|
+
|
5
29
|
def self.is_clean_git?
|
6
30
|
any_changes = CommandProcessor.command("git status --porcelain")
|
7
31
|
'' == any_changes
|
@@ -56,6 +80,15 @@ module Releasinator
|
|
56
80
|
end
|
57
81
|
end
|
58
82
|
|
83
|
+
|
84
|
+
def self.get_local_branch_sha1(branch_name)
|
85
|
+
CommandProcessor.command("git rev-parse --verify #{branch_name}").strip
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.get_remote_branch_sha1(branch_name)
|
89
|
+
CommandProcessor.command("git rev-parse --verify origin/#{branch_name}").strip
|
90
|
+
end
|
91
|
+
|
59
92
|
def self.tag(new_tag, changelog)
|
60
93
|
confirm_tag_overwrite(new_tag)
|
61
94
|
puts "tagging with changelog: \n\n#{changelog}\n".yellow
|
data/lib/releasinator/version.rb
CHANGED
data/lib/tasks/releasinator.rake
CHANGED
@@ -7,6 +7,7 @@ require_relative '../command_processor'
|
|
7
7
|
require_relative '../config_hash'
|
8
8
|
require_relative '../copy_file'
|
9
9
|
require_relative '../current_release'
|
10
|
+
require_relative '../downstream'
|
10
11
|
require_relative '../downstream_repo'
|
11
12
|
require_relative '../publisher'
|
12
13
|
require_relative '../validator'
|
@@ -23,21 +24,6 @@ def get_base_dir
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
26
|
-
def use_git_flow()
|
27
|
-
return @releasinator_config[:use_git_flow] if @releasinator_config.has_key? :use_git_flow
|
28
|
-
false
|
29
|
-
end
|
30
|
-
|
31
|
-
def full_file_sync(options)
|
32
|
-
return options[:full_file_sync] if options.has_key? :full_file_sync
|
33
|
-
false
|
34
|
-
end
|
35
|
-
|
36
|
-
def release_to_github(options)
|
37
|
-
return options[:release_to_github] if options.has_key? :release_to_github
|
38
|
-
false
|
39
|
-
end
|
40
|
-
|
41
27
|
desc "read and validate the config, adding one if not found"
|
42
28
|
task :config do
|
43
29
|
@releasinator_config = ConfigHash.new(verbose == true, Rake.application.options.trace == true)
|
@@ -46,8 +32,17 @@ task :config do
|
|
46
32
|
end
|
47
33
|
|
48
34
|
namespace :validate do
|
35
|
+
desc "validate the presence, formatting, and semver sequence of CHANGELOG.md"
|
36
|
+
task :changelog => :config do
|
37
|
+
@current_release = @validator.validate_changelog(get_base_dir(), DOWNSTREAM_REPOS)
|
38
|
+
@downstream = Downstream.new(@releasinator_config, @validator, @current_release)
|
39
|
+
end
|
49
40
|
|
50
41
|
desc "validate that git is the correct version"
|
42
|
+
task :releasinator_version => :config do
|
43
|
+
@validator.validate_releasinator_version
|
44
|
+
end
|
45
|
+
|
51
46
|
task :git_version => :config do
|
52
47
|
@validator.validate_git_version
|
53
48
|
end
|
@@ -59,46 +54,39 @@ namespace :validate do
|
|
59
54
|
|
60
55
|
desc "validate current branch matches the latest on the server and follows naming conventions"
|
61
56
|
task :branch => [:config, :changelog] do
|
62
|
-
|
63
|
-
@validator.validate_matches_branch(current_branch)
|
64
|
-
if use_git_flow()
|
65
|
-
expected_release_branch = "release/#{@current_release.version}"
|
66
|
-
abort("git flow expects the current branch to be either 'develop' or 'release/#{@current_release.version}'. Current branch is '#{current_branch}'".red) unless current_branch == expected_release_branch || current_branch == "develop"
|
67
|
-
else
|
68
|
-
abort("non-git flow expects releases to come from the master branch. Current branch is '#{current_branch}'".red) unless current_branch == "master"
|
69
|
-
end
|
57
|
+
@validator.validate_branches(@current_release.version)
|
70
58
|
end
|
71
59
|
|
72
|
-
desc "validate the presence README.md, renaming a similar file if found"
|
60
|
+
desc "validate the presence of README.md, renaming a similar file if found"
|
73
61
|
task :readme => :config do
|
74
|
-
@validator.validate_exist(
|
62
|
+
@validator.validate_exist(".", "README.md", DOWNSTREAM_REPOS)
|
63
|
+
@validator.validate_exist(get_base_dir(), ".gitignore", DOWNSTREAM_REPOS) if '.' != get_base_dir()
|
75
64
|
end
|
76
65
|
|
77
|
-
desc "validate the presence LICENSE, renaming a similar file if found - also validates that its referenced from README.md"
|
66
|
+
desc "validate the presence of LICENSE, renaming a similar file if found - also validates that its referenced from README.md"
|
78
67
|
task :license => :config do
|
79
68
|
@validator.validate_exist(get_base_dir(), "LICENSE", DOWNSTREAM_REPOS)
|
80
69
|
@validator.validate_referenced_in_readme(get_base_dir(), "LICENSE")
|
81
70
|
end
|
82
71
|
|
83
|
-
desc "validate the presence CONTRIBUTING.md, renaming a similar file if found - also validates that its referenced from README.md"
|
72
|
+
desc "validate the presence of CONTRIBUTING.md, renaming a similar file if found - also validates that its referenced from README.md"
|
84
73
|
task :contributing => :config do
|
85
74
|
@validator.validate_exist(get_base_dir(), "CONTRIBUTING.md", DOWNSTREAM_REPOS)
|
86
75
|
@validator.validate_referenced_in_readme(get_base_dir(), "CONTRIBUTING.md")
|
87
76
|
end
|
88
77
|
|
89
|
-
desc "validate the presence .github/ISSUE_TEMPLATE.md"
|
78
|
+
desc "validate the presence of .github/ISSUE_TEMPLATE.md"
|
90
79
|
task :issue_template => :config do
|
91
80
|
@validator.validate_exist(get_base_dir(), ".github/ISSUE_TEMPLATE.md", DOWNSTREAM_REPOS)
|
92
81
|
end
|
93
82
|
|
94
|
-
desc "validate the presence
|
95
|
-
task :changelog => :config do
|
96
|
-
@current_release = @validator.validate_changelog(get_base_dir(), DOWNSTREAM_REPOS)
|
97
|
-
end
|
98
|
-
|
99
|
-
desc "validate the presence of .gitignore, adding it and any appropriate releasinator lines if necessary"
|
83
|
+
desc "validate the presence of .gitignore, adding any appropriate releasinator lines if necessary"
|
100
84
|
task :gitignore => :config do
|
101
|
-
@validator.
|
85
|
+
@validator.validate_exist('.', ".gitignore", DOWNSTREAM_REPOS)
|
86
|
+
@validator.validate_exist(get_base_dir(), ".gitignore", DOWNSTREAM_REPOS) if '.' != get_base_dir()
|
87
|
+
if @releasinator_config.has_key?(:downstream_repos)
|
88
|
+
@validator.validate_gitignore_contents("#{DOWNSTREAM_REPOS}/")
|
89
|
+
end
|
102
90
|
end
|
103
91
|
|
104
92
|
desc "validate all submodules are on the latest origin/master versions"
|
@@ -113,13 +101,7 @@ namespace :validate do
|
|
113
101
|
|
114
102
|
desc "validate the current user can push to downstream repos"
|
115
103
|
task :github_permissions_downstream, [:downstream_repo_index] => [:config] do |t, args|
|
116
|
-
|
117
|
-
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
118
|
-
@validator.validate_github_permissions(downstream_repo.url)
|
119
|
-
end
|
120
|
-
else
|
121
|
-
Printer.success("Not validating permissions of downstream repos. None found.")
|
122
|
-
end
|
104
|
+
@downstream.validate_github_permissions(args)
|
123
105
|
end
|
124
106
|
|
125
107
|
desc "run any configatron.custom_validation_methods"
|
@@ -149,46 +131,45 @@ namespace :validate do
|
|
149
131
|
:issue_template,
|
150
132
|
:github_permissions_local,
|
151
133
|
:github_permissions_downstream,
|
134
|
+
:releasinator_version,
|
152
135
|
:custom
|
153
136
|
] do
|
154
137
|
Printer.success("All validations passed.")
|
155
138
|
end
|
156
139
|
end
|
157
140
|
|
158
|
-
task :default => :release
|
159
|
-
|
160
141
|
desc "release all"
|
161
142
|
task :release => [:"validate:all",:"local:build",:"pm:all",:"downstream:all",:"local:push",:"docs:all"] do
|
162
143
|
Printer.success("Done releasing.")
|
163
144
|
end
|
164
145
|
|
165
|
-
desc "iterate over the prerelease_checklist_items, asking the user if each is done"
|
166
|
-
task :prerelease_checklist => :config do
|
167
|
-
@releasinator_config[:prerelease_checklist_items].each do |prerelease_item|
|
168
|
-
Printer.check_proceed("#{prerelease_item}", "Then no release for you!")
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
146
|
namespace :local do
|
173
147
|
desc "ask user whether to proceed with release"
|
174
|
-
task :confirm do
|
148
|
+
task :confirm => [:config, :"validate:changelog"] do
|
175
149
|
Printer.check_proceed("You're about to release #{@current_release.version}!", "Then no release for you!")
|
176
150
|
end
|
177
151
|
|
178
152
|
desc "change branch for git flow, if using git flow"
|
179
153
|
task :prepare => [:config, :"validate:changelog"] do
|
180
|
-
if use_git_flow()
|
154
|
+
if @releasinator_config.use_git_flow()
|
181
155
|
CommandProcessor.command("git checkout -b release/#{@current_release.version} develop") unless GitUtil.get_current_branch() != "develop"
|
182
156
|
end
|
183
157
|
end
|
184
158
|
|
185
159
|
desc "tag the local repo"
|
186
|
-
task :tag => :config do
|
160
|
+
task :tag => [:config, :"validate:changelog"] do
|
187
161
|
GitUtil.tag(@current_release.version, @current_release.changelog)
|
188
162
|
end
|
189
163
|
|
164
|
+
desc "iterate over the prerelease_checklist_items, asking the user if each is done"
|
165
|
+
task :checklist => [:config] do
|
166
|
+
@releasinator_config[:prerelease_checklist_items].each do |prerelease_item|
|
167
|
+
Printer.check_proceed("#{prerelease_item}", "Then no release for you!")
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
190
171
|
desc "build the local repo"
|
191
|
-
task :build => [:config, :"validate:changelog", :
|
172
|
+
task :build => [:config, :"validate:changelog", :checklist, :confirm, :prepare, :tag] do
|
192
173
|
puts "building #{@current_release.version}" if @releasinator_config[:verbose]
|
193
174
|
@releasinator_config[:build_method].call
|
194
175
|
if @releasinator_config.has_key? :post_build_methods
|
@@ -199,17 +180,23 @@ namespace :local do
|
|
199
180
|
end
|
200
181
|
|
201
182
|
desc "run the git flow branch magic (if configured) and push local to remote"
|
202
|
-
task :push => :config do
|
203
|
-
if use_git_flow()
|
183
|
+
task :push => [:config, :"validate:changelog"] do
|
184
|
+
if @releasinator_config.use_git_flow()
|
204
185
|
CommandProcessor.command("git checkout master")
|
205
|
-
CommandProcessor.command("git pull")
|
206
186
|
CommandProcessor.command("git merge --no-ff release/#{@current_release.version}")
|
207
187
|
GitUtil.delete_branch "release/#{@current_release.version}"
|
208
|
-
|
188
|
+
# still on master, so let's push it
|
189
|
+
end
|
190
|
+
|
191
|
+
GitUtil.push_branch("master")
|
192
|
+
|
193
|
+
if @releasinator_config.use_git_flow()
|
194
|
+
# switch back to develop to merge and continue development
|
195
|
+
GitUtil.checkout("develop")
|
209
196
|
CommandProcessor.command("git merge master")
|
210
|
-
|
197
|
+
GitUtil.push_branch("develop")
|
211
198
|
end
|
212
|
-
|
199
|
+
GitUtil.push_tag(@current_release.version)
|
213
200
|
if @releasinator_config[:release_to_github]
|
214
201
|
Publisher.new(@releasinator_config).publish_draft(GitUtil.repo_url, @current_release)
|
215
202
|
end
|
@@ -232,7 +219,7 @@ namespace :pm do
|
|
232
219
|
end
|
233
220
|
|
234
221
|
def copy_the_file(root_dir, copy_file, version=nil)
|
235
|
-
Dir.mkdir(copy_file.target_dir) unless File.
|
222
|
+
Dir.mkdir(copy_file.target_dir) unless File.exist?(copy_file.target_dir)
|
236
223
|
# use __VERSION__ to auto-substitute the version in any input param
|
237
224
|
source_file_name = copy_file.source_file.gsub("__VERSION__", "#{version}")
|
238
225
|
target_dir_name = copy_file.target_dir.gsub("__VERSION__", "#{version}")
|
@@ -244,41 +231,6 @@ def get_new_branch_name(new_branch_name, version)
|
|
244
231
|
new_branch_name.gsub("__VERSION__", "#{version}")
|
245
232
|
end
|
246
233
|
|
247
|
-
def reset_repo(branch_name)
|
248
|
-
# resets the repo to a clean state
|
249
|
-
GitUtil.checkout(branch_name)
|
250
|
-
CommandProcessor.command("git fetch origin --prune --recurse-submodules -j9")
|
251
|
-
CommandProcessor.command("git reset --hard origin/#{branch_name}")
|
252
|
-
CommandProcessor.command("git clean -x -d -f")
|
253
|
-
end
|
254
|
-
|
255
|
-
def get_downstream_repos(downstream_repo_index)
|
256
|
-
repos_to_iterate_over = {}
|
257
|
-
if downstream_repo_index
|
258
|
-
index = Integer(downstream_repo_index) rescue false
|
259
|
-
if !index
|
260
|
-
Printer.fail("downstream_repo_index:#{downstream_repo_index} not a valid integer")
|
261
|
-
abort()
|
262
|
-
end
|
263
|
-
downstream_repo_max_index = @releasinator_config[:downstream_repos].size - 1
|
264
|
-
if index < 0
|
265
|
-
Printer.fail("Index out of bounds downstream_repo_index: #{index} < 0")
|
266
|
-
abort()
|
267
|
-
end
|
268
|
-
if index > downstream_repo_max_index
|
269
|
-
Printer.fail("Index out of bounds downstream_repo_index: #{index} >= #{downstream_repo_max_index}")
|
270
|
-
abort()
|
271
|
-
end
|
272
|
-
# keep original index for printing
|
273
|
-
repos_to_iterate_over[@releasinator_config[:downstream_repos][index]] = index
|
274
|
-
else
|
275
|
-
@releasinator_config[:downstream_repos].each_with_index do |downstream_repo, index|
|
276
|
-
repos_to_iterate_over[downstream_repo] = index
|
277
|
-
end
|
278
|
-
end
|
279
|
-
repos_to_iterate_over
|
280
|
-
end
|
281
|
-
|
282
234
|
namespace :downstream do
|
283
235
|
desc "build, package, and push all downstream repos"
|
284
236
|
task :all => [:reset,:prepare,:build,:package,:push] do
|
@@ -287,152 +239,27 @@ namespace :downstream do
|
|
287
239
|
|
288
240
|
desc "reset the downstream repos to their starting state"
|
289
241
|
task :reset, [:downstream_repo_index] => [:config, :"validate:changelog"] do |t, args|
|
290
|
-
|
291
|
-
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
292
|
-
puts "resetting downstream_repo[#{index}]: #{downstream_repo.url}" if @releasinator_config[:verbose]
|
293
|
-
Dir.mkdir(DOWNSTREAM_REPOS) unless File.exists?(DOWNSTREAM_REPOS)
|
294
|
-
Dir.chdir(DOWNSTREAM_REPOS) do
|
295
|
-
CommandProcessor.command("git clone --origin origin #{downstream_repo.url} #{downstream_repo.name}") unless File.exists?(downstream_repo.name)
|
296
|
-
|
297
|
-
Dir.chdir(downstream_repo.name) do
|
298
|
-
reset_repo(downstream_repo.branch)
|
299
|
-
|
300
|
-
if downstream_repo.options.has_key? :new_branch_name
|
301
|
-
new_branch_name = get_new_branch_name(downstream_repo.options[:new_branch_name], @current_release.version)
|
302
|
-
GitUtil.delete_branch new_branch_name
|
303
|
-
end
|
304
|
-
end
|
305
|
-
end
|
306
|
-
end
|
307
|
-
Printer.success("Done resetting downstream repos.")
|
308
|
-
else
|
309
|
-
Printer.success("Not resetting downstream repos. None found.")
|
310
|
-
end
|
242
|
+
@downstream.reset(args)
|
311
243
|
end
|
312
244
|
|
313
245
|
desc "prepare downstream release, copying files from base_docs_dir and any other configured files"
|
314
246
|
task :prepare, [:downstream_repo_index] => [:config, :"validate:changelog", :reset] do |t, args|
|
315
|
-
|
316
|
-
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
317
|
-
puts "preparing downstream_repo[#{index}]: #{downstream_repo.url}" if @releasinator_config[:verbose]
|
318
|
-
|
319
|
-
root_dir = Dir.pwd.strip
|
320
|
-
copy_from_dir = root_dir + "/" + get_base_dir()
|
321
|
-
|
322
|
-
Dir.chdir(DOWNSTREAM_REPOS) do
|
323
|
-
Dir.chdir(downstream_repo.name) do
|
324
|
-
|
325
|
-
if downstream_repo.options.has_key? :new_branch_name
|
326
|
-
new_branch_name = get_new_branch_name(downstream_repo.options[:new_branch_name], @current_release.version)
|
327
|
-
CommandProcessor.command("git checkout -b #{new_branch_name}")
|
328
|
-
end
|
329
|
-
|
330
|
-
if full_file_sync(downstream_repo.options)
|
331
|
-
# remove old everything
|
332
|
-
CommandProcessor.command("rm -rf *")
|
333
|
-
|
334
|
-
# update all sdk files
|
335
|
-
CommandProcessor.command("rsync -av --exclude='#{DOWNSTREAM_REPOS}' --exclude='.git/' #{copy_from_dir}/* .")
|
336
|
-
CommandProcessor.command("rsync -av --exclude='#{DOWNSTREAM_REPOS}' --exclude='.git/' #{copy_from_dir}/.[!.]* .")
|
337
|
-
end
|
338
|
-
|
339
|
-
# copy custom files
|
340
|
-
if downstream_repo.options.has_key? :files_to_copy
|
341
|
-
downstream_repo.options[:files_to_copy].each do |copy_file|
|
342
|
-
copy_the_file(root_dir, copy_file, @current_release.version)
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
|
-
if downstream_repo.options.has_key? :post_copy_methods
|
347
|
-
downstream_repo.options[:post_copy_methods].each do |method|
|
348
|
-
method.call(@current_release.version)
|
349
|
-
end
|
350
|
-
end
|
351
|
-
|
352
|
-
if GitUtil.is_clean_git?
|
353
|
-
Printer.fail("Nothing changed in #{downstream_repo.name}!")
|
354
|
-
abort()
|
355
|
-
end
|
356
|
-
# add everything to git and commit
|
357
|
-
CommandProcessor.command("git add .")
|
358
|
-
CommandProcessor.command("git add -u .")
|
359
|
-
if downstream_repo.options.has_key? :new_branch_name
|
360
|
-
commit_message = "Update #{@releasinator_config[:product_name]} to #{@current_release.version}"
|
361
|
-
else
|
362
|
-
commit_message = "Release #{@current_release.version}"
|
363
|
-
end
|
364
|
-
CommandProcessor.command("git commit -am \"#{commit_message}\"")
|
365
|
-
end
|
366
|
-
end
|
367
|
-
end
|
368
|
-
Printer.success("Done preparing downstream repos.")
|
369
|
-
else
|
370
|
-
Printer.success("Not preparing downstream repos. None found.")
|
371
|
-
end
|
247
|
+
@downstream.prepare(args)
|
372
248
|
end
|
373
249
|
|
374
250
|
desc "call all build_methods for each downstream repo"
|
375
|
-
task :build, [:downstream_repo_index] => :config do |t, args|
|
376
|
-
|
377
|
-
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
378
|
-
puts "building downstream_repo[#{index}]: #{downstream_repo.url}" if @releasinator_config[:verbose]
|
379
|
-
Dir.chdir(DOWNSTREAM_REPOS) do
|
380
|
-
Dir.chdir(downstream_repo.name) do
|
381
|
-
# build any files to verify release
|
382
|
-
if downstream_repo.options.has_key? :build_methods
|
383
|
-
downstream_repo.options[:build_methods].each do |method|
|
384
|
-
method.call
|
385
|
-
end
|
386
|
-
end
|
387
|
-
end
|
388
|
-
end
|
389
|
-
end
|
390
|
-
Printer.success("Done building downstream repos.")
|
391
|
-
else
|
392
|
-
Printer.success("Not building downstream repos. None found.")
|
393
|
-
end
|
251
|
+
task :build, [:downstream_repo_index] => [:config,:"validate:changelog"] do |t, args|
|
252
|
+
@downstream.build(args)
|
394
253
|
end
|
395
254
|
|
396
255
|
desc "tag all non-branch downstream repos"
|
397
256
|
task :package, [:downstream_repo_index] => [:config,:"validate:changelog"] do |t, args|
|
398
|
-
|
399
|
-
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
400
|
-
puts "packaging downstream_repo[#{index}]: #{downstream_repo.url}" if @releasinator_config[:verbose]
|
401
|
-
Dir.chdir(DOWNSTREAM_REPOS) do
|
402
|
-
Dir.chdir(downstream_repo.name) do
|
403
|
-
# don't tag those where new branches are created
|
404
|
-
GitUtil.tag(@current_release.version, @current_release.changelog) unless downstream_repo.options.has_key? :new_branch_name
|
405
|
-
end
|
406
|
-
end
|
407
|
-
end
|
408
|
-
Printer.success("Done packaging downstream repos.")
|
409
|
-
else
|
410
|
-
Printer.success("Not packaging downstream repos. None found.")
|
411
|
-
end
|
257
|
+
@downstream.package(args)
|
412
258
|
end
|
413
259
|
|
414
260
|
desc "push tags and creates draft release, or pushes branch and creates pull request, depending on the presence of new_branch_name"
|
415
261
|
task :push, [:downstream_repo_index] => [:config,:"validate:changelog"] do |t, args|
|
416
|
-
|
417
|
-
get_downstream_repos(args[:downstream_repo_index]).each do |downstream_repo, index|
|
418
|
-
puts "pushing downstream_repo[#{index}]: #{downstream_repo.url}" if @releasinator_config[:verbose]
|
419
|
-
Dir.chdir(DOWNSTREAM_REPOS) do
|
420
|
-
Dir.chdir(downstream_repo.name) do
|
421
|
-
if downstream_repo.options.has_key? :new_branch_name
|
422
|
-
new_branch_name = get_new_branch_name(downstream_repo.options[:new_branch_name], @current_release.version)
|
423
|
-
CommandProcessor.command("git push -u origin #{new_branch_name}")
|
424
|
-
Publisher.new(@releasinator_config).publish_pull_request(downstream_repo.url, @current_release, @releasinator_config[:product_name], downstream_repo.branch, new_branch_name)
|
425
|
-
else
|
426
|
-
CommandProcessor.command("git push origin master --tags")
|
427
|
-
Publisher.new(@releasinator_config).publish_draft(downstream_repo.url, @current_release) unless ! release_to_github(downstream_repo.options)
|
428
|
-
end
|
429
|
-
end
|
430
|
-
end
|
431
|
-
end
|
432
|
-
Printer.success("Done pushing downstream repos.")
|
433
|
-
else
|
434
|
-
Printer.success("Not pushing downstream repos. None found.")
|
435
|
-
end
|
262
|
+
@downstream.push(args)
|
436
263
|
end
|
437
264
|
end
|
438
265
|
|
@@ -462,7 +289,7 @@ namespace :docs do
|
|
462
289
|
current_branch = GitUtil.get_current_branch()
|
463
290
|
|
464
291
|
GitUtil.init_gh_pages()
|
465
|
-
reset_repo("gh-pages")
|
292
|
+
GitUtil.reset_repo("gh-pages")
|
466
293
|
@releasinator_config[:doc_files_to_copy].each do |copy_file|
|
467
294
|
copy_the_file(root_dir, copy_file)
|
468
295
|
end
|
@@ -488,7 +315,7 @@ namespace :docs do
|
|
488
315
|
Dir.chdir(doc_target_dir) do
|
489
316
|
current_branch = GitUtil.get_current_branch()
|
490
317
|
CommandProcessor.command("git checkout gh-pages")
|
491
|
-
|
318
|
+
GitUtil.push_branch("gh-pages")
|
492
319
|
# switch back to previous branch
|
493
320
|
CommandProcessor.command("git checkout #{current_branch}")
|
494
321
|
end
|
data/lib/validator.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
require 'colorize'
|
1
|
+
require 'colorize'
|
2
2
|
require 'fileutils'
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
3
5
|
require_relative 'command_processor'
|
4
6
|
require_relative 'downstream_repo'
|
5
7
|
require_relative 'github_repo'
|
6
8
|
require_relative 'printer'
|
7
9
|
require_relative 'validator_changelog'
|
10
|
+
require_relative 'releasinator/version'
|
8
11
|
|
9
12
|
module Releasinator
|
10
13
|
class Validator
|
@@ -13,13 +16,32 @@ module Releasinator
|
|
13
16
|
@releasinator_config = releasinator_config
|
14
17
|
end
|
15
18
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
+
def validate_releasinator_version
|
20
|
+
uri = URI('https://rubygems.org/api/v1/gems/releasinator.json')
|
21
|
+
latest_version = JSON.parse(Net::HTTP.get(uri))["version"]
|
22
|
+
current_version = Releasinator::VERSION
|
23
|
+
|
24
|
+
if Gem::Version.new(latest_version) > Gem::Version.new(current_version)
|
25
|
+
Printer.fail("Please upgrade to the latest releasinator version:" + latest_version.bold + ". Current version:" + current_version.bold)
|
26
|
+
abort()
|
27
|
+
elsif Gem::Version.new(latest_version) < Gem::Version.new(current_version)
|
28
|
+
Printer.success("Releasinator version: " + current_version.bold + " is newer than one from rubygems.org: " + latest_version.bold + ". You're probably testing a development version.")
|
29
|
+
else
|
30
|
+
Printer.success("Releasinator version: " + latest_version.bold + " is the latest from rubygems.org.")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def validate_in_path(executable)
|
35
|
+
if "" == CommandProcessor.command("which #{executable} | cat")
|
36
|
+
Printer.fail(executable.bold + " not found on path.")
|
37
|
+
abort()
|
38
|
+
else
|
39
|
+
Printer.success(executable.bold + " found on path.")
|
19
40
|
end
|
20
41
|
end
|
21
42
|
|
22
43
|
def validate_git_version
|
44
|
+
validate_in_path("git")
|
23
45
|
version_output = CommandProcessor.command("git version")
|
24
46
|
# version where the parallel git fetch features were added
|
25
47
|
expected_git_version = "2.8.0"
|
@@ -34,10 +56,11 @@ module Releasinator
|
|
34
56
|
end
|
35
57
|
|
36
58
|
def validate_changelog(base_dir, downstream_dir)
|
59
|
+
validate_base_dir base_dir
|
37
60
|
validate_exist(base_dir, "CHANGELOG.md", downstream_dir, ["release_notes.md"])
|
38
61
|
|
39
62
|
changelog_contents = get_changelog_contents(base_dir)
|
40
|
-
ValidatorChangelog.new.validate_changelog_contents(changelog_contents)
|
63
|
+
ValidatorChangelog.new(@releasinator_config).validate_changelog_contents(changelog_contents)
|
41
64
|
end
|
42
65
|
|
43
66
|
def validate_is_type(obj, type)
|
@@ -114,37 +137,22 @@ module Releasinator
|
|
114
137
|
end
|
115
138
|
end
|
116
139
|
|
117
|
-
def
|
118
|
-
if !
|
119
|
-
is_git_already_clean = GitUtil.
|
120
|
-
|
140
|
+
def validate_gitignore_contents(line)
|
141
|
+
if !line_match_in_file?(line, ".gitignore")
|
142
|
+
is_git_already_clean = GitUtil.is_clean_git?
|
143
|
+
File.open('.gitignore', 'a') do |f|
|
144
|
+
f.puts "# #{@releasinator_config[:releasinator_name]}"
|
145
|
+
f.puts line
|
146
|
+
end
|
147
|
+
|
121
148
|
if is_git_already_clean
|
122
|
-
CommandProcessor.command("git add . && git commit -m \"#{@releasinator_config[:releasinator_name]}: add .gitignore\"")
|
123
|
-
Printer.success("Added .gitignore file.")
|
149
|
+
CommandProcessor.command("git add . && git commit -m \"#{@releasinator_config[:releasinator_name]}: add downstream dir to .gitignore\"")
|
150
|
+
Printer.success("Added downstream dir to .gitignore file.")
|
124
151
|
else
|
125
|
-
Printer.fail("Added .gitignore, but there are other changes in the workspace. Please commit and continue.")
|
152
|
+
Printer.fail("Added downstream dir to .gitignore file, but there are other changes in the workspace. Please commit and continue.")
|
126
153
|
abort()
|
127
154
|
end
|
128
155
|
end
|
129
|
-
Printer.success(".gitignore found.")
|
130
|
-
|
131
|
-
if is_downstream_present
|
132
|
-
if !line_match_in_file?(line, ".gitignore")
|
133
|
-
is_git_already_clean = GitUtil.new().is_clean_git?
|
134
|
-
File.open('.gitignore', 'a') do |f|
|
135
|
-
f.puts "# #{@releasinator_config[:releasinator_name]}"
|
136
|
-
f.puts line
|
137
|
-
end
|
138
|
-
|
139
|
-
if is_git_already_clean
|
140
|
-
CommandProcessor.command("git add . && git commit -m \"#{@releasinator_config[:releasinator_name]}: add downstream dir to .gitignore\"")
|
141
|
-
Printer.success("Added downstream dir to .gitignore file.")
|
142
|
-
else
|
143
|
-
Printer.fail("Added downstream dir to .gitignore file, but there are other changes in the workspace. Please commit and continue.")
|
144
|
-
abort()
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
156
|
end
|
149
157
|
|
150
158
|
def line_match_in_file?(contains_string, filename)
|
@@ -160,6 +168,7 @@ module Releasinator
|
|
160
168
|
end
|
161
169
|
|
162
170
|
def validate_referenced_in_readme(base_dir, filename)
|
171
|
+
validate_base_dir base_dir
|
163
172
|
Dir.chdir(base_dir) do
|
164
173
|
File.open("README.md", "r") do |f|
|
165
174
|
f.each_line do |line|
|
@@ -175,6 +184,7 @@ module Releasinator
|
|
175
184
|
end
|
176
185
|
|
177
186
|
def validate_exist(base_dir, expected_file_name, downstream_dir, alternate_names=[])
|
187
|
+
validate_base_dir base_dir
|
178
188
|
Dir.chdir(base_dir) do
|
179
189
|
if !File.exist?(expected_file_name)
|
180
190
|
puts "#{base_dir}/#{expected_file_name} not found. Searching for similar files.".yellow
|
@@ -199,6 +209,13 @@ module Releasinator
|
|
199
209
|
end
|
200
210
|
end
|
201
211
|
|
212
|
+
def validate_base_dir(base_dir)
|
213
|
+
if !File.exist? base_dir
|
214
|
+
Printer.fail("Directory specified by base_docs_dir '#{base_dir}' not found. Please fix the config, or add this directory.")
|
215
|
+
abort()
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
202
219
|
def validate_clean_git
|
203
220
|
untracked_files = GitUtil.untracked_files
|
204
221
|
diff = GitUtil.diff
|
@@ -231,15 +248,6 @@ module Releasinator
|
|
231
248
|
abort() if error
|
232
249
|
end
|
233
250
|
|
234
|
-
class Submodule
|
235
|
-
attr_reader :name, :path, :url
|
236
|
-
|
237
|
-
def initialize(name, path, url)
|
238
|
-
@name=name
|
239
|
-
@path=path
|
240
|
-
@url=url
|
241
|
-
end
|
242
|
-
end
|
243
251
|
|
244
252
|
def validate_submodules
|
245
253
|
if File.exist?(".gitmodules")
|
@@ -265,7 +273,8 @@ module Releasinator
|
|
265
273
|
Printer.success("Found " + submodules.count.to_s.bold + " submodules in .gitmodules.")
|
266
274
|
submodules.each do |submodule|
|
267
275
|
Dir.chdir(submodule.path) do
|
268
|
-
|
276
|
+
validate_local_matches_remote("master")
|
277
|
+
validate_clean_git()
|
269
278
|
end
|
270
279
|
end
|
271
280
|
else
|
@@ -273,24 +282,37 @@ module Releasinator
|
|
273
282
|
end
|
274
283
|
end
|
275
284
|
|
276
|
-
def
|
277
|
-
|
285
|
+
def validate_branches(version)
|
286
|
+
GitUtil.fetch()
|
287
|
+
current_branch = GitUtil.get_current_branch()
|
278
288
|
|
279
|
-
|
280
|
-
|
281
|
-
|
289
|
+
if @releasinator_config.use_git_flow()
|
290
|
+
expected_release_branch = "release/#{version}"
|
291
|
+
|
292
|
+
unless current_branch == expected_release_branch || current_branch == "develop"
|
293
|
+
Printer.fail("git flow expects the current branch to be either 'develop' or 'release/#{version}'. Current branch is '#{current_branch}'")
|
294
|
+
abort()
|
295
|
+
end
|
282
296
|
|
283
|
-
#
|
284
|
-
|
285
|
-
|
297
|
+
# validate that master is up to date, because git flow requires this.
|
298
|
+
validate_local_matches_remote("master")
|
299
|
+
else
|
300
|
+
unless current_branch == "master"
|
301
|
+
Printer.fail("non-git flow expects releases to come from the master branch. Current branch is '#{current_branch}'")
|
302
|
+
abort()
|
303
|
+
end
|
286
304
|
end
|
287
305
|
|
288
|
-
|
306
|
+
validate_local_matches_remote(current_branch)
|
307
|
+
end
|
289
308
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
309
|
+
private
|
310
|
+
|
311
|
+
def validate_local_matches_remote(branch_name)
|
312
|
+
local_branch_sha1 = GitUtil.get_local_branch_sha1(branch_name)
|
313
|
+
origin_branch_sha1 = GitUtil.get_remote_branch_sha1(branch_name)
|
314
|
+
if local_branch_sha1 != origin_branch_sha1
|
315
|
+
abort_string = "Branches not in sync: #{Dir.pwd} at #{local_branch_sha1}, but origin/#{branch_name} is #{origin_branch_sha1}."\
|
294
316
|
"\nIf you received this error on the root project, you may need to:"\
|
295
317
|
"\n 1. pull the latest changes from the remote,"\
|
296
318
|
"\n 2. push changes up to the remote,"\
|
@@ -298,7 +320,16 @@ module Releasinator
|
|
298
320
|
Printer.fail(abort_string)
|
299
321
|
abort()
|
300
322
|
else
|
301
|
-
Printer.success("
|
323
|
+
Printer.success("Repo #{Dir.pwd} matches origin/#{branch_name}.")
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
class Submodule
|
328
|
+
attr_reader :name, :path, :url
|
329
|
+
def initialize(name, path, url)
|
330
|
+
@name=name
|
331
|
+
@path=path
|
332
|
+
@url=url
|
302
333
|
end
|
303
334
|
end
|
304
335
|
|
@@ -320,5 +351,12 @@ module Releasinator
|
|
320
351
|
end
|
321
352
|
false
|
322
353
|
end
|
354
|
+
|
355
|
+
def get_changelog_contents(base_dir)
|
356
|
+
validate_base_dir base_dir
|
357
|
+
Dir.chdir(base_dir) do
|
358
|
+
open('CHANGELOG.md').read
|
359
|
+
end
|
360
|
+
end
|
323
361
|
end
|
324
362
|
end
|
data/lib/validator_changelog.rb
CHANGED
@@ -7,32 +7,51 @@ require_relative 'printer'
|
|
7
7
|
module Releasinator
|
8
8
|
class ValidatorChangelog
|
9
9
|
|
10
|
-
|
10
|
+
RELEASE_REGEX = /\d+\.\d+\.\d+/
|
11
|
+
|
12
|
+
def initialize(releasinator_config)
|
13
|
+
@releasinator_config = releasinator_config
|
14
|
+
end
|
15
|
+
|
16
|
+
# assume changelog_hash is not empty
|
17
|
+
def validate_semver(changelog_hash)
|
18
|
+
latest_release, latest_release_changelog = changelog_hash.first
|
19
|
+
# extract prefix from first release to use on all subsequent releases
|
20
|
+
latest_release_prefix = latest_release.partition(RELEASE_REGEX)[0]
|
21
|
+
|
11
22
|
newer_version = nil
|
12
23
|
changelog_hash.each do |key,value|
|
13
|
-
|
14
|
-
|
24
|
+
prefix, version, suffix = key.partition(RELEASE_REGEX)
|
25
|
+
puts "Checking version with prefix:'#{prefix}', version:'#{version}', suffix:'#{suffix}'." if @releasinator_config[:verbose]
|
26
|
+
if prefix != latest_release_prefix
|
27
|
+
Printer.fail("version #{key} does not start with extracted prefix '#{latest_release_prefix}'.")
|
15
28
|
abort()
|
16
29
|
end
|
17
|
-
older_version = Semantic::Version.new
|
30
|
+
older_version = Semantic::Version.new version
|
18
31
|
|
19
32
|
if nil != newer_version
|
20
33
|
version_comp = newer_version <=> older_version
|
21
|
-
if version_comp <
|
34
|
+
if version_comp < 0
|
22
35
|
Printer.fail("Semver releases out of order: #{older_version} should be smaller than #{newer_version}")
|
23
36
|
abort()
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
if newer_version.minor == older_version.minor
|
30
|
-
check_semver_criteria(newer_version.patch == older_version.patch + 1, "patch #{error_suffix}")
|
31
|
-
else
|
32
|
-
check_semver_criteria(newer_version.minor == older_version.minor + 1 && newer_version.patch == 0, "minor #{error_suffix}")
|
37
|
+
elsif version_comp == 0
|
38
|
+
# this case cannot be found with Vandamme library because 2 versions in a row get overwritten in the underlying hash
|
39
|
+
if suffix.empty?
|
40
|
+
Printer.fail("2 semver releases in a row without a suffix (like -beta, -rc1, etc...) is not allowed.")
|
41
|
+
abort()
|
33
42
|
end
|
34
43
|
else
|
35
|
-
|
44
|
+
error_suffix = "version increment error - comparing #{newer_version} to #{older_version} does not pass semver validation."
|
45
|
+
# validate the next sequence in semver
|
46
|
+
if newer_version.major == older_version.major
|
47
|
+
if newer_version.minor == older_version.minor
|
48
|
+
check_semver_criteria(newer_version.patch == older_version.patch + 1, "patch #{error_suffix}")
|
49
|
+
else
|
50
|
+
check_semver_criteria(newer_version.minor == older_version.minor + 1 && newer_version.patch == 0, "minor #{error_suffix}")
|
51
|
+
end
|
52
|
+
else
|
53
|
+
check_semver_criteria(newer_version.major == older_version.major + 1 && newer_version.minor == 0 && newer_version.patch == 0, "major #{error_suffix}")
|
54
|
+
end
|
36
55
|
end
|
37
56
|
end
|
38
57
|
newer_version = older_version
|
@@ -46,13 +65,13 @@ module Releasinator
|
|
46
65
|
end
|
47
66
|
end
|
48
67
|
|
49
|
-
def validate_changelog_contents(changelog_contents
|
68
|
+
def validate_changelog_contents(changelog_contents)
|
50
69
|
version_header_regexes = [
|
51
70
|
## h2 using --- separator. Example:
|
52
71
|
# 1.0.0
|
53
72
|
# -----
|
54
73
|
# First release!
|
55
|
-
'(
|
74
|
+
'(^#{RELEASE_REGEX}).*\n----.*',
|
56
75
|
|
57
76
|
# h1/h2 header retrieved from https://github.com/tech-angels/vandamme/#format
|
58
77
|
'^#{0,3} ?([\w\d\.-]+\.[\w\d\.-]+[a-zA-Z0-9])(?: \/ (\w+ \d{1,2}(?:st|nd|rd|th)?,\s\d{4}|\d{4}-\d{2}-\d{2}|\w+))?\n?[=-]*'
|
@@ -73,7 +92,7 @@ module Releasinator
|
|
73
92
|
|
74
93
|
Printer.success("Found " + changelog_hash.count.to_s.bold + " release(s) in CHANGELOG.md.")
|
75
94
|
|
76
|
-
validate_semver(changelog_hash
|
95
|
+
validate_semver(changelog_hash)
|
77
96
|
|
78
97
|
latest_release, latest_release_changelog = changelog_hash.first
|
79
98
|
CurrentRelease.new(latest_release, latest_release_changelog)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: releasinator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- PayPal
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04
|
11
|
+
date: 2016-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -158,6 +158,7 @@ files:
|
|
158
158
|
- lib/copy_file.rb
|
159
159
|
- lib/current_release.rb
|
160
160
|
- lib/default_config.rb
|
161
|
+
- lib/downstream.rb
|
161
162
|
- lib/downstream_repo.rb
|
162
163
|
- lib/git_util.rb
|
163
164
|
- lib/github_repo.rb
|