Workflows

Template Updates

Receive SvelDocs template updates through reviewable pull requests.


How Template Updates Work

GitHub creates an independent repository from a template. The new repository does not remain connected to the template and does not receive later changes automatically.

SvelDocs includes an opt-in workflow that checks BranDenn/SvelDocs for updates every Monday and can also be run manually. When shared infrastructure changes, it opens a pull request in your repository for review.

Enable Update Pull Requests

GitHub may prevent workflows from creating pull requests until you enable the repository setting:

  1. Open Settings > Actions > General in your repository.
  2. Under Workflow permissions, select Read and write permissions.
  3. Select Allow GitHub Actions to create and approve pull requests.
  4. Save the changes.

No personal access token is required. The workflow uses the repository's temporary GITHUB_TOKEN and reads the public SvelDocs template.

Choose The SvelDocs Directory

The workflow supports both standalone repositories and monorepos. Set SVELDOCS_PATH near the top of .github/workflows/template-sync.yml to the directory that contains the SvelDocs app:

.github/workflows/template-sync.yml
env:
	SVELDOCS_PATH: '.' # SvelDocs is at the repository root
.yaml

For a monorepo with the SvelDocs app under docs, use:

.github/workflows/template-sync.yml
env:
	SVELDOCS_PATH: 'docs'
.yaml

This setting applies to scheduled and manual runs. It must be a relative path and cannot contain .. segments.

Run An Update Check

The scheduled check runs weekly. To check immediately:

  1. Open the Actions tab in your repository.
  2. Select Sync Template Updates.
  3. Select Run workflow.

If updates are available, the workflow creates a pull request from a uniquely named chore/template-sync-* branch. Review its checks and resolve any conflicts before merging it. Repeated runs update the same open pull request instead of creating duplicates. If you close one without merging, a later update uses a new branch and pull request, so the closed pull request cannot block future updates.

.github/workflows/template-sync.yml
name: Sync Template Updates
 
on:
  schedule:
    - cron: '0 9 * * 1'
  workflow_dispatch:
 
env:
  # Set to 'docs' when SvelDocs is located in a monorepo subdirectory.
  SVELDOCS_PATH: '.'
 
