rainforest-cli 1.0.6 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 40e961e73be70a98532715ed684c099be7123ee2
4
- data.tar.gz: e9d7c1e437f736f86018c942c427d460214ba1e6
3
+ metadata.gz: 93bba481d733b42bc5f7f7fb501e931264c6e781
4
+ data.tar.gz: d4892987ecabb73e6fd9063e409052b54ac849e6
5
5
  SHA512:
6
- metadata.gz: 2af94476bfdda2979af022be631c24185bc3fa55aef4e555574ca5e96ccbe3515eaa26739d4dc4685517faf45873897c91a328433a85bada8300eebe009661c6
7
- data.tar.gz: f802da9550fd0821e5a265da33abe411047a28cea5c2e588fe7a2864cea4a07eafaaf82220c9c14226e048182c7b803de354ec5eece128c6b5f3911e3a7a0724
6
+ metadata.gz: 1e2b9375fef282917fd66997b4a11715740ea66de6420b8c6e8d1af452fe96cc09a59258bf363a3fda725024a70cc43952c29c51aaf4450d624a10581f91acbd
7
+ data.tar.gz: f829dfa712a368139bd81590fd47022f05b515bc7f3bb2aa4224854f3f1828b42f0f57027af21081dbe34a387a2691fd1d549426d2289e71871c2c6028c6d975
data/.gitignore CHANGED
@@ -18,3 +18,4 @@ tmp
18
18
  tags
19
19
 
20
20
  *.csv
21
+ spec/rainforest
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm use 2.2.0@rainforest-cli --create
1
+ rvm use 2.3.0@rainforest-cli --create
data/.travis.yml CHANGED
@@ -1,5 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 2.3.0
4
+ - 2.2.3
3
5
  - 2.1.2
4
6
  - 2.0.0
5
7
  - 1.9.3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Rainforest CLI Changelog
2
2
 
3
+ ## 1.1.0 - 6th January 2016
4
+ - Added support for tests stored in plain text format, so you can store them locally
5
+
3
6
  ## 1.0.5 - 25th August 2015
4
7
  - Added environment support (278f4fe9a1ca9f507fe1e4b11935d9c37056786b)
5
8
 
data/README.md CHANGED
@@ -56,7 +56,8 @@ The most popular options are:
56
56
  - `--browsers ie8` or `--browsers ie8,chrome` - specficy the browsers you wish to run against. This overrides the test own settings. Valid browsers are ie8, ie9, chrome, firefox and safari.
57
57
  - `--tag run-me` - only run tests which have this tag (recommended if you have lots of [test-steps](http://docs.rainforestqa.com/pages/example-test-suite.html#test_steps))!)
58
58
  - `--site-id` - only run tests for a specific site. Get in touch with us for help on getting that you site id if you are unable to.
59
- - `--conflict abort` - if you trigger rainforest more than once, anything running will be aborted and a fresh run started
59
+ - `--environment-id` - run your tests using this environment. Otherwise it will use your default environment
60
+ - `--conflict OPTION` - use the `abort` option to abort any runs in progress in the same environment as your new run. use the `abort-all` option to abort all runs in progress.
60
61
  - `--fg` - results in the foreground - rainforest-cli will not return until the run is complete. This is what you want to make the build pass / fail dependent on rainforest results
61
62
  - `--fail-fast` - fail the build as soon as the first failed result comes in. If you don't pass this it will wait until 100% of the run is done. Use with `--fg`.
62
63
  - `--custom-url` - use a custom url for this run. Example use case: an ad-hoc QA environment with [Fourchette](https://github.com/rainforestapp/fourchette). You will need to specify a `site_id` too for this to work. Note that we will be creating a new environment for this particular run.
data/bin/rainforest CHANGED
@@ -4,4 +4,4 @@ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "../lib")
4
4
 
5
5
  require "rainforest/cli"
6
6
 
7
- Rainforest::Cli.start(ARGV)
7
+ RainforestCli.start(ARGV)
@@ -4,36 +4,58 @@ require "rainforest/cli/runner"
4
4
  require "rainforest/cli/http_client"
5
5
  require "rainforest/cli/git_trigger"
6
6
  require "rainforest/cli/csv_importer"
7
+ require "rainforest/cli/test_importer"
8
+ require "rainforest/cli/test_parser"
7
9
  require "erb"
8
10
  require "httparty"
9
11
  require "json"
10
12
  require "logger"
11
13
 
12
- module Rainforest
13
- module Cli
14
- def self.start(args)
15
- options = OptionParser.new(args)
16
- OptionParser.new(['--help']) if args.size == 0
14
+ module RainforestCli
15
+ def self.start(args)
16
+ options = OptionParser.new(args)
17
+ OptionParser.new(['--help']) if args.size == 0
17
18
 
18
- begin
19
- options.validate!
20
- rescue OptionParser::ValidationError => e
21
- logger.fatal e.message
22
- exit 2
23
- end
19
+ begin
20
+ options.validate!
21
+ rescue OptionParser::ValidationError => e
22
+ logger.fatal e.message
23
+ exit 2
24
+ end
24
25
 
26
+ case options.command
27
+ when 'run'
25
28
  runner = Runner.new(options)
26
29
  runner.run
30
+ when 'new'
31
+ t = TestImporter.new(options)
32
+ t.create_new
33
+ when 'validate'
34
+ t = TestImporter.new(options)
35
+ t.validate
36
+ when 'upload'
37
+ t = TestImporter.new(options)
38
+ t.upload
27
39
 
28
- true
40
+ # options.tags = ['ro']
41
+ # runner = Runner.new(options)
42
+ # runner.run
43
+ when 'export'
44
+ t = TestImporter.new(options)
45
+ t.export
46
+ else
47
+ logger.fatal "Unknown command"
48
+ exit 2
29
49
  end
30
50
 
31
- def self.logger
32
- @logger ||= Logger.new(STDOUT)
33
- end
51
+ true
52
+ end
34
53
 
35
- def self.logger=(logger)
36
- @logger = logger
37
- end
54
+ def self.logger
55
+ @logger ||= Logger.new(STDOUT)
56
+ end
57
+
58
+ def self.logger=(logger)
59
+ @logger = logger
38
60
  end
39
61
  end
@@ -4,49 +4,47 @@ require 'httparty'
4
4
  require 'parallel'
5
5
  require 'ruby-progressbar'
6
6
 
7
- module Rainforest
8
- module Cli
9
- class CSVImporter
10
- attr_reader :client
11
-
12
- def initialize name, file, token
13
- @generator_name = name
14
- @file = file
15
- @client = HttpClient.new token: token
7
+ module RainforestCli
8
+ class CSVImporter
9
+ attr_reader :client
10
+
11
+ def initialize name, file, token
12
+ @generator_name = name
13
+ @file = file
14
+ @client = HttpClient.new token: token
15
+ end
16
+
17
+ def row_data columns, values
18
+ Hash[(columns.map {|c| c['id']}).zip(values)]
19
+ end
20
+
21
+ def import
22
+ rows = []
23
+ CSV.foreach(@file, encoding: 'windows-1251:utf-8') do |row|
24
+ rows << row
16
25
  end
17
26
 
18
- def row_data columns, values
19
- Hash[(columns.map {|c| c['id']}).zip(values)]
27
+ # Create the generator
28
+ columns = rows.shift.map do |column|
29
+ {name: column.downcase.strip.gsub(/\s/, '_')}
20
30
  end
31
+ raise 'Invalid schema in CSV. You must include headers in first row.' if not columns
32
+
33
+ print "Creating custom step variable"
34
+ response = client.post "/generators", { name: @generator_name, description: @generator_name, columns: columns }
35
+ raise "Error creating custom step variable: #{response['error']}" if response['error']
36
+ puts "\t[OK]"
37
+
38
+ @columns = response['columns']
39
+ @generator_id = response['id']
40
+
41
+ puts "Uploading data..."
42
+ p = ProgressBar.create(title: 'Rows', total: rows.count, format: '%a %B %p%% %t')
21
43
 
22
- def import
23
- rows = []
24
- CSV.foreach(@file, encoding: 'windows-1251:utf-8') do |row|
25
- rows << row
26
- end
27
-
28
- # Create the generator
29
- columns = rows.shift.map do |column|
30
- {name: column.downcase.strip.gsub(/\s/, '_')}
31
- end
32
- raise 'Invalid schema in CSV. You must include headers in first row.' if not columns
33
-
34
- print "Creating custom step variable"
35
- response = client.post "/generators", { name: @generator_name, description: @generator_name, columns: columns }
36
- raise "Error creating custom step variable: #{response['error']}" if response['error']
37
- puts "\t[OK]"
38
-
39
- @columns = response['columns']
40
- @generator_id = response['id']
41
-
42
- puts "Uploading data..."
43
- p = ProgressBar.create(title: 'Rows', total: rows.count, format: '%a %B %p%% %t')
44
-
45
- # Insert the data
46
- Parallel.each(rows, in_threads: 16, finish: lambda { |item, i, result| p.increment }) do |row|
47
- response = client.post("/generators/#{@generator_id}/rows", {data: row_data(@columns, row)})
48
- raise response['error'] if response['error']
49
- end
44
+ # Insert the data
45
+ Parallel.each(rows, in_threads: 16, finish: lambda { |item, i, result| p.increment }) do |row|
46
+ response = client.post("/generators/#{@generator_id}/rows", {data: row_data(@columns, row)})
47
+ raise response['error'] if response['error']
50
48
  end
51
49
  end
52
50
  end
@@ -1,19 +1,17 @@
1
1
  require 'optparse'
2
2
 
3
- module Rainforest
4
- module Cli
5
- class GitTrigger
6
- def self.git_trigger_should_run?(commit_message)
7
- commit_message.include?('@rainforest')
8
- end
3
+ module RainforestCli
4
+ class GitTrigger
5
+ def self.git_trigger_should_run?(commit_message)
6
+ commit_message.include?('@rainforest')
7
+ end
9
8
 
10
- def self.extract_hashtags(commit_message)
11
- commit_message.scan(/#([\w_-]+)/).flatten.map {|s| s.gsub('#','') }
12
- end
9
+ def self.extract_hashtags(commit_message)
10
+ commit_message.scan(/#([\w_-]+)/).flatten.map {|s| s.gsub('#','') }
11
+ end
13
12
 
14
- def self.last_commit_message
15
- `git log -1 --pretty=%B`.strip
16
- end
13
+ def self.last_commit_message
14
+ `git log -1 --pretty=%B`.strip
17
15
  end
18
16
  end
19
17
  end
@@ -1,56 +1,57 @@
1
- module Rainforest
2
- module Cli
3
- class HttpClient
4
- API_URL = ENV.fetch("RAINFOREST_API_URL") do
5
- 'https://app.rainforestqa.com/api/1'
6
- end.freeze
7
-
8
- def initialize(options)
9
- @token = options.fetch(:token)
10
- end
1
+ module RainforestCli
2
+ class HttpClient
3
+ API_URL = ENV.fetch("RAINFOREST_API_URL") do
4
+ 'https://app.rainforestqa.com/api/1'
5
+ end.freeze
6
+
7
+ def initialize(options)
8
+ @token = options.fetch(:token)
9
+ end
11
10
 
12
- def delete(url, body = {})
13
- response = HTTParty.delete make_url(url), {
14
- body: body,
15
- headers: headers,
16
- }
11
+ def delete(url, body = {})
12
+ response = HTTParty.delete make_url(url), {
13
+ body: body,
14
+ headers: headers,
15
+ verify: false
16
+ }
17
17
 
18
- JSON.parse(response.body)
19
- end
18
+ JSON.parse(response.body)
19
+ end
20
20
 
21
- def post(url, body = {})
22
- response = HTTParty.post make_url(url), {
23
- body: body,
24
- headers: headers,
25
- }
21
+ def post(url, body = {})
22
+ response = HTTParty.post make_url(url), {
23
+ body: body,
24
+ headers: headers,
25
+ verify: false
26
+ }
26
27
 
27
- JSON.parse(response.body)
28
- end
28
+ JSON.parse(response.body)
29
+ end
29
30
 
30
- def get(url, body = {})
31
- response = HTTParty.get make_url(url), {
32
- body: body,
33
- headers: headers,
34
- }
35
-
36
- if response.code == 200
37
- JSON.parse(response.body)
38
- else
39
- nil
40
- end
41
- end
31
+ def get(url, body = {})
32
+ response = HTTParty.get make_url(url), {
33
+ body: body,
34
+ headers: headers,
35
+ verify: false
36
+ }
42
37
 
43
- private
44
- def make_url(url)
45
- File.join(API_URL, url)
38
+ if response.code == 200
39
+ JSON.parse(response.body)
40
+ else
41
+ nil
46
42
  end
43
+ end
47
44
 
48
- def headers
49
- {
50
- "CLIENT_TOKEN" => @token,
51
- "User-Agent" => "Rainforest-cli-#{Rainforest::Cli::VERSION}"
52
- }
53
- end
45
+ private
46
+ def make_url(url)
47
+ File.join(API_URL, url)
48
+ end
49
+
50
+ def headers
51
+ {
52
+ "CLIENT_TOKEN" => @token,
53
+ "User-Agent" => "Rainforest-cli-#{RainforestCli::VERSION}"
54
+ }
54
55
  end
55
56
  end
56
57
  end
@@ -1,133 +1,154 @@
1
1
  require 'optparse'
2
2
 
3
- module Rainforest
4
- module Cli
5
- class BrowserException < Exception
6
- def initialize browsers
7
- invalid_browsers = browsers - OptionParser::VALID_BROWSERS
8
- super "#{invalid_browsers.join(', ')} is not valid. Valid browsers: #{OptionParser::VALID_BROWSERS.join(', ')}"
9
- end
3
+ module RainforestCli
4
+ class BrowserException < Exception
5
+ def initialize browsers
6
+ invalid_browsers = browsers - OptionParser::VALID_BROWSERS
7
+ super "#{invalid_browsers.join(', ')} is not valid. Valid browsers: #{OptionParser::VALID_BROWSERS.join(', ')}"
10
8
  end
9
+ end
11
10
 
12
- class OptionParser
13
- attr_reader :command, :token, :tags, :conflict, :browsers, :site_id, :environment_id,
14
- :import_file_name, :import_name, :custom_url, :description, :folder
11
+ class OptionParser
12
+ attr_writer :file_name, :tags
13
+ attr_reader :command, :token, :tags, :conflict, :browsers, :site_id, :environment_id,
14
+ :import_file_name, :import_name, :custom_url, :description, :folder,
15
+ :debug, :file_name
15
16
 
16
- VALID_BROWSERS = %w{chrome firefox safari ie8 ie9}.freeze
17
+ VALID_BROWSERS = %w{chrome firefox safari ie8 ie9}.freeze
17
18
 
18
- def initialize(args)
19
- @args = args.dup
20
- @tags = []
21
- @browsers = nil
19
+ def initialize(args)
20
+ @args = args.dup
21
+ @tags = []
22
+ @browsers = nil
23
+ @require_token = true
24
+ @debug = false
22
25
 
23
- @parsed = ::OptionParser.new do |opts|
24
- opts.on("--import-variable-csv-file FILE", "Import step variables; CSV data") do |value|
25
- @import_file_name = value
26
- end
26
+ @parsed = ::OptionParser.new do |opts|
27
+ opts.on("--debug") do
28
+ @debug = true
29
+ end
27
30
 
28
- opts.on("--import-variable-name NAME", "Import step variables; Name of variable (note, will be replaced if exists)") do |value|
29
- @import_name = value
30
- end
31
+ opts.on("--file") do |value|
32
+ @file_name = value
33
+ end
31
34
 
32
- opts.on("--git-trigger", "Only run if the last commit contains @rainforestapp") do |value|
33
- @git_trigger = true
34
- end
35
+ opts.on("--import-variable-csv-file FILE", "Import step variables; CSV data") do |value|
36
+ @import_file_name = value
37
+ end
35
38
 
36
- opts.on("--fg", "Run the tests in foreground.") do |value|
37
- @foreground = value
38
- end
39
+ opts.on("--import-variable-name NAME", "Import step variables; Name of variable (note, will be replaced if exists)") do |value|
40
+ @import_name = value
41
+ end
39
42
 
40
- opts.on("--fail-fast", String, "Fail as soon as there is a failure (don't wait for completion)") do |value|
41
- @failfast = true
42
- end
43
+ opts.on("--git-trigger", "Only run if the last commit contains @rainforestapp") do |value|
44
+ @git_trigger = true
45
+ end
43
46
 
44
- opts.on("--token TOKEN", String, "Your rainforest API token.") do |value|
45
- @token = value
46
- end
47
+ opts.on("--fg", "Run the tests in foreground.") do |value|
48
+ @foreground = value
49
+ end
47
50
 
48
- opts.on("--tag TAG", String, "A tag to run the tests with") do |value|
49
- @tags << value
50
- end
51
+ opts.on("--fail-fast", String, "Fail as soon as there is a failure (don't wait for completion)") do |value|
52
+ @failfast = true
53
+ end
51
54
 
52
- opts.on("--folder ID", "Run tests in the specified folders") do |value|
53
- @folder = value
54
- end
55
+ opts.on("--token TOKEN", String, "Your rainforest API token.") do |value|
56
+ @token = value
57
+ end
55
58
 
56
- opts.on("--browsers LIST", "Run against the specified browsers") do |value|
57
- @browsers = value.split(',').map{|x| x.strip.downcase }.uniq
59
+ opts.on("--tag TAG", String, "A tag to run the tests with") do |value|
60
+ @tags << value
61
+ end
58
62
 
59
- raise BrowserException, @browsers unless (@browsers - VALID_BROWSERS).empty?
60
- end
63
+ opts.on("--folder ID", "Run tests in the specified folders") do |value|
64
+ @folder = value
65
+ end
61
66
 
62
- opts.on("--conflict MODE", String, "How should Rainforest handle existing in progress runs?") do |value|
63
- @conflict = value
64
- end
67
+ opts.on("--browsers LIST", "Run against the specified browsers") do |value|
68
+ @browsers = value.split(',').map{|x| x.strip.downcase }.uniq
65
69
 
66
- opts.on("--environment-id ID", Integer, "Run using this environment. If excluded, will use your default") do |value|
67
- @environment_id = value
68
- end
70
+ raise BrowserException, @browsers unless (@browsers - VALID_BROWSERS).empty?
71
+ end
69
72
 
70
- opts.on("--site-id ID", Integer, "Only run tests for a specific site") do |value|
71
- @site_id = value
72
- end
73
+ opts.on("--conflict MODE", String, "How should Rainforest handle existing in progress runs?") do |value|
74
+ @conflict = value
75
+ end
73
76
 
74
- opts.on("--custom-url URL", String, "Use a custom url for this run. You will need to specify a site_id too for this to work.") do |value|
75
- @custom_url = value
76
- end
77
+ opts.on("--environment-id ID", Integer, "Run using this environment. If excluded, will use your default") do |value|
78
+ @environment_id = value
79
+ end
77
80
 
78
- opts.on("--description DESCRIPTION", "Add a description for the run.") do |value|
79
- @description = value
80
- end
81
+ opts.on("--site-id ID", Integer, "Only run tests for a specific site") do |value|
82
+ @site_id = value
83
+ end
81
84
 
82
- opts.on_tail("--help", "Display help message and exit") do |value|
83
- puts opts
84
- exit 0
85
- end
85
+ opts.on("--custom-url URL", String, "Use a custom url for this run. You will need to specify a site_id too for this to work.") do |value|
86
+ @custom_url = value
87
+ end
86
88
 
87
- end.parse!(@args)
89
+ opts.on("--description DESCRIPTION", "Add a description for the run.") do |value|
90
+ @description = value
91
+ end
88
92
 
89
- @command = @args.shift
90
- @tests = @args.dup
91
- end
93
+ opts.on_tail("--help", "Display help message and exit") do |value|
94
+ puts opts
95
+ exit 0
96
+ end
92
97
 
93
- def tests
94
- @tests
95
- end
98
+ end.parse!(@args)
96
99
 
97
- def git_trigger?
98
- @git_trigger
99
- end
100
+ @command = @args.shift
100
101
 
101
- def failfast?
102
- @failfast
102
+ if @command == 'new'
103
+ @file_name = @args.shift
103
104
  end
104
105
 
105
- def foreground?
106
- @foreground
107
- end
106
+ @tests = @args.dup
107
+
108
+ # A couple of commands don't need the token
109
+ token_not_required = %w{new validate}
110
+ @require_token = false if token_not_required.include?(@command)
111
+ end
112
+
113
+ def tests
114
+ @tests
115
+ end
116
+
117
+ def git_trigger?
118
+ @git_trigger
119
+ end
120
+
121
+ def failfast?
122
+ @failfast
123
+ end
124
+
125
+ def foreground?
126
+ @foreground
127
+ end
108
128
 
109
- def validate!
129
+ def validate!
130
+ if @require_token
110
131
  unless token
111
132
  raise ValidationError, "You must pass your API token using: --token TOKEN"
112
133
  end
134
+ end
113
135
 
114
- if custom_url && site_id.nil?
115
- raise ValidationError, "The site-id and custom-url options are both required."
116
- end
117
-
118
- if import_file_name && import_name
119
- unless File.exists?(import_file_name)
120
- raise ValidationError, "Input file: #{import_file_name} not found"
121
- end
136
+ if custom_url && site_id.nil?
137
+ raise ValidationError, "The site-id and custom-url options are both required."
138
+ end
122
139
 
123
- elsif import_file_name || import_name
124
- raise ValidationError, "You must pass both --import-variable-csv-file and --import-variable-name"
140
+ if import_file_name && import_name
141
+ unless File.exists?(import_file_name)
142
+ raise ValidationError, "Input file: #{import_file_name} not found"
125
143
  end
126
- true
127
- end
128
144
 
129
- class ValidationError < RuntimeError
145
+ elsif import_file_name || import_name
146
+ raise ValidationError, "You must pass both --import-variable-csv-file and --import-variable-name"
130
147
  end
148
+ true
149
+ end
150
+
151
+ class ValidationError < RuntimeError
131
152
  end
132
153
  end
133
154
  end