Fix ios double-click bug #3
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
| name: AI — ChangeDoc & Code Review (Qwen Code) | |
| on: | |
| pull_request_target: | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| permissions: | |
| contents: write # to open/update the doc PR | |
| pull-requests: write # to post PR comments | |
| concurrency: | |
| group: ai-review-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| changedoc: | |
| # Optional label gate: uncomment the next line to run only when 'ai-review' label is present | |
| # if: contains(github.event.pull_request.labels.*.name, 'ai-review') | |
| runs-on: ubuntu-latest | |
| environment: ai-review # <- create this Env and put the API key(s) there | |
| steps: | |
| - name: Checkout base repo (safe context) | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get PR diff via GitHub API (no untrusted checkout) | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| curl -sSL \ | |
| -H "Authorization: Bearer ${GH_TOKEN}" \ | |
| -H "Accept: application/vnd.github.v3.diff" \ | |
| "${{ github.event.pull_request.diff_url }}" > pr.diff | |
| echo "Diff size: $(wc -c < pr.diff) bytes" | |
| # Chunk very large diffs | |
| split -b 600k -a 3 -d pr.diff pr.diff.part. || true | |
| ls -1 pr.diff* || true | |
| - name: Setup Node.js 20 (Qwen Code requirement) | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Install Qwen Code CLI | |
| run: | | |
| npm i -g @qwen-code/qwen-code@latest | |
| qwen --version | |
| - name: Configure Qwen Code provider & model | |
| env: | |
| OPENAI_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} # add this as an Environment secret on 'ai-review' | |
| run: | | |
| echo "::add-mask::${OPENAI_API_KEY}" | |
| { | |
| echo "OPENAI_API_KEY=${OPENAI_API_KEY}" | |
| echo "OPENAI_BASE_URL=https://openrouter.ai/api/v1" | |
| echo "OPENAI_MODEL=qwen/qwen3-coder" | |
| # To use Alibaba DashScope instead, replace the two lines above with: | |
| # echo "OPENAI_BASE_URL=https://dashscope-intl.aliyuncs.com/compatible-mode/v1" | |
| # echo "OPENAI_MODEL=qwen3-coder-plus" | |
| } >> $GITHUB_ENV | |
| - name: Build prompts | |
| run: | | |
| mkdir -p .github/ai | |
| # ChangeDoc prompt | |
| cat > .github/ai/changedoc.txt <<'DOC' | |
| You are an expert release-notes writer and senior TypeScript reviewer. | |
| Create a clear, linkable **ChangeDoc** for this PR. | |
| Output (Markdown): | |
| <!-- PR #${{ github.event.pull_request.number }} | ${{ github.event.pull_request.title }} --> | |
| # PR #${{ github.event.pull_request.number }} — ${{ github.event.pull_request.title }} | |
| ## TL;DR | |
| - 3–6 bullets with the most important changes. | |
| ## Why | |
| - Brief context for the change. | |
| ## What changed | |
| - Group by area (API, UI, DB, Build, Docs, Tests). | |
| - For DB (Drizzle/Postgres): new tables/columns, indexes, constraints, migrations, backfills; risks. | |
| - For TanStack Query: invalidation strategy, query keys, caching details. | |
| - For Types: breaking signatures, generics, union exhaustiveness, `never/unknown`. | |
| ## Breaking changes | |
| - If any, list with migration guidance. | |
| ## Test plan | |
| - How reviewers can verify. | |
| ## Files touched | |
| - Table: file → summary of changes. | |
| ## Suggested follow-ups | |
| - Cleanups / refactors / tickets. | |
| DOC | |
| # Code Review prompt | |
| cat > .github/ai/review.txt <<'REV' | |
| You are a meticulous senior TypeScript reviewer. | |
| Focus (in order): | |
| 1) Correctness & safety (null/undefined, async/races, error handling) | |
| 2) TanStack Query hygiene (stable queryKeys, staleTime, enabled, cache invalidation) | |
| 3) Drizzle/Postgres (schema, idempotent migrations, indexes/constraints, SQL safety) | |
| 4) Types & API boundaries (DTO validation, unions exhaustive, `never/unknown`) | |
| 5) Performance & DX (N+1, pagination, SSR/ISR, bundle impact, readability) | |
| Output (Markdown): | |
| <!-- AI_REVIEW --> | |
| ## AI Code Review — PR #${{ github.event.pull_request.number }} | |
| ### TL;DR | |
| - 3–6 bullets (critical findings first) | |
| ### Findings by file | |
| - For each file with issues: short bullets + **precise** fixes. | |
| - Include tiny fenced diffs only when helpful. | |
| ### Risk & test notes | |
| - Migration/data risk, rollback ideas, verification steps. | |
| ### Quick wins / refactors | |
| - Small actionable improvements to do now or next PR. | |
| REV | |
| - name: Install envsubst (for templating) | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gettext-base | |
| - name: Generate ChangeDoc with Qwen Code | |
| run: | | |
| : > CHANGELOG_PR.md | |
| if ls pr.diff.part.* >/dev/null 2>&1; then | |
| idx=0 | |
| for part in pr.diff.part.*; do | |
| ( cat .github/ai/changedoc.txt; echo; echo "## DIFF (part $idx)"; cat "$part" ) | qwen >> CHANGELOG_PR.md | |
| echo -e "\n---\n" >> CHANGELOG_PR.md | |
| idx=$((idx+1)) | |
| done | |
| ( printf "Consolidate the following into a single clean PR ChangeDoc:\n\n"; cat CHANGELOG_PR.md ) | qwen > _final.md | |
| mv _final.md CHANGELOG_PR.md | |
| else | |
| ( cat .github/ai/changedoc.txt; echo; echo "## DIFF"; cat pr.diff ) | qwen > CHANGELOG_PR.md | |
| fi | |
| - name: Find existing ChangeDoc comment (idempotent) | |
| id: find_changedoc_comment | |
| uses: peter-evans/find-comment@v3 | |
| with: | |
| issue-number: ${{ github.event.pull_request.number }} | |
| comment-author: 'github-actions[bot]' | |
| body-includes: '# PR #${{ github.event.pull_request.number }} —' | |
| - name: Post/Update ChangeDoc comment | |
| uses: peter-evans/create-or-update-comment@v4 | |
| with: | |
| issue-number: ${{ github.event.pull_request.number }} | |
| comment-id: ${{ steps.find_changedoc_comment.outputs.comment-id }} | |
| edit-mode: replace | |
| body-path: CHANGELOG_PR.md | |
| - name: Stage PR changelog file | |
| run: | | |
| mkdir -p docs/changelogs | |
| FILE="docs/changelogs/pr-${{ github.event.pull_request.number }}.md" | |
| if [ -f "$FILE" ]; then | |
| # Replace body while keeping header if re-running | |
| awk 'BEGIN{p=1} /^## TL;DR/{p=0} {if(p)print}' "$FILE" > _header.md | |
| cat _header.md CHANGELOG_PR.md > "$FILE" | |
| rm _header.md | |
| else | |
| ( echo "<!-- PR #${{ github.event.pull_request.number }} | ${{ github.event.pull_request.title }} -->"; echo; cat CHANGELOG_PR.md ) > "$FILE" | |
| fi | |
| - name: Open/Update PR that persists the ChangeDoc | |
| uses: peter-evans/create-pull-request@v7 | |
| with: | |
| branch: chore/changelog/pr-${{ github.event.pull_request.number }} | |
| add-paths: | | |
| docs/changelogs/pr-${{ github.event.pull_request.number }}.md | |
| commit-message: 'docs(changelog): add/update ChangeDoc for PR #${{ github.event.pull_request.number }}' | |
| title: 'docs(changelog): add/update ChangeDoc for PR #${{ github.event.pull_request.number }}' | |
| body: 'Auto-generated by Qwen Code (Qwen3-Coder).' | |
| labels: changelog, automated | |
| draft: false | |
| - name: Generate AI code review with Qwen Code | |
| run: | | |
| : > REVIEW_PR.md | |
| if ls pr.diff.part.* >/dev/null 2>&1; then | |
| idx=0 | |
| for part in pr.diff.part.*; do | |
| ( cat .github/ai/review.txt; echo; echo "## DIFF (part $idx)"; cat "$part" ) | qwen >> REVIEW_PR.md | |
| echo -e "\n---\n" >> REVIEW_PR.md | |
| idx=$((idx+1)) | |
| done | |
| ( printf "Merge the part-wise reviews into one concise review:\n\n"; cat REVIEW_PR.md ) | qwen > _final_review.md | |
| mv _final_review.md REVIEW_PR.md | |
| else | |
| ( cat .github/ai/review.txt; echo; echo "## DIFF"; cat pr.diff ) | qwen > REVIEW_PR.md | |
| fi | |
| - name: Find existing AI review comment (idempotent) | |
| id: find_ai_review | |
| uses: peter-evans/find-comment@v3 | |
| with: | |
| issue-number: ${{ github.event.pull_request.number }} | |
| comment-author: 'github-actions[bot]' | |
| body-includes: '<!-- AI_REVIEW -->' | |
| - name: Post/Update AI review comment | |
| uses: peter-evans/create-or-update-comment@v4 | |
| with: | |
| issue-number: ${{ github.event.pull_request.number }} | |
| comment-id: ${{ steps.find_ai_review.outputs.comment-id }} | |
| edit-mode: replace | |
| body-path: REVIEW_PR.md |