From 2a308aaad0e25511f8650b783cd9a72adf83a083 Mon Sep 17 00:00:00 2001 From: Salakar Date: Tue, 4 Sep 2018 13:17:30 +0100 Subject: [PATCH] [build][ci] add packager warm up script --- .circleci/scripts/packager-warmup.js | 62 +++++++++++++++ .circleci/scripts/utils.js | 114 +++++++++++++++++++++++++++ package-lock.json | 30 +++++++ package.json | 1 + 4 files changed, 207 insertions(+) create mode 100644 .circleci/scripts/packager-warmup.js create mode 100644 .circleci/scripts/utils.js diff --git a/.circleci/scripts/packager-warmup.js b/.circleci/scripts/packager-warmup.js new file mode 100644 index 00000000..5b7a5c97 --- /dev/null +++ b/.circleci/scripts/packager-warmup.js @@ -0,0 +1,62 @@ +const axios = require('axios'); +const { sleep, getReactNativePlatform, A2A } = require('./utils'); + +let waitAttempts = 1; +let maxWaitAttempts = 60; + +async function waitForPackager() { + let ready = false; + + while (waitAttempts < maxWaitAttempts) { + console.log(`Waiting for packager to be ready, attempt ${waitAttempts} of ${maxWaitAttempts}...`); + const [error, response] = await A2A(axios.get('http://localhost:8081/status', { timeout: 500 })); + if (!error && response.data.includes('packager-status:running')) { + ready = true; + break; + } + await sleep(1500); + waitAttempts++; + } + + if (!ready) { + return Promise.reject(new Error('Packager failed to be ready.')); + } + + console.log('Packager is now ready!'); + + return true; +} + +(async function main() { + const [packagerError] = await A2A(waitForPackager()); + if (packagerError) { + console.error(packagerError); + process.exitCode = 1; + process.exit(); + } + + const platform = getReactNativePlatform(); + const map = `http://localhost:8081/index.map?platform=${platform}&dev=true&minify=false&inlineSourceMap=true`; + const bundle = `http://localhost:8081/index.bundle?platform=${platform}&dev=true&minify=false&inlineSourceMap=true`; + + console.log(`Requesting ${platform} bundle...`); + console.log(bundle); + const [bundleError] = await A2A(axios.get(bundle)); + if (bundleError) { + console.error(bundleError); + process.exitCode = 1; + process.exit(); + } + + console.log(`Requesting ${platform} bundle source map...`); + console.log(map); + const [bundleMapError] = await A2A(axios.get(map)); + if (bundleMapError) { + console.error(bundleMapError); + process.exitCode = 1; + process.exit(); + } + + console.log('Warm-up complete!') +})(); + diff --git a/.circleci/scripts/utils.js b/.circleci/scripts/utils.js new file mode 100644 index 00000000..95427b8c --- /dev/null +++ b/.circleci/scripts/utils.js @@ -0,0 +1,114 @@ +/** + * "sleep" for the specified time in milliseconds - returns a promise + * + * @param duration milliseconds + * @return {Promise | Promise} + */ +module.exports.sleep = function sleep(duration) { + return new Promise(resolve => setTimeout(resolve, duration)); +}; + +/** + * Get the current react native platform based on current test job with + * a fallback to process.platform + * + * @return {string} + */ +module.exports.getReactNativePlatform = function getReactNativePlatform() { + if (process.env.CIRCLE_JOB) { + if (process.env.CIRCLE_JOB.includes('android')) { + return 'android'; + } + if (process.env.CIRCLE_JOB.includes('ios')) { + return 'ios'; + } + } + + if (process.platform.includes('darwin')) { + return 'ios'; + } + + return 'android'; +}; + +/** + * Async/Await to Array [error, result] + * + * Examples: + * + * // 0 - standard usage + * + * const [dbError, dbResult] = await A2A(TodoModel.find({ id: 1 })); + * + * // 1) if an error isn't needed: + * + * const [ , dbResult ] = await A2A(TodoModel.find({ id: 1 })); + * // if (!dbResult) return somethingSomethingHandleResult(); + * + * // 2) if a result isn't needed: + * + * const [ dbError ] = await A2A(TodoModel.destroy({ id: 1 })); + * if (dbError) return somethingSomethingHandleError(); + * + * // 3) if neither error or result are needed: + * + * await A2A(TodoModel.destroy({ id: 1 })); + * + * // 4) multiple promises + * + * const promises = []; + * + * promises.push(Promise.resolve(1)); + * promises.push(Promise.resolve(2)); + * promises.push(Promise.resolve(3)); + * + * const [ , results ] = await A2A(promises); + * + * // 5) non promise values + * + * const [ error, nothingHere ] = await A2A(new Error('Just a foo in a bar world')); + * if (error) profit(); // ? + * + * const [ nothingHere, myThing ] = await A2A('A thing string'); + * + * + * @param oOrP Object or Primitive + * @returns {*} Promise + * @constructor + */ +module.exports.A2A = function A2A(oOrP) { + if (!oOrP) return Promise.resolve([null, oOrP]); + + // single promise + if (oOrP.then) { + return oOrP.then((r) => [null, r]).catch((e) => [e, undefined]); + } + + // function that returns a single promise + if (typeof oOrP === 'function') { + return oOrP() + .then((r) => [null, r]) + .catch((e) => [e, undefined]); + } + + // array of promises + if (Array.isArray(oOrP) && oOrP.length && oOrP[0].then) { + return Promise.all(oOrP) + .then((r) => [null, r]) + .catch((e) => [e, undefined]); + } + + // array of functions that returns a single promise + if (Array.isArray(oOrP) && oOrP.length && typeof oOrP[0] === 'function') { + return Promise.all(oOrP.map((f) => f())) + .then((r) => [null, r]) + .catch((e) => [e, undefined]); + } + + // non promise values - error + if (oOrP instanceof Error) return Promise.resolve([oOrP, undefined]); + + // non promise values - any other value + return Promise.resolve([null, oOrP]); +} + diff --git a/package-lock.json b/package-lock.json index 341c1eca..d6ecc6e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2587,6 +2587,16 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "axios": { + "version": "0.18.0", + "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "dev": true, + "requires": { + "follow-redirects": "1.5.7", + "is-buffer": "1.1.6" + } + }, "axobject-query": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.1.tgz", @@ -4935,6 +4945,26 @@ "yargs": "12.0.1" } }, + "follow-redirects": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.7.tgz", + "integrity": "sha512-NONJVIFiX7Z8k2WxfqBjtwqMifx7X42ORLFrOZ2LTKGj71G3C0kfdyTqGqr8fx5zSX6Foo/D95dgGWbPUiwnew==", + "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" + } + } + } + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", diff --git a/package.json b/package.json index edef202a..56ad3224 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "@babel/cli": "^7.0.0", "@babel/core": "^7.0.0", "@invertase/babel-preset-react-native-syntax": "^0.1.3", + "axios": "^0.18.0", "babel-eslint": "^9.0.0", "eslint": "^5.5.0", "eslint-config-airbnb": "^17.0.0",