repomatic.lint_repo.repo module

Checks of the repository’s GitHub metadata against the project.

The description, the website field and the topics come from the one repository object repo_object reads. The other checks read the funding file, the labels, the draft releases and the release assets the install guide links to.

repomatic.lint_repo.repo.RELEASE_DOWNLOAD_RE = re.compile('/releases/(?:download/(?P<tag>[^/\\s\\")]+)|latest/download)/(?P<filename>[^/\\s\\")]+)')

A GitHub release asset URL, capturing its tag and filename.

Matches both spellings a guide can use: the tag-pinned /releases/download/<tag>/<file> the release freeze writes, and the versionless /releases/latest/download/<file> alias the binary aliases exist to serve, which names no tag and so leaves tag unset.

The alias is where a filename rots unnoticed: the freeze rewrites a pinned tag every release and would surface a bad name, while nothing touches an alias URL again after it is written. meta-package-manager renamed its binaries from mpm-* to meta-package-manager-* in 7.0.0 and its install guide kept advertising the old name for six weeks.

Matches any release download link, not only a binary one, so the install guide’s whole download surface is verified with a single pattern. Both groups stop at a quote, whitespace or a closing parenthesis, covering an HTML src, a Markdown link target and a bare URL in prose alike.

repomatic.lint_repo.repo.SPONSORS_LISTING_QUERY = '\nquery($owner: String!) {\n  repositoryOwner(login: $owner) {\n    ... on Sponsorable { hasSponsorsListing }\n  }\n}'

Reads whether a repository owner runs GitHub Sponsors.

GraphQL because the REST API does not expose hasSponsorsListing.

repomatic.lint_repo.repo.DEV_PRERELEASE_SUFFIX = '.dev0'

Tag suffix of the rolling dev pre-releases sync-dev-release manages.

repomatic.lint_repo.repo.RELEASE_LIST_LIMIT = 100

How many of the most recent releases check_stale_draft_releases() reads.

gh release list stops at 30 when no limit is given. A draft left by an abandoned release sits among the recent ones, and one page of the API holds 100.

repomatic.lint_repo.repo.check_package_name_vs_repo(ctx)[source]

Check that the package name matches the repository name.

Return type:

CheckResult

repomatic.lint_repo.repo.check_website_for_sphinx(ctx)[source]

Check that a Sphinx project’s website field names its documentation.

GitHub renders the website field in the repository sidebar, and for a project publishing Sphinx documentation that is where a visitor expects to land. So the check has two halves: the field is set at all, and it names the site the project itself declares under DOCS_URL_KEYS.

The second half is what a documentation move leaves behind. Sphinx emits <link rel="canonical"> from html_baseurl, and a conf.py commonly derives that from the same [project.urls] entry, so a project that moves to a new domain has every published page naming the new origin as canonical while the sidebar keeps sending visitors to the old one. Nothing but a reader noticing connects the two.

Note

A project declaring no documentation URL gets the presence half only. The comparison needs the project to have named an expected answer, and nothing here invents one from the repository slug.

Return type:

CheckResult

repomatic.lint_repo.repo.check_description_matches(ctx)[source]

Check that the repository description matches the project description.

Return type:

CheckResult

repomatic.lint_repo.repo.check_funding_file(ctx)[source]

Check that a repository whose owner runs GitHub Sponsors has a FUNDING.yml.

Skips forks, which inherit the parent’s sponsor button, and owners without a Sponsors listing.

Return type:

CheckResult

repomatic.lint_repo.repo.check_stale_draft_releases(ctx)[source]

Check for draft releases that are not dev pre-releases.

A draft release whose tag does not end with DEV_PRERELEASE_SUFFIX is likely a leftover from an abandoned or failed release. The only expected drafts are the rolling dev pre-releases sync-dev-release manages.

Return type:

CheckResult

repomatic.lint_repo.repo.check_undeclared_labels(ctx)[source]

Report labels the repository carries that no configured source declares.

sync-labels runs labelmaker apply, which creates, updates and renames but never deletes. So a label retired from declared_label_names()’ sources keeps existing on GitHub, and no other job will ever mention it again. This is the only reading that closes that loop.

Advisory on purpose, and it must stay that way on both counts. A repository may legitimately carry a hand-made label nobody declared, so a red run would be wrong; and deleting a label detaches every issue and pull request carrying it, which is a judgement no check should push someone into making quickly. Of nine orphans meta-package-manager carried, eight held nothing and one held 864 items, and only the counts told them apart.

Return type:

CheckResult

repomatic.lint_repo.repo.check_install_guide_downloads(ctx)[source]

Check the install guide’s release download URLs still resolve.

The release freeze pins those URLs to the version being released, but it runs before the binaries exist: the freeze commit is what triggers the build. So the pin is optimistic, and a release whose binary lane fails leaves the guide advertising files that 404 until the next release ratchets past it.

A versionless latest/download alias fails a different way, and stays broken longer: nothing rewrites it at release time, so it silently outlives a renamed asset instead of being re-pinned every cycle. Both forms are checked, see RELEASE_DOWNLOAD_RE.

Nothing static can catch either: the URLs are well-formed and correct on disk, and only the release’s actual asset list settles whether they resolve. Hence a lint check against the API rather than a conformance test.

Reports rather than repairs: the fix is a one-liner (freeze_install_download_urls() re-pointed at the last release that carries binaries), while an automated rewrite driven by one API read could downgrade a healthy install page on a flaky response.

Return type:

CheckResult

repomatic.lint_repo.repo.check_topics_subset_of_keywords(ctx)[source]

Check that the GitHub repository topics are a subset of the keywords.

Note

A keyword matches the topic GitHub would store for it: lowercased, with each run of whitespace replaced by a hyphen. A topic holds only lowercase letters, numbers and hyphens, while [project] keywords carries the spelling the package publishes. A project keywording an acronym (CLI, EML, MMDF) or a phrase (Weather forecast) would otherwise be told to add topics it already declares, with no spelling of the keyword able to satisfy both sides.

Return type:

CheckResult