Skip to content

v0.11.0

Choose a tag to compare

@github-actions github-actions released this 27 Oct 19:52
· 107 commits to main since this release
Immutable release. Only release title and notes can be modified.
v0.11.0
75755da

Upgrade steps:

  • With publish_to_pypi: push the version tag and approve pypi; let python-release.yml
    create the GitHub release. It replaces release.yml and attaches the distributions
    and their provenance before publishing. Do not create the GitHub release by hand.
    If PyPI succeeds but the release job fails, delete any leftover draft and re-run
    only the release job (recovery steps).
  • Breaking: install Copier 9.19 or later (uv tool upgrade copier) before you run
    copier update. Renovate's copier manager installs the latest Copier.
  • Breaking: a web app made from an untagged main asks the new user_data question,
    which has no default, so copier update --defaults stops on it. Answer it, or pass it:
    copier update --data user_data=nothing (or browser, or accounts). Then add the
    footer and the page routing from a fresh render's src/App.tsx to yours, and
    /accessibility and /privacy (and /terms) to tests/e2e/routes.ts: an update
    leaves both files alone. Fill in the TODOs in docs/. An app on its own domain: pass
    --data site_url=https://<your domain>, or the pages name the pages.dev address.
    The weekly copier-update workflow fails until you have run this update by hand once.
  • Breaking: a private repo: pass --data public=false. The new public question
    is yes by default, so copier update --defaults, Renovate's update PR and the
    copier-update workflow add the public-repo files, including a scorecard.yml that
    fails in a private repo. With no, .github/SECURITY.md, CONTRIBUTING.md,
    CODE_OF_CONDUCT.md, pull_request_template.md, dco.yml and scorecard.yml go.
    Your license answer stays as it is.
  • A public repo: the update adds .github/CONTRIBUTING.md, CODE_OF_CONDUCT.md,
    pull_request_template.md and a dco check on pull requests from forks,
    and SECURITY.md gains a Scope section to fill in. GitHub shows .github/CONTRIBUTING.md
    before a root CONTRIBUTING.md, so if you have your own, keep one and delete the other.
  • With dependency_bot=dependabot: create a fine-grained token with read and write access
    to Contents, Pull requests and Workflows on the repo, and store it as the
    COPIER_UPDATE_TOKEN secret. Without it, the new weekly copier-update workflow opens
    an issue instead of a PR for an update that changes a workflow
    (Hearing about new releases).
  • README.md, CHANGELOG.md and the citation files (CITATION.cff, .zenodo.json,
    codemeta.json) are now your project's, and this update already leaves them alone. So
    this release's README changes don't arrive, such as the badges for the options you
    turned on and the Releasing section. Diff your README against a fresh render with your
    answers and copy the parts you want.
  • Breaking: if a ruleset or branch protection requires the lint, types, tests check
    (lint, types, pipeline, tests in a data-pipeline project), switch it to the new
    name: python: lint, types, tests (python: lint, types, pipeline, tests) or
    ts: lint, types, tests. A library runs one per Python version, named
    python: lint, types, tests (3.12) and so on. Until then, pull requests wait on a
    check that never reports.
  • Run just repo-settings once after the update, and in a new project after the first
    push. It protects main and the v* tags and, in a public repo, turns on private
    vulnerability reporting, which SECURITY.md points to. main then requires the git hooks,
    pull request title, dependency review and, in a public repo, DCO sign-off checks: if
    you renamed any of those jobs, edit .github/rulesets/main.json first (in a public repo,
    main-checks.json), or pull requests wait on a check that never reports. In a public
    repo, main also requires an approval from now on; as the repo admin you can merge your
    own pull requests by ticking the bypass box in the merge box.
  • Run prek install again in each clone, so the new commit-msg hook is installed.
  • The new typos and lychee hooks run on every file in CI's git hooks job. After the
    update, run prek run --all-files typos lychee, review what typos fixed, and fix the
    dead links lychee lists, or that job fails.
  • After the update, refresh the lockfiles for your stacks and commit them: uv lock,
    pnpm install, just go-sync. This release bumps dev tools in every stack, and CI
    installs with --locked and --frozen-lockfile.
  • A TypeScript library with publish_to_npm: after the update, run just ts-api and
    commit <package>.api.md. The template's copy describes the sample add function, not
    your exports, so CI fails until you do.
  • With dependency_bot=renovate: turn Dependabot security updates off
    (gh api -X DELETE repos/OWNER/REPO/automated-security-fixes), or each security fix
    arrives as two PRs. Keep Dependabot alerts on: Renovate's security PRs need them.
  • Breaking: in a Go library made with v0.10.0 or earlier, copier update deletes
    <package>_test.go without asking, your changes to it included, and adds
    add_test.go. Before you commit the update, run git checkout HEAD -- <package>_test.go
    (after committing it, git checkout HEAD~1 -- <package>_test.go). Then delete
    add_test.go, or the two TestAdd functions stop the tests compiling. With
    test_extras=[property], first copy FuzzAdd from add_test.go into your test file.
  • In a Python or TypeScript library, the new sample add function arrives as a conflict
    in src/<module>/__init__.py or src/index.ts: keep your own side. Then delete
    tests/test_add.py, and the add import and test the update merged into
    src/index.test.ts, or those tests fail.
  • In a data-pipeline project (see the two Breaking changes below):
    • src/<module>/pipeline.py becomes a short file that imports sourceledger. If you
      added readers to parse, keep only your own branches, end it with
      return sourceledger.parse_source(source, payload), and keep the imports your
      branches need: the new file no longer imports csv or io.
    • Take the new tests/test_pipeline.py, and keep any tests of your own readers.
    • pyproject.toml gains the sourceledger dependency. Keep any dependencies of your
      own next to it, where copier update can't merge the two lists.
    • In sources.toml, rename release to vintage (the old key still works, with a
      warning). Give each implemented source a license (an SPDX id, or
      LicenseRef-<name>) and redistribute = true or false. Rename any source id with
      a non-ASCII letter: only ASCII letters, digits, _ and - are accepted.
    • Run just pipeline. just validate reports a missing datapackage.json until
      just build has written one.
  • Breaking: python-release.yml and ts-release.yml now run when a vX.Y.Z tag is
    pushed, not when a GitHub release is published. Add the ## [X.Y.Z] section to
    CHANGELOG.md before you tag. The release workflow reads that section and fails
    when it is missing. Releases created by GITHUB_TOKEN don't start other
    workflows, so the publish workflows could not follow the release.

