Skip to content
This repository has been archived by the owner on Jan 23, 2021. It is now read-only.

Commit

Permalink
Support attachments (#7)
Browse files Browse the repository at this point in the history
* Support attachments

* fix docs
  • Loading branch information
ahelal authored Aug 30, 2017
1 parent b030153 commit 4d2476a
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 199 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ Replies with a message to the selected `channel`.

#### `out Parameters`

* `reply`: *Required*. A **string** or **file path** to be used as reply. Supports [template format](#template).
* `reply`: *Required/optional*. A **string** or **file path** to be used as reply. Supports [template format](#template). *Must be defined if `reply_attachments` is not defined.*

* `reply_attachments`: *Required/optional*. A **string** or **JSON file path** to be used as reply in [slack attachment format](https://api.slack.com/docs/message-attachments). You can use [messages builder](https://api.slack.com/docs/messages/builder) Supports [template format](#template). *Must be defined if `reply` is not defined.*

* `reply_thread`: *optional*, *default `False`*. If enabled will post reply to original message as a thread.

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.0.5
0.0.7
42 changes: 40 additions & 2 deletions examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ jobs :
- put: bender
params:
path: "bender"
reply: "Starting deployment {{ENV['ATC_EXTERNAL_URL']}}/teams/{{ ENV['BUILD_TEAM_NAME'] }}/pipelines/{{ENV['BUILD_PIPELINE_NAME']}}/jobs/{{ENV['BUILD_JOB_NAME'}}/builds/{{ENV['BUILD_NAME']}}"
reply: "Starting deployment"
- task : Deploying something
config :
Expand All @@ -126,7 +126,45 @@ jobs :

Same as Example 4 with the following difference `grammar: "^(?P<app>superApp)\\s+(?P<command>deploy)\\s+(?P<environment>live|staging)\\s+(?P<version>\\S+)($|\\s+)"` and `template: "ENVIRONMENT={{ regex[2] }}\nVERSION={{ regex[3] }}\n"`

## `Example 6`: Bumping versions
## `Example 6`: Using `reply_attachments`

You can provide a json file in your source code with slack attachments.

```json
[
{
"fallback": "Deploying {{ regex['environment'] }} {{ regex['app'] }} {{ regex['version'] }}",
"title": "Deploying {{ regex['app'] }}",
"title_link": "{{ENV['ATC_EXTERNAL_URL']}}/teams/{{ ENV['BUILD_TEAM_NAME'] }}/pipelines/{{ENV['BUILD_PIPELINE_NAME']}}/jobs/{{ENV['BUILD_JOB_NAME']}}/builds/{{ENV['BUILD_NAME']}}",
"text": "Deploying {{ regex['environment'] }} {{ regex['app'] }} {{ regex['version'] }}",
"color": "#7CD197"
}
]
```

Snippet of the deployment pipeline.

```yaml
- get: bender
version: every
trigger: true
- get: source_code
- put: bender
params:
path: "bender"
reply_attachments: "source_code/..../start_deployment.json"
# you can also encode it as string
- put: bender
params:
path: "bender"
reply_attachments: "[{\"title\": \"Yeah\",\"text\": \"Deployment {{ regex['version'] }} :white_check_mark:\"}]"
```

## `Example 7`: Bumping versions

```yaml
resources :
Expand Down
2 changes: 1 addition & 1 deletion src/lib/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def write_to_file(content, output_file):

def read_if_exists(base_path, content):
''' Return content of file, if file exists else return content.'''
path = os.path.abspath(os.path.join(base_path, content))
path = os.path.abspath(os.path.join(base_path, str(content)))
is_file = os.path.isfile(path)
if not is_file:
return content
Expand Down
50 changes: 34 additions & 16 deletions src/lib/out_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,43 +14,60 @@ class Out(Base):
def __init__(self, **kwargs):
Base.__init__(self, **kwargs)
self.metadata = []
self.path = kwargs.get("path", False)
self.reply = read_if_exists(self.working_dir, kwargs.get("reply", False))
self.path = kwargs.get("path")
self.reply_attachments = read_if_exists(self.working_dir, kwargs.get("reply_attachments"))
self.reply = read_if_exists(self.working_dir, kwargs.get("reply"))
self.reply_thread = kwargs.get("reply_thread", True)

# Get context from original message
context_json_path = '{}/{}/bender.json'.format(self.working_dir, self.path)
try:
context_content = read_content_from_file(context_json_path)
context_content = json.loads(context_content)
except ValueError as value_error:
fail_unless(False, "JSON Input error: {}".format(value_error))

context_content = read_content_from_file(context_json_path)
context_content = self.serialize_json(context_content)
# Initialize from original message
self.version = context_content["version"]
self.metadata = context_content["metadata"]
self.original_msg = context_content["original_msg"]

def _reply(self, thread_timestamp, text):
@staticmethod
def serialize_json(json_string):
''' Serialize a JSON strong into a python object'''
try:
serialized = json.loads(json_string)
except ValueError as value_error:
fail_unless(False, "JSON Input error: {}".format(value_error))
return serialized

def _reply(self, thread_timestamp=False, text=False, attachments=False):
args = {}
if thread_timestamp:
args = {"thread_ts": thread_timestamp}
args.update({"thread_ts": thread_timestamp})
if text:
args.update({"text": text})
if attachments:
args.update({"attachments": attachments})

self._call_api("chat.postMessage",
channel=self.channel_id,
text=text,
parse="full",
**args)

def out_logic(self):
"""Concourse resource `out` logic """

regex = self._msg_grammar(self.original_msg)
templated_reply = template_with_regex(self.reply, regex)
if self.reply:
self.reply = template_with_regex(self.reply, regex)

if self.reply_attachments:
self.reply_attachments = template_with_regex(self.reply_attachments, regex)
self.reply_attachments = self.serialize_json(self.reply_attachments)

if self.reply_thread:
reply_to_thread = self.version["id_ts"]
else:
reply_to_thread = False
self._reply(reply_to_thread, templated_reply)
self._reply(thread_timestamp=reply_to_thread,
text=self.reply,
attachments=self.reply_attachments)

def out_output(self):
"""Concourse resource `out` output """
Expand All @@ -61,8 +78,9 @@ def out_output(self):
def main():
''' Main `out` entry point'''
payload = PayLoad()
fail_unless(payload.args.get("path", False), "path is required")
fail_unless(payload.args.get("reply", False), "reply is required")
fail_unless(payload.args.get("path"), "path is required, but not defined.")
if not payload.args.get("reply") and not payload.args.get("reply_attachments"):
fail_unless(False, "'reply' or 'reply_attachments' paramater required, but not defined.")

slack_client = Out(**payload.args)
slack_client.out_logic()
Expand Down
3 changes: 2 additions & 1 deletion src/lib/payload.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ def parse_payload(self):
self.args["grammar"] = self.source.get("grammar")
self.args["template"] = self.source.get("template")
self.args["template_filename"] = self.source.get("template_filename", "template_file.txt")
self.args["slack_unread"] = self.source.get("slack_unread", False)
self.args["slack_unread"] = self.source.get("slack_unread")
# Optional params config
self.args["path"] = self.params.get("path")
self.args["reply"] = self.params.get("reply")
self.args["reply_attachments"] = self.params.get("reply_attachments")
self.args["reply_thread"] = self.params.get("reply_thread", True)
176 changes: 0 additions & 176 deletions src/tests/responses/messages_many.json

This file was deleted.

4 changes: 3 additions & 1 deletion src/tests/test_payload.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ def test_parse_payload_defaults(self, mock_get_payload, mock_fail_unless, mock_g
@mock.patch('payload.PayLoad._get_payload')
def test_parse_payload_values(self, mock_get_payload, mock_fail_unless, mock_get_dir_from_argv):
mock_get_dir_from_argv.return_value = "/tmp"
mock_get_payload.side_effect = [{'params': {'path': 'path', 'reply': 'reply', "reply_thread": "reply_thread"},
mock_get_payload.side_effect = [{'params': {'path': 'path', 'reply': 'reply', 'reply_attachments': 'reply_attachments',
'reply_thread': 'reply_thread'},
'source': {'bot_name': 'bot_name',
'channel': 'channel',
'grammar': 'grammar',
Expand All @@ -95,4 +96,5 @@ def test_parse_payload_values(self, mock_get_payload, mock_fail_unless, mock_get
self.assertEqual(py.args["grammar"], "grammar")
self.assertEqual(py.args["path"], "path")
self.assertEqual(py.args["reply"], "reply")
self.assertEqual(py.args["reply_attachments"], "reply_attachments")
self.assertEqual(py.args["reply_thread"], "reply_thread")

0 comments on commit 4d2476a

Please sign in to comment.