Skip to content

ci: add unit-test workflow + single-source __version__ - #22

Merged
ChHsiching merged 5 commits into
mainfrom
ci/add-ci-workflow-and-fix-version-source
Jul 18, 2026
Merged

ci: add unit-test workflow + single-source __version__#22
ChHsiching merged 5 commits into
mainfrom
ci/add-ci-workflow-and-fix-version-source

Conversation

@ChHsiching

Copy link
Copy Markdown
Owner

Why

Two gaps surfaced during the v0.2.1 wrap-up:

  1. No status checks. Only release.yml existed (tag-triggered). Every push to main and every PR carried no ✓/✗ — a red commit could land if someone forgot to run pytest locally.
  2. Version drift. v0.2.1 shipped while both pyproject.toml and __init__.py still read 0.1.0. Two hardcoded sources, no sync mechanism.

What (4 commits)

  1. 799d4e9 ci: add workflow.github/workflows/ci.yml runs the unit suite on push to main + PRs, ubuntu-latest / Python 3.11. Integration tests deselected (-m "not integration") so upstream network blips never turn a correct commit red.
  2. 163298b test: integration marker@pytest.mark.integration on the one network-dependent test (test_tools_call_returns_json_shaped_response), marker registered in pyproject.toml. Local pytest still runs all 25; CI deselects 1.
  3. 11e55d7 fix(version): single-source__init__.py reads __version__ via importlib.metadata.version(); pyproject.toml bumped to 0.2.1. Also updates agent-web-search.spec to copy_metadata("agent-web-search") — without this the frozen binary loses package metadata and silently falls back to 0.0.0+dev.
  4. 3e61f80 test(smoke): version assertionscripts/smoke_test.py now asserts serverInfo.version is present and doesn't look like the dev fallback, so a broken release can't ship with a garbage version.

Verification

  • python -m pytest -m "not integration" → 24 passed, 1 deselected
  • python -m pytest (full) → 25 passed
  • pip install -e . && python -c "import agent_web_search; print(agent_web_search.__version__)"0.2.1
  • Local PyInstaller build + smoke test: smoke test OK: 1.75s startup, server=agent-web-search v0.2.1 — confirms copy_metadata made importlib.metadata resolve in the frozen binary (the key risk the code-review caught)
  • ✅ Commit granularity reviewed (1 concern per commit)
  • ✅ Code-review subagent run (Standards + Spec); findings addressed

The code-review catch worth calling out

The review subagent flagged that importlib.metadata.version() depends on .dist-info that PyInstaller doesn't bundle by default. Without copy_metadata in the spec, every release binary would report serverInfo.version = "0.0.0+dev" and the existing smoke test wouldn't catch it (it only checked serverInfo.name). Commits 3 and 4 close both halves of that gap.

What this PR does NOT do

  • No branch protection. Enabling "require status checks to pass" is a repo-settings action, not code. After merge, to enforce the gate: Settings → Branches → Branch protection for main → Require status checks to pass before merging → select test (the ci.yml job name).
  • No cross-platform CI. release.yml already covers windows/ubuntu/macos for the binary; CI is intentionally logic-only.
  • No new release. Infrastructure-only. The version bump to 0.2.1 fixes drift vs. the existing v0.2.1 tag — not a new release.

Post-merge

The first push to main after merge will trigger ci.yml and you'll see the green ✓ on the merge commit. If you want the gate enforced on future PRs, enable branch protection as above.

Until now only release.yml existed, triggered by version tags. Every
other commit — including all PRs — carried no status check, so a red
commit could land in main if someone forgot to run pytest locally.
The v0.2.1 release shipped with __version__ still at 0.1.0; that kind
of drift is exactly what a CI gate catches.

ci.yml runs the unit suite on ubuntu-latest / Python 3.11 on push to
main and on every PR. Integration tests that hit the live ddgs pipeline
are deselected with -m "not integration" so the check is a stable
signal: upstream rate-limiting or a transient network blip must never
turn a correct commit red. Cross-platform coverage stays with
release.yml, which already builds and smoke-tests the PyInstaller
binary on windows/ubuntu/macos.
test_tools_call_returns_json_shaped_response is the one test that runs
the real ddgs/DuckDuckGo pipeline — every other test is offline (pure
logic or fake-injected seams). Without a marker, the new ci.yml would
have to deselect by test name (-k 'not ...'), which breaks the moment
the test is renamed.

Register the marker in pyproject.toml so it's documented and doesn't
warn. Local `python -m pytest` still runs the full 25 — CI is the only
place that deselects (-m "not integration"). Developers keep a way to
exercise the live network path when they need to.
v0.2.1 shipped while both pyproject.toml and __init__.py still read
0.1.0 — two hardcoded sources with no sync mechanism, so the release
tag and the in-code version drifted apart silently.

__init__.py now reads the version via importlib.metadata, making
pyproject.toml the single source of truth. __version__, the MCP
serverInfo.version reported by server.py, and the PyInstaller-built
binary all follow pyproject automatically once installed. Bumps
pyproject to 0.2.1 to match the current release.

The PackageNotFoundError fallback ("0.0.0+dev") keeps running from a
raw checkout without `pip install -e .` from crashing — version isn't
meaningful in that mode, but tests and dev workflows that don't read
it still work.

Also updates agent-web-search.spec to bundle our own dist-info via
copy_metadata(). Without this, the frozen binary would not carry the
package metadata and importlib.metadata.version() would raise
PackageNotFoundError at runtime — silently falling back to
"0.0.0+dev" in every release. The spec change is what makes the
single-source claim actually hold for the distributed binary.
The smoke test only checked serverInfo.name, so a binary that silently
fell back to __version__ = '0.0.0+dev' (the PackageNotFoundError branch
in __init__.py) would pass smoke and ship. That happens precisely when
package metadata isn't bundled — the exact regression the spec's
copy_metadata() guards against.

Now asserts version is present and doesn't look like the dev fallback.
If the spec or the __init__.py single-sourcing ever regresses, the
release smoke catches it before the binary goes out the door.
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4bc6bc99-4f66-4bc7-bc38-b90ec3d25e03

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/add-ci-workflow-and-fix-version-source

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ChHsiching
ChHsiching merged commit f079846 into main Jul 18, 2026
2 checks passed
@ChHsiching
ChHsiching deleted the ci/add-ci-workflow-and-fix-version-source branch July 18, 2026 16:10
test_stdout_is_clean_json_rpc_only manually closed proc.stdin before
calling proc.communicate(). communicate() closes stdin itself and then
calls stdin.flush() internally; on a pre-closed file that flush raises
ValueError: flush of closed file on Linux, while Windows tolerates it.

This was a latent bug masked by developing on Windows — the new ci.yml
runs on ubuntu and surfaced it immediately as a hard failure. That's
exactly what CI is for. The manual close was redundant anyway:
communicate() handles stdin closure by default.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant