ここんにちはPR TIMES開発本部のインターンの Chanoknan です。
PR TIMESについてフロントエンドのCI パイプラインを改善についてお話しします。
PR TIMESでは、Reactで書かれたすべてのフロントエンドのコードのコードはMonorepo として管理しています。 そのMonorepoのCI パイプラインは、システム全体のLint、Type Check、Test、Buildを行うようにCIパイプラインが設定されており、これにはかなりの時間がかかり、GitHub ActionsのBillable Timeにも影響を与えます。これを緩和するため、CI処理時間を減らすためのいくつかの戦略を実施しています。詳細については、以下の記事を参照してください。

しかし、リポジトリが大きくなるにつれて、CIの時間も長くなりました。これに対処するために、CIパイプラインをさらに改善しました。何を行ったかをお話します。
改善できる点を特定する
この作業に取り組む前、私はCIパイプラインやGitHub Actionsについて詳しくありませんでした。そのため、調査は先輩エンジニアによって行われました。分析の結果、改善すべき2つの領域を特定しました。
- Pull Requestに差分がある場合にのみStorybookのテストを実行するようにする
- 必要な場合にのみPR TIMES EditorをIntegration testを実行するようにする
先輩エンジニアにPR TIMES EditorのIntegration testを確認してもらい、自分はPull Requestに差分がある場合にのみStorybookのテストを実行するように設定を任されました。
Pull Requestに差分がある場合にのみStorybookのテストを実行するようにする
PR TIMESでは、StorybookをUI開発ツールとしてだけでなく、UIコンポーネントのUnit test にも使用しています。
現在は500以上の*.stories.tsxファイルを持っており、Storybookのテスト実行にはCIパイプラインで9〜10分かかります。これを改善するために行った方法は次の通りです。
まず、StorybookのテストがPull requestに変更がある場合にのみ実行されるようにする必要があります。元々の設定では、WorkflowをTriggerされるとき、dependneciesをインストール、Playwrightのインストール、Storybookのビルド、そしてテストの実行を行っています。以下は、公式ドキュメントで紹介されているワークフローの例です。
# .github/workflows/storybook-tests.yml
name: 'Storybook Tests'
on: push
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Install dependencies
run: yarn
- name: Install Playwright
run: npx playwright install --with-deps
- name: Build Storybook
run: yarn build-storybook --quiet
- name: Serve Storybook and run tests
run: |
npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
"npx http-server storybook-static --port 6006 --silent" \
"npx wait-on tcp:6006 && yarn test-storybook"
テストが必要なときだけ実行されるようにすることで、CIパイプラインでのテストにかかる時間を大幅に削減できます。
これを実現するために、tj-actions/changed-files を使用して変更のないディレクトリを除外し、変更のあるディレクトリでのみStorybookのテストを実行するようにしました。実装方法は以下の通りです。
steps:
- name: Assess need for feature tests
id: filter
uses: tj-actions/changed-files@v44
with:
files_yaml: |
src/features/company-detail:
- apps/prtimes/src/features/company-detail/**
src/features/company-registration:
- apps/prtimes/src/features/company-registration/**
src/features/dashboard:
- apps/prtimes/src/features/dashboard/**
src/features/dashboard-renewal:
- apps/prtimes/src/features/dashboard-renewal/**
src/features/media-list:
- apps/prtimes/src/features/media-list/**
src/features/media-list-renewal:
- apps/prtimes/src/features/media-list-renewal/**
src/features/press-release-editor:
- apps/prtimes/src/features/press-release-editor/**
src/features/press-release-editor-v3:
- apps/prtimes/src/features/press-release-editor-v3/**
src/features/press-release-list:
- apps/prtimes/src/features/press-release-list/**
src/features/preview-press-release:
- apps/prtimes/src/features/preview-press-release/**
src/features/price:
- apps/prtimes/src/features/price/**
src/components:
- apps/prtimes/src/components/**
src/templates:
- apps/prtimes/src/templates/**
src/layouts:
- apps/prtimes/src/layouts/**
- name: Build Storybook
if: steps.filter.outputs.modified_keys != ''
working-directory: ./apps/prtimes
run: pnpm build-storybook --quiet
- name: Install Playwright
if: steps.filter.outputs.modified_keys != ''
run: pnpm exec playwright install --with-deps chromium
- name: List all changes
if: steps.filter.outputs.modified_keys != ''
id: changed_dirs
run: |
CHANGED_DIRS=$(echo "${{ steps.filter.outputs.modified_keys }}")
echo "changed_dirs=$CHANGED_DIRS" >> $GITHUB_OUTPUT
- name: Test Storybook
if: steps.filter.outputs.modified_keys != ''
env:
CHANGED_DIRS: ${{ steps.changed_dirs.outputs.changed_dirs }}
run: |
pnpm concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
"pnpm http-server storybook-static --port 6006 --silent" \
"pnpm wait-on tcp:6006 && pnpm test-storybook $CHANGED_DIRS"
この設定により、変更のある機能に対してのみStorybookのテストが実行されるため、CIでのテストにかかる時間が3~4分に削減されます。
必要な場合にのみPR TIMES EditorをIntegration testを実行するようにする
新しいUIと機能を含む新PR TIMES Editorがリリースされて以来、Integration testのカバレッジが大幅に増加しました。その結果、各テストの実行には現在14〜15分かかり、CIパイプラインの最大のボトルネックとなっています。
このタスクは私が担当したわけではありませんが、エディタに関連する変更がある場合にのみテストを実行することがわかります。これも tj-actions/changed-filesを使用して実現されています。
- name: Assess need for all tests
id: filter-editor
uses: tj-actions/changed-files@v44
with:
files: |
pnpm-lock.yaml
common/press-release-ui/**
common/prtimes-company-admin-components/**
packages/openapi/**
packages/prtimes-basis/**
apps/prtimes/src/features/press-release-editor/**
apps/prtimes/src/features/press-release-editor-v3/**
apps/prtimes/src/features/press-release-list/**
apps/prtimes/src/components/unfixed-new-ui/**
tests/prtimes/**
editor-integration-test:
timeout-minutes: 30
runs-on: ubuntu-22.04
needs: [install-deps]
if: steps.filter-editor.outputs.any_modified != 'true'
steps:
- name: Get installed Playwright version
working-directory: tests/prtimes
id: playwright-version
run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package.json').devDependencies['@playwright/test'])")" >> $GITHUB_OUTPUT
- name: Cache playwright binaries
uses: actions/cache@v4
id: playwright-config-cache
with:
path: ~/.cache/ms-playwright
key: playwright-config-cache-${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }}
- name: Install Playwright
if: steps.playwright-config-cache.outputs.cache-hit != 'true'
working-directory: tests/prtimes
run: pnpm dlx playwright@${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }} install --with-deps chromium
- name: Run Playwright
run: pnpm test:ci:editor
working-directory: tests/prtimes
これにより、エディタのIntegretion Testが必要な場合にのみ実行されることが保証され、CI時間とBillable Timeを大幅に削減することができます。
結果
これらの変更を実装した後、CI時間とBillable timeの両方で大幅な削減を確認しました。
エディタの統合テストが必要ない場合、CI時間は16分から8分に、Billable timeは40分から17分に減少しました。
Before

After

まとめ
XOのcache実装にはいくつかの課題があって作業保留していますが、それでもCIの時間とBillable timeを大幅に削減することができました。CIパイプラインを改善し、必要な場合にのみStorybookとエディタのIntegration Testを実行することで、CI時間とBillable timeを半減させることに成功しました。この作業を通じて、GitHub Actionsについての理解を深めることができました。
この記事をお読みいただき、ありがとうございました。少しでも皆さんの参考になれば幸いです。

