qb 0.1.60 → 0.1.61

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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/qb/options.rb +6 -6
  3. data/lib/qb/role.rb +20 -33
  4. data/lib/qb/role/errors.rb +30 -0
  5. data/lib/qb/version.rb +1 -1
  6. data/library/path_facts +304 -0
  7. data/plugins/lookup_plugins/every.py +165 -0
  8. data/roles/qb.facts/defaults/main.yml +3 -0
  9. data/roles/{qb.yarn → qb.facts}/meta/main.yml +1 -1
  10. data/roles/{qb.yarn → qb.facts}/meta/qb.yml +21 -26
  11. data/roles/qb.facts/tasks/main.yml +10 -0
  12. data/roles/qb.git_repo/defaults/main.yml +1 -0
  13. data/roles/qb.git_repo/meta/main.yml +1 -9
  14. data/roles/qb.git_repo/tasks/main.yml +26 -1
  15. data/roles/qb.qb_role/templates/qb.yml.j2 +8 -0
  16. data/roles/qb.role/defaults/main.yml +1 -1
  17. data/roles/qb.role/tasks/main.yml +1 -1
  18. data/roles/qb.yarn_release/defaults/main.yml +4 -0
  19. data/roles/{qb.release_yarn → qb.yarn_release}/meta/main.yml +1 -1
  20. data/roles/{qb.release_yarn → qb.yarn_release}/meta/qb.yml +1 -1
  21. data/roles/qb.yarn_release/tasks/main.yml +73 -0
  22. data/roles/qb.yarn_setup/defaults/main.yml +11 -0
  23. data/roles/qb.yarn_setup/meta/main.yml +8 -0
  24. data/roles/qb.yarn_setup/meta/qb.yml +100 -0
  25. data/roles/qb.yarn_setup/tasks/distribution/MacOSX/brew_create.yml +59 -0
  26. data/roles/qb.yarn_setup/tasks/distribution/MacOSX/main.yml +42 -0
  27. data/roles/qb.yarn_setup/tasks/main.yml +11 -0
  28. data/roles/qb.yarn_setup/templates/yarn@M.m.p.rb.j2 +22 -0
  29. metadata +20 -12
  30. data/lib/qb/options/errors.rb +0 -11
  31. data/roles/qb.release_yarn/defaults/main.yml +0 -4
  32. data/roles/qb.release_yarn/tasks/main.yml +0 -73
  33. data/roles/qb.yarn/defaults/main.yml +0 -5
  34. data/roles/qb.yarn/tasks/distribution/MacOSX.yml +0 -7
  35. data/roles/qb.yarn/tasks/main.yml +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b47bdac25f6db4d1fea5cf3b018229d4b94a0987
4
- data.tar.gz: d3a4cdd1d235048c4f49dbbaf7824fe77706ce46
3
+ metadata.gz: ac5214f10fb124d147d91b4618033b426d389558
4
+ data.tar.gz: f051f2779ee56a8aa1747642080c99e08e567f02
5
5
  SHA512:
6
- metadata.gz: 95cc0afa926ddf49719cbe7b77effbeb99923dc7241430fa5adcf1ead739434662aca811d9978b9f077520a25095b6347887ea99b261bf763c178c23b27d1c62
7
- data.tar.gz: 46ab3b3bd3866aa64cb3982be5fdd126b5ba479dd550f4d7e05c292e3fc49c4506381e891ac951ef05e998e60f8ea21df2547b0b7e44919a9d28a0cfe9d12b85
6
+ metadata.gz: 2102fe8bf8be9a227dc3f5644c31c2e8d0ae57b9aa30dc4578914531c569afc05c71dbed9449f8ec0cda4c4a060203f0c1db91260fd9c423c1a3f6ede0a76323
7
+ data.tar.gz: c992b406840a86966b0b8d8b9e59c215255b23245c0f764db261dfb666639d24a9f30f30ecc5b6ca258ef8b80333bd93949f54023ccd944f68a3ab677cb1970b
@@ -1,6 +1,6 @@
1
1
  require 'optparse'
