Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 72 additions & 48 deletions cli/src/tasks/migrate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { writeFileSync, readFileSync, existsSync } from 'fs-extra';
import { join } from 'path';
import rimraf from 'rimraf';
import { rimraf } from 'rimraf';
import { coerce, gte, lt } from 'semver';

import c from '../colors';
Expand Down Expand Up @@ -43,11 +43,10 @@ const plugins = [
'@capacitor/text-zoom',
'@capacitor/toast',
];
const coreVersion = '^8.0.0';
const pluginVersion = '^8.0.0';
const coreVersion = 'next';
const pluginVersion = 'next';
const gradleVersion = '9.5.1';
const iOSVersion = '16';
const kotlinVersion = '2.4.0';
let installFailed = false;

export async function migrateCommand(config: Config, noprompt: boolean, packagemanager: string): Promise<void> {
Expand All @@ -56,14 +55,14 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
}

const capMajor = await checkCapacitorMajorVersion(config);
if (capMajor < 7) {
fatal('Migrate can only be used on Capacitor 7, please use the CLI in Capacitor 7 to upgrade to 7 first');
if (capMajor < 8) {
fatal('Migrate can only be used on Capacitor 8, please use the CLI in Capacitor 8 to upgrade to 8 first');
}

const jdkMajor = await checkJDKMajorVersion();

if (jdkMajor < 21) {
logger.warn('Capacitor 8 requires JDK 21 or higher. Some steps may fail.');
logger.warn('Capacitor 9 requires JDK 21 or higher. Some steps may fail.');
}

const variablesAndClasspaths:
Expand All @@ -84,13 +83,13 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
};

const monorepoWarning =
'Please note this tool is not intended for use in a mono-repo environment, you should migrate manually instead. Refer to https://capacitorjs.com/docs/next/updating/8-0';
'Please note this tool is not intended for use in a mono-repo environment, you should migrate manually instead. Refer to https://capacitorjs.com/docs/next/updating/9-0';

logger.info(monorepoWarning);

const { migrateconfirm } = noprompt
? { migrateconfirm: 'y' }
: await logPrompt(`Capacitor 8 sets a deployment target of iOS ${iOSVersion} and Android 17 (SDK 37). \n`, {
: await logPrompt(`Capacitor 9 sets a deployment target of iOS ${iOSVersion} and Android 17 (SDK 37). \n`, {
type: 'text',
name: 'migrateconfirm',
message: `Are you sure you want to migrate? (Y/n)`,
Expand Down Expand Up @@ -175,6 +174,10 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
} else {
logger.warn('Skipped updating deployment target');
}

await runTask(`Migrating AppDelegate.swift`, () => {
return updateAppDelegate(join(config.ios.nativeTargetDirAbs, 'AppDelegate.swift'));
});
}

if (!installFailed) {
Expand Down Expand Up @@ -228,6 +231,23 @@ export async function migrateCommand(config: Config, noprompt: boolean, packagem
return updateAppBuildGradle(join(config.android.appDirAbs, 'build.gradle'));
});

// settings.gradle
await runTask(`Migrating settings.gradle file.`, () => {
return (async (): Promise<void> => {
const settingsPath = join(config.android.platformDirAbs, 'settings.gradle');
let txt = readFile(settingsPath);
if (!txt) {
return;
}
txt = txt.replace(`include ':capacitor-cordova-android-plugins'\n`, '');
txt = txt.replace(
`project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')\n`,
'',
);
writeFileSync(settingsPath, txt, { encoding: 'utf-8' });
})();
});

// Variables gradle
await runTask(`Migrating variables.gradle file.`, () => {
return (async (): Promise<void> => {
Expand Down Expand Up @@ -336,14 +356,23 @@ async function installLatestLibs(dependencyManager: string, runInstall: boolean,
for (const devDepKey of Object.keys(pkgJson['devDependencies'] || {})) {
if (libs.includes(devDepKey)) {
pkgJson['devDependencies'][devDepKey] = coreVersion;
} else if (plugins.includes(devDepKey)) {
} else if (
plugins.includes(devDepKey) &&
!(
pkgJson['devDependencies'][devDepKey].startsWith('file:') ||
pkgJson['devDependencies'][devDepKey].startsWith('workspace:')
)
) {
pkgJson['devDependencies'][devDepKey] = pluginVersion;
}
}
for (const depKey of Object.keys(pkgJson['dependencies'] || {})) {
if (libs.includes(depKey)) {
pkgJson['dependencies'][depKey] = coreVersion;
} else if (plugins.includes(depKey)) {
} else if (
plugins.includes(depKey) &&
!(pkgJson['dependencies'][depKey].startsWith('file:') || pkgJson['dependencies'][depKey].startsWith('workspace:'))
) {
pkgJson['dependencies'][depKey] = pluginVersion;
}
}
Expand All @@ -366,18 +395,7 @@ async function installLatestLibs(dependencyManager: string, runInstall: boolean,
}

async function writeBreakingChanges() {
const breaking = [
'@capacitor/action-sheet',
'@capacitor/barcode-scanner',
'@capacitor/browser',
'@capacitor/camera',
'@capacitor/geolocation',
'@capacitor/google-maps',
'@capacitor/push-notifications',
'@capacitor/screen-orientation',
'@capacitor/splash-screen',
'@capacitor/status-bar',
];
const breaking = ['@capacitor/push-notifications', '@capacitor/splash-screen'];
const broken = [];
for (const lib of breaking) {
if (allDependencies[lib]) {
Expand All @@ -386,7 +404,7 @@ async function writeBreakingChanges() {
}
if (broken.length > 0) {
logger.info(
`IMPORTANT: Review https://capacitorjs.com/docs/next/updating/8-0#plugins for breaking changes in these plugins that you use: ${broken.join(
`IMPORTANT: Review https://capacitorjs.com/docs/next/updating/9-0#plugins for breaking changes in these plugins that you use: ${broken.join(
', ',
)}.`,
);
Expand Down Expand Up @@ -492,40 +510,29 @@ async function updateBuildGradle(
}
}

const beforeKotlinVersionUpdate = replaced;
replaced = replaceVersion(replaced, /(ext\.kotlin_version\s*=\s*['"])([^'"]+)(['"])/, kotlinVersion);
replaced = replaceVersion(replaced, /(org\.jetbrains\.kotlin:kotlin[^:]*:)([\d.]+)(['"])/, kotlinVersion);
if (beforeKotlinVersionUpdate !== replaced) {
logger.info(`Set Kotlin version to ${kotlinVersion}`);
}
writeFileSync(filename, replaced, 'utf-8');
}

function replaceVersion(text: string, regex: RegExp, newVersion: string): string {
return text.replace(regex, (match, prefix, currentVersion, suffix) => {
const semVer = coerce(currentVersion)?.version;
if (gte(newVersion, semVer ? semVer : '0.0.0')) {
return `${prefix || ''}${newVersion}${suffix || ''}`;
}
return match;
});
}

async function updateAppBuildGradle(filename: string) {
const txt = readFile(filename);
if (!txt) {
return;
}
let replaced = txt;

const gradlePproperties = ['compileSdk', 'namespace', 'ignoreAssetsPattern'];
for (const prop of gradlePproperties) {
// Use updated Groovy DSL syntax with " = " assignment
const regex = new RegExp(`(^\\s*${prop})\\s+(?!=)(.+)$`, 'gm');
replaced = replaced.replace(regex, (_match, key, value) => {
return `${key} = ${value.trim()}`;
});
}
replaced = replaced.replace(`proguard-android.txt`, `proguard-android-optimize.txt`);
replaced = replaced.replace(' targetSdkVersion rootProject.ext.targetSdkVersion\n', '');
Comment thread
OS-pedrogustavobilro marked this conversation as resolved.
replaced = replaced.replace(` implementation project(':capacitor-cordova-android-plugins')\n`, '');
replaced = replaced.replace(
`repositories {
flatDir{
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
}
}

`,
'',
);
writeFileSync(filename, replaced, 'utf-8');
}

Expand Down Expand Up @@ -622,3 +629,20 @@ async function updateAndroidManifest(filename: string) {
writeFileSync(filename, replaced, 'utf-8');
}
}

async function updateAppDelegate(filename: string) {
const txt = readFile(filename);
if (!txt) {
return;
}

if (txt.includes('@main')) {
return; // Probably already updated
}
const replaced = txt.replace('@UIApplicationMain', '@main');
if (!replaced.includes('@main')) {
logger.error(`Unable to replace @UIApplicationMain to @main in ${filename}. Try replacing it manually`);
} else {
writeFileSync(filename, replaced, 'utf-8');
}
}
Loading