diff --git a/scripts/publish_release_notes_to_discourse.py b/scripts/publish_release_notes_to_discourse.py index 9891fba4f1..092af67b50 100644 --- a/scripts/publish_release_notes_to_discourse.py +++ b/scripts/publish_release_notes_to_discourse.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import os +import re import requests @@ -58,6 +59,17 @@ def find_category_id(config: dict[str, str]) -> int: def format_release_content(config: dict[str, str]) -> tuple[str, str]: title = f"🚀 Release {config['RELEASE_TAG']}" repo_name = config["REPO_NAME"].split("/")[1] + + # Format PR links in the release body + # Replace https://github.com/pymc-devs/pymc/pull/123 with [#123](https://github.com/pymc-devs/pymc/pull/123) + # This avoids redundant link rendering in Discourse + # Use negative lookbehind to avoid formatting already-formatted links + release_body = re.sub( + r"(?)", + config["RELEASE_BODY"], + ) + content = f"""A new release of **{repo_name}** is now available! ## 📦 Release Information @@ -69,7 +81,7 @@ def format_release_content(config: dict[str, str]) -> tuple[str, str]: ## 📋 Release Notes -{config["RELEASE_BODY"]} +{release_body} --- diff --git a/scripts/test_publish_release_notes.py b/scripts/test_publish_release_notes.py new file mode 100644 index 0000000000..e70f01a5b7 --- /dev/null +++ b/scripts/test_publish_release_notes.py @@ -0,0 +1,155 @@ +# Copyright 2024 - present The PyMC Developers +# +# 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. +import re + +from publish_release_notes_to_discourse import format_release_content + + +class TestFormatReleaseContent: + def test_pr_links_are_formatted(self): + """Test that PR links are formatted correctly in the release body.""" + # Realistic release body from v5.26.0 + release_body = """ + +## What's Changed +### Major Changes 🛠 +* Bump PyTensor dependency and drop support for NumPy <2.0, and Python 3.10 by @ricardoV94 in https://github.com/pymc-devs/pymc/pull/7910 + * Functions that try to infer inputs of the graph fail with more than one input. This includes `Model.compile_fn`, `gradient`, `jacobian` and `hessian_diag`. + * `Model.compile_logp` now expects all model variables as input, even when only a subset of the logp terms is requested. + * Many pytensor functions from moved from `pytensor.graph.basic` to `pytensor.graph.traversal`, including `ancestors`, `graph_inputs`, and toposort related functions. +* Remove deprecated `noise` parameter for GPs by @williambdean in https://github.com/pymc-devs/pymc/pull/7886 + +### New Features 🎉 +* Implement `logcdf` for `CensoredRV` by @asifzubair in https://github.com/pymc-devs/pymc/pull/7884 +* Derive logprob for Split operation by @ricardoV94 in https://github.com/pymc-devs/pymc/pull/7875 +### Bugfixes 🪲 +* Fix bug in mixture logprob inference with `None` indices by @asifzubair in https://github.com/pymc-devs/pymc/pull/7877 +### Documentation 📖 +* Add model_to_mermaid to docs by @williambdean in https://github.com/pymc-devs/pymc/pull/7868 +* Use rst code-block over code:: by @williambdean in https://github.com/pymc-devs/pymc/pull/7882 +### Maintenance 🔧 +* Show more digits of step size in progress_bar by @ricardoV94 in https://github.com/pymc-devs/pymc/pull/7870 +* Allow for specification of 'var_names' in 'mock_sample' by @tomicapretto in https://github.com/pymc-devs/pymc/pull/7906 + +## New Contributors +* @asifzubair made their first contribution in https://github.com/pymc-devs/pymc/pull/7871 + +**Full Changelog**: https://github.com/pymc-devs/pymc/compare/v5.25.1...v5.26.0""" + + config = { + "RELEASE_TAG": "v5.26.0", + "REPO_NAME": "pymc-devs/pymc", + "RELEASE_BODY": release_body, + "RELEASE_URL": "https://github.com/pymc-devs/pymc/releases/tag/v5.26.0", + } + + title, content = format_release_content(config) + + # Check that the title is correct + assert title == "🚀 Release v5.26.0" + + # Check that PR links in pymc-devs/pymc are formatted correctly + assert "[#7910](https://github.com/pymc-devs/pymc/pull/7910)" in content + assert "[#7886](https://github.com/pymc-devs/pymc/pull/7886)" in content + assert "[#7884](https://github.com/pymc-devs/pymc/pull/7884)" in content + assert "[#7875](https://github.com/pymc-devs/pymc/pull/7875)" in content + assert "[#7877](https://github.com/pymc-devs/pymc/pull/7877)" in content + assert "[#7868](https://github.com/pymc-devs/pymc/pull/7868)" in content + assert "[#7882](https://github.com/pymc-devs/pymc/pull/7882)" in content + assert "[#7870](https://github.com/pymc-devs/pymc/pull/7870)" in content + assert "[#7906](https://github.com/pymc-devs/pymc/pull/7906)" in content + assert "[#7871](https://github.com/pymc-devs/pymc/pull/7871)" in content + + # Check that the raw PR link format is not present + assert ( + "https://github.com/pymc-devs/pymc/pull/7910" in content + ) # it's still in the formatted link + # But NOT as a standalone link (which would appear without the [#xxx](...) wrapper) + # We can verify this by checking the pattern doesn't match the raw format + # Find raw PR links (not inside markdown link syntax) + raw_pr_links = re.findall( + r"(?