fix: improve submodule sync in gh-pages worktree (#39) #92
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
| # Main PPA workflow — lint & source sync | |
| # Triggers on pushes/PRs to main. Tests source, then syncs to gh-pages. | |
| name: PPA Main | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| lint: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| submodules: true | |
| - name: Lint shell scripts | |
| run: | | |
| set -euo pipefail | |
| echo "Checking shell syntax..." | |
| find . -name "*.sh" -not -path "./.git/*" -print0 | while IFS= read -r -d '' file; do | |
| echo " Checking: $file" | |
| bash -n "$file" || exit 1 | |
| done | |
| echo "All shell scripts passed syntax check" | |
| - name: Lint YAML workflows | |
| run: | | |
| set -euo pipefail | |
| echo "Checking workflow YAML syntax..." | |
| for f in .github/workflows/*.yml; do | |
| echo " OK: $f" | |
| python3 -c "import yaml; yaml.safe_load(open('$f'))" || exit 1 | |
| done | |
| detect-changes: | |
| runs-on: ubuntu-latest | |
| needs: lint | |
| outputs: | |
| packages: ${{ steps.detect.outputs.packages }} | |
| has_changes: ${{ steps.detect.outputs.has_changes }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| submodules: true | |
| - name: Detect changed submodules | |
| id: detect | |
| run: | | |
| set -euo pipefail | |
| SUBMODULES=$(git submodule status | awk '{print $2}' | grep '^src/diepxuan/' | sed 's|^src/diepxuan/||' | sed 's|/$||' | jq -R -s -c 'split("\n") | map(select(length > 0))') | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| echo "packages=$SUBMODULES" >> $GITHUB_OUTPUT | |
| echo "has_changes=true" >> $GITHUB_OUTPUT | |
| echo "All packages will be built (manual trigger)" | |
| exit 0 | |
| fi | |
| BASE_REF="${{ github.base_ref }}" | |
| if [[ -z "$BASE_REF" ]]; then | |
| # Direct push to main (not a PR) — compare with previous commit | |
| CHANGES=$(git diff --name-only HEAD~1...HEAD 2>/dev/null || echo "") | |
| else | |
| # PR — compare with base branch | |
| CHANGES=$(git diff --name-only "origin/$BASE_REF...HEAD" 2>/dev/null || echo "") | |
| fi | |
| echo "Changes detected: $CHANGES" | |
| CHANGED_PACKAGES="[]" | |
| HAS_CHANGES="false" | |
| if [[ -n "$CHANGES" ]]; then | |
| for submodule in $(git submodule status | awk '{print $2}' | grep '^src/diepxuan/' | sed 's|^src/diepxuan/||' | sed 's|/$||'); do | |
| if echo "$CHANGES" | grep -q "^src/diepxuan/$submodule/"; then | |
| echo "Package '$submodule' has changes" | |
| CHANGED_PACKAGES=$(echo "$CHANGED_PACKAGES" | jq -c ". + [\"$submodule\"]") | |
| HAS_CHANGES="true" | |
| fi | |
| done | |
| fi | |
| if [[ "$CHANGED_PACKAGES" == "[]" ]]; then | |
| echo "No package changes detected" | |
| echo "packages=[]" >> $GITHUB_OUTPUT | |
| echo "has_changes=false" >> $GITHUB_OUTPUT | |
| else | |
| echo "packages=$CHANGED_PACKAGES" >> $GITHUB_OUTPUT | |
| echo "has_changes=$HAS_CHANGES" >> $GITHUB_OUTPUT | |
| echo "Will build: $CHANGED_PACKAGES" | |
| fi | |
| sync-to-gh-pages: | |
| runs-on: ubuntu-latest | |
| needs: [lint, detect-changes] | |
| if: github.ref == 'refs/heads/main' | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: main | |
| fetch-depth: 1 | |
| submodules: true | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Sync to gh-pages | |
| run: | | |
| set -euo pipefail | |
| git config user.name "DiepXuan CI" | |
| git config user.email "ci@diepxuan.com" | |
| # Fetch gh-pages | |
| git fetch origin gh-pages | |
| # Create worktree for gh-pages | |
| rm -rf _gh-pages-worktree 2>/dev/null || true | |
| git worktree add -B gh-pages _gh-pages-worktree origin/gh-pages | |
| cd _gh-pages-worktree | |
| # Remove all tracked non-generated files | |
| git rm -rf --ignore-unmatch \ | |
| AGENTS.md BOOTSTRAP.md SOUL.md IDENTITY.md USER.md TOOLS.md HEARTBEAT.md \ | |
| README.md .gitignore .gitmodules .editorconfig \ | |
| Dockerfile install.sh \ | |
| docs/ .github/ .openclaw/ .stfolder/ \ | |
| src/ conf/ \ | |
| 2>/dev/null || true | |
| # Copy source files from main (excluding generated dirs) | |
| cd .. | |
| cp README.md _gh-pages-worktree/ | |
| cp .gitignore _gh-pages-worktree/ | |
| cp .gitmodules _gh-pages-worktree/ 2>/dev/null || true | |
| cp .editorconfig _gh-pages-worktree/ 2>/dev/null || true | |
| # Sync submodule refs | |
| # gh-pages has .gitmodules deleted by cleanup-generated, | |
| # so we re-register submodules from the copied .gitmodules | |
| cd _gh-pages-worktree | |
| git submodule sync | |
| # Initialize submodules from .gitmodules | |
| git submodule update --init --checkout 2>/dev/null || true | |
| # Checkout each submodule to the correct ref from main | |
| cd .. | |
| for submodule_dir in src/diepxuan/*/; do | |
| name=$(basename "$submodule_dir") | |
| ref=$(cd "$submodule_dir" && git rev-parse HEAD 2>/dev/null) || continue | |
| wt_dir="_gh-pages-worktree/src/diepxuan/$name" | |
| if [ -d "$wt_dir" ]; then | |
| (cd "$wt_dir" && git fetch origin main 2>/dev/null && git checkout "$ref" 2>/dev/null) || true | |
| fi | |
| done | |
| # Add submodules to index (git rm removed them; git add -A won't auto-add new submodules) | |
| (cd _gh-pages-worktree && git add src/) || true | |
| # Sync conf directory | |
| rm -rf _gh-pages-worktree/conf 2>/dev/null || true | |
| if [ -d conf ]; then | |
| cp -r conf _gh-pages-worktree/conf | |
| fi | |
| cd _gh-pages-worktree | |
| # Stage and commit | |
| git add -A | |
| if ! git diff --cached --quiet; then | |
| git commit -m "ci: sync source from main@${{ github.sha }}" | |
| git push origin gh-pages | |
| else | |
| echo "No changes to sync" | |
| fi | |
| # Cleanup worktree | |
| cd .. | |
| git worktree remove _gh-pages-worktree -f 2>/dev/null || rm -rf _gh-pages-worktree |