From f454a41ace4cb5986b435c8be9a47141233e41b7 Mon Sep 17 00:00:00 2001 From: New Future Date: Wed, 9 Sep 2026 17:37:52 +0800 Subject: [PATCH] ci(copilot): optimize cloud agent setup and guidance (#743) Co-authored-by: Future New (WEILAI LIU) --- .github/copilot-instructions.md | 12 +++++- .github/workflows/copilot-setup-steps.yml | 46 +++++++++++++++++++---- .github/workflows/update-agents.yml | 1 + AGENTS.md | 22 ++++++++--- tools/check.py | 2 +- tools/tests/test_check.py | 5 +++ 6 files changed, 74 insertions(+), 14 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index f0fc335..fdff922 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -9,6 +9,12 @@ DDNS is a standard-library-only Dynamic DNS client for Python 2.7 and current Py 5. Run focused checks, then the full affected suite. 6. Self-review the diff and continue through required CI/review feedback until merge-ready. +## Cloud environment + +`.github/workflows/copilot-setup-steps.yml` prepares Python, pinned Ruff, Node.js, and locked documentation dependencies. Use the prepared toolchain and run DDNS directly from the repository root; source-based work needs no DDNS installation. If setup failed, a required tool is missing, or a dependency manifest changed, restore the relevant dependencies explicitly. + +Read **Source execution and validation** in `AGENTS.md` for the shared Web/MCP service, configuration metadata, static dashboard, and packaging boundaries. + ## Canonical commands ```bash @@ -16,8 +22,10 @@ python -m unittest discover tests -v python -m unittest tests.test_provider_cloudflare -v python -m unittest tests.test_config_config -v python -m unittest tests.test_ip -v -python -m unittest tests.test_web tests.test_mcp -v +python -m unittest tests.test_web tests.test_mcp tests.test_mcp_http -v python -m unittest tests.e2e -v +python tools/check.py --providers +python tools/check.py --changed ruff check . ruff format --check . npm --prefix docs ci @@ -26,6 +34,8 @@ npm --prefix docs run build Use `tools/AGENTS.md` for Python 3 maintenance tooling. Do not make `tools/` Python 2 compatible unless a task explicitly requires it. +Use focused unittest targets while iterating. `tools/check.py --changed` selects lane checks from committed, staged, unstaged, and untracked changes; set `DDNS_CHECK_BASE_REF` when the comparison base differs from the default branch. It complements, rather than replaces, CI platform and artifact checks. + ## Required constraints - Runtime code under `ddns/`, `run.py`, and tests must retain Python 2.7/3.x compatibility. diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 5f988b6..effe0a0 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -8,12 +8,14 @@ on: - 'docs/package.json' - 'docs/package-lock.json' - 'pyproject.toml' + - 'tools/check.py' pull_request: paths: - '.github/workflows/copilot-setup-steps.yml' - 'docs/package.json' - 'docs/package-lock.json' - 'pyproject.toml' + - 'tools/check.py' permissions: contents: read @@ -25,27 +27,57 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 + - name: Checkout repository + uses: actions/checkout@v7 - - uses: actions/setup-python@v7 + - name: Set up Python + uses: actions/setup-python@v7 with: python-version: '3.12' - - uses: actions/setup-node@v7 + - name: Set up Node.js + uses: actions/setup-node@v7 with: node-version: '24' - cache: npm - cache-dependency-path: docs/package-lock.json + # Explicit restore/save steps keep PR and agent cache access read-only. + package-manager-cache: false + + - name: Restore dependency downloads + id: dependency-cache + uses: actions/cache/restore@v6 + with: + path: | + ~/.cache/pip + ~/.npm/_cacache + key: copilot-setup-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.github/workflows/copilot-setup-steps.yml', 'docs/package-lock.json') }} + restore-keys: | + copilot-setup-${{ runner.os }}-${{ runner.arch }}- - name: Install repository tooling run: python -m pip install --disable-pip-version-check ruff==0.16.2 - name: Install documentation dependencies - run: npm --prefix docs ci + run: npm --prefix docs ci --prefer-offline --no-audit --no-fund - - name: Report tool versions + - name: Verify development environment run: | python --version ruff --version node --version npm --version + python -m ddns --version + python run.py --version + python tools/check.py --help + npm --prefix docs ls --depth=0 + + - name: Save dependency downloads + if: >- + github.event_name == 'push' && + github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && + steps.dependency-cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v6 + with: + path: | + ~/.cache/pip + ~/.npm/_cacache + key: ${{ steps.dependency-cache.outputs.cache-primary-key }} diff --git a/.github/workflows/update-agents.yml b/.github/workflows/update-agents.yml index 39af8cd..4004bdc 100644 --- a/.github/workflows/update-agents.yml +++ b/.github/workflows/update-agents.yml @@ -10,6 +10,7 @@ on: - 'AGENTS.md' - '.agents/**' - '.github/agents/**' + - '.github/copilot-instructions.md' - '.github/aw/**' - '.github/instructions/**' - '.github/scripts/update_agents_structure.py' diff --git a/AGENTS.md b/AGENTS.md index 68fe55e..f9adf6a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -289,13 +289,23 @@ Classify the task first, then read only the nearest code, tests, docs, and schem - **Config/schema**: `ddns/config/`, `schema/`, `tests/test_config_*.py`, `docs/config/`, `docs/en/config/` - **IP/HTTP**: `ddns/ip.py`, `ddns/util/http.py`, `tests/test_ip.py`, `tests/test_util_http*.py` - **Scheduler**: `ddns/scheduler/`, `tests/test_scheduler_*.py` -- **Web/MCP**: `ddns/web/`, `web/`, `ddns/mcp.py`, `tests/test_web.py`, `tests/test_mcp.py` +- **Web/MCP**: `ddns/web/`, `web/`, `ddns/mcp.py`, `ddns/mcp_http.py`, `ddns/http_config.py`, `tests/test_web.py`, `tests/test_mcp*.py` - **Docs**: `README*.md`, `docs/`, `docs/AGENTS.md` - **Build/release**: `pyproject.toml`, `run.py`, `.github/patch.py`, `docker/`, `.github/workflows/` -- **Agent control plane**: `AGENTS.md`, `.agents/skills/`, `.github/agents/`, `.github/instructions/` +- **Agent control plane**: `AGENTS.md`, `.agents/skills/`, `.github/agents/`, `.github/copilot-instructions.md`, `.github/instructions/`, `tools/` Use `rg` / `rg --files` for discovery, make narrow edits, validate the touched behavior, and report any command that could not run. A task is complete only when code, tests, schemas, docs, and generated metadata affected by the behavior are consistent. +### Source execution and validation + +- Run Python commands from the repository root. `python -m ddns --help` and `python run.py --help` work without installing DDNS or adding runtime dependencies. +- `web/` contains the dashboard's plain HTML/CSS/JavaScript assets, served and packaged by Python. It has no npm build. `docs/` is the separate VitePress site and the only npm project. +- `ddns/web/service.py` shares configuration, status, and synchronization behavior with MCP. `ddns/http_config.py` shares HTTP listener settings between Web and MCP HTTP; cover both callers when changing shared behavior. +- `ddns/config/field-model.json` supplies provider and field metadata to the dashboard and documentation configuration studio. Keep the registry, CLI, latest schema, and bilingual docs aligned; `python tools/check.py --providers` checks provider parity without installing dependencies. +- After focused tests, use `python tools/check.py --changed` for lane-specific checks. It includes merge-base, staged, unstaged, and untracked changes; unknown paths deliberately select all lanes. Set `DDNS_CHECK_BASE_REF` for a non-default comparison base. Use `--all` when a complete cross-lane check is needed, not for every iteration. +- `tests/e2e.py` is an explicit, offline suite and is not included in `unittest discover tests`. Run it separately for CLI, Web, MCP, or shared runtime changes. Sample configurations under `tests/config/` are not a substitute for its loopback fixtures. +- `.github/patch.py` transforms source and packaging metadata in place. Use it only for the relevant build in a disposable checkout, not for ordinary setup, linting, or source tests. Keep real scheduler lifecycle and platform/artifact validation in the appropriate CI environments. + ### Useful Commands ```bash @@ -387,10 +397,12 @@ python -m unittest tests.test_config_config -v python -m unittest tests.test_ip -v python -m unittest discover tests -v python -m pytest tests/ -v # optional, when pytest is installed -ruff check --fix --unsafe-fixes . -ruff format . +ruff check . +ruff format --check . ``` +Inspect proposed lint and formatting fixes and limit them to files touched by the task. + Use these focused targets as a guide: - Provider: `python -m unittest tests.test_provider_ -v` @@ -426,7 +438,7 @@ Common checks: - Proxy/network issue: compare with `ddns/util/http.py`; use `--proxy=DIRECT` or `--ssl=false` only as diagnostics. - Schema mismatch: update `schema/v4.1.json` and matching config tests together. - Test failure: inspect mock return values and `mock_http.call_args`. -- Linting issue: run `ruff check --fix --unsafe-fixes .` and `ruff format .`. +- Linting issue: run `ruff check .` and `ruff format --check .`, then review fixes only for the affected files. ```bash python -m ddns --debug --dns=myprovider --ipv4=test.com diff --git a/tools/check.py b/tools/check.py index b5925d0..93f6daf 100644 --- a/tools/check.py +++ b/tools/check.py @@ -86,7 +86,7 @@ def lanes_for_path(path: str) -> tuple[str, ...]: ): lanes.append("Build/Release") if ( - path == "AGENTS.md" + path in ("AGENTS.md", ".github/copilot-instructions.md") or path.endswith("/AGENTS.md") or path.startswith( (".agents/", ".github/agents/", ".github/instructions/", ".github/scripts/", ".github/workflows/", "tools/") diff --git a/tools/tests/test_check.py b/tools/tests/test_check.py index 8a5ba50..e60f6cf 100644 --- a/tools/tests/test_check.py +++ b/tools/tests/test_check.py @@ -42,6 +42,11 @@ class LaneSelectionTests(unittest.TestCase): self.assertEqual(check.lanes_for_path("docs/AGENTS.md"), ("Docs", "Agent/Workflow")) self.assertEqual(check.lanes_for_path("ddns/provider/AGENTS.md"), ("Provider", "Agent/Workflow")) + def test_copilot_instructions_select_only_agent_lane(self) -> None: + for path in (".github/copilot-instructions.md", r".github\copilot-instructions.md"): + self.assertEqual(check.lanes_for_path(path), ("Agent/Workflow",)) + self.assertEqual(check.select_lanes([path])[0], ("Agent/Workflow",)) + def test_executable_docs_are_build_changes(self) -> None: self.assertEqual(check.lanes_for_path("docs/public/install.sh"), ("Docs", "Build/Release")) self.assertEqual(check.lanes_for_path("docs/esa.js"), ("Docs", "Build/Release"))