Salesforce B2C Commerce sfcc-ciについて


※ これから記載する事項は、私が所属する会社とは一切関係のない事柄です。

この記事では B2C Commerce の CI/CD で利用されるコマンドツール sfcc-ci についてインストール方法やツールの利用方法を紹介します。


## sfcc-ciとは？

[Github](https://github.com/SalesforceCommerceCloud/sfcc-ci)に公開されているSalesforceのB2C Commerceの環境に対してCI/CDを実現するためのオープンソースツールです。
このツールを利用する方法は２パターンあります。今回の記事ではコマンドラインのみ取り扱います。Javascript APIの利用方法は[Github](https://github.com/SalesforceCommerceCloud/sfcc-ci)をご覧ください。また、 Javascript API を利用した [CI/CD のツール](https://github.com/SalesforceCommerceCloud/build-suite) もあります。

#### 1. コマンドライン

```sh
# 例
sfcc-ci code:deploy
```

#### 2. Javascript API

```javascript
// 例
const sfcc = require('sfcc-ci');
sfcc.auth.auth(client_id, client_secret, callback);
```



## 前提

* Mac OSを利用して説明します

## sfcc-ciの利用方法

### 1. インストール

1. 自身の環境に合わせた最新のバイナリリソースを[Github](https://github.com/SalesforceCommerceCloud/sfcc-ci/releases/latest)からダウンロードします。今回はMac OSを利用するので、 `sfcc-ci-macos` をダウンロードします。
2. ダウンロードしたバイナリファイルを自身のローカルマシンの任意の場所におきます。
3. 下記コマンドで権限を変更します。
     `chmod +x ./sfcc-ci-macos
        `
4. さらに下記コマンドでパスの通ったディレクトリにファイルを移動します。
     `sudo mv ./sfcc-ci-macos /usr/local/bin/sfcc-ci`
5. 下記コマンドでヘルプが表示されれば完了です。
     `sfcc-ci --help`



### 2. Account Managerでの設定

* [Add API Client](https://documentation.b2c.commercecloud.salesforce.com/DOC1/index.jsp?topic=%2Fcom.demandware.dochelp%2Fcontent%2Fb2c_commerce%2Ftopics%2Faccount_manager%2Fb2c_account_manager_add_api_client_id.html)の手順に沿ってクライアントを作成してください。その際、Redirect URIs には 、`http://localhost:8080/`。Default Scopes には、`roles` `tenantFilter` `profile`を改行して入れてください。
* この際設定したID/パスワードは後にも利用しますのでメモしておいてください。



### 3. Business Managerでの設定

#### OCAPIの設定

1. Business Manager で **管理 > サイトの開発 > Open Commerce API 設定** に遷移
2. 「タイプの選択:」セレクトボックスでは `データ`を選択
3. 「範囲の選択:」セレクトボックスでは、`グローバル(組織全体)`を選択
4. 下記のJSONを`my_client_id` 部分を上記のAccount Managerで作ったクライアントのIDにリプレースし追加。すでに追加されている場合は、clients のリストの内容を追加。

```json
    {
      "_v": "19.5",
      "clients":
      [
        {
          "client_id": "my_client_id",
          "resources":
          [
            {
              "resource_id": "/code_versions",
              "methods": ["get"],
              "read_attributes": "(**)",
              "write_attributes": "(**)"
            },
            {
              "resource_id": "/code_versions/*",
              "methods": ["patch", "delete"],
              "read_attributes": "(**)",
              "write_attributes": "(**)"
            },
            {
              "resource_id": "/jobs/*/executions",
              "methods": ["post"],
              "read_attributes": "(**)",
              "write_attributes": "(**)"
            },
            {
              "resource_id": "/jobs/*/executions/*",
              "methods": ["get"],
              "read_attributes": "(**)",
              "write_attributes": "(**)"
            },
            { 
              "resource_id": "/sites/*/cartridges", 
              "methods": ["post"], 
              "read_attributes": "(**)", 
              "write_attributes": "(**)"
            },
            {
              "resource_id":"/role_search",
              "methods":["post"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/roles/*",
              "methods":["get"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/roles/*/user_search",
              "methods":["post"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/roles/*/users/*",
              "methods":["put","delete"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/user_search",
              "methods":["post"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/users",
              "methods":["get"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/users/*",
              "methods":["put","get","patch","delete"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            }
          ]
        }
      ]
    }
```



#### Web DAVの設定

1. Business Manager で **管理 > 組織 > クライアントの WebDAV 許可** に遷移
2. 下記のJSONを`my_client_id` 部分を上記のAccount Managerで作ったクライアントのIDに、`<your-` で始まる部分を自身の環境に合わせてリプレースし追加。すでに追加されている場合は、clients のリストの内容を追加。

```json
    {
      "clients":
      [
        {
          "client_id": "my_client_id",
          "permissions":
          [
            {
              "path": "/impex",
              "operations": [
                "read_write"
              ]
            },
            {
              "path": "/cartridges",
              "operations": [
                "read_write"
              ]
            },
            {
              "path": "/static",
              "operations": [
                "read_write"
              ]
            },
            {
              "path": "/catalogs/<your-catalog-id>",
              "operations": [
                "read_write"
              ]
            },
            {
              "path": "/libraries/<your-library-id>",
              "operations": [
                "read_write"
              ]
            },
            {
              "path": "/dynamic/<your-site-id>",
              "operations": [
                "read_write"
              ]
            }
          ]
        }
      ]
    }
```

## 

### 4. 認証

Account Managerから作成したAPIクライアントのID(client_id)とパスワード(client_secret)を利用して認証することが可能です。

#### ブラウザログインを利用して認証する方法

下記のコマンドを実行すると、ブラウザが開くので、アカウントManagerにログインして認証する。

```sh
sfcc-ci auth:login <client_id>
```

#### コマンドのみで認証する方法

下記のコマンドを実行するとブラウザの立ち上がりなく認証を行う。

```sh
sfcc-ci client:auth <client_id> <client_secret>
```

#### 引数ではなく変数で定義する場合

```sh
 export SFCC_OAUTH_CLIENT_ID=<client_id>
 export SFCC_OAUTH_CLIENT_SECRET=<client_secret>
 sfcc-ci client:auth
```




## CI／CDでよく利用されそうなコマンド

`sfcc-ci --help` で全てのコマンドを確認できますが、CI/CDよく利用されそうなコマンドを下に記載しておきます。
それぞれのコマンドにさらに `sfcc-ci code:deploy --help` のように `--help` をつけれはコマンドの利用方法を確認することができます。

#### ソースコードのデプロイ

```sh
sfcc-ci code:deploy [options] <archive>
```

#### バージョンのアクティブ化

```sh
sfcc-ci code:activate [options] <version>
```

#### サイト情報のアップロード

```sh
sfcc-ci instance:upload [options] <archive> 
```

#### サイト情報のインポート

```sh
sfcc-ci instance:import [options] <archive> 
```

#### カートリッジパスの追加

```sh
sfcc-ci cartridge:add [options] <cartridgename>
```

#### ジョブの実行

```sh
sfcc-ci job:run [options] <job_id> [job_parameters...]
```

#### ジョブのステータスの確認

```sh
sfcc-ci job:status [options] <job_id> <job_execution_id>
```



## サイトデータとカートリッジをデプロイするシェルを作ってみる

### 作成するシェルの仕様

`deploy.sh`というシェルを作成し、[SFRAのGithub](https://github.com/SalesforceCommerceCloud/storefront-reference-architecture)（要Account Managerアカウント）から取得したソースコードのルートディレクトリに配置する。
* カートリッジは `/cartridges` 配下に設置する
* サイトデータは `/sample_sitedata` に配置する
* 取り込むサイトデータとして `TestDeploy` というカスタムオブジェクトを作成する
* カートリッジのバージョンは `version_{タイムスタンプ}`　とする
* デプロイと同時にバージョンを有効化する
* 実行中、一時的に `/build` ディレクトリを作成する
* JS、CSSファイルのビルドは今回は扱わない
![スクリーンショット 2022-06-01 11.12.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/5dc760c2-0146-e869-8b27-bfed085f39e5.png)




### 作成したシェル

利用の際はコード内の下記の変数に値を入れてください。

* SFCC_OAUTH_CLIENT_ID
    * [2.Account Managerでの設定](https://qiita.com/syunyama/items/bdb67b187df2e6c25972#2-account-manager%E3%81%A7%E3%81%AE%E8%A8%AD%E5%AE%9A) で設定したID
* SFCC_OAUTH_CLIENT_SECRET
    * [2.Account Managerでの設定](https://qiita.com/syunyama/items/bdb67b187df2e6c25972#2-account-manager%E3%81%A7%E3%81%AE%E8%A8%AD%E5%AE%9A) で設定したパスワード
* HOST
    * デプロイ先のホスト名

```sh
#!/bin/sh
set -eu
# set -x

# シェルのあるディレクトリパスの取得
THIS_FILE_DIR=$(cd $(dirname $0); pwd)

# カートリッジとサイトデータのディレクトリ名の定義
CARTRIDGE_DIR_NAME="cartridges"
SITEDATA_DIR_NAME="sample_sitedata"

# カートリッジとサイトデータのディレクトリパスとバージョンの定義
CARTRIDGE_DIR=$THIS_FILE_DIR"/"$CARTRIDGE_DIR_NAME
SITEDATA_DIR=$THIS_FILE_DIR"/"$SITEDATA_DIR_NAME
VERSION="version_"`date +'%Y%m%d%H%M%S'`

# 一時ディレクトリの定義と作成
TMP_DIR=$THIS_FILE_DIR"/build"
mkdir -p $TMP_DIR

# 一時ディレクトリにソースを移動
cp -rf $CARTRIDGE_DIR $TMP_DIR
cp -rf $SITEDATA_DIR $TMP_DIR

# 一時ディレクトリでzip圧縮
cd $TMP_DIR
mv $CARTRIDGE_DIR_NAME $VERSION
zip -r $VERSION".zip" $VERSION
zip -r $SITEDATA_DIR_NAME".zip" $SITEDATA_DIR_NAME

# シェルのあるディレクトリパスに戻る
cd $THIS_FILE_DIR

# sfcc-ciの認証のための環境変数（今回は一旦ソース上にベタ書き）
export SFCC_OAUTH_CLIENT_ID=""
export SFCC_OAUTH_CLIENT_SECRET=""
HOST="XXXXXX.sandbox.us00.dx.commercecloud.salesforce.com"

# sfcc-ciのデバッグを利用
export DEBUG=true

# sfcc-ciの認証
sfcc-ci client:auth

# サイトデータのデプロイとソースコードのアクティブ化
sfcc-ci instance:upload $TMP_DIR"/"$SITEDATA_DIR_NAME".zip" -i $HOST
sfcc-ci instance:import $SITEDATA_DIR_NAME".zip" -fjs -i $HOST

# カートリッジのデプロイとソースコードのアクティブ化
sfcc-ci code:deploy $TMP_DIR"/"$VERSION".zip" -i $HOST
sfcc-ci code:activate $VERSION -i $HOST

# 一時ディレクトリの削除
rm -rf $TMP_DIR
```



### デプロイの確認

バージョンが作成され、アクティブになっている。
![スクリーンショット 2022-05-30 13.59.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/d2f726c6-6f1d-3c84-1f12-00556aab47ee.png)


`TestDeploy` というカスタムオブジェクトがサイトインポートされて作成されている。
![スクリーンショット 2022-05-30 14.42.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/6a8550c7-da71-a074-a3fa-2dd7175ca4af.png)