Skip to content

fix: improve submodule sync in gh-pages worktree (#39) #92

fix: improve submodule sync in gh-pages worktree (#39)

fix: improve submodule sync in gh-pages worktree (#39) #92

Workflow file for this run

# 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