Migrating Texeï SFDX Plugin to sf (V2)

Par 

8 minutes de lecture
SFDX Plugin

We’ve been working on the Texeï SFDX Plugin migration to sf (V2), and just published a first version of it. If you’re unfamiliar with sf (V2), you can have a look at these two great blog post from the Salesforce Developers’ Blog:

Migrating, why ?

With the new Salesforce CLI, sf (V2) being GA, you may have noticed that some Salesforce commands started firing warnings about recent changes. A basic example would be that some flags, like --targetusername, will be replaced by --target-org. Behind the scenes, it’s also the commands architecture that changed.

So why do we care ? Well let’s be honest, we could have stayed with the exact same architecture, and everything would have worked perfectly. But once all commands have been migrated to use the new --target-org flag, Texeï plugin would still use the --targetusername flag, making it inconsistent with Salesforce commands.

Also, new commands would of course use the new architecture, meaning that whether you work on a new command or an old one, code would have been different. Not very convenient to onboard new developers, or to get pull requests from the community.

Lastly, some dependencies will bring new features but also remove some support, for instance SfdxError is not exported anymore in the latest version of the @salesforce/core package.

So we just rolled up our sleeves and started working on it.

Migrating, how ?

Knowing that all plugin authors would want to migrate their plugin, Salesforce CLI team created a wiki explaining all the steps needed to do it:

https://github.com/salesforcecli/cli/wiki/Migrate-Plugins-Built-for-sfdx

This remains the official documentation and best place to start, but we’ll give you our own feedback.

First thing to know is that migrating is pretty easy. What makes it difficult is that Texeï plugin has more than 20 commands, which means repeating all the migration steps for all these commands. Hopefully, Salesforce provides a set of ESLint additional rules that makes it easier (see note just below).

We’ll go through several examples about the things that we had to change in almost all commands, with a before and after code sample, but also note that you can go to the recap section at the end of this article to see a before/after helper table, or look at the same command written both the old way and the new way.

Note that you can use a set of ESLint additional rules that do most of the work for you. Thanks Shane McLaughlin for pointing this out.

Just setup these rules as explained here, and just run yarn lint -- --fix.

Update dependencies

The first step was to update the dependencies in package.json. You can of course update them manually, but as some of them may be removed or new, we created a new plugin (using sf plugins install @salesforce/plugin-dev and sf dev generate plugin) just to have a look at the generated files and dependencies. Using a whole new setup will also bring you better linting than just migrating your command files.

Message files

Messages files are now different, basically they were JSON based previously, with key/value pairs of string, whereas now they are based on markdown. This allows you to bring formatting and variables to your messages.

Before:

After (raw content here):

These are pretty easy to migrate as there is a specific command for that:

sf dev convert messages --file-name messages/my-command.json

Beside that in your code itself, the expected property is now named summary, replacing the description flag:

Before:

After:

Code

Then you’ll have to update each of your commands. The main thing that is changing is that all classes were extending SfdxCommand whereas now they do extend SfCommand. Which comes with several changes regarding the way you write your commands.

Imports

The most important one will be to move the import from SfdxCommand to SfCommand:

will be now:

Some other changes will be to move SfdxError to SfError or SfdxProjectJson to SfProjectJson.

You’ll get warned by linting about other incorrect imports you may have.

Flags

Flags are imported almost the same way.

Before:

After:

In addition, flags should be parsed before used:

const { flags } = await this.parse(CommandName);

Note also that Flags.number doesn’t exist anymore but can be replaced by Flags.integer.

requiresUsername, supportsDevhubUsername and requiresProject
Previously we could easily decide if the command needed a username, a devhub or/and a project via 3 properties:
Now requiresUsername and supportsDevhubUsername are replaced by two flags, requiredOrgFlagWithDeprecations and requiredHubFlagWithDeprecations. requiresProject is still working as before:
Exported type

You’re now required to define the exported type. Whereas before you could use a random and undefined object:

Now you’ll define a type first, and return it from your command (here NewCommandResult):

Connection

One you may use all the time, getting a connection will have to be rewritten from:

to:

Spinner and log

Another change needed even though pretty simple, moving:

to:

Some other change may be needed, like moving this.ux.log() to this.log().

Breaking changes

