qb 0.1.72 → 0.1.73
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/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
|