GitLab CIで生成されたファイルをリポジトリーにコミットし MR を作成する方法


# この記事は？

社内のGitLab CIでbotを動かしているのですが、成果物をリポジトリに残したいことがあります。
例としては「利用しているsubmoduleがアップデートされたときにMRリンクまで作って通知するbotがほしい」というものがありました。

以下の記事がとても参考になりました。この記事では元の記事からの自分のケースの差分について書きます。

- GitLab CI/CDパイプラインで生成されたファイルをGitLabのリポジトリーにコミット(Push)し直す方法 - Qiita
  - ありがとうございます。

https://qiita.com/ynott/items/8cb3b3995cb41ca78437


## 元記事との差分項目

元記事では以下の4項目になっています。

1. SSH鍵を作成します
2. プロジェクトのリポジトリのDeploy KeyにSSH公開鍵を登録します
3. プロジェクトのVariableにSSH秘密鍵を登録します
4. `.gitlab-ci.yml` を書く

1,2,3 については元記事と同じ手順でした。4 の`.gitlab-ci.yml`中のスクリプトが少し差分があります。

## 「`.gitlab-ci.yml` を書く」の差分部分

差分は以下の箇所です。

1. core.sshCommandでsshのホスト確認をスキップするようにした。
2. sshにポートを指定した。
3. 別ブランチにコミット&Pushするようにした。
4. 通知APIを使って、マージリクエスト用のリンクをチャットに通知するようにした。

## `.gitlab-ci.yml`

```yaml
  variables:
    # sshポート
    GITLAB_CI_SERVER_SSH_PORT: 22
  script:
    # git, openssh のインストール(dockerイメージによって変える)
    - apt-get update -q
    - apt-get install -y git curl
    - apk update && apk add --no-cache openssh
    # ssh の設定
    - eval "$(ssh-agent -s)"
    # リポジトリのDeploy Keysで追加したsshキーをVariablesで指定する。
    - echo "${SSH_PRIVATE_KEY}" | ssh-add - > /dev/null
    # git config の設定
    - git config --global user.name "hogehoge-runner@example.jp"
    - git config --global user.email "hogehoge-runner@example.jp"
    # 差分1. core.sshCommandでsshのホスト確認をスキップするようにした。
    - git config --global core.sshCommand "ssh -oStrictHostKeyChecking=no"
    # 差分2. sshにポートを指定した。
    - git remote set-url --push origin ssh://git@$CI_SERVER_HOST:$GITLAB_CI_SERVER_SSH_PORT/$CI_PROJECT_PATH.git
    - git checkout $CI_COMMIT_REF_NAME
    - git pull
    # ========================
    # スクリプト実行箇所( サブモジュール更新は git submodule update --remote {ブランチ名} )
    # ========================
    - git add .
    # 差分3. 別ブランチにコミット&Pushするようにした。
    - TODAY=`date +%Y%m%d_%H%M`
    - BRANCH=update/ci_${TODAY}
    - git checkout -b ${BRANCH}
    - git commit -m "[ci skip] diff commit ${TODAY}"
    - git push --set-upstream origin ${BRANCH}
    # 差分4. 通知APIを使って、マージリクエスト用のリンクをチャットに通知するようにした。
    - curl CHATWORK_API -d "https://$CI_SERVER_HOST/$CI_PROJECT_PATH/-/merge_requests/new?merge_request%5Bsource_branch=${BRANCH} [hr]サブモジュールが更新されました。"
```

## 差分1. core.sshCommandでsshのホスト確認をスキップするようにした。

```diff
+git config --global core.sshCommand "ssh -oStrictHostKeyChecking=no"
```

通常のsshでは`.ssh/known_hosts`に対象サーバがないとホスト確認が必要でCIがストップしてしまいますが、このコンフィグを入れることでホスト確認をスキップできます。

元記事のコメント欄で会話されていることを反映しました。

## 差分2. sshにポートを指定した。

```diff
-git remote set-url --push origin git@$CI_SERVER_HOST:$CI_PROJECT_PATH.git
+git remote set-url --push origin ssh://git@$CI_SERVER_HOST:$GITLAB_CI_SERVER_SSH_PORT/$CI_PROJECT_PATH.git
```

使っているGitLabは社内でホストしているものであり、sshポートをデフォルトから変えているので対応が必要でした。`$GITLAB_CI_SERVER_SSH_PORT`はvariablesで個別定義しました。

GitLab CIでは以下のように環境変数定義がありますが、sshポートの定義はなかったので個別定義が必要でした。

- https://docs.gitlab.com/ee/ci/variables/

## 差分3. 別ブランチにコミット&Pushするようにした。

```diff
+TODAY=`date +%Y%m%d_%H%M`
+BRANCH=update/ci_${TODAY}    
+git checkout -b ${BRANCH}
+git commit -m "[ci skip] diff commit ${TODAY}"
+git push --set-upstream origin ${BRANCH}
```

別ブランチにコミット&Pushするようにしました。
ブランチ名に日時を入れることでブランチ名のコンフリクトが発生しないようにしています。

## 差分4. 通知APIを使って、マージリクエスト用のリンクをチャットに通知するようにした。

```diff
# ※この例のcurlはイメージです。
+curl CHATWORK_API -d
+  "https://$CI_SERVER_HOST/$CI_PROJECT_PATH/-/merge_requests/new?merge_request%5Bsource_branch=${BRANCH} 
+   サブモジュールが更新されました。"
```

`https://$CI_SERVER_HOST/$CI_PROJECT_PATH/-/merge_requests/new?merge_request%5Bsource_branch=${BRANCH}` がブランチのMRを作るリンクとなります。
チャットでリンクをクリックしたらすぐにMRを作れるようにしました。

# ほかやりたいこと

これでbotの通知を見たらすぐにMR作成をすることができるようになりました。

今回例に挙げたサブモジュールが更新されたときの対応はほとんど定型作業だったので、CIにまかせることで手間が減りよかったです。

現在はMR作成用リンクを通知していますが、GitLab API を利用することでMRを作ることもできます。
手間が減りそうなので、今後利用を検討したいです。

https://docs.gitlab.com/ee/api/merge_requests.html#create-mr