@percy/cli-upload 1.0.0-beta.7 → 1.0.0-beta.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,13 +18,14 @@ ARGUMENTS
18
18
  DIRNAME directory of images to upload
19
19
 
20
20
  OPTIONS
21
- -c, --config=config configuration file path
22
- -d, --dry-run prints a list of matching images to upload without uploading
23
- -f, --files=files [default: **/*.{png,jpg,jpeg}] one or more globs matching image file paths to upload
24
- -i, --ignore=ignore one or more globs matching image file paths to ignore
25
- -q, --quiet log errors only
26
- -v, --verbose log everything
27
- --silent log nothing
21
+ -c, --config=config configuration file path
22
+ -d, --dry-run prints a list of matching images to upload without uploading
23
+ -e, --strip-extensions strips file extensions from snapshot names
24
+ -f, --files=files [default: **/*.{png,jpg,jpeg}] one or more globs matching image file paths to upload
25
+ -i, --ignore=ignore one or more globs matching image file paths to ignore
26
+ -q, --quiet log errors only
27
+ -v, --verbose log everything
28
+ --silent log nothing
28
29
 
29
30
  EXAMPLE
30
31
  $ percy upload ./images
@@ -39,6 +40,11 @@ This CLI plugin adds the following Percy configuration options (defaults shown).
39
40
  # defaults
40
41
  version: 2
41
42
  upload:
43
+ strip-extensions: false
42
44
  files: '**/*.{png,jpg,jpeg}'
43
45
  ignore: ''
44
46
  ```
47
+
48
+ - **strip-extensions** - Strips file extensions from snapshot names
49
+ - **files** - A glob or array of globs matching file paths to upload
50
+ - **ignore** - A glob or array of globs matching file paths to ignore
@@ -19,33 +19,42 @@ var _imageSize = _interopRequireDefault(require("image-size"));
19
19
 
20
20
  var _client = _interopRequireDefault(require("@percy/client"));
21
21
 
22
+ var _queue = _interopRequireDefault(require("@percy/core/dist/queue"));
23
+
22
24
  var _resources = _interopRequireDefault(require("../resources"));
23
25
 
24
26
  var _config = require("../config");
25
27
 
26
28
  var _package = _interopRequireDefault(require("../../package.json"));
27
29
 
28
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
30
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
29
31
 
30
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
32
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
31
33
 
32
34
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
33
35
 
34
36
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
35
37
 
36
- const ALLOWED_IMAGE_TYPES = /\.(png|jpg|jpeg)$/i;
38
+ const ALLOWED_FILE_TYPES = /^\.(png|jpg|jpeg)$/i;
37
39
 
38
40
  class Upload extends _cliCommand.default {
41
+ constructor(...args) {
42
+ super(...args);
43
+
44
+ _defineProperty(this, "log", (0, _logger.default)('cli:upload'));
45
+ }
46
+
39
47
  async run() {
40
48
  if (!this.isPercyEnabled()) {
41
- _logger.default.info('Percy is disabled. Skipping upload');
42
-
43
- return;
49
+ return this.log.info('Percy is disabled. Skipping upload');
44
50
  }
45
51
 
46
52
  let {
47
53
  dirname
48
54
  } = this.args;
55
+ let {
56
+ 'dry-run': dry
57
+ } = this.flags;
49
58
 
50
59
  if (!_fs.default.existsSync(dirname)) {
51
60
  return this.error(`Not found: ${dirname}`);
@@ -54,83 +63,88 @@ class Upload extends _cliCommand.default {
54
63
  }
55
64
 
56
65
  let {
57
- upload: {
58
- files,
59
- ignore
60
- }
66
+ upload: conf
61
67
  } = this.percyrc();
62
- ignore = [].concat(ignore).filter(Boolean);
63
- let paths = await (0, _globby.default)(files, {
64
- cwd: dirname,
65
- ignore
68
+ this.queue = new _queue.default(conf.concurrency);
69
+ let paths = await (0, _globby.default)(conf.files, {
70
+ ignore: [].concat(conf.ignore || []),
71
+ cwd: dirname
66
72
  });
73
+ let l = paths.length;
74
+ if (!l) this.error(`No matching files found in '${dirname}'`);
67
75
  paths.sort();
68
-
69
- if (!paths.length) {
70
- return this.error(`No matching files found in '${dirname}'`);
71
- } else if (this.flags['dry-run']) {
72
- _logger.default.info('Matching files:');
73
-
74
- return paths.forEach(p => console.log(p));
75
- } // we already have assets so we don't need asset discovery from @percy/core,
76
- // we can use @percy/client directly to send snapshots
77
-
78
-
79
76
  this.client = new _client.default({
80
- clientInfo: `${_package.default.name}/${_package.default.version}`
77
+ clientInfo: `${_package.default.name}/${_package.default.version}`,
78
+ environmentInfo: `node/${process.version}`
81
79
  });
82
- await this.client.createBuild();
83
- let {
84
- build
85
- } = this.client;
86
-
87
- _logger.default.info('Percy has started!');
88
-
89
- _logger.default.info(`Created build #${build.number}: ${build.url}`);
90
-
91
- for (let name of paths) {
92
- _logger.default.debug(`Uploading snapshot: ${name}`); // only snapshot supported images
93
80
 
81
+ if (dry) {
82
+ this.log.info(`Found ${l} snapshot${l !== 1 ? 's' : ''}`);
83
+ } else {
84
+ let {
85
+ data: build
86
+ } = await this.client.createBuild();
87
+ let {
88
+ 'build-number': number,
89
+ 'web-url': url
90
+ } = build.attributes;
91
+ this.build = {
92
+ id: build.id,
93
+ number,
94
+ url
95
+ };
96
+ this.log.info('Percy has started!');
97
+ }
94
98
 
95
- if (!name.match(ALLOWED_IMAGE_TYPES)) {
96
- _logger.default.info(`Skipping unsupported image type: ${name}`);
99
+ for (let filename of paths) {
100
+ let file = _path.default.parse(filename);
97
101
 
102
+ if (!ALLOWED_FILE_TYPES.test(file.ext)) {
103
+ this.log.info(`Skipping unsupported file type: ${filename}`);
98
104
  continue;
99
105
  }
100
106
 
101
- let filepath = _path.default.resolve(dirname, name);
107
+ let name = conf.stripExtensions ? _path.default.join(file.dir, file.name) : filename;
108
+ if (dry) this.log.info(`Snapshot found: ${name}`);else this.snapshot(name, filename, dirname);
109
+ }
110
+ } // Push a snapshot upload to the queue
111
+
102
112
 
103
- let buffer = _fs.default.readFileSync(filepath);
113
+ snapshot(name, filename, dirname) {
114
+ this.queue.push(`upload/${name}`, async () => {
115
+ let filepath = _path.default.resolve(dirname, filename);
104
116
 
105
117
  let {
106
118
  width,
107
119
  height
108
120
  } = (0, _imageSize.default)(filepath);
109
- await this.client.sendSnapshot({
121
+
122
+ let buffer = _fs.default.readFileSync(filepath);
123
+
124
+ await this.client.sendSnapshot(this.build.id, {
110
125
  // width and height is clamped to API min and max
111
126
  widths: [Math.max(10, Math.min(width, 2000))],
112
- minimumHeight: Math.max(10, Math.min(height, 2000)),
113
- resources: (0, _resources.default)(name, buffer, width, height),
127
+ minHeight: Math.max(10, Math.min(height, 2000)),
128
+ resources: (0, _resources.default)(filename, buffer, width, height),
114
129
  name
115
130
  });
116
-
117
- _logger.default.info(`Snapshot uploaded: ${name}`);
118
- }
131
+ this.log.info(`Snapshot uploaded: ${name}`);
132
+ });
119
133
  } // Finalize the build when finished
120
134
 
121
135
 
122
- async finally() {
123
- var _this$client;
124
-
125
- let build = (_this$client = this.client) === null || _this$client === void 0 ? void 0 : _this$client.build;
126
-
127
- if (build === null || build === void 0 ? void 0 : build.id) {
128
- var _this$client2;
136
+ async finally(error) {
137
+ var _this$build;
129
138
 
130
- await ((_this$client2 = this.client) === null || _this$client2 === void 0 ? void 0 : _this$client2.finalizeBuild());
131
-
132
- _logger.default.info(`Finalized build #${build.number}: ${build.url}`);
133
- }
139
+ if (!((_this$build = this.build) !== null && _this$build !== void 0 && _this$build.id)) return;
140
+ if (error) this.queue.close(true);
141
+ if (this.closing) return;
142
+ this.closing = true;
143
+ await this.queue.empty(s => {
144
+ this.log.progress(`Uploading ${s} snapshot${s !== 1 ? 's' : ''}...`, !!s);
145
+ });
146
+ await this.client.finalizeBuild(this.build.id);
147
+ this.log.info(`Finalized build #${this.build.number}: ${this.build.url}`);
134
148
  }
135
149
 
136
150
  }
@@ -160,6 +174,11 @@ _defineProperty(Upload, "flags", { ..._cliCommand.flags.logging,
160
174
  description: 'one or more globs matching image file paths to ignore',
161
175
  percyrc: 'upload.ignore'
162
176
  }),
177
+ 'strip-extensions': _cliCommand.flags.boolean({
178
+ char: 'e',
179
+ description: 'strips file extensions from snapshot names',
180
+ percyrc: 'upload.stripExtensions'
181
+ }),
163
182
  'dry-run': _cliCommand.flags.boolean({
164
183
  char: 'd',
165
184
  description: 'prints a list of matching images to upload without uploading'
package/dist/config.js CHANGED
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.migration = migration;
6
7
  exports.schema = void 0;
7
8
  const schema = {
8
9
  upload: {
@@ -30,8 +31,29 @@ const schema = {
30
31
  }
31
32
  }],
32
33
  default: ''
34
+ },
35
+ stripExtensions: {
36
+ type: 'boolean',
37
+ default: false
38
+ },
39
+ concurrency: {
40
+ type: 'number',
41
+ minimum: 1
33
42
  }
34
43
  }
35
44
  }
36
45
  };
