-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/contest discussion automation #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
river0525
wants to merge
22
commits into
main
Choose a base branch
from
feature/contest-discussion-automation
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
51511e1
chore: add .gitignore (worktrees, Python artifacts)
river0525 8645e22
docs: add implementation plan for contest discussion automation
river0525 46e4ecc
feat: initialize uv project for contest-discussions automation
river0525 6ec76fb
feat: add contest_discussions package skeleton
river0525 95b6fc9
feat: add fixed repository/category IDs for NoviSteps-Writeups
river0525 8a56595
ci: add smoke test workflow for GITHUB_TOKEN discussions:write
river0525 f5c095a
fix: translate constants.py comment to English for consistency
river0525 62a255c
test: add AtCoder tasks page HTML fixture
river0525 87c6b38
feat: fetch task list from AtCoder tasks page
river0525 1e31a95
fix: harden fetch_tasks (byte-decode HTML, cross-check contest_id, do…
river0525 1f2a819
test: add AtCoder Problems contests.json fixture
river0525 8b1fd52
feat: find recently finished ABC contest ids
river0525 6f6a33a
fix: guard limit<=0 edge case, clarify docstrings for find_recently_f…
river0525 fb0672d
test: add failing tests for github_client discussion query/create
river0525 5991aef
feat: query existing discussion titles and create new discussions via…
river0525 446c28b
test: add failing tests for main orchestration/CLI
river0525 b7b79ff
feat: orchestrate contest discussion creation and add CLI entrypoint
river0525 9318580
fix: log tracebacks on failure, test CLI entrypoint and same-run dedup
river0525 a03758d
feat(ci): add production workflow to post contest discussions
river0525 50d20bd
chore(ci): remove throwaway smoke-test workflow
river0525 34b12ba
fix: add job timeout/concurrency guard, fail run on systemic fetch fa…
river0525 0903188
fix: address Copilot review findings
river0525 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| name: Post contest discussions | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: '50 13 * * 6' | ||
| workflow_dispatch: | ||
| inputs: | ||
| contest_id: | ||
| description: 'Contest ID to backfill (e.g. abc467). Leave empty for automatic detection.' | ||
| required: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
| discussions: write | ||
|
|
||
| concurrency: | ||
| group: post-discussions | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| post-discussions: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 10 | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.13" | ||
|
|
||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v3 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. astral-sh/setup-uv@c771a70 # v9.0.0 ようなコミットハッシュを使われてはいかがでしょうか? 理由: セキュリティ対策(改ざん防止、サプライチェーン攻撃対策)のため |
||
|
|
||
| - name: Install dependencies | ||
| run: uv sync | ||
|
|
||
| - name: Post discussions | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| CONTEST_ID: ${{ github.event.inputs.contest_id }} | ||
| run: | | ||
| if [ -n "$CONTEST_ID" ]; then | ||
| uv run python -m contest_discussions.main --contest-id "$CONTEST_ID" | ||
| else | ||
| uv run python -m contest_discussions.main | ||
| fi | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| .worktrees/ | ||
| .venv/ | ||
| __pycache__/ | ||
| *.pyc |
172 changes: 172 additions & 0 deletions
172
docs/dev-notes/2026-07-21/contest-discussion-automation/phase-1.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| # Phase 1: プロジェクト初期化 + GITHUB_TOKEN 権限検証 | ||
|
|
||
| **目的:** uv プロジェクトの雛形を作り、「Actions 標準の `GITHUB_TOKEN` + `permissions: discussions: write` で Discussion 作成が可能」という設計上の前提を、実際にワークフローを1回動かして検証する。ここで検証できなければ、後続フェーズの認証方式を PAT に差し替える必要があるため、最初に確認する。 | ||
|
|
||
| **注意:** このフェーズの最終ステップ (ワークフローの手動実行) は、公開リポジトリに実際の Discussion を作成する。**ユーザーの明示的な許可を得てから実行すること。** 無断でリモートに push したりワークフローを実行したりしない。 | ||
|
|
||
| --- | ||
|
|
||
| ### Task 1: uv プロジェクトの初期化 | ||
|
|
||
| **Files:** | ||
| - Create: `pyproject.toml` | ||
|
|
||
| - [ ] **Step 1: pyproject.toml を作成** | ||
|
|
||
| ```toml | ||
| [project] | ||
| name = "contest-discussions" | ||
| version = "0.1.0" | ||
| description = "Automatically create GitHub Discussions for each ABC problem after the contest ends." | ||
| readme = "README.md" | ||
| requires-python = ">=3.13,<4.0" | ||
| dependencies = [ | ||
| "requests>=2.32", | ||
| "selectolax>=0.4.6", | ||
| ] | ||
|
|
||
| [dependency-groups] | ||
| dev = [ | ||
| "pytest>=8.3", | ||
| "responses>=0.25", | ||
| ] | ||
|
|
||
| [tool.pytest.ini_options] | ||
| pythonpath = ["src"] | ||
| ``` | ||
|
|
||
| - [ ] **Step 2: 依存関係をインストール** | ||
|
|
||
| Run: `uv sync` | ||
| Expected: `uv.lock` が生成され、`.venv/` が作成される | ||
|
|
||
| - [ ] **Step 3: Commit** | ||
|
|
||
| ```bash | ||
| git add pyproject.toml uv.lock | ||
| git commit -m "chore: initialize uv project for contest discussion automation" | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### Task 2: パッケージ雛形の作成 | ||
|
|
||
| **Files:** | ||
| - Create: `src/contest_discussions/__init__.py` | ||
|
|
||
| - [ ] **Step 1: 空の `__init__.py` を作成** | ||
|
|
||
| ```python | ||
| ``` | ||
|
|
||
| - [ ] **Step 2: Commit** | ||
|
|
||
| ```bash | ||
| git add src/contest_discussions/__init__.py | ||
| git commit -m "chore: add contest_discussions package skeleton" | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### Task 3: 定数モジュールの作成 | ||
|
|
||
| **Files:** | ||
| - Create: `src/contest_discussions/constants.py` | ||
|
|
||
| - [ ] **Step 1: 定数を定義** | ||
|
|
||
| ```python | ||
| """Fixed IDs and text for the NoviSteps-Writeups repository. | ||
|
|
||
| See: https://github.com/AtCoder-NoviSteps/NoviSteps-Writeups | ||
| """ | ||
|
|
||
| # `gh api graphql -f query='query { repository(owner: "AtCoder-NoviSteps", name: "NoviSteps-Writeups") { id } }'` | ||
| REPOSITORY_ID = "R_kgDOTNgHyw" | ||
|
|
||
| # "General" discussion category. | ||
| # `gh api graphql -f query='query { repository(owner: "AtCoder-NoviSteps", name: "NoviSteps-Writeups") { discussionCategories(first: 10) { nodes { id name } } } }'` | ||
| GENERAL_CATEGORY_ID = "DIC_kwDOTNgHy84DAe9x" | ||
|
|
||
| DISCUSSION_BODY = "問題の感想や気づきを投稿・共有するスペースです" | ||
|
|
||
| # 週次 cron が1回失敗しても次回実行で埋め合わせられるよう、直近何件のABCを | ||
| # 重複チェック対象にするか。3件あれば3週分の取りこぼしまでカバーできる。 | ||
| CONTESTS_TO_CHECK = 3 | ||
| ``` | ||
|
|
||
| - [ ] **Step 2: Commit** | ||
|
|
||
| ```bash | ||
| git add src/contest_discussions/constants.py | ||
| git commit -m "feat: add repository/category constants" | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### Task 4: GITHUB_TOKEN の Discussion 書き込み権限を検証するワークフロー | ||
|
|
||
| **Files:** | ||
| - Create: `.github/workflows/smoke_test_discussion.yml` | ||
|
|
||
| - [ ] **Step 1: workflow_dispatch のみで動く検証用ワークフローを作成** | ||
|
|
||
| ```yaml | ||
| name: Smoke test - GITHUB_TOKEN discussions:write | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| discussions: write | ||
|
|
||
| jobs: | ||
| smoke-test: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Create a throwaway test discussion | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| gh api graphql -f query=' | ||
| mutation($repositoryId: ID!, $categoryId: ID!, $title: String!, $body: String!) { | ||
| createDiscussion(input: { | ||
| repositoryId: $repositoryId, | ||
| categoryId: $categoryId, | ||
| title: $title, | ||
| body: $body | ||
| }) { | ||
| discussion { id url } | ||
| } | ||
| }' \ | ||
| -f repositoryId="R_kgDOTNgHyw" \ | ||
| -f categoryId="DIC_kwDOTNgHy84DAe9x" \ | ||
| -f title="[smoke test] GITHUB_TOKEN discussions:write check (safe to delete)" \ | ||
| -f body="Created by CI to verify that the default GITHUB_TOKEN can create Discussions. Safe to delete." | ||
| ``` | ||
|
|
||
| - [ ] **Step 2: Commit** | ||
|
|
||
| ```bash | ||
| git add .github/workflows/smoke_test_discussion.yml | ||
| git commit -m "ci: add smoke test workflow for GITHUB_TOKEN discussions permission" | ||
| ``` | ||
|
|
||
| - [ ] **Step 3 (ユーザー確認必須・手動): push してワークフローを実行** | ||
|
|
||
| ここは実際に公開リポジトリへ push し、ワークフローを実行して Discussion を1件作成する。**必ずユーザーに実行してよいか確認してから進めること。** | ||
|
|
||
| ```bash | ||
| git push -u origin <branch-name> | ||
| gh workflow run smoke_test_discussion.yml | ||
| gh run watch | ||
| ``` | ||
|
|
||
| - [ ] **Step 4: 結果を確認** | ||
|
|
||
| - 成功した場合: NoviSteps-Writeups の Discussions に "[smoke test] ..." が作成されているので、`gh api graphql` の `deleteDiscussion` mutation か GitHub UI から削除する。以降のフェーズは `GITHUB_TOKEN` + `permissions: discussions: write` の方針で進める。 | ||
| - 失敗した場合 (権限エラー等): `plan.md` の「却下した代替案」を更新し、Fine-grained PAT をリポジトリシークレット (`GITHUB_DISCUSSIONS_TOKEN` 等) として発行する方針に切り替える。Phase 4/6 の認証部分をその前提で書き直す。 | ||
|
|
||
| - [ ] **Step 5: 検証用ワークフローを削除 (恒久ワークフローに置き換えるため)** | ||
|
|
||
| Phase 6 で正式なワークフローに差し替えるため、このスモークテスト用ファイルは Phase 6 で削除する (このフェーズでは残しておいてよい)。 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Problems API からコンテスト情報を取得する場合、コンテスト終了後10分では反映されていない可能性が高いかと思います
けんちょんさん、ウルズニャーさんとの議論から、日曜日に投稿できる状態であれば十分そうです
riverさんのお考えはいかがでしょうか?