1- name : Template Update
1+ name : Template Update
22
33on :
44 workflow_call :
55 inputs :
66 template_repo :
7- description : ' URL of the Cookiecutter template repo '
7+ description : ' HTTPS URL or owner/repo of the Cookiecutter template (e.g., https://github.com/your-org/Project.Cookiecutter or your-org/Project.Cookiecutter) '
88 required : true
99 type : string
1010 repo_branch :
11- description : ' Branch of the project repo to update'
11+ description : ' Branch of the caller repo to update (e.g., main) '
1212 required : true
1313 type : string
1414
@@ -17,11 +17,14 @@ permissions:
1717 pull-requests : write
1818
1919jobs :
20- template-update :
20+ update :
21+ name : Update from Cookiecutter Template
2122 runs-on : ubuntu-latest
23+ env :
24+ TEMPLATE_TOKEN : ${{ secrets.TEMPLATE_REPO_TOKEN != '' && secrets.TEMPLATE_REPO_TOKEN || github.token }}
2225
2326 steps :
24- - name : Checkout project repo
27+ - name : Checkout caller repository
2528 uses : actions/checkout@v4
2629 with :
2730 ref : ${{ inputs.repo_branch }}
@@ -32,15 +35,21 @@ jobs:
3235 with :
3336 python-version : ' 3.x'
3437
35- - name : Install Cookiecutter
38+ - name : Install Cookiecutter (and jq if missing)
3639 shell : bash
3740 run : |
41+ set -euo pipefail
3842 python -m pip install --upgrade pip
39- pip install cookiecutter
43+ pip install "cookiecutter==2.6.0"
44+ if ! command -v jq >/dev/null 2>&1; then
45+ sudo apt-get update
46+ sudo apt-get install -y jq
47+ fi
4048
4149 - name : Verify tools
4250 shell : bash
4351 run : |
52+ set -euo pipefail
4453 cookiecutter --version
4554 jq --version
4655 git --version
@@ -62,20 +71,46 @@ jobs:
6271 echo "sha=$OLD_SHA" >> "$GITHUB_OUTPUT"
6372 echo "Detected OLD template sha: $OLD_SHA"
6473
65- - name : Discover NEW template SHA from template HEAD
66- id : new_sha
74+ - name : Parse template repo slug
75+ id : repo
6776 shell : bash
68- env :
69- GITHUB_TOKEN : ${{ github.token }}
7077 run : |
7178 set -euo pipefail
72- # Use token header so private repos work (HTTPS URLs recommended)
73- AUTH="AUTHORIZATION: bearer $GITHUB_TOKEN"
74- NEW_SHA="$(git -c http.extraheader="$AUTH" ls-remote '${{ inputs.template_repo }}' HEAD | awk '{print $1}')"
75- if [ -z "$NEW_SHA" ]; then
76- echo "::error ::Unable to resolve HEAD SHA from ${{ inputs.template_repo }}"
79+ INPUT="${{ inputs.template_repo }}"
80+ if [[ "$INPUT" =~ ^https?://github\.com/ ]]; then
81+ # Extract owner/repo from URL (strip optional .git)
82+ SLUG="$(echo "$INPUT" | sed -E 's#^https?://github\.com/([^/]+/[^/]+)(\.git)?$#\1#')"
83+ else
84+ SLUG="$INPUT"
85+ fi
86+ if [[ ! "$SLUG" =~ ^[^/]+/[^/]+$ ]]; then
87+ echo "::error ::Unable to parse owner/repo from '${{ inputs.template_repo }}'"
7788 exit 1
7889 fi
90+ echo "slug=$SLUG" >> "$GITHUB_OUTPUT"
91+ echo "Template repo slug: $SLUG"
92+
93+ - name : Checkout template at OLD SHA (base-template)
94+ uses : actions/checkout@v4
95+ with :
96+ repository : ${{ steps.repo.outputs.slug }}
97+ ref : ${{ steps.old_sha.outputs.sha }}
98+ token : ${{ env.TEMPLATE_TOKEN }}
99+ path : base-template
100+
101+ - name : Checkout template at default branch HEAD (new-template)
102+ uses : actions/checkout@v4
103+ with :
104+ repository : ${{ steps.repo.outputs.slug }}
105+ token : ${{ env.TEMPLATE_TOKEN }}
106+ path : new-template
107+
108+ - name : Discover NEW template SHA from new-template HEAD
109+ id : new_sha
110+ shell : bash
111+ run : |
112+ set -euo pipefail
113+ NEW_SHA="$(git -C new-template rev-parse HEAD)"
79114 echo "sha=$NEW_SHA" >> "$GITHUB_OUTPUT"
80115 echo "Discovered NEW template sha: $NEW_SHA"
81116
@@ -94,30 +129,6 @@ jobs:
94129 if : env.SHA_CHANGED == 'false'
95130 run : echo "Nothing to do."
96131
97- - name : Clone template at OLD SHA
98- if : env.SHA_CHANGED == 'true'
99- shell : bash
100- env :
101- GITHUB_TOKEN : ${{ github.token }}
102- run : |
103- set -euo pipefail
104- AUTH="AUTHORIZATION: bearer $GITHUB_TOKEN"
105- git -c http.extraheader="$AUTH" clone '${{ inputs.template_repo }}' base-template
106- git -C base-template checkout '${{ steps.old_sha.outputs.sha }}'
107- git -C base-template rev-parse --short HEAD
108-
109- - name : Clone template at NEW SHA
110- if : env.SHA_CHANGED == 'true'
111- shell : bash
112- env :
113- GITHUB_TOKEN : ${{ github.token }}
114- run : |
115- set -euo pipefail
116- AUTH="AUTHORIZATION: bearer $GITHUB_TOKEN"
117- git -c http.extraheader="$AUTH" clone '${{ inputs.template_repo }}' new-template
118- git -C new-template checkout '${{ steps.new_sha.outputs.sha }}'
119- git -C new-template rev-parse --short HEAD
120-
121132 - name : Extract cookiecutter extra context
122133 if : env.SHA_CHANGED == 'true'
123134 id : ctx
@@ -165,13 +176,11 @@ jobs:
165176 mkdir -p template-new
166177 mv "${GEN[0]}"/* template-new/
167178
168-
169179 - name : Build update patch
170180 if : env.SHA_CHANGED == 'true'
171181 shell : bash
172182 run : |
173183 set -euo pipefail
174- # Reduce EOL/whitespace surprises
175184 git config core.autocrlf false
176185 git config apply.whitespace nowarn
177186
@@ -205,8 +214,6 @@ jobs:
205214 fi
206215 fi
207216 echo "::endgroup::"
208-
209- # Stage whatever was applied
210217 git add -A
211218
212219 - name : Bump cookiecutter.template_sha
@@ -255,9 +262,8 @@ jobs:
255262 - New template SHA: \`${{ steps.new_sha.outputs.sha }}\`
256263
257264 If apply mode was 'rejects', download the 'template-update-rejects' artifact to resolve \`.rej\` files, then push fixes to this branch."
258-
259265 gh pr create \
260266 --title "chore: merge template updates ${{ steps.old_sha.outputs.sha }} → ${{ steps.new_sha.outputs.sha }}" \
261267 --body "$BODY" \
262268 --base '${{ inputs.repo_branch }}' \
263- --head "$BRANCH"
269+ --head "$BRANCH"
0 commit comments