きょこみのーと

元六本木でGo書いてました。今はVRでGo書いてます。

monorepoでCircleCIを使ってherokuへのdeployをする

はじめに

かなり特殊な構成なので自分以外には役に立たないかもしれませんが...

個人開発のプロジェクトをmonorepoで開発しているのですが、apiサーバーがherokuなので単純にmasterをそのままherokuにpushするとめちゃ不要なファイルなどが含まれてしまうという問題がありました。

gitignoreすればいいとは思いつつも、heroku用のgitignoreとgithubで管理するコード用のgitignoreみたいなことをするのも辛いので、 git worktree を使ってheroku用のブランチへのpushを行い、それをherokuにもpushするというアプローチにしました。(以下の図のようなイメージ)

herokuまでのdeployの流れ

f:id:kyokomi:20191019212317p:plain
herokuまでのdeployの流れ

CircleCIの各jobの説明

  • build jobは普通にgolangのbuildやtestなどを行う
  • git_push jobは deploy.sh を実行して、 heroku用のworktreeを作成し github にpushします
    • deploy.sh の中から呼び出している deploy_generate_file.sh で必要なファイルだけをコピーするようにしてます
    • githubheroku ブランチへapiサーバーのdeployに必要なファイルだけがpushされ、またCircleCIが呼び出されます
  •   一度ここでCircleCIのworkflowは途切れてしまいます
  • heroku_deploy jobによって herokuのgitリポジトリに対してpushを行います
    • このpushでheroku側でdeployが行われます

登場するファイル(参考までに

deploy.sh

#!/bin/bash

set -x

# shellcheck disable=SC2006
if [ "`git status -s`" ]
then
    echo "The working directory is dirty. Please commit any pending changes."
    exit 1;
fi

echo "Deleting old publication"
rm -rf heroku
mkdir heroku
git worktree prune
rm -rf .git/worktrees/heroku/

echo "Checking out heroku branch into heroku"
git worktree add -B heroku heroku origin/heroku

echo "Removing existing files"
rm -rf heroku/*

echo "Generating site"
sh ./deploy_generate_file.sh

echo "Updating heroku branch"
cd heroku && git add --all && git commit -m "Publishing to heroku (deploy.sh)"

echo "Pushing to github"
git push -u origin heroku

deploy_generate_file.sh

#!/bin/bash

set -x

cp -r .circleci heroku       # circleCIが動くようにするため
cp -r api heroku             # このディレクトリにapiサーバーのコードが入ってます(main.goとかとか)
cp go.mod go.sum heroku      # 訳あってgo.modが上位階層にあるのでそれもコピー
cp app.json Procfile heroku  # herokuのdeployに必要なファイル
cd heroku && go mod vendor   # heroku側でfetchしなくていいように(deployを早くするため)にgo mod vendor

circleci/config.yml

# Golang CircleCI 2.1 configuration file
version: 2.1

jobs:
  build:
    docker:
      - image: circleci/golang:1.13
    environment:
      GO111MODULE:     "on"
    working_directory: /go/src/github.com/kyokomi/webapp-sandbox
    steps:
      - checkout
      - run: go get -u golang.org/x/lint/golint
      - run: go get -u golang.org/x/tools/cmd/goimports
      - run: make test_all
      - run: make build_api

  git_push:
    docker:
      - image: circleci/golang:1.13
    environment:
      GO111MODULE:     "on"
    working_directory: /go/src/github.com/kyokomi/webapp-sandbox
    steps:
      - checkout
      - run:
          name: git settings
          command: |
            git config --global user.email kyokomidev@gmail.com
            git config --global user.name circleci

      - run: sh deploy.sh

  heroku_deploy:
    docker:
      - image: buildpack-deps:trusty
    environment:
        HEROKU_APP_NAME: "kyokomi-webapp-sandbox"
    steps:
      - checkout
      - run:
          name: Deploy Master to Heroku
          command: |
            git push https://heroku:$HEROKU_API_KEY@git.heroku.com/$HEROKU_APP_NAME.git master

workflows:
  api_build_and_deploy:
    jobs:
      - build:
          filters:
            branches:
              ignore: heroku
      - git_push:
          requires:
            - build
          filters:
            branches:
              only:
                - master
      - heroku_deploy:
          filters:
            branches:
              only:
                - heroku