Repository.js

/**
 * @file
 * @copyright  2013 Michael Aufreiter (Development Seed) and 2016 Yahoo Inc.
 * @license    Licensed under {@link https://spdx.org/licenses/BSD-3-Clause-Clear.html BSD-3-Clause-Clear}.
 *             Github.js is freely distributable.
 */

import Requestable from './Requestable';
import Utf8 from 'utf8';
import {
   Base64,
} from 'js-base64';
import debug from 'debug';
const log = debug('github:repository');

/**
 * Respository encapsulates the functionality to create, query, and modify files.
 */
class Repository extends Requestable {
   /**
    * Create a Repository.
    * @param {string} fullname - the full name of the repository
    * @param {Requestable.auth} [auth] - information required to authenticate to Github
    * @param {string} [apiBase=https://api.github.com] - the base Github API URL
    */
   constructor(fullname, auth, apiBase) {
      super(auth, apiBase);
      this.__fullname = fullname;
      this.__currentTree = {
         branch: null,
         sha: null,
      };
   }

   /**
    * Get a reference
    * @see https://developer.github.com/v3/git/refs/#get-a-reference
    * @param {string} ref - the reference to get
    * @param {Requestable.callback} [cb] - will receive the reference's refSpec or a list of refSpecs that match `ref`
    * @return {Promise} - the promise for the http request
    */
   getRef(ref, cb) {
      return this._request('GET', `/repos/${this.__fullname}/git/refs/${ref}`, null, cb);
   }

   /**
    * Create a reference
    * @see https://developer.github.com/v3/git/refs/#create-a-reference
    * @param {Object} options - the object describing the ref
    * @param {Requestable.callback} [cb] - will receive the ref
    * @return {Promise} - the promise for the http request
    */
   createRef(options, cb) {
      return this._request('POST', `/repos/${this.__fullname}/git/refs`, options, cb);
   }

   /**
    * Delete a reference
    * @see https://developer.github.com/v3/git/refs/#delete-a-reference
    * @param {string} ref - the name of the ref to delte
    * @param {Requestable.callback} [cb] - will receive true if the request is successful
    * @return {Promise} - the promise for the http request
    */
   deleteRef(ref, cb) {
      return this._request('DELETE', `/repos/${this.__fullname}/git/refs/${ref}`, null, cb);
   }

   /**
    * Delete a repository
    * @see https://developer.github.com/v3/repos/#delete-a-repository
    * @param {Requestable.callback} [cb] - will receive true if the request is successful
    * @return {Promise} - the promise for the http request
    */
   deleteRepo(cb) {
      return this._request('DELETE', `/repos/${this.__fullname}`, null, cb);
   }

   /**
    * List the tags on a repository
    * @see https://developer.github.com/v3/repos/#list-tags
    * @param {Requestable.callback} [cb] - will receive the tag data
    * @return {Promise} - the promise for the http request
    */
   listTags(cb) {
      return this._request('GET', `/repos/${this.__fullname}/tags`, null, cb);
   }

   /**
    * List the open pull requests on the repository
    * @see https://developer.github.com/v3/pulls/#list-pull-requests
    * @param {Object} options - options to filter the search
    * @param {Requestable.callback} [cb] - will receive the list of PRs
    * @return {Promise} - the promise for the http request
    */
   listPullRequests(options, cb) {
      options = options || {};
      return this._request('GET', `/repos/${this.__fullname}/pulls`, options, cb);
   }

   /**
    * Get information about a specific pull request
    * @see https://developer.github.com/v3/pulls/#get-a-single-pull-request
    * @param {number} number - the PR you wish to fetch
    * @param {Requestable.callback} [cb] - will receive the PR from the API
    * @return {Promise} - the promise for the http request
    */
   getPullRequest(number, cb) {
      return this._request('GET', `/repos/${this.__fullname}/pulls/${number}`, null, cb);
   }

   /**
    * List the files of a specific pull request
    * @see https://developer.github.com/v3/pulls/#list-pull-requests-files
    * @param {number|string} number - the PR you wish to fetch
    * @param {Requestable.callback} [cb] - will receive the list of files from the API
    * @return {Promise} - the promise for the http request
    */
   listPullRequestFiles(number, cb) {
      return this._request('GET', `/repos/${this.__fullname}/pulls/${number}/files`, null, cb);
   }

   /**
    * Compare two branches/commits/repositories
    * @see https://developer.github.com/v3/repos/commits/#compare-two-commits
    * @param {string} base - the base commit
    * @param {string} head - the head commit
    * @param {Requestable.callback} cb - will receive the comparison
    * @return {Promise} - the promise for the http request
    */
   compareBranches(base, head, cb) {
      return this._request('GET', `/repos/${this.__fullname}/compare/${base}...${head}`, null, cb);
   }

   /**
    * List all the branches for the repository
    * @see https://developer.github.com/v3/repos/#list-branches
    * @param {Requestable.callback} cb - will receive the list of branches
    * @return {Promise} - the promise for the http request
    */
   listBranches(cb) {
      return this._request('GET', `/repos/${this.__fullname}/branches`, null, cb);
   }

   /**
    * Get a raw blob from the repository
    * @see https://developer.github.com/v3/git/blobs/#get-a-blob
    * @param {string} sha - the sha of the blob to fetch
    * @param {Requestable.callback} cb - will receive the blob from the API
    * @return {Promise} - the promise for the http request
    */
   getBlob(sha, cb) {
      return this._request('GET', `/repos/${this.__fullname}/git/blobs/${sha}`, null, cb, 'raw');
   }

   /**
    * Get a single branch
    * @see https://developer.github.com/v3/repos/branches/#get-branch
    * @param {string} branch - the name of the branch to fetch
    * @param {Requestable.callback} cb - will receive the branch from the API
    * @returns {Promise} - the promise for the http request
    */
   getBranch(branch, cb) {
      return this._request('GET', `/repos/${this.__fullname}/branches/${branch}`, null, cb);
   }

   /**
    * Get a commit from the repository
    * @see https://developer.github.com/v3/repos/commits/#get-a-single-commit
    * @param {string} sha - the sha for the commit to fetch
    * @param {Requestable.callback} cb - will receive the commit data
    * @return {Promise} - the promise for the http request
    */
   getCommit(sha, cb) {
      return this._request('GET', `/repos/${this.__fullname}/git/commits/${sha}`, null, cb);
   }

   /**
    * List the commits on a repository, optionally filtering by path, author or time range
    * @see https://developer.github.com/v3/repos/commits/#list-commits-on-a-repository
    * @param {Object} [options] - the filtering options for commits
    * @param {string} [options.sha] - the SHA or branch to start from
    * @param {string} [options.path] - the path to search on
    * @param {string} [options.author] - the commit author
    * @param {(Date|string)} [options.since] - only commits after this date will be returned
    * @param {(Date|string)} [options.until] - only commits before this date will be returned
    * @param {Requestable.callback} cb - will receive the list of commits found matching the criteria
    * @return {Promise} - the promise for the http request
    */
   listCommits(options, cb) {
      options = options || {};

      options.since = this._dateToISO(options.since);
      options.until = this._dateToISO(options.until);

      return this._request('GET', `/repos/${this.__fullname}/commits`, options, cb);
   }

    /**
     * Gets a single commit information for a repository
     * @see https://developer.github.com/v3/repos/commits/#get-a-single-commit
     * @param {string} ref - the reference for the commit-ish
     * @param {Requestable.callback} cb - will receive the commit information
     * @return {Promise} - the promise for the http request
     */
   getSingleCommit(ref, cb) {
      ref = ref || '';
      return this._request('GET', `/repos/${this.__fullname}/commits/${ref}`, null, cb);
   }

   /**
    * Get tha sha for a particular object in the repository. This is a convenience function
    * @see https://developer.github.com/v3/repos/contents/#get-contents
    * @param {string} [branch] - the branch to look in, or the repository's default branch if omitted
    * @param {string} path - the path of the file or directory
    * @param {Requestable.callback} cb - will receive a description of the requested object, including a `SHA` property
    * @return {Promise} - the promise for the http request
    */
   getSha(branch, path, cb) {
      branch = branch ? `?ref=${branch}` : '';
      return this._request('GET', `/repos/${this.__fullname}/contents/${path}${branch}`, null, cb);
   }

   /**
    * List the commit statuses for a particular sha, branch, or tag
    * @see https://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref
    * @param {string} sha - the sha, branch, or tag to get statuses for
    * @param {Requestable.callback} cb - will receive the list of statuses
    * @return {Promise} - the promise for the http request
    */
   listStatuses(sha, cb) {
      return this._request('GET', `/repos/${this.__fullname}/commits/${sha}/statuses`, null, cb);
   }

   /**
    * Get a description of a git tree
    * @see https://developer.github.com/v3/git/trees/#get-a-tree
    * @param {string} treeSHA - the SHA of the tree to fetch
    * @param {Requestable.callback} cb - will receive the callback data
    * @return {Promise} - the promise for the http request
    */
   getTree(treeSHA, cb) {
      return this._request('GET', `/repos/${this.__fullname}/git/trees/${treeSHA}`, null, cb);
   }

   /**
    * Create a blob
    * @see https://developer.github.com/v3/git/blobs/#create-a-blob
    * @param {(string|Buffer|Blob)} content - the content to add to the repository
    * @param {Requestable.callback} cb - will receive the details of the created blob
    * @return {Promise} - the promise for the http request
    */
   createBlob(content, cb) {
      let postBody = this._getContentObject(content);

      log('sending content', postBody);
      return this._request('POST', `/repos/${this.__fullname}/git/blobs`, postBody, cb);
   }

   /**
    * Get the object that represents the provided content
    * @param {string|Buffer|Blob} content - the content to send to the server
    * @return {Object} the representation of `content` for the GitHub API
    */
   _getContentObject(content) {
      if (typeof content === 'string') {
         log('contet is a string');
         return {
            content: Utf8.encode(content),
            encoding: 'utf-8',
         };

      } else if (typeof Buffer !== 'undefined' && content instanceof Buffer) {
         log('We appear to be in Node');
         return {
            content: content.toString('base64'),
            encoding: 'base64',
         };

      } else if (typeof Blob !== 'undefined' && content instanceof Blob) {
         log('We appear to be in the browser');
         return {
            content: Base64.encode(content),
            encoding: 'base64',
         };

      } else { // eslint-disable-line
         log(`Not sure what this content is: ${typeof content}, ${JSON.stringify(content)}`);
         throw new Error('Unknown content passed to postBlob. Must be string or Buffer (node) or Blob (web)');
      }
   }

   /**
    * Update a tree in Git
    * @see https://developer.github.com/v3/git/trees/#create-a-tree
    * @param {string} baseTreeSHA - the SHA of the tree to update
    * @param {string} path - the path for the new file
    * @param {string} blobSHA - the SHA for the blob to put at `path`
    * @param {Requestable.callback} cb - will receive the new tree that is created
    * @return {Promise} - the promise for the http request
    * @deprecated use {@link Repository#createTree} instead
    */
   updateTree(baseTreeSHA, path, blobSHA, cb) {
      let newTree = {
         base_tree: baseTreeSHA, // eslint-disable-line
         tree: [{
            path: path,
            sha: blobSHA,
            mode: '100644',
            type: 'blob',
         }],
      };

      return this._request('POST', `/repos/${this.__fullname}/git/trees`, newTree, cb);
   }

   /**
    * Create a new tree in git
    * @see https://developer.github.com/v3/git/trees/#create-a-tree
    * @param {Object} tree - the tree to create
    * @param {string} baseSHA - the root sha of the tree
    * @param {Requestable.callback} cb - will receive the new tree that is created
    * @return {Promise} - the promise for the http request
    */
   createTree(tree, baseSHA, cb) {
      return this._request('POST', `/repos/${this.__fullname}/git/trees`, {
         tree,
         base_tree: baseSHA, // eslint-disable-line camelcase
      }, cb);
   }

   /**
    * Add a commit to the repository
    * @see https://developer.github.com/v3/git/commits/#create-a-commit
    * @param {string} parent - the SHA of the parent commit
    * @param {string} tree - the SHA of the tree for this commit
    * @param {string} message - the commit message
    * @param {Requestable.callback} cb - will receive the commit that is created
    * @return {Promise} - the promise for the http request
    */
   commit(parent, tree, message, cb) {
      let data = {
         message,
         tree,
         parents: [parent],
      };

      return this._request('POST', `/repos/${this.__fullname}/git/commits`, data, cb)
         .then((response) => {
            this.__currentTree.sha = response.data.sha; // Update latest commit
            return response;
         });
   }

   /**
    * Update a ref
    * @see https://developer.github.com/v3/git/refs/#update-a-reference
    * @param {string} ref - the ref to update
    * @param {string} commitSHA - the SHA to point the reference to
    * @param {boolean} force - indicates whether to force or ensure a fast-forward update
    * @param {Requestable.callback} cb - will receive the updated ref back
    * @return {Promise} - the promise for the http request
    */
   updateHead(ref, commitSHA, force, cb) {
      return this._request('PATCH', `/repos/${this.__fullname}/git/refs/${ref}`, {
         sha: commitSHA,
         force: force,
      }, cb);
   }

   /**
    * Update commit status
    * @see https://developer.github.com/v3/repos/statuses/
    * @param {string} commitSHA - the SHA of the commit that should be updated
    * @param {object} options - Commit status parameters
    * @param {string} options.state - The state of the status. Can be one of: pending, success, error, or failure.
    * @param {string} [options.target_url] - The target URL to associate with this status.
    * @param {string} [options.description] - A short description of the status.
    * @param {string} [options.context] - A string label to differentiate this status among CI systems.
    * @param {Requestable.callback} cb - will receive the updated commit back
    * @return {Promise} - the promise for the http request
    */
   updateStatus(commitSHA, options, cb) {
      return this._request('POST', `/repos/${this.__fullname}/statuses/${commitSHA}`, options, cb);
   }

   /**
    * Update repository information
    * @see https://developer.github.com/v3/repos/#edit
    * @param {object} options - New parameters that will be set to the repository
    * @param {string} options.name - Name of the repository
    * @param {string} [options.description] - A short description of the repository
    * @param {string} [options.homepage] - A URL with more information about the repository
    * @param {boolean} [options.private] - Either true to make the repository private, or false to make it public.
    * @param {boolean} [options.has_issues] - Either true to enable issues for this repository, false to disable them.
    * @param {boolean} [options.has_wiki] - Either true to enable the wiki for this repository, false to disable it.
    * @param {boolean} [options.has_downloads] - Either true to enable downloads, false to disable them.
    * @param {string} [options.default_branch] - Updates the default branch for this repository.
    * @param {Requestable.callback} cb - will receive the updated repository back
    * @return {Promise} - the promise for the http request
    */
   updateRepository(options, cb) {
      return this._request('PATCH', `/repos/${this.__fullname}`, options, cb);
   }

  /**
    * Get information about the repository
    * @see https://developer.github.com/v3/repos/#get
    * @param {Requestable.callback} cb - will receive the information about the repository
    * @return {Promise} - the promise for the http request
    */
   getDetails(cb) {
      return this._request('GET', `/repos/${this.__fullname}`, null, cb);
   }

   /**
    * List the contributors to the repository
    * @see https://developer.github.com/v3/repos/#list-contributors
    * @param {Requestable.callback} cb - will receive the list of contributors
    * @return {Promise} - the promise for the http request
    */
   getContributors(cb) {
      return this._request('GET', `/repos/${this.__fullname}/contributors`, null, cb);
   }

   /**
    * List the contributor stats to the repository
    * @see https://developer.github.com/v3/repos/#list-contributors
    * @param {Requestable.callback} cb - will receive the list of contributors
    * @return {Promise} - the promise for the http request
    */
   getContributorStats(cb) {
      return this._request('GET', `/repos/${this.__fullname}/stats/contributors`, null, cb);
   }

   /**
    * List the users who are collaborators on the repository. The currently authenticated user must have
    * push access to use this method
    * @see https://developer.github.com/v3/repos/collaborators/#list-collaborators
    * @param {Requestable.callback} cb - will receive the list of collaborators
    * @return {Promise} - the promise for the http request
    */
   getCollaborators(cb) {
      return this._request('GET', `/repos/${this.__fullname}/collaborators`, null, cb);
   }

   /**
    * Check if a user is a collaborator on the repository
    * @see https://developer.github.com/v3/repos/collaborators/#check-if-a-user-is-a-collaborator
    * @param {string} username - the user to check
    * @param {Requestable.callback} cb - will receive true if the user is a collaborator and false if they are not
    * @return {Promise} - the promise for the http request {Boolean} [description]
    */
   isCollaborator(username, cb) {
      return this._request('GET', `/repos/${this.__fullname}/collaborators/${username}`, null, cb);
   }

   /**
    * Get the contents of a repository
    * @see https://developer.github.com/v3/repos/contents/#get-contents
    * @param {string} ref - the ref to check
    * @param {string} path - the path containing the content to fetch
    * @param {boolean} raw - `true` if the results should be returned raw instead of GitHub's normalized format
    * @param {Requestable.callback} cb - will receive the fetched data
    * @return {Promise} - the promise for the http request
    */
   getContents(ref, path, raw, cb) {
      path = path ? `${encodeURI(path)}` : '';
      return this._request('GET', `/repos/${this.__fullname}/contents/${path}`, {
         ref,
      }, cb, raw);
   }

   /**
    * Get the README of a repository
    * @see https://developer.github.com/v3/repos/contents/#get-the-readme
    * @param {string} ref - the ref to check
    * @param {boolean} raw - `true` if the results should be returned raw instead of GitHub's normalized format
    * @param {Requestable.callback} cb - will receive the fetched data
    * @return {Promise} - the promise for the http request
    */
   getReadme(ref, raw, cb) {
      return this._request('GET', `/repos/${this.__fullname}/readme`, {
         ref,
      }, cb, raw);
   }

   /**
    * Fork a repository
    * @see https://developer.github.com/v3/repos/forks/#create-a-fork
    * @param {Requestable.callback} cb - will receive the information about the newly created fork
    * @return {Promise} - the promise for the http request
    */
   fork(cb) {
      return this._request('POST', `/repos/${this.__fullname}/forks`, null, cb);
   }

   /**
    * List a repository's forks
    * @see https://developer.github.com/v3/repos/forks/#list-forks
    * @param {Requestable.callback} cb - will receive the list of repositories forked from this one
    * @return {Promise} - the promise for the http request
    */
   listForks(cb) {
      return this._request('GET', `/repos/${this.__fullname}/forks`, null, cb);
   }

   /**
    * Create a new branch from an existing branch.
    * @param {string} [oldBranch=master] - the name of the existing branch
    * @param {string} newBranch - the name of the new branch
    * @param {Requestable.callback} cb - will receive the commit data for the head of the new branch
    * @return {Promise} - the promise for the http request
    */
   createBranch(oldBranch, newBranch, cb) {
      if (typeof newBranch === 'function') {
         cb = newBranch;
         newBranch = oldBranch;
         oldBranch = 'master';
      }

      return this.getRef(`heads/${oldBranch}`)
         .then((response) => {
            let sha = response.data.object.sha;
            return this.createRef({
               sha,
               ref: `refs/heads/${newBranch}`,
            }, cb);
         });
   }

   /**
    * Create a new pull request
    * @see https://developer.github.com/v3/pulls/#create-a-pull-request
    * @param {Object} options - the pull request description
    * @param {Requestable.callback} cb - will receive the new pull request
    * @return {Promise} - the promise for the http request
    */
   createPullRequest(options, cb) {
      return this._request('POST', `/repos/${this.__fullname}/pulls`, options, cb);
   }

   /**
    * Update a pull request
    * @see https://developer.github.com/v3/pulls/#update-a-pull-request
    * @param {number|string} number - the number of the pull request to update
    * @param {Object} options - the pull request description
    * @param {Requestable.callback} [cb] - will receive the pull request information
    * @return {Promise} - the promise for the http request
    */
   updatePullRequest(number, options, cb) {
      return this._request('PATCH', `/repos/${this.__fullname}/pulls/${number}`, options, cb);
   }

   /**
    * List the hooks for the repository
    * @see https://developer.github.com/v3/repos/hooks/#list-hooks
    * @param {Requestable.callback} cb - will receive the list of hooks
    * @return {Promise} - the promise for the http request
    */
   listHooks(cb) {
      return this._request('GET', `/repos/${this.__fullname}/hooks`, null, cb);
   }

   /**
    * Get a hook for the repository
    * @see https://developer.github.com/v3/repos/hooks/#get-single-hook
    * @param {number} id - the id of the webook
    * @param {Requestable.callback} cb - will receive the details of the webook
    * @return {Promise} - the promise for the http request
    */
   getHook(id, cb) {
      return this._request('GET', `/repos/${this.__fullname}/hooks/${id}`, null, cb);
   }

   /**
    * Add a new hook to the repository
    * @see https://developer.github.com/v3/repos/hooks/#create-a-hook
    * @param {Object} options - the configuration describing the new hook
    * @param {Requestable.callback} cb - will receive the new webhook
    * @return {Promise} - the promise for the http request
    */
   createHook(options, cb) {
      return this._request('POST', `/repos/${this.__fullname}/hooks`, options, cb);
   }

   /**
    * Edit an existing webhook
    * @see https://developer.github.com/v3/repos/hooks/#edit-a-hook
    * @param {number} id - the id of the webhook
    * @param {Object} options - the new description of the webhook
    * @param {Requestable.callback} cb - will receive the updated webhook
    * @return {Promise} - the promise for the http request
    */
   updateHook(id, options, cb) {
      return this._request('PATCH', `/repos/${this.__fullname}/hooks/${id}`, options, cb);
   }

   /**
    * Delete a webhook
    * @see https://developer.github.com/v3/repos/hooks/#delete-a-hook
    * @param {number} id - the id of the webhook to be deleted
    * @param {Requestable.callback} cb - will receive true if the call is successful
    * @return {Promise} - the promise for the http request
    */
   deleteHook(id, cb) {
      return this._request('DELETE', `${this.__fullname}/hooks/${id}`, null, cb);
   }

   /**
    * List the deploy keys for the repository
    * @see https://developer.github.com/v3/repos/keys/#list-deploy-keys
    * @param {Requestable.callback} cb - will receive the list of deploy keys
    * @return {Promise} - the promise for the http request
    */
   listKeys(cb) {
      return this._request('GET', `/repos/${this.__fullname}/keys`, null, cb);
   }

   /**
    * Get a deploy key for the repository
    * @see https://developer.github.com/v3/repos/keys/#get-a-deploy-key
    * @param {number} id - the id of the deploy key
    * @param {Requestable.callback} cb - will receive the details of the deploy key
    * @return {Promise} - the promise for the http request
    */
   getKey(id, cb) {
      return this._request('GET', `/repos/${this.__fullname}/keys/${id}`, null, cb);
   }

   /**
    * Add a new deploy key to the repository
    * @see https://developer.github.com/v3/repos/keys/#add-a-new-deploy-key
    * @param {Object} options - the configuration describing the new deploy key
    * @param {Requestable.callback} cb - will receive the new deploy key
    * @return {Promise} - the promise for the http request
    */
   createKey(options, cb) {
      return this._request('POST', `/repos/${this.__fullname}/keys`, options, cb);
   }

   /**
    * Delete a deploy key
    * @see https://developer.github.com/v3/repos/keys/#remove-a-deploy-key
    * @param {number} id - the id of the deploy key to be deleted
    * @param {Requestable.callback} cb - will receive true if the call is successful
    * @return {Promise} - the promise for the http request
    */
   deleteKey(id, cb) {
      return this._request('DELETE', `/repos/${this.__fullname}/keys/${id}`, null, cb);
   }

   /**
    * Delete a file from a branch
    * @see https://developer.github.com/v3/repos/contents/#delete-a-file
    * @param {string} branch - the branch to delete from, or the default branch if not specified
    * @param {string} path - the path of the file to remove
    * @param {Requestable.callback} cb - will receive the commit in which the delete occurred
    * @return {Promise} - the promise for the http request
    */
   deleteFile(branch, path, cb) {
      return this.getSha(branch, path)
         .then((response) => {
            const deleteCommit = {
               message: `Delete the file at '${path}'`,
               sha: response.data.sha,
               branch,
            };
            return this._request('DELETE', `/repos/${this.__fullname}/contents/${path}`, deleteCommit, cb);
         });
   }

   /**
    * Change all references in a repo from oldPath to new_path
    * @param {string} branch - the branch to carry out the reference change, or the default branch if not specified
    * @param {string} oldPath - original path
    * @param {string} newPath - new reference path
    * @param {Requestable.callback} cb - will receive the commit in which the move occurred
    * @return {Promise} - the promise for the http request
    */
   move(branch, oldPath, newPath, cb) {
      let oldSha;
      return this.getRef(`heads/${branch}`)
         .then(({data: {object}}) => this.getTree(`${object.sha}?recursive=true`))
         .then(({data: {tree, sha}}) => {
            oldSha = sha;
            let newTree = tree.map((ref) => {
               if (ref.path === oldPath) {
                  ref.path = newPath;
               }
               if (ref.type === 'tree') {
                  delete ref.sha;
               }
               return ref;
            });
            return this.createTree(newTree);
         })
         .then(({data: tree}) => this.commit(oldSha, tree.sha, `Renamed '${oldPath}' to '${newPath}'`))
         .then(({data: commit}) => this.updateHead(`heads/${branch}`, commit.sha, true, cb));
   }

   /**
    * Write a file to the repository
    * @see https://developer.github.com/v3/repos/contents/#update-a-file
    * @param {string} branch - the name of the branch
    * @param {string} path - the path for the file
    * @param {string} content - the contents of the file
    * @param {string} message - the commit message
    * @param {Object} [options] - commit options
    * @param {Object} [options.author] - the author of the commit
    * @param {Object} [options.commiter] - the committer
    * @param {boolean} [options.encode] - true if the content should be base64 encoded
    * @param {Requestable.callback} cb - will receive the new commit
    * @return {Promise} - the promise for the http request
    */
   writeFile(branch, path, content, message, options, cb) {
      if (typeof options === 'function') {
         cb = options;
         options = {};
      }
      let filePath = path ? encodeURI(path) : '';
      let shouldEncode = options.encode !== false;
      let commit = {
         branch,
         message,
         author: options.author,
         committer: options.committer,
         content: shouldEncode ? Base64.encode(content) : content,
      };

      return this.getSha(branch, filePath)
         .then((response) => {
            commit.sha = response.data.sha;
            return this._request('PUT', `/repos/${this.__fullname}/contents/${filePath}`, commit, cb);
         }, () => {
            return this._request('PUT', `/repos/${this.__fullname}/contents/${filePath}`, commit, cb);
         });
   }

   /**
    * Check if a repository is starred by you
    * @see https://developer.github.com/v3/activity/starring/#check-if-you-are-starring-a-repository
    * @param {Requestable.callback} cb - will receive true if the repository is starred and false if the repository
    *                                  is not starred
    * @return {Promise} - the promise for the http request {Boolean} [description]
    */
   isStarred(cb) {
      return this._request204or404(`/user/starred/${this.__fullname}`, null, cb);
   }

   /**
    * Star a repository
    * @see https://developer.github.com/v3/activity/starring/#star-a-repository
    * @param {Requestable.callback} cb - will receive true if the repository is starred
    * @return {Promise} - the promise for the http request
    */
   star(cb) {
      return this._request('PUT', `/user/starred/${this.__fullname}`, null, cb);
   }

   /**
    * Unstar a repository
    * @see https://developer.github.com/v3/activity/starring/#unstar-a-repository
    * @param {Requestable.callback} cb - will receive true if the repository is unstarred
    * @return {Promise} - the promise for the http request
    */
   unstar(cb) {
      return this._request('DELETE', `/user/starred/${this.__fullname}`, null, cb);
   }

   /**
    * Create a new release
    * @see https://developer.github.com/v3/repos/releases/#create-a-release
    * @param {Object} options - the description of the release
    * @param {Requestable.callback} cb - will receive the newly created release
    * @return {Promise} - the promise for the http request
    */
   createRelease(options, cb) {
      return this._request('POST', `/repos/${this.__fullname}/releases`, options, cb);
   }

   /**
    * Edit a release
    * @see https://developer.github.com/v3/repos/releases/#edit-a-release
    * @param {string} id - the id of the release
    * @param {Object} options - the description of the release
    * @param {Requestable.callback} cb - will receive the modified release
    * @return {Promise} - the promise for the http request
    */
   updateRelease(id, options, cb) {
      return this._request('PATCH', `/repos/${this.__fullname}/releases/${id}`, options, cb);
   }

   /**
    * Get information about all releases
    * @see https://developer.github.com/v3/repos/releases/#list-releases-for-a-repository
    * @param {Requestable.callback} cb - will receive the release information
    * @return {Promise} - the promise for the http request
    */
   listReleases(cb) {
      return this._request('GET', `/repos/${this.__fullname}/releases`, null, cb);
   }

   /**
    * Get information about a release
    * @see https://developer.github.com/v3/repos/releases/#get-a-single-release
    * @param {string} id - the id of the release
    * @param {Requestable.callback} cb - will receive the release information
    * @return {Promise} - the promise for the http request
    */
   getRelease(id, cb) {
      return this._request('GET', `/repos/${this.__fullname}/releases/${id}`, null, cb);
   }

   /**
    * Delete a release
    * @see https://developer.github.com/v3/repos/releases/#delete-a-release
    * @param {string} id - the release to be deleted
    * @param {Requestable.callback} cb - will receive true if the operation is successful
    * @return {Promise} - the promise for the http request
    */
   deleteRelease(id, cb) {
      return this._request('DELETE', `/repos/${this.__fullname}/releases/${id}`, null, cb);
   }

   /**
    * Merge a pull request
    * @see https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button
    * @param {number|string} number - the number of the pull request to merge
    * @param {Object} options - the merge options for the pull request
    * @param {Requestable.callback} [cb] - will receive the merge information if the operation is successful
    * @return {Promise} - the promise for the http request
    */
   mergePullRequest(number, options, cb) {
      return this._request('PUT', `/repos/${this.__fullname}/pulls/${number}/merge`, options, cb);
   }

   /**
    * Get information about all projects
    * @see https://developer.github.com/v3/projects/#list-repository-projects
    * @param {Requestable.callback} [cb] - will receive the list of projects
    * @return {Promise} - the promise for the http request
    */
   listProjects(cb) {
      return this._requestAllPages(`/repos/${this.__fullname}/projects`, {AcceptHeader: 'inertia-preview'}, cb);
   }

   /**
    * Create a new project
    * @see https://developer.github.com/v3/projects/#create-a-repository-project
    * @param {Object} options - the description of the project
    * @param {Requestable.callback} cb - will receive the newly created project
    * @return {Promise} - the promise for the http request
    */
   createProject(options, cb) {
      options = options || {};
      options.AcceptHeader = 'inertia-preview';
      return this._request('POST', `/repos/${this.__fullname}/projects`, options, cb);
   }

}

module.exports = Repository;

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy