From 4b23529ca9ce180ec9433afcbed2a10d743e6c1a Mon Sep 17 00:00:00 2001 From: csh Date: Tue, 17 Mar 2026 17:55:59 +0800 Subject: [PATCH] :wrench: chore(ci): merge superpowers update and sync workflow --- .gitea/workflows/sync-superpowers.yml | 76 ----------------- .../update-thirdparty-superpowers.yml | 85 ++++++++++++++++++- tests/test_superpowers_workflows.py | 46 +++++----- 3 files changed, 106 insertions(+), 101 deletions(-) delete mode 100644 .gitea/workflows/sync-superpowers.yml diff --git a/.gitea/workflows/sync-superpowers.yml b/.gitea/workflows/sync-superpowers.yml deleted file mode 100644 index 165684a..0000000 --- a/.gitea/workflows/sync-superpowers.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Sync Superpowers Skills - -on: - push: - branches: - - thirdparty/skill - workflow_dispatch: - -concurrency: - group: superpowers-sync-${{ github.repository }} - cancel-in-progress: true - -env: - WORKSPACE_DIR: "/home/workspace" - TARGET_BRANCH: "main" - SUPERPOWERS_BRANCH: "thirdparty/skill" - SUPERPOWERS_DIR: "superpowers" - SUPERPOWERS_LIST: "codex/skills/.sources/superpowers.list" - -jobs: - sync: - name: Sync to main - runs-on: ubuntu-22.04 - - steps: - - name: Prepare repo - run: | - echo "========================================" - echo "Prepare repo to WORKSPACE_DIR" - echo "========================================" - - REPO_NAME="${{ github.event.repository.name }}" - REPO_DIR="${{ env.WORKSPACE_DIR }}/$REPO_NAME" - TOKEN="${{ secrets.WORKFLOW }}" - if [ -n "$TOKEN" ]; then - REPO_URL="https://oauth2:${TOKEN}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git" - else - REPO_URL="${GITHUB_SERVER_URL}/${{ github.repository }}.git" - fi - - if [ -d "$REPO_DIR" ]; then - if [ -d "$REPO_DIR/.git" ]; then - cd "$REPO_DIR" - # Clear local index flags so checked-out workflow/script files - # always refresh from the latest main branch contents. - git ls-files -v | awk '/^[a-zS] / {sub(/^[a-zS] /, ""); print}' | while IFS= read -r path; do - git update-index --no-assume-unchanged --no-skip-worktree -- "$path" - done - git clean -fdx - git reset --hard - git fetch --all --tags --force --prune --prune-tags - else - rm -rf "$REPO_DIR" - fi - fi - - if [ ! -d "$REPO_DIR/.git" ]; then - mkdir -p "${{ env.WORKSPACE_DIR }}" - git clone "$REPO_URL" "$REPO_DIR" - cd "$REPO_DIR" - fi - - # Always run sync from the latest target branch state. - # This prevents stale/manual dispatch refs from using outdated scripts. - git fetch origin "${{ env.TARGET_BRANCH }}" - git checkout -B "${{ env.TARGET_BRANCH }}" "origin/${{ env.TARGET_BRANCH }}" - - git config --global --add safe.directory "$REPO_DIR" - echo "REPO_DIR=$REPO_DIR" >> $GITHUB_ENV - - - name: Sync superpowers skills to main - shell: bash - run: | - set -euo pipefail - cd "$REPO_DIR" - bash .gitea/ci/sync_superpowers.sh diff --git a/.gitea/workflows/update-thirdparty-superpowers.yml b/.gitea/workflows/update-thirdparty-superpowers.yml index d0d014a..76ad534 100644 --- a/.gitea/workflows/update-thirdparty-superpowers.yml +++ b/.gitea/workflows/update-thirdparty-superpowers.yml @@ -1,4 +1,4 @@ -name: Update Third-party Superpowers +name: Update and Sync Superpowers on: push: @@ -9,19 +9,25 @@ on: - cron: "@daily" concurrency: - group: thirdparty-superpowers-update-${{ github.repository }} + group: superpowers-update-sync-${{ github.repository }} cancel-in-progress: true env: WORKSPACE_DIR: "/home/workspace" - TARGET_BRANCH: "thirdparty/skill" + THIRDPARTY_BRANCH: "thirdparty/skill" UPSTREAM_REPO: "https://github.com/obra/superpowers.git" UPSTREAM_REF: "main" + SUPERPOWERS_DIR: "superpowers" + SUPERPOWERS_LIST: "codex/skills/.sources/superpowers.list" jobs: update: name: Update thirdparty/skill snapshot runs-on: ubuntu-22.04 + outputs: + snapshot_changed: ${{ steps.update_snapshot.outputs.snapshot_changed }} + env: + TARGET_BRANCH: "${{ env.THIRDPARTY_BRANCH }}" steps: - name: Prepare repo @@ -63,8 +69,81 @@ jobs: echo "REPO_DIR=$REPO_DIR" >> $GITHUB_ENV - name: Update thirdparty/skill snapshot + id: update_snapshot shell: bash run: | set -euo pipefail cd "$REPO_DIR" + before_ref="" + if git show-ref --verify --quiet "refs/remotes/origin/$TARGET_BRANCH"; then + before_ref="$(git rev-parse "origin/$TARGET_BRANCH")" + fi bash .gitea/ci/update_thirdparty_superpowers.sh + git fetch origin "$TARGET_BRANCH" + after_ref="$(git rev-parse "origin/$TARGET_BRANCH")" + if [ "$after_ref" != "$before_ref" ]; then + echo "snapshot_changed=true" >> "$GITHUB_OUTPUT" + else + echo "snapshot_changed=false" >> "$GITHUB_OUTPUT" + fi + sync: + name: Sync skills to main + needs: update + if: ${{ needs.update.outputs.snapshot_changed == 'true' }} + runs-on: ubuntu-22.04 + env: + TARGET_BRANCH: "main" + SUPERPOWERS_BRANCH: "${{ env.THIRDPARTY_BRANCH }}" + SUPERPOWERS_DIR: "${{ env.SUPERPOWERS_DIR }}" + SUPERPOWERS_LIST: "${{ env.SUPERPOWERS_LIST }}" + + steps: + - name: Prepare repo + run: | + echo "========================================" + echo "Prepare repo to WORKSPACE_DIR" + echo "========================================" + + REPO_NAME="${{ github.event.repository.name }}" + REPO_DIR="${{ env.WORKSPACE_DIR }}/$REPO_NAME" + TOKEN="${{ secrets.WORKFLOW }}" + if [ -n "$TOKEN" ]; then + REPO_URL="https://oauth2:${TOKEN}@${GITHUB_SERVER_URL#https://}/${{ github.repository }}.git" + else + REPO_URL="${GITHUB_SERVER_URL}/${{ github.repository }}.git" + fi + + if [ -d "$REPO_DIR" ]; then + if [ -d "$REPO_DIR/.git" ]; then + cd "$REPO_DIR" + # Clear local index flags so checked-out workflow/script files + # always refresh from the latest main branch contents. + git ls-files -v | awk '/^[a-zS] / {sub(/^[a-zS] /, ""); print}' | while IFS= read -r path; do + git update-index --no-assume-unchanged --no-skip-worktree -- "$path" + done + git clean -fdx + git reset --hard + git fetch --all --tags --force --prune --prune-tags + else + rm -rf "$REPO_DIR" + fi + fi + + if [ ! -d "$REPO_DIR/.git" ]; then + mkdir -p "${{ env.WORKSPACE_DIR }}" + git clone "$REPO_URL" "$REPO_DIR" + cd "$REPO_DIR" + fi + + git fetch origin "$TARGET_BRANCH" + git checkout -B "$TARGET_BRANCH" "origin/$TARGET_BRANCH" + + git config --global --add safe.directory "$REPO_DIR" + echo "REPO_DIR=$REPO_DIR" >> $GITHUB_ENV + + - name: Sync superpowers skills to main + shell: bash + run: | + set -euo pipefail + cd "$REPO_DIR" + bash .gitea/ci/sync_superpowers.sh diff --git a/tests/test_superpowers_workflows.py b/tests/test_superpowers_workflows.py index 8fa9416..8c02bfb 100644 --- a/tests/test_superpowers_workflows.py +++ b/tests/test_superpowers_workflows.py @@ -2,35 +2,19 @@ import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[1] -SYNC_WORKFLOW = ROOT / ".gitea" / "workflows" / "sync-superpowers.yml" +LEGACY_SYNC_WORKFLOW = ROOT / ".gitea" / "workflows" / "sync-superpowers.yml" AUTO_UPDATE_WORKFLOW = ROOT / ".gitea" / "workflows" / "update-thirdparty-superpowers.yml" AUTO_UPDATE_SCRIPT = ROOT / ".gitea" / "ci" / "update_thirdparty_superpowers.sh" SYNC_SCRIPT = ROOT / ".gitea" / "ci" / "sync_superpowers.sh" class SuperpowersWorkflowTests(unittest.TestCase): - def test_sync_workflow_uses_manual_trigger(self): - text = SYNC_WORKFLOW.read_text(encoding="utf-8") - self.assertIn("workflow_dispatch:", text) + def test_legacy_sync_workflow_is_removed(self): + self.assertFalse(LEGACY_SYNC_WORKFLOW.exists()) - def test_sync_workflow_triggers_on_thirdparty_push(self): - text = SYNC_WORKFLOW.read_text(encoding="utf-8") - self.assertIn("push:", text) - self.assertIn("- thirdparty/skill", text) - - def test_sync_workflow_clears_stale_index_flags(self): - text = SYNC_WORKFLOW.read_text(encoding="utf-8") - self.assertIn("git update-index --no-assume-unchanged", text) - self.assertIn("--no-skip-worktree", text) - - def test_sync_workflow_runs_from_latest_main(self): - text = SYNC_WORKFLOW.read_text(encoding="utf-8") - self.assertIn('TARGET_BRANCH: "main"', text) - self.assertIn('git fetch origin "${{ env.TARGET_BRANCH }}"', text) - self.assertIn( - 'git checkout -B "${{ env.TARGET_BRANCH }}" "origin/${{ env.TARGET_BRANCH }}"', - text, - ) + def test_auto_update_workflow_name_describes_full_pipeline(self): + text = AUTO_UPDATE_WORKFLOW.read_text(encoding="utf-8") + self.assertIn("name: Update and Sync Superpowers", text) def test_auto_update_workflow_triggers_on_main_push(self): text = AUTO_UPDATE_WORKFLOW.read_text(encoding="utf-8") @@ -47,6 +31,24 @@ class SuperpowersWorkflowTests(unittest.TestCase): text = AUTO_UPDATE_WORKFLOW.read_text(encoding="utf-8") self.assertIn("bash .gitea/ci/update_thirdparty_superpowers.sh", text) + def test_auto_update_workflow_runs_sync_after_update(self): + text = AUTO_UPDATE_WORKFLOW.read_text(encoding="utf-8") + self.assertIn("update:", text) + self.assertIn("sync:", text) + self.assertIn("needs: update", text) + self.assertIn("bash .gitea/ci/sync_superpowers.sh", text) + + def test_auto_update_workflow_sync_job_clears_stale_index_flags(self): + text = AUTO_UPDATE_WORKFLOW.read_text(encoding="utf-8") + self.assertIn("git update-index --no-assume-unchanged", text) + self.assertIn("--no-skip-worktree", text) + + def test_auto_update_workflow_sync_job_runs_from_latest_main(self): + text = AUTO_UPDATE_WORKFLOW.read_text(encoding="utf-8") + self.assertIn('TARGET_BRANCH: "main"', text) + self.assertIn('git fetch origin "$TARGET_BRANCH"', text) + self.assertIn('git checkout -B "$TARGET_BRANCH" "origin/$TARGET_BRANCH"', text) + def test_auto_update_script_targets_thirdparty_branch(self): text = AUTO_UPDATE_SCRIPT.read_text(encoding="utf-8") self.assertIn('TARGET_BRANCH="${TARGET_BRANCH:-thirdparty/skill}"', text)