Kiln » KilnSupportScripts Powershell Scripts to help monitor a Kiln environment. Contact Fog Creek support before using.
Clone URL:  
migrate_kiln.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
187
188
189
190
191
192
193
194
195
196
################################ # # This script will migrate repositories from one Kiln Server to another. It should work as long as # there are no name clashes between the old server and the new one, but it has only be tested with a # completely empty new server. # # The script should be run on a machine which has sufficient disk space to clone copies of ALL of the # repositories from the old kiln server. This means it also requires that Mercurial be installed in order to run. # # Beware: Branches will not migrate properly if the parent repo has been changed since the original point of the branch! import sys import os import urllib import urllib2 import urlparse from Queue import Queue try: import json except ImportError: import simplejson as json # Set debug to 0 for errors only, 1 for basic output, 2 for verbose output debug = 1 sourceServer = 'https://my.kilnhg.com' sourceToken = 'SECRET' destinationServer = 'http://server/fogbugz/kiln' destinationToken = 'SECRET' def debug_print(message, level=1): if ( debug >= level ): print message # We cycle through the heirarchy of objects and push them over to the new server. # Projects contain Groups, which in turn contain Repositories, so we have a nested loop in that order. # Note that this does NOT transfer the Users from the previous server nor any specific # permissions on the Projects/Groups/Repositories. # Create a dictionary from old ixRepos to new ones. # oldIxRepo = 123 # newIxRepo = 456 # repo_map[123] = 456 repo_map = {} # A list of pairs indicating the parent associations we will have to recreate. (old_ixrepo, old_parent_ixrepo) old_parent_associations = [] # Load all the source projects src_projects = json.load(urllib2.urlopen('%s/Api/1.0/project/?token=%s' % (sourceServer, sourceToken))) ###### PROJECT LEVEL LOOP ###### for src_project in src_projects: debug_print("Working on project '%s'" % (src_project['sName'])) debug_print("SOURCE PROJECT DATA:\n"+str(src_project), 2) dest_project = None # Try to find the project on the Destination Server dest_projects = json.load(urllib2.urlopen('%s/Api/1.0/Project?token=%s' % (destinationServer, destinationToken))) for a_dest_project in dest_projects: if (a_dest_project['sName'] == src_project['sName']): dest_project = json.load(urllib2.urlopen('%s/Api/1.0/Project/%s?token=%s' % (destinationServer, a_dest_project['ixProject'], destinationToken))) debug_print(" - Found an existing match on the destination server. ixProject = %s" % (dest_project['ixProject'])) debug_print(" - DESTINATION PROJECT DATA:\n" + str(dest_project), 2) # If we don't find an existing project, then create a new project with the information we grabbed from the old server if (not dest_project): data = urllib.urlencode({'token': destinationToken, 'sName': src_project['sName'], \ 'sDescription': src_project['sDescription'], 'permissionDefault': src_project['permissionDefault']}) dest_project = json.load(urllib2.urlopen('%s/Api/1.0/Project/Create' % (destinationServer), data)) debug_print(" + Created a new Project on the destination server. ixProject = %s" % (dest_project['ixProject'])) debug_print(" + DESTINATION PROJECT DATA:\n" + str(dest_project), 2) ###### REPOSITORY GROUP LEVEL LOOP ###### for src_repo_group in src_project['repoGroups']: debug_print(" Working on Group '%s'" % (src_repo_group['sName'])) debug_print(" SOURCE REPO GROUP DATA:\n" + str(src_repo_group), 2) dest_repo_group = None # Try to find the project on the Destination Server dest_repo_groups = dest_project['repoGroups'] for a_dest_repo_group in dest_repo_groups: if (a_dest_repo_group['sName'] == src_repo_group['sName']): dest_repo_group = json.load(urllib2.urlopen('%s/Api/1.0/RepoGroup/%s?token=%s' % (destinationServer, a_dest_repo_group['ixRepoGroup'], destinationToken))) debug_print(" - Found an existing match on the destination server. ixRepogroup = %s" % (dest_repo_group['ixRepoGroup'])) debug_print(" - DESTINATION REPO GROUP DATA:\n" + str(dest_repo_group), 2) # If we don't find an existing project, then create a new project with the information we grabbed from the old server if (not dest_repo_group): data = urllib.urlencode({'token': destinationToken, 'sName': src_repo_group['sName'], 'ixProject': dest_project['ixProject']}) dest_repo_group = json.load(urllib2.urlopen('%s/Api/1.0/RepoGroup/Create/' % (destinationServer), data)) debug_print(" + Created a new Repository Group on the destination server. ixRepoGroup = %s" % (dest_repo_group['ixRepoGroup'])) debug_print(" + DESTINATION REPO GROUP DATA:\n" + str(dest_repo_group), 2) # We build a queue of the repositories so that we can easily wait to process any repos that need parents created first q = Queue() for src_repo in src_repo_group['repos']: q.put(src_repo) ###### REPOSITORY LEVEL LOOP ###### while (not q.empty()): src_repo = q.get() # If the repo has a parent that has NOT been created in the destination yet, then re-enqueue it for later if ((src_repo['ixParent']) and not (src_repo['ixParent'] in repo_map)): q.put(src_repo) debug_print(" Postponing work on Repository '%s'" % (src_repo['sName'])) continue debug_print(" Working on Repository '%s'" % (src_repo['sName'])) # If the old repository had a parent, add the assocation to the old_parent_associations list #if src_repo['ixParent']: # old_parent_associations += [(src_repo['ixRepo'], src_repo['ixParent'])] # add (old_ixrepo, old_parent_ixrepo) to the list dest_repo = None # Try to find the project on the Destination Server dest_repos = dest_repo_group['repos'] for a_dest_repo in dest_repos: if (a_dest_repo['sName'] == src_repo['sName']): dest_repo = json.load(urllib2.urlopen('%s/Api/1.0/Repo/%s?token=%s' % (destinationServer, a_dest_repo['ixRepo'], destinationToken))) debug_print(" - Found an existing match on the destination server. ixRepo = %s" % (dest_repo['ixRepo'])) debug_print(" - DESTINATION REPOSITORY DATA:\n" + str(dest_repo), 2) # If we don't find an existing repo, then create a new repo with the information we grabbed from the old server if (not dest_repo): if (src_repo['ixParent']): # By setting the ixParent field, when Repo/Create is called, it will create a new branch from the ixParent Repo. # This means, that the point at which the src repo branched off from the parent can and most likely will be different from the # point at which the dest repo gets branched. (One option I know of to fix this, after the fact, is to strip changesets in # the dest repo back to the point where the branch was created in the src repo. Then push the src repo to the dest repo and # the src and dest branches should be back in sync. debug_print(" !!! Warning: Branches may not migrate properly !!!") data = urllib.urlencode({'token': destinationToken, 'sName': src_repo['sName'], 'sDescription': src_repo['sDescription'], 'ixRepoGroup': dest_repo_group['ixRepoGroup'], 'permissionDefault': src_repo['permissionDefault'], 'ixParent': repo_map[src_repo['ixParent']], 'fCentral': 'false' }) else: data = urllib.urlencode({'token': destinationToken, 'sName': src_repo['sName'], 'sDescription': src_repo['sDescription'], 'ixRepoGroup': dest_repo_group['ixRepoGroup'], 'permissionDefault': src_repo['permissionDefault'] }) dest_repo = json.load(urllib2.urlopen('%s/Api/1.0/Repo/Create/' % (destinationServer), data)) debug_print(" + Created a new Repository on the destination server. ixRepo = %s" % (dest_repo['ixRepo'])) debug_print(" + DESTINATION REPOSITORY DATA:\n" + str(dest_repo), 2) # Record the mapping from the old server to the new server. repo_map[oldIxRepo] = newIxRepo repo_map[src_repo['ixRepo']] = dest_repo['ixRepo'] # Build a unique folder name to clone the repo into folder_name = src_repo['sName'] + "-"+str(src_repo['ixRepo']) # Convert empty RepoGroup slug values to the default 'Group' group_name = src_repo_group['sSlug'] if (group_name == ''): group_name = 'Group' new_group_name = dest_repo_group['sSlug'] if (new_group_name == ''): new_group_name = 'Group' # Clone the repo locally, and then push it to the destination server os.system("hg clone " + sourceServer +'/Code/'+ src_project["sSlug"] +'/'+ group_name +'/'+ src_repo["sSlug"] +' "'+ folder_name + '"') os.chdir(folder_name) os.system("hg push " + destinationServer +'/Code/'+ dest_project["sSlug"] +'/'+ new_group_name +'/'+ dest_repo["sSlug"]) os.chdir('..') debug_print("\nDONE!")