yes_ship_it 0.0.2 → 0.0.3
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/.gitignore +2 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +14 -0
- data/README.md +9 -1
- data/USERS.md +13 -0
- data/assertions/built_gem.rb +0 -6
- data/assertions/change_log.rb +0 -6
- data/assertions/published_gem.rb +1 -7
- data/assertions/release_archive.rb +43 -0
- data/assertions/release_branch.rb +37 -0
- data/assertions/submitted_rpm.rb +134 -0
- data/assertions/version.rb +22 -11
- data/assertions/working_directory.rb +42 -0
- data/bin/yes_ship_it +22 -5
- data/configs/ruby_gem.conf +2 -0
- data/lib/version.rb +1 -1
- data/lib/yes_ship_it.rb +3 -0
- data/lib/yes_ship_it/assertion.rb +26 -0
- data/lib/yes_ship_it/engine.rb +25 -5
- data/spec/data/obs/mycroft.spec.erb +11 -0
- data/spec/data/obs/oscrc +8 -0
- data/spec/data/red_herring-006.tar.gz +0 -0
- data/spec/data/version/version.go +5 -0
- data/spec/data/version/version.rb +3 -0
- data/spec/integration/cli_spec.rb +74 -0
- data/spec/system/data/red_herring-checkout-build.tar.gz +0 -0
- data/spec/system/data/red_herring-checkout-not-push.tar.gz +0 -0
- data/spec/system/data/red_herring-checkout-push.tar.gz +0 -0
- data/spec/system/data/red_herring-remote.tar.gz +0 -0
- data/spec/system/ruby_gem_spec.rb +119 -0
- data/spec/system/spec_helper.rb +1 -0
- data/spec/unit/assertion_spec.rb +46 -0
- data/spec/unit/assertions/release_archive_spec.rb +13 -0
- data/spec/unit/assertions/release_branch_spec.rb +29 -0
- data/spec/unit/assertions/submitted_rpm_spec.rb +48 -0
- data/spec/unit/assertions/version_spec.rb +44 -0
- data/spec/unit/assertions/working_directory_spec.rb +79 -0
- data/spec/unit/engine_spec.rb +14 -0
- data/yes_ship_it.gemspec +7 -1
- metadata +78 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4392d3f5e95dc46ee07c90f82060e192d450961c
|
4
|
+
data.tar.gz: fca85312702536c2f0a3bdf4e85d87d293be352b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f40cf52945fc8beeac7f925bf14613a2defb151d4d800b0224da6458a41a5ff36d8cd5e0d1c65f328e4949d7cdcdeaecafeb6f3a6184858a6ec91de3c7622dd4
|
7
|
+
data.tar.gz: 0fcb4cc163dc5e891c95e73bc6cbb61b22d79d0562615ca831de7ceb0f964ef2279c067615ed10aa3a769df564161a63fb4c187a066e59aafb62f778c14333c7
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Change log of yes_ship_it
|
2
2
|
|
3
|
+
## Version 0.0.3
|
4
|
+
|
5
|
+
* Implement minimal version of `yes_ship_it init`. The init command is supposed
|
6
|
+
to analyze an existing directory with code and create a suitable initial
|
7
|
+
configuration for yes_ship_it. The current implementation simply assumes that
|
8
|
+
it is a Ruby gem we are going to ship.
|
9
|
+
* Add assertion for submitting RPMs to the Open Build Service
|
10
|
+
* Add assertion for creating a release archive as tarball
|
11
|
+
* Support parsing version from a Go project
|
12
|
+
* Add assertion for clean working directory, which checks unstaged commits and
|
13
|
+
untracked files
|
14
|
+
* Add assertion which checks that the local checkout is on the release branch.
|
15
|
+
The default release branch is master.
|
16
|
+
|
3
17
|
## Version 0.0.2
|
4
18
|
|
5
19
|
* Don't run assertions when dependent assertions have failed
|
data/README.md
CHANGED
@@ -96,7 +96,15 @@ You get basic documentation from the tool itself by executing
|
|
96
96
|
`yes_ship_it help`. There also is a simple man page with some pointers.
|
97
97
|
|
98
98
|
The main documentation with details about different scenarios how `yes_ship_it`
|
99
|
-
can be used is maintained in the
|
99
|
+
can be used is maintained in the
|
100
|
+
[Wiki](https://github.com/cornelius/yes_ship_it/wiki). You are welcome to
|
101
|
+
contribute there.
|
102
|
+
|
103
|
+
## Users
|
104
|
+
|
105
|
+
There is a list of [users of yes_ship_it](https://github.com/cornelius/yes_ship_it/blob/master/USERS.md).
|
106
|
+
I'm happy to add you there. Just send me a pull requests for the `USERS.md`
|
107
|
+
file.
|
100
108
|
|
101
109
|
## License
|
102
110
|
|
data/USERS.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Users of yes_ship_it
|
2
|
+
|
3
|
+
This is a list of projects using yes_ship_it to do releases. If you want to get
|
4
|
+
your project added please send a pull request. If you include a contact email,
|
5
|
+
you will get notified when changes happen in yes_ship_it which are likely to
|
6
|
+
affect you.
|
7
|
+
|
8
|
+
* [yes_ship_it](https://github.com/cornelius/yes_ship_it)
|
9
|
+
* [Trollolo](https://github.com/openSUSE/trollolo)
|
10
|
+
* [Inqlude](https://github.com/cornelius/inqlude) ([Contact](mailto:schumacher@kde.org))
|
11
|
+
* [cli_tester](https://github.com/cornelius/cli_tester)
|
12
|
+
* [Mycroft](https://github.com/cornelius/mycroft)
|
13
|
+
* [Httpotemkin](https://github.com/cornelius/httpotemkin)
|
data/assertions/built_gem.rb
CHANGED
data/assertions/change_log.rb
CHANGED
data/assertions/published_gem.rb
CHANGED
@@ -2,12 +2,6 @@ module YSI
|
|
2
2
|
class PublishedGem < Assertion
|
3
3
|
needs "built_gem"
|
4
4
|
|
5
|
-
attr_accessor :error
|
6
|
-
|
7
|
-
def initialize(engine)
|
8
|
-
@engine = engine
|
9
|
-
end
|
10
|
-
|
11
5
|
def display_name
|
12
6
|
"published gem"
|
13
7
|
end
|
@@ -18,7 +12,7 @@ module YSI
|
|
18
12
|
|
19
13
|
def check
|
20
14
|
begin
|
21
|
-
json = RestClient.get("
|
15
|
+
json = RestClient.get("https://rubygems.org/api/v1/versions/#{engine.project_name}.json")
|
22
16
|
rescue RestClient::ResourceNotFound
|
23
17
|
return nil
|
24
18
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module YSI
|
2
|
+
class ReleaseArchive < Assertion
|
3
|
+
def display_name
|
4
|
+
"release archive"
|
5
|
+
end
|
6
|
+
|
7
|
+
def git_revision
|
8
|
+
`git rev-parse HEAD`.chomp
|
9
|
+
end
|
10
|
+
|
11
|
+
def filename
|
12
|
+
"#{engine.project_name}-#{engine.version}.tar.gz"
|
13
|
+
end
|
14
|
+
|
15
|
+
def release_archive
|
16
|
+
File.join(engine.data_dir, "release_archives", engine.project_name,
|
17
|
+
git_revision, filename)
|
18
|
+
end
|
19
|
+
|
20
|
+
def check
|
21
|
+
engine.release_archive = release_archive
|
22
|
+
if File.exist?(release_archive)
|
23
|
+
return filename
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def assert(dry_run: false)
|
29
|
+
if !dry_run
|
30
|
+
Dir.mktmpdir do |tmp_dir|
|
31
|
+
archive_dir = "#{engine.project_name}-#{engine.version}"
|
32
|
+
cmd = "git clone #{Dir.pwd} #{File.join(tmp_dir, archive_dir)} 2>/dev/null"
|
33
|
+
system(cmd)
|
34
|
+
FileUtils.mkdir_p(File.dirname(release_archive))
|
35
|
+
excludes = [".git", ".gitignore", "yes_ship_it.conf"]
|
36
|
+
exclude_options = excludes.map { |e| "--exclude '#{e}'" }.join(" ")
|
37
|
+
system("cd #{tmp_dir}; tar czf #{release_archive} #{exclude_options} #{archive_dir}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
filename
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module YSI
|
2
|
+
class ReleaseBranch < Assertion
|
3
|
+
def display_name
|
4
|
+
"release branch"
|
5
|
+
end
|
6
|
+
|
7
|
+
def branch
|
8
|
+
"master"
|
9
|
+
end
|
10
|
+
|
11
|
+
def current_branch
|
12
|
+
git_branch.each_line do |line|
|
13
|
+
if line =~ /\* (.*)/
|
14
|
+
return $1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def git_branch
|
21
|
+
`git branch`
|
22
|
+
end
|
23
|
+
|
24
|
+
def check
|
25
|
+
if current_branch != branch
|
26
|
+
@error = "Not on release branch '#{branch}'"
|
27
|
+
return nil
|
28
|
+
else
|
29
|
+
return branch
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def assert(dry_run: false)
|
34
|
+
branch
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module YSI
|
2
|
+
class SubmittedRpm < Assertion
|
3
|
+
parameter :obs_project
|
4
|
+
|
5
|
+
attr_reader :obs_user, :obs_password
|
6
|
+
attr_reader :obs_package_files
|
7
|
+
|
8
|
+
def display_name
|
9
|
+
"submitted RPM"
|
10
|
+
end
|
11
|
+
|
12
|
+
def read_obs_credentials(file_name)
|
13
|
+
oscrc = IniFile.load(file_name)
|
14
|
+
@obs_user = oscrc["https://api.opensuse.org"]["user"]
|
15
|
+
@obs_password = oscrc["https://api.opensuse.org"]["pass"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def archive_file_name
|
19
|
+
engine.release_archive_file_name
|
20
|
+
end
|
21
|
+
|
22
|
+
class RpmSpecHelpers
|
23
|
+
def initialize(engine)
|
24
|
+
@engine = engine
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_binding
|
28
|
+
binding
|
29
|
+
end
|
30
|
+
|
31
|
+
def version
|
32
|
+
@engine.version
|
33
|
+
end
|
34
|
+
|
35
|
+
def release_archive
|
36
|
+
@engine.release_archive_file_name
|
37
|
+
end
|
38
|
+
|
39
|
+
def release_directory
|
40
|
+
"#{@engine.project_name}-#{@engine.version}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_spec_file(template)
|
45
|
+
erb = ERB.new(File.read(template))
|
46
|
+
erb.result(RpmSpecHelpers.new(engine).get_binding)
|
47
|
+
end
|
48
|
+
|
49
|
+
def check
|
50
|
+
if !obs_project
|
51
|
+
@error = "OBS project is not set"
|
52
|
+
return nil
|
53
|
+
end
|
54
|
+
if !engine.release_archive
|
55
|
+
@error = "Release archive is not set. Assert release_archive before submitted_rpm"
|
56
|
+
return nil
|
57
|
+
end
|
58
|
+
|
59
|
+
read_obs_credentials(File.expand_path("~/.oscrc"))
|
60
|
+
|
61
|
+
begin
|
62
|
+
url = "https://#{obs_user}:#{obs_password}@api.opensuse.org/source/home:cschum:go/#{engine.project_name}"
|
63
|
+
xml = RestClient.get(url)
|
64
|
+
rescue RestClient::Exception => e
|
65
|
+
if e.is_a?(RestClient::ResourceNotFound)
|
66
|
+
return nil
|
67
|
+
elsif e.is_a?(RestClient::Unauthorized)
|
68
|
+
@error = "No credentials set for OBS. Use osc to do this."
|
69
|
+
return nil
|
70
|
+
else
|
71
|
+
@error = e.to_s
|
72
|
+
return nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@obs_package_files = []
|
77
|
+
doc = REXML::Document.new(xml)
|
78
|
+
doc.elements.each("directory/entry") do |element|
|
79
|
+
file_name = element.attributes["name"]
|
80
|
+
@obs_package_files.push(file_name)
|
81
|
+
end
|
82
|
+
if @obs_package_files.include?(archive_file_name)
|
83
|
+
return archive_file_name
|
84
|
+
end
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
|
88
|
+
def assert(dry_run: false)
|
89
|
+
engine.out.puts "..."
|
90
|
+
|
91
|
+
old_files = []
|
92
|
+
@obs_package_files.each do |file|
|
93
|
+
next if file == "#{engine.project_name}.spec"
|
94
|
+
next if file == archive_file_name
|
95
|
+
old_files.push(file)
|
96
|
+
end
|
97
|
+
|
98
|
+
engine.out.puts " Uploading release archive '#{archive_file_name}'"
|
99
|
+
if !dry_run
|
100
|
+
url = "https://#{obs_user}:#{obs_password}@api.opensuse.org/source/home:cschum:go/#{engine.project_name}/#{archive_file_name}"
|
101
|
+
file = File.new(engine.release_archive, "rb")
|
102
|
+
begin
|
103
|
+
RestClient.put(url, file, content_type: "application/x-gzip")
|
104
|
+
rescue RestClient::Exception => e
|
105
|
+
STDERR.puts e.inspect
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
spec_file = engine.project_name + ".spec"
|
110
|
+
engine.out.puts " Uploading spec file '#{spec_file}'"
|
111
|
+
if !dry_run
|
112
|
+
url = "https://#{obs_user}:#{obs_password}@api.opensuse.org/source/home:cschum:go/#{engine.project_name}/#{spec_file}"
|
113
|
+
content = create_spec_file("rpm/#{spec_file}.erb")
|
114
|
+
begin
|
115
|
+
RestClient.put(url, content, content_type: "text/plain")
|
116
|
+
rescue RestClient::Exception => e
|
117
|
+
STDERR.puts e.inspect
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
old_files.each do |file|
|
122
|
+
engine.out.puts " Removing '#{file}'"
|
123
|
+
if !dry_run
|
124
|
+
url = "https://#{obs_user}:#{obs_password}@api.opensuse.org/source/home:cschum:go/#{engine.project_name}/#{file}"
|
125
|
+
RestClient.delete(url)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
engine.out.print "... "
|
130
|
+
|
131
|
+
"#{obs_project}/#{engine.project_name}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
data/assertions/version.rb
CHANGED
@@ -1,27 +1,21 @@
|
|
1
1
|
module YSI
|
2
2
|
class Version < Assertion
|
3
|
-
|
4
|
-
|
5
|
-
def initialize(engine)
|
6
|
-
@engine = engine
|
7
|
-
end
|
3
|
+
parameter :version_file, "lib/version.rb"
|
8
4
|
|
9
5
|
def display_name
|
10
6
|
"version number"
|
11
7
|
end
|
12
8
|
|
13
9
|
def check
|
14
|
-
version_file = "lib/version.rb"
|
15
10
|
if !File.exist?(version_file)
|
16
11
|
@error = "Expected version in #{version_file}"
|
17
12
|
return nil
|
18
13
|
end
|
19
14
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
15
|
+
version = parse_version(version_file)
|
16
|
+
if version
|
17
|
+
@engine.version = version
|
18
|
+
return @engine.version
|
25
19
|
end
|
26
20
|
@error = "Couldn't find version in #{version_file}"
|
27
21
|
nil
|
@@ -29,5 +23,22 @@ module YSI
|
|
29
23
|
|
30
24
|
def assert(dry_run: false)
|
31
25
|
end
|
26
|
+
|
27
|
+
def parse_version(file_name)
|
28
|
+
if file_name =~ /\.rb$/
|
29
|
+
File.read(file_name).each_line do |line|
|
30
|
+
if line =~ /VERSION = "(.*)"/
|
31
|
+
return $1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
elsif file_name =~ /\.go$/
|
35
|
+
File.read(file_name).each_line do |line|
|
36
|
+
if line =~ /Version = "(.*)"/
|
37
|
+
return $1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
nil
|
42
|
+
end
|
32
43
|
end
|
33
44
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module YSI
|
2
|
+
class WorkingDirectory < Assertion
|
3
|
+
def display_name
|
4
|
+
"working directory"
|
5
|
+
end
|
6
|
+
|
7
|
+
def git_status
|
8
|
+
`git status`
|
9
|
+
end
|
10
|
+
|
11
|
+
def status
|
12
|
+
if !@status
|
13
|
+
g = git_status
|
14
|
+
if g =~ /working directory clean/
|
15
|
+
@status = "clean"
|
16
|
+
elsif g =~ /Changes to be committed/
|
17
|
+
@status = "uncommitted changes"
|
18
|
+
elsif g =~ /Untracked files/
|
19
|
+
@status = "untracked files"
|
20
|
+
elsif g =~ /Changes not staged/
|
21
|
+
@status = "unstaged changes"
|
22
|
+
else
|
23
|
+
@status = nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
@status
|
27
|
+
end
|
28
|
+
|
29
|
+
def check
|
30
|
+
if status == "clean"
|
31
|
+
return status
|
32
|
+
else
|
33
|
+
@error = status
|
34
|
+
return nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def assert(dry_run: false)
|
39
|
+
"clean"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/bin/yes_ship_it
CHANGED
@@ -9,6 +9,7 @@ option_parser = OptionParser.new do |opts|
|
|
9
9
|
opts.separator ""
|
10
10
|
opts.separator "Commands:"
|
11
11
|
opts.separator " changelog - show change log since last release"
|
12
|
+
opts.separator " init - initialize directory for shipping with yes_ship_it"
|
12
13
|
opts.separator ""
|
13
14
|
opts.separator "Specific options:"
|
14
15
|
|
@@ -16,6 +17,10 @@ option_parser = OptionParser.new do |opts|
|
|
16
17
|
options[:dry_run] = v
|
17
18
|
end
|
18
19
|
|
20
|
+
opts.on("--data-dir=DIR", "Set directory for storing internal data") do |v|
|
21
|
+
options[:data_dir] = v
|
22
|
+
end
|
23
|
+
|
19
24
|
opts.on_tail("-h", "--help", "Show this message") do
|
20
25
|
puts opts
|
21
26
|
exit
|
@@ -25,23 +30,35 @@ option_parser.parse!
|
|
25
30
|
|
26
31
|
config_file = "yes_ship_it.conf"
|
27
32
|
|
28
|
-
if !File.exist?(config_file)
|
29
|
-
STDERR.puts("Unable to find file `yes_ship_it.conf`. I need it.")
|
30
|
-
exit 1
|
31
|
-
end
|
32
|
-
|
33
33
|
if ARGV == ["changelog"]
|
34
34
|
engine = YSI::Engine.new
|
35
35
|
engine.check_assertion(YSI::Version)
|
36
36
|
tag = `git tag`.split("\n").last
|
37
37
|
system("git log #{tag}..HEAD")
|
38
38
|
exit 0
|
39
|
+
elsif ARGV == ["init"]
|
40
|
+
File.open("yes_ship_it.conf", "w") do |file|
|
41
|
+
file.puts "# Experimental release automation. See https://github.com/cornelius/yes_ship_it."
|
42
|
+
file.puts "include:"
|
43
|
+
file.puts " ruby_gem"
|
44
|
+
end
|
45
|
+
puts "Initialized directory for shipping."
|
46
|
+
puts
|
47
|
+
puts "Check the file `yes_ship_it.conf` and adapt it to your needs."
|
48
|
+
puts
|
49
|
+
puts "Happy shipping!"
|
39
50
|
elsif ARGV.empty?
|
51
|
+
if !File.exist?(config_file)
|
52
|
+
STDERR.puts("Unable to find file `yes_ship_it.conf`. I need it.")
|
53
|
+
exit 1
|
54
|
+
end
|
55
|
+
|
40
56
|
puts "Shipping..."
|
41
57
|
puts
|
42
58
|
|
43
59
|
engine = YSI::Engine.new
|
44
60
|
engine.dry_run = options[:dry_run]
|
61
|
+
engine.data_dir = options[:data_dir] if options[:data_dir]
|
45
62
|
|
46
63
|
begin
|
47
64
|
engine.read(config_file)
|