From c3147e554b40796eaac093b7c4e8c03c7cee915c Mon Sep 17 00:00:00 2001 From: "jinli.yl" Date: Thu, 24 Sep 2026 00:46:22 +0800 Subject: [PATCH] ci: sync AgentScope pin with QwenPaw --- .github/dependabot.yml | 17 ----- .github/workflows/sync-qwenpaw-agentscope.yml | 38 ++++++++++ scripts/sync_qwenpaw_agentscope.py | 73 +++++++++++++++++++ tests/unit/test_sync_qwenpaw_agentscope.py | 29 ++++++++ 4 files changed, 140 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/sync-qwenpaw-agentscope.yml create mode 100644 scripts/sync_qwenpaw_agentscope.py create mode 100644 tests/unit/test_sync_qwenpaw_agentscope.py diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2750f3fa..636c00c1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,20 +16,3 @@ updates: commit-message: prefix: "chore" include: "scope" - - - package-ecosystem: "pip" - directory: "/" - target-branch: "main" - schedule: - interval: "cron" - cronjob: "30 9 * * *" - timezone: "Asia/Shanghai" - allow: - - dependency-name: "agentscope" - cooldown: - exclude: - - "agentscope" - open-pull-requests-limit: 1 - commit-message: - prefix: "chore" - include: "scope" diff --git a/.github/workflows/sync-qwenpaw-agentscope.yml b/.github/workflows/sync-qwenpaw-agentscope.yml new file mode 100644 index 00000000..43df26bc --- /dev/null +++ b/.github/workflows/sync-qwenpaw-agentscope.yml @@ -0,0 +1,38 @@ +name: Sync AgentScope with QwenPaw + +on: + schedule: + - cron: "30 1 * * *" # 09:30 Asia/Shanghai + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +concurrency: + group: sync-qwenpaw-agentscope + cancel-in-progress: false + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Fetch QwenPaw's dependency declaration + run: curl --fail --location --silent --show-error --retry 3 https://raw.githubusercontent.com/agentscope-ai/QwenPaw/main/pyproject.toml --output "$RUNNER_TEMP/qwenpaw-pyproject.toml" + - name: Sync AgentScope pin + run: | + python -m pip install packaging + python scripts/sync_qwenpaw_agentscope.py "$RUNNER_TEMP/qwenpaw-pyproject.toml" pyproject.toml + - name: Create update pull request + uses: peter-evans/create-pull-request@v8 + with: + add-paths: pyproject.toml + branch: automation/sync-qwenpaw-agentscope + delete-branch: true + commit-message: "chore(deps): sync AgentScope with QwenPaw" + title: "chore(deps): sync AgentScope with QwenPaw" + body: "Align ReMe's AgentScope pin with the exact stable version in QwenPaw's main-branch pyproject.toml." diff --git a/scripts/sync_qwenpaw_agentscope.py b/scripts/sync_qwenpaw_agentscope.py new file mode 100644 index 00000000..71603219 --- /dev/null +++ b/scripts/sync_qwenpaw_agentscope.py @@ -0,0 +1,73 @@ +"""Sync ReMe's AgentScope pin with QwenPaw's direct dependency.""" + +import argparse +import re +import tomllib +from pathlib import Path + +from packaging.requirements import Requirement +from packaging.version import Version + +_PIN = re.compile(r'"agentscope\[model-ollama\]==[^"\n]+"') + + +def _exact_agentscope_version(dependencies: list[str]) -> str: + requirements = [Requirement(value) for value in dependencies] + matches = [requirement for requirement in requirements if requirement.name.lower() == "agentscope"] + if len(matches) != 1: + raise ValueError(f"Expected one AgentScope dependency, found {len(matches)}") + requirement = matches[0] + specifiers = list(requirement.specifier) + if ( + requirement.extras != {"model-ollama"} + or requirement.marker is not None + or len(specifiers) != 1 + or specifiers[0].operator != "==" + ): + raise ValueError( + f"Expected an exact agentscope[model-ollama] pin, found {requirement}", + ) + version = Version(specifiers[0].version) + if version.is_prerelease or version.is_devrelease: + raise ValueError(f"Expected a stable AgentScope version, found {version}") + return str(version) + + +def sync_pin(qwenpaw_text: str, reme_text: str) -> tuple[str, str]: + """Return the QwenPaw version and updated ReMe manifest, failing on ambiguous pins.""" + qwenpaw = tomllib.loads(qwenpaw_text) + reme = tomllib.loads(reme_text) + version = _exact_agentscope_version(qwenpaw["project"]["dependencies"]) + _exact_agentscope_version(reme["project"]["optional-dependencies"]["as"]) + matches = list(_PIN.finditer(reme_text)) + if len(matches) != 1: + raise ValueError( + f"Expected one replaceable ReMe AgentScope pin, found {len(matches)}", + ) + replacement = f'"agentscope[model-ollama]=={version}"' + return ( + version, + reme_text[: matches[0].start()] + replacement + reme_text[matches[0].end() :], + ) + + +def main() -> None: + """Synchronize the local manifest from a downloaded QwenPaw manifest.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("qwenpaw_manifest", type=Path) + parser.add_argument("reme_manifest", type=Path) + args = parser.parse_args() + original = args.reme_manifest.read_text(encoding="utf-8") + version, updated = sync_pin( + args.qwenpaw_manifest.read_text(encoding="utf-8"), + original, + ) + if updated != original: + args.reme_manifest.write_text(updated, encoding="utf-8") + print(f"Updated ReMe AgentScope pin to QwenPaw's {version}") + else: + print(f"ReMe already matches QwenPaw's AgentScope {version}") + + +if __name__ == "__main__": + main() diff --git a/tests/unit/test_sync_qwenpaw_agentscope.py b/tests/unit/test_sync_qwenpaw_agentscope.py new file mode 100644 index 00000000..71f13199 --- /dev/null +++ b/tests/unit/test_sync_qwenpaw_agentscope.py @@ -0,0 +1,29 @@ +"""Tests for the QwenPaw AgentScope dependency sync.""" + +import pytest + +from scripts.sync_qwenpaw_agentscope import sync_pin + +QWENPAW = '[project]\ndependencies = ["agentscope[model-ollama]==2.0.8"]\n' +REME = '[project.optional-dependencies]\nas = ["agentscope[model-ollama]==2.0.7.post1"]\n' + + +def test_sync_pin_updates_only_reme_pin(): + """A stable QwenPaw pin replaces ReMe's exact pin.""" + version, updated = sync_pin(QWENPAW, REME) + assert version == "2.0.8" + assert updated == REME.replace("2.0.7.post1", "2.0.8") + + +@pytest.mark.parametrize( + "upstream", + [ + '[project]\ndependencies = ["agentscope[model-ollama]>=2.0.8"]\n', + '[project]\ndependencies = ["agentscope[model-ollama]==2.0.9rc1"]\n', + '[project]\ndependencies = ["other==1.0"]\n', + ], +) +def test_sync_pin_rejects_missing_nonexact_or_prerelease_upstream_pin(upstream): + """An absent or ambiguous QwenPaw pin never changes ReMe's manifest.""" + with pytest.raises(ValueError): + sync_pin(upstream, REME)