【第二世代管理パッケージ(2GP)】転送アップグレードの方法

2GP連載記事の第3弾です。今回はなぜかsfdxコマンドでできず、やり方がわかりにくい2GPでの転送アップグレードの方法を説明します。

今までの記事は[連載]第二世代管理パッケージ(2GP)をご覧ください。

開発者ガイドのおさらい

パッケージの作成のようにsfdxコマンドで簡単にできると思いきや、転送アップグレードのsfdxコマンドはありません。

Salesforce DX 開発者ガイド | SOAP API を使用した転送アップグレードのスケジュール に記載されている以下の流れの処理を自力でSOAP APIまたはREST APIで実装する必要があります。

開発者ガイドの処理の流れの解説

この上の処理は一見何をやっているかわかりませんが、実のところは、ただ Salesforce DX 開発者ガイド | パッケージアップグレードの転送 に記載されているいくつかのオブジェクトのレコードをDevHub組織(通常はPBO)で取得/作成/更新するだけです。

これらのオブジェクトは以下のような関係になっています。この中で赤枠内のPackagePushRequestとPackagePushJobオブジェクトのみ転送アップグレード時に手動で作成する必要があるレコードです。
その他のオブジェクトはMetadataPackageとMetadataPackageVersionはsfdxコマンドでパッケージを作成すると自動的に作成され、パッケージを組織にインストールするとPackageSubscriberが作成されます。

2GP_push_upgrade (3).jpg

しかし、注意点があります。レコードを作成すればいいならばとApexで以下のようにinsertしようとするとDML operation Insert not allowed on PackagePushRequest とエラーになってしまいます。

insert new PackagePushRequest(PackageVersionId = '04t0o0000099999ZZZ');

なぜかSOAP APIまたはREST APIでしか作成/更新できません。

REST APIで転送アップグレードする手順

試しにREST APIでやってみましょう。

ロック解除済みパッケージを準備

2GPで転送アップグレードを試したいところなのですが、以下の通り転送アップグレードはセキュリティレビューに合格したパッケージに対してしか実行することができません。

アップグレードを転送できるのは、AppExchange セキュリティレビューに合格したパッケージに対してのみです。

Salesforce DX 開発者ガイド | パッケージアップグレードの転送

ですので、今回は転送アップグレードが可能なもう一つのパッケージであるロック解除済みパッケージで試していきます。ロック解除済みパッケージでも転送アップグレードについてはやれることはほぼ同じですので、説明には問題ないと思います。

sfdxプロジェクトを作成、DevHub組織に認証し、適当にVisualforceページでも追加します。続いて以下のようにパッケージの作成、インストールと進めます。

パッケージ作成

sfdx force:package:create --name "kimunlockedpkg" --path force-app --packagetype Unlocked

パッケージバージョン作成

sfdx force:package:version:create --package "kimunlockedpkg" --wait 10 -x -c

リリース

sfdx force:package:version:promote --package "kimunlockedpkg@0.1.0-3"

適当な組織にパッケージインストールします。後ほどこの組織に対して転送アップグレードを行います。

sfdx force:package:install --package "kimunlockedpkg@0.1.0-3" --targetusername KIM_DEV --wait 10

わかりやすいようにVisualforceページを少し修正して、次のバージョンを作成します。

パッチバージョン作成

sfdx force:package:version:create --package "kimunlockedpkg" --versionnumber "0.1.1.NEXT" --wait 10 -x -c

リリース

sfdx force:package:version:promote --package "kimunlockedpkg@0.1.1-1"


現状はリリース済みバージョンが0.1.0.3と0.1.1.1の2つある状態です。

$ sfdx force:package:version:list --packages kimunlockedpkg --released
=== Package Versions [2]
Package Name    Namespace  Version Name  Version  Subscriber Package Version Id  Alias                   Installation Key  Released  Validation Skipped  Ancestor  Ancestor Version  Branch
──────────────  ─────────  ────────────  ───────  ─────────────────────────────  ──────────────────────  ────────────────  ────────  ──────────────────  ────────  ────────────────  ──────
kimunlockedpkg             ver 0.1       0.1.0.3  04t0o000003Ys27AAC             kimunlockedpkg@0.1.0-3  false             true      false               N/A       N/A
kimunlockedpkg             ver 0.1       0.1.1.1  04t0o000003Ys2CAAS             kimunlockedpkg@0.1.1-1  false             true      false               N/A       N/A

PackagePushRequestを作成

/services/data/v52.0/sobjects/packagepushrequest にPOSTリクエストを投げ、PackagePushRequestレコードを作成します。リクエストボディにはアップグレードしたいパッケージバージョンIDを指定します。

