aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar borenet <borenet@google.com>2014-11-17 09:59:53 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-11-17 09:59:53 -0800
commit0f881c64a32a4a1ed12794ea853848d453ff4d61 (patch)
tree7964a9c2e9e91d407790671847f1b30469daf173
parent84c8e62fad59f0e19b40ac718467f5b7884b431d (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.icobin318 -> 0 bytes
-rw-r--r--tools/bug_chomper/res/style.css72
-rw-r--r--tools/bug_chomper/res/third_party/jquery.tablednd.js314
-rwxr-xr-xtools/bug_chomper/run_server.sh22
-rw-r--r--tools/bug_chomper/src/issue_tracker/issue_tracker.go304
-rw-r--r--tools/bug_chomper/src/server/server.go393
-rw-r--r--tools/bug_chomper/templates/bug_chomper.html118
-rw-r--r--tools/bug_chomper/templates/error.html12
-rw-r--r--tools/bug_chomper/templates/submitted.html13
9 files changed, 0 insertions, 1248 deletions
diff --git a/tools/bug_chomper/res/favicon.ico b/tools/bug_chomper/res/favicon.ico
deleted file mode 100644
index e7440c7512..0000000000
--- a/tools/bug_chomper/res/favicon.ico
+++ /dev/null
Binary files differ
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>