Skip to content

Commit

Permalink
Merge pull request #56 from electricimp/develop
Browse files Browse the repository at this point in the history
v2.5.0
  • Loading branch information
betzrhodes authored Apr 12, 2019
2 parents 007b6ec + a3b1e49 commit 6f034ae
Show file tree
Hide file tree
Showing 18 changed files with 541 additions and 156 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/node_modules
34 changes: 25 additions & 9 deletions CommandsManual.md

Large diffs are not rendered by default.

108 changes: 85 additions & 23 deletions DevelopmentGuide.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright 2018 Electric Imp
Copyright 2018-2019 Electric Imp

SPDX-License-Identifier: MIT

Expand Down
16 changes: 9 additions & 7 deletions ProductionGuide.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# impt Production Guide #

**NOTE:** The contents of this guide have **NOT** been updated with the release of v2.5.0 (support for DUT device groups), and so some of the contents may be out of date.

This additional guide is intended for those customers who use *impt* with [production processes](https://developer.electricimp.com/manufacturing). You may use scripts on top of *impt* commands to automate some of the operations.

Please read the main [Read Me file](./README.md) first as it covers all the basic *impt* usage and its common components.
Expand Down Expand Up @@ -44,14 +46,14 @@ Device Groups may be of different [types](./CommandsManual.md#device-group-type)

### Production Device Groups ###

Your production devices, which are utilized by end-users, are organized into one or more Device Groups of the *production* type. Different Production Device Groups within the same Product may be used to encapsulate and manage different versions or flavors of your application. Production devices are units that have been blessed; up until that point they are referred to as devices under test (DUTs).
Your production devices, which are utilized by end-users, are organized into one or more Device Groups of the *production* type. Different Production Device Groups within the same Product may be used to encapsulate and manage different versions or flavors of your application. Production devices are units that have been blessed; up until that point they are referred to as devices under test (DUTs).

You can create a Production Device Group with [`impt dg create --dg-type production`](./CommandsManual.md#device-group-create).

Production Device Groups have an attribute called *load-code-after-blessing*. This defines when your application is loaded onto production devices: in your factory after blessing, or when an end-user activates a device using BlinkUp™. When a new Production Device Group is created, this attribute always has the value `true`. To change the attribute you can use the `--load-code-after-blessing` option of the [`impt dg update`](./CommandsManual.md#device-group-update) command:

```
impt dg create --name MyProductionDG --descr "Production Device Group for application"
impt dg create --name MyProductionDG --descr "Production Device Group for application"
--dg-type production --product MyProduct
impt dg update --dg MyProductionDG --load-code-after-blessing false
```
Expand All @@ -63,11 +65,11 @@ For your [factory setup](https://developer.electricimp.com/manufacturing/factory
You can create Factory Device Group with the [`impt dg create --dg-type factory`](./CommandsManual.md#device-group-create) command.

Each Factory Device Group references a single Production Device Group within the same Product. This is the Factory Device Group’s *target* and this the Production Device Group to which DUTs will automatically be assigned once they have been blessed and become production devices. You specify a Factory Device Group’s target by using the `--target` option during Factory Device Group creation:

```
impt dg create --name MyFactoryDG --descr "Factory Device Group for factory firmware"
impt dg create --name MyFactoryDG --descr "Factory Device Group for factory firmware"
--dg-type factory --product MyProduct --target MyProductionDG
```
```

## Deployments ##

Expand All @@ -84,7 +86,7 @@ This guide assumes you have already developed and tested your application and fa
impt build copy --build MyRC1 --dg MyProductionDG
```

```
```
impt build copy --build MyFactoryRC1 --dg MyFactoryDG
```

Expand All @@ -98,7 +100,7 @@ In order to connect your Factory BlinkUp Fixtures to the factory’s WiFi networ

```
impt device assign --device <device_id> --dg MyFactoryDG
```
```

### Devices Under Test (DUTs) ###

Expand Down
15 changes: 13 additions & 2 deletions bin/cmds/dg/create.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// MIT License
//
// Copyright 2018 Electric Imp
// Copyright 2018-2019 Electric Imp
//
// SPDX-License-Identifier: MIT
//
Expand Down Expand Up @@ -59,6 +59,13 @@ exports.builder = function (yargs) {
describe : 'An optional description of the Device Group.',
_usage : '<device_group_description>'
},
[Options.DUT] : {
demandOption : false,
describe : Util.format("The Device Group identifier of the new Device Group's device-under-test target Device Group." +
" Should only be specified if the new Device Group is of the %s or %s type." +
" The device-under-test target Device Group must be of the type %s or %s correspondingly, and belong to the specified Product.",
Options.DG_TYPE_FACTORY, Options.DG_TYPE_PRE_FACTORY, Options.DG_TYPE_DUT, Options.DG_TYPE_PRE_DUT)
},
[Options.TARGET] : {
demandOption : false,
describe : Util.format("The Device Group identifier of the new Device Group's production target Device Group." +
Expand All @@ -74,7 +81,11 @@ exports.builder = function (yargs) {
.options(options)
.check(function (argv) {
const opts = new Options(argv);
if (!opts.target && Options.isProductionTargetRequired(opts.deviceGroupType)) {
if (!opts.dut && Options.isTargetRequired(opts.deviceGroupType)) {
return new Errors.ImptError(UserInteractor.ERRORS.CMD_TARGET_REQUIRED,
Options.DUT, Options.getDeviceGroupTypeName(opts.deviceGroupType));
}
if (!opts.target && Options.isTargetRequired(opts.deviceGroupType)) {
return new Errors.ImptError(UserInteractor.ERRORS.CMD_TARGET_REQUIRED,
Options.TARGET, Options.getDeviceGroupTypeName(opts.deviceGroupType));
}
Expand Down
10 changes: 9 additions & 1 deletion bin/cmds/dg/update.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// MIT License
//
// Copyright 2018 Electric Imp
// Copyright 2018-2019 Electric Imp
//
// SPDX-License-Identifier: MIT
//
Expand Down Expand Up @@ -50,6 +50,14 @@ exports.builder = function (yargs) {
describe : 'An optional description of the Device Group.',
_usage : '<device_group_description>'
},
[Options.DUT] : {
demandOption : false,
describe : Util.format("The Device Group identifier of the specified Device Group's device-under-test target Device Group." +
" May only be specified for %s and %s Device Groups." +
" The device-under-test target Device Group must be of the type %s or %s correspondingly," +
" and belong to the same Product as the specified Device Group.",
Options.DG_TYPE_FACTORY, Options.DG_TYPE_PRE_FACTORY, Options.DG_TYPE_DUT, Options.DG_TYPE_PRE_DUT)
},
[Options.TARGET] : {
demandOption : false,
describe : Util.format("The Device Group identifier of the specified Device Group's production target Device Group." +
Expand Down
13 changes: 12 additions & 1 deletion bin/cmds/project/create.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// MIT License
//
// Copyright 2018 Electric Imp
// Copyright 2018-2019 Electric Imp
//
// SPDX-License-Identifier: MIT
//
Expand Down Expand Up @@ -65,6 +65,14 @@ exports.builder = function (yargs) {
default: 'agent.nut'
},
[Options.PRE_FACTORY] : false,
[Options.DUT] : {
demandOption : false,
describe : Util.format("The Device Group identifier of the new Project Device Group's device-under-test target Device Group." +
" May be specified only if --%s is also specified." +
" The specified Device Group must be of the type %s and belong to the specified Product.",
Options.PRE_FACTORY, Options.DG_TYPE_PRE_DUT)
},
[Options.CREATE_DUT] : false,
[Options.TARGET] : {
demandOption : false,
describe : Util.format("The Device Group identifier of the new Project Device Group's production target Device Group." +
Expand All @@ -84,6 +92,9 @@ exports.builder = function (yargs) {
if (opts.preFactory && !opts.target || !opts.preFactory && opts.target) {
return new Errors.CommandSyntaxError(UserInteractor.ERRORS.CMD_COOPERATIVE_OPTIONS, Options.PRE_FACTORY, Options.TARGET);
}
if (opts.preFactory && !opts.dut || !opts.preFactory && opts.dut) {
return new Errors.CommandSyntaxError(UserInteractor.ERRORS.CMD_COOPERATIVE_OPTIONS, Options.PRE_FACTORY, Options.DUT);
}
return Options.checkOptions(argv, options);
})
.strict();
Expand Down
9 changes: 8 additions & 1 deletion bin/cmds/project/update.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// MIT License
//
// Copyright 2018 Electric Imp
// Copyright 2018-2019 Electric Imp
//
// SPDX-License-Identifier: MIT
//
Expand Down Expand Up @@ -60,6 +60,13 @@ exports.builder = function (yargs) {
demandOption : false,
describe: 'A new agent source code file name. If the file does not exist, an empty file is created.'
},
[Options.DUT] : {
demandOption : false,
describe : Util.format("The Device Group identifier of the Project Device Group's device-under-test target Device Group." +
" May only be specified if the Project Device Group is of the %s type." +
" The specified device-under-test target Device Group must be of the type %s and belong to the same Product as the Project Device Group.",
Options.DG_TYPE_PRE_FACTORY, Options.DG_TYPE_PRE_DUT)
},
[Options.TARGET] : {
demandOption : false,
describe : Util.format("The Device Group identifier of the Project Device Group's production target Device Group." +
Expand Down
118 changes: 58 additions & 60 deletions lib/DeviceGroup.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// MIT License
//
// Copyright 2018 Electric Imp
// Copyright 2018-2019 Electric Imp
//
// SPDX-License-Identifier: MIT
//
Expand Down Expand Up @@ -32,6 +32,8 @@ const ListHelper = require('./util/ListHelper');
const DeleteHelper = require('./util/DeleteHelper');
const UserInteractor = require('./util/UserInteractor');
const Identifier = require('./util/Identifier');
const ProductionTarget = require('./util/Target').ProductionTarget;
const DutTarget = require('./util/Target').DutTarget;
const Entity = require('./util/Entity');
const Options = require('./util/Options');
const Errors = require('./util/Errors');
Expand All @@ -47,6 +49,7 @@ const ATTR_REGION = 'region';
const REL_CURRENT_DEPLOYMENT = 'current_deployment';
const REL_MIN_SUPPORTED_DEPLOYMENT = 'min_supported_deployment';
const REL_PRODUCTION_TARGET = 'production_target';
const REL_DUT_TARGET = 'dut_target';

// This class represents Device Group impCentral API entity.
// Provides methods used by impt Device Group Manipulation Commands.
Expand Down Expand Up @@ -80,6 +83,14 @@ class DeviceGroup extends Entity {
return undefined;
}

// Returns the DUT target Device Group, if exists
get dutTargetId() {
if (REL_DUT_TARGET in this.apiEntity.relationships) {
return this.apiEntity.relationships[REL_DUT_TARGET].id;
}
return undefined;
}

// Returns the Device Group related Product id
get relatedProductId() {
return this.apiEntity.relationships[Entity.REL_PRODUCT].id;
Expand All @@ -106,7 +117,10 @@ class DeviceGroup extends Entity {

_createByProductId(productId, options, deviceGroupType) {
const dgType = deviceGroupType ? deviceGroupType : options.deviceGroupType;
return this._processProductionTarget(productId, dgType, options).
this._productionTarget = new ProductionTarget(options, dgType);
this._dutTarget = new DutTarget(options, dgType);
return this._processTarget(this._productionTarget, productId).
then(() => this._processTarget(this._dutTarget, productId)).
then(() => {
const attrs = {
[Entity.ATTR_NAME] : options.name,
Expand All @@ -116,64 +130,25 @@ class DeviceGroup extends Entity {
attrs[ATTR_REGION] = options.region;
}
this.initByName(options.name);
return super._createEntity(productId, dgType, attrs, this._getProductionTargetOptions());
return super._createEntity(
productId,
dgType,
attrs,
this._getTargetOptions(this._productionTarget),
this._getTargetOptions(this._dutTarget));
});
}

_getProductionTargetType(deviceGroupType) {
switch (deviceGroupType) {
case DeviceGroups.TYPE_PRE_FACTORY_FIXTURE:
return DeviceGroups.TYPE_PRE_PRODUCTION;
case DeviceGroups.TYPE_FACTORY_FIXTURE:
return DeviceGroups.TYPE_PRODUCTION;
}
return null;
}

_processProductionTarget(productId, deviceGroupType, options) {
if (options.target) {
if (!Options.isProductionTargetRequired(deviceGroupType)) {
return Promise.reject(new Errors.ImptError(
UserInteractor.ERRORS.WRONG_DG_TYPE_FOR_OPTION,
Options.TARGET,
Options.getDeviceGroupTypeName(deviceGroupType),
Options.getDeviceGroupTypeName(DeviceGroups.TYPE_PRE_FACTORY_FIXTURE),
Options.getDeviceGroupTypeName(DeviceGroups.TYPE_FACTORY_FIXTURE)));
}
this._productionTarget = new DeviceGroup();
return this._productionTarget.initByIdentifier(options.target).findEntity().then(entity => {
const targetRequiredType = this._getProductionTargetType(deviceGroupType);
if (entity) {
if (this._productionTarget.type !== targetRequiredType) {
return Promise.reject(
new Errors.ImptError(
UserInteractor.ERRORS.TARGET_DG_WRONG_TYPE,
this._productionTarget.identifierInfo,
Options.getDeviceGroupTypeName(this._productionTarget.type),
Options.getDeviceGroupTypeName(targetRequiredType)));
}
else if (this._productionTarget.relatedProductId !== productId) {
return Promise.reject(
new Errors.ImptError(UserInteractor.ERRORS.TARGET_DG_WRONG_PRODUCT));
}
return Promise.resolve();
}
else if (options.createTarget) {
return this._productionTarget._createByProductId(
productId, new Options({ [Options.NAME] : options.target }), targetRequiredType);
}
else {
return Promise.reject(
new Errors.ImptError(UserInteractor.ERRORS.TARGET_DG_NOT_FOUND, this._productionTarget.identifierInfo));
}
});
_processTarget(target, productId) {
if (target.isSpecified()) {
return target.findOrCreate(productId);
}
return Promise.resolve();
}

_getProductionTargetOptions() {
return this._productionTarget ?
{ [Entity.ATTR_ID] : this._productionTarget.id, [ATTR_TYPE] : this._productionTarget.type } :
_getTargetOptions(target) {
return target.deviceGroupId ?
{ [Entity.ATTR_ID] : target.deviceGroupId, [ATTR_TYPE] : target.deviceGroupType } :
null;
}

Expand All @@ -187,7 +162,14 @@ class DeviceGroup extends Entity {
// or rejects with an error
_update(options) {
return this.getEntity().
then(() => this._processProductionTarget(this.relatedProductId, this.type, options)).
then(() => {
this._productionTarget = new ProductionTarget(options, this.type);
return this._processTarget(this._productionTarget, this.relatedProductId);
}).
then(() => {
this._dutTarget = new DutTarget(options, this.type);
return this._processTarget(this._dutTarget, this.relatedProductId);
}).
then(() => {
if (options.loadCodeAfterBlessing !== undefined && !Options.isProductionDeviceGroupType(this.type)) {
return Promise.reject(new Errors.ImptError(
Expand Down Expand Up @@ -233,7 +215,11 @@ class DeviceGroup extends Entity {
if (options.loadCodeAfterBlessing !== undefined) {
attrs[ATTR_LOAD_CODE_AFTER_BLESSING] = options.loadCodeAfterBlessing;
}
return super._updateEntity(this.type, attrs, this._getProductionTargetOptions());
return super._updateEntity(
this.type,
attrs,
this._getTargetOptions(this._productionTarget),
this._getTargetOptions(this._dutTarget));
});
}

Expand Down Expand Up @@ -275,14 +261,14 @@ class DeviceGroup extends Entity {
});
}

_collectFullTargetInfo() {
if (Options.isProductionDeviceGroupType(this.type)) {
_collectFullTargetInfo(target) {
if (Options.isProductionDeviceGroupType(this.type) || Options.isDutDeviceGroupType(this.type)) {
const productId = this.relatedProductId;
return new DeviceGroup().listByProduct(productId).
then(devGroups => this._addRelatedEntities(
devGroups.filter((devGroup) => devGroup.productionTargetId === this.id),
devGroups.filter((devGroup) => this.id === target.getTargetId(devGroup)),
false,
UserInteractor.MESSAGES.DG_PRODUCTION_TARGET_FOR));
target.backRelationName));
}
return Promise.resolve();
}
Expand All @@ -301,7 +287,8 @@ class DeviceGroup extends Entity {
}

_collectFullInfo() {
return this._collectFullTargetInfo().
return this._collectFullTargetInfo(new ProductionTarget(null, this.type)).
then(() => this._collectFullTargetInfo(new DutTarget(null, this.type))).
then(() => this._collectFullWebhooksInfo()).
then(() => this._collectFullDevicesInfo());
}
Expand Down Expand Up @@ -538,6 +525,11 @@ class DeviceGroup extends Entity {
name : REL_PRODUCTION_TARGET,
Entity : DeviceGroup,
displayName : UserInteractor.MESSAGES.DG_PRODUCTION_TARGET,
},
{
name : REL_DUT_TARGET,
Entity : DeviceGroup,
displayName : UserInteractor.MESSAGES.DG_DUT_TARGET,
}
].concat(super._getInfoRelationships());
}
Expand All @@ -559,6 +551,11 @@ class DeviceGroup extends Entity {
name : REL_PRODUCTION_TARGET,
Entity : DeviceGroup,
displayName : UserInteractor.MESSAGES.DG_PRODUCTION_TARGET,
},
{
name : REL_DUT_TARGET,
Entity : DeviceGroup,
displayName : UserInteractor.MESSAGES.DG_DUT_TARGET,
}
];
}
Expand Down Expand Up @@ -616,6 +613,7 @@ class DeviceGroup extends Entity {
this._Entity = DeviceGroup;
this._identifier.init(Identifier.ENTITY_TYPE.TYPE_DEVICE_GROUP, [Entity.ATTR_NAME]);
this._productionTarget = null;
this._dutTarget = null;
}

// Sets the Device Group specific options based on impt command options:
Expand Down
Loading

0 comments on commit 6f034ae

Please sign in to comment.