eas-cli 3.18.3 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -64
- package/build/channel/branch-mapping.d.ts +6 -0
- package/build/channel/branch-mapping.js +10 -1
- package/build/channel/print-utils.js +1 -1
- package/build/channel/utils.d.ts +0 -10
- package/build/channel/utils.js +1 -60
- package/build/commands/channel/edit.js +1 -1
- package/build/commands/channel/rollout.d.ts +14 -2
- package/build/commands/channel/rollout.js +106 -270
- package/build/commands/update/republish.js +6 -6
- package/build/devices/actions/create/action.d.ts +2 -1
- package/build/devices/actions/create/action.js +10 -1
- package/build/devices/actions/create/currentMachineMethod.d.ts +3 -0
- package/build/devices/actions/create/currentMachineMethod.js +100 -0
- package/build/devices/actions/create/developerPortalMethod.js +2 -1
- package/build/devices/actions/create/inputMethod.d.ts +0 -1
- package/build/devices/actions/create/inputMethod.js +6 -64
- package/build/devices/actions/create/utils.d.ts +10 -0
- package/build/devices/actions/create/utils.js +73 -0
- package/build/devices/manager.js +3 -3
- package/build/devices/utils/errors.d.ts +3 -0
- package/build/devices/utils/errors.js +7 -1
- package/build/devices/utils/formatDevice.js +1 -0
- package/build/graphql/generated.d.ts +5 -4
- package/build/graphql/generated.js +1 -0
- package/build/graphql/types/credentials/AppleDevice.js +1 -0
- package/build/rollout/actions/CreateRollout.d.ts +2 -0
- package/build/rollout/actions/CreateRollout.js +82 -5
- package/build/rollout/actions/EditRollout.js +5 -2
- package/build/rollout/actions/EndRollout.d.ts +6 -3
- package/build/rollout/actions/EndRollout.js +22 -21
- package/build/rollout/actions/ManageRollout.d.ts +3 -3
- package/build/rollout/actions/ManageRollout.js +1 -1
- package/build/rollout/actions/NonInteractiveRollout.d.ts +6 -4
- package/build/rollout/actions/NonInteractiveRollout.js +1 -1
- package/build/rollout/actions/RolloutMainMenu.d.ts +4 -4
- package/build/rollout/actions/RolloutMainMenu.js +14 -5
- package/build/rollout/actions/SelectRuntime.d.ts +4 -7
- package/build/rollout/actions/SelectRuntime.js +22 -39
- package/build/rollout/branch-mapping.js +2 -2
- package/build/rollout/utils.d.ts +1 -1
- package/build/rollout/utils.js +5 -5
- package/build/update/republish.js +6 -6
- package/build/utils/relay.js +3 -9
- package/oclif.manifest.json +1 -1
- package/package.json +3 -3
- package/build/commands/channel/rollout-preview.d.ts +0 -32
- package/build/commands/channel/rollout-preview.js +0 -140
package/build/channel/utils.js
CHANGED
|
@@ -1,65 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getUpdateBranch =
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
|
-
const branch_mapping_1 = require("./branch-mapping");
|
|
7
|
-
/**
|
|
8
|
-
* Get the branch mapping and determine whether it is a rollout.
|
|
9
|
-
* Ensure that the branch mapping is properly formatted.
|
|
10
|
-
*/
|
|
11
|
-
function getBranchMapping(branchMappingString) {
|
|
12
|
-
var _a;
|
|
13
|
-
if (!branchMappingString) {
|
|
14
|
-
throw new Error('Missing branch mapping.');
|
|
15
|
-
}
|
|
16
|
-
let branchMapping;
|
|
17
|
-
try {
|
|
18
|
-
branchMapping = JSON.parse(branchMappingString);
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
throw new Error(`Could not parse branchMapping string into a JSON: "${branchMappingString}"`);
|
|
22
|
-
}
|
|
23
|
-
(0, assert_1.default)(branchMapping, 'Branch Mapping must be defined.');
|
|
24
|
-
if (branchMapping.version !== 0) {
|
|
25
|
-
throw new Error('Branch mapping must be version 0.');
|
|
26
|
-
}
|
|
27
|
-
const isRollout = branchMapping.data.length === 2;
|
|
28
|
-
const branchMappingNode = (_a = branchMapping.data[0]) === null || _a === void 0 ? void 0 : _a.branchMappingLogic;
|
|
29
|
-
let rolloutPercent;
|
|
30
|
-
if ((0, branch_mapping_1.isNodeObject)(branchMappingNode)) {
|
|
31
|
-
(0, branch_mapping_1.assertNumber)(branchMappingNode.operand);
|
|
32
|
-
rolloutPercent = branchMappingNode.operand;
|
|
33
|
-
}
|
|
34
|
-
switch (branchMapping.data.length) {
|
|
35
|
-
case 0:
|
|
36
|
-
break;
|
|
37
|
-
case 1:
|
|
38
|
-
if (branchMapping.data[0].branchMappingLogic !== 'true') {
|
|
39
|
-
throw new Error('Branch mapping logic for a single branch must be "true"');
|
|
40
|
-
}
|
|
41
|
-
break;
|
|
42
|
-
case 2:
|
|
43
|
-
(0, branch_mapping_1.assertNodeObject)(branchMappingNode);
|
|
44
|
-
if (branchMappingNode.clientKey !== 'rolloutToken') {
|
|
45
|
-
throw new Error('Client key of initial branch mapping must be "rolloutToken"');
|
|
46
|
-
}
|
|
47
|
-
if (branchMappingNode.branchMappingOperator !== 'hash_lt') {
|
|
48
|
-
throw new Error('Branch mapping operator of initial branch mapping must be "hash_lt"');
|
|
49
|
-
}
|
|
50
|
-
if (rolloutPercent == null) {
|
|
51
|
-
throw new Error('Branch mapping is missing a "rolloutPercent"');
|
|
52
|
-
}
|
|
53
|
-
if (branchMapping.data[1].branchMappingLogic !== 'true') {
|
|
54
|
-
throw new Error('Branch mapping logic for a the second branch of a rollout must be "true"');
|
|
55
|
-
}
|
|
56
|
-
break;
|
|
57
|
-
default:
|
|
58
|
-
throw new Error('Branch mapping data must have length less than or equal to 2.');
|
|
59
|
-
}
|
|
60
|
-
return { branchMapping, isRollout, rolloutPercent };
|
|
61
|
-
}
|
|
62
|
-
exports.getBranchMapping = getBranchMapping;
|
|
3
|
+
exports.getUpdateBranch = void 0;
|
|
63
4
|
function getUpdateBranchNullable(channel, branchId) {
|
|
64
5
|
const updateBranches = channel.updateBranches;
|
|
65
6
|
const updateBranch = updateBranches.find(branch => branch.id === branchId);
|
|
@@ -62,7 +62,7 @@ class ChannelEdit extends EasCommand_1.default {
|
|
|
62
62
|
if ((0, branch_mapping_2.isRollout)(existingChannel)) {
|
|
63
63
|
throw new Error('There is a rollout in progress. Manage it with "channel:rollout" instead.');
|
|
64
64
|
}
|
|
65
|
-
else if (!(0, branch_mapping_1.hasStandardBranchMap)(existingChannel)) {
|
|
65
|
+
else if (!(0, branch_mapping_1.hasStandardBranchMap)(existingChannel) && !(0, branch_mapping_1.hasEmptyBranchMap)(existingChannel)) {
|
|
66
66
|
throw new Error('Only standard branch mappings can be edited with this command.');
|
|
67
67
|
}
|
|
68
68
|
const branch = branchFlag
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import EasCommand from '../../commandUtils/EasCommand';
|
|
2
|
+
import { EndOutcome } from '../../rollout/actions/EndRollout';
|
|
3
|
+
declare enum ActionRawFlagValue {
|
|
4
|
+
CREATE = "create",
|
|
5
|
+
EDIT = "edit",
|
|
6
|
+
END = "end"
|
|
7
|
+
}
|
|
2
8
|
export default class ChannelRollout extends EasCommand {
|
|
3
9
|
static description: string;
|
|
4
10
|
static args: {
|
|
@@ -8,13 +14,19 @@ export default class ChannelRollout extends EasCommand {
|
|
|
8
14
|
static flags: {
|
|
9
15
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
16
|
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
|
-
|
|
17
|
+
action: import("@oclif/core/lib/interfaces").OptionFlag<ActionRawFlagValue | undefined>;
|
|
12
18
|
percent: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined>;
|
|
13
|
-
|
|
19
|
+
outcome: import("@oclif/core/lib/interfaces").OptionFlag<EndOutcome | undefined>;
|
|
20
|
+
branch: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
|
|
21
|
+
'runtime-version': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
|
|
22
|
+
'private-key-path': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
|
|
14
23
|
};
|
|
15
24
|
static contextDefinition: {
|
|
16
25
|
loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
|
|
17
26
|
privateProjectConfig: import("../../commandUtils/context/PrivateProjectConfigContextField").PrivateProjectConfigContextField;
|
|
18
27
|
};
|
|
19
28
|
runAsync(): Promise<void>;
|
|
29
|
+
private getAction;
|
|
30
|
+
private sanitizeArgsAndFlags;
|
|
20
31
|
}
|
|
32
|
+
export {};
|
|
@@ -3,262 +3,72 @@ var _a;
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
-
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
7
|
-
const queries_1 = require("../../branch/queries");
|
|
8
|
-
const branch_mapping_1 = require("../../channel/branch-mapping");
|
|
9
|
-
const queries_2 = require("../../channel/queries");
|
|
10
|
-
const utils_1 = require("../../channel/utils");
|
|
11
6
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
12
7
|
const flags_1 = require("../../commandUtils/flags");
|
|
13
|
-
const BranchQuery_1 = require("../../graphql/queries/BranchQuery");
|
|
14
|
-
const ChannelQuery_1 = require("../../graphql/queries/ChannelQuery");
|
|
15
8
|
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
},
|
|
27
|
-
message: promptMessage,
|
|
28
|
-
initial: 0,
|
|
29
|
-
validate: (rolloutPercent) => {
|
|
30
|
-
const floatValue = parseFloat(rolloutPercent);
|
|
31
|
-
return Number.isInteger(floatValue) && floatValue >= 0 && floatValue <= 100
|
|
32
|
-
? true
|
|
33
|
-
: 'The rollout percentage must be an integer between 0 and 100 inclusive.';
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
return rolloutPercent;
|
|
37
|
-
}
|
|
38
|
-
function getRolloutInfo(channel) {
|
|
39
|
-
var _b;
|
|
40
|
-
const { branchMapping } = (0, utils_1.getBranchMapping)(channel.branchMapping);
|
|
41
|
-
const [newBranchId, oldBranchId] = branchMapping.data.map(d => d.branchId);
|
|
42
|
-
const newBranch = channel.updateBranches.filter(branch => branch.id === newBranchId)[0];
|
|
43
|
-
const oldBranch = channel.updateBranches.filter(branch => branch.id === oldBranchId)[0];
|
|
44
|
-
if (!newBranch || !oldBranch) {
|
|
45
|
-
throw new Error(`Branch mapping rollout is missing a branch for channel "${channel.name}".`);
|
|
46
|
-
}
|
|
47
|
-
const branchMappingNode = (_b = branchMapping.data[0]) === null || _b === void 0 ? void 0 : _b.branchMappingLogic;
|
|
48
|
-
(0, branch_mapping_1.assertNodeObject)(branchMappingNode);
|
|
49
|
-
(0, branch_mapping_1.assertNumber)(branchMappingNode.operand);
|
|
50
|
-
const currentPercent = 100 * branchMappingNode.operand;
|
|
51
|
-
return { newBranch, oldBranch, currentPercent };
|
|
52
|
-
}
|
|
53
|
-
async function startRolloutAsync(graphqlClient, { channelName, branchName, percent, projectId, displayName, currentBranchMapping, channel, nonInteractive, }) {
|
|
54
|
-
const branch = await BranchQuery_1.BranchQuery.getBranchByNameAsync(graphqlClient, {
|
|
55
|
-
appId: projectId,
|
|
56
|
-
name: branchName,
|
|
57
|
-
});
|
|
58
|
-
const oldBranchId = currentBranchMapping.data[0].branchId;
|
|
59
|
-
if (branch.id === oldBranchId) {
|
|
60
|
-
throw new Error(`channel "${channelName}" is already pointing at branch "${branchName}". Rollouts must be done with distinct branches.`);
|
|
61
|
-
}
|
|
62
|
-
if (percent == null) {
|
|
63
|
-
if (nonInteractive) {
|
|
64
|
-
throw new Error('You must specify a percent with the --percent flag when initiating a rollout with the --non-interactive flag.');
|
|
65
|
-
}
|
|
66
|
-
const promptMessage = `What percent of users should be directed to the branch "${branchName}"?`;
|
|
67
|
-
percent = await promptForRolloutPercentAsync({ promptMessage });
|
|
68
|
-
}
|
|
69
|
-
const newBranchMapping = {
|
|
70
|
-
version: 0,
|
|
71
|
-
data: [
|
|
72
|
-
{
|
|
73
|
-
branchId: branch.id,
|
|
74
|
-
branchMappingLogic: {
|
|
75
|
-
operand: percent / 100,
|
|
76
|
-
clientKey: 'rolloutToken',
|
|
77
|
-
branchMappingOperator: 'hash_lt',
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
currentBranchMapping.data[0],
|
|
81
|
-
],
|
|
82
|
-
};
|
|
83
|
-
const newChannelInfo = await (0, edit_1.updateChannelBranchMappingAsync)(graphqlClient, {
|
|
84
|
-
channelId: channel.id,
|
|
85
|
-
branchMapping: JSON.stringify(newBranchMapping),
|
|
86
|
-
});
|
|
87
|
-
const oldBranch = channel.updateBranches.filter(branch => branch.id === oldBranchId)[0];
|
|
88
|
-
if (!oldBranch) {
|
|
89
|
-
throw new Error(`Branch mapping is missing its only branch for channel "${channelName}" on app "${displayName}"`);
|
|
90
|
-
}
|
|
91
|
-
const logMessage = `Started a rollout of branch ${chalk_1.default.bold(branchName)} on channel ${chalk_1.default.bold(channelName)}! ${chalk_1.default.bold(percent)}% of users will be directed to branch ${chalk_1.default.bold(branchName)}, ${chalk_1.default.bold(100 - percent)}% to branch ${chalk_1.default.bold(oldBranch.name)}.`;
|
|
92
|
-
return { newChannelInfo, logMessage };
|
|
93
|
-
}
|
|
94
|
-
async function editRolloutAsync(graphqlClient, { channelName, percent, nonInteractive, currentBranchMapping, channel, }) {
|
|
95
|
-
const { newBranch, oldBranch, currentPercent } = getRolloutInfo(channel);
|
|
96
|
-
if (percent == null) {
|
|
97
|
-
if (nonInteractive) {
|
|
98
|
-
throw new Error('A rollout is already in progress. If you wish to modify it you must use specify the new rollout percentage with the --percent flag.');
|
|
99
|
-
}
|
|
100
|
-
const promptMessage = `Currently ${currentPercent}% of all users are routed to branch ${newBranch.name} and ${100 - currentPercent}% of all users are routed to branch ${oldBranch.name}. What percent of users should be directed to the branch ${newBranch.name}?`;
|
|
101
|
-
percent = await promptForRolloutPercentAsync({ promptMessage });
|
|
102
|
-
}
|
|
103
|
-
const newBranchMapping = { ...currentBranchMapping };
|
|
104
|
-
newBranchMapping.data[0].branchMappingLogic.operand = percent / 100;
|
|
105
|
-
const newChannelInfo = await (0, edit_1.updateChannelBranchMappingAsync)(graphqlClient, {
|
|
106
|
-
channelId: channel.id,
|
|
107
|
-
branchMapping: JSON.stringify(newBranchMapping),
|
|
108
|
-
});
|
|
109
|
-
const logMessage = `Rollout of branch ${chalk_1.default.bold(newBranch.name)} on channel ${chalk_1.default.bold(channelName)} updated from ${chalk_1.default.bold(currentPercent)}% to ${chalk_1.default.bold(percent)}%. ${chalk_1.default.bold(percent)}% of users will be directed to branch ${chalk_1.default.bold(newBranch.name)}, ${chalk_1.default.bold(100 - percent)}% to branch ${chalk_1.default.bold(oldBranch.name)}.`;
|
|
110
|
-
return { newChannelInfo, logMessage };
|
|
111
|
-
}
|
|
112
|
-
async function endRolloutAsync(graphqlClient, { channelName, branchName, nonInteractive, projectId, channel, }) {
|
|
113
|
-
// end rollout
|
|
114
|
-
const { newBranch, oldBranch, currentPercent } = getRolloutInfo(channel);
|
|
115
|
-
let endOnNewBranch;
|
|
116
|
-
if (branchName) {
|
|
117
|
-
const branch = await BranchQuery_1.BranchQuery.getBranchByNameAsync(graphqlClient, {
|
|
118
|
-
appId: projectId,
|
|
119
|
-
name: branchName,
|
|
120
|
-
});
|
|
121
|
-
switch (branch.id) {
|
|
122
|
-
case newBranch.id:
|
|
123
|
-
endOnNewBranch = true;
|
|
124
|
-
break;
|
|
125
|
-
case oldBranch.id:
|
|
126
|
-
endOnNewBranch = false;
|
|
127
|
-
break;
|
|
128
|
-
default:
|
|
129
|
-
throw new Error(`The branch "${branchName}" specified by --branch must be one of the branches involved in the rollout: "${newBranch.name}" or "${oldBranch.name}".`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
if (nonInteractive) {
|
|
134
|
-
throw new Error('Branch name must be specified with the --branch flag when both the --end and --non-interactive flag are true.');
|
|
135
|
-
}
|
|
136
|
-
endOnNewBranch = await (0, prompts_1.selectAsync)('Ending the rollout will send all traffic to a single branch. Which one should that be?', [
|
|
137
|
-
{
|
|
138
|
-
title: `${newBranch.name} ${chalk_1.default.grey(`- current percent: ${currentPercent}%`)}`,
|
|
139
|
-
value: true,
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
title: `${oldBranch.name} ${chalk_1.default.grey(`- current percent: ${100 - currentPercent}%`)}`,
|
|
143
|
-
value: false,
|
|
144
|
-
},
|
|
145
|
-
]);
|
|
146
|
-
}
|
|
147
|
-
if (endOnNewBranch == null) {
|
|
148
|
-
throw new Error('Branch to end on is undefined.');
|
|
149
|
-
}
|
|
150
|
-
const newBranchMapping = {
|
|
151
|
-
version: 0,
|
|
152
|
-
data: [
|
|
153
|
-
{
|
|
154
|
-
branchId: endOnNewBranch ? newBranch.id : oldBranch.id,
|
|
155
|
-
branchMappingLogic: 'true',
|
|
156
|
-
},
|
|
157
|
-
],
|
|
158
|
-
};
|
|
159
|
-
const newChannelInfo = await (0, edit_1.updateChannelBranchMappingAsync)(graphqlClient, {
|
|
160
|
-
channelId: channel.id,
|
|
161
|
-
branchMapping: JSON.stringify(newBranchMapping),
|
|
162
|
-
});
|
|
163
|
-
const logMessage = `Rollout on channel ${chalk_1.default.bold(channelName)} ended. All traffic is now sent to branch ${chalk_1.default.bold(endOnNewBranch ? newBranch.name : oldBranch.name)}`;
|
|
164
|
-
return { newChannelInfo, logMessage };
|
|
165
|
-
}
|
|
9
|
+
const EndRollout_1 = require("../../rollout/actions/EndRollout");
|
|
10
|
+
const ManageRollout_1 = require("../../rollout/actions/ManageRollout");
|
|
11
|
+
const NonInteractiveRollout_1 = require("../../rollout/actions/NonInteractiveRollout");
|
|
12
|
+
const RolloutMainMenu_1 = require("../../rollout/actions/RolloutMainMenu");
|
|
13
|
+
var ActionRawFlagValue;
|
|
14
|
+
(function (ActionRawFlagValue) {
|
|
15
|
+
ActionRawFlagValue["CREATE"] = "create";
|
|
16
|
+
ActionRawFlagValue["EDIT"] = "edit";
|
|
17
|
+
ActionRawFlagValue["END"] = "end";
|
|
18
|
+
})(ActionRawFlagValue || (ActionRawFlagValue = {}));
|
|
166
19
|
class ChannelRollout extends EasCommand_1.default {
|
|
167
20
|
async runAsync() {
|
|
168
|
-
const { args
|
|
169
|
-
const
|
|
170
|
-
|
|
21
|
+
const { args, flags } = await this.parse(ChannelRollout);
|
|
22
|
+
const argsAndFlags = this.sanitizeArgsAndFlags({ ...flags, ...args });
|
|
23
|
+
const { privateProjectConfig: { exp, projectId }, loggedIn: { graphqlClient }, } = await this.getContextAsync(ChannelRollout, {
|
|
24
|
+
nonInteractive: argsAndFlags.nonInteractive,
|
|
171
25
|
});
|
|
172
|
-
if (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
},
|
|
186
|
-
});
|
|
187
|
-
channelName = name;
|
|
188
|
-
}
|
|
189
|
-
const channel = await ChannelQuery_1.ChannelQuery.viewUpdateChannelAsync(graphqlClient, {
|
|
190
|
-
appId: projectId,
|
|
191
|
-
channelName,
|
|
192
|
-
});
|
|
193
|
-
if (!channel) {
|
|
194
|
-
throw new Error(`Could not find a channel named "${channelName}". Check which channels exist on this project with ${chalk_1.default.bold('eas channel:list')}.`);
|
|
195
|
-
}
|
|
196
|
-
const { branchMapping: currentBranchMapping, isRollout } = (0, utils_1.getBranchMapping)(channel.branchMapping);
|
|
197
|
-
if (currentBranchMapping.data.length === 0) {
|
|
198
|
-
throw new Error('The channel is not pointing at any branches.');
|
|
199
|
-
}
|
|
200
|
-
if (currentBranchMapping.data.length > 2) {
|
|
201
|
-
throw new Error('"channel:rollout" cannot handle branch mappings with more than 2 branches.');
|
|
202
|
-
}
|
|
203
|
-
// This combination doesn't make sense. Throw an error explaining the options.
|
|
204
|
-
if (isRollout && branchName && !endFlag) {
|
|
205
|
-
throw new Error(`There is a rollout in progress. You can only either edit the rollout percent or 'end' it.`);
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* This if/else block has three branches:
|
|
209
|
-
* 1. The branch mapping is not a rollout, i.e. it is pointing to a single branch.
|
|
210
|
-
* 2. The branch mapping is a rollout.
|
|
211
|
-
* a. increase/decrease the rollout percentage.
|
|
212
|
-
* b. end the rollout.
|
|
213
|
-
*/
|
|
214
|
-
let rolloutMutationResult;
|
|
215
|
-
if (!isRollout) {
|
|
216
|
-
rolloutMutationResult = await startRolloutAsync(graphqlClient, {
|
|
217
|
-
channelName,
|
|
218
|
-
branchName: branchName !== null && branchName !== void 0 ? branchName : (await promptForBranchNameAsync({
|
|
219
|
-
graphqlClient,
|
|
220
|
-
projectId,
|
|
221
|
-
channelName,
|
|
222
|
-
nonInteractive,
|
|
223
|
-
json: jsonFlag,
|
|
224
|
-
})),
|
|
225
|
-
percent,
|
|
226
|
-
nonInteractive,
|
|
227
|
-
projectId,
|
|
228
|
-
displayName: projectDisplayName,
|
|
229
|
-
currentBranchMapping,
|
|
230
|
-
channel,
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
else if (endFlag) {
|
|
234
|
-
rolloutMutationResult = await endRolloutAsync(graphqlClient, {
|
|
235
|
-
channelName,
|
|
236
|
-
branchName,
|
|
237
|
-
nonInteractive,
|
|
238
|
-
projectId,
|
|
239
|
-
channel,
|
|
240
|
-
});
|
|
26
|
+
if (argsAndFlags.json) {
|
|
27
|
+
// TODO(quin): implement json output
|
|
28
|
+
throw new Error('Developer Preview doesnt support JSON output yet');
|
|
29
|
+
}
|
|
30
|
+
const app = { projectId, exp };
|
|
31
|
+
const ctx = {
|
|
32
|
+
projectId,
|
|
33
|
+
nonInteractive: argsAndFlags.nonInteractive,
|
|
34
|
+
graphqlClient,
|
|
35
|
+
app,
|
|
36
|
+
};
|
|
37
|
+
if (argsAndFlags.nonInteractive) {
|
|
38
|
+
await new NonInteractiveRollout_1.NonInteractiveRollout(argsAndFlags).runAsync(ctx);
|
|
241
39
|
}
|
|
242
40
|
else {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
currentBranchMapping,
|
|
248
|
-
channel,
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
if (!rolloutMutationResult) {
|
|
252
|
-
throw new Error('rollout result is empty');
|
|
41
|
+
log_1.default.addNewLineIfNone();
|
|
42
|
+
log_1.default.warn(`✨ This command is in Developer Preview and has not been released to production yet`);
|
|
43
|
+
log_1.default.addNewLineIfNone();
|
|
44
|
+
await new RolloutMainMenu_1.RolloutMainMenu(argsAndFlags).runAsync(ctx);
|
|
253
45
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
46
|
+
}
|
|
47
|
+
getAction(action) {
|
|
48
|
+
switch (action) {
|
|
49
|
+
case ActionRawFlagValue.CREATE:
|
|
50
|
+
return RolloutMainMenu_1.MainMenuActions.CREATE_NEW;
|
|
51
|
+
case ActionRawFlagValue.EDIT:
|
|
52
|
+
return ManageRollout_1.ManageRolloutActions.EDIT;
|
|
53
|
+
case ActionRawFlagValue.END:
|
|
54
|
+
return ManageRollout_1.ManageRolloutActions.END;
|
|
260
55
|
}
|
|
261
56
|
}
|
|
57
|
+
sanitizeArgsAndFlags(rawFlags) {
|
|
58
|
+
var _b;
|
|
59
|
+
const action = rawFlags.action;
|
|
60
|
+
return {
|
|
61
|
+
channelName: rawFlags.channel,
|
|
62
|
+
percent: rawFlags.percent,
|
|
63
|
+
outcome: rawFlags.outcome,
|
|
64
|
+
branchNameToRollout: rawFlags.branch,
|
|
65
|
+
runtimeVersion: rawFlags['runtime-version'],
|
|
66
|
+
privateKeyPath: (_b = rawFlags['private-key-path']) !== null && _b !== void 0 ? _b : null,
|
|
67
|
+
action: action ? this.getAction(action) : undefined,
|
|
68
|
+
nonInteractive: rawFlags['non-interactive'],
|
|
69
|
+
json: rawFlags.json,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
262
72
|
}
|
|
263
73
|
exports.default = ChannelRollout;
|
|
264
74
|
_a = ChannelRollout;
|
|
@@ -270,17 +80,62 @@ ChannelRollout.args = [
|
|
|
270
80
|
},
|
|
271
81
|
];
|
|
272
82
|
ChannelRollout.flags = {
|
|
273
|
-
|
|
274
|
-
description: '
|
|
83
|
+
action: core_1.Flags.enum({
|
|
84
|
+
description: 'Rollout action to perform',
|
|
85
|
+
options: Object.values(ActionRawFlagValue),
|
|
275
86
|
required: false,
|
|
87
|
+
relationships: [
|
|
88
|
+
{
|
|
89
|
+
type: 'all',
|
|
90
|
+
flags: [
|
|
91
|
+
{
|
|
92
|
+
name: 'percent',
|
|
93
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
94
|
+
when: async (flags) => {
|
|
95
|
+
return (!!flags['non-interactive'] &&
|
|
96
|
+
(flags['action'] === ActionRawFlagValue.CREATE ||
|
|
97
|
+
flags['action'] === ActionRawFlagValue.EDIT));
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'outcome',
|
|
102
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
103
|
+
when: async (flags) => !!flags['non-interactive'] && flags['action'] === ActionRawFlagValue.END,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'branch',
|
|
107
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
108
|
+
when: async (flags) => !!flags['non-interactive'] && flags['action'] === ActionRawFlagValue.CREATE,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'runtime-version',
|
|
112
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
113
|
+
when: async (flags) => !!flags['non-interactive'] && flags['action'] === ActionRawFlagValue.CREATE,
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
],
|
|
276
118
|
}),
|
|
277
119
|
percent: core_1.Flags.integer({
|
|
278
|
-
description: '
|
|
120
|
+
description: 'Percent of users to send to the new branch. Use with --action=edit or --action=create',
|
|
279
121
|
required: false,
|
|
280
122
|
}),
|
|
281
|
-
|
|
282
|
-
description: '
|
|
283
|
-
|
|
123
|
+
outcome: core_1.Flags.enum({
|
|
124
|
+
description: 'End outcome of rollout. Use with --action=end',
|
|
125
|
+
options: Object.values(EndRollout_1.EndOutcome),
|
|
126
|
+
required: false,
|
|
127
|
+
}),
|
|
128
|
+
branch: core_1.Flags.string({
|
|
129
|
+
description: 'Branch to roll out. Use with --action=create',
|
|
130
|
+
required: false,
|
|
131
|
+
}),
|
|
132
|
+
'runtime-version': core_1.Flags.string({
|
|
133
|
+
description: 'Runtime version to target. Use with --action=create',
|
|
134
|
+
required: false,
|
|
135
|
+
}),
|
|
136
|
+
'private-key-path': core_1.Flags.string({
|
|
137
|
+
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`,
|
|
138
|
+
required: false,
|
|
284
139
|
}),
|
|
285
140
|
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
286
141
|
};
|
|
@@ -288,22 +143,3 @@ ChannelRollout.contextDefinition = {
|
|
|
288
143
|
..._a.ContextOptions.ProjectConfig,
|
|
289
144
|
..._a.ContextOptions.LoggedIn,
|
|
290
145
|
};
|
|
291
|
-
async function promptForBranchNameAsync({ graphqlClient, projectId, channelName, nonInteractive, json, }) {
|
|
292
|
-
if (nonInteractive) {
|
|
293
|
-
throw new Error('Must supply branch flag in non-interactive mode');
|
|
294
|
-
}
|
|
295
|
-
const { name: branchName } = await (0, queries_1.selectBranchOnAppAsync)(graphqlClient, {
|
|
296
|
-
projectId,
|
|
297
|
-
promptTitle: `Which branch would you like roll out on ${channelName}?`,
|
|
298
|
-
displayTextForListItem: updateBranch => ({
|
|
299
|
-
title: updateBranch.name,
|
|
300
|
-
}),
|
|
301
|
-
// discard limit and offset because this query is not their intended target
|
|
302
|
-
paginatedQueryOptions: {
|
|
303
|
-
json,
|
|
304
|
-
nonInteractive,
|
|
305
|
-
offset: 0,
|
|
306
|
-
},
|
|
307
|
-
});
|
|
308
|
-
return branchName;
|
|
309
|
-
}
|
|
@@ -36,14 +36,14 @@ class UpdateRepublish extends EasCommand_1.default {
|
|
|
36
36
|
throw new Error(`There are no updates on branch "${existingUpdates[0].branchName}" published for the platform(s) "${rawFlags.platform}" with group ID "${flags.groupId ? flags.groupId : updatesToPublish[0].groupId}". Did you mean to publish a new update instead?`);
|
|
37
37
|
}
|
|
38
38
|
if (rawFlags.platform === 'all') {
|
|
39
|
-
log_1.default.withTick(`The republished update will appear only on: ${rawFlags.platform}`);
|
|
39
|
+
log_1.default.withTick(`The republished update group will appear only on: ${rawFlags.platform}`);
|
|
40
40
|
}
|
|
41
41
|
else {
|
|
42
42
|
const platformsFromUpdates = updatesToPublish.map(update => update.platform);
|
|
43
43
|
if (platformsFromUpdates.length < defaultRepublishPlatforms.length) {
|
|
44
|
-
log_1.default.warn(`You are republishing an update that wasn't published for all platforms.`);
|
|
44
|
+
log_1.default.warn(`You are republishing an update group that wasn't published for all platforms.`);
|
|
45
45
|
}
|
|
46
|
-
log_1.default.withTick(`The republished update will appear on the same platforms it was originally published on: ${platformsFromUpdates.join(', ')}`);
|
|
46
|
+
log_1.default.withTick(`The republished update group will appear on the same platforms it was originally published on: ${platformsFromUpdates.join(', ')}`);
|
|
47
47
|
}
|
|
48
48
|
const updateMessage = await getOrAskUpdateMessageAsync(updatesToPublish, flags);
|
|
49
49
|
const arbitraryUpdate = updatesToPublish[0];
|
|
@@ -88,11 +88,11 @@ _a = UpdateRepublish;
|
|
|
88
88
|
UpdateRepublish.description = 'roll back to an existing update';
|
|
89
89
|
UpdateRepublish.flags = {
|
|
90
90
|
channel: core_1.Flags.string({
|
|
91
|
-
description: 'Channel name to select an update to republish from',
|
|
91
|
+
description: 'Channel name to select an update group to republish from',
|
|
92
92
|
exclusive: ['branch', 'group'],
|
|
93
93
|
}),
|
|
94
94
|
branch: core_1.Flags.string({
|
|
95
|
-
description: 'Branch name to select an update to republish from',
|
|
95
|
+
description: 'Branch name to select an update group to republish from',
|
|
96
96
|
exclusive: ['channel', 'group'],
|
|
97
97
|
}),
|
|
98
98
|
group: core_1.Flags.string({
|
|
@@ -101,7 +101,7 @@ UpdateRepublish.flags = {
|
|
|
101
101
|
}),
|
|
102
102
|
message: core_1.Flags.string({
|
|
103
103
|
char: 'm',
|
|
104
|
-
description: 'Short message describing the republished update',
|
|
104
|
+
description: 'Short message describing the republished update group',
|
|
105
105
|
required: false,
|
|
106
106
|
}),
|
|
107
107
|
platform: core_1.Flags.enum({
|
|
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
6
6
|
const log_1 = tslib_1.__importDefault(require("../../../log"));
|
|
7
7
|
const prompts_1 = require("../../../prompts");
|
|
8
|
+
const currentMachineMethod_1 = require("./currentMachineMethod");
|
|
8
9
|
const developerPortalMethod_1 = require("./developerPortalMethod");
|
|
9
10
|
const inputMethod_1 = require("./inputMethod");
|
|
10
11
|
const registrationUrlMethod_1 = require("./registrationUrlMethod");
|
|
@@ -13,7 +14,8 @@ var RegistrationMethod;
|
|
|
13
14
|
RegistrationMethod[RegistrationMethod["WEBSITE"] = 0] = "WEBSITE";
|
|
14
15
|
RegistrationMethod[RegistrationMethod["INPUT"] = 1] = "INPUT";
|
|
15
16
|
RegistrationMethod[RegistrationMethod["DEVELOPER_PORTAL"] = 2] = "DEVELOPER_PORTAL";
|
|
16
|
-
RegistrationMethod[RegistrationMethod["
|
|
17
|
+
RegistrationMethod[RegistrationMethod["CURRENT_MACHINE"] = 3] = "CURRENT_MACHINE";
|
|
18
|
+
RegistrationMethod[RegistrationMethod["EXIT"] = 4] = "EXIT";
|
|
17
19
|
})(RegistrationMethod = exports.RegistrationMethod || (exports.RegistrationMethod = {}));
|
|
18
20
|
class DeviceCreateAction {
|
|
19
21
|
constructor(graphqlClient, appStoreApi, account, appleTeam) {
|
|
@@ -33,6 +35,9 @@ class DeviceCreateAction {
|
|
|
33
35
|
else if (method === RegistrationMethod.INPUT) {
|
|
34
36
|
await (0, inputMethod_1.runInputMethodAsync)(this.graphqlClient, this.account.id, this.appleTeam);
|
|
35
37
|
}
|
|
38
|
+
else if (method === RegistrationMethod.CURRENT_MACHINE) {
|
|
39
|
+
await (0, currentMachineMethod_1.runCurrentMachineMethodAsync)(this.graphqlClient, this.account.id, this.appleTeam);
|
|
40
|
+
}
|
|
36
41
|
else if (method === RegistrationMethod.EXIT) {
|
|
37
42
|
log_1.default.log('Bye!');
|
|
38
43
|
process.exit(0);
|
|
@@ -57,6 +62,10 @@ class DeviceCreateAction {
|
|
|
57
62
|
title: `${chalk_1.default.bold('Input')} - allows you to type in UDIDs (advanced option)`,
|
|
58
63
|
value: RegistrationMethod.INPUT,
|
|
59
64
|
},
|
|
65
|
+
{
|
|
66
|
+
title: `${chalk_1.default.bold('Current Machine')} - automatically sets the provisioning UDID of the current Apple Silicon machine`,
|
|
67
|
+
value: RegistrationMethod.CURRENT_MACHINE,
|
|
68
|
+
},
|
|
60
69
|
{ title: chalk_1.default.bold('Exit'), value: RegistrationMethod.EXIT },
|
|
61
70
|
],
|
|
62
71
|
validate: (val) => Object.values(RegistrationMethod).includes(val),
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
|
|
2
|
+
import { AppleTeam } from '../../../graphql/generated';
|
|
3
|
+
export declare function runCurrentMachineMethodAsync(graphqlClient: ExpoGraphqlClient, accountId: string, appleTeam: Pick<AppleTeam, 'appleTeamIdentifier' | 'appleTeamName' | 'id'>): Promise<void>;
|