From 6e69727244ed70eb34e8bd7545349af0231d33c8 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Thu, 29 Jul 2021 17:23:41 -0700 Subject: [PATCH 01/23] add default format --- rocket_releaser/defaultFormat.json | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 rocket_releaser/defaultFormat.json diff --git a/rocket_releaser/defaultFormat.json b/rocket_releaser/defaultFormat.json new file mode 100644 index 0000000..35d3f2e --- /dev/null +++ b/rocket_releaser/defaultFormat.json @@ -0,0 +1,33 @@ +{ + "note_format": "• $DESCRIPTION <$TICKET_LINK|$TICKET_ID> <$PR_LINK|PR-$PR_ID>", + "release_notes_slack_format": { + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "Release $RELEASE_NUMBER" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "$RELEASE_NOTES" + } + }, + { + "type": "divider" + }, + { + "type": "context", + "elements": [ + { + "type": "mrkdwn", + "text": "*Changeset*: <$CHANGESET_LINK|$CHANGESET>\n*Stats*: $JIRA_TICKETS_NUM Jira tickets | $PR_TICKETS_NUM PR's\n*CI Build*: <$CI_LINK|$CI_ID>" + } + ] + } + ] + } +} \ No newline at end of file From d4a757127a40f1ec9ef8fe9bb8cc1657864b1898 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Fri, 30 Jul 2021 10:12:05 -0700 Subject: [PATCH 02/23] add plaintext format for plaintext ouput --- rocket_releaser/defaultFormat.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rocket_releaser/defaultFormat.json b/rocket_releaser/defaultFormat.json index 35d3f2e..bd82bf0 100644 --- a/rocket_releaser/defaultFormat.json +++ b/rocket_releaser/defaultFormat.json @@ -1,6 +1,7 @@ { "note_format": "• $DESCRIPTION <$TICKET_LINK|$TICKET_ID> <$PR_LINK|PR-$PR_ID>", - "release_notes_slack_format": { + "plaintext_format": "Release $RELEASE_NUMBER\n$RELEASE_NOTES\n*Changeset*: <$CHANGESET_LINK|$CHANGESET>\n*Stats*: $JIRA_TICKETS_NUM Jira tickets | $PR_TICKETS_NUM PR's", + "slack_format": { "blocks": [ { "type": "header", From 5444a99814ea2a4d3cb571235ff310333dff399d Mon Sep 17 00:00:00 2001 From: caleb15 Date: Fri, 30 Jul 2021 10:44:50 -0700 Subject: [PATCH 03/23] add dev instructions darn ImportError... --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 8adaa38..685c74c 100644 --- a/README.md +++ b/README.md @@ -76,3 +76,9 @@ Q: Why use this over [semantic-release](https://github.com/semantic-release/sema A: Semantic-release's [slack plugin](https://github.com/juliuscc/semantic-release-slack-bot) as of 05/21 does not generate an extended changelog. Semantic Release does not have a plugin for tagging github PR's or tickets either, as far as I am aware. +## Contributing to this repo: +We welcome contributions! + +* To setup the repo run `python -m pip install -r dev-requirements.pip`. +* To run the script run `python -m rocket_releaser` from the root of the repo with your desired arguments. Trying to run the release notes script from the command line directly will result in a ImportError! +* To run tests run `pytest` from the root of the repo \ No newline at end of file From b9a77ac7205d04c640adfc76ce9751fde8c6a458 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Mon, 2 Aug 2021 11:48:34 -0700 Subject: [PATCH 04/23] add label information --- rocket_releaser/prs.py | 9 ++++++++- tests/test_prs.py | 11 ++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/rocket_releaser/prs.py b/rocket_releaser/prs.py index 97fa260..e0f5802 100644 --- a/rocket_releaser/prs.py +++ b/rocket_releaser/prs.py @@ -27,7 +27,9 @@ def pull_request_dicts(self, deploy_shas: List[str] = []) -> List[dict]: # number of associatedPullRequests to pull is entirely arbitrary # 99% of cases it should only be 1 anyways - query = """ + # Example query variables: + # {"sha": "fa6e8664600bcf1ff6c2968c74e7555eb1370aaa", "repo": "rocket_releaser", "owner": "15five"} + query: str = """ query associatedPRs($sha: String, $repo: String!, $owner: String!){ repository(name: $repo, owner: $owner) { commit: object(expression: $sha) { @@ -39,6 +41,11 @@ def pull_request_dicts(self, deploy_shas: List[str] = []) -> List[dict]: number body merged + labels(first:100) { + nodes{ + name + } + } } } } diff --git a/tests/test_prs.py b/tests/test_prs.py index 69d4dd8..4bb89a7 100644 --- a/tests/test_prs.py +++ b/tests/test_prs.py @@ -13,8 +13,12 @@ class MockGraphQL: } } - def set_return_val(self, number, body): - node = {"number": number, "body": body} + def set_return_val(self, number, body, label_name): + node: dict = { + "number": number, + "body": body, + "labels": {"nodes": [{"name": label_name}]}, + } self.val["data"]["repository"]["commit"]["associatedPullRequests"]["edges"][0][ "node" ] = node @@ -40,10 +44,11 @@ def mock_graphql(mocker: MockFixture): def test_pull_request_dicts_should_have_correct_content(): - m.set_return_val(12, "test") + m.set_return_val(12, "test", "fake label") pull_request_dicts = p.pull_request_dicts(["fake sha"]) assert len(pull_request_dicts) == 1 assert pull_request_dicts[0]["number"] == 12 assert pull_request_dicts[0]["body"] == "test" assert pull_request_dicts[0]["deploy_sha"] == "fake sha" + assert pull_request_dicts[0]["labels"]["nodes"][0]["name"] == "fake label" From 5f4d83d4eccd6d510b6ff68b5fcbc1a59545dd33 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Mon, 2 Aug 2021 12:01:19 -0700 Subject: [PATCH 05/23] fix makefile and add code coverage directions --- Makefile | 2 +- README.md | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3b5c175..9cc7411 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ test: ## run tests quickly with the default Python pytest coverage: ## check code coverage quickly with the default Python - coverage run -m pytest + coverage run --source rocket_releaser -m pytest coverage report -m coverage html $(BROWSER) htmlcov/index.html diff --git a/README.md b/README.md index 685c74c..dc9100e 100644 --- a/README.md +++ b/README.md @@ -81,4 +81,12 @@ We welcome contributions! * To setup the repo run `python -m pip install -r dev-requirements.pip`. * To run the script run `python -m rocket_releaser` from the root of the repo with your desired arguments. Trying to run the release notes script from the command line directly will result in a ImportError! -* To run tests run `pytest` from the root of the repo \ No newline at end of file +* To run tests run `pytest` from the root of the repo + + +### Generating Code Coverage +Follow the instructions in https://coverage.readthedocs.io/en/coverage-5.5/ +Make note of the following: +* To prevent site packages from being shown in coverage, run `coverage run --source rocket_releaser -m pytest` +* To open a html file in WSL, run explorer.exe index.html in the htmlcov directory. +* There is a handy makefile coverage command to use if you wish \ No newline at end of file From bc49cf405f474ba0603456be32f76131e788405e Mon Sep 17 00:00:00 2001 From: caleb15 Date: Mon, 2 Aug 2021 12:26:44 -0700 Subject: [PATCH 06/23] 100% test coverage yay okay actually 97% but close enough --- tests/test_prs.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/test_prs.py b/tests/test_prs.py index 4bb89a7..d79297e 100644 --- a/tests/test_prs.py +++ b/tests/test_prs.py @@ -23,6 +23,12 @@ def set_return_val(self, number, body, label_name): "node" ] = node + def set_no_associated_prs(self): + self.val["data"]["repository"]["commit"]["associatedPullRequests"] = [] + + def set_error(self): + self.val = {"errors": [{"message": "foo"}]} + def run_query(self, *args, **kwargs): return self.val @@ -52,3 +58,21 @@ def test_pull_request_dicts_should_have_correct_content(): assert pull_request_dicts[0]["body"] == "test" assert pull_request_dicts[0]["deploy_sha"] == "fake sha" assert pull_request_dicts[0]["labels"]["nodes"][0]["name"] == "fake label" + + +def test_method_is_failsafe(caplog): + m.set_no_associated_prs() + + sha = "fake sha" + p.pull_request_dicts([sha]) + assert ( + caplog.records[0].message == f"commit {sha} not found or has no associated PRs" + ) + + +def test_method_logs_errors(caplog): + m.set_error() + + sha = "fake sha" + p.pull_request_dicts([sha]) + assert caplog.records[0].message == f"error with sha {sha}: foo" From 4e205ef1e3ad7a31ef82f3d46f532b08e35f2195 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Mon, 2 Aug 2021 12:27:50 -0700 Subject: [PATCH 07/23] remove unused module --- rocket_releaser/release_notes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rocket_releaser/release_notes.py b/rocket_releaser/release_notes.py index 3323340..c68eaa3 100644 --- a/rocket_releaser/release_notes.py +++ b/rocket_releaser/release_notes.py @@ -1,7 +1,6 @@ import argparse import datetime import logging -import re import subprocess from sys import stdout, argv from typing import List From 0030d6a3112f4f354291e8ed82633a45542db539 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Tue, 10 Aug 2021 16:03:15 -0700 Subject: [PATCH 08/23] add hotfix alert format --- rocket_releaser/defaultFormat.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rocket_releaser/defaultFormat.json b/rocket_releaser/defaultFormat.json index bd82bf0..a206bb3 100644 --- a/rocket_releaser/defaultFormat.json +++ b/rocket_releaser/defaultFormat.json @@ -1,4 +1,5 @@ { + "hotfix_alert_format": ":fire: *HOTFIX* :fire: ", "note_format": "• $DESCRIPTION <$TICKET_LINK|$TICKET_ID> <$PR_LINK|PR-$PR_ID>", "plaintext_format": "Release $RELEASE_NUMBER\n$RELEASE_NOTES\n*Changeset*: <$CHANGESET_LINK|$CHANGESET>\n*Stats*: $JIRA_TICKETS_NUM Jira tickets | $PR_TICKETS_NUM PR's", "slack_format": { @@ -7,7 +8,7 @@ "type": "header", "text": { "type": "plain_text", - "text": "Release $RELEASE_NUMBER" + "text": "${HOTFIX_ALERT}Release $RELEASE_NUMBER" } }, { From fe854d6b5002c7199d49fe445f182961cfae35d3 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Wed, 11 Aug 2021 09:55:17 -0700 Subject: [PATCH 09/23] revamp changelog --- rocket_releaser/changelog.py | 147 ++++++++++++++--------------------- tests/test_changelog.py | 139 ++++++++++----------------------- 2 files changed, 99 insertions(+), 187 deletions(-) diff --git a/rocket_releaser/changelog.py b/rocket_releaser/changelog.py index 7977b3f..c07ed92 100644 --- a/rocket_releaser/changelog.py +++ b/rocket_releaser/changelog.py @@ -1,6 +1,7 @@ +from collections import defaultdict import re import logging -from typing import List +from typing import DefaultDict, List logger = logging.getLogger(__name__) @@ -12,9 +13,6 @@ def __init__( self.pull_request_dicts = pull_request_dicts self.features = [] - self.fixes = [] - self.noteworthy = [] - self.qa_notes = [] self.org_name = org_name self.repo_name = repo_name self.jira_url = jira_url @@ -22,7 +20,7 @@ def __init__( @property def release_bodies(self): return [ - (pr.get("number"), pr.get("body")) + (pr.get("number"), pr.get("body"), pr.get("labels")) for pr in self.pull_request_dicts if "release" in pr.get("body").lower() ] @@ -38,7 +36,7 @@ def is_fix(line: str): @staticmethod def add_github_link(org_name: str, repo_name: str, line, pr_number): - return f"{line} PR: " + return f"{line} " @staticmethod def add_jira_link(line: str, jira_url: str): @@ -49,7 +47,9 @@ def add_jira_link(line: str, jira_url: str): ) @staticmethod - def linkify(org_name: str, repo_name: str, line: str, pr_number, jira_url=""): + def linkify( + org_name: str, repo_name: str, line: str, pr_number, jira_url: str = "" + ): """add jira & github links""" if jira_url: @@ -58,87 +58,56 @@ def linkify(org_name: str, repo_name: str, line: str, pr_number, jira_url=""): return line @staticmethod - def make_jira_id_bold(line: str): - return line.replace("[", "*[").replace("]", "]*") + def extract_notes_from_pr(pr_body: str, header: str): + """ + Extracts the block of text under a specified header + """ + # Remove HTML comments. Will not work in all cases. + lines = re.sub(" - -QA -default avatar image should be a penguin [ENG-1234] ``` ## Using Ansible?: diff --git a/tests/test_release_notes.py b/tests/test_release_notes.py index 54fb1f6..deed13a 100644 --- a/tests/test_release_notes.py +++ b/tests/test_release_notes.py @@ -51,8 +51,7 @@ def test_release_notes_plaintext(mocker): RELEASES Fixes ENG-9999 -QA -bla bla bla +this text should be ignored """, "merged": True, "labels": [], @@ -89,8 +88,6 @@ def test_release_notes_slack(mocker): RELEASES Fixes ENG-9999 -QA -bla bla bla """, "merged": True, "labels": [], @@ -131,9 +128,6 @@ def test_release_notes_skips_unmerged_pr(mocker): "body": """ RELEASES Fixes ENG-9999 - -QA -bla bla bla """, "merged": False, "labels": [], @@ -209,9 +203,6 @@ def test_turn_changelog_into_string_has_correct_num_jira_tickets(mocker): "body": """ RELEASES feature bla which is not associated to jira ticket - -QA -bla bla bla """, "labels": [], "merged": True, From 90726ea00b6e5abe6796a35eb129c80686b9b6a9 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Wed, 11 Aug 2021 15:31:30 -0700 Subject: [PATCH 15/23] add custom format --- README.md | 5 +++++ rocket_releaser/release_notes.py | 22 ++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e026225..9b3d087 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,11 @@ Change default avatar image #public Closes [ENG-1234] --> ``` +## Configuration +To configure the format of the release notes output you can create a `rocket_releaser_format.json` file in the root of your repo. + +You can use the default configuration as a reference: [link](rocket_releaser/defaultFormat.json) + ## Using Ansible?: You can run Rocket Releaser in ansible like so: diff --git a/rocket_releaser/release_notes.py b/rocket_releaser/release_notes.py index 08d61e3..f578a69 100644 --- a/rocket_releaser/release_notes.py +++ b/rocket_releaser/release_notes.py @@ -57,6 +57,21 @@ def build_template_context( return template_context +def get_config(repo_dir: str): + script_directory = os.path.dirname(__file__) + default_format_path = os.path.join(script_directory, "defaultFormat.json") + with open(default_format_path) as f: + release_notes_format: Dict[str] = json.load(f) + try: + custom_config_path = os.path.join(repo_dir, "rocket_releaser_format.json") + with open(custom_config_path) as f: + release_notes_format = json.load(f) + except FileNotFoundError: + logger.debug(f"Custom config not found in {repo_dir}, using default") + pass + return release_notes_format + + def release_notes( github_token: str, from_revision: str, @@ -114,12 +129,7 @@ def release_notes( num_tickets = ticket_labeler.label_tickets(env_name, vpc_name, dry_run=dry_run) logger.info(f"labeled {num_tickets} tickets") - script_directory = os.path.dirname(__file__) - default_format_path = os.path.join(script_directory, "defaultFormat.json") - with open(default_format_path) as f: - default_format: Dict[str] = json.load(f) - # todo: load custom format - release_notes_format = default_format + release_notes_format = get_config(repo_dir) template_context = build_template_context( num_tickets, From 0f0bccb564767e320fd2583bbfa85a4639f6062e Mon Sep 17 00:00:00 2001 From: caleb15 Date: Wed, 11 Aug 2021 15:46:58 -0700 Subject: [PATCH 16/23] add pull request template --- .github/PULL_REQUEST_TEMPLATE.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..30d385b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ + + + + +RELEASES + + + +![](gif_link) + + + \ No newline at end of file From f075dd7044290cc7432778fd1a348803081bed33 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Wed, 11 Aug 2021 17:08:52 -0700 Subject: [PATCH 17/23] remove CI from default format for now MVP and all that jazz --- rocket_releaser/defaultFormat.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocket_releaser/defaultFormat.json b/rocket_releaser/defaultFormat.json index a5404aa..e5d9d79 100644 --- a/rocket_releaser/defaultFormat.json +++ b/rocket_releaser/defaultFormat.json @@ -26,7 +26,7 @@ "elements": [ { "type": "mrkdwn", - "text": "*Changeset*: <$CHANGESET_LINK|$CHANGESET>\n*Stats*: $NUM_TICKETS tickets | $NUM_PRS PR's\n*CI Build*: <$CI_LINK|$CI_ID>" + "text": "*Changeset*: <$CHANGESET_LINK|$CHANGESET>\n*Stats*: $NUM_TICKETS tickets | $NUM_PRS PR's" } ] } From 39ebd43943263a3c7e14e849908c342435dd0aa8 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Wed, 11 Aug 2021 17:09:17 -0700 Subject: [PATCH 18/23] add slack block posting --- rocket_releaser/release_notes.py | 17 +++++++++++------ rocket_releaser/slack.py | 5 +++-- tests/test_release_notes.py | 8 ++++---- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/rocket_releaser/release_notes.py b/rocket_releaser/release_notes.py index f578a69..6e42e6d 100644 --- a/rocket_releaser/release_notes.py +++ b/rocket_releaser/release_notes.py @@ -132,7 +132,7 @@ def release_notes( release_notes_format = get_config(repo_dir) template_context = build_template_context( - num_tickets, + str(num_tickets), env_name, from_revision, to_revision, @@ -145,10 +145,15 @@ def release_notes( plaintext = Template(release_notes_format["plaintext_format"]).substitute( template_context ) - slack_text = "ahhhhh" - # slack_text = Template(release_notes_format["slack_format"]).substitute( - # template_context - # ) + slack_format_string = json.dumps(release_notes_format["slack_format"]) + safe_context: Dict[str] = {} + for key in template_context: + # Prevent quotations marks or newlines from ruining JSON syntax + safe_context[key] = ( + template_context[key].replace('"', '\\"').replace("\n", "\\n") + ) + templated_string = Template(slack_format_string).substitute(safe_context) + slack_blocks = json.loads(templated_string) if verbose: print(plaintext) @@ -158,7 +163,7 @@ def release_notes( if slack_webhook_key: logger.info(f"Pushing ChangeLog data to {env_name} Slack channel.") - post_deployment_message_to_slack(slack_webhook_key, slack_text) + post_deployment_message_to_slack(slack_webhook_key, slack_blocks) else: logger.warning("no slack webhook key. Not pushing to slack.") diff --git a/rocket_releaser/slack.py b/rocket_releaser/slack.py index f36136c..c67f60d 100644 --- a/rocket_releaser/slack.py +++ b/rocket_releaser/slack.py @@ -1,10 +1,11 @@ +from typing import Dict import slacker import logging logger = logging.getLogger(__name__) -def post_deployment_message_to_slack(slack_webhook_key, text): +def post_deployment_message_to_slack(slack_webhook_key: str, slack_blocks: Dict): incoming_webhook_url = f"https://hooks.slack.com/services/{slack_webhook_key}" @@ -18,7 +19,7 @@ def post_deployment_message_to_slack(slack_webhook_key, text): slack.incomingwebhook.post( { - "text": text, + "blocks": slack_blocks, "username": display_name, "icon_url": icon_url, "icon_emoji": icon_url, diff --git a/tests/test_release_notes.py b/tests/test_release_notes.py index deed13a..3b52723 100644 --- a/tests/test_release_notes.py +++ b/tests/test_release_notes.py @@ -95,18 +95,18 @@ def test_release_notes_slack(mocker): mocker.patch("rocket_releaser.prs.PRs.pull_request_dicts", return_value=[mock_pr_1]) with mocker.patch( - "rocket_releaser.slack.post_deployment_message_to_slack", + "rocket_releaser.release_notes.post_deployment_message_to_slack", ) as mocked_post_slack_message: release_notes.release_notes( "github_token", - "0782415", - "8038fc3", + "56bfe2d", + "fa6e866", "org_name", "repo_name", jira_token="jira_token", jira_username="", jira_url="", - dry_run=True, + slack_webhook_key="foo", ) mocked_post_slack_message.assert_called_once() slack_dict: Dict[str] = mocked_post_slack_message.call_args.args[0] From fd304af25333b5c1d246420c6c20408fc17a10fa Mon Sep 17 00:00:00 2001 From: caleb15 Date: Thu, 12 Aug 2021 14:56:51 -0700 Subject: [PATCH 19/23] fix slack test --- tests/test_release_notes.py | 50 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/tests/test_release_notes.py b/tests/test_release_notes.py index 3b52723..d0896a7 100644 --- a/tests/test_release_notes.py +++ b/tests/test_release_notes.py @@ -94,32 +94,32 @@ def test_release_notes_slack(mocker): } mocker.patch("rocket_releaser.prs.PRs.pull_request_dicts", return_value=[mock_pr_1]) - with mocker.patch( + mocked_post_slack_message = mocker.patch( "rocket_releaser.release_notes.post_deployment_message_to_slack", - ) as mocked_post_slack_message: - release_notes.release_notes( - "github_token", - "56bfe2d", - "fa6e866", - "org_name", - "repo_name", - jira_token="jira_token", - jira_username="", - jira_url="", - slack_webhook_key="foo", - ) - mocked_post_slack_message.assert_called_once() - slack_dict: Dict[str] = mocked_post_slack_message.call_args.args[0] - assert slack_dict["blocks"][0]["text"]["text"] == "Prod Release" - assert ( - slack_dict["blocks"][1]["text"]["text"] - == "*Uncategorized*\n• Fixes ENG-9999" - ) - assert ( - slack_dict["blocks"][3]["elements"][0]["text"] - == """*Changeset*: -*Stats*: 0 tickets | 0 PR's""" - ) + ) + release_notes.release_notes( + "github_token", + "56bfe2d", + "fa6e866", + "org_name", + "repo_name", + jira_token="jira_token", + jira_username="", + jira_url="", + slack_webhook_key="foo", + ) + mocked_post_slack_message.assert_called_once() + slack_dict: Dict[str] = mocked_post_slack_message.call_args.args[1] + assert slack_dict["blocks"][0]["text"]["text"] == "Prod Release" + assert ( + slack_dict["blocks"][1]["text"]["text"] + == "*Uncategorized*\n• Fixes ENG-9999 \n\n" + ) + assert ( + slack_dict["blocks"][3]["elements"][0]["text"] + == """*Changeset*: +*Stats*: 1 tickets | 1 PR's""" + ) def test_release_notes_skips_unmerged_pr(mocker): From acd6f1e5e385ef7e39a625d40171bb015d70752b Mon Sep 17 00:00:00 2001 From: caleb15 Date: Thu, 12 Aug 2021 16:38:24 -0700 Subject: [PATCH 20/23] log existance of key --- rocket_releaser/release_notes.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rocket_releaser/release_notes.py b/rocket_releaser/release_notes.py index 6e42e6d..0526c24 100644 --- a/rocket_releaser/release_notes.py +++ b/rocket_releaser/release_notes.py @@ -257,14 +257,16 @@ def main(args: List[str]): "repo_name": parsed_args.repo_name, "repo_dir": parsed_args.repo_dir, "search_branch": parsed_args.search_branch, - "slack_webhook_key": "CENSORED", + "slack_webhook_key": "CENSORED" + if parsed_args.slack_webhook_key + else "", "env_name": parsed_args.env_name, "vpc_name": parsed_args.vpc_name, "label_tickets": parsed_args.label_tickets, "verbose": parsed_args.verbose, "dry_run": parsed_args.dry_run, "fetch_before": parsed_args.fetch_before, - "jira_token": "CENSORED", + "jira_token": "CENSORED" if parsed_args.jira_token else "", "jira_username": parsed_args.jira_username, "jira_url": parsed_args.jira_url, } From 0bec9037175b4a68094111ae5da5ef98843d3325 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Thu, 12 Aug 2021 17:15:27 -0700 Subject: [PATCH 21/23] type slack_blocks --- rocket_releaser/release_notes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocket_releaser/release_notes.py b/rocket_releaser/release_notes.py index 0526c24..005638b 100644 --- a/rocket_releaser/release_notes.py +++ b/rocket_releaser/release_notes.py @@ -153,7 +153,7 @@ def release_notes( template_context[key].replace('"', '\\"').replace("\n", "\\n") ) templated_string = Template(slack_format_string).substitute(safe_context) - slack_blocks = json.loads(templated_string) + slack_blocks: Dict[str] = json.loads(templated_string) if verbose: print(plaintext) From a2875f1b01f2b73cf105b0efa47f3d075967b28a Mon Sep 17 00:00:00 2001 From: caleb15 Date: Thu, 12 Aug 2021 17:16:44 -0700 Subject: [PATCH 22/23] fix slack error also do raise for status so future errors dont happen silently --- rocket_releaser/slack.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rocket_releaser/slack.py b/rocket_releaser/slack.py index c67f60d..10876b9 100644 --- a/rocket_releaser/slack.py +++ b/rocket_releaser/slack.py @@ -1,11 +1,13 @@ -from typing import Dict +from typing import Dict, List import slacker import logging logger = logging.getLogger(__name__) -def post_deployment_message_to_slack(slack_webhook_key: str, slack_blocks: Dict): +def post_deployment_message_to_slack( + slack_webhook_key: str, slack_blocks: Dict[str, List[Dict]] +): incoming_webhook_url = f"https://hooks.slack.com/services/{slack_webhook_key}" @@ -17,11 +19,12 @@ def post_deployment_message_to_slack(slack_webhook_key: str, slack_blocks: Dict) display_name = "Deployment Team" icon_url = ":rocket:" - slack.incomingwebhook.post( + response = slack.incomingwebhook.post( { - "blocks": slack_blocks, + "blocks": slack_blocks["blocks"], "username": display_name, "icon_url": icon_url, "icon_emoji": icon_url, } ) + response.raise_for_status() From bea36db3eebd7c052367bb61f083dceec91dd0d1 Mon Sep 17 00:00:00 2001 From: caleb15 Date: Thu, 12 Aug 2021 17:20:34 -0700 Subject: [PATCH 23/23] fix hotfix format the header is plaintext so I shouldn't do markdown --- rocket_releaser/defaultFormat.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocket_releaser/defaultFormat.json b/rocket_releaser/defaultFormat.json index e5d9d79..fc70a60 100644 --- a/rocket_releaser/defaultFormat.json +++ b/rocket_releaser/defaultFormat.json @@ -1,5 +1,5 @@ { - "hotfix_alert_format": ":fire: *HOTFIX* :fire: ", + "hotfix_alert_format": ":fire: HOTFIX :fire: ", "note_format": "~~currently not used~~• $DESCRIPTION <$TICKET_LINK|$TICKET_ID> <$PR_LINK|PR-$PR_ID>", "plaintext_format": "${HOTFIX_ALERT}${ENV} Release\n$RELEASE_NOTES\n*Changeset*: <$CHANGESET_LINK|$CHANGESET>\n*Stats*: $NUM_TICKETS tickets | $NUM_PRS PR's", "slack_format": {