1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Salesforce CLIのsfプラグインを作成する

Posted at

はじめに

Salesforce CLIはコマンドラインからSalesforce開発に必要な操作を実行できるツールです。
プラグインをインストールすることで機能を拡張することもできます。
プラグイン作成用のツールが用意されているので、意外と簡単にプラグインを自作することができます。

イベントモニタリングのログを出力するプラグインを例にプラグインの作成方法について説明します。

事前準備

プラグインを作成するのに下記のツールが必要です。

インストールしているSalesforce CLIのバージョンが古い場合は下記のコマンドでアップデートしてください。

$ sfdx update

plugin-devはSalesforce CLIプラグインを作成するためのツールです。このツール自体がプラグインです。
下記のコマンドでインストールできます。

$ sf plugins install @salesforce/plugin-dev

プラグインの作成

作成の流れ

  1. プロジェクトフォルダを作成する
  2. コマンドを作成する
  3. 必要に応じてコマンドにフラグを追加する
  4. 実装する
  5. コンパイルする
  6. Salesforce CLIにリンクする

1. プロジェクトフォルダの作成

plugin-devツールを使用してプロジェクトフォルダを作成します。
下記のコマンドを実行するといくつか質問が表示されるので、その質問に答えることでプロジェクトフォルダが作成されます。
最初の質問はSalesforceの内部開発者かどうか問われるのでnと答えます。そのほかの質問でツールの名称、説明、作成者、必要なコードカバレッジ率などを入力します。

$ sf dev generate plugin

sf-plugin001.png

つぎに依存パッケージをインストールします。

$ yarn install

ここまでの作業でプロジェクトフォルダの準備は完了です。

コマンドの実行方法

プロジェクトフォルダにはhello worldというサンプルコマンドが作成されています。
サンプルコマンドの構成は下記になります。

  • src/commands/hello/world.ts: メインの TypeScript ファイル。
  • messages/hello.world.md: コマンドのヘルプとエラーを構成するメッセージを含むファイル。
  • test/commands/hello/world.nut.ts: 非単体テスト。
  • test/commands/hello/world.test.ts: 単体テスト。

こちらのツールを使用してコマンドの実行方法を説明します。
開発中のツールを実行する場合、下記のようにbin/devを実行します。

$ bin/dev hello world
Hello World at Mon Apr 10 2023.

通常のsfコマンドのように実行するためには、コンパイルを行なって、Salesforce CLIにリンクする必要があります。

$ yarn compile
$ sf plugins link .
$ sf hello world
Hello World at Mon Apr 10 2023.

Salesforce CLIにリンクされているsfプラグインを確認するにはpluginsコマンドを実行します。

リンク済みプラグインの確認
$ sf plugins
dev 0.7.0
my-plugin 0.0.1 (link) /Users/tool/sf-plugins/my-plugin

Salesforce CLIのプラグインのリンクを解除する場合はplugins unlinkコマンドを実行します。

プラグインのリンク解除
$ sf plugins unlink プラグイン名

2. コマンドの作成

EventMonitoringLogを出力するコマンドを作成していきます。
コマンド名のガイドラインは公式開発者ガイドに記載があります。

作成するコマンド例
$ sf elf export --connected-org org-alias --date-range Last_n_Days:2 --output-dir ./output

下記のコマンドを実行してコマンド本体のTypeScriptファイルを作成します。

$ # sf dev generate command --name トピック名:コマンド名
$ sf dev generate command --name elf:export

sf-plugin002.png

このコマンドによって下記のファイルが作成されます。

  • src/commands/elf/export.ts
  • messages/elf.export.md
  • test/commands/elf/export.nut.ts
  • test/commands/elf/export.test.ts

3. フラグの追加

作成したコマンドに下記のフラグを追加していきます。

  • --connected-org: Salesforce組織を指定する
  • --date-range: ログを取得する日を文字列で指定する
  • --output-dir: 出力するフォルダを指定する

フラグはdev generate flagコマンドで追加できます。
このコマンドを実行することでsrc/commands/elf/export.tsが上書きされます。
フラグ種別にrequiredOrgを選択することで簡単にSalesforceに接続させることができます。

$ sf dev generate flag

sf-plugin003.png
sf-plugin004.png
sf-plugin005.png

