-
Notifications
You must be signed in to change notification settings - Fork 297
/
Copy pathfreeze_ci_versions.py
174 lines (139 loc) · 4.73 KB
/
freeze_ci_versions.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
165
166
167
168
169
170
171
172
173
174
#!/usr/bin/env python
#
# SPDX-License-Identifier: Apache-2.0
# Copyright Contributors to the OpenTimelineIO project
__doc__ = """Freeze and unfreeze image versions for CI, part of the release
process.
"""
import argparse
import re
import urllib.request
CI_WORKFLOW_FP = ".github/workflows/python-package.yml"
GITHUB_README_URL = (
"https://raw.githubusercontent.com/actions/runner-images/main/README.md"
)
PLATFORMS = ["ubuntu", "macos", "windows"]
def _parsed_args():
parser = argparse.ArgumentParser(
description='Fetch a list of contributors for a given GitHub repo.'
)
op_grp = parser.add_mutually_exclusive_group(required=True)
op_grp.add_argument(
"-f",
"--freeze",
default=False,
action="store_true",
help="freeze the ci version from latest to their version."
)
op_grp.add_argument(
"-u",
"--unfreeze",
default=False,
action="store_true",
help="unfreeze the ci version from the version back to latest."
)
parser.add_argument(
"-d",
"--dryrun",
default=False,
action="store_true",
help="Perform actions but modify no files on disk."
)
return parser.parse_args()
def _fetch_plat_map():
# HACK: pull the image version corresponding to -latest out of the
# README.md for the github repo where they are stored
request = urllib.request.Request(GITHUB_README_URL)
response = urllib.request.urlopen(request).read().decode('utf-8')
def md_row_fields(md_row):
# Split on |, discard the empty entries from leading and trailing |
return [
col.strip() for col in md_row.split("|")[1:-1]
]
# First, just strip the readme down the platform image table
lines = response.split("\n")
table_lines = []
in_images_section = False
for line in lines:
if not in_images_section and line.startswith("## Available Images"):
in_images_section = True
continue
elif in_images_section and line.startswith("#"):
break
elif not in_images_section:
continue
if line.startswith("|"):
table_lines.append(line.strip())
# Extract the table column labels
plat_col_labels = md_row_fields(table_lines[0])
platform_name_re = re.compile(r"`([^`]*)`")
entries = {}
for line in table_lines[2:]:
col_data = md_row_fields(line)
plat_entry = dict(zip(plat_col_labels, col_data))
raw_labels = plat_entry["YAML Label"]
available_labels = platform_name_re.findall(raw_labels)
try:
next(
label for label in available_labels
if label.split("-")[-1] == "latest"
)
except StopIteration:
# not a latest label
continue
label = next(
label for label in available_labels
if label.split("-")[-1] not in {"xl", "xlarge", "latest"}
)
platform = label.split("-")[0]
if platform not in PLATFORMS:
continue
entries[platform] = label
return entries
def main():
args = _parsed_args()
plat_map = _fetch_plat_map()
if args.freeze:
freeze_ci(plat_map, args.dryrun)
if args.unfreeze:
unfreeze_ci(plat_map, args.dryrun)
def freeze_ci(plat_map, dryrun=False):
modified = False
with open(CI_WORKFLOW_FP) as fi:
output_content = fi.read()
for plat in plat_map:
plat_latest = plat + "-latest"
if plat_latest not in output_content:
print(f"Platform {plat} appears to already be frozen.")
continue
output_content = output_content.replace(plat_latest, plat_map[plat])
modified = True
print(f"Platform {plat} frozen to version: {plat_map[plat]}")
if modified and not dryrun:
with open(CI_WORKFLOW_FP, 'w') as fo:
fo.write(output_content)
return True
return False
def unfreeze_ci(plat_map, dryrun=False):
modified = False
with open(CI_WORKFLOW_FP) as fi:
output_content = fi.read()
for plat, plat_current in plat_map.items():
plat_latest = plat + "-latest"
if plat_current not in output_content:
print(
"Platform {} appears to already be set to -latest.".format(
plat
)
)
continue
output_content = output_content.replace(plat_current, plat_latest)
modified = True
print(f"Platform {plat} unfrozen back to: {plat_latest}")
if modified and not dryrun:
with open(CI_WORKFLOW_FP, 'w') as fo:
fo.write(output_content)
return True
return False
if __name__ == "__main__":
main()