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.
Files changed (202) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -0
  3. data/LICENSE +21 -0
  4. data/README.md +197 -0
  5. data/bin/bin-proxy +19 -0
  6. data/bin/pantograph +23 -0
  7. data/pantograph/README.md +11 -0
  8. data/pantograph/lib/assets/ActionDetails.md.erb +106 -0
  9. data/pantograph/lib/assets/Actions.md.erb +43 -0
  10. data/pantograph/lib/assets/DefaultPantfileTemplate +20 -0
  11. data/pantograph/lib/assets/completions/completion.bash +23 -0
  12. data/pantograph/lib/assets/completions/completion.fish +39 -0
  13. data/pantograph/lib/assets/completions/completion.sh +12 -0
  14. data/pantograph/lib/assets/completions/completion.zsh +23 -0
  15. data/pantograph/lib/assets/custom_action_template.rb +80 -0
  16. data/pantograph/lib/assets/report_template.xml.erb +15 -0
  17. data/pantograph/lib/pantograph/action.rb +194 -0
  18. data/pantograph/lib/pantograph/action_collector.rb +35 -0
  19. data/pantograph/lib/pantograph/actions/README.md +3 -0
  20. data/pantograph/lib/pantograph/actions/actions_helper.rb +166 -0
  21. data/pantograph/lib/pantograph/actions/add_extra_platforms.rb +45 -0
  22. data/pantograph/lib/pantograph/actions/artifactory.rb +157 -0
  23. data/pantograph/lib/pantograph/actions/bundle_install.rb +156 -0
  24. data/pantograph/lib/pantograph/actions/changelog_from_git_commits.rb +197 -0
  25. data/pantograph/lib/pantograph/actions/clipboard.rb +52 -0
  26. data/pantograph/lib/pantograph/actions/cloc.rb +89 -0
  27. data/pantograph/lib/pantograph/actions/create_pull_request.rb +190 -0
  28. data/pantograph/lib/pantograph/actions/danger.rb +131 -0
  29. data/pantograph/lib/pantograph/actions/debug.rb +32 -0
  30. data/pantograph/lib/pantograph/actions/default_platform.rb +47 -0
  31. data/pantograph/lib/pantograph/actions/download.rb +76 -0
  32. data/pantograph/lib/pantograph/actions/echo.rb +14 -0
  33. data/pantograph/lib/pantograph/actions/ensure_bundle_exec.rb +59 -0
  34. data/pantograph/lib/pantograph/actions/ensure_env_vars.rb +58 -0
  35. data/pantograph/lib/pantograph/actions/ensure_git_branch.rb +69 -0
  36. data/pantograph/lib/pantograph/actions/ensure_git_status_clean.rb +81 -0
  37. data/pantograph/lib/pantograph/actions/erb.rb +88 -0
  38. data/pantograph/lib/pantograph/actions/get_build_number_repository.rb +120 -0
  39. data/pantograph/lib/pantograph/actions/get_github_release.rb +163 -0
  40. data/pantograph/lib/pantograph/actions/git_add.rb +93 -0
  41. data/pantograph/lib/pantograph/actions/git_branch.rb +58 -0
  42. data/pantograph/lib/pantograph/actions/git_commit.rb +80 -0
  43. data/pantograph/lib/pantograph/actions/git_pull.rb +53 -0
  44. data/pantograph/lib/pantograph/actions/git_submodule_update.rb +52 -0
  45. data/pantograph/lib/pantograph/actions/git_tag_exists.rb +74 -0
  46. data/pantograph/lib/pantograph/actions/github_api.rb +262 -0
  47. data/pantograph/lib/pantograph/actions/gradle.rb +278 -0
  48. data/pantograph/lib/pantograph/actions/import.rb +49 -0
  49. data/pantograph/lib/pantograph/actions/import_from_git.rb +71 -0
  50. data/pantograph/lib/pantograph/actions/is_ci.rb +51 -0
  51. data/pantograph/lib/pantograph/actions/jira.rb +115 -0
  52. data/pantograph/lib/pantograph/actions/lane_context.rb +60 -0
  53. data/pantograph/lib/pantograph/actions/last_git_commit.rb +58 -0
  54. data/pantograph/lib/pantograph/actions/last_git_tag.rb +51 -0
  55. data/pantograph/lib/pantograph/actions/make_changelog_from_jenkins.rb +81 -0
  56. data/pantograph/lib/pantograph/actions/min_pantograph_version.rb +57 -0
  57. data/pantograph/lib/pantograph/actions/nexus_upload.rb +230 -0
  58. data/pantograph/lib/pantograph/actions/notification.rb +75 -0
  59. data/pantograph/lib/pantograph/actions/number_of_commits.rb +75 -0
  60. data/pantograph/lib/pantograph/actions/opt_out_usage.rb +40 -0
  61. data/pantograph/lib/pantograph/actions/pantograph_version.rb +15 -0
  62. data/pantograph/lib/pantograph/actions/println.rb +14 -0
  63. data/pantograph/lib/pantograph/actions/prompt.rb +119 -0
  64. data/pantograph/lib/pantograph/actions/push_git_tags.rb +76 -0
  65. data/pantograph/lib/pantograph/actions/push_to_git_remote.rb +127 -0
  66. data/pantograph/lib/pantograph/actions/puts.rb +68 -0
  67. data/pantograph/lib/pantograph/actions/reset_git_repo.rb +121 -0
  68. data/pantograph/lib/pantograph/actions/rocket.rb +83 -0
  69. data/pantograph/lib/pantograph/actions/rsync.rb +74 -0
  70. data/pantograph/lib/pantograph/actions/ruby_version.rb +56 -0
  71. data/pantograph/lib/pantograph/actions/say.rb +56 -0
  72. data/pantograph/lib/pantograph/actions/scp.rb +114 -0
  73. data/pantograph/lib/pantograph/actions/set_github_release.rb +274 -0
  74. data/pantograph/lib/pantograph/actions/sh.rb +71 -0
  75. data/pantograph/lib/pantograph/actions/skip_docs.rb +52 -0
  76. data/pantograph/lib/pantograph/actions/slack.rb +288 -0
  77. data/pantograph/lib/pantograph/actions/sonar.rb +156 -0
  78. data/pantograph/lib/pantograph/actions/ssh.rb +162 -0
  79. data/pantograph/lib/pantograph/actions/twitter.rb +89 -0
  80. data/pantograph/lib/pantograph/actions/update_pantograph.rb +177 -0
  81. data/pantograph/lib/pantograph/actions/zip.rb +120 -0
  82. data/pantograph/lib/pantograph/auto_complete.rb +82 -0
  83. data/pantograph/lib/pantograph/boolean.rb +5 -0
  84. data/pantograph/lib/pantograph/cli_tools_distributor.rb +183 -0
  85. data/pantograph/lib/pantograph/command_line_handler.rb +43 -0
  86. data/pantograph/lib/pantograph/commands_generator.rb +344 -0
  87. data/pantograph/lib/pantograph/configuration_helper.rb +26 -0
  88. data/pantograph/lib/pantograph/core_ext/bundler_monkey_patch.rb +14 -0
  89. data/pantograph/lib/pantograph/documentation/actions_list.rb +214 -0
  90. data/pantograph/lib/pantograph/documentation/docs_generator.rb +95 -0
  91. data/pantograph/lib/pantograph/documentation/markdown_docs_generator.rb +221 -0
  92. data/pantograph/lib/pantograph/environment_printer.rb +282 -0
  93. data/pantograph/lib/pantograph/erb_template_helper.rb +30 -0
  94. data/pantograph/lib/pantograph/features.rb +4 -0
  95. data/pantograph/lib/pantograph/helper/README.md +29 -0
  96. data/pantograph/lib/pantograph/helper/dotenv_helper.rb +50 -0
  97. data/pantograph/lib/pantograph/helper/gem_helper.rb +26 -0
  98. data/pantograph/lib/pantograph/helper/git_helper.rb +135 -0
  99. data/pantograph/lib/pantograph/helper/gradle_helper.rb +62 -0
  100. data/pantograph/lib/pantograph/helper/sh_helper.rb +134 -0
  101. data/pantograph/lib/pantograph/junit_generator.rb +27 -0
  102. data/pantograph/lib/pantograph/lane.rb +97 -0
  103. data/pantograph/lib/pantograph/lane_list.rb +77 -0
  104. data/pantograph/lib/pantograph/lane_manager.rb +140 -0
  105. data/pantograph/lib/pantograph/lane_manager_base.rb +92 -0
  106. data/pantograph/lib/pantograph/markdown_table_formatter.rb +62 -0
  107. data/pantograph/lib/pantograph/new_action.rb +47 -0
  108. data/pantograph/lib/pantograph/one_off.rb +45 -0
  109. data/pantograph/lib/pantograph/other_action.rb +29 -0
  110. data/pantograph/lib/pantograph/pant_file.rb +377 -0
  111. data/pantograph/lib/pantograph/pantograph_require.rb +75 -0
  112. data/pantograph/lib/pantograph/plugins/plugin_fetcher.rb +55 -0
  113. data/pantograph/lib/pantograph/plugins/plugin_generator.rb +86 -0
  114. data/pantograph/lib/pantograph/plugins/plugin_generator_ui.rb +19 -0
  115. data/pantograph/lib/pantograph/plugins/plugin_info.rb +49 -0
  116. data/pantograph/lib/pantograph/plugins/plugin_info_collector.rb +159 -0
  117. data/pantograph/lib/pantograph/plugins/plugin_manager.rb +387 -0
  118. data/pantograph/lib/pantograph/plugins/plugin_search.rb +46 -0
  119. data/pantograph/lib/pantograph/plugins/plugin_update_manager.rb +70 -0
  120. data/pantograph/lib/pantograph/plugins/plugins.rb +12 -0
  121. data/pantograph/lib/pantograph/plugins/template/%gem_name%.gemspec.erb +35 -0
  122. data/pantograph/lib/pantograph/plugins/template/.circleci/config.yml +43 -0
  123. data/pantograph/lib/pantograph/plugins/template/.gitignore +12 -0
  124. data/pantograph/lib/pantograph/plugins/template/.rspec +5 -0
  125. data/pantograph/lib/pantograph/plugins/template/.rubocop.yml +179 -0
  126. data/pantograph/lib/pantograph/plugins/template/.travis.yml +4 -0
  127. data/pantograph/lib/pantograph/plugins/template/Gemfile +6 -0
  128. data/pantograph/lib/pantograph/plugins/template/LICENSE.erb +21 -0
  129. data/pantograph/lib/pantograph/plugins/template/README.md.erb +52 -0
  130. data/pantograph/lib/pantograph/plugins/template/Rakefile +9 -0
  131. data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/actions/%plugin_name%_action.rb.erb +47 -0
  132. data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/helper/%plugin_name%_helper.rb.erb +16 -0
  133. data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/version.rb.erb +5 -0
  134. data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%.rb.erb +16 -0
  135. data/pantograph/lib/pantograph/plugins/template/pantograph/Pantfile.erb +3 -0
  136. data/pantograph/lib/pantograph/plugins/template/pantograph/Pluginfile.erb +1 -0
  137. data/pantograph/lib/pantograph/plugins/template/spec/%plugin_name%_action_spec.rb.erb +9 -0
  138. data/pantograph/lib/pantograph/plugins/template/spec/spec_helper.rb.erb +15 -0
  139. data/pantograph/lib/pantograph/runner.rb +371 -0
  140. data/pantograph/lib/pantograph/server/action_command.rb +61 -0
  141. data/pantograph/lib/pantograph/server/action_command_return.rb +14 -0
  142. data/pantograph/lib/pantograph/server/command_executor.rb +7 -0
  143. data/pantograph/lib/pantograph/server/command_parser.rb +36 -0
  144. data/pantograph/lib/pantograph/server/control_command.rb +23 -0
  145. data/pantograph/lib/pantograph/server/json_return_value_processor.rb +72 -0
  146. data/pantograph/lib/pantograph/server/socket_server.rb +232 -0
  147. data/pantograph/lib/pantograph/server/socket_server_action_command_executor.rb +101 -0
  148. data/pantograph/lib/pantograph/setup/setup.rb +290 -0
  149. data/pantograph/lib/pantograph/setup/setup_android.rb +64 -0
  150. data/pantograph/lib/pantograph/setup/setup_ios.rb +412 -0
  151. data/pantograph/lib/pantograph/shells.rb +6 -0
  152. data/pantograph/lib/pantograph/supported_platforms.rb +28 -0
  153. data/pantograph/lib/pantograph/tools.rb +10 -0
  154. data/pantograph/lib/pantograph/version.rb +5 -0
  155. data/pantograph/lib/pantograph.rb +51 -0
  156. data/pantograph_core/README.md +79 -0
  157. data/pantograph_core/lib/assets/XMLTemplate.xml.erb +12 -0
  158. data/pantograph_core/lib/pantograph_core/analytics/action_completion_context.rb +34 -0
  159. data/pantograph_core/lib/pantograph_core/analytics/action_launch_context.rb +38 -0
  160. data/pantograph_core/lib/pantograph_core/analytics/analytics_event_builder.rb +23 -0
  161. data/pantograph_core/lib/pantograph_core/analytics/analytics_ingester_client.rb +54 -0
  162. data/pantograph_core/lib/pantograph_core/analytics/analytics_session.rb +71 -0
  163. data/pantograph_core/lib/pantograph_core/cert_checker.rb +116 -0
  164. data/pantograph_core/lib/pantograph_core/command_executor.rb +99 -0
  165. data/pantograph_core/lib/pantograph_core/configuration/commander_generator.rb +103 -0
  166. data/pantograph_core/lib/pantograph_core/configuration/config_item.rb +314 -0
  167. data/pantograph_core/lib/pantograph_core/configuration/configuration.rb +332 -0
  168. data/pantograph_core/lib/pantograph_core/configuration/configuration_file.rb +182 -0
  169. data/pantograph_core/lib/pantograph_core/core_ext/shellwords.rb +63 -0
  170. data/pantograph_core/lib/pantograph_core/core_ext/string.rb +17 -0
  171. data/pantograph_core/lib/pantograph_core/env.rb +9 -0
  172. data/pantograph_core/lib/pantograph_core/feature/feature.rb +51 -0
  173. data/pantograph_core/lib/pantograph_core/features.rb +4 -0
  174. data/pantograph_core/lib/pantograph_core/globals.rb +27 -0
  175. data/pantograph_core/lib/pantograph_core/helper.rb +409 -0
  176. data/pantograph_core/lib/pantograph_core/keychain_importer.rb +74 -0
  177. data/pantograph_core/lib/pantograph_core/languages.rb +14 -0
  178. data/pantograph_core/lib/pantograph_core/module.rb +29 -0
  179. data/pantograph_core/lib/pantograph_core/pantograph_folder.rb +39 -0
  180. data/pantograph_core/lib/pantograph_core/pantograph_pty.rb +57 -0
  181. data/pantograph_core/lib/pantograph_core/pkg_file_analyser.rb +44 -0
  182. data/pantograph_core/lib/pantograph_core/print_table.rb +131 -0
  183. data/pantograph_core/lib/pantograph_core/string_filters.rb +51 -0
  184. data/pantograph_core/lib/pantograph_core/swag.rb +85 -0
  185. data/pantograph_core/lib/pantograph_core/tag_version.rb +31 -0
  186. data/pantograph_core/lib/pantograph_core/test_parser.rb +107 -0
  187. data/pantograph_core/lib/pantograph_core/ui/disable_colors.rb +17 -0
  188. data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_common_error.rb +19 -0
  189. data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_crash.rb +11 -0
  190. data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_error.rb +25 -0
  191. data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_exception.rb +19 -0
  192. data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_shell_error.rb +11 -0
  193. data/pantograph_core/lib/pantograph_core/ui/errors.rb +1 -0
  194. data/pantograph_core/lib/pantograph_core/ui/github_issue_inspector_reporter.rb +62 -0
  195. data/pantograph_core/lib/pantograph_core/ui/implementations/shell.rb +159 -0
  196. data/pantograph_core/lib/pantograph_core/ui/interface.rb +205 -0
  197. data/pantograph_core/lib/pantograph_core/ui/pantograph_runner.rb +276 -0
  198. data/pantograph_core/lib/pantograph_core/ui/ui.rb +26 -0
  199. data/pantograph_core/lib/pantograph_core/update_checker/changelog.rb +37 -0
  200. data/pantograph_core/lib/pantograph_core/update_checker/update_checker.rb +107 -0
  201. data/pantograph_core/lib/pantograph_core.rb +45 -0
  202. 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,7 @@
1
+ module Pantograph
2
+ class CommandExecutor
3
+ def execute(command: nil, target_object: nil)
4
+ not_implemented(__method__)
5
+ end
6
+ end
7
+ 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