0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【個人開発】AIに頼り切るのをやめて、自力でGitHub ActionsのCI(Lint)を導入してハマった話

0
Posted at

はじめに

4月から 個人開発 をはじめて早1ヵ月。
AIコーディングエージェントによる実装を経て、「中身が全くわからない。これではまずい。」と思い手作業でのコーディングへ変更しました。
時間は掛かってますがそのお陰で実務では触らない環境へ慣れてきました。

でも日々、「CI/CD 触ってみたいな。」という思いがあったので、 なら個人開発でやったらいいじゃん! と思い試してみました。

構成のイメージは下記になります。

.
├── .github/workflows/main.yml
├── docker-compose.yml
└── frontend/      <--- CIのworking-directory
    ├── .eslintrc.cjs
    ├── package.json
    └── src/

Gemini に聞いてみると「ルートディレクトリに.github\workflowsフォルダを作成してmain.ymlを配置するだけ」と教えてもらったので早速試してみました!

早とちりコミット

この手軽さ故に、 main.yml を作成し lint をインストール。
packedge.json への反映も済んだのですぐにコミットしました。
すると lintスクリプトが見当たらない というエラーが出ました。

image.png

Gemini の「ルートディレクトリに.github\workflowsフォルダを作成してmain.ymlを配置するだけ」

という説明を鵜呑みにしてしまいました。
原因はローカルからコンテナ内へファイル連携している層が1つずれていた為でした。

.eslintrc.cjsfrontend 配下へ移動する事により解決しました。

docker-compose.yml
  frontend:
    build: ./frontend
    depends_on:
      - backend
    ports:
      - "5173:5173"
    volumes:
      - ./frontend:/app # ここが原因

Docker を使っていると陥りがちの罠でした。
AIコーディングエージェントに頼らないからこそ理解できました。

ローカル(Docker環境)では動くけど、CI(GitHub Actions環境)ではパスが違っていて動かなかった
際のトラブルシューティングの1つになればと思います。

ローカルでのエラー解決

コミットが早かったので初歩的なエラーで止まってしまいました。
なので今度はローカルできちんと動かしてみます。

すると2種類のエラーが出てきました。

  • 使われていない変数がある
  • パースができない
PS C:\dev\ws\docker\Vi-va-Link-detail> docker compose run --rm frontend npm run lint
[+]  2/2t 2/22
 ✔ Container vi-va-link-detail-db-1      Healthy                                                                                                                                                                              0.5s
 ✔ Container vi-va-link-detail-backend-1 Running                                                                                                                                                                              0.0s
Container vi-va-link-detail-frontend-run-f1cf6394605d Creating 
Container vi-va-link-detail-frontend-run-f1cf6394605d Created 

> bus-logistics-frontend@0.0.1 lint
> eslint . --ext .vue,.js --fix


/app/src/router/index.js
  29:24  error  '_from' is defined but never used  no-unused-vars

/app/src/views/ScheduleCreate.vue
  249:7  error  '_debounceTimers' is assigned a value but never used  no-unused-vars

/app/src/views/ScheduleSearch.vue
  355:10  error  '_toBBox' is defined but never used  no-unused-vars

/app/src/views/__tests__/BookingList.test.js
  124:30  error  Parsing error: Identifier directly after number

/app/src/views/__tests__/Tracking.test.js
  110:30  error  Parsing error: Identifier directly after number

✖ 5 problems (5 errors, 0 warnings)

まず最初の 「使われていない変数がある」 ですが、
ruleを作ってそこでアンダーバーが先頭にある変数のエラーを回避しました。

.eslintrc.cjs
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-recommended',
  ],
  env: {
    browser: true,
    node: true,
    es2020: true,
  },
  parserOptions: {
    ecmaVersion: 2020,
    sourceType: 'module',
  },
  rules: {
    'no-unused-vars': ['error', {
      // 引数や変数の名前がアンダースコア(_)で始まる場合は、
      // 「定義されているが未使用」であってもエラーにしない
      'argsIgnorePattern': '^_',
      'varsIgnorePattern': '^_'
    }],
  }
}

もう1つの 「パースができない」 ですが、
テストソース内に vi.advanceTimersByTime(30_000) という表記があったのでアンダーバーを取る事によりこちらも解決しました。

修正前

