LoginSignup
17
7

More than 3 years have passed since last update.

CircleCI で master ブランチとマージされたブランチでテストする

Last updated at Posted at 2019-04-26

やりたいこと

CircleCI で普通に checkout を用いてテストを流して通っても、master にマージ後にエラーになってしまうことがある。それを防ぐためにブランチを master にマージした状態でテストを流したい。

JenkinsやTravisだと選択したらできる程度の機能だが、現状のCircleCIだと頑張らないとできない(という認識)

事前知識

GitHub に pull request (PR) すると github 上では pull/xxx/headpull/xxx/merge というブランチが作られる。

pull/xxx/head が PR されたブランチの head と同じ状態のもので pull/xxx/merge がマージ対象のブランチとマージした状態のブランチになる。

なので、基本的には pull/xxx/merge のほうを CircleCI で checkout してテストを流せば良い。
しかし、CircleCI の checkout では pull/xxx/merge のほうを選ぶことができない。

また、pull/xxx/mergecheckout だと Conflict したかどうかの判断がしづらい。Pull Request を投げた瞬間は

  • Conflict しなかった場合: pull/xxx/merge が作られる
  • Conflict した場合: pull/xxx/merge が作られない

一度 pull/xxx/merge が作られた後に、git commit && push を積むと

  • Conflict しなかった場合: pull/xxx/merge が更新される
  • Conflict した場合: pull/xxx/merge が更新されない

という挙動をする。pull/xx/merge の存在確認だけでは Conflict 判定ができない。

やり方

結局こうなった。つまるところ git checkout master して git merge --no-commit pull/xxx/head で master に merge してあげている。

制約条件としては Pull Request にしていること。
その制約の代わりに fork されたリポジトリから Pull Request を送った場合でも動くようになっている。

if [[ -n "${CIRCLE_PULL_REQUEST}" ]]; then
    # TODO: Any ways to get PR destination branch dynamically?
    PR_DEST_BRANCH=master

    # CIRCLE_PR_NUMBER is available only if PR is created from a fork (unavailable if created from a branch).
    # So, manually construct it from CIRCLE_PULL_REQUEST environment variable.
    CIRCLE_PR_NUMBER=$(basename "${CIRCLE_PULL_REQUEST}")

    # Update PR refs for testing.
    FETCH_REFS="+${PR_DEST_BRANCH}:${PR_DEST_BRANCH}"
    FETCH_REFS="${FETCH_REFS} +refs/pull/${CIRCLE_PR_NUMBER}/head:pull/${CIRCLE_PR_NUMBER}/head"
    FETCH_REFS="${FETCH_REFS} +refs/pull/${CIRCLE_PR_NUMBER}/merge:pull/${CIRCLE_PR_NUMBER}/merge"

    # Retrieve the refs
    echo "git fetch -u origin ${FETCH_REFS}"
    git fetch -u origin ${FETCH_REFS}

    # Checkout PR destination branch and merge PR head ref.
    # If conflicts occur, exit with non-zero.
    echo "git checkout ${PR_DEST_BRANCH}"
    git checkout "${PR_DEST_BRANCH}"
    git config user.name 'foo' # Need to configure something to git merge
    git config user.email 'foo@example.com'
    echo "git merge --no-commit \"pull/${CIRCLE_PR_NUMBER}/head\""
    git merge --no-commit "pull/${CIRCLE_PR_NUMBER}/head"
fi

これを checkout のあとに書く

jobs:
  foobar:
    steps:
      - checkout
      - run:
          name: 'Checkout merged branch'
          command: |
            ここにインデントして書く

CircleCI 2.1 以上なら commands にしておくとよいかもしれない

version: 2.1

commands:
  checkout_merge:
    steps:
      - run:
          name: 'Checkout merged branch'
          command: |
            ここにインデントして書く

jobs:
  foobar:
    steps:
      - checkout
      - checkout_merge

参考文献

17
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
7