cloudfactory 0.1.9 → 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|