<commit_before>'use strict';
var _ = require('lodash');
var chalk = require('chalk');
var utils = require('../utils');

module.exports = function (overview, statistics, ruleSetResults) {
  var renderOverview = function (item) {
    var color = item.label === 'Score' ? utils.scoreColor(item.value) : chalk.cyan;
    return item.label + ':' + utils.buffer(item.label, 11) + color(item.value);
  };

  var renderSection = function (item) {
    return utils.labelize(item.label) + chalk.cyan(item.value);
  };

  return [
    utils.divider,
    _.map(overview, renderOverview).join('\n') + '\n',
    _.map(statistics, renderSection).join('\n'),
    utils.labelize(''),
    _.map(ruleSetResults, renderSection).join('\n'),
    utils.divider
  ].join('\n');
};
<commit_msg>hide `0` values as they indicate the warning doesn't apply<commit_after>'use strict';
var _ = require('lodash');
var chalk = require('chalk');
var utils = require('../utils');

module.exports = function (overview, statistics, ruleSetResults) {
  var renderOverview = function (item) {
    var color = item.label === 'Score' ? utils.scoreColor(item.value) : chalk.cyan;
    return item.label + ':' + utils.buffer(item.label, 11) + color(item.value);
  };

  var renderSection = function (item) {
    return utils.labelize(item.label) + chalk.cyan(item.value);
  };

  return [
    utils.divider,
    _.map(overview, renderOverview).join('\n') + '\n',
    _.map(statistics, renderSection).join('\n'),
    '',
    _.map(ruleSetResults.filter(function (el) {
      return el.value > 0;
    }), renderSection).join('\n'),
    utils.divider
  ].join('\n');
};
<|endoftext|>


<commit_before>var fs = require('fs');
var filePtr = {}
var fileBuffer = {}
var buffer = new Buffer(4096)

exports.fopen = function(path, mode) {
  var handle = fs.openSync(path, mode)
  filePtr[handle] = 0
  fileBuffer[handle]= []
  return handle
}

exports.fclose = function(handle) {
  fs.closeSync(handle)
  if (handle in filePtr) {
    delete filePtr[handle]
    delete fileBuffer[handle]
  }
  return
}

exports.fgets = function(handle) {
  if(fileBuffer[handle].length == 0)
  {
    var pos = filePtr[handle]
    var br = fs.readSync(handle, buffer, 0, 4096, pos)
    if(br < 4096) {
      delete filePtr[handle]
      if(br == 0)  return false
    }
    var lst = buffer.slice(0, br).toString().split("\n")
    var minus = 0
    if(lst.length > 1) {
      var x = lst.pop()
      minus = x.length
    }
    fileBuffer[handle] = lst
    filePtr[handle] = pos + br - minus
  }
  return fileBuffer[handle].shift()
}

exports.eof = function(handle) {
  return (handle in filePtr) == false && (fileBuffer[handle].length == 0)
}
<commit_msg>Last clean up<commit_after><|endoftext|>


<commit_before>
$.extend(String.prototype, {

  change_resource: function(changes) {
    var item = this.resource();
    $.extend(item, changes);
    Resource.add_or_update(this, item);
  }
});

Demo = {
  interval: 15 * 1000,

  init_manual: function() {
    if (!window.demo_random_reports) {
      window.demo_random_reports = ["I'm reporting in", "it's snowing!"];
    }
    if (!window.demo_replies) {
      window.demo_replies = ["I don't understand. What?", "I'm replying", "okay"];
    }

    window.demo_random_reports.sort(Math.randSort);
    window.demo_replies.sort(Math.randSort);

    setTimeout(function(){Demo.random_events();}, Demo.delay(Demo.interval));
  },

  random_events: function() {
    switch(Math.rand(2))
    {
      case 0:
        Demo.random_move();
        break;
      case 1:
        Demo.random_report();
        break;
    }
    setTimeout(function(){Demo.random_events();}, Demo.delay(Demo.interval));
  },

  // qa

  qa_keypresses: function(ch) {
    if (ch == 'M') {
      Demo.random_move();
      return false;
    };
    if (ch == 'R') {
      Demo.random_report();
      return false;
    }
    if (ch == 'X') {
      var lat = 42.2481415 - Math.rand(100)/1000;
      var lng = -72.5796331 - Math.rand(100)/1000;
      item(220,"pmcdcf3421a1c","Elizabeth","/images/02/10/02107108bba957823b328a90f9d5c8df_thumb.jpg",lat,lng,"adv health.healing adv.water_fight community.beertalk adv.stealth service.random_kindness health.game health.game.basketball adv.game community.party service.volunteer community service.cleanup art health.art adv.challenge health.food health.game.frisbee community.reporting service.neighbor art.perform service adv.beauty art.stunt health.walk health.yoga art.music health art.writing","unlatched","reachable 1253543018 1254583581",null,{"image_url":"/images/02/10/02107108bba957823b328a90f9d5c8df_medium.jpg"});
      return false;
    };
    if (ch == 'Y') {
      // she moves to australia
      item(13,"pmcdcf3421a1c","Elizabeth","/images/02/10/02107108bba957823b328a90f9d5c8df_thumb.jpg",-33.881168,151.192959,"adv health.healing adv.water_fight community.beertalk adv.stealth service.random_kindness health.game health.game.basketball adv.game community.party service.volunteer community service.cleanup art health.art adv.challenge health.food health.game.frisbee community.reporting service.neighbor art.perform service adv.beauty art.stunt health.walk health.yoga art.music health art.writing","unlatched","reachable 1253543018 1254583581",null,{"image_url":"/images/02/10/02107108bba957823b328a90f9d5c8df_medium.jpg"});
      return false;
    };
    if (ch == 'Z') {
      // someone new comes to town
      var latZ = 42.2481415 - Math.rand(100)/1000;
      var lngZ = -72.5796331 - Math.rand(100)/1000;
      item(220,"pmcdcf21a1c","Elizabeth2","/images/02/10/02107108bba957823b328a90f9d5c8df_thumb.jpg",latZ,lngZ,"adv health.healing adv.water_fight community.beertalk adv.stealth service.random_kindness health.game health.game.basketball adv.game community.party service.volunteer community service.cleanup art health.art adv.challenge health.food health.game.frisbee community.reporting service.neighbor art.perform service adv.beauty art.stunt health.walk health.yoga art.music health art.writing","unlatched","reachable 1253543018 1254583581",null,{"image_url":"/images/02/10/02107108bba957823b328a90f9d5c8df_medium.jpg"});
      return false;
    };
    return true;
  },

  delay: function(delay_min, delay_max) {
    if (delay_min == null) delay_min = 1000;
    if (delay_max == null) delay_max = delay_min * 2;
    return delay_min + Math.rand(delay_max - delay_min);
  },

  update_comm: function(person, i, new_val) {
    var comm_parts = person.resource().comm.split(' ');
    comm_parts[i] = new_val;
    return comm_parts.join(' ');
  },

  offer: function(person, op) {
    setTimeout(function(){

      latch_parts = ["latched", Date.unix() + "-" + (Date.unix() + 60*60), op.id, This.user.tag];
      person.change_resource({
        latch: latch_parts.join(' '),
        sent: op.title,
        comm: Demo.update_comm(person, 2, Date.unix())});
    }, Demo.delay(50, 250));
  },

  random_agent: function() {
    agents = Agents.here(200);
    if (!agents || agents.length == 0) return null;
    return agents[Math.rand(agents.length)];
  },

  get_random_report: function() {
    report = demo_random_reports.shift();
    demo_random_reports.push(report);
    return report;
  },

  get_reply: function() {
    reply = demo_replies.shift();
    demo_replies.push(reply);
    return reply;
  },

  yesno_answers: [
    {a: "yes", evtype: 'answered'}, {a: "yes, that sounds great", evtype: 'answered_yes'},
    {a: "no", evtype: 'answered'}, {a: "no, sorry", evtype: 'answered_no'},
    {a: "sure", evtype: 'answered'}, {a: "I'm not sure", evtype: 'answered'}, {a: "Maybe", evtype: 'answered'}
  ],

  get_answer: function(question) {
    if (question.yesno_question()) {
      return Demo.yesno_answers[Math.rand(Demo.yesno_answers.length)];
    }
    return { a: "I'm answering your question", evtype: 'answered' };
  },

  random_report: function(agent) {
    if (!agent) agent = Demo.random_agent();
    if (!agent) return;
    Demo.report(agent.id, Demo.get_random_report(), null, 0);
    return true;
  },

  random_move: function(agent) {
    if (!agent) agent = Demo.random_agent();
    if (!agent) return;
    fuzz = make_fuzzfactor();
    changes = {
      lat: agent.lat + fuzz[0],
      lng: agent.lng + fuzz[1],
      loc_ts: Date.unix(),
      comm: Demo.update_comm(agent.id, 1, Date.unix())
    };
    agent.id.change_resource(changes);
  },

  // events

  create_rcv_event: function(atype, person, op, changes, json_etc, delay_min, delay_max) {
    var delay = Demo.delay(delay_min, delay_max);
    setTimeout(function(){
      if (!changes) changes = {};
      if (!json_etc) json_etc = {};
      var now = Date.unix();
      var city_id = op ? op.city_id : This.city_id;
      var op_id = op ? op.id : null;
      changes["comm"] = Demo.update_comm(person, 1, Date.unix());
      if (changes["msg"] == null) changes["msg"] = json_etc["msg"] ? json_etc["msg"] : "yup";
      changes["msg_ts"] = Date.unix();
      person.change_resource(changes);
      ev(city_id, op_id, person, now, atype, json_etc["msg"], json_etc, null, person);
    }, delay);
    return delay;
  },

  report: function(agent, msg, op, delay_min, delay_max) {
    return Demo.create_rcv_event('reported', agent, op, {msg: msg}, {msg: msg}, delay_min, delay_max);
  },

  post_event: function(data) {
    return ev(This.city, data.venture, window.authority, Date.unix(), data.type, data.msg, {
      actor_name: window.user_name || 'You'
    });
  },

  // operations

  create_op: function(site, vtype, body) {
    var op_id = 'v' + StreamLoader.uuid();
    var city_id = site.resource().city_id;
    return operation(city_id, op_id, body, vtype, null, null, null, null, site, null,
      window.authority, window.user_name || 'You', Date.unix(), {});
  },

  assign: function(agents, assignment, callback) {
    var op = Demo.create_op(agents[0], '', assignment);
    go('@' + most_recent_op.id);
    callback && callback(op);

    $.each(agents, function(i, agent){
      Demo.offer(agent, op);
      if (Math.random() < 0.20)
      {
        Demo.create_rcv_event('declined', agent, op, {msg: "no thanks"}, {}, 13*1000);
        return;
      }
      var delay = Demo.create_rcv_event('accepted', agent, op,
        {latch: "latched 1-10000 " + op.id + " " + This.user.tag, msg: "ok"}, null, 10*1000);
      if (Math.random() < 0.33) delay = Demo.report(agent, Demo.get_random_report(), op, delay + 5*1000);
      Demo.create_rcv_event('completed', agent, op, {latch: "unlatched", msg: "done"}, null, delay + 15*1000);
    });
  },

  message: function(agents, msg, callback)
  {
    callback && callback(op);
    $.each(agents, function(i, agent){
      if (Math.random() < 0.33) Demo.report(agent, Demo.get_reply(), op, 5*1000);
    });
  },

  invite: function(agents, landmark, title, assignment, callback) {
    var op = Demo.create_op(landmark, 'invite', title);
    go('@' + most_recent_op.id);
    callback && callback(op);

    $.each(agents, function(i, agent){
      Demo.offer(agent, op);
      var delay = Demo.create_rcv_event('accepted', agent, op,
        {latch: "latched 1-10000 " + op.id + " " + This.user.tag, msg: "ok"}, null, 10*1000);
      Demo.create_rcv_event('completed', agent, op, {latch: "unlatched", msg: "done"}, null, delay + 15*1000);
    });
  },

  question: function(question, agents, site) {
    site = site || agents[0];
    console.log(question + " asked of " + agents);
    var op = Demo.create_op(site, 'question', "Question: " + question);
    go('@' + most_recent_op.id);

    $.each(agents, function(i, agent){
      Demo.offer(agent, op);
      answer = Demo.get_answer(question);
      answers = agent.resource().answers;
      answers[question] = [answer.a, Date.unix() + 30];
      Demo.create_rcv_event(answer.evtype || 'answered', agent, op,
        {latch: "unlatched", msg: answer.a, answers: answers}, {msg: answer.a},
        null, 30*1000);
    });
  },

  // actions

  update_loc: function(agent_id) {
    $('#make_it_happen_form').html('Message sent!');
    setTimeout(function(){ Demo.random_move(agent_id.resource()); }, Demo.delay(3*1000));
  },

  tag: function(agent_ids, tags, callback) {
    callback && callback(op);
    $.each(agent_ids, function(i, agent_id){
      agent = agent_id.resource();
      changes = {atags: tags + (agent.atags ? (" " + agent.atags) : "")};
      return agent_id.change_resource(changes);
    });
  }

};
<commit_msg>demo delay stuff<commit_after>
$.extend(String.prototype, {

  change_resource: function(changes) {
    var item = this.resource();
    $.extend(item, changes);
    Resource.add_or_update(this, item);
  }
});

