Skip to content

Commit

Permalink
Merge branch 'automatic-merge' into 'master'
Browse files Browse the repository at this point in the history
Remove tag need in build_wheel.py

See merge request it/e3-aws!35
  • Loading branch information
adanaja committed Dec 16, 2024
2 parents 065cef0 + 26576c9 commit 7e28bef
Showing 1 changed file with 101 additions and 102 deletions.
203 changes: 101 additions & 102 deletions build_wheel.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
#!/usr/bin/env python
"""Build the wheel.
The number of commits since the last tagged version is automatically
The number of commits since the last major/minor version change is automatically
added to the version of the package as the patch version.
For that, a tag v<major>.<minor>.0 must be manually added after the
merge when a major or minor version change occurs.
"""
from __future__ import annotations
import sys
Expand All @@ -19,24 +16,23 @@

logger = getLogger("build_wheel")

ROOT_DIR = Path(__file__).parent


def run(cmd: list[str], fail_ok: bool | None = None) -> Run:
"""Print a command, run it, and print the result.
def run(cmd: list[str], cwd: Path, fail_ok: bool | None = None) -> str:
"""Run a command and check the status.
:param cmd: the command
:param cwd: the directory where to run the command
:param fail_ok: allow the command to fail
:return: the Run instance
:return: the output of the command
"""
logger.info(f"$ {' '.join(cmd)}")
p = Run(cmd, cwd=str(ROOT_DIR))
p = Run(cmd, cwd=cwd)
if p.status != 0 and not fail_ok:
logger.error(p.out)
sys.exit(1)

logger.info(p.out)
return p
output = p.out
assert output is not None
return output


def main() -> None:
Expand All @@ -46,120 +42,123 @@ def main() -> None:
parser = main.argument_parser
parser.description = "Build the wheel"
parser.add_argument(
"--last-tag",
help="Provide the last tagged version",
"--project",
default="pyproject.toml",
help="Path to a Python project or pyproject.toml file",
)
parser.add_argument("--dry-run", action="store_true", help="Do not build the wheel")

main.parse_args()
assert main.args

# Find and read version file
with open(ROOT_DIR / "pyproject.toml", "rb") as f:
version_config = tomllib.load(f)["tool"]["setuptools"]["dynamic"]["version"]
project = Path(main.args.project)
if project.is_dir():
project = project / "pyproject.toml"

logger.debug(f"Project dir: {project.parent}")
if not project.is_file():
logger.error(f"{project} is not a file")
sys.exit(1)

# Find the path to version file
with open(project, "rb") as f:
version_config = (
tomllib.load(f)
.get("tool", {})
.get("setuptools", {})
.get("dynamic", {})
.get("version")
)

if version_config is None:
logger.error("Missing the version key in [tool.setuptools.dynamic] section")
sys.exit(1)

version_path = ROOT_DIR / (
version_path = (
version_config["file"]
if "file" in version_config
else f'src/{version_config["attr"].replace(".", "/")}.py'
)
with open(version_path) as f:
logger.debug(f"Version path: {version_path}")

# Read the version
root_dir = project.parent
version_abspath = root_dir / version_path
with open(version_abspath) as f:
version_content = f.read()

# Extract the <major>.<minor>(.<patch>)? part.
# We will replace the patch version by the number of commits since the most
# recent tagged version
match = re.search(
r"(?P<version>(?P<major>\d+)\.(?P<minor>\d+)(\.\w+)?)",
version_content,
)
version_pattern = r"(?P<version>(?P<major>\d+)\.(?P<minor>\d+)(\.\w+)?)"
match = re.search(version_pattern, version_content)
if not match:
logger.error(
f"No <major>.<minor>(.<patch>)? version found in {version_path.name}"
)
logger.error(f"No <major>.<minor>(.<patch>)? version found in {version_path}")
sys.exit(1)

version_major = match.group("major")
version_minor = match.group("minor")
version = match.group("version")
logger.info(f"Version is {version}")

# Find previous version from the most recent tag
last_tag = main.args.last_tag
if not last_tag:
# Need to unshallow the clone so we get the list of tags.
# That command can fail for an already complete clone
run(["git", "fetch", "--unshallow", "--tags"], fail_ok=True)
# Describe the most recent tag
p = run(["git", "describe", "--tags"])
output = p.out
assert output is not None
last_tag = output.strip()

# Format is v<major>.<minor>.<patch>(-<commits>)? with commits omitted if
# the current commit is also the one tagged
match = re.match(
r"v(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\w+)(\-(?P<commits>\d+))?",
last_tag,
)
if not match:
logger.error(
f"Expected v<major>.<minor>.<patch>(-<commits>)? format for tag {last_tag}"
)
sys.exit(1)
logger.debug(f"Version: {version}")

# Ensure the major and minor versions match.
# Also ensure the patch version is 0 because multiple tags for the same
# <major>.<minor> would mess up with the versioning system and then only
# <major>.<minor>.0 should exist
tagged_version_major = match.group("major")
tagged_version_minor = match.group("minor")
tagged_version_patch = match.group("patch")
if (version_major, version_minor, "0") != (
tagged_version_major,
tagged_version_minor,
tagged_version_patch,
):
logger.error(
"Found tag "
f"v{tagged_version_major}.{tagged_version_minor}.{tagged_version_patch} "
f"but was expecting v{version_major}.{version_minor}.0. "
"Please manually create the tag if not done yet or make sure this "
"is the most recent tag"
)
sys.exit(1)
# Need to unshallow the clone to get all commits.
# That command can fail for an already complete clone
run(["git", "fetch", "--unshallow", "--tags"], cwd=root_dir, fail_ok=True)

# match.group("commits") is None only if the current commit is also
# the one tagged so there is 0 commits since that tag
new_version = "{}.{}.{}".format(
version_major,
version_minor,
match.group("commits") or "0",
# Walk through the commits on the main branch only that modified the version file
output = run(
["git", "log", "--first-parent", "--format=format:%H", version_path],
cwd=root_dir,
)

# Replace the version in the file
logger.info(f"Set version to {new_version}")
with open(version_path, "w") as f:
f.write(version_content.replace(version, new_version))

try:
# Build the wheel
run(
[
sys.executable,
"-m",
"pip",
"wheel",
".",
"-q",
"--no-deps",
"-C--python-tag=py3",
"-w",
"build",
]
)
finally:
# Revert change to version file
run(["git", "restore", str(version_path)], fail_ok=True)
# Find the SHA when the major/minor version changed
previous_commit_sha = "HEAD"
for commit_sha in output.strip().splitlines():
output = run(["git", "show", f"{commit_sha}:{version_path}"], cwd=root_dir)
match = re.search(version_pattern, output)
if (
not match
or version_major != match.group("major")
or version_minor != match.group("minor")
):
logger.debug(f"Different version found at commit {commit_sha}")
break

previous_commit_sha = commit_sha

# Count the number of commits since that SHA.
output = run(
["git", "rev-list", f"{previous_commit_sha}..HEAD", "--count"],
cwd=root_dir,
)
build_version = f"{version_major}.{version_minor}.{output.strip()}"
logger.info(f"{version_major}.{version_minor} -> {build_version}")

if not main.args.dry_run:
# Replace the version in the file
with open(version_abspath, "w") as f:
f.write(version_content.replace(version, build_version))

try:
# Build the wheel
run(
[
sys.executable,
"-m",
"pip",
"wheel",
".",
"-q",
"--no-deps",
"-C--python-tag=py3",
"-w",
"build",
],
cwd=root_dir,
)
finally:
# Revert change to version file
run(["git", "restore", version_path], cwd=root_dir, fail_ok=True)


if __name__ == "__main__":
Expand Down

0 comments on commit 7e28bef

Please sign in to comment.