fastlane-plugin-slack_bot 0.2.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +167 -27
- data/lib/fastlane/plugin/slack_bot/actions/file_upload_to_slack.rb +176 -0
- data/lib/fastlane/plugin/slack_bot/actions/post_to_slack.rb +36 -6
- data/lib/fastlane/plugin/slack_bot/actions/update_slack_message.rb +5 -4
- data/lib/fastlane/plugin/slack_bot/helper/slack_bot_attachments_helper.rb +113 -0
- data/lib/fastlane/plugin/slack_bot/helper/slack_bot_link_formatter_helper.rb +82 -0
- data/lib/fastlane/plugin/slack_bot/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 289a56616a3791c91d4aa9033fe725da23f086ba112f63f383617de611824aa9
|
|
4
|
+
data.tar.gz: 406ed9f6c5809ed39b6ea2024f9c998409bcb11711616006714fdfef28063441
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 821fbff8025635a8c8728e40ceccc52f54db653fc2aaa4ddeed6d7bb5aaec10d78798b19a88282c44ba8168fb0342da8804030bbbf715299827e0b38aca60f9e
|
|
7
|
+
data.tar.gz: d9bd6cc8c9aa8d0dd1704ddd583735f3400a38d2ac440b0a61ff63aa586b079d3b93b75d5f5770f28e523ef097abeaf4142b56ceaefaf77e1f08d0e99e959b2c
|
data/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2021 Manish Rathi
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
## Fastlane `slack_bot` plugin
|
|
2
2
|
|
|
3
|
-
[](https://rubygems.org/gems/fastlane-plugin-slack_bot)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
[](https://rubygems.org/gems/fastlane-plugin-slack_bot)
|
|
4
|
+
![![License]](https://img.shields.io/badge/license-MIT-green.svg?style=flat)
|
|
5
|
+
[](https://badge.fury.io/rb/fastlane-plugin-slack_bot)
|
|
6
|
+
![![RubyGem Download Badge]](https://ruby-gem-downloads-badge.herokuapp.com/fastlane-plugin-slack_bot?type=total)
|
|
7
|
+
[](https://twitter.com/iammanishrathi)
|
|
8
|
+
|
|
9
|
+
A fastlane plugin to customize your automation workflow(s) with a **Slack Bot** 🤖 using the [Slack APIs](https://api.slack.com/)
|
|
10
|
+
|
|
11
|
+
- [About](#about)
|
|
12
|
+
- [Getting Started](#getting-started)
|
|
13
|
+
- [Features](#features)
|
|
14
|
+
- [Post a message](#examples-post-a-message) examples
|
|
15
|
+
- [Upload a file](#examples-upload-a-message) examples
|
|
16
|
+
- [About Fastlane](#about-fastlane)
|
|
17
|
+
|
|
18
|
+
## About
|
|
19
|
+
|
|
20
|
+
A fastlane plugin to post slack message and much more using Slack bot api token. 🚀\
|
|
21
|
+
**Note:** `Fastlane` comes with built-in `slack` action by default, which uses slack webhook url and have webhook limitations.
|
|
22
|
+
i.e Listing couple of slack **webhook url** limitations:
|
|
23
|
+
- can't post a direct message to a slack user.
|
|
24
|
+
- can’t post a message inside a slack thread.
|
|
25
|
+
- can’t update a posted slack message.
|
|
26
|
+
- can’t list and upload a file inside a slack channel.
|
|
27
|
+
- much more, compare to a **Slack Bot** 🤖 using the [Slack APIs](https://api.slack.com/)
|
|
9
28
|
|
|
10
29
|
## Getting Started
|
|
11
30
|
|
|
@@ -23,41 +42,65 @@ fastlane add_plugin slack_bot
|
|
|
23
42
|
```
|
|
24
43
|
If you are using fastlane using Gemfile in your project, add it to your project by running:
|
|
25
44
|
```bash
|
|
26
|
-
bundle exec fastlane add_plugin slack_bot
|
|
45
|
+
bundle exec fastlane add_plugin slack_bot
|
|
27
46
|
```
|
|
28
47
|
|
|
29
|
-
3.
|
|
48
|
+
3. Use `slack_bot` features inside your lane in `Fastfile` whenever you want.
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
Using this `slack_bot` plugin, you can:
|
|
52
|
+
|
|
53
|
+
- Post a message using [chat.postMessage](https://api.slack.com/methods/chat.postMessage) Slack API
|
|
54
|
+
- [x] Post a message to a _public_ channel
|
|
55
|
+
- [x] Post a message to a _private_ channel
|
|
56
|
+
- [x] Post a message to a _slack user_ (DM)
|
|
57
|
+
- [x] Post a message inside a _slack thread_ 🧵
|
|
58
|
+
- [x] Post a message with _custom Bot username and icon_
|
|
59
|
+
|
|
60
|
+
- Update a message using [chat.update](https://api.slack.com/methods/chat.update) Slack API
|
|
61
|
+
- [x] update a message in a channel
|
|
62
|
+
|
|
63
|
+
- List of files in a channel using [files.list](https://api.slack.com/methods/files.list) Slack API
|
|
64
|
+
- [x] A list of files in a channel, It can be filtered and sliced in various ways.
|
|
65
|
+
|
|
66
|
+
- Upload a file using [files.upload](https://api.slack.com/methods/files.upload) Slack API
|
|
67
|
+
- [x] Upload a file to a _public_ channel
|
|
68
|
+
- [x] Upload a file to a _private_ channel
|
|
69
|
+
- [x] Upload a file to a _slack user_ (DM)
|
|
70
|
+
- [x] Upload a file inside a _slack thread_ 🧵
|
|
71
|
+
- [x] Upload a file with _multiple channels/users_
|
|
72
|
+
|
|
30
73
|
|
|
31
|
-
## Examples
|
|
74
|
+
## Examples (Post a message)
|
|
32
75
|
|
|
33
|
-
|
|
76
|
+
Let’s post a message to the default slack bot channel.
|
|
34
77
|
|
|
35
78
|
```ruby
|
|
36
79
|
# share on Slack
|
|
37
|
-
|
|
80
|
+
post_to_slack(message: "App successfully released!")
|
|
38
81
|
```
|
|
39
82
|
|
|
40
|
-
|
|
83
|
+
Let’s post a direct message to a slack user that unit tests CI has been failed.
|
|
41
84
|
|
|
42
85
|
```ruby
|
|
43
86
|
# share on Slack
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
87
|
+
post_to_slack(
|
|
88
|
+
message: "CI: Your unit tests on #{ENV['CI_COMMIT_REF_NAME']} failed",
|
|
89
|
+
channel: "@SlackUsername" # This can be Slack userID, instead of username i.e @UXXXXX
|
|
90
|
+
)
|
|
48
91
|
```
|
|
49
92
|
|
|
50
|
-
|
|
93
|
+
Let’s post a slack message to the `#ios-team` channel about the new test-flight build.
|
|
51
94
|
|
|
52
95
|
```ruby
|
|
53
96
|
lane :beta do
|
|
54
97
|
gym # Build the app and create .ipa file
|
|
55
98
|
pilot # Upload build to TestFlight
|
|
56
|
-
|
|
99
|
+
|
|
57
100
|
version_number = get_version_number # Get project version
|
|
58
101
|
build_number = get_build_number # Get build number
|
|
59
102
|
beta_release_name = "#{version_number}-#{build_number}-beta-release"
|
|
60
|
-
|
|
103
|
+
|
|
61
104
|
# share on Slack
|
|
62
105
|
post_to_slack(
|
|
63
106
|
message: "Hi team, we have a new test-flight beta build: #{beta_release_name}",
|
|
@@ -66,7 +109,7 @@ lane :beta do
|
|
|
66
109
|
end
|
|
67
110
|
```
|
|
68
111
|
|
|
69
|
-
|
|
112
|
+
Let’s post a slack message with custom payload.
|
|
70
113
|
|
|
71
114
|
```ruby
|
|
72
115
|
# share on Slack
|
|
@@ -93,18 +136,115 @@ post_to_slack(
|
|
|
93
136
|
)
|
|
94
137
|
```
|
|
95
138
|
|
|
96
|
-
|
|
139
|
+
Let’s post a slack message inside a slack thread 🧵
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
lane :release do
|
|
143
|
+
# Start the release with slack release thread
|
|
144
|
+
release_thread = post_to_slack(
|
|
145
|
+
message: "Good morning team, CI has started the AppStore release. You can find more information inside this thread 🧵",
|
|
146
|
+
channel: "#ios-team"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# Important: Save this slack thread timestamp for futher slack messages
|
|
150
|
+
release_thread_ts = release_thread[:json]["ts"]
|
|
151
|
+
|
|
152
|
+
gym # Build the app and create .ipa file
|
|
97
153
|
|
|
98
|
-
|
|
154
|
+
# Post an update in release thread
|
|
155
|
+
post_to_slack(
|
|
156
|
+
message: "App has been build successfully! 💪",
|
|
157
|
+
channel: "#ios-team",
|
|
158
|
+
thread_ts: release_thread_ts
|
|
159
|
+
)
|
|
99
160
|
|
|
100
|
-
|
|
161
|
+
deliver # Upload build to AppStore
|
|
101
162
|
|
|
102
|
-
|
|
163
|
+
# Post an update in release thread
|
|
164
|
+
post_to_slack(
|
|
165
|
+
message: "App has been uploaded to the AppStore and submitted for Apple's review! 🚀",
|
|
166
|
+
channel: "#ios-team",
|
|
167
|
+
thread_ts: release_thread_ts
|
|
168
|
+
)
|
|
169
|
+
end
|
|
170
|
+
```
|
|
103
171
|
|
|
104
|
-
|
|
172
|
+
Let’s post a message with custom slack bot username and icon
|
|
105
173
|
|
|
106
|
-
|
|
174
|
+
```ruby
|
|
175
|
+
# share on Slack
|
|
176
|
+
post_to_slack(
|
|
177
|
+
message: "App successfully released!",
|
|
178
|
+
username: "Release Bot", # Overrides the bot's username
|
|
179
|
+
icon_url: "https://fastlane.tools/assets/img/fastlane_icon.png" # Overrides the bot's icon
|
|
180
|
+
)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Examples (Upload a file)
|
|
184
|
+
|
|
185
|
+
Let’s Upload a file to a slack channel that main branch unit tests has been failed, see scan logs.
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
# File upload on Slack
|
|
189
|
+
file_upload_to_slack(
|
|
190
|
+
initial_comment: "CI: main-branch unit tests failed",
|
|
191
|
+
file_path: "scan.log",
|
|
192
|
+
channels: "#ios-team" # Comma-separated list of slack #channel names where the file will be shared
|
|
193
|
+
)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Let’s Upload a file to a slack user that your branch unit tests has been failed, see scan logs.
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
# File upload on Slack
|
|
200
|
+
file_upload_to_slack(
|
|
201
|
+
initial_comment: "CI: Your unit tests on #{ENV['CI_COMMIT_REF_NAME']} failed",
|
|
202
|
+
file_path: "scan.log",
|
|
203
|
+
channels: "@SlackUsername" # This can be Slack userID, instead of username i.e @UXXXXX
|
|
204
|
+
)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Let’s Upload a file inside a slack thread 🧵
|
|
208
|
+
|
|
209
|
+
```ruby
|
|
210
|
+
lane :release do
|
|
211
|
+
# Start the release with slack release thread
|
|
212
|
+
release_thread = post_to_slack(
|
|
213
|
+
message: "Good morning team, CI has started the AppStore release. You can find more information inside this thread 🧵",
|
|
214
|
+
channel: "#ios-team"
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
# Important: Save this slack thread timestamp for futher slack messages
|
|
218
|
+
release_thread_ts = release_thread[:json]["ts"]
|
|
219
|
+
|
|
220
|
+
gym # Build the app and create .ipa file
|
|
221
|
+
|
|
222
|
+
# Post an update in release thread
|
|
223
|
+
post_to_slack(
|
|
224
|
+
message: "App has been build successfully! 💪",
|
|
225
|
+
channel: "#ios-team",
|
|
226
|
+
thread_ts: release_thread_ts
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
deliver # Upload build to AppStore
|
|
230
|
+
|
|
231
|
+
# Post an update in release thread
|
|
232
|
+
post_to_slack(
|
|
233
|
+
message: "App has been uploaded to the AppStore and submitted for Apple's review! 🚀",
|
|
234
|
+
channel: "#ios-team",
|
|
235
|
+
thread_ts: release_thread_ts
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
# Spaceship logs file upload on Slack
|
|
239
|
+
file_upload_to_slack(
|
|
240
|
+
initial_comment: "Deliver:: Spaceship logs",
|
|
241
|
+
file_path: "spaceship.log",
|
|
242
|
+
channels: "#ios-team",
|
|
243
|
+
thread_ts: release_thread_ts
|
|
244
|
+
)
|
|
245
|
+
end
|
|
246
|
+
```
|
|
107
247
|
|
|
108
|
-
## About
|
|
248
|
+
## About Fastlane
|
|
109
249
|
|
|
110
250
|
_fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
require 'fastlane/action'
|
|
2
|
+
require_relative '../helper/slack_bot_helper'
|
|
3
|
+
|
|
4
|
+
module Fastlane
|
|
5
|
+
module Actions
|
|
6
|
+
module SharedValues
|
|
7
|
+
FILE_UPLOAD_TO_SLACK_RESULT = :FILE_UPLOAD_TO_SLACK_RESULT
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class FileUploadToSlackAction < Action
|
|
11
|
+
def self.run(params)
|
|
12
|
+
file_path = params[:file_path]
|
|
13
|
+
|
|
14
|
+
if params[:file_name].to_s.empty?
|
|
15
|
+
file_name = File.basename(file_path, ".*") # if file_path = "/path/file_name.jpeg" then will return "file_name"
|
|
16
|
+
else
|
|
17
|
+
file_name = params[:file_name]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
if params[:file_type].to_s.empty?
|
|
21
|
+
file_type = File.extname(file_path)[1..-1] # if file_path = "/path/file_name.jpeg" then will return "jpeg"
|
|
22
|
+
else
|
|
23
|
+
file_type = params[:file_type]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
begin
|
|
27
|
+
require 'faraday'
|
|
28
|
+
|
|
29
|
+
api_url = "https://slack.com/api/files.upload"
|
|
30
|
+
conn = Faraday.new(url: api_url) do |faraday|
|
|
31
|
+
faraday.request :multipart
|
|
32
|
+
faraday.request :url_encoded
|
|
33
|
+
faraday.adapter :net_http
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
payload = {
|
|
37
|
+
channels: params[:channels],
|
|
38
|
+
file: Faraday::FilePart.new(file_path, file_type),
|
|
39
|
+
filename: file_name,
|
|
40
|
+
filetype: file_type
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
payload[:title] = params[:title] unless params[:title].nil?
|
|
44
|
+
payload[:initial_comment] = params[:initial_comment] unless params[:initial_comment].nil?
|
|
45
|
+
payload[:thread_ts] = params[:thread_ts] unless params[:thread_ts].nil?
|
|
46
|
+
|
|
47
|
+
response = conn.post do |req|
|
|
48
|
+
req.headers['Authorization'] = "Bearer #{params[:api_token]}"
|
|
49
|
+
req.body = payload
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
result = self.formatted_result(response)
|
|
53
|
+
rescue => exception
|
|
54
|
+
UI.error("Exception: #{exception}")
|
|
55
|
+
return nil
|
|
56
|
+
else
|
|
57
|
+
UI.success("Successfully uploaded file to Slack! 🚀")
|
|
58
|
+
Actions.lane_context[SharedValues::FILE_UPLOAD_TO_SLACK_RESULT] = result
|
|
59
|
+
return result
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.formatted_result(response)
|
|
64
|
+
result = {
|
|
65
|
+
status: response[:status],
|
|
66
|
+
body: response.body || "",
|
|
67
|
+
json: self.parse_json(response.body) || {}
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.parse_json(value)
|
|
72
|
+
require 'json'
|
|
73
|
+
|
|
74
|
+
JSON.parse(value)
|
|
75
|
+
rescue JSON::ParserError
|
|
76
|
+
nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
#####################################################
|
|
80
|
+
# @!group Documentation
|
|
81
|
+
#####################################################
|
|
82
|
+
|
|
83
|
+
def self.description
|
|
84
|
+
"Upload a file to slack channel"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.details
|
|
88
|
+
"Upload a file to slack channel or DM to a slack user"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.available_options
|
|
92
|
+
[
|
|
93
|
+
FastlaneCore::ConfigItem.new(key: :api_token,
|
|
94
|
+
env_name: "FL_FILE_UPLOAD_TO_SLACK_BOT_TOKEN",
|
|
95
|
+
description: "Slack bot Token",
|
|
96
|
+
sensitive: true,
|
|
97
|
+
code_gen_sensitive: true,
|
|
98
|
+
is_string: true,
|
|
99
|
+
default_value: ENV["SLACK_API_TOKEN"],
|
|
100
|
+
default_value_dynamic: true,
|
|
101
|
+
optional: false),
|
|
102
|
+
FastlaneCore::ConfigItem.new(key: :channels,
|
|
103
|
+
env_name: "FL_FETCH_FILES_SLACK_CHANNELS",
|
|
104
|
+
description: "Comma-separated list of slack #channel names where the file will be shared",
|
|
105
|
+
is_string: true,
|
|
106
|
+
optional: false),
|
|
107
|
+
FastlaneCore::ConfigItem.new(key: :file_path,
|
|
108
|
+
env_name: "FL_FILE_UPLOAD_TO_SLACK_FILE_PATH",
|
|
109
|
+
description: "relative file path which will upload to slack",
|
|
110
|
+
is_string: true,
|
|
111
|
+
optional: false),
|
|
112
|
+
FastlaneCore::ConfigItem.new(key: :file_name,
|
|
113
|
+
env_name: "FL_FILE_UPLOAD_TO_SLACK_FILE_NAME",
|
|
114
|
+
description: "This is optional filename of the file",
|
|
115
|
+
is_string: true,
|
|
116
|
+
optional: true),
|
|
117
|
+
FastlaneCore::ConfigItem.new(key: :file_type,
|
|
118
|
+
env_name: "FL_FILE_UPLOAD_TO_SLACK_FILE_TYPE",
|
|
119
|
+
description: "This is optional filetype of the file",
|
|
120
|
+
is_string: true,
|
|
121
|
+
optional: true),
|
|
122
|
+
FastlaneCore::ConfigItem.new(key: :title,
|
|
123
|
+
env_name: "FL_FILE_UPLOAD_TO_SLACK_TITLE",
|
|
124
|
+
description: "This is optional Title of file",
|
|
125
|
+
is_string: true,
|
|
126
|
+
optional: true),
|
|
127
|
+
FastlaneCore::ConfigItem.new(key: :initial_comment,
|
|
128
|
+
env_name: "FL_FILE_UPLOAD_TO_SLACK_INITIAL_COMMENT",
|
|
129
|
+
description: "This is optional message text introducing the file",
|
|
130
|
+
is_string: true,
|
|
131
|
+
optional: true),
|
|
132
|
+
FastlaneCore::ConfigItem.new(key: :thread_ts,
|
|
133
|
+
env_name: "FL_FILE_UPLOAD_TO_SLACK_THREAD_TS",
|
|
134
|
+
description: "Provide another message's ts value to make this message a reply",
|
|
135
|
+
is_string: true,
|
|
136
|
+
optional: true)
|
|
137
|
+
]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def self.authors
|
|
141
|
+
["crazymanish"]
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def self.example_code
|
|
145
|
+
[
|
|
146
|
+
'file_upload_to_slack(
|
|
147
|
+
channels: "slack_channel_name",
|
|
148
|
+
file_path: "fastlane/test.png"
|
|
149
|
+
)',
|
|
150
|
+
'file_upload_to_slack(
|
|
151
|
+
title: "This is test title",
|
|
152
|
+
channels: "slack_channel_name1, slack_channel_name2",
|
|
153
|
+
file_path: "fastlane/report.xml"
|
|
154
|
+
)',
|
|
155
|
+
'file_upload_to_slack(
|
|
156
|
+
title: "This is test title",
|
|
157
|
+
initial_comment: "This is test initial comment",
|
|
158
|
+
channels: "slack_channel_name",
|
|
159
|
+
file_path: "fastlane/screenshots.zip"
|
|
160
|
+
)',
|
|
161
|
+
'file_upload_to_slack(
|
|
162
|
+
title: "This is test title", # Optional, uploading file title
|
|
163
|
+
initial_comment: "This is test initial comment", # Optional, uploading file initial comment
|
|
164
|
+
channels: "slack_channel_name",
|
|
165
|
+
file_path: "fastlane/screenshots.zip",
|
|
166
|
+
thread_ts: thread_ts # Optional, Provide parent slack message `ts` value to upload this file as a reply.
|
|
167
|
+
)'
|
|
168
|
+
]
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def self.is_supported?(platform)
|
|
172
|
+
true
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
require 'fastlane/action'
|
|
2
2
|
require_relative '../helper/slack_bot_helper'
|
|
3
|
+
require_relative '../helper/slack_bot_attachments_helper'
|
|
4
|
+
require_relative '../helper/slack_bot_link_formatter_helper'
|
|
3
5
|
|
|
4
6
|
module Fastlane
|
|
5
7
|
module Actions
|
|
@@ -9,10 +11,8 @@ module Fastlane
|
|
|
9
11
|
|
|
10
12
|
class PostToSlackAction < Action
|
|
11
13
|
def self.run(options)
|
|
12
|
-
require 'slack-notifier'
|
|
13
|
-
|
|
14
14
|
options[:message] = (options[:message].to_s || '').gsub('\n', "\n")
|
|
15
|
-
options[:message] =
|
|
15
|
+
options[:message] = Helper::SlackBotLinkFormatterHelper.format(options[:message])
|
|
16
16
|
options[:pretext] = options[:pretext].gsub('\n', "\n") unless options[:pretext].nil?
|
|
17
17
|
|
|
18
18
|
if options[:channel].to_s.length > 0
|
|
@@ -20,14 +20,25 @@ module Fastlane
|
|
|
20
20
|
slack_channel = ('#' + options[:channel]) unless ['#', 'C', '@'].include?(slack_channel[0]) # Add prefix(#) by default, if needed
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
slack_attachment =
|
|
23
|
+
slack_attachment = Helper::SlackBotAttachmentsHelper.generate_slack_attachments(options)
|
|
24
|
+
bot_username = options[:username]
|
|
25
|
+
bot_icon_url = options[:icon_url]
|
|
24
26
|
|
|
25
27
|
begin
|
|
26
28
|
require 'excon'
|
|
27
29
|
|
|
28
30
|
api_url = "https://slack.com/api/chat.postMessage"
|
|
29
|
-
headers = {
|
|
30
|
-
|
|
31
|
+
headers = {
|
|
32
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
33
|
+
"Authorization": "Bearer #{options[:api_token]}"
|
|
34
|
+
}
|
|
35
|
+
payload = {
|
|
36
|
+
channel: slack_channel,
|
|
37
|
+
username: bot_username,
|
|
38
|
+
icon_url: bot_icon_url,
|
|
39
|
+
attachments: [slack_attachment]
|
|
40
|
+
}
|
|
41
|
+
payload[:as_user] = options[:as_user] if options[:as_user] # default is false
|
|
31
42
|
payload[:thread_ts] = options[:thread_ts] unless options[:thread_ts].nil?
|
|
32
43
|
payload = payload.to_json
|
|
33
44
|
|
|
@@ -82,6 +93,24 @@ module Fastlane
|
|
|
82
93
|
env_name: "FL_POST_TO_SLACK_CHANNEL",
|
|
83
94
|
description: "#channel or @username",
|
|
84
95
|
optional: true),
|
|
96
|
+
FastlaneCore::ConfigItem.new(key: :username,
|
|
97
|
+
env_name: "FL_SLACK_USERNAME",
|
|
98
|
+
description: "Overrides the bot's username (chat:write.customize scope required)",
|
|
99
|
+
default_value: "fastlane",
|
|
100
|
+
is_string: true,
|
|
101
|
+
optional: true),
|
|
102
|
+
FastlaneCore::ConfigItem.new(key: :icon_url,
|
|
103
|
+
env_name: "FL_SLACK_ICON_URL",
|
|
104
|
+
description: "Overrides the bot's image (chat:write.customize scope required)",
|
|
105
|
+
default_value: "https://fastlane.tools/assets/img/fastlane_icon.png",
|
|
106
|
+
is_string: true,
|
|
107
|
+
optional: true),
|
|
108
|
+
FastlaneCore::ConfigItem.new(key: :as_user,
|
|
109
|
+
env_name: "FL_POST_TO_SLACK_AS_USER",
|
|
110
|
+
description: "Pass true to post the message as the authed user. Defaults to false",
|
|
111
|
+
optional: true,
|
|
112
|
+
default_value: false,
|
|
113
|
+
is_string: false),
|
|
85
114
|
FastlaneCore::ConfigItem.new(key: :pretext,
|
|
86
115
|
env_name: "FL_POST_TO_SLACK_PRETEXT",
|
|
87
116
|
description: "This is optional text that appears above the message attachment block. This supports the standard Slack markup language",
|
|
@@ -99,6 +128,7 @@ module Fastlane
|
|
|
99
128
|
env_name: "FL_POST_TO_SLACK_DEFAULT_PAYLOADS",
|
|
100
129
|
description: "Remove some of the default payloads. More information about the available payloads on GitHub",
|
|
101
130
|
optional: true,
|
|
131
|
+
default_value: ['lane', 'test_result', 'git_branch', 'git_author', 'last_git_commit', 'last_git_commit_hash'],
|
|
102
132
|
type: Array),
|
|
103
133
|
FastlaneCore::ConfigItem.new(key: :attachment_properties,
|
|
104
134
|
env_name: "FL_POST_TO_SLACK_ATTACHMENT_PROPERTIES",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
require 'fastlane/action'
|
|
2
2
|
require_relative '../helper/slack_bot_helper'
|
|
3
|
+
require_relative '../helper/slack_bot_attachments_helper'
|
|
4
|
+
require_relative '../helper/slack_bot_link_formatter_helper'
|
|
3
5
|
|
|
4
6
|
module Fastlane
|
|
5
7
|
module Actions
|
|
@@ -8,12 +10,10 @@ module Fastlane
|
|
|
8
10
|
end
|
|
9
11
|
class UpdateSlackMessageAction < Action
|
|
10
12
|
def self.run(options)
|
|
11
|
-
require 'slack-notifier'
|
|
12
|
-
|
|
13
13
|
options[:message] = (options[:message].to_s || '').gsub('\n', "\n")
|
|
14
|
-
options[:message] =
|
|
14
|
+
options[:message] = Helper::SlackBotLinkFormatterHelper.format(options[:message])
|
|
15
15
|
options[:pretext] = options[:pretext].gsub('\n', "\n") unless options[:pretext].nil?
|
|
16
|
-
slack_attachment =
|
|
16
|
+
slack_attachment = Helper::SlackBotAttachmentsHelper.generate_slack_attachments(options)
|
|
17
17
|
|
|
18
18
|
begin
|
|
19
19
|
require 'excon'
|
|
@@ -90,6 +90,7 @@ module Fastlane
|
|
|
90
90
|
env_name: "FL_UPDATE_SLACK_MESSAGE_DEFAULT_PAYLOADS",
|
|
91
91
|
description: "Remove some of the default payloads. More information about the available payloads on GitHub",
|
|
92
92
|
optional: true,
|
|
93
|
+
default_value: ['lane', 'test_result', 'git_branch', 'git_author', 'last_git_commit', 'last_git_commit_hash'],
|
|
93
94
|
type: Array),
|
|
94
95
|
FastlaneCore::ConfigItem.new(key: :attachment_properties,
|
|
95
96
|
env_name: "FL_UPDATE_SLACK_MESSAGE_ATTACHMENT_PROPERTIES",
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require 'fastlane_core/ui/ui'
|
|
2
|
+
require 'fastlane_core/env'
|
|
3
|
+
require_relative 'slack_bot_link_formatter_helper'
|
|
4
|
+
|
|
5
|
+
module Fastlane
|
|
6
|
+
UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
|
|
7
|
+
|
|
8
|
+
module Helper
|
|
9
|
+
class SlackBotAttachmentsHelper
|
|
10
|
+
# class methods that you define here become available in your action
|
|
11
|
+
# as `Helper::SlackBotAttachmentsHelper.your_method`
|
|
12
|
+
#
|
|
13
|
+
def self.show_message
|
|
14
|
+
UI.message("Hello from the slack_bot plugin attachments helper!")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.generate_slack_attachments(options)
|
|
18
|
+
color = (options[:success] ? 'good' : 'danger')
|
|
19
|
+
should_add_payload = ->(payload_name) { options[:default_payloads].map(&:to_sym).include?(payload_name.to_sym) }
|
|
20
|
+
|
|
21
|
+
slack_attachment = {
|
|
22
|
+
fallback: options[:message],
|
|
23
|
+
text: options[:message],
|
|
24
|
+
pretext: options[:pretext],
|
|
25
|
+
color: color,
|
|
26
|
+
mrkdwn_in: ["pretext", "text", "fields", "message"],
|
|
27
|
+
fields: []
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# custom user payloads
|
|
31
|
+
slack_attachment[:fields] += options[:payload].map do |k, v|
|
|
32
|
+
{
|
|
33
|
+
title: k.to_s,
|
|
34
|
+
value: SlackBotLinkFormatterHelper.format(v.to_s),
|
|
35
|
+
short: false
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Add the lane to the Slack message
|
|
40
|
+
# This might be nil, if slack is called as "one-off" action
|
|
41
|
+
if should_add_payload[:lane] && Actions.lane_context[Actions::SharedValues::LANE_NAME]
|
|
42
|
+
slack_attachment[:fields] << {
|
|
43
|
+
title: 'Lane',
|
|
44
|
+
value: Actions.lane_context[Actions::SharedValues::LANE_NAME],
|
|
45
|
+
short: true
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# test_result
|
|
50
|
+
if should_add_payload[:test_result]
|
|
51
|
+
slack_attachment[:fields] << {
|
|
52
|
+
title: 'Result',
|
|
53
|
+
value: (options[:success] ? 'Success' : 'Error'),
|
|
54
|
+
short: true
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# git branch
|
|
59
|
+
if Actions.git_branch && should_add_payload[:git_branch]
|
|
60
|
+
slack_attachment[:fields] << {
|
|
61
|
+
title: 'Git Branch',
|
|
62
|
+
value: Actions.git_branch,
|
|
63
|
+
short: true
|
|
64
|
+
}
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# git_author
|
|
68
|
+
if Actions.git_author_email && should_add_payload[:git_author]
|
|
69
|
+
if FastlaneCore::Env.truthy?('FASTLANE_SLACK_HIDE_AUTHOR_ON_SUCCESS') && options[:success]
|
|
70
|
+
# We only show the git author if the build failed
|
|
71
|
+
else
|
|
72
|
+
slack_attachment[:fields] << {
|
|
73
|
+
title: 'Git Author',
|
|
74
|
+
value: Actions.git_author_email,
|
|
75
|
+
short: true
|
|
76
|
+
}
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# last_git_commit
|
|
81
|
+
if Actions.last_git_commit_message && should_add_payload[:last_git_commit]
|
|
82
|
+
slack_attachment[:fields] << {
|
|
83
|
+
title: 'Git Commit',
|
|
84
|
+
value: Actions.last_git_commit_message,
|
|
85
|
+
short: false
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# last_git_commit_hash
|
|
90
|
+
if Actions.last_git_commit_hash(true) && should_add_payload[:last_git_commit_hash]
|
|
91
|
+
slack_attachment[:fields] << {
|
|
92
|
+
title: 'Git Commit Hash',
|
|
93
|
+
value: Actions.last_git_commit_hash(short: true),
|
|
94
|
+
short: false
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# merge additional properties
|
|
99
|
+
deep_merge(slack_attachment, options[:attachment_properties])
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Adapted from https://stackoverflow.com/a/30225093/158525
|
|
103
|
+
def self.deep_merge(a, b)
|
|
104
|
+
merger = proc do |key, v1, v2|
|
|
105
|
+
Hash === v1 && Hash === v2 ?
|
|
106
|
+
v1.merge(v2, &merger) : Array === v1 && Array === v2 ?
|
|
107
|
+
v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2
|
|
108
|
+
end
|
|
109
|
+
a.merge(b, &merger)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'fastlane_core/ui/ui'
|
|
2
|
+
|
|
3
|
+
module Fastlane
|
|
4
|
+
UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
|
|
5
|
+
|
|
6
|
+
module Helper
|
|
7
|
+
# Fastlane is moving away 'slack-notifier' gem, https://github.com/fastlane/fastlane/pull/18512
|
|
8
|
+
# Duplicate of: https://github.com/stevenosloan/slack-notifier/blob/master/lib/slack-notifier/util/link_formatter.rb
|
|
9
|
+
class SlackBotLinkFormatterHelper
|
|
10
|
+
# http://rubular.com/r/19cNXW5qbH
|
|
11
|
+
HTML_PATTERN = %r{
|
|
12
|
+
<a
|
|
13
|
+
(?:.*?)
|
|
14
|
+
href=['"](.+?)['"]
|
|
15
|
+
(?:.*?)>
|
|
16
|
+
(.+?)
|
|
17
|
+
</a>
|
|
18
|
+
}x
|
|
19
|
+
|
|
20
|
+
# the path portion of a url can contain these characters
|
|
21
|
+
VALID_PATH_CHARS = '\w\-\.\~\/\?\#\='
|
|
22
|
+
|
|
23
|
+
# Attempt at only matching pairs of parens per
|
|
24
|
+
# the markdown spec http://spec.commonmark.org/0.27/#links
|
|
25
|
+
#
|
|
26
|
+
# http://rubular.com/r/y107aevxqT
|
|
27
|
+
MARKDOWN_PATTERN = %r{
|
|
28
|
+
\[ ([^\[\]]*?) \]
|
|
29
|
+
\( ((https?://.*?) | (mailto:.*?)) \)
|
|
30
|
+
(?! [#{VALID_PATH_CHARS}]* \) )
|
|
31
|
+
}x
|
|
32
|
+
|
|
33
|
+
class << self
|
|
34
|
+
def format string, opts={}
|
|
35
|
+
SlackBotLinkFormatterHelper.new(string, opts).formatted
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
attr_reader :formats
|
|
40
|
+
|
|
41
|
+
def initialize string, formats: %i[html markdown]
|
|
42
|
+
@formats = formats
|
|
43
|
+
@orig = string.respond_to?(:scrub) ? string.scrub : string
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# rubocop:disable Lint/RescueWithoutErrorClass
|
|
47
|
+
def formatted
|
|
48
|
+
return @orig unless @orig.respond_to?(:gsub)
|
|
49
|
+
|
|
50
|
+
sub_markdown_links(sub_html_links(@orig))
|
|
51
|
+
rescue => e
|
|
52
|
+
raise e unless RUBY_VERSION < "2.1" && e.message.include?("invalid byte sequence")
|
|
53
|
+
raise e, "#{e.message}. Consider including the 'string-scrub' gem to strip invalid characters"
|
|
54
|
+
end
|
|
55
|
+
# rubocop:enable Lint/RescueWithoutErrorClass
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def sub_html_links string
|
|
60
|
+
return string unless formats.include?(:html)
|
|
61
|
+
|
|
62
|
+
string.gsub(HTML_PATTERN) do
|
|
63
|
+
slack_link Regexp.last_match[1], Regexp.last_match[2]
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def sub_markdown_links string
|
|
68
|
+
return string unless formats.include?(:markdown)
|
|
69
|
+
|
|
70
|
+
string.gsub(MARKDOWN_PATTERN) do
|
|
71
|
+
slack_link Regexp.last_match[2], Regexp.last_match[1]
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def slack_link link, text=nil
|
|
76
|
+
"<#{link}" \
|
|
77
|
+
"#{text && !text.empty? ? "|#{text}" : ''}" \
|
|
78
|
+
">"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fastlane-plugin-slack_bot
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Manish Rathi
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-04-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pry
|
|
@@ -146,9 +146,12 @@ files:
|
|
|
146
146
|
- README.md
|
|
147
147
|
- lib/fastlane/plugin/slack_bot.rb
|
|
148
148
|
- lib/fastlane/plugin/slack_bot/actions/fetch_files_slack.rb
|
|
149
|
+
- lib/fastlane/plugin/slack_bot/actions/file_upload_to_slack.rb
|
|
149
150
|
- lib/fastlane/plugin/slack_bot/actions/post_to_slack.rb
|
|
150
151
|
- lib/fastlane/plugin/slack_bot/actions/update_slack_message.rb
|
|
152
|
+
- lib/fastlane/plugin/slack_bot/helper/slack_bot_attachments_helper.rb
|
|
151
153
|
- lib/fastlane/plugin/slack_bot/helper/slack_bot_helper.rb
|
|
154
|
+
- lib/fastlane/plugin/slack_bot/helper/slack_bot_link_formatter_helper.rb
|
|
152
155
|
- lib/fastlane/plugin/slack_bot/version.rb
|
|
153
156
|
homepage: https://github.com/crazymanish/fastlane-plugin-slack_bot
|
|
154
157
|
licenses:
|