Repository navigation
build(make): stop reinstalling tooling per target and fail doctor on missing tools - #631
Merged
Merged
Conversation
… missing tools Every target depends on bootstrap, which ran `pip install --upgrade pip` and `pip install hatch` each time: three `make bootstrap` runs with Hatch installed made six pip calls and `make check-all` sixteen. `make check` ran `make lint` and then `make typecheck`, but Hatch's `lint` script already ends with the type check, so mypy ran twice. `make doctor` could not fail: its Hatch and `func` probes ended in `|| echo`, so with both missing it printed "No hatch environment found" and "func not found" and exited 0. - bootstrap creates .venv only when it is missing and runs `pip install hatch` only when $(HATCH) is not an executable regular file. It never upgrades pip and prints nothing when there is nothing to do. `-x` alone is also true for a searchable directory, so the test is `-f` and `-x`; a make file target would be wrong for the same reason, because make treats any existing path as up to date. - check is now `check: lint`. check-all, e2e-local and clean-all are untouched, and so is the security recipe. - doctor is read-only: $(HATCH), python3 and git are required and print `ok` or `MISSING <tool> (required)`; any MISSING fails the target. func and azurite are listed as optional and never change the status. The PYTHON variable, used only by the old doctor, is gone. - docs: the CI-only branch no longer upgrades the ambient pip. No workflow calls it, and it was the last `--upgrade` in the file. tests/test_makefile_contract.py runs make on a copy of the Makefile with PATH limited to stubs that log their arguments, so nothing is installed and no network is used. It pins: `make -n check` has one `hatch run lint` and no typecheck, and the real run makes one Hatch call and no pip call; bootstrap calls `pip install hatch` only when Hatch is missing or is a directory; doctor exits non-zero with a MISSING line for each required tool, exits 0 with an optional tool missing, and installs nothing; and that no `--upgrade` is left in the Makefile. All 8 cases fail on the previous Makefile. Refs #614 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
`make doctor` was not documented anywhere, and it now has a contract worth stating: it is a read-only check that exits non-zero when Hatch, python3 or git is missing, and lists func and azurite as optional. Add one row to each of the two command tables that list the other make targets (docs/development.md and docs/contributing.md). CONTRIBUTING.md and AGENTS.md are not touched. Refs #614 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Owner
Author
|
R3 authorization for head The maintainer delegated the merge decision to an Oracle review. The Oracle (AI) reviewed this change at head |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related Issue
Refs #614
Not
Closes: of #614's six criteria, five are met by #628 and this PR. The third, "make e2e-localis labelled local-only", is not met as written (see "What remains of #614"). If you read it as met by the target's name and its "against local Azurite" banner, changeRefstoCloses.Summary
make doctorcould not fail, every Make target re-ranpip, andmake checkran mypy twice. All three reproduced onorigin/main(d3a254f, which contains #628, #629 and #630):.venv/bin/pythonpresent (no Hatch,func,gitorazurite) it printed "No hatch environment found" and "func not found" and exited 0. With a directory at.venv/bin/hatchit also exited 0. In a fresh clone beforemake installit failed only by accident (.venv/bin/python: not found, make exit 2).ensure-hatchranpip install --upgrade pipandpip install hatch. Threemake bootstrapruns with Hatch installed made 6 pip calls,make check-allmade 16, and a fresh venv's pip went 22.0.2 → 26.2.2 as a side effect.checkranlintand thentypecheck, but Hatch'slintscript (pyproject.toml) already ends withhatch run typecheck, so mypy ran twice (2 summaries in a realmake check).After this PR, with Hatch installed
make check-allmakes 0 pip calls and one mypy run; with Hatch missing it makes exactly one (pip install hatch);make doctoris a read-only check that fails with aMISSINGline for each required tool. The same fix already landed in azure-functions-doctor-python (PR 636) and azure-functions-scaffold-python (PR 462); this follows them.Why
bootstrapis not a make file target.bootstrapstays a phony target that tests for an executable regular file. A file target ($(HATCH):) looks tidier, but make treats any existing path as up to date, so it would skip the install for a directory or a non-executable file at.venv/bin/hatch(reproduced in a scratch Makefile: see the last Verification row).-xalone has the same hole for a directory, which is why the test is-fand-x. The doctor PR hit exactly this in review.Changes
Makefile(+19/−18)bootstrap: creates.venvonly if missing; runspip install hatchonly if$(HATCH)is not an executable regular file; never upgrades pip; silent when there is nothing to do (it printed two lines per target).check: lint(one type check).doctor: read-only; required$(HATCH),python3,gitprintokorMISSING <tool> (required)and any MISSING fails the target; optionalfuncandazuriteare listed and never change the status. Removed thePYTHONvariable (only the olddoctorused it) and thepip install --upgrade pipin theCI-only branch ofdocs.tests/test_makefile_contract.py(new, 65 lines, 8 cases)makeon a copy of the Makefile withPATHlimited to stubs that log their arguments, so nothing is installed and no network is used (details below).docs/development.md,docs/contributing.md(+1 row each)make doctorin the two tables that list the other targets.CONTRIBUTING.mdandAGENTS.mdare not touched.Not changed, verified against
origin/main: thesecurityrecipe from #629 (byte-identical), thecheck-all,e2e-local,e2e-azure,cleanandclean-allrecipes (identical), and everything under.github,pyproject.toml,tools,scriptsandsrc(git diff --stat origin/main HEAD -- <those>is empty).Choices to know about:
python3, notpython3.11, is the required interpreter.bootstraprunspython3 -m venv; the Hatch environment's Python 3.11 is resolved (and, since Hatch 1.8, downloaded if absent) by Hatch itself, and CONTRIBUTING lists 3.11–3.14. Apython3.11-on-PATHcheck, as the doctor repo uses, would report a Hatch-managed 3.11 as MISSING; this repo has no need to accept that limitation.pip list,func --version, pre-commit hook state). Nothing in the repository parses it (grepover.github,tests,tools,scripts, docs).CI=1 make docsis already broken onmain, independent of this change: itsmkdocstrings[python]<1.0pin resolves to mkdocstrings 0.30.1, which fails against pymdown-extensions 12.3 (Highlight.__init__() missing ... 'md'). The same traceback occurs onmain(with the pip upgrade) and on this branch (without it), so removing that one line changes nothing observable. No workflow calls that branch. The non-CImake docs(via Hatch) builds on this branch (exit 0).Tests
tests/test_makefile_contract.py(65 lines, 8 cases) pins, withmake -nfor the first and real runs against stubs for the rest:make -n checkhas exactly onehatch run lintand notypecheck; the real run makes one Hatch call (run lint) and no pip call; thelintscript inpyproject.tomlstill contains the type check (whatcheck: lintrelies on); and the Makefile has no--upgrade(coversdocs, which-ncannot dry-run because its recipe line contains$(MAKE)).bootstrapcallspip install hatchonly when Hatch is missing or is a directory.doctorexits non-zero with aMISSINGline when$(HATCH),python3orgitis missing, exits 0 withfuncandazuritemissing (listing them), and calls no tool.Verification
Linux, GNU Make 4.3,
/bin/sh= dash, systempython33.10.12; Python 3.11.15 for the suite. "main" = unmodifiedorigin/maind3a254f; "head" =d468af4. Scripts and logs are kept in/tmp/opencode/logging-pr2-evidence/on the machine that ran them.make check-allgit cloneof head (HEADverified),python33.10.12.venv, Hatch 1.18.1make buildpytest tests/(defaultaddopts, coverage gate)pip install -e ".[dev]"ruff check/ruff format --check(src tests tools examples benchmarks scripts);mypy src tests(strict)tools/lint_release_workflows.py,lint_workflow_pins.py,lint_hatch_matrix.py,lint_doc_links.py,check_pr_format.py origin/main HEAD;git diff --checkmkdocs build --strict;make docs(noCI)make -n check, main / headpip install --upgrade pip,hatch run lintthenhatch run typecheck. Head: one bootstrap line, onehatch run lint, no typecheck, no upgradestub_counts.sh:PATH= stubs,VENV_DIRin scratch)bootstrap, Hatch present: 6 → 0 pip calls. 3×bootstrap, Hatch absent: 6 → 1 (install hatch).check: 6 → 0 (Hatch getsrun lint,run typecheck→run lint).lint2 → 0,test2 → 0,check-all16 → 0;check-allwith no.venv: 16 → 1 and onepython3 -m venvboth times.make -n check-all: 8upgrade pip→ 0.venv/bin/pythonpresent; Hatch,func,git,azuritemissing)exit 1), threeMISSINGlines, two optional linesmake install; after; with a directory at.venv/bin/hatch; after restoring itMISSING .venv/bin/hatch (required)exit 2; allokexit 0;MISSINGexit 2; exit 0. main: exit 2 by accident (.venv/bin/python: not found); exit 0 with a pip list; exit 0 with the directory ("Permission denied", "No hatch environment found"); exit 0CI=true make installin a fresh clone (the stepsecurity.ymlruns afterpip install hatch), then a secondmake bootstrap, thenmake security.venv.venvpip stays 22.0.2 (main: 26.2.2); secondbootstrapprints nothing (main: two lines);make securityexit 0make checkmake installwithoutCI, after theCI=truerun abovedefaultalready exists"; pre-commit hook installedorigin/mainmutate_makefile.py: a mutated Makefile andpyproject.tomlin a scratch tree, real tests run there)checkalso runstypecheck(2 forms);bootstrapupgrades pip; reinstalls Hatch every time; never installs it; accepts a directory (-xonly);doctoraccepts a directory; alwaysexit 0; fails on an optional tool; dropsgit; dropspython3; depends onensure-hatch(installs);docsupgrades pip again; thelintscript drops the type checkbootstrapanddoctor, taken frommake -n, under dash, bash,bash --posixand busyboxshfor an executable file, a directory, a non-executable file and a missing path;shellcheck -s sh,-s dash,-s bash$(HATCH)with a directory, then a non-executable file, at the pathmake lintruns without installing in both cases (the reason for the deviation above)What remains of #614
Criteria as currently written in the issue, against
origin/mainplus this PR:e2e-azure.yml:FAIL_ON_SKIP: "1"on the e2e step, whichRecord certificationfollows with noif:; the version check was already fail-closedotel-nightly.ymlFAIL_ON_SKIPmake e2e-localis labelled local-only; may skip App Insights but cannot produce or replace a certification recordRecord certificationstep ine2e-azure.ymldoes) and may skip App Insights (FAIL_ON_SKIPis opt-in). Missing: nothing says it is local-only. The target prints "against local Azurite", its second line says "override to certify a different deployed build", and no user-facing doc mentions it (only the Makefile and a docstring intests/e2e/conftest.pydo)make checktype-checks once;make doctornon-zero when a required tool is missing--upgradeis left in the Makefile.github,pyproject.toml,tools,scripts,src; coverage 96.26%tests/test_ci_skip_policy.py; negative runs in #628's descriptionWhat remains: criterion 3. One changed
echoin thee2e-localrecipe and one sentence in the docs (for example under "Real Azure E2E Tests") saying that a local run is not Azure certification. I left it out to keepe2e-localas it is and this PR to the bootstrap,checkanddoctorfix. If you want #614 closed by this PR, say so and it is a two-line addition.Not run
sh) were checked on the recipe text only.makeand do not depend on the interpreter.docs.ymlandmaintenance.ymlin normal operation. Neither runs on pull requests (manual/scheduled), so I dispatched both on this branch atd468af4(see "CI on the head commit"); a scheduled run onmainafter the merge is still the real check.CI=1 make docs: broken onmainalready (see "Changes", point 3); not fixed here.Review Evidence
docs/review-evidence-policy.md). Head when written:d468af4.permissions:, secret, release or publishing file, no redaction or telemetry code, and no policy-bearing file (AGENTS.md,CONTRIBUTING.md,SECURITY.md,docs/agent-playbook.md) is touched. The requiredbanditjob'smake installnow takes the new bootstrap path; its Bandit recipe is unchanged.Compatibility and documentation
make doctor's own output and exit status change; that is the fix, and nothing parses it.)make doctorindocs/development.mdanddocs/contributing.md.CI on the head commit (
d468af4)All runs are attempt 1 (nothing was re-run). 25 check-runs, read across all pages of the check-runs API for this exact SHA: 24 success, 1 skipped (
dependabot-auto-merge, by design), 0 failed or pending. The five required contexts (bandit,semgrep,Analyze,PR title,ci-required) are each present once and succeeded;mergeable_stateisclean.banditjob (security.yml), a clean runner checkout:pip install hatch, thenmake installprinted "Creating virtual environment...", "Installing Hatch...", "Creating environment: default" and "CI detected: skipping pre-commit hook installation";make securitythen printed "bandit: 4647 lines analysed, no findings". Somake installstill bootstraps a clean checkout through the newbootstrap. (pip's own "new release available" notice, on stderr, still appears after the install: it is a notice, not an upgrade.)Test (Py 3.11): 878 passed, 4 skipped, 4 deselected, coverage 96.26% (gate 95%). 3.12, 3.13, 3.14: 880 passed, 2 skipped (the two tests that need 3.12+ run there).Minimum dependencies: 878 passed, 4 skipped. The +8 overmainare the new tests, in every cell.Lint, type-check & security (Py 3.11): ruff and format clean, mypy strict 64 files.workflow_dispatchon this branch: Maintenance Checks and Docs (strict build check) both succeeded; their logs show the same "Creating virtual environment..." / "Installing Hatch..." lines.e2e-azure.yml,publish-pypi.yml,otel-nightly.yml.