From 09062d31ae0bc6023079da017e4c756c69456556 Mon Sep 17 00:00:00 2001 From: Martin Yeo Date: Fri, 11 Jul 2025 14:53:04 +0100 Subject: [PATCH 1/3] Provide a way to manually exclude some template prompts/notifications. --- templates/_templating_scripting.py | 66 ++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/templates/_templating_scripting.py b/templates/_templating_scripting.py index cfeee66..7b57388 100755 --- a/templates/_templating_scripting.py +++ b/templates/_templating_scripting.py @@ -2,8 +2,10 @@ """Commands and scripts for administrating templating of files across SciTools repos. """ import argparse +import contextlib import json from pathlib import Path +import re import shlex from subprocess import CalledProcessError, check_output, run from tempfile import NamedTemporaryFile @@ -21,12 +23,21 @@ # ensure any new bots have both a "app/" prefix and a "[bot]" postfix version BOTS = ["dependabot[bot]", "app/dependabot", "pre-commit-ci[bot]", "app/pre-commit-ci"] +_MAGIC_PREFIX = "@scitools-templating: please" +MAGIC_NO_PROMPT = re.compile(rf"{_MAGIC_PREFIX} no share prompt") +MAGIC_NO_NOTIFY = re.compile(rf"{_MAGIC_PREFIX} no update notification on: (\w+)") + def git_command(command: str) -> str: command = shlex.split(f"git {command}") return check_output(command).decode("utf-8").strip() +def gh_json(sub_command: str, field: str) -> dict: + command = shlex.split(f"gh {sub_command} --json {field}") + return json.loads(check_output(command)) + + class Config: """Convenience to give the config JSON some readable structure.""" class TargetRepo(NamedTuple): @@ -82,6 +93,20 @@ def notify_updates(args: argparse.Namespace) -> None: ) return + # Check if the commit's PR (if applicable) had a magic no-notify comment. + repo_exclude = "" # Default to no repo exclusion. + commit_sha = git_command("rev-parse HEAD") + pr_list = gh_json( + f"pr list --search {commit_sha} --state merged --json number", "number" + ) + if pr_list: + (pr,) = pr_list + pr_number = pr["number"] + pr_body = gh_json(f"pr view {pr_number}", "body")["body"] + search = MAGIC_NO_NOTIFY.search(pr_body) + with contextlib.suppress(AttributeError, IndexError): + repo_exclude = search.group(1) + def git_diff(*args: str) -> str: command = "diff HEAD^ HEAD " + " ".join(args) return git_command(command) @@ -93,6 +118,9 @@ def git_diff(*args: str) -> str: file for file in changed_files if file.is_relative_to(TEMPLATES_DIR) ] + # DEBUG + # changed_templates = [TEMPLATES_DIR / "LICENSE"] + for template in changed_templates: templatees = CONFIG.templates[template] @@ -107,6 +135,13 @@ def git_diff(*args: str) -> str: ) template_link = f"[`{template_relative}`]({template_url})" for repo, path_in_repo in templatees: + if repo.casefold() == repo_exclude.casefold(): + print( + f"Skipping {repo} because it is excluded by the magic " + "no-notify comment." + ) + continue + file_url = f"{SCITOOLS_URL}/{repo}/blob/main/{path_in_repo}" file_link = f"[`{path_in_repo}`]({file_url})" issue_body = ( @@ -114,7 +149,7 @@ def git_diff(*args: str) -> str: "diff below. Please either:\n\n" "- Action this issue with a pull request applying some/all of " - f"these changes to `{path_in_repo}`.\n" + f"these changes to `{path_in_repo}`[^1].\n" "- Close this issue if _none_ of these changes are appropriate " "for this repo.\n\n" "Also consider reviewing a full diff between the template and " @@ -127,7 +162,11 @@ def git_diff(*args: str) -> str: # TODO: a link to the whole diff compared to the template? "## Diff\n\n" - f"```diff\n{diff}\n```" + f"```diff\n{diff}\n```\n\n" + + "[^1]: **Include this text in the PR body to avoid any prompts " + "about applying your changes back to the template!**\n" + f"``{MAGIC_NO_PROMPT.pattern}``" ) with NamedTemporaryFile("w") as file_write: file_write.write(issue_body) @@ -165,14 +204,18 @@ def prompt_share(args: argparse.Namespace) -> None: ) return - def gh_json(sub_command: str, field: str) -> dict: - command = shlex.split(f"gh {sub_command} --json {field}") - return json.loads(check_output(command)) - pr_number = args.pr_number # Can use a URL here for local debugging: # pr_number = "https://github.com/SciTools/iris/pull/6496" + body = gh_json(f"pr view {pr_number}", "body")["body"] + if MAGIC_NO_PROMPT.search(body): + print( + f"Skipping PR {pr_number} because the body contains the magic " + "no-share-prompt comment." + ) + return + def split_github_url(url: str) -> tuple[str, str, str]: _, org, repo, _, ref = urlparse(url).path.split("/") return org, repo, ref @@ -269,7 +312,7 @@ def create_issue(title: str, body: str) -> None: "sharing via templating. For each file listed below, please " "either:\n\n" "- Action the suggestion via a pull request editing/adding the " - f"relevant file in the [templates directory]({templates_url}).\n" + f"relevant file in the [templates directory]({templates_url}). [^1]\n" "- Dismiss the suggestion if the changes are not suitable for " "templating." ) @@ -329,6 +372,15 @@ def create_issue(title: str, body: str) -> None: body_args.append(body_candidates) body_args.extend(candidates_list) + pattern = MAGIC_NO_NOTIFY.pattern + pattern_repo = ": ".join(pattern.split(": ")[:-1] + [pr_repo]) + body_args.append( + "\n\n[^1]: **Include this text in the PR body to avoid any " + "notifications about applying the template changes back to the " + "source repo!**\n" + f"``{pattern_repo}``" + ) + issue_body = "\n".join(body_args) create_issue(issue_title, issue_body) From b5b38e912bfc3d4dc98502aa4b4c9fcd326d45eb Mon Sep 17 00:00:00 2001 From: Martin Yeo Date: Mon, 14 Jul 2025 10:15:08 +0100 Subject: [PATCH 2/3] More readable string splitting. --- templates/_templating_scripting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/_templating_scripting.py b/templates/_templating_scripting.py index 7b57388..a05eaae 100755 --- a/templates/_templating_scripting.py +++ b/templates/_templating_scripting.py @@ -372,8 +372,8 @@ def create_issue(title: str, body: str) -> None: body_args.append(body_candidates) body_args.extend(candidates_list) - pattern = MAGIC_NO_NOTIFY.pattern - pattern_repo = ": ".join(pattern.split(": ")[:-1] + [pr_repo]) + tag, prose, word = MAGIC_NO_NOTIFY.pattern.split(": ") + pattern_repo = ": ".join([tag, prose, pr_repo]) body_args.append( "\n\n[^1]: **Include this text in the PR body to avoid any " "notifications about applying the template changes back to the " From d08afa0d4d3c2116896dedf73b639aaa214c174c Mon Sep 17 00:00:00 2001 From: ukmo-ccbunney Date: Thu, 31 Jul 2025 15:57:41 +0100 Subject: [PATCH 3/3] Changed license --- templates/LICENSE | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/LICENSE b/templates/LICENSE index 527df23..76d7ed7 100644 --- a/templates/LICENSE +++ b/templates/LICENSE @@ -1,5 +1,7 @@ BSD 3-Clause License +FLUBBER + Copyright (c) , Met Office. All rights reserved. @@ -26,4 +28,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.