diff --git a/lib/base64.js b/lib/base64.js new file mode 100644 index 0000000..e4299e4 --- /dev/null +++ b/lib/base64.js @@ -0,0 +1,5 @@ +// cThis 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 e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",t={encode:function(t){var n="",r,i,s,o,u,a,f,l=0;do r=t.charCodeAt(l++),i=t.charCodeAt(l++),s=t.charCodeAt(l++),o=r>>2,u=(r&3)<<4|i>>4,a=(i&15)<<2|s>>6,f=s&63,isNaN(i)?a=f=64:isNaN(s)&&(f=64),n=n+e.charAt(o)+e.charAt(u)+e.charAt(a)+e.charAt(f);while(l>4,i=(u&15)<<4|a>>2,s=(a&3)<<6|f,n+=String.fromCharCode(r),a!=64&&(n+=String.fromCharCode(i)),f!=64&&(n+=String.fromCharCode(s));while(l= 200 && this.status < 300 || this.status === 304) { + cb(null, raw ? this.responseText : this.responseText ? JSON.parse(this.responseText) : true); + } else { + cb({request: this, error: this.status}); + } + } + } + xhr.setRequestHeader('Accept','application/vnd.github.raw'); + xhr.setRequestHeader('Content-Type','application/json;charset=UTF-8'); + if ( + (options.auth == 'oauth' && options.token) || + (options.auth == 'basic' && options.username && options.password) + ) { + xhr.setRequestHeader('Authorization',options.auth == 'oauth' + ? 'token '+ options.token + : 'Basic ' + Base64.encode(options.username + ':' + options.password) + ); + } + data ? xhr.send(JSON.stringify(data)) : xhr.send(); + } + + // 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); + }; + + // 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) { + 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(path, cb) { + _request("GET", repoPath + "/contents", { path: path }, cb); + }; + + // Fork repository + // ------- + + this.fork = function(cb) { + _request("POST", repoPath + "/forks", null, cb); + }; + + // Create pull request + // -------- + + this.createPullRequest = function(options, cb) { + _request("POST", repoPath + "/pulls", options, 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); + }); + }); + }); + }); + }; + }; + + // Gists API + // ======= + + Github.Gist = function(options) { + var id = options.id; + var that = this; + var gistPath = "/gists/"+id; + + // Read the gist + // -------- + + this.read = function(cb) { + _request("GET", gistPath, null, function(err, gist) { + cb(err, gist); + }); + }; + + + // 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); + }); + }; + }; + + // Top Level API + // ------- + + this.getRepo = function(user, repo) { + return new Github.Repository({user: user, name: repo}); + }; + +Github.User = function(token) { +console.log(token); + this.validate = function(cb) { + _request("GET", "/applications/"+token+"/tokens/", function(err, res) { + console.log(err); + console.log(res); + cb(err,res); + }); + }; +} + + this.getUser = function(token) { + return new Github.User(token); + }; + + + + }; +}).call(this); \ No newline at end of file diff --git a/lib/underscore-min.js b/lib/underscore-min.js new file mode 100644 index 0000000..da9fe29 --- /dev/null +++ b/lib/underscore-min.js @@ -0,0 +1,12 @@ +// This file contains the select, reject, forEach and has functions +// from underscore.js, then minified to make it extra tiny + +// Underscore.js 1.3.3 +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore may be freely distributed under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore + +(function(){var e=this,t=Array.prototype,n=Object.prototype,r=t.forEach,i=t.filter,s=n.hasOwnProperty,o={};_=function(obj) {return new wrapper(obj);};_.filter=_.select=function(e,t,n){var r=[];return e==null?r:i&&e.filter===i?e.filter(t,n):(u(e,function(e,i,s){t.call(n,e,i,s)&&(r[r.length]=e)}),r)},_.reject=function(e,t,n){var r=[];return e==null?r:(u(e,function(e,i,s){t.call(n,e,i,s)||(r[r.length]=e)}),r)};var u=_.each=_.forEach=function(e,t,n){if(e==null)return;if(r&&e.forEach===r)e.forEach(t,n);else if(e.length===+e.length){for(var i=0,s=e.length;i