Added

  • Weekly Go property runs cache generated fuzz inputs so each run resumes the
    coverage the previous runs found.
  • Copier and howfairis workflow pins follow template updates. Renovate tracks their
    versions in the template, so they no longer need separate manual bumps.
  • The code of conduct tells readers that a report about the maintainer can go to GitHub
    instead, through Report abuse.
  • An openssf_badge question, asked in a public repo with a license, for the
    OpenSSF Best Practices badge. passing adds a test
    policy and each stack's coding standards to .github/CONTRIBUTING.md. silver also
    adds GOVERNANCE.md, docs/roadmap.md and docs/assurance-case.md, short skeletons
    you fill in and then own. It defaults to none, so an update changes nothing unless
    you pass --data openssf_badge=passing (or silver).
  • A cold-install.yml workflow runs the shell blocks under the README's ## Development
    heading as written, in a Debian container with only the tools the README says you
    need, so a setup step the README leaves out fails in CI. It runs weekly and on pull
    requests that change README.md. It skips just up, just pipeline, just ts-e2e
    and the mutation and property recipes, which need Docker, a browser, live sources or hours.
    Your README stays yours on copier update, so the job runs whatever it says now.
  • Spelling and link checks. A typos git hook finds misspelt words and a lychee hook
    finds relative links to missing files in Markdown and HTML. The lychee hook runs
    offline, so a new weekly links.yml workflow checks the web links too. List a word
    typos must leave alone in _typos.toml (Spelling and link checks).
  • A short AGENTS.md in every project, for coding agents: the just check command, each
    stack's test recipe and where the docs are. It names only recipes the project's
    justfile has.
  • Commit message rules in committed.toml: Conventional Commits, an imperative summary,
    no period. A committed commit-msg hook checks each commit, skipping merge
    commits, and a new pr-title.yml workflow checks the pull request title, which a squash
    merge turns into the commit subject. Dependabot and Renovate now write PR titles in the
    same form, chore(deps): ....
  • GPL-3.0-or-later and AGPL-3.0-or-later as license answers, with
    the GNU texts in LICENSE. These texts have no copyright line, so they don't ask
    copyright_year.
  • A python_layout question under customise, src by default. flat is for adopting
    the template in a repo whose package already sits at the root: it renders no
    src/<module> stub or tests/test_add.py, and sets module-root = "" for uv_build.
    Adopting the template in an existing Python package
    covers the rest, including a ruff and ty baseline for code written without them.
  • A docs/decisions/ folder in every project, for recording why you chose what you
    did. It holds a short record template, 0000-template.md (status, date, context,
    decision, consequences), and an index, README.md. The index is yours once written,
    so copier update leaves it alone.
  • README badges for the options you turn on: Codecov coverage (codecov), CodSpeed
    (codspeed), PyPI version and supported Python versions (publish_to_pypi), npm version
    (publish_to_npm) and OpenSSF Scorecard (public).
  • A weekly dependency audit, advisories.yml, on every Monday with a job per stack:
    uv audit, pnpm audit, cargo deny check advisories and govulncheck. Before, a repo
    with no new commits never heard of a new advisory. A failed run shows on the Actions page
    and in the failed-run email.
  • With public, an OpenSSF Scorecard workflow (scorecard.yml): it runs on pushes to
    main, weekly and when branch protection changes, publishes the score for the README
    badge and uploads the findings to code scanning. A private repo gets none. After the
    update, the first run on main publishes the score.
  • The release workflows and .github/scripts/release-notes.sh: a pushed vX.Y.Z tag becomes a
    GitHub release whose notes are that version's CHANGELOG.md section, so the two never
    differ.
  • just repo-settings protects the default branch with a GitHub ruleset (no deletion, no force-push, linear history, PRs squash-merged once the checks every PR runs have passed) from .github/rulesets/main.json, lets only a repo admin create, move or delete a v* tag (.github/rulesets/tags.json), since pushing one publishes a release, and in a public repo turns on private vulnerability reporting, which SECURITY.md points to. Rerun it any time; it updates the ruleset instead of adding a second.
  • just repo-about sets the GitHub About box from your answers with gh repo edit: the description from project_description (skipped when empty), the homepage from site_url in a web app, and a topic per stack. It only adds topics, so ones you set by hand stay. Rerun it any time.
  • With mutation in test_extras, a weekly CI run of mutation testing:
    .github/workflows/mutation.yml, one job per library stack, also startable by hand
    and never run on a pull request. Each job runs the stack's just <stack>-mutation
    recipe. The Rust job fails when a mutant survives; the others print the survivors and
    pass.
  • With property in test_extras, a weekly CI run of the property tests at length:
    .github/workflows/property.yml, one job per library stack, also startable by hand
    and never run on a pull request. Each job runs a new recipe you can also run by hand:
    just py-property (Hypothesis, 10,000 examples a property), just ts-property
    (fast-check, 10,000 runs), just rs-property (proptest, 10,000 cases) or
    just go-property (fuzzes FuzzAdd for 10 minutes). A failing input fails the job. A Python
    library gains tests/conftest.py, which registers the Hypothesis profile.
  • A public question, yes by default. No leaves out .github/SECURITY.md,
    CONTRIBUTING.md, CODE_OF_CONDUCT.md, pull_request_template.md and dco.yml, and makes
    none the license default. See Public repos.
  • CONTRIBUTING.md says where to report a bug, states the commit, pull request and
    changelog conventions, asks for a DCO sign-off on every commit and says who maintains the
    project. CODE_OF_CONDUCT.md is the Contributor Covenant 3.0, with the author email as
    the contact. A dco.yml workflow fails a pull request from a fork with a commit that isn't signed off.
  • SECURITY.md says what to include in a report, promises an answer within 14 days, says
    how a fix is disclosed, and has a scope section to fill in.
  • A customise question, no by default, ahead of the advanced questions: license,
    directories, versions, module names, Codecov, CodSpeed, the dependency bot,
    publishing, test extras, the port and the site URL. A new Python library, TypeScript web app or data pipeline now
    asks 10 questions, or 11 for a web app, down from 18, 14 and 15. Every question says what it changes.
    The questions lists them with their defaults.
  • copier copy says where your details can be saved before it asks, and lists the
    just commands to run after it.
  • A codspeed option for the Python and Rust stacks: a benchmarks.yml workflow runs
    benchmarks on CodSpeed for every pull request and every push to main, with a starter
    benchmark per stack (pytest-codspeed, and divan through codspeed-divan-compat). Import
    the repository on codspeed.io and set Pull Request comments to "On Change" there; see
    usage.
  • A web-app TypeScript kind: a Vite single-page app with React or Preact (the new
    web_framework question), deployed by Cloudflare Pages' Git integration. The docker
    stack builds no image for it, since it is static files.
    • Playwright specs run against the production build, in ts.yml's e2e job and with
      just ts-e2e. They check every route with axe in light and dark mode (WCAG 2.2 AA
      and axe's best-practice rules) and at 320 px wide (reflow), and check that the app
      runs under the Content-Security-Policy in public/_headers, which allows no inline
      script. Removing any security header from that file fails the check.
    • just check and CI enforce a bundle budget, set in scripts/checkBundleBudget.mjs,
      and a pre-push hook runs the unit tests.
    • The e2e run always starts its own preview server, on port 4173, and fails if the
      port is taken, so it can't test another app's server instead.
    • Adopting the template in an existing web app
      lists the files a first copier copy --overwrite adds or replaces, and how to
      install a lockfile resolved before the one-week release wait.
    • The starter files (src/App.tsx, src/App.test.tsx, src/main.tsx, src/app.css,
      index.html and tests/e2e/routes.ts) belong to the project once written:
      copier update never touches them again.
  • A test_extras question for the library kinds, empty by default. property adds a
    property test of the sample add function: Hypothesis, fast-check, proptest, or a
    native Go FuzzAdd. mutation adds a just <stack>-mutation recipe to run by hand:
    mutmut, Stryker, cargo-mutants or gremlins. See Test extras.
    Python and TypeScript libraries now ship the sample add, as Rust and Go already did.
  • With the docker stack, docker.yml scans each built image with Trivy for HIGH and
    CRITICAL vulnerabilities that have a fix, and rebuilds and scans the image every Monday
    without pushing it. Pull requests and pushes show the findings in the job log; only the
    weekly run fails on them. The job that pushes to GHCR runs no scan, so it reads no
    cache on a tag.
  • In a data-pipeline project:
    • data/fetches.jsonl is committed and gets a line each time a source serves bytes it
      has not served before: the history of every version, as checksums, not values.
    • The weekly CI run comments on an open "Source data revised upstream" issue when a
      source in that file serves new bytes, with the old and new checksums. Only that job
      may write issues. uv run <slug> revisions <older log> prints the same list locally.
    • just status lists every source with its vintage, last fetch and licence, and
      just attribution prints the sources and their reuse terms as a Markdown table for
      ATTRIBUTION.md.
  • just fmt runs each stack's fix-and-format recipe, the counterpart of just check.
  • Dependabot groups npm security updates into one pull request instead of one per
    advisory.
  • VS Code formats .tsx, .jsx and .css files with Biome, and the Biome hook also
    checks HTML.
  • The README says how to lock a security fix that is less than a week old, which
    exclude-newer and minimumReleaseAge otherwise hold back.
  • API-break checks for libraries that publish. With publish_to_pypi, a new api job
    in python.yml runs griffe, which fails when a public function, class or argument was
    removed or changed since the last git tag, and passes while there is no tag. It stays
    out of just py-check, so a deliberate break leaves local checks green. With publish_to_npm, ts.yml and just ts-check run API Extractor, which
    fails when the built types differ from the committed <package>.api.md. just ts-api
    rewrites that report after a deliberate change, so the change shows in review.
  • A web-app has legal pages, linked from every page's footer: an accessibility
    statement at /accessibility, a privacy statement at /privacy and, with
    user_data=accounts, terms of use at /terms. Each is one Markdown file in docs/:
    GitHub shows it, and the build turns it into HTML. Its HTML comments are notes for you,
    and the build leaves them out. New e2e tests fail when a page still
    holds a TODO, when the statement says "fully conformant" or goes 400 days without a
    review, and when a first visit sets a cookie, stores anything in the browser or loads a
    file from another site. docs/web-legal.md in the template repository has tips for
    filling the pages in, linked from each page's notes (Legal pages).
  • A web-app gets docs/accessibility-assessment.md beside the accessibility statement: a
    WCAG 2.2 self-assessment with one row for each of the 55 level A and AA criteria, and a
    result and an evidence column to fill in. The app does not serve it. The statement links
    it, and may say "partially conformant" only once every row has a result. An update
    leaves your copy alone.
  • A public repo of a kind that has CITATION.cff (library, research, data-pipeline) gets
    fair.yml, which runs howfairis weekly and lists each fair-software.eu check in the job
    summary, and a fair-software.eu badge in the README. The job fails below FAIR_MIN filled
    dots out of five. A new repo has three, so that is the starting floor: raise it as you
    add a registry entry and the OpenSSF Best Practices badge, and edit the badge to match.
  • With dependency_bot: dependabot, a copier-update workflow opens a weekly PR that
    runs copier update to the newest template tag, with conflicted files listed in the
    PR body. It pushes with a COPIER_UPDATE_TOKEN secret, a fine-grained token you create.
    Without one it uses GITHUB_TOKEN, which GitHub stops from pushing workflow changes, so
    such an update opens an issue asking you to run it locally, and other update PRs start
    no CI. See
    Hearing about new releases.

Changed

  • A public repo's main ruleset requires one approving review, given after the last push,
    and a new push dismisses an earlier one. That lifts Scorecard's branch protection score
    from at most 4 to 8. A repo admin can bypass the review from the merge box. The required
    checks move to a second ruleset, main-checks, which only an admin can bypass, so a
    bypass of the review still waits for them. Rerun just repo-settings after the update to
    apply both. A private repo's ruleset is unchanged.
  • With dependency_bot=renovate, Renovate merges its own minor and patch updates of the
    packages CI installs, and the weekly relock, once their checks pass. Its app may bypass
    the review in a public repo, never the checks. Majors, copier template releases, and the
    actions and hooks group still wait for you. Dependabot PRs still never merge themselves.
  • A web app with user_data=accounts refuses code@duinlab.nl as author_email: an app
    that keeps personal data on a server needs its own contact address. Pass another
    address to copier update if you hit this.
  • copier copy keeps an existing README.md, and copier update no longer touches it.
    Template changes to the README, this release's included, reach existing projects only
    by hand.
  • A ty rule set to "warn" reports without failing ty check, the hook and
    just py-check. ty exits 1 on warnings by default; pyproject.toml now sets
    [tool.ty.terminal] error-on-warning = false.
  • In a Python project, the git hooks skip data/, so the whitespace, end-of-file and
    nbstripout hooks no longer rewrite input data and archived notebooks.
  • pnpm audit --fix=update locks a security fix that is under a week old: it adds the
    patched version to minimumReleaseAgeExclude, and the new
    minimumReleaseAgeExcludePrune drops the entry once the lockfile moves past it.
  • With dependency_bot=renovate, Renovate refreshes the lockfiles every Monday. That is
    how a security fix in a dependency of a dependency arrives, once it is a week old.
  • Breaking: the TypeScript and Python check jobs are now ts: lint, types, tests and
    python: lint, types, tests (python: lint, types, pipeline, tests in a
    data-pipeline project). Both used to be lint, types, tests, so a ruleset could not
    require one without the other. A ruleset that requires the old name needs the new one
    (see the upgrade steps).
  • With the codecov option, just check runs the TypeScript tests with coverage, as CI
    does, so a coverage threshold in the Vitest config fails locally as well as in CI.
  • Dependabot and Renovate group minor and patch bumps of runtime dependencies into one
    weekly PR, instead of one PR each. A major still gets its own PR.
  • GitHub Actions and pre-commit hook updates arrive as one weekly PR, instead of one
    each: a Dependabot multi-ecosystem group, and one Renovate group. Fewer PRs means fewer
    branches to bring up to date in turn where main requires it.
  • With the codecov option, Codecov no longer comments on pull requests. Any line left
    untested drew a comment. A drop of over 2 points still fails the codecov/project
    check, which links to the report.
  • Breaking: a data-pipeline project gets its fetch, build, validate and revisions
    stages from the sourceledger
    package instead of about 400 copied lines in pipeline.py. Fixes now arrive as a
    dependency bump, not a copier update merge. pipeline.py keeps only parse.
    • parse reads CSV, JSON and Excel sources, gzipped or not, by each source's format
      or its URL's extension. just build also writes a datapackage.json.
    • A fetch asks the server whether the file changed (If-None-Match,
      If-Modified-Since) and keeps the record on a 304, unless the raw file was edited or
      no longer matches its pinned sha256. It waits at most 2 minutes for a
      429's Retry-After, and a fetch that fails after its retries names the source and
      its URL.
    • The manifest names the edition vintage, as the fetch record and the output column
      already did. sources.toml has a schema line for editors, pinned to sourceledger
      v0.2.0, and its comments cover every key. The example source is pinned to a
      datasets/co2-ppm commit, so CI and the tripwire tests no longer follow a moving
      branch.
  • Breaking: just validate in a data-pipeline project needs each implemented source
    to state license (an SPDX id) and redistribute (whether the raw file may be
    republished), beside terms. The free-text terms stay for people; these two are for a
    release step to check.
  • go.mod is written once and then belongs to the project, like CHANGELOG.md. Before,
    every copier update conflicted with what go mod tidy had written there. To raise the
    minimum Go version, run go mod edit -go=<version>.
  • copier update no longer touches CITATION.cff, .zenodo.json or codemeta.json once
    they exist, so a release that adds its version, date or DOI to them no longer conflicts
    with every update. Template changes to these files, this release's included, reach
    existing projects only by hand.
  • Web-service projects test with httpx2, which Starlette's test client now prefers,
    instead of httpx, and require Starlette 1.2.0 or later. The pytest filter that hid
    Starlette's deprecation warning is gone.
  • A new Python release becomes the default python_version 90 days after it comes out,
    once the packages projects install have wheels for it.
  • The generated README lists the tools the project needs (uv only where it's used), puts
    just hooks next to just check, says that just check doesn't build the Docker
    image, and, with a publish option, has a Releasing section on setting up the publishing
    environment first.
  • The workflow linter hook runs jactionlint, a maintained fork of actionlint. It adds
    checks for releases, caches and concurrency, so a workflow you wrote yourself may get new
    findings.
  • A library's release workflow runs its wheel tests with the test tools from uv.lock,
    hash-checked, and turns on uv's malware check as python.yml does.
  • python-release.yml and ts-release.yml run one release per tag at a time.
  • The docker workflow cancels a superseded run only on a pull request, so a push to main
    or a tag is never stopped halfway through pushing an image. A tag build doesn't restore
    the shared build cache, so a poisoned cache entry can't reach a release image; release
    builds take longer as a result. When every image builds from a subdirectory, the
    workflow runs only when a build context or the workflow changes, so a required build
    check stays pending on a pull request that touches neither.
  • The Docker image of a data-pipeline project is documented as a stub: it has no
    sources.toml or data/, and it starts the /health placeholder.
  • Python projects accept uv_build 0.13 as their build backend. The 0.12.19 floor stays,
    so older uv versions still build them.
  • With dependency_bot: renovate, Renovate's copier manager opens a PR for each new
    template release. Before, the one-week release age held those PRs back for good, because
    template tags carry no release date. The docs say how Dependabot users hear about
    releases.

Fixed

  • The typos hook skips .copier-answers.yml. The template commit id Copier writes there
    could spell a word typos rejects and fail the hook after a copier update.
  • A project description with """, */ or a line break is refused. It
    broke the Python docstring or the Go and TypeScript comments it lands in.
  • With dependency_bot: renovate, the comments in pyproject.toml, pnpm-workspace.yaml
    and .pre-commit-config.yaml no longer say Dependabot waits the week or moves the hook
    SHAs.
  • The README of a TypeScript project names Node.js among the tools you need.
  • The weekly scheduled run and a push to main no longer cancel each other in
    python.yml and docker.yml. A cancelled weekly run used to skip that week's tripwire
    tests in a data-pipeline project.
  • Copier refuses answers that rendered a broken project: a project name that is a Go,
    Rust or Python keyword (such as type, gen or lambda), an empty stacks list, an
    empty *_dir, a rust_version below 1.85 (the template uses edition 2024), and an
    app_port outside 1 to 65535, or 65535 when two images publish ports. A Go binary no
    longer needs a project name that can be a Go package name.
  • The check-yaml hook no longer fails on pnpm-lock.yaml. pnpm 12 writes its own
    version into the lockfile as a second YAML document, so every TS project failed its
    checks workflow once the lockfile was committed.
  • A name or email with a quote in it, such as Ada "X" Lovelace, no longer breaks the
    generated pyproject.toml, package.json or Cargo.toml. A leading space in the
    author name no longer leaves the given name empty in the citation files.
  • The ts and stdlib Python starter servers in the Docker image stop on SIGTERM. As PID 1
    they ignored it, so docker stop waited 10 seconds and then killed them.
  • A Go library named example no longer loses its TestAdd: the unit test is now
    add_test.go, which can't share a path with example_test.go.
  • The image .dockerignore files match .env, .venv and node_modules in any
    directory, so another stack's secrets stay out of the build context when a package sits
    at the repo root.
  • .gitignore names a Go binary without a trailing major version, as go build does for
    a module path ending in /v2.
  • With a Rust crate below the repo root, .vscode/settings.json sets
    rust-analyzer.linkedProjects, so the editor finds a crate two levels deep.

Security

  • The weekly Copier updater renders in a read-only job. A fresh job applies only
    the patch before pushing, so Copier's dependencies cannot alter the runner that
    holds the update token.
  • With publish_to_ghcr, the image push job runs in a ghcr environment, as PyPI and npm
    releases already do. Limit it to main and v* tags with a required reviewer in the
    repository's settings (see the README's Releasing section); until then GitHub creates it
    unprotected and pushes as before.
  • A library's PyPI release signs a GitHub build-provenance attestation for each file in
    dist/, so users can check where a wheel was built with gh attestation verify. It is
    made in the publish job, which runs no project code.
  • The hooks job installs a set prek version, 0.5.5, instead of the newest one on each run,
    and gives the read-only GitHub token to the zizmor hook only.