Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance generator to update changelog only if generated code differs from existing #684

Merged
merged 2 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Added GHA release ([#614](https://github.com/opensearch-project/opensearch-py/pull/614))
- Incorporated API generation into CI workflow and fixed 'generate' nox session ([#660](https://github.com/opensearch-project/opensearch-py/pull/660))
- Added an automated api update bot for opensearch-py ([#664](https://github.com/opensearch-project/opensearch-py/pull/664))
- Enhance generator to update changelog only if generated code differs from existing ([#684](https://github.com/opensearch-project/opensearch-py/pull/684))
### Changed
- Updated the `get_policy` API in the index_management plugin to allow the policy_id argument as optional ([#633](https://github.com/opensearch-project/opensearch-py/pull/633))
- Updated the `point_in_time.md` guide with examples demonstrating the usage of the new APIs as alternatives to the deprecated ones. ([#661](https://github.com/opensearch-project/opensearch-py/pull/661))
Expand Down
3 changes: 2 additions & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,5 @@ def generate(session: Any) -> None:
"""
session.install("-rdev-requirements.txt")
session.run("python", "utils/generate_api.py")
session.notify("format")
session.run("nox", "-s", "format", external=True)
session.run("python", "utils/changelog_updater.py")
100 changes: 100 additions & 0 deletions utils/changelog_updater.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.
#
# Modifications Copyright OpenSearch Contributors. See
# GitHub history for details.

import filecmp
import os
import shutil

import requests


def main() -> None:
"""
Update CHANGELOG.md when API generator produces new code differing from existing.
"""
root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

after_paths = [
os.path.join(root_dir, f"opensearchpy/{folder}")
for folder in ["client", "_async/client"]
]

before_paths = [
os.path.join(root_dir, f"before_generate/{folder}")
for folder in ["client", "async_client"]
]

# Compare only .py files and take their union for client and async_client directories
before_files_client = set(
file for file in os.listdir(before_paths[0]) if file.endswith(".py")
)
after_files_client = set(
file for file in os.listdir(after_paths[0]) if file.endswith(".py")
)

before_files_async_client = set(
file for file in os.listdir(before_paths[1]) if file.endswith(".py")
)
after_files_async_client = set(
file for file in os.listdir(after_paths[1]) if file.endswith(".py")
)

all_files_union_client = before_files_client.union(after_files_client)
all_files_union_async_client = before_files_async_client.union(
after_files_async_client
)

# Compare files and check for mismatches or errors for client and async_client directories
mismatch_client, errors_client = filecmp.cmpfiles(
before_paths[0], after_paths[0], all_files_union_client, shallow=True
)[1:]
mismatch_async_client, errors_async_client = filecmp.cmpfiles(
before_paths[1], after_paths[1], all_files_union_async_client, shallow=True
)[1:]

if mismatch_client or errors_client or mismatch_async_client or errors_async_client:
print("Changes detected")
response = requests.get(
"https://api.github.com/repos/opensearch-project/opensearch-api-specification/commits"
)
if response.ok:
commit_info = response.json()[0]
commit_url = commit_info["html_url"]
latest_commit_sha = commit_info.get("sha")
else:
raise Exception(
f"Failed to fetch opensearch-api-specification commit information. Status code: {response.status_code}"
)

with open("CHANGELOG.md", "r+", encoding="utf-8") as file:
content = file.read()
if commit_url not in content:
if "### Updated APIs" in content:
file_content = content.replace(
"### Updated APIs",
f"### Updated APIs\n- Updated opensearch-py APIs to reflect [opensearch-api-specification@{latest_commit_sha[:7]}]({commit_url})",
1,
)
file.seek(0)
file.write(file_content)
file.truncate()
else:
raise Exception(
"'Updated APIs' section is not present in CHANGELOG.md"
)
else:
print("No changes detected")

# Clean up
for path in before_paths:
shutil.rmtree(path)


if __name__ == "__main__":
main()
43 changes: 16 additions & 27 deletions utils/generate_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import json
import os
import re
import shutil
from functools import lru_cache
from itertools import chain, groupby
from operator import itemgetter
Expand Down Expand Up @@ -764,34 +765,22 @@ def dump_modules(modules: Any) -> None:
unasync.unasync_files(filepaths, rules)
blacken(CODE_ROOT / "opensearchpy")

# Updating the CHANGELOG.md
response = requests.get(
"https://api.github.com/repos/opensearch-project/opensearch-api-specification/commits"
)
if response.ok:
commit_info = response.json()[0]
commit_url = commit_info["html_url"]
latest_commit_sha = commit_info.get("sha")
else:
raise Exception(
f"Failed to fetch opensearch-api-specification commit information. Status code: {response.status_code}"
)

with open("CHANGELOG.md", "r+", encoding="utf-8") as file:
content = file.read()
if commit_url not in content:
if "### Updated APIs" in content:
file_content = content.replace(
"### Updated APIs",
f"### Updated APIs\n- Updated opensearch-py APIs to reflect [opensearch-api-specification@{latest_commit_sha[:7]}]({commit_url})",
1,
)
file.seek(0)
file.write(file_content)
file.truncate()
else:
raise Exception("'Updated APIs' section is not present in CHANGELOG.md")
if __name__ == "__main__":
# Store directories for comparison pre-generation vs post-generation.
root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
before_paths = [
os.path.join(root_dir, f"before_generate/{folder}")
for folder in ["client", "async_client"]
]

for path in before_paths:
if os.path.exists(path):
shutil.rmtree(path)

shutil.copytree(os.path.join(root_dir, "opensearchpy/client"), before_paths[0])
shutil.copytree(
os.path.join(root_dir, "opensearchpy/_async/client"), before_paths[1]
)

if __name__ == "__main__":
dump_modules(read_modules())
Loading