mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-30 20:35:22 +08:00
feat(plugins): consolidate official plugins with independent releases (LANG-180) (#2797)
Co-authored-by: multica-agent <[email protected]>
This commit is contained in:
co-authored by
multica-agent
parent
d099033d79
commit
3a77306c3c
@@ -2,6 +2,9 @@ name: Build Dev Image
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "plugins/**"
|
||||
- ".github/workflows/plugins-*.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -5,6 +5,7 @@ on:
|
||||
types: [published]
|
||||
jobs:
|
||||
publish-docker-image:
|
||||
if: ${{ !startsWith(github.event.release.tag_name, 'plugins/') }}
|
||||
runs-on: ubuntu-latest
|
||||
name: Build image
|
||||
|
||||
@@ -51,4 +52,4 @@ jobs:
|
||||
if [[ "$RELEASE_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-beta\.[0-9]+$ ]]; then
|
||||
tags+=(-t rockchin/langbot:beta)
|
||||
fi
|
||||
docker buildx build --build-arg LANGBOT_BUILD_REVISION=${{ github.sha }} --platform linux/arm64,linux/amd64 "${tags[@]}" . --push
|
||||
docker buildx build --build-arg LANGBOT_BUILD_REVISION=${{ github.sha }} --platform linux/arm64,linux/amd64 "${tags[@]}" . --push
|
||||
|
||||
@@ -11,6 +11,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
build-fnos-fpk:
|
||||
if: ${{ !startsWith(github.event.release.tag_name, 'plugins/') && !startsWith(github.ref, 'refs/tags/plugins/') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
@@ -8,6 +8,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build-artifacts:
|
||||
if: ${{ !startsWith(github.event.release.tag_name, 'plugins/') && !startsWith(github.ref, 'refs/tags/plugins/') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -37,7 +38,7 @@ jobs:
|
||||
- name: Make Temp Directory
|
||||
run: |
|
||||
mkdir -p /tmp/langbot_build_web
|
||||
cp -r . /tmp/langbot_build_web
|
||||
rsync -a --exclude='/plugins/' --exclude='*.lbpkg' . /tmp/langbot_build_web/
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
@@ -54,12 +55,16 @@ jobs:
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: langbot-${{ steps.check_version.outputs.version }}-all
|
||||
path: .
|
||||
path: |
|
||||
.
|
||||
!plugins/**
|
||||
!**/*.lbpkg
|
||||
|
||||
- name: Upload To Release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.RELEASE_UPLOAD_GITHUB_TOKEN }}
|
||||
run: |
|
||||
# 本目录下所有文件打包成zip
|
||||
zip -r langbot-${{ steps.check_version.outputs.version }}-all.zip .
|
||||
gh release upload ${{ github.event.release.tag_name }} langbot-${{ steps.check_version.outputs.version }}-all.zip
|
||||
zip -r "$RUNNER_TEMP/langbot-${{ steps.check_version.outputs.version }}-all.zip" . -x 'plugins/*' '*.lbpkg' '.git/*'
|
||||
python3 scripts/check_core_artifacts.py "$RUNNER_TEMP/langbot-${{ steps.check_version.outputs.version }}-all.zip"
|
||||
gh release upload ${{ github.event.release.tag_name }} "$RUNNER_TEMP/langbot-${{ steps.check_version.outputs.version }}-all.zip"
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
name: Core packaging boundary
|
||||
|
||||
on:
|
||||
push:
|
||||
paths: ['plugins/**', 'src/**', 'pyproject.toml', 'MANIFEST.in', '.gitattributes', '.gitignore', '.dockerignore', 'Dockerfile', 'packaging/**', 'scripts/check_core_artifacts.py', '.github/workflows/**']
|
||||
pull_request:
|
||||
paths: ['plugins/**', 'src/**', 'pyproject.toml', 'MANIFEST.in', '.gitattributes', '.gitignore', '.dockerignore', 'Dockerfile', 'packaging/**', 'scripts/check_core_artifacts.py', '.github/workflows/**']
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
- name: Check repository release boundaries
|
||||
run: |
|
||||
uv run --no-project --with pyyaml python plugins/scripts/test_repository.py
|
||||
- name: Build Core sdist and wheel without installing Core dependencies
|
||||
run: |
|
||||
uv build
|
||||
python scripts/check_core_artifacts.py dist/*.whl dist/*.tar.gz
|
||||
- name: Verify Git export excludes plugin sources
|
||||
run: |
|
||||
git archive --format=tar --output="$RUNNER_TEMP/core-source.tar" HEAD
|
||||
python scripts/check_core_artifacts.py "$RUNNER_TEMP/core-source.tar"
|
||||
- name: Verify the production Docker context exclusion
|
||||
run: |
|
||||
docker build --file - --tag langbot-packaging-boundary . <<'DOCKERFILE'
|
||||
FROM scratch
|
||||
COPY . /app
|
||||
DOCKERFILE
|
||||
docker save langbot-packaging-boundary -o "$RUNNER_TEMP/core-context.tar"
|
||||
python scripts/check_core_artifacts.py --docker-archive "$RUNNER_TEMP/core-context.tar"
|
||||
@@ -46,22 +46,6 @@ jobs:
|
||||
enable-cache: true
|
||||
- name: Install locked dependencies
|
||||
run: uv sync --dev --frozen
|
||||
- name: Read official plugin source pin
|
||||
id: plugins
|
||||
run: |
|
||||
python - <<'PY'
|
||||
import json, os
|
||||
from pathlib import Path
|
||||
revision = json.loads(Path('tests/fixtures/legacy_plugin_identity_sources.json').read_text())['revision']
|
||||
with open(os.environ['GITHUB_OUTPUT'], 'a') as stream:
|
||||
stream.write(f'revision={revision}\n')
|
||||
PY
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: langbot-app/langbot-plugins
|
||||
ref: ${{ steps.plugins.outputs.revision }}
|
||||
path: .smoke-plugins
|
||||
persist-credentials: false
|
||||
- name: Prepare CLI and sandbox image
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
@@ -76,7 +60,7 @@ jobs:
|
||||
- name: Prepare real services and run the 60-second smoke
|
||||
run: |
|
||||
uv run --no-sync python tools/regression_ci.py \
|
||||
--lbctl .smoke-bin/lbctl_linux_amd64 --plugins .smoke-plugins --output .qa/core-smoke
|
||||
--lbctl .smoke-bin/lbctl_linux_amd64 --plugins plugins --output .qa/core-smoke
|
||||
- name: Publish gate result
|
||||
if: always()
|
||||
run: |
|
||||
|
||||
@@ -48,6 +48,7 @@ jobs:
|
||||
if: >-
|
||||
github.repository == 'langbot-app/LangBot' &&
|
||||
github.event_name == 'release' && github.event.action == 'published' &&
|
||||
!startsWith(github.event.release.tag_name, 'plugins/') &&
|
||||
github.event.release.draft == false && github.event.release.prerelease == false
|
||||
needs: tests
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
@@ -6,6 +6,7 @@ on:
|
||||
paths:
|
||||
- 'src/langbot/**'
|
||||
- 'tests/**'
|
||||
- 'plugins/Runner/**'
|
||||
- 'pyproject.toml'
|
||||
- 'pytest.ini'
|
||||
- 'uv.lock'
|
||||
@@ -15,6 +16,7 @@ on:
|
||||
paths:
|
||||
- 'src/langbot/**'
|
||||
- 'tests/**'
|
||||
- 'plugins/Runner/**'
|
||||
- 'pyproject.toml'
|
||||
- 'pytest.ini'
|
||||
- 'uv.lock'
|
||||
@@ -106,30 +108,6 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Read official source pin
|
||||
id: plugin-source
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
lock = json.loads(Path('tests/fixtures/legacy_plugin_identity_sources.json').read_text())
|
||||
assert lock['repository'] == 'langbot-app/langbot-plugins'
|
||||
assert re.fullmatch(r'[0-9a-f]{40}', lock['revision'])
|
||||
with open(os.environ['GITHUB_OUTPUT'], 'a') as output:
|
||||
output.write(f"revision={lock['revision']}\n")
|
||||
PY
|
||||
|
||||
- name: Checkout pinned official plugin sources
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: langbot-app/langbot-plugins
|
||||
ref: ${{ steps.plugin-source.outputs.revision }}
|
||||
path: .contract-sources/langbot-plugins
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
@@ -143,7 +121,7 @@ jobs:
|
||||
|
||||
- name: Run required identity consumer contracts
|
||||
env:
|
||||
LANGBOT_LEGACY_PLUGIN_ROOT: ${{ github.workspace }}/.contract-sources/langbot-plugins
|
||||
LANGBOT_LEGACY_PLUGIN_ROOT: ${{ github.workspace }}/plugins
|
||||
run: |
|
||||
uv run --no-sync pytest --required-suite plugin_identity \
|
||||
-q --tb=short -rs --junitxml=plugin-identity-results.xml
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
name: Plugins / KnowledgeEngine shared SDK verification
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "plugins/pytest.ini"
|
||||
- 'plugins/KnowledgeEngine/**'
|
||||
- '.github/workflows/plugins-knowledgeengine-shared-tests.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- "plugins/pytest.ini"
|
||||
- 'plugins/KnowledgeEngine/**'
|
||||
- '.github/workflows/plugins-knowledgeengine-shared-tests.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
candidate-sdk:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
defaults:
|
||||
run:
|
||||
working-directory: plugins
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
- name: Install released SDK and test dependencies
|
||||
run: |
|
||||
uv venv
|
||||
uv pip install 'https://files.pythonhosted.org/packages/f2/c7/c870377771cbe27e047b19778b5f249b15efef52409358901af94d13e6c0/langbot_plugin-0.7.4-py3-none-any.whl#sha256=596ecd776c13efa6f6cfe178463dc4a967653238548c9569195cdbb5aa47506e' pytest pytest-asyncio \
|
||||
-r KnowledgeEngine/LangRAG/requirements.txt \
|
||||
-r KnowledgeEngine/DifyDatasetsConnector/requirements.txt \
|
||||
-r KnowledgeEngine/FastGPTConnector/requirements.txt \
|
||||
-r KnowledgeEngine/RAGFlowConnector/requirements.txt
|
||||
- name: Behavioral regressions (fake Host and HTTP provider)
|
||||
run: .venv/bin/python -m pytest KnowledgeEngine/certification-tests -q
|
||||
- name: LangRAG legacy unit and benchmark fixtures
|
||||
working-directory: plugins/KnowledgeEngine/LangRAG
|
||||
run: ../../.venv/bin/python -m unittest discover -s tests -v
|
||||
- name: LongTermMemory regressions
|
||||
working-directory: plugins/KnowledgeEngine/LongTermMemory
|
||||
run: PYTHONPATH=. ../../.venv/bin/python -m pytest tests -q
|
||||
- name: Exact archives, real dependency prepare, discovery and RPC
|
||||
run: .venv/bin/python KnowledgeEngine/certification-tests/verify_candidates.py --evidence "$RUNNER_TEMP/ke-evidence"
|
||||
- name: Retain unsigned candidate evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: knowledgeengine-unsigned-candidates
|
||||
path: |
|
||||
${{ runner.temp }}/ke-evidence/*.json
|
||||
${{ runner.temp }}/ke-evidence/*.log
|
||||
${{ runner.temp }}/ke-evidence/packages/**/*.lbpkg
|
||||
@@ -0,0 +1,41 @@
|
||||
name: Plugins / LangRAG tests
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "plugins/pytest.ini"
|
||||
- 'plugins/KnowledgeEngine/LangRAG/**'
|
||||
- '.github/workflows/plugins-langrag-tests.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- "plugins/pytest.ini"
|
||||
- 'plugins/KnowledgeEngine/LangRAG/**'
|
||||
- '.github/workflows/plugins-langrag-tests.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
uv venv
|
||||
uv pip install \
|
||||
'https://files.pythonhosted.org/packages/f2/c7/c870377771cbe27e047b19778b5f249b15efef52409358901af94d13e6c0/langbot_plugin-0.7.4-py3-none-any.whl#sha256=596ecd776c13efa6f6cfe178463dc4a967653238548c9569195cdbb5aa47506e' \
|
||||
-r plugins/KnowledgeEngine/LangRAG/requirements.txt
|
||||
- name: Real SDK import smoke
|
||||
working-directory: plugins/KnowledgeEngine/LangRAG
|
||||
run: |
|
||||
../../../.venv/bin/python -c "import langbot_plugin; from main import LangRAG; from components.knowledge_engine.langrag import LangRAG as Engine; from components.pages.observability import LangRAGObservabilityPage; print('Real SDK:', langbot_plugin.__file__); print(LangRAG.__name__, Engine.__name__, LangRAGObservabilityPage.__name__)"
|
||||
- name: Unit and benchmark tests
|
||||
working-directory: plugins/KnowledgeEngine/LangRAG
|
||||
run: ../../../.venv/bin/python -m unittest discover -s tests -v
|
||||
@@ -0,0 +1,59 @@
|
||||
name: Plugins / LocalAgent tests
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "plugins/pytest.ini"
|
||||
- "plugins/Runner/LocalAgent/**"
|
||||
- ".github/workflows/plugins-local-agent-tests.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- "plugins/pytest.ini"
|
||||
- "plugins/Runner/LocalAgent/**"
|
||||
- ".github/workflows/plugins-local-agent-tests.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
- name: Checkout plugins
|
||||
uses: actions/checkout@v4
|
||||
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
|
||||
- name: Keep environment outside the checkout
|
||||
run: |
|
||||
printf 'UV_PROJECT_ENVIRONMENT=%s/local-agent-venv\n' "$RUNNER_TEMP" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync --locked --extra dev
|
||||
working-directory: plugins/Runner/LocalAgent
|
||||
|
||||
- name: Verify explicit-export SDK contract
|
||||
run: uv run --no-sync python -c 'from inspect import signature; from langbot_plugin.api.entities.builtin.runner.context import RunnerContext; assert "paths" in signature(RunnerContext.export_box_files).parameters'
|
||||
working-directory: plugins/Runner/LocalAgent
|
||||
|
||||
- name: Ruff check
|
||||
run: uv run --no-sync ruff check .
|
||||
working-directory: plugins/Runner/LocalAgent
|
||||
|
||||
- name: Ruff format check
|
||||
run: uv run --no-sync ruff format --check .
|
||||
working-directory: plugins/Runner/LocalAgent
|
||||
|
||||
- name: Pytest
|
||||
run: uv run --no-sync pytest
|
||||
working-directory: plugins/Runner/LocalAgent
|
||||
@@ -0,0 +1,67 @@
|
||||
name: Plugins / Misc plugin tests
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "plugins/pytest.ini"
|
||||
- "plugins/misc/**"
|
||||
- ".github/workflows/plugins-misc-tests.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- "plugins/pytest.ini"
|
||||
- "plugins/misc/**"
|
||||
- ".github/workflows/plugins-misc-tests.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
defaults:
|
||||
run:
|
||||
working-directory: plugins
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
|
||||
# Each misc plugin imports its own modules through sys.path tricks, so every
|
||||
# suite runs in its own interpreter and its own environment; requirements.txt
|
||||
# is the per-plugin dependency declaration (manifests do not carry them).
|
||||
- name: Run every misc plugin suite in isolation
|
||||
run: |
|
||||
set -uo pipefail
|
||||
status=0
|
||||
ran=0
|
||||
for plugin in misc/*/; do
|
||||
plugin="${plugin%/}"
|
||||
name="$(basename "$plugin")"
|
||||
if [ ! -d "$plugin/tests" ]; then
|
||||
echo "::notice::$name has no tests/ directory; skipped"
|
||||
continue
|
||||
fi
|
||||
ran=$((ran + 1))
|
||||
env_dir="$RUNNER_TEMP/venv-$name"
|
||||
echo "=== $name ==="
|
||||
uv venv "$env_dir" --python 3.11 >/dev/null
|
||||
python_bin="$env_dir/bin/python"
|
||||
install_args=(--python "$python_bin"
|
||||
'https://files.pythonhosted.org/packages/f2/c7/c870377771cbe27e047b19778b5f249b15efef52409358901af94d13e6c0/langbot_plugin-0.7.4-py3-none-any.whl#sha256=596ecd776c13efa6f6cfe178463dc4a967653238548c9569195cdbb5aa47506e'
|
||||
pytest pytest-asyncio)
|
||||
if [ -s "$plugin/requirements.txt" ]; then
|
||||
install_args+=(-r "$plugin/requirements.txt")
|
||||
fi
|
||||
uv pip install "${install_args[@]}" >/dev/null
|
||||
"$python_bin" -c 'from importlib.metadata import version; assert version("langbot-plugin") == "0.7.4"'
|
||||
if ! (cd "$plugin" && "$python_bin" -m pytest tests -q -p no:cacheprovider); then
|
||||
echo "::error::$name test suite failed"
|
||||
status=1
|
||||
fi
|
||||
done
|
||||
echo "Ran $ran misc suites"
|
||||
exit $status
|
||||
@@ -0,0 +1,39 @@
|
||||
name: Plugins / Build package
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
plugin:
|
||||
description: 'Exact catalog path, for example Runner/LocalAgent'
|
||||
type: string
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
package:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
- name: Install the plugin build CLI independently of Core
|
||||
run: |
|
||||
uv venv "$RUNNER_TEMP/plugin-build"
|
||||
uv pip install --python "$RUNNER_TEMP/plugin-build/bin/python" 'langbot-plugin==0.7.18' pyyaml
|
||||
echo "$RUNNER_TEMP/plugin-build/bin" >> "$GITHUB_PATH"
|
||||
- name: Build selected plugin without publishing
|
||||
env:
|
||||
PLUGIN_PATH: ${{ inputs.plugin }}
|
||||
run: python plugins/scripts/package_plugin.py "$PLUGIN_PATH" --output "$RUNNER_TEMP/plugin-packages"
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: plugin-package-${{ github.run_id }}
|
||||
path: ${{ runner.temp }}/plugin-packages/*.lbpkg
|
||||
if-no-files-found: error
|
||||
@@ -0,0 +1,24 @@
|
||||
name: Plugins / Plugin catalog
|
||||
|
||||
on:
|
||||
push:
|
||||
paths: ["plugins/**", ".github/workflows/plugins-*.yml"]
|
||||
pull_request:
|
||||
paths: ["plugins/**", ".github/workflows/plugins-*.yml"]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
catalog:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- run: python -m pip install pyyaml
|
||||
- run: python plugins/scripts/check_catalog.py
|
||||
- run: python plugins/scripts/test_repository.py
|
||||
@@ -0,0 +1,85 @@
|
||||
name: Plugins / Runner tests
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "plugins/pytest.ini"
|
||||
- "plugins/Runner/**"
|
||||
- ".github/workflows/plugins-runner-tests.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- "plugins/pytest.ini"
|
||||
- "plugins/Runner/**"
|
||||
- ".github/workflows/plugins-runner-tests.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
defaults:
|
||||
run:
|
||||
working-directory: plugins/Runner
|
||||
steps:
|
||||
- name: Checkout plugins
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
- name: Keep environment outside the checkout
|
||||
run: |
|
||||
printf 'UV_PROJECT_ENVIRONMENT=%s/runner-venv\n' "$RUNNER_TEMP" >> "$GITHUB_ENV"
|
||||
printf 'RUNNER_EVIDENCE_DIR=%s/runner-evidence\n' "$RUNNER_TEMP" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync --locked --dev
|
||||
- name: Verify published SDK pin
|
||||
run: uv run --no-sync python -c 'from importlib.metadata import version; assert version("langbot-plugin") == "0.7.4"; print("langbot-plugin", version("langbot-plugin"))'
|
||||
- name: Prepare isolated certified coding Runner SDK environment
|
||||
run: |
|
||||
uv venv "$RUNNER_TEMP/coding-074"
|
||||
# PyPI's aggregate index can lag the exact 0.7.4 release endpoint.
|
||||
uv pip install --python "$RUNNER_TEMP/coding-074/bin/python" \
|
||||
'https://files.pythonhosted.org/packages/f2/c7/c870377771cbe27e047b19778b5f249b15efef52409358901af94d13e6c0/langbot_plugin-0.7.4-py3-none-any.whl#sha256=596ecd776c13efa6f6cfe178463dc4a967653238548c9569195cdbb5aa47506e' \
|
||||
-r acp-agent-runner/requirements.txt -r claude-code-agent/requirements.txt -r codex-agent/requirements.txt pytest pyyaml packaging
|
||||
"$RUNNER_TEMP/coding-074/bin/python" -c 'from importlib.metadata import version; assert version("langbot-plugin") == "0.7.4"'
|
||||
printf 'CODING_RUNNER_TEST_PYTHON=%s/coding-074/bin/python\n' "$RUNNER_TEMP" >> "$GITHUB_ENV"
|
||||
- name: Prepare isolated LocalAgent explicit-export SDK environment
|
||||
run: |
|
||||
UV_PROJECT_ENVIRONMENT="$RUNNER_TEMP/localagent-074" uv sync --project LocalAgent --locked --extra dev
|
||||
"$RUNNER_TEMP/localagent-074/bin/python" -c 'from inspect import signature; from langbot_plugin.api.entities.builtin.runner.context import RunnerContext; assert "paths" in signature(RunnerContext.export_box_files).parameters'
|
||||
printf 'LOCALAGENT_TEST_PYTHON=%s/localagent-074/bin/python\n' "$RUNNER_TEMP" >> "$GITHUB_ENV"
|
||||
# Preserve the external Runner lint scope; LocalAgent has its own Ruff config.
|
||||
# RunnerDemo did not have a Ruff gate before consolidation.
|
||||
- name: Ruff check
|
||||
run: uv run --no-sync ruff check tests http-certification-tests ./*-agent acp-agent-runner
|
||||
- name: Ruff format check
|
||||
run: uv run --no-sync ruff format --check tests http-certification-tests ./*-agent acp-agent-runner
|
||||
- name: LocalAgent Ruff check
|
||||
run: uv run --no-sync ruff check LocalAgent
|
||||
- name: LocalAgent Ruff format check
|
||||
run: uv run --no-sync ruff format --check LocalAgent
|
||||
- name: All Runner tests, including isolated plugin suites (LocalAgent, RunnerDemo, shared agents)
|
||||
run: uv run --no-sync python -m pytest --junitxml="${RUNNER_EVIDENCE_DIR}/runner.xml"
|
||||
# Generic pkg/test module names require a fresh pytest interpreter.
|
||||
- name: HTTP Runner certification regressions
|
||||
run: uv run --no-sync python -m pytest http-certification-tests -q --junitxml="${RUNNER_EVIDENCE_DIR}/http-certification.xml"
|
||||
- name: Certified RunnerDemo SDK admission and package tests
|
||||
run: |
|
||||
"$RUNNER_TEMP/coding-074/bin/python" certification-tests/test_runner_demo_dependency_admission.py -v
|
||||
cd RunnerDemo
|
||||
"$RUNNER_TEMP/coding-074/bin/python" -m unittest discover -s tests -v
|
||||
- name: Upload test evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: runner-test-evidence
|
||||
path: ${{ runner.temp }}/runner-evidence
|
||||
if-no-files-found: warn
|
||||
@@ -12,6 +12,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
if: ${{ !startsWith(github.event.release.tag_name, 'plugins/') && !startsWith(inputs.source_ref, 'plugins/') && !startsWith(github.ref, 'refs/tags/plugins/') }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -72,6 +73,7 @@ jobs:
|
||||
run: |
|
||||
python3 scripts/stamp_build_revision.py
|
||||
uv build
|
||||
python3 scripts/check_core_artifacts.py dist/*.whl dist/*.tar.gz
|
||||
|
||||
- name: Publish to PyPI
|
||||
run: |
|
||||
|
||||
@@ -6,6 +6,7 @@ on:
|
||||
paths:
|
||||
- 'src/langbot/**'
|
||||
- 'tests/**'
|
||||
- 'plugins/Runner/**'
|
||||
- '.github/workflows/run-tests.yml'
|
||||
- 'pyproject.toml'
|
||||
- 'uv.lock'
|
||||
@@ -181,30 +182,6 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Read official plugin source pin
|
||||
id: plugin-source
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
lock = json.loads(Path('tests/fixtures/legacy_plugin_identity_sources.json').read_text())
|
||||
assert lock['repository'] == 'langbot-app/langbot-plugins'
|
||||
assert re.fullmatch(r'[0-9a-f]{40}', lock['revision'])
|
||||
with open(os.environ['GITHUB_OUTPUT'], 'a') as output:
|
||||
output.write(f"revision={lock['revision']}\n")
|
||||
PY
|
||||
|
||||
- name: Checkout pinned official plugin sources
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: langbot-app/langbot-plugins
|
||||
ref: ${{ steps.plugin-source.outputs.revision }}
|
||||
path: .contract-sources/langbot-plugins
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
@@ -244,7 +221,7 @@ jobs:
|
||||
|
||||
- name: Run required LocalAgent contracts
|
||||
env:
|
||||
LANGBOT_LEGACY_PLUGIN_ROOT: ${{ github.workspace }}/.contract-sources/langbot-plugins
|
||||
LANGBOT_LEGACY_PLUGIN_ROOT: ${{ github.workspace }}/plugins
|
||||
run: |
|
||||
uv run --no-sync pytest --required-suite local_agent \
|
||||
-q --tb=short -rs --junitxml=local-agent-results.xml
|
||||
|
||||
Reference in New Issue
Block a user