eas-cli 14.7.0 → 15.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,6 +41,7 @@ exports.UpdateFragmentNode = (0, graphql_tag_1.default) `
41
41
  fingerprint {
42
42
  id
43
43
  hash
44
+ debugInfoUrl
44
45
  source {
45
46
  type
46
47
  bucketKey
@@ -10,7 +10,8 @@ const prompts_1 = require("../../prompts");
10
10
  async function ensureNonExemptEncryptionIsDefinedForManagedProjectAsync({ projectDir, exp, nonInteractive, }) {
11
11
  // TODO: We could add bare workflow support in the future.
12
12
  // TODO: We could add wizard support for non-exempt encryption in the future.
13
- if (exp.ios?.infoPlist?.ITSAppUsesNonExemptEncryption == null) {
13
+ const ITSAppUsesNonExemptEncryption = exp.ios?.infoPlist?.ITSAppUsesNonExemptEncryption ?? exp.ios?.config?.usesNonExemptEncryption;
14
+ if (ITSAppUsesNonExemptEncryption == null) {
14
15
  await configureNonExemptEncryptionAsync({
15
16
  projectDir,
16
17
  exp,
@@ -1,17 +1,21 @@
1
1
  import { Client } from '../vcs';
2
2
  export default class GitClient extends Client {
3
3
  private readonly maybeCwdOverride?;
4
- constructor(maybeCwdOverride?: string | undefined);
4
+ requireCommit: boolean;
5
+ constructor(options: {
6
+ maybeCwdOverride?: string;
7
+ requireCommit: boolean;
8
+ });
5
9
  ensureRepoExistsAsync(): Promise<void>;
6
10
  commitAsync({ commitMessage, commitAllFiles, nonInteractive, }: {
7
11
  commitMessage: string;
8
12
  commitAllFiles?: boolean;
9
13
  nonInteractive: boolean;
10
14
  }): Promise<void>;
11
- isCommitRequiredAsync(): Promise<boolean>;
12
15
  showChangedFilesAsync(): Promise<void>;
13
16
  hasUncommittedChangesAsync(): Promise<boolean>;
14
17
  getRootPathAsync(): Promise<string>;
18
+ isCommitRequiredAsync(): Promise<boolean>;
15
19
  makeShallowCopyAsync(destinationPath: string): Promise<void>;
16
20
  getCommitHashAsync(): Promise<string | undefined>;
17
21
  trackFileAsync(file: string): Promise<void>;
@@ -6,17 +6,21 @@ const PackageManagerUtils = tslib_1.__importStar(require("@expo/package-manager"
6
6
  const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
7
7
  const core_1 = require("@oclif/core");
8
8
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
9
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
9
10
  const path_1 = tslib_1.__importDefault(require("path"));
10
11
  const log_1 = tslib_1.__importStar(require("../../log"));
11
12
  const ora_1 = require("../../ora");
12
13
  const prompts_1 = require("../../prompts");
13
14
  const git_1 = require("../git");
15
+ const local_1 = require("../local");
14
16
  const vcs_1 = require("../vcs");
15
17
  class GitClient extends vcs_1.Client {
16
18
  maybeCwdOverride;
17
- constructor(maybeCwdOverride) {
19
+ requireCommit;
20
+ constructor(options) {
18
21
  super();
19
- this.maybeCwdOverride = maybeCwdOverride;
22
+ this.maybeCwdOverride = options.maybeCwdOverride;
23
+ this.requireCommit = options.requireCommit;
20
24
  }
21
25
  async ensureRepoExistsAsync() {
22
26
  try {
@@ -84,9 +88,6 @@ class GitClient extends vcs_1.Client {
84
88
  throw err;
85
89
  }
86
90
  }
87
- async isCommitRequiredAsync() {
88
- return await this.hasUncommittedChangesAsync();
89
- }
90
91
  async showChangedFilesAsync() {
91
92
  const gitStatusOutput = await (0, git_1.gitStatusAsync)({
92
93
  showUntracked: true,
@@ -103,44 +104,61 @@ class GitClient extends vcs_1.Client {
103
104
  cwd: this.maybeCwdOverride,
104
105
  })).stdout.trim();
105
106
  }
107
+ async isCommitRequiredAsync() {
108
+ if (!this.requireCommit) {
109
+ return false;
110
+ }
111
+ return await this.hasUncommittedChangesAsync();
112
+ }
106
113
  async makeShallowCopyAsync(destinationPath) {
107
- if (await this.hasUncommittedChangesAsync()) {
114
+ if (await this.isCommitRequiredAsync()) {
108
115
  // it should already be checked before this function is called, but in case it wasn't
109
116
  // we want to ensure that any changes were introduced by call to `setGitCaseSensitivityAsync`
110
117
  throw new Error('You have some uncommitted changes in your repository.');
111
118
  }
119
+ const rootPath = await this.getRootPathAsync();
112
120
  let gitRepoUri;
113
121
  if (process.platform === 'win32') {
114
122
  // getRootDirectoryAsync() will return C:/path/to/repo on Windows and path
115
123
  // prefix should be file:///
116
- gitRepoUri = `file:///${await this.getRootPathAsync()}`;
124
+ gitRepoUri = `file:///${rootPath}`;
117
125
  }
118
126
  else {
119
127
  // getRootDirectoryAsync() will /path/to/repo, and path prefix should be
120
128
  // file:/// so only file:// needs to be prepended
121
- gitRepoUri = `file://${await this.getRootPathAsync()}`;
129
+ gitRepoUri = `file://${rootPath}`;
122
130
  }
123
- const isCaseSensitive = await isGitCaseSensitiveAsync(this.maybeCwdOverride);
124
- await setGitCaseSensitivityAsync(true, this.maybeCwdOverride);
131
+ await assertEnablingGitCaseSensitivityDoesNotCauseNewUncommittedChangesAsync(rootPath);
132
+ const isCaseSensitive = await isGitCaseSensitiveAsync(rootPath);
125
133
  try {
126
- if (await this.hasUncommittedChangesAsync()) {
127
- log_1.default.error('Detected inconsistent filename casing between your local filesystem and git.');
128
- log_1.default.error('This will likely cause your build to fail. Impacted files:');
129
- await (0, spawn_async_1.default)('git', ['status', '--short'], {
130
- stdio: 'inherit',
131
- cwd: this.maybeCwdOverride,
132
- });
133
- log_1.default.newLine();
134
- log_1.default.error(`Error: Resolve filename casing inconsistencies before proceeding. ${(0, log_1.learnMore)('https://expo.fyi/macos-ignorecase')}`);
135
- throw new Error('You have some uncommitted changes in your repository.');
134
+ await setGitCaseSensitivityAsync(true, rootPath);
135
+ await (0, spawn_async_1.default)('git', ['clone', '--no-hardlinks', '--depth', '1', gitRepoUri, destinationPath], { cwd: rootPath });
136
+ const sourceEasignorePath = path_1.default.join(rootPath, local_1.EASIGNORE_FILENAME);
137
+ if (await fs_extra_1.default.exists(sourceEasignorePath)) {
138
+ const cachedFilesWeShouldHaveIgnored = (await (0, spawn_async_1.default)('git', [
139
+ 'ls-files',
140
+ '--exclude-from',
141
+ sourceEasignorePath,
142
+ // `--ignored --cached` makes git print files that should be
143
+ // ignored by rules from `--exclude-from`, but instead are currently cached.
144
+ '--ignored',
145
+ '--cached',
146
+ // separates file names with null characters
147
+ '-z',
148
+ ], { cwd: destinationPath })).stdout
149
+ .split('\0')
150
+ // ls-files' output is terminated by a null character
151
+ .filter(file => file !== '');
152
+ await Promise.all(cachedFilesWeShouldHaveIgnored.map(file => fs_extra_1.default.rm(path_1.default.join(destinationPath, file))));
136
153
  }
137
- await (0, spawn_async_1.default)('git', ['clone', '--no-hardlinks', '--depth', '1', gitRepoUri, destinationPath], {
138
- cwd: this.maybeCwdOverride,
139
- });
140
154
  }
141
155
  finally {
142
- await setGitCaseSensitivityAsync(isCaseSensitive, this.maybeCwdOverride);
156
+ await setGitCaseSensitivityAsync(isCaseSensitive, rootPath);
143
157
  }
158
+ // After we create the shallow Git copy, we copy the files
159
+ // again. This way we include the changed and untracked files
160
+ // (`git clone` only copies the committed changes).
161
+ await (0, local_1.makeShallowCopyAsync)(rootPath, destinationPath);
144
162
  }
