Skip to content

Instantly share code, notes, and snippets.

@ernestom
Created December 22, 2011 22:44
Show Gist options
  • Save ernestom/1512186 to your computer and use it in GitHub Desktop.
Save ernestom/1512186 to your computer and use it in GitHub Desktop.
Exports Assembla Tickets to GitHub Issues.
// 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:PASS@api.github.com/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")
}
@jaivikram
Copy link

Ernesto do you have an updated version of this? Some packages have changed. I tried to fix. It compiles without errors but does not work.

@ernestom
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment