Skip to content

Commit 9516022

Browse files
Merge branch 'main' into make_nightly_infrastructure_git
2 parents 43610f1 + 6c14b76 commit 9516022

19 files changed

Lines changed: 3667 additions & 55 deletions

git-migration/config.json

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@
179179
{ "vn7.6": 28692 },
180180
{ "vn7.7": 29181 },
181181
{ "vn7.8": 29791 },
182-
{ "vn7.9": 30414 }
182+
{ "vn7.9": 30414 },
183+
{ "git_migration": 31238 }
183184
]
184185
},
185186
{
@@ -242,7 +243,8 @@
242243
{ "um13.6": 4075 },
243244
{ "um13.7": 4898 },
244245
{ "um13.8": 5509 },
245-
{ "um13.9": 6356 }
246+
{ "um13.9": 6356 },
247+
{ "git_migration": 7497 }
246248
]
247249
},
248250
{
@@ -346,7 +348,8 @@
346348
{ "vn1.22": 118501 },
347349
{ "vn1.23": 122041 },
348350
{ "vn1.24": 126461 },
349-
{ "vn1.25": 130034 }
351+
{ "vn1.25": 130034 },
352+
{ "git_migration": 131096 }
350353
]
351354
},
352355
{
@@ -394,7 +397,7 @@
394397
"name": "um_meta",
395398
"description": "Metadata for the Met Office Unified Model (UM)",
396399
"trunk": "um/meta",
397-
"tags": []
400+
"tags": [{ "git_migration": 131163 }]
398401
},
399402
{
400403
"name": "um",
@@ -483,7 +486,8 @@
483486
{ "vn8.1.1": 1226 },
484487
{ "vn8.2": 1251 },
485488
{ "vn8.3": 1288 },
486-
{ "vn8.4": 1386 }
489+
{ "vn8.4": 1386 },
490+
{ "git_migration": 1428 }
487491
]
488492
},
489493
{

github_scripts/get_git_sources.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# *****************************COPYRIGHT*******************************
2+
# (C) Crown copyright Met Office. All rights reserved.
3+
# For further details please refer to the file COPYRIGHT.txt
4+
# which you should have received as part of this distribution.
5+
# *****************************COPYRIGHT*******************************
6+
"""
7+
Clone sources for a rose-stem run for use with git bdiff module in scripts
8+
"""
9+
10+
import re
11+
import subprocess
12+
from typing import Optional
13+
from pathlib import Path
14+
from shutil import rmtree
15+
16+
17+
def run_command(
18+
command: str, rval: bool = False
19+
) -> Optional[subprocess.CompletedProcess]:
20+
"""
21+
Run a subprocess command and return the result object
22+
Inputs:
23+
- command, str with command to run
24+
Outputs:
25+
- result object from subprocess.run
26+
"""
27+
command = command.split()
28+
result = subprocess.run(
29+
command,
30+
capture_output=True,
31+
text=True,
32+
timeout=300,
33+
shell=False,
34+
check=False,
35+
)
36+
if result.returncode:
37+
print(result.stdout, end="\n\n\n")
38+
raise RuntimeError(
39+
f"[FAIL] Issue found running command {command}\n\n{result.stderr}"
40+
)
41+
if rval:
42+
return result
43+
44+
45+
def clone_repo_mirror(
46+
source: str, repo_ref: str, parent: str, mirror_loc: Path, loc: Path
47+
) -> None:
48+
"""
49+
Clone a repo source using a local git mirror.
50+
Assume the mirror is set up as per the Met Office
51+
"""
52+
53+
# Remove if this clone already exists
54+
if loc.exists():
55+
rmtree(loc)
56+
57+
command = f"git clone {mirror_loc} {loc}"
58+
run_command(command)
59+
60+
# If not provided a ref, return
61+
if not repo_ref:
62+
return
63+
64+
source = source.removeprefix("git@github.com:")
65+
user = source.split("/")[0]
66+
# Check that the user is different to the Upstream User
67+
if user in parent.split("/")[0]:
68+
user = None
69+
70+
# If the ref is a hash then we don't need the fork user as part of the fetch.
71+
# Equally, if the user is the Upstream User, it's not needed
72+
if not user or re.match(r"^\s*([0-9a-f]{40})\s*$", repo_ref):
73+
fetch = repo_ref
74+
else:
75+
fetch = f"{user}/{repo_ref}"
76+
commands = (
77+
f"git -C {loc} fetch origin {fetch}",
78+
f"git -C {loc} checkout FETCH_HEAD",
79+
)
80+
for command in commands:
81+
run_command(command)
82+
83+
84+
def clone_repo(repo_source: str, repo_ref: str, loc: Path) -> None:
85+
"""
86+
Clone the repo and checkout the provided ref
87+
Only if a remote source
88+
"""
89+
90+
# Remove if this clone already exists
91+
if loc.exists():
92+
rmtree(loc)
93+
94+
# Create a clean clone location
95+
loc.mkdir(parents=True)
96+
97+
commands = (
98+
f"git -C {loc} init",
99+
f"git -C {loc} remote add origin {repo_source}",
100+
f"git -C {loc} fetch origin {repo_ref}",
101+
f"git -C {loc} checkout FETCH_HEAD",
102+
)
103+
for command in commands:
104+
run_command(command)
105+
106+
107+
def sync_repo(repo_source: str, repo_ref: str, loc: Path) -> None:
108+
"""
109+
Rsync a local git clone and checkout the provided ref
110+
"""
111+
112+
# Remove if this clone already exists
113+
if loc.exists():
114+
rmtree(loc)
115+
116+
# Create a clean clone location
117+
loc.mkdir(parents=True)
118+
119+
# Trailing slash required for rsync
120+
command = f"rsync -av {repo_source}/ {loc}"
121+
run_command(command)
122+
if repo_ref:
123+
command = f"git -C {loc} checkout {repo_ref}"
124+
run_command(command)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env python3
2+
# *****************************COPYRIGHT*******************************
3+
# (C) Crown copyright Met Office. All rights reserved.
4+
# For further details please refer to the file COPYRIGHT.txt
5+
# which you should have received as part of this distribution.
6+
# *****************************COPYRIGHT*******************************
7+
"""
8+
Clone sources for a rose-stem run for use with git bdiff module in scripts
9+
Only intended for use with rose-stem suites that have provided appropriate environment
10+
variables
11+
"""
12+
13+
import os
14+
from datetime import datetime
15+
from pathlib import Path
16+
from ast import literal_eval
17+
from get_git_sources import clone_repo, clone_repo_mirror, sync_repo
18+
from typing import Dict
19+
20+
21+
def set_https(dependencies: Dict) -> Dict:
22+
"""
23+
Change sources in a dependencies dictions to use https instead of ssh
24+
"""
25+
26+
print("Modifying Dependencies")
27+
for dependency, values in dependencies.items():
28+
if values["source"].startswith("git@github.com:"):
29+
source = dependencies[dependency]["source"]
30+
dependencies[dependency]["source"] = source.replace(
31+
"git@github.com:", "https://github.com/"
32+
)
33+
34+
return dependencies
35+
36+
37+
def main() -> None:
38+
39+
clone_loc = Path(os.environ["SOURCE_DIRECTORY"])
40+
41+
dependencies: Dict = literal_eval(os.environ["DEPENDENCIES"])
42+
43+
if os.environ.get("USE_TOKENS", "False") == "True":
44+
dependencies = set_https(dependencies)
45+
46+
for dependency, values in dependencies.items():
47+
48+
print(
49+
f"Extracting {dependency} at time {datetime.now()} "
50+
f"using source {values['source']} and ref {values['ref']}"
51+
)
52+
53+
loc = clone_loc / dependency
54+
55+
if ".git" in values["source"]:
56+
if os.environ.get("USE_MIRRORS", "False") == "True":
57+
mirror_loc = Path(os.environ["GIT_MIRROR_LOC"]) / values["parent"]
58+
clone_repo_mirror(
59+
values["source"], values["ref"], values["parent"], mirror_loc, loc
60+
)
61+
else:
62+
clone_repo(values["source"], values["ref"], loc)
63+
else:
64+
sync_repo(values["source"], values["ref"], loc)
65+
66+
67+
if __name__ == "__main__":
68+
main()
Lines changed: 15 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
Class containing helper methods for gathering data needed for a SuiteReport object
99
"""
1010

11-
import sys
12-
13-
sys.path.append("../")
1411
import re
1512
import shutil
1613
import sqlite3
@@ -19,18 +16,8 @@
1916
from collections import defaultdict
2017
from pathlib import Path
2118
from typing import Dict, List, Optional, Set, Union
22-
23-
try:
24-
from bdiff.git_bdiff import GitBDiff, GitInfo
25-
except ImportError:
26-
try:
27-
from git_bdiff import GitBDiff, GitInfo
28-
except ImportError as err:
29-
raise ImportError(
30-
"Unable to import from git_bdiff module. This is included in the same "
31-
"repository as this script and included with a relative import. Ensure "
32-
"this script is being called from the correct place."
33-
) from err
19+
from git_bdiff import GitBDiff, GitInfo
20+
from get_git_sources import clone_repo, sync_repo
3421

3522

3623
class SuiteData:
@@ -217,20 +204,9 @@ def clone_sources(self) -> None:
217204
for dependency, data in self.dependencies.items():
218205
loc = self.temp_directory / dependency
219206
if data["source"].endswith(".git"):
220-
commands = [
221-
f"git clone {data['source']} {loc}",
222-
f"git -C {loc} checkout {data['ref']}",
223-
]
224-
for command in commands:
225-
self.run_command(command)
207+
clone_repo(data["source"], data["ref"], loc)
226208
else:
227-
source = data["source"]
228-
if not source.endswith("/"):
229-
source = source + "/"
230-
command = (
231-
f'rsync -e "ssh -o StrictHostKeyChecking=no" -avl {source} {loc}'
232-
)
233-
self.run_command(command, shell=True)
209+
sync_repo(data["source"], data["ref"], loc)
234210

235211
def determine_primary_source(self) -> str:
236212
"""
@@ -298,21 +274,18 @@ def read_rose_conf(self) -> Dict[str, str]:
298274

299275
def find_unknown_dependency(self, dependency: str) -> str:
300276
"""
301-
TEMPORARY
302277
The primary dependency may be unset in the dependencies file. In this case find
303-
it from the *_SOURCE variable in the rose-suite.conf.
304-
TODO: Once cylc provides the location of the source code itself, this method
305-
should be changed to use that instead, as then the _SOURCE variable will be
306-
removed
307-
"""
308-
309-
var = f"{dependency.upper()}_SOURCE".replace('"', "")
310-
if var not in self.rose_data:
311-
raise RuntimeError(f"Cant determine source for {dependency}")
312-
rval = self.rose_data[var]
313-
if "$ROSE_ORIG_HOST" in rval:
314-
rval = rval.replace("$ROSE_ORIG_HOST", self.rose_data["ROSE_ORIG_HOST"])
315-
return rval
278+
it from the CYLC_WORKFLOW_SRC_DIR variable that gets set in the
279+
flow-processed.cylc file
280+
"""
281+
282+
pattern = re.compile(rf"{dependency.upper()} SOURCE CLONE=(\S+)")
283+
log_file = self.suite_path / "log" / "scheduler" / "log"
284+
with open(log_file, "r") as f:
285+
for line in f:
286+
if match := pattern.search(line):
287+
return match.group(1).rstrip("/")
288+
raise RuntimeError(f"Unable to find source for dependency {dependency}")
316289

317290
def read_dependencies(self) -> Dict[str, Dict]:
318291
"""
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,8 @@ def main() -> None:
373373

374374
args = parse_args()
375375

376+
suite_report = SuiteReport(args.suite_path)
376377
try:
377-
suite_report = SuiteReport(args.suite_path)
378378
suite_report.create_log()
379379
suite_report.write_log(args.log_path)
380380
finally:

lfric_macros/validate_rose_meta.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
# dependency
1919
INVALID_METADATA = [
2020
"jules-lfric",
21+
"jules-lsm",
2122
"lfric-jules-shared",
2223
"socrates-radiation",
2324
"um-aerosol",
@@ -217,16 +218,16 @@ def main():
217218
if args.apps:
218219
source_path = args.apps
219220
meta_paths += f"-M {os.path.join(args.apps, "rose-meta")} "
220-
rose_meta_path += args.apps
221+
rose_meta_path += f"{os.path.join(args.apps, "rose-meta")}"
221222
if args.core:
222223
meta_paths += f"-M {os.path.join(args.core, "rose-meta")} "
223224
if rose_meta_path:
224225
# Apps has already started this
225-
rose_meta_path += f":{args.core}"
226+
rose_meta_path += f":{os.path.join(args.core, "rose-meta")}"
226227
else:
227228
# Apps hasn't been set
228229
source_path = args.core
229-
rose_meta_path = args.core
230+
rose_meta_path = f"{os.path.join(args.core, "rose-meta")}"
230231

231232
if check_rose_metadata(rose_meta_path, source_path) or check_rose_stem_apps(
232233
meta_paths, source_path

0 commit comments

Comments
 (0)