pantograph 0.1.0
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/.yardopts +1 -0
- data/LICENSE +21 -0
- data/README.md +197 -0
- data/bin/bin-proxy +19 -0
- data/bin/pantograph +23 -0
- data/pantograph/README.md +11 -0
- data/pantograph/lib/assets/ActionDetails.md.erb +106 -0
- data/pantograph/lib/assets/Actions.md.erb +43 -0
- data/pantograph/lib/assets/DefaultPantfileTemplate +20 -0
- data/pantograph/lib/assets/completions/completion.bash +23 -0
- data/pantograph/lib/assets/completions/completion.fish +39 -0
- data/pantograph/lib/assets/completions/completion.sh +12 -0
- data/pantograph/lib/assets/completions/completion.zsh +23 -0
- data/pantograph/lib/assets/custom_action_template.rb +80 -0
- data/pantograph/lib/assets/report_template.xml.erb +15 -0
- data/pantograph/lib/pantograph/action.rb +194 -0
- data/pantograph/lib/pantograph/action_collector.rb +35 -0
- data/pantograph/lib/pantograph/actions/README.md +3 -0
- data/pantograph/lib/pantograph/actions/actions_helper.rb +166 -0
- data/pantograph/lib/pantograph/actions/add_extra_platforms.rb +45 -0
- data/pantograph/lib/pantograph/actions/artifactory.rb +157 -0
- data/pantograph/lib/pantograph/actions/bundle_install.rb +156 -0
- data/pantograph/lib/pantograph/actions/changelog_from_git_commits.rb +197 -0
- data/pantograph/lib/pantograph/actions/clipboard.rb +52 -0
- data/pantograph/lib/pantograph/actions/cloc.rb +89 -0
- data/pantograph/lib/pantograph/actions/create_pull_request.rb +190 -0
- data/pantograph/lib/pantograph/actions/danger.rb +131 -0
- data/pantograph/lib/pantograph/actions/debug.rb +32 -0
- data/pantograph/lib/pantograph/actions/default_platform.rb +47 -0
- data/pantograph/lib/pantograph/actions/download.rb +76 -0
- data/pantograph/lib/pantograph/actions/echo.rb +14 -0
- data/pantograph/lib/pantograph/actions/ensure_bundle_exec.rb +59 -0
- data/pantograph/lib/pantograph/actions/ensure_env_vars.rb +58 -0
- data/pantograph/lib/pantograph/actions/ensure_git_branch.rb +69 -0
- data/pantograph/lib/pantograph/actions/ensure_git_status_clean.rb +81 -0
- data/pantograph/lib/pantograph/actions/erb.rb +88 -0
- data/pantograph/lib/pantograph/actions/get_build_number_repository.rb +120 -0
- data/pantograph/lib/pantograph/actions/get_github_release.rb +163 -0
- data/pantograph/lib/pantograph/actions/git_add.rb +93 -0
- data/pantograph/lib/pantograph/actions/git_branch.rb +58 -0
- data/pantograph/lib/pantograph/actions/git_commit.rb +80 -0
- data/pantograph/lib/pantograph/actions/git_pull.rb +53 -0
- data/pantograph/lib/pantograph/actions/git_submodule_update.rb +52 -0
- data/pantograph/lib/pantograph/actions/git_tag_exists.rb +74 -0
- data/pantograph/lib/pantograph/actions/github_api.rb +262 -0
- data/pantograph/lib/pantograph/actions/gradle.rb +278 -0
- data/pantograph/lib/pantograph/actions/import.rb +49 -0
- data/pantograph/lib/pantograph/actions/import_from_git.rb +71 -0
- data/pantograph/lib/pantograph/actions/is_ci.rb +51 -0
- data/pantograph/lib/pantograph/actions/jira.rb +115 -0
- data/pantograph/lib/pantograph/actions/lane_context.rb +60 -0
- data/pantograph/lib/pantograph/actions/last_git_commit.rb +58 -0
- data/pantograph/lib/pantograph/actions/last_git_tag.rb +51 -0
- data/pantograph/lib/pantograph/actions/make_changelog_from_jenkins.rb +81 -0
- data/pantograph/lib/pantograph/actions/min_pantograph_version.rb +57 -0
- data/pantograph/lib/pantograph/actions/nexus_upload.rb +230 -0
- data/pantograph/lib/pantograph/actions/notification.rb +75 -0
- data/pantograph/lib/pantograph/actions/number_of_commits.rb +75 -0
- data/pantograph/lib/pantograph/actions/opt_out_usage.rb +40 -0
- data/pantograph/lib/pantograph/actions/pantograph_version.rb +15 -0
- data/pantograph/lib/pantograph/actions/println.rb +14 -0
- data/pantograph/lib/pantograph/actions/prompt.rb +119 -0
- data/pantograph/lib/pantograph/actions/push_git_tags.rb +76 -0
- data/pantograph/lib/pantograph/actions/push_to_git_remote.rb +127 -0
- data/pantograph/lib/pantograph/actions/puts.rb +68 -0
- data/pantograph/lib/pantograph/actions/reset_git_repo.rb +121 -0
- data/pantograph/lib/pantograph/actions/rocket.rb +83 -0
- data/pantograph/lib/pantograph/actions/rsync.rb +74 -0
- data/pantograph/lib/pantograph/actions/ruby_version.rb +56 -0
- data/pantograph/lib/pantograph/actions/say.rb +56 -0
- data/pantograph/lib/pantograph/actions/scp.rb +114 -0
- data/pantograph/lib/pantograph/actions/set_github_release.rb +274 -0
- data/pantograph/lib/pantograph/actions/sh.rb +71 -0
- data/pantograph/lib/pantograph/actions/skip_docs.rb +52 -0
- data/pantograph/lib/pantograph/actions/slack.rb +288 -0
- data/pantograph/lib/pantograph/actions/sonar.rb +156 -0
- data/pantograph/lib/pantograph/actions/ssh.rb +162 -0
- data/pantograph/lib/pantograph/actions/twitter.rb +89 -0
- data/pantograph/lib/pantograph/actions/update_pantograph.rb +177 -0
- data/pantograph/lib/pantograph/actions/zip.rb +120 -0
- data/pantograph/lib/pantograph/auto_complete.rb +82 -0
- data/pantograph/lib/pantograph/boolean.rb +5 -0
- data/pantograph/lib/pantograph/cli_tools_distributor.rb +183 -0
- data/pantograph/lib/pantograph/command_line_handler.rb +43 -0
- data/pantograph/lib/pantograph/commands_generator.rb +344 -0
- data/pantograph/lib/pantograph/configuration_helper.rb +26 -0
- data/pantograph/lib/pantograph/core_ext/bundler_monkey_patch.rb +14 -0
- data/pantograph/lib/pantograph/documentation/actions_list.rb +214 -0
- data/pantograph/lib/pantograph/documentation/docs_generator.rb +95 -0
- data/pantograph/lib/pantograph/documentation/markdown_docs_generator.rb +221 -0
- data/pantograph/lib/pantograph/environment_printer.rb +282 -0
- data/pantograph/lib/pantograph/erb_template_helper.rb +30 -0
- data/pantograph/lib/pantograph/features.rb +4 -0
- data/pantograph/lib/pantograph/helper/README.md +29 -0
- data/pantograph/lib/pantograph/helper/dotenv_helper.rb +50 -0
- data/pantograph/lib/pantograph/helper/gem_helper.rb +26 -0
- data/pantograph/lib/pantograph/helper/git_helper.rb +135 -0
- data/pantograph/lib/pantograph/helper/gradle_helper.rb +62 -0
- data/pantograph/lib/pantograph/helper/sh_helper.rb +134 -0
- data/pantograph/lib/pantograph/junit_generator.rb +27 -0
- data/pantograph/lib/pantograph/lane.rb +97 -0
- data/pantograph/lib/pantograph/lane_list.rb +77 -0
- data/pantograph/lib/pantograph/lane_manager.rb +140 -0
- data/pantograph/lib/pantograph/lane_manager_base.rb +92 -0
- data/pantograph/lib/pantograph/markdown_table_formatter.rb +62 -0
- data/pantograph/lib/pantograph/new_action.rb +47 -0
- data/pantograph/lib/pantograph/one_off.rb +45 -0
- data/pantograph/lib/pantograph/other_action.rb +29 -0
- data/pantograph/lib/pantograph/pant_file.rb +377 -0
- data/pantograph/lib/pantograph/pantograph_require.rb +75 -0
- data/pantograph/lib/pantograph/plugins/plugin_fetcher.rb +55 -0
- data/pantograph/lib/pantograph/plugins/plugin_generator.rb +86 -0
- data/pantograph/lib/pantograph/plugins/plugin_generator_ui.rb +19 -0
- data/pantograph/lib/pantograph/plugins/plugin_info.rb +49 -0
- data/pantograph/lib/pantograph/plugins/plugin_info_collector.rb +159 -0
- data/pantograph/lib/pantograph/plugins/plugin_manager.rb +387 -0
- data/pantograph/lib/pantograph/plugins/plugin_search.rb +46 -0
- data/pantograph/lib/pantograph/plugins/plugin_update_manager.rb +70 -0
- data/pantograph/lib/pantograph/plugins/plugins.rb +12 -0
- data/pantograph/lib/pantograph/plugins/template/%gem_name%.gemspec.erb +35 -0
- data/pantograph/lib/pantograph/plugins/template/.circleci/config.yml +43 -0
- data/pantograph/lib/pantograph/plugins/template/.gitignore +12 -0
- data/pantograph/lib/pantograph/plugins/template/.rspec +5 -0
- data/pantograph/lib/pantograph/plugins/template/.rubocop.yml +179 -0
- data/pantograph/lib/pantograph/plugins/template/.travis.yml +4 -0
- data/pantograph/lib/pantograph/plugins/template/Gemfile +6 -0
- data/pantograph/lib/pantograph/plugins/template/LICENSE.erb +21 -0
- data/pantograph/lib/pantograph/plugins/template/README.md.erb +52 -0
- data/pantograph/lib/pantograph/plugins/template/Rakefile +9 -0
- data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/actions/%plugin_name%_action.rb.erb +47 -0
- data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/helper/%plugin_name%_helper.rb.erb +16 -0
- data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/version.rb.erb +5 -0
- data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%.rb.erb +16 -0
- data/pantograph/lib/pantograph/plugins/template/pantograph/Pantfile.erb +3 -0
- data/pantograph/lib/pantograph/plugins/template/pantograph/Pluginfile.erb +1 -0
- data/pantograph/lib/pantograph/plugins/template/spec/%plugin_name%_action_spec.rb.erb +9 -0
- data/pantograph/lib/pantograph/plugins/template/spec/spec_helper.rb.erb +15 -0
- data/pantograph/lib/pantograph/runner.rb +371 -0
- data/pantograph/lib/pantograph/server/action_command.rb +61 -0
- data/pantograph/lib/pantograph/server/action_command_return.rb +14 -0
- data/pantograph/lib/pantograph/server/command_executor.rb +7 -0
- data/pantograph/lib/pantograph/server/command_parser.rb +36 -0
- data/pantograph/lib/pantograph/server/control_command.rb +23 -0
- data/pantograph/lib/pantograph/server/json_return_value_processor.rb +72 -0
- data/pantograph/lib/pantograph/server/socket_server.rb +232 -0
- data/pantograph/lib/pantograph/server/socket_server_action_command_executor.rb +101 -0
- data/pantograph/lib/pantograph/setup/setup.rb +290 -0
- data/pantograph/lib/pantograph/setup/setup_android.rb +64 -0
- data/pantograph/lib/pantograph/setup/setup_ios.rb +412 -0
- data/pantograph/lib/pantograph/shells.rb +6 -0
- data/pantograph/lib/pantograph/supported_platforms.rb +28 -0
- data/pantograph/lib/pantograph/tools.rb +10 -0
- data/pantograph/lib/pantograph/version.rb +5 -0
- data/pantograph/lib/pantograph.rb +51 -0
- data/pantograph_core/README.md +79 -0
- data/pantograph_core/lib/assets/XMLTemplate.xml.erb +12 -0
- data/pantograph_core/lib/pantograph_core/analytics/action_completion_context.rb +34 -0
- data/pantograph_core/lib/pantograph_core/analytics/action_launch_context.rb +38 -0
- data/pantograph_core/lib/pantograph_core/analytics/analytics_event_builder.rb +23 -0
- data/pantograph_core/lib/pantograph_core/analytics/analytics_ingester_client.rb +54 -0
- data/pantograph_core/lib/pantograph_core/analytics/analytics_session.rb +71 -0
- data/pantograph_core/lib/pantograph_core/cert_checker.rb +116 -0
- data/pantograph_core/lib/pantograph_core/command_executor.rb +99 -0
- data/pantograph_core/lib/pantograph_core/configuration/commander_generator.rb +103 -0
- data/pantograph_core/lib/pantograph_core/configuration/config_item.rb +314 -0
- data/pantograph_core/lib/pantograph_core/configuration/configuration.rb +332 -0
- data/pantograph_core/lib/pantograph_core/configuration/configuration_file.rb +182 -0
- data/pantograph_core/lib/pantograph_core/core_ext/shellwords.rb +63 -0
- data/pantograph_core/lib/pantograph_core/core_ext/string.rb +17 -0
- data/pantograph_core/lib/pantograph_core/env.rb +9 -0
- data/pantograph_core/lib/pantograph_core/feature/feature.rb +51 -0
- data/pantograph_core/lib/pantograph_core/features.rb +4 -0
- data/pantograph_core/lib/pantograph_core/globals.rb +27 -0
- data/pantograph_core/lib/pantograph_core/helper.rb +409 -0
- data/pantograph_core/lib/pantograph_core/keychain_importer.rb +74 -0
- data/pantograph_core/lib/pantograph_core/languages.rb +14 -0
- data/pantograph_core/lib/pantograph_core/module.rb +29 -0
- data/pantograph_core/lib/pantograph_core/pantograph_folder.rb +39 -0
- data/pantograph_core/lib/pantograph_core/pantograph_pty.rb +57 -0
- data/pantograph_core/lib/pantograph_core/pkg_file_analyser.rb +44 -0
- data/pantograph_core/lib/pantograph_core/print_table.rb +131 -0
- data/pantograph_core/lib/pantograph_core/string_filters.rb +51 -0
- data/pantograph_core/lib/pantograph_core/swag.rb +85 -0
- data/pantograph_core/lib/pantograph_core/tag_version.rb +31 -0
- data/pantograph_core/lib/pantograph_core/test_parser.rb +107 -0
- data/pantograph_core/lib/pantograph_core/ui/disable_colors.rb +17 -0
- data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_common_error.rb +19 -0
- data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_crash.rb +11 -0
- data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_error.rb +25 -0
- data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_exception.rb +19 -0
- data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_shell_error.rb +11 -0
- data/pantograph_core/lib/pantograph_core/ui/errors.rb +1 -0
- data/pantograph_core/lib/pantograph_core/ui/github_issue_inspector_reporter.rb +62 -0
- data/pantograph_core/lib/pantograph_core/ui/implementations/shell.rb +159 -0
- data/pantograph_core/lib/pantograph_core/ui/interface.rb +205 -0
- data/pantograph_core/lib/pantograph_core/ui/pantograph_runner.rb +276 -0
- data/pantograph_core/lib/pantograph_core/ui/ui.rb +26 -0
- data/pantograph_core/lib/pantograph_core/update_checker/changelog.rb +37 -0
- data/pantograph_core/lib/pantograph_core/update_checker/update_checker.rb +107 -0
- data/pantograph_core/lib/pantograph_core.rb +45 -0
- metadata +987 -0
@@ -0,0 +1,371 @@
|
|
1
|
+
module Pantograph
|
2
|
+
class Runner
|
3
|
+
# Symbol for the current lane
|
4
|
+
attr_accessor :current_lane
|
5
|
+
|
6
|
+
# Symbol for the current platform
|
7
|
+
attr_accessor :current_platform
|
8
|
+
|
9
|
+
# @return [Hash] All the lanes available, first the platform, then the lane
|
10
|
+
attr_accessor :lanes
|
11
|
+
|
12
|
+
def full_lane_name
|
13
|
+
[current_platform, current_lane].reject(&:nil?).join(' ')
|
14
|
+
end
|
15
|
+
|
16
|
+
# This will take care of executing **one** lane. That's when the user triggers a lane from the CLI for example
|
17
|
+
# This method is **not** executed when switching a lane
|
18
|
+
# @param lane_name The name of the lane to execute
|
19
|
+
# @param platform The name of the platform to execute
|
20
|
+
# @param parameters [Hash] The parameters passed from the command line to the lane
|
21
|
+
def execute(lane, platform = nil, parameters = nil)
|
22
|
+
UI.crash!("No lane given") unless lane
|
23
|
+
|
24
|
+
self.current_lane = lane.to_sym
|
25
|
+
self.current_platform = (platform ? platform.to_sym : nil)
|
26
|
+
|
27
|
+
lane_obj = lanes.fetch(current_platform, {}).fetch(current_lane, nil)
|
28
|
+
|
29
|
+
UI.user_error!("Could not find lane '#{full_lane_name}'. Available lanes: #{available_lanes.join(', ')}") unless lane_obj
|
30
|
+
UI.user_error!("You can't call the private lane '#{lane}' directly") if lane_obj.is_private
|
31
|
+
|
32
|
+
ENV["PANTOGRAPH_LANE_NAME"] = current_lane.to_s
|
33
|
+
ENV["PANTOGRAPH_PLATFORM_NAME"] = (current_platform ? current_platform.to_s : nil)
|
34
|
+
|
35
|
+
Actions.lane_context[Actions::SharedValues::PLATFORM_NAME] = current_platform
|
36
|
+
Actions.lane_context[Actions::SharedValues::LANE_NAME] = full_lane_name
|
37
|
+
|
38
|
+
UI.success("Driving the lane '#{full_lane_name}' 🚀")
|
39
|
+
|
40
|
+
return_val = nil
|
41
|
+
|
42
|
+
path_to_use = PantographCore::PantographFolder.path || Dir.pwd
|
43
|
+
parameters ||= {}
|
44
|
+
begin
|
45
|
+
Dir.chdir(path_to_use) do # the file is located in the pantograph folder
|
46
|
+
execute_flow_block(before_all_blocks, current_platform, current_lane, parameters)
|
47
|
+
execute_flow_block(before_each_blocks, current_platform, current_lane, parameters)
|
48
|
+
|
49
|
+
return_val = lane_obj.call(parameters) # by default no parameters
|
50
|
+
|
51
|
+
# after blocks are only called if no exception was raised before
|
52
|
+
# Call the platform specific after block and then the general one
|
53
|
+
execute_flow_block(after_each_blocks, current_platform, current_lane, parameters)
|
54
|
+
execute_flow_block(after_all_blocks, current_platform, current_lane, parameters)
|
55
|
+
end
|
56
|
+
|
57
|
+
return return_val
|
58
|
+
rescue => ex
|
59
|
+
Dir.chdir(path_to_use) do
|
60
|
+
# Provide error block exception without color code
|
61
|
+
begin
|
62
|
+
error_blocks[current_platform].call(current_lane, ex, parameters) if current_platform && error_blocks[current_platform]
|
63
|
+
error_blocks[nil].call(current_lane, ex, parameters) if error_blocks[nil]
|
64
|
+
rescue => error_block_exception
|
65
|
+
UI.error("An error occurred while executing the `error` block:")
|
66
|
+
UI.error(error_block_exception.to_s)
|
67
|
+
raise ex # raise the original error message
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
raise ex
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param filter_platform: Filter, to only show the lanes of a given platform
|
76
|
+
# @return an array of lanes (platform lane_name) to print them out to the user
|
77
|
+
def available_lanes(filter_platform = nil)
|
78
|
+
all = []
|
79
|
+
lanes.each do |platform, platform_lanes|
|
80
|
+
next if filter_platform && filter_platform.to_s != platform.to_s # skip actions that don't match
|
81
|
+
|
82
|
+
platform_lanes.each do |lane_name, lane|
|
83
|
+
all << [platform, lane_name].reject(&:nil?).join(' ') unless lane.is_private
|
84
|
+
end
|
85
|
+
end
|
86
|
+
all
|
87
|
+
end
|
88
|
+
|
89
|
+
# Pass a action symbol (e.g. :commit_version_bump)
|
90
|
+
# and this method will return a reference to the action class
|
91
|
+
# if it exists. In case the action with this name can't be found
|
92
|
+
# this method will return nil.
|
93
|
+
# This method is being called by `trigger_action_by_name` to see
|
94
|
+
# if a given action is available (either built-in or loaded from a plugin)
|
95
|
+
# and is also being called from the pantograph docs generator
|
96
|
+
def class_reference_from_action_name(method_sym)
|
97
|
+
method_str = method_sym.to_s.delete("?") # as a `?` could be at the end of the method name
|
98
|
+
class_ref = Actions.action_class_ref(method_str)
|
99
|
+
|
100
|
+
return class_ref if class_ref && class_ref.respond_to?(:run)
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
|
104
|
+
# Pass a action alias symbol (e.g. :enable_automatic_code_signing)
|
105
|
+
# and this method will return a reference to the action class
|
106
|
+
# if it exists. In case the action with this alias can't be found
|
107
|
+
# this method will return nil.
|
108
|
+
def class_reference_from_action_alias(method_sym)
|
109
|
+
alias_found = find_alias(method_sym.to_s)
|
110
|
+
return nil unless alias_found
|
111
|
+
|
112
|
+
class_reference_from_action_name(alias_found.to_sym)
|
113
|
+
end
|
114
|
+
|
115
|
+
# lookup if an alias exists
|
116
|
+
def find_alias(action_name)
|
117
|
+
Actions.alias_actions.each do |key, v|
|
118
|
+
next unless Actions.alias_actions[key]
|
119
|
+
next unless Actions.alias_actions[key].include?(action_name)
|
120
|
+
return key
|
121
|
+
end
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
|
125
|
+
# This is being called from `method_missing` from the Pantfile
|
126
|
+
# It's also used when an action is called from another action
|
127
|
+
# @param from_action Indicates if this action is being trigged by another action.
|
128
|
+
# If so, it won't show up in summary.
|
129
|
+
def trigger_action_by_name(method_sym, custom_dir, from_action, *arguments)
|
130
|
+
# First, check if there is a predefined method in the actions folder
|
131
|
+
class_ref = class_reference_from_action_name(method_sym)
|
132
|
+
unless class_ref
|
133
|
+
class_ref = class_reference_from_action_alias(method_sym)
|
134
|
+
# notify action that it has been used by alias
|
135
|
+
if class_ref.respond_to?(:alias_used)
|
136
|
+
orig_action = method_sym.to_s
|
137
|
+
arguments = [{}] if arguments.empty?
|
138
|
+
class_ref.alias_used(orig_action, arguments.first)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# It's important to *not* have this code inside the rescue block
|
143
|
+
# otherwise all NameErrors will be caught and the error message is
|
144
|
+
# confusing
|
145
|
+
begin
|
146
|
+
return self.try_switch_to_lane(method_sym, arguments)
|
147
|
+
rescue LaneNotAvailableError
|
148
|
+
# We don't actually handle this here yet
|
149
|
+
# We just try to use a user configured lane first
|
150
|
+
# and only if there is none, we're gonna check for the
|
151
|
+
# built-in actions
|
152
|
+
end
|
153
|
+
|
154
|
+
if class_ref
|
155
|
+
if class_ref.respond_to?(:run)
|
156
|
+
# Action is available, now execute it
|
157
|
+
return self.execute_action(method_sym, class_ref, arguments, custom_dir: custom_dir, from_action: from_action)
|
158
|
+
else
|
159
|
+
UI.user_error!("Action '#{method_sym}' of class '#{class_name}' was found, but has no `run` method.")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# No lane, no action, let's at least show the correct error message
|
164
|
+
if Pantograph.plugin_manager.plugin_is_added_as_dependency?(PluginManager.plugin_prefix + method_sym.to_s)
|
165
|
+
# That's a plugin, but for some reason we can't find it
|
166
|
+
UI.user_error!("Plugin '#{method_sym}' was not properly loaded, make sure to follow the plugin docs for troubleshooting: #{PluginManager::TROUBLESHOOTING_URL}")
|
167
|
+
elsif Pantograph::Actions.formerly_bundled_actions.include?(method_sym.to_s)
|
168
|
+
# This was a formerly bundled action which is now a plugin.
|
169
|
+
UI.verbose(caller.join("\n"))
|
170
|
+
UI.user_error!("The action '#{method_sym}' is no longer bundled with pantograph. You can install it using `pantograph add_plugin #{method_sym}`")
|
171
|
+
else
|
172
|
+
# So there is no plugin under that name, so just show the error message generated by the lane switch
|
173
|
+
UI.verbose(caller.join("\n"))
|
174
|
+
UI.user_error!("Could not find action, lane or variable '#{method_sym}'. Check out the documentation for more details: https://docs.pantograph.tools/actions")
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
#
|
179
|
+
# All the methods that are usually called on execution
|
180
|
+
#
|
181
|
+
|
182
|
+
class LaneNotAvailableError < StandardError
|
183
|
+
end
|
184
|
+
|
185
|
+
def try_switch_to_lane(new_lane, parameters)
|
186
|
+
block = lanes.fetch(current_platform, {}).fetch(new_lane, nil)
|
187
|
+
block ||= lanes.fetch(nil, {}).fetch(new_lane, nil) # fallback to general lane for multiple platforms
|
188
|
+
if block
|
189
|
+
original_full = full_lane_name
|
190
|
+
original_lane = current_lane
|
191
|
+
|
192
|
+
UI.user_error!("Parameters for a lane must always be a hash") unless (parameters.first || {}).kind_of?(Hash)
|
193
|
+
|
194
|
+
execute_flow_block(before_each_blocks, current_platform, new_lane, parameters)
|
195
|
+
|
196
|
+
pretty = [new_lane]
|
197
|
+
pretty = [current_platform, new_lane] if current_platform
|
198
|
+
Actions.execute_action("Switch to #{pretty.join(' ')} lane") {} # log the action
|
199
|
+
UI.message("Cruising over to lane '#{pretty.join(' ')}' 🚖")
|
200
|
+
|
201
|
+
# Actually switch lane now
|
202
|
+
self.current_lane = new_lane
|
203
|
+
|
204
|
+
result = block.call(parameters.first || {}) # to always pass a hash
|
205
|
+
self.current_lane = original_lane
|
206
|
+
|
207
|
+
# after blocks are only called if no exception was raised before
|
208
|
+
# Call the platform specific after block and then the general one
|
209
|
+
execute_flow_block(after_each_blocks, current_platform, new_lane, parameters)
|
210
|
+
|
211
|
+
UI.message("Cruising back to lane '#{original_full}' 🚘")
|
212
|
+
return result
|
213
|
+
else
|
214
|
+
raise LaneNotAvailableError.new, "Lane not found"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def execute_action(method_sym, class_ref, arguments, custom_dir: nil, from_action: false)
|
219
|
+
if custom_dir.nil?
|
220
|
+
custom_dir ||= "." if Helper.test?
|
221
|
+
custom_dir ||= ".."
|
222
|
+
end
|
223
|
+
|
224
|
+
verify_supported_os(method_sym, class_ref)
|
225
|
+
|
226
|
+
begin
|
227
|
+
Dir.chdir(custom_dir) do # go up from the pantograph folder, to the project folder
|
228
|
+
# If another action is calling this action, we shouldn't show it in the summary
|
229
|
+
|
230
|
+
unless from_action
|
231
|
+
args = arguments.kind_of?(Array) && arguments.first.kind_of?(Hash) ? arguments.first : {}
|
232
|
+
action_name = args[:step_name] || class_ref.step_text
|
233
|
+
args.delete(:step_name)
|
234
|
+
end
|
235
|
+
Actions.execute_action(action_name) do
|
236
|
+
# arguments is an array by default, containing an hash with the actual parameters
|
237
|
+
# Since we usually just need the passed hash, we'll just use the first object if there is only one
|
238
|
+
if arguments.count == 0
|
239
|
+
arguments = ConfigurationHelper.parse(class_ref, {}) # no parameters => empty hash
|
240
|
+
elsif arguments.count == 1 && arguments.first.kind_of?(Hash)
|
241
|
+
arguments = ConfigurationHelper.parse(class_ref, arguments.first) # Correct configuration passed
|
242
|
+
elsif !class_ref.available_options
|
243
|
+
# This action does not use the new action format
|
244
|
+
# Just passing the arguments to this method
|
245
|
+
else
|
246
|
+
UI.user_error!("You have to call the integration like `#{method_sym}(key: \"value\")`. Run `pantograph action #{method_sym}` for all available keys. Please check out the current documentation on GitHub.")
|
247
|
+
end
|
248
|
+
|
249
|
+
if Pantograph::Actions.is_deprecated?(class_ref)
|
250
|
+
puts("==========================================".deprecated)
|
251
|
+
puts("This action (#{method_sym}) is deprecated".deprecated)
|
252
|
+
puts(class_ref.deprecated_notes.to_s.remove_markdown.deprecated) if class_ref.deprecated_notes
|
253
|
+
puts("==========================================\n".deprecated)
|
254
|
+
end
|
255
|
+
class_ref.runner = self # needed to call another action form an action
|
256
|
+
return class_ref.run(arguments)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
rescue Interrupt => e
|
260
|
+
raise e # reraise the interruption to avoid logging this as a crash
|
261
|
+
rescue PantographCore::Interface::PantographCommonException => e # these are exceptions that we dont count as crashes
|
262
|
+
raise e
|
263
|
+
rescue PantographCore::Interface::PantographError => e # user_error!
|
264
|
+
action_completed(method_sym.to_s, status: PantographCore::ActionCompletionStatus::USER_ERROR, exception: e)
|
265
|
+
raise e
|
266
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
267
|
+
# high chance this is actually PantographCore::Interface::PantographCrash, but can be anything else
|
268
|
+
# Catches all exceptions, since some plugins might use system exits to get out
|
269
|
+
action_completed(method_sym.to_s, status: PantographCore::ActionCompletionStatus::FAILED, exception: e)
|
270
|
+
raise e
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def action_completed(action_name, status: nil, exception: nil)
|
275
|
+
# https://github.com/pantograph/pantograph/issues/11913
|
276
|
+
# if exception.nil? || exception.pantograph_should_report_metrics?
|
277
|
+
# action_completion_context = PantographCore::ActionCompletionContext.context_for_action_name(action_name, args: ARGV, status: status)
|
278
|
+
# PantographCore.session.action_completed(completion_context: action_completion_context)
|
279
|
+
# end
|
280
|
+
end
|
281
|
+
|
282
|
+
def execute_flow_block(block, current_platform, lane, parameters)
|
283
|
+
# Call the platform specific block and default back to the general one
|
284
|
+
block[current_platform].call(lane, parameters) if block[current_platform] && current_platform
|
285
|
+
block[nil].call(lane, parameters) if block[nil]
|
286
|
+
end
|
287
|
+
|
288
|
+
def verify_supported_os(name, class_ref)
|
289
|
+
if class_ref.respond_to?(:is_supported?)
|
290
|
+
# This value is filled in based on the executed platform block. Might be nil when lane is in root of Pantfile
|
291
|
+
platform = Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]
|
292
|
+
if platform
|
293
|
+
unless class_ref.is_supported?(platform)
|
294
|
+
UI.important("Action '#{name}' isn't known to support operating system '#{platform}'.")
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# Called internally to setup the runner object
|
301
|
+
#
|
302
|
+
|
303
|
+
# @param lane [Lane] A lane object
|
304
|
+
def add_lane(lane, override = false)
|
305
|
+
lanes[lane.platform] ||= {}
|
306
|
+
|
307
|
+
if !override && lanes[lane.platform][lane.name]
|
308
|
+
UI.user_error!("Lane '#{lane.name}' was defined multiple times!")
|
309
|
+
end
|
310
|
+
|
311
|
+
lanes[lane.platform][lane.name] = lane
|
312
|
+
end
|
313
|
+
|
314
|
+
def set_before_each(platform, block)
|
315
|
+
before_each_blocks[platform] = block
|
316
|
+
end
|
317
|
+
|
318
|
+
def set_after_each(platform, block)
|
319
|
+
after_each_blocks[platform] = block
|
320
|
+
end
|
321
|
+
|
322
|
+
def set_before_all(platform, block)
|
323
|
+
unless before_all_blocks[platform].nil?
|
324
|
+
UI.error("You defined multiple `before_all` blocks in your `Pantfile`. The last one being set will be used.")
|
325
|
+
end
|
326
|
+
before_all_blocks[platform] = block
|
327
|
+
end
|
328
|
+
|
329
|
+
def set_after_all(platform, block)
|
330
|
+
unless after_all_blocks[platform].nil?
|
331
|
+
UI.error("You defined multiple `after_all` blocks in your `Pantfile`. The last one being set will be used.")
|
332
|
+
end
|
333
|
+
after_all_blocks[platform] = block
|
334
|
+
end
|
335
|
+
|
336
|
+
def set_error(platform, block)
|
337
|
+
unless error_blocks[platform].nil?
|
338
|
+
UI.error("You defined multiple `error` blocks in your `Pantfile`. The last one being set will be used.")
|
339
|
+
end
|
340
|
+
error_blocks[platform] = block
|
341
|
+
end
|
342
|
+
|
343
|
+
def lanes
|
344
|
+
@lanes ||= {}
|
345
|
+
end
|
346
|
+
|
347
|
+
def did_finish
|
348
|
+
# to maintain compatibility with other sibling classes that have this API
|
349
|
+
end
|
350
|
+
|
351
|
+
def before_each_blocks
|
352
|
+
@before_each ||= {}
|
353
|
+
end
|
354
|
+
|
355
|
+
def after_each_blocks
|
356
|
+
@after_each ||= {}
|
357
|
+
end
|
358
|
+
|
359
|
+
def before_all_blocks
|
360
|
+
@before_all ||= {}
|
361
|
+
end
|
362
|
+
|
363
|
+
def after_all_blocks
|
364
|
+
@after_all ||= {}
|
365
|
+
end
|
366
|
+
|
367
|
+
def error_blocks
|
368
|
+
@error_blocks ||= {}
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Pantograph
|
2
|
+
# Represents an argument to the ActionCommand
|
3
|
+
class Argument
|
4
|
+
def initialize(json: nil)
|
5
|
+
@name = json['name']
|
6
|
+
@value = json['value']
|
7
|
+
@value_type = json['value_type']
|
8
|
+
end
|
9
|
+
|
10
|
+
def is_named
|
11
|
+
return @name.to_s.length > 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
if is_named
|
16
|
+
return "named argument: #{name}, value: #{value}, type: #{value_type}"
|
17
|
+
else
|
18
|
+
return "unnamed argument value: #{value}, type: #{value_type}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :name
|
23
|
+
attr_reader :value
|
24
|
+
attr_reader :value_type
|
25
|
+
end
|
26
|
+
|
27
|
+
# Represents a command that is meant to execute an Action on the client's behalf
|
28
|
+
class ActionCommand
|
29
|
+
attr_reader :command_id # always present
|
30
|
+
attr_reader :args # always present
|
31
|
+
attr_reader :method_name # always present
|
32
|
+
attr_reader :class_name # only present when executing a class-method
|
33
|
+
|
34
|
+
def initialize(json: nil)
|
35
|
+
@method_name = json['methodName']
|
36
|
+
@class_name = json['className']
|
37
|
+
@command_id = json['commandID']
|
38
|
+
|
39
|
+
args_json = json['args'] ||= []
|
40
|
+
@args = args_json.map do |arg|
|
41
|
+
Argument.new(json: arg)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def cancel_signal?
|
46
|
+
return @command_id == "cancelPantographRun"
|
47
|
+
end
|
48
|
+
|
49
|
+
def target_class
|
50
|
+
unless class_name
|
51
|
+
return nil
|
52
|
+
end
|
53
|
+
|
54
|
+
return Pantograph::Actions.const_get(class_name)
|
55
|
+
end
|
56
|
+
|
57
|
+
def is_class_method_command
|
58
|
+
return class_name.to_s.length > 0
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Pantograph
|
2
|
+
# Encapsulates the result and description of a return object returned by an executed pantograph action
|
3
|
+
class ActionCommandReturn
|
4
|
+
attr_reader :return_value
|
5
|
+
attr_reader :return_value_type
|
6
|
+
attr_reader :closure_argument_value
|
7
|
+
|
8
|
+
def initialize(return_value: nil, return_value_type: nil, closure_argument_value: nil)
|
9
|
+
@return_value = return_value
|
10
|
+
@closure_argument_value = closure_argument_value
|
11
|
+
@return_value_type = return_value_type
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'pantograph/server/action_command.rb'
|
2
|
+
require 'pantograph/server/control_command.rb'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Pantograph
|
6
|
+
class CommandParser
|
7
|
+
def self.parse(json: nil)
|
8
|
+
if json.strip == "done"
|
9
|
+
return intercept_old_done_command
|
10
|
+
end
|
11
|
+
|
12
|
+
command_json = JSON.parse(json)
|
13
|
+
return handle_new_style_commands(command_json: command_json)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.handle_new_style_commands(command_json: nil)
|
17
|
+
command_type = command_json['commandType'].to_sym
|
18
|
+
command = command_json['command']
|
19
|
+
|
20
|
+
case command_type
|
21
|
+
when :action
|
22
|
+
return ActionCommand.new(json: command)
|
23
|
+
when :control
|
24
|
+
return ControlCommand.new(json: command)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.handle_old_style_action_command(command_json: nil)
|
29
|
+
return ActionCommand.new(json: command_json)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.intercept_old_done_command
|
33
|
+
return ControlCommand.new(json: '{"command":"done"}')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Pantograph
|
2
|
+
# Represents a command that is meant to signal the server to do something on the client's behalf
|
3
|
+
# Examples are: :cancelPantographRune, and :done
|
4
|
+
class ControlCommand
|
5
|
+
attr_reader :command
|
6
|
+
attr_reader :user_message
|
7
|
+
attr_reader :reason
|
8
|
+
|
9
|
+
def initialize(json: nil)
|
10
|
+
@command = json['command'].to_sym
|
11
|
+
@user_message = json['userMessage']
|
12
|
+
@reason = json['reason'].to_sym if json['reason']
|
13
|
+
end
|
14
|
+
|
15
|
+
def cancel_signal?
|
16
|
+
return @command == :cancelPantographRun
|
17
|
+
end
|
18
|
+
|
19
|
+
def done_signal?
|
20
|
+
return @command == :done
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Pantograph
|
4
|
+
class JSONReturnValueProcessor
|
5
|
+
def prepare_object(return_value: nil, return_value_type: nil)
|
6
|
+
case return_value_type
|
7
|
+
when nil
|
8
|
+
UI.verbose("return_value_type is nil value: #{return_value}")
|
9
|
+
return process_value_as_string(return_value: return_value)
|
10
|
+
when :string
|
11
|
+
return process_value_as_string(return_value: return_value)
|
12
|
+
when :int
|
13
|
+
return process_value_as_int(return_value: return_value)
|
14
|
+
when :bool
|
15
|
+
return process_value_as_bool(return_value: return_value)
|
16
|
+
when :array_of_strings
|
17
|
+
return process_value_as_array_of_strings(return_value: return_value)
|
18
|
+
when :hash_of_strings
|
19
|
+
return process_value_as_hash_of_strings(return_value: return_value)
|
20
|
+
when :hash
|
21
|
+
return process_value_as_hash_of_strings(return_value: return_value)
|
22
|
+
else
|
23
|
+
UI.verbose("Unknown return type defined: #{return_value_type} for value: #{return_value}")
|
24
|
+
return process_value_as_string(return_value: return_value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def process_value_as_string(return_value: nil)
|
29
|
+
if return_value.nil?
|
30
|
+
return_value = ""
|
31
|
+
end
|
32
|
+
|
33
|
+
return_value
|
34
|
+
end
|
35
|
+
|
36
|
+
def process_value_as_array_of_strings(return_value: nil)
|
37
|
+
if return_value.nil?
|
38
|
+
return_value = []
|
39
|
+
end
|
40
|
+
|
41
|
+
# quirks_mode shouldn't be required for real objects
|
42
|
+
return JSON.generate(return_value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def process_value_as_hash_of_strings(return_value: nil)
|
46
|
+
if return_value.nil?
|
47
|
+
return_value = {}
|
48
|
+
end
|
49
|
+
|
50
|
+
# quirks_mode shouldn't be required for real objects
|
51
|
+
return JSON.generate(return_value)
|
52
|
+
end
|
53
|
+
|
54
|
+
def process_value_as_bool(return_value: nil)
|
55
|
+
if return_value.nil?
|
56
|
+
return_value = false
|
57
|
+
end
|
58
|
+
|
59
|
+
# quirks_mode because sometimes the built-in library is used for some folks and that needs quirks_mode: true
|
60
|
+
return JSON.generate(return_value.to_s, quirks_mode: true)
|
61
|
+
end
|
62
|
+
|
63
|
+
def process_value_as_int(return_value: nil)
|
64
|
+
if return_value.nil?
|
65
|
+
return_value = 0
|
66
|
+
end
|
67
|
+
|
68
|
+
# quirks_mode because sometimes the built-in library is used for some folks and that needs quirks_mode: true
|
69
|
+
return JSON.generate(return_value.to_s, quirks_mode: true)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|