curl --location --request POST 'https://ap8.salesforce.com/services/data/v52.0/sobjects/packagepushrequest' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <アクセストークン>' \
--data-raw '{
"PackageVersionId": "04t0o000003Ys2CAAS"
}'

成功すると以下のようなレスポンスが返ってきます。このidはPackagePushJobの作成で使用するのでメモしておいてください。
image.png※実際のリクエストはPostmanで実行しています。上記コマンドはPostmanで生成したもので実行は試していません。

PackagePushJobの作成

インストール先組織のOrgKeyが必要なので、PackageSubscriberオブジェクトにSOQLを投げて調べます。

SELECT Id, MetadataPackageId, MetadataPackageVersionId,
InstalledStatus, OrgKey, OrgName, OrgType, OrgStatus, InstanceName,
SystemModstamp, ParentOrg
FROM PackageSubscriber
WHERE MetadataPackageId = '0330o000000JAlOAAW'

image.pngOrgKeyがわかったので、PackagePushRequestレコードを作成します。リクエストボディには作成したPackagePushRequestのIdと先ほど調べたOrgKeyを指定します。

curl --location --request POST 'https://ap8.salesforce.com/services/data/v52.0/sobjects/packagepushjob' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <アクセストークン>' \
--data-raw '{
"PackagePushRequestId": "0DV0o000000PFzA",
"SubscriberOrganizationKey": "00D2w000003MD4z"
}'

成功すると以下のようなレスポンスが返ってきます。
image.pngこれで指定した組織に指定したパッケージバージョンを転送アップグレードする準備ができました。

PackagePushRequestのStatusをPendingに更新

PackagePushRequestのStatusはこの時点ではCreatedになっています。これをPendingに更新すると転送アップグレードが開始されます。(なお、PackagePushRequestのScheduledStartTimeを指定すると指定時刻に転送アップグレードを開始するように設定できます。)

/services/data/v52.0/sobjects/packagepushrequest/<PackagePushRequestのId> に以下のようにPATCHリクエストを投げます。

curl --location --request PATCH 'https://ap8.salesforce.com/services/data/v52.0/sobjects/packagepushrequest/0DV0o000000PFzA' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <アクセストークン>' \
--data-raw '{
"Status": "Pending"
}'

成功すると204で空が返ってきます。

結果の確認

インストール先組織で確認してみると、ちゃんと0.1.1にバージョンアップされていることが確認できます。
image.pngPackagePushReuqestにSOQLを投げてみると、

SELECT Id, PackageVersionId, ScheduledStartTime, Status,
SystemModstamp, StartTime, EndTime, DurationSeconds
FROM PackagePushRequest

StatusがSucceededになっていることが確認できます。
image.png無事転送アップグレードができました。

jtowers/dxpack

いや、これを自分で実装するのはさすがに面倒だし、絶対誰か作っているだろうと調べてみたらありました。転送アップグレードを行えるsfdxプラグイン jtowers/dxpack です。

更新されておらず、GitHubスターも0なのですが、問題なく動きました。そのうち公式のsfdxコマンドに追加されると思うので、それまでのつなぎとしては使えるのではないかと思っています。

このプラグインで転送アップグレードをしてみましょう。

jtowers/dxpackのインストール

sfdx plugins:install @jtowers/dxpack

パッケージバージョン作成

転送アップグレードのためにパッケージバージョン0.1.2.1を作成します。
image.png

pushコマンド実行

0.1.2.1のバージョンIDを指定してpushコマンドを実行します。なお、ここで--subscriberfilterを使用するとアップグレード対象組織を絞ることができます。このオプションにはPackageSubscriberオブジェクトへのSOQLのWHERE句を指定できます。

sfdx dxpack:package:update:push --packageversionid 04t0o000003Ys2HAAS -w 20

結果の確認

インストール先組織で確認すると、ちゃんと0.1.2にバージョンアップしていることが確認できます。

1コマンドでできて非常に楽ですね!

注意点

試している中でいくつか注意すべき点が見つかったので、まとめておきます。

  • PackagePushRequestやPackagePushJobはApexではinsertできない。
  • インストールしてもPackageSubscriberレコードはすぐにはできない。10分くらいかかることがある。
  • promote直後にpush upgradeするとベータがインストールされることがあるようなので注意が必要。

まとめ

このように2GPの転送アップグレードは大変です。さすがに大変すぎるので、そのうち公式のsfdxコマンドに転送アップグレードが追加されると思います。それまでのつなぎとして@jtowers/dxpackは使えるのではないかと思っています。ただし、ご利用は自己責任でお願いします。

なお、Trailheadにも記載のあるCumulusCIも対応していましたが、AppExchangeアプリ開発には多機能すぎて向いてないと考えています。ただ、CumulusCIは未検証ですので、CumulusCIでAppExchangeアプリを開発した方がいましたらぜひ知見を共有していただきたいです。