Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Script to migrate GoogleCode issues
/**
* Copying and distribution of this file, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved. This file is offered as-is,
* without any warranty.
*
* Migrate issues from one Googlecode project to another (e.g. if you need to rename).
* Note (line 39): fetch of issues from source project currently limited to 50
*
* See: http://code.google.com/p/support/wiki/IssueTrackerAPI for API details
*
* @author Robin Bramley, Ixxus Limited (c) 2011
*/
@Grab(group='commons-logging', module='commons-logging', version='1.1.1')
@Grab(group='commons-codec', module='commons-codec', version='1.4')
@Grab(group='org.apache.httpcomponents', module='httpclient', version='4.1.2')
import groovy.xml.MarkupBuilder
import org.apache.http.*
import org.apache.http.client.*
import org.apache.http.client.entity.UrlEncodedFormEntity
import org.apache.http.client.methods.*
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.message.BasicNameValuePair
import org.apache.http.util.EntityUtils
// ------------------
// Set these 5 items
def sourceProjectName = 'source-project'
def targetProjectName = 'target-project'
def emailAddress = 'foo@gmail.com'
def password = 'foobar'
def sourceScript = 'acme-groovyTest-0.1' // first portion is meant to be a company name
// ------------------
def googleLoginUrl = 'https://www.google.com/accounts/ClientLogin'
def issuesListUrl = "https://code.google.com/feeds/issues/p/${sourceProjectName}/issues/full?max-results=50"
def issuePostUrl = "https://code.google.com/feeds/issues/p/${targetProjectName}/issues/full"
def issuesXmlns = 'http://schemas.google.com/projecthosting/issues/2009'
def atomXmlns = 'http://www.w3.org/2005/Atom'
/** Build an atom feed for an issue */
def buildIssue(entry, issuesXmlns, atomXmlns) {
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.'atom:entry'('xmlns:atom':atomXmlns,'xmlns:issues':issuesXmlns) {
'atom:title'(entry.title)
'atom:content'(type:'html', entry.content)
'atom:author' {
'atom:name'(entry.author.name)
}
entry.'issues:label'.each {
'issues:label'(it)
}
'issues:owner' {
'issues:username'(entry.'issues:owner'.'issues:username')
}
'issues:state'(entry.'issues:state')
'issues:status'(entry.'issues:status')
}
return writer.toString()
}
/** Build an atom feed for a comment */
def buildComment(entry, issuesXmlns, atomXmlns) {
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.'atom:entry'('xmlns:atom':atomXmlns,'xmlns:issues':issuesXmlns) {
'atom:content'(type:'html', entry.content)
'atom:author' {
'atom:name'(entry.author.name)
}
'issues:updates' {
entry.'issues:updates'.'issues:label'.each {
'issues:label'(it)
}
'issues:ownerUpdate'(entry.'issues:updates'.'issues:owner'.'issues:username')
'issues:state'(entry.'issues:updates'.'issues:state')
'issues:status'(entry.'issues:updates'.'issues:status')
}
}
return writer.toString()
}
// set up login parameters
NameValuePair accountType = new BasicNameValuePair('accountType', 'GOOGLE')
NameValuePair email = new BasicNameValuePair('Email', emailAddress)
NameValuePair passwd = new BasicNameValuePair('Passwd', password)
NameValuePair service = new BasicNameValuePair('service', 'code')
NameValuePair source = new BasicNameValuePair('source', sourceScript)
List<NameValuePair> params = new ArrayList<NameValuePair>(5)
params.addAll([accountType, email, passwd, service, source])
UrlEncodedFormEntity form = new UrlEncodedFormEntity(params)
HttpPost post = new HttpPost(googleLoginUrl)
post.setEntity(form)
HttpClient httpclient = new DefaultHttpClient()
HttpResponse response = httpclient.execute(post)
// check whether 200 or 403
if (response.getStatusLine().getStatusCode() == 403) {
println response.getStatusLine().getReasonPhrase()
return
}
HttpEntity entity = response.getEntity()
def strings = EntityUtils.toString(entity).split('\n')
// fetch the 'Auth' token from the response
def authToken
strings.each {
if (it.startsWith('Auth=')) {
authToken = it.substring(5)
}
}
// get the Atom feed
HttpGet get = new HttpGet(issuesListUrl)
// Set the header => Authorization: GoogleLogin auth=<b>yourAuthToken</b>
get.setHeader('Authorization', "GoogleLogin auth=${authToken}")
response = httpclient.execute(get)
//TODO: check response.getStatusLine().getStatusCode()
entity = response.getEntity()
def atom = EntityUtils.toString(entity)
// Parse and process the atom feed
feed = new XmlSlurper().parseText(atom).declareNamespace([issues:issuesXmlns])
feed.entry.each { entry ->
issueId = entry.'issues:id'
println "Issue ${issueId} - ${entry.title}"
issueCreationXml = buildIssue(entry, issuesXmlns, atomXmlns)
// post the issue
post = new HttpPost(issuePostUrl)
post.setHeader('Content-type', 'application/atom+xml')
post.setHeader('Authorization', "GoogleLogin auth=${authToken}")
post.setEntity(new StringEntity(issueCreationXml))
response = httpclient.execute(post)
// check for bad request
println "${response.getStatusLine().getStatusCode()} - ${response.getStatusLine().getReasonPhrase()}"
if (response.statusLine.statusCode == 400) {
println EntityUtils.toString(response.entity)
return
}
EntityUtils.consume(response.entity)
/*
* Now get the comments and iterate
*/
def issuesCommentsListUrl = "https://code.google.com/feeds/issues/p/${sourceProjectName}/issues/${issueId}/comments/full"
def issuesCommentsPostUrl = "https://code.google.com/feeds/issues/p/${targetProjectName}/issues/${issueId}/comments/full"
// get the Atom feed
get = new HttpGet(issuesCommentsListUrl)
get.setHeader('Authorization', "GoogleLogin auth=${authToken}")
response = httpclient.execute(get)
println "${response.getStatusLine().getStatusCode()} - ${response.getStatusLine().getReasonPhrase()}"
entity = response.getEntity()
commentsAtom = EntityUtils.toString(entity)
commentsFeed = new XmlSlurper().parseText(commentsAtom).declareNamespace([issues:issuesXmlns])
commentsFeed.entry.each { commEntry ->
commentCreationXml = buildComment(commEntry, issuesXmlns, atomXmlns)
// post the comment
post = new HttpPost(issuesCommentsPostUrl)
post.setHeader('Authorization', "GoogleLogin auth=${authToken}")
post.setHeader('Content-type', 'application/atom+xml')
post.setEntity(new StringEntity(commentCreationXml))
response = httpclient.execute(post)
// check for bad request
println "${response.getStatusLine().getStatusCode()} - ${response.getStatusLine().getReasonPhrase()}"
if (response.statusLine.statusCode == 400) {
println EntityUtils.toString(response.entity)
return
}
EntityUtils.consume(response.entity)
}
}
return // with no noise in GroovyConsole!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.