Skip to content

Commit 6d70ed5

Browse files
author
Murat
committed
feat(upgrade): added restoring backup files
1 parent 16344bf commit 6d70ed5

34 files changed

+315
-76
lines changed

src/__tests__/unit/upgrade.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ const mockParseConfig = jest.spyOn(
1010
require('../../utils/parseConfig'),
1111
'parseConfig'
1212
);
13+
const mockRestoreBackupFiles = jest.spyOn(
14+
require('../../utils/upgrade/restoreBackupFiles'),
15+
'restoreBackupFiles'
16+
);
1317

1418
import { Constants } from '../../constants';
1519
import { upgrade } from '../../upgrade';
@@ -26,6 +30,26 @@ describe('upgrade', () => {
2630
expect.stringContaining('skipping import from old project')
2731
);
2832
});
33+
it('should restore files', async () => {
34+
mockPrompter.text.mockImplementationOnce(() => '');
35+
mockRestoreBackupFiles.mockReturnValueOnce(Promise.resolve(true));
36+
37+
await upgrade();
38+
39+
expect(mockPrompter.log.message).toHaveBeenCalledWith(
40+
expect.stringContaining('skipping import from old project')
41+
);
42+
});
43+
it('should handle restore error', async () => {
44+
mockPrompter.text.mockImplementationOnce(() => '');
45+
mockRestoreBackupFiles.mockRejectedValueOnce(new Error('test'));
46+
47+
await upgrade();
48+
49+
expect(mockPrompter.log.message).toHaveBeenCalledWith(
50+
expect.stringContaining('skipping import from old project')
51+
);
52+
});
2953
it('should not run tasks when lock does not exist', async () => {
3054
const spinner = mockPrompter.spinner();
3155
spinner.stop.mockReset();
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
require('../../../mocks/mockAll');
2+
import path from 'path';
3+
import { getProjectPath } from '../../../../utils/getProjectPath';
4+
import { restoreBackupFiles } from '../../../../utils/upgrade/restoreBackupFiles';
5+
import { mockFs } from '../../../mocks/mockFs';
6+
7+
describe('restoreBackupFiles', () => {
8+
it('should restore backup files in .upgrade', async () => {
9+
mockFs.writeFileSync(
10+
path.join(getProjectPath(), '.upgrade/backup/test/some.file'),
11+
'random'
12+
);
13+
14+
const didRestore = await restoreBackupFiles();
15+
16+
expect(didRestore).toBeTruthy();
17+
expect(
18+
mockFs.readFileSync(path.join(getProjectPath(), 'test/some.file'))
19+
).toEqual('random');
20+
});
21+
it('should handle not finding backup files', async () => {
22+
const didRestore = await restoreBackupFiles();
23+
24+
expect(didRestore).toBeFalsy();
25+
});
26+
it('should handle copy error', async () => {
27+
mockFs.writeFileSync(
28+
path.join(getProjectPath(), '.upgrade/backup/test/some.file'),
29+
'random'
30+
);
31+
mockFs.copyFile.mockImplementationOnce(
32+
(from: string, to: string, cb: CallableFunction) => {
33+
cb(new Error('random'));
34+
}
35+
);
36+
await expect(restoreBackupFiles()).rejects.toThrow('random');
37+
});
38+
});

src/upgrade.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { taskManager } from './utils/taskManager';
2323
import { topologicalSort } from './utils/topologicalSort';
2424
import { updateIntegrationStatus } from './utils/updateIntegrationStatus';
2525
import { importFromOldProject } from './utils/upgrade/importFromOldProject';
26+
import { restoreBackupFiles } from './utils/upgrade/restoreBackupFiles';
2627
import { validateOldProjectPath } from './utils/upgrade/validateOldProjectPath';
2728
import { getText, transformTextInObject, variables } from './variables';
2829

@@ -310,4 +311,19 @@ export async function upgrade(): Promise<void> {
310311
}
311312

312313
updateIntegrationStatus(packageLockUpdates);
314+
315+
logInfo(
316+
color.bold(color.inverse(color.magenta(' stage 3 '))) +
317+
color.bold(color.magenta(' Restore backup files '))
318+
);
319+
320+
const didRestore = await restoreBackupFiles().catch((e: Error) => {
321+
logWarning(e.message);
322+
});
323+
if (didRestore) {
324+
logSuccess(
325+
color.inverse(color.bold(color.green(' restored '))) +
326+
color.green(' backup files were restored successfully')
327+
);
328+
}
313329
}

src/utils/upgrade/android/importAndroidLaunchIcon.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export function importAndroidLaunchIcon(
1111
): ImportGetter | null {
1212
try {
1313
const mipmaps = globSync(
14-
path.join(projectPath, 'android/app/src/main/res/mipmap-*/*'),
14+
[projectPath, 'android/app/src/main/res/mipmap-*/*'].join('/'),
1515
{ nodir: true }
1616
);
1717
// get launcher icon and launcher round icon name from AndroidManifest.xml

src/utils/upgrade/ios/importIosAssets.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ export function importIosAssets(projectPath: string): ImportGetter | null {
1212
const iosProjectName = getIosProjectName(projectPath);
1313

1414
const imagesAssets = globSync(
15-
path.join(projectPath, 'ios', iosProjectName, 'Images.xcassets/**/*'),
15+
[projectPath, 'ios', iosProjectName, 'Images.xcassets/**/*'].join('/'),
1616
{ nodir: true }
1717
);
1818
const launchScreen = globSync(
19-
path.join(projectPath, 'ios', iosProjectName, 'LaunchScreen.storyboard'),
19+
[projectPath, 'ios', iosProjectName, 'LaunchScreen.storyboard'].join('/'),
2020
{ nodir: true }
2121
);
2222

@@ -36,7 +36,7 @@ export function importIosAssets(projectPath: string): ImportGetter | null {
3636
async function setIosAssets(assets: string[], launchScreen: string) {
3737
const iosProjectName = getIosProjectName();
3838
const existingAssets = globSync(
39-
path.join(getProjectPath(), 'ios', iosProjectName, 'Images.xcassets/**/*'),
39+
[getProjectPath(), 'ios', iosProjectName, 'Images.xcassets/**/*'].join('/'),
4040
{ nodir: true }
4141
);
4242
// delete existing image assets
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import fs from 'fs';
2+
import { globSync } from 'glob';
3+
import path from 'path';
4+
import color from 'picocolors';
5+
import { Constants } from '../../constants';
6+
import {
7+
logMessageGray,
8+
startSpinner,
9+
stopSpinner,
10+
updateSpinner,
11+
} from '../../prompter';
12+
import { getProjectPath } from '../getProjectPath';
13+
14+
export async function restoreBackupFiles(): Promise<boolean> {
15+
const backupFiles = globSync(
16+
[getProjectPath(), Constants.UPGRADE_FOLDER_NAME, 'backup', '**/*'].join(
17+
'/'
18+
),
19+
{ nodir: true }
20+
);
21+
if (backupFiles.length === 0) {
22+
logMessageGray('skipped restore, no backup files found');
23+
return false;
24+
}
25+
26+
startSpinner(`copying files from ${color.yellow('.upgrade/backup')}`);
27+
28+
for (let i = 0; i < backupFiles.length; i++) {
29+
updateSpinner(
30+
`copying files from ${color.yellow('.upgrade/backup')} (${i + 1}/${backupFiles.length})`
31+
);
32+
const file = backupFiles[i];
33+
const relativePath = path.relative(
34+
path.join(getProjectPath(), Constants.UPGRADE_FOLDER_NAME, 'backup'),
35+
file
36+
);
37+
const destination = path.join(getProjectPath(), relativePath);
38+
// ensure dir exists
39+
await new Promise(r =>
40+
fs.mkdir(path.dirname(destination), { recursive: true }, r)
41+
);
42+
await new Promise((res, rej) => {
43+
fs.copyFile(file, destination, err => {
44+
if (err) rej(err);
45+
else res(null);
46+
});
47+
});
48+
}
49+
stopSpinner(`copied ${color.yellow(backupFiles.length)} files`);
50+
return true;
51+
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
22
"label": "Guides",
3-
"position": 2
3+
"position": 2,
4+
"link": {
5+
"type": "generated-index",
6+
"description": "Configuration guides"
7+
}
48
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"label": "Task Types",
3+
"position": 4,
4+
"link": {
5+
"type": "generated-index",
6+
"description": "All possible task types that can be defined in configuration."
7+
}
8+
}
File renamed without changes.

website/docs/for-developers/android-tasks/android-manifest.md renamed to website/docs/for-developers/guides/task-types/android-tasks/android-manifest.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ The `android_manifest` task allows you to modify the AndroidManifest.xml file in
1212
| Property | Type | Description |
1313
|:---------|:------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
1414
| type | "android_manifest", required | Specifies the task type, which should be set to "android_manifest" for this task. |
15-
| name | string | An optional name for the task. If provided, the task state will be saved as a variable. Visit [Task and Action States](../guides/states) page to learn more. |
15+
| name | string | An optional name for the task. If provided, the task state will be saved as a variable. Visit [Task and Action States](../../states) page to learn more. |
1616
| label | string | An optional label or description for the task. |
17-
| when | object | Visit [Conditional Tasks and Actions](../guides/when) page to learn how to execute task conditionally. |
17+
| when | object | Visit [Conditional Tasks and Actions](../../when) page to learn how to execute task conditionally. |
1818
| actions | Array\<[Action](#action-properties)\>, required | An array of action items that define the modifications to be made in the file. Each action item contains the following fields: |
1919

2020
## Action Properties
@@ -23,8 +23,8 @@ The `android_manifest` task allows you to modify the AndroidManifest.xml file in
2323

2424
| Property | Type | Description |
2525
|:-----------|:-------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
26-
| name | string | An optional name for the task. If provided, the task state will be saved as a variable. Visit [Task and Action States](../guides/states) page to learn more. |
27-
| when | object | Visit [Conditional Tasks and Actions](../guides/when) page to learn how to execute action conditionally. |
26+
| name | string | An optional name for the task. If provided, the task state will be saved as a variable. Visit [Task and Action States](../../states) page to learn more. |
27+
| when | object | Visit [Conditional Tasks and Actions](../../when) page to learn how to execute action conditionally. |
2828

2929
### Context reduction properties
3030

0 commit comments

Comments
 (0)