|
82 | 82 | required: false |
83 | 83 | type: string |
84 | 84 | plugin_mode: |
85 | | - description: "none is the safe default. auto is a compatibility alias for none; legacy custom mounts are disabled until P1/P2-bound plugin artifacts exist." |
| 85 | + description: "none disables mounts. current preserves the selected strategy's existing mounts exactly; it cannot add or change a plugin." |
86 | 86 | required: true |
87 | 87 | type: choice |
88 | 88 | default: none |
89 | 89 | options: |
90 | 90 | - none |
| 91 | + - current |
91 | 92 | extra_variables_json: |
92 | 93 | description: "Optional JSON object of non-secret extra variables. DCA profiles may include dca_mode and dca_base_investment_usd control fields. cash_only_execution_mode may be current, enabled, or disabled. Research-only option overlays are rejected." |
93 | 94 | required: false |
@@ -336,7 +337,53 @@ jobs: |
336 | 337 | if [ -f "${EXISTING_SERVICE_TARGETS_JSON_FILE:-}" ]; then |
337 | 338 | echo "existing CLOUD_RUN_SERVICE_TARGETS_JSON requires service_targets_mode=patch or allow_create" >&2 |
338 | 339 | exit 2 |
| 340 | + fi |
| 341 | +
|
| 342 | + - name: Fetch current plugin mounts for continuity |
| 343 | + if: env.PLUGIN_MODE == 'current' |
| 344 | + env: |
| 345 | + TARGET_REPOSITORY: ${{ steps.platform.outputs.repository }} |
| 346 | + run: | |
| 347 | + set -euo pipefail |
| 348 | + case "${PLATFORM}" in |
| 349 | + longbridge) mounts_variable="LONGBRIDGE_STRATEGY_PLUGIN_MOUNTS_JSON" ;; |
| 350 | + ibkr) mounts_variable="IBKR_STRATEGY_PLUGIN_MOUNTS_JSON" ;; |
| 351 | + schwab) mounts_variable="SCHWAB_STRATEGY_PLUGIN_MOUNTS_JSON" ;; |
| 352 | + firstrade) mounts_variable="FIRSTRADE_STRATEGY_PLUGIN_MOUNTS_JSON" ;; |
| 353 | + qmt) mounts_variable="QMT_STRATEGY_PLUGIN_MOUNTS_JSON" ;; |
| 354 | + binance) mounts_variable="BINANCE_STRATEGY_PLUGIN_MOUNTS_JSON" ;; |
| 355 | + *) echo "Unsupported platform: ${PLATFORM}" >&2; exit 2 ;; |
| 356 | + esac |
| 357 | + target_environment="" |
| 358 | + if [ "${VARIABLE_SCOPE}" = "environment" ]; then |
| 359 | + target_environment="${GITHUB_ENVIRONMENT_NAME:-${TARGET_NAME}}" |
| 360 | + elif [ "${VARIABLE_SCOPE}" = "default" ] && [ "${PLATFORM}" = "longbridge" ]; then |
| 361 | + target_environment="longbridge-${TARGET_NAME}" |
339 | 362 | fi |
| 363 | + output_file="${RUNNER_TEMP}/current-plugin-mounts.json" |
| 364 | + python - <<'PY' "${TARGET_REPOSITORY}" "${mounts_variable}" "${target_environment}" "${output_file}" |
| 365 | + import json |
| 366 | + import subprocess |
| 367 | + import sys |
| 368 | +
|
| 369 | + repo, variable, environment, output_path = sys.argv[1:5] |
| 370 | + command = ["gh", "variable", "list", "--repo", repo, "--json", "name,value"] |
| 371 | + if environment: |
| 372 | + command.extend(["--env", environment]) |
| 373 | + values = json.loads(subprocess.check_output(command, text=True)) |
| 374 | + raw = next((item.get("value") for item in values if item.get("name") == variable), None) |
| 375 | + if not isinstance(raw, str) or not raw.strip(): |
| 376 | + raise SystemExit(f"{variable} is required when plugin_mode=current") |
| 377 | + try: |
| 378 | + payload = json.loads(raw) |
| 379 | + except json.JSONDecodeError as exc: |
| 380 | + raise SystemExit(f"{variable} must contain valid JSON") from exc |
| 381 | + if not isinstance(payload, dict) or not isinstance(payload.get("strategy_plugins"), list): |
| 382 | + raise SystemExit(f"{variable} must contain a strategy_plugins array") |
| 383 | + with open(output_path, "w", encoding="utf-8") as handle: |
| 384 | + json.dump(payload, handle, ensure_ascii=False, separators=(",", ":")) |
| 385 | + PY |
| 386 | + echo "CURRENT_PLUGIN_MOUNTS_JSON_FILE=${output_file}" >> "$GITHUB_ENV" |
340 | 387 |
|
341 | 388 | - name: Build switch target |
342 | 389 | run: | |
@@ -369,6 +416,9 @@ jobs: |
369 | 416 | if [ -n "${SERVICE_NAME:-}" ]; then |
370 | 417 | args+=(--service-name "${SERVICE_NAME}") |
371 | 418 | fi |
| 419 | + if [ "${PLUGIN_MODE}" = "current" ]; then |
| 420 | + args+=(--current-plugin-mounts-json-file "${CURRENT_PLUGIN_MOUNTS_JSON_FILE}") |
| 421 | + fi |
372 | 422 | if [ "${LIVE_CONTINUITY_STATE}" != "NONE" ]; then |
373 | 423 | args+=(--live-continuity-state "${LIVE_CONTINUITY_STATE}") |
374 | 424 | args+=(--live-continuity-baseline-id "${LIVE_CONTINUITY_BASELINE_ID}") |
|
0 commit comments