template-sync-wf #5
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
| name: template-sync-wf | |
| on: | |
| schedule: | |
| - cron: "0 7 * * 1" # Mondays 07:00 UTC | |
| workflow_dispatch: {} | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| concurrency: | |
| group: template-sync | |
| cancel-in-progress: false | |
| # Repo-level ENV defaults; override in the GENERATED repo via Actions → Variables | |
| env: | |
| # The official template repo — hardcoded, since this is the source of truth | |
| TEMPLATE_REPO: deresegetachew/systemcraft-stack-npmlib | |
| TEMPLATE_REF: main | |
| # Turn the sync on/off in generated repos: | |
| TEMPLATE_SYNC_ENABLED: ${{ vars.TEMPLATE_SYNC_ENABLED || 'true' }} | |
| # Exclusions — space-separated paths/patterns relative to template root. | |
| # By default we DO NOT sync: packages, .changeset/.changesets, LICENSE/Licenses, node_modules, .gitattributes. | |
| TEMPLATE_EXCLUDE: ${{ vars.TEMPLATE_EXCLUDE || 'packages pnpm-lock.yml pnpm-lock.yaml .changeset .changesets LICENSE LICENSES node_modules .gitattributes README.md' }} | |
| # Branch naming | |
| TARGET_BRANCH: ${{ vars.TARGET_BRANCH || 'main' }} | |
| SYNC_BRANCH: ${{ vars.SYNC_BRANCH || 'chore/sync-template' }} | |
| # Optional label(s) — when set via repo Variables this can be a comma-separated string | |
| TEMPLATE_SYNC_LABEL: ${{ vars.TEMPLATE_SYNC_LABEL || 'template-sync,[skip changeset check]' }} | |
| jobs: | |
| sync: | |
| name: Sync from template systemcraft/play-npmlib (exclude packages, licenses, changesets) | |
| # IMPORTANT: do NOT run on the template repo itself | |
| if: ${{ github.repository != 'deresegetachew/systemcraft-stack-npmlib' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check if enabled | |
| if: ${{ env.TEMPLATE_SYNC_ENABLED != 'true' }} | |
| run: | | |
| echo "Template sync disabled (TEMPLATE_SYNC_ENABLED != 'true'). Exiting." | |
| exit 0 | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ env.TARGET_BRANCH }} | |
| - name: Fetch template repository | |
| run: | | |
| set -euo pipefail | |
| git clone --depth=1 --no-checkout "https://github.com/${{ env.TEMPLATE_REPO }}.git" /tmp/template | |
| cd /tmp/template | |
| git checkout "${{ env.TEMPLATE_REF }}" | |
| # rsync rsync stands for remote synchronization — it’s a file-copying and syncing utility that can efficiently mirror one directory tree into another, | |
| # only copying changed files and deleting ones that no longer exist on the source (if you tell it to). | |
| - name: Build rsync exclusion flags | |
| id: excludes | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| flags="" | |
| for p in $TEMPLATE_EXCLUDE; do | |
| flags="$flags --exclude=$p" | |
| done | |
| # Never try to copy .git | |
| flags="$flags --exclude=.git" | |
| echo "flags=$flags" >> "$GITHUB_OUTPUT" | |
| - uses: ./.github/actions/setup-ci-git-identity | |
| with: | |
| purpose: 'GPG-signed template sync commits' | |
| git-user-name: ${{ vars.CI_GPG_USER_NAME }} | |
| git-user-email: ${{ vars.CI_GPG_USER_EMAIL }} | |
| gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} | |
| gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }} | |
| - name: Copy template content (exclude configured paths) | |
| run: | | |
| set -euo pipefail | |
| rsync -a --delete ${{ steps.excludes.outputs.flags }} /tmp/template/ ./ | |
| # Stage changes if any; leave them staged for create-pull-request to commit | |
| git add -A | |
| if git diff --staged --quiet; then | |
| echo "✅ Everything is already up to date with the template!" | |
| echo "ℹ️ No changes detected, so no PR was created." | |
| echo "If you expected changes, ensure the template repo and ref are correct:" | |
| echo " - Template: $TEMPLATE_REPO" | |
| echo " - Branch: $TEMPLATE_REF" | |
| echo "" | |
| echo "To force a sync, you can trigger this workflow manually from the Actions tab." | |
| exit 0 | |
| fi | |
| - name: Open/Update PR | |
| uses: peter-evans/create-pull-request@v7 | |
| with: | |
| title: "chore: sync from template ${{ env.TEMPLATE_REPO }}" | |
| body: | | |
| Automated sync from **${{ env.TEMPLATE_REPO }}** @ `${{ env.TEMPLATE_REF }}` | |
| **Excluded paths:** `${{ env.TEMPLATE_EXCLUDE }}` | |
| Turn off via **Actions → Variables**: set `TEMPLATE_SYNC_ENABLED=false`. | |
| branch: ${{ env.SYNC_BRANCH }} | |
| base: ${{ env.TARGET_BRANCH }} | |
| labels: ${{ env.TEMPLATE_SYNC_LABEL }} | |
| delete-branch: false | |
| commit-message: "chore: sync from ${{ env.TEMPLATE_REPO }}@${{ env.TEMPLATE_REF }} (excluding: ${{ env.TEMPLATE_EXCLUDE }})" | |
| sign-commits: true | |
| committer: "${{ vars.CI_GPG_USER_NAME }} <${{ vars.CI_GPG_USER_EMAIL }}>" | |
| author: "${{ vars.CI_GPG_USER_NAME }} <${{ vars.CI_GPG_USER_EMAIL }}>" | |
| token: ${{ secrets.BOT_TOKEN }} |