highway 0.0.1 → 1.0.1
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.
- checksums.yaml +7 -0
- data/lib/highway.rb +8 -4
- data/lib/highway/compiler/analyze/analyzer.rb +249 -0
- data/lib/highway/compiler/analyze/tree/root.rb +95 -0
- data/lib/highway/compiler/analyze/tree/segments/text.rb +36 -0
- data/lib/highway/compiler/analyze/tree/segments/variable.rb +43 -0
- data/lib/highway/compiler/analyze/tree/stage.rb +48 -0
- data/lib/highway/compiler/analyze/tree/step.rb +69 -0
- data/lib/highway/compiler/analyze/tree/values/array.rb +45 -0
- data/lib/highway/compiler/analyze/tree/values/base.rb +67 -0
- data/lib/highway/compiler/analyze/tree/values/hash.rb +45 -0
- data/lib/highway/compiler/analyze/tree/values/primitive.rb +43 -0
- data/lib/highway/compiler/analyze/tree/variable.rb +48 -0
- data/lib/highway/compiler/build/builder.rb +154 -0
- data/lib/highway/compiler/build/output/invocation.rb +70 -0
- data/lib/highway/compiler/build/output/manifest.rb +52 -0
- data/lib/highway/compiler/parse/parser.rb +92 -0
- data/lib/highway/compiler/parse/tree/root.rb +73 -0
- data/lib/highway/compiler/parse/tree/step.rb +62 -0
- data/lib/highway/compiler/parse/tree/variable.rb +48 -0
- data/lib/highway/compiler/parse/versions/v1.rb +110 -0
- data/lib/highway/compiler/suite.rb +56 -0
- data/lib/highway/environment.rb +282 -0
- data/lib/highway/fastlane/action.rb +67 -0
- data/lib/highway/interface.rb +135 -0
- data/lib/highway/main.rb +173 -0
- data/lib/highway/runtime/context.rb +229 -0
- data/lib/highway/runtime/report.rb +80 -0
- data/lib/highway/runtime/runner.rb +286 -0
- data/lib/highway/steps/infrastructure.rb +20 -0
- data/lib/highway/steps/library/action.rb +42 -0
- data/lib/highway/steps/library/appcenter.rb +106 -0
- data/lib/highway/steps/library/appstore.rb +137 -0
- data/lib/highway/steps/library/carthage.rb +67 -0
- data/lib/highway/steps/library/cocoapods.rb +76 -0
- data/lib/highway/steps/library/copy_artifacts.rb +36 -0
- data/lib/highway/steps/library/lane.rb +42 -0
- data/lib/highway/steps/library/sh.rb +36 -0
- data/lib/highway/steps/library/slack.rb +381 -0
- data/lib/highway/steps/library/testflight.rb +105 -0
- data/lib/highway/steps/library/xcode_archive.rb +162 -0
- data/lib/highway/steps/library/xcode_test.rb +264 -0
- data/lib/highway/steps/parameters/base.rb +52 -0
- data/lib/highway/steps/parameters/compound.rb +141 -0
- data/lib/highway/steps/parameters/single.rb +74 -0
- data/lib/highway/steps/registry.rb +92 -0
- data/lib/highway/steps/step.rb +52 -0
- data/lib/highway/steps/types/any.rb +65 -0
- data/lib/highway/steps/types/anyof.rb +64 -0
- data/lib/highway/steps/types/array.rb +44 -0
- data/lib/highway/steps/types/bool.rb +36 -0
- data/lib/highway/steps/types/enum.rb +44 -0
- data/lib/highway/steps/types/hash.rb +45 -0
- data/lib/highway/steps/types/number.rb +38 -0
- data/lib/highway/steps/types/set.rb +39 -0
- data/lib/highway/steps/types/string.rb +47 -0
- data/lib/highway/steps/types/url.rb +35 -0
- data/lib/highway/utilities.rb +51 -0
- data/lib/highway/version.rb +9 -1
- metadata +194 -22
- data/.gitignore +0 -4
- data/Gemfile +0 -4
- data/Rakefile +0 -1
- data/highway.gemspec +0 -24
@@ -0,0 +1,52 @@
|
|
1
|
+
#
|
2
|
+
# base.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
module Highway
|
7
|
+
module Steps
|
8
|
+
module Parameters
|
9
|
+
|
10
|
+
# This class is a base abstract class for other classes in this
|
11
|
+
# module. You should not use it directly.
|
12
|
+
class Base
|
13
|
+
|
14
|
+
public
|
15
|
+
|
16
|
+
# Initialize an instance.
|
17
|
+
def initialize()
|
18
|
+
raise NotImplementedError.new("You must not call `#{__method__.to_s}` on `#{self.class.to_s}`.")
|
19
|
+
end
|
20
|
+
|
21
|
+
# Name of the parameter.
|
22
|
+
#
|
23
|
+
# @return [String]
|
24
|
+
attr_reader :name
|
25
|
+
|
26
|
+
# Whether the parameter is required.
|
27
|
+
#
|
28
|
+
# @return [Boolean]
|
29
|
+
def is_required?
|
30
|
+
@required
|
31
|
+
end
|
32
|
+
|
33
|
+
# Typecheck and validate a value of the parameter.
|
34
|
+
#
|
35
|
+
# This method returns typechecked, coerced and validated value or raises
|
36
|
+
# a fatal error if value has invalid type, can't be coerced or is
|
37
|
+
# othweriwse invalid.
|
38
|
+
#
|
39
|
+
# @param value [Object] A value.
|
40
|
+
# @param interface [Highway::Interface] An interface instance.
|
41
|
+
# @param keypath [Array<String>] A keypath to be used for debugging purposes.
|
42
|
+
#
|
43
|
+
# @return [Object]
|
44
|
+
def typecheck_and_validate(value, interface:, keypath: [])
|
45
|
+
raise NotImplementedError.new("You must override `#{__method__.to_s}` in `#{self.class.to_s}`.")
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
#
|
2
|
+
# compound.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "highway/steps/parameters/base"
|
7
|
+
|
8
|
+
module Highway
|
9
|
+
module Steps
|
10
|
+
module Parameters
|
11
|
+
|
12
|
+
# This class is used in step definition classes to represent a compound
|
13
|
+
# parameter of a step that consists of other parameters.
|
14
|
+
class Compound < Parameters::Base
|
15
|
+
|
16
|
+
# Initialize an instance.
|
17
|
+
#
|
18
|
+
# @param name [String] Name of the parameter.
|
19
|
+
# @param required [Boolean] Whether parametr is required.
|
20
|
+
# @param defaults [Boolean] Whether to construct default value from child parameters.
|
21
|
+
# @param children [Array<Highway::Steps::Parameters::*>] Child parameters.
|
22
|
+
def initialize(name:, required:, defaults: false, children:)
|
23
|
+
@name = name
|
24
|
+
@required = required
|
25
|
+
@defaults = defaults
|
26
|
+
@children = children
|
27
|
+
end
|
28
|
+
|
29
|
+
# Child parameters.
|
30
|
+
#
|
31
|
+
# @return [Array<Highway::Steps::Parameters::*>]
|
32
|
+
attr_reader :children
|
33
|
+
|
34
|
+
# Find a child parameter definition by name.
|
35
|
+
#
|
36
|
+
# @param name [String] Name of the parameter
|
37
|
+
#
|
38
|
+
# @return [Highway::Steps::Parameters::*]
|
39
|
+
def find_child_for_name(name)
|
40
|
+
@children.find { |child| child.name == name }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Default value of the parameter.
|
44
|
+
#
|
45
|
+
# @return [Hash, nil]
|
46
|
+
def default
|
47
|
+
if @defaults
|
48
|
+
Utilities::hash_map(@children) { |child| [child.name, child.default] }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Typecheck and validate a value of the parameter.
|
53
|
+
#
|
54
|
+
# This method returns typechecked, coerced and validated value or raises
|
55
|
+
# a fatal error if value has invalid type, can't be coerced or is
|
56
|
+
# othweriwse invalid.
|
57
|
+
#
|
58
|
+
# @param value [Object] A value.
|
59
|
+
# @param interface [Highway::Interface] An interface instance.
|
60
|
+
# @param keypath [Array<String>] A keypath to be used for debugging purposes.
|
61
|
+
#
|
62
|
+
# @return [Object]
|
63
|
+
def typecheck_and_validate(values, interface:, keypath: [])
|
64
|
+
|
65
|
+
unless values.is_a?(Hash)
|
66
|
+
interface.fatal!("Invalid type of value for parameter: '#{Utilities::keypath_to_s(keypath)}'.")
|
67
|
+
end
|
68
|
+
|
69
|
+
@children.each { |child|
|
70
|
+
if child.is_required? && !values.keys.include?(child.name) && child.default == nil
|
71
|
+
interface.fatal!("Missing value for required parameter: '#{Utilities::keypath_to_s(keypath + [child.name])}'.")
|
72
|
+
end
|
73
|
+
}
|
74
|
+
|
75
|
+
values.keys.each { |name|
|
76
|
+
unless find_child_for_name(name)
|
77
|
+
expected = @children.map { |child| "'#{child.name}'" }.join(", ")
|
78
|
+
interface.fatal!("Unknown parameter: '#{Utilities::keypath_to_s(keypath + [name])}'. Expected one of: [#{expected}].")
|
79
|
+
end
|
80
|
+
}
|
81
|
+
|
82
|
+
typechecked = Utilities::hash_map(values) { |name, value|
|
83
|
+
child = find_child_for_name(name)
|
84
|
+
[name, child.typecheck_and_validate(value, interface: interface, keypath: keypath + [name])]
|
85
|
+
}
|
86
|
+
|
87
|
+
(default || {}).merge(typechecked)
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
# Typecheck and prevalidate a value of the parameter. This method is
|
92
|
+
# used during the initial prevalidation of step parameter values before
|
93
|
+
# evaluating all the values.
|
94
|
+
#
|
95
|
+
# This method works in a similar way to `typecheck_and_validate` with
|
96
|
+
# one difference: if it encounters a single parameter whose value
|
97
|
+
# is (or contains) `:ignore` symbol, it doesn't perform any typechecking
|
98
|
+
# and validation on it. That way, the caller can specify which values
|
99
|
+
# should be fully validated and which should be ignored.
|
100
|
+
#
|
101
|
+
# @param value [Object] A value.
|
102
|
+
# @param interface [Highway::Interface] An interface instance.
|
103
|
+
# @param keypath [Array<String>] A keypath to be used for debugging purposes.
|
104
|
+
#
|
105
|
+
# @return [Void]
|
106
|
+
def typecheck_and_prevalidate(values, interface:, keypath: [])
|
107
|
+
|
108
|
+
unless values.is_a?(Hash)
|
109
|
+
interface.fatal!("Invalid type of value for parameter: '#{Utilities::keypath_to_s(keypath)}'.")
|
110
|
+
end
|
111
|
+
|
112
|
+
@children.each { |child|
|
113
|
+
if child.is_required? && !values.keys.include?(child.name) && child.default == nil
|
114
|
+
interface.fatal!("Missing value for required parameter: '#{Utilities::keypath_to_s(keypath + [child.name])}'.")
|
115
|
+
end
|
116
|
+
}
|
117
|
+
|
118
|
+
values.keys.each { |name|
|
119
|
+
unless find_child_for_name(name)
|
120
|
+
expected = @children.map { |child| "'#{child.name}'" }.join(", ")
|
121
|
+
interface.fatal!("Unknown parameter: '#{Utilities::keypath_to_s(keypath + [name])}'. Expected one of: [#{expected}].")
|
122
|
+
end
|
123
|
+
}
|
124
|
+
|
125
|
+
values.each_pair { |name, value|
|
126
|
+
if (child = find_child_for_name(name))
|
127
|
+
if child.is_a?(Parameters::Compound)
|
128
|
+
child.typecheck_and_prevalidate(value, interface: interface, keypath: keypath + [name])
|
129
|
+
elsif !Utilities::recursive_include?(value, :ignore)
|
130
|
+
child.typecheck_and_validate(value, interface: interface, keypath: keypath + [name])
|
131
|
+
end
|
132
|
+
end
|
133
|
+
}
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#
|
2
|
+
# single.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "highway/steps/parameters/base"
|
7
|
+
|
8
|
+
module Highway
|
9
|
+
module Steps
|
10
|
+
module Parameters
|
11
|
+
|
12
|
+
# This class is used in step definition classes to represent a single
|
13
|
+
# parameter of a step.
|
14
|
+
class Single < Parameters::Base
|
15
|
+
|
16
|
+
public
|
17
|
+
|
18
|
+
# Initialize an instance.
|
19
|
+
#
|
20
|
+
# @param name [String] Name of the parameter.
|
21
|
+
# @param type [Highway::Steps::Types::*] Type of the parameter.
|
22
|
+
# @param required [Boolean] Whether parametr is required.
|
23
|
+
# @param default [Object, nil] Default value of the parameter.
|
24
|
+
def initialize(name:, type:, required:, default: nil)
|
25
|
+
@name = name
|
26
|
+
@required = required
|
27
|
+
@type = type
|
28
|
+
@default = default
|
29
|
+
assert_default_value_valid()
|
30
|
+
end
|
31
|
+
|
32
|
+
# Type of the parameter.
|
33
|
+
#
|
34
|
+
# @return [Highway::Steps::Types::*]
|
35
|
+
attr_reader :type
|
36
|
+
|
37
|
+
# Default value of the parameter.
|
38
|
+
#
|
39
|
+
# @return [Object, nil]
|
40
|
+
attr_reader :default
|
41
|
+
|
42
|
+
# Typecheck and validate a value of the parameter.
|
43
|
+
#
|
44
|
+
# This method returns typechecked, coerced and validated value or raises
|
45
|
+
# a fatal error if value has invalid type, can't be coerced or is
|
46
|
+
# othweriwse invalid.
|
47
|
+
#
|
48
|
+
# @param value [Object] A value.
|
49
|
+
# @param interface [Highway::Interface] An interface instance.
|
50
|
+
# @param keypath [Array<String>] A keypath to be used for debugging purposes.
|
51
|
+
#
|
52
|
+
# @return [Object]
|
53
|
+
def typecheck_and_validate(value, interface:, keypath: [])
|
54
|
+
typechecked = @type.typecheck_and_validate(value)
|
55
|
+
if typechecked != nil
|
56
|
+
typechecked
|
57
|
+
else
|
58
|
+
interface.fatal!("Invalid value: '#{value}' for parameter: '#{Utilities::keypath_to_s(keypath)}'.")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def assert_default_value_valid()
|
65
|
+
if @default != nil && @type.typecheck_and_validate(@default) == nil
|
66
|
+
raise ArgumentError.new("Default value: '#{@default}' is not a valid value for parameter: '#{@name}'.")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#
|
2
|
+
# registry.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "highway/steps/step"
|
7
|
+
|
8
|
+
module Highway
|
9
|
+
module Steps
|
10
|
+
|
11
|
+
# This class is responsible for keeping track of available steps.
|
12
|
+
class Registry
|
13
|
+
|
14
|
+
public
|
15
|
+
|
16
|
+
# Initialize an instance.
|
17
|
+
def initialize()
|
18
|
+
@classes = Set.new()
|
19
|
+
end
|
20
|
+
|
21
|
+
# Initialize an instance and automatically load all steps in the default
|
22
|
+
# library.
|
23
|
+
#
|
24
|
+
# @return [Highway::Steps::Registry]
|
25
|
+
def self.new_and_load_default_library()
|
26
|
+
|
27
|
+
registry = self.new()
|
28
|
+
|
29
|
+
Dir[File.expand_path('library/*.rb', File.dirname(__FILE__))].each do |file|
|
30
|
+
require(file)
|
31
|
+
end
|
32
|
+
|
33
|
+
unless Highway::Steps.const_defined?("Library")
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
Highway::Steps::Library.constants.each do |step_symbol|
|
38
|
+
step_class = Highway::Steps::Library.const_get(step_symbol)
|
39
|
+
if step_class_valid?(step_class)
|
40
|
+
registry.register(step_class)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
registry
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add a new step definition class to the registry. Is it is already
|
49
|
+
# registered, this does nothing.
|
50
|
+
#
|
51
|
+
# @param step_class [Class] The step definition class.
|
52
|
+
#
|
53
|
+
# @raise [ArgumentError] If trying to register an invalid step class.
|
54
|
+
#
|
55
|
+
# @return [Void]
|
56
|
+
def register(step_class)
|
57
|
+
if self.class.step_class_valid?(step_class)
|
58
|
+
@classes.add(step_class)
|
59
|
+
else
|
60
|
+
raise ArgumentError.new("Step class `#{step_class}` is invalid.")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Remove a step definition class from the registry. If it is not
|
65
|
+
# registered, this does nothing.
|
66
|
+
#
|
67
|
+
# @param step_class [Class] The step definition class.
|
68
|
+
#
|
69
|
+
# @return [Void]
|
70
|
+
def unregister(step_class)
|
71
|
+
@classes.remove(step_class)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Get a step definition class by its name.
|
75
|
+
#
|
76
|
+
# @param step_name [String] The step name.
|
77
|
+
#
|
78
|
+
# @return [Class, nil]
|
79
|
+
def get_by_name(step_name)
|
80
|
+
@classes.find { |step_class| step_class.name == step_name }
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def self.step_class_valid?(step_class)
|
86
|
+
step_class.is_a?(Class) && step_class < Highway::Steps::Step
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#
|
2
|
+
# step.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require "highway/steps/parameters/compound"
|
7
|
+
|
8
|
+
module Highway
|
9
|
+
module Steps
|
10
|
+
|
11
|
+
# This class serves as a base class for all step definition classes. It
|
12
|
+
# contains a common API and some useful utilities.
|
13
|
+
class Step
|
14
|
+
|
15
|
+
public
|
16
|
+
|
17
|
+
# Name of the step as it appears in configuration file.
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
def self.name
|
21
|
+
raise NotImplementedError.new("You must override `#{__method__.to_s}` in `#{self.class.to_s}`.")
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parameters that this step recognizes.
|
25
|
+
#
|
26
|
+
# @return [Array<Highway::Steps::Parameters::*>]
|
27
|
+
def self.parameters
|
28
|
+
raise NotImplementedError.new("You must override `#{__method__.to_s}` in `#{self.class.to_s}`.")
|
29
|
+
end
|
30
|
+
|
31
|
+
# The root parameter that nests all parameters of the step.
|
32
|
+
#
|
33
|
+
# @return [Highway::Steps::Parameters::Compound]
|
34
|
+
def self.root_parameter
|
35
|
+
return Parameters::Compound.new(name: "root", required: true, defaults: true, children: parameters)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Run the step in given context containing inputs and Fastlane runner.
|
39
|
+
#
|
40
|
+
# @param parameters [Hash] Parameters of the step.
|
41
|
+
# @param context [Highway::Runtime::Context] The runtime context.
|
42
|
+
# @param report [Highway::Runtime::Report] The current runtime report.
|
43
|
+
#
|
44
|
+
# @return [Void]
|
45
|
+
def self.run(parameters:, context:, report:)
|
46
|
+
raise NotImplementedError.new("You must override `#{__method__.to_s}` in `#{self.class.to_s}`.")
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#
|
2
|
+
# any.rb
|
3
|
+
# Copyright © 2019 Netguru S.A. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
module Highway
|
7
|
+
module Steps
|
8
|
+
module Types
|
9
|
+
|
10
|
+
# This class represents any parameter type. It can be used in parameters
|
11
|
+
# which should not perform any type checking.
|
12
|
+
class Any
|
13
|
+
|
14
|
+
public
|
15
|
+
|
16
|
+
# Initialize an instance.
|
17
|
+
#
|
18
|
+
# @param validate [Proc] A custom value validation block.
|
19
|
+
def initialize(validate: nil)
|
20
|
+
@validate = validate
|
21
|
+
end
|
22
|
+
|
23
|
+
# Typecheck and coerce a value if possible.
|
24
|
+
#
|
25
|
+
# This method returns a typechecked and coerced value or `nil` if value
|
26
|
+
# has invalid type and can't be coerced.
|
27
|
+
#
|
28
|
+
# @param value [Object] A value.
|
29
|
+
#
|
30
|
+
# @return [Object, nil]
|
31
|
+
def typecheck(value)
|
32
|
+
value
|
33
|
+
end
|
34
|
+
|
35
|
+
# Validate the typechecked value against a custom validation block.
|
36
|
+
#
|
37
|
+
# This method returns `true` if value is valid or `false` if value is
|
38
|
+
# invalid.
|
39
|
+
#
|
40
|
+
# @param value [Object] A value.
|
41
|
+
#
|
42
|
+
# @return [Boolean]
|
43
|
+
def validate(value)
|
44
|
+
return true if @validate == nil
|
45
|
+
@validate.call(value)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Typecheck and validate the value at the same time.
|
49
|
+
#
|
50
|
+
# This method returns typechecked, coerced and validated value or `nil`
|
51
|
+
# if value has invalid type, can't be coerced or is invalid.
|
52
|
+
#
|
53
|
+
# @param value [Object] A value.
|
54
|
+
#
|
55
|
+
# @return [Object, nil]
|
56
|
+
def typecheck_and_validate(value)
|
57
|
+
typechecked = typecheck(value)
|
58
|
+
typechecked if !typechecked.nil? && validate(typechecked)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|