Skip to content

Phase 2 実装: monorepo 移行 + Python パッケージ追加 #23

Description

@aromarious

概要

ロードマップ #14 の Phase 2 を実装する umbrella issue。cao-holidays を monorepo 化し、Python パッケージを新設する。

着手前提(merge 前にやる)

  • PyPI Trusted Publishing の Pending Publisher 事前登録: PyPI で aromarious/cao-holidays + workflow release-python.yml + environment pypi を登録(プロジェクト作成前でも Pending Publisher として登録可能)
  • main protection ruleset を緩める: CI workflow リネームで status check 名が変わるため、merge 前に Required status checks を一旦空にする(merge 後に新しい check 名で再設定)
  • Release PR で required check が走らない問題を PAT 化で解決する #21 の動作検証準備: monorepo 移行で立つ最初の Release PR が、RELEASE_TOKEN PAT 経由で required CI / CodeQL を空コミット push なしで自動起動するかを確認する。起動すれば Release PR で required check が走らない問題を PAT 化で解決する #21 close

作業計画(PR 分割案)

レビュー負荷を抑えるため、以下の4 PR に分割することを推奨。各 PR の status check は Phase 2-X プレフィックスで識別。

PR 1: monorepo 化(既存 JS の移動 + 共有資産確立)

  • packages/js/ 作成。既存の src/tests/bin/package.jsontsconfig.jsonbiome.jsonvitest.config.tstsup.config.tspnpm-lock.yaml.changeset/dist/(gitignore) を git mv
  • fixtures/ を root に新設。packages/js/tests/fixtures/syukujitsu.csvfixtures/syukujitsu.csv に移動
  • 期待出力 fixture を生成: 既存 CLI で --all --format json/csv/ics2026 --format json/csv/ics2025..20272026-04-01..2026-05-31 を叩いて期待値を fixtures/*.{json,csv,ics} に保存
  • packages/js/tests/ の fixture 参照パスを ../../../fixtures/syukujitsu.csv 等に修正
  • scripts/sync-fixture.mjs を root に移動。出力先を新 fixtures/ に変更
  • CI workflow を ci.ymlci-js.yml にリネーム。paths: filter を packages/js/**fixtures/**scripts/sync-fixture.mjs.github/workflows/ci-js.yml
  • release.ymlrelease-js.yml にリネーム、changesets/actioncwd: packages/js を設定
  • healthcheck.yml の参照パス見直し
  • dependabot.yml 更新: npm ecosystem の directory を /packages/js に変更
  • トップ README.md / README.en.md を全面書き換え: 「multi-language monorepo」を1行目で宣言、各 package へのリンク
  • packages/js/README.md 新設: 既存 README 内容をベースに、冒頭で monorepo 宣言と相互リンク
  • LICENSEpackages/js/LICENSE にもコピー(npm publish 同梱用)
  • root に Makefile 新設(make lint-js / make test-js 等)
  • root に .pre-commit-config.yaml 新設(biome フックのみ、Phase 2 で ruff/mypy も追加)
  • root に .vscode/extensions.json 新設(推奨拡張)
  • 動作確認: cd packages/js && pnpm install && pnpm test && pnpm typecheck && pnpm lint 全緑、publint 緑、@arethetypeswrong/cli
  • Release PR で required check が走らない問題を PAT 化で解決する #21 検証: PR merge 後の Release PR で空コミット push なしで required check が起動するか確認

PR 2: Python skeleton + CI 配管

  • packages/python/ ディレクトリ作成
  • pyproject.toml 新設: [project] (name = cao-holidays)、build backend は hatchling[tool.hatch.version]src/cao_holidays/__init__.py__version__ を真とする、[tool.ruff][tool.mypy] セクション
  • src/cao_holidays/__init__.py 新設: 公開 API は fetch_all_holidays / fetch_holidays_by_year / fetch_holidays_between(NotImplementedError でスタブ)、Holiday (TypedDict)、FetchOptions (TypedDict)、CaoHolidaysError (Exception)、__version__ = "0.0.0"
  • tests/ 空ディレクトリ + tests/conftest.py(fixture path 解決用)
  • packages/python/README.md 新設(PyPI upload 用、相互リンク含む)
  • packages/python/LICENSE コピー
  • .github/workflows/ci-python.yml 新設: paths: packages/python/**fixtures/**、ruff check + ruff format --check + mypy + pytest を Python 3.11/3.12/3.13 matrix で実行
  • .github/workflows/codeql.yml の matrix に Python を追加
  • .github/dependabot.yml に pip ecosystem (directory: /packages/python) を追加
  • .pre-commit-config.yaml に ruff + ruff-format + mypy フックを追加
  • root Makefilelint-python / format-python / test-python / typecheck-python / install ターゲット追加
  • 動作確認: cd packages/python && uv sync && uv run pytest && uv run mypy src && uv run ruff check . && uv run ruff format --check . 全緑

PR 3: Python 実装本体(fixture 一致テスト含む)

  • src/cao_holidays/parse.py: decode_sjis()parse_csv() 実装。JS 版と同等のロジック(ヘッダー行スキップ、YYYY/M/DYYYY-MM-DD 正規化、昇順ソート、PARSE_FAILED 相当の例外)
  • src/cao_holidays/source.py: CKAN_URL 定数、resolve_csv_url()fetch_csv_text()。User-Agent (cao-holidays-py/<version>)、FetchOptions.fetch DI 対応、signal の Python 版相当(asyncio.timeout or 同期版なら urllib3 Retry の活用検討)
  • src/cao_holidays/format.py: CSV (RFC 4180)、JSON (1 行)、ICS (RFC 5545) フォーマッタ。JS 版とバイト単位で一致する出力
  • src/cao_holidays/__init__.py の3関数を実装(INVALID_INPUT / OUT_OF_RANGE / FETCH_FAILED / PARSE_FAILED 例外コード対応)
  • tests/test_parse.pytest_source.pytest_format.pytest_main.py 実装
  • fixture 一致テスト: tests/test_fixture_parity.pyfixtures/syukujitsu.csv を食わせて fixtures/all.json 等と一致することを検証(JS 版と Python 版が同じ出力を返すことの担保)
  • 動作確認: pytest 全緑、mypy --strict src 緑、JS 版と CSV/JSON/ICS 出力がバイト単位で一致

PR 4: Python リリース基盤 + 初版 publish

  • .github/workflows/release-python.yml 新設: tag pattern python-v* を trigger に hatch build + pypa/gh-action-pypi-publish(OIDC、environment pypi
  • packages/python/CHANGELOG.md 新設(Keep a Changelog 形式)
  • hatch version0.0.00.1.0 に bump、CHANGELOG エントリ追加
  • PR merge 後、git tag python-v0.1.0 を push
  • release-python.yml が PyPI publish を実行
  • 動作確認: pip install --no-cache-dir cao-holidays==0.1.0 で fresh install、python -c "from cao_holidays import fetch_holidays_by_year; print(len(fetch_holidays_by_year(2026)))" で実通信動作確認
  • ロードマップ ロードマップ: 多言語展開 #14 の Phase 2 チェックボックスを更新

完了条件

  • npm cao-holidays(既存)が monorepo 配下から問題なく publish されること
  • PyPI cao-holidays 0.1.0 が公開されること
  • JS 版と Python 版が 同じ fixture を食わせて同じバイト列を出力すること(CI で自動検証)
  • main protection / Dependabot / CodeQL / pre-commit が両言語で機能すること
  • Release PR で required check が走らない問題を PAT 化で解決する #21(Release PR の required check 起動)が解決済みであること

Scope 外(このIssueでは扱わない)

  • 多言語展開の Phase 3(Go, Ruby)以降
  • Python パッケージへの CLI 提供(library only と決定済、ロードマップ ロードマップ: 多言語展開 #14 参照)
  • 判定ヘルパーパッケージ(cao-holidays-utils 等)

関連

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions