Compare commits

..
Author SHA1 Message Date
Quinlan Jung 819f0b4c6f sdf 2023-07-18 12:52:23 -07:00
Quinlan Jung 9ffd3a096b fix test 2023-07-18 11:52:51 -07:00
Quinlan Jung e3ff26e1ca update CHANGELOG.md 2023-07-18 17:56:15 +00:00
Quinlan Jung bbd26a8030 [eas-cli] bump urql graphql client 2023-07-18 10:42:44 -07:00
Piotr SzeremetaandSzymon Dziedzic 57dd372957 [ENG-9283][eas-cli] Throw error when project tarball exceeds 1GB (#1928)
* [ENG-9283][eas-cli] Throw error when project tarball exceeds 1GB

* update CHANGELOG.md

* Update packages/eas-cli/src/build/build.ts

Co-authored-by: Szymon Dziedzic <[email protected]>

* Update packages/eas-cli/src/build/build.ts

Co-authored-by: Szymon Dziedzic <[email protected]>

* Update CHANGELOG.md

Co-authored-by: Szymon Dziedzic <[email protected]>

---------

Co-authored-by: Szymon Dziedzic <[email protected]>
2023-07-17 14:12:17 +02:00
Will Schurman 5232641217 [eas-cli] Use node server default port selection for SSO login server (#1930) 2023-07-13 09:29:51 -07:00
Cedric van Putten 3c3d3150c9 [eas-cli] Ignore the existing entitlements when ios is gitignored (#1906)
* [eas-cli] Ignore the existing entitlements when ios is gitignored

* chore: add changelog entry
2023-07-13 16:51:39 +02:00
Will Schurman fd322d4189 [eas-cli] Add styling to SSO auth redirect completion page (#1929) 2023-07-12 09:11:03 -07:00
Expo CI 77254f6be1 update CHANGELOG.md 2023-07-11 06:59:32 +00:00
15 changed files with 186 additions and 89 deletions

No files matched your search

+13
View File
@@ -8,6 +8,19 @@ This is the log of notable changes to EAS CLI and related packages.
### 🎉 New features
- Add styling to SSO auth redirect completion page. ([#1929](https://github.com/expo/eas-cli/pull/1929) by [@wschurman](https://github.com/wschurman))
- Ignore entitlements from native template when `/ios` is gitignored. ([#1906](https://github.com/expo/eas-cli/pull/1906) by [@byCedric](https://github.com/byCedric))
- Use node server default port selection for SSO login server. ([#1930](https://github.com/expo/eas-cli/pull/1930) by [@wschurman](https://github.com/wschurman))
### 🐛 Bug fixes
### 🧹 Chores
- Limit project file upload size to 2GB. ([#1928](https://github.com/expo/eas-cli/pull/1928) by [@khamilowicz](https://github.com/khamilowicz))
- Bump urql graphql client major version. ([#1936](https://github.com/expo/eas-cli/pull/1936) by [@quinlanj](https://github.com/quinlanj))
## [3.15.1](https://github.com/expo/eas-cli/releases/tag/v3.15.1) - 2023-07-11
### 🐛 Bug fixes
- Ensure useClassicUpdates is not set when using EAS Update commands. ([#1915](https://github.com/expo/eas-cli/pull/1915) by [@ide](https://github.com/ide))
+3 -3
View File
@@ -32,8 +32,9 @@
"@oclif/core": "1.23.2",
"@oclif/plugin-autocomplete": "1.3.10",
"@segment/ajv-human-errors": "^2.1.2",
"@urql/core": "3.1.1",
"@urql/exchange-retry": "1.0.0",
"@urql/core": "4.0.11",
"@urql/exchange-graphcache": "6.1.4",
"@urql/exchange-retry": "1.2.0",
"ajv": "8.11.0",
"ajv-formats": "2.1.1",
"better-opn": "3.0.2",
@@ -47,7 +48,6 @@
"fast-glob": "3.2.12",
"figures": "3.2.0",
"form-data": "4.0.0",
"freeport-async": "2.0.0",
"fs-extra": "10.1.0",
"getenv": "1.0.0",
"gradle-to-js": "2.0.1",
-12
View File
@@ -2,7 +2,6 @@ import { JSONValue } from '@expo/json-file';
import { ApiV2Error } from './ApiV2Error';
import fetch, { RequestError, RequestInit } from './fetch';
import { getFreePortAsync } from './utils/port';
interface RequestOptions {
body: JSONValue;
@@ -105,14 +104,3 @@ export function getEASUpdateURL(projectId: string): string {
return new URL(projectId, `https://u.expo.dev`).href;
}
}
export async function getSsoLocalServerPortAsync(): Promise<number> {
let startPort: number;
if (process.env.SSO_LOCAL_SERVER_PORT) {
startPort = Number(process.env.SSO_LOCAL_SERVER_PORT);
} else {
startPort = 19300;
}
const port = await getFreePortAsync(startPort);
return port;
}
@@ -27,12 +27,18 @@ beforeEach(() => {
const EXPECTED_STRINGIFIED_GRAPHQL_ERROR_JSON = `[
{
"name": "GraphQLError",
"extensions": {},
"message": "Error 1"
},
{
"name": "GraphQLError",
"extensions": {},
"message": "Error 2"
},
{
"name": "GraphQLError",
"extensions": {},
"message": "Error 3"
}
]`;
+4
View File
@@ -255,6 +255,10 @@ async function uploadProjectAsync<TPlatform extends Platform>(
);
}
if (projectTarball.size > 2 * 1024 * 1024 * 1024) {
throw new Error('Project archive is too big. Maximum allowed size is 2GB.');
}
projectTarballPath = projectTarball.path;
const bucketKey = await uploadFileAtPathToGCSAsync(
@@ -0,0 +1,8 @@
export class ListChannels {
constructor() {}
async runAsync(): Promise<void> {}
// TODO return channels fragment
async listChannelsAsync(): Promise<void> {}
}
@@ -3,13 +3,14 @@ import {
Client,
OperationContext,
OperationResult,
PromisifiedSource,
OperationResultSource,
TypedDocumentNode,
cacheExchange,
createClient as createUrqlClient,
dedupExchange,
cacheExchange as defaultCacheExchange,
fetchExchange,
} from '@urql/core';
import { cacheExchange as graphqlCacheExchange } from '@urql/exchange-graphcache';
import { relayPagination } from '@urql/exchange-graphcache/extras';
import { retryExchange } from '@urql/exchange-retry';
import { DocumentNode } from 'graphql';
import fetch from 'node-fetch';
@@ -22,18 +23,28 @@ export interface ExpoGraphqlClient extends Client {
query: DocumentNode | TypedDocumentNode<Data, Variables> | string,
variables: Variables,
context: Partial<OperationContext> & { additionalTypenames: string[] }
): PromisifiedSource<OperationResult<Data, Variables>>;
): OperationResultSource<OperationResult<Data, Variables>>;
}
export function createGraphqlClient(authInfo: {
accessToken: string | null;
sessionSecret: string | null;
}): ExpoGraphqlClient {
// TODO: plumb this down, maybe use a feature gate for this?
export function createGraphqlClient(
authInfo: {
accessToken: string | null;
sessionSecret: string | null;
},
_options: { useGraphqlCachePolicy?: boolean } = {}
): ExpoGraphqlClient {
return createUrqlClient({
url: getExpoApiBaseUrl() + '/graphql',
exchanges: [
dedupExchange,
cacheExchange,
//options.useGraphqlCachePolicy ? graphqlCacheExchange() : defaultCacheExchange,
graphqlCacheExchange({
resolvers: {
App: {
updateChannels: relayPagination(),
},
},
}),
retryExchange({
maxDelayMs: 4000,
retryIf: (err, operation) => {
@@ -106,6 +106,41 @@ export const ChannelQuery = {
throw new Error(`Could not find channels on project with id ${appId}`);
}
return updateChannels;
},
async viewUpdateChannelsPaginatedOnAppAsync(
graphqlClient: ExpoGraphqlClient,
{ appId, limit, offset }: ViewUpdateChannelsOnAppQueryVariables
): Promise<UpdateChannelObject[]> {
const response = await withErrorHandlingAsync(
graphqlClient
.query<ViewUpdateChannelsOnAppQuery, ViewUpdateChannelsOnAppQueryVariables>(
gql`
query ViewUpdateChannelsOnApp($appId: String!, $offset: Int!, $limit: Int!) {
app {
byId(appId: $appId) {
id
updateChannels(offset: $offset, limit: $limit) {
id
name
branchMapping
}
}
}
}
${print(UpdateFragmentNode)}
`,
{ appId, offset, limit },
{ additionalTypenames: ['UpdateChannel', 'UpdateBranch', 'Update'] }
)
.toPromise()
);
const { updateChannels } = response.app.byId;
if (!updateChannels) {
throw new Error(`Could not find channels on project with id ${appId}`);
}
return updateChannels;
},
};
@@ -3,6 +3,7 @@ import { JSONObject } from '@expo/json-file';
import { getPrebuildConfigAsync } from '@expo/prebuild-config';
import { readPlistAsync } from '../../utils/plist';
import { hasIgnoredIosProjectAsync } from '../workflow';
interface Target {
buildConfiguration?: string;
@@ -13,6 +14,7 @@ export async function getManagedApplicationTargetEntitlementsAsync(
env: Record<string, string>
): Promise<JSONObject> {
const originalProcessEnv: NodeJS.ProcessEnv = process.env;
try {
process.env = {
...process.env,
@@ -24,6 +26,7 @@ export async function getManagedApplicationTargetEntitlementsAsync(
projectRoot: projectDir,
platforms: ['ios'],
introspect: true,
ignoreExistingNativeFiles: await hasIgnoredIosProjectAsync(projectDir),
});
return expWithMods.ios?.entitlements || {};
} finally {
+12
View File
@@ -44,3 +44,15 @@ export async function resolveWorkflowPerPlatformAsync(
]);
return { android, ios };
}
export async function hasIgnoredIosProjectAsync(projectDir: string): Promise<boolean> {
const vcsClient = getVcsClient();
const vcsRootPath = path.normalize(await vcsClient.getRootPathAsync());
try {
const pbxProjectPath = IOSConfig.Paths.getPBXProjectPath(projectDir);
return await vcsClient.isFileIgnoredAsync(path.relative(vcsRootPath, pbxProjectPath));
} finally {
return false;
}
}
+48 -15
View File
@@ -1,3 +1,4 @@
import assert from 'assert';
import openBrowserAsync from 'better-opn';
import http from 'http';
import { Socket } from 'node:net';
@@ -5,22 +6,48 @@ import querystring from 'querystring';
import Log from '../log';
export async function getSessionUsingBrowserAuthFlowAsync(options: {
const successBody = `
<!DOCTYPE html>
<html lang="en">
<head>
<title>Expo SSO Login</title>
<meta charset="utf-8">
<style type="text/css">
html {
margin: 0;
padding: 0
}
body {
background-color: #fff;
font-family: Tahoma,Verdana;
font-size: 16px;
color: #000;
max-width: 100%;
box-sizing: border-box;
padding: .5rem;
margin: 1em;
overflow-wrap: break-word
}
</style>
</head>
<body>
SSO login complete. You may now close this tab and return to the command prompt.
</body>
</html>`;
export async function getSessionUsingBrowserAuthFlowAsync({
expoWebsiteUrl,
}: {
expoWebsiteUrl: string;
serverPort: number;
}): Promise<string> {
const { expoWebsiteUrl, serverPort } = options;
if (!expoWebsiteUrl || !serverPort) {
throw new Error('Expo website URL and local server port are required.');
}
const scheme = 'http';
const hostname = 'localhost';
const path = '/auth/callback';
const redirectUri = `${scheme}://${hostname}:${serverPort}${path}`;
const buildExpoSsoLoginUrl = (): string => {
const buildExpoSsoLoginUrl = (port: number): string => {
const data = {
app_redirect_uri: redirectUri,
app_redirect_uri: `${scheme}://${hostname}:${port}${path}`,
};
const params = querystring.stringify(data);
return `${expoWebsiteUrl}/sso-login?${params}`;
@@ -44,8 +71,8 @@ export async function getSessionUsingBrowserAuthFlowAsync(options: {
throw new Error('Request missing session_secret search parameter.');
}
resolve(sessionSecret);
response.writeHead(200, { 'Content-Type': 'text/plain' });
response.write(`Website login has completed. You can now close this tab.`);
response.writeHead(200, { 'Content-Type': 'text/html' });
response.write(successBody);
response.end();
} catch (error) {
reject(error);
@@ -59,8 +86,17 @@ export async function getSessionUsingBrowserAuthFlowAsync(options: {
}
);
server.listen(serverPort, hostname, () => {
server.listen(0, hostname, () => {
Log.log('Waiting for browser login...');
const address = server.address();
assert(
address !== null && typeof address === 'object',
'Server address and port should be set after listening has begun'
);
const port = address.port;
const authorizeUrl = buildExpoSsoLoginUrl(port);
openBrowserAsync(authorizeUrl);
});
server.on('connection', connection => {
@@ -70,9 +106,6 @@ export async function getSessionUsingBrowserAuthFlowAsync(options: {
connections.delete(connection);
});
});
const authorizeUrl = buildExpoSsoLoginUrl();
openBrowserAsync(authorizeUrl);
});
};
@@ -1,4 +1,4 @@
import { getExpoWebsiteBaseUrl, getSsoLocalServerPortAsync } from '../api';
import { getExpoWebsiteBaseUrl } from '../api';
import { getSessionUsingBrowserAuthFlowAsync } from './expoSsoLauncher';
import { fetchUserAsync } from './fetchUser';
@@ -7,11 +7,9 @@ export async function fetchSessionSecretAndSsoUserAsync(): Promise<{
id: string;
username: string;
}> {
const config = {
const sessionSecret = await getSessionUsingBrowserAuthFlowAsync({
expoWebsiteUrl: getExpoWebsiteBaseUrl(),
serverPort: await getSsoLocalServerPortAsync(),
};
const sessionSecret = await getSessionUsingBrowserAuthFlowAsync(config);
});
const userData = await fetchUserAsync({ sessionSecret });
-11
View File
@@ -1,11 +0,0 @@
import freeportAsync from 'freeport-async';
/** Get a free port or throw an error. */
export async function getFreePortAsync(rangeStart: number): Promise<number> {
const port = await freeportAsync(rangeStart, { hostnames: [null, 'localhost'] });
if (!port) {
throw new Error('No available port found');
}
return port;
}
-8
View File
@@ -1,8 +0,0 @@
declare module 'freeport-async' {
interface FreePortOptions {
hostnames?: (string | null)[];
}
function freePortAsync(rangeStart: number, options?: FreePortOptions): Promise<number>;
export = freePortAsync;
}
Generated
+30 -25
View File
@@ -2,6 +2,11 @@
# yarn lockfile v1
"@0no-co/graphql.web@^1.0.1":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@0no-co/graphql.web/-/graphql.web-1.0.4.tgz#9606eb651955499525d068ce0ad8bea596286ce2"
integrity sha512-W3ezhHGfO0MS1PtGloaTpg0PbaT8aZSmmaerL7idtU5F7oCI+uu25k+MsMS31BVFlp4aMkHSrNRxiD72IlK8TA==
"@ampproject/remapping@^2.1.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
@@ -4537,20 +4542,30 @@
"@typescript-eslint/types" "5.33.0"
eslint-visitor-keys "^3.3.0"
"@urql/core@3.1.1", "@urql/core@>=3.0.0":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@urql/core/-/core-3.1.1.tgz#a49cd572360d01f2469a786b294fba2269a65e53"
integrity sha512-Mnxtq4I4QeFJsgs7Iytw+HyhiGxISR6qtyk66c9tipozLZ6QVxrCiUPF2HY4BxNIabaxcp+rivadvm8NAnXj4Q==
"@urql/core@4.0.11", "@urql/core@>=4.0.0":
version "4.0.11"
resolved "https://registry.yarnpkg.com/@urql/core/-/core-4.0.11.tgz#b4e8bf3a3ff1a2519bb3aec38c7be99d2523308d"
integrity sha512-FFdY97vF5xnUrElcGw9erOLvtu+KGMLfwrLNDfv4IPgdp2IBsiGe+Kb7Aypfd3kH//BETewVSLm3+y2sSzjX6A==
dependencies:
wonka "^6.1.2"
"@0no-co/graphql.web" "^1.0.1"
wonka "^6.3.2"
"@urql/exchange-[email protected]":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@urql/exchange-retry/-/exchange-retry-1.0.0.tgz#25a48ef0c2f6854f5617e2ca4ea25ae240f1fcbc"
integrity sha512-UGyyGAMXzop9C/fIoe7Ij63DkPSy1uMw2jipB5dnB8R3kl80za7LYzVnA1HvBEt2ZPWfMuwez/VGLOQ7XX4bTA==
"@urql/exchange-[email protected]":
version "6.1.4"
resolved "https://registry.yarnpkg.com/@urql/exchange-graphcache/-/exchange-graphcache-6.1.4.tgz#5d69c838f7a1d313018f63abb8ead79f8c1ea133"
integrity sha512-GQ1scnYjMVoUHrPoYOlw3ZfU2nXuLTEhWhKzPquhZz87GliVpZPuFMf+o64cI1dKy9xDlbU7aQnKiSaGeT248w==
dependencies:
"@urql/core" ">=3.0.0"
wonka "^6.0.0"
"@0no-co/graphql.web" "^1.0.1"
"@urql/core" ">=4.0.0"
wonka "^6.3.2"
"@urql/[email protected]":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@urql/exchange-retry/-/exchange-retry-1.2.0.tgz#23d3ec711754e3c67a843e0106f2cabddff2e5ff"
integrity sha512-1O/biKiVhhn0EtvDF4UOvz325K4RrLupfL8rHcmqD2TBLv4qVDWQuzx4JGa1FfqjjRb+C9TNZ6w19f32Mq85Ug==
dependencies:
"@urql/core" ">=4.0.0"
wonka "^6.3.2"
"@whatwg-node/[email protected]", "@whatwg-node/fetch@^0.5.0":
version "0.5.4"
@@ -7441,11 +7456,6 @@ [email protected]:
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
[email protected]:
version "2.0.0"
resolved "https://registry.yarnpkg.com/freeport-async/-/freeport-async-2.0.0.tgz#6adf2ec0c629d11abff92836acd04b399135bab4"
integrity sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==
[email protected]:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@@ -13621,15 +13631,10 @@ widest-line@^3.1.0:
dependencies:
string-width "^4.0.0"
wonka@^6.0.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.1.0.tgz#65297ebf7031ae46d4b0c56da93950fb3ae5baaa"
integrity sha512-VgiMCz7BXOiDbgpVhf5iNhK7hurteY5Jv0fDJewUkY0s4fbxQD2iKqfGxNXNTwp2v3bgT8QVu2l5H7YdkZ5WIA==
wonka@^6.1.2:
version "6.1.2"
resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.1.2.tgz#2c66fa5b26a12f002a03619b988258313d0b5352"
integrity sha512-zNrXPMccg/7OEp9tSfFkMgTvhhowqasiSHdJ3eCZolXxVTV/aT6HUTofoZk9gwRbGoFey/Nss3JaZKUMKMbofg==
wonka@^6.3.2:
version "6.3.2"
resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.3.2.tgz#6f32992b332251d7b696b038990f4dc284b3b33d"
integrity sha512-2xXbQ1LnwNS7egVm1HPhW2FyKrekolzhpM3mCwXdQr55gO+tAiY76rhb32OL9kKsW8taj++iP7C6hxlVzbnvrw==
word-wrap@^1.2.3:
version "1.2.3"