diff options
Diffstat (limited to 'packaging')
-rw-r--r-- | packaging/release/Makefile | 61 | ||||
-rw-r--r-- | packaging/release/tests/__init__.py | 0 | ||||
-rw-r--r-- | packaging/release/tests/version_helper_test.py | 47 | ||||
-rw-r--r-- | packaging/release/versionhelper/__init__.py | 0 | ||||
-rw-r--r-- | packaging/release/versionhelper/version_helper.py | 195 | ||||
-rwxr-xr-x | packaging/sdist/check-link-behavior.py | 51 |
6 files changed, 354 insertions, 0 deletions
diff --git a/packaging/release/Makefile b/packaging/release/Makefile new file mode 100644 index 0000000..d1ff8f8 --- /dev/null +++ b/packaging/release/Makefile @@ -0,0 +1,61 @@ +version ?= $(shell python versionhelper/version_helper.py --raw) + +.PHONY: all +all: + @echo "USAGE:" + @echo + @echo "make release version={version} # current version is '${version}'" + @echo "make publish" + @echo + @echo "NOTE: Make sure to source hacking/env-setup before running these targets." + +.PHONY: release +release: version summary changelog commit-release + git show -p + git status + @echo + @echo 'Run `git push` if you are satisfied with the changes.' + +.PHONY: version +version: + sed -i.bak "s/^__version__ = .*$$/__version__ = '${version}'/" ../../lib/ansible/release.py + rm ../../lib/ansible/release.py.bak + +.PHONY: summary +summary: + @printf '%s\n%s\n%s\n' \ + 'release_summary: |' \ + ' | Release Date: $(shell date '+%Y-%m-%d')' \ + ' | `Porting Guide <https://docs.ansible.com/ansible/devel/porting_guides.html>`__' > \ + ../../changelogs/fragments/v${version}_summary.yaml + +.PHONY: changelog +changelog: + antsibull-changelog release -vv --use-ansible-doc && antsibull-changelog generate -vv --use-ansible-doc + ansible-test sanity changelogs/ + +.PHONY: commit-release +commit-release: + git add ../../changelogs/ ../../lib/ansible/release.py + git commit -m "New release v${version}" + +.PHONY: publish +publish: tag postversion commit-postversion + git show -p + git status + @echo + @echo 'Run `git push --follow-tags` if you are satisfied with the changes.' + +.PHONY: tag +tag: + git tag -a v${version} -m "New release v${version}" + +.PHONY: postversion +postversion: + sed -i.bak "s/^__version__ = .*$$/__version__ = '${version}.post0'/" ../../lib/ansible/release.py + rm ../../lib/ansible/release.py.bak + +.PHONY: commit-postversion +commit-postversion: + git add ../../lib/ansible/release.py + git commit -m "Update Ansible release version to v${version}." diff --git a/packaging/release/tests/__init__.py b/packaging/release/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/packaging/release/tests/__init__.py diff --git a/packaging/release/tests/version_helper_test.py b/packaging/release/tests/version_helper_test.py new file mode 100644 index 0000000..ff14bd4 --- /dev/null +++ b/packaging/release/tests/version_helper_test.py @@ -0,0 +1,47 @@ +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import pytest + +from packaging.version import InvalidVersion +from versionhelper.version_helper import AnsibleVersionMunger + + +@pytest.mark.parametrize('version,revision,codename,output_propname,expected', [ + ('2.5.0.dev1', None, None, 'raw', '2.5.0.dev1'), + ('2.5.0a0.post0', None, None, 'raw', '2.5.0a0.post0'), + ('2.5.0', None, None, 'raw', '2.5.0'), + ('2.5.0.dev1', None, None, 'major_version', '2.5'), + ('2.5.0', None, None, 'major_version', '2.5'), + ('2.5.0.dev1', None, None, 'base_version', '2.5.0'), + ('2.5.0', None, None, 'base_version', '2.5.0'), + ('2.5.0.dev1', None, None, 'deb_version', '2.5.0~dev1'), + ('2.5.0b1', None, None, 'deb_version', '2.5.0~b1'), + ('2.5.0b1.dev1', None, None, 'deb_version', '2.5.0~b1~dev1'), + ('2.5.0b1.post0', None, None, 'deb_version', '2.5.0~b1~post0'), + ('2.5.0', None, None, 'deb_version', '2.5.0'), + ('2.5.0.dev1', None, None, 'deb_release', '1'), + ('2.5.0b1', 2, None, 'deb_release', '2'), + ('2.5.0.dev1', None, None, 'rpm_release', '0.1.dev1'), + ('2.5.0a1', None, None, 'rpm_release', '0.101.a1'), + ('2.5.0a1.post0', None, None, 'rpm_release', '0.101.a1.post0'), + ('2.5.0b1', None, None, 'rpm_release', '0.201.b1'), + ('2.5.0rc1', None, None, 'rpm_release', '0.1001.rc1'), + ('2.5.0rc1', '0.99', None, 'rpm_release', '0.99.rc1'), + ('2.5.0.rc.1', None, None, 'rpm_release', '0.1001.rc.1'), + ('2.5.0.rc1.dev1', None, None, 'rpm_release', '0.1001.rc1.dev1'), + ('2.5.0', None, None, 'rpm_release', '1'), + ('2.5.0', 2, None, 'rpm_release', '2'), + ('2.5.0', None, None, 'codename', 'UNKNOWN'), + ('2.5.0', None, 'LedZeppelinSongHere', 'codename', 'LedZeppelinSongHere'), + ('2.5.0x1', None, None, None, InvalidVersion) +]) +def test_output_values(version, revision, codename, output_propname, expected): + try: + v = AnsibleVersionMunger(version, revision, codename) + assert getattr(v, output_propname) == expected + except Exception as ex: + if isinstance(expected, type): + assert isinstance(ex, expected) + else: + raise diff --git a/packaging/release/versionhelper/__init__.py b/packaging/release/versionhelper/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/packaging/release/versionhelper/__init__.py diff --git a/packaging/release/versionhelper/version_helper.py b/packaging/release/versionhelper/version_helper.py new file mode 100644 index 0000000..163494b --- /dev/null +++ b/packaging/release/versionhelper/version_helper.py @@ -0,0 +1,195 @@ +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import argparse +import os +import re +import sys + +from packaging.version import Version, VERSION_PATTERN + + +class AnsibleVersionMunger(object): + tag_offsets = dict( + dev=0, + a=100, + b=200, + rc=1000 + ) + + # TODO: allow overrides here for packaging bump etc + def __init__(self, raw_version, revision=None, codename=None): + self._raw_version = raw_version + self._revision = revision + self._parsed_version = Version(raw_version) + self._codename = codename + self._parsed_regex_match = re.match(VERSION_PATTERN, raw_version, re.VERBOSE | re.IGNORECASE) + + @property + def deb_version(self): + v = self._parsed_version + + match = self._parsed_regex_match + + # treat dev/post as prerelease for now; treat dev/post as equivalent and disallow together + if v.is_prerelease or match.group('dev') or match.group('post'): + if match.group('dev') and match.group('post'): + raise Exception("dev and post may not currently be used together") + if match.group('pre'): + tag_value = match.group('pre') + tag_type = match.group('pre_l') + if match.group('dev'): + tag_value += ('~%s' % match.group('dev').strip('.')) + if match.group('post'): + tag_value += ('~%s' % match.group('post').strip('.')) + elif match.group('dev'): + tag_type = "dev" + tag_value = match.group('dev').strip('.') + elif match.group('post'): + tag_type = "dev" + tag_value = match.group('post').strip('.') + else: + raise Exception("unknown prerelease type for version {0}".format(self._raw_version)) + else: + tag_type = None + tag_value = '' + + # not a pre/post/dev release, just return base version + if not tag_type: + return '{base_version}'.format(base_version=self.base_version) + + # it is a pre/dev release, include the tag value with a ~ + return '{base_version}~{tag_value}'.format(base_version=self.base_version, tag_value=tag_value) + + @property + def deb_release(self): + return '1' if self._revision is None else str(self._revision) + + @property + def rpm_release(self): + v = self._parsed_version + match = self._parsed_regex_match + + # treat presence of dev/post as prerelease for now; treat dev/post the same and disallow together + if v.is_prerelease or match.group('dev') or match.group('post'): + if match.group('dev') and match.group('post'): + raise Exception("dev and post may not currently be used together") + if match.group('pre'): + tag_value = match.group('pre') + tag_type = match.group('pre_l') + tag_ver = match.group('pre_n') + if match.group('dev'): + tag_value += match.group('dev') + if match.group('post'): + tag_value += match.group('post') + elif match.group('dev'): + tag_type = "dev" + tag_value = match.group('dev') + tag_ver = match.group('dev_n') + elif match.group('post'): + tag_type = "dev" + tag_value = match.group('post') + tag_ver = match.group('post_n') + else: + raise Exception("unknown prerelease type for version {0}".format(self._raw_version)) + else: + tag_type = None + tag_value = '' + tag_ver = 0 + + # not a pre/post/dev release, just append revision (default 1) + if not tag_type: + if self._revision is None: + self._revision = 1 + return '{revision}'.format(revision=self._revision) + + # cleanse tag value in case it starts with . + tag_value = tag_value.strip('.') + + # coerce to int and None == 0 + tag_ver = int(tag_ver if tag_ver else 0) + + if self._revision is None: + tag_offset = self.tag_offsets.get(tag_type) + if tag_offset is None: + raise Exception('no tag offset defined for tag {0}'.format(tag_type)) + pkgrel = '0.{0}'.format(tag_offset + tag_ver) + else: + pkgrel = self._revision + + return '{pkgrel}.{tag_value}'.format(pkgrel=pkgrel, tag_value=tag_value) + + @property + def raw(self): + return self._raw_version + + # return the x.y.z version without any other modifiers present + @property + def base_version(self): + return self._parsed_version.base_version + + # return the x.y version without any other modifiers present + @property + def major_version(self): + return re.match(r'^(\d+.\d+)', self._raw_version).group(1) + + @property + def codename(self): + return self._codename if self._codename else "UNKNOWN" + + +def main(): + parser = argparse.ArgumentParser(description='Extract/transform Ansible versions to various packaging formats') + + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('--raw', action='store_true') + group.add_argument('--majorversion', action='store_true') + group.add_argument('--baseversion', action='store_true') + group.add_argument('--debversion', action='store_true') + group.add_argument('--debrelease', action='store_true') + group.add_argument('--rpmrelease', action='store_true') + group.add_argument('--codename', action='store_true') + group.add_argument('--all', action='store_true') + + parser.add_argument('--revision', action='store', default='auto') + + args = parser.parse_args() + + mydir = os.path.dirname(__file__) + release_loc = os.path.normpath(mydir + '/../../../lib') + + sys.path.insert(0, release_loc) + + from ansible import release + + rev = None + if args.revision != 'auto': + rev = args.revision + + v_raw = release.__version__ + codename = release.__codename__ + v = AnsibleVersionMunger(v_raw, revision=rev, codename=codename) + + if args.raw: + print(v.raw) + elif args.baseversion: + print(v.base_version) + elif args.majorversion: + print(v.major_version) + elif args.debversion: + print(v.deb_version) + elif args.debrelease: + print(v.deb_release) + elif args.rpmrelease: + print(v.rpm_release) + elif args.codename: + print(v.codename) + elif args.all: + props = [name for (name, impl) in vars(AnsibleVersionMunger).items() if isinstance(impl, property)] + + for propname in props: + print('{0}: {1}'.format(propname, getattr(v, propname))) + + +if __name__ == '__main__': + main() diff --git a/packaging/sdist/check-link-behavior.py b/packaging/sdist/check-link-behavior.py new file mode 100755 index 0000000..34e0502 --- /dev/null +++ b/packaging/sdist/check-link-behavior.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +"""Checks for link behavior required for sdist to retain symlinks.""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import os +import platform +import shutil +import sys +import tempfile + + +def main(): + """Main program entry point.""" + temp_dir = tempfile.mkdtemp() + + target_path = os.path.join(temp_dir, 'file.txt') + symlink_path = os.path.join(temp_dir, 'symlink.txt') + hardlink_path = os.path.join(temp_dir, 'hardlink.txt') + + try: + with open(target_path, 'w'): + pass + + os.symlink(target_path, symlink_path) + os.link(symlink_path, hardlink_path) + + if not os.path.islink(symlink_path): + abort('Symbolic link not created.') + + if not os.path.islink(hardlink_path): + # known issue on MacOS (Darwin) + abort('Hard link of symbolic link created as a regular file.') + finally: + shutil.rmtree(temp_dir) + + +def abort(reason): + """ + :type reason: str + """ + sys.exit('ERROR: %s\n' + 'This will prevent symbolic links from being preserved in the resulting tarball.\n' + 'Aborting creation of sdist on platform: %s' + % (reason, platform.system())) + + +if __name__ == '__main__': + main() |