2
2
 
3
- require_relative "options/errors"
3
+ require_relative "role/errors"
4
4
  require_relative "options/option"
5
5
 
6
6
  module QB
@@ -88,7 +88,7 @@ module QB
88
88
  when String
89
89
  include_path + [include_meta['as']]
90
90
  else
91
- raise QB::Options::MetadataError.new,
91
+ raise QB::Role::MetadataError.new,
92
92
  "bad 'as' value: #{ include_meta.inspect }"
93
93
  end
94
94
  else
@@ -125,7 +125,7 @@ module QB
125
125
  else
126
126
  ruby_type = case option.meta['type']
127
127
  when nil
128
- raise QB::Options::MetadataError,
128
+ raise QB::Role::MetadataError,
129
129
  "must provide type in qb metadata for option #{ option.meta_name }"
130
130
  when 'string', 'str'
131
131
  String
@@ -140,17 +140,17 @@ module QB
140
140
  if option.meta['type']['one_of'].include? value
141
141
  value
142
142
  else
143
- raise QB::Options::MetadataError,
143
+ raise QB::Role::MetadataError,
144
144
  "option '#{ option.cli_name }' must be one of: #{ option.meta['type']['one_of'].join(', ') }"
145
145
  end
146
146
  }
147
147
  klass
148
148
  else
149
- raise QB::Options::MetadataError,
149
+ raise QB::Role::MetadataError,
150
150
  "bad type for option #{ option.meta_name }: #{ option.meta['type'].inspect }"
151
151
  end
152
152
  else
153
- raise QB::Options::MetadataError,
153
+ raise QB::Role::MetadataError,
154
154
  "bad type for option #{ option.meta_name }: #{ option.meta['type'].inspect }"
155
155
  end
156
156
 
@@ -3,6 +3,8 @@ require 'cmds'
3
3
  require 'parseconfig'
4
4
  require 'nrser/refinements'
5
5
 
6
+ require_relative 'role/errors'
7
+
6
8
  using NRSER
7
9
 
8
10
  module QB
@@ -37,36 +39,7 @@ module QB
37
39
  # the path qb metadata was load from. `nil` if it's never been loaded
38
40
  # or doesn't exist.
39
41
  attr_reader :meta_path
40
-
41
- # errors
42
- # =======================================================================
43
-
44
- # base for errors in the module, extends QB:Error
45
- class Error < QB::Error
46
- end
47
-
48
- # raised by `.require` when no roles match input
49
- class NoMatchesError < Error
50
- attr_accessor :input
51
-
52
- def initialize input
53
- @input = input
54
-
55
- super "no roles match input #{ @input.inspect }"
56
- end
57
- end
58
-
59
- # raised by `.require` when multiple roles match
60
- class MultipleMatchesError < Error
61
- attr_accessor :input, :matches
62
-
63
- def initialize input, matches
64
- @input = input
65
- @matches = matches
66
-
67
- super "mutiple roles match input #{ @input.inspect }:\n#{ @matches.join("\n") }"
68
- end
69
- end
42
+
70
43
 
71
44
  # static role utils
72
45
  # =======================================================================
@@ -280,7 +253,7 @@ module QB
280
253
  when String
281
254
  current_include_path + [option_meta['as']]
282
255
  else
283
- raise QB::Options::MetadataError.new,
256
+ raise QB::Role::MetadataError.new,
284
257
  "bad 'as' value: #{ option_meta.inspect }"
285
258
  end
286
259
  else
@@ -361,9 +334,23 @@ module QB
361
334
  #
362
335
  # if `cache` is true caches it as `@meta`
363
336
  #
364
- def load_meta cache = true
337
+ def load_meta cache = true
365
338
  meta = if @meta_path.extname == '.yml'
366
- YAML.load(@meta_path.read) || {}
339
+ contents = begin
340
+ @meta_path.read
341
+ rescue Exception => error
342
+ raise QB::Role::MetadataError,
343
+ "Failed to read metadata file at #{ @meta_path.to_s }, " +
344
+ "error: #{ error.inspect }"
345
+ end
346
+
347
+ begin
348
+ YAML.load(contents) || {}
349
+ rescue Exception => error
350
+ raise QB::Role::MetadataError,
351
+ "Failed to load metadata YAML from #{ @meta_path.to_s }, " +
352
+ "error: #{ error.inspect }"
353
+ end
367
354
  else
368
355
  YAML.load(Cmds.out!(@meta_path.realpath.to_s)) || {}
369
356
  end
@@ -0,0 +1,30 @@
1
+ module QB
2
+ class Role
3
+ # raised by `.require` when no roles match input
4
+ class NoMatchesError < QB::Error
5
+ attr_accessor :input
6
+
7
+ def initialize input
8
+ @input = input
9
+
10
+ super "no roles match input #{ @input.inspect }"
11
+ end
12
+ end
13
+
14
+ # raised by `.require` when multiple roles match
15
+ class MultipleMatchesError < QB::Error
16
+ attr_accessor :input, :matches
17
+
18
+ def initialize input, matches
19
+ @input = input
20
+ @matches = matches
21
+
22
+ super "mutiple roles match input #{ @input.inspect }:\n#{ @matches.join("\n") }"
23
+ end
24
+ end
25
+
26
+ # raised when there's bad metadata
27
+ class MetadataError < QB::Error
28
+ end
29
+ end # Role
30
+ end # QB
@@ -1,7 +1,7 @@
1
1
  module QB
2
2
  GEM_NAME = 'qb'
3
3
 
4
- VERSION = "0.1.60"
4
+ VERSION = "0.1.61"
5
5
 
6
6
  def self.gemspec
7
7
  Gem.loaded_specs[GEM_NAME]
