Skip to content

Commit

Permalink
feat: avoid clashes when generating pre-release version numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandermendes committed Feb 14, 2024
1 parent f06b117 commit 33e612c
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 26 deletions.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,16 +213,16 @@ as the `vesionName`, so this is what we do.

### iOS

For iOS, the [`CFBundleShortVersionString`](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring) and [`CFBundleVersion`](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleversion) do not support pre-release versions. Because of this
we do not append any pre-release identifiers for iOS.

For iOS apps, build numbers must be unique within each release train, which may cause issues if
you push a pre-release to TestFlight with a given build number then merge your work and try to
push again with the same build number. However, build numbers
**do not need to be unique across different release trains**. Therefore, the recommended
way of handling your pre-release builds is to create a separate release train for your
pre-release builds. See the iOS docs on (Version Numbers and Build Numbers
)[https://developer.apple.com/library/archive/technotes/tn2420/_index.html] for more details.
For iOS, the [`CFBundleShortVersionString`](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring) and [`CFBundleVersion`](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleversion) do not support pre-release versions.

To get around this limitation for pre-releases we generate a patch version by multiplying
the current patch by 10,000 and adding the pre-release version. For example, if the
current version is `1.1.1` and the next release version is `1.2.2-beta.42`
resulting iOS version and build number will be `1.1.20042`. This should help
avoid clashes that may otherwise happen if you are pushing pre-releases to TestFlight.

Note that this feature only works when using the `strict` versioning strategy
for iOS (which is the default).

## Xcode project files

Expand Down
14 changes: 11 additions & 3 deletions src/version/ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const getIosPath = (iosPath?: string) => {
/**
* Get the bundle version for iOS using the strict strategy.
*/
const getIosStrictBundleVersion = (currentBundleVersion: string) => {
const getIosStrictBundleVersion = (currentBundleVersion: string, version: string) => {
const [majorStr, minorStr, patchStr] = currentBundleVersion.split('.');
let major = parseInt(majorStr ?? 0, 10);
let minor = parseInt(minorStr ?? 0, 10);
Expand Down Expand Up @@ -63,7 +63,15 @@ const getIosStrictBundleVersion = (currentBundleVersion: string) => {
patch += 1;
}

return `${major}.${minor}.${patch}`;
const [, preReleaseLabel] = version.split('-');

if (!preReleaseLabel) {
return `${major}.${minor}.${patch}`;
}

const preReleaseVersion = parseInt(preReleaseLabel.split('.')[1] ?? 1, 10);

return `${major}.${minor}.${(patch * 10000) + preReleaseVersion}`;
};

/**
Expand Down Expand Up @@ -99,7 +107,7 @@ const getIosBundleVersion = (
return String(major + 1);
}

return getIosStrictBundleVersion(currentBundleVersion);
return getIosStrictBundleVersion(currentBundleVersion, version);
};

/**
Expand Down
26 changes: 13 additions & 13 deletions tests/prepare.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -688,16 +688,16 @@ describe('prepare', () => {
);

it.each`
version | previousBundleVersion
${'1.2.3-alpha.1'} | ${'1.1.1'}
${'1.2.3-beta.3'} | ${'1.1.1'}
${'1.2.3-feature.42'} | ${'1.1.1'}
${'1.2.3-hello.12'} | ${'1.1.1'}
${'1.2.3-alpha.2'} | ${'1.1.1a1'}
${'1.2.3-beta.1'} | ${'1.1.1a1'}
version | previousBundleVersion | expectedBundleVersion
${'1.2.2-alpha.1'} | ${'1.1.1'} | ${'1.1.20001'}
${'1.2.2-beta.3'} | ${'1.1.1'} | ${'1.1.20003'}
${'1.2.2-feature.42'} | ${'1.1.1'} | ${'1.1.20042'}
${'1.2.2-hello.12'} | ${'1.1.1'} | ${'1.1.20012'}
${'1.2.2-alpha.2'} | ${'1.1.1a1'} | ${'1.1.20002'}
${'1.2.2-beta.1'} | ${'1.1.1a1'} | ${'1.1.20001'}
`(
'sets the bundle version to 1.1.2 for version $version',
async ({ version, previousBundleVersion }) => {
'sets the bundle version to $expectedBundleVersion for version $version',
async ({ version, previousBundleVersion, expectedBundleVersion }) => {
const context = createContext({ version });

(plist.parse as jest.Mock).mockReturnValue({
Expand All @@ -714,15 +714,15 @@ describe('prepare', () => {

expect(plist.build).toHaveBeenCalledTimes(1);
expect(plist.build).toHaveBeenCalledWith({
CFBundleShortVersionString: '1.2.3',
CFBundleVersion: '1.1.2',
CFBundleShortVersionString: version.split('-')[0],
CFBundleVersion: expectedBundleVersion,
});

expect(buildConfig.patch).toHaveBeenCalledTimes(1);
expect(buildConfig.patch).toHaveBeenCalledWith({
buildSettings: {
CURRENT_PROJECT_VERSION: '1.1.2',
MARKETING_VERSION: '1.2.3',
CURRENT_PROJECT_VERSION: expectedBundleVersion,
MARKETING_VERSION: version.split('-')[0],
},
});
},
Expand Down

0 comments on commit 33e612c

Please sign in to comment.