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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2f92ab631d36382a3fe2796928681d6c0a7eddaeea0d74b7165647fa3166c81
4
- data.tar.gz: c45c4f0d82a430846049f07ac2a659ded7cc3cb054512823beea37af09175e1b
3
+ metadata.gz: f340adc04181b907e790e3028bb80f1de0d4ea91f1ec4477087d7b2631bde065
4
+ data.tar.gz: e6845d5bcf308d0974b9241420ef3a1dbc8a3fa544bbad43543cae7f6079203e
5
5
  SHA512:
6
- metadata.gz: c696eaf66bb2daba16dc82221f47a3f0fab5362dc6883c9d72656e690690810491fce0ed2d63b4e30cb4152c0dad940156d9c4754cc2c86d88c4e66acc68f6c9
7
- data.tar.gz: 9476247c48c5028eaac4a2e983e6e11c55d7233a23a01e5618ecd874b3dba5e1da7c1f08f4576af9f7c2f1532e370e271df8366c615582051b7339df73a07d02
6
+ metadata.gz: 9b733e83ca820507963da27358d419154d1023ae60e821121935dc116cc3880123e1c1fb8af5b0355d5f6d854b8e1e0f42c4823408b5308008a3ea2e74fd0e21
7
+ data.tar.gz: af5163f1de81ea41d3882f1930f741a9434dd88c181743820d63d837ed19eacf76651644d85310d276c5ca82ff89094fb88327675a24567caadf7fbcd5ccece0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2022-02-03
3
+ # [0.4.0] - 2022-02-26
4
+
5
+ - Test your code against different versions of dependencies
6
+ - Support 3rd plugin
7
+ # [0.1.0] - 2022-02-09
4
8
 
5
9
  - Initial release
data/Gemfile CHANGED
@@ -8,3 +8,7 @@ gemspec
8
8
  gem "rake", "~> 13.0"
9
9
 
10
10
  gem "minitest", "~> 5.0"
11
+
12
+ gem "minitest-focus"
13
+ gem "byebug"
14
+ gem "mocha"
data/README.md CHANGED
@@ -1,9 +1,17 @@
1
- # Matrixeval
1
+ # MatrixEval
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/matrixeval`. To experiment with that code, run `bin/console` for an interactive prompt.
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
- TODO: Delete this and the text above, and describe your gem
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
- TODO: Write usage instructions here
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/[USERNAME]/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).
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/[USERNAME]/matrixeval/blob/main/CODE_OF_CONDUCT.md).
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
@@ -6,7 +6,7 @@ require "rake/testtask"
6
6
  Rake::TestTask.new(:test) do |t|
7
7
  t.libs << "test"
8
8
  t.libs << "lib"
9
- t.test_files = FileList["test/**/*_test.rb"]
9
+ t.test_files = FileList["test/matrixeval/**/*_test.rb"]
10
10
  end
11
11
 
12
12
  task default: :test
data/bin/test ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ system("ruby -Ilib:test #{ARGV.join(" ")}")
data/exe/matrixeval ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'matrixeval'
4
+
5
+ Matrixeval.start(ARGV)
data/exe/meval ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'matrixeval'
4
+
5
+ Matrixeval.start(ARGV)
@@ -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,13 @@
1
+ module Matrixeval
2
+ class Container
3
+
4
+ attr_reader :image, :env
5
+
6
+ def initialize(options)
7
+ options ||= {}
8
+ @image = options["image"]
9
+ @env = options["env"] || {}
10
+ end
11
+
12
+ end
13
+ 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