mirror of
https://github.com/selfxyz/self.git
synced 2026-01-09 14:48:06 -05:00
code rabbit feedback for staging auto deploy logic (#1255)
* code rabbit feedback for staging auto deploy logic * fix jest test * cr feedback * workflow fixes * fix tests * restore cache
This commit is contained in:
56
.github/workflows/mobile-deploy.yml
vendored
56
.github/workflows/mobile-deploy.yml
vendored
@@ -56,9 +56,7 @@ env:
|
||||
IOS_PROV_PROFILE_DIRECTORY: "~/Library/MobileDevice/Provisioning\ Profiles/"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
id-token: write
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -150,6 +148,8 @@ jobs:
|
||||
# NOTE: Checks out the triggering branch (staging for PR merges, or the branch where manually triggered)
|
||||
bump-version:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
if: |
|
||||
(github.event_name != 'pull_request' || github.event.pull_request.merged == true) &&
|
||||
!contains(github.event.pull_request.labels.*.name, 'deploy:skip')
|
||||
@@ -241,9 +241,26 @@ jobs:
|
||||
echo "✅ Version bump calculated successfully"
|
||||
echo "⚠️ Note: Changes are local only. Will be committed in PR after successful builds."
|
||||
|
||||
- name: Verify bump outputs were set
|
||||
run: |
|
||||
VERSION="${{ steps.bump.outputs.version }}"
|
||||
IOS_BUILD="${{ steps.bump.outputs.ios_build }}"
|
||||
ANDROID_BUILD="${{ steps.bump.outputs.android_build }}"
|
||||
|
||||
if [ -z "$VERSION" ] || [ -z "$IOS_BUILD" ] || [ -z "$ANDROID_BUILD" ]; then
|
||||
echo "❌ Version bump failed to set required outputs"
|
||||
echo "version='$VERSION', ios_build='$IOS_BUILD', android_build='$ANDROID_BUILD'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ All version outputs verified"
|
||||
|
||||
build-ios:
|
||||
needs: [bump-version]
|
||||
runs-on: macos-latest-large
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
if: |
|
||||
(github.event_name != 'pull_request' || github.event.pull_request.merged == true) &&
|
||||
(
|
||||
@@ -285,7 +302,7 @@ jobs:
|
||||
echo "NODE_VERSION_SANITIZED=${VERSION//\//-}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Verify branch and commit (iOS)
|
||||
if: inputs.platform != 'android'
|
||||
if: needs.bump-version.outputs.platform != 'android'
|
||||
run: |
|
||||
echo "🔍 Verifying we're building from the correct branch and commit..."
|
||||
echo "Current branch: $(git branch --show-current || git symbolic-ref --short HEAD 2>/dev/null || echo 'detached')"
|
||||
@@ -309,7 +326,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Apply version bump for build
|
||||
if: inputs.platform != 'android'
|
||||
if: needs.bump-version.outputs.platform != 'android'
|
||||
run: |
|
||||
cd ${{ env.APP_PATH }}
|
||||
|
||||
@@ -804,6 +821,10 @@ jobs:
|
||||
build-android:
|
||||
needs: [bump-version]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
id-token: write
|
||||
if: |
|
||||
(github.event_name != 'pull_request' || github.event.pull_request.merged == true) &&
|
||||
(
|
||||
@@ -910,7 +931,7 @@ jobs:
|
||||
echo "NODE_VERSION_SANITIZED=${VERSION//\//-}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Verify branch and commit (Android)
|
||||
if: inputs.platform != 'ios'
|
||||
if: needs.bump-version.outputs.platform != 'ios'
|
||||
run: |
|
||||
echo "🔍 Verifying we're building from the correct branch and commit..."
|
||||
echo "Current branch: $(git branch --show-current || git symbolic-ref --short HEAD 2>/dev/null || echo 'detached')"
|
||||
@@ -930,7 +951,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Apply version bump for build
|
||||
if: inputs.platform != 'ios'
|
||||
if: needs.bump-version.outputs.platform != 'ios'
|
||||
run: |
|
||||
cd ${{ env.APP_PATH }}
|
||||
|
||||
@@ -1234,6 +1255,9 @@ jobs:
|
||||
# but create the version bump PR to dev so it can be reviewed before merging to staging
|
||||
create-version-bump-pr:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
needs: [bump-version, build-ios, build-android]
|
||||
if: |
|
||||
always() &&
|
||||
@@ -1284,6 +1308,20 @@ jobs:
|
||||
|
||||
echo "✅ Versions applied successfully"
|
||||
|
||||
- name: Verify version changes
|
||||
run: |
|
||||
cd ${{ env.APP_PATH }}
|
||||
|
||||
# Check that version files actually changed
|
||||
if ! git diff --quiet package.json version.json; then
|
||||
echo "✅ Version changes detected"
|
||||
git diff package.json version.json
|
||||
else
|
||||
echo "⚠️ No version changes detected in package.json or version.json"
|
||||
echo "This may indicate a problem with version application"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Determine platforms that succeeded and PR title
|
||||
id: platforms
|
||||
run: |
|
||||
@@ -1383,6 +1421,9 @@ jobs:
|
||||
|
||||
# Create git tags after successful deployment
|
||||
create-release-tags:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
needs: [bump-version, build-ios, build-android, create-version-bump-pr]
|
||||
if: |
|
||||
always() &&
|
||||
@@ -1390,7 +1431,6 @@ jobs:
|
||||
needs.create-version-bump-pr.result == 'success' &&
|
||||
(needs.build-ios.result == 'success' || needs.build-android.result == 'success') &&
|
||||
(inputs.deployment_track == 'production')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
4
.github/workflows/release-calendar.yml
vendored
4
.github/workflows/release-calendar.yml
vendored
@@ -160,7 +160,7 @@ jobs:
|
||||
- name: Create dev to staging release PR
|
||||
if: ${{ steps.guard_schedule.outputs.continue == 'true' && steps.check_dev_staging.outputs.existing_pr == '' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_TOKEN: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
PR_DATE: ${{ steps.check_dev_staging.outputs.date }}
|
||||
BRANCH_NAME: ${{ steps.check_dev_staging.outputs.branch_name }}
|
||||
shell: bash
|
||||
@@ -328,7 +328,7 @@ jobs:
|
||||
- name: Create staging to main release PR
|
||||
if: ${{ steps.guard_schedule.outputs.continue == 'true' && steps.production_status.outputs.staging_not_ahead != 'true' && steps.production_status.outputs.existing_pr == '' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_TOKEN: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
PR_DATE: ${{ steps.production_status.outputs.date }}
|
||||
COMMITS_AHEAD: ${{ steps.production_status.outputs.commits }}
|
||||
shell: bash
|
||||
|
||||
@@ -49,12 +49,12 @@ ios_xcode_profile_path = "../ios/#{PROJECT_NAME}.xcodeproj"
|
||||
default_platform(:ios)
|
||||
|
||||
platform :ios do
|
||||
desc "Sync ios version"
|
||||
desc "Sync ios version (DEPRECATED)"
|
||||
lane :sync_version do
|
||||
increment_version_number(
|
||||
xcodeproj: "ios/#{PROJECT_NAME}.xcodeproj",
|
||||
version_number: package_version,
|
||||
)
|
||||
UI.error("⛔ This lane is deprecated!")
|
||||
UI.error("Version management is now centralized in CI.")
|
||||
UI.error("Use: node scripts/version-manager.cjs apply <version> <ios> <android>")
|
||||
UI.user_error!("sync_version lane is deprecated - use version-manager.cjs instead")
|
||||
end
|
||||
|
||||
desc "Push a new build to TestFlight Internal Testing"
|
||||
@@ -247,12 +247,12 @@ platform :ios do
|
||||
end
|
||||
|
||||
platform :android do
|
||||
desc "Sync android version"
|
||||
desc "Sync android version (DEPRECATED)"
|
||||
lane :sync_version do
|
||||
android_set_version_name(
|
||||
version_name: package_version,
|
||||
gradle_file: android_gradle_file_path.gsub("../", ""),
|
||||
)
|
||||
UI.error("⛔ This lane is deprecated!")
|
||||
UI.error("Version management is now centralized in CI.")
|
||||
UI.error("Use: node scripts/version-manager.cjs apply <version> <ios> <android>")
|
||||
UI.user_error!("sync_version lane is deprecated - use version-manager.cjs instead")
|
||||
end
|
||||
|
||||
desc "Push a new build to Google Play Internal Testing"
|
||||
|
||||
@@ -63,10 +63,26 @@ module Fastlane
|
||||
android_matches = android_build == expected_android_build
|
||||
|
||||
unless version_matches && ios_matches && android_matches
|
||||
UI.error("Version mismatch detected!")
|
||||
UI.error("❌ Version mismatch detected!")
|
||||
UI.error("Expected: v#{expected_version} (iOS: #{expected_ios_build}, Android: #{expected_android_build})")
|
||||
UI.error("Actual: v#{pkg_version} (iOS: #{ios_build}, Android: #{android_build})")
|
||||
UI.user_error!("Version mismatch! CI version-manager script should have set these correctly.")
|
||||
UI.error("")
|
||||
|
||||
# Add specific diagnostics
|
||||
UI.error("Mismatched fields:")
|
||||
UI.error(" • package.json version") unless version_matches
|
||||
UI.error(" • version.json iOS build") unless ios_matches
|
||||
UI.error(" • version.json Android build") unless android_matches
|
||||
UI.error("")
|
||||
|
||||
UI.error("💡 Common causes:")
|
||||
UI.error(" 1. version-manager.cjs 'apply' command didn't run in workflow")
|
||||
UI.error(" 2. Files were modified after version bump was applied")
|
||||
UI.error(" 3. CI_VERSION, CI_IOS_BUILD, or CI_ANDROID_BUILD env vars are incorrect")
|
||||
UI.error("")
|
||||
UI.error("🔍 Debug: Check workflow logs for 'Apply version bump' step")
|
||||
|
||||
UI.user_error!("Version verification failed")
|
||||
end
|
||||
|
||||
UI.success("✅ Version verification passed:")
|
||||
|
||||
@@ -4,12 +4,19 @@
|
||||
|
||||
module.exports = {
|
||||
preset: 'react-native',
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'cjs', 'json', 'node'],
|
||||
transformIgnorePatterns: [
|
||||
'node_modules/(?!(react-native|@react-native|@react-navigation|@react-native-community|@segment/analytics-react-native|@openpassport|react-native-keychain|react-native-check-version|react-native-nfc-manager|react-native-passport-reader|react-native-gesture-handler|uuid|@stablelib|@react-native-google-signin|react-native-cloud-storage|@react-native-clipboard|@react-native-firebase|@selfxyz|@sentry|@anon-aadhaar|react-native-svg|react-native-svg-circle-country-flags)/)',
|
||||
],
|
||||
setupFiles: ['<rootDir>/jest.setup.js'],
|
||||
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$',
|
||||
testMatch: [
|
||||
'<rootDir>/**/__tests__/**/*.{js,jsx,ts,tsx,cjs}',
|
||||
'<rootDir>/**/?(*.)+(spec|test).{js,jsx,ts,tsx,cjs}',
|
||||
],
|
||||
testPathIgnorePatterns: [
|
||||
'/node_modules/',
|
||||
'/scripts/tests/', // Node.js native test runner tests
|
||||
],
|
||||
moduleNameMapper: {
|
||||
'^@env$': '<rootDir>/tests/__setup__/@env.js',
|
||||
'\\.svg$': '<rootDir>/tests/__setup__/svgMock.js',
|
||||
|
||||
@@ -204,10 +204,33 @@ function bumpVersion(bumpType, platform = 'both') {
|
||||
* Apply version changes to files
|
||||
*/
|
||||
function applyVersions(version, iosBuild, androidBuild) {
|
||||
// Validate version format (semver X.Y.Z)
|
||||
if (
|
||||
!version ||
|
||||
typeof version !== 'string' ||
|
||||
!/^\d+\.\d+\.\d+$/.test(version)
|
||||
) {
|
||||
throw new Error(`Invalid version format: ${version}. Expected X.Y.Z`);
|
||||
}
|
||||
|
||||
// Validate and coerce build numbers
|
||||
const iosNum = Number(iosBuild);
|
||||
const androidNum = Number(androidBuild);
|
||||
|
||||
if (!Number.isInteger(iosNum) || iosNum < 1) {
|
||||
throw new Error(`Invalid iOS build: ${iosBuild}. Must be positive integer`);
|
||||
}
|
||||
|
||||
if (!Number.isInteger(androidNum) || androidNum < 1) {
|
||||
throw new Error(
|
||||
`Invalid Android build: ${androidBuild}. Must be positive integer`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`📝 Applying versions to files...`);
|
||||
console.log(` Version: ${version}`);
|
||||
console.log(` iOS Build: ${iosBuild}`);
|
||||
console.log(` Android Build: ${androidBuild}`);
|
||||
console.log(` iOS Build: ${iosNum}`);
|
||||
console.log(` Android Build: ${androidNum}`);
|
||||
|
||||
// Update package.json
|
||||
const pkg = readPackageJson();
|
||||
@@ -217,8 +240,8 @@ function applyVersions(version, iosBuild, androidBuild) {
|
||||
|
||||
// Update version.json
|
||||
const versionData = readVersionJson();
|
||||
versionData.ios.build = iosBuild;
|
||||
versionData.android.build = androidBuild;
|
||||
versionData.ios.build = iosNum;
|
||||
versionData.android.build = androidNum;
|
||||
writeVersionJson(versionData);
|
||||
console.log(`✅ Updated version.json`);
|
||||
}
|
||||
|
||||
316
app/scripts/version-manager.test.cjs
Normal file
316
app/scripts/version-manager.test.cjs
Normal file
@@ -0,0 +1,316 @@
|
||||
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
|
||||
|
||||
/**
|
||||
* @jest-environment node
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
* NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Unit tests for version-manager.cjs
|
||||
*
|
||||
* This file is only meant to be run with Jest.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
|
||||
// Mock file system operations - data
|
||||
const mockPackageJson = { version: '1.2.3' };
|
||||
const mockVersionJson = {
|
||||
ios: { build: 100, lastDeployed: '2024-01-01T00:00:00Z' },
|
||||
android: { build: 200, lastDeployed: '2024-01-01T00:00:00Z' },
|
||||
};
|
||||
|
||||
// Use manual mocking instead of jest.mock to avoid hoisting issues
|
||||
const fs = require('fs');
|
||||
|
||||
// Store originals for restore
|
||||
const originalReadFileSync = fs.readFileSync;
|
||||
const originalWriteFileSync = fs.writeFileSync;
|
||||
const originalExistsSync = fs.existsSync;
|
||||
const originalAppendFileSync = fs.appendFileSync;
|
||||
|
||||
// Setup mocks before importing the module
|
||||
function setupMocks() {
|
||||
fs.readFileSync = function (filePath, encoding) {
|
||||
if (filePath.includes('package.json')) {
|
||||
return JSON.stringify(mockPackageJson);
|
||||
}
|
||||
if (filePath.includes('version.json')) {
|
||||
return JSON.stringify(mockVersionJson);
|
||||
}
|
||||
return originalReadFileSync(filePath, encoding);
|
||||
};
|
||||
|
||||
fs.writeFileSync = function () {};
|
||||
fs.existsSync = function () {
|
||||
return true;
|
||||
};
|
||||
fs.appendFileSync = function () {};
|
||||
}
|
||||
|
||||
function restoreMocks() {
|
||||
fs.readFileSync = originalReadFileSync;
|
||||
fs.writeFileSync = originalWriteFileSync;
|
||||
fs.existsSync = originalExistsSync;
|
||||
fs.appendFileSync = originalAppendFileSync;
|
||||
}
|
||||
|
||||
// Setup mocks before requiring the module
|
||||
setupMocks();
|
||||
|
||||
// Import module after mocks are set up
|
||||
const versionManager = require('./version-manager.cjs');
|
||||
|
||||
describe('version-manager', () => {
|
||||
beforeEach(() => {
|
||||
// Reset mock data
|
||||
mockPackageJson.version = '1.2.3';
|
||||
mockVersionJson.ios.build = 100;
|
||||
mockVersionJson.android.build = 200;
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
restoreMocks();
|
||||
});
|
||||
|
||||
describe('getVersionInfo', () => {
|
||||
it('should return current version information', () => {
|
||||
const info = versionManager.getVersionInfo();
|
||||
expect(info.version).toBe('1.2.3');
|
||||
expect(info.iosBuild).toBe(100);
|
||||
expect(info.androidBuild).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bumpVersion', () => {
|
||||
it('should bump major version correctly', () => {
|
||||
const result = versionManager.bumpVersion('major', 'both');
|
||||
expect(result.version).toBe('2.0.0');
|
||||
expect(result.iosBuild).toBe(101);
|
||||
expect(result.androidBuild).toBe(201);
|
||||
});
|
||||
|
||||
it('should bump minor version correctly', () => {
|
||||
const result = versionManager.bumpVersion('minor', 'both');
|
||||
expect(result.version).toBe('1.3.0');
|
||||
expect(result.iosBuild).toBe(101);
|
||||
expect(result.androidBuild).toBe(201);
|
||||
});
|
||||
|
||||
it('should bump patch version correctly', () => {
|
||||
const result = versionManager.bumpVersion('patch', 'both');
|
||||
expect(result.version).toBe('1.2.4');
|
||||
expect(result.iosBuild).toBe(101);
|
||||
expect(result.androidBuild).toBe(201);
|
||||
});
|
||||
|
||||
it('should bump build numbers only', () => {
|
||||
const result = versionManager.bumpVersion('build', 'both');
|
||||
expect(result.version).toBe('1.2.3');
|
||||
expect(result.iosBuild).toBe(101);
|
||||
expect(result.androidBuild).toBe(201);
|
||||
});
|
||||
|
||||
it('should respect platform parameter (ios only)', () => {
|
||||
const result = versionManager.bumpVersion('build', 'ios');
|
||||
expect(result.version).toBe('1.2.3');
|
||||
expect(result.iosBuild).toBe(101);
|
||||
expect(result.androidBuild).toBe(200); // unchanged
|
||||
});
|
||||
|
||||
it('should respect platform parameter (android only)', () => {
|
||||
const result = versionManager.bumpVersion('build', 'android');
|
||||
expect(result.version).toBe('1.2.3');
|
||||
expect(result.iosBuild).toBe(100); // unchanged
|
||||
expect(result.androidBuild).toBe(201);
|
||||
});
|
||||
|
||||
it('should throw on invalid bump type', () => {
|
||||
expect(() => versionManager.bumpVersion('invalid', 'both')).toThrow(
|
||||
/Invalid bump type/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw on invalid platform', () => {
|
||||
expect(() => versionManager.bumpVersion('build', 'invalid')).toThrow(
|
||||
/Invalid platform/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle version with major bump resetting minor and patch', () => {
|
||||
mockPackageJson.version = '2.5.8';
|
||||
const result = versionManager.bumpVersion('major', 'both');
|
||||
expect(result.version).toBe('3.0.0');
|
||||
});
|
||||
|
||||
it('should handle version with minor bump resetting patch', () => {
|
||||
mockPackageJson.version = '2.5.8';
|
||||
const result = versionManager.bumpVersion('minor', 'both');
|
||||
expect(result.version).toBe('2.6.0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('applyVersions', () => {
|
||||
it('should reject invalid version format - not semver', () => {
|
||||
expect(() => versionManager.applyVersions('invalid', 1, 1)).toThrow(
|
||||
/Invalid version format/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid version format - two parts', () => {
|
||||
expect(() => versionManager.applyVersions('1.2', 1, 1)).toThrow(
|
||||
/Invalid version format/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid version format - four parts', () => {
|
||||
expect(() => versionManager.applyVersions('1.2.3.4', 1, 1)).toThrow(
|
||||
/Invalid version format/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid version format - empty string', () => {
|
||||
expect(() => versionManager.applyVersions('', 1, 1)).toThrow(
|
||||
/Invalid version format/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid version format - null', () => {
|
||||
expect(() => versionManager.applyVersions(null, 1, 1)).toThrow(
|
||||
/Invalid version format/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid iOS build number - zero', () => {
|
||||
expect(() => versionManager.applyVersions('1.2.3', 0, 1)).toThrow(
|
||||
/Invalid iOS build/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid iOS build number - negative', () => {
|
||||
expect(() => versionManager.applyVersions('1.2.3', -1, 1)).toThrow(
|
||||
/Invalid iOS build/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid iOS build number - non-numeric string', () => {
|
||||
expect(() => versionManager.applyVersions('1.2.3', 'abc', 1)).toThrow(
|
||||
/Invalid iOS build/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid iOS build number - float', () => {
|
||||
expect(() => versionManager.applyVersions('1.2.3', 1.5, 1)).toThrow(
|
||||
/Invalid iOS build/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid Android build number - zero', () => {
|
||||
expect(() => versionManager.applyVersions('1.2.3', 1, 0)).toThrow(
|
||||
/Invalid Android build/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid Android build number - negative', () => {
|
||||
expect(() => versionManager.applyVersions('1.2.3', 1, -1)).toThrow(
|
||||
/Invalid Android build/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid Android build number - non-numeric string', () => {
|
||||
expect(() => versionManager.applyVersions('1.2.3', 1, 'xyz')).toThrow(
|
||||
/Invalid Android build/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject invalid Android build number - float', () => {
|
||||
expect(() => versionManager.applyVersions('1.2.3', 1, 2.5)).toThrow(
|
||||
/Invalid Android build/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept string build numbers that parse to integers', () => {
|
||||
expect(() =>
|
||||
versionManager.applyVersions('1.2.3', '100', '200'),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it('should accept large build numbers', () => {
|
||||
expect(() =>
|
||||
versionManager.applyVersions('1.2.3', 99999, 88888),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it('should write correct values to files', () => {
|
||||
// Track write calls
|
||||
const writeCalls = [];
|
||||
fs.writeFileSync = function (filePath, content) {
|
||||
writeCalls.push({ filePath, content });
|
||||
};
|
||||
|
||||
versionManager.applyVersions('2.0.0', 150, 250);
|
||||
|
||||
// Verify writes occurred
|
||||
expect(writeCalls.length).toBe(2);
|
||||
|
||||
// Find and verify package.json write
|
||||
const packageWrite = writeCalls.find(call =>
|
||||
call.filePath.includes('package.json'),
|
||||
);
|
||||
expect(packageWrite).toBeDefined();
|
||||
const updatedPackage = JSON.parse(packageWrite.content);
|
||||
expect(updatedPackage.version).toBe('2.0.0');
|
||||
|
||||
// Find and verify version.json write
|
||||
const versionWrite = writeCalls.find(call =>
|
||||
call.filePath.includes('version.json'),
|
||||
);
|
||||
expect(versionWrite).toBeDefined();
|
||||
const updatedVersion = JSON.parse(versionWrite.content);
|
||||
expect(updatedVersion.ios.build).toBe(150);
|
||||
expect(updatedVersion.android.build).toBe(250);
|
||||
});
|
||||
});
|
||||
|
||||
describe('readPackageJson', () => {
|
||||
it('should read and parse package.json', () => {
|
||||
const pkg = versionManager.readPackageJson();
|
||||
expect(pkg.version).toBe('1.2.3');
|
||||
});
|
||||
|
||||
it('should throw error if file does not exist', () => {
|
||||
const originalExists = fs.existsSync;
|
||||
fs.existsSync = function () {
|
||||
return false;
|
||||
};
|
||||
expect(() => versionManager.readPackageJson()).toThrow(
|
||||
/package.json not found/,
|
||||
);
|
||||
fs.existsSync = originalExists;
|
||||
});
|
||||
});
|
||||
|
||||
describe('readVersionJson', () => {
|
||||
it('should read and parse version.json', () => {
|
||||
const version = versionManager.readVersionJson();
|
||||
expect(version.ios.build).toBe(100);
|
||||
expect(version.android.build).toBe(200);
|
||||
});
|
||||
|
||||
it('should throw error if file does not exist', () => {
|
||||
const originalExists = fs.existsSync;
|
||||
fs.existsSync = function () {
|
||||
return false;
|
||||
};
|
||||
expect(() => versionManager.readVersionJson()).toThrow(
|
||||
/version.json not found/,
|
||||
);
|
||||
fs.existsSync = originalExists;
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user