From 4e62da1e5e6baf61674d3f5ae23d6d60c19f9c4a Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Fri, 11 Jul 2025 13:51:54 -0700 Subject: [PATCH] Add release note export script (#15109) --- scripts/export_release_notes.py | 139 ++++++++++++++++++++++++++++++++ scripts/make_release_notes.py | 9 ++- 2 files changed, 145 insertions(+), 3 deletions(-) create mode 100755 scripts/export_release_notes.py diff --git a/scripts/export_release_notes.py b/scripts/export_release_notes.py new file mode 100755 index 0000000000..8660d34229 --- /dev/null +++ b/scripts/export_release_notes.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 + +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Creates release notes files.""" + +import argparse +import os +import subprocess +import sys + + +def main(): + changelog_location = find_changelog_location() + + parser = argparse.ArgumentParser(description='Create release notes files.') + parser.add_argument( + '--version', '-v', required=True, help='Specify the release number.' + ) + parser.add_argument('--date', help='Specify the date.') + parser.add_argument( + '--repo', + '-r', + required=True, + help='The absolute path to the root of the repo containing changelogs.', + ) + parser.add_argument( + 'products', + help=( + 'The products to create changelogs for, separated by a comma (no' + ' space).' + ), + ) + args = parser.parse_args() + + # Check all inputs are valid product names + products = args.products.split(',') + product_paths = product_relative_locations() + for i, product in enumerate(products): + if product_paths[product] is None: + print('Unknown product ' + product, file=sys.stderr) + sys.exit(-1) + + created_files = [] + repo = args.repo + for i, product in enumerate(products): + changelog = '' + if product == 'Firestore' or product == 'Crashlytics': + changelog = product + '/CHANGELOG.md' + else: + changelog = 'Firebase' + product + '/CHANGELOG.md' + result = subprocess.run( + [ + 'python3', + 'scripts/make_release_notes.py', + changelog, + '-r', + 'firebase/firebase-ios-sdk', + ], + cwd=repo, + capture_output=True, + text=True, + check=True, + ) + generated_note = result.stdout + target_path = ( + changelog_location + + product_paths[product] + + '-m' + + args.version + + '.md' + ) + with open(target_path, 'w') as file: + file.write(generated_note) + created_files.append(target_path) + + output = '\n'.join(created_files) + print(output) + + +def find_changelog_location(): + wd = os.getcwd() + google3_index = wd.rfind('google3') + if google3_index == -1: + print('This script must be invoked from a SrcFS volume', file=sys.stderr) + sys.exit(-1) + google3_root = wd[: google3_index + len('google3')] + changelog_relative = ( + '/third_party/devsite/firebase/en/docs/ios/_ios-release-notes/' + ) + changelog_absolute = google3_root + changelog_relative + return changelog_absolute + + +def product_relative_locations(): + module_names = [ + 'ABTesting', + 'AI', + # Note: Analytics is generated separately. + 'AppCheck', + 'Auth', + 'Core', + 'Crashlytics', + 'Database', + 'Firestore', + 'Functions', + 'Installations', + 'Messaging', + 'Storage', + 'RemoteConfig', + # Note: Data Connect must be generated manually. + ] + # Most products follow the format Product/_product(-version.md) + relative_paths = {} + for index, name in enumerate(module_names): + path = name + '/_' + name.lower() + relative_paths[name] = path + + # There are a few exceptions + relative_paths['AppDistribution'] = 'AppDistribution/_appdist' + relative_paths['InAppMessaging'] = 'InAppMessaging/_fiam' + relative_paths['Performance'] = 'Performance/_perf' + return relative_paths + + +if __name__ == '__main__': + main() diff --git a/scripts/make_release_notes.py b/scripts/make_release_notes.py index f79a739717..886bc5d27c 100755 --- a/scripts/make_release_notes.py +++ b/scripts/make_release_notes.py @@ -51,10 +51,9 @@ PRODUCTS = { def main(): - local_repo = find_local_repo() parser = argparse.ArgumentParser(description='Create release notes.') - parser.add_argument('--repo', '-r', default=local_repo, + parser.add_argument('--repo', '-r', help='Specify which GitHub repo is local.') parser.add_argument('--only', metavar='VERSION', help='Convert only a specific version') @@ -64,6 +63,10 @@ def main(): help='The CHANGELOG.md file to parse') args = parser.parse_args() + repo = args.repo + if repo is None: + repo = find_local_repo() + if args.all: text = read_file(args.changelog) else: @@ -73,7 +76,7 @@ def main(): if not args.all: product = PRODUCTS.get(args.changelog) - renderer = Renderer(args.repo, product) + renderer = Renderer(repo, product) translator = Translator(renderer) result = translator.translate(text)