<commit_before>/* jshint node: true */
'use strict';

var crypto = require('crypto');
var fs = require('fs');
var path = require('path');

var bodyParser = require('body-parser');
var PercyClient = require('percy-client');
var Environment = require('percy-client/dist/environment');
var PromisePool = require('es6-promise-pool');
var walk = require('walk');

// Some build assets we never want to upload.
var SKIPPED_ASSETS = [
  '/assets/tests.js',
  '/assets/tests.jsp',
  '/assets/tests.map',
  '/tests/index.html',
  '/assets/test-support.js',
  '/assets/test-loader.js',
  '/assets/test-support.css',
  '/assets/dummy.js',
  '/index.html',
  '/testem.js',
  /\.map$/,
  /\.log$/,
  /\.DS_Store$/
];
var MAX_FILE_SIZE_BYTES = 15728640;  // 15MB.

// Synchronously walk the build directory, read each file and calculate its SHA 256 hash,
// and create a mapping of hashes to Resource objects.
function gatherBuildResources(percyClient, buildDir) {
  var hashToResource = {};
  var walkOptions = {
    // Follow symlinks because many assets in the ember build directory are just symlinks.
    followLinks: true,

    listeners: {
      file: function (root, fileStats, next) {
        var absolutePath = path.join(root, fileStats.name);
        var resourceUrl = absolutePath.replace(buildDir, '');

        if (path.sep == '\\') {
          // Windows support: transform filesystem backslashes into forward-slashes for the URL.
          resourceUrl = resourceUrl.replace(/\\/g, '/');
        }

        // Append the Ember rootURL if it exists.
        resourceUrl = normalizedRootUrl + resourceUrl;

        for (var i in SKIPPED_ASSETS) {
          if (resourceUrl.match(SKIPPED_ASSETS[i])) {
            next();
            return;
          }
        }

        // Skip large files.
        if (fs.statSync(absolutePath)['size'] > MAX_FILE_SIZE_BYTES) {
          console.warn('\n[percy][WARNING] Skipping large build resource: ', resourceUrl);
          return;
        }

        // TODO(fotinakis): this is synchronous and potentially memory intensive, but we don't
        // keep a reference to the content around so this should be garbage collected. Re-evaluate?
        var content = fs.readFileSync(absolutePath);
        var sha = crypto.createHash('sha256').update(content).digest('hex');

        var resource = percyClient.makeResource({
          resourceUrl: encodeURI(resourceUrl),
          sha: sha,
          localPath: absolutePath,
        });

        hashToResource[sha] = resource;
        next();
      }
    }
  };
  walk.walkSync(buildDir, walkOptions);

  return hashToResource;
};

// Helper method to parse missing-resources from an API response.
function parseMissingResources(response) {
  return response.body.data &&
    response.body.data.relationships &&
    response.body.data.relationships['missing-resources'] &&
    response.body.data.relationships['missing-resources'].data || [];
}

function handlePercyFailure(error) {
  isPercyEnabled = false;
  console.warn('\n[percy][ERROR] API call failed, Percy has been disabled for this build.')
  if (error) {
    console.warn(error.toString());  // Stringify to prevent full response output.
  }
}

// TODO: refactor to break down into a more modular design with less global state.
var percyClient;
var percyConfig;
var normalizedRootUrl;
var percyBuildPromise;
var seenSnapshotNames = [];
var buildResourceUploadPromises = [];
var snapshotResourceUploadPromises = [];
var isPercyEnabled = true;


module.exports = {
  name: 'ember-percy',

  _clientInfo: function() {
    if(!this._clientInfoCache) {
      var version = require('./package.json').version;
      this._clientInfoCache = `${this.name}/${version}`;
    }

    return this._clientInfoCache;
  },

  _environmentInfo: function() {
    if(!this._environmentInfoCache) {
      this._environmentInfoCache = [
        `ember/${this._emberSourceVersion()}`,
        `ember-cli/${this._emberCliVersion()}`
      ].filter(function(el) {
        return !el.match(/\/$/);
      }).join('; ');
    }

    return this._environmentInfoCache;
  },

  _emberSourceVersion: function() {
    try {
      return require('ember-source/package.json').version;
    } catch (e) {
      return '';
    };
  },

  _emberCliVersion: function() {
    try {
      return require('ember-cli/lib/utilities/version-utils').emberCLIVersion();
    } catch (e) {
      return '';
    };
  },

  // Only allow the addon to be incorporated in non-production envs.
  isEnabled: function() {<commit_msg>return unknown if we can't extract the version number of ember and ember-cli<commit_after>/* jshint node: true */
'use strict';

var crypto = require('crypto');
var fs = require('fs');
var path = require('path');

var bodyParser = require('body-parser');
var PercyClient = require('percy-client');
var Environment = require('percy-client/dist/environment');
var PromisePool = require('es6-promise-pool');
var walk = require('walk');

// Some build assets we never want to upload.
var SKIPPED_ASSETS = [
  '/assets/tests.js',
  '/assets/tests.jsp',
  '/assets/tests.map',
  '/tests/index.html',
  '/assets/test-support.js',
  '/assets/test-loader.js',
  '/assets/test-support.css',
  '/assets/dummy.js',
  '/index.html',
  '/testem.js',
  /\.map$/,
  /\.log$/,
  /\.DS_Store$/
];
var MAX_FILE_SIZE_BYTES = 15728640;  // 15MB.

// Synchronously walk the build directory, read each file and calculate its SHA 256 hash,
// and create a mapping of hashes to Resource objects.
function gatherBuildResources(percyClient, buildDir) {
  var hashToResource = {};
  var walkOptions = {
    // Follow symlinks because many assets in the ember build directory are just symlinks.
    followLinks: true,

    listeners: {
      file: function (root, fileStats, next) {
        var absolutePath = path.join(root, fileStats.name);
        var resourceUrl = absolutePath.replace(buildDir, '');

        if (path.sep == '\\') {
          // Windows support: transform filesystem backslashes into forward-slashes for the URL.
          resourceUrl = resourceUrl.replace(/\\/g, '/');
        }

        // Append the Ember rootURL if it exists.
        resourceUrl = normalizedRootUrl + resourceUrl;

        for (var i in SKIPPED_ASSETS) {
          if (resourceUrl.match(SKIPPED_ASSETS[i])) {
            next();
            return;
          }
        }

        // Skip large files.
        if (fs.statSync(absolutePath)['size'] > MAX_FILE_SIZE_BYTES) {
          console.warn('\n[percy][WARNING] Skipping large build resource: ', resourceUrl);
          return;
        }

        // TODO(fotinakis): this is synchronous and potentially memory intensive, but we don't
        // keep a reference to the content around so this should be garbage collected. Re-evaluate?
        var content = fs.readFileSync(absolutePath);
        var sha = crypto.createHash('sha256').update(content).digest('hex');

        var resource = percyClient.makeResource({
          resourceUrl: encodeURI(resourceUrl),
          sha: sha,
          localPath: absolutePath,
        });

        hashToResource[sha] = resource;
        next();
      }
    }
  };
  walk.walkSync(buildDir, walkOptions);

  return hashToResource;
};

// Helper method to parse missing-resources from an API response.
function parseMissingResources(response) {
  return response.body.data &&
    response.body.data.relationships &&
    response.body.data.relationships['missing-resources'] &&
    response.body.data.relationships['missing-resources'].data || [];
}

function handlePercyFailure(error) {
  isPercyEnabled = false;
  console.warn('\n[percy][ERROR] API call failed, Percy has been disabled for this build.')
  if (error) {
    console.warn(error.toString());  // Stringify to prevent full response output.
  }
}

// TODO: refactor to break down into a more modular design with less global state.
var percyClient;
var percyConfig;
var normalizedRootUrl;
var percyBuildPromise;
var seenSnapshotNames = [];
var buildResourceUploadPromises = [];
var snapshotResourceUploadPromises = [];
var isPercyEnabled = true;


module.exports = {
  name: 'ember-percy',

  _clientInfo: function() {
    if(!this._clientInfoCache) {
      var version = require('./package.json').version;
      this._clientInfoCache = `${this.name}/${version}`;
    }

    return this._clientInfoCache;
  },

  _environmentInfo: function() {
    if(!this._environmentInfoCache) {
      this._environmentInfoCache = [
        `ember/${this._emberSourceVersion()}`,
        `ember-cli/${this._emberCliVersion()}`
      ].join('; ');
    }

    return this._environmentInfoCache;
  },

  _emberSourceVersion: function() {
    try {
      return require('ember-source/package.json').version;
    } catch (e) {
      return 'unknown';
    };
  },

  _emberCliVersion: function() {
    try {
      return require('ember-cli/lib/utilities/version-utils').emberCLIVersion();
    } catch (e) {
      return 'unknown';
    };
  },

  // Only allow the addon to be incorporated in non-production envs.
  isEnabled: function() {
{'fraction_non_alphanumeric': 0.13345843912131583, 'fraction_numerical': 0.0037531736394745556, 'mean_word_length': 2.966725043782837, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2570484', 'n_tokens_mistral': 2727, 'n_tokens_neox': 2641, 'n_words': 675}