feature: add plugin smoke validation workflow #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Validate Plugin Smoke | |
| on: | |
| pull_request: | |
| paths: | |
| - "plugins.json" | |
| - "scripts/validate_plugins/**" | |
| - ".github/workflows/validate-plugin-smoke.yml" | |
| workflow_dispatch: | |
| inputs: | |
| plugin_names: | |
| description: "Comma-separated plugin keys from plugins.json" | |
| required: false | |
| default: "" | |
| plugin_limit: | |
| description: "Validate the first N plugins when plugin_names is empty. Leave blank or use -1 for all plugins" | |
| required: false | |
| default: "" | |
| astrbot_ref: | |
| description: "AstrBot git ref to validate against" | |
| required: false | |
| default: "master" | |
| jobs: | |
| validate-plugin-smoke: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set manual validation inputs | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| echo "ASTRBOT_REF=${{ inputs.astrbot_ref }}" >> "$GITHUB_ENV" | |
| echo "PLUGIN_NAME_LIST=${{ inputs.plugin_names }}" >> "$GITHUB_ENV" | |
| echo "PLUGIN_LIMIT=${{ inputs.plugin_limit }}" >> "$GITHUB_ENV" | |
| echo "SHOULD_VALIDATE=true" >> "$GITHUB_ENV" | |
| - name: Detect changed plugins from pull request | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| python - <<'PY' | |
| import json | |
| import os | |
| import subprocess | |
| from pathlib import Path | |
| base_ref = os.environ["GITHUB_BASE_REF"] | |
| subprocess.run(["git", "fetch", "origin", base_ref, "--depth", "1"], check=True) | |
| validation_note = "" | |
| try: | |
| base_raw = subprocess.check_output( | |
| ["git", "show", f"origin/{base_ref}:plugins.json"], | |
| text=True, | |
| stderr=subprocess.DEVNULL, | |
| ) | |
| base = json.loads(base_raw) | |
| if not isinstance(base, dict): | |
| base = {} | |
| except (subprocess.CalledProcessError, json.JSONDecodeError): | |
| base = {} | |
| try: | |
| head = json.loads(Path("plugins.json").read_text(encoding="utf-8")) | |
| if not isinstance(head, dict): | |
| raise ValueError("plugins.json must contain a JSON object") | |
| except (json.JSONDecodeError, ValueError) as exc: | |
| changed = [] | |
| should_validate = False | |
| validation_note = f"Skipping smoke validation because plugins.json is invalid on the PR head: {exc}" | |
| else: | |
| changed = [ | |
| name | |
| for name, payload in head.items() | |
| if base.get(name) != payload | |
| ] | |
| should_validate = bool(changed) | |
| if not should_validate: | |
| validation_note = "No plugin entries changed in plugins.json; skipping smoke validation." | |
| with open(os.environ["GITHUB_ENV"], "a", encoding="utf-8") as handle: | |
| handle.write("ASTRBOT_REF=master\n") | |
| handle.write(f"PLUGIN_NAME_LIST={','.join(changed)}\n") | |
| handle.write("PLUGIN_LIMIT=\n") | |
| handle.write(f"SHOULD_VALIDATE={'true' if should_validate else 'false'}\n") | |
| handle.write(f"VALIDATION_NOTE={validation_note}\n") | |
| PY | |
| - name: Show PR diff selection | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| if [ "$SHOULD_VALIDATE" != "true" ]; then | |
| printf '%s\n' "${VALIDATION_NOTE:-Smoke validation skipped.}" | |
| else | |
| printf 'Selected plugins: %s\n' "$PLUGIN_NAME_LIST" | |
| fi | |
| - name: Set up Python | |
| if: env.SHOULD_VALIDATE == 'true' | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install validator dependencies | |
| if: env.SHOULD_VALIDATE == 'true' | |
| run: python -m pip install --upgrade pip pyyaml | |
| - name: Clone AstrBot | |
| if: env.SHOULD_VALIDATE == 'true' | |
| run: git clone --depth 1 --branch "$ASTRBOT_REF" "https://github.com/AstrBotDevs/AstrBot" ".cache/AstrBot" | |
| - name: Install AstrBot dependencies | |
| if: env.SHOULD_VALIDATE == 'true' | |
| run: python -m pip install -r ".cache/AstrBot/requirements.txt" | |
| - name: Run plugin smoke validator | |
| if: env.SHOULD_VALIDATE == 'true' | |
| run: | | |
| args=( | |
| --astrbot-path ".cache/AstrBot" | |
| --report-path "validation-report.json" | |
| ) | |
| if [ -n "${PLUGIN_NAME_LIST:-}" ]; then | |
| args+=(--plugin-name-list "$PLUGIN_NAME_LIST") | |
| fi | |
| if [ -n "${PLUGIN_LIMIT:-}" ]; then | |
| args+=(--limit "$PLUGIN_LIMIT") | |
| fi | |
| python scripts/validate_plugins/run.py "${args[@]}" | |
| - name: Upload validation report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: validation-report | |
| path: validation-report.json | |
| if-no-files-found: warn |