|
| 1 | +#!/opt/local/bin/python2.6 |
| 2 | + |
| 3 | +################################################################################################### |
| 4 | +# |
| 5 | +# pyral.config - config and "consts" for the Rally 'pyral' package for REST API operations |
| 6 | +# |
| 7 | +################################################################################################### |
| 8 | + |
| 9 | +__version__ = (1, 0, 0) |
| 10 | + |
| 11 | +import datetime |
| 12 | +import os |
| 13 | +import platform |
| 14 | +import re |
| 15 | +import glob |
| 16 | + |
| 17 | +################################################################################################### |
| 18 | + |
| 19 | +PROTOCOL = "https" |
| 20 | +SERVER = "rally1.rallydev.com" |
| 21 | +WEB_SERVICE = "slm/webservice/%s" |
| 22 | +SCHEMA_SERVICE = "slm/schema/%s" |
| 23 | +AUTH_ENDPOINT = "security/authorize" |
| 24 | +WS_API_VERSION = "v2.0" |
| 25 | + |
| 26 | +USER_NAME = "wiley@acme.com" |
| 27 | +PASSWORD = "G3ronim0!" |
| 28 | + |
| 29 | +START_INDEX = 1 |
| 30 | +PAGESIZE = 100 |
| 31 | +MAX_PAGESIZE = 200 |
| 32 | +MAX_ITEMS = 1000000 # a million seems an eminently reasonable limit ... |
| 33 | + |
| 34 | +RALLY_REST_HEADERS = \ |
| 35 | + { |
| 36 | + #'X-RallyIntegrationName' : 'Python toolkit for Rally REST API', # although syntactically this is the more correct |
| 37 | + 'X-RallyIntegrationName' : 'Rally REST API toolkit for Python', # this matches the format of the other language toolkits |
| 38 | + 'X-RallyIntegrationVendor' : 'Rally Software Development', |
| 39 | + 'X-RallyIntegrationVersion' : '%s.%s.%s' % __version__, |
| 40 | + 'X-RallyIntegrationLibrary' : 'pyral-%s.%s.%s' % __version__, |
| 41 | + 'X-RallyIntegrationPlatform' : 'Python %s' % platform.python_version(), |
| 42 | + 'X-RallyIntegrationOS' : platform.platform(), |
| 43 | + 'User-Agent' : 'Pyral Rally WebServices Agent', |
| 44 | + 'Content-Type' : 'application/json', |
| 45 | + 'Accept-Encoding' : 'gzip' |
| 46 | + } |
| 47 | + |
| 48 | +################################################################################################## |
| 49 | + |
| 50 | +def timestamp(): |
| 51 | + # for now, don't worry about timezone fluff, and cut off the microseconds to become millis |
| 52 | + return datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] |
| 53 | + |
| 54 | +################################################################################################## |
| 55 | + |
| 56 | +CONFIG_SETTING_PATT = re.compile('^([A-Z]+)\s*=\s*(.+)$') |
| 57 | +RALLY_ARG_SETTING_PATT1 = re.compile('^--(rally[SUPW][a-z]+)=(.+)\s*$') |
| 58 | +RALLY_ARG_SETTING_PATT2 = re.compile('^--([SUPWsupw][a-z]+)=(.+)\s*$') |
| 59 | +RALLY_CONFIG_FILE_PATT = re.compile('^--(cfg|conf|config|rallyConfig)=(\S+)$') |
| 60 | + |
| 61 | +################################################################################ |
| 62 | + |
| 63 | +def rallySettings(args): |
| 64 | + """ |
| 65 | + priority order of Python Rally REST API server ident, credentials, workspace/project: |
| 66 | + 1) command line args with --rallyServer, --rallyUser, --rallyPassword, --workspace, --project |
| 67 | + 2) command line arg specifying a config file --rallyConfig=<config_file_name> |
| 68 | + or --config=<config_file_name> |
| 69 | + or --conf=<config_file_name> |
| 70 | + or --cfg=<config_file_name> |
| 71 | + 3) ENV variable with location of rally-<version>.cfg --> RALLY_CONFIG |
| 72 | + 4) current directory with rally-<version>.cfg |
| 73 | + 5) RALLY_SERVER, RALLY_USER_NAME, RALLY_PASSWORD, RALLY_WORKSPACE, RALLY_PROJECT env VARS |
| 74 | + 6) SERVER, USER_NAME, PASSWORD defined in this module |
| 75 | +
|
| 76 | + start by priming the return values with #6 and work your way up the priority ladder |
| 77 | + """ |
| 78 | + # #6 |
| 79 | + # start with the defaults defined in this module |
| 80 | + server_creds = [SERVER, USER_NAME, PASSWORD, "default", "default"] |
| 81 | + |
| 82 | + def snarfSettings(targetFile, server_creds): |
| 83 | + """ |
| 84 | + read the filename and look for lines containing relevant Rally settings. |
| 85 | + alter the server_creds list if there are entries in the file to do so. |
| 86 | + """ |
| 87 | + if not os.path.exists(targetFile): |
| 88 | + cfg_suffixed = "%s.cfg" % targetFile |
| 89 | + if not os.path.exists(cfg_suffixed): |
| 90 | + return server_creds |
| 91 | + else: |
| 92 | + targetFile = cfg_suffixed |
| 93 | + |
| 94 | + try: |
| 95 | + cf = open(targetFile, 'r') |
| 96 | + for line in cf: |
| 97 | + mo = CONFIG_SETTING_PATT.match(line) |
| 98 | + if mo: |
| 99 | + item, value = mo.groups() |
| 100 | + if item == 'SERVER': |
| 101 | + server_creds[0] = value |
| 102 | + elif item == 'USER': |
| 103 | + server_creds[1] = value |
| 104 | + elif item == 'PASSWORD': |
| 105 | + server_creds[2] = value |
| 106 | + elif item == 'WORKSPACE': |
| 107 | + server_creds[3] = value |
| 108 | + elif item == 'PROJECT': |
| 109 | + server_creds[4] = value |
| 110 | + cf.close() |
| 111 | + sc = "%s, %s, %s, %s, %s" % tuple(server_creds) |
| 112 | + return server_creds |
| 113 | + except Exception as ex: |
| 114 | + pass |
| 115 | + |
| 116 | + # #5 |
| 117 | + # if there are environment vars, use them |
| 118 | + # |
| 119 | + for ix, name in enumerate(['RALLY_SERVER', 'RALLY_USER', 'RALLY_PASSWORD', 'RALLY_WORKSPACE', 'RALLY_PROJECT']): |
| 120 | + if name in os.environ: |
| 121 | + server_creds[ix] = name |
| 122 | + |
| 123 | + # #4 |
| 124 | + # if there is a rally-<version>.cfg file in the current directory matching the WS_API_VERSION |
| 125 | + # load with contents of that file |
| 126 | + entries = glob.glob('rally-*.cfg') |
| 127 | + target_version_config = 'rally-%s.cfg' % WS_API_VERSION |
| 128 | + if entries: |
| 129 | + if target_version_config in entries: |
| 130 | + server_creds = snarfSettings(target_version_config, server_creds) |
| 131 | + else: |
| 132 | + print "Ignoring non-matching version of Rally config settings: %s (working version: %s)" % \ |
| 133 | + (entries.pop(), WS_API_VERSION) |
| 134 | + |
| 135 | + # #3 |
| 136 | + # if there is a RALLY_CONFIG environment variable pointing to a file, load with contents of file |
| 137 | + config_file = os.environ.get('RALLY_CONFIG', None) |
| 138 | + if config_file: |
| 139 | + server_creds = snarfSettings(config_file, server_creds) |
| 140 | + |
| 141 | + # #2 |
| 142 | + # now look at the args (from command line invocation) |
| 143 | + # grab any --(rallyConfig|config|conf|cfg)=<filename> args, |
| 144 | + # and if filename exists attempt to load with contents therein |
| 145 | + for arg in args: |
| 146 | + mo = RALLY_CONFIG_FILE_PATT.match(arg) |
| 147 | + if mo: |
| 148 | + config_name, config_file = mo.groups() |
| 149 | + server_creds = snarfSettings(config_file, server_creds) |
| 150 | + |
| 151 | + # #1 |
| 152 | + # now look at the args (from command line invocation) |
| 153 | + # grab any --rallyServer=?, --rallyUser=?, --rallyPassword=?, --rallyWorkspace=?, --rallyProject=? in args |
| 154 | + # grab any --server=?, --user=?, --password=?, --workspace=?, --project=? in args |
| 155 | + for arg in args: |
| 156 | + mo = RALLY_ARG_SETTING_PATT1.match(arg) |
| 157 | + if mo: |
| 158 | + item, value = mo.groups() |
| 159 | + if item == 'rallyServer': |
| 160 | + server_creds[0] = value |
| 161 | + elif item == 'rallyUser': |
| 162 | + server_creds[1] = value |
| 163 | + elif item == 'rallyPassword': |
| 164 | + server_creds[2] = value |
| 165 | + elif item == 'rallyWorkspace': |
| 166 | + server_creds[3] = value |
| 167 | + elif item == 'rallyProject': |
| 168 | + server_creds[4] = value |
| 169 | + |
| 170 | + mo = RALLY_ARG_SETTING_PATT2.match(arg) |
| 171 | + if mo: |
| 172 | + item, value = mo.groups() |
| 173 | + if item == 'server': |
| 174 | + server_creds[0] = value |
| 175 | + elif item == 'user': |
| 176 | + server_creds[1] = value |
| 177 | + elif item == 'password': |
| 178 | + server_creds[2] = value |
| 179 | + elif item == 'workspace': |
| 180 | + server_creds[3] = value |
| 181 | + elif item == 'project': |
| 182 | + server_creds[4] = value |
| 183 | + |
| 184 | + return server_creds |
| 185 | + |
0 commit comments