File: backCompatChecker.py

package info (click to toggle)
azure-devops-cli-extension 1.0.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 20,384 kB
  • sloc: python: 160,782; xml: 198; makefile: 56; sh: 51
file content (158 lines) | stat: -rw-r--r-- 6,712 bytes parent folder | download | duplicates (4)
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
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import re
import os
import subprocess

oldArguments = []
newArguments = []
allowedMissingArguments = {}
allowedMissingArguments['devops extension uninstall'] = ['--extension-name', '--publisher-name']
allowedMissingArguments['devops extension install'] = ['--extension-name', '--publisher-name']
allowedMissingArguments['devops extension enable'] = ['--extension-name', '--publisher-name']
allowedMissingArguments['devops extension disable'] = ['--extension-name', '--publisher-name']
allowedMissingArguments['devops extension show'] = ['--extension-name', '--publisher-name']

allowedNewMandatoryArguments = {}
allowedNewMandatoryArguments['devops extension uninstall'] = ['--extension-id', '--publisher-id']
allowedNewMandatoryArguments['devops extension install'] = ['--extension-id', '--publisher-id']
allowedNewMandatoryArguments['devops extension enable'] = ['--extension-id', '--publisher-id']
allowedNewMandatoryArguments['devops extension disable'] = ['--extension-id', '--publisher-id']
allowedNewMandatoryArguments['devops extension show'] = ['--extension-id', '--publisher-id']


# Do not compare these commands
ignoreCommands = []

class Arguments(dict):
    def __init__(self, command, name, isRequired):
        self.command = command
        self.name = name
        self.isRequired = isRequired
        dict.__init__(self,command = command, name = name, isRequired = isRequired)

def extractArgumentsFromCommand(command):
    print('running extractArgumentsFromCommand for ' + command)
    argumentList = []
    commandExtended = 'az ' + command + ' -h'
    help_text = subprocess.run(commandExtended.split(' '), shell=True, stdout=subprocess.PIPE)
    print('help text for ' + command)
    print(help_text)
    if " is in preview" in str(help_text):
        return argumentList
    regexReesult = re.search('Arguments(.*)Global Arguments',str(help_text))
    result = regexReesult.group(1)
    argumentLines = result.split('\\r\\n')

    for argumentLine in argumentLines:
        argumentLineSplits = argumentLine.split(" : ")
        if len(argumentLineSplits) > 1 and ' : ' in argumentLine:
            isRequired = False
            if '[Required]' in argumentLineSplits[0]:
                isRequired = True

            names = argumentLineSplits[0].replace('[Required]','').strip().split(' ')
            for name in names:
                argument = Arguments(command, name, isRequired)
                argumentList.append(argument)

    return argumentList

# remove azure-devops extension from index (if installed)
subprocess.run(['az', 'extension', 'remove', '-n', 'azure-devops'], shell=True)

# install extension from index
subprocess.run(['az', 'extension', 'add', '-n', 'azure-devops'], shell=True)

# Check the installed extensions
subprocess.run(['az', 'extension', 'list'], shell=True)

# add extension path to sys.path so that we can get all the commands
import sys
from azure.cli.core.extension import get_extension_path
# Make sure that the extension install directory is on sys.path so that dependencies can be found.
extensionPath = get_extension_path('azure-devops')
sys.path.append(extensionPath)

# loading commands from code
from azure.cli.core.mock import DummyCli
from azext_devops import DevCommandsLoader
cli_ctx = DummyCli()
loader = DevCommandsLoader(cli_ctx)
loader.load_command_table(None)

for command in loader.command_table:
    oldArguments.extend(extractArgumentsFromCommand(command))

print('Unload extension (loaded from index).')

# uninstall extension loaded from index
subprocess.run(['az', 'extension', 'remove', '-n', 'azure-devops'], shell=True, stdout=subprocess.PIPE)

# search and install extension from given path
def findExtension():
    for p, d, f in os.walk('.'):
        for file in f:
            if file.endswith('.whl'):
                return os.path.join(p, file)


newExtensionLocation = findExtension()
print('Install extension (loaded from current code). Wheel path - {}'.format(newExtensionLocation))
subprocess.run(['az', 'extension', 'add', '--source', newExtensionLocation, '-y'], shell=True, stdout=subprocess.PIPE)

# Check the installed extensions
subprocess.run(['az', 'extension', 'list'], shell=True)

# get a set of old commands, we are not reusing the set from ext because we want to keep this clean
oldCommands = []
for oldArgument in oldArguments:
    if oldArgument.command not in ignoreCommands:
        if not (oldArgument.command in oldCommands):
            oldCommands.append(oldArgument.command)
    else:
        print('Ignoring command.. ' + oldArgument.command)


# prepare argument set from new extension
for oldCommand in oldCommands:
    print("Running extract for command: {}".format(oldCommand))
    newArguments.extend(extractArgumentsFromCommand(oldCommand))

errorList = []

# make sure no new argument is mandatory
for newArgument in newArguments:
    if newArgument.isRequired is True:
        isNewMandatory = True
        for oldArgument in oldArguments:
            if oldArgument.command == newArgument.command and oldArgument.name == newArgument.name and oldArgument.isRequired is True:
                isNewMandatory = False
                break

        if isNewMandatory is True:
            allowedNewMandatoryArgumentsForCommand = allowedNewMandatoryArguments.get(newArgument.command, [])
            if not newArgument.name in allowedNewMandatoryArgumentsForCommand:
                errorList.append('\n' + 'New Mandatory argument found for command ' + newArgument.command + ' argument ' +  newArgument.name)

# make sure no argument is removed
for oldArgument in oldArguments:
    if oldArgument.command not in ignoreCommands:
        isArgumentMissing = True
        for newArgument in newArguments:
            if oldArgument.name == newArgument.name and oldArgument.command == newArgument.command:
                isArgumentMissing = False
                break

        if isArgumentMissing is True:
            allowedMissingArgumetsForCommand = allowedMissingArguments.get(oldArgument.command, [])
            if not oldArgument.name in allowedMissingArgumetsForCommand:
                errorList.append('\n' + 'Argument missing for command ' + oldArgument.command + ' argument ' +  oldArgument.name)

if len(errorList) > 0:
    import sys
    sys.stderr.write(' '.join(errorList))
    raise Exception('Something is not correct')