Created
December 22, 2011 22:44
-
-
Save ernestom/1512186 to your computer and use it in GitHub Desktop.
Exports Assembla Tickets to GitHub Issues.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Exports Assembla tickets in XML format to GitHub issues. | |
// | |
// Usage: $ ./export-tickets path/to/tickets.xml repository_name | |
// | |
package main | |
import ( | |
"os" | |
"fmt" | |
"xml" | |
"json" | |
"http" | |
"strings" | |
"io/ioutil" | |
) | |
// GitHub API endpoint for /repos/:user/:repo/issues | |
const GH_API = "https://USER:[email protected]/repos/%s/%s/issues" | |
// GitHub logins to assign tickets to. The first one is considered the default. | |
var validAssignees = []string{"LOGIN1", "LOGIN2"} | |
// A GitHub issue. | |
type Issue struct { | |
Title string `json:"title"` | |
Body string `json:"body"` | |
Assignee string `json:"assignee"` | |
Labels []Label `json:"labels"` | |
} | |
type Label struct { | |
Name string `json:"name"` | |
} | |
// XML tickets from Assembla. | |
type Tickets struct { | |
Ticket []Ticket | |
} | |
// The XML ticket from Assembla. | |
type Ticket struct { | |
Summary string | |
Description string | |
StatusName string | |
AssignedTo Assignee | |
} | |
// The original assignee. | |
type Assignee struct { | |
Name string | |
Login string | |
} | |
// Handles errors. | |
func checkError(err os.Error) { | |
if err != nil { | |
fmt.Println("Error: ", err.String()) | |
os.Exit(1) | |
} | |
} | |
// Checks if the provided assignee exists on GitHub. | |
func isValidAssignee(assignee string) bool { | |
for _, v := range validAssignees { | |
if v == assignee { | |
return true | |
} | |
} | |
return false | |
} | |
// Removes whitespace and newlines. | |
func trim(str string) string { | |
return strings.TrimSpace(strings.Replace(str, "\n", "", -1)) | |
} | |
// Exports the tickets from the given file name into the given repo. | |
func exportTickets(file string, repo string) { | |
var tickets Tickets | |
contents, readErr := ioutil.ReadFile(file) | |
checkError(readErr) | |
r := strings.NewReader(string(contents)) | |
unmarshalErr := xml.Unmarshal(r, &tickets) | |
checkError(unmarshalErr) | |
defaultAssignee := validAssignees[0] | |
for _, ticket := range tickets.Ticket { | |
summary := trim(ticket.Summary) | |
assignee := trim(strings.ToLower(ticket.AssignedTo.Login)) | |
notes := "" | |
if trim(ticket.StatusName) == "Fixed" { | |
fmt.Printf("=====> Skipping fixed ticket: '%s'\n", summary) | |
continue | |
} | |
if isValidAssignee(assignee) == false { | |
notes = fmt.Sprintf("(reassigned to '%s' from '%s')", defaultAssignee, assignee) | |
ticket.AssignedTo.Login = defaultAssignee | |
} | |
fmt.Printf("=====> Posting pending ticket: '%s' %s\n", summary, notes) | |
postIssue(ticket, repo) | |
//break | |
} | |
} | |
// Encodes the given ticket into an issue in JSON. | |
func encodeTicket(ticket Ticket) string { | |
issue := Issue{ | |
trim(ticket.Summary), | |
trim(ticket.Description), | |
trim(ticket.AssignedTo.Login), | |
[]Label{{"Assembla"}}, | |
} | |
b, jsonErr := json.Marshal(issue) | |
checkError(jsonErr) | |
return string(b) | |
} | |
// Posts the new JSON-encoded issue to GitHub using the given ticket. | |
func postIssue(ticket Ticket, repo string) { | |
bodyType := "application/json" | |
jsonIssue := strings.NewReader(encodeTicket(ticket)) | |
url := fmt.Sprintf(GH_API, repo) | |
resp, respErr := http.Post(url, bodyType, jsonIssue) | |
checkError(respErr) | |
fmt.Println(resp.Status) | |
http.DumpResponse(resp, true) | |
} | |
func main() { | |
if len(os.Args) == 3 { | |
exportTickets(os.Args[1], os.Args[2]) | |
} | |
//exportTickets("tickets/menta.xml", "menta") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I don't, sorry. It was useful to me 3 years ago as a fire and forget script. A quick fix might be to use an older version of Go ;)