One of the changes we had to handle is that the shortcut for --target-org is now -o, whereas it was -u previously with --targetusername. This conflicted with some existing commands using -o for another flag (like –objects). We just moved the flag shortcut to a new one to avoid the conflict, and documented it as a breaking change in our documentation.

ES Lint and TypeScript errors

When moving to the new linting, we encountered a lot of new warnings and errors. At first, we started to fix everything, but noticed that this would take A LOT of time. This was a big issue because this was slowing down our migration, and the longer we waited, the more conflicts we would have later will Pull Requests we receive. Not the best recommendation here, but we disabled the most painful warnings per file to be able to migrate quicker.

This doesn’t seem really clean, but the code is still the same as before, so what’s not perfect now wasn’t already. Basically not better code, but as good as before (and working). This is also easier to split the remaining cleaning work per file and developer.

Lastly, as these warnings are disabled per file, this will let us write new commands in a clean way.

Recap

Here is a basic recap of before/after code that we used very often:

Before After
import { flags, SfdxCommand } from ‘@salesforce/command’; import { Flags, SfCommand } from ‘@salesforce/sf-plugins-core’;
const messages = Messages.loadMessages(« texei-sfdx-plugin », « my-command »); const messages = Messages.loadMessages(‘texei-sfdx-plugin’, ‘my.command’);
SfdxError SfError
SfdxProjectJson SfProjectJson
public static description = messages.getMessage(‘commandDescription’); public static readonly summary = messages.getMessage(‘summary’);
wait: flags.number({ char: ‘w’, description: messages.getMessage(‘waitFlagDescription’), required: false }) wait: Flags.integer({ char: ‘w’, summary: messages.getMessage(‘flags.wait.summary’), required: false })
this.ux.log() this.log()
this.ux.warn() this.warn()
this.startSpinner(‘Retrieving Profiles’, null, { stdout: true }); this.spinner.start(‘Retrieving Profiles’, undefined, { stdout: true });
this.ux.stopSpinner(‘Done.’); this.spinner.stop(‘Done.’);
protected static requiresUsername = true; requiredOrgFlagWithDeprecations
protected static requiresDevhubUsername = false; requiredHubFlagWithDeprecations
protected static readonly requiresProject = true; public static readonly requiresProject = true;
const conn = await this.org.getConnection(); const conn = flags[‘target-org’].getConnection(flags[‘api-version’]);

 

Finally, you can have a look at the same command, both written the old way and the new way:

Old way:

New way:

Your turn now to move to sf (V2) ! 👍

A lire également sur le blog

Copado

Introduction à Copado

Vous aimeriez avoir une idée de ce qu’est Copado, savoir ce qu’apporte l’outil et le tester éventuellement ? Peut-être souhaiteriez-vous aussi connaître les étapes pour se former dessus ? …
avril 2024
Conseils
Interview-Romain-Quijal-Texeï

Portrait de Texiens : Romain Quijal, Développeur chez Texeï

👋 Découvrez le portrait de Romain Quijal, Développeur chez Texeï ! 🚀 Arrivé il y a un peu plus d’un an chez Texeï, Romain une étoile montante dans l’univers …
avril 2024
Interviews

Comment utiliser le pré-header ?

Comment utiliser le pré-header ? Dans le paysage en constante évolution du marketing numérique, la création d’emails captivants est devenue un véritable art. Chaque élément joue un rôle crucial …
mars 2024
Conseils
Avantages de Salesforce pour les PME

Pourquoi faire de la conduite du changement ? 

D’abord, qu’est-ce que la conduite du changement ? La conduite du changement (aussi appelée change management ou change) sert à accompagner les différentes parties prenantes lors d’une transformation dans …
mars 2024
Conseils
Interview-zoe-texei-1

Portrait de Texiens : Zoé Cadiou, Responsable Marketing Opérationnel

👋 Découvrez le portrait de Zoé Cadiou, Responsable Marketing Opérationnel chez Texeï ! 🚀 Arrivée chez Texeï en tant que Responsable de Communication, Zoé endosse désormais la casquette de Responsable …
février 2024
Interviews
Virgile-Paré-portrait -de-texien

Portrait de Texiens : Virgile Paré, Senior Business Analyst

👋 A l’honneur dans notre portrait de texiens, Virgile Paré, Senior Business Analyst, Spécialiste CRM-Analytics, et Manager chez Texeï ! 🚀 Arrivé il y a deux ans maintenant, Virgile …
février 2024
Interviews