-
Notifications
You must be signed in to change notification settings - Fork 0
169 lines (141 loc) · 6.14 KB
/
template-sync.yml
File metadata and controls
169 lines (141 loc) · 6.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# Inspired by serpro69/claude-starter-kit template-sync approach
name: Template Sync
on:
workflow_dispatch:
inputs:
dry_run:
description: "Show changes without creating a PR"
type: boolean
default: false
template_repo:
description: "Upstream template repository (owner/repo)"
type: string
default: "stranma/claude-code-python-template"
template_branch:
description: "Upstream template branch"
type: string
default: "master"
schedule:
- cron: "0 9 * * 1" # Weekly on Monday at 09:00 UTC
permissions:
contents: write
pull-requests: write
jobs:
sync:
name: Sync from upstream template
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Determine template repo
id: config
run: |
REPO="${{ inputs.template_repo || 'stranma/claude-code-python-template' }}"
BRANCH="${{ inputs.template_branch || 'master' }}"
echo "repo=${REPO}" >> "$GITHUB_OUTPUT"
echo "branch=${BRANCH}" >> "$GITHUB_OUTPUT"
echo "Syncing from ${REPO}@${BRANCH}"
- name: Add upstream remote and fetch
run: |
git remote add upstream "https://github.com/${{ steps.config.outputs.repo }}.git" || true
git fetch upstream "${{ steps.config.outputs.branch }}"
- name: Compute template diff
id: diff
env:
UPSTREAM_BRANCH: ${{ steps.config.outputs.branch }}
run: |
# Paths managed by the template (synced from upstream)
# Defined once here; reused in the apply step via GITHUB_OUTPUT
TEMPLATE_PATHS=".claude/agents/ .claude/commands/ .claude/hooks/ .claude/rules/ .claude/skills/ .devcontainer/ .github/workflows/ docs/DEVELOPMENT_PROCESS.md"
echo "template_paths=${TEMPLATE_PATHS}" >> "$GITHUB_OUTPUT"
# Get changed files between local and upstream
CHANGED=$(git diff --name-only HEAD "upstream/${UPSTREAM_BRANCH}" -- ${TEMPLATE_PATHS} 2>/dev/null || true)
if [ -z "$CHANGED" ]; then
echo "No template changes found"
echo "has_changes=false" >> "$GITHUB_OUTPUT"
else
echo "Template changes detected:"
echo "$CHANGED"
echo "has_changes=true" >> "$GITHUB_OUTPUT"
# Store diff summary for PR body
DIFF_STAT=$(git diff --stat HEAD "upstream/${UPSTREAM_BRANCH}" -- ${TEMPLATE_PATHS} 2>/dev/null || true)
{
echo "diff_stat<<EOF"
echo "$DIFF_STAT"
echo "EOF"
} >> "$GITHUB_OUTPUT"
fi
- name: Show diff (dry run)
if: steps.diff.outputs.has_changes == 'true' && (inputs.dry_run == true || inputs.dry_run == 'true')
run: |
echo "=== DRY RUN: Changes that would be synced ==="
echo "${{ steps.diff.outputs.diff_stat }}"
- name: Apply template changes
id: apply
if: steps.diff.outputs.has_changes == 'true' && inputs.dry_run != true && inputs.dry_run != 'true'
env:
UPSTREAM_BRANCH: ${{ steps.config.outputs.branch }}
TEMPLATE_PATHS: ${{ steps.diff.outputs.template_paths }}
run: |
SYNC_BRANCH="template-sync/$(date +%Y%m%d)"
# Check if branch already exists
if git rev-parse --verify "refs/heads/${SYNC_BRANCH}" > /dev/null 2>&1; then
echo "Sync branch ${SYNC_BRANCH} already exists, updating"
git checkout "${SYNC_BRANCH}"
else
git checkout -b "${SYNC_BRANCH}"
fi
# Checkout template-managed files from upstream
for path in ${TEMPLATE_PATHS}; do
git checkout "upstream/${UPSTREAM_BRANCH}" -- "${path}" 2>/dev/null || true
done
# Stage and commit
git add -A
if git diff --cached --quiet; then
echo "No changes to commit after checkout"
echo "changes_applied=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "changes_applied=true" >> "$GITHUB_OUTPUT"
git commit -m "chore: sync template from upstream
Source: ${{ steps.config.outputs.repo }}@${{ steps.config.outputs.branch }}"
git push -u origin "${SYNC_BRANCH}"
echo "sync_branch=${SYNC_BRANCH}" >> "$GITHUB_ENV"
- name: Create pull request
if: steps.apply.outputs.changes_applied == 'true' && inputs.dry_run != true && inputs.dry_run != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Check for existing PR from this branch
EXISTING_PR=$(gh pr list --head "${{ env.sync_branch }}" --json number --jq '.[0].number' 2>/dev/null || true)
if [ -n "$EXISTING_PR" ]; then
echo "PR #${EXISTING_PR} already exists for this sync branch"
exit 0
fi
gh pr create \
--title "chore: sync upstream template changes" \
--body "$(cat <<'EOF'
## Template Sync
Automated sync of template-managed files from upstream.
**Source:** ${{ steps.config.outputs.repo }}@${{ steps.config.outputs.branch }}
### Changed files
```
${{ steps.diff.outputs.diff_stat }}
```
### What to review
- Check if any synced files conflict with project-specific customizations
- Template-managed paths: `.claude/`, `.devcontainer/`, `.github/workflows/`, `docs/DEVELOPMENT_PROCESS.md`
- Project-specific files (`apps/`, `libs/`, `tests/`, `pyproject.toml`, `README.md`) are NOT touched
### How to resolve conflicts
If a synced file conflicts with local changes, edit the file on this branch to keep your customizations, then merge.
EOF
)"
- name: Summary
if: steps.diff.outputs.has_changes == 'false'
run: echo "Already up to date with upstream template. No sync needed."