diff --git a/CHANGELOG.md b/CHANGELOG.md index be4a01b73d..1313a81e03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ This is the log of notable changes to EAS CLI and related packages. - Allow for installing custom `expo-cli` version on EAS Build. ([#409](https://github.com/expo/eas-cli/pull/409) by [@randomhajile](https://github.com/randomhajile)) - Support PKCS kesytores for Android. ([#398](https://github.com/expo/eas-cli/pull/398) by [@wkozyra95](https://github.com/wkozyra95)) - Support empty passwords in Android and iOS keystores. ([#398](https://github.com/expo/eas-cli/pull/398) by [@wkozyra95](https://github.com/wkozyra95)) +- Add more build metadata - `appBuildVersion`. ([#413](https://github.com/expo/eas-cli/pull/413) by [@dsokal](https://github.com/dsokal)) ### 🐛 Bug fixes diff --git a/packages/eas-cli/package.json b/packages/eas-cli/package.json index e40d3b079f..6f0286d941 100644 --- a/packages/eas-cli/package.json +++ b/packages/eas-cli/package.json @@ -13,7 +13,7 @@ "@expo/apple-utils": "0.0.0-alpha.20", "@expo/config": "3.3.19", "@expo/config-plugins": "1.0.31", - "@expo/eas-build-job": "0.2.33", + "@expo/eas-build-job": "0.2.35", "@expo/eas-json": "0.14.0", "@expo/json-file": "8.2.25", "@expo/pkcs12": "0.0.4", diff --git a/packages/eas-cli/src/build/android/__tests__/version-test.ts b/packages/eas-cli/src/build/android/__tests__/version-test.ts new file mode 100644 index 0000000000..64dda66fad --- /dev/null +++ b/packages/eas-cli/src/build/android/__tests__/version-test.ts @@ -0,0 +1,114 @@ +import { ExpoConfig } from '@expo/config'; +import fs from 'fs-extra'; +import { vol } from 'memfs'; +import os from 'os'; + +import { readVersionCode, readVersionName } from '../version'; + +jest.mock('fs'); + +afterAll(() => { + // do not remove the following line + // this fixes a weird error with tempy in @expo/image-utils + fs.removeSync(os.tmpdir()); +}); + +beforeEach(() => { + vol.reset(); + // do not remove the following line + // this fixes a weird error with tempy in @expo/image-utils + fs.mkdirpSync(os.tmpdir()); +}); + +describe(readVersionCode, () => { + describe('generic project', () => { + it('reads the version code from native code', () => { + const exp = initGenericProject(); + const versionCode = readVersionCode('/repo', exp); + expect(versionCode).toBe(123); + }); + }); + describe('managed project', () => { + it('reads the version code from expo config', () => { + const exp = initManagedProject(); + const versionCode = readVersionCode('/repo', exp); + expect(versionCode).toBe(123); + }); + }); +}); + +describe(readVersionName, () => { + describe('generic project', () => { + it('reads the version name from native code', () => { + const exp = initGenericProject(); + const versionName = readVersionName('/repo', exp); + expect(versionName).toBe('1.0'); + }); + }); + describe('managed project', () => { + it('reads the version from expo config', () => { + const exp = initManagedProject(); + const versionName = readVersionName('/repo', exp); + expect(versionName).toBe('1.0.0'); + }); + }); +}); + +function initGenericProject(): ExpoConfig { + vol.fromJSON( + { + './app.json': JSON.stringify({ + expo: { + version: '1.0.0', + android: { + versionCode: 1, + }, + }, + }), + './android/app/build.gradle': `android { + defaultConfig { + applicationId "com.expo.testapp" + versionCode 123 + versionName "1.0" + } +}`, + }, + '/repo' + ); + + const fakeExp: ExpoConfig = { + name: 'myproject', + slug: 'myproject', + version: '1.0.0', + android: { + versionCode: 123, + }, + }; + return fakeExp; +} + +function initManagedProject(): ExpoConfig { + vol.fromJSON( + { + './app.json': JSON.stringify({ + expo: { + version: '1.0.0', + android: { + versionCode: 123, + }, + }, + }), + }, + '/repo' + ); + + const fakeExp: ExpoConfig = { + name: 'myproject', + slug: 'myproject', + version: '1.0.0', + android: { + versionCode: 123, + }, + }; + return fakeExp; +} diff --git a/packages/eas-cli/src/build/android/version.ts b/packages/eas-cli/src/build/android/version.ts new file mode 100644 index 0000000000..7d5d8e8be4 --- /dev/null +++ b/packages/eas-cli/src/build/android/version.ts @@ -0,0 +1,44 @@ +import { ExpoConfig } from '@expo/config'; +import { AndroidConfig } from '@expo/config-plugins'; +import { Platform, Workflow } from '@expo/eas-build-job'; +import fs from 'fs-extra'; + +import { resolveWorkflow } from '../../project/workflow'; + +export function readVersionCode(projectDir: string, exp: ExpoConfig): number | undefined { + const workflow = resolveWorkflow(projectDir, Platform.ANDROID); + if (workflow === Workflow.GENERIC) { + const buildGradle = readBuildGradle(projectDir); + const matchResult = buildGradle?.match(/versionCode (.*)/); + if (matchResult) { + return Number(matchResult[1]); + } else { + return undefined; + } + } else { + return AndroidConfig.Version.getVersionCode(exp) ?? undefined; + } +} + +export function readVersionName(projectDir: string, exp: ExpoConfig): string | undefined { + const workflow = resolveWorkflow(projectDir, Platform.ANDROID); + if (workflow === Workflow.GENERIC) { + const buildGradle = readBuildGradle(projectDir); + const matchResult = buildGradle?.match(/versionName ["'](.*)["']/); + if (matchResult) { + return matchResult[1]; + } else { + return undefined; + } + } else { + return exp.version; + } +} + +function readBuildGradle(projectDir: string): string | undefined { + const buildGradlePath = AndroidConfig.Paths.getAppBuildGradle(projectDir); + if (!fs.pathExistsSync(buildGradlePath)) { + return undefined; + } + return fs.readFileSync(buildGradlePath, 'utf8'); +} diff --git a/packages/eas-cli/src/build/ios/__tests__/version-test.ts b/packages/eas-cli/src/build/ios/__tests__/version-test.ts index 570d3284c5..c8ae364249 100644 --- a/packages/eas-cli/src/build/ios/__tests__/version-test.ts +++ b/packages/eas-cli/src/build/ios/__tests__/version-test.ts @@ -5,7 +5,13 @@ import { vol } from 'memfs'; import os from 'os'; import { readPlistAsync } from '../plist'; -import { BumpStrategy, bumpVersionAsync, bumpVersionInAppJsonAsync } from '../version'; +import { + BumpStrategy, + bumpVersionAsync, + bumpVersionInAppJsonAsync, + readBuildNumberAsync, + readShortVersionAsync, +} from '../version'; jest.mock('fs'); @@ -144,6 +150,42 @@ describe(bumpVersionInAppJsonAsync, () => { }); }); +describe(readBuildNumberAsync, () => { + describe('generic project', () => { + it('reads the build number from native code', async () => { + const exp = initGenericProject(); + const buildNumber = await readBuildNumberAsync('/repo', exp); + expect(buildNumber).toBe('1'); + }); + }); + + describe('managed project', () => { + it('reads the build number from expo config', async () => { + const exp = initManagedProject(); + const buildNumber = await readBuildNumberAsync('/repo', exp); + expect(buildNumber).toBe('1'); + }); + }); +}); + +describe(readShortVersionAsync, () => { + describe('generic project', () => { + it('reads the short version from native code', async () => { + const exp = initGenericProject(); + const shortVersion = await readShortVersionAsync('/repo', exp); + expect(shortVersion).toBe('1.0.0'); + }); + }); + + describe('managed project', () => { + it('reads the version from app config', async () => { + const exp = initGenericProject(); + const shortVersion = await readShortVersionAsync('/repo', exp); + expect(shortVersion).toBe('1.0.0'); + }); + }); +}); + function initGenericProject(): ExpoConfig { vol.fromJSON( { diff --git a/packages/eas-cli/src/build/ios/version.ts b/packages/eas-cli/src/build/ios/version.ts index 3a4e6ca10e..aad70e89a2 100644 --- a/packages/eas-cli/src/build/ios/version.ts +++ b/packages/eas-cli/src/build/ios/version.ts @@ -1,10 +1,12 @@ import { ExpoConfig, getConfigFilePaths } from '@expo/config'; import { IOSConfig } from '@expo/config-plugins'; +import { Platform, Workflow } from '@expo/eas-build-job'; import chalk from 'chalk'; import nullthrows from 'nullthrows'; import semver from 'semver'; import Log from '../../log'; +import { resolveWorkflow } from '../../project/workflow'; import { promptAsync } from '../../prompts'; import { updateAppJsonConfigAsync } from '../utils/appJson'; import { readPlistAsync, writePlistAsync } from './plist'; @@ -100,9 +102,30 @@ export async function bumpVersionInAppJsonAsync({ } } -async function readInfoPlistAsync(projectDir: string): Promise { - const infoPlistPath = IOSConfig.Paths.getInfoPlistPath(projectDir); - return (await readPlistAsync(infoPlistPath)) as IOSConfig.InfoPlist; +export async function readShortVersionAsync( + projectDir: string, + exp: ExpoConfig +): Promise { + const workflow = resolveWorkflow(projectDir, Platform.IOS); + if (workflow === Workflow.GENERIC) { + const infoPlist = await readInfoPlistAsync(projectDir); + return infoPlist.CFBundleShortVersionString; + } else { + return exp.version; + } +} + +export async function readBuildNumberAsync( + projectDir: string, + exp: ExpoConfig +): Promise { + const workflow = resolveWorkflow(projectDir, Platform.IOS); + if (workflow === Workflow.GENERIC) { + const infoPlist = await readInfoPlistAsync(projectDir); + return infoPlist.CFBundleVersion; + } else { + return IOSConfig.Version.getBuildNumber(exp); + } } async function writeVersionsToInfoPlistAsync({ @@ -120,6 +143,11 @@ async function writeVersionsToInfoPlistAsync({ return updatedInfoPlist; } +async function readInfoPlistAsync(projectDir: string): Promise { + const infoPlistPath = IOSConfig.Paths.getInfoPlistPath(projectDir); + return (await readPlistAsync(infoPlistPath)) as IOSConfig.InfoPlist; +} + async function writeInfoPlistAsync({ projectDir, infoPlist, diff --git a/packages/eas-cli/src/build/metadata.ts b/packages/eas-cli/src/build/metadata.ts index add0da4ff2..69babb3779 100644 --- a/packages/eas-cli/src/build/metadata.ts +++ b/packages/eas-cli/src/build/metadata.ts @@ -7,8 +7,10 @@ import { getUsername } from '../project/projectUtils'; import { ensureLoggedInAsync } from '../user/actions'; import { gitCommitHashAsync } from '../utils/git'; import { readReleaseChannelSafelyAsync as readAndroidReleaseChannelSafelyAsync } from './android/UpdatesModule'; +import { readVersionCode, readVersionName } from './android/version'; import { BuildContext } from './context'; import { readReleaseChannelSafelyAsync as readIosReleaseChannelSafelyAsync } from './ios/UpdatesModule'; +import { readBuildNumberAsync, readShortVersionAsync } from './ios/version'; import { Platform } from './types'; import { isExpoUpdatesInstalled } from './utils/updates'; @@ -27,13 +29,10 @@ export async function collectMetadata( credentialsSource?: CredentialsSource.LOCAL | CredentialsSource.REMOTE; } ): Promise { - const appIdentifier = - ctx.platform === Platform.IOS - ? getBundleIdentifier(ctx.commandCtx.projectDir, ctx.commandCtx.exp) - : getApplicationId(ctx.commandCtx.projectDir, ctx.commandCtx.exp); return { trackingContext: ctx.trackingCtx, - appVersion: ctx.commandCtx.exp.version!, + appVersion: await resolveAppVersionAsync(ctx), + appBuildVersion: await resolveAppBuildVersionAsync(ctx), cliVersion: packageJSON.version, workflow: ctx.buildProfile.workflow, credentialsSource, @@ -41,13 +40,42 @@ export async function collectMetadata( releaseChannel: await resolveReleaseChannel(ctx), distribution: ctx.buildProfile.distribution ?? 'store', appName: ctx.commandCtx.exp.name, - appIdentifier, + appIdentifier: resolveAppIdentifier(ctx), buildProfile: ctx.commandCtx.profile, gitCommitHash: await gitCommitHashAsync(), username: getUsername(ctx.commandCtx.exp, await ensureLoggedInAsync()), }; } +async function resolveAppVersionAsync( + ctx: BuildContext +): Promise { + if (ctx.platform === Platform.IOS) { + return await readShortVersionAsync(ctx.commandCtx.projectDir, ctx.commandCtx.exp); + } else { + return readVersionName(ctx.commandCtx.projectDir, ctx.commandCtx.exp); + } +} + +async function resolveAppBuildVersionAsync( + ctx: BuildContext +): Promise { + if (ctx.platform === Platform.IOS) { + return await readBuildNumberAsync(ctx.commandCtx.projectDir, ctx.commandCtx.exp); + } else { + const versionCode = readVersionCode(ctx.commandCtx.projectDir, ctx.commandCtx.exp); + return versionCode !== undefined ? String(versionCode) : undefined; + } +} + +function resolveAppIdentifier(ctx: BuildContext): string { + if (ctx.platform === Platform.IOS) { + return getBundleIdentifier(ctx.commandCtx.projectDir, ctx.commandCtx.exp); + } else { + return getApplicationId(ctx.commandCtx.projectDir, ctx.commandCtx.exp); + } +} + async function resolveReleaseChannel( ctx: BuildContext ): Promise { diff --git a/packages/eas-cli/src/build/utils/appJson.ts b/packages/eas-cli/src/build/utils/appJson.ts index beec346c19..98dae7915b 100644 --- a/packages/eas-cli/src/build/utils/appJson.ts +++ b/packages/eas-cli/src/build/utils/appJson.ts @@ -1,4 +1,3 @@ -// import { ExpoConfig, getConfigFilePaths } from '@expo/config'; import * as ExpoConfig from '@expo/config'; import assert from 'assert'; import fs from 'fs-extra'; diff --git a/packages/eas-json/package.json b/packages/eas-json/package.json index 2460f9d973..8f02ca8f25 100644 --- a/packages/eas-json/package.json +++ b/packages/eas-json/package.json @@ -5,7 +5,7 @@ "author": "Expo ", "bugs": "https://github.com/expo/eas-cli/issues", "dependencies": { - "@expo/eas-build-job": "0.2.33", + "@expo/eas-build-job": "0.2.35", "@hapi/joi": "17.1.1", "fs-extra": "9.0.1", "tslib": "1.14.1" diff --git a/yarn.lock b/yarn.lock index 08e2c3c052..27174f7db0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1181,10 +1181,10 @@ xcode "^3.0.0" xml-js "^1.6.11" -"@expo/eas-build-job@0.2.33": - version "0.2.33" - resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-0.2.33.tgz#fef76ad0acce6cdd828ddc22945184024df05fad" - integrity sha512-OB/ytNkNHI9wydOrhVTrP2XjT0AUzn038eEG4U0QYif2fs1nXUBd6gHM3YNiQjdJtTSXjGpvgBDfNPLIgJHlOQ== +"@expo/eas-build-job@0.2.35": + version "0.2.35" + resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-0.2.35.tgz#4e64ebe1314d0af0f33d3922b15d9e3fe415378e" + integrity sha512-+R24ZbZSgC1rLm83pOIUJ8pk2e9e/V6nJBrdl/jLWaCE1YPp1N/Elh8R6x1QuqYyXGOm2AG6r++MGItg9KmggA== dependencies: "@hapi/joi" "^17.1.1"