eas-cli 3.18.0 → 3.18.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 +55 -55
- package/build/branch/actions/SelectBranch.d.ts +33 -0
- package/build/branch/actions/SelectBranch.js +67 -0
- package/build/channel/actions/SelectChannel.d.ts +16 -0
- package/build/channel/actions/SelectChannel.js +42 -24
- package/build/channel/branch-mapping.d.ts +17 -1
- package/build/channel/branch-mapping.js +48 -7
- package/build/channel/queries.d.ts +1 -6
- package/build/channel/queries.js +1 -25
- package/build/commands/channel/rollout-preview.d.ts +32 -0
- package/build/commands/channel/rollout-preview.js +109 -0
- package/build/commands/update/republish.js +23 -74
- package/build/graphql/generated.d.ts +192 -18
- package/build/graphql/generated.js +8 -2
- package/build/graphql/queries/BranchQuery.d.ts +3 -2
- package/build/graphql/queries/BranchQuery.js +43 -1
- package/build/graphql/queries/ChannelQuery.d.ts +3 -2
- package/build/graphql/queries/ChannelQuery.js +19 -5
- package/build/graphql/queries/RuntimeQuery.d.ts +6 -0
- package/build/graphql/queries/RuntimeQuery.js +70 -0
- package/build/graphql/types/Runtime.d.ts +1 -0
- package/build/graphql/types/Runtime.js +11 -0
- package/build/graphql/types/UpdateBranch.js +3 -1
- package/build/graphql/types/UpdateBranchBasicInfo.d.ts +1 -0
- package/build/graphql/types/UpdateBranchBasicInfo.js +11 -0
- package/build/rollout/actions/CreateRollout.d.ts +23 -0
- package/build/rollout/actions/CreateRollout.js +153 -0
- package/build/rollout/actions/EditRollout.d.ts +17 -0
- package/build/rollout/actions/EditRollout.js +79 -0
- package/build/rollout/actions/EndRollout.d.ts +24 -0
- package/build/rollout/actions/EndRollout.js +164 -0
- package/build/rollout/actions/ManageRollout.d.ts +24 -0
- package/build/rollout/actions/ManageRollout.js +78 -0
- package/build/rollout/actions/NonInteractiveRollout.d.ts +18 -0
- package/build/rollout/actions/NonInteractiveRollout.js +46 -0
- package/build/rollout/actions/RolloutMainMenu.d.ts +28 -0
- package/build/rollout/actions/RolloutMainMenu.js +110 -0
- package/build/rollout/actions/SelectRollout.js +18 -8
- package/build/rollout/actions/SelectRuntime.d.ts +36 -0
- package/build/rollout/actions/SelectRuntime.js +167 -0
- package/build/rollout/branch-mapping.d.ts +52 -4
- package/build/rollout/branch-mapping.js +68 -19
- package/build/rollout/utils.d.ts +9 -2
- package/build/rollout/utils.js +66 -21
- package/build/update/configure.d.ts +6 -1
- package/build/update/configure.js +18 -8
- package/build/update/republish.d.ts +26 -0
- package/build/update/republish.js +83 -0
- package/build/utils/relay.d.ts +80 -15
- package/build/utils/relay.js +211 -28
- package/oclif.manifest.json +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RolloutMainMenu = exports.MainMenuActions = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
|
+
const SelectChannel_1 = require("../../channel/actions/SelectChannel");
|
|
7
|
+
const ChannelQuery_1 = require("../../graphql/queries/ChannelQuery");
|
|
8
|
+
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
9
|
+
const prompts_1 = require("../../prompts");
|
|
10
|
+
const branch_mapping_1 = require("../branch-mapping");
|
|
11
|
+
const CreateRollout_1 = require("./CreateRollout");
|
|
12
|
+
const ManageRollout_1 = require("./ManageRollout");
|
|
13
|
+
const SelectRollout_1 = require("./SelectRollout");
|
|
14
|
+
var MainMenuActions;
|
|
15
|
+
(function (MainMenuActions) {
|
|
16
|
+
MainMenuActions["CREATE_NEW"] = "Create a new rollout";
|
|
17
|
+
MainMenuActions["MANAGE_EXISTING"] = "Manage an existing rollout";
|
|
18
|
+
})(MainMenuActions = exports.MainMenuActions || (exports.MainMenuActions = {}));
|
|
19
|
+
/**
|
|
20
|
+
* Manage a rollout for the project.
|
|
21
|
+
*/
|
|
22
|
+
class RolloutMainMenu {
|
|
23
|
+
constructor(options = {}) {
|
|
24
|
+
this.options = options;
|
|
25
|
+
}
|
|
26
|
+
async runAsync(ctx) {
|
|
27
|
+
const { action } = this.options;
|
|
28
|
+
const { nonInteractive } = ctx;
|
|
29
|
+
if (nonInteractive) {
|
|
30
|
+
throw new Error(`rollout main menu cannot be run in non-interactive mode.`);
|
|
31
|
+
}
|
|
32
|
+
const menuOption = action ? this.toMainMenuAction(action) : await this.promptMenuActionAsync();
|
|
33
|
+
await this.runActionAsync(ctx, menuOption);
|
|
34
|
+
}
|
|
35
|
+
async runActionAsync(ctx, menuAction) {
|
|
36
|
+
const { channelName } = this.options;
|
|
37
|
+
switch (menuAction) {
|
|
38
|
+
case MainMenuActions.CREATE_NEW: {
|
|
39
|
+
const channelInfo = channelName
|
|
40
|
+
? await this.resolveChannelNameAsync(ctx, channelName)
|
|
41
|
+
: await this.selectChannelAsync(ctx, channelInfo => !(0, branch_mapping_1.isRollout)(channelInfo));
|
|
42
|
+
await new CreateRollout_1.CreateRollout(channelInfo, this.options).runAsync(ctx);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
case MainMenuActions.MANAGE_EXISTING: {
|
|
46
|
+
const channelInfo = channelName
|
|
47
|
+
? await this.resolveChannelNameAsync(ctx, channelName)
|
|
48
|
+
: await this.selectRolloutAsync(ctx);
|
|
49
|
+
if (!channelInfo) {
|
|
50
|
+
log_1.default.log('You dont have any rollouts.');
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
(0, assert_1.default)(this.options.action !== MainMenuActions.CREATE_NEW, 'Invalid route for create action');
|
|
54
|
+
const manageAction = await new ManageRollout_1.ManageRollout(channelInfo, {
|
|
55
|
+
...this.options,
|
|
56
|
+
action: this.options.action,
|
|
57
|
+
callingAction: this,
|
|
58
|
+
}).runAsync(ctx);
|
|
59
|
+
await manageAction.runAsync(ctx);
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async selectRolloutAsync(ctx) {
|
|
66
|
+
const selectRollout = new SelectRollout_1.SelectRollout();
|
|
67
|
+
const channelInfo = await selectRollout.runAsync(ctx);
|
|
68
|
+
return channelInfo;
|
|
69
|
+
}
|
|
70
|
+
async selectChannelAsync(ctx, filterPredicate) {
|
|
71
|
+
const selectChannelAction = new SelectChannel_1.SelectChannel({ filterPredicate });
|
|
72
|
+
const channelInfo = await selectChannelAction.runAsync(ctx);
|
|
73
|
+
if (!channelInfo) {
|
|
74
|
+
throw new Error(`You dont have any channels. Create one with <TODO>`);
|
|
75
|
+
}
|
|
76
|
+
return channelInfo;
|
|
77
|
+
}
|
|
78
|
+
async resolveChannelNameAsync(ctx, channelName) {
|
|
79
|
+
const { graphqlClient, app } = ctx;
|
|
80
|
+
return await ChannelQuery_1.ChannelQuery.viewUpdateChannelAsync(graphqlClient, {
|
|
81
|
+
appId: app.projectId,
|
|
82
|
+
channelName,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
toMainMenuAction(action) {
|
|
86
|
+
if (action === MainMenuActions.CREATE_NEW) {
|
|
87
|
+
return MainMenuActions.CREATE_NEW;
|
|
88
|
+
}
|
|
89
|
+
else if (action === ManageRollout_1.ManageRolloutActions.EDIT || action === ManageRollout_1.ManageRolloutActions.END) {
|
|
90
|
+
return MainMenuActions.MANAGE_EXISTING;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
throw new Error(`Action not supported yet: ` + action);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async promptMenuActionAsync() {
|
|
97
|
+
const menuOptions = [MainMenuActions.CREATE_NEW, MainMenuActions.MANAGE_EXISTING];
|
|
98
|
+
const { menuOption: selectedMenuOption } = await (0, prompts_1.promptAsync)({
|
|
99
|
+
type: 'select',
|
|
100
|
+
name: 'menuOption',
|
|
101
|
+
message: `What would you like to do?`,
|
|
102
|
+
choices: menuOptions.map(menuOption => ({
|
|
103
|
+
value: menuOption,
|
|
104
|
+
title: menuOption,
|
|
105
|
+
})),
|
|
106
|
+
});
|
|
107
|
+
return selectedMenuOption;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.RolloutMainMenu = RolloutMainMenu;
|
|
@@ -2,22 +2,32 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SelectRollout = void 0;
|
|
4
4
|
const SelectChannel_1 = require("../../channel/actions/SelectChannel");
|
|
5
|
-
const
|
|
6
|
-
const
|
|
5
|
+
const ora_1 = require("../../ora");
|
|
6
|
+
const branch_mapping_1 = require("../branch-mapping");
|
|
7
7
|
/**
|
|
8
8
|
* Select an existing rollout for the project.
|
|
9
9
|
*/
|
|
10
10
|
class SelectRollout {
|
|
11
11
|
async runAsync(ctx) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
let assetSpinner = null;
|
|
13
|
+
const afterEachFilterQuery = (_externalQueryParams, totalNodesFetched, _dataset, willFetchAgain) => {
|
|
14
|
+
if (willFetchAgain && !assetSpinner) {
|
|
15
|
+
assetSpinner = (0, ora_1.ora)().start('Fetching channels...');
|
|
16
|
+
}
|
|
17
|
+
if (assetSpinner) {
|
|
18
|
+
assetSpinner.text = `Fetched ${totalNodesFetched} channels`;
|
|
19
|
+
}
|
|
15
20
|
};
|
|
16
|
-
const
|
|
21
|
+
const selectChannelAction = new SelectChannel_1.SelectChannel({
|
|
17
22
|
printedType: 'rollout',
|
|
18
|
-
filterPredicate:
|
|
23
|
+
filterPredicate: branch_mapping_1.isRollout,
|
|
24
|
+
afterEachFilterQuery,
|
|
19
25
|
});
|
|
20
|
-
|
|
26
|
+
const channelInfo = await selectChannelAction.runAsync(ctx);
|
|
27
|
+
if (assetSpinner) {
|
|
28
|
+
assetSpinner.succeed(`Fetched all channels`);
|
|
29
|
+
}
|
|
30
|
+
return channelInfo;
|
|
21
31
|
}
|
|
22
32
|
}
|
|
23
33
|
exports.SelectRollout = SelectRollout;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
|
2
|
+
import { EASUpdateAction, EASUpdateContext } from '../../eas-update/utils';
|
|
3
|
+
import { RuntimeFragment, UpdateBranchBasicInfoFragment } from '../../graphql/generated';
|
|
4
|
+
import { Connection } from '../../utils/relay';
|
|
5
|
+
/**
|
|
6
|
+
* Select a runtime from a branch
|
|
7
|
+
*/
|
|
8
|
+
export declare class SelectRuntime implements EASUpdateAction<string> {
|
|
9
|
+
private branchInfo;
|
|
10
|
+
private options;
|
|
11
|
+
private printedType;
|
|
12
|
+
constructor(branchInfo: UpdateBranchBasicInfoFragment, options?: {
|
|
13
|
+
anotherBranchToIntersectRuntimesBy?: UpdateBranchBasicInfoFragment;
|
|
14
|
+
});
|
|
15
|
+
warnNoRuntime(): void;
|
|
16
|
+
formatCantFindRuntime(): string;
|
|
17
|
+
runAsync(ctx: EASUpdateContext): Promise<string>;
|
|
18
|
+
getNewestRuntimeAsync(graphqlClient: ExpoGraphqlClient, { appId, branchName, anotherBranchIdToIntersectRuntimesBy, }: {
|
|
19
|
+
appId: string;
|
|
20
|
+
branchName: string;
|
|
21
|
+
anotherBranchIdToIntersectRuntimesBy?: string;
|
|
22
|
+
}): Promise<Connection<RuntimeFragment> | null>;
|
|
23
|
+
displayLatestUpdateGroupAsync({ graphqlClient, appId, branchName, runtime, }: {
|
|
24
|
+
graphqlClient: ExpoGraphqlClient;
|
|
25
|
+
appId: string;
|
|
26
|
+
branchName: string;
|
|
27
|
+
runtime: RuntimeFragment;
|
|
28
|
+
}): Promise<string>;
|
|
29
|
+
selectRuntimesAsync(graphqlClient: ExpoGraphqlClient, { appId, branchName, anotherBranchIdToIntersectRuntimesBy, batchSize, }: {
|
|
30
|
+
appId: string;
|
|
31
|
+
branchName: string;
|
|
32
|
+
anotherBranchIdToIntersectRuntimesBy?: string;
|
|
33
|
+
batchSize?: number;
|
|
34
|
+
}): Promise<RuntimeFragment | null>;
|
|
35
|
+
promptForRuntimeAsync(): Promise<string>;
|
|
36
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SelectRuntime = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
7
|
+
const utils_1 = require("../../eas-update/utils");
|
|
8
|
+
const RuntimeQuery_1 = require("../../graphql/queries/RuntimeQuery");
|
|
9
|
+
const UpdateQuery_1 = require("../../graphql/queries/UpdateQuery");
|
|
10
|
+
const log_1 = tslib_1.__importStar(require("../../log"));
|
|
11
|
+
const prompts_1 = require("../../prompts");
|
|
12
|
+
const relay_1 = require("../../utils/relay");
|
|
13
|
+
const utils_2 = require("../utils");
|
|
14
|
+
function beginSentence(phrase) {
|
|
15
|
+
if (typeof phrase !== 'string' || phrase.length === 0) {
|
|
16
|
+
return phrase; // Return the input without any modification if it's not a string or empty
|
|
17
|
+
}
|
|
18
|
+
return phrase.charAt(0).toUpperCase() + phrase.slice(1);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Select a runtime from a branch
|
|
22
|
+
*/
|
|
23
|
+
class SelectRuntime {
|
|
24
|
+
constructor(branchInfo, options = {}) {
|
|
25
|
+
this.branchInfo = branchInfo;
|
|
26
|
+
this.options = options;
|
|
27
|
+
this.printedType = options.anotherBranchToIntersectRuntimesBy
|
|
28
|
+
? `compatible runtime`
|
|
29
|
+
: `runtime`;
|
|
30
|
+
}
|
|
31
|
+
warnNoRuntime() {
|
|
32
|
+
if (this.options.anotherBranchToIntersectRuntimesBy) {
|
|
33
|
+
const intersectBranchName = this.options.anotherBranchToIntersectRuntimesBy.name;
|
|
34
|
+
log_1.default.warn(`⚠️ Branches ${this.branchInfo.name} and ${intersectBranchName} dont have any updates with the same runtime.`);
|
|
35
|
+
// TODO(quin): write a learn more
|
|
36
|
+
log_1.default.warn(`Your updates could be misconfigured. ${(0, log_1.learnMore)('https://expo.fyi/todo')}`);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// no runtime on branch means no updates published on branch
|
|
40
|
+
log_1.default.warn(`⚠️ There are no updates published on branch ${this.branchInfo.name}.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
formatCantFindRuntime() {
|
|
44
|
+
return `🕵️ Not finding the update you were looking for? ${(0, log_1.learnMore)('https://expo.fyi/todo')}`;
|
|
45
|
+
}
|
|
46
|
+
async runAsync(ctx) {
|
|
47
|
+
var _a, _b;
|
|
48
|
+
const { nonInteractive, graphqlClient, app } = ctx;
|
|
49
|
+
const { projectId } = app;
|
|
50
|
+
if (nonInteractive) {
|
|
51
|
+
throw new utils_1.NonInteractiveError(`runtime selection cannot be run in non-interactive mode.`);
|
|
52
|
+
}
|
|
53
|
+
const newestRuntimeConnection = await this.getNewestRuntimeAsync(graphqlClient, {
|
|
54
|
+
appId: projectId,
|
|
55
|
+
branchName: this.branchInfo.name,
|
|
56
|
+
anotherBranchIdToIntersectRuntimesBy: (_a = this.options.anotherBranchToIntersectRuntimesBy) === null || _a === void 0 ? void 0 : _a.id,
|
|
57
|
+
});
|
|
58
|
+
if (!newestRuntimeConnection) {
|
|
59
|
+
log_1.default.addNewLineIfNone();
|
|
60
|
+
this.warnNoRuntime();
|
|
61
|
+
return await this.promptForRuntimeAsync();
|
|
62
|
+
}
|
|
63
|
+
const moreThanOneRuntime = newestRuntimeConnection.edges.length > 1;
|
|
64
|
+
log_1.default.log(`✅ ${beginSentence(this.printedType)}${moreThanOneRuntime ? 's' : ''} detected`);
|
|
65
|
+
if (!moreThanOneRuntime) {
|
|
66
|
+
const runtime = newestRuntimeConnection.edges[0].node;
|
|
67
|
+
const formattedRuntimeWithGroup = await this.displayLatestUpdateGroupAsync({
|
|
68
|
+
graphqlClient,
|
|
69
|
+
appId: projectId,
|
|
70
|
+
branchName: this.branchInfo.name,
|
|
71
|
+
runtime,
|
|
72
|
+
});
|
|
73
|
+
log_1.default.addNewLineIfNone();
|
|
74
|
+
log_1.default.log(formattedRuntimeWithGroup);
|
|
75
|
+
log_1.default.addNewLineIfNone();
|
|
76
|
+
const useRuntime = await (0, prompts_1.confirmAsync)({
|
|
77
|
+
message: `Target ${this.printedType} ${chalk_1.default.bold(runtime.version)}?`,
|
|
78
|
+
});
|
|
79
|
+
if (useRuntime) {
|
|
80
|
+
return runtime.version;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
log_1.default.newLine();
|
|
84
|
+
log_1.default.warn(this.formatCantFindRuntime());
|
|
85
|
+
return await this.promptForRuntimeAsync();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
log_1.default.log(this.formatCantFindRuntime());
|
|
89
|
+
const selectedRuntime = await this.selectRuntimesAsync(graphqlClient, {
|
|
90
|
+
appId: projectId,
|
|
91
|
+
branchName: this.branchInfo.name,
|
|
92
|
+
anotherBranchIdToIntersectRuntimesBy: (_b = this.options.anotherBranchToIntersectRuntimesBy) === null || _b === void 0 ? void 0 : _b.id,
|
|
93
|
+
});
|
|
94
|
+
if (!selectedRuntime) {
|
|
95
|
+
throw new Error(`No ${this.printedType} selected`);
|
|
96
|
+
}
|
|
97
|
+
return selectedRuntime.version;
|
|
98
|
+
}
|
|
99
|
+
async getNewestRuntimeAsync(graphqlClient, { appId, branchName, anotherBranchIdToIntersectRuntimesBy, }) {
|
|
100
|
+
const connection = await RuntimeQuery_1.RuntimeQuery.getRuntimesOnBranchAsync(graphqlClient, {
|
|
101
|
+
appId,
|
|
102
|
+
name: branchName,
|
|
103
|
+
first: 1,
|
|
104
|
+
filter: {
|
|
105
|
+
branchId: anotherBranchIdToIntersectRuntimesBy,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
const { edges } = connection;
|
|
109
|
+
if (edges.length === 0) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
return connection;
|
|
113
|
+
}
|
|
114
|
+
async displayLatestUpdateGroupAsync({ graphqlClient, appId, branchName, runtime, }) {
|
|
115
|
+
const updateGroups = await UpdateQuery_1.UpdateQuery.viewUpdateGroupsOnBranchAsync(graphqlClient, {
|
|
116
|
+
appId,
|
|
117
|
+
branchName,
|
|
118
|
+
limit: 1,
|
|
119
|
+
offset: 0,
|
|
120
|
+
filter: {
|
|
121
|
+
runtimeVersions: [runtime.version],
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
(0, assert_1.default)(updateGroups.length < 2, `Expected at most one update group. Received: ${JSON.stringify(updateGroups)}`);
|
|
125
|
+
return (0, utils_2.formatRuntimeWithUpdateGroup)(updateGroups[0], runtime);
|
|
126
|
+
}
|
|
127
|
+
async selectRuntimesAsync(graphqlClient, { appId, branchName, anotherBranchIdToIntersectRuntimesBy, batchSize = 5, }) {
|
|
128
|
+
const queryAsync = async (queryParams) => {
|
|
129
|
+
return await RuntimeQuery_1.RuntimeQuery.getRuntimesOnBranchAsync(graphqlClient, {
|
|
130
|
+
appId,
|
|
131
|
+
name: branchName,
|
|
132
|
+
first: queryParams.first,
|
|
133
|
+
after: queryParams.after,
|
|
134
|
+
last: queryParams.last,
|
|
135
|
+
before: queryParams.before,
|
|
136
|
+
filter: {
|
|
137
|
+
branchId: anotherBranchIdToIntersectRuntimesBy,
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
const getTitleAsync = async (runtime) => {
|
|
142
|
+
return await this.displayLatestUpdateGroupAsync({
|
|
143
|
+
graphqlClient,
|
|
144
|
+
appId,
|
|
145
|
+
branchName,
|
|
146
|
+
runtime,
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
return await (0, relay_1.selectPaginatedAsync)({
|
|
150
|
+
queryAsync,
|
|
151
|
+
getTitleAsync,
|
|
152
|
+
printedType: 'target runtime',
|
|
153
|
+
pageSize: batchSize,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
async promptForRuntimeAsync() {
|
|
157
|
+
log_1.default.log(`You can input a runtime manually then publish an update later.`);
|
|
158
|
+
const { runtimeVersion } = await (0, prompts_1.promptAsync)({
|
|
159
|
+
type: 'text',
|
|
160
|
+
name: 'runtimeVersion',
|
|
161
|
+
message: 'Input a runtime version:',
|
|
162
|
+
initial: '1.0.0',
|
|
163
|
+
});
|
|
164
|
+
return runtimeVersion;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.SelectRuntime = SelectRuntime;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BranchMapping } from '../channel/branch-mapping';
|
|
1
|
+
import { BranchMapping, BranchMappingAlwaysTrue } from '../channel/branch-mapping';
|
|
2
2
|
import { UpdateChannelBasicInfoFragment } from '../graphql/generated';
|
|
3
3
|
import { UpdateBranchObject, UpdateChannelObject } from '../graphql/queries/ChannelQuery';
|
|
4
4
|
export type Rollout = LegacyRollout | ConstrainedRollout;
|
|
@@ -18,12 +18,52 @@ type LegacyRolloutInfo = {
|
|
|
18
18
|
percentRolledOut: number;
|
|
19
19
|
defaultBranchId: string;
|
|
20
20
|
};
|
|
21
|
+
export type RolloutBranchMapping = LegacyRolloutBranchMapping | ConstrainedRolloutBranchMapping;
|
|
22
|
+
type RolloutNode = {
|
|
23
|
+
clientKey: 'rolloutToken';
|
|
24
|
+
branchMappingOperator: 'hash_lt';
|
|
25
|
+
operand: number;
|
|
26
|
+
};
|
|
27
|
+
type RuntimeVersionNode = {
|
|
28
|
+
clientKey: 'runtimeVersion';
|
|
29
|
+
branchMappingOperator: '==';
|
|
30
|
+
operand: string;
|
|
31
|
+
};
|
|
32
|
+
type RtvConstrainedRolloutNode = ['and', RolloutNode, RuntimeVersionNode] | ['and', RuntimeVersionNode, RolloutNode];
|
|
33
|
+
export type LegacyRolloutBranchMapping = {
|
|
34
|
+
version: number;
|
|
35
|
+
data: [
|
|
36
|
+
{
|
|
37
|
+
branchId: string;
|
|
38
|
+
branchMappingLogic: RolloutNode;
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
branchId: string;
|
|
42
|
+
branchMappingLogic: BranchMappingAlwaysTrue;
|
|
43
|
+
}
|
|
44
|
+
];
|
|
45
|
+
};
|
|
46
|
+
export type ConstrainedRolloutBranchMapping = {
|
|
47
|
+
version: number;
|
|
48
|
+
data: [
|
|
49
|
+
{
|
|
50
|
+
branchId: string;
|
|
51
|
+
branchMappingLogic: RtvConstrainedRolloutNode;
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
branchId: string;
|
|
55
|
+
branchMappingLogic: BranchMappingAlwaysTrue;
|
|
56
|
+
}
|
|
57
|
+
];
|
|
58
|
+
};
|
|
21
59
|
export declare function isLegacyRolloutInfo(rollout: RolloutInfo): rollout is LegacyRolloutInfo;
|
|
22
60
|
export declare function isConstrainedRolloutInfo(rollout: RolloutInfo): rollout is ConstrainedRolloutInfo;
|
|
23
61
|
export declare function isConstrainedRollout(rollout: Rollout): rollout is ConstrainedRollout;
|
|
24
62
|
export declare function getRolloutInfo(basicChannelInfo: UpdateChannelBasicInfoFragment): RolloutInfo;
|
|
25
|
-
export declare function getRolloutInfoFromBranchMapping(branchMapping:
|
|
63
|
+
export declare function getRolloutInfoFromBranchMapping(branchMapping: RolloutBranchMapping): RolloutInfo;
|
|
26
64
|
export declare function getRollout(channel: UpdateChannelObject): Rollout;
|
|
65
|
+
export declare function composeRollout(rolloutInfo: RolloutInfo, defaultBranch: UpdateBranchObject, rolledOutBranch: UpdateBranchObject): Rollout;
|
|
66
|
+
export declare function getRolloutBranchMapping(branchMappingString: string): RolloutBranchMapping;
|
|
27
67
|
/**
|
|
28
68
|
* Detect if a branch mapping is a rollout.
|
|
29
69
|
*
|
|
@@ -75,6 +115,14 @@ export declare function getRollout(channel: UpdateChannelObject): Rollout;
|
|
|
75
115
|
],
|
|
76
116
|
}
|
|
77
117
|
*/
|
|
78
|
-
export declare function
|
|
79
|
-
export declare function
|
|
118
|
+
export declare function isRolloutBranchMapping(branchMapping: BranchMapping): branchMapping is RolloutBranchMapping;
|
|
119
|
+
export declare function isRollout(channelInfo: UpdateChannelBasicInfoFragment): boolean;
|
|
120
|
+
export declare function createRolloutBranchMapping({ defaultBranchId, rolloutBranchId, percent, runtimeVersion, }: {
|
|
121
|
+
defaultBranchId: string;
|
|
122
|
+
rolloutBranchId: string;
|
|
123
|
+
percent: number;
|
|
124
|
+
runtimeVersion: string;
|
|
125
|
+
}): ConstrainedRolloutBranchMapping;
|
|
126
|
+
export declare function editRolloutBranchMapping(branchMapping: RolloutBranchMapping, percent: number): RolloutBranchMapping;
|
|
127
|
+
export declare function assertRolloutBranchMapping(branchMapping: BranchMapping): asserts branchMapping is RolloutBranchMapping;
|
|
80
128
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.editRolloutBranchMapping = exports.isRollout = exports.getRollout = exports.getRolloutInfoFromBranchMapping = exports.getRolloutInfo = exports.isConstrainedRollout = exports.isConstrainedRolloutInfo = exports.isLegacyRolloutInfo = void 0;
|
|
3
|
+
exports.assertRolloutBranchMapping = exports.editRolloutBranchMapping = exports.createRolloutBranchMapping = exports.isRollout = exports.isRolloutBranchMapping = exports.getRolloutBranchMapping = exports.composeRollout = exports.getRollout = exports.getRolloutInfoFromBranchMapping = exports.getRolloutInfo = exports.isConstrainedRollout = exports.isConstrainedRolloutInfo = exports.isLegacyRolloutInfo = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
6
|
const branch_mapping_1 = require("../channel/branch-mapping");
|
|
@@ -18,13 +18,11 @@ function isConstrainedRollout(rollout) {
|
|
|
18
18
|
}
|
|
19
19
|
exports.isConstrainedRollout = isConstrainedRollout;
|
|
20
20
|
function getRolloutInfo(basicChannelInfo) {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
return getRolloutInfoFromBranchMapping(branchMapping);
|
|
21
|
+
const rolloutBranchMapping = getRolloutBranchMapping(basicChannelInfo.branchMapping);
|
|
22
|
+
return getRolloutInfoFromBranchMapping(rolloutBranchMapping);
|
|
24
23
|
}
|
|
25
24
|
exports.getRolloutInfo = getRolloutInfo;
|
|
26
25
|
function getRolloutInfoFromBranchMapping(branchMapping) {
|
|
27
|
-
assertRollout(branchMapping);
|
|
28
26
|
const rolledOutBranchId = branchMapping.data[0].branchId;
|
|
29
27
|
const defaultBranchId = branchMapping.data[1].branchId;
|
|
30
28
|
if (isRtvConstrainedRollout(branchMapping)) {
|
|
@@ -62,20 +60,35 @@ function getRolloutInfoFromBranchMapping(branchMapping) {
|
|
|
62
60
|
}
|
|
63
61
|
exports.getRolloutInfoFromBranchMapping = getRolloutInfoFromBranchMapping;
|
|
64
62
|
function getRollout(channel) {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
const rolledOutBranchId = branchMapping.data[0].branchId;
|
|
63
|
+
const rolloutBranchMapping = getRolloutBranchMapping(channel.branchMapping);
|
|
64
|
+
const rolledOutBranchId = rolloutBranchMapping.data[0].branchId;
|
|
68
65
|
const rolledOutBranch = (0, utils_1.getUpdateBranch)(channel, rolledOutBranchId);
|
|
69
|
-
const defaultBranchId =
|
|
66
|
+
const defaultBranchId = rolloutBranchMapping.data[1].branchId;
|
|
70
67
|
const defaultBranch = (0, utils_1.getUpdateBranch)(channel, defaultBranchId);
|
|
71
68
|
const rolloutInfo = getRolloutInfo(channel);
|
|
69
|
+
return composeRollout(rolloutInfo, defaultBranch, rolledOutBranch);
|
|
70
|
+
}
|
|
71
|
+
exports.getRollout = getRollout;
|
|
72
|
+
function composeRollout(rolloutInfo, defaultBranch, rolledOutBranch) {
|
|
73
|
+
if (rolloutInfo.defaultBranchId !== defaultBranch.id) {
|
|
74
|
+
throw new branch_mapping_1.BranchMappingValidationError(`Default branch id must match. Received: ${JSON.stringify(rolloutInfo)} ${defaultBranch.id}`);
|
|
75
|
+
}
|
|
76
|
+
if (rolloutInfo.rolledOutBranchId !== rolledOutBranch.id) {
|
|
77
|
+
throw new branch_mapping_1.BranchMappingValidationError(`Rolled out branch id must match. Received: ${JSON.stringify(rolloutInfo)} ${rolledOutBranch.id}`);
|
|
78
|
+
}
|
|
72
79
|
return {
|
|
73
80
|
...rolloutInfo,
|
|
74
81
|
rolledOutBranch,
|
|
75
82
|
defaultBranch,
|
|
76
83
|
};
|
|
77
84
|
}
|
|
78
|
-
exports.
|
|
85
|
+
exports.composeRollout = composeRollout;
|
|
86
|
+
function getRolloutBranchMapping(branchMappingString) {
|
|
87
|
+
const branchMapping = (0, branch_mapping_1.getBranchMapping)(branchMappingString);
|
|
88
|
+
assertRolloutBranchMapping(branchMapping);
|
|
89
|
+
return branchMapping;
|
|
90
|
+
}
|
|
91
|
+
exports.getRolloutBranchMapping = getRolloutBranchMapping;
|
|
79
92
|
/**
|
|
80
93
|
* Detect if a branch mapping is a rollout.
|
|
81
94
|
*
|
|
@@ -127,13 +140,43 @@ exports.getRollout = getRollout;
|
|
|
127
140
|
],
|
|
128
141
|
}
|
|
129
142
|
*/
|
|
130
|
-
function
|
|
143
|
+
function isRolloutBranchMapping(branchMapping) {
|
|
131
144
|
return isUnconstrainedRollout(branchMapping) || isRtvConstrainedRollout(branchMapping);
|
|
132
145
|
}
|
|
146
|
+
exports.isRolloutBranchMapping = isRolloutBranchMapping;
|
|
147
|
+
function isRollout(channelInfo) {
|
|
148
|
+
const branchMapping = (0, branch_mapping_1.getBranchMapping)(channelInfo.branchMapping);
|
|
149
|
+
return isRolloutBranchMapping(branchMapping);
|
|
150
|
+
}
|
|
133
151
|
exports.isRollout = isRollout;
|
|
152
|
+
function createRolloutBranchMapping({ defaultBranchId, rolloutBranchId, percent, runtimeVersion, }) {
|
|
153
|
+
assertPercent(percent);
|
|
154
|
+
return {
|
|
155
|
+
version: 0,
|
|
156
|
+
data: [
|
|
157
|
+
{
|
|
158
|
+
branchId: rolloutBranchId,
|
|
159
|
+
branchMappingLogic: [
|
|
160
|
+
'and',
|
|
161
|
+
{
|
|
162
|
+
operand: runtimeVersion,
|
|
163
|
+
clientKey: 'runtimeVersion',
|
|
164
|
+
branchMappingOperator: '==',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
operand: percent / 100,
|
|
168
|
+
clientKey: 'rolloutToken',
|
|
169
|
+
branchMappingOperator: 'hash_lt',
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
{ branchId: defaultBranchId, branchMappingLogic: (0, branch_mapping_1.alwaysTrue)() },
|
|
174
|
+
],
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
exports.createRolloutBranchMapping = createRolloutBranchMapping;
|
|
134
178
|
function editRolloutBranchMapping(branchMapping, percent) {
|
|
135
|
-
(
|
|
136
|
-
assertRollout(branchMapping);
|
|
179
|
+
assertPercent(percent);
|
|
137
180
|
if (isRtvConstrainedRollout(branchMapping)) {
|
|
138
181
|
return editRtvConstrainedRollout(branchMapping, percent);
|
|
139
182
|
}
|
|
@@ -145,24 +188,18 @@ exports.editRolloutBranchMapping = editRolloutBranchMapping;
|
|
|
145
188
|
function editRtvConstrainedRollout(branchMapping, percent) {
|
|
146
189
|
const newBranchMapping = { ...branchMapping };
|
|
147
190
|
const statementNode = newBranchMapping.data[0].branchMappingLogic;
|
|
148
|
-
(0, branch_mapping_1.assertStatement)(statementNode);
|
|
149
191
|
const nodesFromStatement = (0, branch_mapping_1.getNodesFromStatement)(statementNode);
|
|
150
192
|
const rolloutNode = nodesFromStatement.find(isRolloutNode);
|
|
151
193
|
(0, assert_1.default)(rolloutNode, 'Rollout node must be defined.');
|
|
152
|
-
(0, branch_mapping_1.assertNodeObject)(rolloutNode);
|
|
153
194
|
rolloutNode.operand = percent / 100;
|
|
154
195
|
return newBranchMapping;
|
|
155
196
|
}
|
|
156
197
|
function editLegacyRollout(branchMapping, percent) {
|
|
157
198
|
const newBranchMapping = { ...branchMapping };
|
|
158
199
|
const rolloutNode = newBranchMapping.data[0].branchMappingLogic;
|
|
159
|
-
(0, branch_mapping_1.assertNodeObject)(rolloutNode);
|
|
160
200
|
rolloutNode.operand = percent / 100;
|
|
161
201
|
return newBranchMapping;
|
|
162
202
|
}
|
|
163
|
-
function assertRollout(branchMapping) {
|
|
164
|
-
(0, assert_1.default)(isRollout(branchMapping), 'Branch mapping node must be a rollout. Received: ' + JSON.stringify(branchMapping));
|
|
165
|
-
}
|
|
166
203
|
function isRtvConstrainedRollout(branchMapping) {
|
|
167
204
|
if (branchMapping.data.length !== 2) {
|
|
168
205
|
return false;
|
|
@@ -209,3 +246,15 @@ function isRolloutNode(node) {
|
|
|
209
246
|
}
|
|
210
247
|
return node.clientKey === 'rolloutToken' && node.branchMappingOperator === 'hash_lt';
|
|
211
248
|
}
|
|
249
|
+
function assertRolloutBranchMapping(branchMapping) {
|
|
250
|
+
if (!isRolloutBranchMapping(branchMapping)) {
|
|
251
|
+
throw new branch_mapping_1.BranchMappingValidationError('Branch mapping node must be a rollout. Received: ' + JSON.stringify(branchMapping));
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
exports.assertRolloutBranchMapping = assertRolloutBranchMapping;
|
|
255
|
+
function assertPercent(percent) {
|
|
256
|
+
const isPercent = Number.isInteger(percent) && percent >= 0 && percent <= 100;
|
|
257
|
+
if (!isPercent) {
|
|
258
|
+
throw new branch_mapping_1.BranchMappingValidationError(`The percentage must be an integer between 0 and 100 inclusive. Received: ${percent}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
package/build/rollout/utils.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RuntimeFragment, UpdateFragment } from '../graphql/generated';
|
|
2
|
+
import { UpdateBranchObject, UpdateChannelObject } from '../graphql/queries/ChannelQuery';
|
|
3
|
+
import { Rollout } from './branch-mapping';
|
|
2
4
|
export declare function printRollout(channel: UpdateChannelObject): void;
|
|
3
|
-
export declare function
|
|
5
|
+
export declare function displayRolloutDetails(channelName: string, rollout: Rollout): void;
|
|
6
|
+
export declare function formatBranchWithUpdateGroup(maybeUpdateGroup: UpdateFragment[] | undefined | null, branch: UpdateBranchObject, percentRolledOut: number): string;
|
|
7
|
+
export declare function formatRuntimeWithUpdateGroup(maybeUpdateGroup: UpdateFragment[] | undefined | null, runtime: RuntimeFragment): string;
|
|
8
|
+
export declare function promptForRolloutPercentAsync({ promptMessage, }: {
|
|
9
|
+
promptMessage: string;
|
|
10
|
+
}): Promise<number>;
|