-
Notifications
You must be signed in to change notification settings - Fork 25
Support release-candidate builds as a first-class mode #274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
1dd86ba
4ad4c79
ea3aca9
28965aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| import os | ||
| import subprocess | ||
| from pathlib import Path | ||
|
|
||
| import pytest | ||
|
|
||
| TOOLS_DIRECTORY = Path(__file__).resolve().parents[1] / "tools" | ||
|
|
||
|
|
||
| def _generate_version( | ||
| tmp_path: Path, | ||
| candidate_version: str | None, | ||
| source_version: str | None = None, | ||
| ) -> subprocess.CompletedProcess[str]: | ||
| environment = os.environ.copy() | ||
| environment.pop("RAPIDS_RELEASE_CANDIDATE_SOURCE_VERSION", None) | ||
| if candidate_version is None: | ||
| environment.pop("RAPIDS_RELEASE_CANDIDATE_VERSION", None) | ||
| else: | ||
| environment["RAPIDS_RELEASE_CANDIDATE_VERSION"] = candidate_version | ||
| if source_version is not None: | ||
| environment["RAPIDS_RELEASE_CANDIDATE_SOURCE_VERSION"] = source_version | ||
| return subprocess.run( | ||
| [TOOLS_DIRECTORY / "rapids-generate-version"], | ||
| cwd=tmp_path, | ||
| env=environment, | ||
| text=True, | ||
| capture_output=True, | ||
| check=False, | ||
| ) | ||
|
|
||
|
|
||
| def test_release_candidate_version_returns_exact_final_version_without_git_tag(tmp_path): | ||
| tmp_path.joinpath("VERSION").write_text("26.10.00\n") | ||
|
|
||
| result = _generate_version(tmp_path, "26.10.00") | ||
|
|
||
| assert result.returncode == 0 | ||
| assert result.stdout == "26.10.00" | ||
| assert result.stderr == "" | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("candidate_version", ["v26.10.00", "26", "26.10.00.1", "26.10.00rc0"]) | ||
| def test_release_candidate_version_rejects_non_final_formats(tmp_path, candidate_version): | ||
| tmp_path.joinpath("VERSION").write_text("26.10.00\n") | ||
|
|
||
| result = _generate_version(tmp_path, candidate_version) | ||
|
|
||
| assert result.returncode == 1 | ||
| assert "must use a numeric YY.MM or YY.MM.XX format" in result.stderr | ||
|
|
||
|
|
||
| def test_release_candidate_version_supports_independently_versioned_repository(tmp_path): | ||
| tmp_path.joinpath("VERSION").write_text("0.3.0\n") | ||
|
|
||
| result = _generate_version(tmp_path, "0.3.0") | ||
|
|
||
| assert result.returncode == 0 | ||
| assert result.stdout == "0.3.0" | ||
|
|
||
|
|
||
| def test_release_candidate_version_supports_ucxx_two_component_version(tmp_path): | ||
| tmp_path.joinpath("VERSION").write_text("0.52.00\n") | ||
|
|
||
| result = _generate_version(tmp_path, "0.52") | ||
|
|
||
| assert result.returncode == 0 | ||
| assert result.stdout == "0.52" | ||
|
|
||
|
|
||
| def test_release_candidate_version_rejects_different_source_major_minor(tmp_path): | ||
| tmp_path.joinpath("VERSION").write_text("26.12.00a0\n") | ||
|
|
||
| result = _generate_version(tmp_path, "26.10.00") | ||
|
|
||
| assert result.returncode == 1 | ||
| assert "does not match source major/minor '26.12'" in result.stderr | ||
|
|
||
|
|
||
| def test_release_candidate_version_uses_preserved_source_after_output_truncation(tmp_path): | ||
| tmp_path.joinpath("VERSION").write_text("") | ||
|
|
||
| result = _generate_version(tmp_path, "26.10.00", source_version="26.10.00") | ||
|
|
||
| assert result.returncode == 0 | ||
| assert result.stdout == "26.10.00" | ||
|
|
||
|
|
||
| def test_release_candidate_version_requires_version_file(tmp_path): | ||
| result = _generate_version(tmp_path, "26.10.00") | ||
|
|
||
| assert result.returncode == 1 | ||
| assert "requires a VERSION file" in result.stderr |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import os | ||
| import subprocess | ||
| from pathlib import Path | ||
|
|
||
| TOOLS_DIRECTORY = Path(__file__).resolve().parents[1] / "tools" | ||
|
|
||
|
|
||
| def _environment(**updates: str) -> dict[str, str]: | ||
| environment = os.environ.copy() | ||
| environment["PATH"] = f"{TOOLS_DIRECTORY}:{environment['PATH']}" | ||
| environment.update(updates) | ||
| return environment | ||
|
|
||
|
|
||
| def test_release_candidate_is_a_release_build(): | ||
| result = subprocess.run( | ||
| [TOOLS_DIRECTORY / "rapids-is-release-build"], | ||
| env=_environment(RAPIDS_BUILD_TYPE="release-candidate", GITHUB_REF="refs/heads/main"), | ||
| text=True, | ||
| capture_output=True, | ||
| check=False, | ||
| ) | ||
|
|
||
| assert result.returncode == 0 | ||
| assert "is release build" in result.stderr | ||
|
|
||
|
|
||
| def test_release_candidate_rattler_channels_exclude_public_rapids_channels(): | ||
| command = f'source "{TOOLS_DIRECTORY / "rapids-rattler-channel-string"}"; printf "%s\\n" "${{RATTLER_CHANNELS[*]}}"' | ||
| result = subprocess.run( | ||
| ["bash", "-c", command], | ||
| env=_environment( | ||
| RAPIDS_BUILD_TYPE="release-candidate", | ||
| GITHUB_REF="refs/heads/main", | ||
| RAPIDS_CONDA_BLD_OUTPUT_DIR="/tmp/conda-output", | ||
| ), | ||
| text=True, | ||
| capture_output=True, | ||
| check=False, | ||
| ) | ||
|
|
||
| assert result.returncode == 0 | ||
| assert result.stdout.splitlines()[-1] == "--channel conda-forge" | ||
| assert "rapidsai" not in result.stdout |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,40 @@ | |||||
| set -euo pipefail | ||||||
| export RAPIDS_SCRIPT_NAME="rapids-generate-version" | ||||||
|
|
||||||
| if [[ -n "${RAPIDS_RELEASE_CANDIDATE_VERSION:-}" ]]; then | ||||||
| readonly candidate_version="${RAPIDS_RELEASE_CANDIDATE_VERSION}" | ||||||
| readonly candidate_version_regex='^([0-9]+)\.([0-9]+)(\.[0-9]+)?$' | ||||||
| if [[ ! "${candidate_version}" =~ ${candidate_version_regex} ]]; then | ||||||
| echo "RAPIDS_RELEASE_CANDIDATE_VERSION must use a numeric YY.MM or YY.MM.XX format, got '${candidate_version}'" >&2 | ||||||
| exit 1 | ||||||
| fi | ||||||
| # A successful Bash '=~' comparison stores each parenthesized capture in | ||||||
| # BASH_REMATCH. Save these captures before the source-version match below | ||||||
| # replaces them. | ||||||
| readonly candidate_major_minor="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" | ||||||
| source_version="${RAPIDS_RELEASE_CANDIDATE_SOURCE_VERSION:-}" | ||||||
| if [[ -z "${source_version}" ]]; then | ||||||
| if [[ ! -f VERSION ]]; then | ||||||
| echo "RAPIDS_RELEASE_CANDIDATE_VERSION requires a VERSION file or RAPIDS_RELEASE_CANDIDATE_SOURCE_VERSION" >&2 | ||||||
| exit 1 | ||||||
| fi | ||||||
| source_version="$(head -n 1 VERSION)" | ||||||
| fi | ||||||
| readonly source_version | ||||||
| readonly source_version_regex='^([0-9]+)\.([0-9]+)(\.|$)' | ||||||
| if [[ ! "${source_version}" =~ ${source_version_regex} ]]; then | ||||||
| echo "source version must begin with two numeric components, got '${source_version}'" >&2 | ||||||
| exit 1 | ||||||
| fi | ||||||
| readonly source_major_minor="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" | ||||||
| if [[ "${source_major_minor}" != "${candidate_major_minor}" ]]; then | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This also makes the error message more consistent with the comparison |
||||||
| echo "release-candidate version '${candidate_version}' does not match source major/minor '${source_major_minor}'" >&2 | ||||||
| exit 1 | ||||||
| fi | ||||||
| echo -n "${candidate_version}" | ||||||
| exit 0 | ||||||
| fi | ||||||
|
|
||||||
| if rapids-is-release-build; then | ||||||
| dunamai_version=$(python -m dunamai from git --format "{base}") | ||||||
| else | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,8 +35,11 @@ | |
|
|
||
| RAPIDS_CHANNEL="rapidsai-nightly" | ||
|
|
||
| # Replace dev/nightly channels if build is a release build | ||
| if rapids-is-release-build; then | ||
| # Candidate dependencies come only from the frozen local candidate channel and | ||
| # conda-forge. They must not resolve from either public RAPIDS channel. | ||
| if [[ "${RAPIDS_BUILD_TYPE:-}" == "release-candidate" ]]; then | ||
| RAPIDS_CHANNEL="" | ||
| elif rapids-is-release-build; then | ||
|
Comment on lines
+38
to
+42
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is fine for nearly all of rapids, but |
||
| RAPIDS_CHANNEL="rapidsai" | ||
| fi | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this merits a comment on
BASH_REMATCHsemantics, because I always have to look it up