qb 0.3.8 → 0.3.9

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +4 -0
  3. data/exe/.qb_interop_receive +39 -0
  4. data/exe/qb +8 -5
  5. data/lib/qb.rb +64 -19
  6. data/lib/qb/cli/run.rb +1 -1
  7. data/lib/qb/github.rb +4 -0
  8. data/lib/qb/github/api.rb +43 -0
  9. data/lib/qb/github/issue.rb +83 -0
  10. data/lib/qb/github/repo_id.rb +127 -0
  11. data/lib/qb/github/resource.rb +59 -0
  12. data/lib/qb/github/types.rb +45 -0
  13. data/lib/qb/package.rb +131 -0
  14. data/lib/qb/package/gem.rb +2 -4
  15. data/lib/qb/package/version.rb +175 -2
  16. data/lib/qb/path.rb +2 -2
  17. data/lib/qb/repo.rb +137 -1
  18. data/lib/qb/repo/git.rb +55 -23
  19. data/lib/qb/repo/git/github.rb +137 -0
  20. data/lib/qb/role.rb +74 -30
  21. data/lib/qb/util.rb +1 -4
  22. data/lib/qb/util/docker_mixin.rb +30 -2
  23. data/lib/qb/util/interop.rb +68 -7
  24. data/lib/qb/util/logging.rb +215 -0
  25. data/lib/qb/util/stdio.rb +25 -9
  26. data/lib/qb/version.rb +16 -28
  27. data/library/stream +2 -2
  28. data/plugins/filter_plugins/ruby_interop_plugins.py +49 -31
  29. data/qb.gemspec +16 -4
  30. data/roles/qb.role/defaults/main.yml +6 -2
  31. data/roles/{qb.bump → qb/pkg/bump}/.qb-options.yml +0 -0
  32. data/roles/{qb.bump → qb/pkg/bump}/README.md +0 -0
  33. data/roles/{qb.bump → qb/pkg/bump}/defaults/main.yml +0 -0
  34. data/roles/{qb.bump → qb/pkg/bump}/library/bump +0 -0
  35. data/roles/{qb.bump → qb/pkg/bump}/meta/main.yml +0 -0
  36. data/roles/{qb.bump → qb/pkg/bump}/meta/qb.yml +0 -0
  37. data/roles/{qb.bump → qb/pkg/bump}/tasks/frontend/level/dev.yml +0 -0
  38. data/roles/{qb.bump → qb/pkg/bump}/tasks/frontend/level/rc.yml +0 -0
  39. data/roles/{qb.bump → qb/pkg/bump}/tasks/frontend/level/release.yml +0 -0
  40. data/roles/{qb.bump → qb/pkg/bump}/tasks/frontend/main.yml +0 -0
  41. data/roles/{qb.bump → qb/pkg/bump}/tasks/main.yml +1 -1
  42. data/roles/{qb.qb_role → qb/role/qb}/.qb-options.yml +0 -0
  43. data/roles/{qb.qb_role → qb/role/qb}/defaults/main.yml +0 -0
  44. data/roles/{qb.qb_role → qb/role/qb}/meta/main.yml +0 -0
  45. data/roles/{qb.qb_role → qb/role/qb}/meta/qb.yml +0 -0
  46. data/roles/{qb.qb_role → qb/role/qb}/tasks/main.yml +0 -0
  47. data/roles/{qb.qb_role → qb/role/qb}/templates/.gitkeep +0 -0
  48. data/roles/{qb.qb_role → qb/role/qb}/templates/qb.yml.j2 +0 -0
  49. data/roles/qb/test/rspec/spec/issue/defaults/main.yml +2 -0
  50. data/roles/qb/test/rspec/spec/issue/meta/main.yml +8 -0
  51. data/roles/qb/test/rspec/spec/issue/meta/qb.yml +67 -0
  52. data/roles/qb/test/rspec/spec/issue/tasks/main.yml +21 -0
  53. metadata +95 -26
@@ -68,6 +68,8 @@ module QB::Util::STDIO
68
68
  # their output to it, which is in turn printed to the console `qb` is running
