Wiki

Case Status Kiln
Register Log In

Wiki

 
Promote Area to Project
  • RSS Feed

Last modified on 9/30/2011 2:29 PM by User.

Tags:

Promote Area to Project

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()