Skip to content
This repository was archived by the owner on May 13, 2025. It is now read-only.

Commit 9c52ad9

Browse files
wangzelin007bavneetsingh16
authored andcommitted
{CI} Move find_extension_upgraded.py to azure-cli-extensions repo (Azure#8557)
1 parent 6517097 commit 9c52ad9

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
import os
6+
import sys
7+
import json
8+
from subprocess import check_output
9+
from pkg_resources import parse_version
10+
11+
def separator_line():
12+
print('-' * 100)
13+
14+
class AzdevExtensionHelper:
15+
def __init__(self, extension_name):
16+
self.name = extension_name
17+
18+
def _get_metadata_flags(self, setup_py_dir):
19+
for root, _, files in os.walk(setup_py_dir):
20+
if 'azext_metadata.json' in files:
21+
metadata_path = os.path.join(root, 'azext_metadata.json')
22+
with open(metadata_path, 'r') as f:
23+
metadata = json.load(f)
24+
is_experimental = metadata.get('azext.isExperimental', False)
25+
is_preview = metadata.get('azext.isPreview', False)
26+
return is_experimental, is_preview
27+
return False, False
28+
29+
def _adjust_version_for_preview(self, version, setup_py_dir):
30+
is_experimental, is_preview = self._get_metadata_flags(setup_py_dir)
31+
if is_experimental or is_preview:
32+
version_parts = version.split('.')
33+
if all(part.isdigit() for part in version_parts):
34+
version = f"{version}b1"
35+
return version
36+
37+
def is_version_upgrade(self):
38+
with open('src/index.json') as fd:
39+
current_extensions = json.loads(fd.read()).get("extensions")
40+
41+
setup_py = f'src/{self.name}/setup.py'
42+
if not os.path.isfile(setup_py):
43+
print('no setup.py')
44+
return False
45+
46+
setup_py_dir = os.path.dirname(setup_py)
47+
cmd = f'{sys.executable} setup.py --name'
48+
self.name = check_output(cmd, shell=True, cwd=setup_py_dir).decode('utf-8').strip()
49+
self.name = self.name.replace('_', '-')
50+
51+
metadata = current_extensions.get(self.name, None)
52+
if metadata is None: # for new added extension
53+
return True
54+
55+
current_max_entry = max(metadata, key=lambda e: parse_version(e['metadata']['version']))
56+
current_max_version = current_max_entry['metadata']['version']
57+
current_max_version = self._adjust_version_for_preview(current_max_version, setup_py_dir)
58+
print(f'current max version is {current_max_version}')
59+
60+
cmd = f'{sys.executable} setup.py --version'
61+
modified_version = check_output(cmd, shell=True, cwd=setup_py_dir).decode('utf-8').strip()
62+
print(f'modified version is {modified_version}')
63+
64+
if parse_version(current_max_version) > parse_version(modified_version):
65+
err = f'version downgrade is not allowed in extension {setup_py}. [{current_max_version} -> {modified_version}]'
66+
raise Exception(err)
67+
68+
if parse_version(current_max_version) == parse_version(modified_version):
69+
return False
70+
71+
return True
72+
73+
def find_modified_files_against_master_branch():
74+
"""
75+
Deleted files don't count in diff
76+
"""
77+
cmd = 'git --no-pager diff --diff-filter=ACMRT --name-only HEAD~1 -- src/'
78+
files = check_output(cmd.split()).decode('utf-8').split('\n')
79+
separator_line()
80+
print('modified files:')
81+
for f in files:
82+
print(f)
83+
separator_line()
84+
return [f for f in files if len(f) > 0]
85+
86+
def contain_extension_code(files):
87+
with open('src/index.json', 'r') as fd:
88+
current_extensions = json.loads(fd.read()).get("extensions")
89+
current_extension_homes = set(f'src/{name}' for name in current_extensions)
90+
91+
for file in files:
92+
if any([file.startswith(prefix) for prefix in current_extension_homes]):
93+
return True
94+
95+
# for new added extensions or modules that src folder name does not match its wheel package name
96+
for file in files:
97+
if 'src/' in file and os.path.isfile(file) and os.path.isdir(os.path.dirname(file)):
98+
new_extension_home = os.path.dirname(file)
99+
new_extension_home = os.path.join(*new_extension_home.split('/')[:2])
100+
if os.path.isfile(os.path.join(new_extension_home, 'setup.py')):
101+
return True
102+
return False
103+
104+
def main():
105+
modified_files = find_modified_files_against_master_branch()
106+
if 'src/index.json' in modified_files:
107+
modified_files.remove('src/index.json')
108+
109+
# check setup.py
110+
for f in modified_files:
111+
if f.endswith('setup.py'):
112+
break
113+
else:
114+
separator_line()
115+
print('no setup.py is modified, no need to publish')
116+
separator_line()
117+
return
118+
119+
# check source code
120+
if not contain_extension_code(modified_files):
121+
separator_line()
122+
print('no extension source code is modified, no need to publish')
123+
separator_line()
124+
return
125+
126+
extension_names = set()
127+
for f in modified_files:
128+
src, name, *_ = f.split('/')
129+
if os.path.isdir(os.path.join(src, name)):
130+
extension_names.add(name)
131+
132+
for name in extension_names:
133+
azdev_extension = AzdevExtensionHelper(name)
134+
if azdev_extension.is_version_upgrade() is False:
135+
print(f'extension [{name}] is not upgrade, no need to help publish')
136+
continue
137+
with open('./upgrade_extensions.txt', 'a') as fd:
138+
fd.write(name + '\n')
139+
140+
if __name__ == '__main__':
141+
main()

0 commit comments

Comments
 (0)