Tracking.test.js
  it('照会後30秒ごとに自動更新する', async () => {
    vi.mocked(axios.get).mockResolvedValue({
      data: {
        tracking_number: 'TRK-POLL',
        status: 'accepted',
        status_updated_at: '2099-01-01T00:00:00Z',
        schedule: { origin_name: 'A', dest_name: 'B', depart_at: '2099-01-01T00:00:00Z' },
      },
    })

    const wrapper = mountWrapper()
    await wrapper.find('input[type="text"]').setValue('TRK-POLL')
    await wrapper.find('form').trigger('submit')
    await vi.waitFor(() => expect(axios.get).toHaveBeenCalledTimes(1))

    vi.advanceTimersByTime(30_000) // <-----ここが悪さをしている
    await vi.waitFor(() => expect(axios.get).toHaveBeenCalledTimes(2))
  })

ESLintのパース設定(ECMAScriptのバージョン)が古いこと によるエラー検知みたいです。
無くても挙動は変わらないみたいなので今回は一旦削除で対応しました。

修正後

Tracking.test.js
  it('照会後30秒ごとに自動更新する', async () => {
    vi.mocked(axios.get).mockResolvedValue({
      data: {
        tracking_number: 'TRK-POLL',
        status: 'accepted',
        status_updated_at: '2099-01-01T00:00:00Z',
        schedule: { origin_name: 'A', dest_name: 'B', depart_at: '2099-01-01T00:00:00Z' },
      },
    })

    const wrapper = mountWrapper()
    await wrapper.find('input[type="text"]').setValue('TRK-POLL')
    await wrapper.find('form').trigger('submit')
    await vi.waitFor(() => expect(axios.get).toHaveBeenCalledTimes(1))

    vi.advanceTimersByTime(30000) // <-----意味は同じなのでこの修正でエラー回避
    await vi.waitFor(() => expect(axios.get).toHaveBeenCalledTimes(2))
  })

今度はビルドエラー発生

ローカルでのエラー解消を経てコミットしたんですが、
今度はビルドエラーが出てしまいました。
src/router/index.js の構文ミスです。

image.png

修正前

index.js
const routes = [
  { path: '/shipper/companies', name: 'CompanyList', component: () => import('../views/CompanyList.vue'), meta: { requiresAuth: true, role: 'shipper' } },
  { path: '/tracking', name: 'Tracking', component: () => import('../views/TrackingView.vue/index.js') }, // <-----ここがエラーの原因
  ...
]

import('../views/TrackingView.vue/index.js')
この行に余分なindex.jsが付いているので削除したら解決しました。

import('../views/TrackingView.vue')

修正後

index.js
const routes = [
  { path: '/shipper/companies', name: 'CompanyList', component: () => import('../views/CompanyList.vue'), meta: { requiresAuth: true, role: 'shipper' } },
  { path: '/tracking', name: 'Tracking', component: () => import('../views/TrackingView.vue') },
  ...
]

CIの実行正常終了!

トライアンドエラー を繰り返してようやく正常終了までたどり着きました!
この画面見ると達成感を感じました!開発をしていると実感します。

image.png

ちなみに脆弱性スキャンも同時に行っているので内容確認してみました。

main.yml
  frontend-ci:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./frontend
    steps:
      ... # 省略
      - name: Security Audit
        run: npm audit --audit-level=high # <-----この部分

image.png

高リスクの脆弱性はない という結果になりました。
ここまで自動でやってくれると助かりますね!

おわりに

今回の学びまとめ

  • パスの差異: ローカ ルDockervolumes 設定と、CI環境でのカレントディレクトリの違いに注意が必要。
  • Lintのパースエラー: 30_000 のような最新のJS記法を使うなら、ESLintの ecmaVersion 設定を確認すること。
  • AIとの付き合い方: AIの「フォルダを作って置くだけ」という言葉には、プロジェクト固有の事情(ディレクトリ構造など)が含まれていないことを意識する。

個人開発 では実務でできない事にあえて挑戦しています。
その分 トライアンドエラー が多くつまずきそうになりますが、AIコーディングエージェントが復旧したからこそこの泥臭さが今後役に立つはず!

保守のできないエンジニアにはなりたくないので、今後も時間をかけて粘り強く色んな事に挑戦していきます!

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?