cartage 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,106 @@
1
+ class Cartage
2
+ class Manifest
3
+ # This module provides a command the ability to properly handle the
4
+ # Cartage::Manifest::MissingError.
5
+ module HandleMissingManifest #:nodoc:
6
+ def handle_missing_manifest
7
+ yield
8
+ rescue Cartage::Manifest::MissingError => e
9
+ $stderr.puts e.message
10
+ command = super_command.commands['manifest'].usage.
11
+ gsub(/^\s*Usage:\s+/, ' ')
12
+ $stderr.puts command
13
+ false
14
+ end
15
+ end
16
+
17
+ # Implement <tt>cartage manifest</tt> to generate Manifest.txt.
18
+ class ManifestCommand < Cartage::Command #:nodoc:
19
+ def initialize(cartage)
20
+ super(cartage, 'manifest')
21
+ takes_commands(false)
22
+ short_desc('Update the Cartage Manifest.txt file.')
23
+
24
+ @manifest = cartage.manifest
25
+ end
26
+
27
+ def perform(*)
28
+ @manifest.generate
29
+ end
30
+ end
31
+
32
+ # Implement <tt>cartage check</tt> to compare the repository against
33
+ # Manifest.txt.
34
+ class CheckCommand < Cartage::Command #:nodoc:
35
+ include HandleMissingManifest
36
+
37
+ def initialize(cartage)
38
+ super(cartage, 'check')
39
+ takes_commands(false)
40
+ short_desc('Check the Manifest.txt against the current repository.')
41
+
42
+ @manifest = cartage.manifest
43
+ end
44
+
45
+ def perform(*)
46
+ handle_missing_manifest do
47
+ @manifest.check
48
+ raise Cartage::QuietError.new($?.exitstatus) unless $?.success?
49
+ end
50
+ end
51
+ end
52
+
53
+ class InstallDefaultIgnoreCommand < Cartage::Command #:nodoc:
54
+ def initialize(cartage)
55
+ super(cartage, 'install-ignore')
56
+ takes_commands(false)
57
+ short_desc('Installs the default ignore file.')
58
+
59
+ self.options do |opts|
60
+ opts.on('-f', '--force', 'Force write .cartignore.') {
61
+ @mode = :force
62
+ }
63
+ opts.on('-m', '--merge', 'Merge .cartignore with the default.') {
64
+ @mode = :merge
65
+ }
66
+ end
67
+
68
+ @manifest = cartage.manifest
69
+ @mode = nil
70
+ end
71
+
72
+ def perform(*)
73
+ @manifest.install_default_ignore(mode: @mode)
74
+ end
75
+ end
76
+
77
+ class ShowCommand < Cartage::Command #:nodoc:
78
+ include HandleMissingManifest
79
+
80
+ def initialize(cartage)
81
+ super(cartage, 'show')
82
+ takes_commands(false)
83
+ short_desc('Show the files that will be included in the package.')
84
+
85
+ @manifest = cartage.manifest
86
+ end
87
+
88
+ def perform(*)
89
+ handle_missing_manifest do
90
+ @manifest.resolve do |tmpfile|
91
+ puts Pathname(tmpfile).read
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ def self.commands #:nodoc:
98
+ [
99
+ ManifestCommand,
100
+ CheckCommand,
101
+ InstallDefaultIgnoreCommand,
102
+ ShowCommand
103
+ ]
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,14 @@
1
+ class Cartage
2
+ class PackCommand < Command #:nodoc:
3
+ def initialize(cartage)
4
+ super(cartage, 'pack', takes_commands: false)
5
+
6
+ Cartage.common_build_options(options, cartage)
7
+ short_desc('Create a package with Cartage based on the Manifest.')
8
+ end
9
+
10
+ def perform
11
+ @cartage.pack
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,80 @@
1
+ class Cartage
2
+ # Cartage::Plugin is the basis of the Cartage plugin system. All plug-ins
3
+ # must inherit from this class.
4
+ class Plugin
5
+ class << self
6
+ # Register a subclass.
7
+ def inherited(klass) #:nodoc:
8
+ registered << klass
9
+ end
10
+
11
+ # The plugins registered with Cartage.
12
+ def registered
13
+ @registered ||= []
14
+ end
15
+
16
+ # A utility method that will find all Cartage plugins and load them. A
17
+ # Cartage plugin is found with 'cartage/*.rb' and descends from
18
+ # Cartage::Plugin.
19
+ def load #:nodoc:
20
+ @found ||= {}
21
+ @loaded ||= {}
22
+ @files ||= Gem.find_files('cartage/*.rb')
23
+
24
+ @files.reverse.each do |path|
25
+ name = File.basename(path, '.rb').to_sym
26
+ @found[name] = path
27
+ end
28
+
29
+ :repeat while @found.map { |name, plugin|
30
+ load_plugin(name, plugin)
31
+ }.any?
32
+ end
33
+
34
+ # Decorate the provided class with lazy initialization methods.
35
+ def decorate(klass) #:nodoc:
36
+ registered.each do |plugin|
37
+ name = plugin.name.split(/::/).last.gsub(/([A-Z])/, '_\1').downcase.
38
+ sub(/^_/, '')
39
+ ivar = "@#{name}"
40
+
41
+ klass.send(:define_method, name) do
42
+ instance = instance_variable_defined?(ivar) &&
43
+ instance_variable_get(ivar)
44
+
45
+ instance ||= instance_variable_set(ivar, plugin.new(self))
46
+ end
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def load_plugin(name, plugin)
53
+ return if @loaded[name]
54
+
55
+ warn "loading #{plugin}" if $DEBUG
56
+ @loaded[name] = require plugin
57
+ rescue LoadError => e
58
+ warn "error loading #{plugin.inspect}: #{e.message}. Skipping..."
59
+ end
60
+ end
61
+
62
+ # These are the command classes provided to the cartage binary. Despite the
63
+ # name being plural, the return can either be a single CmdParse::Command
64
+ # class, or an array of CmdParse::Command class. These command classes
65
+ # should inherit from Cartage::Command, since they will be initialized with
66
+ # a cartage parameter.
67
+ def self.commands
68
+ []
69
+ end
70
+
71
+ # A plug-in is initialized with the Cartage instance that owns it.
72
+ def initialize(cartage)
73
+ @cartage = cartage
74
+ end
75
+
76
+ private
77
+ def resolve_config!(*)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,72 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ gem 'minitest'
4
+ require 'minitest/autorun'
5
+ require 'minitest/pretty_diff'
6
+ require 'minitest/focus'
7
+ require 'minitest/moar'
8
+ require 'minitest/bisect'
9
+
10
+ require 'cartage'
11
+
12
+ module Minitest::ENVStub
13
+ def stub_env env, options = {}, *block_args, &block
14
+ mock = lambda { |key|
15
+ env.fetch(key) { |k|
16
+ if options[:passthrough]
17
+ ENV.send(:"__minitest_stub__[]", k)
18
+ else
19
+ nil
20
+ end
21
+ }
22
+ }
23
+
24
+ if defined? Minitest::Moar::Stubbing
25
+ stub ENV, :[], mock, *block_args, &block
26
+ else
27
+ ENV.stub :[], mock, *block_args, &block
28
+ end
29
+ end
30
+
31
+ def stub_cartage_repo_url value = nil, &block
32
+ instance_stub Cartage, :repo_url,
33
+ -> { value || 'git://host/repo-url.git' }, &block
34
+ end
35
+
36
+ def stub_backticks value
37
+ Kernel.send(:alias_method, :__stub_backticks__, :`)
38
+ Kernel.send(:define_method, :`) { |*| value }
39
+ yield
40
+ ensure
41
+ Kernel.send(:undef_method, :`)
42
+ Kernel.send(:alias_method, :`, :__stub_backticks__)
43
+ Kernel.send(:undef_method, :__stub_backticks__)
44
+ end
45
+
46
+ def stub_file_open_for_write expected, string_io = StringIO.new
47
+ mfile = File.singleton_class
48
+ mfile.send(:alias_method, :__stub_open__, :open)
49
+
50
+ fopen = ->(*, &block) {
51
+ if block
52
+ block.call(string_io)
53
+ else
54
+ string_io
55
+ end
56
+ }
57
+
58
+ mfile.send(:define_method, :open, &fopen)
59
+ yield
60
+ assert_equal expected, string_io.string
61
+ ensure
62
+ mfile.send(:undef_method, :open)
63
+ mfile.send(:alias_method, :open, :__stub_open__)
64
+ mfile.send(:undef_method, :__stub_open__)
65
+ end
66
+
67
+ def stub_pathname_expand_path value, &block
68
+ instance_stub Pathname, :expand_path, Pathname(value), &block
69
+ end
70
+
71
+ Minitest::Test.send(:include, self)
72
+ end
@@ -0,0 +1,261 @@
1
+ require 'minitest_config'
2
+
3
+ describe Cartage do
4
+ before do
5
+ @cartage = Cartage.new
6
+ end
7
+
8
+ describe '#name' do
9
+ it 'defaults to #default_name' do
10
+ stub_cartage_repo_url do
11
+ assert_equal 'repo-url', @cartage.name
12
+ assert_equal @cartage.default_name, @cartage.name
13
+ end
14
+ end
15
+
16
+ it 'can be overridden' do
17
+ stub_cartage_repo_url do
18
+ @cartage.name = 'xyz'
19
+ assert_equal 'xyz', @cartage.name
20
+ end
21
+ end
22
+ end
23
+
24
+ describe '#root_path' do
25
+ it 'defaults to #default_root_path' do
26
+ stub_backticks '/x/y/z' do
27
+ assert_equal Pathname('/x/y/z'), @cartage.root_path
28
+ assert_equal @cartage.default_root_path, @cartage.root_path
29
+ end
30
+ end
31
+
32
+ it 'can be overridden and creates a Pathname' do
33
+ stub_cartage_repo_url do
34
+ @cartage.root_path = '/a/b/c'
35
+ assert_equal Pathname('/a/b/c'), @cartage.root_path
36
+ end
37
+ end
38
+
39
+ it 'expands the created Pathname' do
40
+ stub_cartage_repo_url do
41
+ @cartage.root_path = '/a/b/../c'
42
+ assert_equal Pathname('/a/c'), @cartage.root_path
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '#timestamp' do
48
+ it 'defaults to #now.utc.strftime("%Y%m%d%H%M%S")' do
49
+ stub Time, :now, -> { Time.new(2014, 12, 31, 23, 59, 59, "+00:00") } do
50
+ assert_equal '20141231235959', @cartage.timestamp
51
+ assert_equal @cartage.default_timestamp, @cartage.timestamp
52
+ end
53
+ end
54
+
55
+ it 'does no validation of assigned values' do
56
+ @cartage.timestamp = 'not a timestamp'
57
+ assert_equal 'not a timestamp', @cartage.timestamp
58
+ end
59
+ end
60
+
61
+ describe '#without_groups' do
62
+ it 'defaults to %w(development test)' do
63
+ assert_equal %w(development test), @cartage.without_groups
64
+ assert_equal @cartage.default_without_groups, @cartage.without_groups
65
+ end
66
+
67
+ it 'wraps arrays correctly' do
68
+ @cartage.without_groups = 'dit'
69
+ assert_equal %w(dit), @cartage.without_groups
70
+ end
71
+ end
72
+
73
+ describe '#base_config' do
74
+ it 'defaults to an empty OpenStruct' do
75
+ assert_equal OpenStruct.new, @cartage.base_config
76
+ assert_equal @cartage.default_base_config, @cartage.base_config
77
+ refute_same @cartage.default_base_config, @cartage.base_config
78
+ end
79
+ end
80
+
81
+ describe '#config' do
82
+ before do
83
+ data = {
84
+ x: 1,
85
+ plugins: {
86
+ test: {
87
+ x: 2
88
+ }
89
+ },
90
+ development: {
91
+ x: 3,
92
+ plugins: {
93
+ test: {
94
+ x: 4
95
+ }
96
+ }
97
+ }
98
+ }
99
+
100
+ @config = Cartage::Config.new(Cartage::Config.send(:ostructify, data))
101
+
102
+ @cartage.environment = :development
103
+ @cartage.base_config = @config
104
+ end
105
+
106
+ it 'knows the subset for "development"' do
107
+ assert_equal @config.development, @cartage.config
108
+ end
109
+
110
+ it 'knows the subset for the "test" plugin in "development"' do
111
+ assert_equal @config.development.plugins.test,
112
+ @cartage.config(for_plugin: 'test')
113
+ end
114
+
115
+ it 'knows the subset "test" plugin without environment' do
116
+ assert_equal @config.plugins.test,
117
+ @cartage.config(with_environment: false, for_plugin: :test)
118
+ end
119
+
120
+ it 'knows the whole config without environment' do
121
+ assert_equal @config, @cartage.config(with_environment: false)
122
+ end
123
+ end
124
+
125
+ describe '#bundle_cache' do
126
+ def assert_bundle_cache_equal(path)
127
+ path = Pathname(path).join('vendor-bundle.tar.bz2')
128
+ expected = Pathname(".").join(path)
129
+
130
+ instance_stub Pathname, :expand_path, expected do
131
+ yield if block_given?
132
+ assert_equal expected, @cartage.bundle_cache
133
+ end
134
+ end
135
+
136
+ it 'defaults to "tmp/vendor-bundle.tar.bz2"' do
137
+ assert_bundle_cache_equal 'tmp/vendor-bundle.tar.bz2'
138
+ end
139
+
140
+ it 'can be overridden' do
141
+ assert_bundle_cache_equal 'tmp/vendor-bundle.tar.bz2'
142
+ assert_bundle_cache_equal 'tmpx/vendor-bundle.tar.bz2' do
143
+ @cartage.bundle_cache 'tmpx'
144
+ end
145
+ end
146
+ end
147
+
148
+ describe '#release_hashref' do
149
+ it 'returns the current hashref' do
150
+ stub_backticks '12345' do
151
+ assert_equal '12345', @cartage.release_hashref
152
+ end
153
+ end
154
+
155
+ it 'saves the hashref to a file with save_to:' do
156
+ stub_backticks '54321' do
157
+ stub_file_open_for_write '54321' do
158
+ @cartage.release_hashref(save_to: 'x')
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ describe '#repo_url' do
165
+ it 'returns the origin Fetch URL' do
166
+ origin = <<-origin
167
+ * remote origin
168
+ Fetch URL: git@github.com:KineticCafe/cartage.git
169
+ Push URL: git@github.com:KineticCafe/cartage.git
170
+ HEAD branch: (not queried)
171
+ Remote branch: (status not queried)
172
+ master
173
+ Local branch configured for 'git pull':
174
+ master rebases onto remote master
175
+ Local ref configured for 'git push' (status not queried):
176
+ (matching) pushes to (matching)
177
+ origin
178
+ stub_backticks origin do
179
+ assert_equal 'git@github.com:KineticCafe/cartage.git',
180
+ @cartage.repo_url
181
+ end
182
+ end
183
+ end
184
+
185
+ describe '#final_tarball, #final_release_hashref' do
186
+ before do
187
+ @cartage.name = 'test'
188
+ @cartage.timestamp = 'value'
189
+ @cartage.instance_variable_set(:@root_path, Pathname('source'))
190
+ end
191
+
192
+ it 'sets the final tarball name correctly' do
193
+ assert_equal Pathname('source/tmp/test-value.tar.bz2'),
194
+ @cartage.final_tarball
195
+ end
196
+
197
+ it 'sets the final release hashref name correctly' do
198
+ assert_equal Pathname('source/tmp/test-value-release-hashref.txt'),
199
+ @cartage.final_release_hashref
200
+ end
201
+ end
202
+
203
+ describe '#display' do
204
+ it 'does not display a message if not verbose' do
205
+ @cartage.verbose = false
206
+ assert_silent do
207
+ @cartage.display 'hello'
208
+ end
209
+ end
210
+
211
+ it 'displays a message if verbose' do
212
+ @cartage.verbose = true
213
+ assert_output "hello\n" do
214
+ @cartage.display 'hello'
215
+ end
216
+ end
217
+
218
+ it 'does not display a message if verbose and quiet' do
219
+ @cartage.verbose = true
220
+ @cartage.quiet = true
221
+ assert_silent do
222
+ @cartage.display 'hello'
223
+ end
224
+ end
225
+ end
226
+
227
+ describe '#run (private)' do
228
+ before do
229
+ @command = %w(echo yes)
230
+ end
231
+
232
+ it 'displays the output if not verbose and not quiet' do
233
+ assert_output "yes\n" do
234
+ @cartage.send(:run, @command)
235
+ end
236
+ end
237
+
238
+ it 'displays the command and output if verbose and not quiet' do
239
+ @cartage.verbose = true
240
+ assert_output "echo yes\nyes\n" do
241
+ @cartage.send(:run, @command)
242
+ end
243
+ end
244
+
245
+ it 'displays nothing if quiet' do
246
+ @cartage.verbose = true
247
+ @cartage.quiet = true
248
+ assert_silent do
249
+ @cartage.send(:run, @command)
250
+ end
251
+ end
252
+
253
+ it 'raises an exception on error' do
254
+ @cartage.quiet = true
255
+ ex = assert_raises StandardError do
256
+ @cartage.send(:run, %w(false))
257
+ end
258
+ assert_equal %Q(Error running 'false'), ex.message
259
+ end
260
+ end
261
+ end