mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-14 10:08:06 -10:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a3563c963 | ||
|
|
98a20ac841 |
No files matched your search
@@ -8,6 +8,7 @@ This is the log of notable changes to EAS CLI and related packages.
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- [eas-cli] Add `eas submit:list` command to list submissions, including the runtime version and fingerprint of the submitted build. ([#4132](https://github.com/expo/eas-cli/pull/4132) by [@brentvatne](https://github.com/brentvatne))
|
||||
- [eas-build-job] Add optional `ssh` field on build/job payloads. ([#4083](https://github.com/expo/eas-cli/pull/4083) by [@gwdp](https://github.com/gwdp))
|
||||
- [eas-build-job] Add an `SSH_SESSION` build phase for upcoming worker SSH support. ([#4029](https://github.com/expo/eas-cli/pull/4029) by [@gwdp](https://github.com/gwdp))
|
||||
- [build-tools] Add `ref` input to the `eas/checkout` step to check out a different git ref (branch, tag, or commit SHA) than the one that triggered the job. ([#4035](https://github.com/expo/eas-cli/pull/4035) by [@sswrk](https://github.com/sswrk))
|
||||
|
||||
Generated
+1348
-15
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,109 @@
|
||||
import { Flags } from '@oclif/core';
|
||||
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import {
|
||||
EasNonInteractiveAndJsonFlags,
|
||||
resolveNonInteractiveAndJsonFlags,
|
||||
} from '../../commandUtils/flags';
|
||||
import {
|
||||
EasPaginatedQueryFlags,
|
||||
getLimitFlagWithCustomValues,
|
||||
getPaginatedQueryOptions,
|
||||
} from '../../commandUtils/pagination';
|
||||
import { AppPlatform, SubmissionStatus as GraphQLSubmissionStatus } from '../../graphql/generated';
|
||||
import { RequestedPlatform } from '../../platform';
|
||||
import { getDisplayNameForProjectIdAsync } from '../../project/projectUtils';
|
||||
import { SUBMISSIONS_LIMIT, listAndRenderSubmissionsOnAppAsync } from '../../submit/queries';
|
||||
import { enableJsonOutput } from '../../utils/json';
|
||||
|
||||
enum SubmissionStatus {
|
||||
AWAITING_BUILD = 'awaiting-build',
|
||||
IN_QUEUE = 'in-queue',
|
||||
IN_PROGRESS = 'in-progress',
|
||||
FINISHED = 'finished',
|
||||
ERRORED = 'errored',
|
||||
CANCELED = 'canceled',
|
||||
}
|
||||
|
||||
export default class SubmissionList extends EasCommand {
|
||||
static override description = 'list submissions for your project';
|
||||
|
||||
static override flags = {
|
||||
platform: Flags.option({
|
||||
options: Object.values(RequestedPlatform),
|
||||
char: 'p',
|
||||
})(),
|
||||
status: Flags.option({
|
||||
options: Object.values(SubmissionStatus),
|
||||
description: 'Filter only submissions with the specified status',
|
||||
})(),
|
||||
...EasPaginatedQueryFlags,
|
||||
limit: getLimitFlagWithCustomValues({ defaultTo: 10, limit: SUBMISSIONS_LIMIT }),
|
||||
...EasNonInteractiveAndJsonFlags,
|
||||
};
|
||||
|
||||
static override contextDefinition = {
|
||||
...this.ContextOptions.ProjectId,
|
||||
...this.ContextOptions.LoggedIn,
|
||||
};
|
||||
|
||||
async runAsync(): Promise<void> {
|
||||
const { flags } = await this.parse(SubmissionList);
|
||||
const paginatedQueryOptions = getPaginatedQueryOptions(flags);
|
||||
const { json: jsonFlag, nonInteractive } = resolveNonInteractiveAndJsonFlags(flags);
|
||||
const { platform: requestedPlatform, status: submissionStatus } = flags;
|
||||
const {
|
||||
projectId,
|
||||
loggedIn: { graphqlClient },
|
||||
} = await this.getContextAsync(SubmissionList, {
|
||||
nonInteractive,
|
||||
});
|
||||
if (jsonFlag) {
|
||||
enableJsonOutput();
|
||||
}
|
||||
|
||||
const platform = toAppPlatform(requestedPlatform);
|
||||
const graphqlSubmissionStatus = toGraphQLSubmissionStatus(submissionStatus);
|
||||
const displayName = await getDisplayNameForProjectIdAsync(graphqlClient, projectId);
|
||||
|
||||
await listAndRenderSubmissionsOnAppAsync(graphqlClient, {
|
||||
projectId,
|
||||
projectDisplayName: displayName,
|
||||
filter: {
|
||||
platform,
|
||||
status: graphqlSubmissionStatus,
|
||||
},
|
||||
paginatedQueryOptions,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const toAppPlatform = (requestedPlatform?: RequestedPlatform): AppPlatform | undefined => {
|
||||
if (!requestedPlatform || requestedPlatform === RequestedPlatform.All) {
|
||||
return undefined;
|
||||
} else if (requestedPlatform === RequestedPlatform.Android) {
|
||||
return AppPlatform.Android;
|
||||
} else {
|
||||
return AppPlatform.Ios;
|
||||
}
|
||||
};
|
||||
|
||||
const toGraphQLSubmissionStatus = (
|
||||
submissionStatus?: SubmissionStatus
|
||||
): GraphQLSubmissionStatus | undefined => {
|
||||
if (!submissionStatus) {
|
||||
return undefined;
|
||||
} else if (submissionStatus === SubmissionStatus.AWAITING_BUILD) {
|
||||
return GraphQLSubmissionStatus.AwaitingBuild;
|
||||
} else if (submissionStatus === SubmissionStatus.IN_QUEUE) {
|
||||
return GraphQLSubmissionStatus.InQueue;
|
||||
} else if (submissionStatus === SubmissionStatus.IN_PROGRESS) {
|
||||
return GraphQLSubmissionStatus.InProgress;
|
||||
} else if (submissionStatus === SubmissionStatus.FINISHED) {
|
||||
return GraphQLSubmissionStatus.Finished;
|
||||
} else if (submissionStatus === SubmissionStatus.ERRORED) {
|
||||
return GraphQLSubmissionStatus.Errored;
|
||||
} else {
|
||||
return GraphQLSubmissionStatus.Canceled;
|
||||
}
|
||||
};
|
||||
+233
-5
@@ -180,6 +180,8 @@ export type Account = {
|
||||
ssoConfiguration?: Maybe<AccountSsoConfiguration>;
|
||||
/** Subscription info visible to members that have VIEWER role */
|
||||
subscription?: Maybe<SubscriptionDetails>;
|
||||
/** Supabase connection for this account */
|
||||
supabaseConnection?: Maybe<SupabaseConnection>;
|
||||
/** Coalesced project activity for an app using pagination */
|
||||
timelineActivity: TimelineActivityConnection;
|
||||
updatedAt: Scalars['DateTime']['output'];
|
||||
@@ -1494,6 +1496,7 @@ export type App = Project & {
|
||||
submissions: Array<Submission>;
|
||||
submissionsPaginated: AppSubmissionsConnection;
|
||||
suggestedDevDomainName: Scalars['String']['output'];
|
||||
supabaseProject?: Maybe<SupabaseProject>;
|
||||
/** Coalesced project activity for an app using pagination */
|
||||
timelineActivity: TimelineActivityConnection;
|
||||
turtleBrownfieldArtifactsPaginated: BrownfieldArtifactsConnection;
|
||||
@@ -2875,15 +2878,16 @@ export type AppObserveOverviewUpdate = {
|
||||
__typename?: 'AppObserveOverviewUpdate';
|
||||
/** Null for the embedded bundle. */
|
||||
appUpdateId?: Maybe<Scalars['ID']['output']>;
|
||||
/** Downloads recorded in range; null when none were recorded (and always for the embedded bundle). */
|
||||
/** Downloads recorded in range across platforms; null when none were recorded (and always for the embedded bundle). */
|
||||
downloadCount?: Maybe<Scalars['Int']['output']>;
|
||||
/** One entry per platform with downloads in range; empty for the embedded bundle. */
|
||||
downloads: Array<AppObserveOverviewUpdateDownload>;
|
||||
eventCount: Scalars['Int']['output'];
|
||||
firstSeenAt: Scalars['DateTime']['output'];
|
||||
isEmbedded: Scalars['Boolean']['output'];
|
||||
medianDownloadTime?: Maybe<Scalars['Float']['output']>;
|
||||
/** EAS update message; null for the embedded bundle or when the update row no longer exists. */
|
||||
message?: Maybe<Scalars['String']['output']>;
|
||||
/** One entry per metric with data in range, all platforms combined. */
|
||||
/** One entry per (metric, platform) with data in range. */
|
||||
metrics: Array<AppObserveOverviewUpdateMetric>;
|
||||
/** When the update was published; null for the embedded bundle. */
|
||||
publishedAt?: Maybe<Scalars['DateTime']['output']>;
|
||||
@@ -2906,10 +2910,18 @@ export type AppObserveOverviewUpdateComparisonInput = {
|
||||
startTime: Scalars['DateTime']['input'];
|
||||
};
|
||||
|
||||
export type AppObserveOverviewUpdateDownload = {
|
||||
__typename?: 'AppObserveOverviewUpdateDownload';
|
||||
downloadCount: Scalars['Int']['output'];
|
||||
medianDownloadTime: Scalars['Float']['output'];
|
||||
platform: AppObservePlatform;
|
||||
};
|
||||
|
||||
export type AppObserveOverviewUpdateMetric = {
|
||||
__typename?: 'AppObserveOverviewUpdateMetric';
|
||||
eventCount: Scalars['Int']['output'];
|
||||
metricName: Scalars['String']['output'];
|
||||
platform: AppObservePlatform;
|
||||
statistics: AppObserveVersionMarkerStatistics;
|
||||
};
|
||||
|
||||
@@ -4177,6 +4189,10 @@ export enum BackgroundJobState {
|
||||
Success = 'SUCCESS'
|
||||
}
|
||||
|
||||
export type BeginSupabaseOAuthInput = {
|
||||
accountId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export type Billing = {
|
||||
__typename?: 'Billing';
|
||||
/** History of invoices */
|
||||
@@ -4894,6 +4910,11 @@ export type CompletePostHogConnectionInput = {
|
||||
state: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export type CompleteSupabaseOAuthInput = {
|
||||
code: Scalars['String']['input'];
|
||||
state: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export type Concurrencies = {
|
||||
__typename?: 'Concurrencies';
|
||||
android: Scalars['Int']['output'];
|
||||
@@ -5897,6 +5918,8 @@ export type DeviceRunSessionEventLogUploadSession = {
|
||||
};
|
||||
|
||||
export type DeviceRunSessionFilterInput = {
|
||||
/** Case-insensitive prefix match on the session name. */
|
||||
name?: InputMaybe<Scalars['String']['input']>;
|
||||
platforms?: InputMaybe<Array<AppPlatform>>;
|
||||
statuses?: InputMaybe<Array<DeviceRunSessionStatus>>;
|
||||
types?: InputMaybe<Array<DeviceRunSessionType>>;
|
||||
@@ -6856,12 +6879,15 @@ export enum EntityTypeName {
|
||||
CustomerEntity = 'CustomerEntity',
|
||||
EchoProjectEntity = 'EchoProjectEntity',
|
||||
EchoVersionEntity = 'EchoVersionEntity',
|
||||
EnvironmentVariableEntity = 'EnvironmentVariableEntity',
|
||||
GoogleServiceAccountKeyEntity = 'GoogleServiceAccountKeyEntity',
|
||||
IosAppCredentialsEntity = 'IosAppCredentialsEntity',
|
||||
LogRocketOrganizationEntity = 'LogRocketOrganizationEntity',
|
||||
LogRocketProjectEntity = 'LogRocketProjectEntity',
|
||||
PostHogOrganizationConnectionEntity = 'PostHogOrganizationConnectionEntity',
|
||||
PostHogProjectEntity = 'PostHogProjectEntity',
|
||||
SupabaseConnectionEntity = 'SupabaseConnectionEntity',
|
||||
SupabaseProjectEntity = 'SupabaseProjectEntity',
|
||||
UserInvitationEntity = 'UserInvitationEntity',
|
||||
UserPermissionEntity = 'UserPermissionEntity',
|
||||
VexoAccountConnectionEntity = 'VexoAccountConnectionEntity',
|
||||
@@ -8254,10 +8280,18 @@ export type JobRunError = {
|
||||
message: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type JobRunLogsCentrifugoSubscriptionToken = {
|
||||
__typename?: 'JobRunLogsCentrifugoSubscriptionToken';
|
||||
channel: Scalars['String']['output'];
|
||||
token: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type JobRunMutation = {
|
||||
__typename?: 'JobRunMutation';
|
||||
/** Cancel an EAS Job Run */
|
||||
cancelJobRun: JobRun;
|
||||
/** Generate a token for subscribing to an EAS Job Run log channel */
|
||||
generateLogsCentrifugoSubscriptionToken: JobRunLogsCentrifugoSubscriptionToken;
|
||||
};
|
||||
|
||||
|
||||
@@ -8265,6 +8299,12 @@ export type JobRunMutationCancelJobRunArgs = {
|
||||
jobRunId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type JobRunMutationGenerateLogsCentrifugoSubscriptionTokenArgs = {
|
||||
jobRunId: Scalars['ID']['input'];
|
||||
thread?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export enum JobRunPriority {
|
||||
High = 'HIGH',
|
||||
Normal = 'NORMAL'
|
||||
@@ -8350,6 +8390,11 @@ export type LinkSentryInstallationToExpoAccountInput = {
|
||||
sentryOrgSlug: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type LinkSupabaseProjectInput = {
|
||||
appId: Scalars['ID']['input'];
|
||||
supabaseProjectRef: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type LocalBuildArchiveSourceInput = {
|
||||
bucketKey: Scalars['String']['input'];
|
||||
type: LocalBuildArchiveSourceType;
|
||||
@@ -8952,6 +8997,20 @@ export type ProjectPublicData = {
|
||||
id: Scalars['ID']['output'];
|
||||
};
|
||||
|
||||
export type ProvisionAdditionalSupabaseProjectInput = {
|
||||
appId: Scalars['ID']['input'];
|
||||
/** Suffix appended to the app name for the new Supabase project (e.g. preview). */
|
||||
projectNameSuffix: Scalars['String']['input'];
|
||||
/** A Supabase region code (e.g. us-east-1) or smart-group (americas, emea, apac). */
|
||||
region: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type ProvisionSupabaseProjectInput = {
|
||||
appId: Scalars['ID']['input'];
|
||||
/** A Supabase region code (e.g. us-east-1) or smart-group (americas, emea, apac). */
|
||||
region: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type PublicArtifacts = {
|
||||
__typename?: 'PublicArtifacts';
|
||||
applicationArchiveUrl?: Maybe<Scalars['String']['output']>;
|
||||
@@ -8977,6 +9036,17 @@ export type PublishUpdateGroupInput = {
|
||||
updateInfoGroup?: InputMaybe<UpdateInfoGroup>;
|
||||
};
|
||||
|
||||
export type RealtimeLogsCentrifugoConnectionToken = {
|
||||
__typename?: 'RealtimeLogsCentrifugoConnectionToken';
|
||||
token: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type RealtimeLogsMutation = {
|
||||
__typename?: 'RealtimeLogsMutation';
|
||||
/** Generate a token for connecting to EAS Logs Centrifugo */
|
||||
generateCentrifugoConnectionToken: RealtimeLogsCentrifugoConnectionToken;
|
||||
};
|
||||
|
||||
export type RemoteAppStoreConnectApp = {
|
||||
__typename?: 'RemoteAppStoreConnectApp';
|
||||
appStoreIconUrl?: Maybe<Scalars['String']['output']>;
|
||||
@@ -9257,6 +9327,7 @@ export type RootMutation = {
|
||||
notificationPreference: NotificationPreferenceMutation;
|
||||
posthogOrganizationConnection: PostHogOrganizationConnectionMutation;
|
||||
posthogProject: PostHogProjectMutation;
|
||||
realtimeLogs: RealtimeLogsMutation;
|
||||
/** Mutations that create, update, and delete Robots */
|
||||
robot: RobotMutation;
|
||||
/** Mutations for Sentry installations */
|
||||
@@ -9265,6 +9336,8 @@ export type RootMutation = {
|
||||
sentryProject: SentryProjectMutation;
|
||||
/** Mutations that modify an EAS Submit submission */
|
||||
submission: SubmissionMutation;
|
||||
supabaseConnection: SupabaseConnectionMutation;
|
||||
supabaseProject: SupabaseProjectMutation;
|
||||
tunnels: TunnelsMutation;
|
||||
turtleBrownfieldArtifacts: TurtleBrownfieldArtifactMutation;
|
||||
update: UpdateMutation;
|
||||
@@ -9757,6 +9830,11 @@ export type ServeSimRunSessionRemoteConfig = {
|
||||
streamUrl?: Maybe<Scalars['String']['output']>;
|
||||
};
|
||||
|
||||
export type SetSupabaseConnectionOrganizationInput = {
|
||||
organizationSlug: Scalars['String']['input'];
|
||||
supabaseConnectionId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export type SetupConvexProjectInput = {
|
||||
appId: Scalars['ID']['input'];
|
||||
convexTeamConnectionId: Scalars['ID']['input'];
|
||||
@@ -10103,6 +10181,138 @@ export type SubscriptionDetailsPlanEnablementArgs = {
|
||||
serviceMetric: EasServiceMetric;
|
||||
};
|
||||
|
||||
export type SupabaseConnection = {
|
||||
__typename?: 'SupabaseConnection';
|
||||
account: Account;
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
supabaseOrganizationName: Scalars['String']['output'];
|
||||
/** The organization new projects are provisioned under. Chosen at connect time; defaults to the first. */
|
||||
supabaseOrganizationSlug: Scalars['String']['output'];
|
||||
supabaseProjects: Array<SupabaseProject>;
|
||||
updatedAt: Scalars['DateTime']['output'];
|
||||
};
|
||||
|
||||
export type SupabaseConnectionMutation = {
|
||||
__typename?: 'SupabaseConnectionMutation';
|
||||
/** Begins a Supabase connection: creates the PKCE handoff and returns the authorize URL. */
|
||||
beginSupabaseOAuth: SupabaseOAuthStart;
|
||||
/**
|
||||
* Completes a connection from the browser callback: exchanges the authorization code with the
|
||||
* stored PKCE verifier and persists the connection.
|
||||
*/
|
||||
completeSupabaseOAuth: SupabaseConnection;
|
||||
/** Removes the Expo-side connection only; the Supabase organization and its projects are preserved. */
|
||||
disconnectSupabase: Scalars['ID']['output'];
|
||||
/**
|
||||
* Live list of Supabase organizations this connection can access (Management API). Used once at
|
||||
* connect-time for the org picker — not a type field, so casual connection reads stay cheap.
|
||||
*/
|
||||
listSupabaseOrganizations: Array<SupabaseOrganization>;
|
||||
/** Sets which Supabase organization new projects are provisioned under (the connect-time picker). */
|
||||
setSupabaseConnectionOrganization: SupabaseConnection;
|
||||
};
|
||||
|
||||
|
||||
export type SupabaseConnectionMutationBeginSupabaseOAuthArgs = {
|
||||
input: BeginSupabaseOAuthInput;
|
||||
};
|
||||
|
||||
|
||||
export type SupabaseConnectionMutationCompleteSupabaseOAuthArgs = {
|
||||
input: CompleteSupabaseOAuthInput;
|
||||
};
|
||||
|
||||
|
||||
export type SupabaseConnectionMutationDisconnectSupabaseArgs = {
|
||||
id: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type SupabaseConnectionMutationListSupabaseOrganizationsArgs = {
|
||||
accountId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type SupabaseConnectionMutationSetSupabaseConnectionOrganizationArgs = {
|
||||
input: SetSupabaseConnectionOrganizationInput;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handoff for the browser OAuth step. The CLI opens `url`, and once the user authorizes,
|
||||
* the website callback completes the connection; the CLI polls for it with `state`.
|
||||
*/
|
||||
export type SupabaseOAuthStart = {
|
||||
__typename?: 'SupabaseOAuthStart';
|
||||
state: Scalars['ID']['output'];
|
||||
url: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type SupabaseOrganization = {
|
||||
__typename?: 'SupabaseOrganization';
|
||||
id: Scalars['ID']['output'];
|
||||
name: Scalars['String']['output'];
|
||||
slug: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type SupabaseProject = {
|
||||
__typename?: 'SupabaseProject';
|
||||
app: App;
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
supabaseConnection: SupabaseConnection;
|
||||
supabaseProjectName: Scalars['String']['output'];
|
||||
supabaseProjectRef: Scalars['String']['output'];
|
||||
supabaseProjectUrl: Scalars['String']['output'];
|
||||
supabaseRegion: Scalars['String']['output'];
|
||||
updatedAt: Scalars['DateTime']['output'];
|
||||
};
|
||||
|
||||
export type SupabaseProjectMutation = {
|
||||
__typename?: 'SupabaseProjectMutation';
|
||||
/** Removes the Expo-side project link only; the Supabase project is preserved. */
|
||||
deleteSupabaseProject: Scalars['ID']['output'];
|
||||
/**
|
||||
* Live publishable (anon) key for the app's linked Supabase project (Management API). Never
|
||||
* stored — null while the project is still provisioning. Used by the CLI to write EAS env vars.
|
||||
*/
|
||||
fetchSupabasePublishableKey?: Maybe<Scalars['String']['output']>;
|
||||
/** Links an existing Supabase project (by ref) to the app. */
|
||||
linkSupabaseProject: SupabaseProject;
|
||||
/**
|
||||
* Schedules an additional hosted Supabase project for selected EAS environments. Does not replace
|
||||
* the app's primary linked project — poll the receipt for ref/url/publishableKey in resultData.
|
||||
*/
|
||||
provisionAdditionalSupabaseProject: BackgroundJobReceipt;
|
||||
/** Schedules provisioning of a new Supabase project for the app. Poll the returned receipt until success, then read app.supabaseProject. */
|
||||
provisionSupabaseProject: BackgroundJobReceipt;
|
||||
};
|
||||
|
||||
|
||||
export type SupabaseProjectMutationDeleteSupabaseProjectArgs = {
|
||||
id: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type SupabaseProjectMutationFetchSupabasePublishableKeyArgs = {
|
||||
appId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type SupabaseProjectMutationLinkSupabaseProjectArgs = {
|
||||
input: LinkSupabaseProjectInput;
|
||||
};
|
||||
|
||||
|
||||
export type SupabaseProjectMutationProvisionAdditionalSupabaseProjectArgs = {
|
||||
input: ProvisionAdditionalSupabaseProjectInput;
|
||||
};
|
||||
|
||||
|
||||
export type SupabaseProjectMutationProvisionSupabaseProjectArgs = {
|
||||
input: ProvisionSupabaseProjectInput;
|
||||
};
|
||||
|
||||
export enum TargetEntityMutationType {
|
||||
Create = 'CREATE',
|
||||
Delete = 'DELETE',
|
||||
@@ -12400,7 +12610,7 @@ export type WorkflowDeviceTestCaseResult = {
|
||||
export type WorkflowDeviceTestCaseResultInput = {
|
||||
/** Execution time in milliseconds. Must be non-negative. */
|
||||
duration?: InputMaybe<Scalars['Int']['input']>;
|
||||
/** Error message if failed. Max 4096 characters. */
|
||||
/** Error message if failed. Truncated to 4096 characters. */
|
||||
errorMessage?: InputMaybe<Scalars['String']['input']>;
|
||||
/** Test case name (e.g., "login", "checkout"). Max 255 characters. */
|
||||
name: Scalars['String']['input'];
|
||||
@@ -14820,7 +15030,15 @@ export type GetAllSubmissionsForAppQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type GetAllSubmissionsForAppQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, submissions: Array<{ __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logFiles: Array<string>, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: string, releaseStatus?: SubmissionAndroidReleaseStatus | null, rollout?: number | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null }> } } };
|
||||
export type GetAllSubmissionsForAppQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, submissions: Array<{ __typename?: 'Submission', id: string, createdAt: any, completedAt?: any | null, status: SubmissionStatus, platform: AppPlatform, logFiles: Array<string>, submittedBuild?: { __typename?: 'Build', id: string, status: BuildStatus, platform: AppPlatform, logFiles: Array<string>, channel?: string | null, distribution?: DistributionType | null, iosEnterpriseProvisioning?: BuildIosEnterpriseProvisioning | null, buildProfile?: string | null, sdkVersion?: string | null, appVersion?: string | null, appBuildVersion?: string | null, runtimeVersion?: string | null, gitCommitHash?: string | null, gitCommitMessage?: string | null, initialQueuePosition?: number | null, queuePosition?: number | null, estimatedWaitTimeLeftSeconds?: number | null, priority: BuildPriority, createdAt: any, updatedAt: any, message?: string | null, completedAt?: any | null, expirationDate?: any | null, isForIosSimulator: boolean, error?: { __typename?: 'BuildError', errorCode: string, message: string, docsUrl?: string | null } | null, artifacts?: { __typename?: 'BuildArtifacts', buildUrl?: string | null, xcodeBuildLogsUrl?: string | null, applicationArchiveUrl?: string | null, buildArtifactsUrl?: string | null } | null, fingerprint?: { __typename?: 'Fingerprint', id: string, hash: string } | null, initiatingActor?:
|
||||
| { __typename: 'PartnerActor', id: string, displayName: string }
|
||||
| { __typename: 'Robot', id: string, displayName: string }
|
||||
| { __typename: 'SSOUser', id: string, displayName: string }
|
||||
| { __typename: 'User', id: string, displayName: string }
|
||||
| null, project:
|
||||
| { __typename: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }
|
||||
| { __typename: 'Snack', id: string, name: string, slug: string }
|
||||
, metrics?: { __typename?: 'BuildMetrics', buildWaitTime?: number | null, buildQueueTime?: number | null, buildDuration?: number | null } | null } | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: string, releaseStatus?: SubmissionAndroidReleaseStatus | null, rollout?: number | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null }> } } };
|
||||
|
||||
export type ViewUpdateGroupInsightsQueryVariables = Exact<{
|
||||
groupId: Scalars['ID']['input'];
|
||||
@@ -15158,6 +15376,16 @@ export type StatuspageServiceFragment = { __typename?: 'StatuspageService', id:
|
||||
|
||||
export type SubmissionFragment = { __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logFiles: Array<string>, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: string, releaseStatus?: SubmissionAndroidReleaseStatus | null, rollout?: number | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null };
|
||||
|
||||
export type SubmissionWithSubmittedBuildFragment = { __typename?: 'Submission', id: string, createdAt: any, completedAt?: any | null, status: SubmissionStatus, platform: AppPlatform, logFiles: Array<string>, submittedBuild?: { __typename?: 'Build', id: string, status: BuildStatus, platform: AppPlatform, logFiles: Array<string>, channel?: string | null, distribution?: DistributionType | null, iosEnterpriseProvisioning?: BuildIosEnterpriseProvisioning | null, buildProfile?: string | null, sdkVersion?: string | null, appVersion?: string | null, appBuildVersion?: string | null, runtimeVersion?: string | null, gitCommitHash?: string | null, gitCommitMessage?: string | null, initialQueuePosition?: number | null, queuePosition?: number | null, estimatedWaitTimeLeftSeconds?: number | null, priority: BuildPriority, createdAt: any, updatedAt: any, message?: string | null, completedAt?: any | null, expirationDate?: any | null, isForIosSimulator: boolean, error?: { __typename?: 'BuildError', errorCode: string, message: string, docsUrl?: string | null } | null, artifacts?: { __typename?: 'BuildArtifacts', buildUrl?: string | null, xcodeBuildLogsUrl?: string | null, applicationArchiveUrl?: string | null, buildArtifactsUrl?: string | null } | null, fingerprint?: { __typename?: 'Fingerprint', id: string, hash: string } | null, initiatingActor?:
|
||||
| { __typename: 'PartnerActor', id: string, displayName: string }
|
||||
| { __typename: 'Robot', id: string, displayName: string }
|
||||
| { __typename: 'SSOUser', id: string, displayName: string }
|
||||
| { __typename: 'User', id: string, displayName: string }
|
||||
| null, project:
|
||||
| { __typename: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }
|
||||
| { __typename: 'Snack', id: string, name: string, slug: string }
|
||||
, metrics?: { __typename?: 'BuildMetrics', buildWaitTime?: number | null, buildQueueTime?: number | null, buildDuration?: number | null } | null } | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: string, releaseStatus?: SubmissionAndroidReleaseStatus | null, rollout?: number | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null };
|
||||
|
||||
export type UpdateFragment = { __typename?: 'Update', id: string, group: string, message?: string | null, createdAt: any, runtimeVersion: string, platform: string, manifestFragment: string, isRollBackToEmbedded: boolean, manifestPermalink: string, gitCommitHash?: string | null, isGitWorkingTreeDirty: boolean, environment?: any | null, rolloutPercentage?: number | null, manifestHostOverride?: string | null, assetHostOverride?: string | null, actor?:
|
||||
| { __typename: 'PartnerActor', username: string, id: string }
|
||||
| { __typename: 'Robot', firstName?: string | null, id: string }
|
||||
|
||||
@@ -9,10 +9,12 @@ import {
|
||||
GetAllSubmissionsForAppQueryVariables,
|
||||
SubmissionFragment,
|
||||
SubmissionStatus,
|
||||
SubmissionWithSubmittedBuildFragment,
|
||||
SubmissionsByIdQuery,
|
||||
SubmissionsByIdQueryVariables,
|
||||
} from '../generated';
|
||||
import { SubmissionFragmentNode } from '../types/Submission';
|
||||
import { SubmissionWithSubmittedBuildFragmentNode } from '../types/SubmissionWithSubmittedBuild';
|
||||
|
||||
type Filters = {
|
||||
platform?: AppPlatform;
|
||||
@@ -56,7 +58,7 @@ export const SubmissionQuery = {
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
appId: string,
|
||||
{ limit = 10, offset = 0, status, platform }: Filters
|
||||
): Promise<SubmissionFragment[]> {
|
||||
): Promise<SubmissionWithSubmittedBuildFragment[]> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<GetAllSubmissionsForAppQuery, GetAllSubmissionsForAppQueryVariables>(
|
||||
@@ -77,12 +79,12 @@ export const SubmissionQuery = {
|
||||
limit: $limit
|
||||
) {
|
||||
id
|
||||
...SubmissionFragment
|
||||
...SubmissionWithSubmittedBuildFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${print(SubmissionFragmentNode)}
|
||||
${print(SubmissionWithSubmittedBuildFragmentNode)}
|
||||
`,
|
||||
{ appId, offset, limit, status, platform },
|
||||
{ additionalTypenames: ['Submission'] }
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { print } from 'graphql';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { BuildFragmentNode } from './Build';
|
||||
import { SubmissionFragmentNode } from './Submission';
|
||||
|
||||
export const SubmissionWithSubmittedBuildFragmentNode = gql`
|
||||
${print(BuildFragmentNode)}
|
||||
${print(SubmissionFragmentNode)}
|
||||
|
||||
fragment SubmissionWithSubmittedBuildFragment on Submission {
|
||||
id
|
||||
...SubmissionFragment
|
||||
createdAt
|
||||
completedAt
|
||||
submittedBuild {
|
||||
id
|
||||
...BuildFragment
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,84 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { formatGraphQLSubmission } from './utils/formatSubmission';
|
||||
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { PaginatedQueryOptions } from '../commandUtils/pagination';
|
||||
import {
|
||||
AppPlatform,
|
||||
SubmissionStatus,
|
||||
SubmissionWithSubmittedBuildFragment,
|
||||
} from '../graphql/generated';
|
||||
import { SubmissionQuery } from '../graphql/queries/SubmissionQuery';
|
||||
import Log from '../log';
|
||||
import { printJsonOnlyOutput } from '../utils/json';
|
||||
import { paginatedQueryWithConfirmPromptAsync } from '../utils/queries';
|
||||
|
||||
export const SUBMISSIONS_LIMIT = 50;
|
||||
|
||||
export type SubmissionFilter = {
|
||||
platform?: AppPlatform;
|
||||
status?: SubmissionStatus;
|
||||
};
|
||||
|
||||
export async function listAndRenderSubmissionsOnAppAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
{
|
||||
projectId,
|
||||
projectDisplayName,
|
||||
filter,
|
||||
paginatedQueryOptions,
|
||||
}: {
|
||||
projectId: string;
|
||||
projectDisplayName: string;
|
||||
filter?: SubmissionFilter;
|
||||
paginatedQueryOptions: PaginatedQueryOptions;
|
||||
}
|
||||
): Promise<void> {
|
||||
if (paginatedQueryOptions.nonInteractive) {
|
||||
const submissions = await SubmissionQuery.allForAppAsync(graphqlClient, projectId, {
|
||||
limit: paginatedQueryOptions.limit ?? SUBMISSIONS_LIMIT,
|
||||
offset: paginatedQueryOptions.offset,
|
||||
...filter,
|
||||
});
|
||||
renderPageOfSubmissions({ submissions, projectDisplayName, paginatedQueryOptions });
|
||||
} else {
|
||||
await paginatedQueryWithConfirmPromptAsync({
|
||||
limit: paginatedQueryOptions.limit ?? SUBMISSIONS_LIMIT,
|
||||
offset: paginatedQueryOptions.offset,
|
||||
queryToPerform: (limit, offset) =>
|
||||
SubmissionQuery.allForAppAsync(graphqlClient, projectId, {
|
||||
limit,
|
||||
offset,
|
||||
...filter,
|
||||
}),
|
||||
promptOptions: {
|
||||
title: 'Load more submissions?',
|
||||
renderListItems: submissions => {
|
||||
renderPageOfSubmissions({ submissions, projectDisplayName, paginatedQueryOptions });
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renderPageOfSubmissions({
|
||||
submissions,
|
||||
projectDisplayName,
|
||||
paginatedQueryOptions,
|
||||
}: {
|
||||
submissions: SubmissionWithSubmittedBuildFragment[];
|
||||
projectDisplayName: string;
|
||||
paginatedQueryOptions: PaginatedQueryOptions;
|
||||
}): void {
|
||||
if (paginatedQueryOptions.json) {
|
||||
printJsonOnlyOutput(submissions);
|
||||
} else {
|
||||
const list = submissions
|
||||
.map(submission => formatGraphQLSubmission(submission))
|
||||
.join(`\n\n${chalk.dim('———')}\n\n`);
|
||||
|
||||
Log.addNewLineIfNone();
|
||||
Log.log(chalk.bold(`Submissions for ${projectDisplayName}:`));
|
||||
Log.log(`\n${list}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { getSubmissionDetailsUrl } from './urls';
|
||||
import {
|
||||
AppPlatform,
|
||||
SubmissionStatus,
|
||||
SubmissionWithSubmittedBuildFragment,
|
||||
} from '../../graphql/generated';
|
||||
import { link } from '../../log';
|
||||
import { appPlatformDisplayNames } from '../../platform';
|
||||
import formatFields from '../../utils/formatFields';
|
||||
|
||||
export function formatGraphQLSubmission(submission: SubmissionWithSubmittedBuildFragment): string {
|
||||
const { submittedBuild } = submission;
|
||||
const fields: { label: string; value?: string | null }[] = [
|
||||
{ label: 'ID', value: submission.id },
|
||||
{
|
||||
label: 'Platform',
|
||||
value: appPlatformDisplayNames[submission.platform],
|
||||
},
|
||||
{
|
||||
label: 'Status',
|
||||
get value() {
|
||||
switch (submission.status) {
|
||||
case SubmissionStatus.AwaitingBuild:
|
||||
return chalk.blue('awaiting build');
|
||||
case SubmissionStatus.InQueue:
|
||||
return chalk.blue('in queue');
|
||||
case SubmissionStatus.InProgress:
|
||||
return chalk.blue('in progress');
|
||||
case SubmissionStatus.Finished:
|
||||
return chalk.green('finished');
|
||||
case SubmissionStatus.Errored:
|
||||
return chalk.red('errored');
|
||||
case SubmissionStatus.Canceled:
|
||||
return chalk.gray('canceled');
|
||||
default:
|
||||
return 'unknown';
|
||||
}
|
||||
},
|
||||
},
|
||||
...(submission.platform === AppPlatform.Android
|
||||
? [
|
||||
{
|
||||
label: 'Application Identifier',
|
||||
value: submission.androidConfig?.applicationIdentifier,
|
||||
},
|
||||
{ label: 'Track', value: submission.androidConfig?.track?.toLowerCase() },
|
||||
{ label: 'Release Status', value: submission.androidConfig?.releaseStatus?.toLowerCase() },
|
||||
]
|
||||
: [{ label: 'ASC App ID', value: submission.iosConfig?.ascAppIdentifier }]),
|
||||
{ label: 'Build ID', value: submittedBuild?.id },
|
||||
{ label: 'Build Profile', value: submittedBuild?.buildProfile },
|
||||
{ label: 'App Version', value: submittedBuild?.appVersion },
|
||||
{
|
||||
label: submission.platform === AppPlatform.Android ? 'Version code' : 'Build number',
|
||||
value: submittedBuild?.appBuildVersion,
|
||||
},
|
||||
{ label: 'Runtime Version', value: submittedBuild?.runtimeVersion },
|
||||
{ label: 'Fingerprint', value: submittedBuild?.fingerprint?.hash },
|
||||
{ label: 'Commit', value: submittedBuild?.gitCommitHash },
|
||||
{ label: 'Error Code', value: submission.error?.errorCode },
|
||||
{ label: 'Error Message', value: submission.error?.message },
|
||||
{ label: 'Started at', value: new Date(submission.createdAt).toLocaleString() },
|
||||
{
|
||||
label: 'Finished at',
|
||||
value: submission.completedAt ? new Date(submission.completedAt).toLocaleString() : null,
|
||||
},
|
||||
{ label: 'Submission Details', value: link(getSubmissionDetailsUrl(submission)) },
|
||||
];
|
||||
|
||||
const filteredFields = fields.filter(({ value }) => value !== undefined && value !== null) as {
|
||||
label: string;
|
||||
value: string;
|
||||
}[];
|
||||
return formatFields(filteredFields);
|
||||
}
|
||||
Reference in new issue
Block a user