mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-23 02:45:38 -06:00
fix(ci): trust frozen plugin prerelease fixtures (#124446)
* fix(ci): trust frozen plugin prerelease fixtures * fix(ci): apply scoped plugin test omissions
This commit is contained in:
committed by
GitHub
parent
7d05f7c5b9
commit
255ca8d96b
@@ -84,6 +84,11 @@ on:
|
||||
- qa-live
|
||||
- npm-telegram
|
||||
- performance
|
||||
plugin_prerelease_node_exclude_patterns_json:
|
||||
description: Exact Plugin Prerelease Node test paths omitted only for frozen-target validation
|
||||
required: false
|
||||
default: "[]"
|
||||
type: string
|
||||
reuse_evidence:
|
||||
description: Reuse matching green product validation for the same target or a changelog-only Release SHA
|
||||
required: false
|
||||
@@ -216,7 +221,9 @@ jobs:
|
||||
RERUN_GROUP: ${{ inputs.rerun_group }}
|
||||
LIVE_SUITE_FILTER: ${{ inputs.live_suite_filter }}
|
||||
CROSS_OS_SUITE_FILTER: ${{ inputs.cross_os_suite_filter }}
|
||||
PLUGIN_PRERELEASE_NODE_EXCLUDE_PATTERNS_JSON: ${{ inputs.plugin_prerelease_node_exclude_patterns_json }}
|
||||
run: |
|
||||
plugin_prerelease_node_exclusions="$(jq -c . <<< "$PLUGIN_PRERELEASE_NODE_EXCLUDE_PATTERNS_JSON")"
|
||||
{
|
||||
echo "## Full release validation"
|
||||
echo
|
||||
@@ -246,6 +253,7 @@ jobs:
|
||||
fi
|
||||
if [[ "$RERUN_GROUP" == "all" || "$RERUN_GROUP" == "plugin-prerelease" ]]; then
|
||||
echo "- Plugin prerelease: \`Plugin Prerelease\` with \`target_ref=${TARGET_SHA}\`"
|
||||
echo "- Plugin prerelease Node exclusions: \`${plugin_prerelease_node_exclusions}\`"
|
||||
else
|
||||
echo "- Plugin prerelease: skipped by rerun group"
|
||||
fi
|
||||
@@ -342,6 +350,7 @@ jobs:
|
||||
NPM_TELEGRAM_SCENARIO: ${{ inputs.npm_telegram_scenario }}
|
||||
SKIP_PACKAGE_TELEGRAM_E2E: ${{ inputs.skip_package_telegram_e2e }}
|
||||
ALLOW_UNRELEASED_CHANGELOG: ${{ inputs.allow_unreleased_changelog || (inputs.target_context_ref == '' && (inputs.ref == 'main' || inputs.ref == 'refs/heads/main')) }}
|
||||
PLUGIN_PRERELEASE_NODE_EXCLUDE_PATTERNS_JSON: ${{ inputs.plugin_prerelease_node_exclude_patterns_json }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Lane-selection inputs must match the prior run's manifest exactly;
|
||||
@@ -360,6 +369,7 @@ jobs:
|
||||
--arg npmTelegramScenario "$NPM_TELEGRAM_SCENARIO" \
|
||||
--arg skipPackageTelegramE2e "$SKIP_PACKAGE_TELEGRAM_E2E" \
|
||||
--arg allowUnreleasedChangelog "$ALLOW_UNRELEASED_CHANGELOG" \
|
||||
--arg pluginPrereleaseNodeExcludePatternsJson "$PLUGIN_PRERELEASE_NODE_EXCLUDE_PATTERNS_JSON" \
|
||||
'{
|
||||
provider: $provider,
|
||||
mode: $mode,
|
||||
@@ -373,7 +383,8 @@ jobs:
|
||||
npmTelegramProviderMode: $npmTelegramProviderMode,
|
||||
npmTelegramScenario: $npmTelegramScenario,
|
||||
skipPackageTelegramE2e: $skipPackageTelegramE2e,
|
||||
allowUnreleasedChangelog: $allowUnreleasedChangelog
|
||||
allowUnreleasedChangelog: $allowUnreleasedChangelog,
|
||||
pluginPrereleaseNodeExcludePatternsJson: $pluginPrereleaseNodeExcludePatternsJson
|
||||
}')"
|
||||
bash workflow/scripts/github/find-reusable-release-validation.sh \
|
||||
--target-sha "$TARGET_SHA" \
|
||||
@@ -848,15 +859,19 @@ jobs:
|
||||
dispatch_and_wait ci.yml "$dispatch_run_name" "${args[@]}"
|
||||
;;
|
||||
plugin-prerelease)
|
||||
plugin_prerelease_node_exclusions="$(
|
||||
jq -c . <<< "$PLUGIN_PRERELEASE_NODE_EXCLUDE_PATTERNS_JSON"
|
||||
)"
|
||||
{
|
||||
echo "### Plugin prerelease"
|
||||
echo
|
||||
echo "- Target ref: \`${TARGET_REF}\`"
|
||||
echo "- Target SHA: \`${TARGET_SHA}\`"
|
||||
echo "- Frozen-target Node test omissions: \`${plugin_prerelease_node_exclusions}\`"
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
dispatch_id="full-release-validation-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-plugin-prerelease"
|
||||
dispatch_run_name="Plugin Prerelease ${dispatch_id}"
|
||||
args=(-f target_ref="$TARGET_SHA" -f expected_sha="$TARGET_SHA" -f full_release_validation=true -f dispatch_id="$dispatch_id")
|
||||
args=(-f target_ref="$TARGET_SHA" -f expected_sha="$TARGET_SHA" -f full_release_validation=true -f dispatch_id="$dispatch_id" -f node_test_exclude_patterns_json="$PLUGIN_PRERELEASE_NODE_EXCLUDE_PATTERNS_JSON")
|
||||
if [[ -n "${CANDIDATE_ARTIFACT_JSON// }" ]]; then
|
||||
args+=(-f candidate_artifact_json="$CANDIDATE_ARTIFACT_JSON")
|
||||
fi
|
||||
@@ -1006,6 +1021,7 @@ jobs:
|
||||
CHILD_WORKFLOW_REF: ${{ github.ref_name }}
|
||||
PARENT_WORKFLOW_SHA: ${{ github.sha }}
|
||||
CANDIDATE_ARTIFACT_JSON: ${{ needs.prepare_release_candidate.outputs.candidate_artifact_json }}
|
||||
PLUGIN_PRERELEASE_NODE_EXCLUDE_PATTERNS_JSON: ${{ inputs.plugin_prerelease_node_exclude_patterns_json }}
|
||||
FAIL_FAST: ${{ inputs.fail_fast }}
|
||||
run: *full_release_child_dispatch
|
||||
|
||||
@@ -1667,6 +1683,7 @@ jobs:
|
||||
NPM_TELEGRAM_SCENARIO: ${{ inputs.npm_telegram_scenario }}
|
||||
SKIP_PACKAGE_TELEGRAM_E2E: ${{ inputs.skip_package_telegram_e2e }}
|
||||
ALLOW_UNRELEASED_CHANGELOG: ${{ inputs.allow_unreleased_changelog || (inputs.target_context_ref == '' && (inputs.ref == 'main' || inputs.ref == 'refs/heads/main')) }}
|
||||
PLUGIN_PRERELEASE_NODE_EXCLUDE_PATTERNS_JSON: ${{ inputs.plugin_prerelease_node_exclude_patterns_json }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
manifest_dir="${RUNNER_TEMP}/full-release-validation"
|
||||
@@ -1743,6 +1760,7 @@ jobs:
|
||||
--arg npmTelegramScenario "$NPM_TELEGRAM_SCENARIO" \
|
||||
--arg skipPackageTelegramE2e "$SKIP_PACKAGE_TELEGRAM_E2E" \
|
||||
--arg allowUnreleasedChangelog "$ALLOW_UNRELEASED_CHANGELOG" \
|
||||
--arg pluginPrereleaseNodeExcludePatternsJson "$PLUGIN_PRERELEASE_NODE_EXCLUDE_PATTERNS_JSON" \
|
||||
'{
|
||||
version: 3,
|
||||
workflowName: $workflowName,
|
||||
@@ -1770,7 +1788,8 @@ jobs:
|
||||
npmTelegramProviderMode: $npmTelegramProviderMode,
|
||||
npmTelegramScenario: $npmTelegramScenario,
|
||||
skipPackageTelegramE2e: $skipPackageTelegramE2e,
|
||||
allowUnreleasedChangelog: $allowUnreleasedChangelog
|
||||
allowUnreleasedChangelog: $allowUnreleasedChangelog,
|
||||
pluginPrereleaseNodeExcludePatternsJson: $pluginPrereleaseNodeExcludePatternsJson
|
||||
},
|
||||
controls: {
|
||||
stableSoakRequired: ($releaseProfile == "stable" or $releaseProfile == "full"),
|
||||
|
||||
@@ -20,6 +20,11 @@ on:
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
node_test_exclude_patterns_json:
|
||||
description: Full Release Validation-only exact plugin test paths omitted for a frozen target
|
||||
required: false
|
||||
default: "[]"
|
||||
type: string
|
||||
dispatch_id:
|
||||
description: Optional parent workflow dispatch identifier
|
||||
required: false
|
||||
@@ -53,11 +58,73 @@ jobs:
|
||||
plugin_prerelease_static_matrix: ${{ steps.manifest.outputs.plugin_prerelease_static_matrix }}
|
||||
run_plugin_prerelease_node: ${{ steps.manifest.outputs.run_plugin_prerelease_node }}
|
||||
plugin_prerelease_node_matrix: ${{ steps.manifest.outputs.plugin_prerelease_node_matrix }}
|
||||
node_test_exclude_patterns_json: ${{ steps.node_test_exclusions.outputs.patterns_json }}
|
||||
run_plugin_prerelease_extensions: ${{ steps.manifest.outputs.run_plugin_prerelease_extensions }}
|
||||
plugin_prerelease_extension_matrix: ${{ steps.manifest.outputs.plugin_prerelease_extension_matrix }}
|
||||
run_plugin_prerelease_docker: ${{ steps.manifest.outputs.run_plugin_prerelease_docker }}
|
||||
plugin_prerelease_docker_lanes: ${{ steps.manifest.outputs.plugin_prerelease_docker_lanes }}
|
||||
steps:
|
||||
- name: Validate frozen-target Node exclusions
|
||||
id: node_test_exclusions
|
||||
env:
|
||||
FULL_RELEASE_VALIDATION: ${{ inputs.full_release_validation && 'true' || 'false' }}
|
||||
NODE_TEST_EXCLUDE_PATTERNS_JSON: ${{ inputs.node_test_exclude_patterns_json }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
node --input-type=module <<'EOF'
|
||||
import { appendFileSync } from "node:fs";
|
||||
|
||||
const rawPatterns = process.env.NODE_TEST_EXCLUDE_PATTERNS_JSON ?? "";
|
||||
let patterns;
|
||||
try {
|
||||
patterns = JSON.parse(rawPatterns);
|
||||
} catch (error) {
|
||||
console.error(`node_test_exclude_patterns_json must be valid JSON: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
if (!Array.isArray(patterns)) {
|
||||
console.error("node_test_exclude_patterns_json must be a JSON array");
|
||||
process.exit(1);
|
||||
}
|
||||
const invalidPattern = patterns.find((pattern) => {
|
||||
if (typeof pattern !== "string" || pattern.length === 0 || pattern !== pattern.trim()) {
|
||||
return true;
|
||||
}
|
||||
const segments = pattern.split("/");
|
||||
return (
|
||||
!pattern.startsWith("src/plugins/") ||
|
||||
!pattern.endsWith(".test.ts") ||
|
||||
pattern.includes("\\") ||
|
||||
pattern.includes("..") ||
|
||||
segments.some((segment) => segment.length === 0 || segment === ".") ||
|
||||
!/^[A-Za-z0-9._/-]+$/u.test(pattern)
|
||||
);
|
||||
});
|
||||
if (invalidPattern !== undefined) {
|
||||
console.error(
|
||||
`Invalid frozen-target Node test omission: ${JSON.stringify(invalidPattern)}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
if (new Set(patterns).size !== patterns.length) {
|
||||
console.error("node_test_exclude_patterns_json must not contain duplicate paths");
|
||||
process.exit(1);
|
||||
}
|
||||
const fullReleaseValidation = process.env.FULL_RELEASE_VALIDATION === "true";
|
||||
if (!fullReleaseValidation && rawPatterns !== "[]") {
|
||||
console.error(
|
||||
"node_test_exclude_patterns_json may differ from [] only when full_release_validation=true",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
appendFileSync(
|
||||
process.env.GITHUB_OUTPUT,
|
||||
`patterns_json=${JSON.stringify(patterns)}\n`,
|
||||
"utf8",
|
||||
);
|
||||
EOF
|
||||
|
||||
- name: Checkout target
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
@@ -305,6 +372,32 @@ jobs:
|
||||
persist-credentials: false
|
||||
submodules: false
|
||||
|
||||
- name: Checkout trusted npm security inventory
|
||||
if: inputs.full_release_validation
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
ref: ${{ github.sha }}
|
||||
path: .plugin-prerelease-trusted
|
||||
fetch-depth: 1
|
||||
fetch-tags: false
|
||||
persist-credentials: false
|
||||
sparse-checkout: src/plugins/npm-install-security-scan.release.test.ts
|
||||
sparse-checkout-cone-mode: false
|
||||
submodules: false
|
||||
|
||||
- name: Install trusted npm security inventory
|
||||
if: inputs.full_release_validation
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
trusted_checkout=.plugin-prerelease-trusted
|
||||
trap 'rm -rf -- "$trusted_checkout"' EXIT
|
||||
install -m 0644 \
|
||||
"$trusted_checkout/src/plugins/npm-install-security-scan.release.test.ts" \
|
||||
src/plugins/npm-install-security-scan.release.test.ts
|
||||
rm -rf -- "$trusted_checkout"
|
||||
trap - EXIT
|
||||
|
||||
- name: Setup Node environment
|
||||
uses: ./.github/actions/setup-node-env
|
||||
with:
|
||||
@@ -316,6 +409,7 @@ jobs:
|
||||
- name: Run release-only plugin Node shard
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
NODE_TEST_EXCLUDE_PATTERNS_JSON: ${{ needs.preflight.outputs.node_test_exclude_patterns_json }}
|
||||
OPENCLAW_NODE_TEST_CONFIGS_JSON: ${{ toJson(matrix.configs) }}
|
||||
OPENCLAW_NODE_TEST_INCLUDE_PATTERNS_JSON: ${{ toJson(matrix.includePatterns) }}
|
||||
OPENCLAW_VITEST_SHARD_NAME: ${{ matrix.shard_name }}
|
||||
@@ -336,6 +430,16 @@ jobs:
|
||||
const includePatterns = JSON.parse(
|
||||
process.env.OPENCLAW_NODE_TEST_INCLUDE_PATTERNS_JSON ?? "null",
|
||||
);
|
||||
const excludePatterns = JSON.parse(
|
||||
process.env.NODE_TEST_EXCLUDE_PATTERNS_JSON ?? "[]",
|
||||
);
|
||||
if (
|
||||
!Array.isArray(excludePatterns) ||
|
||||
excludePatterns.some((pattern) => typeof pattern !== "string")
|
||||
) {
|
||||
console.error("Invalid frozen-target Node exclusions");
|
||||
process.exit(1);
|
||||
}
|
||||
const childEnv = { ...process.env };
|
||||
if (Array.isArray(includePatterns) && includePatterns.length > 0) {
|
||||
const includeFile = join(
|
||||
@@ -346,7 +450,10 @@ jobs:
|
||||
childEnv.OPENCLAW_VITEST_INCLUDE_FILE = includeFile;
|
||||
}
|
||||
|
||||
const result = spawnSync("pnpm", ["test", "--", ...configs], {
|
||||
const excludeArgs = excludePatterns.map(
|
||||
(pattern) => `--exclude=${pattern.slice("src/plugins/".length)}`,
|
||||
);
|
||||
const result = spawnSync("pnpm", ["test", "--", ...configs, "--", ...excludeArgs], {
|
||||
env: childEnv,
|
||||
stdio: "inherit",
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user