diff --git a/.evergreen/config_generator/components/funcs/fetch_source.py b/.evergreen/config_generator/components/funcs/fetch_source.py index 8ad040f0b3e..3a0b707da52 100644 --- a/.evergreen/config_generator/components/funcs/fetch_source.py +++ b/.evergreen/config_generator/components/funcs/fetch_source.py @@ -18,14 +18,7 @@ class FetchSource(Function): set -o errexit set -o pipefail if [ -n "${github_pr_number}" -o "${is_patch}" = "true" ]; then - # This is a GitHub PR or patch build, probably branched from master - if command -v python3 &>/dev/null; then - # Prefer python3 if it is available - echo $(python3 ./build/calc_release_version.py --next-minor) > VERSION_CURRENT - else - echo $(python ./build/calc_release_version.py --next-minor) > VERSION_CURRENT - fi - VERSION=$VERSION_CURRENT-${version_id} + VERSION=patch-${version_id} else VERSION=latest fi diff --git a/.evergreen/generated_configs/functions.yml b/.evergreen/generated_configs/functions.yml index 588094d13d7..795cb20818a 100644 --- a/.evergreen/generated_configs/functions.yml +++ b/.evergreen/generated_configs/functions.yml @@ -216,14 +216,7 @@ functions: set -o errexit set -o pipefail if [ -n "${github_pr_number}" -o "${is_patch}" = "true" ]; then - # This is a GitHub PR or patch build, probably branched from master - if command -v python3 &>/dev/null; then - # Prefer python3 if it is available - echo $(python3 ./build/calc_release_version.py --next-minor) > VERSION_CURRENT - else - echo $(python ./build/calc_release_version.py --next-minor) > VERSION_CURRENT - fi - VERSION=$VERSION_CURRENT-${version_id} + VERSION=patch-${version_id} else VERSION=latest fi diff --git a/.evergreen/scripts/abi-compliance-check.sh b/.evergreen/scripts/abi-compliance-check.sh index 1359ed55a3b..baa8e3d4fed 100755 --- a/.evergreen/scripts/abi-compliance-check.sh +++ b/.evergreen/scripts/abi-compliance-check.sh @@ -8,12 +8,15 @@ mkdir abi-compliance/changes-install mkdir abi-compliance/latest-release-install mkdir abi-compliance/dumps -python ./build/calc_release_version.py --next-minor >VERSION_CURRENT -python ./build/calc_release_version.py --next-minor -p >VERSION_RELEASED +declare head_commit today +# The 10 digits of the current commit +head_commit=$(git rev-parse --revs-only --short=10 "HEAD^{commit}") +# The YYYYMMDD date +today=$(date +%Y%m%d) declare newest current -newest="$(cat VERSION_RELEASED)" -current="$(cat VERSION_CURRENT)" +current="$(cat VERSION_CURRENT)-$today+git$head_commit" +newest=$(cat etc/prior_version.txt) declare working_dir working_dir="$(pwd)" diff --git a/.evergreen/scripts/build-docs.sh b/.evergreen/scripts/build-docs.sh index e88924ce89b..96e9033f54a 100755 --- a/.evergreen/scripts/build-docs.sh +++ b/.evergreen/scripts/build-docs.sh @@ -9,10 +9,6 @@ CMAKE=$(find_cmake_latest) # Check that a CLion user didn't accidentally convert NEWS from UTF-8 to ASCII grep "á" NEWS > /dev/null || (echo "NEWS file appears to have lost its UTF-8 encoding?" || exit 1) -debug "Calculating release version..." -python build/calc_release_version.py >VERSION_CURRENT -python build/calc_release_version.py -p >VERSION_RELEASED - build_dir=$MONGOC_DIR/_build/for-docs "$CMAKE" -S "$MONGOC_DIR" -B "$build_dir" \ -D ENABLE_MAN_PAGES=ON \ diff --git a/.evergreen/scripts/build_snapshot_rpm.sh b/.evergreen/scripts/build_snapshot_rpm.sh index 476c27c0a78..05b7f481260 100755 --- a/.evergreen/scripts/build_snapshot_rpm.sh +++ b/.evergreen/scripts/build_snapshot_rpm.sh @@ -84,11 +84,7 @@ sudo mock -r ${config} --use-bootstrap-image --isolation=simple --install rpmdev sudo mock -r ${config} --use-bootstrap-image --isolation=simple --dnf-cmd --setopt=powertools.module_hotfixes=true install utf8proc-devel sudo mock -r ${config} --use-bootstrap-image --isolation=simple --copyin "$(pwd)" "$(pwd)/${spec_file}" /tmp -sudo mock -r ${config} --use-bootstrap-image --isolation=simple --cwd "/tmp/${build_dir}" --chroot -- /bin/sh -c "( - python3.11 build/calc_release_version.py | sed -E 's/([^-]+).*/\1/' > VERSION_CURRENT ; - python3.11 build/calc_release_version.py -p > VERSION_RELEASED - )" -sudo mock -r ${config} --use-bootstrap-image --isolation=simple --copyout "/tmp/${build_dir}/VERSION_CURRENT" "/tmp/${build_dir}/VERSION_RELEASED" . +sudo mock -r ${config} --use-bootstrap-image --isolation=simple --copyout "/tmp/${build_dir}/VERSION_CURRENT" . bare_upstream_version=$(rpmspec --srpm -q --qf '%{version}' "$spec_file") # Upstream version in the .spec file cannot have hyphen (-); replace the current diff --git a/.gitignore b/.gitignore index e5feadb8c65..fc7b66b0e61 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,6 @@ CTestTestfile.cmake _build/ dist_manifest.txt test-results.json -VERSION_RELEASED *.pyc # Windows things diff --git a/CMakeLists.txt b/CMakeLists.txt index c1b89926ef9..457663460a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,6 @@ include (ParseVersion) ParseVersion ("${BUILD_VERSION}" MONGOC) # Defines additional similar variables: include (LoadVersion) -file (WRITE VERSION_CURRENT "${BUILD_VERSION}") LoadVersion (VERSION_CURRENT MONGOC) # Extended version attributes that CMake doesn't (yet) understand, which include diff --git a/Earthfile b/Earthfile index 6dc737484c4..db55aebd866 100644 --- a/Earthfile +++ b/Earthfile @@ -26,15 +26,15 @@ build: LET source_dir=/opt/mongoc/source LET build_dir=/opt/mongoc/build COPY --dir \ - src/ \ build/ \ - COPYING \ CMakeLists.txt \ + COPYING \ + NEWS \ README.rst \ + src/ \ THIRD_PARTY_NOTICES \ - NEWS \ + VERSION_CURRENT \ "$source_dir" - COPY +version-current/ $source_dir ENV CCACHE_HOME=/root/.cache/ccache RUN cmake -S "$source_dir" -B "$build_dir" -G "Ninja Multi-Config" \ -D ENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF \ @@ -115,20 +115,6 @@ test-cxx-driver: ENV CCACHE_BASE=$source RUN --mount=type=cache,target=$CCACHE_HOME cmake --build $build -# version-current : -# Create the VERSION_CURRENT file using Git. This file is exported as an artifact at / -version-current: - # Run on Alpine, which does this work the fastest - FROM alpine:3.18 - # Install Python and Git, the only things required for this job: - RUN apk add git python3 - # Copy only the .git/ directory and calc_release_version, which are enough to get the VERSION_CURRENT - COPY --dir .git/ build/calc_release_version.py /s/ - # Calculate it: - RUN cd /s/ && \ - python calc_release_version.py --next-minor > VERSION_CURRENT - SAVE ARTIFACT /s/VERSION_CURRENT - # PREP_CMAKE "warms up" the CMake installation cache for the current environment PREP_CMAKE: COMMAND diff --git a/build/calc_release_version.py b/build/calc_release_version.py deleted file mode 100644 index aaa69e84fa7..00000000000 --- a/build/calc_release_version.py +++ /dev/null @@ -1,403 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Copyright 2009-present MongoDB, Inc. -# -# Licensed 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. -# - -""" -A script that calculates the release version number (based on the current Git -branch and/or recent tags in history) to assign to a tarball generated from the -current Git commit. - -This script needs to remain compatible with its target platforms, which currently -includes RHEL 6, which uses Python 2.6! -""" - -# XXX NOTE XXX NOTE XXX NOTE XXX -# After modifying this script it is advisable to execute the self-tests in this directory: -# - calc_release_version_selftest.sh -# - calc_release_version_selftest.py -# XXX NOTE XXX NOTE XXX NOTE XXX - -# pyright: reportTypeCommentUsage=false - -import datetime -import errno -import re -import subprocess -import optparse # No 'argparse' on Python 2.6 -import sys - - -class Version: - def __init__(self, s): - pat = r'(\d+)\.(\d+)\.(\d+)(\-\S+)?' - match = re.match(pat, s) - assert match, "Unrecognized version string %s" % s - self.major, self.minor, self.micro = ( - map(int, (match.group(1), match.group(2), match.group(3)))) - - if match.group(4): - self.prerelease = match.group(4)[1:] - else: - self.prerelease = '' - - def __lt__(self, other): - if self.major != other.major: - return self.major < other.major - if self.minor != other.minor: - return self.minor < other.minor - if self.micro != other.micro: - return self.micro < other.micro - if self.prerelease != other.prerelease: - if self.prerelease != '' and other.prerelease == '': - # Consider a prerelease less than non-prerelease. - return True - # For simplicity, compare prerelease versions lexicographically. - return self.prerelease < other.prerelease - - # Versions are equal. - return False - - def __eq__(self, other): - self_tuple = self.major, self.minor, self.micro, self.prerelease - other_tuple = other.major, other.minor, other.micro, other.prerelease - return self_tuple == other_tuple - - -def parse_version(ver): - return Version(ver) - - -parser = optparse.OptionParser(description=__doc__) -parser.add_option("--debug", "-d", action="store_true", help="Enable debug output") -parser.add_option("--previous", "-p", action="store_true", help="Calculate the previous version instead of the current") -parser.add_option("--next-minor", action="store_true", help="Calculate the next minor version instead of the current") -args, pos = parser.parse_args() -assert not pos, "No positional arguments are expected" - - -_DEBUG = args.debug # type: bool - - -def debug(msg): # type: (str) -> None - if _DEBUG: - sys.stderr.write(msg) - sys.stderr.write("\n") - sys.stderr.flush() - - -debug("Debugging output enabled.") - -# This option indicates we are to determine the previous release version -PREVIOUS = args.previous # type: bool -# This options indicates to output the next minor release version -NEXT_MINOR = args.next_minor # type: bool - -# fmt: off - -PREVIOUS_TAG_RE = re.compile('(?P(?P[0-9]+)\\.(?P[0-9]+)' - '\\.(?P[0-9]+)(?:-(?P.*))?)') -RELEASE_TAG_RE = re.compile('(?P(?P[0-9]+)\\.(?P[0-9]+)' - '\\.(?P[0-9]+)(?:-(?P.*))?)') -RELEASE_BRANCH_RE = re.compile('(?:(?:refs/remotes/)?origin/)?(?Pr' - '(?P[0-9]+)\\.(?P[0-9]+))') - - -def check_output(args): # type: (list[str]) -> str - """ - Delegates to subprocess.check_output() if it is available, otherwise - provides a reasonable facsimile. - """ - debug('Run command: {0}'.format(args)) - try: - proc = subprocess.Popen(args, stdout=subprocess.PIPE) - except OSError as e: - suppl = '' - if e.errno == errno.ENOENT: - suppl = 'Does the executable “{0}” not exist?'.format(args[0]) - raise RuntimeError("Failed to execute subprocess {0}: {1} [{2}]".format(args, e, suppl)) - out = proc.communicate()[0] - ret = proc.poll() - if ret: - raise subprocess.CalledProcessError(ret, args[0]) - - # git isn't guaranteed to always return UTF-8, but for our purposes - # this should be fine as tags and hashes should be ASCII only. - out = out.decode('utf-8') - - return out - - -def check_head_tag(): # type: () -> str | None - """ - Checks the current HEAD to see if it has been tagged with a tag that matches - the pattern for a release tag. Returns release version calculated from the - tag, or None if there is no matching tag associated with HEAD. - """ - - found_tag = False - version_str = '0.0.0' - version_parsed = parse_version(version_str) - - # have git tell us if any tags that look like release tags point at HEAD; - # based on our policy, a commit should never have more than one release tag - tags = check_output(['git', 'tag', '--points-at', 'HEAD', '--list', '1.*']).split() - tag = '' - if len(tags) == 1: - tag = tags[0] - elif len(tags) > 1: - raise Exception('Expected 1 or 0 tags on HEAD, got: {}'.format(tags)) - - release_tag_match = RELEASE_TAG_RE.match(tag) - if release_tag_match: - new_version_str = release_tag_match.group('ver') - new_version_parsed = parse_version(new_version_str) - if new_version_parsed > version_parsed: # type: ignore - debug('HEAD release tag: ' + new_version_str) - version_str = new_version_str - version_parsed = new_version_parsed - found_tag = True - - if found_tag: - debug('Calculated version: ' + version_str) - return version_str - - return None - -def get_next_minor(prerelease_marker): # type: (str) -> str - """ - get_next_minor does the following: - - Inspect the branches that fit the convention for a release branch. - - Choose the latest and increment the minor version. - - Append .0 to form the new version (e.g., r1.21 becomes 1.22.0) - - Append a pre-release marker. (e.g. 1.22.0 becomes 1.22.0-20220201+gitf6e6a7025d) - """ - - version_str = '0.0.0' - version_parsed = parse_version(version_str) - - version_new = {} - # Use refs (not branches) to get local branches plus remote branches - refs = check_output(['git', 'show-ref']).splitlines() - for ref in refs: - release_branch_match = RELEASE_BRANCH_RE.match(ref.split()[1]) - if release_branch_match: - # Construct a candidate version from this branch name - version_new['major'] = int(release_branch_match.group('vermaj')) - version_new['minor'] = int(release_branch_match.group('vermin')) + 1 - version_new['patch'] = 0 - version_new['prerelease'] = prerelease_marker - new_version_str = str(version_new['major']) + '.' + \ - str(version_new['minor']) + '.' + \ - str(version_new['patch']) + '-' + \ - version_new['prerelease'] - new_version_parsed = parse_version(new_version_str) - if new_version_parsed > version_parsed: # type: ignore - version_str = new_version_str - version_parsed = new_version_parsed - debug('Found new best version "' + version_str \ - + '" based on branch "' \ - + release_branch_match.group('brname') + '"') - return version_str - -def get_branch_tags(active_branch_name): # type: (str) -> list[str] - """ - Returns a list of tags corresponding to the current branch, which must not - be master. If the specified branch is a release branch then return all tags - based on the major/minor X.Y release version. If the specified branch is - neither master nor a release branch, then walk backwards in history until - the first tag matching the glob '1.*' and return that tag. - """ - - if active_branch_name == 'master': - raise Exception('this method is not meant to be called while on "master"') - - release_branch_match = RELEASE_BRANCH_RE.match(active_branch_name) - if release_branch_match: - # This is a release branch, so look for tags only on this branch - tag_glob = release_branch_match.group('vermaj') + '.' \ - + release_branch_match.group('vermin') + '.*' - return check_output(['git', 'tag', '--list', tag_glob]).splitlines() - - # Not a release branch, so look for the most recent tag in history - commits = check_output(['git', 'log', '--pretty=format:%H', '--no-merges']) - tags_by_obj = get_object_tags() - for commit in commits.splitlines(): - got = tags_by_obj.get(commit) - if got: - return got - # No tags - return [] - - -def iter_tag_lines(): - """ - Generate a list of pairs of strings, where the first is a commit hash, and - the second is a tag that is associated with that commit. Duplicate commits - are possible. - """ - output = check_output(['git', 'tag', '--list', '1.*', '--format=%(*objectname)|%(tag)']) - lines = output.splitlines() - for l in lines: - obj, tag = l.split('|', 1) - if tag: - yield obj, tag - - -def get_object_tags(): # type: () -> dict[str, list[str]] - """ - Obtain a mapping between commit hashes and a list of tags that point to - that commit. Untagged commits will not be included in the resulting map. - """ - ret = {} # type: dict[str, list[str]] - for obj, tag in iter_tag_lines(): - ret.setdefault(obj, []).append(tag) - return ret - - -def process_and_sort_tags(tags): # type: (list[str]) -> list[str] - """ - Given a string (as returned from get_branch_tags), return a sorted list of - zero or more tags (sorted based on the Version comparison) which meet - the following criteria: - - a final release tag (i.e., 1.x.y without any pre-release suffix) - - a pre-release tag which is not superseded by a release tag (i.e., - 1.x.y-preX iff 1.x.y does not already exist) - """ - - processed_and_sorted_tags = [] # type: list[str] - if not tags or len(tags) == 0: - return processed_and_sorted_tags - - # find all the final release tags - for tag in tags: - release_tag_match = RELEASE_TAG_RE.match(tag) - if release_tag_match and not release_tag_match.group('verpre'): - processed_and_sorted_tags.append(tag) - # collect together final release tags and pre-release tags for - # versions that have not yet had a final release - for tag in tags: - tag_parts = tag.split('-') - if len(tag_parts) >= 2 and tag_parts[0] not in processed_and_sorted_tags: - processed_and_sorted_tags.append(tag) - processed_and_sorted_tags.sort(key=Version) # type: ignore - - return processed_and_sorted_tags - -def main(): - """ - The algorithm is roughly: - - - Is the --next-minor flag passed? If "yes", then return the next minor - release with a pre-release marker. - - Is the current HEAD associated with a tag that looks like a release - version? - - If "yes" then use that as the version - - If "no" then is the current branch master? - - If "yes" the current branch is master, then return the next minor - release with a pre-release marker. - - If "no" the current branch is not master, then determine the most - recent tag in history; strip any pre-release marker, increment the - patch version, and append a new pre-release marker - """ - - version_str = '0.0.0' - version_parsed = parse_version(version_str) - head_commit_short = check_output(['git', 'rev-parse', '--revs-only', - '--short=10', 'HEAD^{commit}']).strip() - prerelease_marker = datetime.date.today().strftime('%Y%m%d') \ - + '+git' + head_commit_short - - if NEXT_MINOR: - debug('Calculating next minor release') - return get_next_minor(prerelease_marker) - - head_tag_ver = check_head_tag() - if head_tag_ver: - return head_tag_ver - - active_branch_name = check_output(['git', 'rev-parse', - '--abbrev-ref', 'HEAD']).strip() - debug('Calculating release version for branch: ' + active_branch_name) - if active_branch_name == 'master': - return get_next_minor(prerelease_marker) - - branch_tags = get_branch_tags(active_branch_name) - tags = process_and_sort_tags(branch_tags) - - tag = tags[-1] if len(tags) > 0 else '' - # at this point the RE match is redundant, but convenient for accessing - # the components of the version string - release_tag_match = RELEASE_TAG_RE.match(tag) - if release_tag_match: - version_new = {} - version_new['major'] = int(release_tag_match.group('vermaj')) - version_new['minor'] = int(release_tag_match.group('vermin')) - version_new['patch'] = int(release_tag_match.group('verpatch')) + 1 - version_new['prerelease'] = prerelease_marker - new_version_str = str(version_new['major']) + '.' + \ - str(version_new['minor']) + '.' + \ - str(version_new['patch']) + '-' + \ - version_new['prerelease'] - new_version_parsed = parse_version(new_version_str) - if new_version_parsed > version_parsed: # type: ignore - version_str = new_version_str - version_parsed = new_version_parsed - debug('Found new best version "' + version_str \ - + '" from tag "' + release_tag_match.group('ver') + '"') - - return version_str - -def previous(rel_ver): # type: (str) -> str - """ - Given a release version, find the previous version based on the latest Git - tag that is strictly a lower version than the given release version. - """ - debug('Calculating previous release version (option -p was specified).') - version_str = '0.0.0' - version_parsed = parse_version(version_str) - rel_ver_str = rel_ver - rel_ver_parsed = parse_version(rel_ver_str) - tags = check_output(['git', 'tag', '--list', '1.*']).splitlines() - processed_and_sorted_tags = process_and_sort_tags(tags) - for tag in processed_and_sorted_tags: - previous_tag_match = PREVIOUS_TAG_RE.match(tag) - if previous_tag_match: - version_new = {} - version_new['major'] = int(previous_tag_match.group('vermaj')) - version_new['minor'] = int(previous_tag_match.group('vermin')) - version_new['patch'] = int(previous_tag_match.group('verpatch')) - version_new['prerelease'] = previous_tag_match.group('verpre') - new_version_str = str(version_new['major']) + '.' + \ - str(version_new['minor']) + '.' + \ - str(version_new['patch']) - if version_new['prerelease'] is not None: - new_version_str += '-' + version_new['prerelease'] - new_version_parsed = parse_version(new_version_str) - if new_version_parsed < rel_ver_parsed and new_version_parsed > version_parsed: # type: ignore - version_str = new_version_str - version_parsed = new_version_parsed - debug('Found new best version "' + version_str \ - + '" from tag "' + tag + '"') - - return version_str - -if __name__ == "__main__": - RELEASE_VER = previous(main()) if PREVIOUS else main() - - debug('Final calculated release version:') - print(RELEASE_VER) diff --git a/build/calc_release_version_selftest.py b/build/calc_release_version_selftest.py deleted file mode 100644 index ac01f7f0a32..00000000000 --- a/build/calc_release_version_selftest.py +++ /dev/null @@ -1,17 +0,0 @@ -import unittest -import calc_release_version - - -class TestVersionSort(unittest.TestCase): - def test_version_sort(self): - # At time of writing, `input_tags` is the output of `git tag -l "1.*"`: - input_tags = ["1.0.0", "1.0.2", "1.1.0", "1.1.0-rc0", "1.1.10", "1.1.11", "1.1.2", "1.1.4", "1.1.5", "1.1.6", "1.1.7", "1.1.8", "1.1.9", "1.10.0", "1.10.1", "1.10.2", "1.10.3", "1.11.0", "1.12.0", "1.13.0", "1.13.1", "1.14.0", "1.14.1", "1.15.0", "1.15.1", "1.15.2", "1.15.3", "1.16.0", "1.16.1", "1.16.2", "1.17.0", "1.17.0-beta", "1.17.0-beta2", "1.17.0-rc0", "1.17.1", "1.17.2", "1.17.3", "1.17.4", "1.17.5", "1.17.6", "1.17.7", "1.18.0", "1.18.0-alpha", "1.18.0-alpha2", "1.19.0", "1.19.1", "1.19.2", "1.2.0", "1.2.0-beta", "1.2.0-beta1", "1.2.0-rc0", "1.2.1", "1.2.2", "1.2.3", "1.2.4", "1.20.0", "1.20.1", "1.21.0", "1.21.1", "1.21.2", "1.22.0", "1.22.0-beta0", "1.22.1", "1.22.2", "1.23.0", - "1.23.1", "1.23.2", "1.23.3", "1.23.4", "1.23.5", "1.24.0", "1.24.1", "1.24.2", "1.24.3", "1.24.4", "1.3.0", "1.3.0-beta0", "1.3.0-rc0", "1.3.1", "1.3.2", "1.3.3", "1.3.4", "1.3.5", "1.3.6", "1.4.0", "1.4.0-beta0", "1.4.0-beta1", "1.4.1", "1.4.2", "1.4.3", "1.5.0", "1.5.0-rc0", "1.5.0-rc1", "1.5.0-rc2", "1.5.0-rc3", "1.5.0-rc4", "1.5.0-rc6", "1.5.1", "1.5.2", "1.5.3", "1.5.4", "1.5.5", "1.6.0", "1.6.0-rc0", "1.6.1", "1.6.2", "1.6.3", "1.7.0", "1.7.0-rc0", "1.7.0-rc1", "1.7.0-rc2", "1.8.0", "1.8.0-rc0", "1.8.0-rc1", "1.8.1", "1.8.2", "1.9.0", "1.9.0+dfsg", "1.9.0-rc0", "1.9.0-rc1", "1.9.1", "1.9.2", "1.9.2+dfsg", "1.9.3", "1.9.3+dfsg", "1.9.4", "1.9.4+dfsg", "1.9.5", "1.9.5+dfsg"] - expected_tags = ['1.0.0', '1.0.2', '1.1.0-rc0', '1.1.0', '1.1.2', '1.1.4', '1.1.5', '1.1.6', '1.1.7', '1.1.8', '1.1.9', '1.1.10', '1.1.11', '1.2.0-beta', '1.2.0-beta1', '1.2.0-rc0', '1.2.0', '1.2.1', '1.2.2', '1.2.3', '1.2.4', '1.3.0-beta0', '1.3.0-rc0', '1.3.0', '1.3.1', '1.3.2', '1.3.3', '1.3.4', '1.3.5', '1.3.6', '1.4.0-beta0', '1.4.0-beta1', '1.4.0', '1.4.1', '1.4.2', '1.4.3', '1.5.0-rc0', '1.5.0-rc1', '1.5.0-rc2', '1.5.0-rc3', '1.5.0-rc4', '1.5.0-rc6', '1.5.0', '1.5.1', '1.5.2', '1.5.3', '1.5.4', '1.5.5', '1.6.0-rc0', '1.6.0', '1.6.1', '1.6.2', '1.6.3', '1.7.0-rc0', '1.7.0-rc1', '1.7.0-rc2', '1.7.0', '1.8.0-rc0', '1.8.0-rc1', '1.8.0', '1.8.1', '1.8.2', '1.9.0-rc0', '1.9.0-rc1', - '1.9.0', '1.9.0+dfsg', '1.9.1', '1.9.2', '1.9.2+dfsg', '1.9.3', '1.9.3+dfsg', '1.9.4', '1.9.4+dfsg', '1.9.5', '1.9.5+dfsg', '1.10.0', '1.10.1', '1.10.2', '1.10.3', '1.11.0', '1.12.0', '1.13.0', '1.13.1', '1.14.0', '1.14.1', '1.15.0', '1.15.1', '1.15.2', '1.15.3', '1.16.0', '1.16.1', '1.16.2', '1.17.0-beta', '1.17.0-beta2', '1.17.0-rc0', '1.17.0', '1.17.1', '1.17.2', '1.17.3', '1.17.4', '1.17.5', '1.17.6', '1.17.7', '1.18.0-alpha', '1.18.0-alpha2', '1.18.0', '1.19.0', '1.19.1', '1.19.2', '1.20.0', '1.20.1', '1.21.0', '1.21.1', '1.21.2', '1.22.0-beta0', '1.22.0', '1.22.1', '1.22.2', '1.23.0', '1.23.1', '1.23.2', '1.23.3', '1.23.4', '1.23.5', '1.24.0', '1.24.1', '1.24.2', '1.24.3', '1.24.4'] - got_tags = sorted(input_tags, key=calc_release_version.Version) - self.assertEqual(got_tags, expected_tags) - - -if __name__ == "__main__": - unittest.main() diff --git a/build/calc_release_version_selftest.sh b/build/calc_release_version_selftest.sh deleted file mode 100755 index 0830e317f83..00000000000 --- a/build/calc_release_version_selftest.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env bash -# -# calc_release_version_selftest.sh is used to test output of calc_release_version.py. -# run with: -# cd build -# ./calc_release_version_selftest.sh - -set -o errexit -set -o pipefail - -function assert_eq () { - a="$1" - b="$2" - if [[ "$a" != "$b" ]]; then - echo "Assertion failed: $a != $b" - # Print caller - caller - exit 1 - fi -} - -SAVED_REF=$(git rev-parse HEAD) - -function cleanup () { - [[ -e calc_release_version_test.py ]] && rm calc_release_version_test.py - git checkout $SAVED_REF --quiet -} - -trap cleanup EXIT - -: ${PYTHON_INTERP:=python} -if [[ -z $(command -v "${PYTHON_INTERP}") ]]; then - echo "Python interpreter '${PYTHON_INTERP}' is not valid." - echo "Set the PYTHON_INTERP environment variable to a valid interpreter." - exit 1 -fi - -# copy calc_release_version.py to a separate file not tracked by git so it does not change on `git checkout` -cp calc_release_version.py calc_release_version_test.py - -echo "Test a tagged commit ... begin" -{ - git checkout 1.23.4 --quiet - got=$("${PYTHON_INTERP}" calc_release_version_test.py --debug) - assert_eq "$got" "1.23.4" - got=$("${PYTHON_INTERP}" calc_release_version_test.py --debug -p) - assert_eq "$got" "1.23.3" - git checkout - --quiet -} -echo "Test a tagged commit ... end" - -DATE=$(date +%Y%m%d) -echo "Test an untagged commit ... begin" -{ - # 42a818429d6d586a6abf22367ac6fea1e9ce3f2c is commit before 1.23.4 - git checkout 42a818429d6d586a6abf22367ac6fea1e9ce3f2c --quiet - got=$("${PYTHON_INTERP}" calc_release_version_test.py --debug) - assert_eq "$got" "1.23.4-$DATE+git42a818429d" - got=$("${PYTHON_INTERP}" calc_release_version_test.py --debug -p) - assert_eq "$got" "1.23.4" - git checkout - --quiet -} -echo "Test an untagged commit ... end" - -echo "Test next minor version ... begin" -{ - CURRENT_SHORTREF=$(git rev-parse --revs-only --short=10 HEAD) - got=$("${PYTHON_INTERP}" calc_release_version_test.py --debug --next-minor) - # XXX NOTE XXX NOTE XXX - # If you find yourself looking at this line because the assertion below - # failed, then it is probably because a new major/minor release was made. - # Update the expected output to represent the correct next version. - # XXX NOTE XXX NOTE XXX - assert_eq "$got" "1.25.0-$DATE+git$CURRENT_SHORTREF" - got=$("${PYTHON_INTERP}" calc_release_version_test.py --debug --next-minor -p) - # XXX NOTE XXX NOTE XXX - # If you find yourself looking at this line because the assertion below - # failed, then it is probably because a new major/minor release was made. - # Update the expected output to represent the correct next version. - # XXX NOTE XXX NOTE XXX - assert_eq "$got" "1.24.4" -} -echo "Test next minor version ... end" - -echo "All tests passed" diff --git a/build/cmake/BuildVersion.cmake b/build/cmake/BuildVersion.cmake index 18d29a0c218..b6d0e6601ed 100644 --- a/build/cmake/BuildVersion.cmake +++ b/build/cmake/BuildVersion.cmake @@ -1,16 +1,8 @@ include_guard(GLOBAL) -include(MongoSettings) - -# We use Python to calculate the BUILD_VERSION value -find_package(Python COMPONENTS Interpreter) - -set(_CALC_VERSION_PY "${CMAKE_CURRENT_LIST_DIR}/../calc_release_version.py") - #[[ - Attempts to find the current build version string. If VERSION_CURRENT exists - in the current source directory, uses that. Otherwise, runs calc_release_version.py - to compute the version from the Git history. + Attempts to find the current build version string by reading VERSION_CURRENT + from the current source directory. The computed build version is set in the parent scope according to `outvar`. ]] @@ -18,32 +10,10 @@ function(compute_build_version outvar) list(APPEND CMAKE_MESSAGE_CONTEXT ${CMAKE_CURRENT_FUNCTION}) # If it is present, defer to the VERSION_CURRENT file: set(ver_cur_file "${CMAKE_CURRENT_SOURCE_DIR}/VERSION_CURRENT") - if(EXISTS "${ver_cur_file}") - message(DEBUG "Using existing VERSION_CURRENT file as BUILD_VERSION [${ver_cur_file}]") - file(READ "${ver_cur_file}" version) - set("${outvar}" "${version}" PARENT_SCOPE) - return() - endif() - # Otherwise, we require Python: - if(NOT TARGET Python::Interpreter) - message(WARNING "No default build version could be calculated (Python was not found)") - set("${outvar}" "0.0.0-unknown+no-python-found") - return() - endif() - get_target_property(py Python::Interpreter IMPORTED_LOCATION) - message(STATUS "Computing the current release version...") - execute_process( - COMMAND "${py}" "${_CALC_VERSION_PY}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - OUTPUT_VARIABLE output - RESULT_VARIABLE retc - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(retc) - message(FATAL_ERROR "Computing the build version failed! [${retc}]:\n${out}") - endif() - message(DEBUG "calc_release_version.py returned output: “${output}”") - set("${outvar}" "${output}" PARENT_SCOPE) + message(DEBUG "Using existing VERSION_CURRENT file as BUILD_VERSION [${ver_cur_file}]") + file(READ "${ver_cur_file}" version) + message(DEBUG "VERSION_CURRENT is “${version}”") + set("${outvar}" "${version}" PARENT_SCOPE) endfunction() # Compute the BUILD_VERSION if it is not already defined: diff --git a/build/sphinx/homepage-config/conf.py b/build/sphinx/homepage-config/conf.py index 8690810488f..f1fae6c5e7b 100644 --- a/build/sphinx/homepage-config/conf.py +++ b/build/sphinx/homepage-config/conf.py @@ -9,9 +9,8 @@ from mongoc_common import * -version = release = os.environ.get('VERSION_RELEASED') -if not release: - raise RuntimeError('Set the "VERSION_RELEASED" environment variable') +with open(this_path + '/../../../VERSION_CURRENT') as vc: + release = version = vc.read() # -- General configuration ------------------------------------------------ templates_path = ['_templates'] diff --git a/docs/dev/earthly.rst b/docs/dev/earthly.rst index 2bbfb838da8..d216fc81c47 100644 --- a/docs/dev/earthly.rst +++ b/docs/dev/earthly.rst @@ -56,11 +56,11 @@ run Earthly from the ``mongo-c-driver`` repository, use `tools/earthly.sh`. Testing Earthly =============== -To verify that Earthly is running, execute the `+version-current` Earthly +To verify that Earthly is running, execute the ``+env.u20`` Earthly target. This will exercise most Earthly functionality without requiring any special parameters or modifying the working directory:: - $ ./tools/earthly.sh +version-current + $ ./tools/earthly.sh +env.u20 Init 🚀 ———————————————————————————————————————————————————————————————————————————————— @@ -193,14 +193,6 @@ enumerated using ``earthly ls`` or ``earthly doc`` in the root of the repository authenticated with the host.\ [#creds]_ If you are already authenticated, this command will have no effect. -.. earthly-target:: +version-current - - Generates a ``VERSION_CURRENT`` file for the current repository. - - .. earthly-artifact:: +version-current/VERSION_CURRENT - - A plaintext file containing the current version number. - .. earthly-target:: +sbom-generate Updates the `etc/cyclonedx.sbom.json` file **in-place** based on the contents diff --git a/docs/dev/files.rst b/docs/dev/files.rst new file mode 100644 index 00000000000..baffd6bbcfe --- /dev/null +++ b/docs/dev/files.rst @@ -0,0 +1,37 @@ +################ +Repository Files +################ + +The files discussed here are relevant to the project, but do not fit under +other categories + + +Versioning Files +################ + +.. file:: VERSION_CURRENT + + This file contains the full version number of the current working copy of the + project. During development, this should be ``x.y.z-dev``. On tagged commits, + this will have the prerelease tag removed. + + .. note:: + + Previously, this file was auto-generated by inspecting the Git history. This + proved to be somewhat finicky and depended on the local Git history to have + all the proper metadata in place, which wasn't always reliable. + + .. note:: + + The version number ``x.y.z`` in this file is read by CMake at configure-time + and is used as the version number for the ``project()`` call in the + top-level ``CMakeLists.txt`` + + +.. file:: etc/prior_version.txt + + This file, like `VERSION_CURRENT`, contains a version number string. Instead + of referring to the current working copy version, this refers to the most + recent stable release. This is used by various tasks to "compare" the working + copy against the stable version. This version number should correspond to a + published Git tag. diff --git a/docs/dev/index.rst b/docs/dev/index.rst index 56a953f7cf4..4167aa41959 100644 --- a/docs/dev/index.rst +++ b/docs/dev/index.rst @@ -22,6 +22,7 @@ the mongo-c-driver project directory: debian earthly deps + files .. Add the `releasing` page to a hidden toctree. We don't want to include it directly in a visible toctree because the top-level sections would render inline diff --git a/docs/dev/releasing.rst b/docs/dev/releasing.rst index d4fbc960528..45e41ab1853 100644 --- a/docs/dev/releasing.rst +++ b/docs/dev/releasing.rst @@ -346,7 +346,7 @@ to post the release to GitHub: $ python $CDRIVER_TOOLS/release.py upload $GITHUB_TOKEN -Update the ``VERSION_CURRENT`` file on the release branch:: +Update the :file:`VERSION_CURRENT` file on the release branch:: $ python $CDRIVER_TOOLS/release.py post_release_bump @@ -464,12 +464,17 @@ publish a PR to merge the updates to the release files back into ``master``:: (Here we have named the branch ``post-release-merge``, but the branch name is arbitrary.) -Manually update the ``NEWS`` and ``src/libbson/NEWS`` files with the content -from the release branch that we just published. Commit these changes to the new -branch. - -For a minor release, manually update the ``VERSION_CURRENT`` file. Example if -``1.28.0`` was just released, update to ``1.29.0-dev``. +Do the following: + +1. Manually update the ``NEWS`` and ``src/libbson/NEWS`` files with the content + from the release branch that we just published. Commit these changes to the + new branch. +2. For a non-patch release, manually update the :file:`VERSION_CURRENT` file. + Example: if ``1.28.0`` was just released, update to ``1.29.0-dev``. +3. For a non-patch release, update the :file:`etc/prior_version.txt` file to + contain the version that you have just released. This text should match the + generated Git tag. (The tag should always be an ancestor of the branch that + contains that :file:`etc/prior_version.txt`.) Push this branch to your fork of the repository:: diff --git a/etc/prior_version.txt b/etc/prior_version.txt new file mode 100644 index 00000000000..db66ff9be86 --- /dev/null +++ b/etc/prior_version.txt @@ -0,0 +1 @@ +1.30.2 \ No newline at end of file