Advertisement
Guest User

Untitled

a guest
Mar 13th, 2018
163
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 16.05 KB | None | 0 0
  1. import sys #needed for getting command line arguments
  2. import time #determine how long this job took
  3. import datetime #to make subtractions of two times
  4. import re #regex checking
  5. from jira_python import jira #working with jira
  6.  
  7. # Debug Status for Development
  8. debug = False
  9. # LogLevel 4=none, 3-1 different formats
  10. loglevel = 4
  11. # Hardcoded JIRA Base Website
  12. jiraWebsite = "https://jira4it.hellmann.net/rest/api/2/"
  13.  
  14. if debug == True:
  15. import pprint
  16. loglevel = 1
  17.  
  18. # function: main
  19. # param: jiraUser - User for Jira (text)
  20. # jiraPassword - Password for Jira (text)
  21. # jiraKey - current Jira Key (string)
  22. # brief: the main function to create a pach
  23. # description: This function creates the patch.
  24. def main(jiraUser, jiraPassword, jiraKey):
  25. if debug == True:
  26. consolePrint(3, "")
  27. #Start Information of the Script
  28. startTime = time.clock()
  29. startDate = datetime.datetime.now()
  30. consolePrint(loglevel, "Start gathering Data at " + startDate.isoformat())
  31.  
  32. #build up the jira-Connection
  33. jiraConnection = createJiraConnection(jiraUser, jiraPassword)
  34. if debug == True:
  35. printJiraConnectionDetails(jiraConnection)
  36.  
  37. #If jiraConnection is none, the connection doesn't work
  38. if jiraConnection is not None:
  39. #Use a sub-function to get information of the jira-Key.
  40. jiraInfo = getJiraInfo(jiraConnection, jiraKey)
  41. # we have - as expected - only one entry in the dict for the one jira-Key
  42. if len(jiraInfo.keys()) == 1:
  43. # Application Information
  44. app = jiraInfo[jiraKey]["application"]
  45. appID = app[:app.index("-")-1]
  46. appName = app[app.index("-")+2:]
  47. appAlias= jiraInfo[jiraKey]["alias"]
  48. appInst = jiraInfo[jiraKey]["instance"]
  49. wsName = jiraInfo[jiraKey]["workspace"]
  50. schema = ''
  51.  
  52. # pprint.PrettyPrinter(indent=4).pprint(jiraInfo[jiraKey]["instance"])
  53.  
  54. # Debug-Ausgaben
  55. consolePrint(loglevel, "")
  56. consolePrint(loglevel, "Application ID : '" + appID + "'")
  57. consolePrint(loglevel, "Application Name : '" + appName + "'")
  58. consolePrint(loglevel, "Application Alias : '" + appAlias + "'")
  59. consolePrint(loglevel, "Application Inst : '" + appInst + "'")
  60. consolePrint(loglevel, "Workspace Name : '" + wsName + "'")
  61. consolePrint(loglevel, "")
  62.  
  63. # get all files from the current JIRA-Key
  64. jiraFiles = getJiraFiles(jiraConnection, jiraKey)
  65.  
  66. # sort alphabetical (DBO -> fXXX)
  67. fileKeys = jiraFiles.keys()
  68. fileKeys.sort()
  69. fileCount = len(jiraFiles.keys())
  70.  
  71. if debug == True:
  72. consolePrint(loglevel,"Found " + str(fileCount) + " Files referenced by " + jiraKey + "!")
  73.  
  74. # Write the file contents to disk
  75. if fileCount > 0:
  76. # Add file with APEX_INSTALL_APPLICATION calls
  77. fplus = open('sql_plus.sql', 'w')
  78.  
  79. sqlPlus = ""
  80. sqlPlus += "declare\n"
  81. sqlPlus += " l_workspace_id number;\n"
  82. sqlPlus += "begin\n"
  83. sqlPlus += " select workspace_id into l_workspace_id\n"
  84. sqlPlus += " from apex_workspaces\n"
  85. sqlPlus += " where workspace = '" + wsName + "';\n"
  86. sqlPlus += "\n"
  87. sqlPlus += " apex_application_install.set_workspace_id(l_workspace_id);\n"
  88. sqlPlus += " apex_application_install.set_application_id(" + appID + ");\n"
  89. sqlPlus += " apex_application_install.set_application_name('" + appName + "');\n"
  90. # sqlPlus += " apex_application_install.set_application_alias('" + ALIAS + "');\n"
  91. if appInst.find("APEX5") != -1:
  92. consolePrint(loglevel, "APEX5 Deployment!")
  93. sqlPlus += " apex_application_install.set_auto_install_sup_obj(true);\n"
  94. # sqlPlus += " apex_application_install.set_schema('" + schema + "');\n"
  95. sqlPlus += " apex_application_install.generate_offset;\n"
  96. sqlPlus += "end;\n"
  97. sqlPlus += "/\n"
  98. fplus.write(sqlPlus.encode('utf-8'))
  99. fplus.close()
  100.  
  101. for fileName in fileKeys:
  102.  
  103. consolePrint(loglevel, "")
  104. consolePrint(loglevel, "File : " + fileName)
  105. modifyFiles(jiraInfo[jiraKey], fileName, jiraFiles[fileName]['content'])
  106. # Append additional files to sql_plus file
  107. fplus = open('sql_plus.sql', 'a')
  108. fplus.write(("\n" + "@" + fileName[:fileName.rfind(".")] + ".sql\n").encode('utf-8'))
  109. fplus.close()
  110.  
  111. fGit = open('git_save.sh', 'w')
  112. fGit.write(gitCommit(appID, appName, wsName, jiraFiles, jiraKey).encode('utf-8'))
  113. fGit.close()
  114. else:
  115. consolePrint(1, "No files were given, no deployment possible")
  116. sys.exit(1)
  117. else:
  118. consolePrint(1, "There are no or to much Patches to deploy (one allowed!)")
  119. consolePrint(1, "Waiting jiraKeys : ")
  120. for jiraKey in jiraInfo.keys():
  121. consolePrint(1, " '" + jiraKey + "' !")
  122. sys.exit(1)
  123. else:
  124. # No valid JIRA connection could be established!
  125. consolePrint(1, "Connection to JIRA doesn't work! Wrong credentials maybe?")
  126. sys.exit(1)
  127. #end of the script
  128. #at this point we iterated through all the patches
  129.  
  130. if debug == True:
  131. #end the timer
  132. endDate = datetime.datetime.now()
  133. #clock the time
  134. endTime = time.clock()
  135. consolePrint(loglevel, "\nFinished gathering Files at " + endDate.isoformat() + " it took ")
  136. #calculate the difference
  137. consolePrint(loglevel, "%.2gs" % (endTime - startTime))
  138. consolePrint(2, "")
  139.  
  140. # function: modifyFiles
  141. # param: fileInfo - fileInfo (dict)
  142. # fileName - fileName (string)
  143. # fileContent - fileContent (string)
  144. # brief: modifies content of the application files
  145. # returns: void
  146. # description: modifies attached files to produce spool content for error analysis
  147. def modifyFiles(fileInfo, fileName, fileContent):
  148. # Extract AppID and Name / WorkspaceName from JIRA Ticket
  149. app = fileInfo["application"]
  150. appID = app[:app.index("-")-1]
  151. appName = app[app.index("-")+2:]
  152. appInst = fileInfo["instance"]
  153. wsName = fileInfo["workspace"]
  154.  
  155. fName = fileName
  156. fData = fileContent
  157.  
  158. validFile = False
  159.  
  160. # Add Spool Output to content - just copy&pasted from Jochen
  161. # Add an additional message that the original files were altered
  162. newContent = ""
  163. newContent += "------------------------------------------------------------\n"
  164. newContent += "-- This file is altered! Should be deployed with SQL-Plus --\n"
  165. newContent += "------------------------------------------------------------\n"
  166. newContent += "\n"
  167. newContent += "SPOOL " + fName[:fName.index(".")] + ".spool\n"
  168. newContent += "ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL = 1;\n"
  169. newContent += "SET SQLBLANKLINES ON\n"
  170.  
  171. newContent = unicode(newContent)
  172. # The Application file containing pages/images/etc.
  173. if fName.find("f"+appID) != -1:
  174. consolePrint(loglevel, "Application-File found!")
  175. newContent += "\n"
  176. if appInst.find("APEX4") != -1:
  177. consolePrint(loglevel, "APEX4 Application File!")
  178. newContent += "DELETE APEX_040200.WWV_FLOW_WORKSHEET_CONDITIONS where flow_id = '" + appID +"';\n"
  179.  
  180. # Append Application data
  181. newContent += "\n"
  182. newContent += "------------------------------------------------------------\n"
  183. newContent += "-- Contents of Application-File --\n"
  184. newContent += "------------------------------------------------------------\n"
  185. newContent += "\n"
  186. newContent += fData.decode('utf-8')
  187. # Replace all Exit-Statements
  188. newContent = newContent.replace("exit sql.sqlcode", "EXIT 0")
  189. newContent = newContent.replace("EXIT SQL.SQLCODE", "EXIT 0")
  190. validFile = True
  191. elif fName.find("DBO_"+appID) != -1:
  192. consolePrint(loglevel, "Database-File found!")
  193. newContent += generateDB(appInst, wsName, fData)
  194. # newContent += fData.decode('utf-8')
  195. validFile = True
  196.  
  197. # Write content to file
  198. if validFile==True:
  199. f = open(fName, 'wb')
  200. f.write(newContent.encode('ascii', 'xmlcharrefreplace'))
  201. f.close()
  202.  
  203. # function: getJiraFiles
  204. # param: jiraConnection - jira Connection (Object)
  205. # jiraKeys - jira Key (string)
  206. # brief: gather the files from the specified jira Key
  207. # returns: dict of jira files (id->filename, content) found by the
  208. # specified Key OR empty dict
  209. # description: download jira files and extract content into dict (hash)
  210. def getJiraFiles(jiraConnection, jiraKey):
  211. # list of found files
  212. jiraFiles = {}
  213.  
  214. #execute the jql - return value is JSON
  215. respJson = jiraConnection.queryJson("issue/" + jiraKey)
  216.  
  217. #only do something, if there actually are attachments in JIRA
  218. try:
  219. if len(respJson["fields"]["attachment"]) > 0:
  220. consolePrint(loglevel, "Found Attachment Entries!")
  221. #-# iterate through all attachment and retrive the key of all attachment
  222. for x in range(0, len(respJson["fields"]["attachment"])):
  223.  
  224. # downloads the content from the file
  225. # only saves sql files!
  226. fileExt = respJson["fields"]["attachment"][x]["filename"]
  227. if fileExt[fileExt.rfind(".")+1:].lower() == 'sql':
  228. fileContent = jiraConnection.downloadJira(respJson["fields"]["attachment"][x]["content"])
  229. #-# append the jiraKeys to the dict
  230.  
  231. jiraFiles.update(
  232. {
  233. respJson["fields"]["attachment"][x]["filename"] :
  234. {
  235. 'content' : fileContent
  236. }
  237. }
  238. )
  239. # pprint.PrettyPrinter(indent=4).pprint(fileContent)
  240. # print type(fileContent)
  241. return jiraFiles
  242. except KeyError as ke:
  243. # we don't have a subkey named 'attachment'
  244. consolePrint(1, "JSON Key " + str(ke) + " was not found!")
  245. return {}
  246.  
  247. # function: getJiraInfo
  248. # param: jiraConnection - jira Connection (Object)
  249. # jiraKey - jira Key to search for (string)
  250. # brief: gathers information for given jira Key
  251. # returns: dict of information for jira Key
  252. # description: TBD
  253. def getJiraInfo(jiraConnection, jiraKey):
  254. jiraInfo = {}
  255.  
  256. #execute the jql - return value is JSON
  257. respJson = jiraConnection.queryJQL("key="+jiraKey)
  258.  
  259. #only do something, if there actually issues in the jql
  260. try:
  261. if len(respJson["issues"]) > 0:
  262. consolePrint(loglevel, "Found Issue Entries!")
  263. #-# iterate through all issues and retrive the key of all issues
  264. for x in range(0, len(respJson["issues"])):
  265. #-# append the jiraInfo to a dict
  266. jiraInfo.update(
  267. {
  268. respJson["issues"][x]["key"]:
  269. {
  270. 'instance' : respJson["issues"][x]["fields"]["customfield_14700"]["value"],
  271. 'application' : respJson["issues"][x]["fields"]["customfield_15703"],
  272. 'workspace' : "HELIOS",
  273. 'alias' : respJson["issues"][x]["fields"]["customfield_14634"]
  274. }
  275. }
  276. )
  277. return jiraInfo
  278. except KeyError as ke:
  279. # we don't have a subkey named 'issues'
  280. consolePrint(1, "JSON Key " + str(ke) + " was not found!")
  281. return {}
  282.  
  283. # function: printJiraConnectionDetails
  284. # param: jiraConnection - jira Connection (Object)
  285. # brief: prints all the Information about the jira Connection
  286. def printJiraConnectionDetails(jiraConnection):
  287. consolePrint(loglevel, "Arguments of Jira Connection")
  288. consolePrint(loglevel, "- Api Point: " + jiraConnection.apiWebsite)
  289. consolePrint(loglevel, "- User: " + jiraConnection.user)
  290. consolePrint(loglevel, "- Password: " + jiraConnection.password)
  291.  
  292. # function: createJiraConnection
  293. # param: jiraUser - jira User (text)
  294. # jiraPassword - jira Password (text)
  295. # brief: Initalizes the jira Connection
  296. # returns: jiraConnection (Object)
  297. # description: handles the initializiation of the jiraConnection
  298. def createJiraConnection(jiraUser, jiraPassword):
  299. jiraConnection = jira.jira( jiraUser,
  300. jiraPassword,
  301. jiraWebsite)
  302. jiraTest = jiraConnection.testConnection()
  303. if jiraTest == 'null':
  304. jiraConnection = None
  305. return jiraConnection
  306.  
  307. # function: consolePrint
  308. # param: size - size in console (number)
  309. # text - text to be printed (text)
  310. # brief: prints information to the console
  311. # description: pretty prints larger or smaller amounts of text to the console
  312. # so the debugging or logging output is more understandable
  313. def consolePrint(size, text):
  314. if size == 3:
  315. if debug == True:
  316. print("############### DEBUG START ############### DEBUG START ###############")
  317. print(text)
  318. elif size == 2:
  319. print(text)
  320. if debug == True:
  321. print("################ DEBUG END ################# DEBUG END ################")
  322. elif size == 1:
  323. # default just print text
  324. print(text)
  325.  
  326. # function: printHelp
  327. # brief: prints help about this script
  328. def printHelp():
  329. print("Usage: python " + sys.argv[0] + " jiraUser jiraPassword jiraKey")
  330. sys.exit(1)
  331.  
  332. # function: gitCommit
  333. # param: appID - application ID
  334. # appName - application Name
  335. # wsName - workspace Name
  336. # files - files to save
  337. # jiraKey - JIRA issue
  338. # brief: Generates a full featured git-shell file
  339. # returns: string
  340. # description: Builds a git-shell file to simplify commits
  341. def gitCommit(appID, appName, wsName, files, jiraKey):
  342. gitCmd = ''
  343.  
  344. workspace = wsName.strip()
  345. workspace = workspace.replace(" ","_")
  346.  
  347. # Set User Name and Mail for commit Messages
  348. gitCmd += "git config user.email \"Hans-Hermann.Hunfeld@hellmann.com\"" + "\n"
  349. gitCmd += "git config user.name \"apex-deploy-svc\"" + "\n"
  350.  
  351. # Change or create directory
  352. gitCmd += "if [ ! -d \"" + workspace + "/" + appID + "\" ]; then" + "\n"
  353. gitCmd += " mkdir -p " + workspace + "/" + appID + "" + "\n"
  354. gitCmd += "fi" + "\n"
  355.  
  356. # Copy data to target directory
  357. for fileName in files.keys():
  358. gitCmd += "cp ../" + fileName + " ./" + workspace + "/" + appID + "\n"
  359.  
  360. gitCmd += "cp ../sql_plus.sql ./" + workspace + "/" + appID + "" + "\n"
  361. gitCmd += "echo '" + workspace + "/" + appID + "" + "'\n"
  362. gitCmd += "ls -al ./" + workspace + "/" + appID + "" + "\n"
  363.  
  364. gitCmd += "if [ -n \"$(git ls-files --other --exclude-standard --directory | egrep -v '/$')\" ]; then" + "\n"
  365. gitCmd += " git add -A" + "\n"
  366. gitCmd += " git commit -m \"JIRA Issue " + jiraKey + " : " + "Deployed '" + appID + "' from Workspace " + workspace + "\"" + "\n"
  367. gitCmd += " git push origin master" + "\n"
  368. gitCmd += "else" + "\n"
  369. gitCmd += " if [ -n \"$(git status | egrep -v '/$')\" ]; then" + "\n"
  370. gitCmd += " git add -A" + "\n"
  371. gitCmd += " git commit -m \"JIRA Issue " + jiraKey + " : " + "Deployed '" + appID + "' from Workspace " + workspace + "\"" + "\n"
  372. gitCmd += " git push origin master" + "\n"
  373. gitCmd += " else" + "\n"
  374. gitCmd += " echo 'No Changes!'" + "\n"
  375. gitCmd += " fi" + "\n"
  376. gitCmd += "fi" + "\n"
  377.  
  378. return gitCmd
  379.  
  380. # function: generateDB
  381. # param: data - dbo content
  382. # wsName - name of the workspace
  383. # appInst - value of the apex instance
  384. # brief: Generates a complete DBO-File
  385. # returns: content (string)
  386. # description: Modifies content with begin / end and checks for errors
  387. def generateDB(appInst, wsName, data):
  388. # Set exception handling methods
  389. dboContent = "WHENEVER SQLERROR EXIT 0 ROLLBACK;\n"
  390. dboContent += "\n"
  391. # find Schema, Workspace and correct owner
  392. dboContent += "DECLARE\n"
  393. dboContent += " use_schema varchar2(255) := 'SYS';\n"
  394. dboContent += " cur_schema varchar2(255) := 'SYS';\n"
  395. dboContent += " ws_found number := 0;\n"
  396. dboContent += "BEGIN\n"
  397. dboContent += " SELECT COUNT(DISTINCT SCHEMA) into ws_found FROM apex_workspace_schemas where WORKSPACE_NAME = '" + wsName + "';\n"
  398. dboContent += " IF ws_found = 0 THEN\n"
  399. dboContent += " RAISE_APPLICATION_ERROR(-20000, 'No Workspace Found!');\n"
  400. dboContent += " ELSIF ws_found = 1 THEN\n"
  401. dboContent += " SELECT DISTINCT SCHEMA INTO use_schema FROM apex_workspace_schemas where WORKSPACE_NAME = '" + wsName + "';\n"
  402. dboContent += " ELSE\n"
  403. dboContent += " RAISE_APPLICATION_ERROR(-20000, 'Too many Workspaces Found!');\n"
  404. dboContent += " END IF;\n"
  405. dboContent += " EXECUTE IMMEDIATE 'ALTER SESSION SET CURRENT_SCHEMA = ' || use_schema;\n"
  406. dboContent += " select sys_context('USER_SCHEMA','CURRENT_SCHEMA') into cur_schema from dual;\n"
  407. dboContent += " IF cur_schema = 'SYS' THEN\n"
  408. dboContent += " RAISE_APPLICATION_ERROR(-20000, 'No Schema Found!');\n"
  409. dboContent += " END IF;\n"
  410. dboContent += "END;\n"
  411. dboContent += "/\n"
  412. dboContent += "\n"
  413.  
  414. content = data.decode('utf-8')
  415.  
  416. # Add a disclaimer to differentiate between script and file content
  417. dboContent += "\n"
  418. dboContent += "------------------------------------------------------------\n"
  419. dboContent += "-- Contents of DatabaseObject-File --\n"
  420. dboContent += "------------------------------------------------------------\n"
  421. dboContent += "\n"
  422.  
  423. # Append given content
  424. dboContent += content
  425. # End with force commit
  426. if appInst.find("APEX4") != -1:
  427. consolePrint(loglevel, "APEX4 Database-File!")
  428. dboContent += "\ncommit;\n"
  429.  
  430. return dboContent;
  431.  
  432. #This is calles, if you just try to open the file, without calling the main
  433. #function explcitly.
  434. if __name__ == '__main__':
  435. #check if there are enough arguments to proceed
  436. if len(sys.argv) <> 4:
  437. if debug == False:
  438. #if we don't have all arguments, and we're not debugging, print the
  439. #help function
  440. printHelp()
  441. else:
  442. jiraUser = sys.argv[1]
  443. jiraPassword = sys.argv[2]
  444. jiraKey = sys.argv[3]
  445. if debug == True:
  446. #if we are debugging, we'll be lazy and just take these variables instead
  447. consolePrint(loglevel, "DEBUG MODE - ACTIVATE jira-Variables!")
  448. # we should now have everything we need to get started.
  449. main(jiraUser, jiraPassword, jiraKey)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement