diff --git a/.gitignore b/.gitignore index c5b7406016..10f3751b51 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ out.txt vars/ test-report.yml +src/release_notes_workflow/results/* diff --git a/Pipfile b/Pipfile index 328cad7677..0b66bef510 100644 --- a/Pipfile +++ b/Pipfile @@ -38,6 +38,7 @@ typed-ast = "~=1.5.4" zipp = "~=3.8.1" importlib-metadata = "~=4.12.0" ruamel-yaml = "~=0.17.21" +mistune = "~=3.0.1" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 97bdeab8f0..5b493148b7 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c7967cf4ead64b6ca007013a5dd53dd22a044683b5cc7c2e1dd6c375a91e483d" + "sha256": "2693fe85022b7e3a58a900e44ed03c8e635808fef6186077c6a9e9c8e359833f" }, "pipfile-spec": 6, "requires": { @@ -67,7 +67,7 @@ "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" ], - "markers": "python_version >= '3.6'", + "markers": "python_full_version >= '3.6.0'", "version": "==2.1.1" }, "click": { @@ -226,6 +226,14 @@ ], "version": "==0.6.1" }, + "mistune": { + "hashes": [ + "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205", + "sha256:fc7f93ded930c92394ef2cb6f04a8aabab4117a91449e72dcc8dfa646a508be8" + ], + "index": "pypi", + "version": "==3.0.2" + }, "mypy": { "hashes": [ "sha256:02ef476f6dcb86e6f502ae39a16b93285fef97e7f1ff22932b657d1ef1f28655", @@ -564,7 +572,7 @@ "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" ], - "markers": "python_version >= '3.7'", + "markers": "python_version < '3.11'", "version": "==2.0.1" }, "typed-ast": { diff --git a/src/release_notes_workflow/README.md b/src/release_notes_workflow/README.md index e8a3e66c38..9348d0a6d5 100644 --- a/src/release_notes_workflow/README.md +++ b/src/release_notes_workflow/README.md @@ -1,13 +1,19 @@ -#### Components Release Notes Check +- [Consolidated Release Notes Automation](#consolidated-release-notes-automation) + - [Components Release Notes Check](#components-release-notes-check) + - [Consolidated Release Notes](#consolidated-release-notes) + +## Consolidated Release Notes + +### Components Release Notes Check Pulls the latest code to check if the release notes exists and whether new commits have been made based on user passed argument `--date`. Outputs a formated markdown table as follows. -*Usage* +#### Usage ``` ./release_notes.sh check manifests/3.0.0/opensearch-3.0.0.yml --date 2022-07-26 ``` -*Sample Output* +#### Sample Output ``` # OpenSearch CommitID(after 2022-07-26) & Release Notes info | Repo | Branch |CommitID|Commit Date|Release Notes| @@ -25,7 +31,7 @@ Pulls the latest code to check if the release notes exists and whether new commi The workflow uses the following arguments: * `--date`: To check if commit exists after a specific date (in format yyyy-mm-dd, example 2022-07-26). -* `--output`: To dump the output into an `.md` file, example `--output table.md`). +* `--output`: To dump the output into an `.md` file, example `--output table.md`. The following options are available. @@ -35,3 +41,61 @@ The following options are available. | --date | Shows commit after a specific date. | | --output | Saves the table output to user specified file. | | -v, --verbose | Show more verbose output. | + +### Consolidated Release Notes + +This workflow generates a consolidated release notes for all the components. +It utilizes the output from the preceding step to compile these consolidated release notes. If the preceding step hasn't been executed, it will automatically run that step first before generating the consolidated release notes. + +#### Usage +``` +./release_notes.sh compile manifests/3.0.0/opensearch-3.0.0.yml --date 2022-07-26 +``` + +#### Sample Output +Two output files are generated: +- Markdown table containing links to individual components' release notes for quick reference (Example: `release_notes_table-2.10.0.md`) +- Consolidated release notes for all the components (Example: `release_notes-2.10.0.md`) + +
+Markdown table with links + +# OpenSearch CommitID(after 2022-07-26) & Release Notes info +| Repo | Branch |CommitID|Commit Date|Release Notes Exists| URL | +|-------------------------|---------------|--------|-----------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------| +|alerting |[tags/2.10.0.0]|dc1b9bf |2023-09-18 |True |https://raw.githubusercontent.com/opensearch-project/alerting/2.10.0.0/release-notes/opensearch-alerting.release-notes-2.10.0.0.md | +|anomaly-detection |[tags/2.10.0.0]|bc4d8b1 |2023-09-08 |True |https://raw.githubusercontent.com/opensearch-project/anomaly-detection/2.10.0.0/release-notes/opensearch-anomaly-detection.release-notes-2.10.0.0.md | +|asynchronous-search |[tags/2.10.0.0]|a312d9a |2023-09-07 |True |https://raw.githubusercontent.com/opensearch-project/asynchronous-search/2.10.0.0/release-notes/opensearch-asynchronous-search.release-notes-2.10.0.0.md | +|common-utils |[tags/2.10.0.0]|0352c2f |2023-09-08 |True |https://raw.githubusercontent.com/opensearch-project/common-utils/2.10.0.0/release-notes/opensearch-common-utils.release-notes-2.10.0.0.md | +|cross-cluster-replication|[tags/2.10.0.0]|dee2f60 |2023-09-08 |True |https://raw.githubusercontent.com/opensearch-project/cross-cluster-replication/2.10.0.0/release-notes/opensearch-cross-cluster-replication.release-notes-2.10.0.0.md| +|custom-codecs |[tags/2.10.0.0]|3437b43 |2023-09-15 |True |https://raw.githubusercontent.com/opensearch-project/custom-codecs/2.10.0.0/release-notes/opensearch-custom-codecs.release-notes-2.10.0.0.md | +|geospatial |[tags/2.10.0.0]|a3da222 |2023-09-12 |True |https://raw.githubusercontent.com/opensearch-project/geospatial/2.10.0.0/release-notes/opensearch-geospatial.release-notes-2.10.0.0.md | +|index-management |[tags/2.10.0.0]|062badd |2023-09-07 |True |https://raw.githubusercontent.com/opensearch-project/index-management/2.10.0.0/release-notes/opensearch-index-management.release-notes-2.10.0.0.md | +|job-scheduler |[tags/2.10.0.0]|e9d3637 |2023-09-12 |True |https://raw.githubusercontent.com/opensearch-project/job-scheduler/2.10.0.0/release-notes/opensearch.job-scheduler.release-notes-2.10.0.0.md | +|k-NN |[tags/2.10.0.0]|e437016 |2023-09-07 |True |https://raw.githubusercontent.com/opensearch-project/k-NN/2.10.0.0/release-notes/opensearch-knn.release-notes-2.10.0.0.md | +|ml-commons |[tags/2.10.0.0]|521214b |2023-09-13 |True |https://raw.githubusercontent.com/opensearch-project/ml-commons/2.10.0.0/release-notes/opensearch-ml-common.release-notes-2.10.0.0.md | +|neural-search |[tags/2.10.0.0]|9476d43 |2023-09-07 |True |https://raw.githubusercontent.com/opensearch-project/neural-search/2.10.0.0/release-notes/opensearch-neural-search.release-notes-2.10.0.0.md | +|notifications |[tags/2.10.0.0]|0a9dfb0 |2023-09-07 |True |https://raw.githubusercontent.com/opensearch-project/notifications/2.10.0.0/release-notes/opensearch-notifications.release-notes-2.10.0.0.md | +|opensearch-observability |[tags/2.10.0.0]|d2c087c |2023-09-13 |True |https://raw.githubusercontent.com/opensearch-project/observability/2.10.0.0/release-notes/opensearch-observability.release-notes-2.10.0.0.md | +|opensearch-reports |[tags/2.10.0.0]|3095e3c |2023-09-13 |True |https://raw.githubusercontent.com/opensearch-project/reporting/2.10.0.0/release-notes/opensearch-reporting.release-notes-2.10.0.0.md | +|performance-analyzer |[tags/2.10.0.0]|3ee56fc |2023-09-07 |True |https://raw.githubusercontent.com/opensearch-project/performance-analyzer/2.10.0.0/release-notes/opensearch-performance-analyzer.release-notes-2.10.0.0.md | +|security |[tags/2.10.0.0]|6daa697 |2023-09-12 |True |https://raw.githubusercontent.com/opensearch-project/security/2.10.0.0/release-notes/opensearch-security.release-notes-2.10.0.0.md | +|security-analytics |[tags/2.10.0.0]|e005b5a |2023-09-19 |True |https://raw.githubusercontent.com/opensearch-project/security-analytics/2.10.0.0/release-notes/opensearch-security-analytics.release-notes-2.10.0.0.md | +|sql |[tags/2.10.0.0]|ef18b38 |2023-09-07 |True |https://raw.githubusercontent.com/opensearch-project/sql/2.10.0.0/release-notes/opensearch-sql.release-notes-2.10.0.0.md | + +
+ +--- + +The workflow uses the following arguments: +* `--date`: To check if commit exists after a specific date (in format yyyy-mm-dd, example 2022-07-26). This is optional if the previous step is already run. +* `--output`: To dump the consolidated release notes into an `.md` file, example `--output table.md`. + + +The following options are available. + +| name | description | +|--------------------|-------------------------------------------------------------------------| +| --date | Shows commit after a specific date. | +| --output | Saves the release notes to user specified file. | +| -v, --verbose | Show more verbose output. | diff --git a/src/release_notes_workflow/release_notes.py b/src/release_notes_workflow/release_notes.py index 6aa4ed36fb..c84f361ab8 100644 --- a/src/release_notes_workflow/release_notes.py +++ b/src/release_notes_workflow/release_notes.py @@ -19,18 +19,32 @@ class ReleaseNotes: - def __init__(self, manifest: InputManifest, date: str) -> None: + def __init__(self, manifest: InputManifest, date: str, action_type: str) -> None: self.manifest = manifest self.date = date + self.action_type = action_type def table(self) -> MarkdownTableWriter: table_result = [] for component in self.manifest.components.select(): + if component.name == 'OpenSearch' or component.name == 'OpenSearch-Dashboards' or component.name == 'notifications-core': + continue if hasattr(component, "repository"): table_result.append(self.check(component)) # type: ignore[arg-type] + + # Sort table_result based on Repo column + table_result.sort(key=lambda x: (x[0], x[1]) if len(x) > 1 else x[0]) + + if self.action_type == "check": + headers = ["Repo", "Branch", "CommitID", "Commit Date", "Release Notes Exists"] + elif self.action_type == "compile": + headers = ["Repo", "Branch", "CommitID", "Commit Date", "Release Notes Exists", "URL"] + else: + raise ValueError("Invalid action_type. Use 'check' or 'compile'.") + writer = MarkdownTableWriter( table_name=f" {self.manifest.build.name} CommitID(after {self.date}) & Release Notes info", - headers=["Repo", "Branch", "CommitID", "Commit Date", "Release Notes"], + headers=headers, value_matrix=table_result ) return writer @@ -57,4 +71,13 @@ def check(self, component: InputComponentFromSource) -> List: results.append(None) results.append(None) results.append(release_notes.exists()) + + if(release_notes.exists()): + releasenote = os.path.basename(release_notes.full_path) + repo_name = component.repository.split("/")[-1].split('.')[0] + repo_ref = component.ref.split("/")[-1] + url = f"https://raw.githubusercontent.com/opensearch-project/{repo_name}/{repo_ref}/release-notes/{releasenote}" + results.append(url) + else: + results.append(None) return results diff --git a/src/release_notes_workflow/release_notes_check_args.py b/src/release_notes_workflow/release_notes_check_args.py index 52e9621944..df6523f486 100644 --- a/src/release_notes_workflow/release_notes_check_args.py +++ b/src/release_notes_workflow/release_notes_check_args.py @@ -19,7 +19,7 @@ class ReleaseNotesCheckArgs: def __init__(self) -> None: parser = argparse.ArgumentParser(description="Checkout an OpenSearch Bundle and check for CommitID and Release Notes") - parser.add_argument("action", choices=["check"], help="Operation to perform.") + parser.add_argument("action", choices=["check", "compile"], help="Operation to perform.") parser.add_argument("manifest", type=argparse.FileType("r"), help="Manifest file.") parser.add_argument( "-v", diff --git a/src/release_notes_workflow/release_notes_component.py b/src/release_notes_workflow/release_notes_component.py index 1ffef28eea..ff33659cf1 100644 --- a/src/release_notes_workflow/release_notes_component.py +++ b/src/release_notes_workflow/release_notes_component.py @@ -25,27 +25,44 @@ def filename(self) -> str: @property def path(self) -> str: - return os.path.join(self.root, "release-notes") + release_notes_path = os.path.join(self.root, "release-notes") + return release_notes_path + + # combine path with the file in files_in_path such that it ends with the filename + @property + def full_path(self) -> str: + files_in_path = os.listdir(self.path) + for fname in files_in_path: + if fname.endswith(self.filename): + release_notes_full_path = os.path.join(self.path, fname) + return release_notes_full_path + return None def path_exists(self) -> bool: - return os.path.exists(self.path) + path_exists = os.path.exists(self.path) + return path_exists def exists(self) -> bool: - return self.path_exists() and any(fname.endswith(self.filename) for fname in os.listdir(self.path)) + if not os.path.exists(self.path): + return False + files_in_path = os.listdir(self.path) + return self.path_exists() and any(fname.endswith(self.filename) for fname in files_in_path) class ReleaseNotesOpenSearch(ReleaseNotesComponent): @property def filename(self) -> str: - return f'.release-notes-{self.build_version}.md' + release_notes_filename = f'.release-notes-{self.build_version}.md' + return release_notes_filename class ReleaseNotesOpenSearchPlugin(ReleaseNotesComponent): @property def filename(self) -> str: - return f'.release-notes-{self.build_version}.0.md' + release_notes_filename = f'.release-notes-{self.build_version}.0.md' + return release_notes_filename class ReleaseNotesComponents: diff --git a/src/run_releasenotes_check.py b/src/run_releasenotes_check.py index 4b8bdccee3..bd8c1a85ce 100644 --- a/src/run_releasenotes_check.py +++ b/src/run_releasenotes_check.py @@ -5,6 +5,15 @@ # this file be licensed under the Apache-2.0 license or a # compatible open source license. +import logging +import os +import re +import shutil +from collections import defaultdict + +import mistune +import requests + from manifests.input_manifest import InputManifest from release_notes_workflow.release_notes import ReleaseNotes from release_notes_workflow.release_notes_check_args import ReleaseNotesCheckArgs @@ -15,12 +24,175 @@ def main() -> int: args = ReleaseNotesCheckArgs() console.configure(level=args.logging_level) manifest_file = InputManifest.from_file(args.manifest) - release_notes = ReleaseNotes(manifest_file, args.date) - if args.action == "check": - table_output = release_notes.table() - table_output.write_table() + BUILD_VERSION = manifest_file.build.version + + # storing temporary release notes for testing purposes + BASE_FILE_PATH = "release_notes_workflow/results" + table_filename = f"{BASE_FILE_PATH}/release_notes_table-{BUILD_VERSION}.md" + urls_filename = f"{BASE_FILE_PATH}/release_notes_urls-{BUILD_VERSION}.txt" + + def capitalize_acronyms(formatted_name: str) -> str: + acronyms = {"sql": "SQL", "ml": "ML", "knn": "k-NN", "k-nn": "k-NN", "ml-commons": "ML Commons", "ml commons": "ML Commons"} + for acronym, replacement in acronyms.items(): + formatted_name = re.sub(r'\b' + re.escape(acronym) + r'\b', replacement, formatted_name, flags=re.IGNORECASE) + return formatted_name + + def format_component_name_from_url(url: str) -> str: + start_index = url.find("release-notes/") + if start_index == -1: + raise ValueError("'release-notes/' not found in the URL") + end_index = url.find(".release-notes", start_index) + if end_index == -1: + raise ValueError("'.release-notes' not found after 'release-notes/'") + component_name = url[start_index + len("release-notes/"): end_index] + if component_name == "opensearch-sql": + component_name = "SQL" + formatted_name = " ".join(word.capitalize() for word in re.split(r"[-.]", component_name)) + return capitalize_acronyms(formatted_name) + + def create_urls_file_if_not_exists() -> None: + + release_notes = ReleaseNotes(manifest_file, args.date, args.action) + table = release_notes.table() + + table_filepath = os.path.join(os.path.dirname(__file__), table_filename) + os.makedirs(os.path.dirname(table_filepath), exist_ok=True) + with open(table_filepath, "w") as table_file: + table.dump(table_file) + if args.output is not None: - table_output.dump(args.output) + logging.info(f"Moving {table_filepath} to {args.output}") + shutil.move(table_filepath, args.output) + else: + with open(table_filepath, "r") as table_file: + logging.info(table_file.read()) + + urls = [row[-1].strip() for row in table.value_matrix if row[-1]] + + urls_filepath = os.path.join(os.path.dirname(__file__), urls_filename) + os.makedirs(os.path.dirname(urls_filepath), exist_ok=True) + with open(urls_filepath, "w") as urls_file: + urls_file.writelines("\n".join(urls)) + + if args.action == "check": + create_urls_file_if_not_exists() + return 0 + + elif args.action == "compile": + create_urls_file_if_not_exists() + + RELEASENOTES_CATEGORIES = "BREAKING,FEATURES,ENHANCEMENTS,BUG FIXES,INFRASTRUCTURE,DOCUMENTATION,MAINTENANCE,REFACTORING,EXPERIMENTAL" + RELEASE_NOTE_MD = f"{BASE_FILE_PATH}/release_notes-{BUILD_VERSION}.md" + + # Clean up URLs in the file + urls_filepath = os.path.join(os.path.dirname(__file__), urls_filename) + with open(urls_filepath, "r") as file: + urls = [line.strip() for line in file if line.strip()] + + unique_urls = list(set(urls)) + + # store plugin data + plugin_data: defaultdict = defaultdict(lambda: defaultdict(list)) + # handle custom headings + heading_mapping = { + "Feature": "Features", + "Feat": "Features", + "Experimental Features": "Experimental", + "Refactor": "Refactoring", + "Enhancement": "Enhancements", + "Bug Fix": "Bug Fixes", + } + unique_headings = set() + for url in unique_urls: + if not url.startswith("#"): + response = requests.get(url) + + if response.status_code == 200: + content = response.text + plugin_name = format_component_name_from_url(url) + + # obtain headings (###) from the content + headings = [match.strip() for match in re.findall(r"###.+", content)] + if not headings: + continue + + # Store content under each heading in respective plugin + for i in range(len(headings)): + heading = headings[i].strip() + if heading.startswith("### "): + heading = heading[4:] + heading = heading.title() + + if heading in heading_mapping: + heading = heading_mapping[heading] + unique_headings.add(heading) + + content_start = content.find(headings[i]) + if content_start != -1: + if i == len(headings) - 1: + content_to_end = content[content_start:] + else: + content_to_end = content[content_start: content.find(headings[i + 1])] + content_to_end = content_to_end.replace(f"### {heading}", "").lstrip() + parts = content_to_end.split("*", 1) + if len(parts) == 2: + content_to_end = "*" + parts[1] + else: + content_to_end = content_to_end.lstrip().lstrip("-") + if len(content_to_end) > 0: + content_to_end = "* " + content_to_end + plugin_data[plugin_name][heading].append(content_to_end) + plugin_data = defaultdict(list, sorted(plugin_data.items())) + logging.info("Compilation complete.") + + # Markdown renderer + markdown = mistune.create_markdown() + + RELEASE_NOTE_MD_path = os.path.join(os.path.dirname(__file__), RELEASE_NOTE_MD) + os.makedirs(os.path.dirname(RELEASE_NOTE_MD_path), exist_ok=True) + + # Filter content for each category + with open(RELEASE_NOTE_MD_path, "w") as outfile: + outfile.write(markdown(f"# OpenSearch and OpenSearch Dashboards {BUILD_VERSION} Release Notes\n\n")) + + for category in RELEASENOTES_CATEGORIES.split(","): + # Discard category content if no data is available + temp_content = [] + temp_content.append(markdown(f"\n## {category}\n\n")) + + for plugin, categories in plugin_data.items(): + if category.lower() in [cat.lower() for cat in categories.keys()]: + for cat, content_list in categories.items(): + if cat.lower() == category.lower(): + for content in content_list: + if content.strip(): + temp_content.append(markdown(f"\n### {plugin}\n\n")) + temp_content.append(markdown(content)) + + if len(temp_content) > 1: + outfile.write("\n".join(temp_content)) + outfile.write("\n") + else: + logging.info(f"\n## {category} was empty\n\n") + + # Handle unknown categories + temp_content = [] + for plugin, categories in plugin_data.items(): + for cat, content_list in categories.items(): + if cat.lower() not in RELEASENOTES_CATEGORIES.lower(): + temp_content.append(f"\n## {cat.upper()}\n\n") + temp_content.append(f"\n### {plugin}\n\n") + temp_content.extend(content_list) + if temp_content: + outfile.write(markdown("## NON-COMPLIANT")) + for item in temp_content: + outfile.write(markdown(item)) + + if args.output is not None: + logging.info(f"Moving {RELEASE_NOTE_MD} to {args.output}") + shutil.move(RELEASE_NOTE_MD_path, args.output) + else: + logging.info(f"Release notes compiled to {RELEASE_NOTE_MD_path}") return 0 diff --git a/tests/data/opensearch-test-main.yml b/tests/data/opensearch-test-main.yml new file mode 100644 index 0000000000..536ff7ca87 --- /dev/null +++ b/tests/data/opensearch-test-main.yml @@ -0,0 +1,16 @@ +--- +schema-version: '1.0' +build: + name: OpenSearch + version: 'replace' +ci: + image: + name: opensearchstaging/ci-runner:ci-runner-centos7-opensearch-build-v3 + args: -e JAVA_HOME=/opt/java/openjdk-17 +components: + - name: OpenSearch-test + repository: https://github.com/opensearch-project/OpenSearch.git + ref: main + checks: + - gradle:publish + - gradle:properties:version diff --git a/tests/tests_release_notes_workflow/test_release_notes.py b/tests/tests_release_notes_workflow/test_release_notes.py index 0962906fc5..dcf8ca7721 100644 --- a/tests/tests_release_notes_workflow/test_release_notes.py +++ b/tests/tests_release_notes_workflow/test_release_notes.py @@ -20,18 +20,17 @@ def setUp(self) -> None: MANIFESTS = os.path.join( os.path.dirname(__file__), "..", - "..", - "manifests", + "data", ) - OPENSEARCH_MANIFEST = os.path.realpath(os.path.join(MANIFESTS, "templates", "opensearch", "default", "manifest.yml")) + OPENSEARCH_MANIFEST = os.path.realpath(os.path.join(MANIFESTS, "opensearch-test-main.yml")) self.manifest_file = InputManifest.from_file(open(OPENSEARCH_MANIFEST)) - self.release_notes = ReleaseNotes(self.manifest_file, "2022-07-26") - self.component = InputComponentFromSource({"name": "OpenSearch", "repository": "url", "ref": "ref"}) + self.release_notes = ReleaseNotes(self.manifest_file, "2022-07-26", "compile") + self.component = InputComponentFromSource({"name": "OpenSearch-test", "repository": "url", "ref": "ref"}) @patch("subprocess.check_output", return_value=''.encode()) @patch("subprocess.check_call") def test_check(self, *mocks: Any) -> None: - self.assertEqual(self.release_notes.check(self.component), ['OpenSearch', '[ref]', None, None, False]) + self.assertEqual(self.release_notes.check(self.component), ['OpenSearch-test', '[ref]', None, None, False, None]) @patch("subprocess.check_output", return_value=''.encode()) @patch("subprocess.check_call") @@ -39,11 +38,11 @@ def test_check_with_manifest(self, *mocks: Any) -> None: component = next(self.manifest_file.components.select()) if type(component) is InputComponentFromSource: self.assertIsInstance(component, InputComponentFromSource) - self.assertEqual(self.release_notes.check(component), ['OpenSearch', '[main]', None, None, False]) + self.assertEqual(self.release_notes.check(component), ['OpenSearch-test', '[main]', None, None, False]) - @patch('release_notes_workflow.release_notes.ReleaseNotes.check', return_value=['OpenSearch', '[main]', 'ee26e01', '2022-08-18', False]) + @patch('release_notes_workflow.release_notes.ReleaseNotes.check', return_value=['OpenSearch-test', '[main]', 'ee26e01', '2022-08-18', False]) def test_table(self, *mocks: Any) -> None: table_output = self.release_notes.table() self.assertEqual(table_output._table_name.strip(), 'OpenSearch CommitID(after 2022-07-26) & Release Notes info') - self.assertEqual(table_output.headers, ['Repo', 'Branch', 'CommitID', 'Commit Date', 'Release Notes']) - self.assertEqual(table_output.value_matrix, [['OpenSearch', '[main]', 'ee26e01', '2022-08-18', False]]) + self.assertEqual(table_output.headers, ['Repo', 'Branch', 'CommitID', 'Commit Date', 'Release Notes Exists', 'URL']) + self.assertEqual(table_output.value_matrix, [['OpenSearch-test', '[main]', 'ee26e01', '2022-08-18', False]]) diff --git a/tests/tests_release_notes_workflow/test_releasenotes_check_args.py b/tests/tests_release_notes_workflow/test_releasenotes_check_args.py index a9a654c4f8..3ee4fb074b 100644 --- a/tests/tests_release_notes_workflow/test_releasenotes_check_args.py +++ b/tests/tests_release_notes_workflow/test_releasenotes_check_args.py @@ -43,6 +43,11 @@ def test_manifest(self) -> None: self.assertEqual(ReleaseNotesCheckArgs().manifest.name, TestReleaseNotesCheckArgs.OPENSEARCH_MANIFEST) self.assertEqual(ReleaseNotesCheckArgs().date, datetime.date(2022, 7, 26)) + @patch("argparse._sys.argv", [RELEASE_NOTES_CHECK_PY, "compile", OPENSEARCH_MANIFEST, "--date", '2022-07-26']) + def test_manifest_compile(self) -> None: + self.assertEqual(ReleaseNotesCheckArgs().manifest.name, TestReleaseNotesCheckArgs.OPENSEARCH_MANIFEST) + self.assertEqual(ReleaseNotesCheckArgs().date, datetime.date(2022, 7, 26)) + @patch("argparse._sys.argv", [RELEASE_NOTES_CHECK_PY, "check", OPENSEARCH_MANIFEST]) def test_manifest_withoutdate(self) -> None: with self.assertRaises(SystemExit) as cm: @@ -55,6 +60,14 @@ def test_manifest_withoutdate(self) -> None: def test_verbose_true(self) -> None: self.assertTrue(ReleaseNotesCheckArgs().logging_level, logging.DEBUG) + @patch("argparse._sys.argv", [RELEASE_NOTES_CHECK_PY, "compile", OPENSEARCH_MANIFEST, "--date", '2022-07-26', "--verbose"]) + def test_verbose_true_compile(self) -> None: + self.assertTrue(ReleaseNotesCheckArgs().logging_level, logging.DEBUG) + @patch("argparse._sys.argv", [RELEASE_NOTES_CHECK_PY, "check", OPENSEARCH_MANIFEST, "--date", '2022-07-26', "--output", "test.md"]) def test_output(self) -> None: self.assertEqual(ReleaseNotesCheckArgs().output, "test.md") + + @patch("argparse._sys.argv", [RELEASE_NOTES_CHECK_PY, "compile", OPENSEARCH_MANIFEST, "--date", '2022-07-26', "--output", "test.md"]) + def test_output_compile(self) -> None: + self.assertEqual(ReleaseNotesCheckArgs().output, "test.md")