diff --git a/docs/Release_Guide/release_steps/finalize_release_on_github_official.rst b/docs/Release_Guide/release_steps/finalize_release_on_github_official.rst index e3d4018ff..c2ec51b6e 100644 --- a/docs/Release_Guide/release_steps/finalize_release_on_github_official.rst +++ b/docs/Release_Guide/release_steps/finalize_release_on_github_official.rst @@ -5,6 +5,12 @@ Return to GitHub to finalize the details of this release. .. dropdown:: Instructions + * Update issues: + + * Close the GitHub issue for creating this official release. + + * If necessary, reassign any remaining issues for the current milestone to other milestones. + * Update milestones: * Edit the milestone for the current release by updating the *Due date* with the actual release date. @@ -15,12 +21,6 @@ Return to GitHub to finalize the details of this release. * If necessary, create a new milestone for the next official release (e.g. next vX.Y.Z release). - * Update issues: - - * Close the GitHub issue for creating this official release. - - * If necessary, reassign any remaining issues for the current milestone to other milestones. - * Update projects: * Close the existing development project for the current milestone. diff --git a/docs/Release_Guide/release_steps/metplus/update_web_server_data.rst b/docs/Release_Guide/release_steps/metplus/update_web_server_data.rst index 9c0adfe8c..1f080e3ea 100644 --- a/docs/Release_Guide/release_steps/metplus/update_web_server_data.rst +++ b/docs/Release_Guide/release_steps/metplus/update_web_server_data.rst @@ -4,7 +4,6 @@ Update DTC Web Server Data Create Directory for Next Release """"""""""""""""""""""""""""""""" - .. dropdown:: If creating an rc1 release On the DTC web server where the sample input data for use cases is hosted, @@ -21,9 +20,9 @@ Create Directory for Next Release git pull Now run the script passing in the version of the next release, i.e. - if creating the v4.1.0 release, pass in v5.0 as the argument:: + if creating the v6.0.0-rc1 release, pass in v6.1 as the argument:: - new_version=v5.0 + new_version=v6.1 /home/met_test/setup_next_release_data.py ${new_version} See the comments in the script for more details. @@ -42,7 +41,6 @@ Create Directory for Next Release ls -lh /home/met_test/METplus_Data/${new_version} - .. dropdown:: If creating a betaN or rc2+ release - Continue to the next instruction. \ No newline at end of file + Continue to the next instruction. diff --git a/docs/Release_Guide/release_steps/update_docs_official.rst b/docs/Release_Guide/release_steps/update_docs_official.rst index 9250763b1..d29d9cb3a 100644 --- a/docs/Release_Guide/release_steps/update_docs_official.rst +++ b/docs/Release_Guide/release_steps/update_docs_official.rst @@ -13,15 +13,15 @@ repository will need to do the following to update the default branch: * Click on the appropriate METplus component project - * Click on Admin in the top menu - - * Click on Advanced Settings in the left menu + * Click on Settings in the top right menu * Select the new default branch in the dropdown menu for "Default branch" - (e.g. main_v4.0.0) + (e.g. main_v4.0.0) and click the Save button at the bottom of the page * Ensure that "latest" points to the new default branch by clicking on - "View Docs"in the upper right corner and confirm that the version number + "latest" build that just started and click on "Version latest" to view the + build run. When it finishes running, click on "View Docs" on the right of + the page and confirm that the version number displayed in the header is the desired version for "latest". diff --git a/internal/scripts/dev_tools/compile_official_release_notes.py b/internal/scripts/dev_tools/compile_official_release_notes.py new file mode 100644 index 000000000..1b797c3f7 --- /dev/null +++ b/internal/scripts/dev_tools/compile_official_release_notes.py @@ -0,0 +1,59 @@ +#! /usr/bin/env python3 + +# Written by George McCabe +# Helper script that parses release notes from development releases, +# gathers all issues by category, sorts them by issue number, then +# outputs the formatted content +# Note: Careful review and massaging of output is likely needed +# Run this script from the top of the repository to parse +# Assumes location and name of release notes RST file + +import re + +infile = './docs/Users_Guide/release-notes.rst' + +with open(infile, 'r') as file_handle: + content = file_handle.read().splitlines() + +category = None +items = {} +# gather issues and organize them by category +for line in content: + if match := re.match(r' .. dropdown:: (.*)', line): + category = match.group(1) + if not items.get(category): + items[category] = [] + continue + if category is None: continue + if not line: continue + if line.strip().startswith('.. _'): + break + if line.lstrip().startswith('*'): + items[category].append(line) + elif line.strip().lower() == 'none' or line.startswith('MET') or line.startswith('---') or line.startswith('==='): + continue + elif not items.get(category): + continue + else: + items[category][-1] += f'\n{line}' + +# get issues in each category to sort +issues = {} +for cat, item_list in items.items(): + if not issues.get(cat): + issues[cat] = {} + for issue in item_list: + match = re.match(r'.*\#(\d+).*', issue.replace('\n', '')) + if match: + issues[cat][match.group(1)] = issue + +# sort issues within each category and print formatted result +for cat in issues: + nums = sorted([int(item) for item in issues[cat].keys()]) + print(f" .. dropdown:: {cat}\n") + if not nums: + print(' None\n') + continue + for num in nums: + print(issues[cat][str(num)]) + print() diff --git a/internal/scripts/dev_tools/generate_release_notes.py b/internal/scripts/dev_tools/generate_release_notes.py index 9d029c965..5a6591052 100755 --- a/internal/scripts/dev_tools/generate_release_notes.py +++ b/internal/scripts/dev_tools/generate_release_notes.py @@ -65,7 +65,10 @@ def print_issues_by_category(repo_name, issues_by_category): for category, issues in issues_by_category.items(): print() if category != 'none': - print(f" .. dropdown:: {category}\n") + header = category + if header in ('Enhancement', 'New Wrapper', 'New Use Case'): + header = f'{header}s' + print(f" .. dropdown:: {header}\n") elif issues: print('COULD NOT PARSE CATEGORY FROM THESE:\n') diff --git a/internal/tests/pytests/requirements.txt b/internal/tests/pytests/requirements.txt index 0a4449537..804ca34ea 100644 --- a/internal/tests/pytests/requirements.txt +++ b/internal/tests/pytests/requirements.txt @@ -1,4 +1,4 @@ -certifi==2023.7.22 +certifi==2024.7.4 cftime==1.6.2 coverage==7.2.7 exceptiongroup==1.1.2 @@ -8,7 +8,7 @@ numpy==1.25.2 packaging==23.1 pandas==2.0.3 pdf2image==1.16.3 -Pillow==10.0.0 +Pillow==10.3.0 pluggy==1.2.0 pytest==7.4.0 pytest-cov==4.1.0 diff --git a/internal/tests/pytests/util/run_util/test_run_util.py b/internal/tests/pytests/util/run_util/test_run_util.py index 9b95e891e..62d9e8149 100644 --- a/internal/tests/pytests/util/run_util/test_run_util.py +++ b/internal/tests/pytests/util/run_util/test_run_util.py @@ -51,6 +51,10 @@ 'INPUT_THRESH', ] +def remove_output_base(config): + config_output_base = config.getdir("OUTPUT_BASE") + if config_output_base and os.path.exists(config_output_base): + ru.shutil.rmtree(config_output_base) def get_run_util_configs(conf_name): script_dir = os.path.dirname(__file__) @@ -130,6 +134,7 @@ def test_pre_run_setup(): expected_stage = os.path.join(actual.get('config', 'OUTPUT_BASE'), 'stage') assert actual.get('config', 'STAGING_DIR') == expected_stage assert actual.get('user_env_vars', 'GODS_OF_WEATHER') == 'Indra_Thor_Zeus' + remove_output_base(actual) @pytest.mark.util @@ -139,6 +144,7 @@ def test_pre_run_setup_env_vars(): actual = ru.pre_run_setup(conf_inputs) assert actual.env['MY_ENV_VAR'] == '42' assert actual.get('config', 'OMP_NUM_THREADS') == '4' + remove_output_base(actual) @pytest.mark.util @@ -262,6 +268,7 @@ def test_run_metplus(capfd, config_dict, expected, check_err): else: assert err == '' + remove_output_base(config) @pytest.mark.parametrize( "side_effect,return_value,check_err", @@ -285,6 +292,8 @@ def test_run_metplus_errors(capfd, side_effect, return_value, check_err): else: assert err == check_err + remove_output_base(config) + @pytest.mark.util def test_get_wrapper_instance(metplus_config): @@ -308,6 +317,7 @@ def test_get_wrapper_instance_raises(capfd, side_effect, check_err): assert actual == None out, err = capfd.readouterr() assert check_err in err + remove_output_base(config) @pytest.mark.util diff --git a/metplus/component_versions.py b/metplus/component_versions.py index 9e363431c..10e4810e7 100755 --- a/metplus/component_versions.py +++ b/metplus/component_versions.py @@ -14,6 +14,15 @@ import sys VERSION_LOOKUP = { + '6.1': { + 'metplus': '6.1.0', + 'met': '12.1.0', + 'metplotpy': '3.1.0', + 'metcalcpy': '3.1.0', + 'metdataio': '3.1.0', + 'metviewer': '6.1.0', + 'metexpress': None, + }, '6.0': { 'metplus': '6.0.0', 'met': '12.0.0', @@ -21,7 +30,7 @@ 'metcalcpy': '3.0.0', 'metdataio': '3.0.0', 'metviewer': '6.0.0', - 'metexpress': None, + 'metexpress': '6.0.0', }, '5.1': { 'metplus': '5.1.0', @@ -30,7 +39,7 @@ 'metcalcpy': '2.1.0', 'metdataio': '2.1.0', 'metviewer': '5.1.0', - 'metexpress': '5.3.3', + 'metexpress': '5.3.5', }, } diff --git a/metplus/util/config_metplus.py b/metplus/util/config_metplus.py index 238b2c10b..bbfd010a6 100644 --- a/metplus/util/config_metplus.py +++ b/metplus/util/config_metplus.py @@ -462,6 +462,8 @@ def __init__(self, conf=None, run_id=None): super().__init__(conf) self._cycle = None self.run_id = run_id if run_id else str(uuid.uuid4())[0:8] + # if run ID is specified, this is a copy of a config + self.is_copy = run_id is not None self._logger = logging.getLogger(f'metplus.{self.run_id}') # config.logger is called in wrappers, so set this name # so the code doesn't break @@ -475,6 +477,9 @@ def __init__(self, conf=None, run_id=None): def __del__(self): """!When object is deleted, close and remove all log handlers""" + # do not close log handlers if this is a copied config object + if self.is_copy: + return handlers = self.logger.handlers[:] for handler in handlers: self.logger.removeHandler(handler)