Skip to content

Commit 6f034ae

Browse files
author
betzrhodes
authored
Merge pull request #56 from electricimp/develop
v2.5.0
2 parents 007b6ec + a3b1e49 commit 6f034ae

18 files changed

+541
-156
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/node_modules

Diff for: CommandsManual.md

+25-9
Large diffs are not rendered by default.

Diff for: DevelopmentGuide.md

+85-23
Large diffs are not rendered by default.

Diff for: LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright 2018 Electric Imp
3+
Copyright 2018-2019 Electric Imp
44

55
SPDX-License-Identifier: MIT
66

Diff for: ProductionGuide.md

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# impt Production Guide #
22

3+
**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.
4+
35
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.
46

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

4547
### Production Device Groups ###
4648

47-
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).
49+
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).
4850

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

5153
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:
5254

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

6567
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:
66-
68+
6769
```
68-
impt dg create --name MyFactoryDG --descr "Factory Device Group for factory firmware"
70+
impt dg create --name MyFactoryDG --descr "Factory Device Group for factory firmware"
6971
--dg-type factory --product MyProduct --target MyProductionDG
70-
```
72+
```
7173

7274
## Deployments ##
7375

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

87-
```
89+
```
8890
impt build copy --build MyFactoryRC1 --dg MyFactoryDG
8991
```
9092

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

99101
```
100102
impt device assign --device <device_id> --dg MyFactoryDG
101-
```
103+
```
102104

103105
### Devices Under Test (DUTs) ###
104106

Diff for: bin/cmds/dg/create.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// MIT License
22
//
3-
// Copyright 2018 Electric Imp
3+
// Copyright 2018-2019 Electric Imp
44
//
55
// SPDX-License-Identifier: MIT
66
//
@@ -59,6 +59,13 @@ exports.builder = function (yargs) {
5959
describe : 'An optional description of the Device Group.',
6060
_usage : '<device_group_description>'
6161
},
62+
[Options.DUT] : {
63+
demandOption : false,
64+
describe : Util.format("The Device Group identifier of the new Device Group's device-under-test target Device Group." +
65+
" Should only be specified if the new Device Group is of the %s or %s type." +
66+
" The device-under-test target Device Group must be of the type %s or %s correspondingly, and belong to the specified Product.",
67+
Options.DG_TYPE_FACTORY, Options.DG_TYPE_PRE_FACTORY, Options.DG_TYPE_DUT, Options.DG_TYPE_PRE_DUT)
68+
},
6269
[Options.TARGET] : {
6370
demandOption : false,
6471
describe : Util.format("The Device Group identifier of the new Device Group's production target Device Group." +
@@ -74,7 +81,11 @@ exports.builder = function (yargs) {
7481
.options(options)
7582
.check(function (argv) {
7683
const opts = new Options(argv);
77-
if (!opts.target && Options.isProductionTargetRequired(opts.deviceGroupType)) {
84+
if (!opts.dut && Options.isTargetRequired(opts.deviceGroupType)) {
85+
return new Errors.ImptError(UserInteractor.ERRORS.CMD_TARGET_REQUIRED,
86+
Options.DUT, Options.getDeviceGroupTypeName(opts.deviceGroupType));
87+
}
88+
if (!opts.target && Options.isTargetRequired(opts.deviceGroupType)) {
7889
return new Errors.ImptError(UserInteractor.ERRORS.CMD_TARGET_REQUIRED,
7990
Options.TARGET, Options.getDeviceGroupTypeName(opts.deviceGroupType));
8091
}

Diff for: bin/cmds/dg/update.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// MIT License
22
//
3-
// Copyright 2018 Electric Imp
3+
// Copyright 2018-2019 Electric Imp
44
//
55
// SPDX-License-Identifier: MIT
66
//
@@ -50,6 +50,14 @@ exports.builder = function (yargs) {
5050
describe : 'An optional description of the Device Group.',
5151
_usage : '<device_group_description>'
5252
},
53+
[Options.DUT] : {
54+
demandOption : false,
55+
describe : Util.format("The Device Group identifier of the specified Device Group's device-under-test target Device Group." +
56+
" May only be specified for %s and %s Device Groups." +
57+
" The device-under-test target Device Group must be of the type %s or %s correspondingly," +
58+
" and belong to the same Product as the specified Device Group.",
59+
Options.DG_TYPE_FACTORY, Options.DG_TYPE_PRE_FACTORY, Options.DG_TYPE_DUT, Options.DG_TYPE_PRE_DUT)
60+
},
5361
[Options.TARGET] : {
5462
demandOption : false,
5563
describe : Util.format("The Device Group identifier of the specified Device Group's production target Device Group." +

Diff for: bin/cmds/project/create.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// MIT License
22
//
3-
// Copyright 2018 Electric Imp
3+
// Copyright 2018-2019 Electric Imp
44
//
55
// SPDX-License-Identifier: MIT
66
//
@@ -65,6 +65,14 @@ exports.builder = function (yargs) {
6565
default: 'agent.nut'
6666
},
6767
[Options.PRE_FACTORY] : false,
68+
[Options.DUT] : {
69+
demandOption : false,
70+
describe : Util.format("The Device Group identifier of the new Project Device Group's device-under-test target Device Group." +
71+
" May be specified only if --%s is also specified." +
72+
" The specified Device Group must be of the type %s and belong to the specified Product.",
73+
Options.PRE_FACTORY, Options.DG_TYPE_PRE_DUT)
74+
},
75+
[Options.CREATE_DUT] : false,
6876
[Options.TARGET] : {
6977
demandOption : false,
7078
describe : Util.format("The Device Group identifier of the new Project Device Group's production target Device Group." +
@@ -84,6 +92,9 @@ exports.builder = function (yargs) {
8492
if (opts.preFactory && !opts.target || !opts.preFactory && opts.target) {
8593
return new Errors.CommandSyntaxError(UserInteractor.ERRORS.CMD_COOPERATIVE_OPTIONS, Options.PRE_FACTORY, Options.TARGET);
8694
}
95+
if (opts.preFactory && !opts.dut || !opts.preFactory && opts.dut) {
96+
return new Errors.CommandSyntaxError(UserInteractor.ERRORS.CMD_COOPERATIVE_OPTIONS, Options.PRE_FACTORY, Options.DUT);
97+
}
8798
return Options.checkOptions(argv, options);
8899
})
89100
.strict();

Diff for: bin/cmds/project/update.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// MIT License
22
//
3-
// Copyright 2018 Electric Imp
3+
// Copyright 2018-2019 Electric Imp
44
//
55
// SPDX-License-Identifier: MIT
66
//
@@ -60,6 +60,13 @@ exports.builder = function (yargs) {
6060
demandOption : false,
6161
describe: 'A new agent source code file name. If the file does not exist, an empty file is created.'
6262
},
63+
[Options.DUT] : {
64+
demandOption : false,
65+
describe : Util.format("The Device Group identifier of the Project Device Group's device-under-test target Device Group." +
66+
" May only be specified if the Project Device Group is of the %s type." +
67+
" 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.",
68+
Options.DG_TYPE_PRE_FACTORY, Options.DG_TYPE_PRE_DUT)
69+
},
6370
[Options.TARGET] : {
6471
demandOption : false,
6572
describe : Util.format("The Device Group identifier of the Project Device Group's production target Device Group." +

Diff for: lib/DeviceGroup.js

+58-60
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// MIT License
22
//
3-
// Copyright 2018 Electric Imp
3+
// Copyright 2018-2019 Electric Imp
44
//
55
// SPDX-License-Identifier: MIT
66
//
@@ -32,6 +32,8 @@ const ListHelper = require('./util/ListHelper');
3232
const DeleteHelper = require('./util/DeleteHelper');
3333
const UserInteractor = require('./util/UserInteractor');
3434
const Identifier = require('./util/Identifier');
35+
const ProductionTarget = require('./util/Target').ProductionTarget;
36+
const DutTarget = require('./util/Target').DutTarget;
3537
const Entity = require('./util/Entity');
3638
const Options = require('./util/Options');
3739
const Errors = require('./util/Errors');
@@ -47,6 +49,7 @@ const ATTR_REGION = 'region';
4749
const REL_CURRENT_DEPLOYMENT = 'current_deployment';
4850
const REL_MIN_SUPPORTED_DEPLOYMENT = 'min_supported_deployment';
4951
const REL_PRODUCTION_TARGET = 'production_target';
52+
const REL_DUT_TARGET = 'dut_target';
5053

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

86+
// Returns the DUT target Device Group, if exists
87+
get dutTargetId() {
88+
if (REL_DUT_TARGET in this.apiEntity.relationships) {
89+
return this.apiEntity.relationships[REL_DUT_TARGET].id;
90+
}
91+
return undefined;
92+
}
93+
8394
// Returns the Device Group related Product id
8495
get relatedProductId() {
8596
return this.apiEntity.relationships[Entity.REL_PRODUCT].id;
@@ -106,7 +117,10 @@ class DeviceGroup extends Entity {
106117

107118
_createByProductId(productId, options, deviceGroupType) {
108119
const dgType = deviceGroupType ? deviceGroupType : options.deviceGroupType;
109-
return this._processProductionTarget(productId, dgType, options).
120+
this._productionTarget = new ProductionTarget(options, dgType);
121+
this._dutTarget = new DutTarget(options, dgType);
122+
return this._processTarget(this._productionTarget, productId).
123+
then(() => this._processTarget(this._dutTarget, productId)).
110124
then(() => {
111125
const attrs = {
112126
[Entity.ATTR_NAME] : options.name,
@@ -116,64 +130,25 @@ class DeviceGroup extends Entity {
116130
attrs[ATTR_REGION] = options.region;
117131
}
118132
this.initByName(options.name);
119-
return super._createEntity(productId, dgType, attrs, this._getProductionTargetOptions());
133+
return super._createEntity(
134+
productId,
135+
dgType,
136+
attrs,
137+
this._getTargetOptions(this._productionTarget),
138+
this._getTargetOptions(this._dutTarget));
120139
});
121140
}
122141

123-
_getProductionTargetType(deviceGroupType) {
124-
switch (deviceGroupType) {
125-
case DeviceGroups.TYPE_PRE_FACTORY_FIXTURE:
126-
return DeviceGroups.TYPE_PRE_PRODUCTION;
127-
case DeviceGroups.TYPE_FACTORY_FIXTURE:
128-
return DeviceGroups.TYPE_PRODUCTION;
129-
}
130-
return null;
131-
}
132-
133-
_processProductionTarget(productId, deviceGroupType, options) {
134-
if (options.target) {
135-
if (!Options.isProductionTargetRequired(deviceGroupType)) {
136-
return Promise.reject(new Errors.ImptError(
137-
UserInteractor.ERRORS.WRONG_DG_TYPE_FOR_OPTION,
138-
Options.TARGET,
139-
Options.getDeviceGroupTypeName(deviceGroupType),
140-
Options.getDeviceGroupTypeName(DeviceGroups.TYPE_PRE_FACTORY_FIXTURE),
141-
Options.getDeviceGroupTypeName(DeviceGroups.TYPE_FACTORY_FIXTURE)));
142-
}
143-
this._productionTarget = new DeviceGroup();
144-
return this._productionTarget.initByIdentifier(options.target).findEntity().then(entity => {
145-
const targetRequiredType = this._getProductionTargetType(deviceGroupType);
146-
if (entity) {
147-
if (this._productionTarget.type !== targetRequiredType) {
148-
return Promise.reject(
149-
new Errors.ImptError(
150-
UserInteractor.ERRORS.TARGET_DG_WRONG_TYPE,
151-
this._productionTarget.identifierInfo,
152-
Options.getDeviceGroupTypeName(this._productionTarget.type),
153-
Options.getDeviceGroupTypeName(targetRequiredType)));
154-
}
155-
else if (this._productionTarget.relatedProductId !== productId) {
156-
return Promise.reject(
157-
new Errors.ImptError(UserInteractor.ERRORS.TARGET_DG_WRONG_PRODUCT));
158-
}
159-
return Promise.resolve();
160-
}
161-
else if (options.createTarget) {
162-
return this._productionTarget._createByProductId(
163-
productId, new Options({ [Options.NAME] : options.target }), targetRequiredType);
164-
}
165-
else {
166-
return Promise.reject(
167-
new Errors.ImptError(UserInteractor.ERRORS.TARGET_DG_NOT_FOUND, this._productionTarget.identifierInfo));
168-
}
169-
});
142+
_processTarget(target, productId) {
143+
if (target.isSpecified()) {
144+
return target.findOrCreate(productId);
170145
}
171146
return Promise.resolve();
172147
}
173148

174-
_getProductionTargetOptions() {
175-
return this._productionTarget ?
176-
{ [Entity.ATTR_ID] : this._productionTarget.id, [ATTR_TYPE] : this._productionTarget.type } :
149+
_getTargetOptions(target) {
150+
return target.deviceGroupId ?
151+
{ [Entity.ATTR_ID] : target.deviceGroupId, [ATTR_TYPE] : target.deviceGroupType } :
177152
null;
178153
}
179154

@@ -187,7 +162,14 @@ class DeviceGroup extends Entity {
187162
// or rejects with an error
188163
_update(options) {
189164
return this.getEntity().
190-
then(() => this._processProductionTarget(this.relatedProductId, this.type, options)).
165+
then(() => {
166+
this._productionTarget = new ProductionTarget(options, this.type);
167+
return this._processTarget(this._productionTarget, this.relatedProductId);
168+
}).
169+
then(() => {
170+
this._dutTarget = new DutTarget(options, this.type);
171+
return this._processTarget(this._dutTarget, this.relatedProductId);
172+
}).
191173
then(() => {
192174
if (options.loadCodeAfterBlessing !== undefined && !Options.isProductionDeviceGroupType(this.type)) {
193175
return Promise.reject(new Errors.ImptError(
@@ -233,7 +215,11 @@ class DeviceGroup extends Entity {
233215
if (options.loadCodeAfterBlessing !== undefined) {
234216
attrs[ATTR_LOAD_CODE_AFTER_BLESSING] = options.loadCodeAfterBlessing;
235217
}
236-
return super._updateEntity(this.type, attrs, this._getProductionTargetOptions());
218+
return super._updateEntity(
219+
this.type,
220+
attrs,
221+
this._getTargetOptions(this._productionTarget),
222+
this._getTargetOptions(this._dutTarget));
237223
});
238224
}
239225

@@ -275,14 +261,14 @@ class DeviceGroup extends Entity {
275261
});
276262
}
277263

278-
_collectFullTargetInfo() {
279-
if (Options.isProductionDeviceGroupType(this.type)) {
264+
_collectFullTargetInfo(target) {
265+
if (Options.isProductionDeviceGroupType(this.type) || Options.isDutDeviceGroupType(this.type)) {
280266
const productId = this.relatedProductId;
281267
return new DeviceGroup().listByProduct(productId).
282268
then(devGroups => this._addRelatedEntities(
283-
devGroups.filter((devGroup) => devGroup.productionTargetId === this.id),
269+
devGroups.filter((devGroup) => this.id === target.getTargetId(devGroup)),
284270
false,
285-
UserInteractor.MESSAGES.DG_PRODUCTION_TARGET_FOR));
271+
target.backRelationName));
286272
}
287273
return Promise.resolve();
288274
}
@@ -301,7 +287,8 @@ class DeviceGroup extends Entity {
301287
}
302288

303289
_collectFullInfo() {
304-
return this._collectFullTargetInfo().
290+
return this._collectFullTargetInfo(new ProductionTarget(null, this.type)).
291+
then(() => this._collectFullTargetInfo(new DutTarget(null, this.type))).
305292
then(() => this._collectFullWebhooksInfo()).
306293
then(() => this._collectFullDevicesInfo());
307294
}
@@ -538,6 +525,11 @@ class DeviceGroup extends Entity {
538525
name : REL_PRODUCTION_TARGET,
539526
Entity : DeviceGroup,
540527
displayName : UserInteractor.MESSAGES.DG_PRODUCTION_TARGET,
528+
},
529+
{
530+
name : REL_DUT_TARGET,
531+
Entity : DeviceGroup,
532+
displayName : UserInteractor.MESSAGES.DG_DUT_TARGET,
541533
}
542534
].concat(super._getInfoRelationships());
543535
}
@@ -559,6 +551,11 @@ class DeviceGroup extends Entity {
559551
name : REL_PRODUCTION_TARGET,
560552
Entity : DeviceGroup,
561553
displayName : UserInteractor.MESSAGES.DG_PRODUCTION_TARGET,
554+
},
555+
{
556+
name : REL_DUT_TARGET,
557+
Entity : DeviceGroup,
558+
displayName : UserInteractor.MESSAGES.DG_DUT_TARGET,
562559
}
563560
];
564561
}
@@ -616,6 +613,7 @@ class DeviceGroup extends Entity {
616613
this._Entity = DeviceGroup;
617614
this._identifier.init(Identifier.ENTITY_TYPE.TYPE_DEVICE_GROUP, [Entity.ATTR_NAME]);
618615
this._productionTarget = null;
616+
this._dutTarget = null;
619617
}
620618

621619
// Sets the Device Group specific options based on impt command options:

0 commit comments

Comments
 (0)