@@ -0,0 +1,304 @@
1
+ #!/usr/bin/env ruby
2
+ # WANT_JSON
3
+
4
+ # init bundler in dev env
5
+ if ENV['QB_DEV_ENV']
6
+ ENV.each {|k, v|
7
+ if k.start_with? 'QB_DEV_ENV_'
8
+ ENV[k.sub('QB_DEV_ENV_', '')] = v
9
+ end
10
+ }
11
+ require 'bundler/setup'
12
+ end
13
+
14
+ require 'ostruct'
15
+
16
+ require 'qb'
17
+ require 'cmds'
18
+ require 'pathname'
19
+ require 'uri'
20
+ require 'net/http'
21
+
22
+ class Result < OpenStruct
23
+ def to_json *args
24
+ to_h.to_json *args
25
+ end
26
+ end
27
+
28
+ GITHUB_SSH_URL_RE = /^git@github\.com\:(?<owner>.*)\/(?<name>.*)\.git$/
29
+ GITHUB_HTTPS_URL_RE = /^https:\/\/github\.com\/(?<owner>.*)\/(?<name>.*)\.git$/
30
+
31
+ # An attempt to unify NPM and Gem version schemes to a reasonable extend,
32
+ # and hopefully cover whatever else the cat may drag in.
33
+ class Version
34
+ # Create a Version instance from a Gem::Version
35
+ def self.from_gem_version version
36
+ release_segments = version.segments.take_while {|seg| !seg.is_a?(String)}
37
+ prerelease_segments = version.segments[release_segments.length..-1]
38
+
39
+ new raw: version.to_s,
40
+ major: release_segments[0],
41
+ minor: release_segments[1],
42
+ patch: release_segments[2],
43
+ prerelease: prerelease_segments,
44
+ build: [],
45
+ release: version.release
46
+ end
47
+
48
+ def self.from_npm_version version
49
+ stmt = NRSER.squish <<-END
50
+ var Semver = require('semver');
51
+
52
+ console.log(
53
+ JSON.stringify(
54
+ Semver(#{ JSON.dump version })
55
+ )
56
+ );
57
+ END
58
+
59
+ parse = JSON.load Cmds.out!("node --eval %s", stmt)
60
+
61
+ new raw: version,
62
+ major: parse['major'],
63
+ minor: parse['minor'],
64
+ patch: parse['patch'],
65
+ prerelease: parse['prerelease'],
66
+ build: parse['build'],
67
+ release: [parse['major'], parse['minor'], parse['patch']].join(".")
68
+ end
69
+
70
+ # Construct a new Version
71
+ def initialize raw:, major:, minor:, patch:, prerelease:, build:, release:
72
+ @raw = raw
73
+ @major = major
74
+ @minor = minor
75
+ @patch = patch
76
+ @prerelease = prerelease
77
+ @build = build
78
+ @release = release
79
+
80
+ @level = @prerelease[0] || 'release'
81
+
82
+ @is_release = @prerelease.empty?
83
+ @is_dev = @prerelease[0] == 'dev'
84
+ @is_rc = @prerelease[0] == 'rc'
85
+ end
86
+
87
+ # Dump all instance variables in JSON serialization
88
+ def to_json *args
89
+ instance_variables.map {|var|
90
+ [var[1..-1].to_sym, instance_variable_get(var)]
91
+ }.to_h.to_json *args
92
+ end
93
+ end
94
+
95
+ class PathFacts < QB::AnsibleModule
96
+ # Add a bunch of useful things to know about the path
97
+ def add_path_facts
98
+ @result.expanded = @path.expand_path
99
+ @result.exists = @path.exist?
100
+ @result.is_expanded = @result.expanded == @path
101
+ @result.is_absolute = @path.absolute?
102
+ @result.is_relative = @path.relative?
103
+ @result.is_dir = @path.directory?
104
+ @result.is_file = @path.file?
105
+ @result.is_cwd = @path == Pathname.getwd
106
+
107
+ # Will raise if there is no relative path between them, in which case
108
+ # 'relative' will be null.
109
+ @result.relative = begin
110
+ @path.relative_path_from Pathname.getwd
111
+ rescue ArgumentError => error
112
+ end
113
+
114
+ # Pathname#realpath will raise if the path doesn't exist
115
+ @result.realpath = begin
116
+ @path.realpath
117
+ rescue Exception => error
118
+ end
119
+
120
+ @result.is_realpath = @result.realpath == @path
121
+ end
122
+
123
+ # If the path is a Git repo (has a .git file in it's root) add useful
124
+ # Git facts.
125
+ def add_git_facts
126
+ git_file_path = @path.join('.git')
127
+
128
+ unless @path.directory? && git_file_path.exist?
129
+ @result.is_git = false
130
+ return
131
+ end
132
+
133
+ @result.is_git = true
134
+
135
+ Dir.chdir(@path) do
136
+ git = @result.git = Result.new
137
+
138
+ user = git.user = Result.new
139
+
140
+ ['name', 'email'].each {|key|
141
+ user[key] = begin
142
+ Cmds.chomp! "git config user.#{ key }"
143
+ rescue
144
+ end
145
+ }
146
+
147
+ git.root = begin
148
+ Cmds.chomp! "git rev-parse --show-toplevel"
149
+ rescue
150
+ end
151
+
152
+ git.origin = begin
153
+ Cmds.chomp! "git remote get-url origin"
154
+ rescue
155
+ end
156
+
157
+ match = GITHUB_SSH_URL_RE.match(git.origin) ||
158
+ GITHUB_HTTPS_URL_RE.match(git.origin)
159
+
160
+ git.is_github = !! match
161
+
162
+ return unless match
163
+
164
+ git.owner = match['owner']
165
+ git.name = match['name']
166
+ git.full_name = "#{ git.owner }/#{ git.name }"
167
+
168
+ if true == @args['github_api']
169
+ github = git.github = Result.new
170
+ github.api_url = "https://api.github.com/repos/#{ git.owner }/#{ git.name }"
171
+
172
+ response = Net::HTTP.get_response URI(github.api_url)
173
+
174
+ if response.is_a? Net::HTTPSuccess
175
+ # parse response body and add everything to github result
176
+ parsed = JSON.parse response.body
177
+ parsed.each {|k, v| github[k] = v}
178
+ else
179
+ # assume it's private if we failed to find it
180
+ github.private = true
181
+ end
182
+
183
+ end
184
+
185
+ end
186
+ end
187
+
188
+ # Find the only *.gemspec path in the `@path` directory. Warns and returns
189
+ # `nil` if there is more than one match.
190
+ def gemspec_path
191
+ paths = Pathname.glob(@path.join('*.gemspec'))
192
+
193
+ case paths.length
194
+ when 0
195
+ nil
196
+ when 1
197
+ paths[0]
198
+ else
199
+ warn "found multiple gemspecs: #{ paths }, unable to pick one."
200
+ nil
201
+ end
202
+ end
203
+
204
+ # If `path` is a directory containing the source for a Ruby Gem, add
205
+ # useful information about it.
206
+ def add_gem_facts
207
+ unless @path.directory?
208
+ @result.is_gem = false
209
+ return
210
+ end
211
+
212
+ path = gemspec_path
213
+
214
+ if path.nil?
215
+ @result.is_gem = false
216
+ return
217
+ end
218
+
219
+ @result.is_gem = true
220
+ @result.package.types << 'gem'
221
+
222
+ gem = @result.gem = Result.new
223
+
224
+ gem.gemspec_path = gemspec_path.to_s
225
+
226
+ spec = Gem::Specification::load(gemspec_path.to_s)
227
+ gem.name = spec.name
228
+ gem.version = Version.from_gem_version spec.version
229
+ end
230
+
231
+ # Add facts about an NPM package based in `@path`, if any.
232
+ def add_npm_facts
233
+ package_json_path = @path.join('package.json')
234
+
235
+ unless @path.directory? && package_json_path.file?
236
+ @result.is_npm = false
237
+ return
238
+ end
239
+
240
+ @result.is_npm = true
241
+ @result.package.types << 'npm'
242
+
243
+ npm = @result.npm = Result.new
244
+
245
+ npm.package_json = JSON.load package_json_path.read
246
+
247
+ # To stay consistent with Gem
248
+ npm.name = npm.package_json['name']
249
+ npm.version = Version.from_npm_version npm.package_json['version']
250
+ end
251
+
252
+ # Run the module.
253
+ def main
254
+ # check the 'path' arg
255
+ unless @args['path'].is_a? String
256
+ raise ArgumentError,
257
+ "'path' arg must be a string, found #{ @args['path'].inspect }."
258
+ end
259
+
260
+ # We'll return the value of @result
261
+ @result = Result.new
262
+
263
+ # Default to signaling no change (we're not gonna change anything in this
264
+ # module either)
265
+ @result.changed = false
266
+
267
+ # String warnings that will be shown to the user
268
+ @result.warnings = []
269
+
270
+ @result.package = Result.new
271
+ @result.package.types = []
272
+
273
+ # Return the input as 'raw'
274
+ @result.raw = @args['path']
275
+
276
+ @path = Pathname.new @result.raw
277
+
278
+ add_path_facts
279
+ add_git_facts
280
+ add_gem_facts
281
+ add_npm_facts
282
+
283
+ # If we only have one type of package present, we set it's type and
284
+ # version as `package.type` and `package.version`, which makes it easy for
285
+ # code to 'auto-detect' the info.
286
+ #
287
+ # If there's more than one then we obviously can't guess what to do; the
288
+ # user needs to specify.
289
+ #
290
+ if @result.package.types.length == 1
291
+ @result.package.type = @result.package.types[0]
292
+ @result.package.name = @result[@result.package.type].name
293
+ @result.package.version = @result[@result.package.type].version
294
+ end
295
+
296
+ nil
297
+ end
298
+
299
+ def done
300
+ exit_json @result.to_h
301
+ end
302
+ end
303
+
304
+ PathFacts.new.run