diff options
author | borenet <borenet@google.com> | 2014-11-17 09:59:53 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-17 09:59:53 -0800 |
commit | 0f881c64a32a4a1ed12794ea853848d453ff4d61 (patch) | |
tree | 7964a9c2e9e91d407790671847f1b30469daf173 | |
parent | 84c8e62fad59f0e19b40ac718467f5b7884b431d (diff) |
Remove bug_chomper
It has been moved into buildbot repo.
BUG=skia:
Review URL: https://codereview.chromium.org/731123003
-rw-r--r-- | tools/bug_chomper/res/favicon.ico | bin | 318 -> 0 bytes | |||
-rw-r--r-- | tools/bug_chomper/res/style.css | 72 | ||||
-rw-r--r-- | tools/bug_chomper/res/third_party/jquery.tablednd.js | 314 | ||||
-rwxr-xr-x | tools/bug_chomper/run_server.sh | 22 | ||||
-rw-r--r-- | tools/bug_chomper/src/issue_tracker/issue_tracker.go | 304 | ||||
-rw-r--r-- | tools/bug_chomper/src/server/server.go | 393 | ||||
-rw-r--r-- | tools/bug_chomper/templates/bug_chomper.html | 118 | ||||
-rw-r--r-- | tools/bug_chomper/templates/error.html | 12 | ||||
-rw-r--r-- | tools/bug_chomper/templates/submitted.html | 13 |
9 files changed, 0 insertions, 1248 deletions
diff --git a/tools/bug_chomper/res/favicon.ico b/tools/bug_chomper/res/favicon.ico Binary files differdeleted file mode 100644 index e7440c7512..0000000000 --- a/tools/bug_chomper/res/favicon.ico +++ /dev/null diff --git a/tools/bug_chomper/res/style.css b/tools/bug_chomper/res/style.css deleted file mode 100644 index 726e5aecd5..0000000000 --- a/tools/bug_chomper/res/style.css +++ /dev/null @@ -1,72 +0,0 @@ -table#buglist { - border-collapse: collapse; - border-style: solid; - border-color: rgba(0, 0, 0, 1.0); - border-width: 3px; - width: 80%; - margin-left: 10%; - margin-right: 10%; -} - -tr { - border-color: rgba(0, 0, 0, 1.0); - border-style: dashed; - border-width: 1px 3px; -} - -tr.priority_Critical { - background-color: rgba(255, 0, 0, 0.3); -} - -tr.priority_High { - background-color: rgba(255, 165, 0, 0.3); -} - -tr.priority_Medium { - background-color: rgba(255, 255, 0, 0.3); -} - -tr.priority_Low { - background-color: rgba(0, 255, 0, 0.3); -} - -tr.priority_Never { - background-color: rgba(190, 190, 190, 0.3); -} - -tbody { - background-color: rgba(190, 190, 190, 0.1); -} - -tr.priority_row { - background-color: rgba(190, 190, 190, 0.1); - border-style: solid; -} - -tr.tr_head { - background-color: rgba(190, 190, 190, 0.5); -} - -#table_header { - text-align: center; -} - -td { - padding: 5px; -} - -td.priority_td { - text-align: center; -} - -a { - color: black; -} - -a:visited { - color: black; -} - -a:hover { - text-decoration: none; -}
\ No newline at end of file diff --git a/tools/bug_chomper/res/third_party/jquery.tablednd.js b/tools/bug_chomper/res/third_party/jquery.tablednd.js deleted file mode 100644 index 869f94effc..0000000000 --- a/tools/bug_chomper/res/third_party/jquery.tablednd.js +++ /dev/null @@ -1,314 +0,0 @@ -/** - * TableDnD plug-in for JQuery, allows you to drag and drop table rows - * You can set up various options to control how the system will work - * Copyright © Denis Howlett <denish@isocra.com> - * Licensed like jQuery, see http://docs.jquery.com/License. - * - * Configuration options: - * - * onDragStyle - * This is the style that is assigned to the row during drag. There are limitations to the styles that can be - * associated with a row (such as you can't assign a borderâwell you can, but it won't be - * displayed). (So instead consider using onDragClass.) The CSS style to apply is specified as - * a map (as used in the jQuery css(...) function). - * onDropStyle - * This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations - * to what you can do. Also this replaces the original style, so again consider using onDragClass which - * is simply added and then removed on drop. - * onDragClass - * This class is added for the duration of the drag and then removed when the row is dropped. It is more - * flexible than using onDragStyle since it can be inherited by the row cells and other content. The default - * is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your - * stylesheet. - * onDrop - * Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table - * and the row that was dropped. You can work out the new order of the rows by using - * table.rows. - * onDragStart - * Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the - * table and the row which the user has started to drag. - * onAllowDrop - * Pass a function that will be called as a row is over another row. If the function returns true, allow - * dropping on that row, otherwise not. The function takes 2 parameters: the dragged row and the row under - * the cursor. It returns a boolean: true allows the drop, false doesn't allow it. - * scrollAmount - * This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the - * window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2, - * FF3 beta) - * - * Other ways to control behaviour: - * - * Add class="nodrop" to any rows for which you don't want to allow dropping, and class="nodrag" to any rows - * that you don't want to be draggable. - * - * Inside the onDrop method you can also call $.tableDnD.serialize() this returns a string of the form - * <tableID>[]=<rowID1>&<tableID>[]=<rowID2> so that you can send this back to the server. The table must have - * an ID as must all the rows. - * - * Known problems: - * - Auto-scoll has some problems with IE7 (it scrolls even when it shouldn't), work-around: set scrollAmount to 0 - * - * Version 0.2: 2008-02-20 First public version - * Version 0.3: 2008-02-07 Added onDragStart option - * Made the scroll amount configurable (default is 5 as before) - * Version 0.4: 2008-03-15 Changed the noDrag/noDrop attributes to nodrag/nodrop classes - * Added onAllowDrop to control dropping - * Fixed a bug which meant that you couldn't set the scroll amount in both directions - * Added serialise method - */ -jQuery.tableDnD = { - /** Keep hold of the current table being dragged */ - currentTable : null, - /** Keep hold of the current drag object if any */ - dragObject: null, - /** The current mouse offset */ - mouseOffset: null, - /** Remember the old value of Y so that we don't do too much processing */ - oldY: 0, - - /** Actually build the structure */ - build: function(options) { - // Make sure options exists - options = options || {}; - // Set up the defaults if any - - this.each(function() { - // Remember the options - this.tableDnDConfig = { - onDragStyle: options.onDragStyle, - onDropStyle: options.onDropStyle, - // Add in the default class for whileDragging - onDragClass: options.onDragClass ? options.onDragClass : "tDnD_whileDrag", - onDrop: options.onDrop, - onDragStart: options.onDragStart, - scrollAmount: options.scrollAmount ? options.scrollAmount : 5 - }; - // Now make the rows draggable - jQuery.tableDnD.makeDraggable(this); - }); - - // Now we need to capture the mouse up and mouse move event - // We can use bind so that we don't interfere with other event handlers - jQuery(document) - .bind('mousemove', jQuery.tableDnD.mousemove) - .bind('mouseup', jQuery.tableDnD.mouseup); - - // Don't break the chain - return this; - }, - - /** This function makes all the rows on the table draggable apart from those marked as "NoDrag" */ - makeDraggable: function(table) { - // Now initialise the rows - var rows = table.rows; //getElementsByTagName("tr") - var config = table.tableDnDConfig; - for (var i=0; i<rows.length; i++) { - // To make non-draggable rows, add the nodrag class (eg for Category and Header rows) - // inspired by John Tarr and Famic - var nodrag = $(rows[i]).hasClass("nodrag"); - if (! nodrag) { //There is no NoDnD attribute on rows I want to drag - jQuery(rows[i]).mousedown(function(ev) { - if (ev.target.tagName == "TD") { - jQuery.tableDnD.dragObject = this; - jQuery.tableDnD.currentTable = table; - jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev); - if (config.onDragStart) { - // Call the onDrop method if there is one - config.onDragStart(table, this); - } - return false; - } - }).css("cursor", "move"); // Store the tableDnD object - } - } - }, - - /** Get the mouse coordinates from the event (allowing for browser differences) */ - mouseCoords: function(ev){ - if(ev.pageX || ev.pageY){ - return {x:ev.pageX, y:ev.pageY}; - } - return { - x:ev.clientX + document.body.scrollLeft - document.body.clientLeft, - y:ev.clientY + document.body.scrollTop - document.body.clientTop - }; - }, - - /** Given a target element and a mouse event, get the mouse offset from that element. - To do this we need the element's position and the mouse position */ - getMouseOffset: function(target, ev) { - ev = ev || window.event; - - var docPos = this.getPosition(target); - var mousePos = this.mouseCoords(ev); - return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y}; - }, - - /** Get the position of an element by going up the DOM tree and adding up all the offsets */ - getPosition: function(e){ - var left = 0; - var top = 0; - /** Safari fix -- thanks to Luis Chato for this! */ - if (e.offsetHeight == 0) { - /** Safari 2 doesn't correctly grab the offsetTop of a table row - this is detailed here: - http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/ - the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild. - note that firefox will return a text node as a first child, so designing a more thorough - solution may need to take that into account, for now this seems to work in firefox, safari, ie */ - e = e.firstChild; // a table cell - } - - while (e.offsetParent){ - left += e.offsetLeft; - top += e.offsetTop; - e = e.offsetParent; - } - - left += e.offsetLeft; - top += e.offsetTop; - - return {x:left, y:top}; - }, - - mousemove: function(ev) { - if (jQuery.tableDnD.dragObject == null) { - return; - } - - var dragObj = jQuery(jQuery.tableDnD.dragObject); - var config = jQuery.tableDnD.currentTable.tableDnDConfig; - var mousePos = jQuery.tableDnD.mouseCoords(ev); - var y = mousePos.y - jQuery.tableDnD.mouseOffset.y; - //auto scroll the window - var yOffset = window.pageYOffset; - if (document.all) { - // Windows version - //yOffset=document.body.scrollTop; - if (typeof document.compatMode != 'undefined' && - document.compatMode != 'BackCompat') { - yOffset = document.documentElement.scrollTop; - } - else if (typeof document.body != 'undefined') { - yOffset=document.body.scrollTop; - } - - } - - if (mousePos.y-yOffset < config.scrollAmount) { - window.scrollBy(0, -config.scrollAmount); - } else { - var windowHeight = window.innerHeight ? window.innerHeight - : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight; - if (windowHeight-(mousePos.y-yOffset) < config.scrollAmount) { - window.scrollBy(0, config.scrollAmount); - } - } - - - if (y != jQuery.tableDnD.oldY) { - // work out if we're going up or down... - var movingDown = y > jQuery.tableDnD.oldY; - // update the old value - jQuery.tableDnD.oldY = y; - // update the style to show we're dragging - if (config.onDragClass) { - dragObj.addClass(config.onDragClass); - } else { - dragObj.css(config.onDragStyle); - } - // If we're over a row then move the dragged row to there so that the user sees the - // effect dynamically - var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y); - if (currentRow) { - // TODO worry about what happens when there are multiple TBODIES - if (movingDown && jQuery.tableDnD.dragObject != currentRow) { - jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling); - } else if (! movingDown && jQuery.tableDnD.dragObject != currentRow) { - jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow); - } - } - } - - return false; - }, - - /** We're only worried about the y position really, because we can only move rows up and down */ - findDropTargetRow: function(draggedRow, y) { - var rows = jQuery.tableDnD.currentTable.rows; - for (var i=0; i<rows.length; i++) { - var row = rows[i]; - var rowY = this.getPosition(row).y; - var rowHeight = parseInt(row.offsetHeight)/2; - if (row.offsetHeight == 0) { - rowY = this.getPosition(row.firstChild).y; - rowHeight = parseInt(row.firstChild.offsetHeight)/2; - } - // Because we always have to insert before, we need to offset the height a bit - if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) { - // that's the row we're over - // If it's the same as the current row, ignore it - if (row == draggedRow) {return null;} - var config = jQuery.tableDnD.currentTable.tableDnDConfig; - if (config.onAllowDrop) { - if (config.onAllowDrop(draggedRow, row)) { - return row; - } else { - return null; - } - } else { - // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic) - var nodrop = $(row).hasClass("nodrop"); - if (! nodrop) { - return row; - } else { - return null; - } - } - return row; - } - } - return null; - }, - - mouseup: function(e) { - if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) { - var droppedRow = jQuery.tableDnD.dragObject; - var config = jQuery.tableDnD.currentTable.tableDnDConfig; - // If we have a dragObject, then we need to release it, - // The row will already have been moved to the right place so we just reset stuff - if (config.onDragClass) { - jQuery(droppedRow).removeClass(config.onDragClass); - } else { - jQuery(droppedRow).css(config.onDropStyle); - } - jQuery.tableDnD.dragObject = null; - if (config.onDrop) { - // Call the onDrop method if there is one - config.onDrop(jQuery.tableDnD.currentTable, droppedRow); - } - jQuery.tableDnD.currentTable = null; // let go of the table too - } - }, - - serialize: function() { - if (jQuery.tableDnD.currentTable) { - var result = ""; - var tableId = jQuery.tableDnD.currentTable.id; - var rows = jQuery.tableDnD.currentTable.rows; - for (var i=0; i<rows.length; i++) { - if (result.length > 0) result += "&"; - result += tableId + '[]=' + rows[i].id; - } - return result; - } else { - return "Error: No Table id set, you need to set an id on your table and every row"; - } - } -} - -jQuery.fn.extend( - { - tableDnD : jQuery.tableDnD.build - } -);
\ No newline at end of file diff --git a/tools/bug_chomper/run_server.sh b/tools/bug_chomper/run_server.sh deleted file mode 100755 index 76518afa73..0000000000 --- a/tools/bug_chomper/run_server.sh +++ /dev/null @@ -1,22 +0,0 @@ -if [[ -z `which go` ]]; then - echo "Please install Go before running the server." - exit 1 -fi - -if [[ -z "$GOPATH" ]]; then - echo "GOPATH environment variable is not set. Please see" - echo "http://golang.org/doc/code.html#GOPATH for more information." - exit 1 -fi - -go get github.com/gorilla/securecookie -go get code.google.com/p/goauth2/oauth - -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -cd $DIR - -if [[ ! -f oauth_client_secret.json ]]; then - gsutil cp gs://chromium-skia-gm/bugchomper/oauth_client_secret.json . -fi - -GOPATH="$GOPATH:$DIR" go run $DIR/src/server/server.go $@ diff --git a/tools/bug_chomper/src/issue_tracker/issue_tracker.go b/tools/bug_chomper/src/issue_tracker/issue_tracker.go deleted file mode 100644 index 42e2e53681..0000000000 --- a/tools/bug_chomper/src/issue_tracker/issue_tracker.go +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright (c) 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/* - Utilities for interacting with the GoogleCode issue tracker. - - Example usage: - issueTracker := issue_tracker.MakeIssueTraker(myOAuthConfigFile) - authURL := issueTracker.MakeAuthRequestURL() - // Visit the authURL to obtain an authorization code. - issueTracker.UpgradeCode(code) - // Now issueTracker can be used to retrieve and edit issues. -*/ -package issue_tracker - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "strconv" - "strings" - - "code.google.com/p/goauth2/oauth" -) - -// BugPriorities are the possible values for "Priority-*" labels for issues. -var BugPriorities = []string{"Critical", "High", "Medium", "Low", "Never"} - -var apiScope = []string{ - "https://www.googleapis.com/auth/projecthosting", - "https://www.googleapis.com/auth/userinfo.email", -} - -const issueApiURL = "https://www.googleapis.com/projecthosting/v2/projects/" -const issueURL = "https://code.google.com/p/skia/issues/detail?id=" -const personApiURL = "https://www.googleapis.com/userinfo/v2/me" - -// Enum for determining whether a label has been added, removed, or is -// unchanged. -const ( - labelAdded = iota - labelRemoved - labelUnchanged -) - -// loadOAuthConfig reads the OAuth given config file path and returns an -// appropriate oauth.Config. -func loadOAuthConfig(oauthConfigFile string) (*oauth.Config, error) { - errFmt := "failed to read OAuth config file: %s" - fileContents, err := ioutil.ReadFile(oauthConfigFile) - if err != nil { - return nil, fmt.Errorf(errFmt, err) - } - var decodedJson map[string]struct { - AuthURL string `json:"auth_uri"` - ClientId string `json:"client_id"` - ClientSecret string `json:"client_secret"` - TokenURL string `json:"token_uri"` - } - if err := json.Unmarshal(fileContents, &decodedJson); err != nil { - return nil, fmt.Errorf(errFmt, err) - } - config, ok := decodedJson["web"] - if !ok { - return nil, fmt.Errorf(errFmt, err) - } - return &oauth.Config{ - ClientId: config.ClientId, - ClientSecret: config.ClientSecret, - Scope: strings.Join(apiScope, " "), - AuthURL: config.AuthURL, - TokenURL: config.TokenURL, - }, nil -} - -// Issue contains information about an issue. -type Issue struct { - Id int `json:"id"` - Project string `json:"projectId"` - Title string `json:"title"` - Labels []string `json:"labels"` -} - -// URL returns the URL of a given issue. -func (i Issue) URL() string { - return issueURL + strconv.Itoa(i.Id) -} - -// IssueList represents a list of issues from the IssueTracker. -type IssueList struct { - TotalResults int `json:"totalResults"` - Items []*Issue `json:"items"` -} - -// IssueTracker is the primary point of contact with the issue tracker, -// providing methods for authenticating to and interacting with it. -type IssueTracker struct { - OAuthConfig *oauth.Config - OAuthTransport *oauth.Transport -} - -// MakeIssueTracker creates and returns an IssueTracker with authentication -// configuration from the given authConfigFile. -func MakeIssueTracker(authConfigFile string, redirectURL string) (*IssueTracker, error) { - oauthConfig, err := loadOAuthConfig(authConfigFile) - if err != nil { - return nil, fmt.Errorf( - "failed to create IssueTracker: %s", err) - } - oauthConfig.RedirectURL = redirectURL - return &IssueTracker{ - OAuthConfig: oauthConfig, - OAuthTransport: &oauth.Transport{Config: oauthConfig}, - }, nil -} - -// MakeAuthRequestURL returns an authentication request URL which can be used -// to obtain an authorization code via user sign-in. -func (it IssueTracker) MakeAuthRequestURL() string { - // NOTE: Need to add XSRF protection if we ever want to run this on a public - // server. - return it.OAuthConfig.AuthCodeURL(it.OAuthConfig.RedirectURL) -} - -// IsAuthenticated determines whether the IssueTracker has sufficient -// permissions to retrieve and edit Issues. -func (it IssueTracker) IsAuthenticated() bool { - return it.OAuthTransport.Token != nil -} - -// UpgradeCode exchanges the single-use authorization code, obtained by -// following the URL obtained from IssueTracker.MakeAuthRequestURL, for a -// multi-use, session token. This is required before IssueTracker can retrieve -// and edit issues. -func (it *IssueTracker) UpgradeCode(code string) error { - token, err := it.OAuthTransport.Exchange(code) - if err == nil { - it.OAuthTransport.Token = token - return nil - } else { - return fmt.Errorf( - "failed to exchange single-user auth code: %s", err) - } -} - -// GetLoggedInUser retrieves the email address of the authenticated user. -func (it IssueTracker) GetLoggedInUser() (string, error) { - errFmt := "error retrieving user email: %s" - if !it.IsAuthenticated() { - return "", fmt.Errorf(errFmt, "User is not authenticated!") - } - resp, err := it.OAuthTransport.Client().Get(personApiURL) - if err != nil { - return "", fmt.Errorf(errFmt, err) - } - defer resp.Body.Close() - body, _ := ioutil.ReadAll(resp.Body) - if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf(errFmt, fmt.Sprintf( - "user data API returned code %d: %v", resp.StatusCode, string(body))) - } - userInfo := struct { - Email string `json:"email"` - }{} - if err := json.Unmarshal(body, &userInfo); err != nil { - return "", fmt.Errorf(errFmt, err) - } - return userInfo.Email, nil -} - -// GetBug retrieves the Issue with the given ID from the IssueTracker. -func (it IssueTracker) GetBug(project string, id int) (*Issue, error) { - errFmt := fmt.Sprintf("error retrieving issue %d: %s", id, "%s") - if !it.IsAuthenticated() { - return nil, fmt.Errorf(errFmt, "user is not authenticated!") - } - requestURL := issueApiURL + project + "/issues/" + strconv.Itoa(id) - resp, err := it.OAuthTransport.Client().Get(requestURL) - if err != nil { - return nil, fmt.Errorf(errFmt, err) - } - defer resp.Body.Close() - body, _ := ioutil.ReadAll(resp.Body) - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(errFmt, fmt.Sprintf( - "issue tracker returned code %d:%v", resp.StatusCode, string(body))) - } - var issue Issue - if err := json.Unmarshal(body, &issue); err != nil { - return nil, fmt.Errorf(errFmt, err) - } - return &issue, nil -} - -// GetBugs retrieves all Issues with the given owner from the IssueTracker, -// returning an IssueList. -func (it IssueTracker) GetBugs(project string, owner string) (*IssueList, error) { - errFmt := "error retrieving issues: %s" - if !it.IsAuthenticated() { - return nil, fmt.Errorf(errFmt, "user is not authenticated!") - } - params := map[string]string{ - "owner": url.QueryEscape(owner), - "can": "open", - "maxResults": "9999", - } - requestURL := issueApiURL + project + "/issues?" - first := true - for k, v := range params { - if first { - first = false - } else { - requestURL += "&" - } - requestURL += k + "=" + v - } - resp, err := it.OAuthTransport.Client().Get(requestURL) - if err != nil { - return nil, fmt.Errorf(errFmt, err) - } - defer resp.Body.Close() - body, _ := ioutil.ReadAll(resp.Body) - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(errFmt, fmt.Sprintf( - "issue tracker returned code %d:%v", resp.StatusCode, string(body))) - } - - var bugList IssueList - if err := json.Unmarshal(body, &bugList); err != nil { - return nil, fmt.Errorf(errFmt, err) - } - return &bugList, nil -} - -// SubmitIssueChanges creates a comment on the given Issue which modifies it -// according to the contents of the passed-in Issue struct. -func (it IssueTracker) SubmitIssueChanges(issue *Issue, comment string) error { - errFmt := "Error updating issue " + strconv.Itoa(issue.Id) + ": %s" - if !it.IsAuthenticated() { - return fmt.Errorf(errFmt, "user is not authenticated!") - } - oldIssue, err := it.GetBug(issue.Project, issue.Id) - if err != nil { - return fmt.Errorf(errFmt, err) - } - postData := struct { - Content string `json:"content"` - Updates struct { - Title *string `json:"summary"` - Labels []string `json:"labels"` - } `json:"updates"` - }{ - Content: comment, - } - if issue.Title != oldIssue.Title { - postData.Updates.Title = &issue.Title - } - // TODO(borenet): Add other issue attributes, eg. Owner. - labels := make(map[string]int) - for _, label := range issue.Labels { - labels[label] = labelAdded - } - for _, label := range oldIssue.Labels { - if _, ok := labels[label]; ok { - labels[label] = labelUnchanged - } else { - labels[label] = labelRemoved - } - } - labelChanges := make([]string, 0) - for labelName, present := range labels { - if present == labelRemoved { - labelChanges = append(labelChanges, "-"+labelName) - } else if present == labelAdded { - labelChanges = append(labelChanges, labelName) - } - } - if len(labelChanges) > 0 { - postData.Updates.Labels = labelChanges - } - - postBytes, err := json.Marshal(&postData) - if err != nil { - return fmt.Errorf(errFmt, err) - } - requestURL := issueApiURL + issue.Project + "/issues/" + - strconv.Itoa(issue.Id) + "/comments" - resp, err := it.OAuthTransport.Client().Post( - requestURL, "application/json", bytes.NewReader(postBytes)) - if err != nil { - return fmt.Errorf(errFmt, err) - } - defer resp.Body.Close() - body, _ := ioutil.ReadAll(resp.Body) - if resp.StatusCode != http.StatusOK { - return fmt.Errorf(errFmt, fmt.Sprintf( - "Issue tracker returned code %d:%v", resp.StatusCode, string(body))) - } - return nil -} diff --git a/tools/bug_chomper/src/server/server.go b/tools/bug_chomper/src/server/server.go deleted file mode 100644 index 7fdae93c7b..0000000000 --- a/tools/bug_chomper/src/server/server.go +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright (c) 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/* - Serves a webpage for easy management of Skia bugs. - - WARNING: This server is NOT secure and should not be made publicly - accessible. -*/ - -package main - -import ( - "encoding/json" - "flag" - "fmt" - "html/template" - "issue_tracker" - "log" - "net/http" - "net/url" - "os" - "path/filepath" - "runtime" - "strconv" - "strings" - "time" -) - -import "github.com/gorilla/securecookie" - -const ( - certFile = "certs/cert.pem" - keyFile = "certs/key.pem" - issueComment = "Edited by BugChomper" - oauthCallbackPath = "/oauth2callback" - oauthConfigFile = "oauth_client_secret.json" - localHost = "127.0.0.1" - maxSessionLen = time.Duration(3600 * time.Second) - priorityPrefix = "Priority-" - project = "skia" - cookieName = "BugChomperCookie" -) - -// Flags: -var ( - port = flag.String("port", ":8000", "HTTP service address (e.g., ':8000')") - public = flag.Bool("public", false, "Make this server publicly accessible.") -) - -var ( - // templates is the list of html templates used by bug_chomper. - templates *template.Template = nil - - scheme = "http" - hashKey = securecookie.GenerateRandomKey(32) - blockKey = securecookie.GenerateRandomKey(32) - secureCookie = securecookie.New(hashKey, blockKey) -) - -func init() { - // Change the current working directory to two directories up from this - // source file so that we can read templates. - _, filename, _, _ := runtime.Caller(0) - cwd := filepath.Join(filepath.Dir(filename), "../..") - if err := os.Chdir(cwd); err != nil { - log.Fatal(err) - } - - templates = template.Must(template.ParseFiles( - filepath.Join(cwd, "templates/bug_chomper.html"), - filepath.Join(cwd, "templates/submitted.html"), - filepath.Join(cwd, "templates/error.html"), - )) -} - -// SessionState contains data for a given session. -type SessionState struct { - IssueTracker *issue_tracker.IssueTracker - OrigRequestURL string - SessionStart time.Time -} - -// getAbsoluteURL returns the absolute URL of the given Request. -func getAbsoluteURL(r *http.Request) string { - return scheme + "://" + r.Host + r.URL.Path -} - -// getOAuth2CallbackURL returns a callback URL to be used by the OAuth2 login -// page. -func getOAuth2CallbackURL(r *http.Request) string { - return scheme + "://" + r.Host + oauthCallbackPath -} - -func saveSession(session *SessionState, w http.ResponseWriter, r *http.Request) error { - encodedSession, err := secureCookie.Encode(cookieName, session) - if err != nil { - return fmt.Errorf("unable to encode session state: %s", err) - } - cookie := &http.Cookie{ - Name: cookieName, - Value: encodedSession, - Domain: strings.Split(r.Host, ":")[0], - Path: "/", - HttpOnly: true, - } - http.SetCookie(w, cookie) - return nil -} - -// makeSession creates a new session for the Request. -func makeSession(w http.ResponseWriter, r *http.Request) (*SessionState, error) { - log.Println("Creating new session.") - // Create the session state. - issueTracker, err := issue_tracker.MakeIssueTracker( - oauthConfigFile, getOAuth2CallbackURL(r)) - if err != nil { - return nil, fmt.Errorf("unable to create IssueTracker for session: %s", err) - } - session := SessionState{ - IssueTracker: issueTracker, - OrigRequestURL: getAbsoluteURL(r), - SessionStart: time.Now(), - } - - // Encode and store the session state. - if err := saveSession(&session, w, r); err != nil { - return nil, err - } - - return &session, nil -} - -// getSession retrieves the active SessionState or creates and returns a new -// SessionState. -func getSession(w http.ResponseWriter, r *http.Request) (*SessionState, error) { - cookie, err := r.Cookie(cookieName) - if err != nil { - log.Println("No cookie found! Starting new session.") - return makeSession(w, r) - } - var session SessionState - if err := secureCookie.Decode(cookieName, cookie.Value, &session); err != nil { - log.Printf("Invalid or corrupted session. Starting another: %s", err.Error()) - return makeSession(w, r) - } - - currentTime := time.Now() - if currentTime.Sub(session.SessionStart) > maxSessionLen { - log.Printf("Session starting at %s is expired. Starting another.", - session.SessionStart.Format(time.RFC822)) - return makeSession(w, r) - } - saveSession(&session, w, r) - return &session, nil -} - -// reportError serves the error page with the given message. -func reportError(w http.ResponseWriter, msg string, code int) { - errData := struct { - Code int - CodeString string - Message string - }{ - Code: code, - CodeString: http.StatusText(code), - Message: msg, - } - w.WriteHeader(code) - err := templates.ExecuteTemplate(w, "error.html", errData) - if err != nil { - log.Println("Failed to display error.html!!") - } -} - -// makeBugChomperPage builds and serves the BugChomper page. -func makeBugChomperPage(w http.ResponseWriter, r *http.Request) { - session, err := getSession(w, r) - if err != nil { - reportError(w, err.Error(), http.StatusInternalServerError) - return - } - issueTracker := session.IssueTracker - user, err := issueTracker.GetLoggedInUser() - if err != nil { - reportError(w, err.Error(), http.StatusInternalServerError) - return - } - log.Println("Loading bugs for " + user) - bugList, err := issueTracker.GetBugs(project, user) - if err != nil { - reportError(w, err.Error(), http.StatusInternalServerError) - return - } - bugsById := make(map[string]*issue_tracker.Issue) - bugsByPriority := make(map[string][]*issue_tracker.Issue) - for _, bug := range bugList.Items { - bugsById[strconv.Itoa(bug.Id)] = bug - var bugPriority string - for _, label := range bug.Labels { - if strings.HasPrefix(label, priorityPrefix) { - bugPriority = label[len(priorityPrefix):] - } - } - if _, ok := bugsByPriority[bugPriority]; !ok { - bugsByPriority[bugPriority] = make( - []*issue_tracker.Issue, 0) - } - bugsByPriority[bugPriority] = append( - bugsByPriority[bugPriority], bug) - } - bugsJson, err := json.Marshal(bugsById) - if err != nil { - reportError(w, err.Error(), http.StatusInternalServerError) - return - } - data := struct { - Title string - User string - BugsJson template.JS - BugsByPriority *map[string][]*issue_tracker.Issue - Priorities []string - PriorityPrefix string - }{ - Title: "BugChomper", - User: user, - BugsJson: template.JS(string(bugsJson)), - BugsByPriority: &bugsByPriority, - Priorities: issue_tracker.BugPriorities, - PriorityPrefix: priorityPrefix, - } - - if err := templates.ExecuteTemplate(w, "bug_chomper.html", data); err != nil { - reportError(w, err.Error(), http.StatusInternalServerError) - return - } -} - -// authIfNeeded determines whether the current user is logged in. If not, it -// redirects to a login page. Returns true if the user is redirected and false -// otherwise. -func authIfNeeded(w http.ResponseWriter, r *http.Request) bool { - session, err := getSession(w, r) - if err != nil { - reportError(w, err.Error(), http.StatusInternalServerError) - return false - } - issueTracker := session.IssueTracker - if !issueTracker.IsAuthenticated() { - loginURL := issueTracker.MakeAuthRequestURL() - log.Println("Redirecting for login:", loginURL) - http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect) - return true - } - return false -} - -// submitData attempts to submit data from a POST request to the IssueTracker. -func submitData(w http.ResponseWriter, r *http.Request) { - session, err := getSession(w, r) - if err != nil { - reportError(w, err.Error(), http.StatusInternalServerError) - return - } - issueTracker := session.IssueTracker - edits := r.FormValue("all_edits") - var editsMap map[string]*issue_tracker.Issue - if err := json.Unmarshal([]byte(edits), &editsMap); err != nil { - errMsg := "Could not parse edits from form response: " + err.Error() - reportError(w, errMsg, http.StatusInternalServerError) - return - } - data := struct { - Title string - Message string - BackLink string - }{} - if len(editsMap) == 0 { - data.Title = "No Changes Submitted" - data.Message = "You didn't change anything!" - data.BackLink = "" - if err := templates.ExecuteTemplate(w, "submitted.html", data); err != nil { - reportError(w, err.Error(), http.StatusInternalServerError) - return - } - return - } - errorList := make([]error, 0) - for issueId, newIssue := range editsMap { - log.Println("Editing issue " + issueId) - if err := issueTracker.SubmitIssueChanges(newIssue, issueComment); err != nil { - errorList = append(errorList, err) - } - } - if len(errorList) > 0 { - errorStrings := "" - for _, err := range errorList { - errorStrings += err.Error() + "\n" - } - errMsg := "Not all changes could be submitted: \n" + errorStrings - reportError(w, errMsg, http.StatusInternalServerError) - return - } - data.Title = "Submitted Changes" - data.Message = "Your changes were submitted to the issue tracker." - data.BackLink = "" - if err := templates.ExecuteTemplate(w, "submitted.html", data); err != nil { - reportError(w, err.Error(), http.StatusInternalServerError) - return - } - return -} - -// handleBugChomper handles HTTP requests for the bug_chomper page. -func handleBugChomper(w http.ResponseWriter, r *http.Request) { - if authIfNeeded(w, r) { - return - } - switch r.Method { - case "GET": - makeBugChomperPage(w, r) - case "POST": - submitData(w, r) - } -} - -// handleOAuth2Callback handles callbacks from the OAuth2 sign-in. -func handleOAuth2Callback(w http.ResponseWriter, r *http.Request) { - session, err := getSession(w, r) - if err != nil { - reportError(w, err.Error(), http.StatusInternalServerError) - } - issueTracker := session.IssueTracker - invalidLogin := "Invalid login credentials" - params, err := url.ParseQuery(r.URL.RawQuery) - if err != nil { - reportError(w, invalidLogin+": "+err.Error(), http.StatusForbidden) - return - } - code, ok := params["code"] - if !ok { - reportError(w, invalidLogin+": redirect did not include auth code.", - http.StatusForbidden) - return - } - log.Println("Upgrading auth token:", code[0]) - if err := issueTracker.UpgradeCode(code[0]); err != nil { - errMsg := "failed to upgrade token: " + err.Error() - reportError(w, errMsg, http.StatusForbidden) - return - } - if err := saveSession(session, w, r); err != nil { - reportError(w, "failed to save session: "+err.Error(), - http.StatusInternalServerError) - return - } - http.Redirect(w, r, session.OrigRequestURL, http.StatusTemporaryRedirect) - return -} - -// handleRoot is the handler function for all HTTP requests at the root level. -func handleRoot(w http.ResponseWriter, r *http.Request) { - log.Println("Fetching " + r.URL.Path) - if r.URL.Path == "/" || r.URL.Path == "/index.html" { - handleBugChomper(w, r) - return - } - http.NotFound(w, r) -} - -// Run the BugChomper server. -func main() { - flag.Parse() - - http.HandleFunc("/", handleRoot) - http.HandleFunc(oauthCallbackPath, handleOAuth2Callback) - http.Handle("/res/", http.FileServer(http.Dir("./"))) - log.Println("Server is running at " + scheme + "://" + localHost + *port) - var err error - if *public { - log.Println("WARNING: This server is not secure and should not be made " + - "publicly accessible.") - scheme = "https" - err = http.ListenAndServeTLS(*port, certFile, keyFile, nil) - } else { - scheme = "http" - err = http.ListenAndServe(localHost+*port, nil) - } - if err != nil { - log.Println(err.Error()) - } -} diff --git a/tools/bug_chomper/templates/bug_chomper.html b/tools/bug_chomper/templates/bug_chomper.html deleted file mode 100644 index df08570b86..0000000000 --- a/tools/bug_chomper/templates/bug_chomper.html +++ /dev/null @@ -1,118 +0,0 @@ -<html> -<head> -<title>{{.Title}}</title> -<link rel="stylesheet" type="text/css" href="res/style.css" /> -<link rel="icon" type="image/ico" href="res/favicon.ico" /> -<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script> -<script type="text/javascript" src="res/third_party/jquery.tablednd.js"></script> -<script type="text/javascript"> -"use strict"; - -var issues = {{.BugsJson}}; -var edited = {}; - -function edit_label(bug_id, old_value, new_value) { - console.log("issue[" + bug_id + "]: " + old_value + " -> " + new_value); - if (!edited[bug_id]) { - edited[bug_id] = JSON.parse(JSON.stringify(issues[bug_id])); - } - var old_index = edited[bug_id]["labels"].indexOf(old_value); - if (old_index > -1) { - edited[bug_id]["labels"][old_index] = new_value; - } else { - edited[bug_id]["labels"].push(new_value) - } - if (JSON.stringify(issues[bug_id]) == JSON.stringify(edited[bug_id])) { - console.log("Not changing " + bug_id); - delete edited[bug_id] - } - document.getElementById("all_edits").value = JSON.stringify(edited); -} - -</script> -</head> -<body> -<h1>BugChomper</h1> - -<form method="post"> -<input type="hidden" name="all_edits" id="all_edits" value="{}" /> -<input type="submit" value="Submit changes to issue tracker" /> -</form> -<table id="buglist"> - <thead> - <tr id="table_header" class="nodrag tr_head"> - <td colspan=3><h2>Open bugs for {{.User}}</h2></td> - </tr> - <tr id="table_subheader" class="nodrag tr_head"> - <td>ID</td> - <td>Priority</td> - <td>Title</td> - </tr> - </thead> - <tbody> - {{with $all_data := .}} - {{range $index, $priority := index $all_data.Priorities}} - <tr id="priority_{{$priority}}" - class="{{if eq $index 0}}nodrop{{else}}{{end}} nodrag priority_row priority_{{$priority}}" - > - <td colspan=3 class="priority_td">Priority {{$priority}}</td> - </tr> - {{range $index, $bug := index $all_data.BugsByPriority $priority}} - <tr id="{{$bug.Id}}" class="priority_{{$priority}}"> - <td id="id_{{$bug.Id}}"> - <a href="{{$bug.URL}}" target="_blank">{{$bug.Id}}</a> - </td> - <td id="priority_{{$bug.Id}}">{{$priority}}</td> - <td id="title_{{$bug.Id}}">{{$bug.Title}}</td> - </tr> - {{end}} - {{end}} - {{end}} - </tbody> -</table> - -<script type="text/javascript"> -$(document).ready(function() { - $("#buglist").tableDnD({ - onDrop: function(table, dropped_row) { - var id = dropped_row.id; - var css_priority_prefix = "priority_" - var new_priority = null; - var dropped_index = null; - var thead_rows = table.tHead.rows; - var tbody_rows = table.tBodies[0].rows; - var all_rows = []; - for (var i = 0; i < thead_rows.length; i++) { - all_rows.push(thead_rows[i]); - } - for (var i = 0; i < tbody_rows.length; i++) { - all_rows.push(tbody_rows[i]); - } - for (var i = 0; i < all_rows.length; i++) { - if (all_rows[i].id) { - if (all_rows[i].id.indexOf(css_priority_prefix) == 0) { - new_priority = all_rows[i].id.substring(css_priority_prefix.length); - } - if (all_rows[i].id == id) { - break; - } - } else { - console.warn("No id for:"); - console.warn(all_rows[i]); - } - } - if (new_priority) { - priority_td = document.getElementById(css_priority_prefix + id); - old_priority = priority_td.innerHTML; - if (priority_td && new_priority != old_priority) { - priority_td.innerHTML = new_priority; - document.getElementById(id).className = css_priority_prefix + new_priority; - edit_label(id, "{{.PriorityPrefix}}" + old_priority, "{{.PriorityPrefix}}" + new_priority); - } - } - } - }); -}); -</script> -</body> -</html> diff --git a/tools/bug_chomper/templates/error.html b/tools/bug_chomper/templates/error.html deleted file mode 100644 index 1e8fcda491..0000000000 --- a/tools/bug_chomper/templates/error.html +++ /dev/null @@ -1,12 +0,0 @@ -<html> -<head> -<title>Error {{.Code}}: {{.CodeString}}</title> -<link rel="stylesheet" type="text/css" href="res/style.css" /> -<link rel="icon" type="image/ico" href="res/favicon.ico" /> -</head> -<body> -<h1>Error {{.Code}}: {{.CodeString}}</h1> -{{.Message}} -<br/> -</body> -</html> diff --git a/tools/bug_chomper/templates/submitted.html b/tools/bug_chomper/templates/submitted.html deleted file mode 100644 index 2b09c238a8..0000000000 --- a/tools/bug_chomper/templates/submitted.html +++ /dev/null @@ -1,13 +0,0 @@ -<html> -<head> -<title>{{.Title}}</title> -<link rel="stylesheet" type="text/css" href="res/style.css" /> -<link rel="icon" type="image/ico" href="res/favicon.ico" /> -</head> -<body> -<h1>{{.Title}}</h1> -{{.Message}} -<br/> -<a href="{{.BackLink}}">Go back</a> -</body> -</html> |