From f6e404c5f7304191d7fd4c3852462ec2297937cb Mon Sep 17 00:00:00 2001 From: michalChrobot Date: Wed, 16 Jul 2025 15:21:52 +0200 Subject: [PATCH 1/9] Added python script to format the package for the release --- Tools/scripts/release.py | 66 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Tools/scripts/release.py diff --git a/Tools/scripts/release.py b/Tools/scripts/release.py new file mode 100644 index 0000000000..75c9438f6d --- /dev/null +++ b/Tools/scripts/release.py @@ -0,0 +1,66 @@ +""" +NGO release script +- Update changelogs + validation exception file based on manifest version +""" +#!/usr/bin/env python3 +import datetime +import json +import os +import re + +package_name = 'com.unity.netcode.gameobjects' + +def update_changelog(new_version): + changelog_entry = f'## [{new_version}] - {datetime.date.today().isoformat()}' + + print(changelog_entry) + + changelog_path = f'{package_name}/CHANGELOG.md' + with open(changelog_path, 'rb') as f: + changelog_text = f.read() + + changelog_text = re.sub(br'## \[Unreleased\]', bytes(changelog_entry, 'UTF-8'), changelog_text) + + with open(changelog_path, 'wb') as f: + f.write(changelog_text) + +def update_validation_exceptions(new_version): + validation_file = f'{package_name}/ValidationExceptions.json' + if not os.path.exists(validation_file): + return + + with open(validation_file, 'rb') as f: + json_text = f.read() + data = json.loads(json_text) + updated = False + for exceptionElements in ["WarningExceptions", "ErrorExceptions"]: + exceptions = data.get(exceptionElements) + + if exceptions is not None: + for exception in exceptions: + if 'PackageVersion' in exception: + exception['PackageVersion'] = new_version + updated = True + + if not updated: + return + + with open(validation_file, "w", encoding="UTF-8") as json_file: + json.dump(data, json_file, ensure_ascii=False, indent=2) + json_file.write("\n") # Add newline cause Py JSON does not + print(f" updated `{validation_file}`") + + +def get_manifest_json_version(filename): + with open(filename, 'rb') as f: + json_text = f.read() + data = json.loads(json_text) + + return data['version'] + +if __name__ == '__main__': + manifest_path = f'{package_name}/package.json' + version = get_manifest_json_version(manifest_path) + update_validation_exceptions(version) + + update_changelog(version) From b0397b59f14e5beab90cd5e6a8202d2ad652dcf9 Mon Sep 17 00:00:00 2001 From: michalChrobot Date: Wed, 16 Jul 2025 15:23:08 +0200 Subject: [PATCH 2/9] Updated package version to match "current state of the package" --- com.unity.netcode.gameobjects/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/package.json b/com.unity.netcode.gameobjects/package.json index 70eeba81b1..3126631d14 100644 --- a/com.unity.netcode.gameobjects/package.json +++ b/com.unity.netcode.gameobjects/package.json @@ -2,7 +2,7 @@ "name": "com.unity.netcode.gameobjects", "displayName": "Netcode for GameObjects", "description": "Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.", - "version": "2.4.3", + "version": "2.5.0", "unity": "6000.0", "dependencies": { "com.unity.nuget.mono-cecil": "1.11.4", From 269fe219ed7a777f22b367d96cbc912995c4e034 Mon Sep 17 00:00:00 2001 From: michalChrobot Date: Wed, 16 Jul 2025 15:23:25 +0200 Subject: [PATCH 3/9] Added minimal supported editor to metafile --- .yamato/project.metafile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.yamato/project.metafile b/.yamato/project.metafile index c347c412e8..099d274a75 100644 --- a/.yamato/project.metafile +++ b/.yamato/project.metafile @@ -159,6 +159,8 @@ validation_editors: - 6000.1 - 6000.2 - trunk + minimal: + - 6000.0 # Scripting backends used by Standalone RunTimeTests--------------------------------------------------- From c037d539539f20f85ec3fbe756c8a596b1e67d9b Mon Sep 17 00:00:00 2001 From: michalChrobot Date: Wed, 16 Jul 2025 15:24:02 +0200 Subject: [PATCH 4/9] Created vetting test and added to triggers (initial checks and daily) --- .yamato/_run-all.yml | 2 ++ .yamato/_triggers.yml | 2 ++ .yamato/vetting-test.yml | 25 +++++++++++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 .yamato/vetting-test.yml diff --git a/.yamato/_run-all.yml b/.yamato/_run-all.yml index 7ec3bee321..089a8b5247 100644 --- a/.yamato/_run-all.yml +++ b/.yamato/_run-all.yml @@ -17,6 +17,8 @@ run_quick_checks: dependencies: - .yamato/package-pack.yml#package_pack_-_ngo_ubuntu - .yamato/project-standards.yml#standards_ubuntu_testproject_trunk + # Run API validation to early-detect all new APIs that would force us to release new minor version of the package. Note that for this to work the package version in package.json must correspond to "actual package state" which means that it should be higher than last released version + - .yamato/vetting-test.yml#vetting_test # Runs all package tests diff --git a/.yamato/_triggers.yml b/.yamato/_triggers.yml index ec9da28a62..0b651dfe66 100644 --- a/.yamato/_triggers.yml +++ b/.yamato/_triggers.yml @@ -106,6 +106,8 @@ develop_nightly: # Build player for webgl platform on trunk and 6000.0 editors - .yamato/project-updated-dependencies-test.yml#updated-dependencies_testproject_NGO_ubuntu_trunk - .yamato/project-updated-dependencies-test.yml#updated-dependencies_testproject_NGO_win_6000.0 + # Run API validation to early-detect all new APIs that would force us to release new minor version of the package. Note that for this to work the package version in package.json must correspond to "actual package state" which means that it should be higher than last released version + - .yamato/vetting-test.yml#vetting_test # Run all tests on weekly bases diff --git a/.yamato/vetting-test.yml b/.yamato/vetting-test.yml new file mode 100644 index 0000000000..069056c9c0 --- /dev/null +++ b/.yamato/vetting-test.yml @@ -0,0 +1,25 @@ +{% metadata_file .yamato/project.metafile %} # All configuration that is used to create different configurations (used in for loops) is taken from this file. +--- +# DESCRIPTION-------------------------------------------------------------------------- +# This configuration defines vetting tests for the Tools package which allows to validate if the package is in releasable state. This is important in particular because of API validation that allows to detect if we are introducing any new APIs that will force us to bump package version to new minor +# If this test fails with new API error we should either make those API internal OR bump package version to new minor (note that the package version reflects the current package state) + +# Note that we are packing the package only (no project context) so if package have any soft dependencies then project should be used to test it (to enable those APIs) +{% for editor in validation_editors.minimal -%} +vetting_test: + name: MP Tools - Vetting Test (Win, {{editor}} LTS) + agent: { type: Unity::VM, flavor: b1.large, image: package-ci/win11:v4 } + commands: + - Tools\scripts\release.py # Needed to ensure that CHANGELOG is properly formatted for this test + - npm install -g "upm-ci-utils@stable" --registry https://artifactory.prd.it.unity3d.com/artifactory/api/npm/upm-npm + - unity-downloader-cli --fast --wait --unity-version {{ editor }} --components editor --arch x64 + - upm-ci package pack --package-path com.unity.netcode.gameobjects + - upm-ci package test -u .Editor --package-path com.unity.netcode.gameobjects --type vetting-tests + artifacts: + logs: + paths: + - pvp-results/* + - test-results/** + - upm-ci~/test-results/** + - upm-ci~/upm-ci.log +{% endfor -%} \ No newline at end of file From 27c3f2fd55de64ca2799c8b1a52f1bdad65d0bf4 Mon Sep 17 00:00:00 2001 From: michalChrobot Date: Wed, 16 Jul 2025 15:24:32 +0200 Subject: [PATCH 5/9] Added release.py execution to package packing job --- .yamato/package-pack.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.yamato/package-pack.yml b/.yamato/package-pack.yml index 106fa15721..bfe6eb405a 100644 --- a/.yamato/package-pack.yml +++ b/.yamato/package-pack.yml @@ -37,6 +37,7 @@ package_pack_-_ngo_{{ platform.name }}: variables: XRAY_PROFILE: "gold ./pvpExceptions.json" commands: + - Tools\scripts\release.py # Needed to ensure that CHANGELOG is properly formatted for this test due to the fact that we have bumped package version (to properly perform vetting tests) - upm-pvp pack "com.unity.netcode.gameobjects" --output upm-ci~/packages - upm-pvp xray --packages "upm-ci~/packages/com.unity.netcode.gameobjects*.tgz" --results pvp-results - upm-pvp require {% if platform.name == "win" %}"%XRAY_PROFILE%"{% else %}"$XRAY_PROFILE"{% endif %} --results pvp-results --allow-missing From 6bd3221e9c932c6c4ffb51d0ba6c3d2b4f1168d9 Mon Sep 17 00:00:00 2001 From: michalChrobot Date: Wed, 16 Jul 2025 15:44:27 +0200 Subject: [PATCH 6/9] metafile typo --- .yamato/project.metafile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.yamato/project.metafile b/.yamato/project.metafile index 099d274a75..16ae803aa7 100644 --- a/.yamato/project.metafile +++ b/.yamato/project.metafile @@ -159,7 +159,7 @@ validation_editors: - 6000.1 - 6000.2 - trunk - minimal: + minimal: - 6000.0 From b45900bd43c57efcecbb396c8f07b55412357351 Mon Sep 17 00:00:00 2001 From: michalChrobot Date: Thu, 17 Jul 2025 13:54:42 +0200 Subject: [PATCH 7/9] corrected command and release script --- .yamato/package-pack.yml | 2 +- .yamato/vetting-test.yml | 2 +- Tools/scripts/release.py | 20 ++++++++++++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/.yamato/package-pack.yml b/.yamato/package-pack.yml index bfe6eb405a..8e8cd73d47 100644 --- a/.yamato/package-pack.yml +++ b/.yamato/package-pack.yml @@ -37,7 +37,7 @@ package_pack_-_ngo_{{ platform.name }}: variables: XRAY_PROFILE: "gold ./pvpExceptions.json" commands: - - Tools\scripts\release.py # Needed to ensure that CHANGELOG is properly formatted for this test due to the fact that we have bumped package version (to properly perform vetting tests) + - python Tools/scripts/release.py # Needed to ensure that CHANGELOG is properly formatted for this test due to the fact that we have bumped package version (to properly perform vetting tests) - upm-pvp pack "com.unity.netcode.gameobjects" --output upm-ci~/packages - upm-pvp xray --packages "upm-ci~/packages/com.unity.netcode.gameobjects*.tgz" --results pvp-results - upm-pvp require {% if platform.name == "win" %}"%XRAY_PROFILE%"{% else %}"$XRAY_PROFILE"{% endif %} --results pvp-results --allow-missing diff --git a/.yamato/vetting-test.yml b/.yamato/vetting-test.yml index 069056c9c0..3fbba0edd3 100644 --- a/.yamato/vetting-test.yml +++ b/.yamato/vetting-test.yml @@ -10,7 +10,7 @@ vetting_test: name: MP Tools - Vetting Test (Win, {{editor}} LTS) agent: { type: Unity::VM, flavor: b1.large, image: package-ci/win11:v4 } commands: - - Tools\scripts\release.py # Needed to ensure that CHANGELOG is properly formatted for this test + - python Tools/scripts/release.py # Needed to ensure that CHANGELOG is properly formatted for this test - npm install -g "upm-ci-utils@stable" --registry https://artifactory.prd.it.unity3d.com/artifactory/api/npm/upm-npm - unity-downloader-cli --fast --wait --unity-version {{ editor }} --components editor --arch x64 - upm-ci package pack --package-path com.unity.netcode.gameobjects diff --git a/Tools/scripts/release.py b/Tools/scripts/release.py index 75c9438f6d..f3c418aa9b 100644 --- a/Tools/scripts/release.py +++ b/Tools/scripts/release.py @@ -12,14 +12,25 @@ def update_changelog(new_version): changelog_entry = f'## [{new_version}] - {datetime.date.today().isoformat()}' - + changelog_path = f'{package_name}/CHANGELOG.md' print(changelog_entry) + + if not os.path.exists(changelog_path): + print(f"Error: CHANGELOG.md file not found at {changelog_path}") + return - changelog_path = f'{package_name}/CHANGELOG.md' with open(changelog_path, 'rb') as f: changelog_text = f.read() - - changelog_text = re.sub(br'## \[Unreleased\]', bytes(changelog_entry, 'UTF-8'), changelog_text) + + changelog_text_decoded = changelog_text.decode("utf-8") + if '## [Unreleased]' in changelog_text_decoded: + # Replace the `Unreleased` section with the new version entry + print("Found `## [Unreleased]` section. Updating it.") + changelog_text = re.sub(br'## \[Unreleased\]', bytes(changelog_entry, 'UTF-8'), changelog_text) + else: + # `Unreleased` section does not exist, so prepend the new entry at the top + print("No `## [Unreleased]` section found. Prepending the new entry.") + changelog_text = bytes(f"{changelog_entry}\n\n", 'UTF-8') + changelog_text with open(changelog_path, 'wb') as f: f.write(changelog_text) @@ -59,6 +70,7 @@ def get_manifest_json_version(filename): return data['version'] if __name__ == '__main__': + print(f"Current working directory: {os.getcwd()}") manifest_path = f'{package_name}/package.json' version = get_manifest_json_version(manifest_path) update_validation_exceptions(version) From 8563eba871e51f193a52608ffe761c7db1ed7414 Mon Sep 17 00:00:00 2001 From: michalChrobot Date: Wed, 30 Jul 2025 16:52:03 +0200 Subject: [PATCH 8/9] Updated release.py to clean empty CHANGELOG sections --- Tools/scripts/release.py | 75 ++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/Tools/scripts/release.py b/Tools/scripts/release.py index f3c418aa9b..7c6d1c2b8e 100644 --- a/Tools/scripts/release.py +++ b/Tools/scripts/release.py @@ -1,45 +1,61 @@ """ -NGO release script -- Update changelogs + validation exception file based on manifest version +This python script makes the NGO package release ready. What it does is: +1) Update changelogs +2) Update validation exception file based on manifest version + +Note that this script NEEDS TO BE RUN FROM THE ROOT of the project. """ #!/usr/bin/env python3 import datetime import json import os import re +import subprocess +import platform package_name = 'com.unity.netcode.gameobjects' def update_changelog(new_version): + """ + Cleans the [Unreleased] section of the changelog by removing empty subsections, + then replaces the '[Unreleased]' tag with the new version and release date. + """ + changelog_entry = f'## [{new_version}] - {datetime.date.today().isoformat()}' changelog_path = f'{package_name}/CHANGELOG.md' - print(changelog_entry) - - if not os.path.exists(changelog_path): - print(f"Error: CHANGELOG.md file not found at {changelog_path}") - return + print("Latest CHANGELOG entry will be modified to: " + changelog_entry) - with open(changelog_path, 'rb') as f: + with open(changelog_path, 'r', encoding='UTF-8') as f: changelog_text = f.read() - - changelog_text_decoded = changelog_text.decode("utf-8") - if '## [Unreleased]' in changelog_text_decoded: - # Replace the `Unreleased` section with the new version entry - print("Found `## [Unreleased]` section. Updating it.") - changelog_text = re.sub(br'## \[Unreleased\]', bytes(changelog_entry, 'UTF-8'), changelog_text) - else: - # `Unreleased` section does not exist, so prepend the new entry at the top - print("No `## [Unreleased]` section found. Prepending the new entry.") - changelog_text = bytes(f"{changelog_entry}\n\n", 'UTF-8') + changelog_text - - with open(changelog_path, 'wb') as f: - f.write(changelog_text) + + # This pattern finds a line starting with '###', followed by its newline, + # and then two more lines that contain only whitespace. + # The re.MULTILINE flag allows '^' to match the start of each line. + pattern = re.compile(r"^###.*\n\n\n", re.MULTILINE) + + # Replace every match with an empty string. The goal is to remove empty CHANGELOG subsections. + cleaned_content = pattern.sub('', changelog_text) + + # Replace the [Unreleased] section with the new version + cleaned subsections + changelog_text = re.sub(r'## \[Unreleased\]', changelog_entry, cleaned_content) + + # Write the changes + with open(changelog_path, 'w', encoding='UTF-8', newline='\n') as file: + file.write(changelog_text) + def update_validation_exceptions(new_version): + """ + Updates the ValidationExceptions.json file with the new package version. + """ + validation_file = f'{package_name}/ValidationExceptions.json' + + # If files do not exist, exit if not os.path.exists(validation_file): return + # Update the PackageVersion in the exceptions with open(validation_file, 'rb') as f: json_text = f.read() data = json.loads(json_text) @@ -53,26 +69,33 @@ def update_validation_exceptions(new_version): exception['PackageVersion'] = new_version updated = True + # If no exceptions were updated, we do not need to write the file if not updated: return - with open(validation_file, "w", encoding="UTF-8") as json_file: + with open(validation_file, 'w', encoding='UTF-8', newline='\n') as json_file: json.dump(data, json_file, ensure_ascii=False, indent=2) json_file.write("\n") # Add newline cause Py JSON does not print(f" updated `{validation_file}`") def get_manifest_json_version(filename): + """ + Reads the package.json file and returns the version specified in it. + """ with open(filename, 'rb') as f: json_text = f.read() data = json.loads(json_text) return data['version'] + if __name__ == '__main__': - print(f"Current working directory: {os.getcwd()}") manifest_path = f'{package_name}/package.json' - version = get_manifest_json_version(manifest_path) - update_validation_exceptions(version) + package_version = get_manifest_json_version(manifest_path) - update_changelog(version) + # Update the ValidationExceptions.json file + # with the new package version OR remove it if not a release branch + update_validation_exceptions(package_version) + # Clean the CHANGELOG and add latest entry + update_changelog(package_version) From cfdb64990e35cfcdf22b7fbaa980ce48e10b37f8 Mon Sep 17 00:00:00 2001 From: michalChrobot Date: Thu, 31 Jul 2025 22:17:44 +0200 Subject: [PATCH 9/9] corrected current version before 2.5.0 release --- com.unity.netcode.gameobjects/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/package.json b/com.unity.netcode.gameobjects/package.json index 9d7691837d..3126631d14 100644 --- a/com.unity.netcode.gameobjects/package.json +++ b/com.unity.netcode.gameobjects/package.json @@ -2,7 +2,7 @@ "name": "com.unity.netcode.gameobjects", "displayName": "Netcode for GameObjects", "description": "Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.", - "version": "2.5.1", + "version": "2.5.0", "unity": "6000.0", "dependencies": { "com.unity.nuget.mono-cecil": "1.11.4",