Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
18bbefc
add unit testing for get_git_sources
james-bruten-mo Feb 5, 2026
b38b694
full get_git_sources testing
james-bruten-mo Feb 5, 2026
e242923
fix unit tests for nightly scripts
james-bruten-mo Feb 6, 2026
b1fcf04
run ruff
james-bruten-mo Feb 6, 2026
0bb0b6d
remove prints
james-bruten-mo Feb 6, 2026
6250739
more unit tests
james-bruten-mo Feb 6, 2026
f10640c
rewrite apply_macros unit tests
james-bruten-mo Feb 9, 2026
0a89041
Merge branch 'main' into scripts_unit_testing
james-bruten-mo Feb 9, 2026
67094cb
fix yaml
james-bruten-mo Feb 9, 2026
dfeb7e6
Merge branch 'scripts_unit_testing' of github.com:james-bruten-mo/Sim…
james-bruten-mo Feb 9, 2026
b671821
Merge branch 'main' into scripts_unit_testing
james-bruten-mo Feb 9, 2026
fd0d75c
we indent the wrong amount
james-bruten-mo Feb 9, 2026
e7604ff
Merge branch 'scripts_unit_testing' of github.com:james-bruten-mo/Sim…
james-bruten-mo Feb 9, 2026
428fef2
install yaml
james-bruten-mo Feb 9, 2026
c9f0e49
umdir env
james-bruten-mo Feb 9, 2026
72f8713
specify python version
james-bruten-mo Feb 9, 2026
f00ad51
add user/email
james-bruten-mo Feb 9, 2026
0962e5b
reorder git command
james-bruten-mo Feb 9, 2026
2260076
needs =
james-bruten-mo Feb 9, 2026
cbf6650
user/email
james-bruten-mo Feb 9, 2026
0281e8f
fix
james-bruten-mo Feb 9, 2026
8cb8568
default main
james-bruten-mo Feb 9, 2026
e36af12
set init branch
james-bruten-mo Feb 10, 2026
68d3727
remove hostname test
james-bruten-mo Feb 10, 2026
cebdca6
debug
james-bruten-mo Feb 10, 2026
664422e
check if action
james-bruten-mo Feb 10, 2026
66fa4ae
git setup
james-bruten-mo Feb 10, 2026
b15831d
git setup
james-bruten-mo Feb 10, 2026
bb1be20
git setup
james-bruten-mo Feb 10, 2026
f6fb03a
correct yaml
james-bruten-mo Feb 10, 2026
7cfe3f3
correct yaml
james-bruten-mo Feb 10, 2026
4f61f66
fix macros paths
james-bruten-mo Feb 10, 2026
89d4a4b
revert testing change
james-bruten-mo Feb 10, 2026
47239c1
add badge
james-bruten-mo Feb 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/python_unit_tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Python Unit Tests

on:
pull_request:
workflow_dispatch:

permissions: read-all

jobs:
python_unit_tests:
name: python_unit_tests
runs-on: ubuntu-24.04
timeout-minutes: 10

steps:
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.14'
- name: Install dependencies
run: |
# We only have 1 external dependency other than pytest for now, so
# list them here
# If this changes, we may want to switch to a dependencies file of
# some format
python -m pip install --upgrade pip
pip install pytest
pip install networkx
pip install PyYAML
- name: Test with pytest
run: |
git config --global user.name 'Testing'
git config --global user.email 'Testing'
pytest -vv
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

[![Checks](https://github.com/MetOffice/SimSys_Scripts/actions/workflows/lint.yml/badge.svg)](https://github.com/MetOffice/SimSys_Scripts/actions/workflows/lint.yml)
[![CodeQL](https://github.com/MetOffice/SimSys_Scripts/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/MetOffice/SimSys_Scripts/actions/workflows/github-code-scanning/codeql)
[![Python Unit Tests](https://github.com/MetOffice/SimSys_Scripts/actions/workflows/python_unit_tests.yaml/badge.svg)](https://github.com/MetOffice/SimSys_Scripts/actions/workflows/python_unit_tests.yaml)

This repository contains support scripts that are common across the many
simulation and modelling codes owned by the Met Office. Particularly those
Expand Down
71 changes: 46 additions & 25 deletions github_scripts/get_git_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,24 +60,27 @@ def validate_dependencies(dependencies: dict) -> None:
Each dictionary value should be a list of dictionaries (or a single dictionary)
Those dictionaries should have a "source" and a "ref" key
"""
if not isinstance(dependencies, dict):
raise TypeError(
"The dependencies object should be a dict with keys as source repositories"
)
for item, values in dependencies.items():
failed = False
err_message = (
f"The dependency {item} does not contain a list of dictionaries (or a "
"single dictionary) with keys of 'source' and 'ref'.\nPlease edit your "
"dependencies.yaml file to satisfy this."
)

if isinstance(values, dict):
values = [values]
if not isinstance(values, list):
failed = True
else:
for entry in values:
if not isinstance(entry, dict) or (
"source" not in entry or "ref" not in entry
):
failed = True
if failed:
raise ValueError(
f"The dependency {item} does not contain a list of dictionaries (or a "
"single dictionary) with keys of 'source' and 'ref'.\nPlease edit your "
"dependencies.yaml file to satisfy this."
)
raise TypeError(err_message)

for entry in values:
if not isinstance(entry, dict):
raise TypeError(err_message)
if "source" not in entry or "ref" not in entry:
raise ValueError(err_message)


def datetime_str() -> str:
Expand All @@ -88,7 +91,11 @@ def datetime_str() -> str:


def clone_and_merge(
dependency: str, opts: Union[list, dict], loc: Path, use_mirrors: bool, mirror_loc: Path
dependency: str,
opts: Union[list, dict],
loc: Path,
use_mirrors: bool,
mirror_loc: Path,
) -> None:
"""
Wrapper script for calling get_source and merge_source for a single dependency
Expand Down Expand Up @@ -160,7 +167,7 @@ def get_source(


def merge_source(
source: str,
source: Union[Path, str],
ref: str,
dest: Path,
repo: str,
Expand Down Expand Up @@ -214,6 +221,9 @@ def handle_merge_conflicts(source: str, ref: str, loc: Path, dependency: str) ->
# For suites, merge conflicts in these files/directories are unimportant so accept
# the current changes
for filepath in ("dependencies.yaml", "rose-stem"):
full_path = loc / filepath
if not full_path.exists():
continue
logger.warning(f"Ignoring merge conflicts in {filepath}")
run_command(f"git -C {loc} checkout --ours -- {filepath}")
run_command(f"git -C {loc} add {filepath}")
Expand All @@ -239,6 +249,20 @@ def get_unmerged(loc: Path) -> list[str]:
return files.stdout.split()


def check_existing(loc: Path) -> None:
"""
If the repository exists and isn't a git repo, exit now as we don't want to
overwrite it
"""

if loc.exists():
if not Path(loc / ".git").exists():
raise FileExistsError(
f"The destination, '{loc}', already exists but isn't a git directory. "
"Exiting so as to not overwrite it."
)


def clone_repo_mirror(
repo_source: str,
repo_ref: str,
Expand All @@ -254,15 +278,8 @@ def clone_repo_mirror(
- loc: path to clone the repository to
"""

# If the repository exists and isn't a git repo, exit now as we don't want to
# overwrite it
if loc.exists():
if not Path(loc / ".git").exists():
raise RuntimeError(
f"The destination for the clone of {repo_source} already exists but "
"isn't a git directory. Exiting so as to not overwrite it."
)

check_existing(loc)
# Clone if the repo doesn't exist
else:
command = f"git clone {mirror_loc} {loc}"
Expand All @@ -288,6 +305,7 @@ def determine_mirror_fetch(repo_source: str, repo_ref: str) -> str:
"""

repo_source = repo_source.removeprefix("git@github.com:")
repo_source = repo_source.removeprefix("https://github.com/")
user = repo_source.split("/")[0]
# Check that the user is different to the Upstream User
if "MetOffice" in user:
Expand Down Expand Up @@ -328,6 +346,7 @@ def clone_repo(repo_source: str, repo_ref: str, loc: Path) -> None:
for command in commands:
run_command(command)
else:
check_existing(loc)
commands = (
f"git -C {loc} fetch origin {repo_ref}",
f"git -C {loc} checkout FETCH_HEAD",
Expand All @@ -336,11 +355,13 @@ def clone_repo(repo_source: str, repo_ref: str, loc: Path) -> None:
run_command(command)


def sync_repo(repo_source: str, repo_ref: str, loc: Path) -> None:
def sync_repo(repo_source: Union[str, Path], repo_ref: str, loc: Path) -> None:
"""
Rsync a local git clone and checkout the provided ref
"""

repo_source = str(repo_source)

# Remove if this clone already exists
if loc.exists():
rmtree(loc)
Expand Down
Loading