Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
10 changes: 4 additions & 6 deletions messages/convert.source-behavior.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,13 @@ Your project has a default org (target-org) that uses source tracking. This oper
- Run this command again.
- Create a new org ("sf org create scratch" or "sf org create sandbox") and deploy the modified source.

# error.packageDirectoryNeedsMainDefault
# mainDefaultConfirmation

The package directory %s doesn't have a main/default structure.
This command moves metadata into a main/default structure, but your package directories aren't ready for it.
- This command will put components in a newly created `main/default` folder in each package directory. You might need to re-organize them into your preferred structure.

# error.packageDirectoryNeedsMainDefault.actions
# basicConfirmation

- Update %s to have all its metadata inside a main/default directory structure.
- Run the command again.
- This command will make changes to your project. Be sure you've committed any source changes before continuing so you can easily revert if necessary.

# success.dryRun

Expand Down
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
"author": "Salesforce",
"bugs": "https://github.com/forcedotcom/cli/issues",
"dependencies": {
"@oclif/core": "^4.0.12",
"@salesforce/apex-node": "^8.1.1",
"@salesforce/core": "^8.2.8",
"@salesforce/kit": "^3.1.6",
"@oclif/core": "^4.0.17",
"@salesforce/apex-node": "^8.1.3",
"@salesforce/core": "^8.3.0",
"@salesforce/kit": "^3.2.1",
"@salesforce/plugin-info": "^3.3.24",
"@salesforce/sf-plugins-core": "^11.3.0",
"@salesforce/source-deploy-retrieve": "^12.1.11",
"@salesforce/source-tracking": "^7.1.2",
"@salesforce/sf-plugins-core": "^11.3.2",
"@salesforce/source-deploy-retrieve": "^12.2.1",
"@salesforce/source-tracking": "^7.1.5",
"@salesforce/ts-types": "^2.0.12",
"ansis": "^3.3.2"
},
Expand Down
23 changes: 22 additions & 1 deletion src/commands/project/convert/source-behavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
*/

import { rm, readFile, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { existsSync } from 'node:fs';
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { Messages } from '@salesforce/core';
import { Messages, SfProject } from '@salesforce/core';
import {
getValidatedProjectJson,
TMP_DIR,
Expand All @@ -17,6 +19,7 @@ import {
PRESET_CHOICES,
getPackageDirectoriesForPreset,
convertBackToSource,
ComponentSetAndPackageDirPath,
} from '../../../utils/convertBehavior.js';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
Expand Down Expand Up @@ -61,6 +64,13 @@ export default class ConvertSourceBehavior extends SfCommand<SourceBehaviorResul
flags['dry-run'] ? readFile(projectJson.getPath()) : '',
getPackageDirectoriesForPreset(this.project!, flags.behavior),
]);

this.warn(messages.getMessage('basicConfirmation'));
if (!packageDirsWithDecomposable.every(hasMainDefault(this.project!.getPath()))) {
this.warn(messages.getMessage('mainDefaultConfirmation'));
}
await this.confirm({ message: 'Proceed' });

const filesToDelete = await convertToMdapi(packageDirsWithDecomposable);

// flip the preset in the sfdx-project.json, even for dry-run, since the registry will need for conversions
Expand All @@ -71,6 +81,10 @@ export default class ConvertSourceBehavior extends SfCommand<SourceBehaviorResul
// delete the “original” files that no longer work because of project update
await Promise.all(flags['dry-run'] ? [] : filesToDelete.map((f) => rm(f)));

// @ts-expect-error there's publicly accessible way to clear a project's instance
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
SfProject.instances.clear();

const createdFiles = await convertBackToSource({
packageDirsWithPreset: packageDirsWithDecomposable,
projectDir: this.project!.getPath(),
Expand Down Expand Up @@ -103,3 +117,10 @@ export default class ConvertSourceBehavior extends SfCommand<SourceBehaviorResul
};
}
}

/** convert will put things in /main/default. If the packageDirs aren't configured that way, we'll need to warn the user
* See https://salesforce.quip.com/va5IAgXmTMWF for details on that issue */
const hasMainDefault =
(projectDir: string) =>
(i: ComponentSetAndPackageDirPath): boolean =>
existsSync(join(projectDir, i.packageDirPath, 'main', 'default'));
29 changes: 6 additions & 23 deletions src/utils/convertBehavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import { existsSync, readdirSync } from 'node:fs';
import { readdirSync } from 'node:fs';
import { readFile } from 'node:fs/promises';
import { join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
Expand All @@ -15,7 +15,6 @@ import {
ConvertResult,
MetadataConverter,
MetadataRegistry,
RegistryAccess,
SourceComponent,
presetMap,
} from '@salesforce/source-deploy-retrieve';
Expand All @@ -38,20 +37,19 @@ export const getPackageDirectoriesForPreset = async (
preset: string
): Promise<ComponentSetAndPackageDirPath[]> => {
const projectDir = project.getPath();
const messages = loadMessages();
const output = (
await Promise.all(
project
.getPackageDirectories()
.map((pd) => pd.path)
.map(componentSetFromPackageDirectory(projectDir)(await getTypesFromPreset(preset)))
)
)
.filter(componentSetIsNonEmpty)
// we do this after filtering componentSets to reduce false positives (ex: dir does not have main/default but also has nothing to decompose)
.map(validateMainDefault(projectDir));
).filter(componentSetIsNonEmpty);
if (output.length === 0) {
loadMessages().createError('error.noTargetTypes', [preset]);
messages.createError('error.noTargetTypes', [preset]);
}

return output;
};

Expand Down Expand Up @@ -144,7 +142,7 @@ const convertToSource = async ({
}): Promise<ConvertResult[]> => {
// mdapi=>source convert the target dir back to the project
// it's a new converter because the project has changed and it should reload the project's registry.
const converter = new MetadataConverter(new RegistryAccess(undefined, projectDir));
const converter = new MetadataConverter();
return Promise.all(
packageDirsWithPreset.map(async (pd) =>
converter.convert(
Expand Down Expand Up @@ -179,21 +177,6 @@ export const getTypesFromPreset = async (preset: string): Promise<string[]> =>
(JSON.parse(await readFile(join(PRESET_DIR, `${preset}.json`), 'utf-8')) as MetadataRegistry).types
).map((t) => t.name);

/** convert will put things in /main/default. If the packageDirs aren't configured that way, we don't want to make a mess.
* See https://salesforce.quip.com/va5IAgXmTMWF for details on that issue */
const validateMainDefault =
(projectDir: string) =>
(i: ComponentSetAndPackageDirPath): ComponentSetAndPackageDirPath => {
if (!existsSync(join(projectDir, i.packageDirPath, 'main', 'default'))) {
throw loadMessages().createError(
'error.packageDirectoryNeedsMainDefault',
[i.packageDirPath],
[i.packageDirPath]
);
}
return i;
};

const getComponentSetFiles = (cs: ComponentSet): string[] =>
cs
.getSourceComponents()
Expand Down
Loading