eas-cli 3.16.0 → 3.17.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.
Files changed (33) hide show
  1. package/README.md +55 -55
  2. package/build/build/build.js +1 -0
  3. package/build/build/errors.d.ts +2 -0
  4. package/build/build/errors.js +4 -1
  5. package/build/channel/branch-mapping.d.ts +27 -0
  6. package/build/channel/branch-mapping.js +49 -0
  7. package/build/channel/queries.d.ts +6 -1
  8. package/build/channel/queries.js +29 -3
  9. package/build/channel/utils.d.ts +3 -12
  10. package/build/channel/utils.js +24 -4
  11. package/build/commandUtils/context/contextUtils/createGraphqlClient.d.ts +2 -2
  12. package/build/commandUtils/context/contextUtils/createGraphqlClient.js +0 -1
  13. package/build/commands/channel/edit.d.ts +2 -2
  14. package/build/commands/channel/edit.js +4 -2
  15. package/build/commands/channel/rollout.js +6 -1
  16. package/build/credentials/android/api/graphql/mutations/AndroidAppBuildCredentialsMutation.js +2 -2
  17. package/build/graphql/generated.d.ts +180 -19
  18. package/build/graphql/generated.js +11 -2
  19. package/build/graphql/queries/ChannelQuery.d.ts +8 -4
  20. package/build/graphql/queries/ChannelQuery.js +43 -4
  21. package/build/graphql/types/Submission.js +1 -0
  22. package/build/graphql/types/UpdateChannelBasicInfo.d.ts +1 -0
  23. package/build/graphql/types/UpdateChannelBasicInfo.js +12 -0
  24. package/build/rollout/utils.d.ts +53 -0
  25. package/build/rollout/utils.js +105 -0
  26. package/build/submit/android/AndroidSubmitCommand.d.ts +1 -0
  27. package/build/submit/android/AndroidSubmitCommand.js +7 -1
  28. package/build/submit/android/AndroidSubmitter.d.ts +1 -1
  29. package/build/submit/android/AndroidSubmitter.js +5 -2
  30. package/build/utils/relay.d.ts +33 -0
  31. package/build/utils/relay.js +43 -0
  32. package/oclif.manifest.json +1 -1
  33. package/package.json +9 -8
@@ -0,0 +1,53 @@
1
+ import { BranchMapping } from '../channel/branch-mapping';
2
+ /**
3
+ * Detect if a branch mapping is a rollout.
4
+ *
5
+ * Types of rollout:
6
+ * 1. Legacy unconstrained rollout:
7
+ * Maps to a rollout branch via a rollout token
8
+ * Falls back to a default branch
9
+ *
10
+ * Example:
11
+ * {
12
+ version: 0,
13
+ data: [
14
+ {
15
+ branchId: uuidv4(),
16
+ branchMappingLogic: {
17
+ operand: 10 / 100,
18
+ clientKey: 'rolloutToken',
19
+ branchMappingOperator: hashLtOperator(),
20
+ },
21
+ },
22
+ { branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
23
+ ],
24
+ }
25
+ *
26
+ * 2. RTV constrained rollout:
27
+ * Maps to a rollout branch via a rollout token, constrained by runtime version
28
+ * Falls back to a default branch
29
+ *
30
+ * Example:
31
+ * {
32
+ version: 0,
33
+ data: [
34
+ {
35
+ branchId: uuidv4(),
36
+ branchMappingLogic: andStatement([
37
+ {
38
+ operand: '1.0.0',
39
+ clientKey: 'runtimeVersion',
40
+ branchMappingOperator: equalsOperator(),
41
+ },
42
+ {
43
+ operand: 10 / 100,
44
+ clientKey: 'rolloutToken',
45
+ branchMappingOperator: hashLtOperator(),
46
+ },
47
+ ]),
48
+ },
49
+ { branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
50
+ ],
51
+ }
52
+ */
53
+ export declare function isRollout(branchMapping: BranchMapping): boolean;
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRollout = void 0;
4
+ const branch_mapping_1 = require("../channel/branch-mapping");
5
+ /**
6
+ * Detect if a branch mapping is a rollout.
7
+ *
8
+ * Types of rollout:
9
+ * 1. Legacy unconstrained rollout:
10
+ * Maps to a rollout branch via a rollout token
11
+ * Falls back to a default branch
12
+ *
13
+ * Example:
14
+ * {
15
+ version: 0,
16
+ data: [
17
+ {
18
+ branchId: uuidv4(),
19
+ branchMappingLogic: {
20
+ operand: 10 / 100,
21
+ clientKey: 'rolloutToken',
22
+ branchMappingOperator: hashLtOperator(),
23
+ },
24
+ },
25
+ { branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
26
+ ],
27
+ }
28
+ *
29
+ * 2. RTV constrained rollout:
30
+ * Maps to a rollout branch via a rollout token, constrained by runtime version
31
+ * Falls back to a default branch
32
+ *
33
+ * Example:
34
+ * {
35
+ version: 0,
36
+ data: [
37
+ {
38
+ branchId: uuidv4(),
39
+ branchMappingLogic: andStatement([
40
+ {
41
+ operand: '1.0.0',
42
+ clientKey: 'runtimeVersion',
43
+ branchMappingOperator: equalsOperator(),
44
+ },
45
+ {
46
+ operand: 10 / 100,
47
+ clientKey: 'rolloutToken',
48
+ branchMappingOperator: hashLtOperator(),
49
+ },
50
+ ]),
51
+ },
52
+ { branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
53
+ ],
54
+ }
55
+ */
56
+ function isRollout(branchMapping) {
57
+ return isUnconstrainedRollout(branchMapping) || isRtvConstrainedRollout(branchMapping);
58
+ }
59
+ exports.isRollout = isRollout;
60
+ function isRtvConstrainedRollout(branchMapping) {
61
+ if (branchMapping.data.length !== 2) {
62
+ return false;
63
+ }
64
+ const hasRtvRolloutNode = isRtvConstrainedRolloutNode(branchMapping.data[0].branchMappingLogic);
65
+ const defaultsToAlwaysTrueNode = (0, branch_mapping_1.isAlwaysTrue)(branchMapping.data[1].branchMappingLogic);
66
+ return hasRtvRolloutNode && defaultsToAlwaysTrueNode;
67
+ }
68
+ function isRtvConstrainedRolloutNode(node) {
69
+ if (!(0, branch_mapping_1.isStatement)(node) || !(0, branch_mapping_1.isAndStatement)(node)) {
70
+ return false;
71
+ }
72
+ const statementNodes = (0, branch_mapping_1.getNodesFromStatement)(node);
73
+ if (statementNodes.length !== 2) {
74
+ return false;
75
+ }
76
+ const hasRuntimeVersionNode = statementNodes.some(isRuntimeVersionNode);
77
+ const hasRolloutNode = statementNodes.some(isRolloutNode);
78
+ return hasRuntimeVersionNode && hasRolloutNode;
79
+ }
80
+ function isUnconstrainedRollout(branchMapping) {
81
+ if (branchMapping.data.length !== 2) {
82
+ return false;
83
+ }
84
+ const hasRolloutNode = isRolloutNode(branchMapping.data[0].branchMappingLogic);
85
+ const defaultsToAlwaysTrueNode = (0, branch_mapping_1.isAlwaysTrue)(branchMapping.data[1].branchMappingLogic);
86
+ return hasRolloutNode && defaultsToAlwaysTrueNode;
87
+ }
88
+ function isRuntimeVersionNode(node) {
89
+ if (typeof node === 'string') {
90
+ return false;
91
+ }
92
+ if (Array.isArray(node)) {
93
+ return false;
94
+ }
95
+ return node.clientKey === 'runtimeVersion' && node.branchMappingOperator === '==';
96
+ }
97
+ function isRolloutNode(node) {
98
+ if (typeof node === 'string') {
99
+ return false;
100
+ }
101
+ if (Array.isArray(node)) {
102
+ return false;
103
+ }
104
+ return node.clientKey === 'rolloutToken' && node.branchMappingOperator === 'hash_lt';
105
+ }
@@ -9,6 +9,7 @@ export default class AndroidSubmitCommand {
9
9
  private maybeGetAndroidPackageFromCurrentProjectAsync;
10
10
  private resolveTrack;
11
11
  private resolveReleaseStatus;
12
+ private resolveRollout;
12
13
  private resolveArchiveSource;
13
14
  private resolveServiceAccountSourceAsync;
14
15
  }
@@ -24,8 +24,9 @@ class AndroidSubmitCommand {
24
24
  const track = this.resolveTrack();
25
25
  const releaseStatus = this.resolveReleaseStatus();
26
26
  const archiveSource = this.resolveArchiveSource();
27
+ const rollout = this.resolveRollout();
27
28
  const serviceAccountSource = await this.resolveServiceAccountSourceAsync();
28
- const errored = [track, releaseStatus, archiveSource, serviceAccountSource].filter(r => !r.ok);
29
+ const errored = [track, releaseStatus, archiveSource, serviceAccountSource, rollout].filter(r => !r.ok);
29
30
  if (errored.length > 0) {
30
31
  const message = errored.map(err => { var _a; return (_a = err.reason) === null || _a === void 0 ? void 0 : _a.message; }).join('\n');
31
32
  log_1.default.error(message);
@@ -35,6 +36,7 @@ class AndroidSubmitCommand {
35
36
  projectId: this.ctx.projectId,
36
37
  track: track.enforceValue(),
37
38
  releaseStatus: releaseStatus.enforceValue(),
39
+ rollout: rollout.enforceValue(),
38
40
  archiveSource: archiveSource.enforceValue(),
39
41
  serviceAccountSource: serviceAccountSource.enforceValue(),
40
42
  changesNotSentForReview: this.ctx.profile.changesNotSentForReview,
@@ -78,6 +80,10 @@ class AndroidSubmitCommand {
78
80
  return (0, results_1.result)(new Error(`Unsupported release status: ${releaseStatus} (valid options: ${Object.keys(eas_json_1.AndroidReleaseStatus).join(', ')})`));
79
81
  }
80
82
  }
83
+ resolveRollout() {
84
+ const { rollout } = this.ctx.profile;
85
+ return (0, results_1.result)(rollout);
86
+ }
81
87
  resolveArchiveSource() {
82
88
  try {
83
89
  return (0, results_1.result)((0, commons_1.resolveArchiveSource)(this.ctx));
@@ -4,7 +4,7 @@ import { ArchiveSource, ResolvedArchiveSource } from '../ArchiveSource';
4
4
  import BaseSubmitter, { SubmissionInput } from '../BaseSubmitter';
5
5
  import { SubmissionContext } from '../context';
6
6
  import { ServiceAccountKeyResult, ServiceAccountSource } from './ServiceAccountSource';
7
- export interface AndroidSubmissionOptions extends Pick<AndroidSubmissionConfigInput, 'track' | 'releaseStatus' | 'changesNotSentForReview'> {
7
+ export interface AndroidSubmissionOptions extends Pick<AndroidSubmissionConfigInput, 'track' | 'releaseStatus' | 'changesNotSentForReview' | 'rollout'> {
8
8
  projectId: string;
9
9
  archiveSource: ArchiveSource;
10
10
  serviceAccountSource: ServiceAccountSource;
@@ -57,16 +57,17 @@ class AndroidSubmitter extends BaseSubmitter_1.default {
57
57
  });
58
58
  }
59
59
  formatSubmissionConfig(options, { serviceAccountKeyResult }) {
60
- const { track, releaseStatus, changesNotSentForReview } = options;
60
+ const { track, releaseStatus, changesNotSentForReview, rollout } = options;
61
61
  return {
62
62
  track,
63
63
  changesNotSentForReview,
64
64
  releaseStatus,
65
+ rollout,
65
66
  ...serviceAccountKeyResult.result,
66
67
  };
67
68
  }
68
69
  prepareSummaryData(options, { archive, serviceAccountKeyResult }) {
69
- const { projectId, track, releaseStatus, changesNotSentForReview } = options;
70
+ const { projectId, track, releaseStatus, changesNotSentForReview, rollout } = options;
70
71
  // structuring order affects table rows order
71
72
  return {
72
73
  projectId,
@@ -74,6 +75,7 @@ class AndroidSubmitter extends BaseSubmitter_1.default {
74
75
  changesNotSentForReview: changesNotSentForReview !== null && changesNotSentForReview !== void 0 ? changesNotSentForReview : undefined,
75
76
  releaseStatus: releaseStatus !== null && releaseStatus !== void 0 ? releaseStatus : undefined,
76
77
  formattedServiceAccount: formatServiceAccountSummary(serviceAccountKeyResult),
78
+ rollout: rollout !== null && rollout !== void 0 ? rollout : undefined,
77
79
  ...(0, summary_1.formatArchiveSourceSummary)(archive),
78
80
  };
79
81
  }
@@ -87,6 +89,7 @@ const SummaryHumanReadableKeys = {
87
89
  formattedServiceAccount: 'Google Service Account Key',
88
90
  projectId: 'Project ID',
89
91
  releaseStatus: 'Release status',
92
+ rollout: 'Rollout',
90
93
  track: 'Release track',
91
94
  };
92
95
  function formatServiceAccountSummary({ summary }) {
@@ -0,0 +1,33 @@
1
+ import { PageInfo } from '../graphql/generated';
2
+ export type Connection<T> = {
3
+ edges: Edge<T>[];
4
+ pageInfo: PageInfo;
5
+ };
6
+ type Edge<T> = {
7
+ node: T;
8
+ };
9
+ export type QueryParams = {
10
+ first: number;
11
+ after?: string;
12
+ };
13
+ /**
14
+ * Fetches dataset in paginated manner (batch by batch) using GraphQL queries.
15
+ *
16
+ * @param queryAsync A promise based function for querying.
17
+ * @param beforeEachQuery Optional. A callback function to be called before each query
18
+ * @param afterEachQuery Optional. A callback function to be called after each query.
19
+ * @param filterPredicate Optional. A predicate function to filter the node.
20
+ * @param batchSize Optional. The batch size of the pagination. Defaults to 100.
21
+ *
22
+ * @return {Promise<T[]>} - A promise that resolves to an array (the dataset).
23
+ * @throws {Error} - If an error occurs during execution of the query or pagination.
24
+ */
25
+ export declare function getPaginatedDatasetAsync<T>({ queryAsync, beforeEachQuery, afterEachQuery, filterPredicate, batchSize, maxNodesFetched, }: {
26
+ queryAsync: ({ first, after }: QueryParams) => Promise<Connection<T>>;
27
+ beforeEachQuery?: (totalNodesFetched: number, dataset: T[]) => void;
28
+ afterEachQuery?: (totalNodesFetched: number, dataset: T[], batch: T[], pageInfo: PageInfo) => void;
29
+ filterPredicate?: (node: T) => boolean;
30
+ batchSize?: number;
31
+ maxNodesFetched?: number;
32
+ }): Promise<T[]>;
33
+ export {};
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPaginatedDatasetAsync = void 0;
4
+ /**
5
+ * Fetches dataset in paginated manner (batch by batch) using GraphQL queries.
6
+ *
7
+ * @param queryAsync A promise based function for querying.
8
+ * @param beforeEachQuery Optional. A callback function to be called before each query
9
+ * @param afterEachQuery Optional. A callback function to be called after each query.
10
+ * @param filterPredicate Optional. A predicate function to filter the node.
11
+ * @param batchSize Optional. The batch size of the pagination. Defaults to 100.
12
+ *
13
+ * @return {Promise<T[]>} - A promise that resolves to an array (the dataset).
14
+ * @throws {Error} - If an error occurs during execution of the query or pagination.
15
+ */
16
+ async function getPaginatedDatasetAsync({ queryAsync, beforeEachQuery, afterEachQuery, filterPredicate, batchSize = 100, maxNodesFetched = 10000, }) {
17
+ var _a;
18
+ const dataset = [];
19
+ let hasMore = true;
20
+ let after;
21
+ let totalNodesFetched = 0;
22
+ while (hasMore) {
23
+ if (beforeEachQuery) {
24
+ beforeEachQuery(totalNodesFetched, dataset);
25
+ }
26
+ const result = await queryAsync({ first: batchSize, after });
27
+ const { edges, pageInfo } = result;
28
+ const nodes = edges.map(edge => edge.node);
29
+ const batch = filterPredicate ? nodes.filter(filterPredicate) : nodes;
30
+ dataset.push(...batch);
31
+ hasMore = pageInfo.hasNextPage;
32
+ after = (_a = pageInfo.endCursor) !== null && _a !== void 0 ? _a : undefined;
33
+ totalNodesFetched += nodes.length;
34
+ if (afterEachQuery) {
35
+ afterEachQuery(totalNodesFetched, dataset, batch, pageInfo);
36
+ }
37
+ if (totalNodesFetched >= maxNodesFetched) {
38
+ return dataset;
39
+ }
40
+ }
41
+ return dataset;
42
+ }
43
+ exports.getPaginatedDatasetAsync = getPaginatedDatasetAsync;