diff --git a/messages/deploy.metadata.md b/messages/deploy.metadata.md index 349838870..27056a7c3 100644 --- a/messages/deploy.metadata.md +++ b/messages/deploy.metadata.md @@ -257,3 +257,8 @@ The `pushPackageDirectoriesSequentially` property is not respected by this comma # apiVersionMsgDetailed %s %s metadata to %s using the v%s %s API. + +# noSourceTrackingWarning + +Starting in December 2025, this command will require that the target org use source tracking. +Specifically, to use this command with a production org, scratch org created with the `--no-track-source` flag, or other non-source-tracking org, you must specify the metadata you want to deploy with either the `--metadata`, `--source-dir`, or `--manifest` flag. diff --git a/messages/retrieve.start.md b/messages/retrieve.start.md index 4ab517f1c..34431ec9f 100644 --- a/messages/retrieve.start.md +++ b/messages/retrieve.start.md @@ -199,3 +199,8 @@ This command expects the org to support source tracking. If it doesn't, you must - Use the `--source-dir`, `--manifest` or `--package-name` flags to retrieve metadata in source format. - Use the `--target-metadata-dir` flag to retrieve metadata in metadata format to a directory. + +# noSourceTrackingWarning + +Starting in December 2025, this command will require that the target org use source tracking. +Specifically, to use this command with a production org, scratch org created with the `--no-track-source` flag, or other non-source-tracking org, you must specify the metadata you want to retrieve with either the `--metadata`, `--source-dir`, or `--manifest` flag. diff --git a/src/commands/project/deploy/start.ts b/src/commands/project/deploy/start.ts index 58fa7733a..eed1d3640 100644 --- a/src/commands/project/deploy/start.ts +++ b/src/commands/project/deploy/start.ts @@ -199,6 +199,12 @@ export default class DeployMetadata extends SfCommand { throw messages.createError('error.NoTestsSpecified'); } + const noDeployFlags = !flags['source-dir'] && !flags.manifest && !flags.metadata && !flags['metadata-dir']; + + if (noDeployFlags && !(await flags['target-org'].tracksSource())) { + this.warn(messages.getMessage('noSourceTrackingWarning')); + } + const api = await resolveApi(this.configAggregator); const username = flags['target-org'].getUsername(); const title = flags['dry-run'] ? 'Deploying Metadata (dry-run)' : 'Deploying Metadata'; diff --git a/src/commands/project/retrieve/start.ts b/src/commands/project/retrieve/start.ts index f79134776..99f029ca5 100644 --- a/src/commands/project/retrieve/start.ts +++ b/src/commands/project/retrieve/start.ts @@ -176,6 +176,19 @@ export default class RetrieveMetadata extends SfCommand { // eslint-disable-next-line complexity public async run(): Promise { const { flags } = await this.parse(RetrieveMetadata); + + // Add warning for non-source-tracking orgs when using default behavior + const isChanges = + !flags['source-dir'] && + !flags['manifest'] && + !flags['metadata'] && + !flags['target-metadata-dir'] && + !flags['package-name']?.length; + + if (isChanges && !(await flags['target-org'].tracksSource())) { + this.warn(messages.getMessage('noSourceTrackingWarning')); + } + let resolvedTargetDir: string | undefined; if (flags['output-dir']) { resolvedTargetDir = resolve(flags['output-dir']); @@ -518,6 +531,7 @@ const buildRetrieveOptions = async ( output: string | undefined ): Promise => { const apiVersion = await resolveApiVersion(flags); + return { usernameOrConnection: flags['target-org'].getUsername() ?? flags['target-org'].getConnection(flags['api-version']), merge: true, diff --git a/test/nuts/retrieve/noTracking.nut.ts b/test/nuts/retrieve/noTracking.nut.ts index f6fc47391..fa45c054d 100644 --- a/test/nuts/retrieve/noTracking.nut.ts +++ b/test/nuts/retrieve/noTracking.nut.ts @@ -49,6 +49,15 @@ describe('retrieve mdapi format without project', () => { expect(result?.files).to.not.be.empty; }); + it('should fail when retrieving changes from a non-tracking org', () => { + const result = execCmd(`project:retrieve:start -o ${session.hubOrg.username} --json`, { + ensureExitCode: 1, + }); + + expect(result.jsonOutput?.name).to.equal('noSourceTracking'); + expect(result.jsonOutput?.message).to.include('Unable to track changes in your source files'); + }); + after(async () => { await session?.clean(); });