sf dev generate flagでフラグを作成すると自動的にtsファイルに下記のような内容が追加されます。

  public static readonly flags = {
    name: Flags.string({
      summary: messages.getMessage('flags.name.summary'),
      char: 'n',
      required: false,
    }),
    'connected-org': Flags.requiredOrg({
      summary: messages.getMessage('flags.connected-org.summary'),
      char: 'o',
      required: true,
    }),
    'date-range': Flags.string({
      summary: messages.getMessage('flags.date-range.summary'),
      char: 'r',
      default: 'Last_n_Days:2'
    }),
    'output-dir': Flags.directory({
      summary: messages.getMessage('flags.output-dir.summary'),
      char: 'd',
      required: true
    }),
  };

4. 処理の実装

Salesforce組織に接続する

Flags.requiredOrgのフラグを作成している場合、下記のように簡単にSalesforce組織に接続できます。

const { flags } = await this.parse(ElfExport);
const conn = flags['connected-org'].getConnection();

このgetConnectionの戻り値はjsforceのconnectionを継承しているクラスのインスタンスなので、jsforceと同じメソッドが使用できます。

query
const dateRange = flags['date-range'];
const query = `SELECT Id, EventType, LogDate FROM EventLogFile WHERE LogDate = ${dateRange}`;
const result = await conn.query<{ Id: string, EventType: string, LogDate: string }>(query);
sobject
const record = result.records[0];
const contentStream = conn.sobject('EventLogFile').record(record.Id).blob('LogFile');

(サンプル)イベントモニタリング出力スクリプト

import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { Messages } from '@salesforce/core';
import * as fs from 'fs'

Messages.importMessagesDirectory(__dirname);
const messages = Messages.load('elf-downloader', 'elf.export', [
  'summary',
  'description',
  'examples',
  'flags.name.summary',
  'flags.connected-org.summary',
  'flags.date-range.summary',
  'flags.output-dir.summary',
]);

export type ElfExportResult = {
  length: number;
};

export default class ElfExport extends SfCommand<ElfExportResult> {
  public static readonly summary = messages.getMessage('summary');
  public static readonly description = messages.getMessage('description');
  public static readonly examples = messages.getMessages('examples');

  public static readonly flags = {
    name: Flags.string({
      summary: messages.getMessage('flags.name.summary'),
      char: 'n',
      required: false,
    }),
    'connected-org': Flags.requiredOrg({
      summary: messages.getMessage('flags.connected-org.summary'),
      char: 'o',
      required: true,
    }),
    'date-range': Flags.string({
      summary: messages.getMessage('flags.date-range.summary'),
      char: 'r',
      default: 'Last_n_Days:2'
    }),
    'output-dir': Flags.directory({
      summary: messages.getMessage('flags.output-dir.summary'),
      char: 'd',
      required: true
    }),
  };

  public async run(): Promise<ElfExportResult> {
    const { flags } = await this.parse(ElfExport);

    const dateRange = flags['date-range'];

    const query = `SELECT Id, EventType, LogDate FROM EventLogFile WHERE LogDate = ${dateRange}`;
    const conn = flags['connected-org'].getConnection();
    const result = await conn.query<{ Id: string, EventType: string, LogDate: string }>(query);

    const dir = flags['output-dir'];

    if (result.records.length > 0) {
      for (const record of result.records) {
        const type = record.EventType;
        const date = record.LogDate.substring(0, 10);
        const fileName = `${date}-${type}.csv`;

        this.spinner.start(`Downloading: ${fileName} to ${dir}`);

        const contentStream = conn.sobject('EventLogFile').record(record.Id).blob('LogFile');
        const chunks = [];
        contentStream.on('data', (chunk)=>{
          chunks.push(chunk);
        });

        contentStream.on("end", ()=>{
          const body = Buffer.concat(chunks);
          fs.mkdirSync(dir, {recursive: true});
          fs.writeFileSync(`${dir}/${fileName}`, body);
        });

        this.spinner.stop();
      }
    }
    return {length: result.records.length};
  }
}

5. コンパイル

下記のコマンドでコンパイルを実施します。

$ yarn compile

6. Salesforce CLIにリンク

下記のコマンドでSalesforce CLIにリンクできます。

$ sf plugins link .

リンクを行ったら下記のコマンドで実行できます。

$ sf elf export --connected-org org-alias --date-range Last_n_Days:2 --output-dir output

参考資料

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?