s?s:6,A>s-3&&Ay;y++)ia[y]=ea[Ia[y]];for(P=19;4=a:return[265,a-11,1];case 14>=a:return[266,a-13,1];case 16>=a:return[267,a-15,1];case 18>=a:return[268,a-17,1];case 22>=a:return[269,a-19,2];case 26>=a:return[270,a-23,2];case 30>=a:return[271,a-27,2];case 34>=a:return[272,
26 | a-31,2];case 42>=a:return[273,a-35,3];case 50>=a:return[274,a-43,3];case 58>=a:return[275,a-51,3];case 66>=a:return[276,a-59,3];case 82>=a:return[277,a-67,4];case 98>=a:return[278,a-83,4];case 114>=a:return[279,a-99,4];case 130>=a:return[280,a-115,4];case 162>=a:return[281,a-131,5];case 194>=a:return[282,a-163,5];case 226>=a:return[283,a-195,5];case 257>=a:return[284,a-227,5];case 258===a:return[285,a-258,0];default:throw"invalid length: "+a;}}var d=[],c,f;for(c=3;258>=c;c++)f=e(c),d[c]=f[2]<<24|
27 | f[1]<<16|f[0];return d}(),Ga=C?new Uint32Array(Fa):Fa;
28 | function na(e,d){function c(a,c){var b=a.g,d=[],f=0,e;e=Ga[a.length];d[f++]=e&65535;d[f++]=e>>16&255;d[f++]=e>>24;var g;switch(u){case 1===b:g=[0,b-1,0];break;case 2===b:g=[1,b-2,0];break;case 3===b:g=[2,b-3,0];break;case 4===b:g=[3,b-4,0];break;case 6>=b:g=[4,b-5,1];break;case 8>=b:g=[5,b-7,1];break;case 12>=b:g=[6,b-9,2];break;case 16>=b:g=[7,b-13,2];break;case 24>=b:g=[8,b-17,3];break;case 32>=b:g=[9,b-25,3];break;case 48>=b:g=[10,b-33,4];break;case 64>=b:g=[11,b-49,4];break;case 96>=b:g=[12,b-
29 | 65,5];break;case 128>=b:g=[13,b-97,5];break;case 192>=b:g=[14,b-129,6];break;case 256>=b:g=[15,b-193,6];break;case 384>=b:g=[16,b-257,7];break;case 512>=b:g=[17,b-385,7];break;case 768>=b:g=[18,b-513,8];break;case 1024>=b:g=[19,b-769,8];break;case 1536>=b:g=[20,b-1025,9];break;case 2048>=b:g=[21,b-1537,9];break;case 3072>=b:g=[22,b-2049,10];break;case 4096>=b:g=[23,b-3073,10];break;case 6144>=b:g=[24,b-4097,11];break;case 8192>=b:g=[25,b-6145,11];break;case 12288>=b:g=[26,b-8193,12];break;case 16384>=
30 | b:g=[27,b-12289,12];break;case 24576>=b:g=[28,b-16385,13];break;case 32768>=b:g=[29,b-24577,13];break;default:throw"invalid distance";}e=g;d[f++]=e[0];d[f++]=e[1];d[f++]=e[2];var k,m;k=0;for(m=d.length;k=b;)t[b++]=0;for(b=0;29>=b;)w[b++]=0}t[256]=1;f=0;for(a=d.length;f=a){x&&c(x,-1);b=0;for(k=a-f;bk&&d+kb&&(a=f,b=k);if(258===k)break}return new qa(b,d-a)}
33 | function oa(e,d){var c=e.length,f=new ja(572),a=new (C?Uint8Array:Array)(c),b,k,m,g,p;if(!C)for(g=0;g2*a[h-1]+b[h]&&(a[h]=2*a[h-1]+b[h]),m[h]=Array(a[h]),g[h]=Array(a[h]);for(l=0;le[l]?(m[h][q]=t,g[h][q]=d,w+=2):(m[h][q]=e[l],g[h][q]=l,++l);p[h]=0;1===b[h]&&f(h)}return k}
36 | function pa(e){var d=new (C?Uint16Array:Array)(e.length),c=[],f=[],a=0,b,k,m,g;b=0;for(k=e.length;b>>=1}return d};ba("Zlib.RawDeflate",ka);ba("Zlib.RawDeflate.prototype.compress",ka.prototype.h);var Ka={NONE:0,FIXED:1,DYNAMIC:ma},V,La,$,Ma;if(Object.keys)V=Object.keys(Ka);else for(La in V=[],$=0,Ka)V[$++]=La;$=0;for(Ma=V.length;$2;e==null&&(e=[]);if(d&&e.reduce===d)return r&&(t=T.bind(t,r)),i?e.reduce(t,n):e.reduce(t);N(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.reduceRight=T.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(v&&e.reduceRight===v)return r&&(t=T.bind(t,r)),arguments.length>2?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=T.keys(e);s=o.length}N(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError("Reduce of empty array with no initial value");return n},T.find=T.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},T.filter=T.select=function(e,t,n){var r=[];return e==null?r:m&&e.filter===m?e.filter(t,n):(N(e,function(e,i,s){t.call(n,e,i,s)&&(r[r.length]=e)}),r)},T.reject=function(e,t,n){var r=[];return e==null?r:(N(e,function(e,i,s){t.call(n,e,i,s)||(r[r.length]=e)}),r)},T.every=T.all=function(e,t,r){t||(t=T.identity);var i=!0;return e==null?i:g&&e.every===g?e.every(t,r):(N(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=T.some=T.any=function(e,t,r){t||(t=T.identity);var i=!1;return e==null?i:y&&e.some===y?e.some(t,r):(N(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};T.contains=T.include=function(e,t){var n=!1;return e==null?n:b&&e.indexOf===b?e.indexOf(t)!=-1:(n=C(e,function(e){return e===t}),n)},T.invoke=function(e,t){var n=u.call(arguments,2);return T.map(e,function(e){return(T.isFunction(t)?t:e[t]).apply(e,n)})},T.pluck=function(e,t){return T.map(e,function(e){return e[t]})},T.where=function(e,t){return T.isEmpty(t)?[]:T.filter(e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},T.max=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&T.isEmpty(e))return-Infinity;var r={computed:-Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},T.min=function(e,t,n){if(!t&&T.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&T.isEmpty(e))return Infinity;var r={computed:Infinity};return N(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;or||n===void 0)return 1;if(n>>1;n.call(r,e[u])=0})})},T.difference=function(e){var t=a.apply(r,u.call(arguments,1));return T.filter(e,function(e){return!T.contains(t,e)})},T.zip=function(){var e=u.call(arguments),t=T.max(T.pluck(e,"length")),n=new Array(t);for(var r=0;r=0;n--)t=[e[n].apply(this,t)];return t[0]}},T.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},T.keys=S||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)T.has(e,n)&&(t[t.length]=n);return t},T.values=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push(e[n]);return t},T.pairs=function(e){var t=[];for(var n in e)T.has(e,n)&&t.push([n,e[n]]);return t},T.invert=function(e){var t={};for(var n in e)T.has(e,n)&&(t[e[n]]=n);return t},T.functions=T.methods=function(e){var t=[];for(var n in e)T.isFunction(e[n])&&t.push(n);return t.sort()},T.extend=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]=t[n]}),e},T.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return N(n,function(n){n in e&&(t[n]=e[n])}),t},T.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)T.contains(n,i)||(t[i]=e[i]);return t},T.defaults=function(e){return N(u.call(arguments,1),function(t){for(var n in t)e[n]==null&&(e[n]=t[n])}),e},T.clone=function(e){return T.isObject(e)?T.isArray(e)?e.slice():T.extend({},e):e},T.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof T&&(e=e._wrapped),t instanceof T&&(t=t._wrapped);var i=l.call(e);if(i!=l.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,f=t.constructor;if(a!==f&&!(T.isFunction(a)&&a instanceof a&&T.isFunction(f)&&f instanceof f))return!1;for(var c in e)if(T.has(e,c)){o++;if(!(u=T.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(T.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};T.isEqual=function(e,t){return M(e,t,[],[])},T.isEmpty=function(e){if(e==null)return!0;if(T.isArray(e)||T.isString(e))return e.length===0;for(var t in e)if(T.has(e,t))return!1;return!0},T.isElement=function(e){return!!e&&e.nodeType===1},T.isArray=E||function(e){return l.call(e)=="[object Array]"},T.isObject=function(e){return e===Object(e)},N(["Arguments","Function","String","Number","Date","RegExp"],function(e){T["is"+e]=function(t){return l.call(t)=="[object "+e+"]"}}),T.isArguments(arguments)||(T.isArguments=function(e){return!!e&&!!T.has(e,"callee")}),typeof /./!="function"&&(T.isFunction=function(e){return typeof e=="function"}),T.isFinite=function(e){return T.isNumber(e)&&isFinite(e)},T.isNaN=function(e){return T.isNumber(e)&&e!=+e},T.isBoolean=function(e){return e===!0||e===!1||l.call(e)=="[object Boolean]"},T.isNull=function(e){return e===null},T.isUndefined=function(e){return e===void 0},T.has=function(e,t){return c.call(e,t)},T.noConflict=function(){return e._=t,this},T.identity=function(e){return e},T.times=function(e,t,n){for(var r=0;r":">",'"':""","'":"'","/":"/"}};_.unescape=T.invert(_.escape);var D={escape:new RegExp("["+T.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+T.keys(_.unescape).join("|")+")","g")};T.each(["escape","unescape"],function(e){T[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),T.result=function(e,t){if(e==null)return null;var n=e[t];return T.isFunction(n)?n.call(e):n},T.mixin=function(e){N(T.functions(e),function(t){var n=T[t]=e[t];T.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(T,e))}})};var P=0;T.uniqueId=function(e){var t=P++;return e?e+t:t},T.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;T.template=function(e,t,n){n=T.defaults({},n,T.templateSettings);var r=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),i=0,s="__p+='";e.replace(r,function(t,n,r,o,u){s+=e.slice(i,u).replace(j,function(e){return"\\"+B[e]}),s+=n?"'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'":r?"'+\n((__t=("+r+"))==null?'':__t)+\n'":o?"';\n"+o+"\n__p+='":"",i=u+t.length}),s+="';\n",n.variable||(s="with(obj||{}){\n"+s+"}\n"),s="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+s+"return __p;\n";try{var o=new Function(n.variable||"obj","_",s)}catch(u){throw u.source=s,u}if(t)return o(t,T);var a=function(e){return o.call(this,e,T)};return a.source="function("+(n.variable||"obj")+"){\n"+s+"}",a},T.chain=function(e){return T(e).chain()};var F=function(e){return this._chain?T(e).chain():e};T.mixin(T),N(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];T.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),N(["concat","join","slice"],function(e){var t=r[e];T.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),T.extend(T.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);
--------------------------------------------------------------------------------
/ext/github.js:
--------------------------------------------------------------------------------
1 | // Github.js 0.9.0
2 | // (c) 2013 Michael Aufreiter, Development Seed
3 | // Github.js is freely distributable under the MIT license.
4 | // For all details and documentation:
5 | // http://substance.io/michael/github
6 |
7 | (function() {
8 |
9 | // Initial Setup
10 | // -------------
11 |
12 | var XMLHttpRequest, Base64, _;
13 | if (typeof exports !== 'undefined') {
14 | XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
15 | _ = require('underscore');
16 | Base64 = require('./lib/base64.js');
17 | }else{
18 | _ = window._;
19 | Base64 = window.Base64;
20 | }
21 | //prefer native XMLHttpRequest always
22 | if (typeof window !== 'undefined' && typeof window.XMLHttpRequest !== 'undefined'){
23 | XMLHttpRequest = window.XMLHttpRequest;
24 | }
25 |
26 |
27 | var API_URL = 'https://api.github.com';
28 |
29 | var Github = function(options) {
30 |
31 | // HTTP Request Abstraction
32 | // =======
33 | //
34 | // I'm not proud of this and neither should you be if you were responsible for the XMLHttpRequest spec.
35 |
36 | function _request(method, path, data, cb, raw, sync) {
37 | function getURL() {
38 | var url = path.indexOf('//') >= 0 ? path : API_URL + path;
39 | return url + ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime();
40 | }
41 |
42 | var xhr = new XMLHttpRequest();
43 | if (!raw) {xhr.dataType = "json";}
44 |
45 | xhr.open(method, getURL(), !sync);
46 | if (!sync) {
47 | xhr.onreadystatechange = function () {
48 | if (this.readyState == 4) {
49 | if (this.status >= 200 && this.status < 300 || this.status === 304) {
50 | cb(null, raw ? this.responseText : this.responseText ? JSON.parse(this.responseText) : true, this);
51 | } else {
52 | cb({path: path, request: this, error: this.status});
53 | }
54 | }
55 | }
56 | };
57 | xhr.setRequestHeader('Accept','application/vnd.github.raw+json');
58 | xhr.setRequestHeader('Content-Type','application/json;charset=UTF-8');
59 | if ((options.token) || (options.username && options.password)) {
60 | xhr.setRequestHeader('Authorization', options.token
61 | ? 'token '+ options.token
62 | : 'Basic ' + Base64.encode(options.username + ':' + options.password)
63 | );
64 | }
65 | data ? xhr.send(JSON.stringify(data)) : xhr.send();
66 | if (sync) return xhr.response;
67 | }
68 |
69 | function _requestAllPages(path, cb) {
70 | var results = [];
71 | (function iterate() {
72 | _request("GET", path, null, function(err, res, xhr) {
73 | if (err) {
74 | return cb(err);
75 | }
76 |
77 | results.push.apply(results, res);
78 |
79 | var links = (xhr.getResponseHeader('link') || '').split(/\s*,\s*/g),
80 | next = _.find(links, function(link) { return /rel="next"/.test(link); });
81 |
82 | if (next) {
83 | next = (/<(.*)>/.exec(next) || [])[1];
84 | }
85 |
86 | if (!next) {
87 | cb(err, results);
88 | } else {
89 | path = next;
90 | iterate();
91 | }
92 | });
93 | })();
94 | }
95 |
96 |
97 |
98 | // User API
99 | // =======
100 |
101 | Github.User = function() {
102 | this.repos = function(cb) {
103 | // Github does not always honor the 1000 limit so we want to iterate over the data set.
104 | _requestAllPages("/user/repos?type=all&per_page=1000&sort=updated", function(err, res) {
105 | cb(err, res);
106 | });
107 | };
108 |
109 | // List user organizations
110 | // -------
111 |
112 | this.orgs = function(cb) {
113 | _request("GET", "/user/orgs", null, function(err, res) {
114 | cb(err, res);
115 | });
116 | };
117 |
118 | // List authenticated user's gists
119 | // -------
120 |
121 | this.gists = function(cb) {
122 | _request("GET", "/gists", null, function(err, res) {
123 | cb(err,res);
124 | });
125 | };
126 |
127 | // List authenticated user's unread notifications
128 | // -------
129 |
130 | this.notifications = function(cb) {
131 | _request("GET", "/notifications", null, function(err, res) {
132 | cb(err,res);
133 | });
134 | };
135 |
136 | // Show user information
137 | // -------
138 |
139 | this.show = function(username, cb) {
140 | var command = username ? "/users/"+username : "/user";
141 |
142 | _request("GET", command, null, function(err, res) {
143 | cb(err, res);
144 | });
145 | };
146 |
147 | // List user repositories
148 | // -------
149 |
150 | this.userRepos = function(username, cb) {
151 | // Github does not always honor the 1000 limit so we want to iterate over the data set.
152 | _requestAllPages("/users/"+username+"/repos?type=all&per_page=1000&sort=updated", function(err, res) {
153 | cb(err, res);
154 | });
155 | };
156 |
157 | // List a user's gists
158 | // -------
159 |
160 | this.userGists = function(username, cb) {
161 | _request("GET", "/users/"+username+"/gists", null, function(err, res) {
162 | cb(err,res);
163 | });
164 | };
165 |
166 | // List organization repositories
167 | // -------
168 |
169 | this.orgRepos = function(orgname, cb) {
170 | // Github does not always honor the 1000 limit so we want to iterate over the data set.
171 | _requestAllPages("/orgs/"+orgname+"/repos?type=all&&page_num=1000&sort=updated&direction=desc", function(err, res) {
172 | cb(err, res);
173 | });
174 | };
175 |
176 | // Follow user
177 | // -------
178 |
179 | this.follow = function(username, cb) {
180 | _request("PUT", "/user/following/"+username, null, function(err, res) {
181 | cb(err, res);
182 | });
183 | };
184 |
185 | // Unfollow user
186 | // -------
187 |
188 | this.unfollow = function(username, cb) {
189 | _request("DELETE", "/user/following/"+username, null, function(err, res) {
190 | cb(err, res);
191 | });
192 | };
193 | };
194 |
195 |
196 | // Repository API
197 | // =======
198 |
199 | Github.Repository = function(options) {
200 | var repo = options.name;
201 | var user = options.user;
202 |
203 | var that = this;
204 | var repoPath = "/repos/" + user + "/" + repo;
205 |
206 | var currentTree = {
207 | "branch": null,
208 | "sha": null
209 | };
210 |
211 | // Uses the cache if branch has not been changed
212 | // -------
213 |
214 | function updateTree(branch, cb) {
215 | if (branch === currentTree.branch && currentTree.sha) return cb(null, currentTree.sha);
216 | that.getRef("heads/"+branch, function(err, sha) {
217 | currentTree.branch = branch;
218 | currentTree.sha = sha;
219 | cb(err, sha);
220 | });
221 | }
222 |
223 | // Get a particular reference
224 | // -------
225 |
226 | this.getRef = function(ref, cb) {
227 | _request("GET", repoPath + "/git/refs/" + ref, null, function(err, res) {
228 | if (err) return cb(err);
229 | cb(null, res.object.sha);
230 | });
231 | };
232 |
233 | // Create a new reference
234 | // --------
235 | //
236 | // {
237 | // "ref": "refs/heads/my-new-branch-name",
238 | // "sha": "827efc6d56897b048c772eb4087f854f46256132"
239 | // }
240 |
241 | this.createRef = function(options, cb) {
242 | _request("POST", repoPath + "/git/refs", options, cb);
243 | };
244 |
245 | // Delete a reference
246 | // --------
247 | //
248 | // repo.deleteRef('heads/gh-pages')
249 | // repo.deleteRef('tags/v1.0')
250 |
251 | this.deleteRef = function(ref, cb) {
252 | _request("DELETE", repoPath + "/git/refs/"+ref, options, cb);
253 | };
254 |
255 | // Create a repo
256 | // -------
257 |
258 | this.createRepo = function(options, cb) {
259 | _request("POST", "/user/repos", options, cb);
260 | };
261 |
262 | // Delete a repo
263 | // --------
264 |
265 | this.deleteRepo = function(cb) {
266 | _request("DELETE", repoPath, options, cb);
267 | };
268 |
269 | // List all tags of a repository
270 | // -------
271 |
272 | this.listTags = function(cb) {
273 | _request("GET", repoPath + "/tags", null, function(err, tags) {
274 | if (err) return cb(err);
275 | cb(null, tags);
276 | });
277 | };
278 |
279 | // List all pull requests of a respository
280 | // -------
281 |
282 | this.listPulls = function(state, cb) {
283 | _request("GET", repoPath + "/pulls" + (state ? '?state=' + state : ''), null, function(err, pulls) {
284 | if (err) return cb(err);
285 | cb(null, pulls);
286 | });
287 | };
288 |
289 | // Gets details for a specific pull request
290 | // -------
291 |
292 | this.getPull = function(number, cb) {
293 | _request("GET", repoPath + "/pulls/" + number, null, function(err, pull) {
294 | if (err) return cb(err);
295 | cb(null, pull);
296 | });
297 | };
298 |
299 | // Retrieve the changes made between base and head
300 | // -------
301 |
302 | this.compare = function(base, head, cb) {
303 | _request("GET", repoPath + "/compare/" + base + "..." + head, null, function(err, diff) {
304 | if (err) return cb(err);
305 | cb(null, diff);
306 | });
307 | };
308 |
309 | // List all branches of a repository
310 | // -------
311 |
312 | this.listBranches = function(cb) {
313 | _request("GET", repoPath + "/git/refs/heads", null, function(err, heads) {
314 | if (err) return cb(err);
315 | cb(null, _.map(heads, function(head) { return _.last(head.ref.split('/')); }));
316 | });
317 | };
318 |
319 | // Retrieve the contents of a blob
320 | // -------
321 |
322 | this.getBlob = function(sha, cb) {
323 | _request("GET", repoPath + "/git/blobs/" + sha, null, cb, 'raw');
324 | };
325 |
326 | // For a given file path, get the corresponding sha (blob for files, tree for dirs)
327 | // -------
328 |
329 | this.getSha = function(branch, path, cb) {
330 | // Just use head if path is empty
331 | if (path === "") return that.getRef("heads/"+branch, cb);
332 | that.getTree(branch+"?recursive=true", function(err, tree) {
333 | if (err) return cb(err);
334 | var file = _.select(tree, function(file) {
335 | return file.path === path;
336 | })[0];
337 | cb(null, file ? file.sha : null);
338 | });
339 | };
340 |
341 | // Retrieve the tree a commit points to
342 | // -------
343 |
344 | this.getTree = function(tree, cb) {
345 | _request("GET", repoPath + "/git/trees/"+tree, null, function(err, res) {
346 | if (err) return cb(err);
347 | cb(null, res.tree);
348 | });
349 | };
350 |
351 | // Post a new blob object, getting a blob SHA back
352 | // -------
353 |
354 | this.postBlob = function(content, cb) {
355 | if (typeof(content) === "string") {
356 | content = {
357 | "content": content,
358 | "encoding": "utf-8"
359 | };
360 | }
361 |
362 | _request("POST", repoPath + "/git/blobs", content, function(err, res) {
363 | if (err) return cb(err);
364 | cb(null, res.sha);
365 | });
366 | };
367 |
368 | // Update an existing tree adding a new blob object getting a tree SHA back
369 | // -------
370 |
371 | this.updateTree = function(baseTree, path, blob, cb) {
372 | var data = {
373 | "base_tree": baseTree,
374 | "tree": [
375 | {
376 | "path": path,
377 | "mode": "100644",
378 | "type": "blob",
379 | "sha": blob
380 | }
381 | ]
382 | };
383 | _request("POST", repoPath + "/git/trees", data, function(err, res) {
384 | if (err) return cb(err);
385 | cb(null, res.sha);
386 | });
387 | };
388 |
389 | // Post a new tree object having a file path pointer replaced
390 | // with a new blob SHA getting a tree SHA back
391 | // -------
392 |
393 | this.postTree = function(tree, cb) {
394 | _request("POST", repoPath + "/git/trees", { "tree": tree }, function(err, res) {
395 | if (err) return cb(err);
396 | cb(null, res.sha);
397 | });
398 | };
399 |
400 | // Create a new commit object with the current commit SHA as the parent
401 | // and the new tree SHA, getting a commit SHA back
402 | // -------
403 |
404 | this.commit = function(parent, tree, message, cb) {
405 | var data = {
406 | "message": message,
407 | "author": {
408 | "name": options.username
409 | },
410 | "parents": [
411 | parent
412 | ],
413 | "tree": tree
414 | };
415 |
416 | _request("POST", repoPath + "/git/commits", data, function(err, res) {
417 | currentTree.sha = res.sha; // update latest commit
418 | if (err) return cb(err);
419 | cb(null, res.sha);
420 | });
421 | };
422 |
423 | // Update the reference of your head to point to the new commit SHA
424 | // -------
425 |
426 | this.updateHead = function(head, commit, cb) {
427 | _request("PATCH", repoPath + "/git/refs/heads/" + head, { "sha": commit }, function(err, res) {
428 | cb(err);
429 | });
430 | };
431 |
432 | // Show repository information
433 | // -------
434 |
435 | this.show = function(cb) {
436 | _request("GET", repoPath, null, cb);
437 | };
438 |
439 | // Get contents
440 | // --------
441 |
442 | this.contents = function(branch, path, cb, sync) {
443 | return _request("GET", repoPath + "/contents?ref=" + branch + (path ? "&path=" + path : ""), null, cb, 'raw', sync);
444 | };
445 |
446 | // Fork repository
447 | // -------
448 |
449 | this.fork = function(cb) {
450 | _request("POST", repoPath + "/forks", null, cb);
451 | };
452 |
453 | // Branch repository
454 | // --------
455 |
456 | this.branch = function(oldBranch,newBranch,cb) {
457 | if(arguments.length === 2 && typeof arguments[1] === "function") {
458 | cb = newBranch;
459 | newBranch = oldBranch;
460 | oldBranch = "master";
461 | }
462 | this.getRef("heads/" + oldBranch, function(err,ref) {
463 | if(err && cb) return cb(err);
464 | that.createRef({
465 | ref: "refs/heads/" + newBranch,
466 | sha: ref
467 | },cb);
468 | });
469 | }
470 |
471 | // Create pull request
472 | // --------
473 |
474 | this.createPullRequest = function(options, cb) {
475 | _request("POST", repoPath + "/pulls", options, cb);
476 | };
477 |
478 | // List hooks
479 | // --------
480 |
481 | this.listHooks = function(cb) {
482 | _request("GET", repoPath + "/hooks", null, cb);
483 | };
484 |
485 | // Get a hook
486 | // --------
487 |
488 | this.getHook = function(id, cb) {
489 | _request("GET", repoPath + "/hooks/" + id, null, cb);
490 | };
491 |
492 | // Create a hook
493 | // --------
494 |
495 | this.createHook = function(options, cb) {
496 | _request("POST", repoPath + "/hooks", options, cb);
497 | };
498 |
499 | // Edit a hook
500 | // --------
501 |
502 | this.editHook = function(id, options, cb) {
503 | _request("PATCH", repoPath + "/hooks/" + id, options, cb);
504 | };
505 |
506 | // Delete a hook
507 | // --------
508 |
509 | this.deleteHook = function(id, cb) {
510 | _request("DELETE", repoPath + "/hooks/" + id, null, cb);
511 | };
512 |
513 | // Read file at given path
514 | // -------
515 |
516 | this.read = function(branch, path, cb) {
517 | that.getSha(branch, path, function(err, sha) {
518 | if (!sha) return cb("not found", null);
519 | that.getBlob(sha, function(err, content) {
520 | cb(err, content, sha);
521 | });
522 | });
523 | };
524 |
525 | // Remove a file from the tree
526 | // -------
527 |
528 | this.remove = function(branch, path, cb) {
529 | updateTree(branch, function(err, latestCommit) {
530 | that.getTree(latestCommit+"?recursive=true", function(err, tree) {
531 | // Update Tree
532 | var newTree = _.reject(tree, function(ref) { return ref.path === path; });
533 | _.each(newTree, function(ref) {
534 | if (ref.type === "tree") delete ref.sha;
535 | });
536 |
537 | that.postTree(newTree, function(err, rootTree) {
538 | that.commit(latestCommit, rootTree, 'Deleted '+path , function(err, commit) {
539 | that.updateHead(branch, commit, function(err) {
540 | cb(err);
541 | });
542 | });
543 | });
544 | });
545 | });
546 | };
547 |
548 | // Move a file to a new location
549 | // -------
550 |
551 | this.move = function(branch, path, newPath, cb) {
552 | updateTree(branch, function(err, latestCommit) {
553 | that.getTree(latestCommit+"?recursive=true", function(err, tree) {
554 | // Update Tree
555 | _.each(tree, function(ref) {
556 | if (ref.path === path) ref.path = newPath;
557 | if (ref.type === "tree") delete ref.sha;
558 | });
559 |
560 | that.postTree(tree, function(err, rootTree) {
561 | that.commit(latestCommit, rootTree, 'Deleted '+path , function(err, commit) {
562 | that.updateHead(branch, commit, function(err) {
563 | cb(err);
564 | });
565 | });
566 | });
567 | });
568 | });
569 | };
570 |
571 | // Write file contents to a given branch and path
572 | // -------
573 |
574 | this.write = function(branch, path, content, message, cb) {
575 | updateTree(branch, function(err, latestCommit) {
576 | if (err) return cb(err);
577 | that.postBlob(content, function(err, blob) {
578 | if (err) return cb(err);
579 | that.updateTree(latestCommit, path, blob, function(err, tree) {
580 | if (err) return cb(err);
581 | that.commit(latestCommit, tree, message, function(err, commit) {
582 | if (err) return cb(err);
583 | that.updateHead(branch, commit, cb);
584 | });
585 | });
586 | });
587 | });
588 | };
589 |
590 | // List commits on a repository. Takes an object of optional paramaters:
591 | // sha: SHA or branch to start listing commits from
592 | // path: Only commits containing this file path will be returned
593 | // since: ISO 8601 date - only commits after this date will be returned
594 | // until: ISO 8601 date - only commits before this date will be returned
595 | // -------
596 |
597 | this.getCommits = function(options, cb) {
598 | options = options || {};
599 | var url = repoPath + "/commits";
600 | var params = [];
601 | if (options.sha) {
602 | params.push("sha=" + encodeURIComponent(options.sha));
603 | }
604 | if (options.path) {
605 | params.push("path=" + encodeURIComponent(options.path));
606 | }
607 | if (options.since) {
608 | var since = options.since;
609 | if (since.constructor === Date) {
610 | since = since.toISOString();
611 | }
612 | params.push("since=" + encodeURIComponent(since));
613 | }
614 | if (options.until) {
615 | var until = options.until;
616 | if (until.constructor === Date) {
617 | until = until.toISOString();
618 | }
619 | params.push("until=" + encodeURIComponent(until));
620 | }
621 | if (params.length > 0) {
622 | url += "?" + params.join("&");
623 | }
624 | _request("GET", url, null, cb);
625 | };
626 | };
627 |
628 | // Gists API
629 | // =======
630 |
631 | Github.Gist = function(options) {
632 | var id = options.id;
633 | var gistPath = "/gists/"+id;
634 |
635 | // Read the gist
636 | // --------
637 |
638 | this.read = function(cb) {
639 | _request("GET", gistPath, null, function(err, gist) {
640 | cb(err, gist);
641 | });
642 | };
643 |
644 | // Create the gist
645 | // --------
646 | // {
647 | // "description": "the description for this gist",
648 | // "public": true,
649 | // "files": {
650 | // "file1.txt": {
651 | // "content": "String file contents"
652 | // }
653 | // }
654 | // }
655 |
656 | this.create = function(options, cb){
657 | _request("POST","/gists", options, cb);
658 | };
659 |
660 | // Delete the gist
661 | // --------
662 |
663 | this.delete = function(cb) {
664 | _request("DELETE", gistPath, null, function(err,res) {
665 | cb(err,res);
666 | });
667 | };
668 |
669 | // Fork a gist
670 | // --------
671 |
672 | this.fork = function(cb) {
673 | _request("POST", gistPath+"/fork", null, function(err,res) {
674 | cb(err,res);
675 | });
676 | };
677 |
678 | // Update a gist with the new stuff
679 | // --------
680 |
681 | this.update = function(options, cb) {
682 | _request("PATCH", gistPath, options, function(err,res) {
683 | cb(err,res);
684 | });
685 | };
686 |
687 | // Star a gist
688 | // --------
689 |
690 | this.star = function(cb) {
691 | _request("PUT", gistPath+"/star", null, function(err,res) {
692 | cb(err,res);
693 | });
694 | };
695 |
696 | // Untar a gist
697 | // --------
698 |
699 | this.unstar = function(cb) {
700 | _request("DELETE", gistPath+"/star", null, function(err,res) {
701 | cb(err,res);
702 | });
703 | };
704 |
705 | // Check if a gist is starred
706 | // --------
707 |
708 | this.isStarred = function(cb) {
709 | _request("GET", gistPath+"/star", null, function(err,res) {
710 | cb(err,res);
711 | });
712 | };
713 | };
714 |
715 | // Issues API
716 | // ==========
717 |
718 | Github.Issue = function(options) {
719 | var path = "/repos/" + options.user + "/" + options.repo + "/issues";
720 |
721 | this.list = function(options, cb) {
722 | _request("GET", path, options, function(err, res) {
723 | cb(err,res)
724 | });
725 | };
726 | };
727 |
728 | // Top Level API
729 | // -------
730 |
731 | this.getIssues = function(user, repo) {
732 | return new Github.Issue({user: user, repo: repo});
733 | };
734 |
735 | this.getRepo = function(user, repo) {
736 | return new Github.Repository({user: user, name: repo});
737 | };
738 |
739 | this.getUser = function() {
740 | return new Github.User();
741 | };
742 |
743 | this.getGist = function(id) {
744 | return new Github.Gist({id: id});
745 | };
746 | };
747 |
748 |
749 | if (typeof exports !== 'undefined') {
750 | // Github = exports;
751 | module.exports = Github;
752 | } else {
753 | window.Github = Github;
754 | }
755 | }).call(this);
756 |
--------------------------------------------------------------------------------