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 | |
|---|---|---|---|
|
|
b92a9cc5a7 | ||
|
|
763cbadaaa |
No files matched your search
@@ -6,6 +6,8 @@ This is the log of notable changes to EAS CLI and related packages.
|
||||
|
||||
### 🛠 Breaking changes
|
||||
|
||||
- [eas-cli] Build objects in `--json` output (`eas build`, `eas build:list`, `eas build:view`, `eas build:resign`) now have `app`, `updateChannel` (object with `id` and `name`), and `runtime` (object with `id` and `version`) instead of `project`, `channel`, and `runtimeVersion`. `eas update:republish --json` output likewise has `runtime` instead of `runtimeVersion`. Other update commands' `--json` output and `eas-update-metadata.json` are unchanged. ([#4021](https://github.com/expo/eas-cli/pull/4021) by [@tchayen](https://github.com/tchayen))
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- [build-tools] Upload JavaScript source maps generated by builds. ([#4170](https://github.com/expo/eas-cli/pull/4170) by [@AbbanMustafa](https://github.com/AbbanMustafa))
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"npmClient": "yarn",
|
||||
"version": "21.8.0",
|
||||
"version": "22.0.0",
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/build-tools",
|
||||
"version": "21.8.0",
|
||||
"version": "22.0.0",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
"author": "Expo <[email protected]>",
|
||||
@@ -38,17 +38,17 @@
|
||||
"dependencies": {
|
||||
"@expo/config": "55.0.10",
|
||||
"@expo/config-plugins": "55.0.7",
|
||||
"@expo/downloader": "21.0.0",
|
||||
"@expo/eas-build-job": "21.6.0",
|
||||
"@expo/downloader": "22.0.0",
|
||||
"@expo/eas-build-job": "22.0.0",
|
||||
"@expo/env": "^0.4.0",
|
||||
"@expo/logger": "21.0.0",
|
||||
"@expo/logger": "22.0.0",
|
||||
"@expo/package-manager": "1.9.10",
|
||||
"@expo/plist": "^0.3.5",
|
||||
"@expo/results": "^1.0.0",
|
||||
"@expo/spawn-async": "1.7.2",
|
||||
"@expo/steps": "21.7.1",
|
||||
"@expo/template-file": "21.0.2",
|
||||
"@expo/turtle-spawn": "21.0.0",
|
||||
"@expo/steps": "22.0.0",
|
||||
"@expo/template-file": "22.0.0",
|
||||
"@expo/turtle-spawn": "22.0.0",
|
||||
"@expo/xcpretty": "^4.3.1",
|
||||
"@ngrok/ngrok": "1.7.0",
|
||||
"@sentry/node": "7.77.0",
|
||||
|
||||
@@ -1,296 +0,0 @@
|
||||
#include <dlfcn.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Xcode loads one plugin that implements the llcas_* API. This small shim loads
|
||||
* Apple's local CAS plugin and forwards every API call to it. The only exception
|
||||
* is the "remote-service-path" option: Xcode needs that option to schedule C and
|
||||
* Objective-C cache tasks, but Apple's local plugin does not need a remote service.
|
||||
* The shim accepts and discards that option. No cache data leaves the machine.
|
||||
*/
|
||||
|
||||
typedef void *llcas_cas_options_t;
|
||||
typedef void *llcas_cas_t;
|
||||
typedef void *llcas_cancellable_t;
|
||||
typedef uint32_t llcas_lookup_result_t;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *data;
|
||||
size_t size;
|
||||
} llcas_digest_t;
|
||||
|
||||
typedef struct {
|
||||
const void *data;
|
||||
size_t size;
|
||||
} llcas_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t opaque;
|
||||
} llcas_objectid_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t opaque;
|
||||
} llcas_loaded_object_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t opaque_b;
|
||||
uint64_t opaque_e;
|
||||
} llcas_object_refs_t;
|
||||
|
||||
typedef void (*llcas_cas_load_object_cb)(void *, llcas_lookup_result_t,
|
||||
llcas_loaded_object_t, char *);
|
||||
typedef void (*llcas_actioncache_get_cb)(void *, llcas_lookup_result_t,
|
||||
llcas_objectid_t, char *);
|
||||
typedef void (*llcas_actioncache_put_cb)(void *, bool, char *);
|
||||
|
||||
static void *apple_plugin_handle;
|
||||
|
||||
static void *apple_plugin_symbol(const char *name) {
|
||||
if (apple_plugin_handle == NULL) {
|
||||
const char *path = getenv("EAS_XCODE_LOCAL_CAS_APPLE_PLUGIN");
|
||||
if (path == NULL || path[0] == '\0') {
|
||||
path = "/Applications/Xcode.app/Contents/Developer/usr/lib/"
|
||||
"libToolchainCASPlugin.dylib";
|
||||
}
|
||||
apple_plugin_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
|
||||
if (apple_plugin_handle == NULL) {
|
||||
fprintf(stderr, "EAS local CAS plugin could not load %s: %s\n", path,
|
||||
dlerror());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void *symbol = dlsym(apple_plugin_handle, name);
|
||||
if (symbol == NULL) {
|
||||
fprintf(stderr, "EAS local CAS plugin could not find %s: %s\n", name,
|
||||
dlerror());
|
||||
abort();
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
#define APPLE_PLUGIN(name, type) ((type)apple_plugin_symbol(#name))
|
||||
|
||||
void llcas_get_plugin_version(uint32_t *major, uint32_t *minor) {
|
||||
typedef void (*fn_t)(uint32_t *, uint32_t *);
|
||||
APPLE_PLUGIN(llcas_get_plugin_version, fn_t)(major, minor);
|
||||
}
|
||||
|
||||
void llcas_string_dispose(char *value) {
|
||||
typedef void (*fn_t)(char *);
|
||||
APPLE_PLUGIN(llcas_string_dispose, fn_t)(value);
|
||||
}
|
||||
|
||||
void llcas_cancellable_cancel(llcas_cancellable_t token) {
|
||||
typedef void (*fn_t)(llcas_cancellable_t);
|
||||
APPLE_PLUGIN(llcas_cancellable_cancel, fn_t)(token);
|
||||
}
|
||||
|
||||
void llcas_cancellable_dispose(llcas_cancellable_t token) {
|
||||
typedef void (*fn_t)(llcas_cancellable_t);
|
||||
APPLE_PLUGIN(llcas_cancellable_dispose, fn_t)(token);
|
||||
}
|
||||
|
||||
llcas_cas_options_t llcas_cas_options_create(void) {
|
||||
typedef llcas_cas_options_t (*fn_t)(void);
|
||||
return APPLE_PLUGIN(llcas_cas_options_create, fn_t)();
|
||||
}
|
||||
|
||||
void llcas_cas_options_dispose(llcas_cas_options_t options) {
|
||||
typedef void (*fn_t)(llcas_cas_options_t);
|
||||
APPLE_PLUGIN(llcas_cas_options_dispose, fn_t)(options);
|
||||
}
|
||||
|
||||
void llcas_cas_options_set_client_version(llcas_cas_options_t options,
|
||||
uint32_t major, uint32_t minor) {
|
||||
typedef void (*fn_t)(llcas_cas_options_t, uint32_t, uint32_t);
|
||||
APPLE_PLUGIN(llcas_cas_options_set_client_version, fn_t)(options, major, minor);
|
||||
}
|
||||
|
||||
void llcas_cas_options_set_ondisk_path(llcas_cas_options_t options,
|
||||
const char *path) {
|
||||
typedef void (*fn_t)(llcas_cas_options_t, const char *);
|
||||
APPLE_PLUGIN(llcas_cas_options_set_ondisk_path, fn_t)(options, path);
|
||||
}
|
||||
|
||||
bool llcas_cas_options_set_option(llcas_cas_options_t options, const char *name,
|
||||
const char *value, char **error) {
|
||||
if (name != NULL && strcmp(name, "remote-service-path") == 0) {
|
||||
if (error != NULL) {
|
||||
*error = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
typedef bool (*fn_t)(llcas_cas_options_t, const char *, const char *,
|
||||
char **);
|
||||
return APPLE_PLUGIN(llcas_cas_options_set_option, fn_t)(options, name, value,
|
||||
error);
|
||||
}
|
||||
|
||||
llcas_cas_t llcas_cas_create(llcas_cas_options_t options, char **error) {
|
||||
typedef llcas_cas_t (*fn_t)(llcas_cas_options_t, char **);
|
||||
return APPLE_PLUGIN(llcas_cas_create, fn_t)(options, error);
|
||||
}
|
||||
|
||||
void llcas_cas_dispose(llcas_cas_t cas) {
|
||||
typedef void (*fn_t)(llcas_cas_t);
|
||||
APPLE_PLUGIN(llcas_cas_dispose, fn_t)(cas);
|
||||
}
|
||||
|
||||
int64_t llcas_cas_get_ondisk_size(llcas_cas_t cas, char **error) {
|
||||
typedef int64_t (*fn_t)(llcas_cas_t, char **);
|
||||
return APPLE_PLUGIN(llcas_cas_get_ondisk_size, fn_t)(cas, error);
|
||||
}
|
||||
|
||||
bool llcas_cas_set_ondisk_size_limit(llcas_cas_t cas, int64_t size,
|
||||
char **error) {
|
||||
typedef bool (*fn_t)(llcas_cas_t, int64_t, char **);
|
||||
return APPLE_PLUGIN(llcas_cas_set_ondisk_size_limit, fn_t)(cas, size, error);
|
||||
}
|
||||
|
||||
bool llcas_cas_prune_ondisk_data(llcas_cas_t cas, char **error) {
|
||||
typedef bool (*fn_t)(llcas_cas_t, char **);
|
||||
return APPLE_PLUGIN(llcas_cas_prune_ondisk_data, fn_t)(cas, error);
|
||||
}
|
||||
|
||||
char *llcas_cas_get_hash_schema_name(llcas_cas_t cas) {
|
||||
typedef char *(*fn_t)(llcas_cas_t);
|
||||
return APPLE_PLUGIN(llcas_cas_get_hash_schema_name, fn_t)(cas);
|
||||
}
|
||||
|
||||
uint32_t llcas_digest_parse(llcas_cas_t cas, const char *printed,
|
||||
uint8_t *bytes, size_t bytes_size, char **error) {
|
||||
typedef uint32_t (*fn_t)(llcas_cas_t, const char *, uint8_t *, size_t,
|
||||
char **);
|
||||
return APPLE_PLUGIN(llcas_digest_parse, fn_t)(cas, printed, bytes,
|
||||
bytes_size, error);
|
||||
}
|
||||
|
||||
bool llcas_digest_print(llcas_cas_t cas, llcas_digest_t digest, char **printed,
|
||||
char **error) {
|
||||
typedef bool (*fn_t)(llcas_cas_t, llcas_digest_t, char **, char **);
|
||||
return APPLE_PLUGIN(llcas_digest_print, fn_t)(cas, digest, printed, error);
|
||||
}
|
||||
|
||||
bool llcas_cas_get_objectid(llcas_cas_t cas, llcas_digest_t digest,
|
||||
llcas_objectid_t *object, char **error) {
|
||||
typedef bool (*fn_t)(llcas_cas_t, llcas_digest_t, llcas_objectid_t *,
|
||||
char **);
|
||||
return APPLE_PLUGIN(llcas_cas_get_objectid, fn_t)(cas, digest, object, error);
|
||||
}
|
||||
|
||||
llcas_digest_t llcas_objectid_get_digest(llcas_cas_t cas,
|
||||
llcas_objectid_t object) {
|
||||
typedef llcas_digest_t (*fn_t)(llcas_cas_t, llcas_objectid_t);
|
||||
return APPLE_PLUGIN(llcas_objectid_get_digest, fn_t)(cas, object);
|
||||
}
|
||||
|
||||
llcas_lookup_result_t llcas_cas_contains_object(llcas_cas_t cas,
|
||||
llcas_objectid_t object,
|
||||
bool globally, char **error) {
|
||||
typedef llcas_lookup_result_t (*fn_t)(llcas_cas_t, llcas_objectid_t, bool,
|
||||
char **);
|
||||
return APPLE_PLUGIN(llcas_cas_contains_object, fn_t)(cas, object, globally,
|
||||
error);
|
||||
}
|
||||
|
||||
llcas_lookup_result_t llcas_cas_load_object(llcas_cas_t cas,
|
||||
llcas_objectid_t object,
|
||||
llcas_loaded_object_t *loaded,
|
||||
char **error) {
|
||||
typedef llcas_lookup_result_t (*fn_t)(llcas_cas_t, llcas_objectid_t,
|
||||
llcas_loaded_object_t *, char **);
|
||||
return APPLE_PLUGIN(llcas_cas_load_object, fn_t)(cas, object, loaded, error);
|
||||
}
|
||||
|
||||
void llcas_cas_load_object_async(llcas_cas_t cas, llcas_objectid_t object,
|
||||
void *context,
|
||||
llcas_cas_load_object_cb callback,
|
||||
llcas_cancellable_t *cancellable) {
|
||||
typedef void (*fn_t)(llcas_cas_t, llcas_objectid_t, void *,
|
||||
llcas_cas_load_object_cb, llcas_cancellable_t *);
|
||||
APPLE_PLUGIN(llcas_cas_load_object_async,
|
||||
fn_t)(cas, object, context, callback, cancellable);
|
||||
}
|
||||
|
||||
bool llcas_cas_store_object(llcas_cas_t cas, llcas_data_t data,
|
||||
const llcas_objectid_t *refs, size_t refs_count,
|
||||
llcas_objectid_t *stored, char **error) {
|
||||
typedef bool (*fn_t)(llcas_cas_t, llcas_data_t, const llcas_objectid_t *,
|
||||
size_t, llcas_objectid_t *, char **);
|
||||
return APPLE_PLUGIN(llcas_cas_store_object,
|
||||
fn_t)(cas, data, refs, refs_count, stored, error);
|
||||
}
|
||||
|
||||
llcas_data_t llcas_loaded_object_get_data(llcas_cas_t cas,
|
||||
llcas_loaded_object_t object) {
|
||||
typedef llcas_data_t (*fn_t)(llcas_cas_t, llcas_loaded_object_t);
|
||||
return APPLE_PLUGIN(llcas_loaded_object_get_data, fn_t)(cas, object);
|
||||
}
|
||||
|
||||
llcas_object_refs_t llcas_loaded_object_get_refs(llcas_cas_t cas,
|
||||
llcas_loaded_object_t object) {
|
||||
typedef llcas_object_refs_t (*fn_t)(llcas_cas_t, llcas_loaded_object_t);
|
||||
return APPLE_PLUGIN(llcas_loaded_object_get_refs, fn_t)(cas, object);
|
||||
}
|
||||
|
||||
size_t llcas_object_refs_get_count(llcas_cas_t cas, llcas_object_refs_t refs) {
|
||||
typedef size_t (*fn_t)(llcas_cas_t, llcas_object_refs_t);
|
||||
return APPLE_PLUGIN(llcas_object_refs_get_count, fn_t)(cas, refs);
|
||||
}
|
||||
|
||||
llcas_objectid_t llcas_object_refs_get_id(llcas_cas_t cas,
|
||||
llcas_object_refs_t refs,
|
||||
size_t index) {
|
||||
typedef llcas_objectid_t (*fn_t)(llcas_cas_t, llcas_object_refs_t, size_t);
|
||||
return APPLE_PLUGIN(llcas_object_refs_get_id, fn_t)(cas, refs, index);
|
||||
}
|
||||
|
||||
llcas_lookup_result_t llcas_actioncache_get_for_digest(llcas_cas_t cas,
|
||||
llcas_digest_t digest,
|
||||
llcas_objectid_t *result,
|
||||
bool globally,
|
||||
char **error) {
|
||||
typedef llcas_lookup_result_t (*fn_t)(llcas_cas_t, llcas_digest_t,
|
||||
llcas_objectid_t *, bool, char **);
|
||||
return APPLE_PLUGIN(llcas_actioncache_get_for_digest,
|
||||
fn_t)(cas, digest, result, globally, error);
|
||||
}
|
||||
|
||||
void llcas_actioncache_get_for_digest_async(llcas_cas_t cas,
|
||||
llcas_digest_t digest,
|
||||
bool globally, void *context,
|
||||
llcas_actioncache_get_cb callback,
|
||||
llcas_cancellable_t *cancellable) {
|
||||
typedef void (*fn_t)(llcas_cas_t, llcas_digest_t, bool, void *,
|
||||
llcas_actioncache_get_cb, llcas_cancellable_t *);
|
||||
APPLE_PLUGIN(llcas_actioncache_get_for_digest_async,
|
||||
fn_t)(cas, digest, globally, context, callback, cancellable);
|
||||
}
|
||||
|
||||
bool llcas_actioncache_put_for_digest(llcas_cas_t cas, llcas_digest_t digest,
|
||||
llcas_objectid_t value, bool globally,
|
||||
char **error) {
|
||||
typedef bool (*fn_t)(llcas_cas_t, llcas_digest_t, llcas_objectid_t, bool,
|
||||
char **);
|
||||
return APPLE_PLUGIN(llcas_actioncache_put_for_digest,
|
||||
fn_t)(cas, digest, value, globally, error);
|
||||
}
|
||||
|
||||
void llcas_actioncache_put_for_digest_async(llcas_cas_t cas,
|
||||
llcas_digest_t digest,
|
||||
llcas_objectid_t value,
|
||||
bool globally, void *context,
|
||||
llcas_actioncache_put_cb callback,
|
||||
llcas_cancellable_t *cancellable) {
|
||||
typedef void (*fn_t)(llcas_cas_t, llcas_digest_t, llcas_objectid_t, bool,
|
||||
void *, llcas_actioncache_put_cb, llcas_cancellable_t *);
|
||||
APPLE_PLUGIN(llcas_actioncache_put_for_digest_async,
|
||||
fn_t)(cas, digest, value, globally, context, callback,
|
||||
cancellable);
|
||||
}
|
||||
@@ -18,12 +18,8 @@ import { downloadApplicationArchiveAsync } from '../ios/resign';
|
||||
import { resolveArtifactPath, resolveBuildConfiguration, resolveScheme } from '../ios/resolve';
|
||||
import { Sentry } from '../sentry';
|
||||
import { parseAndReportXcactivitylog } from '../steps/utils/ios/xcactivitylog';
|
||||
import {
|
||||
cacheStatsAsync,
|
||||
restoreCcacheAsync,
|
||||
restoreXcodeCompilationCacheAsync,
|
||||
} from '../steps/functions/restoreBuildCache';
|
||||
import { saveCcacheAsync, saveXcodeCompilationCacheAsync } from '../steps/functions/saveBuildCache';
|
||||
import { cacheStatsAsync, restoreCcacheAsync } from '../steps/functions/restoreBuildCache';
|
||||
import { saveCcacheAsync } from '../steps/functions/saveBuildCache';
|
||||
import { uploadApplicationArchive } from '../utils/artifacts';
|
||||
import {
|
||||
configureExpoUpdatesIfInstalledAsync,
|
||||
@@ -104,21 +100,13 @@ async function buildInnerAsync(
|
||||
return;
|
||||
}
|
||||
await ctx.cacheManager?.restoreCache(ctx);
|
||||
await Promise.all([
|
||||
restoreCcacheAsync({
|
||||
logger: ctx.logger,
|
||||
workingDirectory,
|
||||
platform: ctx.job.platform,
|
||||
env: ctx.env,
|
||||
secrets: ctx.job.secrets,
|
||||
}),
|
||||
restoreXcodeCompilationCacheAsync({
|
||||
logger: ctx.logger,
|
||||
workingDirectory,
|
||||
env: ctx.env,
|
||||
secrets: ctx.job.secrets,
|
||||
}),
|
||||
]);
|
||||
await restoreCcacheAsync({
|
||||
logger: ctx.logger,
|
||||
workingDirectory,
|
||||
platform: ctx.job.platform,
|
||||
env: ctx.env,
|
||||
secrets: ctx.job.secrets,
|
||||
});
|
||||
});
|
||||
|
||||
await ctx.runBuildPhase(BuildPhase.INSTALL_PODS, async () => {
|
||||
@@ -254,22 +242,14 @@ async function buildInnerAsync(
|
||||
return;
|
||||
}
|
||||
await ctx.cacheManager?.saveCache(ctx);
|
||||
await Promise.all([
|
||||
saveCcacheAsync({
|
||||
logger: ctx.logger,
|
||||
workingDirectory,
|
||||
platform: ctx.job.platform,
|
||||
evictUsedBefore,
|
||||
env: ctx.env,
|
||||
secrets: ctx.job.secrets,
|
||||
}),
|
||||
saveXcodeCompilationCacheAsync({
|
||||
logger: ctx.logger,
|
||||
workingDirectory,
|
||||
env: ctx.env,
|
||||
secrets: ctx.job.secrets,
|
||||
}),
|
||||
]);
|
||||
await saveCcacheAsync({
|
||||
logger: ctx.logger,
|
||||
workingDirectory,
|
||||
platform: ctx.job.platform,
|
||||
evictUsedBefore,
|
||||
env: ctx.env,
|
||||
secrets: ctx.job.secrets,
|
||||
});
|
||||
});
|
||||
|
||||
await ctx.runBuildPhase(BuildPhase.CACHE_STATS, async () => {
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
import spawn from '@expo/turtle-spawn';
|
||||
import { vol } from 'memfs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import { createMockLogger } from '../../__tests__/utils/logger';
|
||||
import {
|
||||
XCODE_COMPILATION_CACHE_ENV,
|
||||
XCODE_COMPILATION_CACHE_RELATIVE_PATH,
|
||||
compressXcodeCompilationCacheAsync,
|
||||
decompressXcodeCompilationCacheAsync,
|
||||
prepareXcodeCompilationCacheEnvAsync,
|
||||
} from '../compilationCache';
|
||||
|
||||
jest.mock('@expo/turtle-spawn', () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn(),
|
||||
}));
|
||||
|
||||
const DEVELOPER_DIRECTORY = '/Applications/Xcode.app/Contents/Developer';
|
||||
const APPLE_PLUGIN_PATH = path.join(DEVELOPER_DIRECTORY, 'usr/lib/libToolchainCASPlugin.dylib');
|
||||
const BUNDLED_SHIM_PATH = path.resolve(
|
||||
__dirname,
|
||||
'../../../bin/libeas_xcode_local_cas_plugin.dylib'
|
||||
);
|
||||
|
||||
describe(prepareXcodeCompilationCacheEnvAsync, () => {
|
||||
test('does nothing without the explicit opt-in', async () => {
|
||||
const result = await prepareXcodeCompilationCacheEnvAsync({
|
||||
derivedDataPath: '/project/ios/build',
|
||||
env: {},
|
||||
logger: createMockLogger(),
|
||||
});
|
||||
|
||||
expect(result).toEqual({});
|
||||
expect(spawn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('enables compilation caching after validating the bundled arm64 shim', async () => {
|
||||
vol.fromJSON({
|
||||
[BUNDLED_SHIM_PATH]: 'bundled shim',
|
||||
[APPLE_PLUGIN_PATH]: 'Apple plugin',
|
||||
});
|
||||
vol.mkdirSync(os.tmpdir(), { recursive: true });
|
||||
jest.mocked(spawn).mockResolvedValue({} as any);
|
||||
|
||||
const result = await prepareXcodeCompilationCacheEnvAsync({
|
||||
derivedDataPath: '/project/ios/build',
|
||||
env: {
|
||||
[XCODE_COMPILATION_CACHE_ENV]: '1',
|
||||
DEVELOPER_DIR: DEVELOPER_DIRECTORY,
|
||||
},
|
||||
logger: createMockLogger(),
|
||||
});
|
||||
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
'xcrun',
|
||||
expect.arrayContaining([
|
||||
'llvm-cas',
|
||||
`--fcas-plugin-path=${BUNDLED_SHIM_PATH}`,
|
||||
'--fcas-plugin-option=remote-service-path=/dev/null',
|
||||
'--ingest',
|
||||
BUNDLED_SHIM_PATH,
|
||||
]),
|
||||
expect.objectContaining({
|
||||
env: expect.objectContaining({
|
||||
EAS_XCODE_LOCAL_CAS_APPLE_PLUGIN: APPLE_PLUGIN_PATH,
|
||||
}),
|
||||
})
|
||||
);
|
||||
expect(result).toEqual({
|
||||
EAS_XCODE_LOCAL_CAS_APPLE_PLUGIN: APPLE_PLUGIN_PATH,
|
||||
GYM_XCARGS: `COMPILATION_CACHE_ENABLE_CACHING=YES COMPILATION_CACHE_ENABLE_DIAGNOSTIC_REMARKS=YES COMPILATION_CACHE_ENABLE_PLUGIN=YES COMPILATION_CACHE_PLUGIN_PATH=${BUNDLED_SHIM_PATH} COMPILATION_CACHE_REMOTE_SERVICE_PATH=/dev/null`,
|
||||
GYM_DERIVED_DATA_PATH: '/project/ios/build',
|
||||
});
|
||||
});
|
||||
|
||||
test('does not enable compilation caching when the bundled shim is missing', async () => {
|
||||
const logger = createMockLogger();
|
||||
vol.fromJSON({
|
||||
[APPLE_PLUGIN_PATH]: 'Apple plugin',
|
||||
});
|
||||
|
||||
const result = await prepareXcodeCompilationCacheEnvAsync({
|
||||
derivedDataPath: '/project/ios/build',
|
||||
env: {
|
||||
[XCODE_COMPILATION_CACHE_ENV]: '1',
|
||||
DEVELOPER_DIR: DEVELOPER_DIRECTORY,
|
||||
},
|
||||
logger,
|
||||
});
|
||||
|
||||
expect(spawn).not.toHaveBeenCalled();
|
||||
expect(result).toEqual({});
|
||||
expect(logger.warn).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ err: expect.any(Error) }),
|
||||
expect.stringContaining('compilation caching is disabled')
|
||||
);
|
||||
});
|
||||
|
||||
test('does not enable compilation caching when the bundled shim is incompatible', async () => {
|
||||
const logger = createMockLogger();
|
||||
vol.fromJSON({
|
||||
[BUNDLED_SHIM_PATH]: 'bundled shim',
|
||||
[APPLE_PLUGIN_PATH]: 'Apple plugin',
|
||||
});
|
||||
vol.mkdirSync(os.tmpdir(), { recursive: true });
|
||||
jest.mocked(spawn).mockRejectedValue(new Error('incompatible plugin'));
|
||||
|
||||
const result = await prepareXcodeCompilationCacheEnvAsync({
|
||||
derivedDataPath: '/project/ios/build',
|
||||
env: {
|
||||
[XCODE_COMPILATION_CACHE_ENV]: '1',
|
||||
DEVELOPER_DIR: DEVELOPER_DIRECTORY,
|
||||
},
|
||||
logger,
|
||||
});
|
||||
|
||||
expect(result).toEqual({});
|
||||
expect(logger.warn).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ err: expect.any(Error) }),
|
||||
expect.stringContaining('compilation caching is disabled')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Xcode compilation cache archives', () => {
|
||||
test('uses system tar to preserve sparse files', async () => {
|
||||
const workingDirectory = '/working-directory';
|
||||
vol.fromJSON({
|
||||
[path.join(workingDirectory, XCODE_COMPILATION_CACHE_RELATIVE_PATH, 'cache.db')]: 'cache',
|
||||
});
|
||||
vol.mkdirSync(os.tmpdir(), { recursive: true });
|
||||
jest.mocked(spawn).mockResolvedValue({} as any);
|
||||
|
||||
const { archivePath } = await compressXcodeCompilationCacheAsync({
|
||||
workingDirectory,
|
||||
env: {},
|
||||
logger: createMockLogger(),
|
||||
});
|
||||
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
'tar',
|
||||
['-czf', archivePath, '-C', workingDirectory, XCODE_COMPILATION_CACHE_RELATIVE_PATH],
|
||||
expect.any(Object)
|
||||
);
|
||||
|
||||
await decompressXcodeCompilationCacheAsync({
|
||||
archivePath,
|
||||
workingDirectory,
|
||||
env: {},
|
||||
logger: createMockLogger(),
|
||||
});
|
||||
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
'tar',
|
||||
['-xzSf', archivePath, '-C', workingDirectory],
|
||||
expect.any(Object)
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -6,7 +6,6 @@ import path from 'path';
|
||||
import { createTestIosJob } from '../../__tests__/utils/job';
|
||||
import { createMockLogger } from '../../__tests__/utils/logger';
|
||||
import { BuildContext } from '../../context';
|
||||
import * as CompilationCache from '../compilationCache';
|
||||
import { Credentials } from '../credentials/manager';
|
||||
import { DistributionType } from '../credentials/provisioningProfile';
|
||||
import { runFastlaneGym } from '../fastlane';
|
||||
@@ -24,19 +23,13 @@ const WORKING_DIR = '/workingdir';
|
||||
// BuildContext.getReactNativeProjectDirectory() nests the RN project under `${workingdir}/build`.
|
||||
const IOS_DIR = path.join(WORKING_DIR, 'build', 'ios');
|
||||
|
||||
function makeIosBuildContext({
|
||||
simulator,
|
||||
env = {},
|
||||
}: {
|
||||
simulator: boolean;
|
||||
env?: Record<string, string>;
|
||||
}): BuildContext<Ios.Job> {
|
||||
function makeIosBuildContext({ simulator }: { simulator: boolean }): BuildContext<Ios.Job> {
|
||||
const job: Ios.Job = { ...createTestIosJob(), simulator };
|
||||
return new BuildContext(job, {
|
||||
workingdir: WORKING_DIR,
|
||||
logger: createMockLogger(),
|
||||
logBuffer: { getLogs: () => [], getPhaseLogs: () => [] },
|
||||
env: { __API_SERVER_URL: 'http://api.expo.test', ...env },
|
||||
env: { __API_SERVER_URL: 'http://api.expo.test' },
|
||||
uploadArtifact: jest.fn(),
|
||||
});
|
||||
}
|
||||
@@ -78,10 +71,6 @@ describe(runFastlaneGym, () => {
|
||||
(spawn as jest.Mock).mockClear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe.each([
|
||||
{
|
||||
name: 'archive',
|
||||
@@ -136,68 +125,4 @@ describe(runFastlaneGym, () => {
|
||||
workspacePath: IOS_DIR,
|
||||
});
|
||||
});
|
||||
|
||||
it('enables local Swift, C, and Objective-C compilation caching', async () => {
|
||||
jest.spyOn(CompilationCache, 'prepareXcodeCompilationCacheEnvAsync').mockResolvedValue({
|
||||
GYM_XCARGS:
|
||||
'OTHER_SWIFT_FLAGS=-warnings-as-errors COMPILATION_CACHE_ENABLE_CACHING=YES COMPILATION_CACHE_ENABLE_DIAGNOSTIC_REMARKS=YES COMPILATION_CACHE_ENABLE_PLUGIN=YES COMPILATION_CACHE_PLUGIN_PATH=/workingdir/bin/libeas_xcode_local_cas_plugin.dylib COMPILATION_CACHE_REMOTE_SERVICE_PATH=/dev/null',
|
||||
EAS_XCODE_LOCAL_CAS_APPLE_PLUGIN:
|
||||
'/Applications/Xcode.app/Contents/Developer/usr/lib/libToolchainCASPlugin.dylib',
|
||||
GYM_DERIVED_DATA_PATH: path.join(IOS_DIR, 'build'),
|
||||
});
|
||||
const ctx = makeIosBuildContext({
|
||||
simulator: false,
|
||||
env: {
|
||||
EAS_BUILD_XCODE_COMPILATION_CACHE: '1',
|
||||
GYM_XCARGS: 'OTHER_SWIFT_FLAGS=-warnings-as-errors',
|
||||
},
|
||||
});
|
||||
|
||||
await runFastlaneGym(ctx, {
|
||||
scheme: 'App',
|
||||
credentials: ARCHIVE_CREDENTIALS,
|
||||
entitlements: null,
|
||||
});
|
||||
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
'fastlane',
|
||||
['gym'],
|
||||
expect.objectContaining({
|
||||
env: expect.objectContaining({
|
||||
GYM_XCARGS:
|
||||
'OTHER_SWIFT_FLAGS=-warnings-as-errors COMPILATION_CACHE_ENABLE_CACHING=YES COMPILATION_CACHE_ENABLE_DIAGNOSTIC_REMARKS=YES COMPILATION_CACHE_ENABLE_PLUGIN=YES COMPILATION_CACHE_PLUGIN_PATH=/workingdir/bin/libeas_xcode_local_cas_plugin.dylib COMPILATION_CACHE_REMOTE_SERVICE_PATH=/dev/null',
|
||||
EAS_XCODE_LOCAL_CAS_APPLE_PLUGIN:
|
||||
'/Applications/Xcode.app/Contents/Developer/usr/lib/libToolchainCASPlugin.dylib',
|
||||
GYM_DERIVED_DATA_PATH: path.join(IOS_DIR, 'build'),
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('does not enable compilation caching when the local plugin cannot be prepared', async () => {
|
||||
const ctx = makeIosBuildContext({
|
||||
simulator: false,
|
||||
env: {
|
||||
EAS_BUILD_XCODE_COMPILATION_CACHE: '1',
|
||||
},
|
||||
});
|
||||
|
||||
await runFastlaneGym(ctx, {
|
||||
scheme: 'App',
|
||||
credentials: ARCHIVE_CREDENTIALS,
|
||||
entitlements: null,
|
||||
});
|
||||
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
'fastlane',
|
||||
['gym'],
|
||||
expect.objectContaining({
|
||||
env: expect.not.objectContaining({ GYM_XCARGS: expect.any(String) }),
|
||||
})
|
||||
);
|
||||
expect(ctx.logger.warn).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ err: expect.any(Error) }),
|
||||
expect.stringContaining('compilation caching is disabled')
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,194 +0,0 @@
|
||||
import { Env, Platform } from '@expo/eas-build-job';
|
||||
import { bunyan } from '@expo/logger';
|
||||
import spawn from '@expo/turtle-spawn';
|
||||
import { createHash } from 'crypto';
|
||||
import fs from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import { CACHE_KEY_PREFIX_BY_PLATFORM, generateDefaultBuildCacheKeyAsync } from '../utils/cacheKey';
|
||||
|
||||
export const XCODE_COMPILATION_CACHE_ENV = 'EAS_BUILD_XCODE_COMPILATION_CACHE';
|
||||
export const XCODE_COMPILATION_CACHE_RELATIVE_PATH = 'ios/build/CompilationCache.noindex';
|
||||
|
||||
export function getXcodeCompilationCachePath(derivedDataPath: string): string {
|
||||
return path.join(derivedDataPath, 'CompilationCache.noindex');
|
||||
}
|
||||
|
||||
async function prepareXcodeLocalCompilationCachePluginAsync({
|
||||
env,
|
||||
logger,
|
||||
}: {
|
||||
env: Env;
|
||||
logger: bunyan;
|
||||
}): Promise<{ pluginPath: string; applePluginPath: string }> {
|
||||
const bundledPluginPath = path.resolve(
|
||||
__dirname,
|
||||
'../../bin/libeas_xcode_local_cas_plugin.dylib'
|
||||
);
|
||||
const developerDirectory =
|
||||
env.DEVELOPER_DIR ??
|
||||
(
|
||||
await spawn('xcode-select', ['--print-path'], {
|
||||
env,
|
||||
logger,
|
||||
})
|
||||
).stdout.trim();
|
||||
const applePluginPath = path.join(
|
||||
developerDirectory,
|
||||
'usr',
|
||||
'lib',
|
||||
'libToolchainCASPlugin.dylib'
|
||||
);
|
||||
|
||||
if (!(await fs.pathExists(applePluginPath))) {
|
||||
throw new Error(`The Xcode CAS plugin is missing at ${applePluginPath}.`);
|
||||
}
|
||||
if (!(await fs.pathExists(bundledPluginPath))) {
|
||||
throw new Error(`The EAS local CAS plugin is missing at ${bundledPluginPath}.`);
|
||||
}
|
||||
|
||||
const validationDirectory = await fs.mkdtemp(
|
||||
path.join(os.tmpdir(), 'eas-xcode-local-cache-validation-')
|
||||
);
|
||||
try {
|
||||
await spawn(
|
||||
'xcrun',
|
||||
[
|
||||
'llvm-cas',
|
||||
`--fcas-plugin-path=${bundledPluginPath}`,
|
||||
'--fcas-plugin-option=remote-service-path=/dev/null',
|
||||
`--cas=${path.join(validationDirectory, 'cas')}`,
|
||||
'--ingest',
|
||||
bundledPluginPath,
|
||||
],
|
||||
{
|
||||
env: { ...env, EAS_XCODE_LOCAL_CAS_APPLE_PLUGIN: applePluginPath },
|
||||
logger,
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
await fs.remove(validationDirectory);
|
||||
}
|
||||
|
||||
return { pluginPath: bundledPluginPath, applePluginPath };
|
||||
}
|
||||
|
||||
export async function compressXcodeCompilationCacheAsync({
|
||||
workingDirectory,
|
||||
env,
|
||||
logger,
|
||||
}: {
|
||||
workingDirectory: string;
|
||||
env: Env;
|
||||
logger: bunyan;
|
||||
}): Promise<{ archivePath: string }> {
|
||||
const cachePath = path.join(workingDirectory, XCODE_COMPILATION_CACHE_RELATIVE_PATH);
|
||||
if (!(await fs.pathExists(cachePath))) {
|
||||
throw new Error(`The Xcode compilation cache does not exist at ${cachePath}.`);
|
||||
}
|
||||
|
||||
const archiveDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'xcode-compilation-cache-'));
|
||||
const archivePath = path.join(archiveDirectory, 'cache.tar.gz');
|
||||
await spawn(
|
||||
'tar',
|
||||
['-czf', archivePath, '-C', workingDirectory, XCODE_COMPILATION_CACHE_RELATIVE_PATH],
|
||||
{ env, logger }
|
||||
);
|
||||
return { archivePath };
|
||||
}
|
||||
|
||||
export async function decompressXcodeCompilationCacheAsync({
|
||||
archivePath,
|
||||
workingDirectory,
|
||||
env,
|
||||
logger,
|
||||
}: {
|
||||
archivePath: string;
|
||||
workingDirectory: string;
|
||||
env: Env;
|
||||
logger: bunyan;
|
||||
}): Promise<void> {
|
||||
await fs.ensureDir(workingDirectory);
|
||||
await spawn('tar', ['-xzSf', archivePath, '-C', workingDirectory], { env, logger });
|
||||
}
|
||||
|
||||
export async function generateXcodeCompilationCacheKeyAsync({
|
||||
workingDirectory,
|
||||
env,
|
||||
logger,
|
||||
}: {
|
||||
workingDirectory: string;
|
||||
env: Env;
|
||||
logger: bunyan;
|
||||
}): Promise<{ key: string; keyPrefix: string; xcodeVersion: string }> {
|
||||
const xcodeVersion = (
|
||||
await spawn('xcodebuild', ['-version'], {
|
||||
env,
|
||||
logger,
|
||||
})
|
||||
).stdout.trim();
|
||||
const xcodeVersionHash = createHash('sha256').update(xcodeVersion).digest('hex').slice(0, 16);
|
||||
const ccacheKey = await generateDefaultBuildCacheKeyAsync(workingDirectory, Platform.IOS);
|
||||
const dependencyHash = ccacheKey.slice(CACHE_KEY_PREFIX_BY_PLATFORM[Platform.IOS].length);
|
||||
const keyPrefix = `ios-xcode-compilation-cache-${xcodeVersionHash}-`;
|
||||
|
||||
return {
|
||||
key: `${keyPrefix}${dependencyHash}`,
|
||||
keyPrefix,
|
||||
xcodeVersion: xcodeVersion.replace(/\s+/g, ' '),
|
||||
};
|
||||
}
|
||||
|
||||
export async function prepareXcodeCompilationCacheEnvAsync({
|
||||
derivedDataPath,
|
||||
env,
|
||||
logger,
|
||||
}: {
|
||||
derivedDataPath: string;
|
||||
env: Env;
|
||||
logger: bunyan;
|
||||
}): Promise<Env> {
|
||||
if (env[XCODE_COMPILATION_CACHE_ENV] !== '1') {
|
||||
return {};
|
||||
}
|
||||
|
||||
let plugin: { pluginPath: string; applePluginPath: string };
|
||||
try {
|
||||
plugin = await prepareXcodeLocalCompilationCachePluginAsync({
|
||||
env,
|
||||
logger,
|
||||
});
|
||||
logger.info(`The EAS local Xcode CAS plugin is ready at ${plugin.pluginPath}.`);
|
||||
} catch (error: any) {
|
||||
logger.warn(
|
||||
{ err: error },
|
||||
'The EAS local Xcode CAS plugin is missing or incompatible. Xcode compilation caching is disabled.'
|
||||
);
|
||||
return {};
|
||||
}
|
||||
logger.info(
|
||||
`Xcode compilation caching is enabled. The cache directory is ${getXcodeCompilationCachePath(derivedDataPath)}.`
|
||||
);
|
||||
|
||||
const pluginXcargs = [
|
||||
'COMPILATION_CACHE_ENABLE_PLUGIN=YES',
|
||||
`COMPILATION_CACHE_PLUGIN_PATH=${plugin.pluginPath}`,
|
||||
// A non-empty remote service path makes Xcode schedule C, Objective-C,
|
||||
// precompiled-module, and precompiled-header cache tasks. The EAS plugin
|
||||
// consumes this option and never opens the path or performs remote I/O.
|
||||
'COMPILATION_CACHE_REMOTE_SERVICE_PATH=/dev/null',
|
||||
].join(' ');
|
||||
|
||||
return {
|
||||
GYM_XCARGS: [
|
||||
env.GYM_XCARGS,
|
||||
'COMPILATION_CACHE_ENABLE_CACHING=YES COMPILATION_CACHE_ENABLE_DIAGNOSTIC_REMARKS=YES',
|
||||
pluginXcargs,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' '),
|
||||
GYM_DERIVED_DATA_PATH: derivedDataPath,
|
||||
EAS_XCODE_LOCAL_CAS_APPLE_PLUGIN: plugin.applePluginPath,
|
||||
};
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import type { Credentials } from './credentials/manager';
|
||||
import * as CompilationCache from './compilationCache';
|
||||
import { createFastfileForResigningBuild } from './fastfile';
|
||||
import { createGymfileForArchiveBuild, createGymfileForSimulatorBuild } from './gymfile';
|
||||
import { isTVOS } from './tvos';
|
||||
@@ -47,18 +46,13 @@ export async function runFastlaneGym<TJob extends Ios.Job>(
|
||||
if (ctx.skipNativeBuild) {
|
||||
throw new SkipNativeBuildError('Skipping fastlane build');
|
||||
}
|
||||
const compilationCacheEnv = await CompilationCache.prepareXcodeCompilationCacheEnvAsync({
|
||||
derivedDataPath,
|
||||
env: ctx.env,
|
||||
logger: ctx.logger,
|
||||
});
|
||||
const buildLogger = new XcodeBuildLogger(ctx.logger, ctx.getReactNativeProjectDirectory());
|
||||
void buildLogger.watchLogFiles(ctx.buildLogsDirectory);
|
||||
try {
|
||||
await runFastlane(['gym'], {
|
||||
cwd: workspacePath,
|
||||
logger: ctx.logger,
|
||||
env: { ...ctx.env, ...extraEnv, ...compilationCacheEnv },
|
||||
env: { ...ctx.env, ...extraEnv },
|
||||
});
|
||||
} finally {
|
||||
await buildLogger.flush();
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
import { Platform } from '@expo/eas-build-job';
|
||||
import { vol } from 'memfs';
|
||||
|
||||
import { createMockLogger } from '../../../__tests__/utils/logger';
|
||||
import {
|
||||
XCODE_COMPILATION_CACHE_ENV,
|
||||
XCODE_COMPILATION_CACHE_RELATIVE_PATH,
|
||||
compressXcodeCompilationCacheAsync,
|
||||
decompressXcodeCompilationCacheAsync,
|
||||
generateXcodeCompilationCacheKeyAsync,
|
||||
} from '../../../ios/compilationCache';
|
||||
import { downloadCacheAsync } from '../restoreCache';
|
||||
import { restoreXcodeCompilationCacheAsync } from '../restoreBuildCache';
|
||||
import { uploadCacheAsync } from '../saveCache';
|
||||
import { saveXcodeCompilationCacheAsync } from '../saveBuildCache';
|
||||
|
||||
jest.mock('../restoreCache', () => ({
|
||||
downloadCacheAsync: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../saveCache', () => ({
|
||||
uploadCacheAsync: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../ios/compilationCache', () => ({
|
||||
XCODE_COMPILATION_CACHE_ENV: 'EAS_BUILD_XCODE_COMPILATION_CACHE',
|
||||
XCODE_COMPILATION_CACHE_RELATIVE_PATH: 'ios/build/CompilationCache.noindex',
|
||||
compressXcodeCompilationCacheAsync: jest.fn(),
|
||||
decompressXcodeCompilationCacheAsync: jest.fn(),
|
||||
generateXcodeCompilationCacheKeyAsync: jest.fn(),
|
||||
}));
|
||||
|
||||
const WORKING_DIRECTORY = '/working-directory';
|
||||
const ENV = {
|
||||
[XCODE_COMPILATION_CACHE_ENV]: '1',
|
||||
EAS_USE_CACHE: '1',
|
||||
EAS_BUILD_ID: 'build-id',
|
||||
__API_SERVER_URL: 'https://api.expo.test',
|
||||
};
|
||||
const SECRETS = { robotAccessToken: 'robot-access-token' };
|
||||
|
||||
describe('Xcode compilation build cache', () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(generateXcodeCompilationCacheKeyAsync).mockResolvedValue({
|
||||
key: 'ios-xcode-compilation-cache-version-dependencies',
|
||||
keyPrefix: 'ios-xcode-compilation-cache-version-',
|
||||
xcodeVersion: 'Xcode 26.0 Build version 17A000',
|
||||
});
|
||||
});
|
||||
|
||||
test('restores through the active build cache service', async () => {
|
||||
jest.mocked(downloadCacheAsync).mockResolvedValue({
|
||||
archivePath: '/tmp/cache.tar.gz',
|
||||
matchedKey: 'ios-xcode-compilation-cache-version-dependencies',
|
||||
});
|
||||
|
||||
await restoreXcodeCompilationCacheAsync({
|
||||
logger: createMockLogger(),
|
||||
workingDirectory: WORKING_DIRECTORY,
|
||||
env: ENV,
|
||||
secrets: SECRETS,
|
||||
});
|
||||
|
||||
expect(downloadCacheAsync).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
jobId: 'build-id',
|
||||
key: 'ios-xcode-compilation-cache-version-dependencies',
|
||||
keyPrefixes: ['ios-xcode-compilation-cache-version-'],
|
||||
paths: [XCODE_COMPILATION_CACHE_RELATIVE_PATH],
|
||||
platform: Platform.IOS,
|
||||
})
|
||||
);
|
||||
expect(decompressXcodeCompilationCacheAsync).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
archivePath: '/tmp/cache.tar.gz',
|
||||
workingDirectory: WORKING_DIRECTORY,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test('saves through the active build cache service', async () => {
|
||||
vol.fromJSON({ '/tmp/xcode-cache.tar.gz': 'cache' });
|
||||
jest.mocked(compressXcodeCompilationCacheAsync).mockResolvedValue({
|
||||
archivePath: '/tmp/xcode-cache.tar.gz',
|
||||
});
|
||||
|
||||
await saveXcodeCompilationCacheAsync({
|
||||
logger: createMockLogger(),
|
||||
workingDirectory: WORKING_DIRECTORY,
|
||||
env: ENV,
|
||||
secrets: SECRETS,
|
||||
});
|
||||
|
||||
expect(compressXcodeCompilationCacheAsync).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
workingDirectory: WORKING_DIRECTORY,
|
||||
})
|
||||
);
|
||||
|
||||
expect(uploadCacheAsync).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
jobId: 'build-id',
|
||||
key: 'ios-xcode-compilation-cache-version-dependencies',
|
||||
paths: [XCODE_COMPILATION_CACHE_RELATIVE_PATH],
|
||||
platform: Platform.IOS,
|
||||
size: 5,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -20,12 +20,6 @@ import {
|
||||
getCcachePath,
|
||||
} from '../../utils/cacheKey';
|
||||
import { Datadog } from '../../datadog';
|
||||
import {
|
||||
XCODE_COMPILATION_CACHE_ENV,
|
||||
XCODE_COMPILATION_CACHE_RELATIVE_PATH,
|
||||
decompressXcodeCompilationCacheAsync,
|
||||
generateXcodeCompilationCacheKeyAsync,
|
||||
} from '../../ios/compilationCache';
|
||||
import { GRADLE_CACHE_KEY_PREFIX, generateGradleCacheKeyAsync } from '../../utils/gradleCacheKey';
|
||||
import { TurtleFetchError, turtleFetch } from '../../utils/turtleFetch';
|
||||
|
||||
@@ -54,91 +48,26 @@ export function createRestoreBuildCacheFunction(): BuildFunction {
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
restoreCcacheAsync({
|
||||
await restoreCcacheAsync({
|
||||
logger,
|
||||
workingDirectory,
|
||||
platform,
|
||||
env,
|
||||
secrets: stepCtx.global.staticContext.job.secrets,
|
||||
});
|
||||
|
||||
if (platform === Platform.ANDROID) {
|
||||
await restoreGradleCacheAsync({
|
||||
logger,
|
||||
workingDirectory,
|
||||
platform,
|
||||
env,
|
||||
secrets: stepCtx.global.staticContext.job.secrets,
|
||||
}),
|
||||
platform === Platform.IOS
|
||||
? restoreXcodeCompilationCacheAsync({
|
||||
logger,
|
||||
workingDirectory,
|
||||
env,
|
||||
secrets: stepCtx.global.staticContext.job.secrets,
|
||||
})
|
||||
: restoreGradleCacheAsync({
|
||||
logger,
|
||||
workingDirectory,
|
||||
env,
|
||||
secrets: stepCtx.global.staticContext.job.secrets,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function restoreXcodeCompilationCacheAsync({
|
||||
logger,
|
||||
workingDirectory,
|
||||
env,
|
||||
secrets,
|
||||
}: {
|
||||
logger: bunyan;
|
||||
workingDirectory: string;
|
||||
env: Record<string, string | undefined>;
|
||||
secrets?: { robotAccessToken?: string };
|
||||
}): Promise<void> {
|
||||
const buildCacheEnabled =
|
||||
env.EAS_RESTORE_CACHE === '1' || (env.EAS_USE_CACHE === '1' && env.EAS_RESTORE_CACHE !== '0');
|
||||
if (!buildCacheEnabled || env[XCODE_COMPILATION_CACHE_ENV] !== '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const robotAccessToken = nullthrows(
|
||||
secrets?.robotAccessToken,
|
||||
'Robot access token is required for cache operations'
|
||||
);
|
||||
const expoApiServerURL = nullthrows(env.__API_SERVER_URL, '__API_SERVER_URL is not set');
|
||||
const jobId = nullthrows(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');
|
||||
const { key, keyPrefix, xcodeVersion } = await generateXcodeCompilationCacheKeyAsync({
|
||||
workingDirectory,
|
||||
env,
|
||||
logger,
|
||||
});
|
||||
logger.info(`Restoring Xcode compilation cache for ${xcodeVersion} with key: ${key}`);
|
||||
|
||||
const { archivePath, matchedKey } = await downloadCacheAsync({
|
||||
logger,
|
||||
jobId,
|
||||
expoApiServerURL,
|
||||
robotAccessToken,
|
||||
paths: [XCODE_COMPILATION_CACHE_RELATIVE_PATH],
|
||||
key,
|
||||
keyPrefixes: [keyPrefix],
|
||||
platform: Platform.IOS,
|
||||
});
|
||||
await decompressXcodeCompilationCacheAsync({
|
||||
archivePath,
|
||||
workingDirectory,
|
||||
env,
|
||||
logger,
|
||||
});
|
||||
logger.info(
|
||||
`Xcode compilation cache restored ${matchedKey === key ? '(direct hit)' : '(prefix match)'}`
|
||||
);
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof TurtleFetchError && err.response?.status === 404) {
|
||||
logger.info('No Xcode compilation cache found for this key');
|
||||
} else {
|
||||
logger.warn({ err }, 'Failed to restore Xcode compilation cache');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createCacheStatsBuildFunction(): BuildFunction {
|
||||
return new BuildFunction({
|
||||
namespace: 'eas',
|
||||
|
||||
@@ -14,12 +14,6 @@ import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import { compressCacheAsync, uploadCacheAsync } from './saveCache';
|
||||
import {
|
||||
XCODE_COMPILATION_CACHE_ENV,
|
||||
XCODE_COMPILATION_CACHE_RELATIVE_PATH,
|
||||
compressXcodeCompilationCacheAsync,
|
||||
generateXcodeCompilationCacheKeyAsync,
|
||||
} from '../../ios/compilationCache';
|
||||
import { formatBytes } from '../../utils/artifacts';
|
||||
import { generateDefaultBuildCacheKeyAsync, getCcachePath } from '../../utils/cacheKey';
|
||||
import { generateGradleCacheKeyAsync } from '../../utils/gradleCacheKey';
|
||||
@@ -49,87 +43,27 @@ export function createSaveBuildCacheFunction(evictUsedBefore: Date): BuildFuncti
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
saveCcacheAsync({
|
||||
await saveCcacheAsync({
|
||||
logger,
|
||||
workingDirectory,
|
||||
platform,
|
||||
evictUsedBefore,
|
||||
env,
|
||||
secrets: stepCtx.global.staticContext.job.secrets,
|
||||
});
|
||||
|
||||
if (platform === Platform.ANDROID) {
|
||||
await saveGradleCacheAsync({
|
||||
logger,
|
||||
workingDirectory,
|
||||
platform,
|
||||
evictUsedBefore,
|
||||
env,
|
||||
secrets: stepCtx.global.staticContext.job.secrets,
|
||||
}),
|
||||
platform === Platform.IOS
|
||||
? saveXcodeCompilationCacheAsync({
|
||||
logger,
|
||||
workingDirectory,
|
||||
env,
|
||||
secrets: stepCtx.global.staticContext.job.secrets,
|
||||
})
|
||||
: saveGradleCacheAsync({
|
||||
logger,
|
||||
workingDirectory,
|
||||
env,
|
||||
secrets: stepCtx.global.staticContext.job.secrets,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function saveXcodeCompilationCacheAsync({
|
||||
logger,
|
||||
workingDirectory,
|
||||
env,
|
||||
secrets,
|
||||
}: {
|
||||
logger: bunyan;
|
||||
workingDirectory: string;
|
||||
env: Record<string, string | undefined>;
|
||||
secrets?: { robotAccessToken?: string };
|
||||
}): Promise<void> {
|
||||
const buildCacheEnabled =
|
||||
env.EAS_SAVE_CACHE === '1' || (env.EAS_USE_CACHE === '1' && env.EAS_SAVE_CACHE !== '0');
|
||||
if (!buildCacheEnabled || env[XCODE_COMPILATION_CACHE_ENV] !== '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { key, xcodeVersion } = await generateXcodeCompilationCacheKeyAsync({
|
||||
workingDirectory,
|
||||
env,
|
||||
logger,
|
||||
});
|
||||
logger.info(`Saving Xcode compilation cache for ${xcodeVersion} with key: ${key}`);
|
||||
const jobId = nullthrows(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');
|
||||
const robotAccessToken = nullthrows(
|
||||
secrets?.robotAccessToken,
|
||||
'Robot access token is required for cache operations'
|
||||
);
|
||||
const expoApiServerURL = nullthrows(env.__API_SERVER_URL, '__API_SERVER_URL is not set');
|
||||
const { archivePath } = await compressXcodeCompilationCacheAsync({
|
||||
workingDirectory,
|
||||
env,
|
||||
logger,
|
||||
});
|
||||
const { size } = await fs.promises.stat(archivePath);
|
||||
logger.info(`Xcode compilation cache archive size: ${formatBytes(size)}`);
|
||||
|
||||
await uploadCacheAsync({
|
||||
logger,
|
||||
jobId,
|
||||
expoApiServerURL,
|
||||
robotAccessToken,
|
||||
archivePath,
|
||||
key,
|
||||
paths: [XCODE_COMPILATION_CACHE_RELATIVE_PATH],
|
||||
size,
|
||||
platform: Platform.IOS,
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error({ err }, 'Failed to save Xcode compilation cache');
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveCcacheAsync({
|
||||
logger,
|
||||
workingDirectory,
|
||||
|
||||
@@ -5,7 +5,6 @@ import path from 'path';
|
||||
|
||||
import { COMMON_FASTLANE_ENV } from '../../../common/fastlane';
|
||||
import { XcodeBuildLogger } from '../../../common/xcpretty';
|
||||
import * as CompilationCache from '../../../ios/compilationCache';
|
||||
|
||||
export async function runFastlaneGym({
|
||||
workingDir,
|
||||
@@ -20,23 +19,14 @@ export async function runFastlaneGym({
|
||||
env: BuildStepEnv;
|
||||
extraEnv?: BuildStepEnv;
|
||||
}): Promise<void> {
|
||||
const workspacePath = path.join(workingDir, 'ios');
|
||||
const derivedDataPath = path.join(workspacePath, 'build');
|
||||
// When caching is enabled, this also sets GYM_DERIVED_DATA_PATH so Fastlane
|
||||
// and the cache restore/save operations use this exact directory.
|
||||
const compilationCacheEnv = await CompilationCache.prepareXcodeCompilationCacheEnvAsync({
|
||||
derivedDataPath,
|
||||
env,
|
||||
logger,
|
||||
});
|
||||
const buildLogger = new XcodeBuildLogger(logger, workingDir);
|
||||
void buildLogger.watchLogFiles(buildLogsDirectory);
|
||||
try {
|
||||
await runFastlane(['gym'], {
|
||||
cwd: workspacePath,
|
||||
cwd: path.join(workingDir, 'ios'),
|
||||
logger,
|
||||
env,
|
||||
extraEnv: { ...extraEnv, ...compilationCacheEnv },
|
||||
extraEnv,
|
||||
});
|
||||
} finally {
|
||||
await buildLogger.flush();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-eas-build-function",
|
||||
"version": "21.7.1",
|
||||
"version": "22.0.0",
|
||||
"description": "Create functions for use in EAS Build custom builds.",
|
||||
"keywords": [
|
||||
"expo",
|
||||
@@ -35,7 +35,7 @@
|
||||
"clean": "rimraf ./build/ \"*.tsbuildinfo\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/steps": "21.7.1"
|
||||
"@expo/steps": "22.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expo/package-manager": "1.9.10",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/downloader",
|
||||
"version": "21.0.0",
|
||||
"version": "22.0.0",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
"author": "Expo <[email protected]>",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eas-build-cache-provider",
|
||||
"version": "21.0.0",
|
||||
"version": "22.0.0",
|
||||
"description": "A build cache provider plugin for the Expo CLI",
|
||||
"homepage": "https://github.com/expo/eas-cli",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/eas-build-job",
|
||||
"version": "21.6.0",
|
||||
"version": "22.0.0",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "MIT",
|
||||
"author": "Expo <[email protected]>",
|
||||
@@ -25,9 +25,9 @@
|
||||
"clean": "rimraf node_modules dist coverage \"*.tsbuildinfo\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/logger": "21.0.0",
|
||||
"@expo/logger": "22.0.0",
|
||||
"@expo/results": "1.0.0",
|
||||
"@expo/turtle-spawn": "21.0.0",
|
||||
"@expo/turtle-spawn": "22.0.0",
|
||||
"joi": "^17.13.1",
|
||||
"semver": "^7.6.2",
|
||||
"zod": "^4.3.5"
|
||||
|
||||
+162
-152
File diff suppressed because it is too large.
Load diff
Generated
+1199
-49
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eas-cli",
|
||||
"version": "21.8.0",
|
||||
"version": "22.0.0",
|
||||
"description": "EAS command line tool",
|
||||
"keywords": [
|
||||
"cli",
|
||||
@@ -48,11 +48,11 @@
|
||||
"@expo/code-signing-certificates": "0.0.5",
|
||||
"@expo/config": "55.0.10",
|
||||
"@expo/config-plugins": "55.0.7",
|
||||
"@expo/eas-build-job": "21.6.0",
|
||||
"@expo/eas-json": "21.6.0",
|
||||
"@expo/eas-build-job": "22.0.0",
|
||||
"@expo/eas-json": "22.0.0",
|
||||
"@expo/env": "^1.0.0",
|
||||
"@expo/json-file": "8.3.3",
|
||||
"@expo/logger": "21.0.0",
|
||||
"@expo/logger": "22.0.0",
|
||||
"@expo/multipart-body-parser": "2.0.0",
|
||||
"@expo/osascript": "2.1.4",
|
||||
"@expo/package-manager": "1.9.10",
|
||||
@@ -64,7 +64,7 @@
|
||||
"@expo/results": "1.0.0",
|
||||
"@expo/rudder-sdk-node": "1.1.1",
|
||||
"@expo/spawn-async": "1.7.2",
|
||||
"@expo/steps": "21.7.1",
|
||||
"@expo/steps": "22.0.0",
|
||||
"@expo/timeago.js": "1.0.0",
|
||||
"@oclif/core": "^4.8.3",
|
||||
"@oclif/plugin-autocomplete": "^3.2.40",
|
||||
|
||||
@@ -38,14 +38,9 @@ export function getMockAppFragment(): AppFragment {
|
||||
ownerAccount: {
|
||||
id: 'test-account-id',
|
||||
name: 'testuser',
|
||||
users: [
|
||||
{
|
||||
role: Role.Owner,
|
||||
actor: {
|
||||
id: 'test-user-id',
|
||||
},
|
||||
},
|
||||
],
|
||||
viewerUserPermission: {
|
||||
role: Role.Owner,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ describe(WorkflowLogView, () => {
|
||||
createdAt: '2022-01-01T00:00:00.000Z',
|
||||
updatedAt: '2022-01-01T00:00:00.000Z',
|
||||
isForIosSimulator: false,
|
||||
project: {
|
||||
app: {
|
||||
id: mockProjectId,
|
||||
__typename: 'App',
|
||||
name: 'App',
|
||||
|
||||
@@ -74,7 +74,7 @@ function createMockBuildFragment({
|
||||
id: buildId ?? uuid(),
|
||||
logFiles: [],
|
||||
priority: BuildPriority.Normal,
|
||||
project: {
|
||||
app: {
|
||||
__typename: 'App',
|
||||
slug: 'test-project',
|
||||
id: projectId,
|
||||
|
||||
@@ -74,7 +74,7 @@ function createMockBuildFragment({
|
||||
platform: AppPlatform.Android,
|
||||
id: buildId ?? uuid(),
|
||||
priority: BuildPriority.Normal,
|
||||
project: {
|
||||
app: {
|
||||
__typename: 'App',
|
||||
slug: 'test-project',
|
||||
id: projectId,
|
||||
|
||||
@@ -76,7 +76,6 @@ export async function collectMetadataAsync<T extends Platform>(
|
||||
customWorkflowName: ctx.customBuildConfigMetadata?.workflowName,
|
||||
developmentClient: ctx.developmentClient,
|
||||
requiredPackageManager: ctx.requiredPackageManager ?? undefined,
|
||||
selectedImage: ctx.buildProfile.image,
|
||||
customNodeVersion: ctx.buildProfile.node,
|
||||
simulator: 'simulator' in ctx.buildProfile && ctx.buildProfile.simulator,
|
||||
};
|
||||
|
||||
@@ -597,7 +597,7 @@ export async function downloadAndRunAsync(
|
||||
simulator?: SimulatorRunTarget
|
||||
): Promise<void> {
|
||||
assert(build.artifacts?.applicationArchiveUrl);
|
||||
const cachedAppPath = getEasBuildRunCachedAppPath(build.project.id, build.id, build.platform);
|
||||
const cachedAppPath = getEasBuildRunCachedAppPath(build.app.id, build.id, build.platform);
|
||||
|
||||
if (await pathExists(cachedAppPath)) {
|
||||
Log.newLine();
|
||||
|
||||
@@ -93,7 +93,7 @@ export function formatGraphQLBuild(build: BuildFragment): string {
|
||||
},
|
||||
{
|
||||
label: 'Channel',
|
||||
value: build.channel,
|
||||
value: build.updateChannel?.name,
|
||||
},
|
||||
{
|
||||
label: 'SDK Version',
|
||||
@@ -101,7 +101,7 @@ export function formatGraphQLBuild(build: BuildFragment): string {
|
||||
},
|
||||
{
|
||||
label: 'Runtime Version',
|
||||
value: build.runtimeVersion,
|
||||
value: build.runtime?.version,
|
||||
},
|
||||
{
|
||||
label: 'Version',
|
||||
|
||||
@@ -19,13 +19,10 @@ export function getProjectPageUrl(
|
||||
}
|
||||
|
||||
export function getBuildLogsUrl(build: BuildFragment, hash?: string): string {
|
||||
const { project } = build;
|
||||
const url =
|
||||
project.__typename !== 'App'
|
||||
? `/builds/${build.id}`
|
||||
: `/accounts/${project.ownerAccount.name}/projects/${project.slug}/builds/${build.id}${
|
||||
hash ? `#${hash}` : ''
|
||||
}`;
|
||||
const { app } = build;
|
||||
const url = `/accounts/${app.ownerAccount.name}/projects/${app.slug}/builds/${build.id}${
|
||||
hash ? `#${hash}` : ''
|
||||
}`;
|
||||
|
||||
return new URL(url, getExpoWebsiteBaseUrl()).toString();
|
||||
}
|
||||
@@ -37,7 +34,7 @@ export function getArtifactUrl(artifactId: string): string {
|
||||
export function getInternalDistributionInstallUrl(build: BuildFragment): string {
|
||||
if (build.platform === AppPlatform.Ios) {
|
||||
return `itms-services://?action=download-manifest;url=${getExpoApiBaseUrl()}/v2/projects/${
|
||||
build.project.id
|
||||
build.app.id
|
||||
}/builds/${build.id}/manifest.plist`;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export const testUpdateBranch1: UpdateBranchObject = {
|
||||
group: '16ca6dba-e63b-48b0-baa3-15a894ee9434',
|
||||
message: 'fix bug',
|
||||
createdAt: '2023-07-17T22:48:59.278Z',
|
||||
runtimeVersion: 'exposdk:48.0.0',
|
||||
runtime: { id: 'runtime-exposdk-48', version: 'exposdk:48.0.0' },
|
||||
platform: 'ios',
|
||||
manifestFragment:
|
||||
'{"extra":{"expoClient":{"ios":{"supportsTablet":true,"bundleIdentifier":"com.quintest113.updatestest4"},"web":{"favicon":"./assets/favicon.png"},"icon":"./assets/icon.png","name":"updates-test-4","slug":"updates-test-4","extra":{"eas":{"projectId":"789a8784-0186-4f41-8bd2-7f219291a2b8"}},"splash":{"image":"./assets/splash.png","resizeMode":"contain","backgroundColor":"#ffffff"},"android":{"package":"com.quintest113.updatestest4","adaptiveIcon":{"backgroundColor":"#ffffff","foregroundImage":"./assets/adaptive-icon.png"}},"updates":{"url":"https://u.expo.dev/789a8784-0186-4f41-8bd2-7f219291a2b8"},"version":"1.0.0","platforms":["ios","android"],"sdkVersion":"48.0.0","orientation":"portrait","runtimeVersion":{"policy":"sdkVersion"},"currentFullName":"@quintest113/updates-test-4","originalFullName":"@quintest113/updates-test-4","userInterfaceStyle":"light","assetBundlePatterns":["**/*"]}},"assets":[{"bundleKey":"7d40544b395c5949f4646f5e150fe020","fileSHA256":"LN_rjlzN55dvcBL7jM5zryIpAp7iHU8VCf7RFIccbNg","storageKey":"Pi65ns2w9xLI5G_m9aGrJ5wK5FpWcGcInSSFwnA_0aA","contentType":"image/png","fileExtension":".png"},{"bundleKey":"cdd04e13d4ec83ff0cd13ec8dabdc341","fileSHA256":"irHji01LPI9giDYxtJo9bTPHaEHzuUcCMTlb4xn90Ks","storageKey":"oJZ9JX1m8IKNDgnIqcKOo5KUFOoa_NCaxruigZu65E0","contentType":"image/png","fileExtension":".png"},{"bundleKey":"a132ecc4ba5c1517ff83c0fb321bc7fc","fileSHA256":"K3RDqaWOksoRpXW9wRWYYVpX3eMFzYznDWAmBrMCzZg","storageKey":"X3OAkUu5P_LqyKFx1bNkA_qDQFLlSjCYNAlVEaOamHE","contentType":"image/png","fileExtension":".png"},{"bundleKey":"0ea69b5077e7c4696db85dbcba75b0e1","fileSHA256":"Pd0Hc-0n4j0leJ8wFzGzrEVa2L5aonoKG4OPicbSciU","storageKey":"FwJkAbrRNahBGX1KXnTAgiiwyzENu3D7DeEzCwmInyo","contentType":"image/png","fileExtension":".png"},{"bundleKey":"f5b790e2ac193b3d41015edb3551f9b8","fileSHA256":"vCfIss7SLYKt1AAi0hxjsgOMEDceLJB6ZWjQf6gTU4k","storageKey":"GQtYm7r0G9N3WJyrymjZ26p8eNMIb7rzqwSVgGco5EU","contentType":"image/png","fileExtension":".png"},{"bundleKey":"5223c8d9b0d08b82a5670fb5f71faf78","fileSHA256":"LJXowmdeeZM1_QBGuwfb2gbLfs_1HtN5IsYwnWGcxNM","storageKey":"jeqOrdQBNY4hgl04B3wtGs8QNWMDmjvbjIMUXPtOBpw","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02d5848f62ade9617cf96894727d32e7","fileSHA256":"u1-8zHOj9oxS8maH-7JbShJIq1-KEV7FXnrGpEUcR-4","storageKey":"LMUvUZZpdGFb7KqaB_l9N4TXTkFn1Pw92ws9fWDNZPw","contentType":"model/gltf-binary","fileExtension":".glb"},{"bundleKey":"6013c27e421ab23c826713af3ebec891","fileSHA256":"dutQNnvzTCS4NgwvbeMbvhro5QnW0GJUeY_4rrvlcLY","storageKey":"85KB9Jr7eqz1Jwt1mYQGRzTy6ZXyO0j7ZcaLImCbzkU","contentType":"image/jpeg","fileExtension":".jpg"}],"launchAsset":{"bundleKey":"3d0ac172fe41ab941a8c68cd7e3a17ee","fileSHA256":"jjnar-ZPrb_g0Bx5tcFfjJrP3v8HdeAlXMk__xN7I1U","storageKey":"bimf-UXq5IFH5nNHCIHdcQ2MyJwTnwDVBb-P8hr2CZw","contentType":"application/javascript","fileExtension":".bundle"}}',
|
||||
@@ -37,7 +37,7 @@ export const testUpdateBranch1: UpdateBranchObject = {
|
||||
group: '16ca6dba-e63b-48b0-baa3-15a894ee9434',
|
||||
message: 'fix bug',
|
||||
createdAt: '2023-07-17T22:48:59.278Z',
|
||||
runtimeVersion: 'exposdk:48.0.0',
|
||||
runtime: { id: 'runtime-exposdk-48', version: 'exposdk:48.0.0' },
|
||||
platform: 'android',
|
||||
manifestFragment:
|
||||
'{"extra":{"expoClient":{"ios":{"supportsTablet":true,"bundleIdentifier":"com.quintest113.updatestest4"},"web":{"favicon":"./assets/favicon.png"},"icon":"./assets/icon.png","name":"updates-test-4","slug":"updates-test-4","extra":{"eas":{"projectId":"789a8784-0186-4f41-8bd2-7f219291a2b8"}},"splash":{"image":"./assets/splash.png","resizeMode":"contain","backgroundColor":"#ffffff"},"android":{"package":"com.quintest113.updatestest4","adaptiveIcon":{"backgroundColor":"#ffffff","foregroundImage":"./assets/adaptive-icon.png"}},"updates":{"url":"https://u.expo.dev/789a8784-0186-4f41-8bd2-7f219291a2b8"},"version":"1.0.0","platforms":["ios","android"],"sdkVersion":"48.0.0","orientation":"portrait","runtimeVersion":{"policy":"sdkVersion"},"currentFullName":"@quintest113/updates-test-4","originalFullName":"@quintest113/updates-test-4","userInterfaceStyle":"light","assetBundlePatterns":["**/*"]}},"assets":[{"bundleKey":"778ffc9fe8773a878e9c30a6304784de","fileSHA256":"i2Gkx-9w3JJ1PwSUl2SC9m_UFQ7CPfx3KrZeEDc6-lU","storageKey":"idnX8z03q4vGLzhYMPaQGBADjhqvWe67_afPqJ1vGzM","contentType":"image/png","fileExtension":".png"},{"bundleKey":"376d6a4c7f622917c39feb23671ef71d","fileSHA256":"QJsG0VpGM-5viirUgoKq0M4zQ_TYyPfLhAhN5mrM54I","storageKey":"46DQ95-UdSKiRkQgt5FyXkE1FrKOT9tBZP3nS7auKlg","contentType":"image/png","fileExtension":".png"},{"bundleKey":"c79c3606a1cf168006ad3979763c7e0c","fileSHA256":"kGZm3WiTRq2iMs42ia3vkHtCV_obWT8DY40rlJf2SIQ","storageKey":"k-3xHp3vP8mR36WdccUZVPTRJKpP-zlyboWdkXCIQpQ","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02bc1fa7c0313217bde2d65ccbff40c9","fileSHA256":"_6fuRbdkBbpzkhSVAI99aMneY5X0tpQdsGNGX244IyA","storageKey":"lfqeUjiWFXwowhxVDBEzxsbTOEzYxMLebljy5Bh1mpU","contentType":"image/png","fileExtension":".png"},{"bundleKey":"35ba0eaec5a4f5ed12ca16fabeae451d","fileSHA256":"hM9es7ICUPaeDkczvrTaX0F_BoKJKlrRteYlcHU8IbE","storageKey":"fMoMrsUeB5xWw_Ugn8FqGJf-M2pld2hkXKR704z0MM8","contentType":"image/png","fileExtension":".png"},{"bundleKey":"5223c8d9b0d08b82a5670fb5f71faf78","fileSHA256":"LJXowmdeeZM1_QBGuwfb2gbLfs_1HtN5IsYwnWGcxNM","storageKey":"jeqOrdQBNY4hgl04B3wtGs8QNWMDmjvbjIMUXPtOBpw","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02d5848f62ade9617cf96894727d32e7","fileSHA256":"u1-8zHOj9oxS8maH-7JbShJIq1-KEV7FXnrGpEUcR-4","storageKey":"LMUvUZZpdGFb7KqaB_l9N4TXTkFn1Pw92ws9fWDNZPw","contentType":"model/gltf-binary","fileExtension":".glb"},{"bundleKey":"6013c27e421ab23c826713af3ebec891","fileSHA256":"dutQNnvzTCS4NgwvbeMbvhro5QnW0GJUeY_4rrvlcLY","storageKey":"85KB9Jr7eqz1Jwt1mYQGRzTy6ZXyO0j7ZcaLImCbzkU","contentType":"image/jpeg","fileExtension":".jpg"}],"launchAsset":{"bundleKey":"4cc2ee49988e438ac066827b809721de","fileSHA256":"ctfK72f8EdS1IQmDvJLya38RMSma16beJcMoQToZIe0","storageKey":"QdEoKuCQPvVPA71gY52wqJ9vmtV4ObnCcPE2FP4SIdo","contentType":"application/javascript","fileExtension":".bundle"}}',
|
||||
@@ -73,7 +73,7 @@ export const testUpdateBranch2: UpdateBranchObject = {
|
||||
group: 'e40ad156-e9af-4cc2-8e9d-c7b5c328db48',
|
||||
message: 'fix bug',
|
||||
createdAt: '2023-06-23T23:37:10.004Z',
|
||||
runtimeVersion: 'exposdk:48.0.0',
|
||||
runtime: { id: 'runtime-exposdk-48', version: 'exposdk:48.0.0' },
|
||||
platform: 'ios',
|
||||
manifestFragment:
|
||||
'{"extra":{"expoClient":{"ios":{"supportsTablet":true,"bundleIdentifier":"com.quintest113.updatestest4"},"web":{"favicon":"./assets/favicon.png"},"icon":"./assets/icon.png","name":"updates-test-4","slug":"updates-test-4","extra":{"eas":{"projectId":"789a8784-0186-4f41-8bd2-7f219291a2b8"}},"splash":{"image":"./assets/splash.png","resizeMode":"contain","backgroundColor":"#ffffff"},"android":{"package":"com.quintest113.updatestest4","adaptiveIcon":{"backgroundColor":"#ffffff","foregroundImage":"./assets/adaptive-icon.png"}},"updates":{"url":"https://u.expo.dev/789a8784-0186-4f41-8bd2-7f219291a2b8"},"version":"1.0.0","platforms":["ios","android"],"sdkVersion":"48.0.0","orientation":"portrait","runtimeVersion":{"policy":"sdkVersion"},"currentFullName":"@quintest113/updates-test-4","originalFullName":"@quintest113/updates-test-4","userInterfaceStyle":"light","assetBundlePatterns":["**/*"]}},"assets":[{"bundleKey":"7d40544b395c5949f4646f5e150fe020","fileSHA256":"LN_rjlzN55dvcBL7jM5zryIpAp7iHU8VCf7RFIccbNg","storageKey":"Pi65ns2w9xLI5G_m9aGrJ5wK5FpWcGcInSSFwnA_0aA","contentType":"image/png","fileExtension":".png"},{"bundleKey":"cdd04e13d4ec83ff0cd13ec8dabdc341","fileSHA256":"irHji01LPI9giDYxtJo9bTPHaEHzuUcCMTlb4xn90Ks","storageKey":"oJZ9JX1m8IKNDgnIqcKOo5KUFOoa_NCaxruigZu65E0","contentType":"image/png","fileExtension":".png"},{"bundleKey":"a132ecc4ba5c1517ff83c0fb321bc7fc","fileSHA256":"K3RDqaWOksoRpXW9wRWYYVpX3eMFzYznDWAmBrMCzZg","storageKey":"X3OAkUu5P_LqyKFx1bNkA_qDQFLlSjCYNAlVEaOamHE","contentType":"image/png","fileExtension":".png"},{"bundleKey":"0ea69b5077e7c4696db85dbcba75b0e1","fileSHA256":"Pd0Hc-0n4j0leJ8wFzGzrEVa2L5aonoKG4OPicbSciU","storageKey":"FwJkAbrRNahBGX1KXnTAgiiwyzENu3D7DeEzCwmInyo","contentType":"image/png","fileExtension":".png"},{"bundleKey":"f5b790e2ac193b3d41015edb3551f9b8","fileSHA256":"vCfIss7SLYKt1AAi0hxjsgOMEDceLJB6ZWjQf6gTU4k","storageKey":"GQtYm7r0G9N3WJyrymjZ26p8eNMIb7rzqwSVgGco5EU","contentType":"image/png","fileExtension":".png"},{"bundleKey":"5223c8d9b0d08b82a5670fb5f71faf78","fileSHA256":"LJXowmdeeZM1_QBGuwfb2gbLfs_1HtN5IsYwnWGcxNM","storageKey":"jeqOrdQBNY4hgl04B3wtGs8QNWMDmjvbjIMUXPtOBpw","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02d5848f62ade9617cf96894727d32e7","fileSHA256":"u1-8zHOj9oxS8maH-7JbShJIq1-KEV7FXnrGpEUcR-4","storageKey":"LMUvUZZpdGFb7KqaB_l9N4TXTkFn1Pw92ws9fWDNZPw","contentType":"model/gltf-binary","fileExtension":".glb"},{"bundleKey":"6013c27e421ab23c826713af3ebec891","fileSHA256":"dutQNnvzTCS4NgwvbeMbvhro5QnW0GJUeY_4rrvlcLY","storageKey":"85KB9Jr7eqz1Jwt1mYQGRzTy6ZXyO0j7ZcaLImCbzkU","contentType":"image/jpeg","fileExtension":".jpg"}],"launchAsset":{"bundleKey":"76ec49faddaef30ba78fe50edc5ab3d6","fileSHA256":"OLUdgP-fZI2shwGS5qlIk7nWnybL_13RJl5xR85CDBU","storageKey":"OCvI0-34zApbdo3eSGfIaQUbWdZeLeKH-nJSeedKTFs","contentType":"application/javascript","fileExtension":".bundle"}}',
|
||||
@@ -99,7 +99,7 @@ export const testUpdateBranch2: UpdateBranchObject = {
|
||||
group: 'e40ad156-e9af-4cc2-8e9d-c7b5c328db48',
|
||||
message: 'fix bug',
|
||||
createdAt: '2023-06-23T23:37:10.004Z',
|
||||
runtimeVersion: 'exposdk:48.0.0',
|
||||
runtime: { id: 'runtime-exposdk-48', version: 'exposdk:48.0.0' },
|
||||
platform: 'android',
|
||||
manifestFragment:
|
||||
'{"extra":{"expoClient":{"ios":{"supportsTablet":true,"bundleIdentifier":"com.quintest113.updatestest4"},"web":{"favicon":"./assets/favicon.png"},"icon":"./assets/icon.png","name":"updates-test-4","slug":"updates-test-4","extra":{"eas":{"projectId":"789a8784-0186-4f41-8bd2-7f219291a2b8"}},"splash":{"image":"./assets/splash.png","resizeMode":"contain","backgroundColor":"#ffffff"},"android":{"package":"com.quintest113.updatestest4","adaptiveIcon":{"backgroundColor":"#ffffff","foregroundImage":"./assets/adaptive-icon.png"}},"updates":{"url":"https://u.expo.dev/789a8784-0186-4f41-8bd2-7f219291a2b8"},"version":"1.0.0","platforms":["ios","android"],"sdkVersion":"48.0.0","orientation":"portrait","runtimeVersion":{"policy":"sdkVersion"},"currentFullName":"@quintest113/updates-test-4","originalFullName":"@quintest113/updates-test-4","userInterfaceStyle":"light","assetBundlePatterns":["**/*"]}},"assets":[{"bundleKey":"778ffc9fe8773a878e9c30a6304784de","fileSHA256":"i2Gkx-9w3JJ1PwSUl2SC9m_UFQ7CPfx3KrZeEDc6-lU","storageKey":"idnX8z03q4vGLzhYMPaQGBADjhqvWe67_afPqJ1vGzM","contentType":"image/png","fileExtension":".png"},{"bundleKey":"376d6a4c7f622917c39feb23671ef71d","fileSHA256":"QJsG0VpGM-5viirUgoKq0M4zQ_TYyPfLhAhN5mrM54I","storageKey":"46DQ95-UdSKiRkQgt5FyXkE1FrKOT9tBZP3nS7auKlg","contentType":"image/png","fileExtension":".png"},{"bundleKey":"c79c3606a1cf168006ad3979763c7e0c","fileSHA256":"kGZm3WiTRq2iMs42ia3vkHtCV_obWT8DY40rlJf2SIQ","storageKey":"k-3xHp3vP8mR36WdccUZVPTRJKpP-zlyboWdkXCIQpQ","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02bc1fa7c0313217bde2d65ccbff40c9","fileSHA256":"_6fuRbdkBbpzkhSVAI99aMneY5X0tpQdsGNGX244IyA","storageKey":"lfqeUjiWFXwowhxVDBEzxsbTOEzYxMLebljy5Bh1mpU","contentType":"image/png","fileExtension":".png"},{"bundleKey":"35ba0eaec5a4f5ed12ca16fabeae451d","fileSHA256":"hM9es7ICUPaeDkczvrTaX0F_BoKJKlrRteYlcHU8IbE","storageKey":"fMoMrsUeB5xWw_Ugn8FqGJf-M2pld2hkXKR704z0MM8","contentType":"image/png","fileExtension":".png"},{"bundleKey":"5223c8d9b0d08b82a5670fb5f71faf78","fileSHA256":"LJXowmdeeZM1_QBGuwfb2gbLfs_1HtN5IsYwnWGcxNM","storageKey":"jeqOrdQBNY4hgl04B3wtGs8QNWMDmjvbjIMUXPtOBpw","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02d5848f62ade9617cf96894727d32e7","fileSHA256":"u1-8zHOj9oxS8maH-7JbShJIq1-KEV7FXnrGpEUcR-4","storageKey":"LMUvUZZpdGFb7KqaB_l9N4TXTkFn1Pw92ws9fWDNZPw","contentType":"model/gltf-binary","fileExtension":".glb"},{"bundleKey":"6013c27e421ab23c826713af3ebec891","fileSHA256":"dutQNnvzTCS4NgwvbeMbvhro5QnW0GJUeY_4rrvlcLY","storageKey":"85KB9Jr7eqz1Jwt1mYQGRzTy6ZXyO0j7ZcaLImCbzkU","contentType":"image/jpeg","fileExtension":".jpg"}],"launchAsset":{"bundleKey":"f4c6981626dbabcf51078d07a1611f4e","fileSHA256":"q-k1hSWl49aXpSg4jOSaVVnYFSFL6xf7HVl_TQE-ObM","storageKey":"FwK1PaZqtpL0QZIgaHsxU1AV93JhMdu9K1wZizXROAc","contentType":"application/javascript","fileExtension":".bundle"}}',
|
||||
|
||||
@@ -46,7 +46,11 @@ function makeInsights(
|
||||
id: u.id,
|
||||
group: u.group,
|
||||
message: u.message,
|
||||
runtimeVersion: u.runtimeVersion,
|
||||
runtime: {
|
||||
__typename: 'Runtime' as const,
|
||||
id: `${u.id}-runtime`,
|
||||
version: u.runtimeVersion,
|
||||
},
|
||||
platform: u.platform,
|
||||
insights: {
|
||||
__typename: 'UpdateInsights' as const,
|
||||
|
||||
+8
-8
@@ -48,18 +48,18 @@ describe(getProjectIdAsync, () => {
|
||||
primaryAccount: {
|
||||
id: 'account_id_1',
|
||||
name: 'notnotbrent',
|
||||
users: [{ role: Role.Owner, actor: { id: 'user_id' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
accounts: [
|
||||
{
|
||||
id: 'account_id_1',
|
||||
name: 'notnotbrent',
|
||||
users: [{ role: Role.Owner, actor: { id: 'user_id' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
{
|
||||
id: 'account_id_2',
|
||||
name: 'dominik',
|
||||
users: [{ role: Role.ViewOnly, actor: { id: 'user_id' } }],
|
||||
viewerUserPermission: { role: Role.ViewOnly },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
@@ -198,12 +198,12 @@ describe(getProjectIdAsync, () => {
|
||||
{
|
||||
id: 'account_id_1',
|
||||
name: 'notnotbrent',
|
||||
users: [{ role: Role.Admin, actor: { id: 'robot_id' } }],
|
||||
viewerUserPermission: { role: Role.Admin },
|
||||
},
|
||||
{
|
||||
id: 'account_id_2',
|
||||
name: 'dominik',
|
||||
users: [{ role: Role.ViewOnly, actor: { id: 'robot_id' } }],
|
||||
viewerUserPermission: { role: Role.ViewOnly },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
@@ -423,13 +423,13 @@ describe(getProjectIdAsync, () => {
|
||||
primaryAccount: {
|
||||
id: 'account_id_1',
|
||||
name: 'notnotbrent',
|
||||
users: [{ role: Role.Owner, actor: { id: 'user_id' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
accounts: [
|
||||
{
|
||||
id: 'account_id_1',
|
||||
name: 'notnotbrent',
|
||||
users: [{ role: Role.Owner, actor: { id: 'user_id' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
@@ -465,7 +465,7 @@ describe(getProjectIdAsync, () => {
|
||||
{
|
||||
id: 'account_id_1',
|
||||
name: 'notnotbrent',
|
||||
users: [{ role: Role.Admin, actor: { id: 'robot_id' } }],
|
||||
viewerUserPermission: { role: Role.Admin },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ExpoConfig } from '@expo/config';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import { getEASUpdateURL } from '../../../api';
|
||||
import { AppFragment } from '../../../graphql/generated';
|
||||
import { AppFragment, Role } from '../../../graphql/generated';
|
||||
import { easCliVersion } from '../../../utils/easCli';
|
||||
import {
|
||||
cleanAndPrefix,
|
||||
@@ -62,7 +62,7 @@ describe('projectFiles', () => {
|
||||
ownerAccount: {
|
||||
id: 'testowner-account-id',
|
||||
name: 'testowner',
|
||||
users: [],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
...overrides,
|
||||
});
|
||||
@@ -126,7 +126,7 @@ describe('projectFiles', () => {
|
||||
ownerAccount: {
|
||||
id: 'test-owner-account-id',
|
||||
name: 'test-owner',
|
||||
users: [],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -151,7 +151,7 @@ describe('projectFiles', () => {
|
||||
ownerAccount: {
|
||||
id: 'test-owner-123-account-id',
|
||||
name: 'test-owner-123',
|
||||
users: [],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -80,8 +80,7 @@ function getAccountPermissionsMap(actor: Actor): Map<string, boolean> {
|
||||
const permissionsMap = new Map<string, boolean>();
|
||||
|
||||
for (const account of actor.accounts) {
|
||||
const hasPermission =
|
||||
account.users.find(it => it.actor.id === actor.id)?.role !== Role.ViewOnly;
|
||||
const hasPermission = account.viewerUserPermission.role !== Role.ViewOnly;
|
||||
permissionsMap.set(account.name, hasPermission);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import chalk from 'chalk';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import { Role } from '../../graphql/generated';
|
||||
@@ -52,7 +51,7 @@ export default class AccountView extends EasCommand {
|
||||
return Role.Owner;
|
||||
}
|
||||
|
||||
return nullthrows(account.users.find(user => user.actor.id === actor.id)?.role);
|
||||
return account.viewerUserPermission.role;
|
||||
}
|
||||
|
||||
private static getLabelForRole(role: Role): string {
|
||||
|
||||
@@ -27,8 +27,8 @@ async function cancelBuildAsync(
|
||||
.mutation<CancelBuildMutation, CancelBuildMutationVariables>(
|
||||
gql`
|
||||
mutation CancelBuildMutation($buildId: ID!) {
|
||||
build(buildId: $buildId) {
|
||||
cancel {
|
||||
build {
|
||||
cancelBuild(buildId: $buildId) {
|
||||
id
|
||||
status
|
||||
}
|
||||
@@ -39,7 +39,7 @@ async function cancelBuildAsync(
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.build.cancel;
|
||||
return data.build.cancelBuild;
|
||||
}
|
||||
|
||||
export async function selectBuildToCancelAsync(
|
||||
|
||||
@@ -235,7 +235,7 @@ export default class Download extends EasCommand {
|
||||
|
||||
async getPathToBuildArtifactAsync(build: BuildFragment, platform: AppPlatform): Promise<string> {
|
||||
const cachedBuildArtifactPath = getEasBuildRunCachedAppPath(
|
||||
build.project.id,
|
||||
build.app.id,
|
||||
build.id,
|
||||
platform
|
||||
);
|
||||
|
||||
@@ -26,7 +26,7 @@ const insightsResponse = {
|
||||
id: 'u1',
|
||||
group: 'group-a',
|
||||
message: 'first',
|
||||
runtimeVersion: '1.0.0',
|
||||
runtime: { __typename: 'Runtime' as const, id: 'u1-runtime', version: '1.0.0' },
|
||||
platform: 'ios',
|
||||
insights: { __typename: 'UpdateInsights' as const, id: 'u1-i', totalUniqueUsers: 200 },
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@ import { AppStoreConnectApiKeyQuery } from '../../../../credentials/ios/api/grap
|
||||
import { AscAppLinkMutation } from '../../../../graphql/mutations/AscAppLinkMutation';
|
||||
import { AscAppLinkQuery } from '../../../../graphql/queries/AscAppLinkQuery';
|
||||
import IntegrationsAscConnect from '../connect';
|
||||
import { Role } from '../../../../graphql/generated';
|
||||
|
||||
jest.mock('../../../../graphql/queries/AscAppLinkQuery');
|
||||
jest.mock('../../../../graphql/mutations/AscAppLinkMutation');
|
||||
@@ -18,7 +19,12 @@ const testProjectId = 'test-project-id';
|
||||
const mockMetadataConnected = {
|
||||
id: testProjectId,
|
||||
fullName: '@testuser/testapp',
|
||||
ownerAccount: { id: 'account-id', name: 'testuser', ownerUserActor: null, users: [] },
|
||||
ownerAccount: {
|
||||
id: 'account-id',
|
||||
name: 'testuser',
|
||||
ownerUserActor: null,
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
appStoreConnectApp: {
|
||||
id: 'asc-app-link-id',
|
||||
ascAppIdentifier: '1234567890',
|
||||
@@ -34,7 +40,12 @@ const mockMetadataConnected = {
|
||||
const mockMetadataDisconnected = {
|
||||
id: testProjectId,
|
||||
fullName: '@testuser/testapp',
|
||||
ownerAccount: { id: 'account-id', name: 'testuser', ownerUserActor: null, users: [] },
|
||||
ownerAccount: {
|
||||
id: 'account-id',
|
||||
name: 'testuser',
|
||||
ownerUserActor: null,
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
appStoreConnectApp: null,
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { AscAppLinkQuery } from '../../../../graphql/queries/AscAppLinkQuery';
|
||||
import Log from '../../../../log';
|
||||
import { toggleConfirmAsync } from '../../../../prompts';
|
||||
import IntegrationsAscDisconnect from '../disconnect';
|
||||
import { Role } from '../../../../graphql/generated';
|
||||
|
||||
jest.mock('../../../../graphql/queries/AscAppLinkQuery');
|
||||
jest.mock('../../../../graphql/mutations/AscAppLinkMutation');
|
||||
@@ -19,7 +20,12 @@ const testProjectId = 'test-project-id';
|
||||
const mockMetadataConnected = {
|
||||
id: testProjectId,
|
||||
fullName: '@testuser/testapp',
|
||||
ownerAccount: { id: 'account-id', name: 'testuser', ownerUserActor: null, users: [] },
|
||||
ownerAccount: {
|
||||
id: 'account-id',
|
||||
name: 'testuser',
|
||||
ownerUserActor: null,
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
appStoreConnectApp: {
|
||||
id: 'asc-app-link-id',
|
||||
ascAppIdentifier: '1234567890',
|
||||
@@ -35,7 +41,12 @@ const mockMetadataConnected = {
|
||||
const mockMetadataDisconnected = {
|
||||
id: testProjectId,
|
||||
fullName: '@testuser/testapp',
|
||||
ownerAccount: { id: 'account-id', name: 'testuser', ownerUserActor: null, users: [] },
|
||||
ownerAccount: {
|
||||
id: 'account-id',
|
||||
name: 'testuser',
|
||||
ownerUserActor: null,
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
appStoreConnectApp: null,
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ExpoGraphqlClient } from '../../../../commandUtils/context/contextUtils
|
||||
import { AscAppLinkQuery } from '../../../../graphql/queries/AscAppLinkQuery';
|
||||
import Log from '../../../../log';
|
||||
import IntegrationsAscStatus from '../status';
|
||||
import { Role } from '../../../../graphql/generated';
|
||||
|
||||
jest.mock('../../../../graphql/queries/AscAppLinkQuery');
|
||||
jest.mock('../../../../log');
|
||||
@@ -15,7 +16,12 @@ const testProjectId = 'test-project-id';
|
||||
const mockMetadataConnected = {
|
||||
id: testProjectId,
|
||||
fullName: '@testuser/testapp',
|
||||
ownerAccount: { id: 'account-id', name: 'testuser', ownerUserActor: null, users: [] },
|
||||
ownerAccount: {
|
||||
id: 'account-id',
|
||||
name: 'testuser',
|
||||
ownerUserActor: null,
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
appStoreConnectApp: {
|
||||
id: 'asc-app-link-id',
|
||||
ascAppIdentifier: '1234567890',
|
||||
@@ -31,7 +37,12 @@ const mockMetadataConnected = {
|
||||
const mockMetadataDisconnected = {
|
||||
id: testProjectId,
|
||||
fullName: '@testuser/testapp',
|
||||
ownerAccount: { id: 'account-id', name: 'testuser', ownerUserActor: null, users: [] },
|
||||
ownerAccount: {
|
||||
id: 'account-id',
|
||||
name: 'testuser',
|
||||
ownerUserActor: null,
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
appStoreConnectApp: null,
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
EnvironmentSecretType,
|
||||
EnvironmentVariableScope,
|
||||
EnvironmentVariableVisibility,
|
||||
Role,
|
||||
} from '../../../../graphql/generated';
|
||||
import { ConvexMutation } from '../../../../graphql/mutations/ConvexMutation';
|
||||
import { EnvironmentVariableMutation } from '../../../../graphql/mutations/EnvironmentVariableMutation';
|
||||
@@ -59,7 +60,7 @@ describe(IntegrationsConvexConnect, () => {
|
||||
id: testAccountId,
|
||||
name: testAccountName,
|
||||
ownerUserActor: null,
|
||||
users: [],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
accounts: [],
|
||||
};
|
||||
@@ -76,7 +77,7 @@ describe(IntegrationsConvexConnect, () => {
|
||||
id: testAccountId,
|
||||
name: testAccountName,
|
||||
ownerUserActor: { id: 'test-user-id', username: testAccountName },
|
||||
users: [{ role: 'OWNER' as any, actor: { id: 'test-user-id' } }],
|
||||
viewerUserPermission: { role: 'OWNER' as any },
|
||||
};
|
||||
|
||||
const mockConnection: ConvexTeamConnectionData = {
|
||||
|
||||
@@ -32,7 +32,7 @@ describe(IntegrationsConvexTeamDelete, () => {
|
||||
id: testAccountId,
|
||||
name: testAccountName,
|
||||
ownerUserActor: { id: 'test-user-id', username: testAccountName },
|
||||
users: [{ role: 'OWNER' as any, actor: { id: 'test-user-id' } }],
|
||||
viewerUserPermission: { role: 'OWNER' as any },
|
||||
};
|
||||
|
||||
const mockConnection: ConvexTeamConnectionData = {
|
||||
|
||||
@@ -41,7 +41,7 @@ describe(IntegrationsConvexTeamInvite, () => {
|
||||
id: testAccountId,
|
||||
name: testAccountName,
|
||||
ownerUserActor: { id: 'test-user-id', username: testAccountName },
|
||||
users: [{ role: 'OWNER' as any, actor: { id: 'test-user-id' } }],
|
||||
viewerUserPermission: { role: 'OWNER' as any },
|
||||
};
|
||||
|
||||
const mockConnection: ConvexTeamConnectionData = {
|
||||
|
||||
@@ -21,7 +21,7 @@ describe(IntegrationsConvexTeam, () => {
|
||||
id: testAccountId,
|
||||
name: testAccountName,
|
||||
ownerUserActor: { id: 'test-user-id', username: testAccountName },
|
||||
users: [{ role: 'OWNER' as any, actor: { id: 'test-user-id' } }],
|
||||
viewerUserPermission: { role: 'OWNER' as any },
|
||||
};
|
||||
|
||||
const mockConnection: ConvexTeamConnectionData = {
|
||||
|
||||
@@ -62,7 +62,12 @@ describe(IntegrationsPostHogConnect, () => {
|
||||
email: '[email protected]',
|
||||
featureGates: {},
|
||||
isExpoAdmin: false,
|
||||
primaryAccount: { id: testAccountId, name: testAccountName, ownerUserActor: null, users: [] },
|
||||
primaryAccount: {
|
||||
id: testAccountId,
|
||||
name: testAccountName,
|
||||
ownerUserActor: null,
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
accounts: [],
|
||||
};
|
||||
|
||||
@@ -70,7 +75,7 @@ describe(IntegrationsPostHogConnect, () => {
|
||||
id: testAccountId,
|
||||
name: testAccountName,
|
||||
ownerUserActor: { id: 'test-user-id', username: testAccountName },
|
||||
users: [{ role: Role.Owner, actor: { id: 'test-user-id' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
};
|
||||
|
||||
const mockConnection: PostHogOrganizationConnectionData = {
|
||||
|
||||
@@ -35,7 +35,7 @@ const updateStub: UpdateFragment = {
|
||||
group: 'group-1234',
|
||||
branch: { id: 'branch-1234', name: 'main' },
|
||||
message: 'test message',
|
||||
runtimeVersion: 'exposdk:47.0.0',
|
||||
runtime: { id: 'runtime-1234', version: 'exposdk:47.0.0' },
|
||||
platform: 'ios',
|
||||
gitCommitHash: 'commit',
|
||||
isGitWorkingTreeDirty: false,
|
||||
|
||||
@@ -30,7 +30,7 @@ const updateStub: UpdateFragment = {
|
||||
group: 'group-1234',
|
||||
branch: { id: 'branch-1234', name: 'main' },
|
||||
message: 'test message',
|
||||
runtimeVersion: 'exposdk:47.0.0',
|
||||
runtime: { id: 'runtime-1234', version: 'exposdk:47.0.0' },
|
||||
platform: 'ios',
|
||||
gitCommitHash: 'commit',
|
||||
isGitWorkingTreeDirty: false,
|
||||
@@ -154,7 +154,7 @@ describe(UpdateRepublish.name, () => {
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
branchId: updateStub.branch.id,
|
||||
runtimeVersion: updateStub.runtimeVersion,
|
||||
runtimeVersion: updateStub.runtime.version,
|
||||
updateInfoGroup: expect.objectContaining({
|
||||
ios: expect.any(Object),
|
||||
}),
|
||||
@@ -225,7 +225,7 @@ describe(UpdateRepublish.name, () => {
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
branchId: updateStub.branch.id,
|
||||
runtimeVersion: updateStub.runtimeVersion,
|
||||
runtimeVersion: updateStub.runtime.version,
|
||||
updateInfoGroup: expect.objectContaining({
|
||||
ios: expect.any(Object),
|
||||
}),
|
||||
@@ -270,7 +270,7 @@ describe(UpdateRepublish.name, () => {
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
branchId: updateStub.branch.id,
|
||||
runtimeVersion: updateStub.runtimeVersion,
|
||||
runtimeVersion: updateStub.runtime.version,
|
||||
updateInfoGroup: expect.objectContaining({
|
||||
ios: expect.any(Object),
|
||||
}),
|
||||
@@ -313,7 +313,7 @@ describe(UpdateRepublish.name, () => {
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
branchId: updateStub.branch.id,
|
||||
runtimeVersion: updateStub.runtimeVersion,
|
||||
runtimeVersion: updateStub.runtime.version,
|
||||
updateInfoGroup: expect.objectContaining({
|
||||
ios: expect.any(Object),
|
||||
}),
|
||||
@@ -357,7 +357,7 @@ describe(UpdateRepublish.name, () => {
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
branchId: 'other-id',
|
||||
runtimeVersion: updateStub.runtimeVersion,
|
||||
runtimeVersion: updateStub.runtime.version,
|
||||
updateInfoGroup: expect.objectContaining({
|
||||
ios: expect.any(Object),
|
||||
}),
|
||||
@@ -401,7 +401,7 @@ describe(UpdateRepublish.name, () => {
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
branchId: 'blah-id',
|
||||
runtimeVersion: updateStub.runtimeVersion,
|
||||
runtimeVersion: updateStub.runtime.version,
|
||||
updateInfoGroup: expect.objectContaining({
|
||||
ios: expect.any(Object),
|
||||
}),
|
||||
|
||||
@@ -30,7 +30,7 @@ const updateStub: UpdateFragment = {
|
||||
group: 'group-1234',
|
||||
branch: { id: 'branch-1234', name: 'main' },
|
||||
message: 'test message',
|
||||
runtimeVersion: 'exposdk:47.0.0',
|
||||
runtime: { id: 'runtime-1234', version: 'exposdk:47.0.0' },
|
||||
platform: 'ios',
|
||||
gitCommitHash: 'commit',
|
||||
isGitWorkingTreeDirty: false,
|
||||
|
||||
@@ -24,7 +24,7 @@ const updateStub: UpdateFragment = {
|
||||
group: 'group-source',
|
||||
branch: { id: 'branch-1234', name: 'main' },
|
||||
message: 'source message',
|
||||
runtimeVersion: 'exposdk:47.0.0',
|
||||
runtime: { id: 'runtime-1234', version: 'exposdk:47.0.0' },
|
||||
platform: 'ios',
|
||||
gitCommitHash: 'commit',
|
||||
isGitWorkingTreeDirty: false,
|
||||
|
||||
@@ -33,7 +33,7 @@ const updateGroup = [
|
||||
actor: null,
|
||||
createdAt: '2026-04-09T00:00:00.000Z',
|
||||
message: 'first',
|
||||
runtimeVersion: '1.0.0',
|
||||
runtime: { __typename: 'Runtime' as const, id: 'runtime-1', version: '1.0.0' },
|
||||
platform: 'ios',
|
||||
manifestPermalink: 'https://expo.dev/manifest/u1',
|
||||
isRollBackToEmbedded: false,
|
||||
|
||||
@@ -670,7 +670,7 @@ export default class UpdatePublish extends EasCommand {
|
||||
version => version.runtimeVersion
|
||||
)) {
|
||||
const newUpdatesForRuntimeVersion = newUpdates.filter(
|
||||
update => update.runtimeVersion === runtime.runtimeVersion
|
||||
update => update.runtime.version === runtime.runtimeVersion
|
||||
);
|
||||
if (newUpdatesForRuntimeVersion.length === 0) {
|
||||
throw new Error(
|
||||
|
||||
@@ -322,7 +322,7 @@ export default class UpdateRevertUpdateRollout extends EasCommand {
|
||||
});
|
||||
|
||||
const platforms = rolloutUpdateGroup.map(update => update.platform) as UpdatePublishPlatform[];
|
||||
const runtimeVersion = rolloutUpdateGroup[0].runtimeVersion;
|
||||
const runtimeVersion = rolloutUpdateGroup[0].runtime.version;
|
||||
const targetBranch = {
|
||||
name: rolloutUpdateGroup[0].branchName,
|
||||
id: rolloutUpdateGroup[0].branchId,
|
||||
|
||||
@@ -147,7 +147,7 @@ async function getSourceUpdateGroupAsync(
|
||||
return {
|
||||
groupId,
|
||||
branchName: arbitraryUpdate.branch.name,
|
||||
runtimeVersion: arbitraryUpdate.runtimeVersion,
|
||||
runtimeVersion: arbitraryUpdate.runtime.version,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -60,14 +60,7 @@ export const testAppFragment: AppFragment = {
|
||||
ownerAccount: {
|
||||
id: 'test-account-id',
|
||||
name: 'testuser',
|
||||
users: [
|
||||
{
|
||||
role: Role.Owner,
|
||||
actor: {
|
||||
id: 'test-user-id',
|
||||
},
|
||||
},
|
||||
],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -11,18 +11,18 @@ export const jester: Actor = {
|
||||
primaryAccount: {
|
||||
id: 'jester-account-id',
|
||||
name: 'jester',
|
||||
users: [{ role: Role.Admin, actor: { id: 'jester-id' } }],
|
||||
viewerUserPermission: { role: Role.Admin },
|
||||
},
|
||||
accounts: [
|
||||
{
|
||||
id: 'jester-account-id',
|
||||
name: 'jester',
|
||||
users: [{ role: Role.Admin, actor: { id: 'jester-id' } }],
|
||||
viewerUserPermission: { role: Role.Admin },
|
||||
},
|
||||
{
|
||||
id: 'other-account-id',
|
||||
name: 'other',
|
||||
users: [{ role: Role.ViewOnly, actor: { id: 'jester-id' } }],
|
||||
viewerUserPermission: { role: Role.ViewOnly },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
@@ -37,7 +37,7 @@ export const jester2 = {
|
||||
{
|
||||
id: 'jester2-account-id',
|
||||
name: 'jester2',
|
||||
users: [{ role: Role.Admin, actor: { id: 'jester2-id' } }],
|
||||
viewerUserPermission: { role: Role.Admin },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
@@ -52,7 +52,7 @@ export const robot: Actor = {
|
||||
{
|
||||
id: 'robot-account-id',
|
||||
name: 'robot-account',
|
||||
users: [],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
|
||||
@@ -60,14 +60,7 @@ export const testAppFragment: AppFragment = {
|
||||
ownerAccount: {
|
||||
id: 'test-account-id',
|
||||
name: 'testuser',
|
||||
users: [
|
||||
{
|
||||
role: Role.Owner,
|
||||
actor: {
|
||||
id: 'test-user-id',
|
||||
},
|
||||
},
|
||||
],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CredentialsSource } from '@expo/eas-json';
|
||||
import { vol } from 'memfs';
|
||||
|
||||
import { IosAppBuildCredentialsFragment } from '../../../graphql/generated';
|
||||
import { IosAppBuildCredentialsFragment, Role } from '../../../graphql/generated';
|
||||
import { AppQuery } from '../../../graphql/queries/AppQuery';
|
||||
import { findApplicationTarget } from '../../../project/ios/target';
|
||||
import { getAppstoreMock } from '../../__tests__/fixtures-appstore';
|
||||
@@ -58,7 +58,7 @@ describe(IosCredentialsProvider, () => {
|
||||
account: {
|
||||
id: `id-${appLookupParams.account.name}`,
|
||||
name: appLookupParams.account.name,
|
||||
users: [],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
projectName: appLookupParams.projectName,
|
||||
},
|
||||
@@ -102,7 +102,7 @@ describe(IosCredentialsProvider, () => {
|
||||
account: {
|
||||
id: `id-${appLookupParams.account.name}`,
|
||||
name: appLookupParams.account.name,
|
||||
users: [],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
projectName: appLookupParams.projectName,
|
||||
},
|
||||
|
||||
+55
-11
@@ -1,4 +1,8 @@
|
||||
import { IosAppBuildCredentialsFragment, IosDistributionType } from '../../../../graphql/generated';
|
||||
import {
|
||||
IosAppBuildCredentialsFragment,
|
||||
IosDistributionType,
|
||||
Role,
|
||||
} from '../../../../graphql/generated';
|
||||
import { promptAsync } from '../../../../prompts';
|
||||
import { getAppstoreMock, testAuthCtx } from '../../../__tests__/fixtures-appstore';
|
||||
import { createCtxMock } from '../../../__tests__/fixtures-context';
|
||||
@@ -43,7 +47,11 @@ describe(SetUpInternalProvisioningProfile, () => {
|
||||
});
|
||||
const action = new SetUpInternalProvisioningProfile({
|
||||
app: {
|
||||
account: { id: 'account-id', name: 'account-name', users: [] },
|
||||
account: {
|
||||
id: 'account-id',
|
||||
name: 'account-name',
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
bundleIdentifier: 'com.expo.test',
|
||||
projectName: 'testproject',
|
||||
},
|
||||
@@ -77,7 +85,11 @@ describe(SetUpInternalProvisioningProfile, () => {
|
||||
|
||||
const action = new SetUpInternalProvisioningProfile({
|
||||
app: {
|
||||
account: { id: 'account-id', name: 'account-name', users: [] },
|
||||
account: {
|
||||
id: 'account-id',
|
||||
name: 'account-name',
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
bundleIdentifier: 'com.expo.test',
|
||||
projectName: 'testproject',
|
||||
},
|
||||
@@ -118,7 +130,11 @@ describe(SetUpInternalProvisioningProfile, () => {
|
||||
|
||||
const action = new SetUpInternalProvisioningProfile({
|
||||
app: {
|
||||
account: { id: 'account-id', name: 'account-name', users: [] },
|
||||
account: {
|
||||
id: 'account-id',
|
||||
name: 'account-name',
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
bundleIdentifier: 'com.expo.test',
|
||||
projectName: 'testproject',
|
||||
},
|
||||
@@ -152,7 +168,11 @@ describe(SetUpInternalProvisioningProfile, () => {
|
||||
|
||||
const action = new SetUpInternalProvisioningProfile({
|
||||
app: {
|
||||
account: { id: 'account-id', name: 'account-name', users: [] },
|
||||
account: {
|
||||
id: 'account-id',
|
||||
name: 'account-name',
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
bundleIdentifier: 'com.expo.test',
|
||||
projectName: 'testproject',
|
||||
},
|
||||
@@ -188,7 +208,11 @@ describe(SetUpInternalProvisioningProfile, () => {
|
||||
|
||||
const action = new SetUpInternalProvisioningProfile({
|
||||
app: {
|
||||
account: { id: 'account-id', name: 'account-name', users: [] },
|
||||
account: {
|
||||
id: 'account-id',
|
||||
name: 'account-name',
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
bundleIdentifier: 'com.expo.test',
|
||||
projectName: 'testproject',
|
||||
},
|
||||
@@ -222,7 +246,11 @@ describe(SetUpInternalProvisioningProfile, () => {
|
||||
|
||||
const action = new SetUpInternalProvisioningProfile({
|
||||
app: {
|
||||
account: { id: 'account-id', name: 'account-name', users: [] },
|
||||
account: {
|
||||
id: 'account-id',
|
||||
name: 'account-name',
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
bundleIdentifier: 'com.expo.test',
|
||||
projectName: 'testproject',
|
||||
},
|
||||
@@ -255,7 +283,11 @@ describe(SetUpInternalProvisioningProfile, () => {
|
||||
});
|
||||
const action = new SetUpInternalProvisioningProfile({
|
||||
app: {
|
||||
account: { id: 'account-id', name: 'account-name', users: [] },
|
||||
account: {
|
||||
id: 'account-id',
|
||||
name: 'account-name',
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
bundleIdentifier: 'com.expo.test',
|
||||
projectName: 'testproject',
|
||||
},
|
||||
@@ -276,7 +308,11 @@ describe(SetUpInternalProvisioningProfile, () => {
|
||||
});
|
||||
const action = new SetUpInternalProvisioningProfile({
|
||||
app: {
|
||||
account: { id: 'account-id', name: 'account-name', users: [] },
|
||||
account: {
|
||||
id: 'account-id',
|
||||
name: 'account-name',
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
bundleIdentifier: 'com.expo.test',
|
||||
projectName: 'testproject',
|
||||
},
|
||||
@@ -295,7 +331,11 @@ describe(SetUpInternalProvisioningProfile, () => {
|
||||
});
|
||||
const action = new SetUpInternalProvisioningProfile({
|
||||
app: {
|
||||
account: { id: 'account-id', name: 'account-name', users: [] },
|
||||
account: {
|
||||
id: 'account-id',
|
||||
name: 'account-name',
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
bundleIdentifier: 'com.expo.test',
|
||||
projectName: 'testproject',
|
||||
},
|
||||
@@ -320,7 +360,11 @@ describe(SetUpInternalProvisioningProfile, () => {
|
||||
});
|
||||
const action = new SetUpInternalProvisioningProfile({
|
||||
app: {
|
||||
account: { id: 'account-id', name: 'account-name', users: [] },
|
||||
account: {
|
||||
id: 'account-id',
|
||||
name: 'account-name',
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
bundleIdentifier: 'com.expo.test',
|
||||
projectName: 'testproject',
|
||||
},
|
||||
|
||||
@@ -76,18 +76,22 @@ export const AppleDeviceQuery = {
|
||||
account {
|
||||
byName(accountName: $accountName) {
|
||||
id
|
||||
appleTeams(appleTeamIdentifier: $appleTeamIdentifier) {
|
||||
id
|
||||
appleTeamIdentifier
|
||||
appleTeamName
|
||||
appleDevices(offset: $offset, limit: $limit) {
|
||||
id
|
||||
identifier
|
||||
name
|
||||
deviceClass
|
||||
enabled
|
||||
model
|
||||
createdAt
|
||||
appleTeamsPaginated(first: 1, filter: { appleTeamIdentifier: $appleTeamIdentifier }) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
appleTeamIdentifier
|
||||
appleTeamName
|
||||
appleDevices(offset: $offset, limit: $limit) {
|
||||
id
|
||||
identifier
|
||||
name
|
||||
deviceClass
|
||||
enabled
|
||||
model
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,7 +105,12 @@ export const AppleDeviceQuery = {
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
const [appleTeam] = data.account.byName.appleTeams;
|
||||
const appleTeam = data.account.byName.appleTeamsPaginated.edges[0]?.node;
|
||||
if (!appleTeam) {
|
||||
throw new Error(
|
||||
`Could not find Apple team with the identifier ${appleTeamIdentifier} on account ${accountName}`
|
||||
);
|
||||
}
|
||||
const { appleDevices } = appleTeam;
|
||||
if (!appleDevices) {
|
||||
throw new Error(`Could not find devices on Apple team -- ${formatAppleTeam(appleTeam)}`);
|
||||
|
||||
@@ -5,35 +5,100 @@ import { ExpoGraphqlClient } from '../../../../../commandUtils/context/contextUt
|
||||
import { withErrorHandlingAsync } from '../../../../../graphql/client';
|
||||
import {
|
||||
AppleTeamByIdentifierQuery,
|
||||
AppleTeamFilterInput,
|
||||
AppleTeamFragment,
|
||||
AppleTeamsByAccountNameQuery,
|
||||
AppleTeamsByAccountNameQueryVariables,
|
||||
AppleTeamsPaginatedByAccountQuery,
|
||||
} from '../../../../../graphql/generated';
|
||||
import { AppleTeamFragmentNode } from '../../../../../graphql/types/credentials/AppleTeam';
|
||||
import { Connection } from '../../../../../utils/relay';
|
||||
|
||||
export const AppleTeamQuery = {
|
||||
async getAllForAccountAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
{ accountName, offset, limit }: AppleTeamsByAccountNameQueryVariables
|
||||
{
|
||||
accountName,
|
||||
offset,
|
||||
limit,
|
||||
}: { accountName: string; offset?: number | null; limit?: number | null }
|
||||
): Promise<AppleTeamFragment[]> {
|
||||
// appleTeamsPaginated is cursor-based, so emulate offset/limit by fetching
|
||||
// pages from the start until enough nodes are collected
|
||||
const start = offset ?? 0;
|
||||
const teams: AppleTeamFragment[] = [];
|
||||
let after: string | undefined;
|
||||
while (limit == null || teams.length < start + limit) {
|
||||
const connection = await AppleTeamQuery.getAllForAccountPaginatedAsync(
|
||||
graphqlClient,
|
||||
accountName,
|
||||
{ first: 100, after }
|
||||
);
|
||||
teams.push(...connection.edges.map(edge => edge.node));
|
||||
if (!connection.pageInfo.hasNextPage) {
|
||||
break;
|
||||
}
|
||||
after = connection.pageInfo.endCursor ?? undefined;
|
||||
}
|
||||
return limit == null ? teams.slice(start) : teams.slice(start, start + limit);
|
||||
},
|
||||
async getAllForAccountPaginatedAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string,
|
||||
{
|
||||
after,
|
||||
first,
|
||||
before,
|
||||
last,
|
||||
filter,
|
||||
}: {
|
||||
after?: string;
|
||||
first?: number;
|
||||
before?: string;
|
||||
last?: number;
|
||||
filter?: AppleTeamFilterInput;
|
||||
}
|
||||
): Promise<Connection<AppleTeamFragment>> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<AppleTeamsByAccountNameQuery>(
|
||||
.query<AppleTeamsPaginatedByAccountQuery>(
|
||||
gql`
|
||||
query AppleTeamsByAccountName($accountName: String!, $offset: Int, $limit: Int) {
|
||||
query AppleTeamsPaginatedByAccountQuery(
|
||||
$accountName: String!
|
||||
$after: String
|
||||
$first: Int
|
||||
$before: String
|
||||
$last: Int
|
||||
$filter: AppleTeamFilterInput
|
||||
) {
|
||||
account {
|
||||
byName(accountName: $accountName) {
|
||||
id
|
||||
appleTeams(offset: $offset, limit: $limit) {
|
||||
id
|
||||
...AppleTeamFragment
|
||||
appleTeamsPaginated(
|
||||
after: $after
|
||||
first: $first
|
||||
before: $before
|
||||
last: $last
|
||||
filter: $filter
|
||||
) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
id
|
||||
...AppleTeamFragment
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${print(AppleTeamFragmentNode)}
|
||||
`,
|
||||
{ accountName, offset, limit },
|
||||
{ accountName, after, first, before, last, filter },
|
||||
{
|
||||
additionalTypenames: ['AppleTeam'],
|
||||
}
|
||||
@@ -41,7 +106,7 @@ export const AppleTeamQuery = {
|
||||
.toPromise()
|
||||
);
|
||||
|
||||
return data.account.byName.appleTeams ?? [];
|
||||
return data.account.byName.appleTeamsPaginated;
|
||||
},
|
||||
async getByAppleTeamIdentifierAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
|
||||
@@ -7,6 +7,7 @@ import Log from '../../../../log';
|
||||
import { IosAppCredentialsQuery } from '../../api/graphql/queries/IosAppCredentialsQuery';
|
||||
import { App, Target } from '../../types';
|
||||
import { displayIosCredentials } from '../printCredentials';
|
||||
import { Role } from '../../../../graphql/generated';
|
||||
|
||||
jest.mock('../../../../log');
|
||||
jest.mock('chalk', () => ({
|
||||
@@ -29,7 +30,7 @@ describe('print credentials', () => {
|
||||
account: {
|
||||
id: 'account-id',
|
||||
name: 'quinlanj',
|
||||
users: [],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
projectName: 'test52',
|
||||
};
|
||||
|
||||
@@ -29,18 +29,18 @@ describe(AccountResolver, () => {
|
||||
primaryAccount: {
|
||||
id: 'account_id_777',
|
||||
name: 'dominik',
|
||||
users: [{ role: Role.Owner, actor: { id: 'user_id_666' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
accounts: [
|
||||
{
|
||||
id: 'account_id_777',
|
||||
name: 'dominik',
|
||||
users: [{ role: Role.Owner, actor: { id: 'user_id_666' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
{
|
||||
id: 'account_id_888',
|
||||
name: 'foo',
|
||||
users: [{ role: Role.Owner, actor: { id: 'user_id_666' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
@@ -57,7 +57,7 @@ describe(AccountResolver, () => {
|
||||
ownerAccount: {
|
||||
id: 'account_id_888',
|
||||
name: 'foo',
|
||||
users: [{ role: Role.Owner, actor: { id: 'user_id_666' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -73,7 +73,7 @@ describe(AccountResolver, () => {
|
||||
expect(account).toEqual({
|
||||
id: user.accounts[1].id,
|
||||
name: user.accounts[1].name,
|
||||
users: user.accounts[1].users,
|
||||
viewerUserPermission: user.accounts[1].viewerUserPermission,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -40,14 +40,7 @@ describe(DeviceCreateAction, () => {
|
||||
const account: AccountFragment = {
|
||||
id: 'account_id',
|
||||
name: 'foobar',
|
||||
users: [
|
||||
{
|
||||
role: Role.Owner,
|
||||
actor: {
|
||||
id: 'user_id',
|
||||
},
|
||||
},
|
||||
],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
};
|
||||
const appleTeam = {
|
||||
id: 'apple-team-id',
|
||||
@@ -71,14 +64,7 @@ describe(DeviceCreateAction, () => {
|
||||
const account: AccountFragment = {
|
||||
id: 'account_id',
|
||||
name: 'foobar',
|
||||
users: [
|
||||
{
|
||||
role: Role.Owner,
|
||||
actor: {
|
||||
id: 'user_id',
|
||||
},
|
||||
},
|
||||
],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
};
|
||||
const appleTeam = {
|
||||
id: 'apple-team-id',
|
||||
@@ -102,14 +88,7 @@ describe(DeviceCreateAction, () => {
|
||||
const account: AccountFragment = {
|
||||
id: 'account_id',
|
||||
name: 'foobar',
|
||||
users: [
|
||||
{
|
||||
role: Role.Owner,
|
||||
actor: {
|
||||
id: 'user_id',
|
||||
},
|
||||
},
|
||||
],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
};
|
||||
const appleTeam = {
|
||||
id: 'apple-team-id',
|
||||
@@ -133,14 +112,7 @@ describe(DeviceCreateAction, () => {
|
||||
const account: AccountFragment = {
|
||||
id: 'account_id',
|
||||
name: 'foobar',
|
||||
users: [
|
||||
{
|
||||
role: Role.Owner,
|
||||
actor: {
|
||||
id: 'user_id',
|
||||
},
|
||||
},
|
||||
],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
};
|
||||
const appleTeam = {
|
||||
id: 'apple-team-id',
|
||||
|
||||
+324
-421
File diff suppressed because it is too large.
Load diff
@@ -52,7 +52,10 @@ export const ChannelInsightsQuery = {
|
||||
id
|
||||
group
|
||||
message
|
||||
runtimeVersion
|
||||
runtime {
|
||||
id
|
||||
version
|
||||
}
|
||||
platform
|
||||
insights {
|
||||
id
|
||||
|
||||
@@ -10,10 +10,7 @@ export const AccountFragmentNode = gql`
|
||||
id
|
||||
username
|
||||
}
|
||||
users {
|
||||
actor {
|
||||
id
|
||||
}
|
||||
viewerUserPermission {
|
||||
role
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,26 +30,31 @@ export const BuildFragmentNode = gql`
|
||||
displayName
|
||||
}
|
||||
logFiles
|
||||
project {
|
||||
app {
|
||||
__typename
|
||||
id
|
||||
name
|
||||
slug
|
||||
... on App {
|
||||
ownerAccount {
|
||||
id
|
||||
name
|
||||
}
|
||||
ownerAccount {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
channel
|
||||
updateChannel {
|
||||
id
|
||||
name
|
||||
}
|
||||
distribution
|
||||
iosEnterpriseProvisioning
|
||||
buildProfile
|
||||
appIdentifier
|
||||
sdkVersion
|
||||
appVersion
|
||||
appBuildVersion
|
||||
runtimeVersion
|
||||
runtime {
|
||||
id
|
||||
version
|
||||
}
|
||||
gitCommitHash
|
||||
gitCommitMessage
|
||||
initialQueuePosition
|
||||
|
||||
@@ -15,7 +15,6 @@ export const SubmissionFragmentNode = gql`
|
||||
}
|
||||
}
|
||||
androidConfig {
|
||||
applicationIdentifier
|
||||
track
|
||||
releaseStatus
|
||||
rollout
|
||||
|
||||
@@ -6,7 +6,10 @@ export const UpdateFragmentNode = gql`
|
||||
group
|
||||
message
|
||||
createdAt
|
||||
runtimeVersion
|
||||
runtime {
|
||||
id
|
||||
version
|
||||
}
|
||||
platform
|
||||
manifestFragment
|
||||
isRollBackToEmbedded
|
||||
|
||||
@@ -7,11 +7,17 @@ import {
|
||||
formatAscAppLinkStatus,
|
||||
isAscAuthenticationError,
|
||||
} from '../utils';
|
||||
import { Role } from '../../../graphql/generated';
|
||||
|
||||
const mockMetadataConnected = {
|
||||
id: 'app-id',
|
||||
fullName: '@testuser/testapp',
|
||||
ownerAccount: { id: 'account-id', name: 'testuser', ownerUserActor: null, users: [] },
|
||||
ownerAccount: {
|
||||
id: 'account-id',
|
||||
name: 'testuser',
|
||||
ownerUserActor: null,
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
appStoreConnectApp: {
|
||||
id: 'asc-app-link-id',
|
||||
ascAppIdentifier: '1234567890',
|
||||
@@ -27,7 +33,12 @@ const mockMetadataConnected = {
|
||||
const mockMetadataDisconnected = {
|
||||
id: 'app-id',
|
||||
fullName: '@testuser/testapp',
|
||||
ownerAccount: { id: 'account-id', name: 'testuser', ownerUserActor: null, users: [] },
|
||||
ownerAccount: {
|
||||
id: 'account-id',
|
||||
name: 'testuser',
|
||||
ownerUserActor: null,
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
appStoreConnectApp: null,
|
||||
};
|
||||
|
||||
|
||||
@@ -13,26 +13,26 @@ const userActor: Actor = {
|
||||
primaryAccount: {
|
||||
id: 'account-id-personal',
|
||||
name: 'jane',
|
||||
users: [{ role: Role.Owner, actor: { id: 'user-id' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
accounts: [
|
||||
{
|
||||
id: 'account-id-org',
|
||||
name: 'acme',
|
||||
ownerUserActor: null,
|
||||
users: [{ role: Role.ViewOnly, actor: { id: 'user-id' } }],
|
||||
viewerUserPermission: { role: Role.ViewOnly },
|
||||
},
|
||||
{
|
||||
id: 'account-id-personal',
|
||||
name: 'jane',
|
||||
ownerUserActor: { id: 'user-id' },
|
||||
users: [{ role: Role.Owner, actor: { id: 'user-id' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
{
|
||||
id: 'account-id-team',
|
||||
name: 'bob',
|
||||
ownerUserActor: { id: 'other-user-id' },
|
||||
users: [{ role: Role.Admin, actor: { id: 'user-id' } }],
|
||||
viewerUserPermission: { role: Role.Admin },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
@@ -46,12 +46,12 @@ const robotActor: Actor = {
|
||||
{
|
||||
id: 'account-id-1',
|
||||
name: 'acme',
|
||||
users: [{ role: Role.Admin, actor: { id: 'robot-id' } }],
|
||||
viewerUserPermission: { role: Role.Admin },
|
||||
},
|
||||
{
|
||||
id: 'account-id-2',
|
||||
name: 'other-org',
|
||||
users: [{ role: Role.ViewOnly, actor: { id: 'robot-id' } }],
|
||||
viewerUserPermission: { role: Role.ViewOnly },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
@@ -87,7 +87,7 @@ describe(getAccountChoices, () => {
|
||||
id: 'account-id-personal',
|
||||
name: 'jane',
|
||||
ownerUserActor: { id: 'user-id' },
|
||||
users: [{ role: Role.ViewOnly, actor: { id: 'user-id' } }],
|
||||
viewerUserPermission: { role: Role.ViewOnly },
|
||||
},
|
||||
],
|
||||
} as any as Actor;
|
||||
|
||||
@@ -6,9 +6,7 @@ export function getAccountNamesWhereUserHasSufficientPermissionsToCreateApp(
|
||||
actor: Actor
|
||||
): Set<string> {
|
||||
return new Set(
|
||||
actor.accounts
|
||||
.filter(a => a.users.find(it => it.actor.id === actor.id)?.role !== Role.ViewOnly)
|
||||
.map(it => it.name)
|
||||
actor.accounts.filter(a => a.viewerUserPermission.role !== Role.ViewOnly).map(it => it.name)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+1
-3
@@ -33,9 +33,7 @@ export async function fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsyn
|
||||
|
||||
const allAccounts = actor.accounts;
|
||||
const accountNamesWhereUserHasSufficientPublishPermissions = new Set(
|
||||
allAccounts
|
||||
.filter(a => a.users.find(it => it.actor.id === actor.id)?.role !== Role.ViewOnly)
|
||||
.map(it => it.name)
|
||||
allAccounts.filter(a => a.viewerUserPermission.role !== Role.ViewOnly).map(it => it.name)
|
||||
);
|
||||
|
||||
if (options.nonInteractive) {
|
||||
|
||||
@@ -348,11 +348,11 @@ function formatBuildChoice(build: BuildFragment): prompts.Choice {
|
||||
const {
|
||||
id,
|
||||
updatedAt,
|
||||
runtimeVersion,
|
||||
runtime,
|
||||
buildProfile,
|
||||
gitCommitHash,
|
||||
gitCommitMessage,
|
||||
channel,
|
||||
updateChannel,
|
||||
message,
|
||||
status,
|
||||
} = build;
|
||||
@@ -370,8 +370,8 @@ function formatBuildChoice(build: BuildFragment): prompts.Choice {
|
||||
|
||||
const descriptionItems: { name: string; value: string | null }[] = [
|
||||
{ name: 'Profile', value: buildProfile ? chalk.bold(buildProfile) : null },
|
||||
{ name: 'Channel', value: channel ? chalk.bold(channel) : null },
|
||||
{ name: 'Runtime version', value: runtimeVersion ? chalk.bold(runtimeVersion) : null },
|
||||
{ name: 'Channel', value: updateChannel ? chalk.bold(updateChannel.name) : null },
|
||||
{ name: 'Runtime version', value: runtime ? chalk.bold(runtime.version) : null },
|
||||
{ name: 'Commit', value: formattedCommitData },
|
||||
{
|
||||
name: 'Message',
|
||||
|
||||
@@ -99,7 +99,7 @@ function toEasBuildLinkage(
|
||||
return {
|
||||
easSubmissionId: easSubmission?.id ?? null,
|
||||
easBuildId: easSubmission?.submittedBuild?.id ?? null,
|
||||
runtimeVersion: easSubmission?.submittedBuild?.runtimeVersion ?? null,
|
||||
runtimeVersion: easSubmission?.submittedBuild?.runtime?.version ?? null,
|
||||
fingerprintHash: easSubmission?.submittedBuild?.fingerprint?.hash ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export function formatGraphQLSubmission(submission: SubmissionWithSubmittedBuild
|
||||
? [
|
||||
{
|
||||
label: 'Application Identifier',
|
||||
value: sanitize(submission.androidConfig?.applicationIdentifier),
|
||||
value: sanitize(submittedBuild?.appIdentifier),
|
||||
},
|
||||
{ label: 'Track', value: sanitize(submission.androidConfig?.track)?.toLowerCase() },
|
||||
{
|
||||
@@ -65,7 +65,7 @@ export function formatGraphQLSubmission(submission: SubmissionWithSubmittedBuild
|
||||
label: submission.platform === AppPlatform.Android ? 'Version code' : 'Build number',
|
||||
value: sanitize(submittedBuild?.appBuildVersion),
|
||||
},
|
||||
{ label: 'Runtime Version', value: sanitize(submittedBuild?.runtimeVersion) },
|
||||
{ label: 'Runtime Version', value: sanitize(submittedBuild?.runtime?.version) },
|
||||
{ label: 'Fingerprint', value: submittedBuild?.fingerprint?.hash },
|
||||
{ label: 'Commit', value: sanitize(submittedBuild?.gitCommitHash) },
|
||||
{ label: 'Error Code', value: sanitize(submission.error?.errorCode) },
|
||||
|
||||
+1
@@ -161,6 +161,7 @@ function mockUpdateChannel({
|
||||
pageInfo: { hasNextPage: false, hasPreviousPage: false },
|
||||
},
|
||||
embeddedUpdateCount: 0,
|
||||
isProtected: false,
|
||||
latestRuntimes: { edges: [], pageInfo: { hasNextPage: false, hasPreviousPage: false } },
|
||||
runtimeInsights: {} as UpdateChannelRuntimeInsights,
|
||||
name: channelName ?? 'default-channel-name',
|
||||
|
||||
@@ -202,7 +202,7 @@ export async function selectUpdateGroupOnBranchAsync(
|
||||
.map(group => {
|
||||
const first = group[0];
|
||||
return first
|
||||
? `${first.group} (runtime: ${first.runtimeVersion}, message: ${first.message ?? 'N/A'})`
|
||||
? `${first.group} (runtime: ${first.runtime.version}, message: ${first.message ?? 'N/A'})`
|
||||
: 'unknown';
|
||||
})
|
||||
.join('\n ');
|
||||
|
||||
@@ -71,7 +71,7 @@ export async function republishAsync({
|
||||
update.groupId === arbitraryUpdate.groupId &&
|
||||
update.branchId === arbitraryUpdate.branchId &&
|
||||
update.branchName === arbitraryUpdate.branchName &&
|
||||
update.runtimeVersion === arbitraryUpdate.runtimeVersion &&
|
||||
update.runtime.version === arbitraryUpdate.runtime.version &&
|
||||
update.manifestHostOverride === arbitraryUpdate.manifestHostOverride &&
|
||||
update.assetHostOverride === arbitraryUpdate.assetHostOverride;
|
||||
assert(
|
||||
@@ -90,7 +90,7 @@ export async function republishAsync({
|
||||
'Cannot republish an update that is being rolled-out. Either complete the update rollout and then republish or publish a new rollout update.'
|
||||
);
|
||||
|
||||
const { runtimeVersion } = arbitraryUpdate;
|
||||
const runtimeVersion = arbitraryUpdate.runtime.version;
|
||||
|
||||
// If codesigning was created for the original update, we need to add it to the republish.
|
||||
// If one wishes to not sign the republish or sign with a different key, a normal publish should
|
||||
@@ -246,7 +246,7 @@ export async function republishAsync({
|
||||
Log.log(
|
||||
formatFields([
|
||||
{ label: 'Branch', value: targetBranchName },
|
||||
{ label: 'Runtime version', value: arbitraryRepublishedUpdate.runtimeVersion },
|
||||
{ label: 'Runtime version', value: arbitraryRepublishedUpdate.runtime.version },
|
||||
{ label: 'Platform', value: updatesRepublished.map(update => update.platform).join(', ') },
|
||||
{ label: 'Update group ID', value: arbitraryRepublishedUpdate.group },
|
||||
...(updatesRepublishedByPlatform.android
|
||||
|
||||
@@ -84,7 +84,7 @@ export async function publishRollBackToEmbeddedUpdateAsync({
|
||||
version => version.runtimeVersion
|
||||
)) {
|
||||
const newUpdatesForRuntimeVersion = newUpdates.filter(
|
||||
update => update.runtimeVersion === runtime.runtimeVersion
|
||||
update => update.runtime.version === runtime.runtimeVersion
|
||||
);
|
||||
if (newUpdatesForRuntimeVersion.length === 0) {
|
||||
throw new Error(
|
||||
|
||||
@@ -34,16 +34,9 @@ export type FormatUpdateParameter = Pick<Update, 'id' | 'createdAt' | 'message'>
|
||||
| null;
|
||||
};
|
||||
|
||||
export type UpdateJsonInfo = { branch: string } & Pick<
|
||||
export type UpdateJsonInfo = { branch: string; runtimeVersion: string } & Pick<
|
||||
UpdateFragment,
|
||||
| 'id'
|
||||
| 'createdAt'
|
||||
| 'group'
|
||||
| 'message'
|
||||
| 'runtimeVersion'
|
||||
| 'platform'
|
||||
| 'manifestPermalink'
|
||||
| 'gitCommitHash'
|
||||
'id' | 'createdAt' | 'group' | 'message' | 'platform' | 'manifestPermalink' | 'gitCommitHash'
|
||||
>;
|
||||
|
||||
export type UpdateGroupDescription = FormatUpdateParameter & {
|
||||
@@ -191,7 +184,7 @@ export function ensureValidVersions(exp: ExpoConfig, platform: RequestedPlatform
|
||||
}
|
||||
|
||||
export function formatUpdateTitle(update: UpdateFragment): string {
|
||||
const { message, createdAt, actor, runtimeVersion } = update;
|
||||
const { message, createdAt, actor, runtime } = update;
|
||||
|
||||
let actorName: string;
|
||||
switch (actor?.__typename) {
|
||||
@@ -213,7 +206,7 @@ export function formatUpdateTitle(update: UpdateFragment): string {
|
||||
return `[${dateFormat(
|
||||
createdAt,
|
||||
'mmm dd HH:MM'
|
||||
)} by ${actorName}, runtimeVersion: ${runtimeVersion}] ${message}`;
|
||||
)} by ${actorName}, runtimeVersion: ${runtime.version}] ${message}`;
|
||||
}
|
||||
|
||||
export function getUpdateJsonInfosForUpdates(updates: UpdateFragment[]): UpdateJsonInfo[] {
|
||||
@@ -223,7 +216,7 @@ export function getUpdateJsonInfosForUpdates(updates: UpdateFragment[]): UpdateJ
|
||||
group: update.group,
|
||||
branch: update.branch.name,
|
||||
message: update.message,
|
||||
runtimeVersion: update.runtimeVersion,
|
||||
runtimeVersion: update.runtime.version,
|
||||
platform: update.platform,
|
||||
manifestPermalink: update.manifestPermalink,
|
||||
isRollBackToEmbedded: update.isRollBackToEmbedded,
|
||||
@@ -236,7 +229,7 @@ export function getUpdateGroupDescriptions(
|
||||
): FormattedUpdateGroupDescription[] {
|
||||
return updateGroups.map(updateGroup => ({
|
||||
message: formatUpdateMessage(updateGroup[0]),
|
||||
runtimeVersion: updateGroup[0].runtimeVersion,
|
||||
runtimeVersion: updateGroup[0].runtime.version,
|
||||
isRollBackToEmbedded: updateGroup[0].isRollBackToEmbedded,
|
||||
rolloutPercentage: updateGroup[0].rolloutPercentage ?? undefined,
|
||||
codeSigningKey: updateGroup[0].codeSigningInfo?.keyid,
|
||||
@@ -251,7 +244,7 @@ export function getUpdateGroupDescriptionsWithBranch(
|
||||
return updateGroups.map(updateGroup => ({
|
||||
branch: updateGroup[0].branch.name,
|
||||
message: formatUpdateMessage(updateGroup[0]),
|
||||
runtimeVersion: updateGroup[0].runtimeVersion,
|
||||
runtimeVersion: updateGroup[0].runtime.version,
|
||||
isRollBackToEmbedded: updateGroup[0].isRollBackToEmbedded,
|
||||
rolloutPercentage: updateGroup[0].rolloutPercentage ?? undefined,
|
||||
codeSigningKey: updateGroup[0].codeSigningInfo?.keyid,
|
||||
@@ -270,7 +263,7 @@ export function getBranchDescription(branch: UpdateBranchFragment): FormattedBra
|
||||
branch: branch.name,
|
||||
update: {
|
||||
message: formatUpdateMessage(latestUpdate),
|
||||
runtimeVersion: latestUpdate.runtimeVersion,
|
||||
runtimeVersion: latestUpdate.runtime.version,
|
||||
isRollBackToEmbedded: latestUpdate.isRollBackToEmbedded,
|
||||
rolloutPercentage: latestUpdate.rolloutPercentage ?? undefined,
|
||||
codeSigningKey: latestUpdate.codeSigningInfo?.keyid,
|
||||
@@ -322,7 +315,7 @@ export async function prewarmDiffingAsync(
|
||||
appId,
|
||||
branchName: update.branch.name,
|
||||
platform: updatePublishPlatformToAppPlatform[updatePublishPlatform],
|
||||
runtimeVersion: update.runtimeVersion,
|
||||
runtimeVersion: update.runtime.version,
|
||||
limit: 2,
|
||||
});
|
||||
if (updateIds.length !== 2) {
|
||||
|
||||
@@ -9,7 +9,7 @@ export type Actor = NonNullable<CurrentUserQuery['meActor']>;
|
||||
*/
|
||||
export function getCreatableAccountNames(actor: Actor): string[] {
|
||||
const creatableAccounts = actor.accounts.filter(
|
||||
a => a.users.find(it => it.actor.id === actor.id)?.role !== Role.ViewOnly
|
||||
a => a.viewerUserPermission.role !== Role.ViewOnly
|
||||
);
|
||||
if (actor.__typename === 'Robot') {
|
||||
return creatableAccounts.map(it => it.name);
|
||||
|
||||
@@ -9,13 +9,13 @@ const userStub: Actor = {
|
||||
primaryAccount: {
|
||||
id: 'account_id_777',
|
||||
name: 'username',
|
||||
users: [{ role: Role.Owner, actor: { id: 'userId' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
accounts: [
|
||||
{
|
||||
id: 'account_id_777',
|
||||
name: 'username',
|
||||
users: [{ role: Role.Owner, actor: { id: 'userId' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
@@ -29,13 +29,13 @@ const ssoUserStub: Actor = {
|
||||
primaryAccount: {
|
||||
id: 'account_id_888',
|
||||
name: 'ssoUsername',
|
||||
users: [{ role: Role.Owner, actor: { id: 'ssoUserId' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
accounts: [
|
||||
{
|
||||
id: 'account_id_888',
|
||||
name: 'ssoUsername',
|
||||
users: [{ role: Role.Owner, actor: { id: 'ssoUserId' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
@@ -81,24 +81,24 @@ describe('getCreatableAccountNames', () => {
|
||||
{
|
||||
id: 'account_id_1',
|
||||
name: 'some-org',
|
||||
users: [{ role: Role.Owner, actor: { id: 'userId' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
{
|
||||
id: 'account_id_2',
|
||||
name: 'other-user-team',
|
||||
ownerUserActor: { id: 'otherUserId', username: 'other-user' },
|
||||
users: [{ role: Role.Admin, actor: { id: 'userId' } }],
|
||||
viewerUserPermission: { role: Role.Admin },
|
||||
},
|
||||
{
|
||||
id: 'account_id_3',
|
||||
name: 'view-only-org',
|
||||
users: [{ role: Role.ViewOnly, actor: { id: 'userId' } }],
|
||||
viewerUserPermission: { role: Role.ViewOnly },
|
||||
},
|
||||
{
|
||||
id: 'account_id_4',
|
||||
name: 'username',
|
||||
ownerUserActor: { id: 'userId', username: 'username' },
|
||||
users: [{ role: Role.Owner, actor: { id: 'userId' } }],
|
||||
viewerUserPermission: { role: Role.Owner },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/eas-json",
|
||||
"version": "21.6.0",
|
||||
"version": "22.0.0",
|
||||
"description": "A library for interacting with eas.json",
|
||||
"homepage": "https://github.com/expo/eas-cli",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
@@ -32,7 +32,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "7.23.5",
|
||||
"@expo/eas-build-job": "21.6.0",
|
||||
"@expo/eas-build-job": "22.0.0",
|
||||
"chalk": "4.1.2",
|
||||
"env-string": "1.0.1",
|
||||
"fs-extra": "11.2.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eas-cli-local-build-plugin",
|
||||
"version": "21.8.0",
|
||||
"version": "22.0.0",
|
||||
"description": "Tool for running EAS compatible builds on a local machine.",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
@@ -26,11 +26,11 @@
|
||||
"clean": "rimraf node_modules dist coverage \"*.tsbuildinfo\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/build-tools": "21.8.0",
|
||||
"@expo/eas-build-job": "21.6.0",
|
||||
"@expo/logger": "21.0.0",
|
||||
"@expo/build-tools": "22.0.0",
|
||||
"@expo/eas-build-job": "22.0.0",
|
||||
"@expo/logger": "22.0.0",
|
||||
"@expo/spawn-async": "^1.7.2",
|
||||
"@expo/turtle-spawn": "21.0.0",
|
||||
"@expo/turtle-spawn": "22.0.0",
|
||||
"bunyan": "^1.8.15",
|
||||
"chalk": "4.1.2",
|
||||
"env-paths": "^2.2.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/logger",
|
||||
"version": "21.0.0",
|
||||
"version": "22.0.0",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
"author": "Expo <[email protected]>",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/steps",
|
||||
"version": "21.7.1",
|
||||
"version": "22.0.0",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
"author": "Expo <[email protected]>",
|
||||
@@ -27,8 +27,8 @@
|
||||
"clean": "rimraf node_modules dist coverage \"*.tsbuildinfo\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/eas-build-job": "21.6.0",
|
||||
"@expo/logger": "21.0.0",
|
||||
"@expo/eas-build-job": "22.0.0",
|
||||
"@expo/logger": "22.0.0",
|
||||
"@expo/spawn-async": "^1.7.2",
|
||||
"arg": "^5.0.2",
|
||||
"fast-glob": "^3.3.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/template-file",
|
||||
"version": "21.0.2",
|
||||
"version": "22.0.0",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
"author": "Expo <[email protected]>",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/turtle-spawn",
|
||||
"version": "21.0.0",
|
||||
"version": "22.0.0",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
"author": "Expo <[email protected]>",
|
||||
@@ -25,7 +25,7 @@
|
||||
"clean": "rimraf node_modules dist coverage \"*.tsbuildinfo\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/logger": "21.0.0",
|
||||
"@expo/logger": "22.0.0",
|
||||
"@expo/spawn-async": "^1.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/worker",
|
||||
"version": "21.8.0",
|
||||
"version": "22.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "yarn watch",
|
||||
@@ -19,18 +19,18 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "7.24.7",
|
||||
"@expo/build-tools": "21.8.0",
|
||||
"@expo/build-tools": "22.0.0",
|
||||
"@expo/config-plugins": "55.0.7",
|
||||
"@expo/config-types": "55.0.5",
|
||||
"@expo/downloader": "21.0.0",
|
||||
"@expo/eas-build-job": "21.6.0",
|
||||
"@expo/logger": "21.0.0",
|
||||
"@expo/downloader": "22.0.0",
|
||||
"@expo/eas-build-job": "22.0.0",
|
||||
"@expo/logger": "22.0.0",
|
||||
"@expo/results": "1.0.0",
|
||||
"@expo/rudder-sdk-node": "1.1.1",
|
||||
"@expo/spawn-async": "1.7.2",
|
||||
"@expo/steps": "21.7.1",
|
||||
"@expo/template-file": "21.0.2",
|
||||
"@expo/turtle-spawn": "21.0.0",
|
||||
"@expo/steps": "22.0.0",
|
||||
"@expo/template-file": "22.0.0",
|
||||
"@expo/turtle-spawn": "22.0.0",
|
||||
"@hapi/boom": "10.0.1",
|
||||
"check-disk-space": "3.4.0",
|
||||
"fast-glob": "3.3.2",
|
||||
|
||||
@@ -103,8 +103,8 @@ fi
|
||||
|
||||
if [[ "$PLATFORM" == "ios" ]]; then
|
||||
record_sim_package_dir="$ROOT_DIR/packages/build-tools/resources/record-sim"
|
||||
build_tools_bin_dir="$target_root_dir/packages/build-tools/bin"
|
||||
mkdir -p "$build_tools_bin_dir"
|
||||
record_sim_bin_dir="$target_root_dir/packages/build-tools/bin"
|
||||
mkdir -p "$record_sim_bin_dir"
|
||||
record_sim_bin_path=$(swift build \
|
||||
-c release \
|
||||
--package-path "$record_sim_package_dir" \
|
||||
@@ -114,18 +114,8 @@ if [[ "$PLATFORM" == "ios" ]]; then
|
||||
-c release \
|
||||
--package-path "$record_sim_package_dir" \
|
||||
--build-path "$record_sim_build_dir"
|
||||
cp "$record_sim_bin_path/record-sim" "$build_tools_bin_dir/record-sim"
|
||||
chmod +x "$build_tools_bin_dir/record-sim"
|
||||
|
||||
xcrun clang \
|
||||
-arch arm64 \
|
||||
-dynamiclib \
|
||||
-O2 \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Werror \
|
||||
-o "$build_tools_bin_dir/libeas_xcode_local_cas_plugin.dylib" \
|
||||
"$ROOT_DIR/packages/build-tools/resources/xcode-local-cache-plugin/eas_local_cas_plugin.c"
|
||||
cp "$record_sim_bin_path/record-sim" "$record_sim_bin_dir/record-sim"
|
||||
chmod +x "$record_sim_bin_dir/record-sim"
|
||||
|
||||
# build plugin
|
||||
pushd "$ROOT_DIR/packages/expo-cocoapods-proxy" >/dev/null 2>&1
|
||||
|
||||
@@ -2291,24 +2291,24 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@expo/build-tools@npm:21.8.0, @expo/build-tools@workspace:packages/build-tools":
|
||||
"@expo/build-tools@npm:22.0.0, @expo/build-tools@workspace:packages/build-tools":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/build-tools@workspace:packages/build-tools"
|
||||
dependencies:
|
||||
"@expo/config": "npm:55.0.10"
|
||||
"@expo/config-plugins": "npm:55.0.7"
|
||||
"@expo/downloader": "npm:21.0.0"
|
||||
"@expo/eas-build-job": "npm:21.6.0"
|
||||
"@expo/downloader": "npm:22.0.0"
|
||||
"@expo/eas-build-job": "npm:22.0.0"
|
||||
"@expo/env": "npm:^0.4.0"
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
"@expo/logger": "npm:22.0.0"
|
||||
"@expo/package-manager": "npm:1.9.10"
|
||||
"@expo/plist": "npm:^0.3.5"
|
||||
"@expo/repack-app": "npm:~0.6.1"
|
||||
"@expo/results": "npm:^1.0.0"
|
||||
"@expo/spawn-async": "npm:1.7.2"
|
||||
"@expo/steps": "npm:21.7.1"
|
||||
"@expo/template-file": "npm:21.0.2"
|
||||
"@expo/turtle-spawn": "npm:21.0.0"
|
||||
"@expo/steps": "npm:22.0.0"
|
||||
"@expo/template-file": "npm:22.0.0"
|
||||
"@expo/turtle-spawn": "npm:22.0.0"
|
||||
"@expo/xcpretty": "npm:^4.3.1"
|
||||
"@ngrok/ngrok": "npm:1.7.0"
|
||||
"@sentry/node": "npm:7.77.0"
|
||||
@@ -2531,7 +2531,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@expo/downloader@npm:21.0.0, @expo/downloader@workspace:packages/downloader":
|
||||
"@expo/downloader@npm:22.0.0, @expo/downloader@workspace:packages/downloader":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/downloader@workspace:packages/downloader"
|
||||
dependencies:
|
||||
@@ -2547,13 +2547,13 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@expo/eas-build-job@npm:21.6.0, @expo/eas-build-job@workspace:packages/eas-build-job":
|
||||
"@expo/eas-build-job@npm:22.0.0, @expo/eas-build-job@workspace:packages/eas-build-job":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/eas-build-job@workspace:packages/eas-build-job"
|
||||
dependencies:
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
"@expo/logger": "npm:22.0.0"
|
||||
"@expo/results": "npm:1.0.0"
|
||||
"@expo/turtle-spawn": "npm:21.0.0"
|
||||
"@expo/turtle-spawn": "npm:22.0.0"
|
||||
"@types/jest": "npm:^29.5.12"
|
||||
"@types/node": "npm:20.14.2"
|
||||
jest: "npm:^29.7.0"
|
||||
@@ -2566,12 +2566,12 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@expo/eas-json@npm:21.6.0, @expo/eas-json@workspace:packages/eas-json":
|
||||
"@expo/eas-json@npm:22.0.0, @expo/eas-json@workspace:packages/eas-json":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/eas-json@workspace:packages/eas-json"
|
||||
dependencies:
|
||||
"@babel/code-frame": "npm:7.23.5"
|
||||
"@expo/eas-build-job": "npm:21.6.0"
|
||||
"@expo/eas-build-job": "npm:22.0.0"
|
||||
"@tsconfig/node20": "npm:20.1.8"
|
||||
"@types/babel__code-frame": "npm:7.0.3"
|
||||
"@types/fs-extra": "npm:11.0.4"
|
||||
@@ -2685,7 +2685,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@expo/logger@npm:21.0.0, @expo/logger@workspace:packages/logger":
|
||||
"@expo/logger@npm:22.0.0, @expo/logger@workspace:packages/logger":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/logger@workspace:packages/logger"
|
||||
dependencies:
|
||||
@@ -2884,12 +2884,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@expo/steps@npm:21.7.1, @expo/steps@workspace:packages/steps":
|
||||
"@expo/steps@npm:22.0.0, @expo/steps@workspace:packages/steps":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/steps@workspace:packages/steps"
|
||||
dependencies:
|
||||
"@expo/eas-build-job": "npm:21.6.0"
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
"@expo/eas-build-job": "npm:22.0.0"
|
||||
"@expo/logger": "npm:22.0.0"
|
||||
"@expo/spawn-async": "npm:^1.7.2"
|
||||
"@jest/globals": "npm:^29.7.0"
|
||||
"@types/jest": "npm:^29.5.12"
|
||||
@@ -2916,7 +2916,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@expo/template-file@npm:21.0.2, @expo/template-file@workspace:packages/template-file":
|
||||
"@expo/template-file@npm:22.0.0, @expo/template-file@workspace:packages/template-file":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/template-file@workspace:packages/template-file"
|
||||
dependencies:
|
||||
@@ -2939,11 +2939,11 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@expo/turtle-spawn@npm:21.0.0, @expo/turtle-spawn@workspace:packages/turtle-spawn":
|
||||
"@expo/turtle-spawn@npm:22.0.0, @expo/turtle-spawn@workspace:packages/turtle-spawn":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/turtle-spawn@workspace:packages/turtle-spawn"
|
||||
dependencies:
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
"@expo/logger": "npm:22.0.0"
|
||||
"@expo/spawn-async": "npm:^1.7.2"
|
||||
"@types/jest": "npm:^29.5.12"
|
||||
"@types/node": "npm:20.14.2"
|
||||
@@ -2959,18 +2959,18 @@ __metadata:
|
||||
resolution: "@expo/worker@workspace:packages/worker"
|
||||
dependencies:
|
||||
"@babel/core": "npm:7.24.7"
|
||||
"@expo/build-tools": "npm:21.8.0"
|
||||
"@expo/build-tools": "npm:22.0.0"
|
||||
"@expo/config-plugins": "npm:55.0.7"
|
||||
"@expo/config-types": "npm:55.0.5"
|
||||
"@expo/downloader": "npm:21.0.0"
|
||||
"@expo/eas-build-job": "npm:21.6.0"
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
"@expo/downloader": "npm:22.0.0"
|
||||
"@expo/eas-build-job": "npm:22.0.0"
|
||||
"@expo/logger": "npm:22.0.0"
|
||||
"@expo/results": "npm:1.0.0"
|
||||
"@expo/rudder-sdk-node": "npm:1.1.1"
|
||||
"@expo/spawn-async": "npm:1.7.2"
|
||||
"@expo/steps": "npm:21.7.1"
|
||||
"@expo/template-file": "npm:21.0.2"
|
||||
"@expo/turtle-spawn": "npm:21.0.0"
|
||||
"@expo/steps": "npm:22.0.0"
|
||||
"@expo/template-file": "npm:22.0.0"
|
||||
"@expo/turtle-spawn": "npm:22.0.0"
|
||||
"@hapi/boom": "npm:10.0.1"
|
||||
"@types/babel__core": "npm:7.20.5"
|
||||
"@types/fs-extra": "npm:11.0.4"
|
||||
@@ -9724,7 +9724,7 @@ __metadata:
|
||||
resolution: "create-eas-build-function@workspace:packages/create-eas-build-function"
|
||||
dependencies:
|
||||
"@expo/package-manager": "npm:1.9.10"
|
||||
"@expo/steps": "npm:21.7.1"
|
||||
"@expo/steps": "npm:22.0.0"
|
||||
"@jest/globals": "npm:^29.7.0"
|
||||
"@types/jest": "npm:^29.5.12"
|
||||
"@types/node": "npm:20.14.2"
|
||||
@@ -10297,11 +10297,11 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "eas-cli-local-build-plugin@workspace:packages/local-build-plugin"
|
||||
dependencies:
|
||||
"@expo/build-tools": "npm:21.8.0"
|
||||
"@expo/eas-build-job": "npm:21.6.0"
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
"@expo/build-tools": "npm:22.0.0"
|
||||
"@expo/eas-build-job": "npm:22.0.0"
|
||||
"@expo/logger": "npm:22.0.0"
|
||||
"@expo/spawn-async": "npm:^1.7.2"
|
||||
"@expo/turtle-spawn": "npm:21.0.0"
|
||||
"@expo/turtle-spawn": "npm:22.0.0"
|
||||
"@types/bunyan": "npm:^1.8.11"
|
||||
"@types/fs-extra": "npm:^11.0.4"
|
||||
"@types/hapi__joi": "npm:^17.1.14"
|
||||
@@ -10355,11 +10355,11 @@ __metadata:
|
||||
"@expo/code-signing-certificates": "npm:0.0.5"
|
||||
"@expo/config": "npm:55.0.10"
|
||||
"@expo/config-plugins": "npm:55.0.7"
|
||||
"@expo/eas-build-job": "npm:21.6.0"
|
||||
"@expo/eas-json": "npm:21.6.0"
|
||||
"@expo/eas-build-job": "npm:22.0.0"
|
||||
"@expo/eas-json": "npm:22.0.0"
|
||||
"@expo/env": "npm:^1.0.0"
|
||||
"@expo/json-file": "npm:8.3.3"
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
"@expo/logger": "npm:22.0.0"
|
||||
"@expo/multipart-body-parser": "npm:2.0.0"
|
||||
"@expo/osascript": "npm:2.1.4"
|
||||
"@expo/package-manager": "npm:1.9.10"
|
||||
@@ -10371,7 +10371,7 @@ __metadata:
|
||||
"@expo/results": "npm:1.0.0"
|
||||
"@expo/rudder-sdk-node": "npm:1.1.1"
|
||||
"@expo/spawn-async": "npm:1.7.2"
|
||||
"@expo/steps": "npm:21.7.1"
|
||||
"@expo/steps": "npm:22.0.0"
|
||||
"@expo/timeago.js": "npm:1.0.0"
|
||||
"@graphql-codegen/cli": "npm:6.3.1"
|
||||
"@graphql-codegen/introspection": "npm:5.0.2"
|
||||
|
||||
Reference in new issue
Block a user