Repository navigation
Description
Background
#199 factored the shared test/collateral setup into a reusable test-suite.yml (reusable workflows having been chosen over composite actions per the discussion in #162 / #163). For most consumers this is a clear win: main.yml shrinks to thin uses: calls, and the shared steps + env live in one place.
For heavily-customized downstreams it's a harder fit. setuptools is the motivating case. Its test job interleaves a lot of project-specific work with the shared steps:
- pre-building the sdist/wheel and exporting
PRE_BUILT_SETUPTOOLS_* - a cached download of setupcfg examples
SETUPTOOLS_USE_DISTUTILSand a pypycontinue-on-error- publishing coverage
Plus two jobs that can't use the reusable workflow at all: test_cygwin (every step runs under a Cygwin bash shell) and integration (separate, tag-gated).
The friction
-
You can't inject steps into a reusable workflow. A calling job may only set
uses/with/secrets/needs/if/strategy/permissions— neversteps. So setuptools can't "call the shared workflow and add its pre-build steps"; the custom steps have nowhere to live in the caller. -
So the only way to keep the pattern is to fork
test-suite.ymland add the project steps there, gated by an input (setuptools uses afull-testflag). But that customizes the skeleton's own shared file — the one the skeleton will keep iterating on — so every future skeleton update totest-suite.ymlnow conflicts. It inverts the usual "customizemain.yml, inherittest-suite.yml" contract. -
Env can't be shared with decoupled jobs. A called reusable workflow doesn't inherit the caller's top-level
env:, andtest_cygwin/integrationcan't call it, so the shared env block (FORCE_COLOR,PIP_*,TOX_OVERRIDE) ends up duplicated acrosstest-suite.ymland each decoupled job.
setuptools' current resolution (in the pending skeleton merge) is Option-D-style: a forked test-suite.yml with a full-test input gating the setuptools-specific steps, and test_cygwin/integration decoupled with duplicated env. It works, but it accepts (2) and (3).
Question
Could the skeleton offer extension points so a downstream can customize without forking test-suite.yml? A couple of directions:
- Convention hooks —
test-suite.ymlruns a downstream-provided script at a well-known path if it exists (e.g. a pre-tox./.github/pre-testand/or a post-tox hook). Degenerate/no-op by default; setuptools would move its pre-build / download-cache logic into such a script, keepingtest-suite.ymlupstream-pristine. - Composite actions for the genuinely shared concerns (setup-python + tox; publish-coverage) that both
test-suite.ymland decoupled jobs liketest_cygwincould call — which would also address the env/coverage duplication in (3). (Acknowledging the composite-action tradeoffs already raised in tests and collateral share some behavior implicitly #162 — collapsed/ugly log output in particular.)
Curious whether hooks, composites, or "downstreams just fork test-suite.yml and own it" is the intended story for cases like setuptools.
Activity
jaraco commentedon Aug 2, 2026
Recording an analysis + recommendation here to shelve for later; setuptools has landed the Option-D workaround (forked
test-suite.ymlwith afull-testinput;test_cygwin/integrationdecoupled with duplicated env).Residual duplication in Option D as shipped
FORCE_COLOR/PIP_*/TOX_OVERRIDE)test-suite.yml,test_cygwin,integrationtest-suite.yml,test_cygwintest-suite.ymlThree levers, and what each can/can't do
Pre/post-test hooks in
test-suite.yml— run a downstream script at a well-known path if present (if hashFiles('.github/pre-test.sh')). setuptools moves its shell setup there (pre-build,downloads.preload,echo SETUPTOOLS_USE_DISTUTILS >> $GITHUB_ENV). Keepstest-suite.ymlun-forked → clean future merges. Limit: hooks are shell only, so action-based steps — setuptools'actions/cacherestore, and job-levelcontinue-on-error— can't move into a script. Hooks shrink the fork but don't fully remove it.A
publish-coveragecomposite action used by bothtest-suite.ymland decoupled jobs liketest_cygwin. This is a single action-wrapping step, exactly the composite use-case endorsed in tests and collateral share some behavior implicitly #162 — so it dodges the collapsed/ugly-log objection to multi-step composites, and it dedupes coverage across the reusable path and Cygwin. I'd recommend this one regardless.Env is the stubborn one. A called reusable workflow can't inherit the caller's
env:, a composite can't cleanly set job-level env, and decoupled jobs can't call the reusable workflow — so the only true single source across all of them is repo-levelvars.*(config in GitHub settings, less visible/portable). Otherwise the duplication fortest_cygwin/integrationis irreducible in-repo.Recommendation (mostly skeleton-side)
publish-coveragecomposite (lever 2) and a pre-test hook intest-suite.yml(lever 1).actions/cache+continue-on-error) as a much smallertest-suite.ymldelta.vars.*if it must go.The two underlying platform gaps are already tracked upstream (no new reports filed):
Shelving the implementation here for now.