diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8748ac..0aba258 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,10 +67,49 @@ jobs: uv run ruff check tests/unit/test_probe.py rm demo_lib/probe.py tests/unit/test_probe.py + # A library takes template changes with `copier update`, so a change has to + # arrive that way too: a render of master, updated to this commit, has to + # come out exactly as a fresh render of this commit. + update: + name: copier update brings the change into a render of master + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + - uses: astral-sh/setup-uv@v7 + + - name: Update a render of master to this commit + run: | + git fetch --no-tags origin master:refs/heads/ci-base + git branch -f ci-head HEAD + if ! git cat-file -e 'ci-base:template/{{_copier_conf.answers_file}}.jinja' 2>/dev/null; then + echo "A render of master has no answers file to update from." + exit 0 + fi + render() { + uvx --from copier==9.19.1 --with jinja2-time==0.2.0 copier copy --quiet --defaults --trust --vcs-ref "$1" \ + --data project_name=demo-lib \ + --data project_slug=demo-lib \ + --data package_name=demo_lib \ + --data project_description="Demo library rendered from the template" \ + --data author_name="Bedrock Python" \ + --data author_email="maintainers@example.com" \ + "$GITHUB_WORKSPACE" "$2" + } + render ci-base "$RUNNER_TEMP/updated" + render ci-head "$RUNNER_TEMP/fresh" + cd "$RUNNER_TEMP/updated" + git init -q -b master + git add -A + git -c user.name=ci -c user.email=ci@example.com commit -q -m "render of master" + uvx --from copier==9.19.1 --with jinja2-time==0.2.0 copier update --quiet --defaults --trust --vcs-ref ci-head + diff -r --exclude=.git "$RUNNER_TEMP/fresh" "$RUNNER_TEMP/updated" + all-checks-passed: name: All checks passed if: always() - needs: [render] + needs: [render, update] runs-on: ubuntu-latest steps: - name: Every job above succeeded diff --git a/README.md b/README.md index 641ad7b..e1264b7 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,24 @@ Then: 4. Set up PyPI Trusted Publisher at pypi.org/manage/account/publishing/ 5. Add `CODECOV_TOKEN` secret in repo Settings → Secrets → Actions +## Pulling template changes into a library + +A render records its answers and the template commit it came from in +`.copier-answers.yml`. Commit that file and leave it to Copier. To bring a library up to +the template's `master`, from the library's clean working tree: + +```bash +uvx --with jinja2-time copier update --trust --defaults +``` + +Copier applies what changed in the template since the recorded commit as a three-way +merge with the library's own edits, leaves conflicts as inline markers, and moves +`_commit` forward. A file the library deleted, such as the checklist, stays deleted. + +A library rendered before the answers file existed needs one written by hand first: the +answers it was rendered with, `_src_path: gh:bedrock-python/python-library-template`, +and as `_commit` the template commit it was rendered from, or the closest one. + ## For AI Agents See [`.claude/LIBRARY_CREATION.md`](.claude/LIBRARY_CREATION.md) for important rules: diff --git a/copier.yml b/copier.yml index 7cc451b..95500bd 100644 --- a/copier.yml +++ b/copier.yml @@ -45,13 +45,16 @@ _jinja_extensions: - jinja2_time.TimeExtension _tasks: - - >- - echo "Template generated. Next steps: - 1. uv sync --group dev - 2. uv run pre-commit install --hook-type commit-msg - 3. Create the GitHub repo and push (branch: master) - 4. After the first CI pass, from the template repo: - python scripts/setup_repo.py {{ github_org }}/{{ project_slug }} - 5. Configure the PyPI Trusted Publisher at pypi.org - 6. Add the CODECOV_TOKEN secret. - See NEW_LIBRARY_CHECKLIST.md for full details." + # On a copy only: `copier update` runs tasks too, and a library taking a + # template update finished these steps long ago. + - command: >- + echo "Template generated. Next steps: + 1. uv sync --group dev + 2. uv run pre-commit install --hook-type commit-msg + 3. Create the GitHub repo and push (branch: master) + 4. After the first CI pass, from the template repo: + python scripts/setup_repo.py {{ github_org }}/{{ project_slug }} + 5. Configure the PyPI Trusted Publisher at pypi.org + 6. Add the CODECOV_TOKEN secret. + See NEW_LIBRARY_CHECKLIST.md for full details." + when: "{{ _copier_operation == 'copy' }}" diff --git a/template/{{_copier_conf.answers_file}}.jinja b/template/{{_copier_conf.answers_file}}.jinja new file mode 100644 index 0000000..69141bb --- /dev/null +++ b/template/{{_copier_conf.answers_file}}.jinja @@ -0,0 +1,2 @@ +# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY +{{ _copier_answers|to_nice_yaml -}}