-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtasks.py
164 lines (130 loc) · 4.95 KB
/
tasks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
"""Repository management tasks powered by `invoke`.
More information on `invoke` can be found at http://www.pyinvoke.org/.
"""
# pylint: disable=import-outside-toplevel
import datetime as dt
import os
import re
import sys
from pathlib import Path
from typing import TYPE_CHECKING
from invoke import task
if TYPE_CHECKING: # pragma: no cover
from typing import Optional
from dulwich.objects import Commit
TOP_DIR = Path(__file__).parent.resolve()
def update_file(
filename: Path, sub_line: "tuple[str, str]", strip: "Optional[str]" = None
) -> None:
"""Utility function for tasks to read, update, and write files.
Parameters:
filename: The file to read, update, and write to.
sub_line: A tuple of first, what to look for and secondly, what to replace with.
strip: What to strip from the right end of the line in the file.
"""
lines = [
re.sub(sub_line[0], sub_line[1], line.rstrip(strip))
for line in filename.read_text(encoding="utf8").splitlines()
]
filename.write_text("\n".join(lines) + "\n", encoding="utf8")
def compile_version(
api_version: str = "1", default_branch: str = "origin/master"
) -> str:
"""Compile OTEAPI Services version.
The version syntax and semantics are laid out in the GitHub issue #71:
https://github.com/EMMC-ASBL/oteapi-services/issues/71.
Parameters:
api_version: The API version.
default_branch: The default branch to determine the build number from.
This is to be given as `<REMOTE>/<BRANCH NAME>`, e.g., `origin/main`.
Returns:
The compiled version for the OTEAPI Services.
"""
from dulwich.repo import Repo
repo = Repo(TOP_DIR)
for ref in [
f"refs/remotes/{default_branch}".encode(),
b"refs/remotes/origin/master",
b"refs/remotes/origin/main",
]:
if ref in repo.get_refs():
default_branch_sha = repo.get_refs()[ref]
break
else:
sys.exit(
"Error: Expected a valid ref in the git repo ! Did this run via "
"`invoke setver`?"
)
head_master: "Commit" = repo.get_object(default_branch_sha)
head_master_time = dt.datetime.fromtimestamp(
head_master.commit_time,
dt.timezone(dt.timedelta(seconds=head_master.commit_timezone)),
)
calver = head_master_time.astimezone(dt.timezone.utc).strftime("%Y%m%d")
build_number = len(list(repo.get_walker(default_branch_sha)))
return f"{api_version}.{calver}.{build_number}"
def dir_is_git(default_branch: str = "origin/master") -> bool:
"""Validate the repository with regards to using `git` and compiling the
version.
Parameters:
default_branch: The default branch to determine the build number from.
This is to be given as `<REMOTE>/<BRANCH NAME>`, e.g., `origin/main`.
Returns:
Whether or not the repository is a valid `git` repository and the OTEAPI
Services version is expected to be compiled properly.
"""
from dulwich import porcelain
from dulwich.errors import NotGitRepository
from dulwich.repo import Repo
try:
repo = Repo(TOP_DIR)
except NotGitRepository:
return False
with open(os.devnull, "wb") as handle:
porcelain.fetch(repo, outstream=handle, errstream=handle)
return any(
ref in repo.get_refs()
for ref in [
f"refs/remotes/{default_branch}".encode(),
b"refs/remotes/origin/master",
b"refs/remotes/origin/main",
]
)
@task(help={"ver": "OTEAPI Services version to set."})
def setver(_, ver=""):
"""Sets the OTEAPI Services version."""
if os.getenv("CI", "false") != "true":
sys.exit("This invoke task should only be run as part of a CI/CD workflow.")
if ver:
match = re.fullmatch(
(
r"v?(?P<version>[1-9]+[0-9]*" # API version
r"\.20[0-9]{2}[0-1][0-9][0-3][0-9]" # CalVer (YYYY0M0D)
r"\.[0-9]+)" # Build number
),
ver,
)
if not match:
sys.exit(
"Error: Please specify version as "
"'<API version>.<CalVer (YYYY0M0D)>.<Build number>' or "
"'v<API version>.<CalVer (YYYY0M0D)>.<Build number>'."
)
ver = match.group("version")
else:
if dir_is_git(default_branch="origin/master"):
ver = compile_version(
api_version="1",
default_branch="origin/master",
)
else:
sys.exit(
"Could not set version. No version is provided using the `--ver` "
"option. Nor can the `master` remote branch be properly accessed in "
"the repository folder. Is this a git repository?"
)
update_file(
TOP_DIR / "app" / "__init__.py",
(r'__version__ = (\'|").*(\'|")', f'__version__ = "{ver}"'),
)
print(f"Bumped version to {ver}.")