145
163
  async getCommitHashAsync() {
146
164
  try {
@@ -192,10 +210,16 @@ class GitClient extends vcs_1.Client {
192
210
  !trackedFiles.includes(pathWithoutLeadingDot));
193
211
  }
194
212
  async isFileIgnoredAsync(filePath) {
213
+ const rootPath = await this.getRootPathAsync();
214
+ const easIgnorePath = path_1.default.join(rootPath, local_1.EASIGNORE_FILENAME);
215
+ if (await fs_extra_1.default.exists(easIgnorePath)) {
216
+ const ignore = new local_1.Ignore(rootPath);
217
+ const wouldNotBeCopiedToClone = ignore.ignores(filePath);
218
+ const wouldBeDeletedFromClone = (await (0, spawn_async_1.default)('git', ['ls-files', '--exclude-from', easIgnorePath, '--ignored', '--cached', filePath], { cwd: rootPath })).stdout.trim() !== '';
219
+ return wouldNotBeCopiedToClone && wouldBeDeletedFromClone;
220
+ }
195
221
  try {
196
- await (0, spawn_async_1.default)('git', ['check-ignore', '-q', filePath], {
197
- cwd: this.maybeCwdOverride ?? path_1.default.normalize(await this.getRootPathAsync()),
198
- });
222
+ await (0, spawn_async_1.default)('git', ['check-ignore', '-q', filePath], { cwd: rootPath });
199
223
  return true;
200
224
  }
201
225
  catch {
@@ -318,3 +342,39 @@ async function setGitCaseSensitivityAsync(enable, cwd) {
318
342
  });
319
343
  }
320
344
  }
345
+ async function assertEnablingGitCaseSensitivityDoesNotCauseNewUncommittedChangesAsync(cwd) {
346
+ // Remember uncommited changes before case sensitivity change
347
+ // for later comparison so we log to the user only the files
348
+ // that were marked as changed after the case sensitivity change.
349
+ const uncommittedChangesBeforeCaseSensitivityChange = await (0, git_1.gitStatusAsync)({
350
+ showUntracked: true,
351
+ cwd,
352
+ });
353
+ const isCaseSensitive = await isGitCaseSensitiveAsync(cwd);
354
+ await setGitCaseSensitivityAsync(true, cwd);
355
+ try {
356
+ const uncommitedChangesAfterCaseSensitivityChange = await (0, git_1.gitStatusAsync)({
357
+ showUntracked: true,
358
+ cwd,
359
+ });
360
+ if (uncommitedChangesAfterCaseSensitivityChange !== uncommittedChangesBeforeCaseSensitivityChange) {
361
+ const baseUncommitedChangesSet = new Set(uncommittedChangesBeforeCaseSensitivityChange.split('\n'));
362
+ const errorMessage = [
363
+ 'Detected inconsistent filename casing between your local filesystem and git.',
364
+ 'This will likely cause your job to fail. Impacted files:',
365
+ ...uncommitedChangesAfterCaseSensitivityChange.split('\n').flatMap(changedFile => {
366
+ // This file was changed before the case sensitivity change too.
367
+ if (baseUncommitedChangesSet.has(changedFile)) {
368
+ return [];
369
+ }
370
+ return [changedFile];
371
+ }),
372
+ `Resolve filename casing inconsistencies before proceeding. ${(0, log_1.learnMore)('https://expo.fyi/macos-ignorecase')}`,
373
+ ];
374
+ throw new Error(errorMessage.join('\n'));
375
+ }
376
+ }
377
+ finally {
378
+ await setGitCaseSensitivityAsync(isCaseSensitive, cwd);
379
+ }
380
+ }
@@ -4,23 +4,23 @@ exports.resolveVcsClient = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
6
  const git_1 = tslib_1.__importDefault(require("./clients/git"));
7
- const gitNoCommit_1 = tslib_1.__importDefault(require("./clients/gitNoCommit"));
8
7
  const noVcs_1 = tslib_1.__importDefault(require("./clients/noVcs"));
9
8
  const NO_VCS_WARNING = `Using EAS CLI without version control system is not recommended, use this mode only if you know what you are doing.`;
9
+ let wasNoVcsWarningPrinted = false;
10
10
  function resolveVcsClient(requireCommit = false) {
11
11
  if (process.env.EAS_NO_VCS) {
12
12
  if (process.env.NODE_ENV !== 'test') {
13
- // This log might be printed before cli arguments are evaluated,
14
- // so it needs to go to stderr in case command is run in JSON
15
- // only mode.
16
- // eslint-disable-next-line no-console
17
- console.error(chalk_1.default.yellow(NO_VCS_WARNING));
13
+ if (!wasNoVcsWarningPrinted) {
14
+ // This log might be printed before cli arguments are evaluated,
15
+ // so it needs to go to stderr in case command is run in JSON
16
+ // only mode.
17
+ // eslint-disable-next-line no-console
18
+ console.error(chalk_1.default.yellow(NO_VCS_WARNING));
19
+ wasNoVcsWarningPrinted = true;
20
+ }
18
21
  }
19
22
  return new noVcs_1.default();
20
23
  }
21
- if (requireCommit) {
22
- return new git_1.default();
23
- }
24
- return new gitNoCommit_1.default();
24
+ return new git_1.default({ requireCommit });
25
25
  }
26
26
  exports.resolveVcsClient = resolveVcsClient;
@@ -1,3 +1,4 @@
1
+ export declare const EASIGNORE_FILENAME = ".easignore";
1
2
  export declare function getRootPath(): string;
2
3
  /**
3
4
  * Ignore wraps the 'ignore' package to support multiple .gitignore files
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeShallowCopyAsync = exports.Ignore = exports.getRootPath = void 0;
3
+ exports.makeShallowCopyAsync = exports.Ignore = exports.getRootPath = exports.EASIGNORE_FILENAME = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const fast_glob_1 = tslib_1.__importDefault(require("fast-glob"));
6
6
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
7
7
  const ignore_1 = tslib_1.__importDefault(require("ignore"));
8
8
  const path_1 = tslib_1.__importDefault(require("path"));
9
- const EASIGNORE_FILENAME = '.easignore';
9
+ exports.EASIGNORE_FILENAME = '.easignore';
10
10
  const GITIGNORE_FILENAME = '.gitignore';
11
11
  const DEFAULT_IGNORE = `
12
12
  .git
@@ -37,7 +37,7 @@ class Ignore {
37
37
  this.rootDir = rootDir;
38
38
  }
39
39
  async initIgnoreAsync() {
40
- const easIgnorePath = path_1.default.join(this.rootDir, EASIGNORE_FILENAME);
40
+ const easIgnorePath = path_1.default.join(this.rootDir, exports.EASIGNORE_FILENAME);
41
41
  if (await fs_extra_1.default.pathExists(easIgnorePath)) {
42
42
  this.ignoreMapping = [
43
43
  ['', (0, ignore_1.default)().add(DEFAULT_IGNORE)],
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "14.7.0",
2
+ "version": "15.0.0",
3
3
  "commands": {
4
4
  "analytics": {
5
5
  "id": "analytics",
@@ -2778,20 +2778,32 @@
2778
2778
  "aliases": [],
2779
2779
  "examples": [
2780
2780
  "$ eas fingerprint:compare \t # Compare fingerprints in interactive mode",
2781
- "$ eas fingerprint:compare c71a7d475aa6f75291bc93cd74aef395c3c94eee \t # Compare fingerprint against local directory",
2782
- "$ eas fingerprint:compare c71a7d475aa6f75291bc93cd74aef395c3c94eee f0d6a916e73f401d428e6e006e07b12453317ba2 \t # Compare provided fingerprints",
2783
- "$ eas fingerprint:compare --build-id 82bc6456-611a-48cb-8db4-5f9eb2ca1003 \t # Compare fingerprint from build against local directory"
2781
+ "$ eas fingerprint:compare <FINGERPRINT-HASH> \t # Compare fingerprint against local directory",
2782
+ "$ eas fingerprint:compare <FINGERPRINT-HASH-1> <FINGERPRINT-HASH-2> \t # Compare provided fingerprints",
2783
+ "$ eas fingerprint:compare --build-id <BUILD-ID> \t # Compare fingerprint from build against local directory",
2784
+ "$ eas fingerprint:compare --build-id <BUILD-ID-1> --build-id <BUILD-ID-2>\t # Compare fingerprint from a build against another build",
2785
+ "$ eas fingerprint:compare --build-id <BUILD-ID> --update-id <UPDATE-ID>\t # Compare fingerprint from build against fingerprint from update",
2786
+ "$ eas fingerprint:compare <FINGERPRINT-HASH> --update-id <UPDATE-ID> \t # Compare fingerprint from update against provided fingerprint"
2784
2787
  ],
2785
2788
  "flags": {
2786
2789
  "build-id": {
2787
2790
  "name": "build-id",
2788
2791
  "type": "option",
2789
2792
  "description": "Compare the fingerprint with the build with the specified ID",
2790
- "multiple": false,
2793
+ "multiple": true,
2791
2794
  "aliases": [
2792
2795
  "buildId"
2793
2796
  ]
2794
2797
  },
2798
+ "update-id": {
2799
+ "name": "update-id",
2800
+ "type": "option",
2801
+ "description": "Compare the fingerprint with the update with the specified ID",
2802
+ "multiple": true,
2803
+ "aliases": [
2804
+ "updateId"
2805
+ ]
2806
+ },
2795
2807
  "json": {
2796
2808
  "name": "json",
2797
2809
  "type": "boolean",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eas-cli",
3
3
  "description": "EAS command line tool",
4
- "version": "14.7.0",
4
+ "version": "15.0.0",
5
5
  "author": "Expo <support@expo.dev>",
6
6
  "bin": {
7
7
  "eas": "./bin/run"
@@ -13,7 +13,7 @@
13
13
  "@expo/config": "10.0.6",
14
14
  "@expo/config-plugins": "9.0.12",
15
15
  "@expo/eas-build-job": "1.0.165",
16
- "@expo/eas-json": "14.5.0",
16
+ "@expo/eas-json": "15.0.0",
17
17
  "@expo/env": "^1.0.0",
18
18
  "@expo/json-file": "8.3.3",
19
19
  "@expo/logger": "1.0.117",
@@ -237,5 +237,5 @@
237
237
  "node": "20.11.0",
238
238
  "yarn": "1.22.21"
239
239
  },
240
- "gitHead": "8a38cc24e1ab435bd5e150294c65c8324406af37"
240
+ "gitHead": "21c8131bcffa8ef78b1775ae6f8bed2c24e1fa72"
241
241
  }
@@ -1,8 +0,0 @@
1
- import GitClient from './git';
2
- export default class GitNoCommitClient extends GitClient {
3
- isCommitRequiredAsync(): Promise<boolean>;
4
- getRootPathAsync(): Promise<string>;
5
- makeShallowCopyAsync(destinationPath: string): Promise<void>;
6
- isFileIgnoredAsync(filePath: string): Promise<boolean>;
7
- trackFileAsync(file: string): Promise<void>;
8
- }
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
5
- const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
- const path_1 = tslib_1.__importDefault(require("path"));
7
- const git_1 = tslib_1.__importDefault(require("./git"));
8
- const log_1 = tslib_1.__importDefault(require("../../log"));
9
- const local_1 = require("../local");
10
- class GitNoCommitClient extends git_1.default {
11
- async isCommitRequiredAsync() {
12
- return false;
13
- }
14
- async getRootPathAsync() {
15
- return (await (0, spawn_async_1.default)('git', ['rev-parse', '--show-toplevel'])).stdout.trim();
16
- }
17
- async makeShallowCopyAsync(destinationPath) {
18
- // normalize converts C:/some/path to C:\some\path on windows
19
- const srcPath = path_1.default.normalize(await this.getRootPathAsync());
20
- await (0, local_1.makeShallowCopyAsync)(srcPath, destinationPath);
21
- }
22
- async isFileIgnoredAsync(filePath) {
23
- // normalize converts C:/some/path to C:\some\path on windows
24
- const rootPath = path_1.default.normalize(await this.getRootPathAsync());
25
- const ignore = new local_1.Ignore(rootPath);
26
- await ignore.initIgnoreAsync();
27
- return ignore.ignores(filePath);
28
- }
29
- async trackFileAsync(file) {
30
- try {
31
- await super.trackFileAsync(file);
32
- }
33
- catch {
34
- // In the no commit workflow it doesn't matter if we fail to track changes,
35
- // so we can ignore if this throws an exception
36
- log_1.default.warn(`Unable to track ${chalk_1.default.bold(path_1.default.basename(file))} in Git. Proceeding without tracking.`);
37
- log_1.default.warn(` Reason: the command ${chalk_1.default.bold(`"git add ${file}"`)} exited with an error.`);
38
- log_1.default.newLine();
39
- }
40
- }
41
- }
42
- exports.default = GitNoCommitClient;