gitlab schedule で自動 MR open や close

# はしがき

自分が働いている会社の project では修正することの merge は以下の手順で行っています。
1. 修正のことをプログラマーお互いに MR を実行
1. MR 後、merge 向け branch に merge する
1. merge 向け branch を master に merge する

リリース向けの branch を感違えないように日付をしています。

しかし、gitlab ウェブから、毎日 merge 向けの branch を作ること、また、作っても merge しないと、削除することもあるので、手間がかかります。

そのために、毎日生成や削除する gitlab の pipeline を作ります。

# CICD とは？

https://en.wikipedia.org/wiki/CI/CD

https://www.redhat.com/en/topics/devops/what-is-ci-cd?cicd=32h281b

Red Hat には以下に紹介されています。

```
CI/CD (継続的インテグレーションおよび継続的デリバリー/デプロイメントの略) は、ソフトウェア開発ライフサイクルを最適化し、加速することを目的としています。
```

継続的インテグレーション(continuous integration)は**コードの変更**を **共有ソースコードリポジトリ**に **自動的かつ頻繁に取り込む**手法

継続的デリバリーまたはデプロイメント (CD) は 2 つの部分からなるプロセスで、**コード変更の統合、テスト、デリバリー**を指します。

build, テスト、デプロイ...　などを自動化することで、アプリケーションのエラーをよく発見したり、開発を高速化します。

# pipeline (パイプライン)とは？

https://ja.wikipedia.org/wiki/%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3%E5%87%A6%E7%90%86

```
パイプライン処理（パイプラインしょり、英: pipeline processing）とは、コンピュータ等において、処理要素を直列に連結し、ある要素の出力が次の要素の入力となるようにして、並行（必ずしも並列とは限らない）に処理させるという利用技術である。
```

pipeline はある業務の段階、手順、流れを直列に連結、**各段階の出力が次の段階に入力**します。

gitlab の pipeline を使ってみたら、yaml file の作成によって、段階を分けて実行することもできます。(今回はしません。)

# CICD pipeline とは？

https://www.redhat.com/ja/topics/devops/what-cicd-pipeline

```
継続的インテグレーションおよび継続的デプロイメント (CI/CD) パイプラインは、新しいバージョンのソフトウェアを提供するために実行する必要のある一連のステップです。
```

上書きした CICD と pipeline の概念を合わせて、**ある一連の pipeline 作業**をコードのビルド、テスト、デプロイなどを自動的に処理して、開発を推進するプロセスです。

# やり方

このやり方は gitlab の加入前提で行います。

1. gitlab project を作る
1. TOKEN 取得
1. TOKEN 適用
1. MR の branch を作る
1. MR 作成 pipeline
1. MR および branch 削除 pipeline
1. 結果
1. schedule 設定

## gitlab project を作る

多分初めに入ったら、からの空間ですが、create a project -> create blank project で作りましょう。

![スクリーンショット 2024-05-07 17.20.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/430bb544-f4f6-6f56-92c6-c9b9118ae9af.png)

![スクリーンショット 2024-05-07 17.21.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/5647bbab-23cd-4d77-bfee-f961c2a6b262.png)

## TOKEN 取得

project > settings > access tokens > add new token をクリックします。

![スクリーンショット 2024-05-07 18.02.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/d48b4b9f-d0fb-35be-2d0f-0c0050d3d3c0.png)

access token の expiration date やネームを設定します。

これは、merge request を assignee の nickname になります。

![スクリーンショット 2024-05-07 18.43.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/b6f960f3-408f-9e7c-f785-e22c93c1e075.png)

git push pull には owner の権限が必要なので、owner で設定します。

![スクリーンショット 2024-05-07 18.23.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/5e0ba247-3e73-5925-a0b2-b2302b419fc7.png)

登録した access key をセーブしましょう。

![スクリーンショット 2024-05-07 18.02.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/f05e2b5c-8faf-4a2e-bf60-d484968c1f2e.png)

## TOKEN 適用

project > setting > CI/CD に移動します。

![スクリーンショット 2024-05-07 17.38.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/032a7651-fca3-c6e0-b7bf-f5bfdaf41283.png)

閉まっている Variables を開けて、Add variable します。

![スクリーンショット 2024-05-07 17.39.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/266a1fbc-768a-c44c-a4e6-344fdc434dd1.png)

先、取得した token を value に入力してください。

![スクリーンショット 2024-05-07 17.39.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/7502572a-24ec-76e0-37f0-c8d29362049d.png)

その中、Variables に Add variable

## web page でやり方

### MR の branch を作る

project に入ったら、branch を作ることができます。

![スクリーンショット 2024-05-07 17.21.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/05dcf71e-6c3c-7fcb-1eef-49474f3ca3e7.png)
![スクリーンショット 2024-05-07 17.22.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/eec9367b-0b71-4004-e9d6-c529e1e8f7ff.png)

create/close branch を作りました！

### MR 作成 pipeline

project > build > Pipeline editor に入ります。

![スクリーンショット 2024-05-07 17.45.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/bca6bb91-4b02-aca2-4e09-ad7beb551847.png)

左上から branch を選択して、configure pipeline をクリックします。

![スクリーンショット 2024-05-07 17.45.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/89f1e129-bd0c-770b-2cce-75c73bfc8fbb.png)

では、何とか表示されますが、以下のコードを適当に変更して、入力してください。

```yaml
image: node:latest

ci:
  script:
    - git config --global user.email "your@address.com"
    - git config --global user.name "Ci Scheduler"
    - BRANCH_NAME="merge-$(date +%Y-%m-%d)"
    - git remote set-url origin https://gitlab-ci-token:$AUTOMATIC_MR_CREATE_CLOSE_TOKEN@gitlab.com/deliyami/hello_world.git
    - git fetch origin main
    - git checkout -b $BRANCH_NAME origin/main
    - git push -o merge_request.create -o merge_request.target=main -o merge_request.title="$BRANCH_NAME" origin $BRANCH_NAME 2>&1
```

