mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-14 10:08:06 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aadef09d1e |
No files matched your search
@@ -37,7 +37,6 @@
|
||||
"cli-progress": "3.11.2",
|
||||
"cli-table3": "0.6.2",
|
||||
"dateformat": "4.6.3",
|
||||
"enquirer": "2.3.6",
|
||||
"env-paths": "2.2.0",
|
||||
"envinfo": "7.8.1",
|
||||
"fast-deep-equal": "3.1.3",
|
||||
|
||||
@@ -378,7 +378,7 @@ export default class UpdatePublish extends EasCommand {
|
||||
if (!skipBundler) {
|
||||
const bundleSpinner = ora().start('Building bundle...');
|
||||
try {
|
||||
await buildBundlesAsync({ projectDir, inputDir });
|
||||
await buildBundlesAsync({ projectDir, inputDir, platform: platformFlag });
|
||||
bundleSpinner.succeed('Built bundle!');
|
||||
} catch (e) {
|
||||
bundleSpinner.fail('Failed to build bundle!');
|
||||
|
||||
@@ -147,9 +147,11 @@ export async function buildUnsortedUpdateInfoGroupAsync(
|
||||
export async function buildBundlesAsync({
|
||||
projectDir,
|
||||
inputDir,
|
||||
platform = 'all',
|
||||
}: {
|
||||
projectDir: string;
|
||||
inputDir: string;
|
||||
platform?: PublishPlatform | 'all';
|
||||
}): Promise<void> {
|
||||
const packageJSON = JsonFile.read(path.resolve(projectDir, 'package.json'));
|
||||
if (!packageJSON) {
|
||||
@@ -160,6 +162,8 @@ export async function buildBundlesAsync({
|
||||
'export',
|
||||
'--output-dir',
|
||||
inputDir,
|
||||
'--platform',
|
||||
platform,
|
||||
'--experimental-bundle',
|
||||
'--non-interactive',
|
||||
'--dump-sourcemap',
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
// @ts-ignore
|
||||
import { MultiSelect } from 'enquirer';
|
||||
import { constants } from 'os';
|
||||
import prompts, { Answers, Choice, Options, PromptType, PromptObject as Question } from 'prompts';
|
||||
|
||||
import { PAGINATION_FETCH_MORE_VALUE } from './utils/queryConstants';
|
||||
|
||||
export { PromptType, Question, Choice };
|
||||
|
||||
export interface ExpoChoice<T> extends Choice {
|
||||
@@ -97,56 +93,3 @@ export async function pressAnyKeyToContinueAsync(): Promise<void> {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class ExpoMultiSelect extends MultiSelect {
|
||||
state: any;
|
||||
selected: any;
|
||||
styles: any;
|
||||
run!: () => Promise<any>;
|
||||
submit!: () => Promise<any>;
|
||||
|
||||
constructor(options = {}) {
|
||||
super({ ...options, multiple: true });
|
||||
}
|
||||
|
||||
toggle(choice: ExpoChoice<any>, enabled: boolean): ExpoChoice<any> | void {
|
||||
super.toggle(choice, enabled);
|
||||
|
||||
if (choice?.value === PAGINATION_FETCH_MORE_VALUE) {
|
||||
this.submit();
|
||||
return;
|
||||
}
|
||||
|
||||
return choice;
|
||||
}
|
||||
|
||||
format(): string {
|
||||
if (!this.state.submitted || this.state.cancelled) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (Array.isArray(this.selected)) {
|
||||
return this.selected
|
||||
.filter(choice => choice.value !== PAGINATION_FETCH_MORE_VALUE)
|
||||
.map(choice => this.styles.primary(choice.name))
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
return this.styles.primary(this.selected.name);
|
||||
}
|
||||
}
|
||||
|
||||
export async function multiselectAsync<T>(message: string, choices: ExpoChoice<T>[]): Promise<T[]> {
|
||||
const result = await new ExpoMultiSelect({
|
||||
message,
|
||||
// prompt will mutate input
|
||||
choices,
|
||||
initial: choices.filter(x => x.selected),
|
||||
}).run();
|
||||
|
||||
if (result && typeof choices === 'object' && choices.length > 0) {
|
||||
return choices.filter(choice => result.includes(choice.title)).map(choice => choice.value);
|
||||
}
|
||||
|
||||
return result ?? null;
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
import { confirmAsync, multiselectAsync, selectAsync } from '../../prompts';
|
||||
import { confirmAsync, selectAsync } from '../../prompts';
|
||||
import {
|
||||
paginatedQueryWithConfirmPromptAsync,
|
||||
paginatedQueryWithMultiSelectPromptAsync,
|
||||
paginatedQueryWithSelectPromptAsync,
|
||||
} from '../queries';
|
||||
import { PAGINATION_FETCH_MORE_VALUE } from '../queryConstants';
|
||||
|
||||
jest.mock('../../prompts', () => ({
|
||||
selectAsync: jest.fn(),
|
||||
multiselectAsync: jest.fn(),
|
||||
confirmAsync: jest.fn(),
|
||||
}));
|
||||
|
||||
@@ -22,7 +19,7 @@ const mockRenderMethod = jest.fn();
|
||||
|
||||
const selectMoreObject = {
|
||||
title: 'Next page...',
|
||||
value: PAGINATION_FETCH_MORE_VALUE,
|
||||
value: '_fetchMore',
|
||||
};
|
||||
|
||||
function createPaginatedQueryResponse(
|
||||
@@ -121,8 +118,8 @@ describe(paginatedQueryWithSelectPromptAsync.name, () => {
|
||||
);
|
||||
jest
|
||||
.mocked(selectAsync)
|
||||
.mockResolvedValueOnce(PAGINATION_FETCH_MORE_VALUE)
|
||||
.mockResolvedValueOnce(PAGINATION_FETCH_MORE_VALUE)
|
||||
.mockResolvedValueOnce(selectMoreObject.value)
|
||||
.mockResolvedValueOnce(selectMoreObject.value)
|
||||
.mockResolvedValueOnce(selectedItem.value);
|
||||
|
||||
const selectedQueryItem = await paginatedQueryWithSelectPromptAsync({
|
||||
@@ -132,7 +129,7 @@ describe(paginatedQueryWithSelectPromptAsync.name, () => {
|
||||
promptOptions: {
|
||||
title: '',
|
||||
getIdentifierForQueryItem: item => item.id,
|
||||
createDisplayTextForSelectionPromptListItem: jest.fn(),
|
||||
createDisplayTextForSelectionPromptListItem: item => 'item: ' + item.value,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -189,96 +186,3 @@ describe(paginatedQueryWithSelectPromptAsync.name, () => {
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe(paginatedQueryWithMultiSelectPromptAsync.name, () => {
|
||||
const mockHandleEmptySelectList = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
mockQuery.mockClear();
|
||||
mockRenderMethod.mockClear();
|
||||
mockHandleEmptySelectList.mockClear();
|
||||
jest.mocked(multiselectAsync).mockClear();
|
||||
});
|
||||
|
||||
it('carries over user selections to new pages', async () => {
|
||||
const selectionStates = [
|
||||
['first-2', 'first-3', PAGINATION_FETCH_MORE_VALUE],
|
||||
['first-2', 'second-1', PAGINATION_FETCH_MORE_VALUE],
|
||||
['first-2', 'second-1', 'third-3'],
|
||||
];
|
||||
const limit = 5;
|
||||
const offset = 0;
|
||||
|
||||
mockQuery
|
||||
.mockResolvedValueOnce(createPaginatedQueryResponse(limit + 1, 'first'))
|
||||
// we need to insert the last item from the previous query
|
||||
// as the first item in the following query.
|
||||
// the id is used for grouping items, so it must match an id in the previous query
|
||||
.mockResolvedValueOnce(
|
||||
createPaginatedQueryResponse(limit + 1, 'second', {
|
||||
id: `first-${limit}`,
|
||||
value: `first-${limit}`,
|
||||
})
|
||||
)
|
||||
.mockResolvedValueOnce(
|
||||
createPaginatedQueryResponse(4, 'third', {
|
||||
id: `second-${limit}`,
|
||||
value: `second-${limit}`,
|
||||
})
|
||||
);
|
||||
jest
|
||||
.mocked(multiselectAsync)
|
||||
.mockResolvedValueOnce(selectionStates[0])
|
||||
.mockResolvedValueOnce(selectionStates[1])
|
||||
.mockResolvedValueOnce(selectionStates[2]);
|
||||
|
||||
const selectedQueryItems = await paginatedQueryWithMultiSelectPromptAsync({
|
||||
limit,
|
||||
offset,
|
||||
queryToPerform: mockQuery,
|
||||
promptOptions: {
|
||||
title: '',
|
||||
getIdentifierForQueryItem: item => item.id,
|
||||
createDisplayTextForSelectionPromptListItem: jest.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(selectedQueryItems).toEqual(
|
||||
selectionStates[2].map(selection => ({ id: selection, value: selection }))
|
||||
);
|
||||
});
|
||||
|
||||
it('does not fetch additional pages when "Next page..." is not selected', async () => {
|
||||
const limit = 5;
|
||||
const offset = 0;
|
||||
|
||||
mockQuery
|
||||
.mockResolvedValueOnce(createPaginatedQueryResponse(limit + 1, 'first'))
|
||||
// we need to insert the last item from the previous query
|
||||
// as the first item in the following query.
|
||||
// the id is used for grouping items, so it must match an id in the previous query
|
||||
.mockResolvedValueOnce(
|
||||
createPaginatedQueryResponse(limit + 1, 'second', {
|
||||
id: `first-${limit}`,
|
||||
value: `first-${limit}`,
|
||||
})
|
||||
);
|
||||
jest
|
||||
.mocked(multiselectAsync)
|
||||
.mockResolvedValueOnce([`first-0`])
|
||||
.mockResolvedValueOnce([`Fail this test`]);
|
||||
|
||||
const selectedQueryItems = await paginatedQueryWithMultiSelectPromptAsync({
|
||||
limit,
|
||||
offset,
|
||||
queryToPerform: mockQuery,
|
||||
promptOptions: {
|
||||
title: '',
|
||||
getIdentifierForQueryItem: item => item.id,
|
||||
createDisplayTextForSelectionPromptListItem: jest.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(selectedQueryItems).toEqual([{ id: `first-0`, value: `first-0` }]);
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ExpoChoice, confirmAsync, multiselectAsync, selectAsync } from '../prompts';
|
||||
import { confirmAsync, selectAsync } from '../prompts';
|
||||
import uniqBy from './expodash/uniqBy';
|
||||
import { PAGINATION_FETCH_MORE_VALUE } from './queryConstants';
|
||||
|
||||
const fetchMoreValue = '_fetchMore';
|
||||
|
||||
type BasePaginatedQueryArgs<QueryReturnType extends Record<string, any>> = {
|
||||
limit: number;
|
||||
@@ -68,6 +69,10 @@ async function paginatedQueryWithConfirmPromptInternalAsync<
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of item(s) where the id is equal to the id of the user's selected item
|
||||
* If no items are available for a user to select, this will return an empty array.
|
||||
*/
|
||||
export async function paginatedQueryWithSelectPromptAsync<
|
||||
QueryReturnType extends Record<string, any>
|
||||
>(queryArgs: PaginatedQueryWithSelectPromptArgs<QueryReturnType>): Promise<QueryReturnType | void> {
|
||||
@@ -94,23 +99,23 @@ async function paginatedQueryWithSelectPromptInternalAsync<
|
||||
|
||||
const selectionPromptListItems = uniqBy(newAccumulator, queryItem =>
|
||||
promptOptions.getIdentifierForQueryItem(queryItem)
|
||||
).map<ExpoChoice<string>>(queryItem => ({
|
||||
).map(queryItem => ({
|
||||
title: promptOptions.createDisplayTextForSelectionPromptListItem(queryItem),
|
||||
value: promptOptions.getIdentifierForQueryItem(queryItem),
|
||||
}));
|
||||
if (areMorePagesAvailable) {
|
||||
selectionPromptListItems.push({ title: 'Next page...', value: PAGINATION_FETCH_MORE_VALUE });
|
||||
selectionPromptListItems.push({ title: 'Next page...', value: fetchMoreValue });
|
||||
}
|
||||
if (selectionPromptListItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const valueOfUserSelectedListItem = await selectAsync(
|
||||
const valueOfUserSelectedListItem = await selectAsync<string>(
|
||||
promptOptions.title,
|
||||
selectionPromptListItems
|
||||
);
|
||||
|
||||
if (valueOfUserSelectedListItem === PAGINATION_FETCH_MORE_VALUE) {
|
||||
if (valueOfUserSelectedListItem === fetchMoreValue) {
|
||||
return await paginatedQueryWithSelectPromptInternalAsync(
|
||||
{
|
||||
limit,
|
||||
@@ -126,70 +131,3 @@ async function paginatedQueryWithSelectPromptInternalAsync<
|
||||
items => promptOptions.getIdentifierForQueryItem(items) === valueOfUserSelectedListItem
|
||||
);
|
||||
}
|
||||
|
||||
export async function paginatedQueryWithMultiSelectPromptAsync<
|
||||
QueryReturnType extends Record<string, any>
|
||||
>(
|
||||
queryArgs: PaginatedQueryWithSelectPromptArgs<QueryReturnType>
|
||||
): Promise<QueryReturnType[] | void> {
|
||||
return await paginatedQueryWithMultiSelectPromptInternalAsync(queryArgs, [], []);
|
||||
}
|
||||
|
||||
async function paginatedQueryWithMultiSelectPromptInternalAsync<
|
||||
QueryReturnType extends Record<string, any>
|
||||
>(
|
||||
{
|
||||
limit,
|
||||
offset,
|
||||
queryToPerform,
|
||||
promptOptions,
|
||||
}: PaginatedQueryWithSelectPromptArgs<QueryReturnType>,
|
||||
queryItemAccumulator: QueryReturnType[],
|
||||
selectedIdsAccumulator: string[]
|
||||
): Promise<QueryReturnType[] | void> {
|
||||
// query an extra item to determine if there are more pages left
|
||||
const paginatedItems = await queryToPerform(limit + 1, offset);
|
||||
const areMorePagesAvailable = paginatedItems.length > limit;
|
||||
// drop that extra item used for pagination from our render logic
|
||||
const currentPage = paginatedItems.slice(0, limit);
|
||||
const newQueryItemAccumulator = [...queryItemAccumulator, ...currentPage];
|
||||
|
||||
const selectionPromptListItems = uniqBy(newQueryItemAccumulator, queryItem =>
|
||||
promptOptions.getIdentifierForQueryItem(queryItem)
|
||||
).map<ExpoChoice<string>>(queryItem => ({
|
||||
title: promptOptions.createDisplayTextForSelectionPromptListItem(queryItem),
|
||||
value: promptOptions.getIdentifierForQueryItem(queryItem),
|
||||
selected: selectedIdsAccumulator.includes(promptOptions.getIdentifierForQueryItem(queryItem)),
|
||||
}));
|
||||
if (areMorePagesAvailable) {
|
||||
selectionPromptListItems.push({ title: 'Next page...', value: PAGINATION_FETCH_MORE_VALUE });
|
||||
}
|
||||
if (selectionPromptListItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const valueOfUserSelectedListItems = await multiselectAsync(
|
||||
promptOptions.title,
|
||||
selectionPromptListItems
|
||||
);
|
||||
const newSelectedIdsAccumulator = valueOfUserSelectedListItems.filter(
|
||||
id => id !== PAGINATION_FETCH_MORE_VALUE
|
||||
);
|
||||
|
||||
if (valueOfUserSelectedListItems.includes(PAGINATION_FETCH_MORE_VALUE)) {
|
||||
return await paginatedQueryWithMultiSelectPromptInternalAsync(
|
||||
{
|
||||
limit,
|
||||
offset: offset + limit,
|
||||
queryToPerform,
|
||||
promptOptions,
|
||||
},
|
||||
newQueryItemAccumulator,
|
||||
newSelectedIdsAccumulator
|
||||
);
|
||||
}
|
||||
|
||||
return newQueryItemAccumulator.filter(queryItem =>
|
||||
newSelectedIdsAccumulator.includes(promptOptions.getIdentifierForQueryItem(queryItem))
|
||||
);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export const PAGINATION_FETCH_MORE_VALUE = '_fetchMore';
|
||||
@@ -4191,11 +4191,6 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.6:
|
||||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
ansi-colors@^4.1.1:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b"
|
||||
integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==
|
||||
|
||||
ansi-escapes@^3.1.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
|
||||
@@ -5966,13 +5961,6 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1:
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
[email protected]:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
|
||||
integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
|
||||
dependencies:
|
||||
ansi-colors "^4.1.1"
|
||||
|
||||
[email protected], env-paths@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43"
|
||||
|
||||
Reference in new issue
Block a user