pantograph 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,50 @@
1
+ module Pantograph
2
+ module Helper
3
+ class DotenvHelper
4
+ # @param env_cl_param [String] an optional list of dotenv environment names separated by commas, without space
5
+ def self.load_dot_env(env_cl_param)
6
+ base_path = find_dotenv_directory
7
+
8
+ return unless base_path
9
+
10
+ load_dot_envs_from(env_cl_param, base_path)
11
+ end
12
+
13
+ # finds the first directory of [pantograph, its parent] containing dotenv files
14
+ def self.find_dotenv_directory
15
+ path = PantographCore::PantographFolder.path
16
+ search_paths = [path]
17
+ search_paths << path + "/.." unless path.nil?
18
+ search_paths.compact!
19
+ search_paths.find do |dir|
20
+ Dir.glob(File.join(dir, '*.env*'), File::FNM_DOTMATCH).count > 0
21
+ end
22
+ end
23
+
24
+ # loads the dotenvs. First the .env and .env.default and
25
+ # then override with all speficied extra environments
26
+ def self.load_dot_envs_from(env_cl_param, base_path)
27
+ require 'dotenv'
28
+
29
+ # Making sure the default '.env' and '.env.default' get loaded
30
+ env_file = File.join(base_path, '.env')
31
+ env_default_file = File.join(base_path, '.env.default')
32
+ Dotenv.load(env_file, env_default_file)
33
+
34
+ return unless env_cl_param
35
+
36
+ Pantograph::Actions.lane_context[Pantograph::Actions::SharedValues::ENVIRONMENT] = env_cl_param
37
+
38
+ # multiple envs?
39
+ envs = env_cl_param.split(",")
40
+
41
+ # Loads .env file for the environment(s) passed in through options
42
+ envs.each do |env|
43
+ env_file = File.join(base_path, ".env.#{env}")
44
+ UI.success("Loading from '#{env_file}'")
45
+ Dotenv.overload(env_file)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ module Pantograph
2
+ module Actions
3
+ # will make sure a gem is installed. If it's not an appropriate error message is shown
4
+ # this will *not* 'require' the gem
5
+ def self.verify_gem!(gem_name)
6
+ begin
7
+ PantographRequire.install_gem_if_needed(gem_name: gem_name, require_gem: false)
8
+ # We don't import this by default, as it's not always the same
9
+ # also e.g. cocoapods is just required and not imported
10
+ rescue Gem::LoadError
11
+ UI.error("Could not find gem '#{gem_name}'")
12
+ UI.error("")
13
+ UI.error("If you installed pantograph using `gem install pantograph` run")
14
+ UI.command("gem install #{gem_name}")
15
+ UI.error("to install the missing gem")
16
+ UI.error("")
17
+ UI.error("If you use a Gemfile add this to your Gemfile:")
18
+ UI.important(" gem '#{gem_name}'")
19
+ UI.error("and run `bundle install`")
20
+
21
+ UI.user_error!("You have to install the `#{gem_name}` gem on this machine") unless Helper.test?
22
+ end
23
+ true
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,135 @@
1
+ module Pantograph
2
+ module Actions
3
+ GIT_MERGE_COMMIT_FILTERING_OPTIONS = [:include_merges, :exclude_merges, :only_include_merges].freeze
4
+
5
+ def self.git_log_between(pretty_format, from, to, merge_commit_filtering, date_format = nil, ancestry_path)
6
+ command = %w(git log)
7
+ command << "--pretty=#{pretty_format}"
8
+ command << "--date=#{date_format}" if date_format
9
+ command << '--ancestry-path' if ancestry_path
10
+ command << "#{from}...#{to}"
11
+ command << git_log_merge_commit_filtering_option(merge_commit_filtering)
12
+ # "*command" syntax expands "command" array into variable arguments, which
13
+ # will then be individually shell-escaped by Actions.sh.
14
+ Actions.sh(*command.compact, log: false).chomp
15
+ rescue
16
+ nil
17
+ end
18
+
19
+ def self.git_log_last_commits(pretty_format, commit_count, merge_commit_filtering, date_format = nil, ancestry_path)
20
+ command = %w(git log)
21
+ command << "--pretty=#{pretty_format}"
22
+ command << "--date=#{date_format}" if date_format
23
+ command << '--ancestry-path' if ancestry_path
24
+ command << '-n' << commit_count.to_s
25
+ command << git_log_merge_commit_filtering_option(merge_commit_filtering)
26
+ Actions.sh(*command.compact, log: false).chomp
27
+ rescue
28
+ nil
29
+ end
30
+
31
+ def self.last_git_tag_hash(tag_match_pattern = nil)
32
+ tag_pattern_param = tag_match_pattern ? "=#{tag_match_pattern}" : ''
33
+ Actions.sh('git', 'rev-list', "--tags#{tag_pattern_param}", '--max-count=1').chomp
34
+ rescue
35
+ nil
36
+ end
37
+
38
+ def self.last_git_tag_name(match_lightweight = true, tag_match_pattern = nil)
39
+ hash = last_git_tag_hash(tag_match_pattern)
40
+ # If hash is nil (command fails), "git describe" command below will still
41
+ # run and provide some output, although it's definitely not going to be
42
+ # anything reasonably expected. Bail out early.
43
+ return unless hash
44
+
45
+ command = %w(git describe)
46
+ command << '--tags' if match_lightweight
47
+ command << hash
48
+ Actions.sh(*command.compact, log: false).chomp
49
+ rescue
50
+ nil
51
+ end
52
+
53
+ def self.last_git_commit_dict
54
+ return nil if last_git_commit_formatted_with('%an').nil?
55
+
56
+ {
57
+ author: last_git_commit_formatted_with('%an'),
58
+ author_email: last_git_commit_formatted_with('%ae'),
59
+ message: last_git_commit_formatted_with('%B'),
60
+ commit_hash: last_git_commit_formatted_with('%H'),
61
+ abbreviated_commit_hash: last_git_commit_formatted_with('%h')
62
+ }
63
+ end
64
+
65
+ # Gets the last git commit information formatted into a String by the provided
66
+ # pretty format String. See the git-log documentation for valid format placeholders
67
+ def self.last_git_commit_formatted_with(pretty_format, date_format = nil)
68
+ command = %w(git log -1)
69
+ command << "--pretty=#{pretty_format}"
70
+ command << "--date=#{date_format}" if date_format
71
+ Actions.sh(*command.compact, log: false).chomp
72
+ rescue
73
+ nil
74
+ end
75
+
76
+ # @deprecated Use <tt>git_author_email</tt> instead
77
+ # Get the author email of the last git commit
78
+ # <b>DEPRECATED:</b> Use <tt>git_author_email</tt> instead.
79
+ def self.git_author
80
+ UI.deprecated('`git_author` is deprecated. Please use `git_author_email` instead.')
81
+ git_author_email
82
+ end
83
+
84
+ # Get the author email of the last git commit
85
+ def self.git_author_email
86
+ s = last_git_commit_formatted_with('%ae')
87
+ return s if s.to_s.length > 0
88
+ return nil
89
+ end
90
+
91
+ # Returns the unwrapped subject and body of the last commit
92
+ # <b>DEPRECATED:</b> Use <tt>last_git_commit_message</tt> instead.
93
+ def self.last_git_commit
94
+ UI.important('`last_git_commit` is deprecated. Please use `last_git_commit_message` instead.')
95
+ last_git_commit_message
96
+ end
97
+
98
+ # Returns the unwrapped subject and body of the last commit
99
+ def self.last_git_commit_message
100
+ s = (last_git_commit_formatted_with('%B') || "").strip
101
+ return s if s.to_s.length > 0
102
+ nil
103
+ end
104
+
105
+ # Get the hash of the last commit
106
+ def self.last_git_commit_hash(short)
107
+ format_specifier = short ? '%h' : '%H'
108
+ string = last_git_commit_formatted_with(format_specifier).to_s
109
+ return string unless string.empty?
110
+ return nil
111
+ end
112
+
113
+ # Returns the current git branch - can be replaced using the environment variable `GIT_BRANCH`
114
+ def self.git_branch
115
+ return ENV['GIT_BRANCH'] if ENV['GIT_BRANCH'].to_s.length > 0 # set by Jenkins
116
+ s = Actions.sh("git rev-parse --abbrev-ref HEAD", log: false).chomp
117
+ return s.to_s.strip if s.to_s.length > 0
118
+ nil
119
+ rescue
120
+ nil
121
+ end
122
+
123
+ private_class_method
124
+ def self.git_log_merge_commit_filtering_option(merge_commit_filtering)
125
+ case merge_commit_filtering
126
+ when :exclude_merges
127
+ "--no-merges"
128
+ when :only_include_merges
129
+ "--merges"
130
+ when :include_merges
131
+ nil
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,62 @@
1
+ module Pantograph
2
+ module Helper
3
+ class GradleTask
4
+ attr_accessor :title
5
+
6
+ attr_accessor :description
7
+
8
+ def initialize(title: nil, description: nil)
9
+ self.title = title
10
+ self.description = description
11
+ end
12
+ end
13
+
14
+ class GradleHelper
15
+ # Path to the gradle script
16
+ attr_accessor :gradle_path
17
+
18
+ # Read-only path to the shell-escaped gradle script, suitable for use in shell commands
19
+ attr_reader :escaped_gradle_path
20
+
21
+ # All the available tasks
22
+ attr_accessor :tasks
23
+
24
+ def initialize(gradle_path: nil)
25
+ self.gradle_path = gradle_path
26
+ end
27
+
28
+ # Run a certain action
29
+ def trigger(task: nil, flags: nil, serial: nil, print_command: true, print_command_output: true)
30
+ android_serial = (serial != "") ? "ANDROID_SERIAL=#{serial}" : nil
31
+ command = [android_serial, escaped_gradle_path, task, flags].compact.join(" ")
32
+ Action.sh(command, print_command: print_command, print_command_output: print_command_output)
33
+ end
34
+
35
+ def task_available?(task)
36
+ load_all_tasks
37
+ return tasks.collect(&:title).include?(task)
38
+ end
39
+
40
+ def gradle_path=(gradle_path)
41
+ @gradle_path = gradle_path
42
+ @escaped_gradle_path = gradle_path.shellescape
43
+ end
44
+
45
+ private
46
+
47
+ def load_all_tasks
48
+ self.tasks = []
49
+
50
+ command = [escaped_gradle_path, "tasks", "--console=plain"].join(" ")
51
+ output = Action.sh(command, print_command: false, print_command_output: false)
52
+ output.split("\n").each do |line|
53
+ if (result = line.match(/(\w+)\s\-\s([\w\s]+)/))
54
+ self.tasks << GradleTask.new(title: result[1], description: result[2])
55
+ end
56
+ end
57
+
58
+ self.tasks
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,134 @@
1
+ require "open3"
2
+
3
+ module Pantograph
4
+ module Actions
5
+ # Execute a shell command
6
+ # This method will output the string and execute it
7
+ # Just an alias for sh_no_action
8
+ # When running this in tests, it will return the actual command instead of executing it
9
+ # @param log [Boolean] should pantograph print out the executed command
10
+ # @param error_callback [Block] a callback invoked with the command output if there is a non-zero exit status
11
+ def self.sh(*command, log: true, error_callback: nil, &b)
12
+ sh_control_output(*command, print_command: log, print_command_output: log, error_callback: error_callback, &b)
13
+ end
14
+
15
+ def self.sh_no_action(*command, log: true, error_callback: nil, &b)
16
+ sh_control_output(*command, print_command: log, print_command_output: log, error_callback: error_callback, &b)
17
+ end
18
+
19
+ # @param command The command to be executed (variadic)
20
+ # @param print_command [Boolean] Should we print the command that's being executed
21
+ # @param print_command_output [Boolean] Should we print the command output during execution
22
+ # @param error_callback [Block] A block that's called if the command exits with a non-zero status
23
+ # @yield [status, result, cmd] The return status of the command, all output from the command and an equivalent shell command
24
+ # @yieldparam [Process::Status] status A Process::Status indicating the status of the completed command
25
+ # @yieldparam [String] result The complete output to stdout and stderr of the completed command
26
+ # @yieldparam [String] cmd A shell command equivalent to the arguments passed
27
+ # rubocop: disable Metrics/PerceivedComplexity
28
+ def self.sh_control_output(*command, print_command: true, print_command_output: true, error_callback: nil)
29
+ print_command = print_command_output = true if $troubleshoot
30
+ # Set the encoding first, the user might have set it wrong
31
+ previous_encoding = [Encoding.default_external, Encoding.default_internal]
32
+ Encoding.default_external = Encoding::UTF_8
33
+ Encoding.default_internal = Encoding::UTF_8
34
+
35
+ # Workaround to support previous Pantograph syntax.
36
+ # This has some limitations. For example, it requires the caller to shell escape
37
+ # everything because of usages like ["ls -la", "/tmp"] instead of ["ls", "-la", "/tmp"].
38
+ command = [command.first.join(" ")] if command.length == 1 && command.first.kind_of?(Array)
39
+
40
+ shell_command = shell_command_from_args(*command)
41
+ UI.command(shell_command) if print_command
42
+
43
+ result = ''
44
+ exit_status = nil
45
+ if Helper.sh_enabled?
46
+ # The argument list is passed directly to Open3.popen2e, which
47
+ # handles the variadic argument list in the same way as Kernel#spawn.
48
+ # (http://ruby-doc.org/core-2.4.2/Kernel.html#method-i-spawn) or
49
+ # Process.spawn (http://ruby-doc.org/core-2.4.2/Process.html#method-c-spawn).
50
+ #
51
+ # sh "ls -la /Applications/Xcode\ 7.3.1.app"
52
+ # sh "ls", "-la", "/Applications/Xcode 7.3.1.app"
53
+ # sh({ "FOO" => "Hello" }, "echo $FOO")
54
+ Open3.popen2e(*command) do |stdin, io, thread|
55
+ io.sync = true
56
+ io.each do |line|
57
+ UI.command_output(line.strip) if print_command_output
58
+ result << line
59
+ end
60
+ exit_status = thread.value
61
+ end
62
+
63
+ # Checking Process::Status#exitstatus instead of #success? makes for more
64
+ # testable code. (Tests mock exitstatus only.) This is also consistent
65
+ # with previous implementations of sh and... probably portable to all
66
+ # relevant platforms.
67
+ if exit_status.exitstatus != 0
68
+ message = if print_command
69
+ "Exit status of command '#{shell_command}' was #{exit_status.exitstatus} instead of 0."
70
+ else
71
+ "Shell command exited with exit status #{exit_status.exitstatus} instead of 0."
72
+ end
73
+ message += "\n#{result}" if print_command_output
74
+
75
+ if error_callback || block_given?
76
+ UI.error(message)
77
+ # block notified below, on success or failure
78
+ error_callback && error_callback.call(result)
79
+ else
80
+ UI.shell_error!(message)
81
+ end
82
+ end
83
+ else
84
+ result << shell_command # only for the tests
85
+ end
86
+
87
+ if block_given?
88
+ # Avoid yielding nil in tests. $? will be meaningless, but calls to
89
+ # it will not crash. There is no Process::Status.new. The alternative
90
+ # is to move this inside the sh_enabled? check and not yield in tests.
91
+ return yield(exit_status || $?, result, shell_command)
92
+ end
93
+ result
94
+ rescue => ex
95
+ raise ex
96
+ ensure
97
+ Encoding.default_external = previous_encoding.first
98
+ Encoding.default_internal = previous_encoding.last
99
+ end
100
+ # rubocop: enable Metrics/PerceivedComplexity
101
+
102
+ # Used to produce a shell command string from a list of arguments that may
103
+ # be passed to methods such as Kernel#system, Kernel#spawn and Open3.popen2e
104
+ # in order to print the command to the terminal. The same *args are passed
105
+ # directly to a system call (Open3.popen2e). This interpretation is not
106
+ # used when executing a command.
107
+ #
108
+ # @param args Any number of arguments used to construct a command
109
+ # @raise [ArgumentError] If no arguments passed
110
+ # @return [String] A shell command representing the arguments passed in
111
+ def self.shell_command_from_args(*args)
112
+ raise ArgumentError, "sh requires at least one argument" unless args.count > 0
113
+
114
+ command = ""
115
+
116
+ # Optional initial environment Hash
117
+ if args.first.kind_of?(Hash)
118
+ command = args.shift.map { |k, v| "#{k}=#{v.shellescape}" }.join(" ") + " "
119
+ end
120
+
121
+ # Support [ "/usr/local/bin/foo", "foo" ], "-x", ...
122
+ if args.first.kind_of?(Array)
123
+ command += args.shift.first.shellescape + " " + args.shelljoin
124
+ command.chomp!(" ")
125
+ elsif args.count == 1 && args.first.kind_of?(String)
126
+ command += args.first
127
+ else
128
+ command += args.shelljoin
129
+ end
130
+
131
+ command
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,27 @@
1
+ module Pantograph
2
+ class JUnitGenerator
3
+ def self.generate(results)
4
+ # JUnit file documentation: http://llg.cubic.org/docs/junit/
5
+ # And http://nelsonwells.net/2012/09/how-jenkins-ci-parses-and-displays-junit-output/
6
+ # And http://windyroad.com.au/dl/Open%20Source/JUnit.xsd
7
+
8
+ containing_folder = ENV['FL_REPORT_PATH'] || PantographCore::PantographFolder.path || Dir.pwd
9
+ path = File.join(containing_folder, 'report.xml')
10
+
11
+ @steps = results
12
+ xml_path = File.join(Pantograph::ROOT, "lib/assets/report_template.xml.erb")
13
+ xml = ERB.new(File.read(xml_path)).result(binding) # https://web.archive.org/web/20160430190141/www.rrn.dk/rubys-erb-templating-system
14
+
15
+ xml = xml.gsub('system_', 'system-').delete("\e") # Jenkins can not parse 'ESC' symbol
16
+
17
+ begin
18
+ File.write(path, xml)
19
+ rescue => ex
20
+ UI.error(ex)
21
+ UI.error("Couldn't save report.xml at path '#{File.expand_path(path)}', make sure you have write access to the containing directory.")
22
+ end
23
+
24
+ return path
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,97 @@
1
+ module Pantograph
2
+ # Represents a lane
3
+ class Lane
4
+ attr_accessor :platform
5
+
6
+ attr_accessor :name
7
+
8
+ # @return [Array] An array containing the description of this lane
9
+ # Each item of the array is one line
10
+ attr_accessor :description
11
+
12
+ attr_accessor :block
13
+
14
+ # @return [Boolean] Is that a private lane that can't be called from the CLI?
15
+ attr_accessor :is_private
16
+
17
+ def initialize(platform: nil, name: nil, description: nil, block: nil, is_private: false)
18
+ UI.user_error!("description must be an array") unless description.kind_of?(Array)
19
+ UI.user_error!("lane name must not contain any spaces") if name.to_s.include?(" ")
20
+ UI.user_error!("lane name must start with :") unless name.kind_of?(Symbol)
21
+
22
+ self.class.verify_lane_name(name)
23
+
24
+ self.platform = platform
25
+ self.name = name
26
+ self.description = description
27
+ self.block = block
28
+ self.is_private = is_private
29
+ end
30
+
31
+ # Execute this lane
32
+ def call(parameters)
33
+ block.call(parameters || {})
34
+ end
35
+
36
+ # @return [String] The lane + name of the lane. If there is no platform, it will only be the lane name
37
+ def pretty_name
38
+ [platform, name].reject(&:nil?).join(' ')
39
+ end
40
+
41
+ class << self
42
+ # Makes sure the lane name is valid
43
+ def verify_lane_name(name)
44
+ if self.black_list.include?(name.to_s)
45
+ UI.error("Lane name '#{name}' is invalid! Invalid names are #{self.black_list.join(', ')}.")
46
+ UI.user_error!("Lane name '#{name}' is invalid")
47
+ end
48
+
49
+ if self.gray_list.include?(name.to_sym)
50
+ UI.error("------------------------------------------------")
51
+ UI.error("Lane name '#{name}' should not be used because it is the name of a pantograph tool")
52
+ UI.error("It is recommended to not use '#{name}' as the name of your lane")
53
+ UI.error("------------------------------------------------")
54
+ # We still allow it, because we're nice
55
+ # Otherwise we might break existing setups
56
+ return
57
+ end
58
+
59
+ self.ensure_name_not_conflicts(name.to_s)
60
+ end
61
+
62
+ def black_list
63
+ %w(
64
+ run
65
+ init
66
+ new_action
67
+ lanes
68
+ list
69
+ docs
70
+ action
71
+ actions
72
+ enable_auto_complete
73
+ new_plugin
74
+ add_plugin
75
+ install_plugins
76
+ update_plugins
77
+ search_plugins
78
+ help
79
+ env
80
+ update_pantograph
81
+ )
82
+ end
83
+
84
+ def gray_list
85
+ Pantograph::TOOLS
86
+ end
87
+
88
+ def ensure_name_not_conflicts(name)
89
+ # First, check if there is a predefined method in the actions folder
90
+ return unless Actions.action_class_ref(name)
91
+ UI.error("------------------------------------------------")
92
+ UI.error("Name of the lane '#{name}' is already taken by the action named '#{name}'")
93
+ UI.error("------------------------------------------------")
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,77 @@
1
+ module Pantograph
2
+ class LaneList
3
+ # Print out the result of `generate`
4
+
5
+ def self.output(path)
6
+ puts(generate(path))
7
+
8
+ puts("Execute using `pantograph [lane_name]`".yellow)
9
+ end
10
+
11
+ def self.generate(path)
12
+ ff = Pantograph::PantFile.new(path)
13
+ lanes = ff.runner.lanes
14
+
15
+ output = ""
16
+
17
+ all_keys = lanes.keys.reject(&:nil?)
18
+ all_keys.unshift(nil) # because we want root elements on top. always! They have key nil
19
+
20
+ all_keys.each do |platform|
21
+ next if (lanes[platform] || []).count == 0
22
+
23
+ plat_text = platform
24
+ plat_text = "general" if platform.to_s.empty?
25
+ output += "\n--------- #{plat_text}---------\n".yellow
26
+
27
+ value = lanes[platform]
28
+ next unless value
29
+
30
+ value.each do |lane_name, lane|
31
+ next if lane.is_private
32
+
33
+ output += "----- pantograph #{lane.pretty_name}".green
34
+ if lane.description.count > 0
35
+ output += "\n" + lane.description.join("\n") + "\n\n"
36
+ else
37
+ output += "\n\n"
38
+ end
39
+ end
40
+ end
41
+
42
+ output
43
+ end
44
+
45
+ def self.output_json(path)
46
+ puts(JSON.pretty_generate(self.generate_json(path)))
47
+ end
48
+
49
+ # Returns a hash
50
+ def self.generate_json(path)
51
+ output = {}
52
+ return output if path.nil?
53
+ ff = Pantograph::PantFile.new(path)
54
+
55
+ all_keys = ff.runner.lanes.keys
56
+
57
+ all_keys.each do |platform|
58
+ next if (ff.runner.lanes[platform] || []).count == 0
59
+
60
+ output[platform] ||= {}
61
+
62
+ value = ff.runner.lanes[platform]
63
+ next unless value
64
+
65
+ value.each do |lane_name, lane|
66
+ next if lane.is_private
67
+
68
+ output[platform][lane_name] = {
69
+ description: lane.description.join("\n")
70
+ }
71
+ end
72
+ end
73
+
74
+ return output
75
+ end
76
+ end
77
+ end