Skip to content

Instantly share code, notes, and snippets.

@jussi-kalliokoski
Created December 25, 2012 21:54

Revisions

  1. jussi-kalliokoski created this gist Dec 25, 2012.
    146 changes: 146 additions & 0 deletions bugzilla-to-github.coffee
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,146 @@
    request = require 'request'
    Restzilla = require 'restzilla'

    BUGZILLA_URL = 'https://www.w3.org/Bugs/Public/'
    BURL = 'http://localhost:8000/AudioWG/MIDI%20API/'
    GH_USER = 'jussi-kalliokoski'
    GH_REPO = 'webmidi-issues'
    GH_URL = 'https://api.github.com/repos/' + GH_USER + '/' + GH_REPO + '/issues'
    GH_AUTH =
    username: 'octocat'
    password: 'secret'


    # create a RESTful wrapper for Bugzilla

    server = Restzilla
    baseURL: BUGZILLA_URL
    server.listen 8000

    gh = (method, url, body, callback) ->
    options =
    method: method
    headers:
    authorization: 'Basic ' + Buffer(GH_AUTH.username + ':' + GH_AUTH.password).toString('base64')
    body: JSON.stringify(body)
    url: GH_URL + url

    request options, (e, res, body) ->
    callback e, res, JSON.parse(body)

    createIssue = (issue, callback) ->
    gh 'POST', '', issue, (e, res, body) ->
    return callback(e, null) if e
    return callback(Error('Error creating issue (' + res.statusCode + ')\n' + JSON.stringify(body)), null) if res.statusCode isnt 201
    callback null, body

    createComment = (issueNumber, comment, callback) ->
    gh 'POST', '/' + issueNumber + '/comments', comment, (e, res, body) ->
    return callback(e, null) if e
    return callback(Error('Error creating comment (' + res.statusCode + ')\n' + JSON.stringify(body)), null) if res.statusCode isnt 201
    callback null, body

    closeIssue = (issueNumber, callback) ->
    body =
    state: 'closed'
    gh 'PATCH', '/' + issueNumber, body, (e, res, body) ->
    return callback(e, null) if e
    return callback(Error('Error closing issue ' + issueNumber + ' (' + res.statusCode + ')\n' + JSON.stringify(body)), null) if res.statusCode isnt 200
    callback null, body


    start = ->
    request BURL, (e, res, body) ->
    throw e if e

    issues = JSON.parse(body)
    c = issues.length

    for issue in issues
    processIssue issue, ->
    if not --c
    process.nextTick finish

    convertBugToIssue = (bug) ->
    body = '> Originally reported on W3C Bugzilla [ISSUE-' + bug.number + '](' + BUGZILLA_URL + 'show_bug.cgi?id=' + bug.number + ')'
    body += ' ' + (new Date(bug.created_at)).toGMTString() + '\n'
    body += '> Reported by ' + bug.reporter + '\n'
    body += '> Assigned to ' + bug.assignee + '\n'
    body += '\n' + bug.body

    issue =
    user: GH_USER
    repo: GH_REPO
    title: bug.title
    body: body
    labels: bug.status.split(' ').filter (v) -> !~['NEW'].indexOf(v)

    processIssue = (id, done) ->
    request BURL + id, (e, res, body) ->
    throw e if e

    bug = JSON.parse body
    issue = convertBugToIssue bug

    createIssue issue, (e, ghissue) ->
    throw e if e

    console.error 'Created issue #' + ghissue.number, ghissue.title

    closeIfNeeded = ->
    closed = /^(RESOLVED|CLOSED)/.test(bug.status)
    return done() if not closed

    closeIssue ghissue.number, (e, body) ->
    throw e if e

    console.error 'Closed issue #' + ghissue.number, ghissue.title, '(Was ' + bug.status + ')'

    done()

    return closeIfNeeded() if not bug.comments

    request BURL + id + '/comments', (e, res, body) ->
    throw e if e

    comments = JSON.parse(body)
    ids = []

    cont = (id) ->
    ids.push id if id
    comment = comments.shift()

    if not comment
    console.error 'Populated ' + ids.length + ' comments for issue #' + ghissue.number, ghissue.title
    return closeIfNeeded()

    comment.bugURL = BUGZILLA_URL + 'show_bug.cgi?id=' + bug.number + '#' + comment.number
    processComment(comment, ghissue, ids, cont)

    cont()

    convertCommentToGHComment = (comment, idlist) ->
    body = '> [Original comment](' + comment.bugURL + ') by ' + comment.user + ' on W3C Bugzilla.'
    body += ' ' + (new Date(comment.created_at)).toGMTString() + '\n'
    body += '\n'
    body += comment.body.replace /\(In reply to comment #(\d+)\)/g, (all, num) ->
    num -= 1
    return all if not idlist[num]
    return '(In reply to [comment #' + (num + 1) + '](#issuecomment-' + idlist[num] + '))'

    comm =
    body: body

    processComment = (comment, ghissue, idlist, done) ->
    body = convertCommentToGHComment comment, idlist

    createComment ghissue.number, body, (e, ghcomment) ->
    throw e if e

    done(ghcomment.id)

    finish = ->
    console.log 'Done'
    process.exit()

    start()