text: const exec = require("child_process").exec;
  const execSync = require("child_process").execSync;
  const path = require("path");
  const fs = require("fs");
  const crypto = require("crypto");
  const util = require("util");
  const _ = require("lodash");
  const stripJsonComments = require("strip-json-comments");
  const readFile = util.promisify(fs.readFile);
  const logger = require("pino")({
  
      prettyPrint: { colorize: true },
      translateTime: false
  });
  const { fileExists } = require("./utilities");
  const configs = require("./configs");
  
  /**
   * utils
   *
   * Used to store all non-related methods used through the project.
   *
   * @author Luis Cardoso (luis.cardoso@feedzai.com)
   * @author Henrique Dias (henrique.dias@feedzai.com)
   */
  
  
  const TMP_DIR = "./tmp";
  
  const METRIC_GROUPS = {
      RANDOM: "Random",
      VERSIONS: "Versions",
      COMMANDS: "Commands",
      HAS: "Has"
  };
  
  module.exports.TMP_DIR = TMP_DIR;
  
  /**
   * Loads jest config file for a given `repoFolder`
   * @param  {string} repoFolder
   * @returns {string}
   */
  async function loadJestConfig(repoFolder) {
      let rawTextFile;
  
      try {
          rawTextFile = await readFile(path.join(repoFolder, "jest.config.js"), "utf8");
      } catch (err) {
          logger.error("error openning file");
          return null;
      }
  
      return rawTextFile;
  }
  
  /**
   * Checks whether a repository is installed or not
   * @param  {string} repoFolder
   * @returns {boolean}
   */
  function isInstalled(repoFolder) {
      const r = `${repoFolder}/node_modules`;
  
      if (fs.existsSync(r)) {
          return true;
      }
      return false;
  }
  
  /**
   * Loads Eslint config for a given `repoFolder`
   * @param  {string} repoFolder
   */
  async function loadEslintFile(repoFolder) {
      let eslintRc;
  
      if (await fileExists(repoFolder, ".eslintrc.json")) {
          const rawTextFile = await readFile(path.join(repoFolder, ".eslintrc.json"), "utf8");
  
          eslintRc = JSON.parse(stripJsonComments(rawTextFile));
      } else if (await fileExists(repoFolder, ".eslintrc")) {
          const rawTextFile = await readFile(path.join(repoFolder, ".eslintrc"), "utf8");
  
          try {
              eslintRc = JSON.parse(stripJsonComments(rawTextFile));
          } catch (error) {
              eslintRc = null;
          }
      } else {
          eslintRc = {};
      }
      return eslintRc;
  }
  
  /**
   * Gets the SHA1 checksum for the package.json in the `repoFolder`
   * @param  {string} repoFolder
   * @returns {string}
   */
  function getPackageChecksum(repoFolder) {
      try {
          const file = fs.readFileSync(path.resolve(repoFolder, "package.json"));
  
          const shasum = crypto.createHash("sha1");
  
          shasum.update(file);
  
          return shasum.digest("hex");
      } catch (err) {
          logger.error("Error calculating checksum");
          return 0;
      }
  }
  
  /**
   * Returns all Dependencies for a given `packageJson`
   * @param  {object} packageJson
   * @returns {Array}
   */
  function getAllDependencies(packageJson) {
      return Object.assign({}, packageJson.devDependencies, packageJson.dependencies);
  }
  
  /**
   * Executes the given `command` on the given `folder`
   * @param  {string} folder
   * @param  {string} command
   * @returns {boolean}
   */
  function executeCommand(folder, command) {
      const com = `cd ${folder} &&  ${command} `;
  
      return new Promise((resolve) => {
          // eslint-disable-next-line no-unused-vars
          exec(com, { maxBuffer: 1024 * 1024 * 100 }, function (err, stdout, stderr) {
              if (err) {
                  resolve(false);
              }
              resolve(true);
          });
      });
  }
  
  /**
   * Executes a `command` in a `folder`
   * @param  {string} folder
   * @param  {string} command
   * @returns {string}
   */
  function executeCommandSync(folder, command) {
      try {
          return execSync(`cd ${folder} && ${command}`);
      } catch (err) {
          logger.error(`Error executing ${command} on ${folder}`);
      }
  }
  
  /**
   * As the name implies, this method will execute a `command` on
   * a `folder` and return its output
   * @param  {string} folder
   * @param  {string} command
   * @returns {Promise<string>}
   */
  function executeCommandGetOutput(folder, command) {
      const com = `cd ${folder} &&  ${command} `;
  
      return new Promise((resolve, reject) => {
          // eslint-disable-next-line no-unused-vars
          exec(com, { maxBuffer: Infinity }, function (err, stdout, stderr) {
              if (!_.isNull(err)) {
                  reject(null);
              }
              resolve(stdout);
          });
      });
  }
  
  /**
   * Reads `file` from `repoFolder`
   * @param  {string} repoFolder
   * @param  {string} file
   * @returns {string}
   */
  function getFileFolder(repoFolder, file) {
      return new Promise((resolve) => {
          fs.readFile(path.join(repoFolder, file), "utf8", (err, data) => {
              resolve(data);
          });
      });
  }
  
  /**
   * Open a file with the fiven full path (including filename)
   * @param  {string} completePath
   * @returns {Promise<string>}
   */
  function openFileFromPath(completePath) {
      return new Promise((resolve) => {
          fs.readFile(completePath, "utf8", (err, data) => {
              resolve(data);
          });
      });
  }
  
  
  /**
   * Gets last commit hash for a given repo
   * @param  {string} repoFolder
   * @returns {string}
   */
  function getLastCommitHash(repoFolder) {
      const result = executeCommandSync(repoFolder, "git rev-parse HEAD").toString();
  
      result.replace("\n", "");
      return result;
  }
  
  /**
   * Loads the last report from his config file
   * @returns {object | null}
   */
  function loadLastReport() {
      return openFileFromPath(configs.getJsonReporter()["output-file"]).then((file) => {
          try {
              return JSON.parse(file);
          } catch (e) {
              return null;
          }
      });
  }
  
  /**
   * Returns the repository folder path to run the analysis.
   *
   * @param {Object} repo
   * @returns {string}
   */
  function getRepoFolder(repo) {
      if (_.isBoolean(repo.isLocal)) {
          return process.cwd();
      }
  
      return "/tmp/repo-analyzer";
  }
  
  /**
   * Checks out a git repository in `repoFolder` to a git `hash`
   * @param  {string} repoFolder
   * @param  {string} hash
   */
  async function checkoutToCommit(repoFolder, hash) {
      return executeCommandSync(repoFolder, `git checkout -f && git checkout ${hash}`);
  }
  
  /**
   * Returns all the commits for a given folder
   * @param  {string} repoFolder
   * @returns {Array}
   */
  async function getAllCommits(repoFolder) {
      return executeCommandGetOutput(repoFolder, "git log --decorate --pretty=oneline ").then((res) => {
          let lines = [];
  
          lines = res.split("\n");
          const hashes = [];
  
          for (let i = 0; i < lines.length; i++) {
              if (lines[i] !== "") {
                  hashes.push(lines[i].split(" ")[0]);
              }
          }
  
          return hashes;
      });
  }
  
  
  /**
   * Returns the date for a given repo in `repoFolder` with the following`commit`
   * @param  {string} repoFolder
   * @param  {string} commit
   * @returns {Date}
   */
  function getDateForCommit(repoFolder, commit) {
      if (!_.isString(commit)) {
          return null;
      }
      const out = executeCommandSync(repoFolder, `git show -s --format=%ci ${commit} `);
  
      return new Date(out);
  }
  
  
  module.exports.getRepoFolder = getRepoFolder;
  
  module.exports.fileExists = fileExists;
  
  module.exports.executeCommand = executeCommand;
  
  module.exports.getFileFolder = getFileFolder;
  
  module.exports.isInstalled = isInstalled;
  
  module.exports.METRIC_GROUPS = METRIC_GROUPS;
  
  module.exports.getAllDependencies = getAllDependencies;
  
  module.exports.loadEslintFile = loadEslintFile;
  
  module.exports.loadJestConfig = loadJestConfig;
  
  module.exports.openFileFromPath = openFileFromPath;
  
  module.exports.executeCommandGetOutput = executeCommandGetOutput;
  
  module.exports.getLastCommitHash = getLastCommitHash;
  
  module.exports.loadLastReport = loadLastReport;
  
  module.exports.getAllCommits = getAllCommits;
  
  module.exports.checkoutToCommit = checkoutToCommit;
  
  module.exports.getDateForCommit = getDateForCommit;
  
  module.exports.executeCommandSync = executeCommandSync;
  
  module.exports.getPackageChecksum = getPackageChecksum;
  
  