Skip to content

Commit 527a3ff

Browse files
Scripts unit testing (#184)
* add unit testing for get_git_sources * full get_git_sources testing * fix unit tests for nightly scripts * run ruff * remove prints * more unit tests * rewrite apply_macros unit tests * fix yaml * we indent the wrong amount * install yaml * umdir env * specify python version * add user/email * reorder git command * needs = * user/email * fix * default main * set init branch * remove hostname test * debug * check if action * git setup * git setup * git setup * correct yaml * correct yaml * fix macros paths * revert testing change * add badge
1 parent 26d06a3 commit 527a3ff

File tree

32 files changed

+764
-334
lines changed

32 files changed

+764
-334
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Python Unit Tests
2+
3+
on:
4+
pull_request:
5+
workflow_dispatch:
6+
7+
permissions: read-all
8+
9+
jobs:
10+
python_unit_tests:
11+
name: python_unit_tests
12+
runs-on: ubuntu-24.04
13+
timeout-minutes: 10
14+
15+
steps:
16+
- uses: actions/checkout@v5
17+
- name: Set up Python
18+
uses: actions/setup-python@v5
19+
with:
20+
python-version: '3.14'
21+
- name: Install dependencies
22+
run: |
23+
# We only have 1 external dependency other than pytest for now, so
24+
# list them here
25+
# If this changes, we may want to switch to a dependencies file of
26+
# some format
27+
python -m pip install --upgrade pip
28+
pip install pytest
29+
pip install networkx
30+
pip install PyYAML
31+
- name: Test with pytest
32+
run: |
33+
git config --global user.name 'Testing'
34+
git config --global user.email 'Testing'
35+
pytest -vv

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
[![Checks](https://github.com/MetOffice/SimSys_Scripts/actions/workflows/lint.yml/badge.svg)](https://github.com/MetOffice/SimSys_Scripts/actions/workflows/lint.yml)
44
[![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)
5+
[![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)
56

67
This repository contains support scripts that are common across the many
78
simulation and modelling codes owned by the Met Office. Particularly those

github_scripts/get_git_sources.py

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -60,24 +60,27 @@ def validate_dependencies(dependencies: dict) -> None:
6060
Each dictionary value should be a list of dictionaries (or a single dictionary)
6161
Those dictionaries should have a "source" and a "ref" key
6262
"""
63+
if not isinstance(dependencies, dict):
64+
raise TypeError(
65+
"The dependencies object should be a dict with keys as source repositories"
66+
)
6367
for item, values in dependencies.items():
64-
failed = False
68+
err_message = (
69+
f"The dependency {item} does not contain a list of dictionaries (or a "
70+
"single dictionary) with keys of 'source' and 'ref'.\nPlease edit your "
71+
"dependencies.yaml file to satisfy this."
72+
)
73+
6574
if isinstance(values, dict):
6675
values = [values]
6776
if not isinstance(values, list):
68-
failed = True
69-
else:
70-
for entry in values:
71-
if not isinstance(entry, dict) or (
72-
"source" not in entry or "ref" not in entry
73-
):
74-
failed = True
75-
if failed:
76-
raise ValueError(
77-
f"The dependency {item} does not contain a list of dictionaries (or a "
78-
"single dictionary) with keys of 'source' and 'ref'.\nPlease edit your "
79-
"dependencies.yaml file to satisfy this."
80-
)
77+
raise TypeError(err_message)
78+
79+
for entry in values:
80+
if not isinstance(entry, dict):
81+
raise TypeError(err_message)
82+
if "source" not in entry or "ref" not in entry:
83+
raise ValueError(err_message)
8184

8285

8386
def datetime_str() -> str:
@@ -88,7 +91,11 @@ def datetime_str() -> str:
8891

8992

9093
def clone_and_merge(
91-
dependency: str, opts: Union[list, dict], loc: Path, use_mirrors: bool, mirror_loc: Path
94+
dependency: str,
95+
opts: Union[list, dict],
96+
loc: Path,
97+
use_mirrors: bool,
98+
mirror_loc: Path,
9299
) -> None:
93100
"""
94101
Wrapper script for calling get_source and merge_source for a single dependency
@@ -160,7 +167,7 @@ def get_source(
160167

161168

162169
def merge_source(
163-
source: str,
170+
source: Union[Path, str],
164171
ref: str,
165172
dest: Path,
166173
repo: str,
@@ -214,6 +221,9 @@ def handle_merge_conflicts(source: str, ref: str, loc: Path, dependency: str) ->
214221
# For suites, merge conflicts in these files/directories are unimportant so accept
215222
# the current changes
216223
for filepath in ("dependencies.yaml", "rose-stem"):
224+
full_path = loc / filepath
225+
if not full_path.exists():
226+
continue
217227
logger.warning(f"Ignoring merge conflicts in {filepath}")
218228
run_command(f"git -C {loc} checkout --ours -- {filepath}")
219229
run_command(f"git -C {loc} add {filepath}")
@@ -239,6 +249,20 @@ def get_unmerged(loc: Path) -> list[str]:
239249
return files.stdout.split()
240250

241251

252+
def check_existing(loc: Path) -> None:
253+
"""
254+
If the repository exists and isn't a git repo, exit now as we don't want to
255+
overwrite it
256+
"""
257+
258+
if loc.exists():
259+
if not Path(loc / ".git").exists():
260+
raise FileExistsError(
261+
f"The destination, '{loc}', already exists but isn't a git directory. "
262+
"Exiting so as to not overwrite it."
263+
)
264+
265+
242266
def clone_repo_mirror(
243267
repo_source: str,
244268
repo_ref: str,
@@ -254,15 +278,8 @@ def clone_repo_mirror(
254278
- loc: path to clone the repository to
255279
"""
256280

257-
# If the repository exists and isn't a git repo, exit now as we don't want to
258-
# overwrite it
259281
if loc.exists():
260-
if not Path(loc / ".git").exists():
261-
raise RuntimeError(
262-
f"The destination for the clone of {repo_source} already exists but "
263-
"isn't a git directory. Exiting so as to not overwrite it."
264-
)
265-
282+
check_existing(loc)
266283
# Clone if the repo doesn't exist
267284
else:
268285
command = f"git clone {mirror_loc} {loc}"
@@ -288,6 +305,7 @@ def determine_mirror_fetch(repo_source: str, repo_ref: str) -> str:
288305
"""
289306

290307
repo_source = repo_source.removeprefix("git@github.com:")
308+
repo_source = repo_source.removeprefix("https://github.com/")
291309
user = repo_source.split("/")[0]
292310
# Check that the user is different to the Upstream User
293311
if "MetOffice" in user:
@@ -328,6 +346,7 @@ def clone_repo(repo_source: str, repo_ref: str, loc: Path) -> None:
328346
for command in commands:
329347
run_command(command)
330348
else:
349+
check_existing(loc)
331350
commands = (
332351
f"git -C {loc} fetch origin {repo_ref}",
333352
f"git -C {loc} checkout FETCH_HEAD",
@@ -336,11 +355,13 @@ def clone_repo(repo_source: str, repo_ref: str, loc: Path) -> None:
336355
run_command(command)
337356

338357

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

363+
repo_source = str(repo_source)
364+
344365
# Remove if this clone already exists
345366
if loc.exists():
346367
rmtree(loc)

0 commit comments

Comments
 (0)