Insist on minimal pyproject.toml file

Change-Id: I9e8a134067593c393cff063b6c02a40afdd18c89
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane
2026-06-11 21:30:18 +00:00
committed by Michal Nasiadka
parent 416dba9bba
commit e198674f86
3 changed files with 111 additions and 0 deletions
+29
View File
@@ -123,6 +123,35 @@ def _read_setup_cfg_extras(root: str) -> dict[str, list[str]] | None:
return result
def verify_pyproject_toml(root: str) -> bool:
data = _read_pyproject_toml(root)
if data is None:
print('Missing pyproject.toml file', file=sys.stderr)
return False
if 'build-system' not in data:
print("pyproject.toml is missing 'build-system' table", file=sys.stderr)
return False
if (build_backend := data['build-system'].get('build-backend')) != 'pbr.build':
print(
f"pyproject.toml has invalid 'build-system.build-backend'. "
f"Expected 'pbr.build'; got {build_backend!r}",
file=sys.stderr,
)
return False
if 'project' not in data:
print(
"pyproject.toml is missing 'project' table. This is not currently "
"an error but may be in the future",
file=sys.stderr,
)
return True
class Project(TypedDict):
# The root directory path
root: str
@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from io import StringIO
import os
import textwrap
@@ -56,6 +57,73 @@ class TestReadProject(testtools.TestCase):
)
class TestVerifyPyprojectToml(testtools.TestCase):
def setUp(self):
super().setUp()
self.stderr = StringIO()
self.useFixture(fixtures.MonkeyPatch('sys.stderr', self.stderr))
def test_valid(self):
root = self.useFixture(common.pep_518_fixture).root
self.assertTrue(project.verify_pyproject_toml(root))
self.assertEqual('', self.stderr.getvalue())
def test_missing_file(self):
root = self.useFixture(fixtures.TempDir()).path
self.assertFalse(project.verify_pyproject_toml(root))
self.assertEqual(
'Missing pyproject.toml file\n', self.stderr.getvalue()
)
def test_missing_build_system(self):
root = self.useFixture(fixtures.TempDir()).path
with open(os.path.join(root, 'pyproject.toml'), 'w') as fh:
fh.write(
textwrap.dedent("""
[project]
name = "foo"
""")
)
self.assertFalse(project.verify_pyproject_toml(root))
self.assertIn(
"pyproject.toml is missing 'build-system' table",
self.stderr.getvalue(),
)
def test_invalid_build_backend(self):
root = self.useFixture(fixtures.TempDir()).path
with open(os.path.join(root, 'pyproject.toml'), 'w') as fh:
fh.write(
textwrap.dedent("""
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
""")
)
self.assertFalse(project.verify_pyproject_toml(root))
self.assertIn(
"pyproject.toml has invalid 'build-system.build-backend'. "
"Expected 'pbr.build'; got 'setuptools.build_meta'",
self.stderr.getvalue(),
)
def test_missing_project_table(self):
root = self.useFixture(fixtures.TempDir()).path
with open(os.path.join(root, 'pyproject.toml'), 'w') as fh:
fh.write(
textwrap.dedent("""
[build-system]
requires = ["pbr>=6.0.0", "setuptools>=64.0.0"]
build-backend = "pbr.build"
""")
)
self.assertTrue(project.verify_pyproject_toml(root))
self.assertIn(
"pyproject.toml is missing 'project' table",
self.stderr.getvalue(),
)
class TestProjectExtras(testtools.TestCase):
def test_pyproject_toml(self):
root = self.useFixture(fixtures.TempDir()).path
@@ -126,6 +126,14 @@ def main():
backports = {}
cwd = os.getcwd()
# Verify that pyproject.toml is present and contains the required
# attributes. We only do this on master since we don't want to be
# strict on already released branches
pyproject_found = None
if branch in ('master', 'main'):
pyproject_found = project.verify_pyproject_toml(cwd)
# build a list of requirements in the proposed change,
# and check them for style violations while doing so
head_proj = project.read(cwd)
@@ -149,8 +157,14 @@ def main():
)
# report the results
error = False
if failed or head_reqs.failed:
print("*** Incompatible requirement found!")
error = True
if pyproject_found is False:
print("*** Invalid or missing pyproject.toml!")
error = True
if error:
print("*** See https://docs.openstack.org/requirements/latest/")
sys.exit(1)