fetch repo from github
This commit is contained in:
parent
0a355c690d
commit
6fdd258b09
|
@ -34,6 +34,8 @@ module.exports = (grunt) ->
|
||||||
'vendor/firebase/firebase.js'
|
'vendor/firebase/firebase.js'
|
||||||
'vendor/firebase-simple-login/firebase-simple-login.js'
|
'vendor/firebase-simple-login/firebase-simple-login.js'
|
||||||
'vendor/grapnel/src/grapnel.js'
|
'vendor/grapnel/src/grapnel.js'
|
||||||
|
'vendor/github/lib/base64.js'
|
||||||
|
'vendor/github/github.js'
|
||||||
# Our app.
|
# Our app.
|
||||||
'public/js/app.js'
|
'public/js/app.js'
|
||||||
]
|
]
|
||||||
|
|
19
README.md
19
README.md
|
@ -26,6 +26,20 @@ charcoal, charriot
|
||||||
[ ] rotate between percentage progress and points left
|
[ ] rotate between percentage progress and points left
|
||||||
[ ] Send notifications to people like Codeship or have our own delivery system perhaps like Github or just show a notification icon and onclick ask people to upgrade
|
[ ] Send notifications to people like Codeship or have our own delivery system perhaps like Github or just show a notification icon and onclick ask people to upgrade
|
||||||
|
|
||||||
|
### The 20%
|
||||||
|
|
||||||
|
[ ] Do not show login/logged-in state when we are still fetching that information from Firebase
|
||||||
|
[ ] Handle 404 on routes; from catch all check if '/' or go 404 controller
|
||||||
|
[ ] Variable document.title on different pages
|
||||||
|
[ ] In add a project form autocomplete on my username, orgs I am member of and repos I have access to
|
||||||
|
[ ] Someone might create a public repo, add it to the system and switch it to private; need to check repo priviledges at runtime; or when asking for auth, one would choose either public OR public/private, but this could get confusign.
|
||||||
|
[ ] Make sure the padding fits throughout the interface; we have user-select on elements.
|
||||||
|
[ ] Validate repo input and show a loading sign of sorts
|
||||||
|
[ ] When fetching repo say if no perms to access or does not exist
|
||||||
|
[ ] Check location.hash is supported
|
||||||
|
[ ] Have an app wide of triggering a URL and have named routes too
|
||||||
|
[ ] Check that we have not run out of requests to make
|
||||||
|
|
||||||
### Extras
|
### Extras
|
||||||
|
|
||||||
[ ] choose your own strategy for naming issues, e.g. all issues are one size
|
[ ] choose your own strategy for naming issues, e.g. all issues are one size
|
||||||
|
@ -44,11 +58,6 @@ charcoal, charriot
|
||||||
[ ] show velocity number for each member of the team in the corner of the layout
|
[ ] show velocity number for each member of the team in the corner of the layout
|
||||||
[ ] show velocity for all team members and how it progresses through time
|
[ ] show velocity for all team members and how it progresses through time
|
||||||
[ ] points collector - give medals for 1st 3 spots in terms of velocity
|
[ ] points collector - give medals for 1st 3 spots in terms of velocity
|
||||||
[ ] Do not show login/logged-in state when we are still fetching that information from Firebase
|
|
||||||
[ ] Handle 404 on routes; from catch all check if '/' or go 404 controller
|
|
||||||
[ ] Variable document.title on different pages
|
|
||||||
[ ] In add a project form autocomplete on my username, orgs I am member of and repos I have access to
|
|
||||||
[ ] Someone might create a public repo, add it to the system and switch it to private; need to check repo priviledges at runtime; or when asking for auth, one would choose either public OR public/private, but this could get confusign.
|
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
"ractive-adaptor": "radekstepan/ractive-adaptor-ractive",
|
"ractive-adaptor": "radekstepan/ractive-adaptor-ractive",
|
||||||
"firebase": "~1.0.21",
|
"firebase": "~1.0.21",
|
||||||
"firebase-simple-login": "~1.6.3",
|
"firebase-simple-login": "~1.6.3",
|
||||||
"grapnel": "~0.4.2"
|
"grapnel": "~0.4.2",
|
||||||
|
"github": "~0.9.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21477,6 +21477,848 @@ goog.exportProperty(FirebaseSimpleLogin,"onOpen",FirebaseSimpleLogin.onOpen);Fir
|
||||||
}
|
}
|
||||||
|
|
||||||
}).call({}, window);
|
}).call({}, window);
|
||||||
|
;// This code was written by Tyler Akins and has been placed in the
|
||||||
|
// public domain. It would be nice if you left this header intact.
|
||||||
|
// Base64 code from Tyler Akins -- http://rumkin.com
|
||||||
|
|
||||||
|
var Base64 = (function () {
|
||||||
|
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||||
|
|
||||||
|
var obj = {
|
||||||
|
/**
|
||||||
|
* Encodes a string in base64
|
||||||
|
* @param {String} input The string to encode in base64.
|
||||||
|
*/
|
||||||
|
encode: function (input) {
|
||||||
|
var output = "";
|
||||||
|
var chr1, chr2, chr3;
|
||||||
|
var enc1, enc2, enc3, enc4;
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
chr1 = input.charCodeAt(i++);
|
||||||
|
chr2 = input.charCodeAt(i++);
|
||||||
|
chr3 = input.charCodeAt(i++);
|
||||||
|
|
||||||
|
enc1 = chr1 >> 2;
|
||||||
|
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||||||
|
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||||||
|
enc4 = chr3 & 63;
|
||||||
|
|
||||||
|
if (isNaN(chr2)) {
|
||||||
|
enc3 = enc4 = 64;
|
||||||
|
} else if (isNaN(chr3)) {
|
||||||
|
enc4 = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
|
||||||
|
keyStr.charAt(enc3) + keyStr.charAt(enc4);
|
||||||
|
} while (i < input.length);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a base64 string.
|
||||||
|
* @param {String} input The string to decode.
|
||||||
|
*/
|
||||||
|
decode: function (input) {
|
||||||
|
var output = "";
|
||||||
|
var chr1, chr2, chr3;
|
||||||
|
var enc1, enc2, enc3, enc4;
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
|
||||||
|
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
||||||
|
|
||||||
|
do {
|
||||||
|
enc1 = keyStr.indexOf(input.charAt(i++));
|
||||||
|
enc2 = keyStr.indexOf(input.charAt(i++));
|
||||||
|
enc3 = keyStr.indexOf(input.charAt(i++));
|
||||||
|
enc4 = keyStr.indexOf(input.charAt(i++));
|
||||||
|
|
||||||
|
chr1 = (enc1 << 2) | (enc2 >> 4);
|
||||||
|
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
||||||
|
chr3 = ((enc3 & 3) << 6) | enc4;
|
||||||
|
|
||||||
|
output = output + String.fromCharCode(chr1);
|
||||||
|
|
||||||
|
if (enc3 != 64) {
|
||||||
|
output = output + String.fromCharCode(chr2);
|
||||||
|
}
|
||||||
|
if (enc4 != 64) {
|
||||||
|
output = output + String.fromCharCode(chr3);
|
||||||
|
}
|
||||||
|
} while (i < input.length);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
})();
|
||||||
|
if (typeof exports !== 'undefined') {
|
||||||
|
// Github = exports;
|
||||||
|
module.exports = Base64;
|
||||||
|
} else {
|
||||||
|
window.Base64 = Base64;
|
||||||
|
}
|
||||||
|
|
||||||
|
;// Github.js 0.9.0
|
||||||
|
// (c) 2013 Michael Aufreiter, Development Seed
|
||||||
|
// Github.js is freely distributable under the MIT license.
|
||||||
|
// For all details and documentation:
|
||||||
|
// http://substance.io/michael/github
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
// Initial Setup
|
||||||
|
// -------------
|
||||||
|
|
||||||
|
var XMLHttpRequest, Base64, _;
|
||||||
|
if (typeof exports !== 'undefined') {
|
||||||
|
XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
|
||||||
|
_ = require('underscore');
|
||||||
|
Base64 = require('./lib/base64.js');
|
||||||
|
}else{
|
||||||
|
_ = window._;
|
||||||
|
Base64 = window.Base64;
|
||||||
|
}
|
||||||
|
//prefer native XMLHttpRequest always
|
||||||
|
if (typeof window !== 'undefined' && typeof window.XMLHttpRequest !== 'undefined'){
|
||||||
|
XMLHttpRequest = window.XMLHttpRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var API_URL = 'https://api.github.com';
|
||||||
|
|
||||||
|
var Github = function(options) {
|
||||||
|
|
||||||
|
// HTTP Request Abstraction
|
||||||
|
// =======
|
||||||
|
//
|
||||||
|
// I'm not proud of this and neither should you be if you were responsible for the XMLHttpRequest spec.
|
||||||
|
|
||||||
|
function _request(method, path, data, cb, raw, sync) {
|
||||||
|
function getURL() {
|
||||||
|
var url = path.indexOf('//') >= 0 ? path : API_URL + path;
|
||||||
|
return url + ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
if (!raw) {xhr.dataType = "json";}
|
||||||
|
|
||||||
|
xhr.open(method, getURL(), !sync);
|
||||||
|
if (!sync) {
|
||||||
|
xhr.onreadystatechange = function () {
|
||||||
|
if (this.readyState == 4) {
|
||||||
|
if (this.status >= 200 && this.status < 300 || this.status === 304) {
|
||||||
|
cb(null, raw ? this.responseText : this.responseText ? JSON.parse(this.responseText) : true, this);
|
||||||
|
} else {
|
||||||
|
cb({path: path, request: this, error: this.status});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.setRequestHeader('Accept','application/vnd.github.raw+json');
|
||||||
|
xhr.setRequestHeader('Content-Type','application/json;charset=UTF-8');
|
||||||
|
if ((options.token) || (options.username && options.password)) {
|
||||||
|
xhr.setRequestHeader('Authorization', options.token
|
||||||
|
? 'token '+ options.token
|
||||||
|
: 'Basic ' + Base64.encode(options.username + ':' + options.password)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
data ? xhr.send(JSON.stringify(data)) : xhr.send();
|
||||||
|
if (sync) return xhr.response;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _requestAllPages(path, cb) {
|
||||||
|
var results = [];
|
||||||
|
(function iterate() {
|
||||||
|
_request("GET", path, null, function(err, res, xhr) {
|
||||||
|
if (err) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
results.push.apply(results, res);
|
||||||
|
|
||||||
|
var links = (xhr.getResponseHeader('link') || '').split(/\s*,\s*/g),
|
||||||
|
next = _.find(links, function(link) { return /rel="next"/.test(link); });
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
next = (/<(.*)>/.exec(next) || [])[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!next) {
|
||||||
|
cb(err, results);
|
||||||
|
} else {
|
||||||
|
path = next;
|
||||||
|
iterate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// User API
|
||||||
|
// =======
|
||||||
|
|
||||||
|
Github.User = function() {
|
||||||
|
this.repos = function(cb) {
|
||||||
|
// Github does not always honor the 1000 limit so we want to iterate over the data set.
|
||||||
|
_requestAllPages("/user/repos?type=all&per_page=1000&sort=updated", function(err, res) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// List user organizations
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.orgs = function(cb) {
|
||||||
|
_request("GET", "/user/orgs", null, function(err, res) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// List authenticated user's gists
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.gists = function(cb) {
|
||||||
|
_request("GET", "/gists", null, function(err, res) {
|
||||||
|
cb(err,res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// List authenticated user's unread notifications
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.notifications = function(cb) {
|
||||||
|
_request("GET", "/notifications", null, function(err, res) {
|
||||||
|
cb(err,res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Show user information
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.show = function(username, cb) {
|
||||||
|
var command = username ? "/users/"+username : "/user";
|
||||||
|
|
||||||
|
_request("GET", command, null, function(err, res) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// List user repositories
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.userRepos = function(username, cb) {
|
||||||
|
// Github does not always honor the 1000 limit so we want to iterate over the data set.
|
||||||
|
_requestAllPages("/users/"+username+"/repos?type=all&per_page=1000&sort=updated", function(err, res) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// List a user's gists
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.userGists = function(username, cb) {
|
||||||
|
_request("GET", "/users/"+username+"/gists", null, function(err, res) {
|
||||||
|
cb(err,res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// List organization repositories
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.orgRepos = function(orgname, cb) {
|
||||||
|
// Github does not always honor the 1000 limit so we want to iterate over the data set.
|
||||||
|
_requestAllPages("/orgs/"+orgname+"/repos?type=all&&page_num=1000&sort=updated&direction=desc", function(err, res) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Follow user
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.follow = function(username, cb) {
|
||||||
|
_request("PUT", "/user/following/"+username, null, function(err, res) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Unfollow user
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.unfollow = function(username, cb) {
|
||||||
|
_request("DELETE", "/user/following/"+username, null, function(err, res) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Repository API
|
||||||
|
// =======
|
||||||
|
|
||||||
|
Github.Repository = function(options) {
|
||||||
|
var repo = options.name;
|
||||||
|
var user = options.user;
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
var repoPath = "/repos/" + user + "/" + repo;
|
||||||
|
|
||||||
|
var currentTree = {
|
||||||
|
"branch": null,
|
||||||
|
"sha": null
|
||||||
|
};
|
||||||
|
|
||||||
|
// Uses the cache if branch has not been changed
|
||||||
|
// -------
|
||||||
|
|
||||||
|
function updateTree(branch, cb) {
|
||||||
|
if (branch === currentTree.branch && currentTree.sha) return cb(null, currentTree.sha);
|
||||||
|
that.getRef("heads/"+branch, function(err, sha) {
|
||||||
|
currentTree.branch = branch;
|
||||||
|
currentTree.sha = sha;
|
||||||
|
cb(err, sha);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a particular reference
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.getRef = function(ref, cb) {
|
||||||
|
_request("GET", repoPath + "/git/refs/" + ref, null, function(err, res) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, res.object.sha);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new reference
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "ref": "refs/heads/my-new-branch-name",
|
||||||
|
// "sha": "827efc6d56897b048c772eb4087f854f46256132"
|
||||||
|
// }
|
||||||
|
|
||||||
|
this.createRef = function(options, cb) {
|
||||||
|
_request("POST", repoPath + "/git/refs", options, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete a reference
|
||||||
|
// --------
|
||||||
|
//
|
||||||
|
// repo.deleteRef('heads/gh-pages')
|
||||||
|
// repo.deleteRef('tags/v1.0')
|
||||||
|
|
||||||
|
this.deleteRef = function(ref, cb) {
|
||||||
|
_request("DELETE", repoPath + "/git/refs/"+ref, options, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a repo
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.createRepo = function(options, cb) {
|
||||||
|
_request("POST", "/user/repos", options, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete a repo
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.deleteRepo = function(cb) {
|
||||||
|
_request("DELETE", repoPath, options, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// List all tags of a repository
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.listTags = function(cb) {
|
||||||
|
_request("GET", repoPath + "/tags", null, function(err, tags) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, tags);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// List all pull requests of a respository
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.listPulls = function(state, cb) {
|
||||||
|
_request("GET", repoPath + "/pulls" + (state ? '?state=' + state : ''), null, function(err, pulls) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, pulls);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gets details for a specific pull request
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.getPull = function(number, cb) {
|
||||||
|
_request("GET", repoPath + "/pulls/" + number, null, function(err, pull) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, pull);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve the changes made between base and head
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.compare = function(base, head, cb) {
|
||||||
|
_request("GET", repoPath + "/compare/" + base + "..." + head, null, function(err, diff) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, diff);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// List all branches of a repository
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.listBranches = function(cb) {
|
||||||
|
_request("GET", repoPath + "/git/refs/heads", null, function(err, heads) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, _.map(heads, function(head) { return _.last(head.ref.split('/')); }));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve the contents of a blob
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.getBlob = function(sha, cb) {
|
||||||
|
_request("GET", repoPath + "/git/blobs/" + sha, null, cb, 'raw');
|
||||||
|
};
|
||||||
|
|
||||||
|
// For a given file path, get the corresponding sha (blob for files, tree for dirs)
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.getSha = function(branch, path, cb) {
|
||||||
|
// Just use head if path is empty
|
||||||
|
if (path === "") return that.getRef("heads/"+branch, cb);
|
||||||
|
that.getTree(branch+"?recursive=true", function(err, tree) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
var file = _.select(tree, function(file) {
|
||||||
|
return file.path === path;
|
||||||
|
})[0];
|
||||||
|
cb(null, file ? file.sha : null);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve the tree a commit points to
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.getTree = function(tree, cb) {
|
||||||
|
_request("GET", repoPath + "/git/trees/"+tree, null, function(err, res) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, res.tree);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Post a new blob object, getting a blob SHA back
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.postBlob = function(content, cb) {
|
||||||
|
if (typeof(content) === "string") {
|
||||||
|
content = {
|
||||||
|
"content": content,
|
||||||
|
"encoding": "utf-8"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_request("POST", repoPath + "/git/blobs", content, function(err, res) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, res.sha);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update an existing tree adding a new blob object getting a tree SHA back
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.updateTree = function(baseTree, path, blob, cb) {
|
||||||
|
var data = {
|
||||||
|
"base_tree": baseTree,
|
||||||
|
"tree": [
|
||||||
|
{
|
||||||
|
"path": path,
|
||||||
|
"mode": "100644",
|
||||||
|
"type": "blob",
|
||||||
|
"sha": blob
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
_request("POST", repoPath + "/git/trees", data, function(err, res) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, res.sha);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Post a new tree object having a file path pointer replaced
|
||||||
|
// with a new blob SHA getting a tree SHA back
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.postTree = function(tree, cb) {
|
||||||
|
_request("POST", repoPath + "/git/trees", { "tree": tree }, function(err, res) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, res.sha);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new commit object with the current commit SHA as the parent
|
||||||
|
// and the new tree SHA, getting a commit SHA back
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.commit = function(parent, tree, message, cb) {
|
||||||
|
var data = {
|
||||||
|
"message": message,
|
||||||
|
"author": {
|
||||||
|
"name": options.username
|
||||||
|
},
|
||||||
|
"parents": [
|
||||||
|
parent
|
||||||
|
],
|
||||||
|
"tree": tree
|
||||||
|
};
|
||||||
|
|
||||||
|
_request("POST", repoPath + "/git/commits", data, function(err, res) {
|
||||||
|
currentTree.sha = res.sha; // update latest commit
|
||||||
|
if (err) return cb(err);
|
||||||
|
cb(null, res.sha);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update the reference of your head to point to the new commit SHA
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.updateHead = function(head, commit, cb) {
|
||||||
|
_request("PATCH", repoPath + "/git/refs/heads/" + head, { "sha": commit }, function(err, res) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Show repository information
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.show = function(cb) {
|
||||||
|
_request("GET", repoPath, null, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get contents
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.contents = function(branch, path, cb, sync) {
|
||||||
|
return _request("GET", repoPath + "/contents?ref=" + branch + (path ? "&path=" + path : ""), null, cb, 'raw', sync);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fork repository
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.fork = function(cb) {
|
||||||
|
_request("POST", repoPath + "/forks", null, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Branch repository
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.branch = function(oldBranch,newBranch,cb) {
|
||||||
|
if(arguments.length === 2 && typeof arguments[1] === "function") {
|
||||||
|
cb = newBranch;
|
||||||
|
newBranch = oldBranch;
|
||||||
|
oldBranch = "master";
|
||||||
|
}
|
||||||
|
this.getRef("heads/" + oldBranch, function(err,ref) {
|
||||||
|
if(err && cb) return cb(err);
|
||||||
|
that.createRef({
|
||||||
|
ref: "refs/heads/" + newBranch,
|
||||||
|
sha: ref
|
||||||
|
},cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create pull request
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.createPullRequest = function(options, cb) {
|
||||||
|
_request("POST", repoPath + "/pulls", options, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// List hooks
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.listHooks = function(cb) {
|
||||||
|
_request("GET", repoPath + "/hooks", null, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a hook
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.getHook = function(id, cb) {
|
||||||
|
_request("GET", repoPath + "/hooks/" + id, null, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a hook
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.createHook = function(options, cb) {
|
||||||
|
_request("POST", repoPath + "/hooks", options, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Edit a hook
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.editHook = function(id, options, cb) {
|
||||||
|
_request("PATCH", repoPath + "/hooks/" + id, options, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete a hook
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.deleteHook = function(id, cb) {
|
||||||
|
_request("DELETE", repoPath + "/hooks/" + id, null, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Read file at given path
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.read = function(branch, path, cb) {
|
||||||
|
that.getSha(branch, path, function(err, sha) {
|
||||||
|
if (!sha) return cb("not found", null);
|
||||||
|
that.getBlob(sha, function(err, content) {
|
||||||
|
cb(err, content, sha);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove a file from the tree
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.remove = function(branch, path, cb) {
|
||||||
|
updateTree(branch, function(err, latestCommit) {
|
||||||
|
that.getTree(latestCommit+"?recursive=true", function(err, tree) {
|
||||||
|
// Update Tree
|
||||||
|
var newTree = _.reject(tree, function(ref) { return ref.path === path; });
|
||||||
|
_.each(newTree, function(ref) {
|
||||||
|
if (ref.type === "tree") delete ref.sha;
|
||||||
|
});
|
||||||
|
|
||||||
|
that.postTree(newTree, function(err, rootTree) {
|
||||||
|
that.commit(latestCommit, rootTree, 'Deleted '+path , function(err, commit) {
|
||||||
|
that.updateHead(branch, commit, function(err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Move a file to a new location
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.move = function(branch, path, newPath, cb) {
|
||||||
|
updateTree(branch, function(err, latestCommit) {
|
||||||
|
that.getTree(latestCommit+"?recursive=true", function(err, tree) {
|
||||||
|
// Update Tree
|
||||||
|
_.each(tree, function(ref) {
|
||||||
|
if (ref.path === path) ref.path = newPath;
|
||||||
|
if (ref.type === "tree") delete ref.sha;
|
||||||
|
});
|
||||||
|
|
||||||
|
that.postTree(tree, function(err, rootTree) {
|
||||||
|
that.commit(latestCommit, rootTree, 'Deleted '+path , function(err, commit) {
|
||||||
|
that.updateHead(branch, commit, function(err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write file contents to a given branch and path
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.write = function(branch, path, content, message, cb) {
|
||||||
|
updateTree(branch, function(err, latestCommit) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
that.postBlob(content, function(err, blob) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
that.updateTree(latestCommit, path, blob, function(err, tree) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
that.commit(latestCommit, tree, message, function(err, commit) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
that.updateHead(branch, commit, cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// List commits on a repository. Takes an object of optional paramaters:
|
||||||
|
// sha: SHA or branch to start listing commits from
|
||||||
|
// path: Only commits containing this file path will be returned
|
||||||
|
// since: ISO 8601 date - only commits after this date will be returned
|
||||||
|
// until: ISO 8601 date - only commits before this date will be returned
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.getCommits = function(options, cb) {
|
||||||
|
options = options || {};
|
||||||
|
var url = repoPath + "/commits";
|
||||||
|
var params = [];
|
||||||
|
if (options.sha) {
|
||||||
|
params.push("sha=" + encodeURIComponent(options.sha));
|
||||||
|
}
|
||||||
|
if (options.path) {
|
||||||
|
params.push("path=" + encodeURIComponent(options.path));
|
||||||
|
}
|
||||||
|
if (options.since) {
|
||||||
|
var since = options.since;
|
||||||
|
if (since.constructor === Date) {
|
||||||
|
since = since.toISOString();
|
||||||
|
}
|
||||||
|
params.push("since=" + encodeURIComponent(since));
|
||||||
|
}
|
||||||
|
if (options.until) {
|
||||||
|
var until = options.until;
|
||||||
|
if (until.constructor === Date) {
|
||||||
|
until = until.toISOString();
|
||||||
|
}
|
||||||
|
params.push("until=" + encodeURIComponent(until));
|
||||||
|
}
|
||||||
|
if (params.length > 0) {
|
||||||
|
url += "?" + params.join("&");
|
||||||
|
}
|
||||||
|
_request("GET", url, null, cb);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gists API
|
||||||
|
// =======
|
||||||
|
|
||||||
|
Github.Gist = function(options) {
|
||||||
|
var id = options.id;
|
||||||
|
var gistPath = "/gists/"+id;
|
||||||
|
|
||||||
|
// Read the gist
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.read = function(cb) {
|
||||||
|
_request("GET", gistPath, null, function(err, gist) {
|
||||||
|
cb(err, gist);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the gist
|
||||||
|
// --------
|
||||||
|
// {
|
||||||
|
// "description": "the description for this gist",
|
||||||
|
// "public": true,
|
||||||
|
// "files": {
|
||||||
|
// "file1.txt": {
|
||||||
|
// "content": "String file contents"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
this.create = function(options, cb){
|
||||||
|
_request("POST","/gists", options, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete the gist
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.delete = function(cb) {
|
||||||
|
_request("DELETE", gistPath, null, function(err,res) {
|
||||||
|
cb(err,res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fork a gist
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.fork = function(cb) {
|
||||||
|
_request("POST", gistPath+"/fork", null, function(err,res) {
|
||||||
|
cb(err,res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update a gist with the new stuff
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.update = function(options, cb) {
|
||||||
|
_request("PATCH", gistPath, options, function(err,res) {
|
||||||
|
cb(err,res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Star a gist
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.star = function(cb) {
|
||||||
|
_request("PUT", gistPath+"/star", null, function(err,res) {
|
||||||
|
cb(err,res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Untar a gist
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.unstar = function(cb) {
|
||||||
|
_request("DELETE", gistPath+"/star", null, function(err,res) {
|
||||||
|
cb(err,res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if a gist is starred
|
||||||
|
// --------
|
||||||
|
|
||||||
|
this.isStarred = function(cb) {
|
||||||
|
_request("GET", gistPath+"/star", null, function(err,res) {
|
||||||
|
cb(err,res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Issues API
|
||||||
|
// ==========
|
||||||
|
|
||||||
|
Github.Issue = function(options) {
|
||||||
|
var path = "/repos/" + options.user + "/" + options.repo + "/issues";
|
||||||
|
|
||||||
|
this.list = function(options, cb) {
|
||||||
|
_request("GET", path, options, function(err, res) {
|
||||||
|
cb(err,res)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Top Level API
|
||||||
|
// -------
|
||||||
|
|
||||||
|
this.getIssues = function(user, repo) {
|
||||||
|
return new Github.Issue({user: user, repo: repo});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getRepo = function(user, repo) {
|
||||||
|
return new Github.Repository({user: user, name: repo});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getUser = function() {
|
||||||
|
return new Github.User();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getGist = function(id) {
|
||||||
|
return new Github.Gist({id: id});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof exports !== 'undefined') {
|
||||||
|
// Github = exports;
|
||||||
|
module.exports = Github;
|
||||||
|
} else {
|
||||||
|
window.Github = Github;
|
||||||
|
}
|
||||||
|
}).call(this);
|
||||||
;// Concat modules and export them as an app.
|
;// Concat modules and export them as an app.
|
||||||
(function(root) {
|
(function(root) {
|
||||||
|
|
||||||
|
@ -21525,7 +22367,7 @@ goog.exportProperty(FirebaseSimpleLogin,"onOpen",FirebaseSimpleLogin.onOpen);Fir
|
||||||
// addProjectForm.coffee
|
// addProjectForm.coffee
|
||||||
root.require.register('burnchart/src/components/addProjectForm.js', function(exports, require, module) {
|
root.require.register('burnchart/src/components/addProjectForm.js', function(exports, require, module) {
|
||||||
|
|
||||||
var firebase, mediator, user;
|
var firebase, github, mediator, user;
|
||||||
|
|
||||||
firebase = require('../modules/firebase');
|
firebase = require('../modules/firebase');
|
||||||
|
|
||||||
|
@ -21533,6 +22375,8 @@ goog.exportProperty(FirebaseSimpleLogin,"onOpen",FirebaseSimpleLogin.onOpen);Fir
|
||||||
|
|
||||||
mediator = require('../modules/mediator');
|
mediator = require('../modules/mediator');
|
||||||
|
|
||||||
|
github = require('../modules/github');
|
||||||
|
|
||||||
module.exports = Ractive.extend({
|
module.exports = Ractive.extend({
|
||||||
'template': require('../templates/addProjectForm'),
|
'template': require('../templates/addProjectForm'),
|
||||||
'data': {
|
'data': {
|
||||||
|
@ -21549,7 +22393,15 @@ goog.exportProperty(FirebaseSimpleLogin,"onOpen",FirebaseSimpleLogin.onOpen);Fir
|
||||||
'init': false
|
'init': false
|
||||||
});
|
});
|
||||||
return this.on('submit', function() {
|
return this.on('submit', function() {
|
||||||
return console.log('Submit the form with', this.get('value'));
|
var repo, reponame, username, _ref;
|
||||||
|
_ref = this.get('value').split('/'), username = _ref[0], reponame = _ref[1];
|
||||||
|
repo = github.getRepo(username, reponame);
|
||||||
|
return repo.show(function(err, repo, xhr) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
return window.location.hash = '#';
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -21644,6 +22496,30 @@ goog.exportProperty(FirebaseSimpleLogin,"onOpen",FirebaseSimpleLogin.onOpen);Fir
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// github.coffee
|
||||||
|
root.require.register('burnchart/src/modules/github.js', function(exports, require, module) {
|
||||||
|
|
||||||
|
var auth, github, setToken, user;
|
||||||
|
|
||||||
|
user = require('./user');
|
||||||
|
|
||||||
|
auth = 'oauth';
|
||||||
|
|
||||||
|
github = null;
|
||||||
|
|
||||||
|
(setToken = function(token) {
|
||||||
|
return github = new Github({
|
||||||
|
token: token,
|
||||||
|
auth: auth
|
||||||
|
});
|
||||||
|
})(null);
|
||||||
|
|
||||||
|
user.observe('accessToken', setToken);
|
||||||
|
|
||||||
|
module.exports = github;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
// mediator.coffee
|
// mediator.coffee
|
||||||
root.require.register('burnchart/src/modules/mediator.js', function(exports, require, module) {
|
root.require.register('burnchart/src/modules/mediator.js', function(exports, require, module) {
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
// addProjectForm.coffee
|
// addProjectForm.coffee
|
||||||
root.require.register('burnchart/src/components/addProjectForm.js', function(exports, require, module) {
|
root.require.register('burnchart/src/components/addProjectForm.js', function(exports, require, module) {
|
||||||
|
|
||||||
var firebase, mediator, user;
|
var firebase, github, mediator, user;
|
||||||
|
|
||||||
firebase = require('../modules/firebase');
|
firebase = require('../modules/firebase');
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@
|
||||||
|
|
||||||
mediator = require('../modules/mediator');
|
mediator = require('../modules/mediator');
|
||||||
|
|
||||||
|
github = require('../modules/github');
|
||||||
|
|
||||||
module.exports = Ractive.extend({
|
module.exports = Ractive.extend({
|
||||||
'template': require('../templates/addProjectForm'),
|
'template': require('../templates/addProjectForm'),
|
||||||
'data': {
|
'data': {
|
||||||
|
@ -70,7 +72,15 @@
|
||||||
'init': false
|
'init': false
|
||||||
});
|
});
|
||||||
return this.on('submit', function() {
|
return this.on('submit', function() {
|
||||||
return console.log('Submit the form with', this.get('value'));
|
var repo, reponame, username, _ref;
|
||||||
|
_ref = this.get('value').split('/'), username = _ref[0], reponame = _ref[1];
|
||||||
|
repo = github.getRepo(username, reponame);
|
||||||
|
return repo.show(function(err, repo, xhr) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
return window.location.hash = '#';
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -165,6 +175,30 @@
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// github.coffee
|
||||||
|
root.require.register('burnchart/src/modules/github.js', function(exports, require, module) {
|
||||||
|
|
||||||
|
var auth, github, setToken, user;
|
||||||
|
|
||||||
|
user = require('./user');
|
||||||
|
|
||||||
|
auth = 'oauth';
|
||||||
|
|
||||||
|
github = null;
|
||||||
|
|
||||||
|
(setToken = function(token) {
|
||||||
|
return github = new Github({
|
||||||
|
token: token,
|
||||||
|
auth: auth
|
||||||
|
});
|
||||||
|
})(null);
|
||||||
|
|
||||||
|
user.observe('accessToken', setToken);
|
||||||
|
|
||||||
|
module.exports = github;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
// mediator.coffee
|
// mediator.coffee
|
||||||
root.require.register('burnchart/src/modules/mediator.js', function(exports, require, module) {
|
root.require.register('burnchart/src/modules/mediator.js', function(exports, require, module) {
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
firebase = require '../modules/firebase'
|
firebase = require '../modules/firebase'
|
||||||
user = require '../modules/user'
|
user = require '../modules/user'
|
||||||
mediator = require '../modules/mediator'
|
mediator = require '../modules/mediator'
|
||||||
|
github = require '../modules/github'
|
||||||
|
|
||||||
module.exports = Ractive.extend
|
module.exports = Ractive.extend
|
||||||
|
|
||||||
|
@ -19,4 +20,11 @@ module.exports = Ractive.extend
|
||||||
@observe 'value', _.debounce(autocomplete, 200), { 'init': no }
|
@observe 'value', _.debounce(autocomplete, 200), { 'init': no }
|
||||||
|
|
||||||
@on 'submit', ->
|
@on 'submit', ->
|
||||||
console.log 'Submit the form with', @get('value')
|
[ username, reponame ] = @get('value').split('/')
|
||||||
|
repo = github.getRepo username, reponame
|
||||||
|
repo.show (err, repo, xhr) ->
|
||||||
|
throw err if err
|
||||||
|
# TODO: save repo to us & Firebase.
|
||||||
|
# Redirect to the dashboard.
|
||||||
|
# TODO: trigger a named route
|
||||||
|
window.location.hash = '#'
|
|
@ -0,0 +1,13 @@
|
||||||
|
user = require './user'
|
||||||
|
|
||||||
|
auth = 'oauth'
|
||||||
|
|
||||||
|
github = null
|
||||||
|
|
||||||
|
do setToken = (token=null) ->
|
||||||
|
github = new Github { token, auth }
|
||||||
|
|
||||||
|
# Set token when we have one (otherwise init to null).
|
||||||
|
user.observe 'accessToken', setToken
|
||||||
|
|
||||||
|
module.exports = github
|
Loading…
Reference in New Issue