diff --git a/.github/workflows/ansible-test.yml b/.github/workflows/ansible-test.yml index ad0121232..4431bea5a 100644 --- a/.github/workflows/ansible-test.yml +++ b/.github/workflows/ansible-test.yml @@ -26,12 +26,6 @@ jobs: ansible: # It's important that Sanity is tested against all stable-X.Y branches # Testing against `devel` may fail as new tests are added. - - stable-2.9 - - stable-2.10 - - stable-2.11 - - stable-2.12 - - stable-2.13 - - stable-2.14 - stable-2.15 - stable-2.16 - stable-2.17 @@ -54,10 +48,9 @@ jobs: ansible-core-version: ${{ matrix.ansible }} codecov-token: ${{ secrets.CODECOV_TOKEN }} testing-type: sanity - # NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429) - pre-test-cmd: |- - git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.netcommon.git ../../ansible/netcommon - git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.utils.git ../../ansible/utils + test-deps: >- + git+https://github.com/ansible-collections/ansible.utils.git,main + git+https://github.com/ansible-collections/ansible.netcommon.git,main units: # Ansible-test on various stable branches does not yet work well with cgroups v2. @@ -75,13 +68,6 @@ jobs: fail-fast: true matrix: ansible: - - stable-2.9 - - stable-2.10 - - stable-2.11 - - stable-2.12 - - stable-2.13 - - stable-2.14 - - stable-2.15 - stable-2.16 - stable-2.17 - stable-2.18 @@ -97,10 +83,9 @@ jobs: ansible-core-version: ${{ matrix.ansible }} codecov-token: ${{ secrets.CODECOV_TOKEN }} testing-type: units - # NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429) - pre-test-cmd: |- - git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.netcommon.git ../../ansible/netcommon - git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.utils.git ../../ansible/utils + test-deps: >- + git+https://github.com/ansible-collections/ansible.utils.git,main + git+https://github.com/ansible-collections/ansible.netcommon.git,main integration: # Ansible-test on various stable branches does not yet work well with cgroups v2. @@ -122,41 +107,24 @@ jobs: - "3.10" - "3.11" - "3.12" + - "3.13" include: - # 2.9 - - ansible: stable-2.9 - python: 2.7 - - ansible: stable-2.9 - python: 3.5 - # 2.10 - - ansible: stable-2.10 - python: 3.5 - # 2.11 - - ansible: stable-2.11 - python: 2.7 - - ansible: stable-2.11 - python: 3.6 - # 2.12 - - ansible: stable-2.12 - python: 3.8 - # 2.13 - - ansible: stable-2.13 - python: "3.10" - # 2.14 - - ansible: stable-2.14 - python: "3.11" # 2.15 - ansible: stable-2.15 - python: "3.9" + python: "2.7" + - ansible: stable-2.15 + python: "3.6" + - ansible: stable-2.15 + python: "3.7" # 2.16 - ansible: stable-2.16 python: "3.10" # 2.17 - ansible: stable-2.17 - python: "3.7" + python: "3.8" # 2.18 - ansible: stable-2.18 - python: "3.8" + python: "3.9" steps: - name: >- @@ -171,9 +139,8 @@ jobs: integration-continue-on-error: 'false' integration-diff: 'false' integration-retry-on-error: 'true' - # NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429) - pre-test-cmd: |- - git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.netcommon.git ../../ansible/netcommon - git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.utils.git ../../ansible/utils + test-deps: >- + git+https://github.com/ansible-collections/ansible.utils.git,main + git+https://github.com/ansible-collections/ansible.netcommon.git,main target-python-version: ${{ matrix.python }} testing-type: integration diff --git a/.github/workflows/ee.yml b/.github/workflows/ee.yml index cd6341f43..9d6f3fd5f 100644 --- a/.github/workflows/ee.yml +++ b/.github/workflows/ee.yml @@ -57,11 +57,6 @@ jobs: ansible_runner: ansible-runner base_image: quay.io/rockylinux/rockylinux:9 pre_base: '"#"' - - name: ansible-core 2.14 @ CentOS Stream 9 - ansible_core: https://github.com/ansible/ansible/archive/stable-2.14.tar.gz - ansible_runner: ansible-runner - base_image: quay.io/centos/centos:stream9 - pre_base: '"#"' runs-on: ubuntu-latest steps: - name: Check out code diff --git a/LICENSES/PSF-2.0.txt b/LICENSES/PSF-2.0.txt deleted file mode 100644 index 35acd7fb5..000000000 --- a/LICENSES/PSF-2.0.txt +++ /dev/null @@ -1,48 +0,0 @@ -PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 --------------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using this software ("Python") in source or binary form and -its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF hereby -grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, -analyze, test, perform and/or display publicly, prepare derivative works, -distribute, and otherwise use Python alone or in any derivative version, -provided, however, that PSF's License Agreement and PSF's notice of copyright, -i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Python Software Foundation; -All Rights Reserved" are retained in Python alone or in any derivative version -prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python. - -4. PSF is making Python available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. diff --git a/README.md b/README.md index a773b727f..f7b488d9c 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ For more information about communication, see the [Ansible communication guide]( ## Tested with Ansible -Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, ansible-core 2.16, ansible-core 2.17, and ansible-core 2.18 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported. +Tested with the current ansible-core 2.15, ansible-core 2.16, ansible-core 2.17, and ansible-core 2.18 releases and the current development version of ansible-core. Ansible 2.9, ansible-base 2.10, and ansible-core versions before 2.15.0 are not supported. ## External requirements diff --git a/changelogs/fragments/3.0.0.yml b/changelogs/fragments/3.0.0.yml new file mode 100644 index 000000000..4a71c2f3d --- /dev/null +++ b/changelogs/fragments/3.0.0.yml @@ -0,0 +1,7 @@ +release_summary: Major release that drops support for End of Life Python versions and fixes check mode for community.routeros.command. +removed_features: + - "The collection no longer supports Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, and ansible-core 2.14. + If you need to continue using End of Life versions of Ansible/ansible-base/ansible-core, please use community.routeros 2.x.y + (https://github.com/ansible-collections/community.routeros/pull/318)." +breaking_changes: + - "command - the module no longer declares that it supports check mode (https://github.com/ansible-collections/community.routeros/pull/318)." diff --git a/galaxy.yml b/galaxy.yml index 7c40edafa..15084671e 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -7,7 +7,7 @@ namespace: community name: routeros -version: 2.20.0 +version: 3.0.0 readme: README.md authors: - Egor Zaitsev (github.com/heuels) diff --git a/meta/runtime.yml b/meta/runtime.yml index 5aafd31d0..aae1259ac 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -3,7 +3,7 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -requires_ansible: '>=2.9.10' +requires_ansible: '>=2.15.0' action_groups: api: - api diff --git a/plugins/module_utils/_version.py b/plugins/module_utils/_version.py deleted file mode 100644 index f7954074e..000000000 --- a/plugins/module_utils/_version.py +++ /dev/null @@ -1,345 +0,0 @@ -# Vendored copy of distutils/version.py from CPython 3.9.5 -# -# Implements multiple version numbering conventions for the -# Python Module Distribution Utilities. -# -# Copyright (c) 2001-2022 Python Software Foundation. All rights reserved. -# PSF License (see LICENSES/PSF-2.0.txt or https://opensource.org/licenses/Python-2.0) -# SPDX-License-Identifier: PSF-2.0 -# - -"""Provides classes to represent module version numbers (one class for -each style of version numbering). There are currently two such classes -implemented: StrictVersion and LooseVersion. - -Every version number class implements the following interface: - * the 'parse' method takes a string and parses it to some internal - representation; if the string is an invalid version number, - 'parse' raises a ValueError exception - * the class constructor takes an optional string argument which, - if supplied, is passed to 'parse' - * __str__ reconstructs the string that was passed to 'parse' (or - an equivalent string -- ie. one that will generate an equivalent - version number instance) - * __repr__ generates Python code to recreate the version number instance - * _cmp compares the current instance with either another instance - of the same class or a string (which will be parsed to an instance - of the same class, thus must follow the same rules) -""" - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import re - -try: - RE_FLAGS = re.VERBOSE | re.ASCII -except AttributeError: - RE_FLAGS = re.VERBOSE - - -class Version: - """Abstract base class for version numbering classes. Just provides - constructor (__init__) and reproducer (__repr__), because those - seem to be the same for all version numbering classes; and route - rich comparisons to _cmp. - """ - - def __init__(self, vstring=None): - if vstring: - self.parse(vstring) - - def __repr__(self): - return "%s ('%s')" % (self.__class__.__name__, str(self)) - - def __eq__(self, other): - c = self._cmp(other) - if c is NotImplemented: - return c - return c == 0 - - def __lt__(self, other): - c = self._cmp(other) - if c is NotImplemented: - return c - return c < 0 - - def __le__(self, other): - c = self._cmp(other) - if c is NotImplemented: - return c - return c <= 0 - - def __gt__(self, other): - c = self._cmp(other) - if c is NotImplemented: - return c - return c > 0 - - def __ge__(self, other): - c = self._cmp(other) - if c is NotImplemented: - return c - return c >= 0 - - -# Interface for version-number classes -- must be implemented -# by the following classes (the concrete ones -- Version should -# be treated as an abstract class). -# __init__ (string) - create and take same action as 'parse' -# (string parameter is optional) -# parse (string) - convert a string representation to whatever -# internal representation is appropriate for -# this style of version numbering -# __str__ (self) - convert back to a string; should be very similar -# (if not identical to) the string supplied to parse -# __repr__ (self) - generate Python code to recreate -# the instance -# _cmp (self, other) - compare two version numbers ('other' may -# be an unparsed version string, or another -# instance of your version class) - - -class StrictVersion(Version): - """Version numbering for anal retentives and software idealists. - Implements the standard interface for version number classes as - described above. A version number consists of two or three - dot-separated numeric components, with an optional "pre-release" tag - on the end. The pre-release tag consists of the letter 'a' or 'b' - followed by a number. If the numeric components of two version - numbers are equal, then one with a pre-release tag will always - be deemed earlier (lesser) than one without. - - The following are valid version numbers (shown in the order that - would be obtained by sorting according to the supplied cmp function): - - 0.4 0.4.0 (these two are equivalent) - 0.4.1 - 0.5a1 - 0.5b3 - 0.5 - 0.9.6 - 1.0 - 1.0.4a3 - 1.0.4b1 - 1.0.4 - - The following are examples of invalid version numbers: - - 1 - 2.7.2.2 - 1.3.a4 - 1.3pl1 - 1.3c4 - - The rationale for this version numbering system will be explained - in the distutils documentation. - """ - - version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$', - RE_FLAGS) - - def parse(self, vstring): - match = self.version_re.match(vstring) - if not match: - raise ValueError("invalid version number '%s'" % vstring) - - (major, minor, patch, prerelease, prerelease_num) = \ - match.group(1, 2, 4, 5, 6) - - if patch: - self.version = tuple(map(int, [major, minor, patch])) - else: - self.version = tuple(map(int, [major, minor])) + (0,) - - if prerelease: - self.prerelease = (prerelease[0], int(prerelease_num)) - else: - self.prerelease = None - - def __str__(self): - if self.version[2] == 0: - vstring = '.'.join(map(str, self.version[0:2])) - else: - vstring = '.'.join(map(str, self.version)) - - if self.prerelease: - vstring = vstring + self.prerelease[0] + str(self.prerelease[1]) - - return vstring - - def _cmp(self, other): - if isinstance(other, str): - other = StrictVersion(other) - elif not isinstance(other, StrictVersion): - return NotImplemented - - if self.version != other.version: - # numeric versions don't match - # prerelease stuff doesn't matter - if self.version < other.version: - return -1 - else: - return 1 - - # have to compare prerelease - # case 1: neither has prerelease; they're equal - # case 2: self has prerelease, other doesn't; other is greater - # case 3: self doesn't have prerelease, other does: self is greater - # case 4: both have prerelease: must compare them! - - if (not self.prerelease and not other.prerelease): - return 0 - elif (self.prerelease and not other.prerelease): - return -1 - elif (not self.prerelease and other.prerelease): - return 1 - elif (self.prerelease and other.prerelease): - if self.prerelease == other.prerelease: - return 0 - elif self.prerelease < other.prerelease: - return -1 - else: - return 1 - else: - raise AssertionError("never get here") - -# end class StrictVersion - -# The rules according to Greg Stein: -# 1) a version number has 1 or more numbers separated by a period or by -# sequences of letters. If only periods, then these are compared -# left-to-right to determine an ordering. -# 2) sequences of letters are part of the tuple for comparison and are -# compared lexicographically -# 3) recognize the numeric components may have leading zeroes -# -# The LooseVersion class below implements these rules: a version number -# string is split up into a tuple of integer and string components, and -# comparison is a simple tuple comparison. This means that version -# numbers behave in a predictable and obvious way, but a way that might -# not necessarily be how people *want* version numbers to behave. There -# wouldn't be a problem if people could stick to purely numeric version -# numbers: just split on period and compare the numbers as tuples. -# However, people insist on putting letters into their version numbers; -# the most common purpose seems to be: -# - indicating a "pre-release" version -# ('alpha', 'beta', 'a', 'b', 'pre', 'p') -# - indicating a post-release patch ('p', 'pl', 'patch') -# but of course this can't cover all version number schemes, and there's -# no way to know what a programmer means without asking him. -# -# The problem is what to do with letters (and other non-numeric -# characters) in a version number. The current implementation does the -# obvious and predictable thing: keep them as strings and compare -# lexically within a tuple comparison. This has the desired effect if -# an appended letter sequence implies something "post-release": -# eg. "0.99" < "0.99pl14" < "1.0", and "5.001" < "5.001m" < "5.002". -# -# However, if letters in a version number imply a pre-release version, -# the "obvious" thing isn't correct. Eg. you would expect that -# "1.5.1" < "1.5.2a2" < "1.5.2", but under the tuple/lexical comparison -# implemented here, this just isn't so. -# -# Two possible solutions come to mind. The first is to tie the -# comparison algorithm to a particular set of semantic rules, as has -# been done in the StrictVersion class above. This works great as long -# as everyone can go along with bondage and discipline. Hopefully a -# (large) subset of Python module programmers will agree that the -# particular flavour of bondage and discipline provided by StrictVersion -# provides enough benefit to be worth using, and will submit their -# version numbering scheme to its domination. The free-thinking -# anarchists in the lot will never give in, though, and something needs -# to be done to accommodate them. -# -# Perhaps a "moderately strict" version class could be implemented that -# lets almost anything slide (syntactically), and makes some heuristic -# assumptions about non-digits in version number strings. This could -# sink into special-case-hell, though; if I was as talented and -# idiosyncratic as Larry Wall, I'd go ahead and implement a class that -# somehow knows that "1.2.1" < "1.2.2a2" < "1.2.2" < "1.2.2pl3", and is -# just as happy dealing with things like "2g6" and "1.13++". I don't -# think I'm smart enough to do it right though. -# -# In any case, I've coded the test suite for this module (see -# ../test/test_version.py) specifically to fail on things like comparing -# "1.2a2" and "1.2". That's not because the *code* is doing anything -# wrong, it's because the simple, obvious design doesn't match my -# complicated, hairy expectations for real-world version numbers. It -# would be a snap to fix the test suite to say, "Yep, LooseVersion does -# the Right Thing" (ie. the code matches the conception). But I'd rather -# have a conception that matches common notions about version numbers. - - -class LooseVersion(Version): - """Version numbering for anarchists and software realists. - Implements the standard interface for version number classes as - described above. A version number consists of a series of numbers, - separated by either periods or strings of letters. When comparing - version numbers, the numeric components will be compared - numerically, and the alphabetic components lexically. The following - are all valid version numbers, in no particular order: - - 1.5.1 - 1.5.2b2 - 161 - 3.10a - 8.02 - 3.4j - 1996.07.12 - 3.2.pl0 - 3.1.1.6 - 2g6 - 11g - 0.960923 - 2.2beta29 - 1.13++ - 5.5.kw - 2.0b1pl0 - - In fact, there is no such thing as an invalid version number under - this scheme; the rules for comparison are simple and predictable, - but may not always give the results you want (for some definition - of "want"). - """ - - component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE) - - def __init__(self, vstring=None): - if vstring: - self.parse(vstring) - - def parse(self, vstring): - # I've given up on thinking I can reconstruct the version string - # from the parsed tuple -- so I just store the string here for - # use by __str__ - self.vstring = vstring - components = [x for x in self.component_re.split(vstring) if x and x != '.'] - for i, obj in enumerate(components): - try: - components[i] = int(obj) - except ValueError: - pass - - self.version = components - - def __str__(self): - return self.vstring - - def __repr__(self): - return "LooseVersion ('%s')" % str(self) - - def _cmp(self, other): - if isinstance(other, str): - other = LooseVersion(other) - elif not isinstance(other, LooseVersion): - return NotImplemented - - if self.version == other.version: - return 0 - if self.version < other.version: - return -1 - if self.version > other.version: - return 1 - -# end class LooseVersion diff --git a/plugins/module_utils/version.py b/plugins/module_utils/version.py index dc01ffe8f..cc3028c3e 100644 --- a/plugins/module_utils/version.py +++ b/plugins/module_utils/version.py @@ -10,9 +10,4 @@ __metaclass__ = type -# Once we drop support for Ansible 2.9, ansible-base 2.10, and ansible-core 2.11, we can -# remove the _version.py file, and replace the following import by -# -# from ansible.module_utils.compat.version import LooseVersion - -from ._version import LooseVersion # noqa: F401, pylint: disable=unused-import +from ansible.module_utils.compat.version import LooseVersion # pylint: disable=unused-import diff --git a/plugins/modules/command.py b/plugins/modules/command.py index 52b916ba2..bf74d4745 100644 --- a/plugins/modules/command.py +++ b/plugins/modules/command.py @@ -20,16 +20,14 @@ - The module always indicates a (changed) status. You can use R(the changed_when task property,override_the_changed_result) to determine whether a command task actually resulted in a change or not. -notes: - - The module declares that it B(supports check mode). This is a bug and will - be changed in community.routeros 3.0.0. extends_documentation_fragment: - community.routeros.attributes attributes: check_mode: - support: partial + support: none details: - - The module claims to support check mode, but it simply always executes the command. + - Before community.routeros 3.0.0, the module claimed to support check mode. + It simply executed the command in check mode. diff_mode: support: none platform: @@ -165,7 +163,7 @@ def main(): argument_spec.update(routeros_argument_spec) module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True) + supports_check_mode=False) result = {'changed': False} diff --git a/tests/sanity/extra/update-docs.json b/tests/sanity/extra/update-docs.json index 029699f0f..3a63af889 100644 --- a/tests/sanity/extra/update-docs.json +++ b/tests/sanity/extra/update-docs.json @@ -4,5 +4,8 @@ "docs/docsite/rst/api-guide.rst", "plugins/modules/" ], - "output": "path-line-column-message" + "output": "path-line-column-message", + "requirements": [ + "ansible-core" + ] } diff --git a/tests/sanity/extra/update-docs.py b/tests/sanity/extra/update-docs.py index 68e2edf87..601551267 100644 --- a/tests/sanity/extra/update-docs.py +++ b/tests/sanity/extra/update-docs.py @@ -12,7 +12,7 @@ def main(): """Main entry point.""" - p = subprocess.run(['./update-docs.py'], check=False) + p = subprocess.run([sys.executable, 'update-docs.py'], check=False) if p.returncode not in (0, 1): print('{0}:0:0: unexpected return code {1}'.format(sys.argv[0], p.returncode))