releasinator 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/releasinator.svg)](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
|