blob: fb5b7d11b1f7fc4ce71e90623cc8ebd3d7cb0dad [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import hashlib
import importlib.util
import sys
from argparse import Namespace
from pathlib import Path
from types import SimpleNamespace
import pytest
def _load_release_module():
module_path = Path(__file__).resolve().parent.parent / "scripts" / "apache_release.py"
spec = importlib.util.spec_from_file_location("apache_release", module_path)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module
release = _load_release_module()
def test_git_source_date_epoch_ignores_ambient_epoch_and_anchors_repo(monkeypatch, capsys):
monkeypatch.setenv("SOURCE_DATE_EPOCH", "123456789")
calls = []
def fake_run_command(command, **kwargs):
calls.append((command, kwargs))
return SimpleNamespace(stdout="987654321\n")
monkeypatch.setattr(release, "_run_command", fake_run_command)
assert release._git_source_date_epoch() == 987654321
assert calls[0][0] == [
"git",
"-C",
str(release.PROJECT_ROOT),
"-c",
"log.showSignature=false",
"show",
"-s",
"--format=%ct",
"HEAD",
]
assert "Ignoring ambient SOURCE_DATE_EPOCH=123456789" in capsys.readouterr().out
def test_wheel_source_date_epoch_uses_explicit_rebuild_epoch(monkeypatch):
monkeypatch.setenv("SOURCE_DATE_EPOCH", "123456789")
assert release._wheel_source_date_epoch() == 123456789
def test_wheel_source_date_epoch_treats_blank_as_unset(monkeypatch):
monkeypatch.setenv("SOURCE_DATE_EPOCH", " ")
monkeypatch.setattr(release, "_git_source_date_epoch", lambda: 987654321)
assert release._wheel_source_date_epoch() == 987654321
def test_environment_source_date_epoch_rejects_non_integer(monkeypatch):
monkeypatch.setenv("SOURCE_DATE_EPOCH", "not-an-epoch")
with pytest.raises(SystemExit):
release._environment_source_date_epoch()
def _write_artifact_set(directory: Path, version: str, wheel_name: str = None) -> None:
wheel_name = wheel_name or f"apache_burr-{version}-py3-none-any.whl"
artifact_names = [
f"apache-burr-{version}-incubating-src.tar.gz",
f"apache-burr-{version}-incubating-sdist.tar.gz",
wheel_name,
]
for artifact_name in artifact_names:
artifact_path = directory / artifact_name
artifact_path.write_bytes(b"artifact")
artifact_path.with_name(f"{artifact_name}.asc").write_text("sig", encoding="utf-8")
artifact_path.with_name(f"{artifact_name}.sha512").write_text("sha", encoding="utf-8")
def test_parse_rc_label_accepts_supported_formats():
assert release._parse_rc_label("0.42.0-RC1") == ("0.42.0", "1")
assert release._parse_rc_label("0.42.0-incubating-RC1") == ("0.42.0", "1")
def test_parse_rc_label_rejects_invalid_format():
with pytest.raises(SystemExit):
release._parse_rc_label("0.42.0")
def test_validate_promotion_artifacts_requires_expected_set(tmp_path):
_write_artifact_set(tmp_path, "0.42.0")
artifacts = release._validate_promotion_artifacts(str(tmp_path), "0.42.0")
assert len(artifacts) == 9
assert any(path.endswith("apache-burr-0.42.0-incubating-src.tar.gz") for path in artifacts)
assert any(path.endswith("apache-burr-0.42.0-incubating-sdist.tar.gz") for path in artifacts)
assert any(path.endswith("apache_burr-0.42.0-py3-none-any.whl") for path in artifacts)
def test_validate_promotion_artifacts_fails_when_companion_missing(tmp_path):
_write_artifact_set(tmp_path, "0.42.0")
(tmp_path / "apache-burr-0.42.0-incubating-src.tar.gz.asc").unlink()
with pytest.raises(SystemExit):
release._validate_promotion_artifacts(str(tmp_path), "0.42.0")
def test_promotion_target_url_appends_version_subdir():
assert (
release._promotion_target_url(
"0.42.0", "https://dist.apache.org/repos/dist/release/incubator/burr"
)
== "https://dist.apache.org/repos/dist/release/incubator/burr/0.42.0"
)
def test_twine_upload_command_includes_only_sdist_and_wheel():
command = release._twine_upload_command(
[
"apache-burr-0.42.0-incubating-src.tar.gz",
"apache-burr-0.42.0-incubating-src.tar.gz.asc",
"apache-burr-0.42.0-incubating-sdist.tar.gz",
"apache_burr-0.42.0-py3-none-any.whl",
]
)
assert command == (
"twine upload apache-burr-0.42.0-incubating-sdist.tar.gz "
"apache_burr-0.42.0-py3-none-any.whl"
)
def test_cmd_promote_rejects_already_promoted_release(monkeypatch):
monkeypatch.setattr(release, "_verify_project_root", lambda: None)
monkeypatch.setattr(release, "_svn_target_exists", lambda url: True)
args = Namespace(
rc_label="0.42.0-RC1",
apache_id="hari",
dry_run=False,
dev_svn_root="https://dist.apache.org/repos/dist/dev/incubator/burr",
release_svn_root="https://dist.apache.org/repos/dist/release/incubator/burr",
)
with pytest.raises(SystemExit):
release.cmd_promote(args)
def test_cmd_promote_dry_run_uses_server_copy_without_committing(monkeypatch, tmp_path):
calls = {"checkout": [], "promote": None}
class _TempDir:
def __enter__(self):
return str(tmp_path)
def __exit__(self, exc_type, exc, tb):
return False
def fake_checkout(url: str, checkout_dir: str):
calls["checkout"].append((url, checkout_dir))
Path(checkout_dir).mkdir(parents=True, exist_ok=True)
def fake_validate(rc_checkout_dir: str, version: str):
assert version == "0.42.0"
return [
f"{rc_checkout_dir}/apache-burr-0.42.0-incubating-sdist.tar.gz",
f"{rc_checkout_dir}/apache_burr-0.42.0-py3-none-any.whl",
]
def fake_promote(source_url, target_url, message, apache_id, dry_run=False):
calls["promote"] = (source_url, target_url, message, apache_id, dry_run)
return True
monkeypatch.setattr(release, "_verify_project_root", lambda: None)
monkeypatch.setattr(release.tempfile, "TemporaryDirectory", lambda prefix=None: _TempDir())
monkeypatch.setattr(release, "_svn_target_exists", lambda url: False)
monkeypatch.setattr(release, "_svn_checkout", fake_checkout)
monkeypatch.setattr(release, "_validate_promotion_artifacts", fake_validate)
monkeypatch.setattr(release, "_promote_with_server_copy", fake_promote)
args = Namespace(
rc_label="0.42.0-RC1",
apache_id="hari",
dry_run=True,
dev_svn_root="https://dist.apache.org/repos/dist/dev/incubator/burr",
release_svn_root="https://dist.apache.org/repos/dist/release/incubator/burr",
)
assert release.cmd_promote(args) is True
# only the RC is checked out; the release tree is never downloaded
assert len(calls["checkout"]) == 1
assert calls["checkout"][0][0].endswith("/0.42.0-incubating-RC1")
source_url, target_url, message, apache_id, dry_run = calls["promote"]
assert source_url.endswith("/0.42.0-incubating-RC1")
assert target_url == "https://dist.apache.org/repos/dist/release/incubator/burr/0.42.0"
assert apache_id == "hari"
assert dry_run is True
def test_verify_parser_accepts_skip_signing():
parser = release._build_parser()
args = parser.parse_args(["verify", "0.42.0", "0", "--skip-signing"])
assert args.skip_signing is True
def test_cmd_verify_skip_signing_succeeds_without_asc_files(tmp_path):
version = "0.42.0"
content = b"fake artifact content"
sha = hashlib.sha512(content).hexdigest()
artifact_name = f"apache-burr-{version}-incubating-src.tar.gz"
(tmp_path / artifact_name).write_bytes(content)
(tmp_path / f"{artifact_name}.sha512").write_text(f"{sha} {artifact_name}\n")
# No .asc file — simulates a --skip-signing build
args = Namespace(version=version, rc_num="0", artifacts_dir=str(tmp_path), skip_signing=True)
assert release.cmd_verify(args) is True