Demo = {
  interval: 15 * 1000,

  init_manual: function() {
    if (!window.demo_random_reports) {
      window.demo_random_reports = ["I'm reporting in", "it's snowing!"];
    }
    if (!window.demo_replies) {
      window.demo_replies = ["I don't understand. What?", "I'm replying", "okay"];
    }

    window.demo_random_reports.sort(Math.randSort);
    window.demo_replies.sort(Math.randSort);

    setTimeout(function(){Demo.random_events();}, Demo.delay(Demo.interval));
  },

  random_events: function() {
    switch(Math.rand(2))
    {
      case 0:
        Demo.random_move();
        break;
      case 1:
        Demo.random_report();
        break;
    }
    setTimeout(function(){Demo.random_events();}, Demo.delay(Demo.interval));
  },

  // qa

  qa_keypresses: function(ch) {
    if (ch == 'M') {
      Demo.random_move();
      return false;
    };
    if (ch == 'R') {
      Demo.random_report();
      return false;
    }
    if (ch == 'X') {
      var lat = 42.2481415 - Math.rand(100)/1000;
      var lng = -72.5796331 - Math.rand(100)/1000;
      item(220,"pmcdcf3421a1c","Elizabeth","/images/02/10/02107108bba957823b328a90f9d5c8df_thumb.jpg",lat,lng,"adv health.healing adv.water_fight community.beertalk adv.stealth service.random_kindness health.game health.game.basketball adv.game community.party service.volunteer community service.cleanup art health.art adv.challenge health.food health.game.frisbee community.reporting service.neighbor art.perform service adv.beauty art.stunt health.walk health.yoga art.music health art.writing","unlatched","reachable 1253543018 1254583581",null,{"image_url":"/images/02/10/02107108bba957823b328a90f9d5c8df_medium.jpg"});
      return false;
    };
    if (ch == 'Y') {
      // she moves to australia
      item(13,"pmcdcf3421a1c","Elizabeth","/images/02/10/02107108bba957823b328a90f9d5c8df_thumb.jpg",-33.881168,151.192959,"adv health.healing adv.water_fight community.beertalk adv.stealth service.random_kindness health.game health.game.basketball adv.game community.party service.volunteer community service.cleanup art health.art adv.challenge health.food health.game.frisbee community.reporting service.neighbor art.perform service adv.beauty art.stunt health.walk health.yoga art.music health art.writing","unlatched","reachable 1253543018 1254583581",null,{"image_url":"/images/02/10/02107108bba957823b328a90f9d5c8df_medium.jpg"});
      return false;
    };
    if (ch == 'Z') {
      // someone new comes to town
      var latZ = 42.2481415 - Math.rand(100)/1000;
      var lngZ = -72.5796331 - Math.rand(100)/1000;
      item(220,"pmcdcf21a1c","Elizabeth2","/images/02/10/02107108bba957823b328a90f9d5c8df_thumb.jpg",latZ,lngZ,"adv health.healing adv.water_fight community.beertalk adv.stealth service.random_kindness health.game health.game.basketball adv.game community.party service.volunteer community service.cleanup art health.art adv.challenge health.food health.game.frisbee community.reporting service.neighbor art.perform service adv.beauty art.stunt health.walk health.yoga art.music health art.writing","unlatched","reachable 1253543018 1254583581",null,{"image_url":"/images/02/10/02107108bba957823b328a90f9d5c8df_medium.jpg"});
      return false;
    };
    return true;
  },

  delay: function(delay_min, delay_max) {
    if (delay_min == null) delay_min = 1000;
    if (delay_max == null) delay_max = delay_min * 2;
    return delay_min + Math.rand(delay_max - delay_min);
  },

  w_delay: function(f, delay_min, delay_max) {
    if (delay_min == -1) return f();
    if (delay_min == null) delay_min = 1000;
    if (delay_max == null) delay_max = delay_min * 2;
    var delay = delay_min + Math.rand(delay_max - delay_min);
    setTimeout(f, delay);
  },

  update_comm: function(person, i, new_val) {
    var comm_parts = person.resource().comm.split(' ');
    comm_parts[i] = new_val;
    return comm_parts.join(' ');
  },

  offer: function(person, op) {
    Demo.w_delay(function(){
      latch_parts = ["latched", Date.unix() + "-" + (Date.unix() + 60*60), op.id, This.user.tag];
      person.change_resource({
        latch: latch_parts.join(' '),
        sent: op.title,
        comm: Demo.update_comm(person, 2, Date.unix())});
    }, 50, 250);
  },

  random_agent: function(city) {
    if (!city) agents = Agents.here(200);
    else agents = Agents.in_city(city).slice(0, 200);
    if (!agents || agents.length == 0) return null;
    return agents[Math.rand(agents.length)];
  },

  get_random_report: function() {
    report = demo_random_reports.shift();
    demo_random_reports.push(report);
    return report;
  },

  get_reply: function() {
    reply = demo_replies.shift();
    demo_replies.push(reply);
    return reply;
  },

  yesno_answers: [
    {a: "yes", evtype: 'answered'}, {a: "yes, that sounds great", evtype: 'answered_yes'},
    {a: "no", evtype: 'answered'}, {a: "no, sorry", evtype: 'answered_no'},
    {a: "sure", evtype: 'answered'}, {a: "I'm not sure", evtype: 'answered'}, {a: "Maybe", evtype: 'answered'}
  ],

  get_answer: function(question) {
    if (question.yesno_question()) {
      return Demo.yesno_answers[Math.rand(Demo.yesno_answers.length)];
    }
    return { a: "I'm answering your question", evtype: 'answered' };
  },

  random_report: function(agent) {
    if (!agent) agent = Demo.random_agent();
    if (!agent) return;
    Demo.report(agent.id, Demo.get_random_report(), null, 0);
    return true;
  },

  random_move: function(agent) {
    if (!agent) agent = Demo.random_agent();
    if (!agent) return;
    fuzz = make_fuzzfactor();
    changes = {
      lat: agent.lat + fuzz[0],
      lng: agent.lng + fuzz[1],
      loc_ts: Date.unix(),
      comm: Demo.update_comm(agent.id, 1, Date.unix())
    };
    agent.id.change_resource(changes);
  },

  // events

  create_rcv_event: function(atype, person, op, changes, json_etc, delay_min, delay_max) {
    return Demo.w_delay(function(){
      if (!changes) changes = {};
      if (!json_etc) json_etc = {};
      var now = Date.unix();
      var city_id = op ? op.city_id : This.city_id;
      var op_id = op ? op.id : null;
      changes["comm"] = Demo.update_comm(person, 1, Date.unix());
      if (changes["msg"] == null) changes["msg"] = json_etc["msg"] ? json_etc["msg"] : "yup";
      changes["msg_ts"] = Date.unix();
      person.change_resource(changes);
      ev(city_id, op_id, person, now, atype, json_etc["msg"], json_etc, null, person);
    }, delay_min, delay_max);
  },

  report: function(agent, msg, op, delay_min, delay_max) {
    return Demo.create_rcv_event('reported', agent, op, {msg: msg}, {msg: msg}, delay_min, delay_max);
  },

  post_event: function(data) {
    return ev(This.city, data.venture, window.authority, Date.unix(), data.type, data.msg, {
      actor_name: window.user_name || 'You'
    });
  },

  // operations

  create_op: function(site, vtype, body) {
    var op_id = 'v' + StreamLoader.uuid();
    var city_id = site.resource().city_id;
    return operation(city_id, op_id, body, vtype, null, null, null, null, site, null,
      window.authority, window.user_name || 'You', Date.unix(), {});
  },

  assign: function(agents, assignment, callback) {
    var op = Demo.create_op(agents[0], '', assignment);
    go('@' + most_recent_op.id);
    callback && callback(op);

    $.each(agents, function(i, agent){
      Demo.offer(agent, op);
      if (Math.random() < 0.20)
      {
        Demo.create_rcv_event('declined', agent, op, {msg: "no thanks"}, {}, 13*1000);
        return;
      }
      var delay = Demo.create_rcv_event('accepted', agent, op,
        {latch: "latched 1-10000 " + op.id + " " + This.user.tag, msg: "ok"}, null, 10*1000);
      if (Math.random() < 0.33) delay = Demo.report(agent, Demo.get_random_report(), op, delay + 5*1000);
      Demo.create_rcv_event('completed', agent, op, {latch: "unlatched", msg: "done"}, null, delay + 15*1000);
    });
  },

  message: function(agents, msg, callback)
  {
    callback && callback(op);
    $.each(agents, function(i, agent){
      if (Math.random() < 0.33) Demo.report(agent, Demo.get_reply(), op, 5*1000);
    });
  },

  invite: function(agents, landmark, title, assignment, callback) {
    var op = Demo.create_op(landmark, 'invite', title);
    go('@' + most_recent_op.id);
    callback && callback(op);

    $.each(agents, function(i, agent){
      Demo.offer(agent, op);
      var delay = Demo.create_rcv_event('accepted', agent, op,
        {latch: "latched 1-10000 " + op.id + " " + This.user.tag, msg: "ok"}, null, 10*1000);
      Demo.create_rcv_event('completed', agent, op, {latch: "unlatched", msg: "done"}, null, delay + 15*1000);
    });
  },

  question: function(question, agents, site) {
    site = site || agents[0];
    console.log(question + " asked of " + agents);
    var op = Demo.create_op(site, 'question', "Question: " + question);
    go('@' + most_recent_op.id);

    $.each(agents, function(i, agent){
      Demo.offer(agent, op);
      answer = Demo.get_answer(question);
      answers = agent.resource().answers;
      answers[question] = [answer.a, Date.unix() + 30];
      Demo.create_rcv_event(answer.evtype || 'answered', agent, op,
        {latch: "unlatched", msg: answer.a, answers: answers}, {msg: answer.a},
        null, 30*1000);
    });
  },

  // actions

  update_loc: function(agent_id) {
    $('#make_it_happen_form').html('Message sent!');
    setTimeout(function(){ Demo.random_move(agent_id.resource()); }, Demo.delay(3*1000));
  },

  tag: function(agent_ids, tags, callback) {
    callback && callback(op);
    $.each(agent_ids, function(i, agent_id){
      agent = agent_id.resource();
      changes = {atags: tags + (agent.atags ? (" " + agent.atags) : "")};
      return agent_id.change_resource(changes);
    });
  }

};
<|endoftext|>


