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,288 @@
1
+ # rubocop:disable Style/CaseEquality
2
+ # rubocop:disable Style/MultilineTernaryOperator
3
+ # rubocop:disable Style/NestedTernaryOperator
4
+ module Pantograph
5
+ module Actions
6
+ class SlackAction < Action
7
+ def self.is_supported?(platform)
8
+ true
9
+ end
10
+
11
+ # As there is a text limit in the notifications, we are
12
+ # usually interested in the last part of the message
13
+ # e.g. for tests
14
+ def self.trim_message(message)
15
+ # We want the last 7000 characters, instead of the first 7000, as the error is at the bottom
16
+ start_index = [message.length - 7000, 0].max
17
+ message = message[start_index..-1]
18
+ # We want line breaks to be shown on slack output so we replace
19
+ # input non-interpreted line break with interpreted line break
20
+ message.gsub('\n', "\n")
21
+ end
22
+
23
+ def self.run(options)
24
+ require 'slack-notifier'
25
+
26
+ options[:message] = self.trim_message(options[:message].to_s || '')
27
+ options[:message] = Slack::Notifier::Util::LinkFormatter.format(options[:message])
28
+
29
+ options[:pretext] = options[:pretext].gsub('\n', "\n") unless options[:pretext].nil?
30
+
31
+ if options[:channel].to_s.length > 0
32
+ channel = options[:channel]
33
+ channel = ('#' + options[:channel]) unless ['#', '@'].include?(channel[0]) # send message to channel by default
34
+ end
35
+
36
+ username = options[:use_webhook_configured_username_and_icon] ? nil : options[:username]
37
+
38
+ notifier = Slack::Notifier.new(options[:slack_url], channel: channel, username: username)
39
+
40
+ link_names = options[:link_names]
41
+
42
+ icon_url = options[:use_webhook_configured_username_and_icon] ? nil : options[:icon_url]
43
+
44
+ slack_attachment = generate_slack_attachments(options)
45
+
46
+ return [notifier, slack_attachment] if Helper.test? # tests will verify the slack attachments and other properties
47
+
48
+ begin
49
+ results = notifier.ping('', link_names: link_names, icon_url: icon_url, attachments: [slack_attachment])
50
+ rescue => exception
51
+ UI.error("Exception: #{exception}")
52
+ ensure
53
+ result = results.first if results
54
+ if !result.nil? && result.code.to_i == 200
55
+ UI.success('Successfully sent Slack notification')
56
+ else
57
+ UI.verbose(result) unless result.nil?
58
+ message = "Error pushing Slack message, maybe the integration has no permission to post on this channel? Try removing the channel parameter in your Pantfile, this is usually caused by a misspelled or changed group/channel name or an expired SLACK_URL"
59
+ if options[:fail_on_error]
60
+ UI.user_error!(message)
61
+ else
62
+ UI.error(message)
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ def self.description
69
+ "Send a success/error message to your [Slack](https://slack.com) group"
70
+ end
71
+
72
+ def self.available_options
73
+ [
74
+ PantographCore::ConfigItem.new(key: :message,
75
+ env_name: "FL_SLACK_MESSAGE",
76
+ description: "The message that should be displayed on Slack. This supports the standard Slack markup language",
77
+ optional: true),
78
+ PantographCore::ConfigItem.new(key: :pretext,
79
+ env_name: "FL_SLACK_PRETEXT",
80
+ description: "This is optional text that appears above the message attachment block. This supports the standard Slack markup language",
81
+ optional: true),
82
+ PantographCore::ConfigItem.new(key: :channel,
83
+ env_name: "FL_SLACK_CHANNEL",
84
+ description: "#channel or @username",
85
+ optional: true),
86
+ PantographCore::ConfigItem.new(key: :use_webhook_configured_username_and_icon,
87
+ env_name: "FL_SLACK_USE_WEBHOOK_CONFIGURED_USERNAME_AND_ICON",
88
+ description: "Use webhook's default username and icon settings? (true/false)",
89
+ default_value: false,
90
+ is_string: false,
91
+ optional: true),
92
+ PantographCore::ConfigItem.new(key: :slack_url,
93
+ env_name: "SLACK_URL",
94
+ sensitive: true,
95
+ description: "Create an Incoming WebHook for your Slack group",
96
+ verify_block: proc do |value|
97
+ UI.user_error!("Invalid URL, must start with https://") unless value.start_with?("https://")
98
+ end),
99
+ PantographCore::ConfigItem.new(key: :username,
100
+ env_name: "FL_SLACK_USERNAME",
101
+ description: "Overrides the webhook's username property if use_webhook_configured_username_and_icon is false",
102
+ default_value: "pantograph",
103
+ is_string: true,
104
+ optional: true),
105
+ PantographCore::ConfigItem.new(key: :icon_url,
106
+ env_name: "FL_SLACK_ICON_URL",
107
+ description: "Overrides the webhook's image property if use_webhook_configured_username_and_icon is false",
108
+ default_value: "https://s3-eu-west-1.amazonaws.com/pantograph.tools/pantograph.png",
109
+ is_string: true,
110
+ optional: true),
111
+ PantographCore::ConfigItem.new(key: :payload,
112
+ env_name: "FL_SLACK_PAYLOAD",
113
+ description: "Add additional information to this post. payload must be a hash containing any key with any value",
114
+ default_value: {},
115
+ is_string: false),
116
+ PantographCore::ConfigItem.new(key: :default_payloads,
117
+ env_name: "FL_SLACK_DEFAULT_PAYLOADS",
118
+ description: "Remove some of the default payloads. More information about the available payloads on GitHub",
119
+ optional: true,
120
+ type: Array),
121
+ PantographCore::ConfigItem.new(key: :attachment_properties,
122
+ env_name: "FL_SLACK_ATTACHMENT_PROPERTIES",
123
+ description: "Merge additional properties in the slack attachment, see https://api.slack.com/docs/attachments",
124
+ default_value: {},
125
+ is_string: false),
126
+ PantographCore::ConfigItem.new(key: :success,
127
+ env_name: "FL_SLACK_SUCCESS",
128
+ description: "Was this build successful? (true/false)",
129
+ optional: true,
130
+ default_value: true,
131
+ is_string: false),
132
+ PantographCore::ConfigItem.new(key: :fail_on_error,
133
+ env_name: "FL_SLACK_FAIL_ON_ERROR",
134
+ description: "Should an error sending the slack notification cause a failure? (true/false)",
135
+ optional: true,
136
+ default_value: true,
137
+ is_string: false),
138
+ PantographCore::ConfigItem.new(key: :link_names,
139
+ env_name: "FL_SLACK_LINK_NAMES",
140
+ description: "Find and link channel names and usernames (true/false)",
141
+ optional: true,
142
+ default_value: false,
143
+ is_string: false)
144
+ ]
145
+ end
146
+
147
+ def self.author
148
+ "KrauseFx"
149
+ end
150
+
151
+ def self.example_code
152
+ [
153
+ 'slack(message: "App successfully released!")',
154
+ 'slack(
155
+ message: "App successfully released!",
156
+ channel: "#channel", # Optional, by default will post to the default channel configured for the POST URL.
157
+ success: true, # Optional, defaults to true.
158
+ payload: { # Optional, lets you specify any number of your own Slack attachments.
159
+ "Build Date" => Time.new.to_s,
160
+ "Built by" => "Jenkins",
161
+ },
162
+ default_payloads: [:git_branch, :git_author], # Optional, lets you specify a whitelist of default payloads to include. Pass an empty array to suppress all the default payloads.
163
+ # Don\'t add this key, or pass nil, if you want all the default payloads. The available default payloads are: `lane`, `test_result`, `git_branch`, `git_author`, `last_git_commit`, `last_git_commit_hash`.
164
+ attachment_properties: { # Optional, lets you specify any other properties available for attachments in the slack API (see https://api.slack.com/docs/attachments).
165
+ # This hash is deep merged with the existing properties set using the other properties above. This allows your own fields properties to be appended to the existing fields that were created using the `payload` property for instance.
166
+ thumb_url: "http://example.com/path/to/thumb.png",
167
+ fields: [{
168
+ title: "My Field",
169
+ value: "My Value",
170
+ short: true
171
+ }]
172
+ }
173
+ )'
174
+ ]
175
+ end
176
+
177
+ def self.category
178
+ :notifications
179
+ end
180
+
181
+ def self.details
182
+ "Create an Incoming WebHook and export this as `SLACK_URL`. Can send a message to **#channel** (by default), a direct message to **@username** or a message to a private group **group** with success (green) or failure (red) status."
183
+ end
184
+
185
+ #####################################################
186
+ # @!group Helper
187
+ #####################################################
188
+
189
+ def self.generate_slack_attachments(options)
190
+ color = (options[:success] ? 'good' : 'danger')
191
+ should_add_payload = ->(payload_name) { options[:default_payloads].nil? || options[:default_payloads].map(&:to_sym).include?(payload_name.to_sym) }
192
+
193
+ slack_attachment = {
194
+ fallback: options[:message],
195
+ text: options[:message],
196
+ pretext: options[:pretext],
197
+ color: color,
198
+ mrkdwn_in: ["pretext", "text", "fields", "message"],
199
+ fields: []
200
+ }
201
+
202
+ # custom user payloads
203
+ slack_attachment[:fields] += options[:payload].map do |k, v|
204
+ {
205
+ title: k.to_s,
206
+ value: Slack::Notifier::Util::LinkFormatter.format(v.to_s),
207
+ short: false
208
+ }
209
+ end
210
+
211
+ # Add the lane to the Slack message
212
+ # This might be nil, if slack is called as "one-off" action
213
+ if should_add_payload[:lane] && Actions.lane_context[Actions::SharedValues::LANE_NAME]
214
+ slack_attachment[:fields] << {
215
+ title: 'Lane',
216
+ value: Actions.lane_context[Actions::SharedValues::LANE_NAME],
217
+ short: true
218
+ }
219
+ end
220
+
221
+ # test_result
222
+ if should_add_payload[:test_result]
223
+ slack_attachment[:fields] << {
224
+ title: 'Result',
225
+ value: (options[:success] ? 'Success' : 'Error'),
226
+ short: true
227
+ }
228
+ end
229
+
230
+ # git branch
231
+ if Actions.git_branch && should_add_payload[:git_branch]
232
+ slack_attachment[:fields] << {
233
+ title: 'Git Branch',
234
+ value: Actions.git_branch,
235
+ short: true
236
+ }
237
+ end
238
+
239
+ # git_author
240
+ if Actions.git_author_email && should_add_payload[:git_author]
241
+ if PantographCore::Env.truthy?('PANTOGRAPH_SLACK_HIDE_AUTHOR_ON_SUCCESS') && options[:success]
242
+ # We only show the git author if the build failed
243
+ else
244
+ slack_attachment[:fields] << {
245
+ title: 'Git Author',
246
+ value: Actions.git_author_email,
247
+ short: true
248
+ }
249
+ end
250
+ end
251
+
252
+ # last_git_commit
253
+ if Actions.last_git_commit_message && should_add_payload[:last_git_commit]
254
+ slack_attachment[:fields] << {
255
+ title: 'Git Commit',
256
+ value: Actions.last_git_commit_message,
257
+ short: false
258
+ }
259
+ end
260
+
261
+ # last_git_commit_hash
262
+ if Actions.last_git_commit_hash(true) && should_add_payload[:last_git_commit_hash]
263
+ slack_attachment[:fields] << {
264
+ title: 'Git Commit Hash',
265
+ value: Actions.last_git_commit_hash(short: true),
266
+ short: false
267
+ }
268
+ end
269
+
270
+ # merge additional properties
271
+ deep_merge(slack_attachment, options[:attachment_properties])
272
+ end
273
+
274
+ # Adapted from https://stackoverflow.com/a/30225093/158525
275
+ def self.deep_merge(a, b)
276
+ merger = proc do |key, v1, v2|
277
+ Hash === v1 && Hash === v2 ?
278
+ v1.merge(v2, &merger) : Array === v1 && Array === v2 ?
279
+ v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2
280
+ end
281
+ a.merge(b, &merger)
282
+ end
283
+ end
284
+ end
285
+ end
286
+ # rubocop:enable Style/CaseEquality
287
+ # rubocop:enable Style/MultilineTernaryOperator
288
+ # rubocop:enable Style/NestedTernaryOperator
@@ -0,0 +1,156 @@
1
+ module Pantograph
2
+ module Actions
3
+ class SonarAction < Action
4
+ def self.run(params)
5
+ verify_sonar_scanner_binary
6
+
7
+ command_prefix = [
8
+ 'cd',
9
+ File.expand_path('.').shellescape,
10
+ '&&'
11
+ ].join(' ')
12
+
13
+ sonar_scanner_args = []
14
+ sonar_scanner_args << "-Dproject.settings=\"#{params[:project_configuration_path]}\"" if params[:project_configuration_path]
15
+ sonar_scanner_args << "-Dsonar.projectKey=\"#{params[:project_key]}\"" if params[:project_key]
16
+ sonar_scanner_args << "-Dsonar.projectName=\"#{params[:project_name]}\"" if params[:project_name]
17
+ sonar_scanner_args << "-Dsonar.projectVersion=\"#{params[:project_version]}\"" if params[:project_version]
18
+ sonar_scanner_args << "-Dsonar.sources=\"#{params[:sources_path]}\"" if params[:sources_path]
19
+ sonar_scanner_args << "-Dsonar.language=\"#{params[:project_language]}\"" if params[:project_language]
20
+ sonar_scanner_args << "-Dsonar.sourceEncoding=\"#{params[:source_encoding]}\"" if params[:source_encoding]
21
+ sonar_scanner_args << "-Dsonar.login=\"#{params[:sonar_login]}\"" if params[:sonar_login]
22
+ sonar_scanner_args << "-Dsonar.host.url=\"#{params[:sonar_url]}\"" if params[:sonar_url]
23
+ sonar_scanner_args << "-Dsonar.branch.name=\"#{params[:branch_name]}\"" if params[:branch_name]
24
+ sonar_scanner_args << "-Dsonar.pullrequest.branch=\"#{params[:pull_request_branch]}\"" if params[:pull_request_branch]
25
+ sonar_scanner_args << "-Dsonar.pullrequest.base=\"#{params[:pull_request_base]}\"" if params[:pull_request_base]
26
+ sonar_scanner_args << "-Dsonar.pullrequest.key=\"#{params[:pull_request_key]}\"" if params[:pull_request_key]
27
+ sonar_scanner_args << params[:sonar_runner_args] if params[:sonar_runner_args]
28
+
29
+ command = [
30
+ command_prefix,
31
+ 'sonar-scanner',
32
+ sonar_scanner_args
33
+ ].join(' ')
34
+ # hide command, as it may contain credentials
35
+ Pantograph::Actions.sh_control_output(command, print_command: false, print_command_output: true)
36
+ end
37
+
38
+ def self.verify_sonar_scanner_binary
39
+ UI.user_error!("You have to install sonar-scanner using `brew install sonar-scanner`") unless `which sonar-scanner`.to_s.length > 0
40
+ end
41
+
42
+ #####################################################
43
+ # @!group Documentation
44
+ #####################################################
45
+
46
+ def self.description
47
+ "Invokes sonar-scanner to programmatically run SonarQube analysis"
48
+ end
49
+
50
+ def self.details
51
+ [
52
+ "See [http://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner](http://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner) for details.",
53
+ "It can process unit test results if formatted as junit report as shown in [xctest](https://docs.pantograph.tools/actions/xctest/) action. It can also integrate coverage reports in Cobertura format, which can be transformed into by the [slather](https://docs.pantograph.tools/actions/slather/) action."
54
+ ].join("\n")
55
+ end
56
+
57
+ def self.available_options
58
+ [
59
+ PantographCore::ConfigItem.new(key: :project_configuration_path,
60
+ env_name: "FL_SONAR_RUNNER_PROPERTIES_PATH",
61
+ description: "The path to your sonar project configuration file; defaults to `sonar-project.properties`", # default is enforced by sonar-scanner binary
62
+ optional: true,
63
+ verify_block: proc do |value|
64
+ UI.user_error!("Couldn't find file at path '#{value}'") unless value.nil? || File.exist?(value)
65
+ end),
66
+ PantographCore::ConfigItem.new(key: :project_key,
67
+ env_name: "FL_SONAR_RUNNER_PROJECT_KEY",
68
+ description: "The key sonar uses to identify the project, e.g. `name.gretzki.awesomeApp`. Must either be specified here or inside the sonar project configuration file",
69
+ optional: true),
70
+ PantographCore::ConfigItem.new(key: :project_name,
71
+ env_name: "FL_SONAR_RUNNER_PROJECT_NAME",
72
+ description: "The name of the project that gets displayed on the sonar report page. Must either be specified here or inside the sonar project configuration file",
73
+ optional: true),
74
+ PantographCore::ConfigItem.new(key: :project_version,
75
+ env_name: "FL_SONAR_RUNNER_PROJECT_VERSION",
76
+ description: "The project's version that gets displayed on the sonar report page. Must either be specified here or inside the sonar project configuration file",
77
+ optional: true),
78
+ PantographCore::ConfigItem.new(key: :sources_path,
79
+ env_name: "FL_SONAR_RUNNER_SOURCES_PATH",
80
+ description: "Comma-separated paths to directories containing source files. Must either be specified here or inside the sonar project configuration file",
81
+ optional: true),
82
+ PantographCore::ConfigItem.new(key: :project_language,
83
+ env_name: "FL_SONAR_RUNNER_PROJECT_LANGUAGE",
84
+ description: "Language key, e.g. objc",
85
+ optional: true),
86
+ PantographCore::ConfigItem.new(key: :source_encoding,
87
+ env_name: "FL_SONAR_RUNNER_SOURCE_ENCODING",
88
+ description: "Used encoding of source files, e.g., UTF-8",
89
+ optional: true),
90
+ PantographCore::ConfigItem.new(key: :sonar_runner_args,
91
+ env_name: "FL_SONAR_RUNNER_ARGS",
92
+ description: "Pass additional arguments to sonar-scanner. Be sure to provide the arguments with a leading `-D` e.g. FL_SONAR_RUNNER_ARGS=\"-Dsonar.verbose=true\"",
93
+ optional: true),
94
+ PantographCore::ConfigItem.new(key: :sonar_login,
95
+ env_name: "FL_SONAR_LOGIN",
96
+ description: "Pass the Sonar Login token (e.g: xxxxxxprivate_token_XXXXbXX7e)",
97
+ optional: true,
98
+ is_string: true,
99
+ sensitive: true),
100
+ PantographCore::ConfigItem.new(key: :sonar_url,
101
+ env_name: "FL_SONAR_URL",
102
+ description: "Pass the url of the Sonar server",
103
+ optional: true,
104
+ is_string: true),
105
+ PantographCore::ConfigItem.new(key: :branch_name,
106
+ env_name: "FL_SONAR_RUNNER_BRANCH_NAME",
107
+ description: "Pass the branch name which is getting scanned",
108
+ optional: true,
109
+ is_string: true),
110
+ PantographCore::ConfigItem.new(key: :pull_request_branch,
111
+ env_name: "FL_SONAR_RUNNER_PULL_REQUEST_BRANCH",
112
+ description: "The name of the branch that contains the changes to be merged",
113
+ optional: true,
114
+ is_string: true),
115
+ PantographCore::ConfigItem.new(key: :pull_request_base,
116
+ env_name: "FL_SONAR_RUNNER_PULL_REQUEST_BASE",
117
+ description: "The long-lived branch into which the PR will be merged",
118
+ optional: true,
119
+ is_string: true),
120
+ PantographCore::ConfigItem.new(key: :pull_request_key,
121
+ env_name: "FL_SONAR_RUNNER_PULL_REQUEST_KEY",
122
+ description: "Unique identifier of your PR. Must correspond to the key of the PR in GitHub or TFS",
123
+ optional: true,
124
+ is_string: true)
125
+ ]
126
+ end
127
+
128
+ def self.return_value
129
+ "The exit code of the sonar-scanner binary"
130
+ end
131
+
132
+ def self.authors
133
+ ["c_gretzki"]
134
+ end
135
+
136
+ def self.is_supported?(platform)
137
+ true
138
+ end
139
+
140
+ def self.example_code
141
+ [
142
+ 'sonar(
143
+ project_key: "name.gretzki.awesomeApp",
144
+ project_version: "1.0",
145
+ project_name: "AwesomeApp",
146
+ sources_path: File.expand_path("../AwesomeApp")
147
+ )'
148
+ ]
149
+ end
150
+
151
+ def self.category
152
+ :testing
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,162 @@
1
+ module Pantograph
2
+ module Actions
3
+ module SharedValues
4
+ SSH_STDOUT_VALUE = :SSH_STDOUT_VALUE
5
+ SSH_STDERR_VALUE = :SSH_STDERR_VALUE
6
+ end
7
+
8
+ class SshAction < Action
9
+ def self.ssh_exec!(ssh, command, log = true)
10
+ stdout_data = ""
11
+ stderr_data = ""
12
+ exit_code = nil
13
+ exit_signal = nil
14
+ ssh.open_channel do |channel|
15
+ channel.exec(command) do |ch, success|
16
+ unless success
17
+ abort("FAILED: couldn't execute command (ssh.channel.exec)")
18
+ end
19
+ channel.on_data do |ch1, data|
20
+ stdout_data += data
21
+ UI.command_output(data) if log
22
+ end
23
+
24
+ channel.on_extended_data do |ch2, type, data|
25
+ # Only type 1 data is stderr (though no other types are defined by the standard)
26
+ # See http://net-ssh.github.io/net-ssh/Net/SSH/Connection/Channel.html#method-i-on_extended_data
27
+ stderr_data += data if type == 1
28
+ end
29
+
30
+ channel.on_request("exit-status") do |ch3, data|
31
+ exit_code = data.read_long
32
+ end
33
+
34
+ channel.on_request("exit-signal") do |ch4, data|
35
+ exit_signal = data.read_long
36
+ end
37
+ end
38
+ end
39
+
40
+ # Wait for all open channels to close
41
+ ssh.loop
42
+ { stdout: stdout_data, stderr: stderr_data, exit_code: exit_code, exit_signal: exit_signal }
43
+ end
44
+
45
+ def self.run(params)
46
+ Actions.verify_gem!('net-ssh')
47
+ require "net/ssh"
48
+
49
+ Actions.lane_context[SharedValues::SSH_STDOUT_VALUE] = ""
50
+ Actions.lane_context[SharedValues::SSH_STDERR_VALUE] = ""
51
+ stdout = ""
52
+ stderr = ""
53
+
54
+ Net::SSH.start(params[:host], params[:username], { port: params[:port].to_i, password: params[:password] }) do |ssh|
55
+ params[:commands].each do |cmd|
56
+ UI.command(cmd) if params[:log]
57
+ return_value = ssh_exec!(ssh, cmd, params[:log])
58
+ if return_value[:exit_code] != 0
59
+ UI.error("SSH Command failed '#{cmd}' Exit-Code: #{return_value[:exit_code]}")
60
+ UI.user_error!("SSH Command failed")
61
+ end
62
+
63
+ stderr << return_value[:stderr]
64
+ stdout << return_value[:stdout]
65
+ end
66
+ end
67
+ command_word = params[:commands].count == 1 ? "command" : "commands"
68
+ UI.success("Successfully executed #{params[:commands].count} #{command_word} on host #{params[:host]}")
69
+ Actions.lane_context[SharedValues::SSH_STDOUT_VALUE] = stdout
70
+ Actions.lane_context[SharedValues::SSH_STDERR_VALUE] = stderr
71
+ return { stdout: Actions.lane_context[SharedValues::SSH_STDOUT_VALUE], stderr: Actions.lane_context[SharedValues::SSH_STDERR_VALUE] }
72
+ end
73
+
74
+ #####################################################
75
+ # @!group Documentation
76
+ #####################################################
77
+
78
+ def self.description
79
+ "Allows remote command execution using ssh"
80
+ end
81
+
82
+ def self.details
83
+ "Lets you execute remote commands via ssh using username/password or ssh-agent. If one of the commands in command-array returns non 0, it fails."
84
+ end
85
+
86
+ def self.available_options
87
+ [
88
+ PantographCore::ConfigItem.new(key: :username,
89
+ short_option: "-u",
90
+ env_name: "FL_SSH_USERNAME",
91
+ description: "Username",
92
+ is_string: true),
93
+ PantographCore::ConfigItem.new(key: :password,
94
+ short_option: "-p",
95
+ env_name: "FL_SSH_PASSWORD",
96
+ sensitive: true,
97
+ description: "Password",
98
+ optional: true,
99
+ is_string: true),
100
+ PantographCore::ConfigItem.new(key: :host,
101
+ short_option: "-H",
102
+ env_name: "FL_SSH_HOST",
103
+ description: "Hostname",
104
+ is_string: true),
105
+ PantographCore::ConfigItem.new(key: :port,
106
+ short_option: "-P",
107
+ env_name: "FL_SSH_PORT",
108
+ description: "Port",
109
+ optional: true,
110
+ default_value: "22",
111
+ is_string: true),
112
+ PantographCore::ConfigItem.new(key: :commands,
113
+ short_option: "-C",
114
+ env_name: "FL_SSH_COMMANDS",
115
+ description: "Commands",
116
+ optional: true,
117
+ is_string: false,
118
+ type: Array),
119
+ PantographCore::ConfigItem.new(key: :log,
120
+ short_option: "-l",
121
+ env_name: "FL_SSH_LOG",
122
+ description: "Log commands and output",
123
+ optional: true,
124
+ default_value: true,
125
+ is_string: false)
126
+ ]
127
+ end
128
+
129
+ def self.output
130
+ [
131
+ ['SSH_STDOUT_VALUE', 'Holds the standard output of all commands'],
132
+ ['SSH_STDERR_VALUE', 'Holds the standard error of all commands']
133
+ ]
134
+ end
135
+
136
+ def self.authors
137
+ ["hjanuschka"]
138
+ end
139
+
140
+ def self.is_supported?(platform)
141
+ true
142
+ end
143
+
144
+ def self.example_code
145
+ [
146
+ 'ssh(
147
+ host: "dev.januschka.com",
148
+ username: "root",
149
+ commands: [
150
+ "date",
151
+ "echo 1 > /tmp/file1"
152
+ ]
153
+ )'
154
+ ]
155
+ end
156
+
157
+ def self.category
158
+ :misc
159
+ end
160
+ end
161
+ end
162
+ end