37
- exports.schema = schema;
46
+ exports.schema = schema;
47
+
48
+ function migration(config, {
49
+ map,
50
+ del
51
+ }) {
52
+ /* eslint-disable curly */
53
+ if (config.version < 2) {
54
+ // image-snapshots and options were renamed
55
+ map('imageSnapshots.files', 'upload.files');
56
+ map('imageSnapshots.ignore', 'upload.ignore');
57
+ del('imageSnapshots');
58
+ }
59
+ }
@@ -7,10 +7,16 @@ exports.default = _default;
7
7
 
8
8
  var _config = _interopRequireDefault(require("@percy/config"));
9
9
 
10
- var _config2 = require("../config");
10
+ var UploadConfig = _interopRequireWildcard(require("../config"));
11
+
12
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
13
+
14
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
11
15
 
12
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
17
 
14
18
  function _default() {
15
- _config.default.addSchema(_config2.schema);
19
+ _config.default.addSchema(UploadConfig.schema);
20
+
21
+ _config.default.addMigration(UploadConfig.migration);
16
22
  }
package/dist/index.js CHANGED
@@ -1,8 +1,3 @@
1
1
  "use strict";
2
2
 
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _default = {};
8
- exports.default = _default;
3
+ module.exports = require('./commands/upload').Upload;
package/dist/resources.js CHANGED
@@ -37,13 +37,15 @@ function createImageResource(url, content, mimetype) {
37
37
 
38
38
  function createImageResources(filename, content, width, height) {
39
39
  let {
40
+ dir,
40
41
  name,
41
42
  ext
42
43
  } = _path.default.parse(filename);
43
44
 
44
- let url = `/${encodeURIComponent(filename)}`;
45
+ let rootUrl = `/${encodeURIComponent(_path.default.join(dir, name))}`;
46
+ let imageUrl = `/${encodeURIComponent(filename)}`;
45
47
  let mimetype = ext === '.png' ? 'image/png' : 'image/jpeg';
46
- return [createRootResource(encodeURIComponent(name), `
48
+ return [createRootResource(rootUrl, `
47
49
  <!doctype html>
48
50
  <html lang="en">
49
51
  <head>
@@ -56,8 +58,8 @@ function createImageResources(filename, content, width, height) {
56
58
  </style>
57
59
  </head>
58
60
  <body>
59
- <img src="${url}" width="${width}px" height="${height}px"/>
61
+ <img src="${imageUrl}" width="${width}px" height="${height}px"/>
60
62
  </body>
61
63
  </html>
62
- `), createImageResource(url, content, mimetype)];
64
+ `), createImageResource(imageUrl, content, mimetype)];
63
65
  }
@@ -1 +1 @@
1
- {"version":"1.0.0-beta.7","commands":{"upload":{"id":"upload","description":"Upload a directory of images to Percy","pluginName":"@percy/cli-upload","pluginType":"core","aliases":[],"examples":["$ percy upload ./images"],"flags":{"verbose":{"name":"verbose","type":"boolean","char":"v","description":"log everything","allowNo":false},"quiet":{"name":"quiet","type":"boolean","char":"q","description":"log errors only","allowNo":false},"silent":{"name":"silent","type":"boolean","description":"log nothing","allowNo":false},"config":{"name":"config","type":"option","char":"c","description":"configuration file path"},"files":{"name":"files","type":"option","char":"f","description":"one or more globs matching image file paths to upload","default":"**/*.{png,jpg,jpeg}"},"ignore":{"name":"ignore","type":"option","char":"i","description":"one or more globs matching image file paths to ignore"},"dry-run":{"name":"dry-run","type":"boolean","char":"d","description":"prints a list of matching images to upload without uploading","allowNo":false}},"args":[{"name":"dirname","description":"directory of images to upload","required":true}]}}}
1
+ {"version":"1.0.0-beta.70","commands":{"upload":{"id":"upload","description":"Upload a directory of images to Percy","pluginName":"@percy/cli-upload","pluginType":"core","aliases":[],"examples":["$ percy upload ./images"],"flags":{"verbose":{"name":"verbose","type":"boolean","char":"v","description":"log everything","allowNo":false},"quiet":{"name":"quiet","type":"boolean","char":"q","description":"log errors only","allowNo":false},"silent":{"name":"silent","type":"boolean","description":"log nothing","allowNo":false},"config":{"name":"config","type":"option","char":"c","description":"configuration file path"},"files":{"name":"files","type":"option","char":"f","description":"one or more globs matching image file paths to upload","default":"**/*.{png,jpg,jpeg}"},"ignore":{"name":"ignore","type":"option","char":"i","description":"one or more globs matching image file paths to ignore"},"strip-extensions":{"name":"strip-extensions","type":"boolean","char":"e","description":"strips file extensions from snapshot names","allowNo":false},"dry-run":{"name":"dry-run","type":"boolean","char":"d","description":"prints a list of matching images to upload without uploading","allowNo":false}},"args":[{"name":"dirname","description":"directory of images to upload","required":true}]}}}
package/package.json CHANGED
@@ -1,26 +1,26 @@
1
1
  {
2
2
  "name": "@percy/cli-upload",
3
- "version": "1.0.0-beta.7",
3
+ "version": "1.0.0-beta.70",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "files": [
7
7
  "dist",
8
8
  "oclif.manifest.json"
9
9
  ],
10
+ "engines": {
11
+ "node": ">=12"
12
+ },
10
13
  "scripts": {
11
- "build": "babel --root-mode upward src --out-dir dist",
14
+ "build": "node ../../scripts/build",
12
15
  "lint": "eslint --ignore-path ../../.gitignore .",
13
16
  "postbuild": "oclif-dev manifest",
14
17
  "readme": "oclif-dev readme",
15
- "test": "cross-env NODE_ENV=test mocha",
16
- "test:coverage": "nyc yarn test"
18
+ "test": "node ../../scripts/test",
19
+ "test:coverage": "yarn test --coverage"
17
20
  },
18
21
  "publishConfig": {
19
22
  "access": "public"
20
23
  },
21
- "mocha": {
22
- "require": "../../scripts/babel-register"
23
- },
24
24
  "oclif": {
25
25
  "bin": "percy",
26
26
  "commands": "./dist/commands",
@@ -29,12 +29,17 @@
29
29
  }
30
30
  },
31
31
  "dependencies": {
32
- "@percy/cli-command": "^1.0.0-beta.7",
33
- "@percy/client": "^1.0.0-beta.7",
34
- "@percy/config": "^1.0.0-beta.7",
35
- "@percy/logger": "^1.0.0-beta.7",
36
- "globby": "^11.0.0",
37
- "image-size": "^0.8.3"
32
+ "@percy/cli-command": "1.0.0-beta.70",
33
+ "@percy/client": "1.0.0-beta.70",
34
+ "@percy/config": "1.0.0-beta.70",
35
+ "@percy/logger": "1.0.0-beta.70",
36
+ "globby": "^11.0.4",
37
+ "image-size": "^1.0.0"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/percy/cli",
42
+ "directory": "packages/cli-upload"
38
43
  },
39
- "gitHead": "5be796ec8f17958e93ada0b634899b945c9b0d60"
44
+ "gitHead": "34f37a98ff71281cebadd39e53bb55a65b0d3456"
40
45
  }