<commit_before>var Q = require("q");
var fs = require("fs");
var fsExtra = require("fs-extra");
var Ignore = require("fstream-ignore");

var getFiles = function(path) {
    var d = Q.defer();

    // Our list of files
    var files = [];

    var ig = Ignore({
        path: path,
        ignoreFiles: ['.ignore', '.gitignore']
    });

    // Add extra rules to ignore common folders
    ig.addIgnoreRules([
        '.git/'
    ], '__custom_stuff');

    // Push each file to our list
    ig.on('child', function (c) {
        files.push(
            c.path.substr(c.root.path.length + 1) + (c.props.Directory === true ? '/' : '')
        );
    });

    ig.on('end', function() {
        d.resolve(files);
    });

    ig.on('error', d.reject);

    return d.promise;
}

module.exports = {
    list: getFiles,
    readFile: Q.denodeify(fs.readFile),
    writeFile: Q.denodeify(fs.writeFile),
    mkdirp: Q.denodeify(fsExtra.mkdirp),
    copy: Q.denodeify(fsExtra.copy),
    remove: Q.denodeify(fsExtra.remove),
    symlink: Q.denodeify(fsExtra.symlink),
};
<commit_msg>Normalize paths on Windows to Unix convention<commit_after>var Q = require("q");
var fs = require("fs");
var fsExtra = require("fs-extra");
var Ignore = require("fstream-ignore");

var getFiles = function(path) {
    var d = Q.defer();

    // Our list of files
    var files = [];

    var ig = Ignore({
        path: path,
        ignoreFiles: ['.ignore', '.gitignore']
    });

    // Add extra rules to ignore common folders
    ig.addIgnoreRules([
        '.git/'
    ], '__custom_stuff');

    // Push each file to our list
    ig.on('child', function (c) {
        files.push(
            c.path.substr(c.root.path.length + 1) + (c.props.Directory === true ? '/' : '')
        );
    });

    ig.on('end', function() {
        // Normalize paths on Windows
        if(process.platform === 'win32') {
            return d.resolve(files.map(function(file) {
                return file.replace(/\\/g, '/');
            }));
        }

        // Simply return paths otherwise
        return d.resolve(files);
    });

    ig.on('error', d.reject);

    return d.promise;
};

module.exports = {
    list: getFiles,
    readFile: Q.denodeify(fs.readFile),
    writeFile: Q.denodeify(fs.writeFile),
    mkdirp: Q.denodeify(fsExtra.mkdirp),
    copy: Q.denodeify(fsExtra.copy),
    remove: Q.denodeify(fsExtra.remove),
    symlink: Q.denodeify(fsExtra.symlink),
};
<|endoftext|>


<commit_before>var { Octokit } = require('@octokit/rest'),
    { throttling } = require("@octokit/plugin-throttling"),
    MyOctokit = Octokit.plugin(throttling),
    config = require('./config-loader'),
    Promise = require('bluebird'),
    _ = require('underscore'),
    debug = require('./debug')('pulldasher:github'),
    utils = require('./utils'),
    Pull = require('../models/pull'),
    Issue = require('../models/issue'),
    Comment = require('../models/comment'),
    Review = require('../models/review'),
    Label = require('../models/label'),
    Status = require('../models/status'),
    Signature = require('../models/signature'),
    getLogin  = require('./get-user-login');

const github = new MyOctokit({
   auth: config.github.token,
   throttle: {
      onRateLimit: (retryAfter, options) => {
        github.log.warn(
          `Request quota exhausted for request ${options.method} ${options.url}`
        );

        // Retry five times after hitting a rate limit error, then give up
        if (options.request.retryCount <= 5) {
          github.log.debug(`Retrying after ${retryAfter} seconds!`);
          return true;
        }
      },
      onAbuseLimit: (retryAfter, options) => {
        // does not retry, only logs a warning
        github.log.warn(
          `Abuse detected for request ${options.method} ${options.url}`
        );
      },
    }
});

const githubRest = github.rest;

module.exports = {
   github: githubRest,

   /**
    * Returns a promise which resolves to a GitHub API response to
    * a query for a particular Pull Request.
    */
   getPull: function(repo, number) {
      debug("Getting pull %s", number);
      return githubRest.pulls.get(params({ pull_number: number }, repo))
       .then(res => res.data);
   },

   /**
    * Get all *open* pull requests for a repo.
    *
    * Returns a promise which resolves to an array of all open pull requests
    */
   getOpenPulls: function(repo) {
      debug("Getting open pulls in repo %s", repo);
      return github.paginate(githubRest.pulls.list, params({state: 'open'}, repo));
   },

   /**
    * Get *all* pull requests for a repo.
    *
    * Returns a promise which resolves to an array of all pull requests
    */
   getAllPulls: function(repo) {
      debug("Getting all pulls in repo %s", repo);
      return github.paginate(githubRest.pulls.list, params({ state: 'all'}, repo));
   },

   /**
    * Get an issue for a repo.
    *
    * Returns a promise which resolves to a github issue
    */
   getIssue: function(repo, number) {
      const searchParams = params({ issue_number: number }, repo);
      debug("Getting issue %s in repo %s", number, repo);
      return githubRest.issues.get(searchParams)
       .then(res => res.data)
       .then(addRepo(searchParams));
   },

   /**
    * Get all open issues for a repo.
    *
    * Returns a promise which resolves to an array of all open issues
    */
   getOpenIssues: function(repo) {
      const searchParams = params({state: 'open'}, repo);
      debug("Getting open issues in repo %s", repo);
      return github.paginate(githubRest.issues.listForRepo, searchParams)
       .then(filterOutPulls)
       .then(addRepo(searchParams));
   },

   /**
    * Get *all* issues for a repo.
    *
    * Returns a promise which resolves to an array of all issues
    */
   getAllIssues: function(repo) {
      const searchParams = params({state: 'all'}, repo);
      debug("Getting all issues");
      return github.paginate(githubRest.issues.listForRepo, searchParams)
       .then(filterOutPulls)
       .then(addRepo(searchParams));
   },

   /**
    * Takes a promise that resolves to a GitHub pull request API response,
    * parses it, and returns a promise that resolves to a Pull objects.
    */
   parse: function(githubPull) {
      debug("Getting all information for pull %s in repo %s", githubPull.number,
         githubPull.base.repo.full_name);
      // We've occasionally noticed a null pull body, so lets fix it upfront
      // before errors happen.
      githubPull.body = githubPull.body || '';

      var repo = githubPull.base.repo.full_name;

      var reviewComments = getPullReviewComments(repo, githubPull.number);
      var comments = getIssueComments(repo, githubPull.number);
      var headCommit = getCommit(repo, githubPull.head.sha);
      var commitStatuses = getCommitStatuses(repo, githubPull.head.sha);
      var events = getIssueEvents(repo, githubPull.number);
      // Only so we have the canonical list of labels.
      var ghIssue = module.exports.getIssue(repo, githubPull.number);
      var reviews = getReviews(repo, githubPull.number);

      // Returned to the map function. Each element of githubPulls maps to
      // a promise that resolves to a Pull.
      return Promise.all([reviewComments,
                          comments,
                          headCommit,
                          commitStatuses,
                          events,
                          ghIssue,
                          reviews])
       .then(function(results) {
         var reviewComments = results[0],
             comments       = results[1],
             headCommit     = results[2],
             commitStatuses = results[3],
             events         = results[4],
             ghIssue        = results[5],
             reviews        = results[6];

         // Array of Signature objects.
         var commentSignatures = comments.reduce(function(sigs, comment) {
            var commentSigs = Signature.parseComment(
             comment, repo, githubPull.number);

            return sigs.concat(commentSigs);
         }, []);

         var signatures = reviews.reduce(function(sigs, review) {
            var reviewSigs = Signature.parseReview(
             review, repo, githubPull.number);

            return sigs.concat(reviewSigs);
         }, commentSignatures);

         // Signoffs from before the most recent commit are no longer active.
         var headCommitDate = new Date(headCommit.commit.committer.date);
         signatures.forEach(function(signature) {
            if ((signature.data.type === 'CR' ||
             signature.data.type === 'QA') &&
             new Date(signature.data.created_at) < headCommitDate) {
               signature.data.active = false;
            }
         });

         // Array of Comment objects.
         comments = comments.map(function(commentData) {
            commentData.number = githubPull.number;
            commentData.repo = repo;
            commentData.type = 'issue';

            return new Comment(commentData);
         });

         // Array of Comment objects.
         comments = comments.concat(reviewComments.map(function(commentData) {
            commentData.number = githubPull.number;
            commentData.repo = repo;
            commentData.type = 'review';

            return new Comment(commentData);
         }));

         reviews = reviews.map(function(reviewData) {
            reviewData.number = githubPull.number;
            reviewData.repo = repo;

            return new Review(reviewData);
         });

         let statuses = commitStatuses.map(function(commitStatus) {
            let state = commitStatus.state || mapCheckToStatus(commitStatus.conclusion || commitStatus.status);
            let desc = commitStatus.description || mapCheckToStatus(commitStatus.conclusion || commitStatus.status);
            let url = commitStatus.target_url || commitStatus.html_url;
            let context = commitStatus.context || commitStatus.name;

            return new Status({
               repo:          repo,
               sha:           githubPull.head.sha,
               state:         state,
               description:   desc,
               target_url:    url,
               context:       context,
            });
         });

         // Array of Label objects.
         const labels = getLabelsFromEvents(events, ghIssue);

         const pull = Pull.fromGithubApi(githubPull, signatures, comments, reviews, statuses, labels);
         return pull.syncToIssue();
      });
   },

   /**
    * Takes a GitHub issue API response
    * parses it, and returns a promise that resolves to an Issue object.
    */
   parseIssue: function(ghIssue) {
      debug("Getting all information for issue %s in repo %s", ghIssue.number,
         ghIssue.repo);
      return getIssueEvents(ghIssue.repo, ghIssue.number)
      .then(function(events) {
         // Array of Label objects.
         // Note: using the repo name from the config for now until we support
         // multiple repos. The ghIssue object doesn't contain the repo name.
         var labels = getLabelsFromEvents(events, ghIssue);

         return Issue.getFromGH(ghIssue, labels);
      });
   },
};

/**
 * Get array of Label objects from complete list of a Issue's events.
 *
 * Note: ghIssue at this point has always come from one of the
 * get*Issues() commands and thus has been augmented with the
 * issue.repo property.
 */
function getLabelsFromEvents(events, ghIssue) {
   debug("Extracting label assignments from %s issue events for #%s",
    events.length, ghIssue.number);

   // Narrow list to relevant labeled/unlabeled events.
   events = _.filter(events, function(event) {
      return event.event === 'labeled' || event.event === 'unlabeled';
   });

   debug("Found %s label events for #%s", events.length, ghIssue.number);

   // Build simple Event objects with all the info we care about.
   events = events.map(function(event) {
      return {
         type: event.event,
         name: event.label.name,
         user: getLogin(event.actor),
         created_at: utils.fromDateString(event.created_at)
      };
   });

   // Group label events by label name.
   var labels = _.groupBy(events, 'name');

   // Get a list of the most recent events for each label.
   labels = _.map(labels, function(events) {
      events = _.sortBy(events, 'created_at');
      return _.last(events);
   });

   labels = _.filter(labels, function(event) {
      return event.type === 'labeled';
   });

   debug("Found %s unique labels for #%s", labels.length, ghIssue.number);

   // If these are available, use them as the canonical source, only augmented
   // by the data from events. If a label is renamed, the events will retain
   // the old name but the list of labels on the issue itself will be correct.
   // So, if a label is renamed, we'll lose the labeler and the date.
   if (ghIssue.labels && ghIssue.labels.length) {
      debug("Using %s labels from the github issue", ghIssue.labels.length);
      // Includes labeller and a time from the events api
      var eventLabels = _.indexBy(labels, 'name');

      return ghIssue.labels.map(function(label) {
         var eventLabel = eventLabels[label.name];
         return new Label(
            {name: label.name},
            ghIssue.number,
            ghIssue.repo,
            eventLabel && eventLabel.user,
            eventLabel && eventLabel.created_at
         );
      });
   }

   // Construct Label objects.
   return labels.map(function(label) {
      return new Label(
         {name: label.name},
         ghIssue.number,
         ghIssue.repo,
         label.user,
         label.created_at
      );
   });
}

/**
 * Return the default api params merged with the overrides
 */
function params(apiParams, fullRepoName) {
   const [owner, repo] = parseRepo(fullRepoName);

   return _.extend({
      owner,
      repo,
   }, apiParams);
}

/**
 * Returns a function that uses the search parameters to add the "repo"
 * property to all the results. When we ask for a list of open issues from the
 * API for a particular repo, those results don't have references to the repo
 * we asked about, so we have to inject them to normalize the structure of the
 * object.
 */
function addRepo({owner, repo}) {
   function addRepositoryField(ghIssue) {
      ghIssue.repo = owner + "/" + repo;
   }
   return function(results) {
      if (Array.isArray(results)) {
         results.forEach(addRepositoryField);
      } else {
         addRepositoryField(results);
      }
      return results;
   };
}

/**
 * Splits the repo into the owner and repo name.
 */
function parseRepo(repo) {
   return repo.split("/");
}

/**
 * Return a promise for all issue events for the given issue / pull
 */
function getIssueEvents(repo, number) {
   debug("Getting events for issue #%s", number);
   return github.paginate(githubRest.issues.listEvents, params({ issue_number: number }, repo))
}

function getIssueComments(repo, number) {
   debug("Getting comments for issue #%s", number);
   return github.paginate(githubRest.issues.listComments, params({ issue_number: number }, repo));
}

function getReviews(repo, number) {
   debug("Getting reviews for pull #%s", number);
   return github.paginate(githubRest.pulls.listReviews, params({ pull_number: number }, repo));
}

function getPullReviewComments(repo, number) {
   debug("Getting pull review comments for pull #%s", number);
   return github.paginate(githubRest.pulls.listReviewComments, params({ pull_number: number }, repo))
}

function getCommit(repo, sha) {
   return githubRest.repos.getCommit(params({ ref: sha }, repo)).then(res => res.data);
}

function getCommitStatuses(repo, ref) {
   debug("Getting commit status for %s", ref);
   let statuses = githubRest.repos.getCombinedStatusForRef(params({ ref }, repo))
      .then(res => res.data.statuses)
      .then(statuses => statuses || [])
   let checks = githubRest.checks.listForRef(params({ ref }, repo))
      .then(res => res.data.check_runs)
      .then(check_runs => check_runs || [])
   return statuses.concat(checks)
}

/**
 * Statuses and checks have slightly different status names. Let's map the
 * check values to match the status values.
 */
function mapCheckToStatus(status) {
   switch (status) {
      case 'in_progress':
      case 'queued':
         return 'pending';
      case 'success':
         return 'success';
      case 'failure':
         return 'failure';
      default:
         return 'error';
   }
}

/**
 * Remove all entries that have the pull_request key set to something truthy
 */
function filterOutPulls(issues) {
   debug("Filtering out pulls from list of %s issues", issues.length);
   issues = _.filter(issues,
                     issue => !issue.pull_request || !issue.pull_request.url);
   debug("Filtered down to %s issues", issues.length);
   return issues;
}
<commit_msg>git-manage: Use async functions for statuses<commit_after>var { Octokit } = require('@octokit/rest'),
    { throttling } = require("@octokit/plugin-throttling"),
    MyOctokit = Octokit.plugin(throttling),
    config = require('./config-loader'),
    Promise = require('bluebird'),
    _ = require('underscore'),
    debug = require('./debug')('pulldasher:github'),
    utils = require('./utils'),
    Pull = require('../models/pull'),
    Issue = require('../models/issue'),
    Comment = require('../models/comment'),
    Review = require('../models/review'),
    Label = require('../models/label'),
    Status = require('../models/status'),
    Signature = require('../models/signature'),
    getLogin  = require('./get-user-login');

const github = new MyOctokit({
   auth: config.github.token,
   throttle: {
      onRateLimit: (retryAfter, options) => {
        github.log.warn(
          `Request quota exhausted for request ${options.method} ${options.url}`
        );

        // Retry five times after hitting a rate limit error, then give up
        if (options.request.retryCount <= 5) {
          github.log.debug(`Retrying after ${retryAfter} seconds!`);
          return true;
        }
      },
      onAbuseLimit: (retryAfter, options) => {
        // does not retry, only logs a warning
        github.log.warn(
          `Abuse detected for request ${options.method} ${options.url}`
        );
      },
    }
});

const githubRest = github.rest;

module.exports = {
   github: githubRest,

   /**
    * Returns a promise which resolves to a GitHub API response to
    * a query for a particular Pull Request.
    */
   getPull: function(repo, number) {
      debug("Getting pull %s", number);
      return githubRest.pulls.get(params({ pull_number: number }, repo))
       .then(res => res.data);
   },

   /**
    * Get all *open* pull requests for a repo.
    *
    * Returns a promise which resolves to an array of all open pull requests
    */
   getOpenPulls: function(repo) {
      debug("Getting open pulls in repo %s", repo);
      return github.paginate(githubRest.pulls.list, params({state: 'open'}, repo));
   },

   /**
    * Get *all* pull requests for a repo.
    *
    * Returns a promise which resolves to an array of all pull requests
    */
   getAllPulls: function(repo) {
      debug("Getting all pulls in repo %s", repo);
      return github.paginate(githubRest.pulls.list, params({ state: 'all'}, repo));
   },

   /**
    * Get an issue for a repo.
    *
    * Returns a promise which resolves to a github issue
    */
   getIssue: function(repo, number) {
      const searchParams = params({ issue_number: number }, repo);
      debug("Getting issue %s in repo %s", number, repo);
      return githubRest.issues.get(searchParams)
       .then(res => res.data)
       .then(addRepo(searchParams));
   },

   /**
    * Get all open issues for a repo.
    *
    * Returns a promise which resolves to an array of all open issues
    */
   getOpenIssues: function(repo) {
      const searchParams = params({state: 'open'}, repo);
      debug("Getting open issues in repo %s", repo);
      return github.paginate(githubRest.issues.listForRepo, searchParams)
       .then(filterOutPulls)
       .then(addRepo(searchParams));
   },

   /**
    * Get *all* issues for a repo.
    *
    * Returns a promise which resolves to an array of all issues
    */
   getAllIssues: function(repo) {
      const searchParams = params({state: 'all'}, repo);
      debug("Getting all issues");
      return github.paginate(githubRest.issues.listForRepo, searchParams)
       .then(filterOutPulls)
       .then(addRepo(searchParams));
   },

   /**
    * Takes a promise that resolves to a GitHub pull request API response,
    * parses it, and returns a promise that resolves to a Pull objects.
    */
   parse: function(githubPull) {
      debug("Getting all information for pull %s in repo %s", githubPull.number,
         githubPull.base.repo.full_name);
      // We've occasionally noticed a null pull body, so lets fix it upfront
      // before errors happen.
      githubPull.body = githubPull.body || '';

      var repo = githubPull.base.repo.full_name;

      var reviewComments = getPullReviewComments(repo, githubPull.number);
      var comments = getIssueComments(repo, githubPull.number);
      var headCommit = getCommit(repo, githubPull.head.sha);
      var commitStatuses = getCommitStatuses(repo, githubPull.head.sha);
      var events = getIssueEvents(repo, githubPull.number);
      // Only so we have the canonical list of labels.
      var ghIssue = module.exports.getIssue(repo, githubPull.number);
      var reviews = getReviews(repo, githubPull.number);

      // Returned to the map function. Each element of githubPulls maps to
      // a promise that resolves to a Pull.
      return Promise.all([reviewComments,
                          comments,
                          headCommit,
                          commitStatuses,
                          events,
                          ghIssue,
                          reviews])
       .then(function(results) {
         var reviewComments = results[0],
             comments       = results[1],
             headCommit     = results[2],
             commitStatuses = results[3],
             events         = results[4],
             ghIssue        = results[5],
             reviews        = results[6];

         // Array of Signature objects.
         var commentSignatures = comments.reduce(function(sigs, comment) {
            var commentSigs = Signature.parseComment(
             comment, repo, githubPull.number);

            return sigs.concat(commentSigs);
         }, []);

         var signatures = reviews.reduce(function(sigs, review) {
            var reviewSigs = Signature.parseReview(
             review, repo, githubPull.number);

            return sigs.concat(reviewSigs);
         }, commentSignatures);

         // Signoffs from before the most recent commit are no longer active.
         var headCommitDate = new Date(headCommit.commit.committer.date);
         signatures.forEach(function(signature) {
            if ((signature.data.type === 'CR' ||
             signature.data.type === 'QA') &&
             new Date(signature.data.created_at) < headCommitDate) {
               signature.data.active = false;
            }
         });

         // Array of Comment objects.
         comments = comments.map(function(commentData) {
            commentData.number = githubPull.number;
            commentData.repo = repo;
            commentData.type = 'issue';

            return new Comment(commentData);
         });

         // Array of Comment objects.
         comments = comments.concat(reviewComments.map(function(commentData) {
            commentData.number = githubPull.number;
            commentData.repo = repo;
            commentData.type = 'review';

            return new Comment(commentData);
         }));

         reviews = reviews.map(function(reviewData) {
            reviewData.number = githubPull.number;
            reviewData.repo = repo;

            return new Review(reviewData);
         });

         let statuses = commitStatuses.map(function(commitStatus) {
            let state = commitStatus.state || mapCheckToStatus(commitStatus.conclusion || commitStatus.status);
            let desc = commitStatus.description || mapCheckToStatus(commitStatus.conclusion || commitStatus.status);
            let url = commitStatus.target_url || commitStatus.html_url;
            let context = commitStatus.context || commitStatus.name;

            return new Status({
               repo:          repo,
               sha:           githubPull.head.sha,
               state:         state,
               description:   desc,
               target_url:    url,
               context:       context,
            });
         });

         // Array of Label objects.
         const labels = getLabelsFromEvents(events, ghIssue);

         const pull = Pull.fromGithubApi(githubPull, signatures, comments, reviews, statuses, labels);
         return pull.syncToIssue();
      });
   },

   /**
    * Takes a GitHub issue API response
    * parses it, and returns a promise that resolves to an Issue object.
    */
   parseIssue: function(ghIssue) {
      debug("Getting all information for issue %s in repo %s", ghIssue.number,
         ghIssue.repo);
      return getIssueEvents(ghIssue.repo, ghIssue.number)
      .then(function(events) {
         // Array of Label objects.
         // Note: using the repo name from the config for now until we support
         // multiple repos. The ghIssue object doesn't contain the repo name.
         var labels = getLabelsFromEvents(events, ghIssue);

         return Issue.getFromGH(ghIssue, labels);
      });
   },
};

/**
 * Get array of Label objects from complete list of a Issue's events.
 *
 * Note: ghIssue at this point has always come from one of the
 * get*Issues() commands and thus has been augmented with the
 * issue.repo property.
 */
function getLabelsFromEvents(events, ghIssue) {
   debug("Extracting label assignments from %s issue events for #%s",
    events.length, ghIssue.number);

   // Narrow list to relevant labeled/unlabeled events.
   events = _.filter(events, function(event) {
      return event.event === 'labeled' || event.event === 'unlabeled';
   });

   debug("Found %s label events for #%s", events.length, ghIssue.number);

   // Build simple Event objects with all the info we care about.
   events = events.map(function(event) {
      return {
         type: event.event,
         name: event.label.name,
         user: getLogin(event.actor),
         created_at: utils.fromDateString(event.created_at)
      };
   });

   // Group label events by label name.
   var labels = _.groupBy(events, 'name');

   // Get a list of the most recent events for each label.
   labels = _.map(labels, function(events) {
      events = _.sortBy(events, 'created_at');
      return _.last(events);
   });

   labels = _.filter(labels, function(event) {
      return event.type === 'labeled';
   });

   debug("Found %s unique labels for #%s", labels.length, ghIssue.number);

   // If these are available, use them as the canonical source, only augmented
   // by the data from events. If a label is renamed, the events will retain
   // the old name but the list of labels on the issue itself will be correct.
   // So, if a label is renamed, we'll lose the labeler and the date.
   if (ghIssue.labels && ghIssue.labels.length) {
      debug("Using %s labels from the github issue", ghIssue.labels.length);
      // Includes labeller and a time from the events api
      var eventLabels = _.indexBy(labels, 'name');

      return ghIssue.labels.map(function(label) {
         var eventLabel = eventLabels[label.name];
         return new Label(
            {name: label.name},
            ghIssue.number,
            ghIssue.repo,
            eventLabel && eventLabel.user,
            eventLabel && eventLabel.created_at
         );
      });
   }

   // Construct Label objects.
   return labels.map(function(label) {
      return new Label(
         {name: label.name},
         ghIssue.number,
         ghIssue.repo,
         label.user,
         label.created_at
      );
   });
}

/**
 * Return the default api params merged with the overrides
 */
function params(apiParams, fullRepoName) {
   const [owner, repo] = parseRepo(fullRepoName);

   return _.extend({
      owner,
      repo,
   }, apiParams);
}

/**
 * Returns a function that uses the search parameters to add the "repo"
 * property to all the results. When we ask for a list of open issues from the
 * API for a particular repo, those results don't have references to the repo
 * we asked about, so we have to inject them to normalize the structure of the
 * object.
 */
function addRepo({owner, repo}) {
   function addRepositoryField(ghIssue) {
      ghIssue.repo = owner + "/" + repo;
   }
   return function(results) {
      if (Array.isArray(results)) {
         results.forEach(addRepositoryField);
      } else {
         addRepositoryField(results);
      }
      return results;
   };
}

/**
 * Splits the repo into the owner and repo name.
 */
function parseRepo(repo) {
   return repo.split("/");
}

/**
 * Return a promise for all issue events for the given issue / pull
 */
function getIssueEvents(repo, number) {
   debug("Getting events for issue #%s", number);
   return github.paginate(githubRest.issues.listEvents, params({ issue_number: number }, repo))
}

function getIssueComments(repo, number) {
   debug("Getting comments for issue #%s", number);
   return github.paginate(githubRest.issues.listComments, params({ issue_number: number }, repo));
}

function getReviews(repo, number) {
   debug("Getting reviews for pull #%s", number);
   return github.paginate(githubRest.pulls.listReviews, params({ pull_number: number }, repo));
}

function getPullReviewComments(repo, number) {
   debug("Getting pull review comments for pull #%s", number);
   return github.paginate(githubRest.pulls.listReviewComments, params({ pull_number: number }, repo))
}

function getCommit(repo, sha) {
   return githubRest.repos.getCommit(params({ ref: sha }, repo)).then(res => res.data);
}

async function getCommitStatuses(repo, ref) {
   debug("Getting commit status for %s", ref);
   let statuses = await githubRest.repos.getCombinedStatusForRef(params({ ref }, repo))
      .then(res => res.data.statuses)
      .then(statuses => statuses || [])
   let checks = await githubRest.checks.listForRef(params({ ref }, repo))
      .then(res => res.data.check_runs)
      .then(check_runs => check_runs || [])
   return statuses.concat(checks)
}

/**
 * Statuses and checks have slightly different status names. Let's map the
 * check values to match the status values.
 */
function mapCheckToStatus(status) {
   switch (status) {
      case 'in_progress':
      case 'queued':
         return 'pending';
      case 'success':
         return 'success';
      case 'failure':
         return 'failure';
      default:
         return 'error';
   }
}

/**
 * Remove all entries that have the pull_request key set to something truthy
 */
function filterOutPulls(issues) {
   debug("Filtering out pulls from list of %s issues", issues.length);
   issues = _.filter(issues,
                     issue => !issue.pull_request || !issue.pull_request.url);
   debug("Filtered down to %s issues", issues.length);
   return issues;
}
<|endoftext|>


<commit_before>
var fs = require('fs')
  , path = require('path')
  , spawn = require('child_process').spawn;

module.exports = GitScripts;

function GitScripts(pathStr) {
  this.path = pathStr = pathStr || '.';
  this.packagePath = pathStr + '/package.json';
  this.gitPath = this.getGitPath(pathStr);
  this.hooksPath = this.gitPath + '/hooks';
  this.oldHooksPath = this.gitPath + '/hooks.old';
}

/**
 * Install git-scripts.
 *
 * @param {Function} callback
 * @api public
 */

GitScripts.prototype.install = function(callback) {
  callback = callback || function() {};

  var self = this;

  this.isGitRepo(function(result) {
    if (!result) {
      return callback(new Error('Not a git repository.'));
    }

    self.installed(function(installed) {
      if (installed) {
        return callback(new Error('Already installed.'));
      }

      fs.exists(self.hooksPath, function(exists) {
        if (exists) {
          install();
        } else {
          fs.mkdir(self.hooksPath, function(err) {
            if (err) return callback(err);
            install();
          });
        }

        function install() {
          fs.rename(self.hooksPath, self.oldHooksPath, function(err) {
            if (err) return callback(err);

            var hooksSrcPath = __dirname + '/../bin/hooks';
            fs.symlink(path.relative(self.gitPath, hooksSrcPath), self.hooksPath, callback);
          });
        }
      });
    });
  });
};

/**
 * Uninstall git-scripts.
 *
 * @param {Function} callback
 * @api public
 */

GitScripts.prototype.uninstall = function(callback) {
  callback = callback || function() {};

  var self = this;

  this.isGitRepo(function(result) {
    if (!result) {
      return callback(new Error('Not a git repository.'));
    }

    self.installed(function(result) {
      if (!result) {
        return callback(new Error('Not installed.'));
      }

      fs.unlink(self.hooksPath, function(err) {
        if (err) return callback(err);

        fs.rename(self.oldHooksPath, self.hooksPath, callback);
      });
    });
  });
};

/**
 * Run a git-hooks script.
 *
 * @param {String} hook name
 * @param {String} args
 * @param {Function} callback
 * @api public
 */

GitScripts.prototype.run = function(name) {
  var args = Array.prototype.slice.call(arguments)
    , callback = function() {};

  if ('function' == typeof args[args.length - 1]) {
    callback = args.pop();
  }

  this.readCommand(name, function(err, cmd) {
    if (err) return callback(err);
    if (!cmd) return callback();

    var conf = {stdio: 'inherit', customFds: [0, 1, 2]}
      , proc = spawn('sh', ['-c', cmd].concat(args), conf);

    proc.on('close', function(code) {
      var err;
      if (code) {
        err = new Error('Failed to exec ' + name + ' hook script');
        err.code = code;
      }

      callback(err);
    });
  });
};

/**
 * Read the script command.
 *
 * @api private
 */

GitScripts.prototype.readCommand = function(name, callback) {
  fs.readFile(this.packagePath, function(err, data) {
    if (err) return callback(err);

    var pkg = JSON.parse(data)
      , git = pkg.git || {}
      , scripts = git.scripts || {};

    callback(null, scripts[name]);
  });
};

/**
 * @api private
 */

GitScripts.prototype.isGitRepo = function(callback) {
  fs.exists(this.gitPath, callback);
};

/**
 * @api private
 */

GitScripts.prototype.getGitPath = function(pathStr) {
  var gitPath = pathStr + '/.git';
  if (fs.existsSync(gitPath)) {
    var pathStats = fs.lstatSync(gitPath);
    // file contains a pointer to the git path
    if (pathStats.isFile()) {
      var gitPathTxt = fs.readFileSync(gitPath, 'utf8');
      gitPath = path.join(pathStr, gitPathTxt.replace('gitdir: ', '')).replace('\n', '');
    }

  }

  return gitPath;
};

/**
 * @api private
 */

GitScripts.prototype.installed = function(callback) {
  fs.exists(this.oldHooksPath, callback);
};

<commit_msg>clean up whitespace<commit_after>
var fs = require('fs')
  , path = require('path')
  , spawn = require('child_process').spawn;

module.exports = GitScripts;

function GitScripts(pathStr) {
  this.path = pathStr = pathStr || '.';
  this.packagePath = pathStr + '/package.json';
  this.gitPath = this.getGitPath(pathStr);
  this.hooksPath = this.gitPath + '/hooks';
  this.oldHooksPath = this.gitPath + '/hooks.old';
}

/**
 * Install git-scripts.
 *
 * @param {Function} callback
 * @api public
 */

GitScripts.prototype.install = function(callback) {
  callback = callback || function() {};

  var self = this;

  this.isGitRepo(function(result) {
    if (!result) {
      return callback(new Error('Not a git repository.'));
    }

    self.installed(function(installed) {
      if (installed) {
        return callback(new Error('Already installed.'));
      }

      fs.exists(self.hooksPath, function(exists) {
        if (exists) {
          install();
        } else {
          fs.mkdir(self.hooksPath, function(err) {
            if (err) return callback(err);
            install();
          });
        }

        function install() {
          fs.rename(self.hooksPath, self.oldHooksPath, function(err) {
            if (err) return callback(err);

            var hooksSrcPath = __dirname + '/../bin/hooks';
            fs.symlink(path.relative(self.gitPath, hooksSrcPath), self.hooksPath, callback);
          });
        }
      });
    });
  });
};

/**
 * Uninstall git-scripts.
 *
 * @param {Function} callback
 * @api public
 */

GitScripts.prototype.uninstall = function(callback) {
  callback = callback || function() {};

  var self = this;

  this.isGitRepo(function(result) {
    if (!result) {
      return callback(new Error('Not a git repository.'));
    }

    self.installed(function(result) {
      if (!result) {
        return callback(new Error('Not installed.'));
      }

      fs.unlink(self.hooksPath, function(err) {
        if (err) return callback(err);

        fs.rename(self.oldHooksPath, self.hooksPath, callback);
      });
    });
  });
};

/**
 * Run a git-hooks script.
 *
 * @param {String} hook name
 * @param {String} args
 * @param {Function} callback
 * @api public
 */

GitScripts.prototype.run = function(name) {
  var args = Array.prototype.slice.call(arguments)
    , callback = function() {};

  if ('function' == typeof args[args.length - 1]) {
    callback = args.pop();
  }

  this.readCommand(name, function(err, cmd) {
    if (err) return callback(err);
    if (!cmd) return callback();

    var conf = {stdio: 'inherit', customFds: [0, 1, 2]}
      , proc = spawn('sh', ['-c', cmd].concat(args), conf);

    proc.on('close', function(code) {
      var err;
      if (code) {
        err = new Error('Failed to exec ' + name + ' hook script');
        err.code = code;
      }

      callback(err);
    });
  });
};

/**
 * Read the script command.
 *
 * @api private
 */

GitScripts.prototype.readCommand = function(name, callback) {
  fs.readFile(this.packagePath, function(err, data) {
    if (err) return callback(err);

    var pkg = JSON.parse(data)
      , git = pkg.git || {}
      , scripts = git.scripts || {};

    callback(null, scripts[name]);
  });
};

/**
 * @api private
 */

GitScripts.prototype.isGitRepo = function(callback) {
  fs.exists(this.gitPath, callback);
};

/**
 * @api private
 */

GitScripts.prototype.getGitPath = function(pathStr) {
  var gitPath = pathStr + '/.git';
  if (fs.existsSync(gitPath)) {
    var pathStats = fs.lstatSync(gitPath);
    // file contains a pointer to the git path
    if (pathStats.isFile()) {
      var gitPathTxt = fs.readFileSync(gitPath, 'utf8');
      gitPath = path.join(pathStr, gitPathTxt.replace('gitdir: ', '')).replace('\n', '');
    }
  }
  return gitPath;
};

/**
 * @api private
 */

GitScripts.prototype.installed = function(callback) {
  fs.exists(this.oldHooksPath, callback);
};

<|endoftext|>


<commit_before>Router.map(function () {
	this.route('frameSchedule', {
		path: '/frame/schedule',
		layoutTemplate: 'frameLayout',
	});
});

Template.frameSchedule.onCreated(function() {
	var filter = Filtering(EventPredicates);

	var instance = this;
	instance.interval = new ReactiveVar(60);
	instance.scheduleStart = new ReactiveVar(moment());
	instance.separators = new ReactiveVar([]);

	this.autorun(function() {
		var query = Router.current().params.query;

		var scheduleStart;
		if (query.start) scheduleStart = moment(query.start);
		if (!scheduleStart || !scheduleStart.isValid()) scheduleStart = moment(minuteTime.get()).startOf('week');
		instance.scheduleStart.set(scheduleStart);

		var rawSeps = (query.sep || "").split(',');
		var seps = [];
		_.each(rawSeps, function(rawSep) {
			if (rawSep.length == 0) {
				return;
			}

			if (rawSep.length < 3) {
				rawSep = rawSep + "00";
			}

			var hm = parseInt(rawSep, 10);
			if (!isNaN(hm)) {
				var h = Math.floor(hm/100);
				var m = hm % 100;
				seps.push(h*60+m);
			}
		});
		var separators = _.uniq(seps);
		instance.separators.set(separators);

		var readInterval = parseInt(query.interval, 10);
		if (!isNaN(readInterval) && readInterval > 0) {
			instance.interval.set(readInterval);
		} else {
			if (separators.length > 0) {
				instance.interval.set(24*60);
			} else {
				instance.interval.set(60);
			}
		}

		filter.clear().read(query);
		filter.add('after', scheduleStart);
		filter.add('end', moment(scheduleStart).add(1, 'week'));
		filter.done();
	});

	this.autorun(function() {
		subs.subscribe('eventsFind', filter.toQuery(), 100);
	});

	instance.days = new ReactiveVar([]);
	instance.intervals = new ReactiveVar([]);
	instance.slots = new ReactiveVar({});
	instance.kindMap = function() { return 0; };

	this.autorun(function() {
		var scheduleStart = moment(filter.get('after'));
		var end = moment(filter.get('end'));
		var dayCount = end.diff(scheduleStart, 'days');
		var interval = instance.interval.get();

		// Because we need to find the closest separator later on
		// we create a reversed copy which is easier to search
		var separators = instance.separators.get().slice().reverse();

		// List of intervals where events or separators are placed
		var intervals = _.reduce(separators, function(intervals, separator) {
			intervals[separator] = separator;
			return intervals;
		}, {});

		// List of days where events where found
		var days = {};

		// Map of slots where events were found. each slot holds a list of events.
		var slots = {};

		// Count occurences of first few chars in event titles
		var kinds = {};

		// Place found events into the slots
		eventsFind(filter.toQuery(), 100).forEach(function(event) {
			var eventStart = moment(event.start);
			var dayStart = moment(eventStart).startOf('day');

			var day = dayStart.diff(scheduleStart, 'days');
			days[day] = day;

			var minuteDiff = eventStart.diff(dayStart, 'minutes');
			var intervalStart = Math.floor(minuteDiff / interval) * interval;
			var closestSeparator = _.find(separators, function(sep) {
				return sep < minuteDiff;
			});

			var mins = Math.max(intervalStart, closestSeparator || 0);
			intervals[mins] = mins;

			if (!slots[mins]) slots[mins] = [];
			if (!slots[mins][day]) slots[mins][day] = [];
			slots[mins][day].push(event);

			var kindId = event.title.substr(0, 5);
			if (!kinds[kindId]) kinds[kindId] = 1;
			kinds[kindId] += 1;
		});

		var numCmp = function(a, b) { return a - b; };
		instance.days.set(_.values(days).sort(numCmp));
		instance.intervals.set(_.values(intervals).sort(numCmp));
		instance.slots.set(slots);

		// Build list of most used titles (first few chars)
		var mostUsedKinds = _.sortBy(_.pairs(kinds), function(kv) { return -kv[1]; });
		var kindRank = _.object(_.map(mostUsedKinds.slice(0, 15), function(kv, rank) {
			return [kv[0], rank+1];
		}));
		instance.kindMap = function(title) {
			var kindId = title.substr(0, 5);
			if (kindRank[kindId]) return kindRank[kindId];
			return 0;
		};
	});
});

Template.frameSchedule.helpers({
	days: function() {
		var instance = Template.instance();
		var scheduleStart = instance.scheduleStart.get();
		return _.map(Template.instance().days.get(), function(day) {
			return moment(scheduleStart).add(day, 'days').format('dddd');
		});
	},

	intervals: function() {
		var slots = Template.instance().slots.get();

		return _.map(Template.instance().intervals.get(), function(mins) {
			return {
				interval: moment().hour(0).minute(mins).format('LT'),
				slots: _.map(Template.instance().days.get(), function(day) {
					return slots[mins] && slots[mins][day];
				})
			}
		});
	},

	type: function() {
		return Template.instance().kindMap(this.title);
	}
});
<commit_msg>fix comparison<commit_after>Router.map(function () {
	this.route('frameSchedule', {
		path: '/frame/schedule',
		layoutTemplate: 'frameLayout',
	});
});

Template.frameSchedule.onCreated(function() {
	var filter = Filtering(EventPredicates);

	var instance = this;
	instance.interval = new ReactiveVar(60);
	instance.scheduleStart = new ReactiveVar(moment());
	instance.separators = new ReactiveVar([]);

	this.autorun(function() {
		var query = Router.current().params.query;

		var scheduleStart;
		if (query.start) scheduleStart = moment(query.start);
		if (!scheduleStart || !scheduleStart.isValid()) scheduleStart = moment(minuteTime.get()).startOf('week');
		instance.scheduleStart.set(scheduleStart);

		var rawSeps = (query.sep || "").split(',');
		var seps = [];
		_.each(rawSeps, function(rawSep) {
			if (rawSep.length == 0) {
				return;
			}

			if (rawSep.length < 3) {
				rawSep = rawSep + "00";
			}

			var hm = parseInt(rawSep, 10);
			if (!isNaN(hm)) {
				var h = Math.floor(hm/100);
				var m = hm % 100;
				seps.push(h*60+m);
			}
		});
		var separators = _.uniq(seps);
		instance.separators.set(separators);

		var readInterval = parseInt(query.interval, 10);
		if (!isNaN(readInterval) && readInterval > 0) {
			instance.interval.set(readInterval);
		} else {
			if (separators.length > 0) {
				instance.interval.set(24*60);
			} else {
				instance.interval.set(60);
			}
		}

		filter.clear().read(query);
		filter.add('after', scheduleStart);
		filter.add('end', moment(scheduleStart).add(1, 'week'));
		filter.done();
	});

	this.autorun(function() {
		subs.subscribe('eventsFind', filter.toQuery(), 100);
	});

	instance.days = new ReactiveVar([]);
	instance.intervals = new ReactiveVar([]);
	instance.slots = new ReactiveVar({});
	instance.kindMap = function() { return 0; };

	this.autorun(function() {
		var scheduleStart = moment(filter.get('after'));
		var end = moment(filter.get('end'));
		var dayCount = end.diff(scheduleStart, 'days');
		var interval = instance.interval.get();

		// Because we need to find the closest separator later on
		// we create a reversed copy which is easier to search
		var separators = instance.separators.get().slice().reverse();

		// List of intervals where events or separators are placed
		var intervals = _.reduce(separators, function(intervals, separator) {
			intervals[separator] = separator;
			return intervals;
		}, {});

		// List of days where events where found
		var days = {};

		// Map of slots where events were found. each slot holds a list of events.
		var slots = {};

		// Count occurences of first few chars in event titles
		var kinds = {};

		// Place found events into the slots
		eventsFind(filter.toQuery(), 100).forEach(function(event) {
			var eventStart = moment(event.start);
			var dayStart = moment(eventStart).startOf('day');

			var day = dayStart.diff(scheduleStart, 'days');
			days[day] = day;

			var minuteDiff = eventStart.diff(dayStart, 'minutes');
			var intervalStart = Math.floor(minuteDiff / interval) * interval;
			var closestSeparator = _.find(separators, function(sep) {
				return sep <= minuteDiff;
			});

			var mins = Math.max(intervalStart, closestSeparator || 0);
			intervals[mins] = mins;

			if (!slots[mins]) slots[mins] = [];
			if (!slots[mins][day]) slots[mins][day] = [];
			slots[mins][day].push(event);

			var kindId = event.title.substr(0, 5);
			if (!kinds[kindId]) kinds[kindId] = 1;
			kinds[kindId] += 1;
		});

		var numCmp = function(a, b) { return a - b; };
		instance.days.set(_.values(days).sort(numCmp));
		instance.intervals.set(_.values(intervals).sort(numCmp));
		instance.slots.set(slots);

		// Build list of most used titles (first few chars)
		var mostUsedKinds = _.sortBy(_.pairs(kinds), function(kv) { return -kv[1]; });
		var kindRank = _.object(_.map(mostUsedKinds.slice(0, 15), function(kv, rank) {
			return [kv[0], rank+1];
		}));
		instance.kindMap = function(title) {
			var kindId = title.substr(0, 5);
			if (kindRank[kindId]) return kindRank[kindId];
			return 0;
		};
	});
});

Template.frameSchedule.helpers({
	days: function() {
		var instance = Template.instance();
		var scheduleStart = instance.scheduleStart.get();
		return _.map(Template.instance().days.get(), function(day) {
			return moment(scheduleStart).add(day, 'days').format('dddd');
		});
	},

	intervals: function() {
		var slots = Template.instance().slots.get();

		return _.map(Template.instance().intervals.get(), function(mins) {
			return {
				interval: moment().hour(0).minute(mins).format('LT'),
				slots: _.map(Template.instance().days.get(), function(day) {
					return slots[mins] && slots[mins][day];
				})
			}
		});
	},

	type: function() {
		return Template.instance().kindMap(this.title);
	}
});
<|endoftext|>


<commit_before>/** @babel */

import {shell} from 'electron'
import {Range} from 'atom'
import {parse as parseURL} from 'url'
import path from 'path'

export default class GitHubFile {
  // Public
  static fromPath (filePath) {
    return new GitHubFile(filePath)
  }

  constructor (filePath) {
    this.filePath = filePath
    const [rootDir] = atom.project.relativizePath(this.filePath)

    if (rootDir != null) {
      const rootDirIndex = atom.project.getPaths().indexOf(rootDir)
      this.repo = atom.project.getRepositories()[rootDirIndex]
    }
  }

