イマドキのSalesforce開発のプロジェクト雛形を作った #salesforce

ひとまず取り入れたかった技術要素が盛り込めたので、公開してみました。

開発環境の構築は最初に必要な作業ですが、得てしてハードルが高いので、そのあたりの敷居を下げるのが狙いです。

Lightning Testing Service (LTS) の使い方

LTSを使ってみようとしたわけですが、ドキュメント( https://forcedotcom.github.io/LightningTestingService/ )の情報量が少なく、独自のテストを追加してテストを走らせる方法が、ソースを見るまで分からなかったので、簡単に使い方をメモします。

LTSのインストール

$ sfdx force:lightning:test:install

対象のスクラッチ組織に LTS の非管理パッケージをインストールします。
パッケージ名は「Lightning Testing Service with Examples」です。
デフォルトでは最新バージョンがインストールされ、執筆時点で1.3でした。

これはスクラッチ組織ごとに必須な処理ですが、そんなに大きなパッケージではないため、おおよそ10秒未満でインストールが完了するようです。これくらいだったらCIを回す上でも許容範囲かなと。

独自のテストを作成

$ sfdx force:lightning:test:create -n {テスト名}

ここで作成されるテストクラスは、実体(メタデータ)は静的リソースです。

静的リソースといってもZIPファイルではなく単なるJavaScriptなので、ここにテストを記述していくことができます。

テストスイートとなるLightningアプリケーションを作成

追加した独自のテストを実行させるためには、別途Lightningアプリケーションが必要なようです。
これは、LTSパッケージに含まれているテストスイートでは、LTSパッケージ内に事前に用意されているテストしか実行されないためです。
例えばjasmineTestsテストスイートは以下のように記述されており、3つのテストを実行させるように指定されていますが、当然、こちらで新たに追加したテストは含まれていません。

<aura:application>

    <c:lts_jasmineRunner testFiles="{!join(',', 
      $Resource.jasmineHelloWorldTests,
      $Resource.jasmineExampleTests,
      $Resource.jasmineLightningDataServiceTests
    )}" />

</aura:application>

自分で追加するテストスイート用のアプリケーションでは、上記を真似て、testFiles 属性のところで、作成したテストクラス(静的リソース)の名前を渡してあげるよう変更すればOKです。

<aura:application >
    <c:lts_jasmineRunner testFiles="{!join(',', $Resource.<テスト名>)}" />
</aura:application>

テスト関連のメタデータをデプロイ

上記のLightningアプリケーションと静的リソースをスクラッチ組織にデプロイします。

$ sfdx force:source:push

テストの実行

$ sfdx force:lightning:test:run -a <テストアプリケーション名>

ちなみに、標準でJUnitのレポート出力も用意されているので、Travis CIなどのサービスでなくJenkinsでレポートすることも余計な手間なくできそうです。

テストの書き方

テストコードの文法は、JasmineやMochaの流儀にしたがっていけばよいわけですが、Lightningコンポーネントのテストをするのが目的なので、テストコード中でLightningコンポーネントへのアクセスが必要になります。

LTSの場合、テストコード中では $T というグローバルなオブジェクトが利用できるので、それを使うみたいです。

Jasmineの場合はこんな感じ。

describe("c:Hoge", function () {
  it("sets component attributes", function (done) {
    var that = this;

    $T.createComponent("c:Hoge", null)  // テスト対象となるコンポーネントを作成
      .then(function (component) {

        // 必要であれば、$T.waitFor を使って、条件を満たすまでウエイトを入れることができる
        return $T.waitFor(function () {
          that.component = component;
          return 1 === 1; // サンプルのためすぐに true が評価されるようにして、抜ける
        }, 10000);
      }).then(function () {
        // $T.createComponent のコールバックに作成されたコンポーネントが渡されるので、それを使ってassertionを記述する
        expect(that.component.get("v.attr1")).toBe("aaaaa");
        done();
      }).catch(function (e) {
        done.fail(e);
      });
  });
});

テストコードはバージョン管理上どこに置くべき?

どうすべきなんでしょうね…。

sfdxで素直に作ったプロジェクトであれば foce-app がパッケージディレクトリとなっていると思うので、今回は force-app/test/default 以下にテストコード(静的リソース)やテストスイート(Lightningアプリケーション)を置くようにしてみました。

適当に作ったDE組織のメタデータをSFDXのプロジェクト化する #salesforce

作業メモです。

developer.salesforce.com

非管理パッケージを作った後で、取ってきたメタデータをコピーしてあげればよいみたいですね。

CLI: プロジェクトの土台を作成

$ sfdx force:project:create --projectname sample-project

慣れないうちはレイアウトもデフォルトにしておいた方が無難でしょう。

CLI: DE組織を接続

CLI経由で、DE組織へのアクセスが行えるようにします。

$ sfdx force:auth:web:login -a de1

ブラウザが立ち上がって、Salesforceへのログインが促されるので、ログインします。
何かと使うので、組織のエイリアス de1 も指定しておきます。

DE: 非管理パッケージを作成

バージョン管理したいメタデータコンポーネントに追加した上で、非管理パッケージをアップロードします。

とりあえず重要なのは

だけなので、それ以外はテキトーに…。

以下、パッケージ名は「pkg1」にしたことを前提としています(要:適宜読み替え)。

CLI: 非管理パッケージを取得

$ sfdx force:mdapi:retrieve -s -r ./tmp -u de1 -p pkg1

./tmp/ の下に unpackaged.zip が落ちてくるはず。

CLI: 非管理パッケージを展開

$ unzip ./tmp/unpackaged.zip -d ./unzipped

CLI: メタデータをsfdx形式のフォーマットに変換する

$ sfdx force:mdapi:convert -r ./unzipped

コマンドリファレンスに "This command must be run in a project." とあるので、必須な処理みたいですね。

ところでこのコマンド、「一体何をしているか?」ですが、基本的には、unzipped/**/* から force-app/main/default/**/* への再帰的なファイルコピーのようです。

ただし単純なコピーではなく、以下のように、いくつか例外(?)があります。

  • package.xml はコピーしない。これは .forceignore が効いているせいかもしれません。
  • 対応するソースに *-meta.xml ファイルがない場合、オリジナルのファイルに -meta.xml を付けた形でリネームする。
  • Zip形式の静的リソースは展開してコピーする。

挙動から推測するより、中身を見たほうが早いかも、と思いました。

Bulk API 2.0のJavaクライアントを作った #salesforce

Winter '18にて、Bulk API 2.0が正式リリースされました。

Bulk API 2.0 (正式リリース)

あんまり話題になっていないような気がするので、簡単にまとめてみます。

Bulk API 2.0とは

新機能については上記ページでも言及されていますが、主観で重要そうだなと思うところをピックアップします。

一番大きな違いはSOAPからRESTになったことですね。そのため、使う側からするとほぼ別物として見た方がよさそうです。

v1.0 v2.0
API SOAP(XML)ベース REST(JSON,CSV)ベース
結果の評価・後処理 結果(Request)はID, Success, Created, Errorの4項目しかないため、RequestとResultを行番号やIDで突き合わせて行なう 結果取得APIレスポンスの中に要求した各項目も含めて返ってくるため、突き合わせが不要
バッチのローテーション CSVが10,000行あるいは10,000,000 文字を超えたら 自分で 面倒を見る 最大 150MB (base64 エンコード後) までは 自動で 分割される
処理されなかったジョブデータ 結果CSVから自分で評価して抜き出す 専用のAPIがある

また、アップロードするデータが20,000 文字以下の場合、ジョブの作成とアップロードをマルチパート要求で1回でできるので、 (大半のケースで)SalesforceAPI消費が1.0よりも少なくて済むと思います(多分)。

Javaクライント

APISOAPからRESTに変わったことで、「APIのドキュメントは公開するから好きなHTTPクライアントで実装してね」という方針になったのかどうかは分かりませんが、ネットで探してもあまり利用例が見当たりません。