69
69
  # in.
70
70
  class Service
71
+ include SemanticLogger::Loggable
72
+
71
73
  def initialize name
72
74
  @name = name
73
75
  @thread = nil
@@ -81,15 +83,25 @@ module QB::Util::STDIO
81
83
 
82
84
  @path = SOCKET_DIR.join "#{ name }.#{ SecureRandom.uuid }.sock"
83
85
 
84
- @debug_header = "#{ name }@#{ @path.to_s }"
86
+ self.logger = SemanticLogger[
87
+ [
88
+ "#{ self.class.name } {",
89
+ " name: #{ name }",
90
+ " path: #{ @path.to_s }",
91
+ "}"
92
+ ].join( "\n" )
93
+ ]
94
+
95
+ logger.trace "Initialized"
85
96
  end
86
97
 
87
98
  def debug *args
88
- QB.debug "#{ @debug_header }", *args
99
+ # logger.debug "#{ @debug_header }", args
100
+ logger.debug *args
89
101
  end
90
102
 
91
103
  def open!
92
- debug "opening..."
104
+ logger.trace "opening..."
93
105
 
94
106
  # make sure env var is not already set (basically just prevents you from
95
107
  # accidentally opening two instances with the same name)
@@ -100,7 +112,8 @@ module QB::Util::STDIO
100
112
  end
101
113
 
102
114
  @thread = Thread.new do
103
- debug "thread started."
115
+ Thread.current.name = @name
116
+ logger.trace "thread started."
104
117
 
105
118
  @server = UNIXServer.new @path.to_s
106
119
 
@@ -113,9 +126,9 @@ module QB::Util::STDIO
113
126
 
114
127
  # set the env key so children can find the socket path
115
128
  ENV[@env_key] = @path.to_s
116
- debug "set env var #{ @env_key }=#{ ENV[@env_key] }"
129
+ logger.trace "set env var", @env_key => ENV[@env_key]
117
130
 
118
- debug "service open."
131
+ logger.trace "service open."
119
132
  end # open
120
133
 
121
134
  def close!
@@ -123,7 +136,7 @@ module QB::Util::STDIO
123
136
  #
124
137
  # TODO not sure how correct this is...
125
138
  #
126
- debug "closing..."
139
+ logger.trace "closing..."
127
140
 
128
141
  @socket.close unless @socket.nil?
129
142
  @socket = nil
@@ -132,7 +145,7 @@ module QB::Util::STDIO
132
145
  FileUtils.rm(@path) if @path.exist?
133
146
  @thread.kill unless @thread.nil?
134
147
 
135
- debug "closed."
148
+ logger.trace "closed."
136
149
  end
137
150
  end # Service
138
151
 
@@ -146,7 +159,10 @@ module QB::Util::STDIO
146
159
 
147
160
  def work_in_thread
148
161
  while (line = @socket.gets) do
149
- debug "#{ @name } received: #{ line.inspect }"
162
+ logger.trace "received line",
163
+ line: line,
164
+ dest: @dest
165
+
150
166
  @dest.puts line
151
167
  end
152
168
  end
@@ -4,7 +4,7 @@ module QB
4
4
 
5
5
  GEM_NAME = 'qb'
6
6
 
7
- VERSION = "0.3.8"
7
+ VERSION = "0.3.9"
8
8
 
9
9
  MIN_ANSIBLE_VERSION = Gem::Version.new '2.1.2'
10
10
 
@@ -27,12 +27,11 @@ module QB
27
27
  end
28
28
 
29
29
 
30
- # Check that the Ansible version is not less than {QB::MIN_ANSIBLE_VERSION}.
31
- #
32
- # @raise [QB::AnsibleVersionError]
33
- # If the version of Ansible found is less than {QB::MIN_ANSIBLE_VERSION}.
30
+ # @return [Gem::Version]
31
+ # the Ansible executable version parsed into a Gem version so we can
32
+ # compare it.
34
33
  #
35
- def self.check_ansible_version
34
+ def self.ansible_version
36
35
  out = Cmds.out! 'ansible --version'
37
36
  version_str = out[/ansible\ ([\d\.]+)/, 1]
38
37
 
@@ -44,36 +43,25 @@ module QB
44
43
  END
45
44
  end
46
45
 
47
- version = Gem::Version.new version_str
48
-
49
- if version < QB::MIN_ANSIBLE_VERSION
50
- raise QB::AnsibleVersionError, NRSER.squish(
51
- <<-END
52
- QB #{ QB::VERSION } requires Ansible #{ QB::MIN_ANSIBLE_VERSION },
53
- found version #{ version_str } at #{ `which ansible` }
54
- END
55
- )
56
- end
57
- end # .check_ansible_version
46
+ Gem::Version.new version_str
47
+ end # .ansible_version
58
48
 
59
49
 
60
- # If `role` has a {QB::Role#qb_requirement} raise an error if this version of
61
- # QB doesn't satisfy it.
50
+ # Check that the Ansible version is not less than {QB::MIN_ANSIBLE_VERSION}.
62
51
  #
63
- # @raise [QB::QBVersionError]
64
- # If this version of QB doesn't satisfy the role's requirements.
52
+ # @raise [QB::AnsibleVersionError]
53
+ # If the version of Ansible found is less than {QB::MIN_ANSIBLE_VERSION}.
65
54
  #
66
- def self.check_qb_version role
67
- unless role.qb_requirement.nil? ||
68
- role.qb_requirement.satisfied_by?(QB.gem_version)
69
- raise QB::QBVersionError, NRSER.squish(
55
+ def self.check_ansible_version
56
+ if ansible_version < QB::MIN_ANSIBLE_VERSION
57
+ raise QB::AnsibleVersionError, NRSER.squish(
70
58
  <<-END
71
- Role #{ role } requires QB #{ role.qb_requirement }, using QB
72
- #{ QB.gem_version } from #{ QB::ROOT }.
59
+ QB #{ QB::VERSION } requires Ansible #{ QB::MIN_ANSIBLE_VERSION },
60
+ found version #{ version_str } at #{ `which ansible` }
73
61
  END
74
62
  )
75
63
  end
76
- end # .check_qb_version
64
+ end # .check_ansible_version
77
65
 
78
66
 
79
67
  end # module QB
@@ -30,13 +30,13 @@ class Stream < QB::Ansible::Module
30
30
  }
31
31
 
32
32
  [:format, :env_mode].each { |key|
33
- opts[key] = @args[key].to_sym if @args.key?(key.to_s)
33
+ opts[key] = @args[key.to_s].to_sym if @args.key?(key.to_s)
34
34
  }
35
35
 
36
36
  cmd = Cmds.new(template, **opts)
37
37
 
38
38
  if @args['log']
39
- info "STREAMING #{ cmd.prepare.inspect }"
39
+ info "STREAMING\n\n#{ cmd.prepare }\n\n"
40
40
  end
41
41
 
42
42
  cmd.stream!
@@ -5,46 +5,37 @@ from ansible.errors import AnsibleError
5
5
 
6
6
  import subprocess
7
7
  import yaml
8
+ import os
8
9
  from ansible.parsing.yaml.dumper import AnsibleDumper
9
10
 
10
- def qb_send(data, method, *args, **kwds):
11
+
12
+ QB_ROOT = os.path.realpath(
13
+ os.path.join(
14
+ os.path.dirname(os.path.realpath(__file__)), # /plugins/filter_plugins
15
+ '..', # /plugins
16
+ '..', # /
17
+ )
18
+ )
19
+
20
+ INTEROP_RECEIVE_EXE = os.path.join( QB_ROOT, 'exe', '.qb_interop_receive' )
21
+
22
+
23
+ def send_to_interop( payload ):
11
24
  '''
12
- Load data as an object in ruby and send it a message (call a method).
25
+ Send a payload to QB Ruby code via a subprocess.
13
26
  '''
14
27
 
