Kiln » KilnSupportScripts Powershell Scripts to help monitor a Kiln environment. Contact Fog Creek support before using.
Clone URL:  
Pushed to one repository · View In Graph Contained in tip

Basic testing complete for migrate_kiln python script to move Kiln project structure and Hg data from one server to another.

Changeset 05bf790b4d7e

Parent a003225a0599

by Profile picture of User 1563Quentin Schroeder <quentin@fogcreek.com>

Changes to one file · Browse files at 05bf790b4d7e Showing diff from parent a003225a0599 Diff from another changeset...

Change 1 of 1 Show Entire File misc/​migrate_kiln.py Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
@@ -0,0 +1,189 @@
+################################ +# +# 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. + + + + + + + +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']): + 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!")