そうしたら、commit します。

![スクリーンショット 2024-05-07 17.50.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/7f66f1f8-d328-9efe-0801-16bba6497c0d.png)

### MR 削除 pipeline

MR 生成と同じ configure pipeline に入力します。

```yaml
image: node:latest

ci:
  before_script:
    - apt-get -qq update
    - apt-get install -y jq
  script:
    - BRANCH_NAME="merge-$(date +%Y-%m-%d)"
    - 'MR_LIST=$(curl --header "PRIVATE-TOKEN: $AUTOMATIC_MR_CREATE_CLOSE_TOKEN" "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/merge_requests?state=opened")'
    - FIRST_MR_ID=$(echo "$MR_LIST" | jq -r ".[] | select(.title | test(\"$BRANCH_NAME\")) | .iid" | head -n 1)
    - MR_MERGED=$(echo "$MR_LIST" | jq -r ".[] | select(.iid == $FIRST_MR_ID) | .merged_at")
    - >
      if [ "$MR_MERGED" = "null" ]; then
        echo "MR $FIRST_MR_ID is not merged. Closing..."
        curl --request PUT --header "PRIVATE-TOKEN: $AUTOMATIC_MR_CREATE_CLOSE_TOKEN" "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/merge_requests/$FIRST_MR_ID/?state_event=close"
      else
        echo "MR ID $FIRST_MR_ID is already merged. Skipping close."
      fi
```

## local でやり方

git の基本的な設定(gitlab project に接続している account と同じこと)の前提で説明します。

### MR 作成 pipeline

```bash
$ git checkout -b create-merge-branch

$ vi .gitlab-ci.yml
```

以下のコードをコピペお願いします。

```yaml
image: node:latest

ci:
  script:
    - git config --global user.email "your@address.com"
    - git config --global user.name "Ci Scheduler"
    - BRANCH_NAME="merge-$(date +%Y-%m-%d)"
    - git remote set-url origin https://gitlab-ci-token:$AUTOMATIC_MR_CREATE_CLOSE_TOKEN@gitlab.com/deliyami/hello_world.git
    - git fetch origin main
    - git checkout -b $BRANCH_NAME origin/main
    - git push -o merge_request.create -o merge_request.target=main -o merge_request.title="$BRANCH_NAME" origin $BRANCH_NAME 2>&1
```

```bash
$ git commit -a

$ git push origin create-merge-branch
```

### MR 削除 pipeline

```bash
$ git checkout -b close-merge-branch
```

```bash
$ vi .gitlab-ci.yml
```

以下のコードをコピペお願いします。

```yaml
image: node:latest

ci:
  before_script:
    - apt-get -qq update
    - apt-get install -y jq
  script:
    - BRANCH_NAME="merge-$(date +%Y-%m-%d)"
    - 'MR_LIST=$(curl --header "PRIVATE-TOKEN: $AUTOMATIC_MR_CREATE_CLOSE_TOKEN" "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/merge_requests?state=opened")'
    - FIRST_MR_ID=$(echo "$MR_LIST" | jq -r ".[] | select(.title | test(\"$BRANCH_NAME\")) | .iid" | head -n 1)
    - MR_MERGED=$(echo "$MR_LIST" | jq -r ".[] | select(.iid == $FIRST_MR_ID) | .merged_at")
    - >
      if [ "$MR_MERGED" = "null" ]; then
        echo "MR $FIRST_MR_ID is not merged. Closing..."
        curl --request PUT --header "PRIVATE-TOKEN: $AUTOMATIC_MR_CREATE_CLOSE_TOKEN" "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/merge_requests/$FIRST_MR_ID/?state_event=close"
      else
        echo "MR ID $FIRST_MR_ID is already merged. Skipping close."
      fi
```

```bash
$ git commit -a

$ git push origin close-merge-branch
```

## 結果

### create MR

![スクリーンショット 2024-05-07 19.27.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/a7c247da-7f6e-03ec-c33a-e9f39e43c606.png)

### close MR

![スクリーンショット 2024-05-07 19.29.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/ecfa0f0f-1b53-69b6-eeb8-aeb96ed93fe6.png)

## schedule 設定

project > build > pipeline schedules に遷移して、新しい schedule を作ります。

![スクリーンショット 2024-05-07 19.26.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/51e7b87c-7e99-bb10-25ea-4ca8e0094cd7.png)

ここから cron の設定する必要があります。

月曜日から金曜日まで、朝9時に MR を作って、午後6時になったら、MR を削除します。

|create|close|
|-|-|
|![スクリーンショット 2024-05-07 19.36.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/5a5644a4-ffae-1043-1585-915bde50cf3d.png)|![スクリーンショット 2024-05-07 19.36.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/5882ea96-7343-c21c-9bf9-fba8da8fd456.png)|

![スクリーンショット 2024-05-07 19.37.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582489/4306e545-5856-43c3-011e-19ad3352e6bd.png)

このように設定されました。\
cron に設定した時間にも実行しました、強制的に実行することもできるので、便利ですね。

# まとめ

CICD 作ることは、普通に考えるコードと違うので、実行することは手間がかか利ますが、作成すれば、楽になるます。

# 参考したページ

https://git-scm.com/docs/git-push

https://docs.gitlab.com/ee/ci/variables/predefined_variables.html

https://docs.gitlab.com/ee/api/branches.html#delete-repository-branch

https://docs.gitlab.com/ee/topics/cron/