mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-15 03:38:08 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7787c0cf8 |
No files matched your search
@@ -15,6 +15,7 @@
|
|||||||
"@expo/config-types": "50.0.0",
|
"@expo/config-types": "50.0.0",
|
||||||
"@expo/eas-build-job": "1.0.70",
|
"@expo/eas-build-job": "1.0.70",
|
||||||
"@expo/eas-json": "7.1.3",
|
"@expo/eas-json": "7.1.3",
|
||||||
|
"@expo/fingerprint": "0.6.0",
|
||||||
"@expo/json-file": "8.2.37",
|
"@expo/json-file": "8.2.37",
|
||||||
"@expo/multipart-body-parser": "1.1.0",
|
"@expo/multipart-body-parser": "1.1.0",
|
||||||
"@expo/osascript": "2.0.33",
|
"@expo/osascript": "2.0.33",
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ export async function syncProjectConfigurationAsync({
|
|||||||
localAutoIncrement?: AndroidVersionAutoIncrement;
|
localAutoIncrement?: AndroidVersionAutoIncrement;
|
||||||
vcsClient: Client;
|
vcsClient: Client;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
const versionBumpStrategy = resolveVersionBumpStrategy(localAutoIncrement ?? false);
|
const versionBumpStrategy = resolveVersionBumpStrategy(localAutoIncrement ?? false);
|
||||||
|
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
|
|||||||
@@ -100,7 +100,9 @@ export async function maybeResolveVersionsAsync(
|
|||||||
buildProfile: BuildProfile<Platform.ANDROID>,
|
buildProfile: BuildProfile<Platform.ANDROID>,
|
||||||
vcsClient: Client
|
vcsClient: Client
|
||||||
): Promise<{ appVersion?: string; appBuildVersion?: string }> {
|
): Promise<{ appVersion?: string; appBuildVersion?: string }> {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
const buildGradle = await getAppBuildGradleAsync(projectDir);
|
const buildGradle = await getAppBuildGradleAsync(projectDir);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -61,7 +61,9 @@ export async function createBuildContextAsync<T extends Platform>({
|
|||||||
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env });
|
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env });
|
||||||
const projectName = exp.slug;
|
const projectName = exp.slug;
|
||||||
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
|
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, platform, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, platform, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
const accountId = account.id;
|
const accountId = account.id;
|
||||||
const runFromCI = getenv.boolish('CI', false);
|
const runFromCI = getenv.boolish('CI', false);
|
||||||
const developmentClient =
|
const developmentClient =
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ export async function syncProjectConfigurationAsync({
|
|||||||
localAutoIncrement?: IosVersionAutoIncrement;
|
localAutoIncrement?: IosVersionAutoIncrement;
|
||||||
vcsClient: Client;
|
vcsClient: Client;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
const versionBumpStrategy = resolveVersionBumpStrategy(localAutoIncrement ?? false);
|
const versionBumpStrategy = resolveVersionBumpStrategy(localAutoIncrement ?? false);
|
||||||
|
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
|
|||||||
@@ -114,7 +114,9 @@ export async function readShortVersionAsync(
|
|||||||
buildSettings: XCBuildConfiguration['buildSettings'],
|
buildSettings: XCBuildConfiguration['buildSettings'],
|
||||||
vcsClient: Client
|
vcsClient: Client
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
const infoPlist = await readInfoPlistAsync(projectDir, buildSettings);
|
const infoPlist = await readInfoPlistAsync(projectDir, buildSettings);
|
||||||
|
|
||||||
@@ -136,7 +138,9 @@ export async function readBuildNumberAsync(
|
|||||||
buildSettings: XCBuildConfiguration['buildSettings'],
|
buildSettings: XCBuildConfiguration['buildSettings'],
|
||||||
vcsClient: Client
|
vcsClient: Client
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
const infoPlist = await readInfoPlistAsync(projectDir, buildSettings);
|
const infoPlist = await readInfoPlistAsync(projectDir, buildSettings);
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -43,7 +43,11 @@ export async function ensureExpoDevClientInstalledForDevClientBuildsAsync({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const workflowPerPlatformList = await Promise.all(
|
const workflowPerPlatformList = await Promise.all(
|
||||||
platformsToCheck.map(platform => resolveWorkflowAsync(projectDir, platform, vcsClient))
|
platformsToCheck.map(platform =>
|
||||||
|
resolveWorkflowAsync(projectDir, platform, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
Log.newLine();
|
Log.newLine();
|
||||||
|
|||||||
@@ -107,7 +107,9 @@ export async function makeProjectTarballAsync(
|
|||||||
startTimer(compressTimerLabel);
|
startTimer(compressTimerLabel);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await vcsClient.makeShallowCopyAsync(shallowClonePath);
|
await vcsClient.makeShallowCopyAsync(shallowClonePath, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
await tar.create({ cwd: shallowClonePath, file: tarPath, prefix: 'project', gzip: true }, [
|
await tar.create({ cwd: shallowClonePath, file: tarPath, prefix: 'project', gzip: true }, [
|
||||||
'.',
|
'.',
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ export async function checkGoogleServicesFileAsync<T extends Platform>(
|
|||||||
if (
|
if (
|
||||||
(await fs.pathExists(absGoogleServicesFilePath)) &&
|
(await fs.pathExists(absGoogleServicesFilePath)) &&
|
||||||
(!isInsideDirectory(absGoogleServicesFilePath, rootDir) ||
|
(!isInsideDirectory(absGoogleServicesFilePath, rootDir) ||
|
||||||
(await ctx.vcsClient.isFileIgnoredAsync(path.relative(rootDir, absGoogleServicesFilePath))))
|
(await ctx.vcsClient.isFileIgnoredAsync(path.relative(rootDir, absGoogleServicesFilePath), {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
})))
|
||||||
) {
|
) {
|
||||||
Log.warn(
|
Log.warn(
|
||||||
`File specified via "${ctx.platform}.googleServicesFile" field in your app.json is not checked in to your repository and won't be uploaded to the builder.`
|
`File specified via "${ctx.platform}.googleServicesFile" field in your app.json is not checked in to your repository and won't be uploaded to the builder.`
|
||||||
|
|||||||
@@ -72,14 +72,18 @@ export default class BuildConfigure extends EasCommand {
|
|||||||
// configure expo-updates
|
// configure expo-updates
|
||||||
if (expoUpdatesIsInstalled) {
|
if (expoUpdatesIsInstalled) {
|
||||||
if ([RequestedPlatform.Android, RequestedPlatform.All].includes(platform)) {
|
if ([RequestedPlatform.Android, RequestedPlatform.All].includes(platform)) {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
await syncAndroidUpdatesConfigurationAsync(projectDir, exp);
|
await syncAndroidUpdatesConfigurationAsync(projectDir, exp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([RequestedPlatform.Ios, RequestedPlatform.All].includes(platform)) {
|
if ([RequestedPlatform.Ios, RequestedPlatform.All].includes(platform)) {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
await syncIosUpdatesConfigurationAsync(vcsClient, projectDir, exp);
|
await syncIosUpdatesConfigurationAsync(vcsClient, projectDir, exp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,9 @@ export default class BuildInspect extends EasCommand {
|
|||||||
|
|
||||||
if (flags.stage === InspectStage.ARCHIVE) {
|
if (flags.stage === InspectStage.ARCHIVE) {
|
||||||
await vcsClient.ensureRepoExistsAsync();
|
await vcsClient.ensureRepoExistsAsync();
|
||||||
await vcsClient.makeShallowCopyAsync(tmpWorkingdir);
|
await vcsClient.makeShallowCopyAsync(tmpWorkingdir, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
await this.copyToOutputDirAsync(tmpWorkingdir, outputDirectory);
|
await this.copyToOutputDirAsync(tmpWorkingdir, outputDirectory);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -109,7 +109,9 @@ export default class BuildVersionSyncView extends EasCommand {
|
|||||||
toAppPlatform(profileInfo.platform),
|
toAppPlatform(profileInfo.platform),
|
||||||
applicationIdentifier
|
applicationIdentifier
|
||||||
);
|
);
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, profileInfo.platform, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, profileInfo.platform, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
if (!remoteVersions?.buildVersion) {
|
if (!remoteVersions?.buildVersion) {
|
||||||
Log.warn(
|
Log.warn(
|
||||||
`Skipping versions sync for ${platformDisplayName}. There are no versions configured on Expo servers, use "eas build:version:set" or run a build to initialize it.`
|
`Skipping versions sync for ${platformDisplayName}. There are no versions configured on Expo servers, use "eas build:version:set" or run a build to initialize it.`
|
||||||
|
|||||||
@@ -50,8 +50,12 @@ export default class Diagnostics extends EasCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async printWorkflowAsync(projectDir: string, vcsClient: Client): Promise<void> {
|
private async printWorkflowAsync(projectDir: string, vcsClient: Client): Promise<void> {
|
||||||
const androidWorkflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
|
const androidWorkflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, {
|
||||||
const iosWorkflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
|
const iosWorkflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
|
|
||||||
if (androidWorkflow === iosWorkflow) {
|
if (androidWorkflow === iosWorkflow) {
|
||||||
Log.log(` Project workflow: ${androidWorkflow}`);
|
Log.log(` Project workflow: ${androidWorkflow}`);
|
||||||
|
|||||||
@@ -359,12 +359,13 @@ export default class UpdatePublish extends EasCommand {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
const runtimeVersions = await getRuntimeVersionObjectAsync(
|
const runtimeVersions = await getRuntimeVersionObjectAsync({
|
||||||
exp,
|
exp,
|
||||||
realizedPlatforms,
|
platforms: realizedPlatforms,
|
||||||
projectDir,
|
projectDir,
|
||||||
vcsClient
|
vcsClient,
|
||||||
);
|
nonInteractive,
|
||||||
|
});
|
||||||
const runtimeToPlatformMapping =
|
const runtimeToPlatformMapping =
|
||||||
getRuntimeToPlatformMappingFromRuntimeVersions(runtimeVersions);
|
getRuntimeToPlatformMappingFromRuntimeVersions(runtimeVersions);
|
||||||
|
|
||||||
|
|||||||
@@ -201,12 +201,13 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
|
|||||||
const gitCommitHash = await vcsClient.getCommitHashAsync();
|
const gitCommitHash = await vcsClient.getCommitHashAsync();
|
||||||
const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
|
const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
|
||||||
|
|
||||||
const runtimeVersions = await getRuntimeVersionObjectAsync(
|
const runtimeVersions = await getRuntimeVersionObjectAsync({
|
||||||
exp,
|
exp,
|
||||||
realizedPlatforms,
|
platforms: realizedPlatforms,
|
||||||
projectDir,
|
projectDir,
|
||||||
vcsClient
|
vcsClient,
|
||||||
);
|
nonInteractive,
|
||||||
|
});
|
||||||
|
|
||||||
let newUpdates: UpdatePublishMutation['updateBranch']['publishUpdateGroups'];
|
let newUpdates: UpdatePublishMutation['updateBranch']['publishUpdateGroups'];
|
||||||
const publishSpinner = ora('Publishing...').start();
|
const publishSpinner = ora('Publishing...').start();
|
||||||
|
|||||||
@@ -23,12 +23,16 @@ describe(resolveWorkflowAsync, () => {
|
|||||||
projectDir
|
projectDir
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient)).resolves.toBe(
|
await expect(
|
||||||
Workflow.GENERIC
|
resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, {
|
||||||
);
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
await expect(resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient)).resolves.toBe(
|
})
|
||||||
Workflow.GENERIC
|
).resolves.toBe(Workflow.GENERIC);
|
||||||
);
|
await expect(
|
||||||
|
resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
})
|
||||||
|
).resolves.toBe(Workflow.GENERIC);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('bare workflow for single platform', async () => {
|
test('bare workflow for single platform', async () => {
|
||||||
@@ -39,12 +43,16 @@ describe(resolveWorkflowAsync, () => {
|
|||||||
projectDir
|
projectDir
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient)).resolves.toBe(
|
await expect(
|
||||||
Workflow.MANAGED
|
resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, {
|
||||||
);
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
await expect(resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient)).resolves.toBe(
|
})
|
||||||
Workflow.GENERIC
|
).resolves.toBe(Workflow.MANAGED);
|
||||||
);
|
await expect(
|
||||||
|
resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
})
|
||||||
|
).resolves.toBe(Workflow.GENERIC);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('android/ios directories are ignored', async () => {
|
test('android/ios directories are ignored', async () => {
|
||||||
@@ -57,12 +65,16 @@ describe(resolveWorkflowAsync, () => {
|
|||||||
projectDir
|
projectDir
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient)).resolves.toBe(
|
await expect(
|
||||||
Workflow.MANAGED
|
resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, {
|
||||||
);
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
await expect(resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient)).resolves.toBe(
|
})
|
||||||
Workflow.MANAGED
|
).resolves.toBe(Workflow.MANAGED);
|
||||||
);
|
await expect(
|
||||||
|
resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
})
|
||||||
|
).resolves.toBe(Workflow.MANAGED);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -80,7 +92,11 @@ describe(resolveWorkflowPerPlatformAsync, () => {
|
|||||||
projectDir
|
projectDir
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(resolveWorkflowPerPlatformAsync(projectDir, vcsClient)).resolves.toEqual({
|
await expect(
|
||||||
|
resolveWorkflowPerPlatformAsync(projectDir, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
})
|
||||||
|
).resolves.toEqual({
|
||||||
android: Workflow.GENERIC,
|
android: Workflow.GENERIC,
|
||||||
ios: Workflow.GENERIC,
|
ios: Workflow.GENERIC,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ export async function ensureApplicationIdIsDefinedForManagedProjectAsync({
|
|||||||
exp: ExpoConfig;
|
exp: ExpoConfig;
|
||||||
vcsClient: Client;
|
vcsClient: Client;
|
||||||
}): Promise<string> {
|
}): Promise<string> {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
assert(workflow === Workflow.MANAGED, 'This function should be called only for managed projects');
|
assert(workflow === Workflow.MANAGED, 'This function should be called only for managed projects');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -101,7 +103,9 @@ export async function getApplicationIdAsync(
|
|||||||
vcsClient: Client,
|
vcsClient: Client,
|
||||||
gradleContext?: GradleBuildContext
|
gradleContext?: GradleBuildContext
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
warnIfAndroidPackageDefinedInAppConfigForBareWorkflowProject(projectDir, exp);
|
warnIfAndroidPackageDefinedInAppConfigForBareWorkflowProject(projectDir, exp);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ export async function resolveGradleBuildContextAsync(
|
|||||||
buildProfile: BuildProfile<Platform.ANDROID>,
|
buildProfile: BuildProfile<Platform.ANDROID>,
|
||||||
vcsClient: Client
|
vcsClient: Client
|
||||||
): Promise<GradleBuildContext | undefined> {
|
): Promise<GradleBuildContext | undefined> {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
try {
|
try {
|
||||||
if (buildProfile.gradleCommand) {
|
if (buildProfile.gradleCommand) {
|
||||||
|
|||||||
@@ -36,7 +36,9 @@ export async function getApplicationIdentifierAsync({
|
|||||||
}): Promise<string> {
|
}): Promise<string> {
|
||||||
if (platform === Platform.ANDROID) {
|
if (platform === Platform.ANDROID) {
|
||||||
const profile = buildProfile as BuildProfile<Platform.ANDROID>;
|
const profile = buildProfile as BuildProfile<Platform.ANDROID>;
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
|
|
||||||
if (workflow === Workflow.MANAGED) {
|
if (workflow === Workflow.MANAGED) {
|
||||||
return await ensureApplicationIdIsDefinedForManagedProjectAsync({
|
return await ensureApplicationIdIsDefinedForManagedProjectAsync({
|
||||||
@@ -51,7 +53,9 @@ export async function getApplicationIdentifierAsync({
|
|||||||
const gradleContext = await resolveGradleBuildContextAsync(projectDir, profile, vcsClient);
|
const gradleContext = await resolveGradleBuildContextAsync(projectDir, profile, vcsClient);
|
||||||
return await getApplicationIdAsync(projectDir, exp, vcsClient, gradleContext);
|
return await getApplicationIdAsync(projectDir, exp, vcsClient, gradleContext);
|
||||||
} else {
|
} else {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
const profile = buildProfile as BuildProfile<Platform.IOS>;
|
const profile = buildProfile as BuildProfile<Platform.IOS>;
|
||||||
if (workflow === Workflow.MANAGED) {
|
if (workflow === Workflow.MANAGED) {
|
||||||
return await ensureBundleIdentifierIsDefinedForManagedProjectAsync({
|
return await ensureBundleIdentifierIsDefinedForManagedProjectAsync({
|
||||||
|
|||||||
@@ -31,7 +31,11 @@ export async function validateCustomBuildConfigAsync({
|
|||||||
`Custom build configuration file ${chalk.bold(relativeConfigPath)} does not exist.`
|
`Custom build configuration file ${chalk.bold(relativeConfigPath)} does not exist.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (await vcsClient.isFileIgnoredAsync(relativeConfigPath)) {
|
if (
|
||||||
|
await vcsClient.isFileIgnoredAsync(relativeConfigPath, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
})
|
||||||
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Custom build configuration file ${chalk.bold(
|
`Custom build configuration file ${chalk.bold(
|
||||||
relativeConfigPath
|
relativeConfigPath
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ export async function ensureBundleIdentifierIsDefinedForManagedProjectAsync({
|
|||||||
exp: ExpoConfig;
|
exp: ExpoConfig;
|
||||||
vcsClient: Client;
|
vcsClient: Client;
|
||||||
}): Promise<string> {
|
}): Promise<string> {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
assert(workflow === Workflow.MANAGED, 'This function should be called only for managed projects');
|
assert(workflow === Workflow.MANAGED, 'This function should be called only for managed projects');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -55,7 +57,9 @@ export async function getBundleIdentifierAsync(
|
|||||||
vcsClient: Client,
|
vcsClient: Client,
|
||||||
xcodeContext?: { targetName?: string; buildConfiguration?: string }
|
xcodeContext?: { targetName?: string; buildConfiguration?: string }
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
warnIfBundleIdentifierDefinedInAppConfigForBareWorkflowProject(projectDir, exp);
|
warnIfBundleIdentifierDefinedInAppConfigForBareWorkflowProject(projectDir, exp);
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ export async function getManagedApplicationTargetEntitlementsAsync(
|
|||||||
projectRoot: projectDir,
|
projectRoot: projectDir,
|
||||||
platforms: ['ios'],
|
platforms: ['ios'],
|
||||||
introspect: true,
|
introspect: true,
|
||||||
ignoreExistingNativeFiles: await hasIgnoredIosProjectAsync(projectDir, vcsClient),
|
ignoreExistingNativeFiles: await hasIgnoredIosProjectAsync(projectDir, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
return expWithMods.ios?.entitlements || {};
|
return expWithMods.ios?.entitlements || {};
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ export async function resolveXcodeBuildContextAsync(
|
|||||||
}: { exp: ExpoConfig; projectDir: string; nonInteractive: boolean; vcsClient: Client },
|
}: { exp: ExpoConfig; projectDir: string; nonInteractive: boolean; vcsClient: Client },
|
||||||
buildProfile: BuildProfile<Platform.IOS>
|
buildProfile: BuildProfile<Platform.IOS>
|
||||||
): Promise<XcodeBuildContext> {
|
): Promise<XcodeBuildContext> {
|
||||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
|
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
const buildScheme =
|
const buildScheme =
|
||||||
buildProfile.scheme ??
|
buildProfile.scheme ??
|
||||||
|
|||||||
@@ -145,7 +145,9 @@ export async function resolveBareProjectTargetsAsync({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveTargetsAsync(opts: ResolveTargetOptions): Promise<Target[]> {
|
export async function resolveTargetsAsync(opts: ResolveTargetOptions): Promise<Target[]> {
|
||||||
const workflow = await resolveWorkflowAsync(opts.projectDir, Platform.IOS, opts.vcsClient);
|
const workflow = await resolveWorkflowAsync(opts.projectDir, Platform.IOS, opts.vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
if (workflow === Workflow.GENERIC) {
|
if (workflow === Workflow.GENERIC) {
|
||||||
return await resolveBareProjectTargetsAsync(opts);
|
return await resolveBareProjectTargetsAsync(opts);
|
||||||
} else if (workflow === Workflow.MANAGED) {
|
} else if (workflow === Workflow.MANAGED) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ExpoConfig, Platform } from '@expo/config';
|
import { ExpoConfig, Platform } from '@expo/config';
|
||||||
import { Updates } from '@expo/config-plugins';
|
import { Updates } from '@expo/config-plugins';
|
||||||
import { Platform as EASBuildJobPlatform, Workflow } from '@expo/eas-build-job';
|
import { Platform as EASBuildJobPlatform, Workflow } from '@expo/eas-build-job';
|
||||||
|
import * as Fingerprint from '@expo/fingerprint';
|
||||||
import JsonFile from '@expo/json-file';
|
import JsonFile from '@expo/json-file';
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
@@ -8,7 +9,6 @@ import crypto from 'crypto';
|
|||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import Joi from 'joi';
|
import Joi from 'joi';
|
||||||
import mime from 'mime';
|
import mime from 'mime';
|
||||||
import nullthrows from 'nullthrows';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import promiseLimit from 'promise-limit';
|
import promiseLimit from 'promise-limit';
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ import { PublishMutation } from '../graphql/mutations/PublishMutation';
|
|||||||
import { PublishQuery } from '../graphql/queries/PublishQuery';
|
import { PublishQuery } from '../graphql/queries/PublishQuery';
|
||||||
import Log, { learnMore } from '../log';
|
import Log, { learnMore } from '../log';
|
||||||
import { RequestedPlatform, requestedPlatformDisplayNames } from '../platform';
|
import { RequestedPlatform, requestedPlatformDisplayNames } from '../platform';
|
||||||
import { promptAsync } from '../prompts';
|
import { confirmAsync, promptAsync } from '../prompts';
|
||||||
import { getBranchNameFromChannelNameAsync } from '../update/getBranchNameFromChannelNameAsync';
|
import { getBranchNameFromChannelNameAsync } from '../update/getBranchNameFromChannelNameAsync';
|
||||||
import { formatUpdateMessage, truncateString as truncateUpdateMessage } from '../update/utils';
|
import { formatUpdateMessage, truncateString as truncateUpdateMessage } from '../update/utils';
|
||||||
import { PresignedPost, uploadWithPresignedPostWithRetryAsync } from '../uploads';
|
import { PresignedPost, uploadWithPresignedPostWithRetryAsync } from '../uploads';
|
||||||
@@ -675,47 +675,123 @@ export function getRequestedPlatform(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Get runtime versions grouped by platform. Runtime version is always `null` on web where the platform is always backwards compatible. */
|
/** Get runtime versions grouped by platform. Runtime version is always `null` on web where the platform is always backwards compatible. */
|
||||||
export async function getRuntimeVersionObjectAsync(
|
export async function getRuntimeVersionObjectAsync({
|
||||||
exp: ExpoConfig,
|
exp,
|
||||||
platforms: Platform[],
|
platforms,
|
||||||
projectDir: string,
|
projectDir,
|
||||||
vcsClient: Client
|
vcsClient,
|
||||||
): Promise<{ platform: string; runtimeVersion: string }[]> {
|
nonInteractive,
|
||||||
|
}: {
|
||||||
|
exp: ExpoConfig;
|
||||||
|
platforms: Platform[];
|
||||||
|
projectDir: string;
|
||||||
|
vcsClient: Client;
|
||||||
|
nonInteractive: boolean;
|
||||||
|
}): Promise<{ platform: string; runtimeVersion: string }[]> {
|
||||||
|
const runtimeVersionObjects: { platform: string; runtimeVersion: string }[] = [];
|
||||||
|
|
||||||
|
// calculate these serially since in some cases (fingerprint) we need to prompt the user to confirm that
|
||||||
|
// the runtime version is ready to be calculated
|
||||||
for (const platform of platforms) {
|
for (const platform of platforms) {
|
||||||
if (platform === 'web') {
|
runtimeVersionObjects.push({
|
||||||
continue;
|
platform,
|
||||||
}
|
runtimeVersion: await getRuntimeVersionForPlatformAsync({
|
||||||
const isPolicy = typeof (exp[platform]?.runtimeVersion ?? exp.runtimeVersion) === 'object';
|
exp,
|
||||||
if (isPolicy) {
|
platform,
|
||||||
const isManaged =
|
projectDir,
|
||||||
(await resolveWorkflowAsync(projectDir, platform as EASBuildJobPlatform, vcsClient)) ===
|
vcsClient,
|
||||||
Workflow.MANAGED;
|
nonInteractive,
|
||||||
if (!isManaged) {
|
}),
|
||||||
throw new Error(
|
});
|
||||||
`You're currently using the bare workflow, where runtime version policies are not supported. You must set your runtime version manually. For example, define your runtime version as "1.0.0", not {"policy": "appVersion"} in your app config. ${learnMore(
|
}
|
||||||
'https://docs.expo.dev/eas-update/runtime-versions'
|
|
||||||
)}`
|
return runtimeVersionObjects;
|
||||||
);
|
}
|
||||||
|
|
||||||
|
async function getRuntimeVersionForPlatformAsync({
|
||||||
|
exp,
|
||||||
|
platform,
|
||||||
|
projectDir,
|
||||||
|
vcsClient,
|
||||||
|
nonInteractive,
|
||||||
|
}: {
|
||||||
|
exp: ExpoConfig;
|
||||||
|
platform: Platform;
|
||||||
|
projectDir: string;
|
||||||
|
vcsClient: Client;
|
||||||
|
nonInteractive: boolean;
|
||||||
|
}): Promise<string> {
|
||||||
|
if (platform === 'web') {
|
||||||
|
return 'UNVERSIONED';
|
||||||
|
}
|
||||||
|
|
||||||
|
const runtimeVersion = exp[platform]?.runtimeVersion ?? exp.runtimeVersion;
|
||||||
|
if (typeof runtimeVersion === 'object') {
|
||||||
|
const workflowIgnoringEASIgnoreToMatchExpoUpdatesDetection = await resolveWorkflowAsync(
|
||||||
|
projectDir,
|
||||||
|
platform as EASBuildJobPlatform,
|
||||||
|
vcsClient,
|
||||||
|
{ useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: false }
|
||||||
|
);
|
||||||
|
const policy = runtimeVersion.policy;
|
||||||
|
|
||||||
|
if (policy === 'fingerprintExperimental') {
|
||||||
|
if (workflowIgnoringEASIgnoreToMatchExpoUpdatesDetection === Workflow.GENERIC) {
|
||||||
|
if (nonInteractive) {
|
||||||
|
// log to inform the user that the fingerprint has been calculated
|
||||||
|
Log.warn(
|
||||||
|
`Calculating native fingerprint for platform ${platform} using current state of the "${platform}" directory.`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// prompt the user to confirm that their native projects are in a state that is ready
|
||||||
|
// for the fingerprint to be calculated
|
||||||
|
const confirm = await confirmAsync({
|
||||||
|
message: `Calculating native fingerprint for platform ${platform} using current state of the "${platform}" directory. Do you want to continue?`,
|
||||||
|
});
|
||||||
|
if (!confirm) {
|
||||||
|
throw new Error('Aborted');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return await Fingerprint.createProjectHashAsync(projectDir, {
|
||||||
|
platforms: [platform],
|
||||||
|
});
|
||||||
|
} else if (workflowIgnoringEASIgnoreToMatchExpoUpdatesDetection === Workflow.MANAGED) {
|
||||||
|
// ignore everything in native directories to ensure fingerprint is the same
|
||||||
|
// no matter whether project has been prebuilt
|
||||||
|
return await Fingerprint.createProjectHashAsync(projectDir, {
|
||||||
|
platforms: [platform],
|
||||||
|
ignorePaths: ['/android/**/*', '/ios/**/*'],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error('Unknown workflow');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const workflow = await resolveWorkflowAsync(
|
||||||
|
projectDir,
|
||||||
|
platform as EASBuildJobPlatform,
|
||||||
|
vcsClient,
|
||||||
|
{ useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true }
|
||||||
|
);
|
||||||
|
if (workflow !== Workflow.MANAGED) {
|
||||||
|
throw new Error(
|
||||||
|
`You're currently using the bare workflow, where runtime version policies are not supported. You must set your runtime version manually. For example, define your runtime version as "1.0.0", not {"policy": "appVersion"} in your app config. ${learnMore(
|
||||||
|
'https://docs.expo.dev/eas-update/runtime-versions'
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await Promise.all(
|
const resolvedRuntimeVersion = await Updates.getRuntimeVersionAsync(projectDir, exp, platform);
|
||||||
[...new Set(platforms)].map(async platform => {
|
if (!resolvedRuntimeVersion) {
|
||||||
if (platform === 'web') {
|
throw new Error(
|
||||||
return { platform: 'web', runtimeVersion: 'UNVERSIONED' };
|
`Unable to determine runtime version for ${
|
||||||
}
|
requestedPlatformDisplayNames[platform]
|
||||||
return {
|
}. ${learnMore('https://docs.expo.dev/eas-update/runtime-versions/')}`
|
||||||
platform,
|
);
|
||||||
runtimeVersion: nullthrows(
|
}
|
||||||
await Updates.getRuntimeVersionAsync(projectDir, exp, platform),
|
|
||||||
`Unable to determine runtime version for ${
|
return resolvedRuntimeVersion;
|
||||||
requestedPlatformDisplayNames[platform]
|
|
||||||
}. ${learnMore('https://docs.expo.dev/eas-update/runtime-versions/')}`
|
|
||||||
),
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRuntimeToPlatformMappingFromRuntimeVersions(
|
export function getRuntimeToPlatformMappingFromRuntimeVersions(
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ import { Client } from '../vcs/vcs';
|
|||||||
export async function resolveWorkflowAsync(
|
export async function resolveWorkflowAsync(
|
||||||
projectDir: string,
|
projectDir: string,
|
||||||
platform: Platform,
|
platform: Platform,
|
||||||
vcsClient: Client
|
vcsClient: Client,
|
||||||
|
options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
): Promise<Workflow> {
|
): Promise<Workflow> {
|
||||||
let platformWorkflowMarkers: string[];
|
let platformWorkflowMarkers: string[];
|
||||||
try {
|
try {
|
||||||
@@ -27,7 +30,7 @@ export async function resolveWorkflowAsync(
|
|||||||
for (const marker of platformWorkflowMarkers) {
|
for (const marker of platformWorkflowMarkers) {
|
||||||
if (
|
if (
|
||||||
(await fs.pathExists(marker)) &&
|
(await fs.pathExists(marker)) &&
|
||||||
!(await vcsClient.isFileIgnoredAsync(path.relative(vcsRootPath, marker)))
|
!(await vcsClient.isFileIgnoredAsync(path.relative(vcsRootPath, marker), options))
|
||||||
) {
|
) {
|
||||||
return Workflow.GENERIC;
|
return Workflow.GENERIC;
|
||||||
}
|
}
|
||||||
@@ -37,24 +40,30 @@ export async function resolveWorkflowAsync(
|
|||||||
|
|
||||||
export async function resolveWorkflowPerPlatformAsync(
|
export async function resolveWorkflowPerPlatformAsync(
|
||||||
projectDir: string,
|
projectDir: string,
|
||||||
vcsClient: Client
|
vcsClient: Client,
|
||||||
|
options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
): Promise<Record<Platform, Workflow>> {
|
): Promise<Record<Platform, Workflow>> {
|
||||||
const [android, ios] = await Promise.all([
|
const [android, ios] = await Promise.all([
|
||||||
resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient),
|
resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient, options),
|
||||||
resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient),
|
resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient, options),
|
||||||
]);
|
]);
|
||||||
return { android, ios };
|
return { android, ios };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function hasIgnoredIosProjectAsync(
|
export async function hasIgnoredIosProjectAsync(
|
||||||
projectDir: string,
|
projectDir: string,
|
||||||
vcsClient: Client
|
vcsClient: Client,
|
||||||
|
options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const vcsRootPath = path.normalize(await vcsClient.getRootPathAsync());
|
const vcsRootPath = path.normalize(await vcsClient.getRootPathAsync());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const pbxProjectPath = IOSConfig.Paths.getPBXProjectPath(projectDir);
|
const pbxProjectPath = IOSConfig.Paths.getPBXProjectPath(projectDir);
|
||||||
return await vcsClient.isFileIgnoredAsync(path.relative(vcsRootPath, pbxProjectPath));
|
return await vcsClient.isFileIgnoredAsync(path.relative(vcsRootPath, pbxProjectPath), options);
|
||||||
} finally {
|
} finally {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -384,7 +384,9 @@ export async function ensureEASUpdateIsConfiguredAsync({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflows = await resolveWorkflowPerPlatformAsync(projectDir, vcsClient);
|
const workflows = await resolveWorkflowPerPlatformAsync(projectDir, vcsClient, {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true,
|
||||||
|
});
|
||||||
const { projectChanged, exp: expWithUpdates } =
|
const { projectChanged, exp: expWithUpdates } =
|
||||||
await ensureEASUpdatesIsConfiguredInExpoConfigAsync({
|
await ensureEASUpdatesIsConfiguredInExpoConfigAsync({
|
||||||
exp: expMaybeWithoutUpdates,
|
exp: expMaybeWithoutUpdates,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ describe(Ignore, () => {
|
|||||||
'/root'
|
'/root'
|
||||||
);
|
);
|
||||||
|
|
||||||
const ignore = new Ignore('/root');
|
const ignore = new Ignore('/root', { useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true });
|
||||||
await ignore.initIgnoreAsync();
|
await ignore.initIgnoreAsync();
|
||||||
expect(ignore.ignores('aaa')).toBe(true);
|
expect(ignore.ignores('aaa')).toBe(true);
|
||||||
expect(ignore.ignores('bbb')).toBe(false);
|
expect(ignore.ignores('bbb')).toBe(false);
|
||||||
@@ -36,7 +36,7 @@ describe(Ignore, () => {
|
|||||||
'/root'
|
'/root'
|
||||||
);
|
);
|
||||||
|
|
||||||
const ignore = new Ignore('/root');
|
const ignore = new Ignore('/root', { useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true });
|
||||||
await ignore.initIgnoreAsync();
|
await ignore.initIgnoreAsync();
|
||||||
expect(ignore.ignores('aaa')).toBe(false);
|
expect(ignore.ignores('aaa')).toBe(false);
|
||||||
expect(ignore.ignores('bbb')).toBe(false);
|
expect(ignore.ignores('bbb')).toBe(false);
|
||||||
@@ -44,6 +44,25 @@ describe(Ignore, () => {
|
|||||||
expect((ignore as any).ignoreMapping.map((i: any) => i[0])).toEqual(['', '']);
|
expect((ignore as any).ignoreMapping.map((i: any) => i[0])).toEqual(['', '']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses .gitignore files if .easignore is present but useEASIgnoreIfAvailableWhenEvaluatingFileIgnores is false', async () => {
|
||||||
|
vol.fromJSON(
|
||||||
|
{
|
||||||
|
'.gitignore': 'aaa',
|
||||||
|
'.easignore': 'ccc',
|
||||||
|
'dir/.gitignore': 'bbb',
|
||||||
|
},
|
||||||
|
'/root'
|
||||||
|
);
|
||||||
|
|
||||||
|
const ignore = new Ignore('/root', { useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: false });
|
||||||
|
await ignore.initIgnoreAsync();
|
||||||
|
expect(ignore.ignores('aaa')).toBe(true);
|
||||||
|
expect(ignore.ignores('bbb')).toBe(false);
|
||||||
|
expect(ignore.ignores('ccc')).toBe(false);
|
||||||
|
expect(ignore.ignores('dir/aaa')).toBe(true);
|
||||||
|
expect(ignore.ignores('dir/bbb')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('ignores .gitignore files in node_modules content', async () => {
|
it('ignores .gitignore files in node_modules content', async () => {
|
||||||
vol.fromJSON(
|
vol.fromJSON(
|
||||||
{
|
{
|
||||||
@@ -54,7 +73,7 @@ describe(Ignore, () => {
|
|||||||
'/root'
|
'/root'
|
||||||
);
|
);
|
||||||
|
|
||||||
const ignore = new Ignore('/root');
|
const ignore = new Ignore('/root', { useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true });
|
||||||
await ignore.initIgnoreAsync();
|
await ignore.initIgnoreAsync();
|
||||||
expect(ignore.ignores('aaa')).toBe(true);
|
expect(ignore.ignores('aaa')).toBe(true);
|
||||||
expect(ignore.ignores('bbb')).toBe(false);
|
expect(ignore.ignores('bbb')).toBe(false);
|
||||||
@@ -72,7 +91,7 @@ describe(Ignore, () => {
|
|||||||
'/root'
|
'/root'
|
||||||
);
|
);
|
||||||
|
|
||||||
const ignore = new Ignore('/root');
|
const ignore = new Ignore('/root', { useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true });
|
||||||
await ignore.initIgnoreAsync();
|
await ignore.initIgnoreAsync();
|
||||||
expect(ignore.ignores('dir/ccc')).toBe(true);
|
expect(ignore.ignores('dir/ccc')).toBe(true);
|
||||||
});
|
});
|
||||||
@@ -80,7 +99,7 @@ describe(Ignore, () => {
|
|||||||
it('ignores .git', async () => {
|
it('ignores .git', async () => {
|
||||||
vol.fromJSON({}, '/root');
|
vol.fromJSON({}, '/root');
|
||||||
|
|
||||||
const ignore = new Ignore('/root');
|
const ignore = new Ignore('/root', { useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true });
|
||||||
await ignore.initIgnoreAsync();
|
await ignore.initIgnoreAsync();
|
||||||
expect(ignore.ignores('.git')).toBe(true);
|
expect(ignore.ignores('.git')).toBe(true);
|
||||||
});
|
});
|
||||||
@@ -93,7 +112,7 @@ describe(Ignore, () => {
|
|||||||
'/root'
|
'/root'
|
||||||
);
|
);
|
||||||
|
|
||||||
const ignore = new Ignore('/root');
|
const ignore = new Ignore('/root', { useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: true });
|
||||||
await ignore.initIgnoreAsync();
|
await ignore.initIgnoreAsync();
|
||||||
expect(() => ignore.ignores('dir/test')).not.toThrowError();
|
expect(() => ignore.ignores('dir/test')).not.toThrowError();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -120,7 +120,12 @@ export default class GitClient extends Client {
|
|||||||
return (await spawnAsync('git', ['rev-parse', '--show-toplevel'])).stdout.trim();
|
return (await spawnAsync('git', ['rev-parse', '--show-toplevel'])).stdout.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async makeShallowCopyAsync(destinationPath: string): Promise<void> {
|
public async makeShallowCopyAsync(
|
||||||
|
destinationPath: string,
|
||||||
|
_options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
|
): Promise<void> {
|
||||||
if (await this.hasUncommittedChangesAsync()) {
|
if (await this.hasUncommittedChangesAsync()) {
|
||||||
// it should already be checked before this function is called, but in case it wasn't
|
// it should already be checked before this function is called, but in case it wasn't
|
||||||
// we want to ensure that any changes were introduced by call to `setGitCaseSensitivityAsync`
|
// we want to ensure that any changes were introduced by call to `setGitCaseSensitivityAsync`
|
||||||
@@ -207,7 +212,12 @@ export default class GitClient extends Client {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async isFileIgnoredAsync(filePath: string): Promise<boolean> {
|
public override async isFileIgnoredAsync(
|
||||||
|
filePath: string,
|
||||||
|
_options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
|
): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
await spawnAsync('git', ['check-ignore', '-q', filePath], {
|
await spawnAsync('git', ['check-ignore', '-q', filePath], {
|
||||||
cwd: path.normalize(await this.getRootPathAsync()),
|
cwd: path.normalize(await this.getRootPathAsync()),
|
||||||
|
|||||||
@@ -15,16 +15,26 @@ export default class GitNoCommitClient extends GitClient {
|
|||||||
return (await spawnAsync('git', ['rev-parse', '--show-toplevel'])).stdout.trim();
|
return (await spawnAsync('git', ['rev-parse', '--show-toplevel'])).stdout.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async makeShallowCopyAsync(destinationPath: string): Promise<void> {
|
public override async makeShallowCopyAsync(
|
||||||
|
destinationPath: string,
|
||||||
|
options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
|
): Promise<void> {
|
||||||
// normalize converts C:/some/path to C:\some\path on windows
|
// normalize converts C:/some/path to C:\some\path on windows
|
||||||
const srcPath = path.normalize(await this.getRootPathAsync());
|
const srcPath = path.normalize(await this.getRootPathAsync());
|
||||||
await makeShallowCopyAsync(srcPath, destinationPath);
|
await makeShallowCopyAsync(srcPath, destinationPath, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async isFileIgnoredAsync(filePath: string): Promise<boolean> {
|
public override async isFileIgnoredAsync(
|
||||||
|
filePath: string,
|
||||||
|
options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
|
): Promise<boolean> {
|
||||||
// normalize converts C:/some/path to C:\some\path on windows
|
// normalize converts C:/some/path to C:\some\path on windows
|
||||||
const rootPath = path.normalize(await this.getRootPathAsync());
|
const rootPath = path.normalize(await this.getRootPathAsync());
|
||||||
const ignore = new Ignore(rootPath);
|
const ignore = new Ignore(rootPath, options);
|
||||||
await ignore.initIgnoreAsync();
|
await ignore.initIgnoreAsync();
|
||||||
return ignore.ignores(filePath);
|
return ignore.ignores(filePath);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,23 @@ export default class NoVcsClient extends Client {
|
|||||||
return getRootPath();
|
return getRootPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async makeShallowCopyAsync(destinationPath: string): Promise<void> {
|
public async makeShallowCopyAsync(
|
||||||
|
destinationPath: string,
|
||||||
|
options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
|
): Promise<void> {
|
||||||
const srcPath = getRootPath();
|
const srcPath = getRootPath();
|
||||||
await makeShallowCopyAsync(srcPath, destinationPath);
|
await makeShallowCopyAsync(srcPath, destinationPath, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async isFileIgnoredAsync(filePath: string): Promise<boolean> {
|
public override async isFileIgnoredAsync(
|
||||||
const ignore = new Ignore(getRootPath());
|
filePath: string,
|
||||||
|
options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
|
): Promise<boolean> {
|
||||||
|
const ignore = new Ignore(getRootPath(), options);
|
||||||
await ignore.initIgnoreAsync();
|
await ignore.initIgnoreAsync();
|
||||||
return ignore.ignores(filePath);
|
return ignore.ignores(filePath);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,16 +32,23 @@ export function getRootPath(): string {
|
|||||||
export class Ignore {
|
export class Ignore {
|
||||||
private ignoreMapping: (readonly [string, SingleFileIgnore])[] = [];
|
private ignoreMapping: (readonly [string, SingleFileIgnore])[] = [];
|
||||||
|
|
||||||
constructor(private rootDir: string) {}
|
constructor(
|
||||||
|
private readonly rootDir: string,
|
||||||
|
private readonly options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
|
) {}
|
||||||
|
|
||||||
public async initIgnoreAsync(): Promise<void> {
|
public async initIgnoreAsync(): Promise<void> {
|
||||||
const easIgnorePath = path.join(this.rootDir, EASIGNORE_FILENAME);
|
if (this.options.useEASIgnoreIfAvailableWhenEvaluatingFileIgnores) {
|
||||||
if (await fs.pathExists(easIgnorePath)) {
|
const easIgnorePath = path.join(this.rootDir, EASIGNORE_FILENAME);
|
||||||
this.ignoreMapping = [
|
if (await fs.pathExists(easIgnorePath)) {
|
||||||
['', createIgnore().add(DEFAULT_IGNORE)],
|
this.ignoreMapping = [
|
||||||
['', createIgnore().add(await fs.readFile(easIgnorePath, 'utf-8'))],
|
['', createIgnore().add(DEFAULT_IGNORE)],
|
||||||
];
|
['', createIgnore().add(await fs.readFile(easIgnorePath, 'utf-8'))],
|
||||||
return;
|
];
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const ignoreFilePaths = (
|
const ignoreFilePaths = (
|
||||||
await fg(`**/${GITIGNORE_FILENAME}`, {
|
await fg(`**/${GITIGNORE_FILENAME}`, {
|
||||||
@@ -74,8 +81,14 @@ export class Ignore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function makeShallowCopyAsync(src: string, dst: string): Promise<void> {
|
export async function makeShallowCopyAsync(
|
||||||
const ignore = new Ignore(src);
|
src: string,
|
||||||
|
dst: string,
|
||||||
|
options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
|
): Promise<void> {
|
||||||
|
const ignore = new Ignore(src, options);
|
||||||
await ignore.initIgnoreAsync();
|
await ignore.initIgnoreAsync();
|
||||||
await fs.copy(src, dst, {
|
await fs.copy(src, dst, {
|
||||||
filter: (srcFilePath: string) => {
|
filter: (srcFilePath: string) => {
|
||||||
|
|||||||
@@ -3,7 +3,12 @@ export abstract class Client {
|
|||||||
// destination, folder created this way will be uploaded "as is", so implementation should skip
|
// destination, folder created this way will be uploaded "as is", so implementation should skip
|
||||||
// anything that is not committed to the repository. Most optimal solution is to create shallow clone
|
// anything that is not committed to the repository. Most optimal solution is to create shallow clone
|
||||||
// using tooling provided by specific VCS, that respects all ignore rules
|
// using tooling provided by specific VCS, that respects all ignore rules
|
||||||
public abstract makeShallowCopyAsync(destinationPath: string): Promise<void>;
|
public abstract makeShallowCopyAsync(
|
||||||
|
destinationPath: string,
|
||||||
|
options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
// Find root of the repository.
|
// Find root of the repository.
|
||||||
//
|
//
|
||||||
@@ -75,7 +80,12 @@ export abstract class Client {
|
|||||||
//
|
//
|
||||||
// @param filePath has to be a relative normalized path pointing to a file
|
// @param filePath has to be a relative normalized path pointing to a file
|
||||||
// located under the root of the repository
|
// located under the root of the repository
|
||||||
public async isFileIgnoredAsync(_filePath: string): Promise<boolean> {
|
public async isFileIgnoredAsync(
|
||||||
|
_filePath: string,
|
||||||
|
_options: {
|
||||||
|
useEASIgnoreIfAvailableWhenEvaluatingFileIgnores: boolean;
|
||||||
|
}
|
||||||
|
): Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1470,7 +1470,7 @@
|
|||||||
joi "^17.11.0"
|
joi "^17.11.0"
|
||||||
semver "^7.5.4"
|
semver "^7.5.4"
|
||||||
|
|
||||||
"@expo/fingerprint@^0.6.0":
|
"@expo/[email protected]", "@expo/fingerprint@^0.6.0":
|
||||||
version "0.6.0"
|
version "0.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@expo/fingerprint/-/fingerprint-0.6.0.tgz#77366934673d4ecea37284109b4dd67f9e6a7487"
|
resolved "https://registry.yarnpkg.com/@expo/fingerprint/-/fingerprint-0.6.0.tgz#77366934673d4ecea37284109b4dd67f9e6a7487"
|
||||||
integrity sha512-KfpoVRTMwMNJ/Cf5o+Ou8M/Y0EGSTqK+rbi70M2Y0K2qgWNfMJ1gm6sYO9uc8lcTr7YSYM1Rme3dk7QXhpScNA==
|
integrity sha512-KfpoVRTMwMNJ/Cf5o+Ou8M/Y0EGSTqK+rbi70M2Y0K2qgWNfMJ1gm6sYO9uc8lcTr7YSYM1Rme3dk7QXhpScNA==
|
||||||
|
|||||||
Reference in new issue
Block a user