cloudfactory 0.1.9 → 0.1.10
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.
- data/cf.gemspec +1 -0
- data/features/error_custom_task_form.feature +117 -0
- data/features/error_form_field.feature +58 -0
- data/features/error_task_form.feature +64 -0
- data/features/errors.feature +192 -0
- data/features/run.feature +136 -121
- data/features/support/cli_steps.rb +44 -0
- data/features/support/env.rb +2 -2
- data/lib/cf.rb +3 -4
- data/lib/cf/account.rb +12 -1
- data/lib/cf/cli.rb +2 -2
- data/lib/cf/cli/config.rb +2 -2
- data/lib/cf/cli/form.rb +5 -5
- data/lib/cf/cli/line.rb +40 -16
- data/lib/cf/cli/production.rb +50 -18
- data/lib/cf/cli/templates/sample-line/form.css +41 -17
- data/lib/cf/cli/templates/sample-line/form.html +27 -18
- data/lib/cf/cli/templates/sample-line/form.js +12 -3
- data/lib/cf/cli/templates/sample-line/line.yml.erb +42 -32
- data/lib/cf/client.rb +3 -3
- data/lib/cf/custom_task_form.rb +21 -91
- data/lib/cf/department.rb +1 -10
- data/lib/cf/final_output.rb +2 -16
- data/lib/cf/form_field.rb +11 -6
- data/lib/cf/human_worker.rb +93 -1
- data/lib/cf/input_format.rb +10 -62
- data/lib/cf/line.rb +46 -37
- data/lib/cf/robot_worker.rb +63 -2
- data/lib/cf/run.rb +37 -66
- data/lib/cf/station.rb +42 -104
- data/lib/cf/task_form.rb +17 -56
- data/lib/cf/version.rb +2 -2
- data/lib/generators/cf/form/form_generator.rb +3 -3
- data/lib/generators/cf/install/install_generator.rb +3 -3
- data/spec/custom_task_form_spec.rb +169 -1
- data/spec/generators/form_generator_spec.rb +2 -2
- data/spec/generators/install_generator_spec.rb +2 -2
- data/spec/run_spec.rb +3 -3
- data/spec/spec_helper.rb +1 -0
- data/spec/station_spec.rb +13 -1
- data/spec/task_form_spec.rb +38 -6
- metadata +63 -44
@@ -13,4 +13,48 @@ end
|
|
13
13
|
|
14
14
|
Then /^the file "([^"]*)" should contain:$/ do |file, partial_content|
|
15
15
|
check_file_content(file, partial_content, true)
|
16
|
+
end
|
17
|
+
|
18
|
+
When /^I run `([^`]*)` for cf$/ do |cmd|
|
19
|
+
Timecop.freeze(Time.now) do
|
20
|
+
run_simple(unescape(cmd), false)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Given /^a line exists with title "([^"]*)"$/ do |title|
|
25
|
+
dir = title
|
26
|
+
steps %Q{
|
27
|
+
Given a file named "#{dir}/line.yml" with:
|
28
|
+
"""
|
29
|
+
title: #{title}
|
30
|
+
department: Web Research
|
31
|
+
input_formats:
|
32
|
+
- name: email
|
33
|
+
required: true
|
34
|
+
valid_type: email
|
35
|
+
stations:
|
36
|
+
- station:
|
37
|
+
station_index: 1
|
38
|
+
station_type: work
|
39
|
+
worker:
|
40
|
+
worker_type: human
|
41
|
+
num_workers: 1
|
42
|
+
reward: 5
|
43
|
+
task_form:
|
44
|
+
form_title: Enter the email address
|
45
|
+
instruction: Do research to get the email address
|
46
|
+
form_fields:
|
47
|
+
- label: CEO Email
|
48
|
+
field_type: email
|
49
|
+
required: true
|
50
|
+
"""
|
51
|
+
And I cd to "#{dir}"
|
52
|
+
When I run `cf line create`
|
53
|
+
Then the output should match:
|
54
|
+
"""
|
55
|
+
Line was successfully created.
|
56
|
+
"""
|
57
|
+
And I cd to "../"
|
58
|
+
}
|
59
|
+
|
16
60
|
end
|
data/features/support/env.rb
CHANGED
@@ -4,8 +4,8 @@ require 'cf'
|
|
4
4
|
ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
|
5
5
|
|
6
6
|
Before('@slow_process') do
|
7
|
-
@aruba_io_wait_seconds =
|
8
|
-
@aruba_timeout_seconds =
|
7
|
+
@aruba_io_wait_seconds = 5
|
8
|
+
@aruba_timeout_seconds = 5
|
9
9
|
end
|
10
10
|
|
11
11
|
Before('@moderate_slow_process') do
|
data/lib/cf.rb
CHANGED
@@ -4,13 +4,12 @@ rescue LoadError
|
|
4
4
|
# do nothing
|
5
5
|
end
|
6
6
|
require 'yaml'
|
7
|
-
require 'rails'
|
8
7
|
require 'hashie'
|
9
8
|
require 'active_support/concern'
|
10
|
-
#require 'active_support/rescuable'
|
11
9
|
require 'active_support/core_ext/string/inflections'
|
12
10
|
require 'active_support/core_ext/object/blank'
|
13
11
|
require 'active_support/core_ext/object/try'
|
12
|
+
require 'active_support/hash_with_indifferent_access'
|
14
13
|
require "rest_client"
|
15
14
|
require 'json'
|
16
15
|
require 'terminal-table/import'
|
@@ -20,9 +19,9 @@ directory = File.expand_path(File.dirname(__FILE__))
|
|
20
19
|
Hash.send :include, Hashie::HashExtensions
|
21
20
|
|
22
21
|
|
23
|
-
module CF
|
22
|
+
module CF # :nodoc: all
|
24
23
|
|
25
|
-
class << self
|
24
|
+
class << self # :nodoc: all
|
26
25
|
attr_accessor :api_key, :account_name, :api_version, :api_url
|
27
26
|
def configure
|
28
27
|
yield self
|
data/lib/cf/account.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
|
-
module CF
|
1
|
+
module CF
|
2
2
|
class Account
|
3
3
|
include Client
|
4
4
|
|
5
5
|
class << self
|
6
|
+
|
7
|
+
# Contains Error message if any
|
6
8
|
attr_accessor :errors
|
7
9
|
|
10
|
+
# ==Returns Account Info
|
11
|
+
# ===Usage Example:
|
12
|
+
# CF::Account.info
|
8
13
|
def info
|
9
14
|
resp = get('/account.json')
|
10
15
|
|
@@ -14,11 +19,17 @@ module CF
|
|
14
19
|
return resp
|
15
20
|
end
|
16
21
|
|
22
|
+
# ==Validation of account
|
23
|
+
# ===Usage Example:
|
24
|
+
# CF::Account.valid?
|
17
25
|
def valid?
|
18
26
|
info
|
19
27
|
errors.nil?
|
20
28
|
end
|
21
29
|
|
30
|
+
# ==Login to CloudFactory app through cloudfactory GEM
|
31
|
+
# ===Usage Example:
|
32
|
+
# CF::Account.login("sprout@sprout-technology.com", "password")
|
22
33
|
def login(email, passwd)
|
23
34
|
resp = post('/account_login.json', :user => {:email => email, :password => passwd})
|
24
35
|
resp
|
data/lib/cf/cli.rb
CHANGED
data/lib/cf/cli/config.rb
CHANGED
data/lib/cf/cli/form.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'thor/group'
|
2
2
|
|
3
|
-
module Cf
|
4
|
-
class Newform < Thor::Group
|
3
|
+
module Cf # :nodoc: all
|
4
|
+
class Newform < Thor::Group # :nodoc: all
|
5
5
|
include Thor::Actions
|
6
6
|
include Cf::Config
|
7
7
|
source_root File.expand_path('../templates', __FILE__)
|
@@ -17,7 +17,7 @@ module Cf
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
class FormPreview < Thor::Group
|
20
|
+
class FormPreview < Thor::Group # :nodoc: all
|
21
21
|
include Thor::Actions
|
22
22
|
include Cf::Config
|
23
23
|
source_root File.expand_path('../templates', __FILE__)
|
@@ -37,8 +37,8 @@ module Cf
|
|
37
37
|
end
|
38
38
|
|
39
39
|
module Cf
|
40
|
-
class Form < Thor
|
41
|
-
include Cf::Config
|
40
|
+
class Form < Thor # :nodoc: all
|
41
|
+
include Cf::Config
|
42
42
|
|
43
43
|
desc "form generate", "generates a custom task form at <line-title>/<form-title>.html and its associated css and js files"
|
44
44
|
method_option :station, :type => :numeric, :required => true, :aliases => "-st", :desc => "the station index this form should be associated with"
|
data/lib/cf/cli/line.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'thor/group'
|
3
3
|
|
4
|
-
module Cf
|
5
|
-
class Newline < Thor::Group
|
4
|
+
module Cf # :nodoc: all
|
5
|
+
class Newline < Thor::Group # :nodoc: all
|
6
6
|
include Thor::Actions
|
7
7
|
include Cf::Config
|
8
8
|
source_root File.expand_path('../templates/', __FILE__)
|
@@ -24,8 +24,8 @@ module Cf
|
|
24
24
|
end
|
25
25
|
|
26
26
|
|
27
|
-
module Cf
|
28
|
-
class Line < Thor
|
27
|
+
module Cf # :nodoc: all
|
28
|
+
class Line < Thor # :nodoc: all
|
29
29
|
include Cf::Config
|
30
30
|
desc "line generate LINE-TITLE", "generates a line template at <line-title>/line.yml"
|
31
31
|
method_option :force, :type => :boolean, :default => false, :aliases => "-f", :desc => "force to overwrite the files if the line already exists, default is false"
|
@@ -68,6 +68,19 @@ module Cf
|
|
68
68
|
say("The line #{line_title} was deleted successfully!", :yellow)
|
69
69
|
end
|
70
70
|
|
71
|
+
no_tasks {
|
72
|
+
# method to call with line title to delete the line if validation fails during the creation of line
|
73
|
+
def rollback(line_title)
|
74
|
+
CF::Line.destroy(line_title)
|
75
|
+
end
|
76
|
+
|
77
|
+
def display_error(line_title, error_message)
|
78
|
+
say("Error: #{error_message}", :red)
|
79
|
+
rollback(line_title)
|
80
|
+
exit(1)
|
81
|
+
end
|
82
|
+
}
|
83
|
+
|
71
84
|
desc "line create", "takes the yaml file at line.yml and creates a new line at http://cloudfactory.com"
|
72
85
|
def create
|
73
86
|
line_source = Dir.pwd
|
@@ -89,24 +102,24 @@ module Cf
|
|
89
102
|
line_department = line_dump['department']
|
90
103
|
line = CF::Line.new(line_title, line_department, :description => line_description)
|
91
104
|
|
92
|
-
unless line.errors.blank?
|
93
|
-
say("#{line.errors.message}", :red) and return
|
94
|
-
end
|
95
|
-
|
96
105
|
say "Creating new assembly line: #{line.title}", :green
|
106
|
+
display_error(line_title, "#{line.errors}") if line.errors.present?
|
107
|
+
|
97
108
|
say "Adding InputFormats", :green
|
98
109
|
|
99
110
|
# Creation of InputFormat from yaml file
|
100
111
|
input_formats = line_dump['input_formats']
|
101
|
-
input_formats.
|
112
|
+
input_formats.each_with_index do |input_format, index|
|
113
|
+
|
102
114
|
attrs = {
|
103
115
|
:name => input_format['name'],
|
104
116
|
:required => input_format['required'],
|
105
117
|
:valid_type => input_format['valid_type']
|
106
118
|
}
|
107
119
|
input_format_for_line = CF::InputFormat.new(attrs)
|
108
|
-
line.input_formats input_format_for_line
|
120
|
+
input_format = line.input_formats input_format_for_line
|
109
121
|
say_status "input", "#{attrs[:name]}"
|
122
|
+
display_error(line_title, "#{line.input_formats[index].errors}") if line.input_formats[index].errors.present?
|
110
123
|
end
|
111
124
|
|
112
125
|
# Creation of Station
|
@@ -123,8 +136,9 @@ module Cf
|
|
123
136
|
station_params = {:line => line, :type => type, :input_formats => input_formats_for_station}
|
124
137
|
end
|
125
138
|
station = CF::Station.create(station_params) do |s|
|
126
|
-
#say "New Station has been created of type => #{s.type}", :green
|
127
139
|
say "Adding Station #{index}: #{s.type}", :green
|
140
|
+
display_error(line_title, "#{s.errors}") if s.errors.present?
|
141
|
+
|
128
142
|
# For Worker
|
129
143
|
worker = station_file['station']['worker']
|
130
144
|
number = worker['num_workers']
|
@@ -138,19 +152,23 @@ module Cf
|
|
138
152
|
else
|
139
153
|
human_worker = CF::HumanWorker.new({:station => s, :number => number, :reward => reward, :stat_badge => stat_badge})
|
140
154
|
end
|
155
|
+
|
141
156
|
if worker['skill_badges'].present?
|
142
157
|
skill_badges.each do |badge|
|
143
158
|
human_worker.badge = badge
|
144
159
|
end
|
145
160
|
end
|
146
|
-
|
161
|
+
|
147
162
|
say_status "worker", "#{number} Cloud #{pluralize(number, "Worker")} with reward of #{reward} #{pluralize(reward, "cent")}"
|
148
|
-
|
163
|
+
display_error(line_title, "#{human_worker.errors}") if human_worker.errors.present?
|
164
|
+
elsif worker_type =~ /robot/
|
149
165
|
settings = worker['settings']
|
150
166
|
robot_worker = CF::RobotWorker.create({:station => s, :type => worker_type, :settings => settings})
|
151
167
|
|
152
|
-
#say "New Worker has been created of type => #{worker_type} and settings => #{worker['settings']}", :green
|
153
168
|
say_status "robot", "Robot worker: #{worker_type}"
|
169
|
+
display_error(line_title, "#{robot_worker.errors}") if robot_worker.errors.present?
|
170
|
+
else
|
171
|
+
display_error(line_title, "Invalid worker type: #{worker_type}")
|
154
172
|
end
|
155
173
|
|
156
174
|
# Creation of Form
|
@@ -159,12 +177,18 @@ module Cf
|
|
159
177
|
title = station_file['station']['task_form']['form_title']
|
160
178
|
instruction = station_file['station']['task_form']['instruction']
|
161
179
|
form = CF::TaskForm.create({:station => s, :title => title, :instruction => instruction}) do |f|
|
180
|
+
|
162
181
|
# Creation of FormFields
|
182
|
+
say_status "form", "TaskForm '#{f.title}'"
|
183
|
+
display_error(line_title, "#{f.errors}") if f.errors.present?
|
184
|
+
|
163
185
|
station_file['station']['task_form']['form_fields'].each do |form_field|
|
164
186
|
form_field_params = form_field.merge(:form => f)
|
165
187
|
field = CF::FormField.new(form_field_params.symbolize_keys)
|
188
|
+
say_status "form_field", "FormField '#{field.form_field_params}'"
|
189
|
+
display_error(line_title, field.errors) if field.errors.present?
|
166
190
|
end
|
167
|
-
|
191
|
+
|
168
192
|
end
|
169
193
|
|
170
194
|
elsif station_file['station']['custom_task_form'].present?
|
@@ -179,8 +203,8 @@ module Cf
|
|
179
203
|
js_file = station_file['station']['custom_task_form']['js']
|
180
204
|
js = File.read("#{line_source}/station_#{station_file['station']['station_index']}/#{js_file}")
|
181
205
|
form = CF::CustomTaskForm.create({:station => s, :title => title, :instruction => instruction, :raw_html => html, :raw_css => css, :raw_javascript => js})
|
182
|
-
|
183
206
|
say_status "form", "CustomTaskForm '#{form.title}'"
|
207
|
+
display_error(line_title, "#{form.errors}") if form.errors.present?
|
184
208
|
end
|
185
209
|
|
186
210
|
end
|
data/lib/cf/cli/production.rb
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
require 'thor/group'
|
2
2
|
|
3
|
-
module Cf
|
4
|
-
class Production < Thor
|
3
|
+
module Cf # :nodoc: all
|
4
|
+
class Production < Thor # :nodoc: all
|
5
5
|
include Cf::Config
|
6
|
-
|
6
|
+
|
7
|
+
no_tasks do
|
8
|
+
def extract_name(file_path)
|
9
|
+
Pathname.new(file_path).basename.to_s
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
7
13
|
desc "production start <run-title>", "creates a production run with input data file at input/<run-title>.csv"
|
8
14
|
method_option :input_data, :type => :string, :aliases => "-i", :desc => "the name of the input data file"
|
9
15
|
method_option :live, :type => :boolean, :default => false, :aliases => "-l", :desc => "force the host to set to live mturk environment"
|
10
16
|
def start(title=nil)
|
11
17
|
|
12
|
-
if title.nil?
|
13
|
-
say("The run title is required to start the production.", :red) and return
|
14
|
-
end
|
15
|
-
|
16
|
-
run_title = title.parameterize
|
17
18
|
line_destination = Dir.pwd
|
18
19
|
yaml_source = "#{line_destination}/line.yml"
|
19
20
|
|
@@ -24,14 +25,43 @@ module Cf
|
|
24
25
|
line_yaml_dump = YAML::load(File.open(yaml_source))
|
25
26
|
line_title = line_yaml_dump['title'].parameterize
|
26
27
|
|
27
|
-
if
|
28
|
+
if title.nil?
|
29
|
+
run_title = "#{line_title}-#{Time.new.strftime('%y%b%e-%H%M%S')}"
|
30
|
+
else
|
31
|
+
run_title = "#{title.parameterize}-#{Time.new.strftime('%y%b%e-%H%M%S')}"
|
32
|
+
end
|
33
|
+
|
34
|
+
if !options[:input_data].nil?
|
28
35
|
input_data = "input/#{options[:input_data]}"
|
29
36
|
else
|
30
|
-
|
37
|
+
input_data_dir = "#{line_destination}/input"
|
38
|
+
input_files = Dir["#{input_data_dir}/*.csv"]
|
39
|
+
file_count = input_files.size
|
40
|
+
case file_count
|
41
|
+
when 0
|
42
|
+
say("No input data file present inside the input folder", :red) and return
|
43
|
+
when 1
|
44
|
+
input_data = "input/#{extract_name(input_files.first)}"
|
45
|
+
else
|
46
|
+
# Let the user choose the file
|
47
|
+
chosen_file = nil
|
48
|
+
choose do |menu|
|
49
|
+
menu.header = "Input data files"
|
50
|
+
menu.prompt = "Please choose which file to be used as input data"
|
51
|
+
|
52
|
+
input_files.each do |item|
|
53
|
+
menu.choice(extract_name(item)) do
|
54
|
+
chosen_file = extract_name(item)
|
55
|
+
say("Using the file #{chosen_file} as input data")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
input_data = "input/#{chosen_file}"
|
60
|
+
end
|
31
61
|
end
|
32
62
|
|
33
63
|
unless File.exist?(input_data)
|
34
|
-
say("The input data
|
64
|
+
say("The input data file named #{input_data} is missing.", :red) and return
|
35
65
|
end
|
36
66
|
|
37
67
|
set_target_uri(options[:live])
|
@@ -41,13 +71,13 @@ module Cf
|
|
41
71
|
set_api_key(yaml_source)
|
42
72
|
CF.account_name = CF::Account.info.name
|
43
73
|
line = CF::Line.info(line_title)
|
44
|
-
|
74
|
+
input_data_file = "#{Dir.pwd}/#{input_data}"
|
45
75
|
if line.error.blank?
|
46
|
-
say "Creating a production run with title #{run_title}", :green
|
47
|
-
run = CF::Run.create(line, run_title,
|
76
|
+
say "Creating a production run with title #{run_title}.", :green
|
77
|
+
run = CF::Run.create(line, run_title, input_data_file)
|
48
78
|
if run.errors.blank?
|
49
|
-
say("
|
50
|
-
say("View your run at http://#{CF.account_name}.#{CF.api_url.split("/")[-2]}/runs/#{CF.account_name}/#{run.title}", :yellow)
|
79
|
+
say("Run created successfully.", :green)
|
80
|
+
say("View your run at http://#{CF.account_name}.#{CF.api_url.split("/")[-2]}/runs/#{CF.account_name}/#{run.title}\n", :yellow)
|
51
81
|
else
|
52
82
|
say("Error: #{run.errors}", :red)
|
53
83
|
end
|
@@ -56,9 +86,11 @@ module Cf
|
|
56
86
|
say("Creating the line: #{line_title}", :green)
|
57
87
|
Cf::Line.new.create
|
58
88
|
# Now create a production run with the title run_title
|
59
|
-
run
|
89
|
+
say "Creating a production run with title #{run_title}.", :green
|
90
|
+
run = CF::Run.create(CF::Line.info(line_title), run_title, input_data_file)
|
60
91
|
if run.errors.blank?
|
61
|
-
say("
|
92
|
+
say("Run created successfully.", :green)
|
93
|
+
say("View your run at http://#{CF.account_name}.#{CF.api_url.split("/")[-2]}/runs/#{CF.account_name}/#{run.title}\n", :yellow)
|
62
94
|
else
|
63
95
|
say("Error: #{run.errors}", :red)
|
64
96
|
end
|
@@ -1,26 +1,50 @@
|
|
1
|
-
body {
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
body {
|
2
|
+
margin: 0 auto;
|
3
|
+
padding: 0;
|
4
|
+
color: #000;
|
5
|
+
width: 960px;
|
6
|
+
background: #302D2F;
|
7
|
+
font-family: georgia;
|
5
8
|
}
|
6
|
-
|
7
|
-
#
|
8
|
-
|
9
|
-
|
9
|
+
#wrapper {
|
10
|
+
background: #FFF;
|
11
|
+
position: relative;
|
12
|
+
padding:0 10px;
|
10
13
|
}
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
#header {
|
15
|
+
border-bottom: solid 1px grey;
|
16
|
+
padding: 10px;
|
17
|
+
height: 50px;
|
18
|
+
text-align: center;
|
19
|
+
font-size: 36px;
|
20
|
+
font-weight: bold;
|
21
|
+
color: #666666;
|
17
22
|
}
|
18
23
|
|
19
|
-
|
20
|
-
|
24
|
+
ul{
|
25
|
+
list-style: decimal;
|
26
|
+
}
|
27
|
+
input[type=text] {
|
28
|
+
width:660px;
|
21
29
|
margin:4px;
|
30
|
+
font-size: 12px;
|
31
|
+
height:40px;
|
32
|
+
}
|
33
|
+
input[type=submit]{
|
34
|
+
width: 160px;
|
35
|
+
height: 40px;
|
36
|
+
border: solid 1px black;
|
22
37
|
}
|
23
38
|
|
24
|
-
#gender, #age {
|
39
|
+
#gender, #age, #location {
|
25
40
|
font-weight: bold;
|
41
|
+
color: #A9BED4;
|
42
|
+
}
|
43
|
+
a{
|
44
|
+
color: #007EB9;
|
45
|
+
}
|
46
|
+
#footer{
|
47
|
+
border-top: solid 1px grey;
|
48
|
+
padding: 10px;
|
49
|
+
text-align: center;
|
26
50
|
}
|