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.
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
  }