name: Shadow Sync on: push: branches: - "**" - "!shadow/**" - "!shadow" # If you do NOT want shadows for these, keep them excluded: # - "!main" # - "!master" delete: jobs: sync-logic: runs-on: ubuntu-latest if: github.event_name == 'push' permissions: contents: write concurrency: group: shadow-sync-${{ github.ref_name }} cancel-in-progress: true steps: - name: Checkout Source uses: actions/checkout@v4 with: fetch-depth: 0 - name: Sync Shadow Branch run: | set -euo pipefail git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" SOURCE_BRANCH="${{ github.ref_name }}" SHADOW_BRANCH="shadow/${SOURCE_BRANCH}" # Create/reset shadow branch at the current source HEAD git checkout -B "$SHADOW_BRANCH" EXCLUDE_LIST=("packages/core/tests/fixtures") for item in "${EXCLUDE_LIST[@]}"; do if [ -e "$item" ]; then rm -rf "$item" git add -A "$item" fi done if ! git diff --cached --quiet; then git commit -m "chore(shadow): strip fixtures for $SOURCE_BRANCH" fi git push origin "$SHADOW_BRANCH" --force cleanup-logic: runs-on: ubuntu-latest if: github.event_name == 'delete' && github.event.ref_type == 'branch' && !startsWith(github.event.ref, 'shadow/') permissions: contents: write steps: - name: Delete Shadow Branch (via API) uses: actions/github-script@v7 with: script: | const source = context.payload.ref; // deleted branch name const shadow = `shadow/${source}`; const ref = `heads/${shadow}`; core.info(`Cleaning up shadow branch for ${source} -> ${shadow}`); try { await github.rest.git.deleteRef({ owner: context.repo.owner, repo: context.repo.repo, ref, }); core.info(`Deleted ${shadow}`); } catch (e) { if (e.status === 404 || e.status === 422) { core.info(`Shadow branch ${shadow} not found (already gone).`); } else { throw e; } }