specimen 0.0.2.alpha → 0.0.4.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +53 -49
- data/VERSION +1 -1
- data/lib/specimen/command/exec_command_builder.rb +42 -14
- data/lib/specimen/command/runner/cukes_runner.rb +2 -18
- data/lib/specimen/command/runner/specs_runner.rb +2 -17
- data/lib/specimen/command/test_runner.rb +19 -25
- data/lib/specimen/command.rb +12 -7
- data/lib/specimen/commands/encrypted_configuration/USAGE +37 -0
- data/lib/specimen/commands/encrypted_configuration/encrypted_configuration_command.rb +108 -0
- data/lib/specimen/commands/gem_help/USAGE +6 -3
- data/lib/specimen/config_parser.rb +31 -0
- data/lib/specimen/generator/configs/specimen_project_config.rb +2 -2
- data/lib/specimen/generator/cucumber/cucumber_project_generator.rb +2 -0
- data/lib/specimen/generator/cucumber/templates/config/cucumber.yml.tt +4 -1
- data/lib/specimen/generator/cucumber/templates/config/specimen.cukes.yml.tt +22 -0
- data/lib/specimen/generator/cucumber/templates/features/examples/add_numbers.feature.tt +4 -2
- data/lib/specimen/generator/cucumber/templates/features/step_definitions/examples/example_steps.rb.tt +9 -0
- data/lib/specimen/generator/cucumber/templates/features/support/env.rb.tt +22 -0
- data/lib/specimen/generator/project/project_root_generator.rb +0 -3
- data/lib/specimen/generator/project/specimen_project_generator.rb +37 -0
- data/lib/specimen/generator/project/templates/root/config/specimen.yml.tt +11 -7
- data/lib/specimen/generator/rspec/rspec_project_generator.rb +1 -0
- data/lib/specimen/generator/rspec/templates/config/.rspec.tt +0 -4
- data/lib/specimen/generator/rspec/templates/config/specimen.specs.yml.tt +19 -0
- data/lib/specimen/generator/rspec/templates/spec/examples/example_spec.rb.tt +9 -5
- data/lib/specimen/generator/rspec/templates/spec/spec_helper.rb.tt +7 -5
- data/lib/specimen/runtime.rb +124 -54
- data/lib/specimen/utils/encrypted_config_path.rb +54 -0
- data/lib/specimen/utils/encrypted_configuration.rb +156 -0
- data/lib/specimen/utils.rb +8 -0
- data/lib/specimen/version.rb +1 -1
- data/lib/specimen.rb +14 -5
- metadata +26 -6
- data/lib/specimen/command/runner/exec_runner.rb +0 -37
- data/lib/specimen/commands/exec/exec_command.rb +0 -9
- data/lib/specimen/runtime/yml_parser.rb +0 -49
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib_path = "#{File.expand_path(__dir__)}/lib"
|
4
|
+
$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
|
5
|
+
|
6
|
+
require 'pry' if ENV.key?('DEBUG')
|
7
|
+
require 'specimen'
|
8
|
+
require 'rspec'
|
9
|
+
|
10
|
+
World RSpec::Expectations, RSpec::Matchers
|
11
|
+
|
12
|
+
BeforeAll do
|
13
|
+
Specimen.run_testrunner_hooks!
|
14
|
+
end
|
15
|
+
|
16
|
+
Before do
|
17
|
+
@enc_config = Specimen.enc_config
|
18
|
+
end
|
19
|
+
|
20
|
+
at_exit do
|
21
|
+
p 'bye bye'
|
22
|
+
end
|
@@ -13,12 +13,49 @@ module Specimen
|
|
13
13
|
CucumberProjectGenerator.start([config]) if config[:cucumber]
|
14
14
|
RSpecProjectGenerator.start([config]) if config[:rspec]
|
15
15
|
|
16
|
+
inside config[:root_path] do
|
17
|
+
run('specimen enc create --name example')
|
18
|
+
|
19
|
+
env_file = '.example.env'
|
20
|
+
enc_key = File.read "#{Dir.pwd}/config/enc/example.key"
|
21
|
+
content = "MASTER_KEY='#{enc_key}'\n"
|
22
|
+
File.write(env_file, content)
|
23
|
+
|
24
|
+
say("Created env-file '#{env_file}' containing the MASTER_KEY to decrypt config/enc/example.yml.enc".bold)
|
25
|
+
end
|
26
|
+
|
27
|
+
say(init_message.green.bold)
|
16
28
|
true
|
17
29
|
end
|
18
30
|
|
19
31
|
def config
|
20
32
|
@config ||= Generator::SpecimenProjectConfig.parse(options)
|
21
33
|
end
|
34
|
+
|
35
|
+
def init_message
|
36
|
+
enc_config = 'config/enc/example.yml.enc'
|
37
|
+
|
38
|
+
<<~STRING
|
39
|
+
|
40
|
+
Created new specimen project in
|
41
|
+
#{config[:root_path]}
|
42
|
+
|
43
|
+
Please cd into the directory and run e.g.
|
44
|
+
|
45
|
+
# check out the help for cukes and specs command
|
46
|
+
$> specimen cukes|specs --help|-h
|
47
|
+
|
48
|
+
# run tests using the encrypted example configuration
|
49
|
+
$> specimen cukes|specs --specimen-profile|--sp examples
|
50
|
+
|
51
|
+
# Check out the 'enc' command help
|
52
|
+
$> specimen enc --help|-h
|
53
|
+
|
54
|
+
# Read and update the encrypted config '#{enc_config}'
|
55
|
+
$> specimen enc update --name|-n example
|
56
|
+
|
57
|
+
STRING
|
58
|
+
end
|
22
59
|
end
|
23
60
|
end
|
24
61
|
end
|
@@ -3,6 +3,7 @@ default: &default
|
|
3
3
|
env:
|
4
4
|
- FOO='123'
|
5
5
|
|
6
|
+
<% if data[:cucumber] -%>
|
6
7
|
cucumber: &cucumber
|
7
8
|
framework: cucumber
|
8
9
|
profiles: []
|
@@ -14,6 +15,15 @@ cucumber: &cucumber
|
|
14
15
|
- FOO='123'
|
15
16
|
- BAZ='something'
|
16
17
|
|
18
|
+
ci_cukes:
|
19
|
+
<<: *cucumber
|
20
|
+
env:
|
21
|
+
- CI='1'
|
22
|
+
profiles:
|
23
|
+
- regression
|
24
|
+
<% end -%>
|
25
|
+
|
26
|
+
<% if data[:rspec] -%>
|
17
27
|
rspec: &rspec
|
18
28
|
framework: rspec
|
19
29
|
options:
|
@@ -29,10 +39,4 @@ ci_specs:
|
|
29
39
|
<<: *rspec
|
30
40
|
env:
|
31
41
|
- CI='1'
|
32
|
-
|
33
|
-
ci_cukes:
|
34
|
-
<<: *cucumber
|
35
|
-
env:
|
36
|
-
- CI='1'
|
37
|
-
profiles:
|
38
|
-
- regression
|
42
|
+
<% end -%>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
default_opts: &default_opts
|
2
|
+
- --options config/.rspec
|
3
|
+
- --format documentation
|
4
|
+
- --format html --out tmp/rspec_result.html
|
5
|
+
|
6
|
+
rspec: &rspec
|
7
|
+
options: *default_opts
|
8
|
+
|
9
|
+
examples:
|
10
|
+
<<: *rspec
|
11
|
+
env_file: .example.env
|
12
|
+
enc_configs:
|
13
|
+
- name: example
|
14
|
+
env_key: MASTER_KEY
|
15
|
+
|
16
|
+
ci_specs:
|
17
|
+
<<: *rspec
|
18
|
+
env:
|
19
|
+
- CI='1'
|
@@ -1,13 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
RSpec.describe '
|
4
|
-
context '
|
3
|
+
RSpec.describe 'Add numbers specs' do
|
4
|
+
context 'add 1 + 1', add_numbers: true do
|
5
5
|
before(:example) do
|
6
|
-
@
|
6
|
+
@result = 1 + 1
|
7
7
|
end
|
8
8
|
|
9
|
-
it 'passes' do
|
10
|
-
expect(@
|
9
|
+
it 'passes', pass: true do
|
10
|
+
expect(@result).to eq 2
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'fails due to not being an integer', fail: true do
|
14
|
+
expect(@result).to eq '2'
|
11
15
|
end
|
12
16
|
end
|
13
17
|
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require 'pry'
|
3
|
+
require 'specimen'
|
5
4
|
|
6
5
|
RSpec.configure do |config|
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
config.before(:suite) do
|
7
|
+
Specimen.run_testrunner_hooks!
|
8
|
+
end
|
9
|
+
|
10
|
+
config.before(:all) do
|
11
|
+
@enc_config = Specimen.enc_config
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
data/lib/specimen/runtime.rb
CHANGED
@@ -1,84 +1,154 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'dotenv'
|
4
|
+
require 'specimen/config_parser'
|
4
5
|
|
5
6
|
module Specimen
|
6
|
-
|
7
|
-
class
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
class Runtime
|
8
|
+
class ConfigNotFoundError < RuntimeError; end
|
9
|
+
class ProfileNotFoundError < RuntimeError; end
|
10
|
+
|
11
|
+
attr_reader :wd_path, :config_directory,
|
12
|
+
:program_name, :config_data,
|
13
|
+
:profile_data, :framework
|
14
|
+
|
15
|
+
attr_accessor :command, :specimen_config, :specimen_profile
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@wd_path = Pathname.getwd
|
19
|
+
@config_directory = Pathname.new("#{wd_path}/config")
|
20
|
+
@program_name = $PROGRAM_NAME
|
21
|
+
@command = nil
|
22
|
+
@specimen_config = nil
|
23
|
+
@specimen_profile = nil
|
24
|
+
@config_data = nil
|
25
|
+
@profile_data = nil
|
12
26
|
end
|
13
27
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
28
|
+
def set_testrunner!(config, profile, command)
|
29
|
+
@specimen_config = config
|
30
|
+
@specimen_profile = profile
|
31
|
+
@command = command
|
32
|
+
|
33
|
+
define_framework!
|
34
|
+
run_default_profile_checks!
|
35
|
+
|
36
|
+
load_specimen_config!
|
37
|
+
load_specimen_profile!
|
19
38
|
end
|
20
39
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
40
|
+
def run_load_profile_hook!
|
41
|
+
@specimen_config = ENV.fetch('SPECIMEN_CONFIG_NAME')
|
42
|
+
@specimen_profile = ENV.fetch('SPECIMEN_PROFILE_NAME')
|
43
|
+
|
44
|
+
load_specimen_config!
|
45
|
+
load_specimen_profile!
|
26
46
|
end
|
27
47
|
|
28
|
-
|
48
|
+
def run_env_file_hook!
|
49
|
+
return unless profile_with_env_file?
|
29
50
|
|
30
|
-
|
31
|
-
|
51
|
+
file = profile_data['env_file']
|
52
|
+
path = Pathname.new("#{wd_path}/#{file}")
|
32
53
|
|
33
|
-
|
34
|
-
@command = command
|
35
|
-
@config = config
|
54
|
+
return Dotenv.load!(path.to_path) if path.exist?
|
36
55
|
|
37
|
-
|
38
|
-
|
56
|
+
raise "Environment file: '#{path.to_path}' is defined in profile '#{specimen_profile}' but it does not exist!"
|
57
|
+
end
|
39
58
|
|
40
|
-
|
41
|
-
|
59
|
+
def run_decrypt_enc_configs_hook!
|
60
|
+
return unless profile_with_enc_configs?
|
42
61
|
|
43
|
-
|
44
|
-
|
45
|
-
end
|
62
|
+
encrypted_config = {}
|
63
|
+
enc_configs = profile_data['enc_configs']
|
46
64
|
|
47
|
-
|
48
|
-
|
49
|
-
|
65
|
+
enc_configs.each do |enc_config|
|
66
|
+
name = enc_config['name']
|
67
|
+
env_key = enc_config['env_key']
|
50
68
|
|
51
|
-
|
52
|
-
|
53
|
-
end
|
69
|
+
warn "env key '#{env_key}' defined but not set!" if env_key && !ENV.key?(env_key)
|
70
|
+
env_key.nil? ? env_key = '' : env_key
|
54
71
|
|
55
|
-
|
56
|
-
|
72
|
+
config = Specimen::Utils::EncryptedConfiguration.decrypt(name:, env_key:)
|
73
|
+
encrypted_config.merge!(config)
|
57
74
|
end
|
58
75
|
|
59
|
-
|
60
|
-
|
76
|
+
Specimen.enc_config = encrypted_config
|
77
|
+
end
|
61
78
|
|
62
|
-
|
63
|
-
|
79
|
+
def define_framework!
|
80
|
+
raise 'Unrecognized command' unless cukes? || specs?
|
64
81
|
|
65
|
-
|
66
|
-
|
82
|
+
@framework = cukes? ? 'cucumber' : 'rspec'
|
83
|
+
end
|
67
84
|
|
68
|
-
|
69
|
-
|
85
|
+
def run_default_profile_checks!
|
86
|
+
raise 'You can not use the rspec profile with Cucumber!' if cukes? && specimen_profile == 'rspec'
|
87
|
+
raise 'You can not use the cucumber profile with RSpec!' if specs? && specimen_profile == 'cucumber'
|
88
|
+
end
|
70
89
|
|
71
|
-
|
72
|
-
|
73
|
-
end
|
90
|
+
def load_specimen_profile!
|
91
|
+
raise 'Specimen profile is not set!' if specimen_profile.nil? || specimen_profile.empty?
|
74
92
|
|
75
|
-
|
76
|
-
|
93
|
+
unless config_data&.key?(specimen_profile)
|
94
|
+
raise ProfileNotFoundError, "Can not find profile '#{specimen_profile}' in #{specimen_config_path.to_path}"
|
77
95
|
end
|
78
96
|
|
79
|
-
|
80
|
-
|
81
|
-
|
97
|
+
@profile_data = config_data[specimen_profile]
|
98
|
+
end
|
99
|
+
|
100
|
+
def load_specimen_config!
|
101
|
+
raise ConfigNotFoundError, 'Specimen config not found' unless specimen_config_exist?
|
102
|
+
|
103
|
+
@config_data = ConfigParser.read!(specimen_config_path.to_path)
|
104
|
+
end
|
105
|
+
|
106
|
+
def specimen_config_path
|
107
|
+
Pathname.new("#{config_directory}/#{specimen_config}")
|
108
|
+
end
|
109
|
+
|
110
|
+
def custom_config
|
111
|
+
@specimen_config
|
112
|
+
end
|
113
|
+
|
114
|
+
def profile_with_enc_configs?
|
115
|
+
return false unless profile_data.is_a?(Hash)
|
116
|
+
|
117
|
+
profile_data&.key?('enc_configs')
|
118
|
+
end
|
119
|
+
|
120
|
+
def profile_with_env_file?
|
121
|
+
return false unless profile_data.is_a?(Hash)
|
122
|
+
|
123
|
+
profile_data&.key?('env_file')
|
124
|
+
end
|
125
|
+
|
126
|
+
def cukes?
|
127
|
+
return false if command.nil?
|
128
|
+
|
129
|
+
command.is_a?(Command::CukesCommand)
|
130
|
+
end
|
131
|
+
|
132
|
+
def specs?
|
133
|
+
return false if command.nil?
|
134
|
+
|
135
|
+
command.is_a?(Command::SpecsCommand)
|
136
|
+
end
|
137
|
+
|
138
|
+
def specimen_config_exist?
|
139
|
+
specimen_config_path.exist?
|
140
|
+
end
|
141
|
+
|
142
|
+
def specimen_bin?
|
143
|
+
program_name.include?('bin/specimen')
|
144
|
+
end
|
145
|
+
|
146
|
+
def cucumber_bin?
|
147
|
+
program_name.include?('bin/cucumber')
|
148
|
+
end
|
149
|
+
|
150
|
+
def parallel_cucumber_bin?
|
151
|
+
program_name.include?('bin/parallel_cucumber')
|
82
152
|
end
|
83
153
|
end
|
84
154
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Specimen
|
4
|
+
module Utils
|
5
|
+
class EncryptedConfigPath
|
6
|
+
ENC_DIRECTORY = 'config/enc'
|
7
|
+
|
8
|
+
attr_reader :name, :runtime
|
9
|
+
|
10
|
+
def initialize(name:)
|
11
|
+
@name = name
|
12
|
+
@runtime = Specimen.runtime
|
13
|
+
end
|
14
|
+
|
15
|
+
def config_base_dir
|
16
|
+
@config_base_dir ||= Pathname.new("#{runtime.wd_path}/#{ENC_DIRECTORY}")
|
17
|
+
end
|
18
|
+
|
19
|
+
def enc_dir
|
20
|
+
return Pathname.new(config_base_dir.to_path) if config_dir.empty?
|
21
|
+
|
22
|
+
Pathname.new("#{config_base_dir}/#{config_dir}")
|
23
|
+
end
|
24
|
+
|
25
|
+
def config_file_name
|
26
|
+
"#{split_name.last}.yml.enc"
|
27
|
+
end
|
28
|
+
|
29
|
+
def config_dir
|
30
|
+
split_name[0...-1].join('/')
|
31
|
+
end
|
32
|
+
|
33
|
+
def split_name
|
34
|
+
name.split('/')
|
35
|
+
end
|
36
|
+
|
37
|
+
def full_enc_path
|
38
|
+
@full_enc_path ||= Pathname.new("#{enc_dir}/#{config_file_name}")
|
39
|
+
end
|
40
|
+
|
41
|
+
def full_key_path
|
42
|
+
@full_key_path ||= Pathname.new("#{enc_dir}/#{config_file_name.gsub('.yml.enc', '.key')}")
|
43
|
+
end
|
44
|
+
|
45
|
+
def config_exist?
|
46
|
+
full_enc_path.exist?
|
47
|
+
end
|
48
|
+
|
49
|
+
def key_exist?
|
50
|
+
full_key_path.exist?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/encrypted_configuration'
|
4
|
+
require 'specimen/utils/encrypted_config_path'
|
5
|
+
|
6
|
+
module Specimen
|
7
|
+
module Utils
|
8
|
+
class EncryptedConfiguration
|
9
|
+
class ExistingConfigFilesError < StandardError; end
|
10
|
+
class NoSuchConfigError < StandardError; end
|
11
|
+
class MissingKeyFileError < StandardError; end
|
12
|
+
class MissingKeyFileError < StandardError; end
|
13
|
+
|
14
|
+
attr_accessor :name
|
15
|
+
attr_reader :enc_path, :env_key, :config_path, :key_path
|
16
|
+
|
17
|
+
def self.create(name:)
|
18
|
+
new(name:).create_encrypted_config!
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.update(name:)
|
22
|
+
new(name:).update_encrypted_config!
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.validate(name:)
|
26
|
+
new(name:).validate_encrypted_config!
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.decrypt(name:, env_key: 'MASTER_KEY')
|
30
|
+
new(name:, env_key:).decrypt_config!
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(name:, env_key: '')
|
34
|
+
@name = name
|
35
|
+
@enc_path = EncryptedConfigPath.new(name:)
|
36
|
+
@config_path = @enc_path.full_enc_path
|
37
|
+
@key_path = @enc_path.full_key_path
|
38
|
+
@env_key = env_key
|
39
|
+
end
|
40
|
+
|
41
|
+
def decrypt_config!
|
42
|
+
raise NoSuchConfigError, "No such file: '#{config_path.to_path}'" unless config_exist?
|
43
|
+
raise "Missing decryption key for enc-config '#{enc_path.name}'" unless decryption_key?
|
44
|
+
|
45
|
+
YAML.load(enc_yml_content).deep_symbolize_keys!
|
46
|
+
end
|
47
|
+
|
48
|
+
def validate_encrypted_config!
|
49
|
+
run_enc_files_check!
|
50
|
+
YAML.load(enc_yml_content)
|
51
|
+
enc_path
|
52
|
+
rescue StandardError => e
|
53
|
+
e
|
54
|
+
end
|
55
|
+
|
56
|
+
def enc_yml_content
|
57
|
+
enc_config.read
|
58
|
+
end
|
59
|
+
|
60
|
+
def decryption_key?
|
61
|
+
key_exist? || env_key_set?
|
62
|
+
end
|
63
|
+
|
64
|
+
def env_key_set?
|
65
|
+
return false if env_key.empty?
|
66
|
+
|
67
|
+
ENV.key?(env_key)
|
68
|
+
end
|
69
|
+
|
70
|
+
def run_enc_files_check!
|
71
|
+
raise NoSuchConfigError, "No such file: '#{config_path.to_path}'" unless config_exist?
|
72
|
+
raise MissingKeyFileError, "Missing encryption key file: '#{key_path.to_path}'" unless key_exist?
|
73
|
+
end
|
74
|
+
|
75
|
+
def update_encrypted_config!
|
76
|
+
raise NoSuchConfigError, "No such file: '#{config_path.to_path}'" unless config_exist?
|
77
|
+
raise MissingKeyFileError, "Missing encryption key file: '#{key_path.to_path}'" unless key_exist?
|
78
|
+
raise 'Missing EDITOR variable' unless editor_set?
|
79
|
+
raise "Can not find executable for editor '#{editor}'" unless editor?
|
80
|
+
|
81
|
+
enc_config.change do |tmp_path|
|
82
|
+
system("#{ENV.fetch('EDITOR')} #{tmp_path}")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_encrypted_config!
|
87
|
+
raise ExistingConfigFilesError, "Existing config at #{config_path.to_path}" if config_exist?
|
88
|
+
raise ExistingConfigFilesError, "Existing key file at #{key_path.to_path}" if key_exist?
|
89
|
+
|
90
|
+
create_key_file!
|
91
|
+
create_enc_config!
|
92
|
+
|
93
|
+
enc_path
|
94
|
+
end
|
95
|
+
|
96
|
+
def enc_config
|
97
|
+
@enc_config ||= ActiveSupport::EncryptedConfiguration.new(
|
98
|
+
config_path:,
|
99
|
+
key_path:,
|
100
|
+
env_key:,
|
101
|
+
raise_if_missing_key: true
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
def config_exist?
|
106
|
+
enc_path.config_exist?
|
107
|
+
end
|
108
|
+
|
109
|
+
def key_exist?
|
110
|
+
enc_path.key_exist?
|
111
|
+
end
|
112
|
+
|
113
|
+
def create_key_file!
|
114
|
+
FileUtils.mkdir_p(key_path.dirname) unless key_path.directory?
|
115
|
+
key_path.write(generate_key)
|
116
|
+
end
|
117
|
+
|
118
|
+
def create_enc_config!
|
119
|
+
enc_config.write(example_yml)
|
120
|
+
end
|
121
|
+
|
122
|
+
def generate_key
|
123
|
+
ActiveSupport::EncryptedFile.generate_key
|
124
|
+
end
|
125
|
+
|
126
|
+
def editor
|
127
|
+
ENV.fetch('EDITOR')
|
128
|
+
end
|
129
|
+
|
130
|
+
def editor_set?
|
131
|
+
ENV.fetch('EDITOR', false)
|
132
|
+
end
|
133
|
+
|
134
|
+
def editor?
|
135
|
+
system("command -v #{editor}")
|
136
|
+
end
|
137
|
+
|
138
|
+
def example_yml
|
139
|
+
<<~YML
|
140
|
+
user:
|
141
|
+
email: john.doe@example.com
|
142
|
+
password: johnspassword
|
143
|
+
|
144
|
+
service:
|
145
|
+
host: https://api.my-website.biz
|
146
|
+
client_id: secret-id
|
147
|
+
client_secret: client-secret
|
148
|
+
|
149
|
+
platform:
|
150
|
+
website_url: https://my-website.biz
|
151
|
+
admin_url: https://admin.my-website.biz
|
152
|
+
YML
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
data/lib/specimen/version.rb
CHANGED
data/lib/specimen.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'active_support'
|
4
4
|
require 'colorize'
|
5
5
|
require 'pathname'
|
6
|
+
require 'psych'
|
6
7
|
|
7
8
|
# require Ruby extensions
|
8
9
|
require 'specimen/extensions/ruby/hash'
|
@@ -12,13 +13,21 @@ require 'specimen/runtime'
|
|
12
13
|
require 'specimen/version'
|
13
14
|
|
14
15
|
module Specimen
|
15
|
-
extend ActiveSupport::Autoload
|
16
|
-
|
17
16
|
class << self
|
18
|
-
attr_accessor :
|
17
|
+
attr_accessor :enc_config
|
18
|
+
|
19
|
+
def runtime
|
20
|
+
@runtime ||= Specimen::Runtime.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def run_testrunner_hooks!
|
24
|
+
runtime.run_load_profile_hook!
|
25
|
+
runtime.run_env_file_hook!
|
26
|
+
runtime.run_decrypt_enc_configs_hook!
|
27
|
+
end
|
19
28
|
|
20
|
-
def
|
21
|
-
|
29
|
+
def shell
|
30
|
+
runtime&.command.shell
|
22
31
|
end
|
23
32
|
end
|
24
33
|
end
|