  // Public
  open (lineRange) {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.blobURL() + this.getLineRangeSuffix(lineRange))
    }
  }

  // Public
  openOnMaster (lineRange) {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.blobURLForMaster() + this.getLineRangeSuffix(lineRange))
    }
  }

  // Public
  blame (lineRange) {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.blameURL() + this.getLineRangeSuffix(lineRange))
    }
  }

  history () {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.historyURL())
    }
  }

  copyURL (lineRange) {
    if (this.validateRepo()) {
      atom.clipboard.write(this.shaURL() + this.getLineRangeSuffix(lineRange))
    }
  }

  openBranchCompare () {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.branchCompareURL())
    }
  }

  openIssues () {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.issuesURL())
    }
  }

  openPullRequests () {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.pullRequestsURL())
    }
  }

  openRepository () {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.githubRepoURL())
    }
  }

  getLineRangeSuffix (lineRange) {
    if (lineRange && !this.isGitHubWikiURL(this.githubRepoURL()) && atom.config.get('open-on-github.includeLineNumbersInUrls')) {
      lineRange = Range.fromObject(lineRange)
      const startRow = lineRange.start.row + 1
      const endRow = lineRange.end.row + 1

      if (startRow === endRow) {
        if (this.isGistURL(this.githubRepoURL())) {
          return `-L${startRow}`
        } else {
          return `#L${startRow}`
        }
      } else {
        if (this.isGistURL(this.githubRepoURL())) {
          return `-L${startRow}-L${endRow}`
        } else {
          return `#L${startRow}-L${endRow}`
        }
      }
    } else {
      return ''
    }
  }

  // Internal
  validateRepo () {
    if (!this.repo) {
      atom.notifications.addWarning(`No repository found for path: ${this.filePath}.`)
      return false
    } else if (!this.gitURL()) {
      atom.notifications.addWarning(`No URL defined for remote: ${this.remoteName()}`)
      return false
    } else if (!this.githubRepoURL()) {
      atom.notifications.addWarning(`Remote URL is not hosted on GitHub: ${this.gitURL()}`)
      return false
    }
    return true
  }

  // Internal
  openURLInBrowser (url) {
    shell.openExternal(url)
  }

  // Internal
  blobURL () {
    const gitHubRepoURL = this.githubRepoURL()
    const repoRelativePath = this.repoRelativePath()

    if (this.isGitHubWikiURL(gitHubRepoURL)) {
      return `${gitHubRepoURL.slice(0, -5)}/wiki/${this.extractFileName(repoRelativePath)}`
    } else if (this.isGistURL(gitHubRepoURL)) {
      return `${gitHubRepoURL}#file-${this.encodeSegments(repoRelativePath.replace(/\./g, '-'))}`
    } else {
      return `${gitHubRepoURL}/blob/${this.remoteBranchName()}/${this.encodeSegments(repoRelativePath)}`
    }
  }

  // Internal
  blobURLForMaster () {
    if (this.isGistURL(this.githubRepoURL())) {
      return this.blobURL() // Gists do not have branches
    } else {
      return `${this.githubRepoURL()}/blob/master/${this.encodeSegments(this.repoRelativePath())}`
    }
  }

  // Internal
  shaURL () {
    const gitHubRepoURL = this.githubRepoURL()
    const encodedSHA = this.encodeSegments(this.sha())
    const repoRelativePath = this.repoRelativePath()

    if (this.isGistURL(gitHubRepoURL)) {
      return `${gitHubRepoURL}/${encodedSHA}#file-${this.encodeSegments(repoRelativePath.replace(/\./g, '-'))}`
    } else {
      return `${gitHubRepoURL}/blob/${encodedSHA}/${this.encodeSegments(repoRelativePath)}`
    }
  }

  // Internal
  blameURL () {
    return `${this.githubRepoURL()}/blame/${this.remoteBranchName()}/${this.encodeSegments(this.repoRelativePath())}`
  }

  // Internal
  historyURL () {
    const gitHubRepoURL = this.githubRepoURL()

    if (this.isGistURL(gitHubRepoURL)) {
      return `${gitHubRepoURL}/revisions`
    } else {
      return `${gitHubRepoURL}/commits/${this.remoteBranchName()}/${this.encodeSegments(this.repoRelativePath())}`
    }
  }

  // Internal
  issuesURL () {
    return `${this.githubRepoURL()}/issues`
  }

  // Internal
  pullRequestsURL () {
    return `${this.githubRepoURL()}/pulls`
  }

  // Internal
  branchCompareURL () {
    return `${this.githubRepoURL()}/compare/${this.encodeSegments(this.branchName())}`
  }

  encodeSegments (segments = '') {
    return segments.split('/').map(segment => encodeURIComponent(segment)).join('/')
  }

  // Internal
  extractFileName (relativePath = '') {
    return path.parse(relativePath).name
  }

  // Internal
  gitURL () {
    const remoteName = this.remoteName()
    if (remoteName != null) {
      return this.repo.getConfigValue(`remote.${remoteName}.url`, this.filePath)
    } else {
      return this.repo.getConfigValue(`remote.origin.url`, this.filePath)
    }
  }

  // Internal
  githubRepoURL () {
    let url = this.gitURL()

    if (url.match(/git@[^:]+:/)) {
      url = url.replace(/^git@([^:]+):(.+)$/, (match, host, repoPath) => {
        repoPath = repoPath.replace(/^\/+/, '')
        return `http://${host}/${repoPath}`
      })
    } else if (url.match(/ssh:\/\/git@([^/]+)\//)) {
      url = `http://${url.substring(10)}`
    } else if (url.match(/^git:\/\/[^/]+\//)) {
      url = `http${url.substring(3)}`
    }

    // Remove trailing .git and trailing slashes
    url = url.replace(/\.git$/, '').replace(/\/+$/, '')

    if (!this.isBitbucketURL(url)) {
      return url
    }
  }

  isGistURL (url) {
    try {
      const {host} = parseURL(url)

      return host === 'gist.github.com'
    } finally {}
  }

  isGitHubWikiURL (url) {
    return /\.wiki$/.test(url)
  }

  isBitbucketURL (url) {
    if (url.startsWith('git@bitbucket.org')) {
      return true
    }

    try {
      const {host} = parseURL(url)

      return host === 'bitbucket.org'
    } finally {}
  }

  // Internal
  repoRelativePath () {
    return this.repo.getRepo(this.filePath).relativize(this.filePath)
  }

  // Internal
  remoteName () {
    const gitConfigRemote = this.repo.getConfigValue('atom.open-on-github.remote', this.filePath)

    if (gitConfigRemote) {
      return gitConfigRemote
    }

    const shortBranch = this.repo.getShortHead(this.filePath)

    if (!shortBranch) {
      return null
    }

    const branchRemote = this.repo.getConfigValue(`branch.${shortBranch}.remote`, this.filePath)

    if (branchRemote && branchRemote.length > 0) {
      return branchRemote
    }

    return null
  }

  // Internal
  sha () {
    return this.repo.getReferenceTarget('HEAD', this.filePath)
  }

  // Internal
  branchName () {
    const shortBranch = this.repo.getShortHead(this.filePath)

    if (!shortBranch) {
      return null
    }

    const branchMerge = this.repo.getConfigValue(`branch.${shortBranch}.merge`, this.filePath)
    if (!(branchMerge && branchMerge.length > 11)) {
      return shortBranch
    }

    if (branchMerge.indexOf('refs/heads/') !== 0) {
      return shortBranch
    }

    return branchMerge.substring(11)
  }

  // Internal
  remoteBranchName () {
    const gitConfigBranch = this.repo.getConfigValue('atom.open-on-github.branch', this.filePath)

    if (gitConfigBranch) {
      return gitConfigBranch
    } else if (this.remoteName() != null) {
      return this.encodeSegments(this.branchName())
    } else {
      return 'master'
    }
  }
}
<commit_msg>Alias file-on-master to file for wikis<commit_after>/** @babel */

import {shell} from 'electron'
import {Range} from 'atom'
import {parse as parseURL} from 'url'
import path from 'path'

export default class GitHubFile {
  // Public
  static fromPath (filePath) {
    return new GitHubFile(filePath)
  }

  constructor (filePath) {
    this.filePath = filePath
    const [rootDir] = atom.project.relativizePath(this.filePath)

    if (rootDir != null) {
      const rootDirIndex = atom.project.getPaths().indexOf(rootDir)
      this.repo = atom.project.getRepositories()[rootDirIndex]
    }
  }

  // Public
  open (lineRange) {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.blobURL() + this.getLineRangeSuffix(lineRange))
    }
  }

  // Public
  openOnMaster (lineRange) {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.blobURLForMaster() + this.getLineRangeSuffix(lineRange))
    }
  }

  // Public
  blame (lineRange) {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.blameURL() + this.getLineRangeSuffix(lineRange))
    }
  }

  history () {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.historyURL())
    }
  }

  copyURL (lineRange) {
    if (this.validateRepo()) {
      atom.clipboard.write(this.shaURL() + this.getLineRangeSuffix(lineRange))
    }
  }

  openBranchCompare () {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.branchCompareURL())
    }
  }

  openIssues () {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.issuesURL())
    }
  }

  openPullRequests () {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.pullRequestsURL())
    }
  }

  openRepository () {
    if (this.validateRepo()) {
      this.openURLInBrowser(this.githubRepoURL())
    }
  }

  getLineRangeSuffix (lineRange) {
    if (lineRange && !this.isGitHubWikiURL(this.githubRepoURL()) && atom.config.get('open-on-github.includeLineNumbersInUrls')) {
      lineRange = Range.fromObject(lineRange)
      const startRow = lineRange.start.row + 1
      const endRow = lineRange.end.row + 1

      if (startRow === endRow) {
        if (this.isGistURL(this.githubRepoURL())) {
          return `-L${startRow}`
        } else {
          return `#L${startRow}`
        }
      } else {
        if (this.isGistURL(this.githubRepoURL())) {
          return `-L${startRow}-L${endRow}`
        } else {
          return `#L${startRow}-L${endRow}`
        }
      }
    } else {
      return ''
    }
  }

  // Internal
  validateRepo () {
    if (!this.repo) {
      atom.notifications.addWarning(`No repository found for path: ${this.filePath}.`)
      return false
    } else if (!this.gitURL()) {
      atom.notifications.addWarning(`No URL defined for remote: ${this.remoteName()}`)
      return false
    } else if (!this.githubRepoURL()) {
      atom.notifications.addWarning(`Remote URL is not hosted on GitHub: ${this.gitURL()}`)
      return false
    }
    return true
  }

  // Internal
  openURLInBrowser (url) {
    shell.openExternal(url)
  }

  // Internal
  blobURL () {
    const gitHubRepoURL = this.githubRepoURL()
    const repoRelativePath = this.repoRelativePath()

    if (this.isGitHubWikiURL(gitHubRepoURL)) {
      return `${gitHubRepoURL.slice(0, -5)}/wiki/${this.extractFileName(repoRelativePath)}`
    } else if (this.isGistURL(gitHubRepoURL)) {
      return `${gitHubRepoURL}#file-${this.encodeSegments(repoRelativePath.replace(/\./g, '-'))}`
    } else {
      return `${gitHubRepoURL}/blob/${this.remoteBranchName()}/${this.encodeSegments(repoRelativePath)}`
    }
  }

  // Internal
  blobURLForMaster () {
    const gitHubRepoURL = this.githubRepoURL()

    if (this.isGitHubWikiURL(gitHubRepoURL) || this.isGistURL(gitHubRepoURL)) {
      return this.blobURL() // Gists do not have branches
    } else {
      return `${gitHubRepoURL}/blob/master/${this.encodeSegments(this.repoRelativePath())}`
    }
  }

  // Internal
  shaURL () {
    const gitHubRepoURL = this.githubRepoURL()
    const encodedSHA = this.encodeSegments(this.sha())
    const repoRelativePath = this.repoRelativePath()

    if (this.isGistURL(gitHubRepoURL)) {
      return `${gitHubRepoURL}/${encodedSHA}#file-${this.encodeSegments(repoRelativePath.replace(/\./g, '-'))}`
    } else {
      return `${gitHubRepoURL}/blob/${encodedSHA}/${this.encodeSegments(repoRelativePath)}`
    }
  }

  // Internal
  blameURL () {
    return `${this.githubRepoURL()}/blame/${this.remoteBranchName()}/${this.encodeSegments(this.repoRelativePath())}`
  }

  // Internal
  historyURL () {
    const gitHubRepoURL = this.githubRepoURL()

    if (this.isGistURL(gitHubRepoURL)) {
      return `${gitHubRepoURL}/revisions`
    } else {
      return `${gitHubRepoURL}/commits/${this.remoteBranchName()}/${this.encodeSegments(this.repoRelativePath())}`
    }
  }

  // Internal
  issuesURL () {
    return `${this.githubRepoURL()}/issues`
  }

  // Internal
  pullRequestsURL () {
    return `${this.githubRepoURL()}/pulls`
  }

  // Internal
  branchCompareURL () {
    return `${this.githubRepoURL()}/compare/${this.encodeSegments(this.branchName())}`
  }

  encodeSegments (segments = '') {
    return segments.split('/').map(segment => encodeURIComponent(segment)).join('/')
  }

  // Internal
  extractFileName (relativePath = '') {
    return path.parse(relativePath).name
  }

  // Internal
  gitURL () {
    const remoteName = this.remoteName()
    if (remoteName != null) {
      return this.repo.getConfigValue(`remote.${remoteName}.url`, this.filePath)
    } else {
      return this.repo.getConfigValue(`remote.origin.url`, this.filePath)
    }
  }

  // Internal
  githubRepoURL () {
    let url = this.gitURL()

    if (url.match(/git@[^:]+:/)) {
      url = url.replace(/^git@([^:]+):(.+)$/, (match, host, repoPath) => {
        repoPath = repoPath.replace(/^\/+/, '')
        return `http://${host}/${repoPath}`
      })
    } else if (url.match(/ssh:\/\/git@([^/]+)\//)) {
      url = `http://${url.substring(10)}`
    } else if (url.match(/^git:\/\/[^/]+\//)) {
      url = `http${url.substring(3)}`
    }

    // Remove trailing .git and trailing slashes
    url = url.replace(/\.git$/, '').replace(/\/+$/, '')

    if (!this.isBitbucketURL(url)) {
      return url
    }
  }

  isGistURL (url) {
    try {
      const {host} = parseURL(url)

      return host === 'gist.github.com'
    } finally {}
  }

  isGitHubWikiURL (url) {
    return /\.wiki$/.test(url)
  }

  isBitbucketURL (url) {
    if (url.startsWith('git@bitbucket.org')) {
      return true
    }

    try {
      const {host} = parseURL(url)

      return host === 'bitbucket.org'
    } finally {}
  }

  // Internal
  repoRelativePath () {
    return this.repo.getRepo(this.filePath).relativize(this.filePath)
  }

  // Internal
  remoteName () {
    const gitConfigRemote = this.repo.getConfigValue('atom.open-on-github.remote', this.filePath)

    if (gitConfigRemote) {
      return gitConfigRemote
    }

    const shortBranch = this.repo.getShortHead(this.filePath)

    if (!shortBranch) {
      return null
    }

    const branchRemote = this.repo.getConfigValue(`branch.${shortBranch}.remote`, this.filePath)

    if (branchRemote && branchRemote.length > 0) {
      return branchRemote
    }

    return null
  }

  // Internal
  sha () {
    return this.repo.getReferenceTarget('HEAD', this.filePath)
  }

  // Internal
  branchName () {
    const shortBranch = this.repo.getShortHead(this.filePath)

    if (!shortBranch) {
      return null
    }

    const branchMerge = this.repo.getConfigValue(`branch.${shortBranch}.merge`, this.filePath)
    if (!(branchMerge && branchMerge.length > 11)) {
      return shortBranch
    }

    if (branchMerge.indexOf('refs/heads/') !== 0) {
      return shortBranch
    }

    return branchMerge.substring(11)
  }

  // Internal
  remoteBranchName () {
    const gitConfigBranch = this.repo.getConfigValue('atom.open-on-github.branch', this.filePath)

    if (gitConfigBranch) {
      return gitConfigBranch
    } else if (this.remoteName() != null) {
      return this.encodeSegments(this.branchName())
    } else {
      return 'master'
    }
  }
}
<|endoftext|>