nonebot-plugin-htmlrender 0.7.1__tar.gz → 0.7.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/docs.yml +3 -38
- nonebot_plugin_htmlrender-0.7.2/.github/workflows/publish.yml +231 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/CONTRIBUTING.md +3 -6
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/PKG-INFO +1 -1
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/quality/ci-actions.md +15 -15
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/quality/versioning.md +7 -5
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/api.md +7 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/index.md +1 -0
- nonebot_plugin_htmlrender-0.7.2/docs/users/migration-v072.md +46 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/migration.md +4 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/security.md +18 -2
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/mkdocs.yml +1 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/operations.py +24 -11
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/markdown.html +3 -3
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/text/text.html +1 -1
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/pyproject.toml +1 -1
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_operations.py +77 -9
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/remote_smoke.py +6 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/render/test_render_api.py +2 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/uv.lock +1 -1
- nonebot_plugin_htmlrender-0.7.1/.github/workflows/publish.yml +0 -129
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/auto-tag.yml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/ci.yml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/coverage.yml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/docs-pr-preview.yml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/prek.yml +0 -0
- {nonebot_plugin_htmlrender-0.7.1/.github/workflows → nonebot_plugin_htmlrender-0.7.2/.github/workflows-disabled}/publish-test.yml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.gitignore +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.markdownlint.json +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.pre-commit-config.yaml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.python-version +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/CODE_OF_CONDUCT.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/CODING_STANDARDS.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/COMMIT_MESSAGE.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/LICENSE +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/Makefile +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/README.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/SECURITY.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docker-compose.dev.yaml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/assets/logo.png +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/assets/nonebot_plugin.svg +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/html2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/index.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/architecture/architecture.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/architecture/custom-backends.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/architecture/filehost-resource-resolution.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/architecture/render-backend-development.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/contributing/coding-standards.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/contributing/commit-message.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/contributing/contributing.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/contributing/engineering-guide.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/index.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/maintainers/quality/testing-matrix.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/md2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/overrides/main.html +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/stylesheets/extra.css +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/template2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/text2pic.png +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/best-practices.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/config/core.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/config/index.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/config/integrations.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/config/playwright.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/examples.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/faq.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/quickstart.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/remote-playwright.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/docs/users/troubleshooting.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/remote_browser/.env.prod +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/remote_browser/README.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/remote_browser/docker-compose.yml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/remote_browser/plugins/remote_render/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/remote_browser/pyproject.toml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/screenshot/README.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/screenshot/plugins/screenshot/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/screenshot/pyproject.toml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/template_render/README.md +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/template_render/plugins/template_render/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/template_render/plugins/template_render/templates/profile.html +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/template_render/plugins/template_render/templates/style.css +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/examples/template_render/pyproject.toml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/_bootstrap.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/_compat.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/base.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/factory.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/_page.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/config.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/data_source.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/install.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/models.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/render.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/runtime.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/telemetry.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/backend/playwright/types.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/browser.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/config.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/consts.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/data_source.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/py.typed +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/render.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/config.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/filehost/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/filehost/cache.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/filehost/guard.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/filehost/warmup.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/resolve.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/resources/template.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/github-markdown-light.css +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/katex/katex.min.b64_fonts.css +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/katex/katex.min.js +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/katex/mathtex-script-type.min.js +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/katex/mhchem.min.js +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/markdown/pygments-default.css +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/templates/text/text.css +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/install.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/process.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/signal.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/telemetry/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/telemetry/common.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/telemetry/prometheus.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/nonebot_plugin_htmlrender/utils/telemetry/sentry.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/__init__.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_backend.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_config.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_install.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_runtime_extra.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/playwright/test_telemetry.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/backend/test_factory.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/conftest.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_config_compat.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_data_source_wrappers.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_install_more.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_lazy_imports.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_plugin_install.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_plugin_module.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_process.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_reexports.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_telemetry_common.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_telemetry_prometheus.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_telemetry_sentry.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_telemetry_track_render.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/core/test_utils_runtime.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/infra/docker-compose.remote-test.yaml +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/infra/dockerfile.playwright-server +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/infra/dockerfile.remote-test +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/infra/playwright-server.mjs +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/render/test_browser_compat.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/render/test_render_concurrency.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/render/test_render_unit.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/resources/test_filehost_extra.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/resources/test_resources.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/resources/test_resources_extra.py +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/resources/test_template_filter.png +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/templates/markdown.css +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/templates/mystyle.css +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/templates/progress.html.jinja2 +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/templates/remote_filehost.html.jinja2 +0 -0
- {nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/tests/templates/text.html +0 -0
{nonebot_plugin_htmlrender-0.7.1 → nonebot_plugin_htmlrender-0.7.2}/.github/workflows/docs.yml
RENAMED
|
@@ -18,11 +18,11 @@ on:
|
|
|
18
18
|
type: boolean
|
|
19
19
|
|
|
20
20
|
permissions:
|
|
21
|
-
contents:
|
|
21
|
+
contents: read
|
|
22
22
|
|
|
23
23
|
jobs:
|
|
24
|
-
|
|
25
|
-
name: Build
|
|
24
|
+
build:
|
|
25
|
+
name: Build Docs
|
|
26
26
|
runs-on: ubuntu-latest
|
|
27
27
|
timeout-minutes: 20
|
|
28
28
|
env:
|
|
@@ -68,38 +68,3 @@ jobs:
|
|
|
68
68
|
path: ${{ env.DOCS_LOG }}
|
|
69
69
|
if-no-files-found: warn
|
|
70
70
|
retention-days: 14
|
|
71
|
-
|
|
72
|
-
- name: Configure git
|
|
73
|
-
run: |
|
|
74
|
-
git config user.name "github-actions[bot]"
|
|
75
|
-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
76
|
-
|
|
77
|
-
- name: Configure authenticated origin
|
|
78
|
-
env:
|
|
79
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
80
|
-
run: |
|
|
81
|
-
git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
|
|
82
|
-
|
|
83
|
-
- name: Get project version
|
|
84
|
-
id: version
|
|
85
|
-
run: |
|
|
86
|
-
VERSION=$(uv version --short)
|
|
87
|
-
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
|
|
88
|
-
|
|
89
|
-
- name: Deploy versioned docs
|
|
90
|
-
env:
|
|
91
|
-
VERSION: ${{ steps.version.outputs.version }}
|
|
92
|
-
run: |
|
|
93
|
-
uv run mike deploy --push --update-aliases "${VERSION}" latest
|
|
94
|
-
|
|
95
|
-
- name: Set default version
|
|
96
|
-
run: |
|
|
97
|
-
uv run mike set-default --push latest
|
|
98
|
-
|
|
99
|
-
- name: Show docs url
|
|
100
|
-
env:
|
|
101
|
-
DOCS_OWNER: ${{ github.repository_owner }}
|
|
102
|
-
DOCS_REPO: ${{ github.event.repository.name }}
|
|
103
|
-
VERSION: ${{ steps.version.outputs.version }}
|
|
104
|
-
run: |
|
|
105
|
-
echo "Docs deployed: https://${DOCS_OWNER}.github.io/${DOCS_REPO}/${VERSION}/"
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
debug_enabled:
|
|
10
|
+
description: Enable extra debug diagnostics
|
|
11
|
+
required: false
|
|
12
|
+
default: false
|
|
13
|
+
type: boolean
|
|
14
|
+
release_tag:
|
|
15
|
+
description: Tag to publish as GitHub Release when manually triggered (e.g. v0.7.0)
|
|
16
|
+
required: false
|
|
17
|
+
default: ""
|
|
18
|
+
type: string
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
pypi-publish:
|
|
22
|
+
name: Upload release to PyPI
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
timeout-minutes: 30
|
|
25
|
+
outputs:
|
|
26
|
+
release_tag: ${{ steps.release_tag.outputs.tag }}
|
|
27
|
+
environment: release
|
|
28
|
+
permissions:
|
|
29
|
+
# IMPORTANT: this permission is mandatory for trusted publishing
|
|
30
|
+
id-token: write
|
|
31
|
+
contents: write
|
|
32
|
+
env:
|
|
33
|
+
BUILD_LOG: publish-build.log
|
|
34
|
+
steps:
|
|
35
|
+
- name: Resolve Release Tag
|
|
36
|
+
id: release_tag
|
|
37
|
+
shell: bash
|
|
38
|
+
env:
|
|
39
|
+
RELEASE_TAG_INPUT: ${{ github.event.inputs.release_tag }}
|
|
40
|
+
run: |
|
|
41
|
+
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
|
|
42
|
+
TAG="${GITHUB_REF_NAME}"
|
|
43
|
+
elif [[ -n "${RELEASE_TAG_INPUT}" ]]; then
|
|
44
|
+
TAG="${RELEASE_TAG_INPUT}"
|
|
45
|
+
else
|
|
46
|
+
echo "::error::No release tag found. Use a tag push or provide workflow_dispatch input 'release_tag'."
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
echo "tag=${TAG}" >> "${GITHUB_OUTPUT}"
|
|
50
|
+
echo "Resolved release tag: ${TAG}"
|
|
51
|
+
|
|
52
|
+
- name: Checkout
|
|
53
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
54
|
+
with:
|
|
55
|
+
ref: refs/tags/${{ steps.release_tag.outputs.tag }}
|
|
56
|
+
fetch-depth: 0
|
|
57
|
+
persist-credentials: false
|
|
58
|
+
|
|
59
|
+
- name: Verify tagged commit is on master
|
|
60
|
+
shell: bash
|
|
61
|
+
env:
|
|
62
|
+
RELEASE_TAG: ${{ steps.release_tag.outputs.tag }}
|
|
63
|
+
run: |
|
|
64
|
+
git fetch --no-tags origin master:refs/remotes/origin/master
|
|
65
|
+
TAG_COMMIT=$(git rev-list -n 1 "${RELEASE_TAG}")
|
|
66
|
+
if [[ "$(git rev-parse HEAD)" != "${TAG_COMMIT}" ]]; then
|
|
67
|
+
echo "::error::Checkout does not match ${RELEASE_TAG}. Refusing to publish."
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
if ! git merge-base --is-ancestor "${TAG_COMMIT}" origin/master; then
|
|
71
|
+
echo "::error::Tagged commit ${TAG_COMMIT} is not an ancestor of master. Refusing to publish."
|
|
72
|
+
exit 1
|
|
73
|
+
fi
|
|
74
|
+
echo "Tagged commit ${TAG_COMMIT} is on master."
|
|
75
|
+
|
|
76
|
+
- name: Install the latest version of uv
|
|
77
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78
|
|
78
|
+
with:
|
|
79
|
+
enable-cache: false
|
|
80
|
+
|
|
81
|
+
- name: Set up Python
|
|
82
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
|
|
83
|
+
with:
|
|
84
|
+
python-version-file: ".python-version"
|
|
85
|
+
|
|
86
|
+
- name: Show Runner Context
|
|
87
|
+
run: |
|
|
88
|
+
echo "Runner: $RUNNER_NAME ($RUNNER_OS/$RUNNER_ARCH)"
|
|
89
|
+
python --version
|
|
90
|
+
uv --version
|
|
91
|
+
|
|
92
|
+
- name: Verify tag matches package version
|
|
93
|
+
shell: bash
|
|
94
|
+
env:
|
|
95
|
+
RELEASE_TAG: ${{ steps.release_tag.outputs.tag }}
|
|
96
|
+
run: |
|
|
97
|
+
VERSION=$(uv version --short)
|
|
98
|
+
EXPECTED_TAG="v${VERSION}"
|
|
99
|
+
if [[ "${RELEASE_TAG}" != "${EXPECTED_TAG}" ]]; then
|
|
100
|
+
echo "::error::Release tag ${RELEASE_TAG} does not match package version ${VERSION}. Expected ${EXPECTED_TAG}."
|
|
101
|
+
exit 1
|
|
102
|
+
fi
|
|
103
|
+
echo "Release tag ${RELEASE_TAG} matches package version ${VERSION}."
|
|
104
|
+
|
|
105
|
+
- name: Sync deps
|
|
106
|
+
run: uv sync
|
|
107
|
+
shell: bash
|
|
108
|
+
|
|
109
|
+
- name: Debug Dependency Snapshot
|
|
110
|
+
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
|
|
111
|
+
run: |
|
|
112
|
+
uv pip list
|
|
113
|
+
uv tree
|
|
114
|
+
|
|
115
|
+
- name: Build Package
|
|
116
|
+
run: |
|
|
117
|
+
set -o pipefail
|
|
118
|
+
uv build 2>&1 | tee "${BUILD_LOG}"
|
|
119
|
+
|
|
120
|
+
- name: Show built distributions
|
|
121
|
+
run: |
|
|
122
|
+
ls -la dist
|
|
123
|
+
sha256sum dist/* || true
|
|
124
|
+
|
|
125
|
+
- name: Upload build artifacts
|
|
126
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
|
127
|
+
with:
|
|
128
|
+
name: artifact
|
|
129
|
+
path: dist/
|
|
130
|
+
|
|
131
|
+
- name: Upload build logs
|
|
132
|
+
if: ${{ always() }}
|
|
133
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
|
134
|
+
with:
|
|
135
|
+
name: publish-build-logs
|
|
136
|
+
path: ${{ env.BUILD_LOG }}
|
|
137
|
+
if-no-files-found: warn
|
|
138
|
+
retention-days: 14
|
|
139
|
+
|
|
140
|
+
- name: pypi-publish
|
|
141
|
+
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e
|
|
142
|
+
|
|
143
|
+
- name: Publish GitHub Release
|
|
144
|
+
env:
|
|
145
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
146
|
+
RELEASE_TAG: ${{ steps.release_tag.outputs.tag }}
|
|
147
|
+
run: |
|
|
148
|
+
gh release create "${RELEASE_TAG}" \
|
|
149
|
+
dist/*.whl \
|
|
150
|
+
dist/*.tar.gz \
|
|
151
|
+
--title "${RELEASE_TAG}" \
|
|
152
|
+
--generate-notes
|
|
153
|
+
|
|
154
|
+
docs-deploy:
|
|
155
|
+
name: Deploy versioned docs
|
|
156
|
+
needs: pypi-publish
|
|
157
|
+
runs-on: ubuntu-latest
|
|
158
|
+
timeout-minutes: 20
|
|
159
|
+
permissions:
|
|
160
|
+
contents: write
|
|
161
|
+
env:
|
|
162
|
+
DOCS_LOG: docs-build.log
|
|
163
|
+
RELEASE_TAG: ${{ needs.pypi-publish.outputs.release_tag }}
|
|
164
|
+
steps:
|
|
165
|
+
- name: Checkout release tag
|
|
166
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
167
|
+
with:
|
|
168
|
+
ref: refs/tags/${{ needs.pypi-publish.outputs.release_tag }}
|
|
169
|
+
fetch-depth: 0
|
|
170
|
+
persist-credentials: false
|
|
171
|
+
|
|
172
|
+
- name: Set up uv
|
|
173
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78
|
|
174
|
+
with:
|
|
175
|
+
python-version: "3.12"
|
|
176
|
+
enable-cache: false
|
|
177
|
+
|
|
178
|
+
- name: Sync docs deps
|
|
179
|
+
run: uv sync --locked --group docs
|
|
180
|
+
|
|
181
|
+
- name: Verify docs version
|
|
182
|
+
id: version
|
|
183
|
+
shell: bash
|
|
184
|
+
run: |
|
|
185
|
+
VERSION=$(uv version --short)
|
|
186
|
+
EXPECTED_TAG="v${VERSION}"
|
|
187
|
+
if [[ "${RELEASE_TAG}" != "${EXPECTED_TAG}" ]]; then
|
|
188
|
+
echo "::error::Release tag ${RELEASE_TAG} does not match docs version ${VERSION}."
|
|
189
|
+
exit 1
|
|
190
|
+
fi
|
|
191
|
+
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
|
|
192
|
+
|
|
193
|
+
- name: Build docs
|
|
194
|
+
run: |
|
|
195
|
+
set -o pipefail
|
|
196
|
+
uv run zensical build --strict 2>&1 | tee "${DOCS_LOG}"
|
|
197
|
+
|
|
198
|
+
- name: Upload docs build logs
|
|
199
|
+
if: ${{ always() }}
|
|
200
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
|
201
|
+
with:
|
|
202
|
+
name: release-docs-build-logs
|
|
203
|
+
path: ${{ env.DOCS_LOG }}
|
|
204
|
+
if-no-files-found: warn
|
|
205
|
+
retention-days: 14
|
|
206
|
+
|
|
207
|
+
- name: Configure git
|
|
208
|
+
run: |
|
|
209
|
+
git config user.name "github-actions[bot]"
|
|
210
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
211
|
+
|
|
212
|
+
- name: Configure authenticated origin
|
|
213
|
+
env:
|
|
214
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
215
|
+
run: |
|
|
216
|
+
git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
|
|
217
|
+
|
|
218
|
+
- name: Deploy versioned docs
|
|
219
|
+
env:
|
|
220
|
+
VERSION: ${{ steps.version.outputs.version }}
|
|
221
|
+
run: |
|
|
222
|
+
uv run mike deploy --push --update-aliases "${VERSION}" latest
|
|
223
|
+
uv run mike set-default --push latest
|
|
224
|
+
|
|
225
|
+
- name: Show docs URL
|
|
226
|
+
env:
|
|
227
|
+
DOCS_OWNER: ${{ github.repository_owner }}
|
|
228
|
+
DOCS_REPO: ${{ github.event.repository.name }}
|
|
229
|
+
VERSION: ${{ steps.version.outputs.version }}
|
|
230
|
+
run: |
|
|
231
|
+
echo "Docs deployed: https://${DOCS_OWNER}.github.io/${DOCS_REPO}/${VERSION}/"
|
|
@@ -46,14 +46,11 @@ If docs were changed:
|
|
|
46
46
|
make docs-build
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
## PR
|
|
49
|
+
## PR Documentation Preview
|
|
50
50
|
|
|
51
|
-
When opening a PR from a branch in this repository (not a fork),
|
|
51
|
+
When opening a PR from a branch in this repository (not a fork), documentation changes under `docs/**`, `mkdocs.yml`, or `README.md` are deployed automatically. A sticky comment shows the preview URL under `pr-preview/pr-<NUMBER>/` of the Pages site. The preview is removed automatically when the PR is closed.
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
- **Docs preview** (only when `docs/**`, `mkdocs.yml`, or `README.md` change): a sticky comment on the PR shows the preview URL under `pr-preview/pr-<NUMBER>/` of the Pages site. The preview is removed automatically when the PR is closed.
|
|
55
|
-
|
|
56
|
-
PRs from forks skip both because the workflow tokens cannot write to gh-pages or use TestPyPI trusted publishing.
|
|
53
|
+
PRs from forks skip the deployment because the workflow token cannot write to `gh-pages`. TestPyPI publishing is currently suspended for all PRs.
|
|
57
54
|
|
|
58
55
|
## Commit Message Format
|
|
59
56
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nonebot-plugin-htmlrender
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: 通过浏览器渲染图片
|
|
5
5
|
Project-URL: Homepage, https://github.com/kexue-z/nonebot-plugin-htmlrender
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/kexue-z/nonebot-plugin-htmlrender/issues
|
|
@@ -18,11 +18,11 @@ tags:
|
|
|
18
18
|
| ------------------ | --------------------------------------- | ------------------------------------------------------------------------ | ---------------------------------------- |
|
|
19
19
|
| CI | `.github/workflows/ci.yml` | lint、类型检查、打包校验、远程浏览器 smoke | push master、pull request、手动触发 |
|
|
20
20
|
| Coverage | `.github/workflows/coverage.yml` | Python 版本 + CPU 架构覆盖率矩阵 | push master、pull request、手动触发 |
|
|
21
|
-
| Docs | `.github/workflows/docs.yml` | master
|
|
21
|
+
| Docs | `.github/workflows/docs.yml` | master 推送时严格构建文档 | push master(文档路径)、手动触发 |
|
|
22
22
|
| Docs PR Preview | `.github/workflows/docs-pr-preview.yml` | PR 文档预览部署与关闭清理 | pull request open/sync/close(文档路径) |
|
|
23
|
-
| Publish (TestPyPI) | `.github/workflows/publish-test.yml`
|
|
23
|
+
| Publish (TestPyPI) | `.github/workflows-disabled/publish-test.yml` | 保留 TestPyPI 发布实现,当前挂起 | 无 |
|
|
24
24
|
| Auto Tag | `.github/workflows/auto-tag.yml` | PR 合并到 master 后读取 `pyproject.toml` 版本号自动打 tag 并触发 Publish | pull request closed on master |
|
|
25
|
-
| Publish | `.github/workflows/publish.yml` | 构建分发包、PyPI
|
|
25
|
+
| Publish | `.github/workflows/publish.yml` | 构建分发包、PyPI、GitHub Release,并在成功后部署版本化文档 | tag push、手动触发 |
|
|
26
26
|
|
|
27
27
|
## CI
|
|
28
28
|
|
|
@@ -63,15 +63,13 @@ pytest-py<python-version>-<arch>.log
|
|
|
63
63
|
- `README.md`
|
|
64
64
|
- `.github/workflows/docs.yml`
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
它只执行严格文档构建:
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
69
|
uv run zensical build --strict
|
|
70
|
-
uv run mike deploy --push --update-aliases <version> latest
|
|
71
|
-
uv run mike set-default --push latest
|
|
72
70
|
```
|
|
73
71
|
|
|
74
|
-
|
|
72
|
+
版本化部署由 Publish workflow 在正式发布成功后执行,避免未发布版本提前成为 `latest`。多版本管理细节见 [文档版本管理](versioning.md)。
|
|
75
73
|
|
|
76
74
|
非 master 分支或 PR 上的文档预览由 `Docs PR Preview` 负责,不再走分支名预览。
|
|
77
75
|
|
|
@@ -93,12 +91,9 @@ https://<owner>.github.io/<repo>/pr-preview/pr-<NUMBER>/
|
|
|
93
91
|
|
|
94
92
|
## Publish (TestPyPI)
|
|
95
93
|
|
|
96
|
-
|
|
94
|
+
TestPyPI 发布当前挂起。完整 workflow 保留在 `.github/workflows-disabled/publish-test.yml`,不位于 GitHub Actions 注册目录,因此没有 PR 或手动触发入口。
|
|
97
95
|
|
|
98
|
-
|
|
99
|
-
- fork PR 跳过:trusted publishing 需要 `id-token: write`,fork 不可用;
|
|
100
|
-
- 版本注入:以 `pyproject.toml` 中的当前版本为 base,附加 UTC 时间戳后缀,例如 `0.7.0.dev20260509120000`,保证 TestPyPI 单调递增不撞包;
|
|
101
|
-
- 发布完成后用 `marocchino/sticky-pull-request-comment` 在 PR 上贴一条固定评论,给出装包命令。
|
|
96
|
+
保留实现仍会以 `pyproject.toml` 的当前版本为 base,附加 UTC 时间戳 dev 后缀,构建 wheel 与 sdist,并通过 trusted publishing 上传 TestPyPI。恢复时需将文件移回 `.github/workflows/`,再明确配置所需触发器;不能只修改文档或 environment。
|
|
102
97
|
|
|
103
98
|
```bash
|
|
104
99
|
pip install -i https://test.pypi.org/simple/ \
|
|
@@ -106,7 +101,7 @@ pip install -i https://test.pypi.org/simple/ \
|
|
|
106
101
|
nonebot-plugin-htmlrender==<dev-version>
|
|
107
102
|
```
|
|
108
103
|
|
|
109
|
-
`environment: testpypi` 与 `https://test.pypi.org/legacy/` 仓库 URL
|
|
104
|
+
`environment: testpypi` 与 `https://test.pypi.org/legacy/` 仓库 URL 仍保留在挂起的 workflow 中。
|
|
110
105
|
|
|
111
106
|
## Auto Tag
|
|
112
107
|
|
|
@@ -126,11 +121,13 @@ pip install -i https://test.pypi.org/simple/ \
|
|
|
126
121
|
|
|
127
122
|
`Publish` workflow 负责正式发布产物:
|
|
128
123
|
|
|
129
|
-
1.
|
|
124
|
+
1. 解析并检出待发布 tag;
|
|
125
|
+
1. 校验 tag 指向 `master` 历史、tag 名与包版本完全一致;
|
|
130
126
|
1. 使用 `uv build` 构建 wheel 与 sdist;
|
|
131
127
|
1. 上传构建产物和构建日志 artifact;
|
|
132
128
|
1. 通过 PyPI trusted publishing 发布;
|
|
133
129
|
1. 根据 tag 或 `release_tag` 输入创建 GitHub Release。
|
|
130
|
+
1. GitHub Release 创建成功后严格构建 tag 对应文档,通过 `mike` 部署该版本并更新 `latest`。
|
|
134
131
|
|
|
135
132
|
触发方式:
|
|
136
133
|
|
|
@@ -138,6 +135,8 @@ pip install -i https://test.pypi.org/simple/ \
|
|
|
138
135
|
- 也可以维护者手动 push 一个 tag 到 master 上的 commit;
|
|
139
136
|
- 也可以手动 `workflow_dispatch` 并提供 `release_tag` 输入。
|
|
140
137
|
|
|
138
|
+
无论通过哪种方式触发,Publish 都从 tag 检出源码,不会用 dispatch 所在分支的工作树替代发布内容。Mike 部署是发布的后置 job;PyPI 或 GitHub Release 失败时不会运行。
|
|
139
|
+
|
|
141
140
|
## 本地对应命令
|
|
142
141
|
|
|
143
142
|
| CI 项 | 本地命令 |
|
|
@@ -169,5 +168,6 @@ pip install -i https://test.pypi.org/simple/ \
|
|
|
169
168
|
- 对文档构建失败,下载 `docs-build-logs`;
|
|
170
169
|
- 对打包失败,下载 `package-dist` 与 `package-build-logs`;
|
|
171
170
|
- 对正式发布失败,下载 `publish-build-logs`;
|
|
172
|
-
-
|
|
171
|
+
- 对正式发布后的文档部署失败,下载 `release-docs-build-logs`;
|
|
172
|
+
- TestPyPI workflow 恢复后若发布失败,下载 `publish-test-build-logs` 与 `artifact-testpypi`;
|
|
173
173
|
- 对 Auto Tag 失败(tag 推送或 publish dispatch 失败),查看 job 日志中的 `gh` 命令输出。
|
|
@@ -15,7 +15,8 @@ tags:
|
|
|
15
15
|
|
|
16
16
|
## 工作原理
|
|
17
17
|
|
|
18
|
-
- 推送到 `master` 分支且涉及文档相关路径时,Docs workflow
|
|
18
|
+
- 推送到 `master` 分支且涉及文档相关路径时,Docs workflow 只执行严格构建,阻止无效文档进入主分支
|
|
19
|
+
- Publish workflow 完成 PyPI 发布和 GitHub Release 后,才读取 tag 对应版本并通过 `mike deploy` 发布到 `gh-pages` 分支
|
|
19
20
|
- 版本以子目录形式存在,例如 `docs.example.com/0.7.0/`、`docs.example.com/0.8.0/`
|
|
20
21
|
- `latest` 别名始终指向最新版本,根路径自动重定向到 `latest`
|
|
21
22
|
- 旧版本页面顶部会显示过期提醒横幅
|
|
@@ -26,9 +27,10 @@ PR 阶段的文档预览由独立的 `Docs PR Preview` workflow 部署到 `gh-pa
|
|
|
26
27
|
|
|
27
28
|
发版时不需要手动打 tag。维护者只需在 PR 中改好 `pyproject.toml` 的 `project.version` 后合并到 `master`:
|
|
28
29
|
|
|
29
|
-
1. 合并到 `master`
|
|
30
|
-
2.
|
|
31
|
-
3. `
|
|
30
|
+
1. 合并到 `master` 后,`Auto Tag` workflow 读取版本号并创建 `v<version>` tag;
|
|
31
|
+
2. `Auto Tag` 通过 `gh workflow run` 调起 `Publish`;
|
|
32
|
+
3. `Publish` 检出 tag,校验 tag、包版本和 `master` 祖先关系,再完成 PyPI 发布与 GitHub Release;
|
|
33
|
+
4. 只有前述发布成功后,Publish 的文档 job 才通过 `mike` 部署版本化文档并更新 `latest`。
|
|
32
34
|
|
|
33
35
|
完整 workflow 触发条件与排障入口见 [CI Actions](ci-actions.md)。
|
|
34
36
|
|
|
@@ -37,7 +39,7 @@ mike deploy --push --update-aliases <version> latest
|
|
|
37
39
|
mike set-default --push latest
|
|
38
40
|
```
|
|
39
41
|
|
|
40
|
-
版本号从 `pyproject.toml`
|
|
42
|
+
版本号从 tag 对应提交的 `pyproject.toml` 中读取,且必须与 `v<version>` tag 完全一致。
|
|
41
43
|
|
|
42
44
|
## 本地操作
|
|
43
45
|
|
|
@@ -86,6 +86,13 @@ async def render_markdown(
|
|
|
86
86
|
|
|
87
87
|
**返回值:** `bytes` — 图片二进制数据
|
|
88
88
|
|
|
89
|
+
!!! warning "Markdown 中的原始 HTML 会进入页面"
|
|
90
|
+
|
|
91
|
+
`render_markdown` 会保留 Markdown 中的原始 HTML,并将转换结果作为 HTML
|
|
92
|
+
片段插入页面;它不是 HTML 消毒器。若内容来自不可信用户或模型输出,调用方
|
|
93
|
+
应先按业务需要做标签、属性和 URL 白名单清洗,或在不需要富文本时改用
|
|
94
|
+
`render_text`。详见[安全须知](security.md)。
|
|
95
|
+
|
|
89
96
|
---
|
|
90
97
|
|
|
91
98
|
### `render_html`
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: v0.7.2 迁移说明
|
|
3
|
+
description: 从 v0.7.1 升级到 v0.7.2 时需要了解的远程 Markdown 修复
|
|
4
|
+
icon: lucide/bug-off
|
|
5
|
+
tags:
|
|
6
|
+
- Users
|
|
7
|
+
- Migration
|
|
8
|
+
- Release
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# v0.7.2 迁移说明
|
|
12
|
+
|
|
13
|
+
v0.7.2 是面向远程 Playwright 部署的兼容性修复版本,不包含公共 API 或配置项变更。
|
|
14
|
+
|
|
15
|
+
## 修复内容
|
|
16
|
+
|
|
17
|
+
使用远程 Playwright 渲染 Markdown 时,默认模板此前会让远端浏览器导航到 Bot
|
|
18
|
+
进程所在主机的 `file://` 地址。浏览器与 Bot 不共享文件系统时,该地址不可达,
|
|
19
|
+
渲染会以 `ERR_FILE_NOT_FOUND` 失败。
|
|
20
|
+
|
|
21
|
+
v0.7.2 在远程模式下直接通过 `page.set_content()` 注入默认 Markdown HTML,
|
|
22
|
+
不再导航到本地模板文件。自定义的 HTTP(S) 基址和显式传入的渲染配置保持原有行为。
|
|
23
|
+
|
|
24
|
+
## 是否需要修改配置
|
|
25
|
+
|
|
26
|
+
通常不需要。符合以下条件的部署可直接升级:
|
|
27
|
+
|
|
28
|
+
- 使用 Playwright WS 或 CDP 连接远端浏览器;
|
|
29
|
+
- 调用 `render_markdown` 或兼容入口 `md_to_pic`;
|
|
30
|
+
- 使用内置 Markdown 模板和样式。
|
|
31
|
+
|
|
32
|
+
若 Markdown 引用了本地图片、字体或其他静态资源,仍需确保远端浏览器能够访问这些
|
|
33
|
+
资源;本次修复只消除了默认模板文件本身的跨主机 `file://` 导航。
|
|
34
|
+
|
|
35
|
+
## 升级后验证
|
|
36
|
+
|
|
37
|
+
在实际远程浏览器环境执行一次最小渲染即可:
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from nonebot_plugin_htmlrender import render_markdown
|
|
41
|
+
|
|
42
|
+
image = await render_markdown("# remote markdown")
|
|
43
|
+
assert image
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
本地 Playwright、HTML 渲染和模板渲染行为不受影响。
|
|
@@ -10,6 +10,10 @@ tags:
|
|
|
10
10
|
|
|
11
11
|
# 旧版本迁移指南
|
|
12
12
|
|
|
13
|
+
!!! info "v0.7.2 补丁版本"
|
|
14
|
+
从 v0.7.1 升级时,请先阅读 [v0.7.2 迁移说明](migration-v072.md)。
|
|
15
|
+
该版本仅修复远程 Playwright 的 Markdown 模板导航,不改变公共 API 或配置。
|
|
16
|
+
|
|
13
17
|
新版本将渲染逻辑与底层驱动解耦,引入分层架构(Render / Backend / Runtime / Session / Context)。
|
|
14
18
|
旧 API 仍保留为兼容层,但调用时会触发弃用警告,且不再承载新能力。
|
|
15
19
|
新项目请直接使用新 API;存量项目按本页对照表逐步迁移即可。
|
|
@@ -19,6 +19,7 @@ tags:
|
|
|
19
19
|
| 入口 | 威胁 | 默认行为 | 责任方 |
|
|
20
20
|
| --- | --- | --- | --- |
|
|
21
21
|
| `render_html(...)` | 攻击者构造 HTML/JS 在浏览器进程执行 | 直接装载到 Page | 调用方 |
|
|
22
|
+
| `render_markdown(...)` | Markdown 携带原始 HTML、脚本或外链资源 | 转换后作为 HTML 片段装载到 Page,不做消毒 | 调用方 |
|
|
22
23
|
| `render_template(..., templates=...)` | 模板变量未转义被插入 HTML | Jinja2 `select_autoescape()` 仅对 `.html/.xml` 自动转义 | 调用方 |
|
|
23
24
|
| `capture_html_element(url, ...)` | 任意 URL 被远端浏览器请求 | 直接 `goto(url)` | 调用方 |
|
|
24
25
|
| filehost `/filehost/*` | 浏览器/外部请求读取本地文件 | 路径白名单 + 请求头守卫 | 配置方 |
|
|
@@ -35,9 +36,22 @@ tags:
|
|
|
35
36
|
- 模板内的外链可能拉取攻击者控制的资源;
|
|
36
37
|
- 浏览器进程可对内网发起请求(参考下文 SSRF)。
|
|
37
38
|
|
|
39
|
+
### Markdown 原始 HTML
|
|
40
|
+
|
|
41
|
+
`render_markdown` 使用 Python-Markdown 生成 HTML。为了让段落、标题、引用块和
|
|
42
|
+
KaTeX 等转换结果形成真实 DOM,生成的 HTML 片段不会再经过 Jinja2 转义。
|
|
43
|
+
Python-Markdown 会保留输入中的原始 HTML,因此 `render_markdown` **不提供 HTML
|
|
44
|
+
消毒或安全边界**:输入中的 `<script>`、事件处理属性和带外链的元素可能进入页面,
|
|
45
|
+
脚本执行与网络访问风险和 `render_html` 相同。
|
|
46
|
+
|
|
47
|
+
模型输出也应视为不可信内容。用户可以通过提示词诱导模型输出原始 HTML、脚本或
|
|
48
|
+
指向内网的资源 URL;“内容由模型生成”不能替代输入校验。
|
|
49
|
+
|
|
38
50
|
建议:
|
|
39
51
|
|
|
40
|
-
-
|
|
52
|
+
- 不需要富文本时使用 `render_text`,其文本插槽保持 HTML 转义;
|
|
53
|
+
- 需要 Markdown 时,在调用 `render_markdown` 前按业务需求对原始 HTML 的标签、属性和 URL 做白名单清洗;
|
|
54
|
+
- 不可信数据需要进入自定义布局时,使用 `render_template` 的模板变量,不要拼接模板或 HTML 字符串;
|
|
41
55
|
- 不要拼字符串。`render_template` 默认 `select_autoescape()` 对 `.html/.xml` 后缀模板启用 HTML 转义,模板变量中的 `<` / `>` / `&` 会被转义;
|
|
42
56
|
- 自定义模板后缀(如 `.j2`)时显式开 `autoescape=True`,否则等于零防护;
|
|
43
57
|
- 需要原始 HTML 的字段,明确定义白名单标签集合后再交给模板,不要走 `|safe`。
|
|
@@ -53,7 +67,8 @@ env = jinja2.Environment(
|
|
|
53
67
|
|
|
54
68
|
## SSRF 与外部请求
|
|
55
69
|
|
|
56
|
-
`render_html` / `render_template` / `capture_html_element`
|
|
70
|
+
`render_html` / `render_markdown` / `render_template` / `capture_html_element`
|
|
71
|
+
触发的浏览器内网请求不受 NoneBot HTTP 客户端的限制。
|
|
57
72
|
攻击者可以让你的浏览器请求:
|
|
58
73
|
|
|
59
74
|
- 内网管理界面(`http://10.0.0.1/admin`);
|
|
@@ -172,6 +187,7 @@ await render_template_html(template=user_supplied_template_string)
|
|
|
172
187
|
部署前快速复核:
|
|
173
188
|
|
|
174
189
|
- [ ] 渲染入口已与不可信用户输入解耦(用模板变量而非字符串拼接);
|
|
190
|
+
- [ ] 传给 `render_markdown` 的不可信内容已经过 HTML 标签、属性和 URL 白名单清洗;
|
|
175
191
|
- [ ] 自定义模板后缀时显式开 `autoescape=True`;
|
|
176
192
|
- [ ] 不要使用 `filehost_allow_any_path=true`,除非环境严格隔离;
|
|
177
193
|
- [ ] `filehost_allowed_paths` 显式列出可暴露目录,且不包含 `~`、`/etc`、`/var`、`/srv` 整目录;
|
|
@@ -110,6 +110,11 @@ def _enum_value(raw: object) -> str:
|
|
|
110
110
|
return str(getattr(raw, "value", raw))
|
|
111
111
|
|
|
112
112
|
|
|
113
|
+
def _should_navigate_to_base_url(base_url: str) -> bool:
|
|
114
|
+
"""判断浏览器是否应先导航到页面的 base URL。"""
|
|
115
|
+
return base_url != "about:blank"
|
|
116
|
+
|
|
117
|
+
|
|
113
118
|
async def read_file(path: str) -> str:
|
|
114
119
|
"""异步读取文件内容。"""
|
|
115
120
|
f = await anyio.open_file(path, mode="r", encoding="utf-8")
|
|
@@ -264,7 +269,8 @@ async def render_html(
|
|
|
264
269
|
),
|
|
265
270
|
) as page,
|
|
266
271
|
):
|
|
267
|
-
|
|
272
|
+
remote_mode = is_remote_playwright_mode()
|
|
273
|
+
if remote_mode and (
|
|
268
274
|
_enum_value(get_playwright_config().remote_local_resource_policy)
|
|
269
275
|
== RemoteLocalResourcePolicy.FILEHOST.value
|
|
270
276
|
):
|
|
@@ -274,7 +280,9 @@ async def render_html(
|
|
|
274
280
|
)
|
|
275
281
|
|
|
276
282
|
_setup_page_logging(page)
|
|
277
|
-
|
|
283
|
+
base_url = render_request.render.page.base_url
|
|
284
|
+
if _should_navigate_to_base_url(base_url):
|
|
285
|
+
await page.goto(base_url)
|
|
278
286
|
await page.set_content(
|
|
279
287
|
render_request.content.html,
|
|
280
288
|
wait_until=render_request.content.wait_until,
|
|
@@ -444,17 +452,16 @@ async def render_markdown(
|
|
|
444
452
|
)
|
|
445
453
|
css = github_css + pygments_css
|
|
446
454
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
)
|
|
451
|
-
|
|
452
|
-
|
|
455
|
+
if render is None:
|
|
456
|
+
base_url = (
|
|
457
|
+
_path_to_uri(css_path) if css_path else MARKDOWN_TEMPLATE_FILE.as_uri()
|
|
458
|
+
)
|
|
459
|
+
if is_remote_playwright_mode():
|
|
460
|
+
base_url = "about:blank"
|
|
461
|
+
render = RenderConfig(
|
|
453
462
|
page=PageConfig(
|
|
454
463
|
viewport=ViewportConfig(width=width, height=10),
|
|
455
|
-
base_url=
|
|
456
|
-
if css_path
|
|
457
|
-
else MARKDOWN_TEMPLATE_FILE.as_uri(),
|
|
464
|
+
base_url=base_url,
|
|
458
465
|
),
|
|
459
466
|
screenshot=_build_screenshot_config(
|
|
460
467
|
image_type,
|
|
@@ -464,7 +471,13 @@ async def render_markdown(
|
|
|
464
471
|
full_page=True,
|
|
465
472
|
wait_before_screenshot=0,
|
|
466
473
|
),
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
render_request = HtmlRenderRequest(
|
|
477
|
+
content=ContentConfig(
|
|
478
|
+
html=await template.render_async(md=md, css=css, extra=extra)
|
|
467
479
|
),
|
|
480
|
+
render=render,
|
|
468
481
|
)
|
|
469
482
|
|
|
470
483
|
return await render_html(render_request, session=session)
|