mirror of
https://github.com/resume/resume.github.com.git
synced 2025-12-31 08:10:10 -06:00
687 lines
22 KiB
JavaScript
687 lines
22 KiB
JavaScript
// ## Client-side Javascript API wrapper for GitHub
|
|
//
|
|
// Tries to map one-to-one with the GitHub API V2, but in a Javascripty manner.
|
|
|
|
(function (globals) {
|
|
|
|
// Before we implement the API methods, we will define all of our private
|
|
// variables and helper functions with one `var` statement.
|
|
var
|
|
|
|
// The username and authentication token of the library's user.
|
|
authUsername,
|
|
authToken,
|
|
|
|
// To save keystrokes when we make JSONP calls to the HTTP API, we will keep
|
|
// track of the root from which all V2 urls extend.
|
|
apiRoot = "https://github.com/api/v2/json/",
|
|
|
|
// Send a JSONP request to the Github API that calls `callback` with
|
|
// the `context` argument as `this`.
|
|
//
|
|
// The `url` parameter is concatenated with the apiRoot, for the reasons
|
|
// mentioned above. The way that we are supporting non-global, anonymous
|
|
// functions is by sticking them in the globally exposed
|
|
// `gh.__jsonp_callbacks` object with a "unique" `id` that is the current
|
|
// time in milliseconds. Once the callback is called, it is deleted from the
|
|
// object to prevent memory leaks.
|
|
jsonp = function (url, callback, context) {
|
|
var id = +new Date,
|
|
script = document.createElement("script");
|
|
|
|
while (gh.__jsonp_callbacks[id] !== undefined)
|
|
id += Math.random(); // Avoid slight possibility of id clashes.
|
|
|
|
gh.__jsonp_callbacks[id] = function () {
|
|
delete gh.__jsonp_callbacks[id];
|
|
callback.apply(context, arguments);
|
|
};
|
|
|
|
var prefix = "?";
|
|
if (url.indexOf("?") >= 0)
|
|
prefix = "&";
|
|
|
|
url += prefix + "callback=" + encodeURIComponent("gh.__jsonp_callbacks[" + id + "]");
|
|
if (authUsername && authToken) {
|
|
url += "&login=" + authUsername + "&authToken=" + authToken;
|
|
}
|
|
script.setAttribute("src", apiRoot + url);
|
|
|
|
document.getElementsByTagName('head')[0].appendChild(script);
|
|
},
|
|
|
|
// Send an HTTP POST. Unfortunately, it isn't possible to support a callback
|
|
// with the resulting data. (Please prove me wrong if you can!)
|
|
//
|
|
// This is implemented with a hack to get around the cross-domain
|
|
// restrictions on ajax calls. Basically, a form is created that will POST
|
|
// to the GitHub API URL, stuck inside an iframe so that it won't redirect
|
|
// this page, and then submitted.
|
|
post = function (url, vals) {
|
|
var
|
|
form = document.createElement("form"),
|
|
iframe = document.createElement("iframe"),
|
|
doc = iframe.contentDocument !== undefined ?
|
|
iframe.contentDocument :
|
|
iframe.contentWindow.document,
|
|
key, field;
|
|
vals = vals || {};
|
|
|
|
form.setAttribute("method", "post");
|
|
form.setAttribute("action", apiRoot + url);
|
|
for (key in vals) {
|
|
if (vals.hasOwnProperty(key)) {
|
|
field = document.createElement("input");
|
|
field.type = "hidden";
|
|
field.value = encodeURIComponent(vals[key]);
|
|
form.appendChild(field);
|
|
}
|
|
}
|
|
|
|
iframe.setAttribute("style", "display: none;");
|
|
doc.body.appendChild(form);
|
|
document.body.appendChild(iframe);
|
|
form.submit();
|
|
},
|
|
|
|
// This helper function will throw a TypeError if the library user is not
|
|
// properly authenticated. Otherwise, it silently returns.
|
|
authRequired = function (username) {
|
|
if (!authUsername || !authToken || authUsername !== username) {
|
|
throw new TypeError("gh: Must be authenticated to do that.");
|
|
}
|
|
},
|
|
|
|
// Convert an object to a url parameter string.
|
|
//
|
|
// paramify({foo:1, bar:3}) -> "foo=1&bar=3".
|
|
paramify = function (params) {
|
|
var str = "", key;
|
|
for (key in params) if (params.hasOwnProperty(key))
|
|
str += key + "=" + params[key] + "&";
|
|
return str.replace(/&$/, "");
|
|
},
|
|
|
|
// Get around how the GH team haven't migrated all the API to version 2, and
|
|
// how gists use a different api root.
|
|
withTempApiRoot = function (tempApiRoot, fn) {
|
|
return function () {
|
|
var oldRoot = apiRoot;
|
|
apiRoot = tempApiRoot;
|
|
fn.apply(this, arguments);
|
|
apiRoot = oldRoot;
|
|
};
|
|
},
|
|
|
|
// Expose the global `gh` variable, through which every API method is
|
|
// accessed, but keep a local variable around so we can reference it easily.
|
|
gh = globals.gh = {};
|
|
|
|
// Psuedo private home for JSONP callbacks (which are required to be global
|
|
// by the nature of JSONP, as discussed earlier).
|
|
gh.__jsonp_callbacks = {};
|
|
|
|
// Authenticate as a user. Does not try to validate at any point; that job
|
|
// is up to each individual method, which calls `authRequired` as needed.
|
|
gh.authenticate = function (username, token) {
|
|
authUsername = username;
|
|
authToken = token;
|
|
return this;
|
|
};
|
|
|
|
// ### Users
|
|
|
|
// The constructor for user objects. Just creating an instance of a user
|
|
// doesn't fetch any data from GitHub, you need to get explicit about what
|
|
// you want to do that.
|
|
//
|
|
// var huddlej = gh.user("huddlej");
|
|
gh.user = function (username) {
|
|
if ( !(this instanceof gh.user)) {
|
|
return new gh.user(username);
|
|
}
|
|
this.username = username;
|
|
};
|
|
|
|
// Show basic user info; you can get more info if you are authenticated as
|
|
// this user.
|
|
//
|
|
// gh.user("fitzgen").show(function (data) {
|
|
// console.log(data.user);
|
|
// });
|
|
gh.user.prototype.show = function (callback, context) {
|
|
jsonp("user/show/" + this.username, callback, context);
|
|
return this;
|
|
};
|
|
|
|
// Update a user's info. You must be authenticated as this user for this to
|
|
// succeed.
|
|
//
|
|
// TODO: example
|
|
gh.user.prototype.update = function (params) {
|
|
authRequired(this.username);
|
|
var key, postData = {
|
|
login: authUsername,
|
|
token: authToken
|
|
};
|
|
for (key in params) {
|
|
if (params.hasOwnProperty(key)) {
|
|
postData["values["+key+"]"] = encodeURIComponent(params[key]);
|
|
}
|
|
}
|
|
post("user/show/" + this.username, postData);
|
|
return this;
|
|
};
|
|
|
|
// Get a list of who this user is following.
|
|
//
|
|
// TODO: example
|
|
gh.user.prototype.following = function (callback, context) {
|
|
jsonp("user/show/" + this.username + "/following", callback, context);
|
|
};
|
|
|
|
// Find out what other users are following this user.
|
|
//
|
|
// TODO: example
|
|
gh.user.prototype.followers = function (callback, context) {
|
|
jsonp("user/show/" + this.username + "/followers", callback, context);
|
|
};
|
|
|
|
// Make this user follow some other user. You must be authenticated as this
|
|
// user for this to succeed.
|
|
//
|
|
// TODO: example
|
|
gh.user.prototype.follow = function (user) {
|
|
authRequired.call(this);
|
|
post("user/follow/" + user);
|
|
return this;
|
|
};
|
|
|
|
// Make this user quit following the given `user`. You must be authenticated
|
|
// as this user to succeed.
|
|
//
|
|
// TODO: example
|
|
gh.user.prototype.unfollow = function (user) {
|
|
authRequired.call(this);
|
|
post("user/unfollow/" + user);
|
|
return this;
|
|
};
|
|
|
|
// Get a list of repositories that this user is watching.
|
|
//
|
|
// TODO: example
|
|
gh.user.prototype.watching = function (callback, context) {
|
|
jsonp("repos/watched/" + this.username, callback, context);
|
|
return this;
|
|
};
|
|
|
|
// Get a list of this user's repositories.
|
|
//
|
|
// gh.user("fitzgen").repos(function (data) {
|
|
// alert(data.repositories.length);
|
|
// });
|
|
gh.user.prototype.repos = function (callback, context) {
|
|
gh.repo.forUser(this.username, callback, context);
|
|
return this;
|
|
};
|
|
|
|
gh.user.prototype.orgs = function (callback, context) {
|
|
gh.org.forUser(this.username, callback, context);
|
|
return this;
|
|
};
|
|
|
|
// Make this user fork the repo that lives at
|
|
// http://github.com/user/repo. You must be authenticated as this user for
|
|
// this to succeed.
|
|
//
|
|
// gh.user("fitzgen").forkRepo("brianleroux", "wtfjs");
|
|
gh.user.prototype.forkRepo = function (user, repo) {
|
|
authRequired(this.username);
|
|
post("repos/fork/" + user + "/" + repo);
|
|
return this;
|
|
};
|
|
|
|
// Get a list of all repos that this user can push to (including ones that
|
|
// they are just a collaborator on, and do not own). Must be authenticated
|
|
// as this user.
|
|
gh.user.prototype.pushable = function (callback, context) {
|
|
authRequired(authUsername);
|
|
jsonp("repos/pushable", callback, context);
|
|
};
|
|
|
|
gh.user.prototype.publicGists = withTempApiRoot(
|
|
"http://gist.github.com/api/v1/json/gists/",
|
|
function (callback, context) {
|
|
jsonp(this.username, callback, context);
|
|
return this;
|
|
}
|
|
);
|
|
|
|
// Search users for `query`.
|
|
gh.user.search = function (query, callback, context) {
|
|
jsonp("user/search/" + query, callback, context);
|
|
return this;
|
|
};
|
|
|
|
// ### Repositories
|
|
|
|
// This is the base constructor for creating repo objects. Note that this
|
|
// won't actually hit the GitHub API until you specify what data you want,
|
|
// or what action you wish to take via a prototype method.
|
|
gh.repo = function (user, repo) {
|
|
if ( !(this instanceof gh.repo)) {
|
|
return new gh.repo(user, repo);
|
|
}
|
|
this.repo = repo;
|
|
this.user = user;
|
|
};
|
|
|
|
gh.org = function(user, org) {
|
|
if (!(this instanceof gh.org)) {
|
|
return new gh.org(user, org);
|
|
}
|
|
|
|
this.org = org;
|
|
this.user = user;
|
|
};
|
|
|
|
// Get basic information on this repo.
|
|
//
|
|
// gh.repo("schacon", "grit").show(function (data) {
|
|
// console.log(data.repository.description);
|
|
// });
|
|
gh.repo.prototype.show = function (callback, context) {
|
|
jsonp("repos/show/" + this.user + "/" + this.repo, callback, context);
|
|
return this;
|
|
};
|
|
|
|
// Update the information for this repo. Must be authenticated as the
|
|
// repository owner. Params can include:
|
|
//
|
|
// * description
|
|
// * homepage
|
|
// * has_wiki
|
|
// * has_issues
|
|
// * has_downloads
|
|
gh.repo.prototype.update = function (params) {
|
|
authRequired(this.user);
|
|
var key, postData = {
|
|
login: authUsername,
|
|
token: authToken
|
|
};
|
|
for (key in params) {
|
|
if (params.hasOwnProperty(key)) {
|
|
postData["values["+key+"]"] = encodeURIComponent(params[key]);
|
|
}
|
|
}
|
|
post("repos/show/" + this.user + "/" + this.repo, postData);
|
|
return this;
|
|
};
|
|
|
|
// Get all tags for this repo.
|
|
gh.repo.prototype.tags = function (callback, context) {
|
|
jsonp("repos/show/" + this.user + "/" + this.repo + "/tags",
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Get all branches in this repo.
|
|
gh.repo.prototype.branches = function (callback, context) {
|
|
jsonp("repos/show/" + this.user + "/" + this.repo + "/branches",
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Gather line count information on the language(s) used in this repo.
|
|
gh.repo.prototype.languages = function (callback, context) {
|
|
jsonp("/repos/show/" + this.user + "/" + this.repo + "/languages",
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Gather data on all the forks of this repo.
|
|
gh.repo.prototype.network = function (callback, context) {
|
|
jsonp("repos/show/" + this.user + "/" + this.repo + "/network",
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// All users who have contributed to this repo. Pass `true` to showAnon if you
|
|
// want to see the non-github contributors.
|
|
gh.repo.prototype.contributors = function (callback, context, showAnon) {
|
|
var url = "repos/show/" + this.user + "/" + this.repo + "/contributors";
|
|
if (showAnon)
|
|
url += "/anon";
|
|
jsonp(url,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Get all of the collaborators for this repo.
|
|
gh.repo.prototype.collaborators = function (callback, context) {
|
|
jsonp("repos/show/" + this.user + "/" + this.repo + "/collaborators",
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Add a collaborator to this project. Must be authenticated.
|
|
gh.repo.prototype.addCollaborator = function (collaborator) {
|
|
authRequired(this.user);
|
|
post("repos/collaborators/" + this.repo + "/add/" + collaborator);
|
|
return this;
|
|
};
|
|
|
|
// Remove a collaborator from this project. Must be authenticated.
|
|
gh.repo.prototype.removeCollaborator = function (collaborator) {
|
|
authRequired(this.user);
|
|
post("repos/collaborators/" + this.repo + "/remove/" + collaborator);
|
|
return this;
|
|
};
|
|
|
|
// Make this repository private. Authentication required.
|
|
gh.repo.prototype.setPrivate = function () {
|
|
authRequired(this.user);
|
|
post("repo/set/private/" + this.repo);
|
|
return this;
|
|
};
|
|
|
|
// Make this repository public. Authentication required.
|
|
gh.repo.prototype.setPublic = function () {
|
|
authRequired(this.user);
|
|
post("repo/set/public/" + this.repo);
|
|
return this;
|
|
};
|
|
|
|
// Search for repositories. `opts` may include `start_page` or `language`,
|
|
// which must be capitalized.
|
|
gh.repo.search = function (query, opts, callback, context) {
|
|
var url = "repos/search/" + query.replace(" ", "+");
|
|
if (typeof opts === "function") {
|
|
opts = {};
|
|
callback = arguments[1];
|
|
context = arguments[2];
|
|
}
|
|
url += "?" + paramify(opts);
|
|
return this;
|
|
};
|
|
|
|
// Get all the repos that are owned by `user`.
|
|
gh.repo.forUser = function (user, callback, context) {
|
|
jsonp("repos/show/" + user, callback, context);
|
|
return this;
|
|
};
|
|
|
|
gh.org.forUser = function (user, callback, context) {
|
|
jsonp("user/show/" + user + "/organizations", callback, context);
|
|
return this;
|
|
};
|
|
|
|
// Create a repository. Must be authenticated.
|
|
gh.repo.create = function (name, opts) {
|
|
authRequired(authUsername);
|
|
opts.name = name;
|
|
post("repos/create", opts);
|
|
return this;
|
|
};
|
|
|
|
// Delete a repository. Must be authenticated.
|
|
gh.repo.del = function (name) {
|
|
authRequired(authUsername);
|
|
post("repos/delete/" + name);
|
|
return this;
|
|
};
|
|
|
|
// ### Commits
|
|
|
|
gh.commit = function (user, repo, sha) {
|
|
if ( !(this instanceof gh.commit) )
|
|
return new gh.commit(user, repo, sha);
|
|
this.user = user;
|
|
this.repo = repo;
|
|
this.sha = sha;
|
|
};
|
|
|
|
gh.commit.prototype.show = function (callback, context) {
|
|
jsonp("commits/show/" + this.user + "/" + this.repo + "/" + this.sha,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Get a list of all commits on a repos branch.
|
|
gh.commit.forBranch = function (user, repo, branch, callback, context) {
|
|
jsonp("commits/list/" + user + "/" + repo + "/" + branch,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Get a list of all commits on this path (file or dir).
|
|
gh.commit.forPath = function (user, repo, branch, path, callback, context) {
|
|
jsonp("commits/list/" + user + "/" + repo + "/" + branch + "/" + path,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// ### Issues
|
|
|
|
gh.issue = function (user, repo, number) {
|
|
if ( !(this instanceof gh.issue) )
|
|
return new gh.commit(user, repo, number);
|
|
this.user = user;
|
|
this.repo = repo;
|
|
this.number = number;
|
|
};
|
|
|
|
// View this issue's info.
|
|
gh.issue.prototype.show = function (callback, context) {
|
|
jsonp("issues/show/" + this.user + "/" + this.repo + "/" + this.number,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Get a list of all comments on this issue.
|
|
gh.issue.prototype.comments = function (callback, context) {
|
|
jsonp("issues/comments/" + this.user + "/" + this.repo + "/" + this.number,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Close this issue.
|
|
gh.issue.prototype.close = function () {
|
|
authRequired(this.user);
|
|
post("issues/close/" + this.user + "/" + this.repo + "/" + this.number);
|
|
return this;
|
|
};
|
|
|
|
// Reopen this issue.
|
|
gh.issue.prototype.reopen = function () {
|
|
authRequired(this.user);
|
|
post("issues/reopen/" + this.user + "/" + this.repo + "/" + this.number);
|
|
return this;
|
|
};
|
|
|
|
// Reopen this issue.
|
|
gh.issue.prototype.update = function (title, body) {
|
|
authRequired(this.user);
|
|
post("issues/edit/" + this.user + "/" + this.repo + "/" + this.number, {
|
|
title: title,
|
|
body: body
|
|
});
|
|
return this;
|
|
};
|
|
|
|
// Add `label` to this issue. If the label is not yet in the system, it will
|
|
// be created.
|
|
gh.issue.prototype.addLabel = function (label) {
|
|
post("issues/label/add/" + this.user + "/" + this.repo + "/" + label + "/" + this.number);
|
|
return this;
|
|
};
|
|
|
|
// Remove a label from this issue.
|
|
gh.issue.prototype.removeLabel = function (label) {
|
|
post("issues/label/remove/" + this.user + "/" + this.repo + "/" + label + "/" + this.number);
|
|
return this;
|
|
};
|
|
|
|
// Comment on this issue as the user that is authenticated.
|
|
gh.issue.prototype.comment = function (comment) {
|
|
authRequired(authUsername);
|
|
post("/issues/comment/" + user + "/" + repo + "/" + this.number, {
|
|
comment: comment
|
|
});
|
|
return this;
|
|
};
|
|
|
|
// Get all issues' labels for the repo.
|
|
gh.issue.labels = function (user, repo) {
|
|
jsonp("issues/labels/" + user + "/" + repo,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Open an issue. Must be authenticated.
|
|
gh.issue.open = function (repo, title, body) {
|
|
authRequired(authUsername);
|
|
post("issues/open/" + authUsername + "/" + repo, {
|
|
title: title,
|
|
body: body
|
|
});
|
|
return this;
|
|
};
|
|
|
|
// Search a repository's issue tracker. `state` can be "open" or "closed".
|
|
gh.issue.search = function (user, repo, state, query, callback, context) {
|
|
jsonp("/issues/search/" + user + "/" + repo + "/" + state + "/" + query,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Get a list of issues for the given repo. `state` can be "open" or
|
|
// "closed".
|
|
gh.issue.list = function (user, repo, state, callback, context) {
|
|
jsonp("issues/list/" + user + "/" + repo + "/" + state,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// ### Gists
|
|
|
|
gh.gist = function (id) {
|
|
if ( !(this instanceof gh.gist) ) {
|
|
return new gh.gist(id);
|
|
}
|
|
this.id = id;
|
|
};
|
|
|
|
gh.gist.prototype.show = withTempApiRoot(
|
|
"http://gist.github.com/api/v1/json/",
|
|
function (callback, context) {
|
|
jsonp(this.id, callback, cont);
|
|
return this;
|
|
}
|
|
);
|
|
|
|
gh.gist.prototype.file = withTempApiRoot(
|
|
"http://gist.github.com/raw/v1/json/",
|
|
function (filename, callback, context) {
|
|
jsonp(this.id + "/" + filename, callback, cont);
|
|
return this;
|
|
}
|
|
);
|
|
|
|
// ### Objects
|
|
|
|
gh.object = function (user, repo) {
|
|
if (!(this instanceof gh.object)) {
|
|
return new gh.object(user, repo);
|
|
}
|
|
this.user = user;
|
|
this.repo = repo;
|
|
};
|
|
|
|
// Get the contents of a tree by tree SHA
|
|
gh.object.prototype.tree = function (sha, callback, context) {
|
|
jsonp("tree/show/" + this.user + "/" + this.repo + "/" + sha,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Get the data about a blob by tree SHA and path
|
|
gh.object.prototype.blob = function (path, sha, callback, context) {
|
|
jsonp("blob/show/" + this.user + "/" + this.repo + "/" + sha + "/" + path,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Get only blob meta
|
|
gh.object.prototype.blobMeta = function (path, sha, callback, context) {
|
|
jsonp("blob/show/" + this.user + "/" + this.repo + "/" + sha + "/" + path + "?meta=1",
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Get list of blobs
|
|
gh.object.prototype.blobAll = function (branch, callback, context) {
|
|
jsonp("blob/all/" + this.user + "/" + this.repo + "/" + branch,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// Get meta of each blob in tree
|
|
gh.object.prototype.blobFull = function (sha, callback, context) {
|
|
jsonp("blob/full/" + this.user + "/" + this.repo + "/" + sha,
|
|
callback,
|
|
context);
|
|
return this;
|
|
};
|
|
|
|
// ### Network
|
|
|
|
gh.network = function(user, repo) {
|
|
if (!(this instanceof gh.network)) {
|
|
return new gh.network(user, repo);
|
|
}
|
|
this.user = user;
|
|
this.repo = repo;
|
|
};
|
|
|
|
gh.network.prototype.data = withTempApiRoot(
|
|
"http://github.com/",
|
|
function (nethash, start, end, callback, context) {
|
|
jsonp(this.user + "/" + this.repo + "/network_data_chunk?"
|
|
+ nethash + "&" + start + "&" + end,
|
|
callback,
|
|
context);
|
|
return this;
|
|
}
|
|
);
|
|
|
|
gh.network.prototype.meta = withTempApiRoot(
|
|
"http://github.com/",
|
|
function (callback, context) {
|
|
jsonp(this.user + "/" + this.repo + "/network_meta",
|
|
callback,
|
|
context);
|
|
return this;
|
|
}
|
|
);
|
|
|
|
}(window));
|