prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  no-changelog: check_collection_changelog
  check the collection structure to confirm if there is a changelog file present at the root of the directory. 
  
  rule should be optional and only enabled at users discretion. Error level should be Warn/Info (0)
  
  based off of code found [here ](https://github.com/ansible/galaxy-importer/blob/master/galaxy_importer/loaders/collection.py#L119)
  
  </issue>
  <code>
  [start of src/ansiblelint/rules/galaxy.py]
  1 """Implementation of GalaxyRule."""
  2 from __future__ import annotations
  3 
  4 import sys
  5 from functools import total_ordering
  6 from typing import TYPE_CHECKING, Any
  7 
  8 from ansiblelint.constants import LINE_NUMBER_KEY
  9 from ansiblelint.errors import MatchError
  10 from ansiblelint.rules import AnsibleLintRule
  11 
  12 if TYPE_CHECKING:
  13     from ansiblelint.file_utils import Lintable
  14 
  15 
  16 class GalaxyRule(AnsibleLintRule):
  17     """Rule for checking collection version is greater than 1.0.0."""
  18 
  19     id = "galaxy"
  20     description = "Confirm via galaxy.yml file if collection version is greater than or equal to 1.0.0"
  21     severity = "MEDIUM"
  22     tags = ["metadata", "opt-in", "experimental"]
  23     version_added = "v6.6.0 (last update)"
  24 
  25     def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]:
  26         """Return matches found for a specific play (entry in playbook)."""
  27         if file.kind != "galaxy":  # type: ignore
  28             return []
  29         if "version" not in data:
  30             return [
  31                 self.create_matcherror(
  32                     message="galaxy.yaml should have version tag.",
  33                     linenumber=data[LINE_NUMBER_KEY],
  34                     tag="galaxy[version-missing]",
  35                     filename=file,
  36                 )
  37             ]
  38         version = data.get("version")
  39         if Version(version) < Version("1.0.0"):
  40             return [
  41                 self.create_matcherror(
  42                     message="collection version should be greater than or equal to 1.0.0",
  43                     # pylint: disable=protected-access
  44                     linenumber=version._line_number,
  45                     tag="galaxy[version-incorrect]",
  46                     filename=file,
  47                 )
  48             ]
  49         return []
  50 
  51 
  52 @total_ordering
  53 class Version:
  54     """Simple class to compare arbitrary versions."""
  55 
  56     def __init__(self, version_string: str):
  57         """Construct a Version object."""
  58         self.components = version_string.split(".")
  59 
  60     def __eq__(self, other: object) -> bool:
  61         """Implement equality comparison."""
  62         other = _coerce(other)
  63         if not isinstance(other, Version):
  64             return NotImplemented
  65 
  66         return self.components == other.components
  67 
  68     def __lt__(self, other: Version) -> bool:
  69         """Implement lower-than operation."""
  70         other = _coerce(other)
  71         if not isinstance(other, Version):
  72             return NotImplemented
  73 
  74         return self.components < other.components
  75 
  76 
  77 def _coerce(other: object) -> Version:
  78     if isinstance(other, str):
  79         other = Version(other)
  80     if isinstance(other, (int, float)):
  81         other = Version(str(other))
  82     if isinstance(other, Version):
  83         return other
  84     raise NotImplementedError(f"Unable to coerce object type {type(other)} to Version")
  85 
  86 
  87 if "pytest" in sys.modules:  # noqa: C901
  88 
  89     from ansiblelint.rules import RulesCollection
  90     from ansiblelint.runner import Runner
  91 
  92     def test_galaxy_collection_version_positive() -> None:
  93         """Positive test for collection version in galaxy."""
  94         collection = RulesCollection()
  95         collection.register(GalaxyRule())
  96         success = "examples/collection/galaxy.yml"
  97         good_runner = Runner(success, rules=collection)
  98         assert [] == good_runner.run()
  99 
  100     def test_galaxy_collection_version_negative() -> None:
  101         """Negative test for collection version in galaxy."""
  102         collection = RulesCollection()
  103         collection.register(GalaxyRule())
  104         failure = "examples/meta/galaxy.yml"
  105         bad_runner = Runner(failure, rules=collection)
  106         errs = bad_runner.run()
  107         assert len(errs) == 1
  108
  [end of src/ansiblelint/rules/galaxy.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/src/ansiblelint/rules/galaxy.py b/src/ansiblelint/rules/galaxy.py
  --- a/src/ansiblelint/rules/galaxy.py
  +++ b/src/ansiblelint/rules/galaxy.py
  @@ -1,6 +1,7 @@
   """Implementation of GalaxyRule."""
   from __future__ import annotations
   
  +import os
   import sys
   from functools import total_ordering
   from typing import TYPE_CHECKING, Any
  @@ -14,10 +15,10 @@
   
   
   class GalaxyRule(AnsibleLintRule):
  -    """Rule for checking collection version is greater than 1.0.0."""
  +    """Rule for checking collection version is greater than 1.0.0 and checking for changelog."""
   
       id = "galaxy"
  -    description = "Confirm via galaxy.yml file if collection version is greater than or equal to 1.0.0"
  +    description = "Confirm via galaxy.yml file if collection version is greater than or equal to 1.0.0 and check for changelog."
       severity = "MEDIUM"
       tags = ["metadata", "opt-in", "experimental"]
       version_added = "v6.6.0 (last update)"
  @@ -26,18 +27,21 @@
           """Return matches found for a specific play (entry in playbook)."""
           if file.kind != "galaxy":  # type: ignore
               return []
  +
  +        results = []
  +
           if "version" not in data:
  -            return [
  +            results.append(
                   self.create_matcherror(
                       message="galaxy.yaml should have version tag.",
                       linenumber=data[LINE_NUMBER_KEY],
                       tag="galaxy[version-missing]",
                       filename=file,
                   )
  -            ]
  +            )
           version = data.get("version")
           if Version(version) < Version("1.0.0"):
  -            return [
  +            results.append(
                   self.create_matcherror(
                       message="collection version should be greater than or equal to 1.0.0",
                       # pylint: disable=protected-access
  @@ -45,8 +49,33 @@
                       tag="galaxy[version-incorrect]",
                       filename=file,
                   )
  -            ]
  -        return []
  +            )
  +
  +        # Changelog Check - building off Galaxy rule as there is no current way to check
  +        # for a nonexistent file
  +
  +        base_path = os.path.split(str(file.abspath))[0]
  +        changelog_found = 0
  +        changelog_paths = [
  +            os.path.join(base_path, "changelogs", "changelog.yaml"),
  +            os.path.join(base_path, "CHANGELOG.rst"),
  +            os.path.join(base_path, "CHANGELOG.md"),
  +        ]
  +
  +        for path in changelog_paths:
  +            if os.path.isfile(path):
  +                changelog_found = 1
  +
  +        if not changelog_found:
  +            results.append(
  +                self.create_matcherror(
  +                    message="No changelog found. Please add a changelog file. Refer to the galaxy.md file for more info.",
  +                    tag="galaxy[no-changelog]",
  +                    filename=file,
  +                )
  +            )
  +
  +        return results
   
   
   @total_ordering
  @@ -105,3 +134,18 @@
           bad_runner = Runner(failure, rules=collection)
           errs = bad_runner.run()
           assert len(errs) == 1
  +
  +    def test_changelog_present() -> None:
  +        """Positive test for finding a changelog."""
  +        collection = RulesCollection()
  +        collection.register(GalaxyRule())
  +        good_runner = Runner("examples/collection/galaxy.yml", rules=collection)
  +        assert [] == good_runner.run()
  +
  +    def test_changelog_missing() -> None:
  +        """Negative test for finding a changelog."""
  +        collection = RulesCollection()
  +        collection.register(GalaxyRule())
  +        bad_runner = Runner("examples/no_changelog/galaxy.yml", rules=collection)
  +        errs = bad_runner.run()
  +        assert len(errs) == 1
  
verification_info: {"golden_diff": "diff --git a/src/ansiblelint/rules/galaxy.py b/src/ansiblelint/rules/galaxy.py\n--- a/src/ansiblelint/rules/galaxy.py\n+++ b/src/ansiblelint/rules/galaxy.py\n@@ -1,6 +1,7 @@\n \"\"\"Implementation of GalaxyRule.\"\"\"\n from __future__ import annotations\n \n+import os\n import sys\n from functools import total_ordering\n from typing import TYPE_CHECKING, Any\n@@ -14,10 +15,10 @@\n \n \n class GalaxyRule(AnsibleLintRule):\n-    \"\"\"Rule for checking collection version is greater than 1.0.0.\"\"\"\n+    \"\"\"Rule for checking collection version is greater than 1.0.0 and checking for changelog.\"\"\"\n \n     id = \"galaxy\"\n-    description = \"Confirm via galaxy.yml file if collection version is greater than or equal to 1.0.0\"\n+    description = \"Confirm via galaxy.yml file if collection version is greater than or equal to 1.0.0 and check for changelog.\"\n     severity = \"MEDIUM\"\n     tags = [\"metadata\", \"opt-in\", \"experimental\"]\n     version_added = \"v6.6.0 (last update)\"\n@@ -26,18 +27,21 @@\n         \"\"\"Return matches found for a specific play (entry in playbook).\"\"\"\n         if file.kind != \"galaxy\":  # type: ignore\n             return []\n+\n+        results = []\n+\n         if \"version\" not in data:\n-            return [\n+            results.append(\n                 self.create_matcherror(\n                     message=\"galaxy.yaml should have version tag.\",\n                     linenumber=data[LINE_NUMBER_KEY],\n                     tag=\"galaxy[version-missing]\",\n                     filename=file,\n                 )\n-            ]\n+            )\n         version = data.get(\"version\")\n         if Version(version) < Version(\"1.0.0\"):\n-            return [\n+            results.append(\n                 self.create_matcherror(\n                     message=\"collection version should be greater than or equal to 1.0.0\",\n                     # pylint: disable=protected-access\n@@ -45,8 +49,33 @@\n                     tag=\"galaxy[version-incorrect]\",\n                     filename=file,\n                 )\n-            ]\n-        return []\n+            )\n+\n+        # Changelog Check - building off Galaxy rule as there is no current way to check\n+        # for a nonexistent file\n+\n+        base_path = os.path.split(str(file.abspath))[0]\n+        changelog_found = 0\n+        changelog_paths = [\n+            os.path.join(base_path, \"changelogs\", \"changelog.yaml\"),\n+            os.path.join(base_path, \"CHANGELOG.rst\"),\n+            os.path.join(base_path, \"CHANGELOG.md\"),\n+        ]\n+\n+        for path in changelog_paths:\n+            if os.path.isfile(path):\n+                changelog_found = 1\n+\n+        if not changelog_found:\n+            results.append(\n+                self.create_matcherror(\n+                    message=\"No changelog found. Please add a changelog file. Refer to the galaxy.md file for more info.\",\n+                    tag=\"galaxy[no-changelog]\",\n+                    filename=file,\n+                )\n+            )\n+\n+        return results\n \n \n @total_ordering\n@@ -105,3 +134,18 @@\n         bad_runner = Runner(failure, rules=collection)\n         errs = bad_runner.run()\n         assert len(errs) == 1\n+\n+    def test_changelog_present() -> None:\n+        \"\"\"Positive test for finding a changelog.\"\"\"\n+        collection = RulesCollection()\n+        collection.register(GalaxyRule())\n+        good_runner = Runner(\"examples/collection/galaxy.yml\", rules=collection)\n+        assert [] == good_runner.run()\n+\n+    def test_changelog_missing() -> None:\n+        \"\"\"Negative test for finding a changelog.\"\"\"\n+        collection = RulesCollection()\n+        collection.register(GalaxyRule())\n+        bad_runner = Runner(\"examples/no_changelog/galaxy.yml\", rules=collection)\n+        errs = bad_runner.run()\n+        assert len(errs) == 1\n", "issue": "no-changelog: check_collection_changelog\ncheck the collection structure to confirm if there is a changelog file present at the root of the directory. \r\n\r\nrule should be optional and only enabled at users discretion. Error level should be Warn/Info (0)\r\n\r\nbased off of code found [here ](https://github.com/ansible/galaxy-importer/blob/master/galaxy_importer/loaders/collection.py#L119)\n", "before_files": [{"content": "\"\"\"Implementation of GalaxyRule.\"\"\"\nfrom __future__ import annotations\n\nimport sys\nfrom functools import total_ordering\nfrom typing import TYPE_CHECKING, Any\n\nfrom ansiblelint.constants import LINE_NUMBER_KEY\nfrom ansiblelint.errors import MatchError\nfrom ansiblelint.rules import AnsibleLintRule\n\nif TYPE_CHECKING:\n    from ansiblelint.file_utils import Lintable\n\n\nclass GalaxyRule(AnsibleLintRule):\n    \"\"\"Rule for checking collection version is greater than 1.0.0.\"\"\"\n\n    id = \"galaxy\"\n    description = \"Confirm via galaxy.yml file if collection version is greater than or equal to 1.0.0\"\n    severity = \"MEDIUM\"\n    tags = [\"metadata\", \"opt-in\", \"experimental\"]\n    version_added = \"v6.6.0 (last update)\"\n\n    def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]:\n        \"\"\"Return matches found for a specific play (entry in playbook).\"\"\"\n        if file.kind != \"galaxy\":  # type: ignore\n            return []\n        if \"version\" not in data:\n            return [\n                self.create_matcherror(\n                    message=\"galaxy.yaml should have version tag.\",\n                    linenumber=data[LINE_NUMBER_KEY],\n                    tag=\"galaxy[version-missing]\",\n                    filename=file,\n                )\n            ]\n        version = data.get(\"version\")\n        if Version(version) < Version(\"1.0.0\"):\n            return [\n                self.create_matcherror(\n                    message=\"collection version should be greater than or equal to 1.0.0\",\n                    # pylint: disable=protected-access\n                    linenumber=version._line_number,\n                    tag=\"galaxy[version-incorrect]\",\n                    filename=file,\n                )\n            ]\n        return []\n\n\n@total_ordering\nclass Version:\n    \"\"\"Simple class to compare arbitrary versions.\"\"\"\n\n    def __init__(self, version_string: str):\n        \"\"\"Construct a Version object.\"\"\"\n        self.components = version_string.split(\".\")\n\n    def __eq__(self, other: object) -> bool:\n        \"\"\"Implement equality comparison.\"\"\"\n        other = _coerce(other)\n        if not isinstance(other, Version):\n            return NotImplemented\n\n        return self.components == other.components\n\n    def __lt__(self, other: Version) -> bool:\n        \"\"\"Implement lower-than operation.\"\"\"\n        other = _coerce(other)\n        if not isinstance(other, Version):\n            return NotImplemented\n\n        return self.components < other.components\n\n\ndef _coerce(other: object) -> Version:\n    if isinstance(other, str):\n        other = Version(other)\n    if isinstance(other, (int, float)):\n        other = Version(str(other))\n    if isinstance(other, Version):\n        return other\n    raise NotImplementedError(f\"Unable to coerce object type {type(other)} to Version\")\n\n\nif \"pytest\" in sys.modules:  # noqa: C901\n\n    from ansiblelint.rules import RulesCollection\n    from ansiblelint.runner import Runner\n\n    def test_galaxy_collection_version_positive() -> None:\n        \"\"\"Positive test for collection version in galaxy.\"\"\"\n        collection = RulesCollection()\n        collection.register(GalaxyRule())\n        success = \"examples/collection/galaxy.yml\"\n        good_runner = Runner(success, rules=collection)\n        assert [] == good_runner.run()\n\n    def test_galaxy_collection_version_negative() -> None:\n        \"\"\"Negative test for collection version in galaxy.\"\"\"\n        collection = RulesCollection()\n        collection.register(GalaxyRule())\n        failure = \"examples/meta/galaxy.yml\"\n        bad_runner = Runner(failure, rules=collection)\n        errs = bad_runner.run()\n        assert len(errs) == 1\n", "path": "src/ansiblelint/rules/galaxy.py"}]}