ということで、試してみました(言語はJavaです)。

とは言え、Bulk API 2.0では、一般的なREST APIJSONCSVをやり取りするだけなので、呼び出し方さえ間違えなければさくっと動いてくれました*1

で、色々と試行錯誤した結果、薄いクライアントライブラリ(ラッパー)ができあがったので、公開してみます。

github.com

(使用例はリポジトリのREADMEにあります)

  • ドキュメントとして公開されているものについては、一通りのAPIとオプション(リクエストパラメータの種類)をカバーしています。
  • HTTPクライアントにはOkHttpを使っています。
  • JSONエンコーダ・デコーダはJacksonを使いました。OkHttpのWikiでは、Moshiというライブラリが紹介されていましたが…(はじめて知りました)

*1:エラーレスポンスのフォーマットがドキュメントに見当たらなかったり、日本語版のドキュメントでレスポンスパラメータ名が間違っていたりはありましたが…w

継続的なアウトプットのために、ひとりAdvent Calendarを目論んだが、10/25でFinishした

一度は「ひとりAdvent Calendar」をやってみたいなーと思っていて、密かな目標として12月は25日まで毎日更新を目論んでいたのですが、半分にも満たない10日でFinishしました。
予定外に風邪をひいたりしてしまったことも多少は影響していますが、いやはや、完走できる人はすごいですね。

日付 記事
12/1 SOAP API(wsc)で地理位置情報型や時間型を扱う #salesforce
12/2 AWS CodeBuildでいつの間にかDependency Cacheがサポートされてた
12/4 ゼロからはじめるServerless Java Container (Qiita)
12/6 Salesforce開発デザインパターン集 #salesforce
12/9 AWS Lambdaでストリームベースのイベントソースのリトライ回数を有限にしてDLQを使う (Qiita)
12/12 $A.createComponentsでちょっと複雑なコンポーネントを動的に作成してみる #salesforce
12/13 Lightning Experience流のUIを作る4つの方法と比較 #salesforce
12/14 Lightning基本コンポーネントのライブエディタを作ってみる #salesforce
12/15 sfdxのカスタムプラグインを作ってみる #salesforce
12/20 古いDev Hub Trial Orgを消す #salesforce

Salesforceネタが7つ、AWSネタが3つでした。
本分はJava屋(だと思っている)のですが、今年はあまり新しい刺激が(業務においては)少なく、守りの年でした。

あと、ブログに感想は書けていませんが、12月は以下の勉強会に参加していました。

継続的なアウトプットのために

さて、日頃からインプットとアウトプットのバランスをとるように心がけているのですが、相変わらずアウトプット(ここでのアウトプットはブログを書くことに限定します)はムラが多すぎるなーと反省。。

目標の25日には届きませんでしたが、継続的にアウトプットをするための気構えとして感じたことを書き留めておきます。

1記事は大作でなくてもよい

Advent Calendarにエントリするのは今年で4回目でしたが、今までで一番リラックスして書くことができました。こう言ってしまうとなんですが、記事を書くための仕込みの時間も一番短かったと思います。

なんとなくAdvent Calendarというと、大作(=分量が多い・技術的に高度・ネタ色が強い)でないとダメ、みたいに感じていましたが、そんなことはないのかなと思うようになりました。テーマに沿っており、将来の自分や誰かの役に立つネタであれば、極論、一文・一行でもいいのかなと思います。これはAdvent Calendarにかぎらず、普段のブログでも同じでもいえると思います。
そもそも、短いほうが読者もすぐに読めますし…。

というわけで、もっと気軽に、自分の日頃の気づきをアウトプットする場として、来年はブログを使っていきたいです。

事前に準備しても熱は冷めてる

一応、ひとりAdvent Calendarということで、始まる前に20日分くらいのネタ(タイトルだけ)は考えたりしていました。
ただ、その当時は「××のことを調べてxxの記事に書くぞ!」と思っていても、時間が経ってしまうと、その熱が冷めていて、結局調べもせず、書きもしないことがあるんですよね…。

なので自分は、書くと決めたらその日に(多少粗くても)書き切って投稿する、というスタイルが合っているように思いました。

ちなみに、日の目を見なかったネタについては、来年どこかで記事にしたいとは思っていますが…。

アクセス数は気にしない

「反応があると嬉しい」ということは否定しませんが、アクセス数を稼ぐことが目的化してしまうと本末転倒であり、そもそもこのブログ、基本的に検索しかアクセスがないので、「自分のため」と割り切って書くのが長続きするコツかなと思います。
もうちょっと綺麗事を言うと、「将来の自分や誰かの役に立つネタ」を提供したい、というのがブログを書くモチベーションの源泉ですが…。

毎月xx回以上書く、毎週xx回以上書く、みたいな目標は決めない

定量的な回数を決めてしまうと、それ以上書こうという気が薄れるし、逆に目標が高すぎてもモチベーションが下がるし、目標を決めないほうが性にあっているような気がしました。これは人によるかもしれません。コンスタントに素晴らしい記事を書いている人も世の中にはたくさんいますし。

古いDev Hub Trial Orgを消す #salesforce

Dev Hub Trial Orgはトライアル期限が過ぎてしまうと無用の長物になるわけなので、削除したいことがあります。

~/.sfdx の下にある、 {Dev Hub Orgのユーザ名}.json を消せばいいみたいです。

あと、~/.sfdx/alias.json の方も修正する必要もあるかもしれません。

sfdxのカスタムプラグインを作ってみる #salesforce

sfdxにも少しずつ慣れていきたいなと思い、色々試してみようとしているところです。

手始めに

$ sfdx help

とヘルプコマンドを打ち、そこで初めて、sfdxはプラグイン機構を備えていることを知りました。

f:id:jappy:20171215004240p:plain

sfdxのカスタムプラグインはどんな感じに作られるのか、試してみました。

作ったもの

https://github.com/tq-jappy/sfdx-hello-plugin

$ sfdx hello:sayHello

と打つと、

Hello sfdx!

とコンソールに出力するだけのものです。

作り方を学ぶ

これまで、趣味と実益を兼ねて、RedmineやJenkinsのプラグインの作成(や改修)に関わってきましたが、プラグインの作り方を学ぶには、似たような動作をする既存のプラグインを真似するのが一番の近道だと思っています。

とはいえ、sfdxの場合、まだそんなに数が豊富にあるわけではないので、「そもそもどうやって作ればいいんだろう?」と思って検索したところ、例えば以下のようなリポジトリが見つかりました。

github.com

あと、作者の方の紹介記事もありました。

www.wadewegner.com

これらを踏まえて、作りました。

作り方まとめ

基本的には、sfdxのプラグインは普通のNode.js開発の要領で作っていけばよいみたいですね。

エントリポイント(メイン) である index.js の中で、 topics, namespace, commands をそれぞれ exports してあげるのがルールなようです。
ただ、コマンド体系が複雑でなければ、namespaceは省略してもよいみたいです。プラグインの作法としてはさておき、動作上は問題ありませんでした。

コマンドのロジックは以下のコードです。 context の中には認証情報なども含まれていそうなので、うまく駆使すれば色んな用途を満たすプラグインが作れるんじゃないかなと。

(function() {
  'use strict';

  module.exports = {
    topic: 'hello',
    command: 'sayHello',
    description: 'display hello message',
    run(context) {
      console.log('Hello sfdx!');
    }
  }
}());

JavaScriptで作成することから、jsforce(やその他のJS系のSalesforceライブラリ)と組み合わせるとよさそうですね。

今のプロジェクトでは、sfdxは実戦投入できていないものの、Jenkins, jsforce, gulp, jsforce-metadata-toolsを使ったCIを組んでおり、その中でApexのテスト結果をJenkinsのJunit/Coberturaレポート形式に出力する、みたいなこともしているのですが、そういう部分をsfdxのプラグイン化することで、sfdxへの移行も緩やかにしていけそうな気がしました。