cloudfactory 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/cf.gemspec +1 -0
  2. data/features/error_custom_task_form.feature +117 -0
  3. data/features/error_form_field.feature +58 -0
  4. data/features/error_task_form.feature +64 -0
  5. data/features/errors.feature +192 -0
  6. data/features/run.feature +136 -121
  7. data/features/support/cli_steps.rb +44 -0
  8. data/features/support/env.rb +2 -2
  9. data/lib/cf.rb +3 -4
  10. data/lib/cf/account.rb +12 -1
  11. data/lib/cf/cli.rb +2 -2
  12. data/lib/cf/cli/config.rb +2 -2
  13. data/lib/cf/cli/form.rb +5 -5
  14. data/lib/cf/cli/line.rb +40 -16
  15. data/lib/cf/cli/production.rb +50 -18
  16. data/lib/cf/cli/templates/sample-line/form.css +41 -17
  17. data/lib/cf/cli/templates/sample-line/form.html +27 -18
  18. data/lib/cf/cli/templates/sample-line/form.js +12 -3
  19. data/lib/cf/cli/templates/sample-line/line.yml.erb +42 -32
  20. data/lib/cf/client.rb +3 -3
  21. data/lib/cf/custom_task_form.rb +21 -91
  22. data/lib/cf/department.rb +1 -10
  23. data/lib/cf/final_output.rb +2 -16
  24. data/lib/cf/form_field.rb +11 -6
  25. data/lib/cf/human_worker.rb +93 -1
  26. data/lib/cf/input_format.rb +10 -62
  27. data/lib/cf/line.rb +46 -37
  28. data/lib/cf/robot_worker.rb +63 -2
  29. data/lib/cf/run.rb +37 -66
  30. data/lib/cf/station.rb +42 -104
  31. data/lib/cf/task_form.rb +17 -56
  32. data/lib/cf/version.rb +2 -2
  33. data/lib/generators/cf/form/form_generator.rb +3 -3
  34. data/lib/generators/cf/install/install_generator.rb +3 -3
  35. data/spec/custom_task_form_spec.rb +169 -1
  36. data/spec/generators/form_generator_spec.rb +2 -2
  37. data/spec/generators/install_generator_spec.rb +2 -2
  38. data/spec/run_spec.rb +3 -3
  39. data/spec/spec_helper.rb +1 -0
  40. data/spec/station_spec.rb +13 -1
  41. data/spec/task_form_spec.rb +38 -6
  42. 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
@@ -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 = 4
8
- @aruba_timeout_seconds = 4
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
@@ -23,8 +23,8 @@ if ENV['TEST']
23
23
  require 'ruby-debug'
24
24
  end
25
25
 
26
- module Cf
27
- class CLI < Thor
26
+ module Cf # :nodoc: all
27
+ class CLI < Thor # :nodoc: all
28
28
  include Thor::Actions
29
29
  include Cf::Config
30
30
 
data/lib/cf/cli/config.rb CHANGED
@@ -1,5 +1,5 @@
1
- module Cf
2
- module Config
1
+ module Cf # :nodoc: all
2
+ module Config # :nodoc: all
3
3
  def config_file
4
4
  File.join(find_home, '.cf_credentials')
5
5
  end
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.each do |input_format|
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
- #say "New Worker has been created of type => #{worker_type}, Number => #{number} and Reward => #{reward}", :green
161
+
147
162
  say_status "worker", "#{number} Cloud #{pluralize(number, "Worker")} with reward of #{reward} #{pluralize(reward, "cent")}"
148
- else
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
- say_status "form", "TaskForm '#{f.title}'"
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
@@ -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 !options[:input_data].nil?
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
- input_data = "input/#{run_title}.csv"
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 csv file named #{input_data} is missing.", :red) and return
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
- input_data_path = "#{Dir.pwd}/#{input_data}"
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, input_data_path)
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("A run with title #{run.title} created successfully.", :green)
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 = CF::Run.create(CF::Line.info(line_title), run_title, input_data_path)
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("A run with title #{run.title} using the line #{line_title} was successfully created.", :red)
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 {background: grey;}
2
-
3
- #instructions {
4
- text-align:center;
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
- #image-field-wrapper {
8
- min-width:1050px;
9
- overflow:hidden;
9
+ #wrapper {
10
+ background: #FFF;
11
+ position: relative;
12
+ padding:0 10px;
10
13
  }
11
-
12
- #field-panel {
13
- float:left;
14
- padding: 10px 10px 0 10px;
15
- min-width:512px;
16
- overflow:hidden;
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
- .input-field {
20
- width:150px;
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
  }