From 7594cca671fb9d437ec3e21f1a5279041b3471f6 Mon Sep 17 00:00:00 2001 From: Georgette Pincin Date: Tue, 29 Dec 2015 01:21:48 -0500 Subject: [PATCH] first implementation --- index.js | 90 +++++++++++++++++++++- package.json | 8 +- test/error.js | 16 ++++ test/init.js | 8 -- test/options.js | 193 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 302 insertions(+), 13 deletions(-) create mode 100644 test/error.js delete mode 100644 test/init.js create mode 100644 test/options.js diff --git a/index.js b/index.js index 6169962..1605c64 100644 --- a/index.js +++ b/index.js @@ -1,2 +1,90 @@ -module.exports = function () { +var exec = require('child_process').exec + +module.exports = produce + +function produce (options, cb) { + + if (typeof options === 'function') { + cb = options + options = {} + } + options = options || {} + cb = cb || function () {} + options.timeout = options.timeout !== undefined ? options.timeout : 0 + + var cmd = 'produce' + if (options.create) cmd += ' create' + if (options.identifier) cmd += ` -a ${options.identifier}` + if (options.user) cmd += ` -u ${options.user}` + if (options.suffix) cmd += ` -e ${options.suffix}` + if (options.name) cmd += ` -q ${options.name}` + if (options.version) cmd += ` -z ${options.version}` + if (options.sku) cmd += ` -y ${options.sku}` + if (options.language) cmd += ` -m ${options.language}` + if (options.company) cmd += ` -c ${options.company}` + if (options.teamId) cmd += ` -b ${options.teamId}` + if (options.teamName) cmd += ` -l ${options.teamName}` + if (options.skipItc) cmd += ' -i' + if (options.devCenter) cmd += ' -d' + + if (options.createAppGroup && options.createAppGroup.name) { + cmd += ` group -g ${options.createAppGroup.name}` + if (options.createAppGroup.description) cmd += ` -n '${options.createAppGroup.description}'` + } + + if (options.associateGroup && options.associateGroup.app && options.associateGroup.group) { + cmd += ` associate_group -a ${options.associateGroup.app} '${options.associateGroup.group}'` + } + + var services = [ 'app-group', 'associated-domains', 'data-protection', 'healthkit', + 'homekit', 'wireless-conf', 'icloud', 'inter-app-audio', 'passbook', 'push-notification', 'vpn-conf' ] + + if (options.enableServices) { + var enableServices = options.enableServices.map((option) => { + if (typeof option === 'string' && ~services.indexOf(option)) { + return { service: option } + } + else if (typeof option === 'object' && option.value !== false && ~services.indexOf(option.service)) { + return option + } + }).filter((option) => { + return option !== undefined + }) + + cmd += ' enable_services' + + enableServices.forEach((option) => { + switch (option.service) { + case 'data-protection': + cmd += ` --data-protection ${option.value || 'complete'}` + break + case 'icloud': + cmd += ` --icloud ${option.value || 'cloudkit'}` + break + default: + cmd += ` --${option.service}` + break + } + }) + } + + if (options.disableServices) { + cmd += ' disable_services' + options.disableServices.forEach((option) => { + console.log(option, typeof option, option.value !== false, ~services.indexOf(option.service)) + if (typeof option === 'string' && ~services.indexOf(option)) cmd += ` --${option}` + else if (typeof option === 'object' && option.value !== false && ~services.indexOf(option.service)) cmd += ` --${option.service}` + }) + } + + var runtimeOptions = { env: Object.assign({}, process.env) } + + if (options.timeout) runtimeOptions.timeout = options.timeout + if (options.password) runtimeOptions.env.FASTLANE_PASSWORD = options.password + if (options.path) runtimeOptions.cwd = options.path + + exec(cmd, runtimeOptions, (err, stdout, stderr) => { + cb(err, { stdout, stderr }) + }) + } diff --git a/package.json b/package.json index b55f422..6b0bddc 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,7 @@ "type": "git", "url": "git://github.com/Georgette/fastlane-produce.git" }, - "keywords": [ - ], + "keywords": [], "license": "MIT", "bugs": { "url": "https://github.com/Georgette/fastlane-produce/issues" @@ -19,13 +18,14 @@ "email": "gege@pincin.com", "url": "http://gege.pincin.com/" }, - "contributors": [ - ], + "contributors": [], "devDependencies": { "@jasonpincin/standard": "~5.0.0-8", "faucet": "0.0.1", "istanbul": "~0.4.0", "opn": "~1.0.2", + "proxyquire": "^1.7.3", + "sinon": "^1.17.2", "snazzy": "~2.0.1", "tape": "~4.2.1" }, diff --git a/test/error.js b/test/error.js new file mode 100644 index 0000000..3f78a8d --- /dev/null +++ b/test/error.js @@ -0,0 +1,16 @@ +var proxyquire = require('proxyquire'), + test = require('tape'), + sinon = require('sinon') + +var error = new Error('boom') +var exec = sinon.stub().callsArgWith(2, error, '', '') +var child_process = { exec } +var produce = proxyquire('..', { child_process }) + +test('produce wrapper callback receives exec errors', (t) => { + t.plan(1) + exec.reset() + produce({}, (err) => { + t.equal(err, error, 'got error') + }) +}) diff --git a/test/init.js b/test/init.js deleted file mode 100644 index 2e59cb8..0000000 --- a/test/init.js +++ /dev/null @@ -1,8 +0,0 @@ -var test = require('tape'), - subject = require('..') - -test('init', function (t) { - var thing = subject() - t.ok(thing, 'module can be required') - t.end() -}) diff --git a/test/options.js b/test/options.js new file mode 100644 index 0000000..4b77d18 --- /dev/null +++ b/test/options.js @@ -0,0 +1,193 @@ +var proxyquire = require('proxyquire'), + test = require('tape'), + sinon = require('sinon') + +var exec = sinon.stub().callsArgWith(2, null, '', '') +var child_process = { exec } +var produce = proxyquire('..', { child_process }) + +test('accepts no options', (t) => { + t.plan(1) + exec.reset() + produce(() => { + t.pass('function called') + }) +}) + +test('accepts no args', (t) => { + t.plan(1) + exec.reset() + t.doesNotThrow(produce) +}) + +test('accepts create command', (t) => { + t.plan(1) + exec.reset() + produce({ create: true }, () => { + t.ok(exec.calledWith('produce create'), 'produce called with create') + }) +}) + +test('accepts option to turn off devCenter creation', (t) => { + t.plan(1) + exec.reset() + produce({ devCenter: true }, () => { + t.ok(exec.calledWith('produce -d'), 'produce called with -d') + }) +}) + +test('accepts option to turn off itunes connect creation', (t) => { + t.plan(1) + exec.reset() + produce({ skipItc: true }, () => { + t.ok(exec.calledWith('produce -i'), 'produce called with -i') + }) +}) + +test('accepts an identifier option', (t) => { + t.plan(1) + exec.reset() + produce({ identifier: 'test.test.123' }, () => { + t.ok(exec.calledWith('produce -a test.test.123'), 'produce called with -a') + }) +}) + +test('accepts a user option', (t) => { + t.plan(1) + exec.reset() + produce({ user: 'gege' }, () => { + t.ok(exec.calledWith('produce -u gege'), 'produce called with -u') + }) +}) + +test('accepts an teamName option', (t) => { + t.plan(1) + exec.reset() + produce({ teamName: 'teama' }, () => { + t.ok(exec.calledWith('produce -l teama'), 'produce called with -l') + }) +}) + +test('accepts an teamId option', (t) => { + t.plan(1) + exec.reset() + produce({ teamId: 'teama' }, () => { + t.ok(exec.calledWith('produce -b teama'), 'produce called with -b') + }) +}) + +test('accepts an company option', (t) => { + t.plan(1) + exec.reset() + produce({ company: 'pincin' }, () => { + t.ok(exec.calledWith('produce -c pincin'), 'produce called with -c') + }) +}) + +test('accepts an language option', (t) => { + t.plan(1) + exec.reset() + produce({ language: 'english' }, () => { + t.ok(exec.calledWith('produce -m english'), 'produce called with -m') + }) +}) + +test('accepts an sku option', (t) => { + t.plan(1) + exec.reset() + produce({ sku: '131' }, () => { + t.ok(exec.calledWith('produce -y 131'), 'produce called with -y') + }) +}) + +test('accepts an version option', (t) => { + t.plan(1) + exec.reset() + produce({ version: '1.1' }, () => { + t.ok(exec.calledWith('produce -z 1.1'), 'produce called with -z') + }) +}) + +test('accepts an app name', (t) => { + t.plan(1) + exec.reset() + produce({ name: 'test' }, () => { + t.ok(exec.calledWith('produce -q test'), 'produce called with -q') + }) +}) + +test('accepts a suffix option', (t) => { + t.plan(1) + exec.reset() + produce({ suffix: 'gege' }, () => { + t.ok(exec.calledWith('produce -e gege'), 'produce called with -e') + }) +}) + +test('accepts a createAppGroup command', (t) => { + t.plan(2) + exec.reset() + produce({ createAppGroup: {name: 'winners', description: 'app group'} }, () => { + t.ok(exec.calledWith("produce group -g winners -n 'app group'"), 'produce called with group -g name description') + }) + exec.reset() + produce({ createAppGroup: {name: 'winners'} }, () => { + t.ok(exec.calledWith('produce group -g winners'), 'produce called with group -g name') + }) +}) + +test('accepts a associateGroup command with app and group', (t) => { + t.plan(1) + exec.reset() + produce({ associateGroup: {app: 'app', group: 'app group'} }, () => { + t.ok(exec.calledWith("produce associate_group -a app 'app group'"), 'produce called with associate_group -a app group') + }) +}) + +test('accepts a runtime option of timeout', (t) => { + t.plan(1) + exec.reset() + produce({ timeout: 1 }, () => { + t.ok(exec.calledWithMatch('produce', { timeout: 1 }), 'produce called with timeout runtime option') + }) +}) + +test('accepts a runtime option of password', (t) => { + t.plan(1) + exec.reset() + produce({ password: 'password' }, () => { + t.ok(exec.calledWithMatch('produce', { env: { FASTLANE_PASSWORD: 'password' } }), 'produce called with password runtime option') + }) +}) + +test('accepts a runtime option of path', (t) => { + t.plan(1) + exec.reset() + produce({ path: '/something' }, () => { + t.ok(exec.calledWithMatch('produce', { cwd: '/something' }), 'produce called with runtime path') + }) +}) + +test('accepts enable services with accepted options and formats', (t) => { + t.plan(2) + exec.reset() + produce({ enableServices: ['app-group', { service: 'associated-domains', value: true }, 'icloud', 'foo', 'data-protection']}, () => { + t.ok(exec.calledWith('produce enable_services --app-group --associated-domains --icloud cloudkit --data-protection complete'), + 'produce called with enable services with default setting for icloud and data protection, and checking for invalid entry') + }) + + exec.reset() + produce({ enableServices: [{service: 'foo'}, {}, { service: 'data-protection', value: 'unlessopen' }]}, () => { + t.ok(exec.calledWith('produce enable_services --data-protection unlessopen'), + 'produce called with enable services with data protection as object, also incorrect object service name, and empty object') + }) +}) + +test('accepts disable services with accepted services and formats', (t) => { + t.plan(1) + exec.reset() + produce({ disableServices: ['app-group', { service: 'associated-domains', value: false }, { service: 'data-protection', value: true }, 'foo', { service: 'passbook' }, {service: 'foo'}]}, () => { + t.ok(exec.calledWith('produce disable_services --app-group --data-protection --passbook'), + 'produce called with disable services with default setting') + }) +})