Skip to content

Instantly share code, notes, and snippets.

@subversivo58
Forked from iktash/GithubApiPush.js
Last active May 31, 2023 16:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save subversivo58/9ad5273e931b3c223c4826c5ef5403f5 to your computer and use it in GitHub Desktop.
Save subversivo58/9ad5273e931b3c223c4826c5ef5403f5 to your computer and use it in GitHub Desktop.
Upload a binary data to your repository

Minimal example of upload binary file to GitHub repository

<input id="file" type="file" name="file">

<!-- standalone GitHub.js (all dependencies included) -->
<script src="path/to/modified-version-of/GitHub.js"></script>
<!-- GithubApiPush.js -->
<script src="path/to/GithubApiPush.js"></script>
// instance of GitHub API ({username:'', password:''} or {token:''})
let api = new GitHubAPI({
    token: 'GHMasterTokem-xxxxxxxx'
})

// define repository (username + repository)
api.setRepo('username', 'repository')

// define branch (branch name)
api.setBranch('master')

// `<input>` element
const inputFile = document.getElementById('file')

// file change event
inputFile.addEventListener('change', function(evt) {
     if ( event.target.files.length > 0 ) {
         let fileReader = new FileReader()
         fileReader.onload = function(e) {
             let content = e.target.result
             // send binary file
             api.pushFile('your commit message', [
                 {
                     content: {
                         content: content.replace(/^(.+,)/, ''), // clear (remove mime-type)
                         encoding: 'base64'
                     },
                     path: 'path/in/your-repo/filename.extension'
                 }
             ]).then(console.log).catch(console.error)
         }
         fileReader.readAsDataURL(event.target.files[0])
     }
}, false)

Note that the wrapper above is only for uploading a binary file to your GitHub repository.

If you want to use the rest of the functionalities of the GitHub.js library without having to create a new instance you can do as in the example below:

// instance of GitHub API ({username:'', password:''} or {token:''})
let api = new GitHubAPI({
    token: 'GHMasterTokem-xxxxxxxx'
})

// instance of GitHub.js
let gh = api.GHInstance

// get repo from GitHub.js 
let repo = gh.getRepo('username', 'repository');

// current user
let me = gh.getUser()
me.listNotifications(function(err, notifications) {
     // do some stuff
})

// or direct access (less prone to reuse)
let me = api.GHInstance.getUser()
me.listNotifications(function(err, notifications) {
     // do some stuff
})

// rest of traditional operations at `gh` ....

Enjoy 🚀

/**
* Wraper to upload binary files to GitHub repo
* Uses the modified GitHub library under the hood and exposes it as `GHInstance` property for get instance of all methods
* @note:
* -- inspired at article: @see <https://medium.freecodecamp.org/pushing-a-list-of-files-to-the-github-with-javascript-b724c8c09b66>
* -- issue (not yet resolved): @see issue <https://github.com/github-tools/github/issues/417>
* @copyright Copyright (c) 2020 Lauro Moraes <https://github.com/subversivo58>
* @license MIT License <https://github.com/subversivo58/subversivo58.github.io/blob/master/LICENSE>
*/
const GithubAPI = function(auth) {
let repo,
filesToCommit = [],
currentBranch = {},
newCommit = {},
//the underlying library for making requests
gh = new GitHub(auth)
/**
* Get current instance of GitHub library (very suggestive method name)
* @public
* @return {Object} instanceof GitHub
*/
this.GHInstance = gh
/**
* Sets the current repository to make push to
* @public
* @param {string} userName Name of the user who owns the repository
* @param {string} repoName Name of the repository
* @return void
*/
this.setRepo = (userName, repoName) => {
repo = gh.getRepo(userName, repoName)
}
/**
* Sets the current branch to make push to. If the branch doesn't exist yet,
* it will be created first
* @public
* @param {string} branchName The name of the branch
* @return {Promise}
*/
this.setBranch = branchName => {
if ( !repo ) {
throw 'Repository is not initialized'
}
return repo.listBranches().then(branches => {
let branchExists = branches.data.find( branch => branch.name === branchName )
if ( !branchExists ) {
return repo.createBranch('master', branchName).then(() => {
currentBranch.name = branchName
})
} else {
currentBranch.name = branchName
}
})
}
/**
* Makes the push to the currently set branch
* @public
* @param {string} message Message of the commit
* @param {object[]} files Array of objects (with keys 'content' and 'path'),
* containing data to push
* @return {Promise}
*/
this.pushFiles = (message, files) => {
if ( !repo ) {
throw 'Repository is not initialized'
}
if ( !currentBranch.hasOwnProperty('name') ) {
throw 'Branch is not set'
}
return getCurrentCommitSHA()
.then(getCurrentTreeSHA)
.then( () => createFiles(files) )
.then(createTree)
.then( () => createCommit(message) )
.then(updateHead)
.catch(e => {
console.error(e)
})
}
/**
* Sets the current commit's SHA
* @private
* @return {Promise}
*/
const getCurrentCommitSHA = () => {
return repo.getRef('heads/' + currentBranch.name).then(ref => {
currentBranch.commitSHA = ref.data.object.sha
})
}
/**
* Sets the current commit tree's SHA
* @private
* @return {Promise}
*/
const getCurrentTreeSHA = () => {
return repo.getCommit(currentBranch.commitSHA).then(commit => {
currentBranch.treeSHA = commit.data.tree.sha
})
}
/**
* Creates blobs for all passed files
* @private
* @param {object[]} filesInfo Array of objects (with keys 'content' and 'path'),
* containing data to push
* @return {Promise}
*/
const createFiles = filesInfo => {
let promises = [],
length = filesInfo.length
for (let i = 0; i < length; i++) {
promises.push(createFile(filesInfo[i]))
}
return Promise.all(promises)
}
/**
* Creates a blob for a single file
* @private
* @param {object} fileInfo Array of objects (with keys 'content' and 'path'),
* containing data to push
* @return {Promise}
*/
const createFile = fileInfo => {
return repo.createBlob(fileInfo.content).then(blob => {
filesToCommit.push({
sha: blob.data.sha,
path: fileInfo.path,
mode: '100644',
type: 'blob'
})
})
}
/**
* Creates a new tree
* @private
* @return {Promise}
*/
const createTree = () => {
return repo.createTree(filesToCommit, currentBranch.treeSHA).then(tree => {
newCommit.treeSHA = tree.data.sha
})
}
/**
* Creates a new commit
* @private
* @param {string} message A message for the commit
* @return {Promise}
*/
const createCommit = message => {
return repo.commit(currentBranch.commitSHA, newCommit.treeSHA, message).then(commit => {
newCommit.sha = commit.data.sha
})
}
/**
* Updates the pointer of the current branch to point the newly created commit
* @private
* @return {Promise}
*/
const updateHead = () => {
return repo.updateHead('heads/' + currentBranch.name, newCommit.sha)
}
}
/**
* Compressed from https://jscompress.com/ [ECMAScript 2018 (via Babili)]
*/
const GithubAPI=function(a){let b,c=[],d={},f={},g=new GitHub(a);this.GHInstance=g,this.setRepo=(p,q)=>{b=g.getRepo(p,q)},this.setBranch=p=>{if(!b)throw'Repository is not initialized';return b.listBranches().then(q=>{let r=q.data.find(s=>s.name===p);return r?void(d.name=p):b.createBranch('master',p).then(()=>{d.name=p})})},this.pushFiles=(p,q)=>{if(!b)throw'Repository is not initialized';if(!d.hasOwnProperty('name'))throw'Branch is not set';return h().then(j).then(()=>k(q)).then(m).then(()=>n(p)).then(o).catch(r=>{console.error(r)})};const h=()=>{return b.getRef('heads/'+d.name).then(p=>{d.commitSHA=p.data.object.sha})},j=()=>{return b.getCommit(d.commitSHA).then(p=>{d.treeSHA=p.data.tree.sha})},k=p=>{let q=[],r=p.length;for(let s=0;s<r;s++)q.push(l(p[s]));return Promise.all(q)},l=p=>{return b.createBlob(p.content).then(q=>{c.push({sha:q.data.sha,path:p.path,mode:'100644',type:'blob'})})},m=()=>{return b.createTree(c,d.treeSHA).then(p=>{f.treeSHA=p.data.sha})},n=p=>{return b.commit(d.commitSHA,f.treeSHA,p).then(q=>{f.sha=q.data.sha})},o=()=>{return b.updateHead('heads/'+d.name,f.sha)}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment