[codex] Allow leg splitting in edit modes #1989
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: CI | |
| # Lint / static checks for the static web app. Enforces the rules | |
| # AGENTS.md describes (node --check, JSON parse, consistent ?v=N) so | |
| # PRs into main / dev can't ship broken JS or stale cache busts. | |
| on: | |
| pull_request: | |
| branches: [main, dev] | |
| push: | |
| branches: [main, dev] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| dev-history: | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/dev' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 3 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Ensure dev received no merge commits | |
| run: | | |
| set -e | |
| BEFORE="${{ github.event.before }}" | |
| AFTER="${{ github.sha }}" | |
| if [ "$BEFORE" = "0000000000000000000000000000000000000000" ]; then | |
| RANGE="$AFTER" | |
| else | |
| RANGE="$BEFORE..$AFTER" | |
| fi | |
| COUNT=$(git rev-list --count "$RANGE") | |
| # Reject real merge commits (squash-merge policy), but tolerate | |
| # no-op merges — a "Merge branch 'main' into dev" whose tree is | |
| # identical to its first parent brings no changes and is harmless | |
| # (happens when main is already behind dev). Such a merge has an | |
| # empty diff against its first parent. | |
| BAD="" | |
| for m in $(git rev-list --merges "$RANGE"); do | |
| if ! git diff --quiet "$m^1" "$m"; then | |
| BAD="$BAD $m" | |
| fi | |
| done | |
| if [ -n "$BAD" ]; then | |
| echo "❌ dev received a non-trivial merge commit. Use squash merge." | |
| for m in $BAD; do git show -s --oneline "$m"; done | |
| exit 1 | |
| fi | |
| echo "✅ dev received $COUNT commit(s); any merges were no-ops." | |
| lint: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check PR is rebased | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| if ! git merge-base --is-ancestor ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}; then | |
| echo "❌ PR branch is not rebased on ${{ github.base_ref }}. Run 'git rebase origin/${{ github.base_ref }}' and push." | |
| exit 1 | |
| fi | |
| echo "✅ PR is rebased on ${{ github.base_ref }}" | |
| - name: Set up Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install npm dependencies | |
| run: npm ci | |
| - name: JS syntax check (node --check) | |
| run: | | |
| set -e | |
| for f in docs/app/core.js docs/app/draw.js docs/app/interact.js docs/app/io.js docs/app/ui.js docs/sw.js docs/i18n/he/strings.js docs/i18n/en/strings.js; do | |
| echo "node --check $f" | |
| node --check "$f" | |
| done | |
| - name: JSON validation | |
| run: | | |
| set -e | |
| for f in docs/manifest.json docs/data/nav-waypoints.json; do | |
| echo "validating $f" | |
| node -e "JSON.parse(require('fs').readFileSync('$f','utf8'));" | |
| done | |
| - name: XML validation (sitemap.xml, BingSiteAuth.xml) | |
| run: | | |
| set -e | |
| python3 -c "import xml.etree.ElementTree as ET; ET.parse('docs/sitemap.xml'); print('sitemap.xml ok')" | |
| python3 -c "import xml.etree.ElementTree as ET; ET.parse('docs/BingSiteAuth.xml'); print('BingSiteAuth.xml ok')" | |
| - name: HTML well-formedness (html-validate) | |
| run: npx --yes html-validate@8 --formatter=stylish docs/index.html docs/en/index.html docs/he/index.html | |
| - name: Cache-bust consistency (?v= in docs/index.html) | |
| run: | | |
| # Source HTML may carry a placeholder integer (e.g. ?v=134) or a | |
| # short commit SHA (e.g. ?v=abc1234) — Deploy rewrites it at upload | |
| # time. Either form is fine here; all values just have to agree so | |
| # nobody accidentally leaves one stale. | |
| vs=$(grep -oE '\?v=[A-Za-z0-9]+' docs/index.html | sort -u) | |
| n=$(printf "%s\n" "$vs" | wc -l | tr -d ' ') | |
| if [ "$n" -gt 1 ]; then | |
| echo "Inconsistent ?v= values in docs/index.html:" | |
| printf "%s\n" "$vs" | |
| exit 1 | |
| fi | |
| echo "cache-bust ok: $vs" | |
| - name: Service worker cache name sanity (docs/sw.js) | |
| run: | | |
| if ! grep -qE "^const CACHE = 'navaid-v[0-9]+';" docs/sw.js; then | |
| echo "docs/sw.js is missing the expected 'const CACHE = \"navaid-vN\"' constant." | |
| echo "Found:" | |
| grep -nE "CACHE" docs/sw.js || true | |
| exit 1 | |
| fi | |
| line=$(grep -E "^const CACHE = 'navaid-v[0-9]+';" docs/sw.js) | |
| echo "sw cache ok: $line" | |
| - name: Spell check (English + Hebrew) | |
| run: npm run lint:spell | |
| e2e: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| needs: lint | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check PR is rebased | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| if ! git merge-base --is-ancestor ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}; then | |
| echo "❌ PR branch is not rebased on ${{ github.base_ref }}. Run 'git rebase origin/${{ github.base_ref }}' and push." | |
| exit 1 | |
| fi | |
| echo "✅ PR is rebased on ${{ github.base_ref }}" | |
| - name: Set up Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install npm dependencies | |
| run: npm ci | |
| - name: Cache Playwright browsers | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }} | |
| restore-keys: | | |
| playwright-${{ runner.os }}- | |
| - name: Install Playwright browsers | |
| run: npx playwright install --with-deps chromium | |
| - name: Start local server and run tests | |
| run: | | |
| python3 -m http.server -d docs 8000 --bind 127.0.0.1 & SERVER=$! | |
| # Run tests against local server | |
| BASE_URL="http://127.0.0.1:8000" npm test | |
| EXIT=$? | |
| kill $SERVER 2>/dev/null | |
| exit $EXIT | |
| - name: Upload Playwright report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: playwright-report | |
| path: | | |
| playwright-report/ | |
| test-results/ | |
| retention-days: 7 |