quest 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +15 -0
- data/README.md +99 -0
- data/bin/ballad +10 -0
- data/bin/quest +107 -0
- data/bin/questctl +38 -0
- data/bin/test_all_quests +21 -0
- data/lib/quest.rb +6 -0
- data/lib/quest/api.rb +83 -0
- data/lib/quest/colorization.rb +26 -0
- data/lib/quest/logger.rb +5 -0
- data/lib/quest/messenger.rb +77 -0
- data/lib/quest/quest_watcher.rb +31 -0
- data/lib/quest/rspec_runner.rb +37 -0
- metadata +202 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f44a8be44d1dabdcf3496a45686269255c4af45c
|
4
|
+
data.tar.gz: e3c77ca330b15ba15d9b20d84f82325c6115f901
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 293f9cd835a9d13c1efc8b162ea15bdbe20a1e9bcb6a914f3a1aecb4934b79cdab8275ef5a3ce4d7bf1920a2f718c9097d6332aee9fa4a6f81f4e200df1d587a
|
7
|
+
data.tar.gz: b353bfcbb12b6ccfc0071f13d2289c21f4aac540e6ddf06baff0d78130c8b6e803cfa7f16d44d6e3dad62385f28c04ed8b187affdf2446587cf0c146e093a234
|
data/LICENSE
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Copyright (C) 2015 Puppet Labs Inc
|
2
|
+
|
3
|
+
Puppet Labs can be contacted at: info@puppetlabs.com
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
## Quest
|
2
|
+
|
3
|
+
Quest-driven learning with RSpec and Serverspec.
|
4
|
+
|
5
|
+
### What it is
|
6
|
+
|
7
|
+
The quest gem provides a learner with live feedback as a learner progresses through
|
8
|
+
a series of configuration management tasks defined by RSpec tests.
|
9
|
+
It was designed to support the [Puppet Quest Guide](https://github.com/puppetlabs/puppet-quest-guide)
|
10
|
+
content on the [Puppet Learning VM](https://puppetlabs.com/download-learning-vm), but can be
|
11
|
+
used for any project with a compatible format.
|
12
|
+
|
13
|
+
### Installation
|
14
|
+
|
15
|
+
From source:
|
16
|
+
|
17
|
+
git clone https://github.com/puppetlabs/quest.git
|
18
|
+
cd quest
|
19
|
+
gem build quest.gemspec
|
20
|
+
gem install quest<VERSION>.gem
|
21
|
+
|
22
|
+
### Setup
|
23
|
+
|
24
|
+
This gem was designed to support the [Puppet Quest Guide](https://github.com/puppetlabs/puppet-quest-guide),
|
25
|
+
and works with any set of tests and metadata following the same pattern.
|
26
|
+
|
27
|
+
Any project you wish to use with this tool must contain a directory with the following contents:
|
28
|
+
|
29
|
+
An `index.json` file consisting with available quest names, the list of files to watch for each quest
|
30
|
+
and an optional setup command for that quest. These setup commands will be run with the directory
|
31
|
+
of your tests as the current working directory when a user begins the quest.
|
32
|
+
|
33
|
+
```
|
34
|
+
{
|
35
|
+
"welcome": {
|
36
|
+
"setup_command": "puppet apply ./manifests/welcome.pp"
|
37
|
+
}
|
38
|
+
}
|
39
|
+
```
|
40
|
+
|
41
|
+
A series of `*_spec.rb` files corresponding the the quest names specified in the `index.json`.
|
42
|
+
These files must contain valid Rspec tests that correspond to the tasks in that quest. For example,
|
43
|
+
`my_first_quest_spec.rb` might contain the following. (Note the callous abuse of the RSpec format to
|
44
|
+
coerce its output into something appropriate to the quest tool interface.)
|
45
|
+
|
46
|
+
```
|
47
|
+
describe "Task 1: do
|
48
|
+
it 'create a user named test' do
|
49
|
+
file('/etc/passwd').should contain "test"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
describe "Task 2: do
|
53
|
+
...
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
A `spec_helper` file with any required libraries, helper functions, or variables
|
58
|
+
needed by the tests.
|
59
|
+
|
60
|
+
```
|
61
|
+
require 'serverspec'
|
62
|
+
require 'pathname'
|
63
|
+
|
64
|
+
PROD_PATH = '/etc/puppetlabs/code/environments/production'
|
65
|
+
MODULE_PATH = PROD_PATH + "modules/"
|
66
|
+
```
|
67
|
+
|
68
|
+
### Use
|
69
|
+
|
70
|
+
The `questctl` command is used to start the quest service. Run it from the
|
71
|
+
task directory, or use the `--task_dir` flag.
|
72
|
+
|
73
|
+
```
|
74
|
+
/usr/local/bin/questctl start --task_dir /usr/src/puppet-quest-guide/tests
|
75
|
+
```
|
76
|
+
|
77
|
+
This works best when the service is managed by an init system, for example:
|
78
|
+
|
79
|
+
```
|
80
|
+
# /etc/systemd/system/quest.service
|
81
|
+
[Unit]
|
82
|
+
Description=Quest tool service
|
83
|
+
|
84
|
+
[Service]
|
85
|
+
ExecStart=/usr/local/bin/questctl start --task_dir /usr/src/puppet-quest-guide/tests
|
86
|
+
|
87
|
+
[Install]
|
88
|
+
WantedBy=multi-user.target
|
89
|
+
```
|
90
|
+
|
91
|
+
### How it works
|
92
|
+
|
93
|
+
The quest service runs a set of RSpec tests for the current test in a loop,
|
94
|
+
updating the quest status each time the test completes. The service provides
|
95
|
+
api endpoints on port 4567 that allow access to the RSpec output and a POST
|
96
|
+
endpoint to change the current quest.
|
97
|
+
|
98
|
+
The `quest` command is a wrapper for these API endpoints.
|
99
|
+
|
data/bin/ballad
ADDED
data/bin/quest
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'quest'
|
5
|
+
require 'gli'
|
6
|
+
require 'net/http'
|
7
|
+
require 'json'
|
8
|
+
rescue
|
9
|
+
require 'rubygems'
|
10
|
+
require 'quest'
|
11
|
+
require 'gli'
|
12
|
+
require 'json'
|
13
|
+
end
|
14
|
+
|
15
|
+
module GLIWrapper
|
16
|
+
include GLI::App
|
17
|
+
extend self
|
18
|
+
|
19
|
+
BASE_URI = URI('http://localhost:4567/')
|
20
|
+
OFFER_BAILOUT = false
|
21
|
+
|
22
|
+
def get_path(*path)
|
23
|
+
begin
|
24
|
+
Net::HTTP.get(URI.join(BASE_URI, *path))
|
25
|
+
rescue Errno::ECONNREFUSED => e
|
26
|
+
puts "You may need to restart the quest service: systemctl restart quest"
|
27
|
+
raise e
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def post_path(form_data, *path)
|
32
|
+
begin
|
33
|
+
Net::HTTP.post_form(URI.join(BASE_URI, *path), form_data)
|
34
|
+
rescue Errno::ECONNREFUSED => e
|
35
|
+
puts "You may need to restart the quest service: systemctl restart quest"
|
36
|
+
raise e
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def offer_bailout(message)
|
41
|
+
print "#{message} Continue? [Y/n]:"
|
42
|
+
raise "Cancelled" unless [ 'y', 'yes', ''].include? STDIN.gets.strip.downcase
|
43
|
+
end
|
44
|
+
|
45
|
+
def fancy_status
|
46
|
+
active_quest = get_path('active_quest')
|
47
|
+
output = "Quest: #{active_quest}\n"
|
48
|
+
examples = JSON.parse(get_path('status/', 'examples'))
|
49
|
+
examples.each do |example|
|
50
|
+
if example["status"] == "passed"
|
51
|
+
output << '√ '.green
|
52
|
+
else
|
53
|
+
output << 'X '.yellow
|
54
|
+
end
|
55
|
+
output << example["full_description"] + "\n"
|
56
|
+
end
|
57
|
+
output
|
58
|
+
end
|
59
|
+
|
60
|
+
def summary_status
|
61
|
+
active_quest = get_path('active_quest')
|
62
|
+
output = "Quest: #{active_quest} - Progress: "
|
63
|
+
summary = JSON.parse(get_path('status/', 'summary'))
|
64
|
+
complete_count = summary["example_count"].to_i - summary["failure_count"].to_i
|
65
|
+
output << "#{complete_count} of #{summary['example_count']} tasks."
|
66
|
+
end
|
67
|
+
|
68
|
+
program_desc 'Track the status of quests and tasks.'
|
69
|
+
|
70
|
+
desc 'Begin a quest'
|
71
|
+
arg :quest_name
|
72
|
+
arg_name 'quest_name'
|
73
|
+
command :begin do |c|
|
74
|
+
c.action do |global_options, options, args|
|
75
|
+
if args.length < 1
|
76
|
+
raise 'You must specify a quest name. Refer to the Quest Guide or use the "quest list" command.'
|
77
|
+
elsif not JSON.parse(get_path('quests')).include? args[0]
|
78
|
+
raise "#{args[0]} is not a valid quest name. Refer to the Quest Guide or use the \"quest list\" command."
|
79
|
+
elsif OFFER_BAILOUT and not get_path('status/', 'summary/', 'failure_count') == '0'
|
80
|
+
offer_bailout("The current quest is not complete. If you begin a new quest, your agent nodes will be reset. Your master node and Puppet code will not be affected.\n")
|
81
|
+
end
|
82
|
+
post_path({}, 'begin/', args[0])
|
83
|
+
puts "You have started the #{args[0]} quest."
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
desc 'List available quests'
|
88
|
+
command :list do |c|
|
89
|
+
c.action do |global_options, options, args|
|
90
|
+
puts JSON.parse(get_path('quests'))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
desc 'Show status of the current quest'
|
95
|
+
command :status do |c|
|
96
|
+
c.switch [:s], :desc => 'Show status in summary form.'
|
97
|
+
c.action do |global_options, options, args|
|
98
|
+
if options[:s]
|
99
|
+
puts summary_status
|
100
|
+
else
|
101
|
+
puts fancy_status
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
exit run(ARGV)
|
107
|
+
end
|
data/bin/questctl
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'quest'
|
4
|
+
require 'gli'
|
5
|
+
|
6
|
+
module GLIWrapper
|
7
|
+
include GLI::App
|
8
|
+
extend self
|
9
|
+
|
10
|
+
# Controllers for the quest service
|
11
|
+
# Move to questctl
|
12
|
+
|
13
|
+
program_desc 'Controller for quest tool services.'
|
14
|
+
|
15
|
+
desc 'Start the quest service'
|
16
|
+
command :start do |c|
|
17
|
+
c.flag [:q, :task_dir, 'task_dir'], :desc => 'Specify the task directory.'
|
18
|
+
c.action do |global_options, options, args|
|
19
|
+
messenger = Quest::Messenger.new( {'task_dir' => options[:task_dir]} )
|
20
|
+
api = Thread.new do
|
21
|
+
Quest::API.set :messenger, messenger
|
22
|
+
Quest::API.run!
|
23
|
+
end
|
24
|
+
watcher = Thread.new do
|
25
|
+
Quest::QuestWatcher.new(messenger).run!
|
26
|
+
end
|
27
|
+
Signal.trap("INT") do
|
28
|
+
puts "Exiting"
|
29
|
+
Thread.kill watcher
|
30
|
+
Thread.kill api
|
31
|
+
exit 130
|
32
|
+
end
|
33
|
+
watcher.join
|
34
|
+
api.join
|
35
|
+
end
|
36
|
+
end
|
37
|
+
exit run(ARGV)
|
38
|
+
end
|
data/bin/test_all_quests
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'quest'
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
BASE_URI = URI('http://localhost:4567/')
|
7
|
+
|
8
|
+
def get_path(*path)
|
9
|
+
Net::HTTP.get(URI.join(BASE_URI, *path))
|
10
|
+
end
|
11
|
+
|
12
|
+
def post_path(form_data, *path)
|
13
|
+
Net::HTTP.post_form(URI.join(BASE_URI, *path), form_data)
|
14
|
+
end
|
15
|
+
|
16
|
+
quests = JSON.parse(get_path('quests'))
|
17
|
+
|
18
|
+
quests.each do |q|
|
19
|
+
completion_script = File.join('/usr/src/puppet-quest-guide/tests', 'test_tests', "#{q}.sh")
|
20
|
+
`#{completion_script}`
|
21
|
+
end
|
data/lib/quest.rb
ADDED
data/lib/quest/api.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
module Quest
|
4
|
+
|
5
|
+
class API < Sinatra::Base
|
6
|
+
|
7
|
+
# Set defaults
|
8
|
+
before { content_type 'application/json' }
|
9
|
+
not_found { JSON.dump("error" => "Not Found") }
|
10
|
+
|
11
|
+
set :traps, false
|
12
|
+
|
13
|
+
helpers do
|
14
|
+
def messenger
|
15
|
+
settings.messenger
|
16
|
+
end
|
17
|
+
def quest_status
|
18
|
+
settings.messenger.quest_status
|
19
|
+
end
|
20
|
+
def active_quest
|
21
|
+
settings.messenger.active_quest
|
22
|
+
end
|
23
|
+
def active_quest_status
|
24
|
+
settings.messenger.quest_status[settings.messenger.active_quest]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
get '/status' do
|
29
|
+
active_quest_status.to_json
|
30
|
+
end
|
31
|
+
|
32
|
+
get '/status/examples' do
|
33
|
+
active_quest_status['examples'].to_json
|
34
|
+
end
|
35
|
+
|
36
|
+
get '/status/examples/:number' do
|
37
|
+
active_quest_status['examples'][params[:number].to_i - 1].to_json
|
38
|
+
end
|
39
|
+
|
40
|
+
get '/status/examples/count' do
|
41
|
+
content_type 'text/html'
|
42
|
+
active_quest_status['examples'].size
|
43
|
+
end
|
44
|
+
|
45
|
+
get '/status/examples/:number/description' do
|
46
|
+
active_quest_status['examples'][params[:number].to_i - 1]['description'].to_json
|
47
|
+
end
|
48
|
+
|
49
|
+
get '/status/examples/:number/file_path' do
|
50
|
+
active_quest_status['examples'][params[:number].to_i - 1]['file_path'].to_json
|
51
|
+
end
|
52
|
+
|
53
|
+
get '/status/examples/:number/status' do
|
54
|
+
active_quest_status['examples'][params[:number].to_i - 1]['status'].to_json
|
55
|
+
end
|
56
|
+
|
57
|
+
get '/status/examples/:number/run_time' do
|
58
|
+
active_quest_status['examples'][params[:number].to_i - 1]['run_time'].to_json
|
59
|
+
end
|
60
|
+
|
61
|
+
get '/status/summary' do
|
62
|
+
active_quest_status['summary'].to_json
|
63
|
+
end
|
64
|
+
|
65
|
+
get '/status/summary/failure_count' do
|
66
|
+
active_quest_status['summary']['failure_count'].to_json
|
67
|
+
end
|
68
|
+
|
69
|
+
get '/active_quest' do
|
70
|
+
content_type 'text/html'
|
71
|
+
active_quest
|
72
|
+
end
|
73
|
+
|
74
|
+
get '/quests' do
|
75
|
+
messenger.quests.to_json
|
76
|
+
end
|
77
|
+
|
78
|
+
post '/begin/:quest' do
|
79
|
+
messenger.begin_quest(params[:quest])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class String
|
2
|
+
def black; "\e[30m#{self}\e[0m" end
|
3
|
+
def red; "\e[31m#{self}\e[0m" end
|
4
|
+
def green; "\e[32m#{self}\e[0m" end
|
5
|
+
def brown; "\e[33m#{self}\e[0m" end
|
6
|
+
def yellow; "\e[1;33m#{self}\e[0m" end
|
7
|
+
def blue; "\e[34m#{self}\e[0m" end
|
8
|
+
def magenta; "\e[35m#{self}\e[0m" end
|
9
|
+
def cyan; "\e[36m#{self}\e[0m" end
|
10
|
+
def gray; "\e[37m#{self}\e[0m" end
|
11
|
+
|
12
|
+
def bg_black; "\e[40m#{self}\e[0m" end
|
13
|
+
def bg_red; "\e[41m#{self}\e[0m" end
|
14
|
+
def bg_green; "\e[42m#{self}\e[0m" end
|
15
|
+
def bg_brown; "\e[43m#{self}\e[0m" end
|
16
|
+
def bg_blue; "\e[44m#{self}\e[0m" end
|
17
|
+
def bg_magenta; "\e[45m#{self}\e[0m" end
|
18
|
+
def bg_cyan; "\e[46m#{self}\e[0m" end
|
19
|
+
def bg_gray; "\e[47m#{self}\e[0m" end
|
20
|
+
|
21
|
+
def bold; "\e[1m#{self}\e[21m" end
|
22
|
+
def italic; "\e[3m#{self}\e[23m" end
|
23
|
+
def underline; "\e[4m#{self}\e[24m" end
|
24
|
+
def blink; "\e[5m#{self}\e[25m" end
|
25
|
+
def reverse_color; "\e[7m#{self}\e[27m" end
|
26
|
+
end
|
data/lib/quest/logger.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Quest
|
6
|
+
|
7
|
+
# Shared state and methods for reading from the content directory
|
8
|
+
class Messenger
|
9
|
+
|
10
|
+
require 'fileutils'
|
11
|
+
|
12
|
+
attr_reader :quest_index_file
|
13
|
+
attr_reader :spec_helper
|
14
|
+
attr_accessor :active_quest
|
15
|
+
attr_accessor :quest_status
|
16
|
+
|
17
|
+
def initialize(config = {})
|
18
|
+
@task_dir = config['task_dir'] || Dir.pwd
|
19
|
+
@quest_index_file = File.join(@task_dir, 'index.json')
|
20
|
+
validate_task_dir
|
21
|
+
@spec_helper = File.join(@task_dir, 'spec_helper.rb')
|
22
|
+
@quest_status = {}
|
23
|
+
@active_quest = quests.first
|
24
|
+
run_setup_command(@active_quest)
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_raw_status(quest, raw_status_hash)
|
28
|
+
@quest_status[quest] = raw_status_hash
|
29
|
+
end
|
30
|
+
|
31
|
+
def validate_task_dir
|
32
|
+
begin
|
33
|
+
JSON.parse(File.read(@quest_index_file))
|
34
|
+
rescue Errno::ENOENT
|
35
|
+
puts "No valid quest index.json file found at #{@quest_index_file}"
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def run_setup_command(quest)
|
41
|
+
if setup_command
|
42
|
+
begin
|
43
|
+
puts "Setting up the #{active_quest} quest..."
|
44
|
+
Dir.chdir(@task_dir){
|
45
|
+
setup_io = IO.popen(setup_command) do |io|
|
46
|
+
io.each do |line|
|
47
|
+
puts line
|
48
|
+
end
|
49
|
+
end
|
50
|
+
}
|
51
|
+
rescue
|
52
|
+
puts "Setup for #{active_quest} failed"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def spec_path(quest)
|
58
|
+
File.join(@task_dir, "#{quest}_spec.rb")
|
59
|
+
end
|
60
|
+
|
61
|
+
def quests
|
62
|
+
JSON.parse(File.read(@quest_index_file)).keys
|
63
|
+
end
|
64
|
+
|
65
|
+
def setup_command
|
66
|
+
JSON.parse(File.read(@quest_index_file))[@active_quest]["setup_command"]
|
67
|
+
end
|
68
|
+
|
69
|
+
def begin_quest(quest)
|
70
|
+
if quests.include?(quest)
|
71
|
+
@active_quest = quest
|
72
|
+
run_setup_command(quest)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'timers'
|
2
|
+
|
3
|
+
module Quest
|
4
|
+
class QuestWatcher
|
5
|
+
|
6
|
+
def initialize(messenger)
|
7
|
+
@messenger = messenger
|
8
|
+
@timers = Timers::Group.new
|
9
|
+
@lock = Mutex.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def start_timer
|
13
|
+
task_timer = @timers.now_and_every(5) do
|
14
|
+
unless @lock.locked?
|
15
|
+
@lock.lock
|
16
|
+
active_quest = @messenger.active_quest
|
17
|
+
runner = Quest::RSpecRunner.new(@messenger.spec_path(active_quest), @messenger.spec_helper)
|
18
|
+
@messenger.set_raw_status(active_quest, runner.result)
|
19
|
+
@lock.unlock
|
20
|
+
end
|
21
|
+
end
|
22
|
+
loop {@timers.wait}
|
23
|
+
end
|
24
|
+
|
25
|
+
# This is the main function to set up and run the watcher process
|
26
|
+
def run!
|
27
|
+
start_timer
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Quest
|
2
|
+
class RSpecRunner
|
3
|
+
# Based loosely on https://github.com/guard/guard-rspec/blob/master/lib/guard/rspec/rspec_process.rb
|
4
|
+
|
5
|
+
attr_reader :result
|
6
|
+
|
7
|
+
def initialize(spec_file, spec_helper)
|
8
|
+
@spec_file = spec_file
|
9
|
+
@spec_helper = spec_helper
|
10
|
+
Tempfile.open('quest-rspec-runner') do |tmp_file|
|
11
|
+
@exit_code = run_spec(@spec_file, @spec_helper, tmp_file.path)
|
12
|
+
@result = read_result(tmp_file.path)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def run_spec(spec_file, spec_helper, tmp_file)
|
17
|
+
home = ENV["HOME"] || '/tmp'
|
18
|
+
command = "HOME=#{home} rspec #{spec_file} -r #{spec_helper} -f json -o #{tmp_file}"
|
19
|
+
begin
|
20
|
+
pid = Kernel.spawn(command)
|
21
|
+
result = ::Process.wait2(pid)
|
22
|
+
result.last.exitstatus
|
23
|
+
rescue Errno::ENOENT => ex
|
24
|
+
raise Failure, "Failed: #{command} (#{ex})"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def read_result(tmp_file)
|
29
|
+
begin
|
30
|
+
JSON.parse(File.read(tmp_file))
|
31
|
+
rescue Errno::ENOENT => ex
|
32
|
+
raise Failure, "Cannot open status file #{tmp_file}, (#{ex})"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: quest
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.7
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kevin Henner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-11-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: serverspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.36'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.36'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: json
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.7'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rack
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.6'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.6'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: gli
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.12'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.12'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: mono_logger
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.1'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.1'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sinatra
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: highline
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: net-ssh
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: timers
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description: quest uses serverspec to track completion of configuration management
|
154
|
+
related learning tasks.
|
155
|
+
email:
|
156
|
+
- kevin@puppetlabs.com
|
157
|
+
executables:
|
158
|
+
- quest
|
159
|
+
- questctl
|
160
|
+
- test_all_quests
|
161
|
+
extensions: []
|
162
|
+
extra_rdoc_files: []
|
163
|
+
files:
|
164
|
+
- LICENSE
|
165
|
+
- README.md
|
166
|
+
- bin/ballad
|
167
|
+
- bin/quest
|
168
|
+
- bin/questctl
|
169
|
+
- bin/test_all_quests
|
170
|
+
- lib/quest.rb
|
171
|
+
- lib/quest/api.rb
|
172
|
+
- lib/quest/colorization.rb
|
173
|
+
- lib/quest/logger.rb
|
174
|
+
- lib/quest/messenger.rb
|
175
|
+
- lib/quest/quest_watcher.rb
|
176
|
+
- lib/quest/rspec_runner.rb
|
177
|
+
homepage: http://github.com/puppetlabs/quest
|
178
|
+
licenses:
|
179
|
+
- Apache 2.0
|
180
|
+
metadata: {}
|
181
|
+
post_install_message:
|
182
|
+
rdoc_options: []
|
183
|
+
require_paths:
|
184
|
+
- lib
|
185
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - '>='
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - '>='
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
requirements: []
|
196
|
+
rubyforge_project:
|
197
|
+
rubygems_version: 2.4.8
|
198
|
+
signing_key:
|
199
|
+
specification_version: 4
|
200
|
+
summary: Track completion of configuration management tasks.
|
201
|
+
test_files: []
|
202
|
+
has_rdoc:
|