15
- payload = {
16
- 'data': data,
17
- 'method': method,
18
- 'args': args,
19
- 'kwds': kwds,
20
- }
21
-
22
- input = yaml.dump(payload, Dumper=AnsibleDumper)
23
-
24
- ruby_code = '''
25
- # init bundler in dev env
26
- if ENV['QB_DEV_ENV']
27
- ENV.each {|k, v|
28
- if k.start_with? 'QB_DEV_ENV_'
29
- ENV[k.sub('QB_DEV_ENV_', '')] = v
30
- end
31
- }
32
- require 'bundler/setup'
33
- end
34
-
35
- require 'qb'
36
-
37
- QB::Util::Interop.receive
38
- '''
28
+ input = yaml.dump( payload, Dumper=AnsibleDumper )
39
29
 
40
30
  process = subprocess.Popen(
41
- ['/usr/bin/env', 'ruby', '-e', ruby_code],
31
+ [ INTEROP_RECEIVE_EXE ],
42
32
  stdin=subprocess.PIPE,
43
33
  stdout=subprocess.PIPE,
44
34
  stderr=subprocess.PIPE,
35
+ env=os.environ,
45
36
  )
46
37
 
47
- out, err = process.communicate(input)
38
+ out, err = process.communicate( input )
48
39
 
49
40
  if process.returncode != 0:
50
41
  raise AnsibleError('''
@@ -64,16 +55,43 @@ def qb_send(data, method, *args, **kwds):
64
55
  ''' % out)
65
56
 
66
57
  return result
58
+
59
+
60
+ def qb_send( data, method, *args, **kwds ):
61
+ '''
62
+ Load data as an object in ruby and send it a message (call a method).
63
+ '''
67
64
 
65
+ return send_to_interop({
66
+ 'data': data,
67
+ 'method': method,
68
+ 'args': args,
69
+ 'kwds': kwds,
70
+ })
71
+
72
+
73
+ def qb_send_const( name, method, *args, **kwds ):
74
+ '''
75
+ Send a message (call a method) to a Ruby constant by name.
76
+ '''
77
+
78
+ return send_to_interop({
79
+ 'const': name,
80
+ 'method': method,
81
+ 'args': args,
82
+ 'kwds': kwds,
83
+ })
84
+
68
85
 
69
- class FilterModule(object):
86
+ class FilterModule( object ):
70
87
  '''
71
88
  Ruby interop filters.
72
89
  '''
73
90
 
74
- def filters(self):
91
+ def filters( self ):
75
92
  return {
76
- 'qb_send': qb_send,
93
+ 'qb_send': qb_send,
94
+ 'qb_send_const': qb_send_const,
77
95
  }
78
96
  # filters()
79
97
  # FilterModule
data/qb.gemspec CHANGED
@@ -85,20 +85,32 @@ Gem::Specification.new do |spec|
85
85
  end
86
86
 
87
87
  spec.bindir = "exe"
88
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
88
+
89
+ # All files in //exe that *do not* start with `.`:
90
+ spec.executables = spec.files.grep(%r{^exe/[^\.]}) { |f| File.basename(f) }
91
+
89
92
  spec.require_paths = ["lib"]
90
93
 
91
94
  spec.add_development_dependency "bundler", "~> 1.10"
92
95
  spec.add_development_dependency "rake", "~> 10.0"
93
- spec.add_development_dependency "rspec"
96
+ spec.add_development_dependency "rspec", "~> 3.7.0"
94
97
  spec.add_development_dependency "yard"
95
98
  spec.add_development_dependency "pry"
96
99
 
97
- spec.add_dependency "cmds",'~> 0.0', ">= 0.2.2"
98
- spec.add_dependency "nrser",'~> 0.0', ">= 0.0.25"
100
+ spec.add_dependency "cmds", '~> 0.0', ">= 0.2.2"
101
+ spec.add_dependency "nrser", '~> 0.0', ">= 0.0.28"
99
102
  spec.add_dependency "nrser-extras", '~> 0.0', ">= 0.0.3"
100
103
  spec.add_dependency "state_mate", '~> 0.0', ">= 0.0.9"
101
104
  spec.add_dependency 'parseconfig', '~> 1.0', '>= 1.0.8'
105
+ spec.add_dependency "octokit", "~> 4.0"
106
+
107
+ # Much better logging
108
+ spec.add_dependency 'semantic_logger', '~> 4.2'
109
+ # With much more awesome printing!
110
+ spec.add_dependency 'awesome_print', '~> 1.8'
111
+
112
+ # Ruby lib wrapping `git` binary system calls for use in {QB::Repo::Git}
113
+ spec.add_dependency 'git', '~> 1.3.0'
102
114
 
103
115
 
104
116
  if QB::VERSION.end_with? '.dev'
@@ -2,8 +2,12 @@
2
2
  role_dest: "{{ qb_dir }}"
3
3
  role_force: false
4
4
 
5
- # can't be named `role_name` 'cause Ansible sets that?
6
- role_role_name: "{{ role_dest | basename }}"
5
+ # NOTE can't be named `role_name` 'cause Ansible sets that?
6
+ #
7
+ # Call `QB::Role.default_role_name role_dest` to get the default name
8
+ #
9
+ role_role_name: >-
10
+ {{ 'QB::Role' | qb_send_const( 'default_role_name', role_dest ) }}
7
11
 
8
12
  role_defaults: true
9
13
  role_files: false
File without changes
@@ -1,5 +1,5 @@
1
1
  ---
2
- # tasks file for bump
2
+ # tasks file for qb/pkg/bump
3
3
 
4
4
  # set up variables...
5
5
 
@@ -0,0 +1,2 @@
1
+ ---
2
+ # defaults file for qb/test/rspec/spec/issue
@@ -0,0 +1,8 @@
1
+ ---
2
+ # meta file for qb/test/rspec/spec/issue
3
+
4
+ allow_duplicates: yes
5
+
6
+ dependencies: []
7
+ # - role: role-name
8
+
@@ -0,0 +1,67 @@
1
+ ---
2
+ # meta/qb.yml file for qb/test/rspec/spec/issue
3
+ #
4
+ # qb settings for this role. see README.md for more info.
5
+ #
6
+
7
+ # description of the role to show in it's help output.
8
+ description: null
9
+
10
+ # Gemspec-style requirements. Right now only `gems:qb` is used, but plan to
11
+ # generalize in the future.
12
+ requirements:
13
+ gems:
14
+ qb: ~> 0.3.0
15
+
16
+ # prefix for role variables
17
+ var_prefix: null
18
+
19
+ # how to get a default for `dir` if it's not provided as the only
20
+ # positional argument. if a positional argument is provided it will
21
+ # override the method defined here.
22
+ #
23
+ # options:
24
+ #
25
+ # - null
26
+ # - require the value on the command line.
27
+ # - false
28
+ # - don't provide qb_dir (means doesn't load or save options either).
29
+ # - git_root
30
+ # - use the git root of the directory that the `qb` command is invoked
31
+ # from. useful for 'project-centric' commands so they can be invoked
32
+ # from anywhere in the repo.
33
+ # - cwd
34
+ # - use the directory the `qb` command is invoked form.
35
+ # - {exe: PATH}
36
+ # - invoke an executable, passing a JSON serialization of the options
37
+ # mapping their CLI names to values. path can be relative to role
38
+ # directory.
39
+ # - {find_up: FILENAME}
40
+ # - starting at the current directory and climbing up to parent
41
+ # directories, use the first one that contains FILENAME. error
42
+ # if none is found.
43
+ default_dir: null
44
+
45
+ # If `true`, QB will ensure the default dir exists before starting the play.
46
+ #
47
+ # For legacy reasons, this defaults to `true` if not present, but we want to
48
+ # default declare it as `false` here so new roles can turn it on only if
49
+ # they need it.
50
+ #
51
+ mkdir: false
52
+
53
+ # default user to become for play
54
+ default_user: null
55
+
56
+ # set to false to not save options in .qb-options.yml files
57
+ save_options: true
58
+
59
+ # options to pass to ansible-playbook
60
+ ansible_options: {}
61
+
62
+ options: []
63
+ # - name: example
64
+ # description: an example of a variable.
65
+ # required: false
66
+ # type: boolean # boolean (default) | string
67
+ # short: e