yes_ship_it 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 444ecc2191ed065ffeb7d23921a8518897ef5f59
4
+ data.tar.gz: 41ccaa7257b29964108a58bd27ddd5a9519984b8
5
+ SHA512:
6
+ metadata.gz: e5ab4853e2fd9337988199767d0264046b49f3122c773bda25d15d0f182f9f75caa73fa30764cb6dfa4c53fc72b1dafb52ccdba7ed625a9fafbf2d2599042afb
7
+ data.tar.gz: 9396162f0020b8ce79e9fc15475010f41b0da38a55c3f677172436a12e1c2d61b3a8d5152a07721688f1f5ab7037b6d9fc78d1a6323d3eb12da132c9a7fb84c4
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # Yes, ship it!
2
+
3
+ *The ultimate release script*
4
+
5
+ Whenever the answer is "Yes, ship it!" you will need `yes_ship_it`, this tool.
6
+ It is the ultimate helper in releasing software.
7
+
8
+ Shipping software is not an action. It's a state of mind. `yes_ship_it` helps
9
+ you to make sure that reality matches this state of mind. It won't fix the bugs
10
+ in your software, it doesn't create the tests which would need to be there, it
11
+ doesn't write your release notes. It does make sure that your good engineering
12
+ is delivered to your users with zero cost.
13
+
14
+ The approach of `yes_ship_it` is different from the typical release script. It
15
+ doesn't define a series of steps which are executed to make a release. It
16
+ defines a sequence of assertions about the release, which then are checked and
17
+ enforced.
18
+
19
+ This works in a way you could describe as idempotent, which means you
20
+ can execute it as many times as you want, the result will always be the same,
21
+ regardless of the initial state. That means the whole process is robust against
22
+ errors which happen during releasing, it transparently copes with manual tweaks
23
+ and changes, and it works on old releases just as well as on new releases.
24
+
25
+ After successfully running `yes_ship_it` your release will have shipped, and the
26
+ state of the world will reflect the state of your mind.
27
+
28
+ ## Assumptions
29
+
30
+ `yes_ship_it` assumes that you develop your software in a version control
31
+ system and keep at least some minimal state of releases there. This could just
32
+ be a tag. It also assumes that you are able to run `yes_ship_it` from the
33
+ command line and have some access to the systems which are needed to complete
34
+ the things part of a release.
35
+
36
+ ## How to run it
37
+
38
+ Go to the checkout of the sources of your software. Check that there is a file
39
+ called `yes_ship_it.conf` there. Run `yes_ship_it`. Done.
40
+
41
+ ## Configuration
42
+
43
+ The central configuration of what happens when you run `yes_ship_it` is the
44
+ `yes_ship_it.conf` file in the root directory of the sources of your software.
45
+ There you define the sequence of assertions which are run through for making
46
+ sure that the release is happening in the way you intend. `yes_ship_it` comes
47
+ with some predefined sequences of assertions you can simply reuse.
48
+
49
+ The format of `yes_ship_it.conf` uses YAML. A minimal `yes_ship_it.conf` file
50
+ could look like this:
51
+
52
+ ```yaml
53
+ include:
54
+ standard_rubygem
55
+ ```
56
+
57
+ A more detailed configuration could look like this:
58
+
59
+ ```yaml
60
+ assertions:
61
+ ci_green
62
+ release_notes
63
+ version_number
64
+ gem_built
65
+ release_tagged
66
+ gem_pushed
67
+ ```
68
+
69
+ There can be more configuration on a general level or the level of the
70
+ assertions to adjust to specific needs of each software project. There also can
71
+ be other or additional assertions.
72
+
73
+ ## Extending `yes_ship_it`
74
+
75
+ Many software projects will have specific needs for their releases. These can
76
+ be broken down and reflected in additional assertions. Adding assertions is
77
+ easy. There is a well-defined API for it.
78
+
79
+ There is no supported plugin concept. The idea is that all assertions ship with
80
+ `yes_ship_it`. This will maximize the value for the community of people who ship
81
+ software. The project is very open to include new assertions. Just submit a pull
82
+ request. `yes_ship_it` will ship it with the next release.
83
+
84
+ ## Testing
85
+
86
+ Testing a tool such as `yes_ship_it` is not easy because its prime functionality
87
+ is to interact with other systems and publish data. There are unit tests for the
88
+ code. There also are integration tests which work in a virtual environment which
89
+ fakes the services `yes_ship_it` interacts with. It uses the `pennyworth` tool
90
+ to manage the virtual environment and make them accessible in a convenient way
91
+ from the RSpec tests.
92
+
93
+ ## Further documentation
94
+
95
+ You get basic documentation from the tool itself by executing
96
+ `yes_ship_it help`. There also is a simple man page with some pointers.
97
+
98
+ The main documentation with details about different scenarios how `yes_ship_it`
99
+ can be used is maintained in the Wiki. You are welcome to contribute there.
100
+
101
+ ## License
102
+
103
+ `yes_ship_it` is licensed under the MIT license.
104
+
105
+ ## Contact
106
+
107
+ If you have any questions or comments, please don't hesitate to get in touch
108
+ with me: Cornelius Schumacher <schumacher@kde.org>.
@@ -0,0 +1,43 @@
1
+ module YSI
2
+ class BuiltGem < Assertion
3
+ attr_accessor :error
4
+
5
+ def initialize(engine)
6
+ @engine = engine
7
+ end
8
+
9
+ def display_name
10
+ "built gem"
11
+ end
12
+
13
+ def gem_file
14
+ "#{@engine.project_name}-#{@engine.version}.gem"
15
+ end
16
+
17
+ def gemspec_file
18
+ "#{@engine.project_name}.gemspec"
19
+ end
20
+
21
+ def check
22
+ if !File.exist?(gemspec_file)
23
+ @error = "I need a gemspec: #{gemspec_file}"
24
+ return nil
25
+ end
26
+
27
+ if !File.exist?(gem_file)
28
+ return nil
29
+ end
30
+
31
+ gem_file
32
+ end
33
+
34
+ def assert(dry_run: false)
35
+ if !dry_run
36
+ if !system("gem build #{gemspec_file}")
37
+ return nil
38
+ end
39
+ end
40
+ gem_file
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,25 @@
1
+ module YSI
2
+ class ChangeLog < Assertion
3
+ attr_reader :error
4
+
5
+ def initialize(engine)
6
+ @engine = engine
7
+ end
8
+
9
+ def display_name
10
+ "change log"
11
+ end
12
+
13
+ def check
14
+ if !File.exist?("CHANGELOG.md")
15
+ @error = "Expected change log in CHANGELOG.md"
16
+ return nil
17
+ end
18
+
19
+ "CHANGELOG.md"
20
+ end
21
+
22
+ def assert(dry_run: false)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,39 @@
1
+ module YSI
2
+ class PublishedGem < Assertion
3
+ attr_accessor :error
4
+
5
+ def initialize(engine)
6
+ @engine = engine
7
+ end
8
+
9
+ def display_name
10
+ "published gem"
11
+ end
12
+
13
+ def gem_file
14
+ "#{@engine.project_name}-#{@engine.version}.gem"
15
+ end
16
+
17
+ def check
18
+ begin
19
+ json = RestClient.get("http://rubygems.org/api/v1/versions/#{engine.project_name}.json")
20
+ rescue RestClient::ResourceNotFound
21
+ return nil
22
+ end
23
+ versions = JSON.parse(json)
24
+ versions.each do |version|
25
+ if version["number"] == @engine.version
26
+ return @engine.version
27
+ end
28
+ end
29
+ nil
30
+ end
31
+
32
+ def assert(dry_run: false)
33
+ if !dry_run
34
+ `gem push #{gem_file}`
35
+ end
36
+ gem_file
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ module YSI
2
+ class PushedTag < Assertion
3
+ def display_name
4
+ "pushed tag"
5
+ end
6
+
7
+ def tag
8
+ "v#{@engine.version}"
9
+ end
10
+
11
+ def check
12
+ response = `git ls-remote --tags origin #{tag}`
13
+ if response.include?(tag)
14
+ return response
15
+ end
16
+
17
+ nil
18
+ end
19
+
20
+ def assert(dry_run: false)
21
+ if !dry_run
22
+ `git push --tags`
23
+ end
24
+ tag
25
+ end
26
+ end
27
+ end
data/assertions/tag.rb ADDED
@@ -0,0 +1,32 @@
1
+ module YSI
2
+ class Tag < Assertion
3
+ def display_name
4
+ "tag"
5
+ end
6
+
7
+ def tag
8
+ "v#{@engine.version}"
9
+ end
10
+
11
+ def check
12
+ `git tag`.each_line do |line|
13
+ if line.chomp == tag
14
+ `git show #{tag}`.each_line do |show_line|
15
+ if show_line =~ /Date:\s+(.*)/
16
+ @engine.tag_date = $1
17
+ end
18
+ end
19
+ return tag
20
+ end
21
+ end
22
+ return nil
23
+ end
24
+
25
+ def assert(dry_run: false)
26
+ if !dry_run
27
+ `git tag -a #{tag} -m "Version #{@engine.version}"`
28
+ end
29
+ tag
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,33 @@
1
+ module YSI
2
+ class Version < Assertion
3
+ attr_accessor :error
4
+
5
+ def initialize(engine)
6
+ @engine = engine
7
+ end
8
+
9
+ def display_name
10
+ "version number"
11
+ end
12
+
13
+ def check
14
+ version_file = "lib/version.rb"
15
+ if !File.exist?(version_file)
16
+ @error = "Expected version in #{version_file}"
17
+ return nil
18
+ end
19
+
20
+ File.read(version_file).each_line do |line|
21
+ if line =~ /VERSION = "(.*)"/
22
+ @engine.version = $1
23
+ return @engine.version
24
+ end
25
+ end
26
+ @error = "Couldn't find version in #{version_file}"
27
+ nil
28
+ end
29
+
30
+ def assert(dry_run: false)
31
+ end
32
+ end
33
+ end
data/bin/yes_ship_it ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require_relative("../lib/yes_ship_it.rb")
4
+
5
+ puts "Shipping..."
6
+ puts
7
+
8
+ config_file = "yes_ship_it.conf"
9
+
10
+ if !File.exist?(config_file)
11
+ STDERR.puts("Unable to find file `yes_ship_it.conf`. I need it.")
12
+ exit 1
13
+ end
14
+
15
+ engine = YSI::Engine.new
16
+ engine.dry_run = ARGV == ["--dry-run"]
17
+
18
+ begin
19
+ engine.read(config_file)
20
+
21
+ exit engine.run
22
+ rescue YSI::Error => e
23
+ STDERR.puts e
24
+ exit 1
25
+ end
@@ -0,0 +1,10 @@
1
+ module YSI
2
+ class Assertion
3
+ attr_reader :error
4
+ attr_accessor :engine
5
+
6
+ def initialize(engine)
7
+ @engine = engine
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,104 @@
1
+ module YSI
2
+ class Engine
3
+ attr_reader :assertions
4
+ attr_accessor :version, :tag_date
5
+ attr_accessor :out
6
+ attr_accessor :dry_run
7
+
8
+ def self.class_for_assertion_name(name)
9
+ class_name = name.split("_").map { |n| n.capitalize }.join
10
+ begin
11
+ Object.const_get("YSI::" + class_name)
12
+ rescue NameError
13
+ raise YSI::Error.new("Error: Unknown assertion '#{name}'")
14
+ end
15
+ end
16
+
17
+ def initialize
18
+ @assertions = []
19
+ @out = STDOUT
20
+ end
21
+
22
+ def read(filename)
23
+ config = YAML.load_file(filename)
24
+
25
+ assertions = config["assertions"]
26
+ if assertions
27
+ assertions.each do |assertion|
28
+ if assertion == "version_number"
29
+ out.puts "Warning: use `version` instead of `version_number`."
30
+ out.puts
31
+ assertion = "version"
32
+ end
33
+
34
+ @assertions << YSI::Engine.class_for_assertion_name(assertion).new(self)
35
+ end
36
+ end
37
+ end
38
+
39
+ def project_name
40
+ File.basename(Dir.pwd)
41
+ end
42
+
43
+ def run
44
+ failed_assertions = []
45
+ errored_assertions = []
46
+
47
+ @assertions.each do |assertion|
48
+ out.print "Checking #{assertion.display_name}: "
49
+ success = assertion.check
50
+ if success
51
+ out.puts success
52
+ else
53
+ if assertion.error
54
+ out.puts "error"
55
+ out.puts " " + assertion.error
56
+ errored_assertions.push(assertion)
57
+ else
58
+ out.puts "fail"
59
+ failed_assertions.push(assertion)
60
+ end
61
+ end
62
+ end
63
+
64
+ out.puts
65
+
66
+ if !errored_assertions.empty?
67
+ out.puts "Couldn't ship #{project_name}. Help me."
68
+ return 1
69
+ else
70
+ if failed_assertions.empty?
71
+ if tag_date
72
+ out.puts "#{project_name} #{version} already shipped on #{tag_date}"
73
+ else
74
+ out.puts "#{project_name} #{version} already shipped"
75
+ end
76
+ return 0
77
+ else
78
+ failed_assertions.each do |assertion|
79
+ if dry_run
80
+ out.print "Dry run: "
81
+ end
82
+ out.print "Asserting #{assertion.display_name}: "
83
+ success = assertion.assert(dry_run: dry_run)
84
+ if !success
85
+ out.puts
86
+ out.puts "Ran into an error. Stopping shipping."
87
+ return 1
88
+ end
89
+ out.puts success
90
+ end
91
+
92
+ out.puts
93
+ if dry_run
94
+ out.puts "Did a dry run of shipping #{project_name} #{version}." +
95
+ " Nothing was changed."
96
+ else
97
+ out.puts "Shipped #{project_name} #{version}. Hooray!"
98
+ end
99
+ return 0
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,4 @@
1
+ module YSI
2
+ class Error < StandardError
3
+ end
4
+ end
@@ -0,0 +1,9 @@
1
+ require "yaml"
2
+ require "rest-client"
3
+
4
+ require_relative "yes_ship_it/assertion.rb"
5
+ require_relative "yes_ship_it/engine.rb"
6
+ require_relative "yes_ship_it/exceptions.rb"
7
+
8
+ assertions_dir = File.expand_path("../../assertions", __FILE__)
9
+ Dir[File.join(assertions_dir, "*.rb")].each { |f| require(f) }
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,3 @@
1
+ assertions:
2
+ - version
3
+ - change_log
@@ -0,0 +1,4 @@
1
+ assertions:
2
+ - version
3
+ - change_log
4
+ - xyz
@@ -0,0 +1,123 @@
1
+ require_relative "spec_helper"
2
+
3
+ include CliTester
4
+ include GivenFilesystemSpecHelpers
5
+
6
+ describe "command line interface" do
7
+ use_given_filesystem(keep_files: true)
8
+
9
+ it "does not find yes_ship_it.conf" do
10
+ dir = given_directory
11
+ expect(run_command(working_directory: dir)).to exit_with_error(1, /yes_ship_it.conf/)
12
+ end
13
+
14
+ describe "runs" do
15
+ it "fails when version is not there" do
16
+ dir = given_directory
17
+
18
+ setup_test_git_repo("000", dir)
19
+
20
+ expected_output = <<EOT
21
+ Shipping...
22
+
23
+ Warning: use `version` instead of `version_number`.
24
+
25
+ Checking version number: error
26
+ Expected version in lib/version.rb
27
+ Checking change log: error
28
+ Expected change log in CHANGELOG.md
29
+
30
+ Couldn't ship red_herring. Help me.
31
+ EOT
32
+
33
+ expect(run_command(working_directory: File.join(dir, "red_herring"))).
34
+ to exit_with_error(1, "", expected_output)
35
+ end
36
+
37
+ it "succeeds when all checks are met" do
38
+ dir = given_directory
39
+
40
+ setup_test_git_repo("001", dir)
41
+
42
+ expected_output = <<EOT
43
+ Shipping...
44
+
45
+ Warning: use `version` instead of `version_number`.
46
+
47
+ Checking version number: 0.0.1
48
+ Checking change log: CHANGELOG.md
49
+
50
+ red_herring 0.0.1 already shipped
51
+ EOT
52
+
53
+ expect(run_command(working_directory: File.join(dir, "red_herring"))).
54
+ to exit_with_success(expected_output)
55
+ end
56
+
57
+ it "succeeds when tag is there" do
58
+ dir = given_directory
59
+
60
+ setup_test_git_repo("002", dir)
61
+
62
+ expected_output = <<EOT
63
+ Shipping...
64
+
65
+ Warning: use `version` instead of `version_number`.
66
+
67
+ Checking version number: 0.0.1
68
+ Checking change log: CHANGELOG.md
69
+ Checking tag: v0.0.1
70
+
71
+ red_herring 0.0.1 already shipped on Wed Jul 1 00:46:19 2015 +0200
72
+ EOT
73
+
74
+ expect(run_command(working_directory: File.join(dir, "red_herring"))).
75
+ to exit_with_success(expected_output)
76
+ end
77
+
78
+ it "fails when gem is not built" do
79
+ dir = given_directory
80
+
81
+ setup_test_git_repo("003", dir)
82
+
83
+ expected_output = <<EOT
84
+ Shipping...
85
+
86
+ Checking version number: 0.0.1
87
+ Checking change log: CHANGELOG.md
88
+ Checking built gem: fail
89
+ Checking tag: v0.0.1
90
+
91
+ Asserting built gem: red_herring-0.0.1.gem
92
+
93
+ Shipped red_herring 0.0.1. Hooray!
94
+ EOT
95
+
96
+ expect(run_command(working_directory: File.join(dir, "red_herring"))).
97
+ to exit_with_success(expected_output)
98
+ end
99
+
100
+ it "processes the --dry-run option" do
101
+ dir = given_directory
102
+
103
+ setup_test_git_repo("003", dir)
104
+
105
+ expected_output = <<EOT
106
+ Shipping...
107
+
108
+ Checking version number: 0.0.1
109
+ Checking change log: CHANGELOG.md
110
+ Checking built gem: fail
111
+ Checking tag: v0.0.1
112
+
113
+ Dry run: Asserting built gem: red_herring-0.0.1.gem
114
+
115
+ Did a dry run of shipping red_herring 0.0.1. Nothing was changed.
116
+ EOT
117
+
118
+ expect(run_command(args: ["--dry-run"],
119
+ working_directory: File.join(dir, "red_herring"))).
120
+ to exit_with_success(expected_output)
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,10 @@
1
+ require "cli_tester"
2
+ require "given_filesystem/spec_helpers"
3
+
4
+ def setup_test_git_repo(version, dir)
5
+ tarball = "spec/data/red_herring-#{version}.tar.gz"
6
+ tarball_path = File.expand_path(tarball)
7
+ if !system("cd #{dir}; tar xzf #{tarball_path}")
8
+ raise "Unable to extract tarball #{tarball}"
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe "all assertions" do
4
+ all_classes = ObjectSpace.each_object(Class).select { |klass| klass < YSI::Assertion }
5
+
6
+ all_classes.each do |assertion_class|
7
+ describe assertion_class do
8
+ it_behaves_like "an assertion" do
9
+ let(:assertion) {assertion_class.new(YSI::Engine.new) }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,68 @@
1
+ require_relative "spec_helper.rb"
2
+
3
+ include GivenFilesystemSpecHelpers
4
+
5
+ describe YSI::Engine do
6
+ use_given_filesystem
7
+
8
+ describe "#class_for_assertion_name" do
9
+ it "creates VersionNumber class" do
10
+ expect(YSI::Engine.class_for_assertion_name("version")).
11
+ to be(YSI::Version)
12
+ end
13
+
14
+ it "creates ChangeLog class" do
15
+ expect(YSI::Engine.class_for_assertion_name("change_log")).
16
+ to be(YSI::ChangeLog)
17
+ end
18
+ end
19
+
20
+ describe "#read" do
21
+ it "reads valid configuration" do
22
+ path = nil
23
+ given_directory do
24
+ path = given_file("yes_ship_it.conf")
25
+ end
26
+
27
+ ysi = YSI::Engine.new
28
+
29
+ ysi.read(path)
30
+
31
+ expect(ysi.assertions.count).to eq(2)
32
+ expect(ysi.assertions[0].class).to eq(YSI::Version)
33
+ expect(ysi.assertions[1].class).to eq(YSI::ChangeLog)
34
+ end
35
+
36
+ it "fails on configuration with unknown assertions" do
37
+ path = nil
38
+ given_directory do
39
+ path = given_file("yes_ship_it.conf", from: "yes_ship_it.unknown.conf")
40
+ end
41
+
42
+ ysi = YSI::Engine.new
43
+
44
+ expect {
45
+ ysi.read(path)
46
+ }.to raise_error YSI::Error
47
+ end
48
+ end
49
+
50
+ it "runs assertions" do
51
+ path = nil
52
+ given_directory do
53
+ path = given_file("yes_ship_it.conf")
54
+ end
55
+
56
+ ysi = YSI::Engine.new
57
+
58
+ ysi.read(path)
59
+
60
+ ysi.assertions.each do |a|
61
+ expect(a).to receive(:check)
62
+ end
63
+
64
+ ysi.out = StringIO.new
65
+
66
+ ysi.run
67
+ end
68
+ end
@@ -0,0 +1,5 @@
1
+ require_relative "../../lib/yes_ship_it.rb"
2
+
3
+ support = File.expand_path("../support", __FILE__) + "/*.rb"
4
+
5
+ Dir[support].each { |f| require f }
@@ -0,0 +1,21 @@
1
+ shared_examples "an assertion" do
2
+ it "initializes with an engine" do
3
+ expect(assertion.engine).to be_a(YSI::Engine)
4
+ end
5
+
6
+ it "has a display name" do
7
+ expect(assertion.display_name).to be_a(String)
8
+ end
9
+
10
+ it "checks" do
11
+ expect(assertion).to respond_to(:check)
12
+ end
13
+
14
+ it "asserts" do
15
+ expect(assertion).to respond_to(:assert)
16
+ end
17
+
18
+ it "reports errors" do
19
+ expect(assertion).to respond_to(:error)
20
+ end
21
+ end
data/yes_ship_it.conf ADDED
@@ -0,0 +1,9 @@
1
+ # Experimental release automation. See https://github.com/cornelius/yes_ship_it.
2
+
3
+ assertions:
4
+ - version
5
+ - change_log
6
+ - built_gem
7
+ - published_gem
8
+ - tag
9
+ - pushed_tag
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yes_ship_it
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Cornelius Schumacher
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: given_filesystem
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: cli_tester
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Whenever the answer is 'Yes, ship it!' you will need yes_ship_it. It
56
+ is the ultimate helper in releasing software..
57
+ email:
58
+ - schumacher@kde.org
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - .rspec
64
+ - README.md
65
+ - assertions/built_gem.rb
66
+ - assertions/change_log.rb
67
+ - assertions/published_gem.rb
68
+ - assertions/pushed_tag.rb
69
+ - assertions/tag.rb
70
+ - assertions/version.rb
71
+ - bin/yes_ship_it
72
+ - lib/yes_ship_it.rb
73
+ - lib/yes_ship_it/assertion.rb
74
+ - lib/yes_ship_it/engine.rb
75
+ - lib/yes_ship_it/exceptions.rb
76
+ - spec/data/red_herring-000.tar.gz
77
+ - spec/data/red_herring-001.tar.gz
78
+ - spec/data/red_herring-002.tar.gz
79
+ - spec/data/red_herring-003.tar.gz
80
+ - spec/data/yes_ship_it.conf
81
+ - spec/data/yes_ship_it.unknown.conf
82
+ - spec/integration/cli_spec.rb
83
+ - spec/integration/spec_helper.rb
84
+ - spec/unit/assertions_spec.rb
85
+ - spec/unit/engine_spec.rb
86
+ - spec/unit/spec_helper.rb
87
+ - spec/unit/support/assertion_examples.rb
88
+ - yes_ship_it.conf
89
+ homepage: http://github.com/cornelius/yes_ship_it
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: 1.3.6
107
+ requirements: []
108
+ rubyforge_project: yes_ship_it
109
+ rubygems_version: 2.0.3
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: The ultimate release script
113
+ test_files: []
114
+ has_rdoc: