-
Notifications
You must be signed in to change notification settings - Fork 31
Migrate Plugins Built for sfdx
You can install and use plugins originally built for sfdx
in sf
, although the general look-and-feel is different. We therefore recommend that you explicitly migrate your sfdx
plugin to sf
so its commands look and behave the same as other sf
commands. You can also then take advantage of the many improvements we've made to sf
plugins.
If you haven't already, update oclif
and the @salesforce/core library
to their current versions.
- Update to oclif/core by following this document.
- Update to sfdx-core v3 by following this document. We discuss converting your messages files later in this document.
Salesforce provides a set of eslint rules for CLI plugins.
If you are migrating an sfdx
plugin, there's a series of additional rules that do most of the work for you. Follow their setup instructions.
The rules will automatically change some code. For some rules, you'll see suggestions where you can choose which fix to apply.
v3 Messages support dynamic references to command and CLI names. For example, if your plugin supports both sfdx
and sf
, instead of hardcoding the command and CLI name, you can use a placeholder for the bin (CLI) and command name
# examples
- do something
<%= config.bin %> <%= command.id %> -i 7500x000005BdFzXXX
This way, the help examples
- reference the CLI the user is using
- don't have to be rewritten when you change your command structure/name
v3 messages work with your existing json message files, but we prefer markdown files.
If you haven't already, install plugin-dev
: sf plugins install dev
Then run sf dev convert messages -f [some message file]
. That converts json messages to markdown (delete the json ones when you're done)
You can also run sf dev audit messages
to find missing or unused messages.
We encourage you to follow sf
's styles in your names and flags. If you need to maintain backward compatibility, you have some options.
If you rename a command, you can alias it back to its original name.
export class LimitsApiDisplayCommand extends SfCommand<ApiLimits> {
...
// this command is now `limits api display` but was previously 'force:limits:api:display'` so an alias keeps that old name operable
public static readonly aliases = ['force:limits:api:display', 'org:list:limits'];
// when someone uses the old name, display a warning encouraging them to use the new name.
// without this property, the old name works but no warning occurs.
public static deprecateAliases = true;
If you rename a flag, there are similar alias behaviors to support its previous name
sobject: Flags.string({
char: 's',
required: true,
summary: messages.getMessage('flags.sobject'),
// the flag's previous name could be simplified to a single word
aliases: ['sobjecttype'],
// display a warning when someone uses the previous flag name
deprecateAliases: true,
}),
// sf uses the more readable hyphenated name
'use-tooling-api': Flags.boolean({
char: 't',
summary: messages.getMessage('flags.useToolingApi'),
aliases: ['usetoolingapi'],
deprecateAliases: true,
}),
// this flag was renamed and its short character was changed. both -f and -p work now, but -p provides a warning when used
'file': Flags.boolean({
char: 'f',
summary: messages.getMessage('flags.useToolingApi'),
aliases: ['pathtofile', 'p'],
deprecateAliases: true,
}),
Additionally, there are some helpers for compatibility within sf-plugins-core. They're marked as deprecated
so you don't use them on "new work".
public static flags = {
// allow but warn on --targetusername and -u
'target-org': requiredOrgFlagWithDeprecations,
// allow but warn on --apiversion
'api-version': orgApiVersionFlagWithDeprecations,
// loglevel is a no-op, but this flag is added to avoid breaking scripts and warn users who are using it
loglevel,
};
The eslint plugin should handle getting you to sfCommand. There are some differences to be aware of
some properties like this.logger
don't exist automatically. You can create those (import Logger from sfdx-core)
other properties like requiresUsername
don't do anything (and are removed by the linter rules). You'll need to add a flag for the org.
SfCommand
has private ux
property, meaning you can't pass it to helper functions. Instead of
// SfdxCommand
myHelper(this.ux);
construct a new ux
instance and pass it to your help
import { ux, Flags, SfCommand } from '@salesforce/sf-plugins-core'
...
// myHelper can call any `ux` method and terminal output is suppressed if json enabled
myHelper(new ux({jsonEnabled: this.jsonEnabled()}))
SfdxCommand's requires|supports(devhub)username
properties no only created flag for the username but also an apiversion flag.
If your command needs to support an apiversion (or just keep it in place for compatibility), do the following
public static flags = {
'target-org': requiredOrgFlagWithDeprecations,
'api-version': orgApiVersionFlagWithDeprecations,
}
// when you get a Connection, pass the api-version flag to it
// that way, if the user specified an api version, the Connection is set
const conn = flags['target-org'].getConnection([flags.api-version]);
Once you yarn remove @salesforce/command
you may realize you were also using its test
library, based on fancy-test
.
sfdx-core
v3 includes better tools for mocking auths/orgs/projects/users/connections. See its docs
This example uses TestSetup to mock an org/connection and calls a command's run
method
It's helpful to leave existing tests to verify that you've properly aliases all commands and flags to avoid breaking changes.
© Copyright 2024 Salesforce.com, inc. All rights reserved. Various trademarks held by their respective owners.
- Quick Intro to Developing sf Plugins
- Get Started: Create Your First Plugin
- Design Guidelines
- Code Your Plugin
- Debug Your Plugin
- Write Useful Messages
- Test Your Plugin
- Maintain Your Plugin
- Integrate Your Plugin With the Doctor Command
- Migrate Plugins Built for sfdx
- Conceptual Overview of Salesforce CLI