octonode is a library for nodejs to access the github v3 api
npm install octonode
var github = require('octonode');
// Then we instantiate a client with or without a token (as show in a later section)
var ghme = client.me();
var ghuser = client.user('pksunkara');
var ghrepo = client.repo('pksunkara/hub');
var ghorg = client.org('flatiron');
var ghissue = client.issue('pksunkara/hub', 37);
var ghmilestone = client.milestone('pksunkara/hub', 37);
var ghlabel = client.label('pksunkara/hub', 'todo');
var ghpr = client.pr('pksunkara/hub', 37);
var ghrelease = client.release('pksunkara/hub', 37);
var ghgist = client.gist();
var ghteam = client.team(37);
var ghproject = client.project(37);
var ghnotification = client.notification(37);
var ghsearch = client.search();var client = github.client();
client.get('/users/pksunkara', {}, function (err, status, body, headers) {
console.log(body); //json object
});var client = github.client('some_access_token');
client.get('/user', {}, function (err, status, body, headers) {
console.log(body); //json object
});You can configure the protocol, hostname and port to use. For example to connect to a GitHub Enterprise instance.
var client = github.client('some_access_token', {
hostname: 'mydomain.com/api/v3'
});
client.get('/user', {}, function (err, status, body, headers) {
console.log(body); //json object
});Request options can be set by setting defaults on the client. (e.g. Proxies)
var client = github.client();
client.requestDefaults['proxy'] = 'https://myproxy.com:1085'These options are passed through to request, see their API here: https://github.com/request/request#requestoptions-callback
You can set proxies dynamically by using the example above, but Octonode will respect environment proxies by default. Just set this using:
export HTTP_PROXY='https://myproxy.com:1085' if you are using the command line
Many of the below use cases use parts of the above code
The client supports conditional requests and helps you respecting rate limits by caching information that hasn't changed.
You can add the If-None-Match header to each request calling the conditional method.
var client = github.client();
// This add If-None-Match header to the request
github.repo().conditional('ETAG').issues();More info about conditional requests can be founded here.
Note: Ensure that the scopes argument is an object containing the required note property. For two-factor authentication add the One Time Password otp key with its corresponding code to the configuration object.
var scopes = {
'scopes': ['user', 'repo', 'gist'],
'note': 'admin script'
};
github.auth.config({
username: 'pksunkara',
password: 'password'
}).login(scopes, function (err, id, token, headers) {
console.log(id, token);
});// Web application which authenticates to github
var http = require('http')
, url = require('url')
, qs = require('querystring')
, github = require('octonode');
// Build the authorization config and url
var auth_url = github.auth.config({
id: 'mygithubclientid',
secret: 'mygithubclientsecret',
apiUrl: 'https://optional-internal-github-enterprise/api/v3',
webUrl: 'https://optional-internal-github-enterprise'
}).login(['user', 'repo', 'gist']);
// Store info to verify against CSRF
var state = auth_url.match(/&state=([0-9a-z]{32})/i);
// Web server
http.createServer(function (req, res) {
uri = url.parse(req.url);
// Redirect to github login
if (uri.pathname=='/login') {
res.writeHead(302, {'Content-Type': 'text/plain', 'Location': auth_url})
res.end('Redirecting to ' + auth_url);
}
// Callback url from github login
else if (uri.pathname=='/auth') {
var values = qs.parse(uri.query);
// Check against CSRF attacks
if (!state || state[1] != values.state) {
res.writeHead(403, {'Content-Type': 'text/plain'});
res.end('');
} else {
github.auth.login(values.code, function (err, token, headers) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(token);
});
}
} else {
res.writeHead(200, {'Content-Type': 'text/plain'})
res.end('');
}
}).listen(3000);
console.log('Server started on 3000');You can also check your rate limit status by calling the following.
client.limit(function (err, left, max, reset) {
console.log(left); // 4999
console.log(max); // 5000
console.log(reset); // 1372700873 (UTC epoch seconds)
});All the callbacks for the following will take first an error argument, then a data argument, like this:
ghme.info(function(err, data, headers) {
console.log("error: " + err);
console.log("data: " + data);
console.log("headers:" + headers);
});If you would like to work with promises rather than callbacks, you can call the promise based version of any of the api calls by appending Async to the function call.
For example prs() becomes prsAsync() like this:
async function getPullRequests () {
const client = github.client(config.githubAccessToken)
const repo = client.repo('pksunkara/octonode')
const result = await repo.prsAsync({ per_page: 100 })
return result[0]
}If a function is said to be supporting pagination, then that function can be used in many ways as shown below. Results from the function are arranged in pages.
The page argument is optional and is used to specify which page of issues to retrieve. The perPage argument is also optional and is used to specify how many issues per page.
// Normal usage of function
ghrepo.issues(callback); //array of first 30 issues
// Using pagination parameters
ghrepo.issues(2, 100, callback); //array of second 100 issues
ghrepo.issues(10, callback); //array of 30 issues from page 10
// Pagination parameters can be set with query object too
ghrepo.issues({
page: 2,
per_page: 100, //maximum is 100
state: 'closed'
}, callback); //array of second 100 issues which are closedToken/Credentials required for the following:
ghme.info(callback); //jsonghme.update({
"name": "monalisa octocat",
"email": "octocat@github.com",
}, callback);ghme.emails(callback); //array of emailsghme.emails(['new1@ma.il', 'new2@ma.il'], callback); //array of emails
ghme.emails('new@ma.il', callback); //array of emailsghme.emails(['new1@ma.il', 'new2@ma.il']);
ghme.emails('new@ma.il');ghme.followers(callback); //array of github usersThis query supports pagination.
ghme.following(callback); //array of github usersghme.following('marak', callback); //booleanghme.follow('marak');ghme.unfollow('marak');ghme.keys(callback); //array of keysghme.keys(1, callback); //keyghme.keys({"title":"laptop", "key":"ssh-rsa AAA..."}, callback); //keyghme.keys(1, {"title":"desktop", "key":"ssh-rsa AAA..."}, callback); //keyghme.keys(1);This query supports pagination.
ghme.starred(callback); //array of reposghme.checkStarred('flatiron/flatiron', callback); //booleanghme.star('flatiron/flatiron');ghme.unstar('flatiron/flatiron');This query supports pagination.
ghme.watched(callback); //array of reposThis query supports pagination.
ghme.orgs(callback); //array of orgsThis query supports pagination.
ghme.repos(callback); //array of reposghme.repo({
"name": "Hello-World",
"description": "This is your first repo",
}, callback); //repoghme.fork('pksunkara/hub', callback); //forked repoThis query supports pagination.
ghme.issues({
page: 2,
per_page: 100,
filter: 'assigned',
state: 'open',
sort: 'created'
}, callback); //array of issuesThis query supports pagination.
ghme.teams({
page: 1,
per_page: 50
}, callback); //array of team membershipsOptions based on http://git.io/vYYOx
ghme.notifications({}, callback); //array of notificationsNo token required for the following
ghuser.info(callback); //jsonThis query supports pagination.
ghuser.followers(callback); //array of github usersThis query supports pagination.
ghuser.following(callback); //array of github usersThis query supports pagination.
ghuser.repos(callback); //array of public github reposThis query supports pagination.
Optionally, supply an array of Event Types to filter by.
ghuser.events(['PushEvent'], callback); //array of PushEvent eventsOr leave it out to get all Event Types.
ghuser.events(callback); //array of eventsThis query supports pagination.
ghuser.orgs(callback); //array of organizationsghrepo.info(callback); //jsonghrepo.update({
private: false
}, callback); // repoghrepo.collaborators(callback); //array of github usersghrepo.collaborators('marak', callback); //booleanghrepo.commits(callback); //array of commitsghrepo.commit('18293abcd72', callback); //commitGet a comparison between branches for a repository (GET /repos/pksunkara/hub/compare/master...develop)
ghrepo.compare('master', 'develop', callback); //compare develop to masterghrepo.tags(callback); //array of tagsghrepo.releases(callback); //array of releasesghrepo.languages(callback); //array of languagesghrepo.contributors(callback); //array of github usersThis query supports pagination.
ghrepo.branches(callback); //array of branchesghrepo.branch('master', callback); //branchghrepo.createReference('master', '18293abcd72', callback);This query supports pagination.
ghrepo.issues(callback); //array of issuesghrepo.issue({
"title": "Found a bug",
"body": "I'm having a problem with this.",
"assignee": "octocat",
"milestone": 1,
"labels": ["Label1", "Label2"]
}, callback); //issueThis query supports pagination.
ghrepo.milestones(callback); //array of milestonesghrepo.milestone({
"title": "Sprint 345",
"description": "The sprint where we fix all the things!",
"due_on": new Date(2014, 7, 1)
}, callback); //milestoneThis query supports pagination.
ghrepo.projects(callback); //array of projectsghrepo.project({
"name": "Sprint 345",
"body": "The sprint where we fix all the things!"
}, callback); //projectThis query supports pagination.
ghrepo.labels(callback); //array of labelsghrepo.label({
"name": "Priority",
"color": "ff0000",
}, callback); //labelThis query supports pagination.
ghrepo.prs(callback); //array of pull requestsghrepo.pr({
"title": "Amazing new feature",
"body": "Please pull this in!",
"head": "octocat:new-feature",
"base": "master"
}, callback); //pull requestThis query supports pagination.
ghrepo.hooks(callback); //array of hooksghrepo.hook({
"name": "web",
"active": true,
"events": ["push", "pull_request"],
"config": {
"url": "http://myawesomesite.com/github/events"
}
}, callback); // hookghrepo.deleteHook(37, callback);ghrepo.readme(callback); //file
ghrepo.readme('v0.1.0', callback); //fileghrepo.contents('', "myBranch", callback);ghrepo.contents('lib/index.js', callback); //path
ghrepo.contents('lib/index.js', 'v0.1.0', callback); //pathghrepo.createContents('lib/index.js', 'commit message', 'content', callback); //path
ghrepo.createContents('lib/index.js', 'commit message', 'content', 'v0.1.0', callback); //pathghrepo.updateContents('lib/index.js', 'commit message', 'content', 'put-sha-here', callback); //path
ghrepo.updateContents('lib/index.js', 'commit message', 'content', 'put-sha-here', 'master', callback); //path
ghrepo.updateContents('lib/index.js', 'commit message', 'content', 'put-sha-here', 'v0.1.0', callback); //pathghrepo.deleteContents('lib/index.js', 'commit message', 'put-sha-here', callback); //path
ghrepo.deleteContents('lib/index.js', 'commit message', 'put-sha-here', 'v0.1.0', callback); //pathghrepo.archive('tarball', callback); //link to archive
ghrepo.archive('zipball', 'v0.1.0', callback); //link to archiveghrepo.blob('18293abcd72', callback); //blobghrepo.stargazers(1, 100, callback); //array of users
ghrepo.stargazers(10, callback); //array of users
ghrepo.stargazers(callback); //array of usersghrepo.teams(callback); //array of teamsghrepo.tree('18293abcd72', callback); //tree
ghrepo.tree('18293abcd72', true, callback); //recursive treeghrepo.destroy();ghrepo.statuses('master', callback); //array of statusesghrepo.combinedStatus('master', callback); //array of statusesghrepo.status('18e129c213848c7f239b93fe5c67971a64f183ff', {
"state": "success",
"target_url": "http://ci.mycompany.com/job/hub/3",
"description": "Build success."
}, callback); // created statusghnotification.markAsRead(callback);ghnotification.subscribe(callback);ghnotification.unsubscribe(callback);ghnotification.mute(callback);ghorg.info(callback); //jsonghorg.update({
blog: 'https://blog.com'
}, callback); // orgThis query supports pagination.
ghorg.repos(callback); //array of reposghorg.repo({
name: 'Hello-world',
description: 'My first world program'
}, callback); //repoThis query supports pagination.
ghorg.teams(callback); //array of teamsThis query supports pagination.
ghorg.members(callback); //array of github usersghorg.member('pksunkara', callback); //booleanghorg.publicMember('pksunkara', callback); //booleanghorg.publicizeMembership('pksunkara', callback);ghorg.concealMembership('pksunkara', callback);ghorg.membership('pksunkara', callback); //membership status object indicating state, role, etc.ghorg.createTeam({
"name": "new team name",
"permission": "push",
"repo_names": [
"flatiron/utile"
]
}, callback);This query supports pagination.
ghorg.hooks(callback); //array of hooksghorg.hook({
"name": "web",
"active": true,
"events": ["push", "pull_request"],
"config": {
"url": "http://myawesomesite.com/github/events"
}
}, callback); // hookghorg.deleteHook(37, callback);ghissue.info(callback); //issueghissue.update({
"title": "Found a bug and I am serious",
}, callback); //issueThis query supports pagination.
ghissue.comments(callback); //array of commentsghissue.createComment({
body: 'Me too.'
}, callback);ghissue.updateComment(3, {
body: 'The updated body of the comment.'
}, callback);ghissue.deleteComment(3, callback);ghissue.labels(callback);ghissue.addLabels(['label-name'], callback);ghissue.replaceAllLabels(['label-name'], callback);ghissue.removeLabel('label-name', callback);ghissue.removeAllLabels(callback);ghmilestone.info(callback); //milestoneghmilestone.update({
"title": "Updated milestone title",
}, callback); //milestoneghmilestone.delete(callback); //milestoneghproject.info(callback); //projectghproject.update({
"name": "Updated project name",
}, callback); //projectghproject.delete(callback); //projectghlabel.info(callback); //labelghlabel.update({
"color": "000000",
}, callback); //labelghlabel.delete(callback); //labelghrepo.merge({ base: baseBranch, head: destinationBranch }, callback);ghpr.info(callback); //pull requestghpr.update({
'title': 'Wow this pr'
}, callback); //pull requestghpr.close(callback); //pull requestghpr.merged(callback); //booleanghpr.commits(callback); //array of commitsghpr.comments(callback); //array of commentsghpr.createComment({
body: 'my comment',
commit_id: '8cde3b6c5be2c3067cd87ee4117c0f65e30f3e1f', // needed to comment on current time in PR
path: 'file.txt', // optional
position: 4 // optional
}, callback);ghpr.removecomment(104, callback);ghpr.files(callback); //array of filesghpr.reviews(callback); //array of pull request reviewsghpr.review(104, callback); //pull request reviewghpr.removeReview(104, callback); //pull request reviewghpr.reviewComments(104, callback); //array of review commentsghpr.createReview({
body: 'review message', // optional
comments: [ // optional
{
body: 'comment message', // required for each optional comment
path: 'file.txt', // required for each optional comment
position: 4 // required for each optional comment
}
],
event: 'APPROVE || COMMENT || REQUEST_CHANGES' // optional
}, callback); //pull request reviewghpr.submitReview(104, {
body: 'review message', // optional
event: 'APPROVE || COMMENT || REQUEST_CHANGES' // required
}, callback); //pull request reviewghpr.dismissReview(104, 'dismissal message', callback); //pull request reviewghpr.reviewRequests(callback); //array of review requestsghpr.createReviewRequests(['user1', 'user2'], callback); //pull requestghpr.removeReviewRequests(['user1', 'user2'], callback); //pull requestghrepo.release({
tag_name: 'v1.0.0',
draft: true
}, callback);Upload assets in a release (POST /uploads.github.com/repos/pksunkara/hub/releases/37/assets?name=archve-v0.0.1.zip)
var archive = fs.readFileSync(__dirname, 'archive-v0.0.1.zip');
// Will upload a file with the default options
/*
{
name: 'archive.zip',
contentType: 'application/zip',
uploadHost: 'uploads.github.com'
}
*/
ghrelease.uploadAssets(archive, callback);
// Will upload a file with your custom options
var image = fs.readFileSync(__dirname, 'octonode.png');
var options = {
name: 'octonode.png',
contentType: 'image/png',
uploadHost: 'uploads.github.com'
};
ghrelease.uploadAssets(image, options, callback)This query supports pagination.
ghgist.list(callback); //array of gistsThis query supports pagination.
ghgist.public(callback); //array of gistsThis query supports pagination.
ghgist.starred(callback); //array of gistsThis query supports pagination.
ghgist.user('pksunkara', callback); //array of gistsghgist.get(37, callback); //gistghgist.create({
description: "the description",
files: { ... }
}), callback); //gistghgist.edit(37, {
description: "hello gist"
}, callback); //gistghgist.delete(37);ghgist.fork(37, callback); //gistghgist.star(37);ghgist.unstar(37);ghgist.check(37); //booleanghgist.comments(37, callback); //array of commentsghgist.comments(37, {
body: "Just commenting"
}, callback); //commentghgist.comment(1, callback); //commentghgist.comment(1, {
body: "lol at commenting"
}, callback); //commentghgist.comment(1);ghteam.info(callback); //jsonghteam.members(callback); //array of github usersghteam.member('pksunkara', callback); //booleanghteam.addUser("pksunkara", callback); //booleanghteam.removeUser("pksunkara", callback); //booleanghteam.membership("pksunkara", callback); //booleanghteam.addMembership("pksunkara", callback); //booleanghteam.removeMembership("pksunkara", callback); //booleanghteam.repos(callback); //array of reposghteam.removeRepo("flatiron/hub", callback);ghteam.destroy(callback);ghsearch.issues({
q: 'windows+state:open+repo:pksunkara/hub',
sort: 'created',
order: 'asc'
}, callback); //array of search resultsghsearch.repos({
q: 'hub+language:go',
sort: 'created',
order: 'asc'
}, callback); //array of search resultsghsearch.users({
q: 'tom+followers:>100',
sort: 'created',
order: 'asc'
}, callback); //array of search resultsghsearch.code({
q: 'auth+in:file+repo:pksunkara/hub',
sort: 'created',
order: 'asc'
}, callback); //array of search resultsThis query supports pagination.
Note: For listing all Organizations / Users pagination is powered exclusively by the since parameter
( Github APIs ) .
since denotes the login ID of last org / user you encountered. Also, note that it's important to pass
true as third param when using pagination.
Organizations
var client = github.client();
client.get('/organizations', callback);
// OR
client.get('/organizations', since, per_page, true, callback);Users
var client = github.client();
client.get('/users', callback);
// OR
client.get('/users', since, per_page, true, callback);Before run test copy the config.example.json file in test folder to config.json and populate it with your github information.
Is suggested to fork https://github.com/octocat/Spoon-Knife repo and run test on your copy.
npm test
If you like this project, please watch this and follow me.
Here is a list of Contributors
The following method names use underscore as an example. The library contains camel cased method names.
// public repos for unauthenticated, private and public for authenticated
me.get_watched_repositories(callback);
me.is_watching('repo', callback);
me.start_watching('repo', callback);
me.stop_watching('repo', callback);
// organization data
var org = octonode.Organization('bulletjs');
org.update(dict_with_update_properties, callback);
org.get_public_members(callback);
org.is_public_member('user', callback);
org.make_member_public('user', callback);
org.conceal_member('user', callback);
org.get_team('team', callback);
org.create_team({name:'', repo_names:'', permission:''}, callback);
org.edit_team({name:'', permission:''}, callback);
org.delete_team('name', callback);
org.get_team_members('team', callback);
org.get_team_member('team', 'user', callback);
org.remove_member_from_team('user', 'team', callback);
org.get_repositories(callback);
org.create_repository({name: ''}, callback);
org.get_team_repositories('team', callback);
org.get_team_repository('team', 'name', callback);
org.add_team_repository('team', 'name', callback);
org.remove_team_repository('team', 'name', callback);
var repo = octonode.Repository('pksunkara/octonode');
repo.update({name: ''}, callback);
// collaborator information
repo.add_collaborator('name', callback);
repo.remove_collaborator('name', callback);
// commit data
repo.get_commit('sha-id', callback);
repo.get_all_comments(callback);
repo.get_commit_comments('SHA ID', callback);
repo.comment_on_commit({body: '', commit_id: '', line: '', path: '', position: ''}, callback);
repo.get_single_comment('comment id', callback);
repo.edit_single_comment('comment id', callback);
repo.delete_single_comment('comment id', callback);
// downloads
repo.get_downloads(callback);
repo.get_download(callback);
repo.create_download({name: ''}, 'filepath', callback);
repo.delete_download(callback);
// keys
repo.get_deploy_keys(callback);
repo.get_deploy_key('id', callback);
repo.create_deploy_key({title: '', key: ''}, callback);
repo.edit_deploy_key({title: '', key: ''}, callback);
repo.delete_deploy_key('id', callback);
// watcher data
repo.get_watchers(callback);
// pull requests
repo.get_all_pull_request_comments(callback);
repo.get_pull_request_comment('id', callback);
repo.reply_to_pull_request_comment('id', 'body', callback);
repo.edit_pull_request_comment('id', 'body', callback);
repo.get_issues(params, callback);
repo.get_issue('id', callback);
repo.create_issue({title: ''}, callback);
repo.edit_issue({title: ''}, callback);
repo.get_issue_comments('issue', callback);
repo.get_issue_comment('id', callback);
repo.create_issue_comment('id', 'comment', callback);
repo.edit_issue_comment('id', 'comment', callback);
repo.delete_issue_comment('id', callback);
repo.get_issue_events('id', callback);
repo.get_events(callback);
repo.get_event('id', callback);
repo.get_labels(callback);
repo.get_label('id', callback);
repo.create_label('name', 'color', callback);
repo.edit_label('name', 'color', callback);
repo.delete_label('id', callback);
repo.get_labels_for_milestone_issues('milestone', callback);
repo.get_milestones(callback);
repo.get_milestone('id', callback);
repo.create_milestone('title', callback);
repo.edit_milestone('title', callback);
repo.delete_milestone('id', callback);
// raw git access
repo.create_blob('content', 'encoding', callback);
repo.get_commit('sha-id', callback);
repo.create_commit('message', 'tree', [parents], callback);
repo.get_reference('ref', callback);
repo.get_all_references(callback);
repo.update_reference('ref', 'sha', force, callback);I accept pull requests
MIT/X11
Report here.
Pavan Kumar Sunkara (pavan.sss1991@gmail.com)