From 5ada5b4027f733cde6132a29c28eea008cf16727 Mon Sep 17 00:00:00 2001 From: "Andrew C. Dvorak" Date: Tue, 3 Apr 2018 17:16:59 -0700 Subject: [PATCH] feat(infrastructure): Upload compiled screenshot test assets to GCS (#2500) New NPM command: `screenshot:upload-assets`. First, run: ```bash npm start ``` Then, in another terminal, run: ```bash export MDC_GCLOUD_SERVICE_ACCOUNT_KEY_FILE_PATH=path/to/gcloud-service-account-key.json npm run screenshot:upload-assets ``` To avoid collisions between developers, every batch of files is uploaded to a directory with the following format: ``` /////assets/ ``` E.g.: `/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/`. Sample output: * [`mdc-button/classes/baseline.html`](https://storage.googleapis.com/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/mdc-button/classes/baseline.html) * [`mdc-button/classes/dense.html`](https://storage.googleapis.com/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/mdc-button/classes/dense.html) * [`mdc-button/mixins/container-fill-color.html`](https://storage.googleapis.com/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/mdc-button/mixins/container-fill-color.html) * [`mdc-button/mixins/corner-radius.html`](https://storage.googleapis.com/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/mdc-button/mixins/corner-radius.html) * [`mdc-button/mixins/filled-accessible.html`](https://storage.googleapis.com/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/mdc-button/mixins/filled-accessible.html) * [`mdc-button/mixins/horizontal-padding-baseline.html`](https://storage.googleapis.com/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/mdc-button/mixins/horizontal-padding-baseline.html) * [`mdc-button/mixins/horizontal-padding-dense.html`](https://storage.googleapis.com/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/mdc-button/mixins/horizontal-padding-dense.html) * [`mdc-button/mixins/icon-color.html`](https://storage.googleapis.com/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/mdc-button/mixins/icon-color.html) * [`mdc-button/mixins/ink-color.html`](https://storage.googleapis.com/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/mdc-button/mixins/ink-color.html) * [`mdc-button/mixins/stroke-color.html`](https://storage.googleapis.com/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/mdc-button/mixins/stroke-color.html) * [`mdc-button/mixins/stroke-width.html`](https://storage.googleapis.com/mdc-web-screenshot-tests/advorak/2018/04/03/23_00_32_993/5ca514fe/assets/mdc-button/mixins/stroke-width.html) --- package-lock.json | 1099 +++++++++++++++++++++++++- package.json | 3 + test/screenshot/.eslintrc.yaml | 5 + test/screenshot/README.md | 12 + test/screenshot/asset-uploader.js | 131 +++ test/screenshot/run-upload-assets.js | 34 + 6 files changed, 1268 insertions(+), 16 deletions(-) create mode 100644 test/screenshot/.eslintrc.yaml create mode 100644 test/screenshot/asset-uploader.js create mode 100644 test/screenshot/run-upload-assets.js diff --git a/package-lock.json b/package-lock.json index 2af37a128a5..e6482646343 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2,6 +2,273 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "@google-cloud/common": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.16.2.tgz", + "integrity": "sha512-GrkaFoj0/oO36pNs4yLmaYhTujuA3i21FdQik99Fd/APix1uhf01VlpJY4lAteTDFLRNkRx6ydEh7OVvmeUHng==", + "dev": true, + "requires": { + "array-uniq": "1.0.3", + "arrify": "1.0.1", + "concat-stream": "1.6.0", + "create-error-class": "3.0.2", + "duplexify": "3.5.4", + "ent": "2.2.0", + "extend": "3.0.1", + "google-auto-auth": "0.9.7", + "is": "3.2.1", + "log-driver": "1.2.7", + "methmeth": "1.1.0", + "modelo": "4.2.3", + "request": "2.79.0", + "retry-request": "3.3.1", + "split-array-stream": "1.0.3", + "stream-events": "1.0.3", + "string-format-obj": "1.1.1", + "through2": "2.0.3" + } + }, + "@google-cloud/storage": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-1.6.0.tgz", + "integrity": "sha512-yQ63bJYoiwY220gn/KdTLPoHppAPwFHfG7VFLPwJ+1R5U1eqUN5XV2a7uPj1szGF8/gxlKm2UbE8DgoJJ76DFw==", + "dev": true, + "requires": { + "@google-cloud/common": "0.16.2", + "arrify": "1.0.1", + "async": "2.4.1", + "compressible": "2.0.13", + "concat-stream": "1.6.0", + "create-error-class": "3.0.2", + "duplexify": "3.5.4", + "extend": "3.0.1", + "gcs-resumable-upload": "0.9.0", + "hash-stream-validation": "0.2.1", + "is": "3.2.1", + "mime": "2.2.2", + "mime-types": "2.1.18", + "once": "1.4.0", + "pumpify": "1.4.0", + "request": "2.85.0", + "safe-buffer": "5.1.1", + "snakeize": "0.1.0", + "stream-events": "1.0.3", + "string-format-obj": "1.1.1", + "through2": "2.0.3" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "compressible": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.13.tgz", + "integrity": "sha1-DRAgq5JLL9tNYnmHXH1tq6a6p6k=", + "dev": true, + "requires": { + "mime-db": "1.33.0" + } + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + } + } + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + }, + "dependencies": { + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "5.2.2", + "har-schema": "2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "mime": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.2.2.tgz", + "integrity": "sha512-A7PDg4s48MkqFEcYg2b069m3DXOEq7hx+9q9rIFrSSYfzsh35GX+LOVMQ8Au0ko7d8bSQCIAuzkjp0vCtwENlQ==", + "dev": true + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "request": { + "version": "2.85.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", + "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, "JSONStream": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz", @@ -24,7 +291,7 @@ "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", "dev": true, "requires": { - "mime-types": "2.1.15", + "mime-types": "2.1.18", "negotiator": "0.6.1" } }, @@ -1171,6 +1438,12 @@ "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", "dev": true }, + "base64url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz", + "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs=", + "dev": true + }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -1639,6 +1912,18 @@ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", "dev": true }, + "buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "dev": true + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=", + "dev": true + }, "buffer-shims": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", @@ -2103,7 +2388,7 @@ "is-typedarray": "1.0.0", "isstream": "0.1.2", "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", + "mime-types": "2.1.18", "oauth-sign": "0.8.2", "performance-now": "0.2.0", "qs": "6.4.0", @@ -2111,7 +2396,7 @@ "stringstream": "0.0.5", "tough-cookie": "2.3.2", "tunnel-agent": "0.6.0", - "uuid": "3.0.1" + "uuid": "3.2.1" } }, "tunnel-agent": { @@ -3383,6 +3668,18 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, + "duplexify": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.4.tgz", + "integrity": "sha512-JzYSLYMhoVVBe8+mbHQ4KgpvHpm0DZpJuL8PY93Vyv1fW7jYJ90LoXa1di/CVbJM+TgMs91rbDapE/RNIfnJsA==", + "dev": true, + "requires": { + "end-of-stream": "1.4.0", + "inherits": "2.0.3", + "readable-stream": "2.2.9", + "stream-shift": "1.0.0" + } + }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", @@ -3393,6 +3690,16 @@ "jsbn": "0.1.1" } }, + "ecdsa-sig-formatter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz", + "integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=", + "dev": true, + "requires": { + "base64url": "2.0.0", + "safe-buffer": "5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4451,7 +4758,7 @@ "requires": { "asynckit": "0.4.0", "combined-stream": "1.0.5", - "mime-types": "2.1.15" + "mime-types": "2.1.18" } }, "forwarded": { @@ -5513,6 +5820,253 @@ "globule": "1.2.0" } }, + "gcp-metadata": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.6.3.tgz", + "integrity": "sha512-MSmczZctbz91AxCvqp9GHBoZOSbJKAICV7Ow/AIWSJZRrRchUd5NL1b2P4OfP+4m490BEUPhhARfpHdqCxuCvg==", + "dev": true, + "requires": { + "axios": "0.18.0", + "extend": "3.0.1", + "retry-axios": "0.3.2" + }, + "dependencies": { + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "dev": true, + "requires": { + "follow-redirects": "1.4.1", + "is-buffer": "1.1.5" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", + "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", + "dev": true, + "requires": { + "debug": "3.1.0" + } + } + } + }, + "gcs-resumable-upload": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/gcs-resumable-upload/-/gcs-resumable-upload-0.9.0.tgz", + "integrity": "sha512-+Zrmr0JKO2y/2mg953TW6JLu+NAMHqQsKzqCm7CIT24gMQakolPJCMzDleVpVjXAqB7ZCD276tcUq2ebOfqTug==", + "dev": true, + "requires": { + "buffer-equal": "1.0.0", + "configstore": "3.1.0", + "google-auto-auth": "0.9.7", + "pumpify": "1.4.0", + "request": "2.85.0", + "stream-events": "1.0.3", + "through2": "2.0.3" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + } + } + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + }, + "dependencies": { + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "5.2.2", + "har-schema": "2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "request": { + "version": "2.85.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", + "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, "generate-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", @@ -5726,6 +6280,73 @@ } } }, + "google-auth-library": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-1.3.2.tgz", + "integrity": "sha512-aRz0om4Bs85uyR2Ousk3Gb8Nffx2Sr2RoKts1smg1MhRwrehE1aD1HC4RmprNt1HVJ88IDnQ8biJQ/aXjiIxlQ==", + "dev": true, + "requires": { + "axios": "0.18.0", + "gcp-metadata": "0.6.3", + "gtoken": "2.3.0", + "jws": "3.1.4", + "lodash.isstring": "4.0.1", + "lru-cache": "4.1.2", + "retry-axios": "0.3.2" + }, + "dependencies": { + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "dev": true, + "requires": { + "follow-redirects": "1.4.1", + "is-buffer": "1.1.5" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", + "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", + "dev": true, + "requires": { + "debug": "3.1.0" + } + }, + "lru-cache": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", + "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + } + } + }, + "google-auto-auth": { + "version": "0.9.7", + "resolved": "https://registry.npmjs.org/google-auto-auth/-/google-auto-auth-0.9.7.tgz", + "integrity": "sha512-Nro7aIFrL2NP0G7PoGrJqXGMZj8AjdBOcbZXRRm/8T3w08NUHIiNN3dxpuUYzDsZizslH+c8e+7HXL8vh3JXTQ==", + "dev": true, + "requires": { + "async": "2.4.1", + "gcp-metadata": "0.6.3", + "google-auth-library": "1.3.2", + "request": "2.79.0" + } + }, "google-closure-compiler": { "version": "20170521.0.0", "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20170521.0.0.tgz", @@ -5737,6 +6358,24 @@ "vinyl-sourcemaps-apply": "0.2.1" } }, + "google-p12-pem": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-1.0.2.tgz", + "integrity": "sha512-+EuKr4CLlGsnXx4XIJIVkcKYrsa2xkAmCvxRhX2HsazJzUBAJ35wARGeApHUn4nNfPD03Vl057FskNr20VaCyg==", + "dev": true, + "requires": { + "node-forge": "0.7.5", + "pify": "3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "got": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", @@ -5774,6 +6413,61 @@ "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", "dev": true }, + "gtoken": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-2.3.0.tgz", + "integrity": "sha512-Jc9/8mV630cZE9FC5tIlJCZNdUjwunvlwOtCz6IDlaiB4Sz68ki29a1+q97sWTnTYroiuF9B135rod9zrQdHLw==", + "dev": true, + "requires": { + "axios": "0.18.0", + "google-p12-pem": "1.0.2", + "jws": "3.1.4", + "mime": "2.2.2", + "pify": "3.0.0" + }, + "dependencies": { + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "dev": true, + "requires": { + "follow-redirects": "1.4.1", + "is-buffer": "1.1.5" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", + "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", + "dev": true, + "requires": { + "debug": "3.1.0" + } + }, + "mime": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.2.2.tgz", + "integrity": "sha512-A7PDg4s48MkqFEcYg2b069m3DXOEq7hx+9q9rIFrSSYfzsh35GX+LOVMQ8Au0ko7d8bSQCIAuzkjp0vCtwENlQ==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "handle-thing": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", @@ -5889,6 +6583,15 @@ "inherits": "2.0.3" } }, + "hash-stream-validation": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.1.tgz", + "integrity": "sha1-7Mm5l7IYvluzEphii7gHhptz3NE=", + "dev": true, + "requires": { + "through2": "2.0.3" + } + }, "hash.js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", @@ -6448,6 +7151,12 @@ "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=", "dev": true }, + "is": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz", + "integrity": "sha1-0Kwq1V63sL7JJqUmb2xmKqqD3KU=", + "dev": true + }, "is-absolute-url": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", @@ -6748,6 +7457,12 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", + "dev": true + }, "is-subset": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", @@ -7086,6 +7801,29 @@ } } }, + "jwa": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz", + "integrity": "sha1-oFUs4CIHQs1S4VN3SjKQXDDnVuU=", + "dev": true, + "requires": { + "base64url": "2.0.0", + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.9", + "safe-buffer": "5.0.1" + } + }, + "jws": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz", + "integrity": "sha1-+ei5M46KhHJ31kRLFGT2GIDgUKI=", + "dev": true, + "requires": { + "base64url": "2.0.0", + "jwa": "1.1.5", + "safe-buffer": "5.0.1" + } + }, "karma": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/karma/-/karma-2.0.0.tgz", @@ -7611,6 +8349,12 @@ "integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=", "dev": true }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", + "dev": true + }, "lodash.map": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", @@ -7666,6 +8410,12 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", "dev": true }, + "log-driver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", + "dev": true + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -7780,7 +8530,7 @@ "requires": { "asynckit": "0.4.0", "combined-stream": "1.0.5", - "mime-types": "2.1.15" + "mime-types": "2.1.18" } }, "node-uuid": { @@ -7833,7 +8583,7 @@ "is-typedarray": "1.0.0", "isstream": "0.1.2", "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", + "mime-types": "2.1.18", "node-uuid": "1.4.8", "oauth-sign": "0.8.2", "qs": "6.2.3", @@ -8128,6 +8878,12 @@ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, + "methmeth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/methmeth/-/methmeth-1.1.0.tgz", + "integrity": "sha1-6AomYY5S9cQiKGG7dIUQvRDikIk=", + "dev": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -8189,12 +8945,20 @@ "dev": true }, "mime-types": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", - "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "dev": true, "requires": { - "mime-db": "1.27.0" + "mime-db": "1.33.0" + }, + "dependencies": { + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + } } }, "mimic-fn": { @@ -8317,6 +9081,12 @@ } } }, + "modelo": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/modelo/-/modelo-4.2.3.tgz", + "integrity": "sha512-9DITV2YEMcw7XojdfvGl3gDD8J9QjZTJ7ZOUuSAkP+F3T6rDbzMJuPktxptsdHYEvZcmXrCD3LMOhdSAEq6zKA==", + "dev": true + }, "modify-values": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.0.tgz", @@ -8446,6 +9216,12 @@ "lower-case": "1.1.4" } }, + "node-forge": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", + "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", + "dev": true + }, "node-gyp": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", @@ -10611,6 +11387,27 @@ "randombytes": "2.0.5" } }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "1.4.0", + "once": "1.4.0" + } + }, + "pumpify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.4.0.tgz", + "integrity": "sha512-2kmNR9ry+Pf45opRVirpNuIFotsxUGLaYqxIwuR77AYrYRMuFCz9eryHBS52L360O+NcR383CL4QYlMKPq4zYA==", + "dev": true, + "requires": { + "duplexify": "3.5.4", + "inherits": "2.0.3", + "pump": "2.0.1" + } + }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", @@ -11127,13 +11924,13 @@ "is-typedarray": "1.0.0", "isstream": "0.1.2", "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", + "mime-types": "2.1.18", "oauth-sign": "0.8.2", "qs": "6.3.2", "stringstream": "0.0.5", "tough-cookie": "2.3.2", "tunnel-agent": "0.4.3", - "uuid": "3.0.1" + "uuid": "3.2.1" } }, "requestretry": { @@ -11208,6 +12005,213 @@ "signal-exit": "3.0.2" } }, + "retry-axios": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/retry-axios/-/retry-axios-0.3.2.tgz", + "integrity": "sha512-jp4YlI0qyDFfXiXGhkCOliBN1G7fRH03Nqy8YdShzGqbY5/9S2x/IR6C88ls2DFkbWuL3ASkP7QD3pVrNpPgwQ==", + "dev": true + }, + "retry-request": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-3.3.1.tgz", + "integrity": "sha512-PjAmtWIxjNj4Co/6FRtBl8afRP3CxrrIAnUzb1dzydfROd+6xt7xAebFeskgQgkfFf8NmzrXIoaB3HxmswXyxw==", + "dev": true, + "requires": { + "request": "2.85.0", + "through2": "2.0.3" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + } + } + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + }, + "dependencies": { + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "5.2.2", + "har-schema": "2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "request": { + "version": "2.85.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", + "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", @@ -11743,6 +12747,26 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "simple-git": { + "version": "1.92.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.92.0.tgz", + "integrity": "sha1-YGFGjrfRnwFBB4/HQuYkV+kQ9Uc=", + "dev": true, + "requires": { + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, "slack-node": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/slack-node/-/slack-node-0.2.0.tgz", @@ -11787,6 +12811,12 @@ "nodemailer-shared": "1.1.0" } }, + "snakeize": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", + "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=", + "dev": true + }, "sntp": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", @@ -12029,6 +13059,16 @@ "through": "2.3.8" } }, + "split-array-stream": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/split-array-stream/-/split-array-stream-1.0.3.tgz", + "integrity": "sha1-0rdajl4Ngk1S/eyLgiWDncLjXfo=", + "dev": true, + "requires": { + "async": "2.4.1", + "is-stream-ended": "0.1.4" + } + }, "split2": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", @@ -12167,6 +13207,15 @@ } } }, + "stream-events": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.3.tgz", + "integrity": "sha512-SvnBCMhEBQSJml4/ImlWkzGWgchjo1tVxnoBUOa1i1g3BsYNWz4W6a9Hc8VhqfmwJiEGu6tLrGdNRm/K/I4YXw==", + "dev": true, + "requires": { + "stubs": "3.0.0" + } + }, "stream-http": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", @@ -12180,6 +13229,12 @@ "xtend": "4.0.1" } }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, "stream-splicer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", @@ -12249,6 +13304,12 @@ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "dev": true }, + "string-format-obj": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string-format-obj/-/string-format-obj-1.1.1.tgz", + "integrity": "sha512-Mm+sROy+pHJmx0P/0Bs1uxIX6UhGJGj6xDGQZ5zh9v/SZRmLGevp+p0VJxV7lirrkAmQ2mvva/gHKpnF/pTb+Q==", + "dev": true + }, "string-width": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz", @@ -12354,6 +13415,12 @@ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, + "stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=", + "dev": true + }, "style-search": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", @@ -13380,7 +14447,7 @@ "dev": true, "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.15" + "mime-types": "2.1.18" } }, "typedarray": { @@ -13702,9 +14769,9 @@ "dev": true }, "uuid": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", - "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", "dev": true }, "uws": { diff --git a/package.json b/package.json index 53972863335..99e4539e2ea 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "test": "npm run test:unit && npm run test:closure && npm run test:dependency && npm run build && npm run clean", "posttest": "istanbul report --root coverage text-summary && istanbul check-coverage --lines 95 --statements 95 --branches 95 --functions 95", "screenshot:serve": "node test/screenshot/run-static-server.js", + "screenshot:upload-assets": "node test/screenshot/run-upload-assets.js", "screenshot:watch": "npm run clean && mkdirp test/screenshot/out/ && webpack --config=test/screenshot/webpack.config.js --watch --progress --colors", "start": "npm run clean && npm-run-all --parallel screenshot:serve screenshot:watch", "test:watch": "karma start --auto-watch", @@ -31,6 +32,7 @@ "test:dependency": "./scripts/dependency-test.sh" }, "devDependencies": { + "@google-cloud/storage": "^1.6.0", "ascii-table": "0.0.9", "autoprefixer": "^8.0.0", "babel-core": "^6.22.1", @@ -88,6 +90,7 @@ "scss-parser": "^1.0.0", "semver": "^5.3.0", "serve-index": "^1.9.1", + "simple-git": "^1.92.0", "standard-changelog": "^1.0.4", "stylelint": "^9.0.0", "stylelint-config-standard": "^18.0.0", diff --git a/test/screenshot/.eslintrc.yaml b/test/screenshot/.eslintrc.yaml new file mode 100644 index 00000000000..12e8b813c0f --- /dev/null +++ b/test/screenshot/.eslintrc.yaml @@ -0,0 +1,5 @@ +extends: ../../.eslintrc.yaml +env: + browser: true +parserOptions: + ecmaVersion: 2017 # Enable async/await support in Node scripts diff --git a/test/screenshot/README.md b/test/screenshot/README.md index ca72b09c2cc..3e43cf1490a 100644 --- a/test/screenshot/README.md +++ b/test/screenshot/README.md @@ -47,3 +47,15 @@ Guidelines: ## Example test page ![localhost_8080_mdc-button_classes_baseline html](https://user-images.githubusercontent.com/409245/38001695-05c55d10-31e3-11e8-9f35-91e3ea82f566.png) + +## Uploading compiled assets to Google Cloud Storage + +1. Start the local dev server: + ```bash + npm start + ``` +2. In a separate terminal, run: + ```bash + export MDC_GCLOUD_SERVICE_ACCOUNT_KEY_FILE_PATH=path/to/gcloud-service-account-key.json + npm run screenshot:upload-assets + ``` diff --git a/test/screenshot/asset-uploader.js b/test/screenshot/asset-uploader.js new file mode 100644 index 00000000000..cdd51390b0a --- /dev/null +++ b/test/screenshot/asset-uploader.js @@ -0,0 +1,131 @@ +/** + * Copyright 2018 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const Storage = require('@google-cloud/storage'); +const glob = require('glob'); +const simpleGit = require('simple-git/promise'); + +const USERNAME = process.env.USER || process.env.USERNAME; +const GCLOUD_SERVICE_ACCOUNT_KEY_FILE_PATH = process.env.MDC_GCLOUD_SERVICE_ACCOUNT_KEY_FILE_PATH; +const GCLOUD_STORAGE_BUCKET_NAME = 'mdc-web-screenshot-tests'; +const GCLOUD_STORAGE_BASE_URL = `https://storage.googleapis.com/${GCLOUD_STORAGE_BUCKET_NAME}/`; +const LOCAL_DIRECTORY_PREFIX = 'test/screenshot/'; + +const gitRepo = simpleGit(); +const storage = new Storage({ + credentials: require(GCLOUD_SERVICE_ACCOUNT_KEY_FILE_PATH), +}); +const bucket = storage.bucket(GCLOUD_STORAGE_BUCKET_NAME); + +async function upload() { + const promises = []; + + // Attaching Git metadata to the uploaded files makes it easier to track down their source. + const gitCommitShort = await git('revparse', ['--short', 'HEAD']); + const gitBranchName = await git('revparse', ['--abbrev-ref', 'HEAD']); + + // Every batch of files gets uploaded to a unique timestamped directory to prevent collisions between developers. + const {year, month, day, hour, minute, second, ms} = getUtcDateTime(); + const baseGcsDir = `${USERNAME}/${year}/${month}/${day}/${hour}_${minute}_${second}_${ms}/${gitCommitShort}/assets/`; + const relativeLocalFilePaths = glob.sync(path.join(LOCAL_DIRECTORY_PREFIX, '**/*')).filter(isFile); + + relativeLocalFilePaths.forEach((relativeLocalFilePath) => { + const fileContents = fs.readFileSync(relativeLocalFilePath); + const relativeGcsFilePath = relativeLocalFilePath.replace(LOCAL_DIRECTORY_PREFIX, ''); + const absoluteGcsFilePath = `${baseGcsDir}${relativeGcsFilePath}`; + + console.log(`➡️ Uploading ${absoluteGcsFilePath} ...`); + + const file = bucket.file(absoluteGcsFilePath); + + // Note: The GCS API mutates this object, so we need to create a new object every time we call the API. + const fileOptions = { + contentType: 'auto', + + // The nested `metadata` object is not a typo - it's required by the GCS `File#save()` API. + metadata: { + metadata: { + 'X-MDC-Git-Commit': gitCommitShort, + 'X-MDC-Git-Branch': gitBranchName, + }, + }, + }; + + promises.push( + file.save(fileContents, fileOptions) + .then(() => handleUploadSuccess(baseGcsDir, relativeGcsFilePath)) + .catch((err) => handleUploadFailure(baseGcsDir, relativeGcsFilePath, err)) + ); + }); + + return Promise.all(promises); +} + +function getUtcDateTime() { + const pad = (num) => String(num).padStart(2, '0'); + const date = new Date(); + + return { + year: date.getUTCFullYear(), + month: pad(date.getUTCMonth() + 1), // getUTCMonth() returns a zero-based value (e.g., January is `0`) + day: pad(date.getUTCDate()), + hour: pad(date.getUTCHours()), + minute: pad(date.getUTCMinutes()), + second: pad(date.getUTCSeconds()), + ms: pad(date.getUTCMilliseconds()), + }; +} + +function handleUploadSuccess(baseGcsDir, relativeGcsFilePath) { + console.log(`✔︎ Uploaded ${GCLOUD_STORAGE_BASE_URL}${baseGcsDir}${relativeGcsFilePath}`); + return { + status: 'SUCCESS', + error: null, + bucketUrl: GCLOUD_STORAGE_BASE_URL, + parentDir: baseGcsDir, + relativePath: relativeGcsFilePath, + fullUrl: `${GCLOUD_STORAGE_BASE_URL}${baseGcsDir}${relativeGcsFilePath}`, + }; +} + +function handleUploadFailure(baseGcsDir, relativeGcsFilePath, err) { + console.error(`✗︎ FAILED to upload ${GCLOUD_STORAGE_BASE_URL}${baseGcsDir}${relativeGcsFilePath}:\n`, err); + return { + status: 'ERROR', + error: err, + bucketUrl: GCLOUD_STORAGE_BASE_URL, + parentDir: baseGcsDir, + relativePath: relativeGcsFilePath, + fullUrl: `${GCLOUD_STORAGE_BASE_URL}${baseGcsDir}${relativeGcsFilePath}`, + }; +} + +function isFile(path) { + return fs.statSync(path).isFile(); +} + +async function git(cmd, argList = []) { + return (await gitRepo[cmd](argList) || '').trim(); +} + +module.exports = { + upload, +}; diff --git a/test/screenshot/run-upload-assets.js b/test/screenshot/run-upload-assets.js new file mode 100644 index 00000000000..a87b54ddb0a --- /dev/null +++ b/test/screenshot/run-upload-assets.js @@ -0,0 +1,34 @@ +/** + * Copyright 2018 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +const assetUploader = require('./asset-uploader'); + +assetUploader.upload() + .then((files) => { + const htmlFileUrls = + files + .filter((file) => file.relativePath.endsWith('.html')) + .map((file) => file.fullUrl) + .sort(); + console.log('\n\nDONE!\n\n'); + console.log(htmlFileUrls.join('\n')); + }) + .catch((err) => { + console.error('\n\nERROR!\n\n'); + console.error(err); + });