qb 0.1.72 → 0.1.73
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/qb/ansible_module.rb +65 -15
- data/lib/qb/errors.rb +4 -0
- data/lib/qb/options.rb +22 -9
- data/lib/qb/package/version.rb +293 -30
- data/lib/qb/role.rb +4 -1
- data/lib/qb/role/errors.rb +10 -1
- data/lib/qb/version.rb +1 -1
- data/library/path_facts +115 -10
- data/qb.gemspec +1 -1
- data/roles/nrser.rbenv_gem/tasks/main.yml +2 -2
- data/roles/nrser.rbenv_gem/tasks/manage-version.yml +2 -2
- data/roles/qb.bump/tasks/frontend/level/rc.yml +1 -1
- data/roles/qb.git_repo/tasks/main.yml +27 -10
- data/roles/qb.install/defaults/main.yml +21 -11
- data/roles/qb.install/meta/main.yml +1 -1
- data/roles/qb.install/meta/qb.yml +22 -1
- data/roles/qb.install/tasks/edit.yml +9 -0
- data/roles/qb.install/tasks/link.yml +8 -5
- data/roles/qb.install/tasks/main.yml +2 -2
- data/roles/qb.release_gem/tasks/main.yml +44 -14
- metadata +5 -7
- data/roles/nrser.rbenv_gem/handlers/main.yml +0 -2
- data/roles/nrser.rbenv_gem/vars/main.yml +0 -2
- data/roles/qb.install/tasks/create.yml +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: baf1eddaaa71efa535ebd3f532c7c2d8e28a1b23
|
4
|
+
data.tar.gz: b250253f17d6f9e39e2acaea1c62b2355260dc6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4a205093b9e7b961fb1c3c4dbab7589228d58a954dcde6ee8bdcb637ef9e8b338e39da1b4333b03b5de43a0d5b12d73fae77a93f7d9fe06f29abb0de075b6ff
|
7
|
+
data.tar.gz: 78d9edc4152419d0f0af107355b2eb494f16c01694720b5605575fc597484f6ba3e7e988d3f97da9c8e9453eaaf0656566d3c6837edfbbff0360de2f7a48f497
|
data/lib/qb/ansible_module.rb
CHANGED
@@ -3,27 +3,28 @@ require 'pp'
|
|
3
3
|
|
4
4
|
module QB
|
5
5
|
class AnsibleModule
|
6
|
+
|
7
|
+
# Class Variables
|
8
|
+
# =====================================================================
|
9
|
+
|
6
10
|
@@arg_types = {}
|
7
11
|
|
12
|
+
|
13
|
+
# Class Methods
|
14
|
+
# =====================================================================
|
15
|
+
|
8
16
|
def self.stringify_keys hash
|
9
17
|
hash.map {|k, v| [k.to_s, v]}.to_h
|
10
18
|
end
|
11
19
|
|
20
|
+
|
12
21
|
def self.arg name, type
|
13
22
|
@@arg_types[name.to_sym] = type
|
14
23
|
end
|
15
24
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
if args[0].is_a? String
|
21
|
-
header += " " + args.shift
|
22
|
-
end
|
23
|
-
|
24
|
-
QB.debug header, *args
|
25
|
-
end
|
26
|
-
end
|
25
|
+
|
26
|
+
# Constructor
|
27
|
+
# =====================================================================
|
27
28
|
|
28
29
|
def initialize
|
29
30
|
@changed = false
|
@@ -31,13 +32,14 @@ module QB
|
|
31
32
|
@input = File.read @input_file
|
32
33
|
@args = JSON.load @input
|
33
34
|
@facts = {}
|
35
|
+
@warnings = []
|
34
36
|
|
35
37
|
@qb_stdio_out = nil
|
36
38
|
@qb_stdio_err = nil
|
37
39
|
@qb_stdio_in = nil
|
38
40
|
|
39
|
-
debug "HERE!"
|
40
|
-
debug ENV
|
41
|
+
# debug "HERE!"
|
42
|
+
# debug ENV
|
41
43
|
|
42
44
|
# if QB_STDIO_ env vars are set send stdout and stderr
|
43
45
|
# to those sockets to print in the parent process
|
@@ -75,6 +77,53 @@ module QB
|
|
75
77
|
}
|
76
78
|
end
|
77
79
|
|
80
|
+
|
81
|
+
|
82
|
+
# Instance Methods
|
83
|
+
# =====================================================================
|
84
|
+
|
85
|
+
# Logging
|
86
|
+
# ---------------------------------------------------------------------
|
87
|
+
#
|
88
|
+
# Logging is a little weird in Ansible modules... Ansible has facilities
|
89
|
+
# for notifying the user about warnings and depreciations, which we will
|
90
|
+
# make accessible, but it doesn't seem to have facilities for notices and
|
91
|
+
# debugging, which I find very useful.
|
92
|
+
#
|
93
|
+
# When run inside of QB (targeting localhost only at the moment, sadly)
|
94
|
+
# we expose additional IO channels for STDIN, STDOUT and STDERR through
|
95
|
+
# opening unix socket files that the main QB process spawns threads to
|
96
|
+
# listen to, and we provide those file paths via environment variables
|
97
|
+
# so modules can pick those up and interact with those streams, allowing
|
98
|
+
# them to act like regular scripts inside Ansible-world (see
|
99
|
+
# QB::Util::STDIO for details and implementation).
|
100
|
+
#
|
101
|
+
# We use those channels if present to provide logging mechanisms.
|
102
|
+
#
|
103
|
+
|
104
|
+
# Forward args to {QB.debug} if we are connected to a QB STDERR stream
|
105
|
+
# (write to STDERR).
|
106
|
+
#
|
107
|
+
# @param args see QB.debug
|
108
|
+
#
|
109
|
+
def debug *args
|
110
|
+
if @qb_stdio_err
|
111
|
+
header = "<QB::AnsibleModule #{ self.class.name }>"
|
112
|
+
|
113
|
+
if args[0].is_a? String
|
114
|
+
header += " " + args.shift
|
115
|
+
end
|
116
|
+
|
117
|
+
QB.debug header, *args
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Append a warning message to @warnings.
|
122
|
+
def warn msg
|
123
|
+
@warnings << msg
|
124
|
+
end
|
125
|
+
|
126
|
+
|
78
127
|
def run
|
79
128
|
result = main
|
80
129
|
|
@@ -98,7 +147,8 @@ module QB
|
|
98
147
|
|
99
148
|
def done
|
100
149
|
exit_json changed: @changed,
|
101
|
-
ansible_facts: self.class.stringify_keys(@facts)
|
150
|
+
ansible_facts: self.class.stringify_keys(@facts),
|
151
|
+
warnings: @warnings
|
102
152
|
end
|
103
153
|
|
104
154
|
def exit_json hash
|
@@ -123,7 +173,7 @@ module QB
|
|
123
173
|
end
|
124
174
|
|
125
175
|
def fail msg
|
126
|
-
exit_json failed: true, msg: msg
|
176
|
+
exit_json failed: true, msg: msg, warnings: @warnings
|
127
177
|
end
|
128
178
|
end
|
129
179
|
end # QB
|
data/lib/qb/errors.rb
CHANGED
@@ -16,4 +16,8 @@ module QB
|
|
16
16
|
# Raised when the current QB version doesn't satisfy a role as defined
|
17
17
|
# in `<role_dir>/meta/qb[.yml]:required_qb_version`).
|
18
18
|
class QBVersionError < VersionError; end
|
19
|
+
|
20
|
+
# Raised when the file system is in a state that doesn't work for what we're
|
21
|
+
# trying to do.
|
22
|
+
class FSStateError < Error; end
|
19
23
|
end # module QB
|
data/lib/qb/options.rb
CHANGED
@@ -136,18 +136,31 @@ module QB
|
|
136
136
|
Integer
|
137
137
|
when 'version'
|
138
138
|
QB::Package::Version
|
139
|
+
when 'hash', 'dict'
|
140
|
+
Class.new.tap { |klass|
|
141
|
+
opts.accept(klass) {|value|
|
142
|
+
value.split(',').map { |pair_str|
|
143
|
+
split = pair_str.split ':'
|
144
|
+
if split.length > 2
|
145
|
+
raise "Can only have a single ':' in hash options, " +
|
146
|
+
"found #{ pair_str.inspect } in #{ value.inspect }"
|
147
|
+
end
|
148
|
+
[split[0], split[1]]
|
149
|
+
}.to_h
|
150
|
+
}
|
151
|
+
}
|
139
152
|
when Hash
|
140
153
|
if option.meta['type'].key? 'one_of'
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
154
|
+
Class.new.tap { |klass|
|
155
|
+
opts.accept(klass) {|value|
|
156
|
+
if option.meta['type']['one_of'].include? value
|
157
|
+
value
|
158
|
+
else
|
159
|
+
raise QB::Role::MetadataError,
|
160
|
+
"option '#{ option.cli_name }' must be one of: #{ option.meta['type']['one_of'].join(', ') }"
|
161
|
+
end
|
162
|
+
}
|
149
163
|
}
|
150
|
-
klass
|
151
164
|
else
|
152
165
|
raise QB::Role::MetadataError,
|
153
166
|
"bad type for option #{ option.meta_name }: #{ option.meta['type'].inspect }"
|
data/lib/qb/package/version.rb
CHANGED
@@ -1,20 +1,56 @@
|
|
1
|
+
require 'nrser/types'
|
2
|
+
|
3
|
+
T = NRSER::Types
|
4
|
+
|
1
5
|
module QB
|
2
6
|
module Package
|
3
7
|
# An attempt to unify NPM and Gem version schemes to a reasonable extend,
|
4
8
|
# and hopefully cover whatever else the cat may drag in.
|
9
|
+
#
|
10
|
+
# Intended to be immutable for practical purposes.
|
11
|
+
#
|
5
12
|
class Version
|
13
|
+
|
14
|
+
# Class Methods
|
15
|
+
# =====================================================================
|
16
|
+
|
17
|
+
# Utilities
|
18
|
+
# ---------------------------------------------------------------------
|
19
|
+
|
20
|
+
# @return [String]
|
21
|
+
# Time formatted to be stuck in a version segment per Semver spec.
|
22
|
+
# We also strip out '-' to avoid possible parsing weirdness.
|
23
|
+
def self.to_time_segment time
|
24
|
+
time.utc.iso8601.gsub /[^0-9A-Za-z]/, ''
|
25
|
+
end
|
26
|
+
|
27
|
+
# Instance Builders
|
28
|
+
# ---------------------------------------------------------------------
|
29
|
+
|
6
30
|
# Create a Version instance from a Gem::Version
|
7
31
|
def self.from_gem_version version
|
8
|
-
|
32
|
+
# release segments are everything before a string
|
33
|
+
release_segments = version.segments.take_while { |seg|
|
34
|
+
!seg.is_a?(String)
|
35
|
+
}
|
36
|
+
|
37
|
+
# We don't support > 3 release segments to make life somewhat
|
38
|
+
# reasonable. Yeah, I think I've seen projects do it. We'll cross that
|
39
|
+
# bridge if and when we get to it.
|
40
|
+
if release_segments.length > 3
|
41
|
+
raise ArgumentError,
|
42
|
+
"We don't handle releases with more than 3 segments " +
|
43
|
+
"(found #{ release_segments.inspect } in #{ version })"
|
44
|
+
end
|
45
|
+
|
9
46
|
prerelease_segments = version.segments[release_segments.length..-1]
|
10
47
|
|
11
48
|
new raw: version.to_s,
|
12
|
-
major: release_segments[0],
|
13
|
-
minor: release_segments[1],
|
14
|
-
patch: release_segments[2],
|
49
|
+
major: release_segments[0] || 0,
|
50
|
+
minor: release_segments[1] || 0,
|
51
|
+
patch: release_segments[2] || 0,
|
15
52
|
prerelease: prerelease_segments,
|
16
|
-
build: []
|
17
|
-
release: version.release.to_s
|
53
|
+
build: []
|
18
54
|
end
|
19
55
|
|
20
56
|
def self.from_npm_version version
|
@@ -37,8 +73,7 @@ module QB
|
|
37
73
|
minor: parse['minor'],
|
38
74
|
patch: parse['patch'],
|
39
75
|
prerelease: parse['prerelease'],
|
40
|
-
build: parse['build']
|
41
|
-
release: [parse['major'], parse['minor'], parse['patch']].join(".")
|
76
|
+
build: parse['build']
|
42
77
|
end
|
43
78
|
|
44
79
|
def self.from_string string
|
@@ -49,6 +84,44 @@ module QB
|
|
49
84
|
end
|
50
85
|
end
|
51
86
|
|
87
|
+
|
88
|
+
# Instantiate from a hash. Slices out
|
89
|
+
#
|
90
|
+
# - `raw`
|
91
|
+
# - `major`
|
92
|
+
# - `minor`
|
93
|
+
# - `patch`
|
94
|
+
# - `prerelease`
|
95
|
+
# - `build`
|
96
|
+
#
|
97
|
+
# And passes their values to the constructor. Keys may be strings or
|
98
|
+
# symbols. All other key/values are ignored, allowing you to pass in
|
99
|
+
# the JSON encoding of a version instance.
|
100
|
+
#
|
101
|
+
# @param [Hash] hash
|
102
|
+
# Values to be passed to constructor.
|
103
|
+
#
|
104
|
+
# @return [QB::Package::Version]
|
105
|
+
#
|
106
|
+
def self.from_h hash
|
107
|
+
self.new(
|
108
|
+
NRSER.slice_keys(
|
109
|
+
NRSER.symbolize_keys(hash),
|
110
|
+
:raw,
|
111
|
+
:major,
|
112
|
+
:minor,
|
113
|
+
:patch,
|
114
|
+
:prerelease,
|
115
|
+
:build,
|
116
|
+
)
|
117
|
+
)
|
118
|
+
end # #from_h
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
# Attributes
|
123
|
+
# =====================================================================
|
124
|
+
|
52
125
|
attr_reader :raw,
|
53
126
|
:major,
|
54
127
|
:minor,
|
@@ -56,40 +129,219 @@ module QB
|
|
56
129
|
:prerelease,
|
57
130
|
:build,
|
58
131
|
:release,
|
59
|
-
:level
|
60
|
-
|
61
|
-
|
62
|
-
|
132
|
+
:level
|
133
|
+
|
134
|
+
|
135
|
+
# Constructor
|
136
|
+
# =====================================================================
|
63
137
|
|
64
138
|
# Construct a new Version
|
65
|
-
def initialize
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
@
|
139
|
+
def initialize(
|
140
|
+
raw: nil,
|
141
|
+
major:,
|
142
|
+
minor: 0,
|
143
|
+
patch: 0,
|
144
|
+
prerelease: [],
|
145
|
+
build: []
|
146
|
+
)
|
147
|
+
@raw = T.maybe(T.str).check raw
|
148
|
+
@major = T.non_neg_int.check major
|
149
|
+
@minor = T.non_neg_int.check minor
|
150
|
+
@patch = T.non_neg_int.check patch
|
151
|
+
@prerelease = T.array(T.union(T.non_neg_int, T.str)).check prerelease
|
152
|
+
@build = T.array(T.union(T.non_neg_int, T.str)).check build
|
153
|
+
@release = [major, minor, patch].join '.'
|
75
154
|
|
76
|
-
@
|
77
|
-
|
78
|
-
|
155
|
+
@level = T.match @prerelease[0], {
|
156
|
+
T.is(nil) => ->(_) { nil },
|
157
|
+
|
158
|
+
T.str => ->(str) { str },
|
159
|
+
|
160
|
+
T.non_neg_int => ->(int) { nil },
|
161
|
+
}
|
79
162
|
end
|
80
163
|
|
164
|
+
|
165
|
+
# Instance Methods
|
166
|
+
# =====================================================================
|
167
|
+
|
168
|
+
# Tests
|
169
|
+
# ---------------------------------------------------------------------
|
170
|
+
|
171
|
+
# @return [Boolean]
|
172
|
+
# True if this version is a release (no prerelease or build values).
|
173
|
+
#
|
81
174
|
def release?
|
82
|
-
@
|
175
|
+
@prerelease.empty? && @build.empty?
|
83
176
|
end
|
84
177
|
|
178
|
+
|
179
|
+
# @return [Boolean]
|
180
|
+
# True if any prerelease segments are present (stuff after '-' in
|
181
|
+
# SemVer / "NPM" format, or the first string segment and anything
|
182
|
+
# following it in "Gem" format). Tests if {@prerelease} is not
|
183
|
+
# empty.
|
184
|
+
#
|
185
|
+
def prerelease?
|
186
|
+
!@prerelease.empty?
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
# @return [Boolean]
|
191
|
+
# True if any build segments are present (stuff after '+' character
|
192
|
+
# in SemVer / "NPM" format). Tests if {@build} is empty.
|
193
|
+
#
|
194
|
+
# As of writing, we don't have a way to convey build segments in
|
195
|
+
# "Gem" version format, so this will always be false when loading a
|
196
|
+
# Gem version.
|
197
|
+
#
|
198
|
+
def build?
|
199
|
+
!@build.empty?
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
# @return [Boolean]
|
204
|
+
# True if self is a prerelease version that starts with a string that
|
205
|
+
# we consider the 'level'.
|
206
|
+
#
|
207
|
+
def level?
|
208
|
+
!@level.nil?
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
# @return [Boolean]
|
213
|
+
# True if this version is a dev prerelease (first prerelease element
|
214
|
+
# is 'dev').
|
215
|
+
#
|
85
216
|
def dev?
|
86
|
-
@
|
217
|
+
@level == 'dev'
|
87
218
|
end
|
88
219
|
|
220
|
+
|
221
|
+
# @return [Boolean]
|
222
|
+
# True if this version is a release candidate (first prerelease element
|
223
|
+
# is 'rc').
|
224
|
+
#
|
89
225
|
def rc?
|
90
|
-
@
|
226
|
+
@level == 'rc'
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
# Transformations
|
231
|
+
# ---------------------------------------------------------------------
|
232
|
+
|
233
|
+
# @return [String]
|
234
|
+
# A normalized raw version string in
|
235
|
+
# `Major.minor.patch-prerelease+build` format.
|
236
|
+
def normalized
|
237
|
+
result = release
|
238
|
+
|
239
|
+
unless prerelease.empty?
|
240
|
+
result += "-#{ prerelease.join '.' }"
|
241
|
+
end
|
242
|
+
|
243
|
+
unless build.empty?
|
244
|
+
result += "+#{ build.join '.' }"
|
245
|
+
end
|
246
|
+
|
247
|
+
result
|
248
|
+
end # #normalized
|
249
|
+
|
250
|
+
|
251
|
+
# @return [QB::Package::Version]
|
252
|
+
# A new {QB::Package::Version} created from {#release}. Even if `self`
|
253
|
+
# *is* a release version already, still returns a new instance.
|
254
|
+
#
|
255
|
+
def release_version
|
256
|
+
self.class.from_string release
|
257
|
+
end # #release_version
|
258
|
+
|
259
|
+
|
260
|
+
def merge overrides = {}
|
261
|
+
self.class.new self.to_h.merge(overrides)
|
262
|
+
end
|
263
|
+
|
264
|
+
|
265
|
+
# Return a new {QB::Package::Version} with build information added.
|
266
|
+
#
|
267
|
+
# @return [QB::Package::Version]
|
268
|
+
#
|
269
|
+
def build_version branch: nil, ref: nil, time: nil
|
270
|
+
time = self.class.to_time_segment(time) unless time.nil?
|
271
|
+
|
272
|
+
segments = [branch, ref, time].reject &:nil?
|
273
|
+
|
274
|
+
if segments.empty?
|
275
|
+
raise ArgumentError,
|
276
|
+
"Need to provide at least one of branch, ref, time."
|
277
|
+
end
|
278
|
+
|
279
|
+
merge raw: nil,
|
280
|
+
build: segments.join('.')
|
91
281
|
end
|
92
282
|
|
283
|
+
|
284
|
+
# Language Interface
|
285
|
+
# =====================================================================
|
286
|
+
|
287
|
+
# Test for equality.
|
288
|
+
#
|
289
|
+
# Compares classes then {QB::Package::Version#to_a} results.
|
290
|
+
#
|
291
|
+
# @param [Object] other
|
292
|
+
# Object to compare to self.
|
293
|
+
#
|
294
|
+
# @return [Boolean]
|
295
|
+
# True if self and other are considered equal.
|
296
|
+
#
|
297
|
+
def == other
|
298
|
+
other.class == self.class &&
|
299
|
+
other.to_a == self.to_a
|
300
|
+
end # #==
|
301
|
+
|
302
|
+
|
303
|
+
# Return array of the version elements in order from greatest to least
|
304
|
+
# precedence.
|
305
|
+
#
|
306
|
+
# This is considered the representative structure for the object's data,
|
307
|
+
# from which all other values are dependently derived, and is used in
|
308
|
+
# {#==}, {#hash} and {#eql?}.
|
309
|
+
#
|
310
|
+
# @example
|
311
|
+
#
|
312
|
+
# version = QB::Package::Version.from_string(
|
313
|
+
# "0.1.2-rc.10+master.0ab1c3d"
|
314
|
+
# )
|
315
|
+
#
|
316
|
+
# version.to_a
|
317
|
+
# # => [0, 1, 2, ['rc', 10], ['master', '0ab1c3d']]
|
318
|
+
#
|
319
|
+
# QB::Package::Version.from_string('1').to_a
|
320
|
+
# # => [1, nil, nil, [], []]
|
321
|
+
#
|
322
|
+
# @return [Array]
|
323
|
+
#
|
324
|
+
def to_a
|
325
|
+
[
|
326
|
+
major,
|
327
|
+
minor,
|
328
|
+
patch,
|
329
|
+
prerelease,
|
330
|
+
build,
|
331
|
+
]
|
332
|
+
end # #to_a
|
333
|
+
|
334
|
+
|
335
|
+
def hash
|
336
|
+
to_a.hash
|
337
|
+
end
|
338
|
+
|
339
|
+
|
340
|
+
def eql? other
|
341
|
+
self == other && self.hash == other.hash
|
342
|
+
end
|
343
|
+
|
344
|
+
|
93
345
|
# dump all instance variables into a hash
|
94
346
|
def to_h
|
95
347
|
instance_variables.map {|var|
|
@@ -97,14 +349,25 @@ module QB
|
|
97
349
|
}.to_h
|
98
350
|
end # #to_h
|
99
351
|
|
352
|
+
|
100
353
|
# Dump all instance variables in JSON serialization
|
101
354
|
def to_json *args
|
102
|
-
to_h.
|
355
|
+
to_h.merge(
|
356
|
+
is_release: release?,
|
357
|
+
is_prerelease: prerelease?,
|
358
|
+
is_build: build?,
|
359
|
+
is_dev: dev?,
|
360
|
+
is_rc: rc?,
|
361
|
+
has_level: level?,
|
362
|
+
normalized: normalized,
|
363
|
+
).to_json *args
|
103
364
|
end
|
104
365
|
|
366
|
+
|
105
367
|
def to_s
|
106
368
|
"#<QB::Package::Version #{ @raw }>"
|
107
369
|
end
|
108
|
-
|
370
|
+
|
371
|
+
end # class Version
|
109
372
|
end # Package
|
110
373
|
end # QB
|
data/lib/qb/role.rb
CHANGED
@@ -139,7 +139,10 @@ module QB
|
|
139
139
|
uniq
|
140
140
|
end
|
141
141
|
|
142
|
-
#
|
142
|
+
# Get an array of QB::Role that match an input string.
|
143
|
+
#
|
144
|
+
# @return [Array<QB::Role>]
|
145
|
+
#
|
143
146
|
def self.matches input
|
144
147
|
# keep this here to we don't re-gen every loop
|
145
148
|
available = self.available
|
data/lib/qb/role/errors.rb
CHANGED
@@ -19,7 +19,16 @@ module QB
|
|
19
19
|
@input = input
|
20
20
|
@matches = matches
|
21
21
|
|
22
|
-
super
|
22
|
+
super <<-END
|
23
|
+
multiple roles match input #{ @input.inspect }:\
|
24
|
+
|
25
|
+
#{
|
26
|
+
@matches.map { |role|
|
27
|
+
"- #{ role.to_s } (#{ role.path.to_s })"
|
28
|
+
}.join("\n")
|
29
|
+
}
|
30
|
+
|
31
|
+
END
|
23
32
|
end
|
24
33
|
end
|
25
34
|
|
data/lib/qb/version.rb
CHANGED
data/library/path_facts
CHANGED
@@ -29,6 +29,7 @@ end
|
|
29
29
|
GITHUB_SSH_URL_RE = /^git@github\.com\:(?<owner>.*)\/(?<name>.*)\.git$/
|
30
30
|
GITHUB_HTTPS_URL_RE = /^https:\/\/github\.com\/(?<owner>.*)\/(?<name>.*)\.git$/
|
31
31
|
|
32
|
+
|
32
33
|
class PathFacts < QB::AnsibleModule
|
33
34
|
# Add a bunch of useful things to know about the path
|
34
35
|
def add_path_facts
|
@@ -57,8 +58,9 @@ class PathFacts < QB::AnsibleModule
|
|
57
58
|
@result.is_realpath = @result.realpath == @path
|
58
59
|
end
|
59
60
|
|
60
|
-
|
61
|
-
# Git
|
61
|
+
|
62
|
+
# If the path is part of a Git repo, as well as useful general
|
63
|
+
# Git environment facts.
|
62
64
|
def add_git_facts
|
63
65
|
# see if we're in a git repo. first, we need a directory that exists
|
64
66
|
dir = @path.expand_path.ascend.find {|p| p.directory? }
|
@@ -143,6 +145,7 @@ class PathFacts < QB::AnsibleModule
|
|
143
145
|
end
|
144
146
|
end
|
145
147
|
|
148
|
+
|
146
149
|
# Find the only *.gemspec path in the `@path` directory. Warns and returns
|
147
150
|
# `nil` if there is more than one match.
|
148
151
|
def gemspec_path
|
@@ -159,6 +162,7 @@ class PathFacts < QB::AnsibleModule
|
|
159
162
|
end
|
160
163
|
end
|
161
164
|
|
165
|
+
|
162
166
|
# If `path` is a directory containing the source for a Ruby Gem, add
|
163
167
|
# useful information about it.
|
164
168
|
def add_gem_facts
|
@@ -186,6 +190,8 @@ class PathFacts < QB::AnsibleModule
|
|
186
190
|
gem.version = QB::Package::Version.from_gem_version spec.version
|
187
191
|
end
|
188
192
|
|
193
|
+
|
194
|
+
|
189
195
|
# Add facts about an NPM package based in `@path`, if any.
|
190
196
|
def add_npm_facts
|
191
197
|
package_json_path = @path.join('package.json')
|
@@ -212,6 +218,57 @@ class PathFacts < QB::AnsibleModule
|
|
212
218
|
end
|
213
219
|
end
|
214
220
|
|
221
|
+
|
222
|
+
# Add version/package facts derives from @path/VERSION file if one exists.
|
223
|
+
#
|
224
|
+
# Added values:
|
225
|
+
#
|
226
|
+
# - Always:
|
227
|
+
# - `has_version_file` - Boolean
|
228
|
+
# - True if `@path/VERSION` exists and was successfully parsed.
|
229
|
+
#
|
230
|
+
# - If `has_version_file` is `true`:
|
231
|
+
# -
|
232
|
+
#
|
233
|
+
def add_version_file_facts
|
234
|
+
unless @path.directory?
|
235
|
+
@result.has_version_file = false
|
236
|
+
return
|
237
|
+
end
|
238
|
+
|
239
|
+
version_file_path = @path.join 'VERSION'
|
240
|
+
|
241
|
+
unless version_file_path.file?
|
242
|
+
@result.has_version_file = false
|
243
|
+
return
|
244
|
+
end
|
245
|
+
|
246
|
+
version = begin
|
247
|
+
QB::Package::Version.from_string version_file_path.read
|
248
|
+
rescue Exception => e
|
249
|
+
warn "Unable to parse version from #{ version_file_path.to_s }; #{ e }"
|
250
|
+
@result.has_version_file = false
|
251
|
+
return
|
252
|
+
end
|
253
|
+
|
254
|
+
@result.has_version_file = true
|
255
|
+
|
256
|
+
version_file = @result.version_file = Result.new
|
257
|
+
@result.package.types << 'version_file'
|
258
|
+
|
259
|
+
# get the name from git if we have it
|
260
|
+
if @result.is_git && @result.git.name
|
261
|
+
version_file.name = @result.git.name
|
262
|
+
else
|
263
|
+
# otherwise use the directory name
|
264
|
+
version_file.name = version_file_path.dirname.basename.to_s
|
265
|
+
end
|
266
|
+
|
267
|
+
version_file.version = version
|
268
|
+
version_file.path = version_file_path
|
269
|
+
end
|
270
|
+
|
271
|
+
|
215
272
|
# Run the module.
|
216
273
|
def main
|
217
274
|
# check the 'path' arg
|
@@ -225,13 +282,14 @@ class PathFacts < QB::AnsibleModule
|
|
225
282
|
|
226
283
|
# Default to signaling no change (we're not gonna change anything in this
|
227
284
|
# module either)
|
228
|
-
@result.changed =
|
285
|
+
@result.changed = @changed
|
229
286
|
|
230
287
|
# String warnings that will be shown to the user
|
231
|
-
@result.warnings =
|
288
|
+
@result.warnings = @warnings
|
232
289
|
|
233
|
-
|
234
|
-
@result.package
|
290
|
+
# Set this up here so `add_*_facts` can append to `package.types`
|
291
|
+
package = @result.package = Result.new
|
292
|
+
package.types = []
|
235
293
|
|
236
294
|
# Return the input as 'raw'
|
237
295
|
@result.raw = @args['path']
|
@@ -239,10 +297,19 @@ class PathFacts < QB::AnsibleModule
|
|
239
297
|
@path = Pathname.new @result.raw
|
240
298
|
|
241
299
|
add_path_facts
|
300
|
+
|
301
|
+
# Add git facts if @path is in a git repo
|
242
302
|
add_git_facts
|
303
|
+
|
304
|
+
# Add Ruby Gem version/package facts if @path is the root of a Ruby Gem
|
243
305
|
add_gem_facts
|
306
|
+
|
307
|
+
# Add version/package facts from a @path/package.json file if present
|
244
308
|
add_npm_facts
|
245
309
|
|
310
|
+
# Add version/package facts from a @path/VERSION file if present
|
311
|
+
add_version_file_facts
|
312
|
+
|
246
313
|
# If we only have one type of package present, we set it's type and
|
247
314
|
# version as `package.type` and `package.version`, which makes it easy for
|
248
315
|
# code to 'auto-detect' the info.
|
@@ -250,10 +317,48 @@ class PathFacts < QB::AnsibleModule
|
|
250
317
|
# If there's more than one then we obviously can't guess what to do; the
|
251
318
|
# user needs to specify.
|
252
319
|
#
|
253
|
-
if
|
254
|
-
|
255
|
-
|
256
|
-
|
320
|
+
if package.types.length == 1
|
321
|
+
package.type = package.types[0]
|
322
|
+
package.name = @result[package.type].name
|
323
|
+
package.version = @result[package.type].version
|
324
|
+
else
|
325
|
+
# Otherwise, if all the present info matches, we can use that.
|
326
|
+
#
|
327
|
+
# We won't have a `type` though, because that doesn't make any sense.
|
328
|
+
#
|
329
|
+
|
330
|
+
# See if we have a unique common version that we can use for the overall
|
331
|
+
# version of the package.
|
332
|
+
#
|
333
|
+
versions = package.types.
|
334
|
+
# Map the types to their version object
|
335
|
+
map { |type| @result[type].version }.
|
336
|
+
# Omit any that don't have a version
|
337
|
+
reject(&:nil?).
|
338
|
+
# Reduce to unique versions
|
339
|
+
uniq
|
340
|
+
|
341
|
+
# Do we have a single unique version?
|
342
|
+
if versions.length == 1
|
343
|
+
# Yes!
|
344
|
+
package.version = versions.first
|
345
|
+
end
|
346
|
+
|
347
|
+
# See if we have a unique common name that we can use use for the overall
|
348
|
+
# name of the package
|
349
|
+
#
|
350
|
+
# TODO since version_file kinda fudges this using the git repo name or
|
351
|
+
# directory name, this might be problematic since those may not
|
352
|
+
# stay consistent... we'll have to see how it goes.
|
353
|
+
#
|
354
|
+
names = package.types.
|
355
|
+
map { |type| @result[type].name }.
|
356
|
+
reject(&:nil?).
|
357
|
+
uniq
|
358
|
+
|
359
|
+
if names.length == 1
|
360
|
+
package.name = names.first
|
361
|
+
end
|
257
362
|
end
|
258
363
|
|
259
364
|
nil
|
data/qb.gemspec
CHANGED
@@ -94,7 +94,7 @@ Gem::Specification.new do |spec|
|
|
94
94
|
spec.add_development_dependency "yard"
|
95
95
|
|
96
96
|
spec.add_dependency "cmds",'~> 0.0', ">= 0.2.1"
|
97
|
-
spec.add_dependency "nrser",'~> 0.0', ">= 0.0.
|
97
|
+
spec.add_dependency "nrser",'~> 0.0', ">= 0.0.18"
|
98
98
|
spec.add_dependency "nrser-extras", '~> 0.0', ">= 0.0.3"
|
99
99
|
spec.add_dependency "state_mate", '~> 0.0', ">= 0.0.9"
|
100
100
|
spec.add_dependency 'parseconfig', '~> 1.0', '>= 1.0.8'
|
@@ -30,7 +30,7 @@
|
|
30
30
|
version: "{{ rbenv_gem_version }}"
|
31
31
|
executable: /usr/bin/gem
|
32
32
|
become: true
|
33
|
-
when:
|
33
|
+
when: rbenv_gem_version and (item == 'system')
|
34
34
|
with_items: "{{ rbenv_gem_rubies_list }}"
|
35
35
|
|
36
36
|
- name: "manage {{ rbenv_gem_name }} gem in system ruby"
|
@@ -41,5 +41,5 @@
|
|
41
41
|
version: "{{ rbenv_gem_version }}"
|
42
42
|
executable: /usr/bin/gem
|
43
43
|
become: true
|
44
|
-
when:
|
44
|
+
when: (not rbenv_gem_version) and (item == 'system')
|
45
45
|
with_items: "{{ rbenv_gem_rubies_list }}"
|
@@ -1,34 +1,51 @@
|
|
1
1
|
---
|
2
2
|
# tasks file for qb.git_repo
|
3
3
|
|
4
|
-
- name:
|
4
|
+
- name: >-
|
5
|
+
Create {{ git_repo_dest }} directory
|
6
|
+
file:
|
7
|
+
dest: >-
|
8
|
+
{{ git_repo_dest }}
|
9
|
+
state: directory
|
10
|
+
|
11
|
+
- name: >-
|
12
|
+
Initialize git
|
5
13
|
command: git init
|
6
14
|
args:
|
7
|
-
chdir:
|
8
|
-
|
15
|
+
chdir: >-
|
16
|
+
{{ git_repo_dest }}
|
17
|
+
creates: >-
|
18
|
+
{{ git_repo_dest }}/.git
|
9
19
|
|
10
|
-
- name:
|
20
|
+
- name: >-
|
21
|
+
Tell Git to ignore OSX artifacts
|
11
22
|
when: ansible_distribution == "MacOSX"
|
12
23
|
include_role:
|
13
24
|
name: qb.gitignore
|
14
25
|
vars:
|
15
26
|
gitignore_name: Global/macOS
|
16
|
-
gitignore_dest:
|
27
|
+
gitignore_dest: >-
|
28
|
+
{{ git_repo_dest }}
|
17
29
|
|
18
|
-
- name:
|
30
|
+
- name: >-
|
31
|
+
Tell Git to ignore QB artifacts
|
19
32
|
include_role:
|
20
33
|
name: qb.gitignore
|
21
34
|
vars:
|
22
35
|
gitignore_name: QB
|
23
|
-
gitignore_dest:
|
36
|
+
gitignore_dest: >-
|
37
|
+
{{ git_repo_dest }}
|
24
38
|
|
25
39
|
- name: >-
|
26
40
|
Tell Git to ignore each of <git_repo_gitignores>
|
27
|
-
with_items:
|
41
|
+
with_items: >-
|
42
|
+
{{ git_repo_gitignores }}
|
28
43
|
loop_control:
|
29
44
|
loop_var: name
|
30
45
|
include_role:
|
31
46
|
name: qb.gitignore
|
32
47
|
vars:
|
33
|
-
gitignore_name:
|
34
|
-
|
48
|
+
gitignore_name: >-
|
49
|
+
{{ name }}
|
50
|
+
gitignore_dest: >-
|
51
|
+
{{ git_repo_dest }}
|
@@ -1,13 +1,20 @@
|
|
1
1
|
---
|
2
2
|
# defaults file for qb.install
|
3
3
|
|
4
|
-
install_path:
|
4
|
+
install_path: >-
|
5
|
+
{{ qb_user_roles_dir }}
|
5
6
|
|
6
|
-
install_src:
|
7
|
-
{{
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
install_src: >-
|
8
|
+
{{
|
9
|
+
(
|
10
|
+
ansible_env.GITHUB_HOME | path_join(
|
11
|
+
install_name.split('.')[0],
|
12
|
+
('ansible-' + install_name)
|
13
|
+
)
|
14
|
+
) if install_create else (
|
15
|
+
install_name.split('.')[0] | path_join('ansible-' + install_name)
|
16
|
+
)
|
17
|
+
}}
|
11
18
|
|
12
19
|
install_version: master
|
13
20
|
|
@@ -15,10 +22,13 @@ install_force: false
|
|
15
22
|
|
16
23
|
install_update: false
|
17
24
|
|
18
|
-
install_link:
|
19
|
-
|
20
|
-
{%- else -%}
|
21
|
-
false
|
22
|
-
{%- endif %}"
|
25
|
+
install_link: >-
|
26
|
+
{{ install_create }}
|
23
27
|
|
24
28
|
install_create: false
|
29
|
+
|
30
|
+
install_edit: >-
|
31
|
+
{{ install_create }}
|
32
|
+
|
33
|
+
install_add_to_project: false
|
34
|
+
|
@@ -39,11 +39,17 @@ default_user: null
|
|
39
39
|
save_options: false
|
40
40
|
|
41
41
|
examples:
|
42
|
-
|
42
|
+
Create a new role backed by a GitHub repo: >
|
43
43
|
|
44
44
|
qb install --create --name=nrser.blah
|
45
45
|
|
46
46
|
(`name` needs to have the namespace attached if one is desired)
|
47
|
+
|
48
|
+
Add a newly created role to the current Atom project:
|
49
|
+
|
50
|
+
(Assumes $EDITOR is set to Atom's path)
|
51
|
+
|
52
|
+
qb install --create --name=nrser.blah --add-to-project
|
47
53
|
|
48
54
|
options:
|
49
55
|
# - name: example
|
@@ -101,3 +107,18 @@ options:
|
|
101
107
|
required: false
|
102
108
|
type: boolean
|
103
109
|
short: c
|
110
|
+
|
111
|
+
- name: edit
|
112
|
+
description: >-
|
113
|
+
Open the role direcotry in EDITOR when done.
|
114
|
+
type: boolean
|
115
|
+
short: e
|
116
|
+
|
117
|
+
- name: add_to_project
|
118
|
+
description: >-
|
119
|
+
Include an `--add` option when opening role directory in EDITOR.
|
120
|
+
Added for Atom to add to current project, but who knows, maybe
|
121
|
+
works elsewhere too.
|
122
|
+
type: boolean
|
123
|
+
short: a
|
124
|
+
|
@@ -1,16 +1,17 @@
|
|
1
1
|
---
|
2
2
|
# symlink to src directory
|
3
3
|
|
4
|
-
-
|
4
|
+
- when: install_force
|
5
|
+
name: |
|
5
6
|
remove destination
|
6
7
|
|
7
8
|
{{ install_path }}/{{ install_name }}
|
8
9
|
|
9
10
|
prior to linking.
|
10
11
|
file:
|
11
|
-
path:
|
12
|
+
path: >-
|
13
|
+
{{ install_path }}/{{ install_name }}
|
12
14
|
state: absent
|
13
|
-
when: "{{ install_force }}"
|
14
15
|
|
15
16
|
- name: |
|
16
17
|
symlink
|
@@ -21,7 +22,9 @@
|
|
21
22
|
|
22
23
|
{{ install_src | realpath }}
|
23
24
|
file:
|
24
|
-
src:
|
25
|
-
|
25
|
+
src: >-
|
26
|
+
{{ install_src | realpath }}
|
27
|
+
dest: >-
|
28
|
+
{{ install_path }}/{{ install_name }}
|
26
29
|
state: link
|
27
30
|
|
@@ -7,10 +7,37 @@
|
|
7
7
|
bind:
|
8
8
|
qb_dir: "{{ qb_dir }}"
|
9
9
|
src: |
|
10
|
-
|
11
|
-
|
10
|
+
spec_pattern = "#{ qb_dir }/*.gemspec"
|
11
|
+
spec_path = Dir.glob(spec_pattern)[0]
|
12
12
|
|
13
|
-
|
13
|
+
if spec_path.nil?
|
14
|
+
raise "No gemspec found for pattern #{ spec_pattern }"
|
15
|
+
end
|
16
|
+
|
17
|
+
spec = Gem::Specification.load spec_path
|
18
|
+
|
19
|
+
# The gem *may already be loaded*, which would break the standard gemspec
|
20
|
+
# approach because the `require` will be a no-op, resulting in the
|
21
|
+
# already loaded version number being used instead of the one in the
|
22
|
+
# file.
|
23
|
+
#
|
24
|
+
# This is only a problem for NRSER, which is loaded in vars.rb.rb, but
|
25
|
+
# this fix should work for any module without worrying about what is
|
26
|
+
# currently loaded... grab the info we need in a clean child process.
|
27
|
+
#
|
28
|
+
code = <<-END
|
29
|
+
require 'json'
|
30
|
+
spec = Gem::Specification.load(#{ JSON.dump spec_path })
|
31
|
+
puts JSON.dump({
|
32
|
+
'version' => spec.version.version,
|
33
|
+
'name' => spec.name,
|
34
|
+
})
|
35
|
+
END
|
36
|
+
obj = JSON.load `ruby -e #{ code.shellescape }`
|
37
|
+
version = Gem::Version.new obj['version']
|
38
|
+
name = obj['name']
|
39
|
+
|
40
|
+
segments = version.segments.dup
|
14
41
|
segments.pop while segments.any? {|s| s.is_a? String}
|
15
42
|
|
16
43
|
segments[-1] = segments[-1].succ
|
@@ -18,24 +45,27 @@
|
|
18
45
|
|
19
46
|
next_version = segments.join('.')
|
20
47
|
|
21
|
-
# match = /^(\d+)\.(\d+)\.(\d+)(\.dev)?$/.match(current_version)
|
22
|
-
|
23
|
-
# if current_version.ends_with? '.dev'
|
24
|
-
# end
|
25
|
-
|
26
48
|
{
|
27
49
|
'name' => name,
|
28
|
-
'current_version' =>
|
29
|
-
'release_version' =>
|
50
|
+
'current_version' => version.version,
|
51
|
+
'release_version' => version.release,
|
30
52
|
'next_version' => next_version,
|
31
53
|
'version_path' => "#{ qb_dir }/lib/#{ name }/version.rb",
|
54
|
+
'spec_path' => spec_path,
|
32
55
|
}
|
33
56
|
|
34
57
|
- debug:
|
35
|
-
msg:
|
36
|
-
|
37
|
-
|
38
|
-
|
58
|
+
msg:
|
59
|
+
# - spec_path: >-
|
60
|
+
# {{ release_gem_spec_path }}
|
61
|
+
# - version_path: >-
|
62
|
+
# {{ release_gem_version_path }}
|
63
|
+
- current: >-
|
64
|
+
{{ release_gem_current_version }}
|
65
|
+
- release: >-
|
66
|
+
{{ release_gem_release_version }}
|
67
|
+
- next: >-
|
68
|
+
{{ release_gem_next_version }}
|
39
69
|
|
40
70
|
- name: "change version to release version {{ release_gem_release_version }}"
|
41
71
|
replace:
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.73
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nrser
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-08-
|
11
|
+
date: 2017-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -95,7 +95,7 @@ dependencies:
|
|
95
95
|
version: '0.0'
|
96
96
|
- - ">="
|
97
97
|
- !ruby/object:Gem::Version
|
98
|
-
version: 0.0.
|
98
|
+
version: 0.0.18
|
99
99
|
type: :runtime
|
100
100
|
prerelease: false
|
101
101
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -105,7 +105,7 @@ dependencies:
|
|
105
105
|
version: '0.0'
|
106
106
|
- - ">="
|
107
107
|
- !ruby/object:Gem::Version
|
108
|
-
version: 0.0.
|
108
|
+
version: 0.0.18
|
109
109
|
- !ruby/object:Gem::Dependency
|
110
110
|
name: nrser-extras
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
@@ -288,13 +288,11 @@ files:
|
|
288
288
|
- roles/nrser.rbenv_gem/README.md
|
289
289
|
- roles/nrser.rbenv_gem/VERSION
|
290
290
|
- roles/nrser.rbenv_gem/defaults/main.yml
|
291
|
-
- roles/nrser.rbenv_gem/handlers/main.yml
|
292
291
|
- roles/nrser.rbenv_gem/meta/main.yml
|
293
292
|
- roles/nrser.rbenv_gem/tasks/clone-repo.yml
|
294
293
|
- roles/nrser.rbenv_gem/tasks/main.yml
|
295
294
|
- roles/nrser.rbenv_gem/tasks/manage-source.yml
|
296
295
|
- roles/nrser.rbenv_gem/tasks/manage-version.yml
|
297
|
-
- roles/nrser.rbenv_gem/vars/main.yml
|
298
296
|
- roles/nrser.state_mate/.gitignore
|
299
297
|
- roles/nrser.state_mate/.rspec
|
300
298
|
- roles/nrser.state_mate/README.md
|
@@ -562,7 +560,7 @@ files:
|
|
562
560
|
- roles/qb.install/defaults/main.yml
|
563
561
|
- roles/qb.install/meta/main.yml
|
564
562
|
- roles/qb.install/meta/qb.yml
|
565
|
-
- roles/qb.install/tasks/
|
563
|
+
- roles/qb.install/tasks/edit.yml
|
566
564
|
- roles/qb.install/tasks/git.yml
|
567
565
|
- roles/qb.install/tasks/link.yml
|
568
566
|
- roles/qb.install/tasks/main.yml
|