🐛 fix(ci): route scheduled thirdparty updates through prepare
This commit is contained in:
@@ -14,7 +14,7 @@ on:
|
|||||||
- main
|
- main
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
# 北京时间(UTC+8)每日 06:00;Prepare 成功后由 workflow_run 触发 thirdparty 快照更新。
|
# 北京时间(UTC+8)每日 06:00;Prepare 成功后内部调用 thirdparty updater。
|
||||||
- cron: "0 22 * * *"
|
- cron: "0 22 * * *"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
@@ -293,3 +293,19 @@ jobs:
|
|||||||
echo "- npm:\`$actual_npm_version\`"
|
echo "- npm:\`$actual_npm_version\`"
|
||||||
echo "- 缓存目录:\`$FNM_DIR\`"
|
echo "- 缓存目录:\`$FNM_DIR\`"
|
||||||
} >> "$GITHUB_STEP_SUMMARY"
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
|
update_thirdparty_scheduled:
|
||||||
|
# Gitea 1.27 会抑制由 gitea-actions 定时运行产生的后续 workflow_run。
|
||||||
|
# 因此 schedule 在 Prepare 成功后直接调用 updater;updater 本身不暴露
|
||||||
|
# schedule / workflow_dispatch 入口。push / 手动 Prepare 仍走原 workflow_run 链。
|
||||||
|
needs: prepare
|
||||||
|
if: ${{ github.event_name == 'schedule' }}
|
||||||
|
uses: ./.gitea/workflows/update-thirdparty-skills.yml
|
||||||
|
with:
|
||||||
|
source_branch: ${{ github.ref_name }}
|
||||||
|
source_sha: ${{ github.sha }}
|
||||||
|
secrets:
|
||||||
|
WORKFLOW: ${{ secrets.WORKFLOW }}
|
||||||
|
concurrency:
|
||||||
|
group: update-thirdparty-${{ github.repository }}
|
||||||
|
cancel-in-progress: false
|
||||||
|
|||||||
@@ -1,6 +1,19 @@
|
|||||||
name: ♻️ 更新第三方 Skills
|
name: ♻️ 更新第三方 Skills
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
# schedule 由 prepare.yml 在 prepare job 成功后内部调用;这里不提供独立
|
||||||
|
# schedule / workflow_dispatch 入口。
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
source_branch:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
source_sha:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
secrets:
|
||||||
|
WORKFLOW:
|
||||||
|
required: true
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: ["🧰 准备环境"]
|
workflows: ["🧰 准备环境"]
|
||||||
types:
|
types:
|
||||||
@@ -15,8 +28,8 @@ env:
|
|||||||
ACCESS_TOKEN: ${{ secrets.WORKFLOW }}
|
ACCESS_TOKEN: ${{ secrets.WORKFLOW }}
|
||||||
WORKSPACE_ROOT: "/data/workspace"
|
WORKSPACE_ROOT: "/data/workspace"
|
||||||
WORKSPACE_SLOT: "thirdparty"
|
WORKSPACE_SLOT: "thirdparty"
|
||||||
SOURCE_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
SOURCE_BRANCH: ${{ inputs.source_branch || github.event.workflow_run.head_branch }}
|
||||||
SOURCE_SHA: ${{ github.event.workflow_run.head_sha }}
|
SOURCE_SHA: ${{ inputs.source_sha || github.event.workflow_run.head_sha }}
|
||||||
THIRDPARTY_BRANCH: "thirdparty/skill"
|
THIRDPARTY_BRANCH: "thirdparty/skill"
|
||||||
MANIFEST_PATH: ".gitea/ci/thirdparty_skills.json"
|
MANIFEST_PATH: ".gitea/ci/thirdparty_skills.json"
|
||||||
GIT_USER_NAME: "ci[bot]"
|
GIT_USER_NAME: "ci[bot]"
|
||||||
@@ -24,8 +37,9 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update_and_sync:
|
update_and_sync:
|
||||||
# 仅在 Prepare 于主分支成功后触发(含每日 schedule 触发的 Prepare)。
|
# workflow_call 只能由 schedule Prepare 的 needs 成功路径进入;
|
||||||
if: ${{ github.event.workflow_run.conclusion == 'success' && (github.event.workflow_run.head_branch == 'main' || github.event.workflow_run.head_branch == 'master') }}
|
# workflow_run 仍需要显式校验 Prepare 成功且来自主分支。
|
||||||
|
if: ${{ github.event_name == 'workflow_call' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event != 'schedule' && (github.event.workflow_run.head_branch == 'main' || github.event.workflow_run.head_branch == 'master')) }}
|
||||||
name: 📥 更新快照并同步 main
|
name: 📥 更新快照并同步 main
|
||||||
runs-on: standard-ubuntu-22
|
runs-on: standard-ubuntu-22
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from pathlib import Path
|
|||||||
ROOT = Path(__file__).resolve().parents[1]
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
MANIFEST = ROOT / ".gitea" / "ci" / "thirdparty_skills.json"
|
MANIFEST = ROOT / ".gitea" / "ci" / "thirdparty_skills.json"
|
||||||
WORKFLOW = ROOT / ".gitea" / "workflows" / "update-thirdparty-skills.yml"
|
WORKFLOW = ROOT / ".gitea" / "workflows" / "update-thirdparty-skills.yml"
|
||||||
|
PREPARE_WORKFLOW = ROOT / ".gitea" / "workflows" / "prepare.yml"
|
||||||
TSL_SYNC_WORKFLOW = ROOT / ".gitea" / "workflows" / "sync-tsl-playbook.yml"
|
TSL_SYNC_WORKFLOW = ROOT / ".gitea" / "workflows" / "sync-tsl-playbook.yml"
|
||||||
LEGACY_WORKFLOW = ROOT / ".gitea" / "workflows" / "update-thirdparty-superpowers.yml"
|
LEGACY_WORKFLOW = ROOT / ".gitea" / "workflows" / "update-thirdparty-superpowers.yml"
|
||||||
UPDATE_SCRIPT = ROOT / ".gitea" / "ci" / "update_thirdparty_skills.sh"
|
UPDATE_SCRIPT = ROOT / ".gitea" / "ci" / "update_thirdparty_skills.sh"
|
||||||
@@ -21,6 +22,21 @@ def load_manifest() -> dict:
|
|||||||
return json.loads(MANIFEST.read_text(encoding="utf-8"))
|
return json.loads(MANIFEST.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def workflow_mapping_keys(text: str, section: str) -> list[str]:
|
||||||
|
lines = text.splitlines()
|
||||||
|
section_line = f"{section}:"
|
||||||
|
start = lines.index(section_line) + 1
|
||||||
|
keys = []
|
||||||
|
for line in lines[start:]:
|
||||||
|
if line and not line.startswith(" "):
|
||||||
|
break
|
||||||
|
if line.startswith(" ") and not line.startswith(" "):
|
||||||
|
stripped = line.strip()
|
||||||
|
if stripped.endswith(":") and not stripped.startswith("#"):
|
||||||
|
keys.append(stripped[:-1])
|
||||||
|
return keys
|
||||||
|
|
||||||
|
|
||||||
def bash_path(path: Path) -> str:
|
def bash_path(path: Path) -> str:
|
||||||
resolved = path.resolve()
|
resolved = path.resolve()
|
||||||
if os.name != "nt":
|
if os.name != "nt":
|
||||||
@@ -212,6 +228,45 @@ class ThirdpartySkillsPipelineTests(unittest.TestCase):
|
|||||||
self.assertIn("update_thirdparty_snapshots", text)
|
self.assertIn("update_thirdparty_snapshots", text)
|
||||||
self.assertIn("sync_thirdparty_skills", text)
|
self.assertIn("sync_thirdparty_skills", text)
|
||||||
|
|
||||||
|
def test_scheduled_prepare_calls_updater_without_an_independent_entry(self):
|
||||||
|
prepare_text = PREPARE_WORKFLOW.read_text(encoding="utf-8")
|
||||||
|
updater_text = WORKFLOW.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
workflow_mapping_keys(prepare_text, "jobs"),
|
||||||
|
["prepare", "update_thirdparty_scheduled"],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
workflow_mapping_keys(updater_text, "on"),
|
||||||
|
["workflow_call", "workflow_run"],
|
||||||
|
)
|
||||||
|
self.assertIn(" needs: prepare", prepare_text)
|
||||||
|
self.assertIn(" if: ${{ github.event_name == 'schedule' }}", prepare_text)
|
||||||
|
self.assertIn(
|
||||||
|
" uses: ./.gitea/workflows/update-thirdparty-skills.yml",
|
||||||
|
prepare_text,
|
||||||
|
)
|
||||||
|
self.assertIn(" source_branch: ${{ github.ref_name }}", prepare_text)
|
||||||
|
self.assertIn(" source_sha: ${{ github.sha }}", prepare_text)
|
||||||
|
self.assertIn(" WORKFLOW: ${{ secrets.WORKFLOW }}", prepare_text)
|
||||||
|
self.assertIn(" workflow_call:", updater_text)
|
||||||
|
self.assertIn(" source_branch:", updater_text)
|
||||||
|
self.assertIn(" source_sha:", updater_text)
|
||||||
|
self.assertIn(" WORKFLOW:", updater_text)
|
||||||
|
self.assertIn(" required: true", updater_text)
|
||||||
|
self.assertIn(
|
||||||
|
"SOURCE_BRANCH: ${{ inputs.source_branch || "
|
||||||
|
"github.event.workflow_run.head_branch }}",
|
||||||
|
updater_text,
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
"SOURCE_SHA: ${{ inputs.source_sha || "
|
||||||
|
"github.event.workflow_run.head_sha }}",
|
||||||
|
updater_text,
|
||||||
|
)
|
||||||
|
self.assertIn("github.event_name == 'workflow_call' ||", updater_text)
|
||||||
|
self.assertIn("github.event.workflow_run.event != 'schedule'", updater_text)
|
||||||
|
|
||||||
def test_inline_workflow_exposes_manifest_and_publish_contract(self):
|
def test_inline_workflow_exposes_manifest_and_publish_contract(self):
|
||||||
text = WORKFLOW.read_text(encoding="utf-8")
|
text = WORKFLOW.read_text(encoding="utf-8")
|
||||||
self.assertIn('MANIFEST_PATH="${MANIFEST_PATH:-.gitea/ci/thirdparty_skills.json}"', text)
|
self.assertIn('MANIFEST_PATH="${MANIFEST_PATH:-.gitea/ci/thirdparty_skills.json}"', text)
|
||||||
|
|||||||
Reference in New Issue
Block a user