| # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 |
| # For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt |
| |
| # Makefile for utility work on coverage.py. |
| |
| .DEFAULT_GOAL := help |
| |
| |
| ### Utilities |
| |
| .PHONY: help _clean_platform debug_clean clean_platform clean sterile venv install |
| |
| help: #- Show this help. |
| @# Adapted from https://www.thapaliya.com/en/writings/well-documented-makefiles/ |
| @# Markdown-inspired syntax is used in comments to print help. |
| @# Lines starting with '###' are section headers. |
| @# Targets with '#- ' comments are shown. |
| @echo Available targets: |
| @awk -F ':.*#-' '/^[^: ]+:.*#-/{printf " \033[1m%-20s\033[m %s\n",$$1,$$2} /^###/{printf "\n%s\n",substr($$0,5)}' $(MAKEFILE_LIST) |
| |
| # For managing development tooling, use uv if it's available, otherwise pip. |
| HAS_UV := $(shell command -v uv 2>/dev/null) |
| ifdef HAS_UV |
| # PYVERSIONS |
| VENV := uv venv --python=3.10 --prompt=coverage |
| INSTALL := uv pip install |
| INSTALL_R := uv pip sync |
| UNINSTALL := uv pip uninstall |
| else |
| VENV := python -m venv .venv |
| INSTALL := python -m pip install |
| INSTALL_R := python -m pip install -r |
| UNINSTALL := python -m pip uninstall -y |
| endif |
| |
| _clean_platform: |
| @rm -f *.so */*.so |
| @rm -f *.pyd */*.pyd |
| @rm -rf __pycache__ */__pycache__ */*/__pycache__ */*/*/__pycache__ */*/*/*/__pycache__ */*/*/*/*/__pycache__ |
| @rm -f *.pyc */*.pyc */*/*.pyc */*/*/*.pyc */*/*/*/*.pyc */*/*/*/*/*.pyc |
| @rm -f *.pyo */*.pyo */*/*.pyo */*/*/*.pyo */*/*/*/*.pyo */*/*/*/*/*.pyo |
| @rm -f .DS_Store */.DS_Store */*/.DS_Store */*/*/.DS_Store */*/*/*/.DS_Store |
| |
| debug_clean: #- Delete various debugging artifacts. |
| @rm -rf /tmp/dis /tmp/foo.out $$COVERAGE_DEBUG_FILE |
| |
| clean: debug_clean _clean_platform #- Remove artifacts of test execution, installation, etc. |
| @echo "Cleaning..." |
| @-$(UNINSTALL) -q coverage |
| @mkdir -p build # so the chmod won't fail if build doesn't exist |
| @chmod -R 777 build |
| @rm -rf build coverage.egg-info dist htmlcov |
| @rm -f *.bak */*.bak */*/*.bak */*/*/*.bak */*/*/*/*.bak */*/*/*/*/*.bak |
| @rm -f coverage/*,cover |
| @rm -f MANIFEST |
| @rm -f .coverage .coverage.* .metacov* |
| @rm -f coverage.xml coverage.json coverage.lcov |
| @rm -f .tox/*/lib/*/site-packages/a0_metacov.pth |
| @rm -f */.coverage */*/.coverage */*/*/.coverage */*/*/*/.coverage */*/*/*/*/.coverage */*/*/*/*/*/.coverage |
| @rm -f tests/covmain.zip tests/zipmods.zip tests/zip1.zip |
| @rm -rf doc/_build doc/_spell doc/sample_html_beta |
| @rm -rf tmp |
| @rm -rf a1_coverage.pth |
| @rm -rf .*cache */.*cache */*/.*cache */*/*/.*cache .hypothesis |
| @rm -rf tests/actual |
| @-make -C tests/gold/html clean |
| |
| sterile: clean #- Remove all non-controlled content, even if expensive. |
| rm -rf .venv |
| rm -rf .tox |
| rm -f cheats.txt |
| |
| venv: .venv #- Create a virtualenv in .venv. |
| .venv: |
| $(VENV) |
| |
| install: venv #- Install the developer tools. |
| $(INSTALL_R) requirements/dev.pip |
| |
| |
| ### Tests and quality checks |
| |
| .PHONY: lint mypy precommit quality test |
| |
| lint: #- Run linters and checkers. |
| tox -q -e lint |
| |
| mypy: #- Run the type checker. |
| tox -q -e mypy |
| |
| precommit: #- Run the pre-commit checks. |
| PYTHONWARNDEFAULTENCODING= pre-commit run --all-files |
| |
| quality: lint mypy precommit #- Run all the quality checks. |
| |
| test: #- Run the test suite. |
| tox -q -m py |
| |
| ### Metacov: coverage measurement of coverage.py itself |
| # See metacov.ini for details. |
| |
| .PHONY: metacov metahtml |
| |
| metacov: #- Run meta-coverage, measuring ourself. |
| COVERAGE_COVERAGE=yes tox -q $(ARGS) |
| |
| metahtml: #- Produce meta-coverage HTML reports. |
| tox exec -q $(ARGS) -- python3 igor.py combine_html |
| |
| |
| ### Requirements management |
| |
| # When updating requirements, a few rules to follow: |
| # |
| # 1) Don't install more than one .pip file at once. Always use pip-compile to |
| # combine .in files onto a single .pip file that can be installed where needed. |
| # |
| # 2) Check manual pins before `make upgrade` to see if they can be removed. Look |
| # in requirements/pins.pip, and search for "windows" in .in files to find pins |
| # and extra requirements that have been needed, but might be obsolete. |
| |
| .PHONY: upgrade upgrade_one _upgrade diff_upgrade |
| |
| DOCBIN = .tox/doc/bin |
| |
| # PYVERSION to use for kitting, based on cibuildwheel's requirements. |
| KITVER = py311 |
| KITBIN = .tox/$(KITVER)/bin |
| |
| $(KITBIN): |
| tox -q -e $(KITVER) --notest |
| |
| PIP_COMPILE = uv pip compile -q --universal --generate-hashes ${COMPILE_OPTS} |
| |
| # Limit to packages that were released more than 10 days ago. |
| # https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns |
| upgrade: export UV_EXCLUDE_NEWER=P10D |
| upgrade: #- Update the *.pip files with the latest packages satisfying *.in files. |
| $(MAKE) _upgrade COMPILE_OPTS="--upgrade" |
| |
| # Upgrade just one package, with no cooldown. |
| upgrade_one: #- Update the *.pip files for one package. `make upgrade_one package=...` |
| @test -n "$(package)" || { echo "\nUsage: make upgrade_one package=...\n"; exit 1; } |
| $(MAKE) _upgrade COMPILE_OPTS="--upgrade-package $(package)" |
| |
| _upgrade: export UV_CUSTOM_COMPILE_COMMAND=make upgrade |
| _upgrade: $(DOCBIN) $(KITBIN) |
| $(PIP_COMPILE) -o requirements/pip.pip requirements/pip.in |
| $(PIP_COMPILE) -o requirements/pytest.pip requirements/pytest.in |
| $(PIP_COMPILE) -p $(KITBIN)/python3 -o requirements/kit.pip requirements/kit.in |
| $(PIP_COMPILE) -o requirements/tox.pip requirements/tox.in |
| $(PIP_COMPILE) -o requirements/dev.pip requirements/dev.in |
| $(PIP_COMPILE) -o requirements/light-threads.pip requirements/light-threads.in |
| $(PIP_COMPILE) -o requirements/mypy.pip requirements/mypy.in |
| $(PIP_COMPILE) -p $(DOCBIN)/python3 -o doc/requirements.pip doc/requirements.in |
| PYTHONWARNDEFAULTENCODING= pre-commit autoupdate |
| |
| diff_upgrade: #- Summarize the last `make upgrade`. |
| @# The sort flags sort by the package name first, then by the -/+, and |
| @# sort by version numbers, so we get a summary with lines like this: |
| @# -bashlex==0.16 |
| @# +bashlex==0.17 |
| @# -build==0.9.0 |
| @# +build==0.10.0 |
| @git diff -U0 | grep -v '^@' | grep == | sort -k1.2,1.99 -k1.1,1.1r -u -V |
| |
| |
| ### Pre-builds for prepping the code |
| |
| .PHONY: css workflows prebuild |
| |
| CSS = coverage/htmlfiles/style.css |
| SCSS = coverage/htmlfiles/style.scss |
| |
| css: $(CSS) #- Compile .scss into .css. |
| $(CSS): $(SCSS) |
| pysassc --style=compact $(SCSS) $@ |
| cp $@ tests/gold/html/styled |
| |
| workflows: #- Run cog on the workflows to keep them up-to-date. |
| python -m cogapp -crP .github/workflows/*.yml |
| |
| prebuild: css workflows cogdoc #- One command for all source prep. |
| |
| |
| ### Sample HTML reports |
| |
| .PHONY: _sample_cog_html sample_html sample_html_beta |
| |
| _sample_cog_html: clean |
| $(INSTALL) -e . |
| cd ~/cog; \ |
| rm -rf htmlcov; \ |
| PYTEST_ADDOPTS= coverage run --branch --source=cogapp -m pytest -k CogTestsInMemory; \ |
| coverage combine; \ |
| coverage html |
| |
| sample_html: _sample_cog_html #- Generate sample HTML report. |
| rm -f doc/sample_html/*.* |
| cp -r ~/cog/htmlcov/ doc/sample_html/ |
| rm doc/sample_html/.gitignore doc/sample_html/status.json |
| |
| sample_html_beta: _sample_cog_html #- Generate sample HTML report for a beta release. |
| rm -f doc/sample_html_beta/*.* |
| cp -r ~/cog/htmlcov/ doc/sample_html_beta/ |
| rm doc/sample_html_beta/.gitignore doc/sample_html_beta/status.json |
| |
| |
| ### Kitting: making releases |
| |
| .PHONY: release_version edit_for_release cheats relbranch relcommit1 relcommit2 |
| .PHONY: kit pypi_upload test_upload build_kits update_rtd |
| .PHONY: _check_github_auth download_kits |
| .PHONY: tag bump_version |
| |
| REPO_OWNER = coveragepy/coveragepy |
| RTD_PROJECT = coverage |
| |
| release_version: # Update the version for a release. |
| python igor.py release_version |
| |
| edit_for_release: # Edit sources to insert release facts (see howto.txt). |
| python igor.py edit_for_release |
| |
| cheats: #- Create some useful snippets for releasing. |
| python igor.py cheats | tee cheats.txt |
| |
| relbranch: # Create the branch for releasing (see howto.txt). |
| git switch -c nedbat/release-$$(date +%Y%m%d-%H%M%S) |
| |
| relcommit1: # Commit the first release changes (see howto.txt). |
| git commit -am "docs: prep for $$(python setup.py --version)" |
| |
| relcommit2: # Commit the latest sample HTML report (see howto.txt). |
| git add doc/sample_html |
| git commit -am "docs: sample HTML for $$(python setup.py --version)" |
| |
| kit: #- Make a source distribution and some wheels. |
| @# Makes sdist and binary wheel for current Python version and platform: |
| python -m build |
| @# Makes py3-none-any wheel: |
| COVERAGE_DISABLE_EXTENSION=1 python -m build --wheel |
| |
| pypi_upload: #- Upload the built distributions to PyPI. |
| python ci/trigger_action.py $(REPO_OWNER) publish-pypi |
| @echo "Use that^ URL to approve the upload" |
| |
| test_upload: #- Upload the distributions to PyPI's testing server. |
| python ci/trigger_action.py $(REPO_OWNER) publish-testpypi |
| @echo "Use that^ URL to approve the upload" |
| |
| _check_github_auth: # Check that we have GITHUB_TOKEN for other commands that need it. |
| @if [[ -z "$$GITHUB_TOKEN" ]]; then \ |
| echo 'Missing GITHUB_TOKEN: opvars github'; \ |
| exit 1; \ |
| fi |
| |
| build_kits: _check_github_auth #- Trigger GitHub to build all the distributions. |
| python ci/trigger_action.py $(REPO_OWNER) build-kits |
| |
| download_kits: _check_github_auth #- Download the kits built on GitHub. |
| @# This is only if we need to examine them for debugging. |
| mkdir -p dist |
| gh run download --dir=dist $$(gh run list --workflow=Kits --json=databaseId --jq='.[0].databaseId') |
| |
| tag: # Make a git tag with the version number (see howto.txt). |
| git tag -s -m "Version $$(python setup.py --version)" $$(python setup.py --version) |
| git push --follow-tags |
| |
| update_rtd: # Update ReadTheDocs with the versions to show. |
| python ci/update_rtfd.py $(RTD_PROJECT) |
| |
| bump_version: # Edit sources to bump the version after a release (see howto.txt). |
| git switch -c nedbat/bump-version |
| python igor.py bump_version |
| git commit -a -m "build: bump version to $$(python setup.py --version | sed 's/a.*//')" |
| git push -u origin @ |
| |
| |
| ### Documentation |
| |
| .PHONY: cogdoc dochtml docdev docspell |
| |
| SPHINXOPTS = -aE |
| SPHINXBUILD = $(DOCBIN)/sphinx-build $(SPHINXOPTS) |
| SPHINXAUTOBUILD = $(DOCBIN)/sphinx-autobuild --port 9876 --ignore '.git/**' --open-browser |
| |
| $(DOCBIN): |
| tox -q -e doc --notest |
| |
| cogdoc: $(DOCBIN) #- Run docs through cog. |
| $(DOCBIN)/python -m cogapp -crP --verbosity=1 doc/*.rst doc/*/*.rst |
| |
| dochtml: cogdoc $(DOCBIN) #- Build the docs HTML output. |
| $(SPHINXBUILD) -b html doc doc/_build/html |
| @echo "Start at: doc/_build/html/index.html" |
| |
| docdev: dochtml #- Build docs, and auto-watch for changes. |
| PATH=$(DOCBIN):$(PATH) $(SPHINXAUTOBUILD) -b html doc doc/_build/html |
| |
| docspell: $(DOCBIN) #- Run the spell checker on the docs. |
| # Very mac-specific... |
| PYENCHANT_LIBRARY_PATH=/opt/homebrew/lib/libenchant-2.dylib $(SPHINXBUILD) -b spelling doc doc/_spell |
| |
| |
| ### Publishing docs |
| |
| .PHONY: publish publishbeta github_releases comment_on_fixes |
| |
| WEBHOME = ~/web/stellated |
| WEBSAMPLE = $(WEBHOME)/files/sample_coverage_html |
| WEBSAMPLEBETA = $(WEBHOME)/files/sample_coverage_html_beta |
| |
| publish: #- Publish the sample HTML report. |
| rm -f $(WEBSAMPLE)/*.* |
| mkdir -p $(WEBSAMPLE) |
| cp doc/sample_html/*.* $(WEBSAMPLE) |
| |
| publishbeta: |
| rm -f $(WEBSAMPLEBETA)/*.* |
| mkdir -p $(WEBSAMPLEBETA) |
| cp doc/sample_html_beta/*.* $(WEBSAMPLEBETA) |
| |
| CHANGES_MD = tmp/rst_rst/changes.md |
| SCRIV_SOURCE = tmp/only-changes.md |
| |
| $(CHANGES_MD): CHANGES.rst $(DOCBIN) |
| $(SPHINXBUILD) -b rst doc tmp/rst_rst |
| pandoc -frst -tmarkdown_strict --markdown-headings=atx --wrap=none tmp/rst_rst/changes.rst > $(CHANGES_MD) |
| |
| $(SCRIV_SOURCE): $(CHANGES_MD) |
| @# Trim parts of the file that aren't changelog entries. |
| sed -n -e '/## Version/,/## Earlier/p' < $(CHANGES_MD) > tmp/trimmed.md |
| @# Replace sphinx references with published URLs. |
| sed -r -e 's@]\(([a-zA-Z0-9_]+)\.rst#([^)]+)\)@](https://coverage.readthedocs.io/en/latest/\1.html#\2)@g' < tmp/trimmed.md > $(SCRIV_SOURCE) |
| |
| github_releases: $(SCRIV_SOURCE) #- Update GitHub releases. |
| $(DOCBIN)/python -m scriv github-release --all --repo=coveragepy/coveragepy |
| |
| comment_on_fixes: $(SCRIV_SOURCE) #- Add a comment to issues that were fixed. |
| python ci/comment_on_fixes.py $(REPO_OWNER) |