@percy/cli-upload 1.0.0-beta.9 → 1.0.2

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
@@ -4,29 +4,36 @@ Percy CLI command to uploade a directory of static images to Percy for diffing.
4
4
 
5
5
  ## Commands
6
6
  <!-- commands -->
7
- * [`percy upload DIRNAME`](#percy-upload-dirname)
7
+ * [`percy upload`](#percy-upload)
8
8
 
9
- ## `percy upload DIRNAME`
9
+ ### `percy upload`
10
10
 
11
11
  Upload a directory of images to Percy
12
12
 
13
13
  ```
14
- USAGE
15
- $ percy upload DIRNAME
16
-
17
- ARGUMENTS
18
- DIRNAME directory of images to upload
19
-
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
28
-
29
- EXAMPLE
14
+ Usage:
15
+ $ percy upload [options] <dirname>
16
+
17
+ Arguments:
18
+ dirname Directory of images to upload
19
+
20
+ Options:
21
+ -f, --files [pattern] One or more globs matching image file paths to upload (default:
22
+ "**/*.{png,jpg,jpeg}")
23
+ -i, --ignore <pattern> One or more globs matching image file paths to ignore
24
+ -e, --strip-extensions Strips file extensions from snapshot names
25
+
26
+ Percy options:
27
+ -c, --config <file> Config file path
28
+ -d, --dry-run Print snapshot names only
29
+
30
+ Global options:
31
+ -v, --verbose Log everything
32
+ -q, --quiet Log errors only
33
+ -s, --silent Log nothing
34
+ -h, --help Display command help
35
+
36
+ Examples:
30
37
  $ percy upload ./images
31
38
  ```
32
39
  <!-- commandsstop -->
@@ -39,6 +46,11 @@ This CLI plugin adds the following Percy configuration options (defaults shown).
39
46
  # defaults
40
47
  version: 2
41
48
  upload:
49
+ strip-extensions: false
42
50
  files: '**/*.{png,jpg,jpeg}'
43
51
  ignore: ''
44
52
  ```
53
+
54
+ - **strip-extensions** - Strips file extensions from snapshot names
55
+ - **files** - A glob or array of globs matching file paths to upload
56
+ - **ignore** - A glob or array of globs matching file paths to ignore
package/dist/config.js CHANGED
@@ -1,10 +1,4 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.schema = void 0;
7
- const schema = {
1
+ export const schema = {
8
2
  upload: {
9
3
  type: 'object',
10
4
  additionalProperties: false,
@@ -30,8 +24,27 @@ const schema = {
30
24
  }
31
25
  }],
32
26
  default: ''
27
+ },
28
+ stripExtensions: {
29
+ type: 'boolean',
30
+ default: false
31
+ },
32
+ concurrency: {
33
+ type: 'number',
34
+ minimum: 1
33
35
  }
34
36
  }
35
37
  }
36
38
  };
37
- exports.schema = schema;
39
+ export function migration(config, {
40
+ map,
41
+ del
42
+ }) {
43
+ /* eslint-disable curly */
44
+ if (config.version < 2) {
45
+ // image-snapshots and options were renamed
46
+ map('imageSnapshots.files', 'upload.files');
47
+ map('imageSnapshots.ignore', 'upload.ignore');
48
+ del('imageSnapshots');
49
+ }
50
+ }
package/dist/index.js CHANGED
@@ -1,8 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _default = {};
8
- exports.default = _default;
1
+ export { default, upload } from './upload.js';
package/dist/resources.js CHANGED
@@ -1,22 +1,11 @@
1
- "use strict";
1
+ import path from 'path';
2
+ import { sha256hash } from '@percy/client/utils'; // Returns a root resource object with a sha and mimetype.
2
3
 
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = createImageResources;
7
-
8
- var _path = _interopRequireDefault(require("path"));
9
-
10
- var _utils = require("@percy/client/dist/utils");
11
-
12
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
-
14
- // Returns a root resource object with a sha and mimetype.
15
4
  function createRootResource(url, content) {
16
5
  return {
17
6
  url,
18
7
  content,
19
- sha: (0, _utils.sha256hash)(content),
8
+ sha: sha256hash(content),
20
9
  mimetype: 'text/html',
21
10
  root: true
22
11
  };
@@ -27,7 +16,7 @@ function createImageResource(url, content, mimetype) {
27
16
  return {
28
17
  url,
29
18
  content,
30
- sha: (0, _utils.sha256hash)(content),
19
+ sha: sha256hash(content),
31
20
  mimetype
32
21
  };
33
22
  } // Returns root resource and image resource objects based on an image's
@@ -35,15 +24,16 @@ function createImageResource(url, content, mimetype) {
35
24
  // designed to display an image at it's native size without margins or padding.
36
25
 
37
26
 
38
- function createImageResources(filename, content, width, height) {
27
+ export function createImageResources(filename, content, size) {
39
28
  let {
29
+ dir,
40
30
  name,
41
31
  ext
42
- } = _path.default.parse(filename);
43
-
44
- let url = `/${encodeURIComponent(filename)}`;
32
+ } = path.parse(filename);
33
+ let rootUrl = `/${encodeURIComponent(path.join(dir, name))}`;
34
+ let imageUrl = `/${encodeURIComponent(filename)}`;
45
35
  let mimetype = ext === '.png' ? 'image/png' : 'image/jpeg';
46
- return [createRootResource(encodeURIComponent(name), `
36
+ return [createRootResource(rootUrl, `
47
37
  <!doctype html>
48
38
  <html lang="en">
49
39
  <head>
@@ -56,8 +46,9 @@ function createImageResources(filename, content, width, height) {
56
46
  </style>
57
47
  </head>
58
48
  <body>
59
- <img src="${url}" width="${width}px" height="${height}px"/>
49
+ <img src="${imageUrl}" width="${size.width}px" height="${size.height}px"/>
60
50
  </body>
61
51
  </html>
62
- `), createImageResource(url, content, mimetype)];
63
- }
52
+ `), createImageResource(imageUrl, content, mimetype)];
53
+ }
54
+ export default createImageResources;
package/dist/upload.js ADDED
@@ -0,0 +1,125 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import command from '@percy/cli-command';
4
+ import * as UploadConfig from './config.js';
5
+ const ALLOWED_FILE_TYPES = /\.(png|jpg|jpeg)$/i;
6
+ export const upload = command('upload', {
7
+ description: 'Upload a directory of images to Percy',
8
+ args: [{
9
+ name: 'dirname',
10
+ description: 'Directory of images to upload',
11
+ required: true,
12
+ validate: dir => {
13
+ if (!fs.existsSync(dir)) {
14
+ throw new Error(`Not found: ${dir}`);
15
+ } else if (!fs.lstatSync(dir).isDirectory()) {
16
+ throw new Error(`Not a directory: ${dir}`);
17
+ }
18
+ }
19
+ }],
20
+ flags: [{
21
+ name: 'files',
22
+ description: 'One or more globs matching image file paths to upload',
23
+ default: UploadConfig.schema.upload.properties.files.default,
24
+ percyrc: 'upload.files',
25
+ type: 'pattern',
26
+ multiple: true,
27
+ short: 'f'
28
+ }, {
29
+ name: 'ignore',
30
+ description: 'One or more globs matching image file paths to ignore',
31
+ percyrc: 'upload.ignore',
32
+ type: 'pattern',
33
+ multiple: true,
34
+ short: 'i'
35
+ }, {
36
+ name: 'strip-extensions',
37
+ description: 'Strips file extensions from snapshot names',
38
+ percyrc: 'upload.stripExtensions',
39
+ short: 'e'
40
+ }],
41
+ examples: ['$0 ./images'],
42
+ percy: {
43
+ discoveryFlags: false,
44
+ deferUploads: true
45
+ },
46
+ config: {
47
+ schemas: [UploadConfig.schema],
48
+ migrations: [UploadConfig.migration]
49
+ }
50
+ }, async function* ({
51
+ flags,
52
+ args,
53
+ percy,
54
+ log,
55
+ exit
56
+ }) {
57
+ if (!percy) exit(0, 'Percy is disabled');
58
+ let config = percy.config.upload;
59
+ let {
60
+ default: glob
61
+ } = await import('fast-glob');
62
+ let pathnames = yield glob(config.files, {
63
+ ignore: [].concat(config.ignore || []),
64
+ cwd: args.dirname,
65
+ fs
66
+ });
67
+
68
+ if (!pathnames.length) {
69
+ exit(1, `No matching files found in '${args.dirname}'`);
70
+ }
71
+
72
+ let {
73
+ default: imageSize
74
+ } = await import('image-size');
75
+ let {
76
+ createImageResources
77
+ } = await import('./resources.js'); // the internal upload queue shares a concurrency with the snapshot queue
78
+
79
+ percy.setConfig({
80
+ discovery: {
81
+ concurrency: config.concurrency
82
+ }
83
+ }); // do not launch a browser when starting
84
+
85
+ yield* percy.yield.start({
86
+ browser: false
87
+ });
88
+
89
+ for (let filename of pathnames) {
90
+ let file = path.parse(filename);
91
+ let name = config.stripExtensions ? path.join(file.dir, file.name) : filename;
92
+
93
+ if (!ALLOWED_FILE_TYPES.test(filename)) {
94
+ log.info(`Skipping unsupported file type: ${filename}`);
95
+ } else {
96
+ if (percy.dryRun) log.info(`Snapshot found: ${name}`);
97
+
98
+ percy._scheduleUpload(filename, async () => {
99
+ let filepath = path.resolve(args.dirname, filename);
100
+ let buffer = fs.readFileSync(filepath); // width and height is clamped to API min and max
101
+
102
+ let size = imageSize(filepath);
103
+ let widths = [Math.max(10, Math.min(size.width, 2000))];
104
+ let minHeight = Math.max(10, Math.min(size.height, 2000));
105
+ let resources = createImageResources(filename, buffer, size);
106
+ return {
107
+ name,
108
+ widths,
109
+ minHeight,
110
+ resources
111
+ };
112
+ }).then(() => {
113
+ log.info(`Snapshot uploaded: ${name}`);
114
+ });
115
+ }
116
+ }
117
+
118
+ try {
119
+ yield* percy.yield.stop();
120
+ } catch (error) {
121
+ await percy.stop(true);
122
+ throw error;
123
+ }
124
+ });
125
+ export default upload;
package/package.json CHANGED
@@ -1,40 +1,40 @@
1
1
  {
2
2
  "name": "@percy/cli-upload",
3
- "version": "1.0.0-beta.9",
3
+ "version": "1.0.2",
4
4
  "license": "MIT",
5
- "main": "dist/index.js",
6
- "files": [
7
- "dist",
8
- "oclif.manifest.json"
9
- ],
10
- "scripts": {
11
- "build": "babel --root-mode upward src --out-dir dist",
12
- "lint": "eslint --ignore-path ../../.gitignore .",
13
- "postbuild": "oclif-dev manifest",
14
- "readme": "oclif-dev readme",
15
- "test": "cross-env NODE_ENV=test mocha",
16
- "test:coverage": "nyc yarn test"
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/percy/cli",
8
+ "directory": "packages/cli-upload"
17
9
  },
18
10
  "publishConfig": {
19
11
  "access": "public"
20
12
  },
21
- "mocha": {
22
- "require": "../../scripts/babel-register"
13
+ "engines": {
14
+ "node": ">=14"
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "main": "./dist/index.js",
20
+ "type": "module",
21
+ "exports": "./dist/index.js",
22
+ "scripts": {
23
+ "build": "node ../../scripts/build",
24
+ "lint": "eslint --ignore-path ../../.gitignore .",
25
+ "readme": "percy-cli-readme",
26
+ "test": "node ../../scripts/test",
27
+ "test:coverage": "yarn test --coverage"
23
28
  },
24
- "oclif": {
25
- "bin": "percy",
26
- "commands": "./dist/commands",
27
- "hooks": {
28
- "init": "./dist/hooks/init"
29
- }
29
+ "@percy/cli": {
30
+ "commands": [
31
+ "./dist/upload.js"
32
+ ]
30
33
  },
31
34
  "dependencies": {
32
- "@percy/cli-command": "^1.0.0-beta.9",
33
- "@percy/client": "^1.0.0-beta.9",
34
- "@percy/config": "^1.0.0-beta.9",
35
- "@percy/logger": "^1.0.0-beta.9",
36
- "globby": "^11.0.0",
37
- "image-size": "^0.8.3"
35
+ "@percy/cli-command": "1.0.2",
36
+ "fast-glob": "^3.2.11",
37
+ "image-size": "^1.0.0"
38
38
  },
39
- "gitHead": "57a2eeb90c7f5cdf8827c78be1e5c12df581f4b5"
39
+ "gitHead": "7288764b8088e444e853d5d78756959e46516dc7"
40
40
  }
@@ -1,169 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.Upload = void 0;
7
-
8
- var _fs = _interopRequireDefault(require("fs"));
9
-
10
- var _path = _interopRequireDefault(require("path"));
11
-
12
- var _cliCommand = _interopRequireWildcard(require("@percy/cli-command"));
13
-
14
- var _logger = _interopRequireDefault(require("@percy/logger"));
15
-
16
- var _globby = _interopRequireDefault(require("globby"));
17
-
18
- var _imageSize = _interopRequireDefault(require("image-size"));
19
-
20
- var _client = _interopRequireDefault(require("@percy/client"));
21
-
22
- var _resources = _interopRequireDefault(require("../resources"));
23
-
24
- var _config = require("../config");
25
-
26
- var _package = _interopRequireDefault(require("../../package.json"));
27
-
28
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
29
-
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; }
31
-
32
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
33
-
34
- 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
-
36
- const ALLOWED_IMAGE_TYPES = /\.(png|jpg|jpeg)$/i;
37
-
38
- class Upload extends _cliCommand.default {
39
- async run() {
40
- if (!this.isPercyEnabled()) {
41
- _logger.default.info('Percy is disabled. Skipping upload');
42
-
43
- return;
44
- }
45
-
46
- let {
47
- dirname
48
- } = this.args;
49
-
50
- if (!_fs.default.existsSync(dirname)) {
51
- return this.error(`Not found: ${dirname}`);
52
- } else if (!_fs.default.lstatSync(dirname).isDirectory()) {
53
- return this.error(`Not a directory: ${dirname}`);
54
- }
55
-
56
- let {
57
- upload: {
58
- files,
59
- ignore
60
- }
61
- } = this.percyrc();
62
- ignore = [].concat(ignore).filter(Boolean);
63
- let paths = await (0, _globby.default)(files, {
64
- cwd: dirname,
65
- ignore
66
- });
67
- 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
- this.client = new _client.default({
80
- clientInfo: `${_package.default.name}/${_package.default.version}`
81
- });
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
-
94
-
95
- if (!name.match(ALLOWED_IMAGE_TYPES)) {
96
- _logger.default.info(`Skipping unsupported image type: ${name}`);
97
-
98
- continue;
99
- }
100
-
101
- let filepath = _path.default.resolve(dirname, name);
102
-
103
- let buffer = _fs.default.readFileSync(filepath);
104
-
105
- let {
106
- width,
107
- height
108
- } = (0, _imageSize.default)(filepath);
109
- await this.client.sendSnapshot({
110
- // width and height is clamped to API min and max
111
- widths: [Math.max(10, Math.min(width, 2000))],
112
- minHeight: Math.max(10, Math.min(height, 2000)),
113
- resources: (0, _resources.default)(name, buffer, width, height),
114
- name
115
- });
116
-
117
- _logger.default.info(`Snapshot uploaded: ${name}`);
118
- }
119
- } // Finalize the build when finished
120
-
121
-
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;
129
-
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
- }
134
- }
135
-
136
- }
137
-
138
- exports.Upload = Upload;
139
-
140
- _defineProperty(Upload, "description", 'Upload a directory of images to Percy');
141
-
142
- _defineProperty(Upload, "args", [{
143
- name: 'dirname',
144
- description: 'directory of images to upload',
145
- required: true
146
- }]);
147
-
148
- _defineProperty(Upload, "flags", { ..._cliCommand.flags.logging,
149
- ..._cliCommand.flags.config,
150
- files: _cliCommand.flags.string({
151
- char: 'f',
152
- multiple: true,
153
- description: 'one or more globs matching image file paths to upload',
154
- default: _config.schema.upload.properties.files.default,
155
- percyrc: 'upload.files'
156
- }),
157
- ignore: _cliCommand.flags.string({
158
- char: 'i',
159
- multiple: true,
160
- description: 'one or more globs matching image file paths to ignore',
161
- percyrc: 'upload.ignore'
162
- }),
163
- 'dry-run': _cliCommand.flags.boolean({
164
- char: 'd',
165
- description: 'prints a list of matching images to upload without uploading'
166
- })
167
- });
168
-
169
- _defineProperty(Upload, "examples", ['$ percy upload ./images']);
@@ -1,16 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = _default;
7
-
8
- var _config = _interopRequireDefault(require("@percy/config"));
9
-
10
- var _config2 = require("../config");
11
-
12
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
-
14
- function _default() {
15
- _config.default.addSchema(_config2.schema);
16
- }
@@ -1 +0,0 @@
1
- {"version":"1.0.0-beta.9","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}]}}}