matrixeval 0.1.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -1
- data/Gemfile +4 -0
- data/README.md +91 -6
- data/Rakefile +1 -1
- data/bin/test +4 -0
- data/exe/matrixeval +5 -0
- data/exe/meval +5 -0
- data/lib/matrixeval/command_line/parse_context_arguments.rb +80 -0
- data/lib/matrixeval/command_line/parse_init_arguments.rb +50 -0
- data/lib/matrixeval/command_line.rb +57 -0
- data/lib/matrixeval/config/yaml.rb +47 -0
- data/lib/matrixeval/config.rb +101 -0
- data/lib/matrixeval/container.rb +13 -0
- data/lib/matrixeval/context/build_docker_compose_extend.rb +41 -0
- data/lib/matrixeval/context/find_by_command_options.rb +65 -0
- data/lib/matrixeval/context.rb +80 -0
- data/lib/matrixeval/docker_compose/extend.rb +19 -0
- data/lib/matrixeval/docker_compose/extend_raw.rb +15 -0
- data/lib/matrixeval/docker_compose/file.rb +122 -0
- data/lib/matrixeval/docker_compose.rb +65 -0
- data/lib/matrixeval/extra_mount_files.rb +21 -0
- data/lib/matrixeval/gitignore.rb +40 -0
- data/lib/matrixeval/runner.rb +207 -0
- data/lib/matrixeval/target.rb +45 -0
- data/lib/matrixeval/templates/matrixeval.yml +70 -0
- data/lib/matrixeval/variant.rb +51 -0
- data/lib/matrixeval/vector.rb +38 -0
- data/lib/matrixeval/version.rb +1 -1
- data/lib/matrixeval.rb +44 -1
- metadata +72 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f340adc04181b907e790e3028bb80f1de0d4ea91f1ec4477087d7b2631bde065
|
4
|
+
data.tar.gz: e6845d5bcf308d0974b9241420ef3a1dbc8a3fa544bbad43543cae7f6079203e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b733e83ca820507963da27358d419154d1023ae60e821121935dc116cc3880123e1c1fb8af5b0355d5f6d854b8e1e0f42c4823408b5308008a3ea2e74fd0e21
|
7
|
+
data.tar.gz: af5163f1de81ea41d3882f1930f741a9434dd88c181743820d63d837ed19eacf76651644d85310d276c5ca82ff89094fb88327675a24567caadf7fbcd5ccece0
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,17 @@
|
|
1
|
-
#
|
1
|
+
# MatrixEval
|
2
2
|
|
3
|
-
|
3
|
+
Test your code against multiple versions of dependencies like:
|
4
|
+
- Programming language version
|
5
|
+
- Framework version
|
6
|
+
- Package version
|
7
|
+
- Environment variables
|
4
8
|
|
5
|
-
|
9
|
+
## Features
|
6
10
|
|
11
|
+
- Parallel test your code against multiple versions of dependencies combinations.
|
12
|
+
- Test your code against a specific dependencies combination.
|
13
|
+
- Choose any docker image you like for each job.
|
14
|
+
- Easy to use CLI to speed up your development efficiency
|
7
15
|
## Installation
|
8
16
|
|
9
17
|
Add this line to your application's Gemfile:
|
@@ -20,9 +28,86 @@ Or install it yourself as:
|
|
20
28
|
|
21
29
|
$ gem install matrixeval
|
22
30
|
|
31
|
+
### Plugins
|
32
|
+
|
33
|
+
If you plan to test ruby code, you can use [matrixeval-ruby](https://github.com/MatrixEval/matrixeval-ruby) directly.
|
34
|
+
|
23
35
|
## Usage
|
24
36
|
|
25
|
-
|
37
|
+
Initialize
|
38
|
+
|
39
|
+
```bash
|
40
|
+
matrixeval init
|
41
|
+
```
|
42
|
+
|
43
|
+
Customize `matrixeval.yml` file and run commands like:
|
44
|
+
|
45
|
+
```bash
|
46
|
+
matrixeval --all COMMAND
|
47
|
+
matrixeval --PROGRAMMING_LANGUAGE LANGUAGE_VERSION --PACKAGE_NAME PACKAGE_VERSION COMMAND OPTIONS
|
48
|
+
matrixeval bash
|
49
|
+
```
|
50
|
+
Run `matrixeval --help` for more details
|
51
|
+
|
52
|
+
### Configuration Example
|
53
|
+
|
54
|
+
Here is the configuration file `matrixeval.yml` which will auto created by `matrixeval init`
|
55
|
+
|
56
|
+
```yaml
|
57
|
+
version: 0.4
|
58
|
+
project_name: REPLACE_ME
|
59
|
+
parallel_workers: number_of_processors
|
60
|
+
# commands:
|
61
|
+
# - ps
|
62
|
+
# - top
|
63
|
+
# - an_additional_command
|
64
|
+
# mounts:
|
65
|
+
# - /a/path/need/to/mount:/a/path/mount/to
|
66
|
+
matrix:
|
67
|
+
# YOUR_PROGRAMMING_LANGUAGE_NAME:
|
68
|
+
# main: true
|
69
|
+
# variants:
|
70
|
+
# - key: LANGUAGE_VERSION_1
|
71
|
+
# default: true
|
72
|
+
# container:
|
73
|
+
# image: LANGUAGE_DOCKER_NAME_1
|
74
|
+
# - key: LANGUAGE_VERSION_2
|
75
|
+
# container:
|
76
|
+
# image: LANGUAGE_DOCKER_NAME_2
|
77
|
+
# env:
|
78
|
+
# AN_ENV_KEY: ENV_VALUE
|
79
|
+
# mounts:
|
80
|
+
# - /a/path/need/to/mount:/a/path/mount/to
|
81
|
+
|
82
|
+
# another:
|
83
|
+
# variants:
|
84
|
+
# - key: key1
|
85
|
+
# default: true
|
86
|
+
# env:
|
87
|
+
# ENV_KEY: 1
|
88
|
+
# - key: key2
|
89
|
+
# env:
|
90
|
+
# ENV_KEY: 2
|
91
|
+
|
92
|
+
exclude:
|
93
|
+
# - YOUR_PROGRAMMING_LANGUAGE_NAME: LANGUAGE_VERSION_1
|
94
|
+
# another: key1
|
95
|
+
|
96
|
+
docker-compose-extend:
|
97
|
+
# services:
|
98
|
+
# postgres:
|
99
|
+
# image: postgres:12.8
|
100
|
+
# volumes:
|
101
|
+
# - postgres12:/var/lib/postgresql/data
|
102
|
+
# environment:
|
103
|
+
# POSTGRES_HOST_AUTH_METHOD: trust
|
104
|
+
|
105
|
+
# redis:
|
106
|
+
# image: redis:6.2-alpine
|
107
|
+
|
108
|
+
# volumes:
|
109
|
+
# postgres12:
|
110
|
+
```
|
26
111
|
|
27
112
|
## Development
|
28
113
|
|
@@ -32,7 +117,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
117
|
|
33
118
|
## Contributing
|
34
119
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
120
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/matrixeval/matrixeval. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/matrixeval/blob/main/CODE_OF_CONDUCT.md).
|
36
121
|
|
37
122
|
## License
|
38
123
|
|
@@ -40,4 +125,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
40
125
|
|
41
126
|
## Code of Conduct
|
42
127
|
|
43
|
-
Everyone interacting in the Matrixeval project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/
|
128
|
+
Everyone interacting in the Matrixeval::Ruby project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/matrixeval/matrixeval/blob/main/CODE_OF_CONDUCT.md).
|
data/Rakefile
CHANGED
data/bin/test
ADDED
data/exe/matrixeval
ADDED
data/exe/meval
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
module Matrixeval
|
2
|
+
class CommandLine
|
3
|
+
class ParseContextArguments
|
4
|
+
class << self
|
5
|
+
def call(context_arguments)
|
6
|
+
new(context_arguments).call
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :context_arguments, :options
|
11
|
+
|
12
|
+
def initialize(context_arguments)
|
13
|
+
@context_arguments = context_arguments
|
14
|
+
@options = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
parse!
|
19
|
+
options
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def parse!
|
25
|
+
OptionParser.new do |opts|
|
26
|
+
opts.version = Config.target.version
|
27
|
+
opts.program_name = ""
|
28
|
+
opts.banner = <<~USAGE
|
29
|
+
Usage:
|
30
|
+
matrixeval(meval) [OPTIONS] COMMAND
|
31
|
+
USAGE
|
32
|
+
|
33
|
+
opts.separator ""
|
34
|
+
opts.separator "Options:"
|
35
|
+
|
36
|
+
opts.on "-a", "--all", "# Run the COMMAND against all matrix combinations"
|
37
|
+
|
38
|
+
Config.vectors.each do |vector|
|
39
|
+
# short = "-#{vector.short_key}"
|
40
|
+
long = "--#{vector.key} [VERSION]"
|
41
|
+
desc = [
|
42
|
+
"# Run the COMMAND against a specific #{vector.key} version",
|
43
|
+
"# Options: #{vector.variants.map(&:key).join("/")}",
|
44
|
+
"# Default: #{vector.default_variant.key}",
|
45
|
+
"# Customizable"
|
46
|
+
]
|
47
|
+
opts.separator ""
|
48
|
+
opts.on(long, *desc)
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.separator ""
|
52
|
+
opts.separator "Commands: #{Config.commands.join("/")} (Customizable)"
|
53
|
+
|
54
|
+
opts.separator ""
|
55
|
+
opts.separator "MatrixEval Options:"
|
56
|
+
|
57
|
+
opts.on("-h", "--help", "# Show help") do
|
58
|
+
puts opts.help
|
59
|
+
exit
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on("-v", "--version", "# Show version") do
|
63
|
+
puts opts.version
|
64
|
+
exit
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.separator ""
|
68
|
+
opts.separator "Customizations:"
|
69
|
+
opts.separator " You can customize all options in matrixeval.yml"
|
70
|
+
|
71
|
+
Config.target.cli_example_lines.each do |line|
|
72
|
+
opts.separator line
|
73
|
+
end
|
74
|
+
|
75
|
+
end.parse!(context_arguments, into: options)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Matrixeval
|
2
|
+
class CommandLine
|
3
|
+
class ParseInitArguments
|
4
|
+
class << self
|
5
|
+
def call(arguments)
|
6
|
+
new(arguments).call
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :init_arguments, :options
|
11
|
+
|
12
|
+
def initialize(init_arguments)
|
13
|
+
@init_arguments = init_arguments
|
14
|
+
@options = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
parse!
|
19
|
+
options
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def parse!
|
25
|
+
OptionParser.new do |opts|
|
26
|
+
opts.version = Matrixeval::VERSION
|
27
|
+
opts.program_name = ""
|
28
|
+
opts.banner = <<~USAGE
|
29
|
+
Usage:
|
30
|
+
matrixeval(meval) init [Options]
|
31
|
+
USAGE
|
32
|
+
|
33
|
+
opts.separator ""
|
34
|
+
opts.separator "Options:"
|
35
|
+
opts.on("-t", "--target [TARGET]", *[
|
36
|
+
"# Initialize with a specific target",
|
37
|
+
"# Options: #{Matrixeval.targets.keys}",
|
38
|
+
"# Default: none"
|
39
|
+
])
|
40
|
+
|
41
|
+
opts.on("-h", "--help", "# Show help") do
|
42
|
+
puts opts.help
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
end.parse!(init_arguments, into: options)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative "./command_line/parse_context_arguments"
|
2
|
+
require_relative "./command_line/parse_init_arguments"
|
3
|
+
|
4
|
+
module Matrixeval
|
5
|
+
|
6
|
+
COMMANDS = ['bash', 'dash', 'sh', 'zsh']
|
7
|
+
|
8
|
+
class CommandLine
|
9
|
+
|
10
|
+
attr_reader :argv
|
11
|
+
|
12
|
+
def initialize(argv)
|
13
|
+
@argv = argv
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid?
|
17
|
+
init? ||
|
18
|
+
!context_options.empty? ||
|
19
|
+
!seperator_index.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def init?
|
23
|
+
@argv[0] == 'init'
|
24
|
+
end
|
25
|
+
|
26
|
+
def init_options
|
27
|
+
@init_options ||= ParseInitArguments.call(@argv[1..-1])
|
28
|
+
end
|
29
|
+
|
30
|
+
def all?
|
31
|
+
context_options[:all]
|
32
|
+
end
|
33
|
+
|
34
|
+
def context_options
|
35
|
+
@context_options ||= ParseContextArguments.call(context_arguments)
|
36
|
+
end
|
37
|
+
|
38
|
+
def context_arguments
|
39
|
+
arguments = @argv[0...seperator_index]
|
40
|
+
arguments << "-h" if @argv.empty?
|
41
|
+
arguments
|
42
|
+
end
|
43
|
+
|
44
|
+
def rest_arguments
|
45
|
+
@argv[seperator_index..-1]
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def seperator_index
|
51
|
+
@argv.index do |argument|
|
52
|
+
Config.commands.include?(argument)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Matrixeval
|
4
|
+
class Config
|
5
|
+
class YAML
|
6
|
+
|
7
|
+
class MissingError < StandardError; end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def create_for(target_name)
|
12
|
+
return if File.exist?(path)
|
13
|
+
|
14
|
+
FileUtils.cp(
|
15
|
+
target(target_name).matrixeval_yml_template_path,
|
16
|
+
path
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def path
|
21
|
+
Matrixeval.working_dir.join("matrixeval.yml")
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](key)
|
25
|
+
yaml[key]
|
26
|
+
end
|
27
|
+
|
28
|
+
def yaml
|
29
|
+
raise MissingError unless File.exist?(path)
|
30
|
+
|
31
|
+
::YAML.load File.read(path)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def target(target_name)
|
37
|
+
target_klass(target_name).new
|
38
|
+
end
|
39
|
+
|
40
|
+
def target_klass(target_name)
|
41
|
+
Matrixeval.targets[target_name] || Target
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require_relative "./config/yaml"
|
3
|
+
|
4
|
+
module Matrixeval
|
5
|
+
class Config
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def version
|
9
|
+
YAML["version"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def target_name
|
13
|
+
YAML["target"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def target
|
17
|
+
@target ||= target_klass.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def project_name
|
21
|
+
name = YAML["project_name"]
|
22
|
+
|
23
|
+
if name.nil? || name.strip.empty?
|
24
|
+
raise Error.new('missing project_name')
|
25
|
+
end
|
26
|
+
|
27
|
+
name
|
28
|
+
end
|
29
|
+
|
30
|
+
def vectors
|
31
|
+
@vectors = YAML["matrix"].map do |key, vector_config|
|
32
|
+
Vector.new(key, vector_config)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def main_vector
|
37
|
+
vectors.find(&:main?)
|
38
|
+
end
|
39
|
+
|
40
|
+
def rest_vectors
|
41
|
+
vectors.reject(&:main?)
|
42
|
+
end
|
43
|
+
|
44
|
+
def variant_combinations
|
45
|
+
main_vector_variants.product(*rest_vector_variants_matrix)
|
46
|
+
end
|
47
|
+
|
48
|
+
def main_vector_variants
|
49
|
+
main_vector.variants
|
50
|
+
end
|
51
|
+
|
52
|
+
def rest_vector_variants_matrix
|
53
|
+
rest_vectors.map(&:variants)
|
54
|
+
end
|
55
|
+
|
56
|
+
def exclusions
|
57
|
+
YAML["exclude"] || []
|
58
|
+
end
|
59
|
+
|
60
|
+
def parallel_workers
|
61
|
+
YAML["parallel_workers"] || "number_of_processors"
|
62
|
+
end
|
63
|
+
|
64
|
+
def commands
|
65
|
+
cmds = YAML["commands"] || []
|
66
|
+
COMMANDS + target.support_commands + cmds
|
67
|
+
end
|
68
|
+
|
69
|
+
def docker_compose_extend_raw
|
70
|
+
DockerCompose::ExtendRaw.new(
|
71
|
+
YAML["docker-compose-extend"] || {}
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def env
|
76
|
+
YAML["env"] || {}
|
77
|
+
end
|
78
|
+
|
79
|
+
def mounts
|
80
|
+
YAML["mounts"] || []
|
81
|
+
end
|
82
|
+
|
83
|
+
def all_mounts
|
84
|
+
mounts + all_variant_mounts
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def all_variant_mounts
|
90
|
+
Config.vectors
|
91
|
+
.map(&:variants).flatten
|
92
|
+
.map(&:mounts).flatten
|
93
|
+
end
|
94
|
+
|
95
|
+
def target_klass
|
96
|
+
Matrixeval.targets[target_name&.to_sym] || Target
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Matrixeval
|
5
|
+
class Context
|
6
|
+
class BuildDockerComposeExtend
|
7
|
+
class << self
|
8
|
+
def call(context)
|
9
|
+
new(context).call
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :context
|
14
|
+
|
15
|
+
def initialize(context)
|
16
|
+
@context = context
|
17
|
+
end
|
18
|
+
|
19
|
+
def matrix_combination_id
|
20
|
+
context.id
|
21
|
+
end
|
22
|
+
|
23
|
+
def call
|
24
|
+
DockerCompose::Extend.new(docker_compose_extend)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def docker_compose_extend
|
30
|
+
JSON.parse(render_erb)
|
31
|
+
end
|
32
|
+
|
33
|
+
def render_erb
|
34
|
+
ERB.new(
|
35
|
+
Config.docker_compose_extend_raw.content
|
36
|
+
).result(binding)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Matrixeval
|
2
|
+
class Context
|
3
|
+
class FindByCommandOptions
|
4
|
+
class << self
|
5
|
+
def call(options)
|
6
|
+
new(options).call
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :options
|
11
|
+
|
12
|
+
def initialize(options)
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
context = Context.all.find do |context|
|
18
|
+
context.main_variant == main_variant &&
|
19
|
+
context.rest_variants == rest_variants
|
20
|
+
end
|
21
|
+
|
22
|
+
raise Error.new("Can't find a corresponding matrix") if context.nil?
|
23
|
+
|
24
|
+
context
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def main_variant
|
30
|
+
dig_variant Config.main_vector
|
31
|
+
end
|
32
|
+
|
33
|
+
def rest_variants
|
34
|
+
Config.rest_vectors.map do |vector|
|
35
|
+
dig_variant vector
|
36
|
+
end.sort do |v1, v2|
|
37
|
+
v1.id <=> v2.id
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def dig_variant(vector)
|
42
|
+
if option_key?(vector.key)
|
43
|
+
find_variant(vector)
|
44
|
+
else
|
45
|
+
vector.default_variant
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def find_variant(vector)
|
50
|
+
vector.variants.find do |variant|
|
51
|
+
option(vector.key) == variant.key
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def option(key)
|
56
|
+
options[key.to_sym] || options[key.to_s]
|
57
|
+
end
|
58
|
+
|
59
|
+
def option_key?(key)
|
60
|
+
options.key?(key.to_sym) || options.key?(key.to_s)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|