jobs:
  sync-template:
    if: github.repository != 'BranDenn/SvelDocs'
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
 
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
 
      - name: Sync template-owned paths
        id: sync
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SOURCE_REPOSITORY: https://github.com/BranDenn/SvelDocs.git
        run: |
          if [[ "$SVELDOCS_PATH" = /* || "$SVELDOCS_PATH" =~ (^|/)\.\.(/|$) ]]; then
            echo "SVELDOCS_PATH must be a relative path without '..' segments" >&2
            exit 1
          fi
 
          target_path="${SVELDOCS_PATH%/}"
          [[ -n "$target_path" ]] || target_path='.'
          source_path="$(mktemp -d)"
          git clone --depth 1 "$SOURCE_REPOSITORY" "$source_path"
 
          base_commit="$(git rev-parse HEAD)"
          branch="$(
            gh pr list \
              --state open \
              --base "$GITHUB_REF_NAME" \
              --json headRefName \
              --jq 'map(select(.headRefName | startswith("chore/template-sync-"))) | .[0].headRefName // ""'
          )"
          if [[ -n "$branch" ]]; then
            git fetch origin "$branch:refs/remotes/origin/$branch"
          else
            branch="chore/template-sync-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
          fi
          git checkout -B "$branch" "$base_commit"
 
          ignore_file="$target_path/.templatesyncignore"
 
          while IFS= read -r managed_path || [[ -n "$managed_path" ]]; do
            [[ -n "$managed_path" && "$managed_path" != \#* ]] || continue
            if [[ "$managed_path" = /* || "$managed_path" =~ (^|/)\.\.(/|$) ]]; then
              echo "Invalid managed path: $managed_path" >&2
              exit 1
            fi
 
            source_item="$source_path/$managed_path"
            target_item="$target_path/$managed_path"
 
            skip_managed_path=false
            directory_excludes="$(mktemp)"
            if [[ -f "$ignore_file" ]]; then
              while IFS= read -r ignored_path || [[ -n "$ignored_path" ]]; do
                [[ -n "$ignored_path" && "$ignored_path" != \#* ]] || continue
                ignored_path="${ignored_path#/}"
                ignored_path="${ignored_path%/}"
                if [[ "$ignored_path" =~ (^|/)\.\.(/|$) ]]; then
                  echo "Invalid ignored path: $ignored_path" >&2
                  exit 1
                fi
 
                managed_root="${managed_path%/}"
                if [[ "$managed_root" == "$ignored_path" || "$managed_root" == "$ignored_path/"* ]]; then
                  skip_managed_path=true
                  break
                fi
                if [[ "$ignored_path" == "$managed_root/"* ]]; then
                  echo "/${ignored_path#"$managed_root/"}" >> "$directory_excludes"
                fi
              done < "$ignore_file"
            fi
 
            if [[ "$skip_managed_path" == true ]]; then
              continue
            fi
 
            if [[ -d "$source_item" ]]; then
              mkdir -p "$target_item"
              rsync --archive --delete --exclude-from="$directory_excludes" "$source_item/" "$target_item/"
            elif [[ -f "$source_item" ]]; then
              mkdir -p "$(dirname "$target_item")"
              cp "$source_item" "$target_item"
            else
              rm -rf "$target_item"
            fi
          done < "$source_path/.templatesyncpaths"
 
          git add -A -- "$target_path"
          if git diff --cached --quiet; then
            echo 'has_changes=false' >> "$GITHUB_OUTPUT"
            exit 0
          fi
 
          template_revision="$(git -C "$source_path" rev-parse --short HEAD)"
          git config user.name 'github-actions[bot]'
          git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
          git commit -m "chore: sync SvelDocs template ($template_revision)"
          git push --force-with-lease origin "$branch"
 
          echo 'has_changes=true' >> "$GITHUB_OUTPUT"
          echo "branch=$branch" >> "$GITHUB_OUTPUT"
 
      - name: Create update pull request
        if: steps.sync.outputs.has_changes == 'true'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          HEAD_BRANCH: ${{ steps.sync.outputs.branch }}
        run: |
          open_prs="$(
            gh pr list \
              --state open \
              --base "$GITHUB_REF_NAME" \
              --head "$HEAD_BRANCH" \
              --json number \
              --jq 'length'
          )"
          if [[ "$open_prs" != '0' ]]; then
            exit 0
          fi
 
          gh pr create \
            --base "$GITHUB_REF_NAME" \
            --head "$HEAD_BRANCH" \
            --title 'chore: sync SvelDocs template updates' \
            --body "Sync template-owned infrastructure from \`BranDenn/SvelDocs\` into \`$SVELDOCS_PATH\`.
 
          Review the changes and resolve any conflicts before merging. Site content,
          configuration, branding, styling, and workflow files are not managed."
.yml

Change The Schedule

The default cron expression runs at 09:00 UTC every Monday:

.github/workflows/template-sync.yml
on:
	schedule:
		- cron: '0 9 * * 1'
	workflow_dispatch:
.yaml

Change the final number to choose another day: 0 or 7 is Sunday, 1 is Monday, and 6 is Saturday. For example, use '0 9 * * 5' to check every Friday at 09:00 UTC. GitHub Actions schedules use UTC and may start later during periods of high demand.

To disable scheduled checks and keep only the Run workflow button, replace the trigger with:

.github/workflows/template-sync.yml
on:
	workflow_dispatch:
.yaml

What Gets Updated

Update pull requests include shared application code, routes, Markdown processing plugins, dependencies, and build configuration.

The .templatesyncpaths file explicitly lists the template-owned files and directories that can be changed:

.templatesyncpaths
# Framework directories
 
plugins/
src/lib/components/
src/lib/docs/
src/lib/markdown/
src/params/
src/routes/
src/types/
 
# Framework entry points and configuration
 
src/app.d.ts
src/app.html
src/lib/utils.ts
eslint.config.js
package.json
bun.lockb
svelte.config.js
tsconfig.json
vite.config.ts
 
# Keep this ownership manifest in downstream repositories
 
.templatesyncpaths
.txt

Everything outside that list remains untouched, including documentation content, site configuration, styling, environment files, and unrelated monorepo applications. Files removed from a managed directory in the template are also removed from that directory in the update pull request.

Preserve Custom Files

Use .templatesyncignore for site-specific files that are located inside a managed directory. Paths are relative to the SvelDocs app, regardless of whether SVELDOCS_PATH is . or docs:

.templatesyncignore
# Site-specific navigation and branding
 
src/lib/docs/server/navigation/doc-navigation.config.ts
src/lib/components/docs/header/header-logo.svelte
src/lib/components/logo/
.txt

For example, use src/lib/docs/server/navigation/doc-navigation.config.ts, not docs/src/lib/docs/server/navigation/doc-navigation.config.ts, when the app is under docs. Add one exact file or directory path per line. The workflow preserves those paths when synchronizing their parent directories.

The default exclusions protect the navigation configuration, header logo wrapper, and shared logo component. Add other locally customized files before running the workflow. Because .templatesyncignore is downstream-owned, template update pull requests do not replace it.

Workflow Updates

GitHub does not allow GITHUB_TOKEN to create or update files under .github/workflows. Those files are therefore excluded from template update pull requests.

Compare your workflow files with the SvelDocs template workflows when release notes call out workflow changes. This includes updates to the GitHub Pages deployment workflow and the template sync workflow itself.