promoteArea.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: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: |
""" Promote Area You may want to "promote" an area to be its own project. This script will move do that by creating a new project from the area and then editing all the cases currently within that area and moving them to the new project. You can create the new project/area manually if you prefer. How to use this script: 1. Change the IX_AREA_SOURCE value below to be the value of the area that you want to promote. 2. OPTIONAL: Change the IX_PROJECT_DEST value to be the project you want to move cases to. Leave at 0 if you want the script to create the project for you. 3. OPTIONAL: Change the IX_AREA_DEST value to be the area you want to move cases to. If this is 0, FogBugz will determine which area to use. 4. Run this script in practice mode (without changing fogbugz) > python promoteArea.py debug practice 5. Run this script without 'practice' to make edits to FogBugz: > python promoteArea.py debug or > python promoteArea.py See https://developers.fogbugz.com/default.asp?W194 for more information on using the FogBugz XML API with Python. """ IX_AREA_SOURCE = 50 # The id of the area that's being promoted to a project IX_PROJECT_DEST = 0 # The project that cases will move to. Leave at 0 to make # a new project. IX_AREA_DEST = 0 # Optional. If IX_PROJECT_DEST is specified, an area within # that project can be specified as a destination. from fogbugz import FogBugz import sys from sys import argv import fbSettings fDebug = False fPractice = False fCreateNewProject = False fUseSpecifiedArea = False ixProjectDest = 0 fb = None def main(): '''main() is the only function called directly within this module. It is called from the bottom of the module and is responsbile for calling other functions.''' parseArgs() fbLogon() assertIsValidProjectDestAndAreaDest() assertIsValidSourceArea() if fCreateNewProject: ixProjectDest = createNewProjectFromArea() else: ixProjectDest = IX_PROJECT_DEST moveCasesToNewProject(ixProjectDest) def parseArgs(): '''Parse command line arguments looking for 'practice' and 'debug' ''' global fDebug, fPractice for arg in argv[1:len(argv)]: if arg.lower().find("debug") >= 0: fDebug = True print "Debug mode" if arg.lower().find("practice") >= 0: fPractice = True print "Practice mode: no changes will be made to FogBugz" def fbLogon(): '''Log on to FogBugz, setting the global fb object for other functions to use''' global fb fb = FogBugz(fbSettings.URL, fbSettings.TOKEN) def assertIsValidProjectDestAndAreaDest(): '''Some guard code to make sure IX_PROJECT_DEST and IX_AREA DEST are valid''' global fCreateNewProject, fUseSpecifiedArea if IX_PROJECT_DEST == 0: #If no project is specified, assume the user wants to create the project from #the existing Area fCreateNewProject = True fUseSpecifiedArea = False if IX_AREA_DEST != 0: exitWithError("If you specify a value for IX_AREA_DEST, you must also specify "\ "a value for IX_PROJECT_DEST") else: #If an IX_PROJECT_DEST is specified, assume the user has manually created the #project that they want cases to go into fCreateNewProject = False resp = fb.viewProject(ixProject=IX_PROJECT_DEST) #check to see if the project exists if len(resp.contents) == 0: exitWithError("The IX_PROJECT_DEST specified, %s, does not exist in FogBugz" % IX_PROJECT_DEST) #check to see if the project has been deleted if resp.project.fdeleted.string == 'true': exitWithError("The IX_PROJECT_DEST specified, %s, has been deleted." % IX_PROJECT_DEST) if IX_AREA_DEST == 0: fUseSpecifiedArea = False else: fUseSpecifiedArea = True #check to see if this area is a child of the project resp = fb.viewArea(ixArea=IX_AREA_DEST) if len(resp.contents) == 0 or \ int(resp.area.ixproject.string) != IX_PROJECT_DEST or \ resp.area.fdeleted.string == "true": exitWithError("The IX_AREA_DEST specified, %s, is not an active Area of the "\ "IX_PROJECT_DEST specified, %s." % (IX_AREA_DEST, IX_PROJECT_DEST)) def assertIsValidSourceArea(): '''Determines if the source area exists and that a project does not already exist with the same name as the area''' respArea = fb.viewArea(ixArea=IX_AREA_SOURCE) respProject = None if len(respArea.contents) == 0: exitWithError("The IX_AREA_SOURCE specified, %s, does not exist" % IX_AREA_SOURCE) if fCreateNewProject: respProject = fb.viewProject(sProject=respArea.area.sarea.string) if len(respProject.contents) > 0: exitWithError("A new project can't be created because a project with the "\ "name '%s' already exists." % respArea.area.sarea.string.encode('UTF-8')) def createNewProjectFromArea(): '''Creates a new project based on the source area''' respArea = fb.viewArea(ixArea=IX_AREA_SOURCE) sArea = respArea.area.sarea.string.encode('UTF-8') ixPersonPrimaryContact = int(respArea.area.ixpersonowner.string) if ixPersonPrimaryContact == -1: respParentProject = fb.viewProject(ixProject=respArea.area.ixproject.string) ixPersonPrimaryContact = int(respParentProject.project.ixpersonowner.string) if fDebug: print "Creating New Project. sProject: %s, ixPersonPrimaryContact: %s" % \ (sArea, ixPersonPrimaryContact) ixProject = -1 if not fPractice: respNew = fb.newProject(sProject=sArea, ixPersonPrimaryContact=ixPersonPrimaryContact) ixProject = int(respNew.project.ixproject.string) return ixProject def moveCasesToNewProject(ixProjectDest): '''Edits cases matchin IX_AREA_SOURCE and moves them to the new project''' if fDebug: respAreaSource = fb.viewArea(ixArea=IX_AREA_SOURCE) sAreaSource = "%s: %s" % (IX_AREA_SOURCE, respAreaSource.area.sarea.string.encode('UTF-8')) sProject = "(New Project)" if (fCreateNewProject and not fPractice) or not fCreateNewProject: respProject = fb.viewProject(ixProject=ixProjectDest) sProject = "%s: %s" % (ixProjectDest, respProject.project.sproject.string.encode('UTF-8')) sAreaDest = "(Default)" if fUseSpecifiedArea: respAreaDest = fb.viewArea(ixArea=IX_AREA_DEST) sAreaDest = "%s: %s" % (IX_AREA_DEST, respAreaDest.area.sarea.string.encode('UTF-8')) print "Moving Cases from area %s to Project %s and Area %s" % \ (sAreaSource, sProject, sAreaDest) #find all cases that match IX_AREA_SOURCE respCases = fb.search(q='area:"=%s"' % IX_AREA_SOURCE, cols="sTitle") if fDebug and int(respCases.cases["count"]) == 0: print "No cases found" for case in respCases.cases.findAll('case'): ixBug = int(case['ixbug']) if fDebug: sTitle = case.stitle.string.encode('UTF-8') print "Moving Case %s: %s" % (ixBug, sTitle) if not fPractice: if fUseSpecifiedArea: fb.edit(ixBug=ixBug,ixProject=ixProjectDest,ixArea=IX_AREA_DEST) else: fb.edit(ixBug=ixBug,ixProject=ixProjectDest) def exitWithError(msg = ""): '''Used to exit in case something is wrong''' print "Can't continue:" print msg sys.exit() #now that we have defined all the functions we want to use, run main() main() |