github.js

const Bottleneck = require('bottleneck')
const GitHubApi = require('github')

/**
 * the [github Node.js module](https://github.com/octokit/node-github),
 * which wraps the [GitHub API](https://developer.github.com/v3/) and allows
 * you to do almost anything programmatically that you can do through a web
 * browser.
 * @typedef github
 * @see {@link https://github.com/octokit/node-github}
 */

// Default callback should just return the response passed to it.
const defaultCallback = response => response

class EnhancedGitHubClient extends GitHubApi {
  constructor (options) {
    super(options)
    this.limiter = new Bottleneck(1, 1000)
    this.logger = options.logger
  }

  handler (params, block, callback) {
    // Only allow one request at a time with a 1s delay
    // https://github.com/octokit/node-github/issues/526
    this.limiter.submit(super.handler.bind(this), params, block, (err, res) => {
      let msg = `GitHub request: ${block.method} ${block.url}`
      if (res) {
        msg += ` - ${res.meta.status}`
      } else if (err) {
        msg += ` - ${err.code} ${err.status}`
      }
      this.logger.debug({params}, msg)

      if (res) {
        this.logger.trace(res, 'GitHub response:')
      }

      callback(err, res)
    })
  }

  async paginate (responsePromise, callback = defaultCallback) {
    let collection = []
    let getNextPage = true
    let done = () => {
      getNextPage = false
    }
    let response = await responsePromise
    collection = collection.concat(await callback(response, done))
    // eslint-disable-next-line no-unmodified-loop-condition
    while (getNextPage && this.hasNextPage(response)) {
      response = await this.getNextPage(response)
      collection = collection.concat(await callback(response, done))
    }
    return collection
  }
}

module.exports = EnhancedGitHubClient