Skip to content

Commit

Permalink
Present the approval notifications in a slightly better way (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
kjagiello authored Dec 17, 2023
1 parent d2f33d4 commit 2058f04
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 101 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,20 @@ module "codepipeline_notifications" {
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_additional_tag_map"></a> [additional\_tag\_map](#input\_additional\_tag\_map) | Additional tags for appending to tags\_as\_list\_of\_maps. Not added to `tags`. | `map(string)` | `{}` | no |
| <a name="input_approval_event_type_ids"></a> [approval\_event\_type\_ids](#input\_approval\_event\_type\_ids) | The list of pipeline events to trigger a notification on | `list(string)` | <pre>[<br> "started",<br> "succeeded",<br> "failed"<br>]</pre> | no |
| <a name="input_attributes"></a> [attributes](#input\_attributes) | Additional attributes (e.g. `1`) | `list(string)` | `[]` | no |
| <a name="input_codepipelines"></a> [codepipelines](#input\_codepipelines) | CodePipeline resources that should trigger Slack notifications | `list(any)` | n/a | yes |
| <a name="input_context"></a> [context](#input\_context) | Single object for setting entire context at once.<br>See description of individual variables for details.<br>Leave string and numeric variables as `null` to use default value.<br>Individual variable settings (non-null) override settings in context object,<br>except for attributes, tags, and additional\_tag\_map, which are merged. | `any` | <pre>{<br> "additional_tag_map": {},<br> "attributes": [],<br> "delimiter": null,<br> "enabled": true,<br> "environment": null,<br> "id_length_limit": null,<br> "label_key_case": null,<br> "label_order": [],<br> "label_value_case": null,<br> "name": null,<br> "namespace": null,<br> "regex_replace_chars": null,<br> "stage": null,<br> "tags": {}<br>}</pre> | no |
| <a name="input_delimiter"></a> [delimiter](#input\_delimiter) | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.<br>Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no |
| <a name="input_enabled"></a> [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no |
| <a name="input_environment"></a> [environment](#input\_environment) | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
| <a name="input_event_type_ids"></a> [event\_type\_ids](#input\_event\_type\_ids) | The list of event type to trigger a notification on | `list(string)` | <pre>[<br> "failed",<br> "canceled",<br> "started",<br> "resumed",<br> "succeeded",<br> "superseded"<br>]</pre> | no |
| <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br>Set to `0` for unlimited length.<br>Set to `null` for default, which is `0`.<br>Does not affect `id_full`. | `number` | `null` | no |
| <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.<br>Possible values: `lower`, `title`, `upper`.<br>Default value: `title`. | `string` | `null` | no |
| <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The naming order of the id output and Name tag.<br>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br>You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no |
| <a name="input_label_value_case"></a> [label\_value\_case](#input\_label\_value\_case) | The letter case of output label values (also used in `tags` and `id`).<br>Possible values: `lower`, `title`, `upper` and `none` (no transformation).<br>Default value: `lower`. | `string` | `null` | no |
| <a name="input_name"></a> [name](#input\_name) | Solution name, e.g. 'app' or 'jenkins' | `string` | `null` | no |
| <a name="input_namespace"></a> [namespace](#input\_namespace) | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no |
| <a name="input_pipeline_event_type_ids"></a> [pipeline\_event\_type\_ids](#input\_pipeline\_event\_type\_ids) | The list of pipeline events to trigger a notification on | `list(string)` | <pre>[<br> "started",<br> "failed",<br> "canceled",<br> "resumed",<br> "succeeded",<br> "superseded"<br>]</pre> | no |
| <a name="input_regex_replace_chars"></a> [regex\_replace\_chars](#input\_regex\_replace\_chars) | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.<br>If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no |
| <a name="input_slack_channel"></a> [slack\_channel](#input\_slack\_channel) | A slack channel to send the deployment notifications to | `string` | n/a | yes |
| <a name="input_slack_emoji"></a> [slack\_emoji](#input\_slack\_emoji) | The emoji avatar of the user that sends the notifications | `string` | `":rocket:"` | no |
Expand Down
39 changes: 30 additions & 9 deletions lambdas/notifier/notifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@
logger = logging.getLogger(__name__)

STATE_COLORS = {
"STARTED": "#1a9edb",
"SUCCEEDED": "#50ba32",
"RESUMED": "#1a9edb",
"FAILED": "#f02b1d",
"CANCELED": "#919191",
"SUPERSEDED": "#919191",
"Deployment": {
"STARTED": "#1a9edb",
"SUCCEEDED": "#50ba32",
"RESUMED": "#1a9edb",
"FAILED": "#f02b1d",
"CANCELED": "#919191",
"SUPERSEDED": "#919191",
},
"Approval": {
"STARTED": "#f5d142",
"SUCCEEDED": "#50ba32",
"FAILED": "#f02b1d",
},
}


Expand All @@ -31,6 +38,7 @@ def format_slack_attachment(
execution_id: str,
environment: str,
region: str,
action: str,
revision_summary: t.Optional[str],
revision_url: t.Optional[str],
) -> dict:
Expand All @@ -57,8 +65,12 @@ def format_slack_attachment(
},
]
return {
"color": STATE_COLORS[pipeline_state],
"fallback": (f"`{pipeline_name}` has `{pipeline_state}`"),
"color": STATE_COLORS[action][pipeline_state],
"fallback": format_slack_text(
pipeline_name=pipeline_name,
pipeline_state=pipeline_state,
action=action,
).replace("*", ""),
"fields": [
{"title": "Pipeline", "value": pipeline_name},
{"title": "Execution ID", "value": execution_link},
Expand All @@ -70,6 +82,13 @@ def format_slack_attachment(


def format_slack_text(*, pipeline_name: str, pipeline_state: str, action: str):
if action == "Approval":
if pipeline_state == "STARTED":
return f"*Deployment* of *{pipeline_name}* is awaiting approval."
elif pipeline_state == "FAILED":
return f"*Deployment* of *{pipeline_name}* has been rejected."
elif pipeline_state == "SUCCEEDED":
return f"*Deployment* of *{pipeline_name}* has been approved."
return f"*{action}* of *{pipeline_name}* has {pipeline_state.lower()}."


Expand All @@ -90,18 +109,20 @@ def build_slack_message_from_event(event):
revision = pipeline_execution["artifactRevisions"][0]
revision_url = revision.get("revisionUrl")
revision_summary = revision.get("revisionSummary")
action = pipeline_action or "Deployment"

# Build a message with an attachment with details
text = format_slack_text(
pipeline_name=pipeline_name,
pipeline_state=pipeline_state,
action=pipeline_action or "Deployment",
action=action,
)
attachment = format_slack_attachment(
pipeline_name=pipeline_name,
pipeline_state=pipeline_state,
execution_id=execution_id,
region=region,
action=action,
revision_summary=revision_summary,
revision_url=revision_url,
environment=os.environ["ENVIRONMENT"],
Expand Down
Loading

0 comments on commit 2058f04

Please sign in to comment.