Repository: ansible-community/antsibull-changelog

Issue:
Create constants for and document return codes
See https://github.com/ansible-community/antsibull-changelog/pull/76#discussion_r835931008.

Discussion:

Solution patch:
diff --git a/changelogs/fragments/166-use-constants.yml b/changelogs/fragments/166-use-constants.yml
new file mode 100644
index 0000000..c79b570
--- /dev/null
+++ b/changelogs/fragments/166-use-constants.yml
@@ -0,0 +1,3 @@
+---
+minor_changes:
+  - "Replaces numbers with constants for return codes (https://github.com/ansible-community/antsibull-changelog/issues/77)."
\ No newline at end of file
diff --git a/src/antsibull_changelog/cli.py b/src/antsibull_changelog/cli.py
index a3ab6c3..908bcec 100644
--- a/src/antsibull_changelog/cli.py
+++ b/src/antsibull_changelog/cli.py
@@ -30,6 +30,7 @@ except ImportError:
     HAS_ARGCOMPLETE = False
 
 from . import __version__ as _version
+from . import constants as C
 from .ansible import get_ansible_release
 from .changes import ChangesBase, add_release, load_changes
 from .config import ChangelogConfig, CollectionDetails, PathsConfig, TextFormat
@@ -319,7 +320,7 @@ def run(args: list[str]) -> int:
 
         if getattr(arguments, "func", None) is None:
             parser.print_help()
-            return 2
+            return C.RC_BAD_CLI_ARG
 
         verbosity = arguments.verbose
         setup_logger(verbosity)
@@ -329,7 +330,7 @@ def run(args: list[str]) -> int:
         LOGGER.error(str(e))
         if verbosity > 2:
             traceback.print_exc()
-        return 5
+        return C.RC_COMMAND_FAILED
     except SystemExit as e:
         # All cases that sys.exit is called directly or indirectly in the above
         # code (that we are aware of) always return an int.
@@ -339,7 +340,7 @@ def run(args: list[str]) -> int:
             traceback.print_exc()
         else:
             print("ERROR: Uncaught exception. Run with -v to see traceback.")
-        return 1
+        return C.RC_UNHANDLED_ERROR
 
 
 def command_init(args: Any) -> int:
@@ -355,11 +356,11 @@ def command_init(args: Any) -> int:
 
     if not is_other_project and paths.galaxy_path is None:
         LOGGER.error("The file galaxy.yml does not exists in the collection root!")
-        return 5
+        return C.RC_COMMAND_FAILED
     LOGGER.debug('Checking for existance of "{}"', paths.config_path)
     if os.path.exists(paths.config_path):
         LOGGER.error('A configuration file already exists at "{}"!', paths.config_path)
-        return 5
+        return C.RC_COMMAND_FAILED
 
     collection_details = CollectionDetails(paths)
 
@@ -379,7 +380,7 @@ def command_init(args: Any) -> int:
     except Exception as exc:  # pylint: disable=broad-except
         LOGGER.error('Cannot create fragments directory "{}"', fragments_dir)
         LOGGER.info("Exception: {}", str(exc))
-        return 5
+        return C.RC_COMMAND_FAILED
 
     try:
         config.store()
@@ -387,9 +388,9 @@ def command_init(args: Any) -> int:
     except Exception as exc:  # pylint: disable=broad-except
         LOGGER.error('Cannot create config file "{}"', paths.config_path)
         LOGGER.info("Exception: {}", str(exc))
-        return 5
+        return C.RC_COMMAND_FAILED
 
-    return 0
+    return C.RC_SUCCESS
 
 
 def _determine_flatmap(
@@ -707,7 +708,7 @@ def command_release(args: Any) -> int:
             flatmap=flatmap,
         )
 
-    return 0
+    return C.RC_SUCCESS
 
 
 def command_generate(args: Any) -> int:  # pylint: disable=too-many-locals
@@ -738,10 +739,10 @@ def command_generate(args: Any) -> int:  # pylint: disable=too-many-locals
             changes.restrict_to(version)
         except ValueError as exc:
             print(f"Cannot restrict to version '{version}': {exc}")
-            return 5
+            return C.RC_COMMAND_FAILED
     if not changes.has_release:
         print("Cannot create changelog when not at least one release has been added.")
-        return 5
+        return C.RC_COMMAND_FAILED
     plugins, fragments = _do_refresh(
         args, paths, collection_details, config, changes, None, None
     )
@@ -758,7 +759,7 @@ def command_generate(args: Any) -> int:  # pylint: disable=too-many-locals
             "When an explicit output path is specified and more than one output format"
             " is configured, you need to explicitly specify an output format"
         )
-        return 5
+        return C.RC_COMMAND_FAILED
     output_formats = (
         [TextFormat.from_extension(output_format)]
         if output_format
@@ -777,7 +778,7 @@ def command_generate(args: Any) -> int:  # pylint: disable=too-many-locals
             only_latest=only_latest,
         )
 
-    return 0
+    return C.RC_SUCCESS
 
 
 def command_lint(args: Any) -> int:
@@ -833,7 +834,7 @@ def lint_fragments(
     for message in messages:
         print(message)
 
-    return 3 if messages else 0
+    return C.RC_INVALID_FRAGMENT if messages else C.RC_SUCCESS
 
 
 def command_lint_changelog_yaml(args: Any) -> int:
@@ -853,7 +854,7 @@ def command_lint_changelog_yaml(args: Any) -> int:
     for message in messages:
         print(message)
 
-    return 3 if messages else 0
+    return C.RC_INVALID_FRAGMENT if messages else C.RC_SUCCESS
 
 
 def main() -> int:
@@ -865,17 +866,11 @@ def main() -> int:
     heavy lifting.
 
     :returns: A program return code.
-
-    Return codes:
-        :0: Success
-        :1: Unhandled error.  See the Traceback for more information.
-        :2: There was a problem with the command line arguments
-        :3: Found invalid changelog fragments
-        :4: Needs to be run on a newer version of Python
-        :5: Problem occured which prevented the execution of the command
+    See constants.py for the return codes.
     """
+
     if sys.version_info < (3, 6):
         print("Needs Python 3.6 or later")
-        return 4
+        return C.RC_OLD_PYTHON
 
     return run(sys.argv)
diff --git a/src/antsibull_changelog/constants.py b/src/antsibull_changelog/constants.py
new file mode 100644
index 0000000..dd98f6d
--- /dev/null
+++ b/src/antsibull_changelog/constants.py
@@ -0,0 +1,16 @@
+# 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
+# SPDX-FileCopyrightText: 2020, Ansible Project
+"""
+Constants used by antsibull-changelog.
+"""
+
+
+# Return codes used in cli.py and test files.
+RC_SUCCESS = 0  # Success
+RC_UNHANDLED_ERROR = 1  # Unhandled error.  See the Traceback for more information.
+RC_BAD_CLI_ARG = 2  # There was a problem with the command line arguments.
+RC_INVALID_FRAGMENT = 3  # Found invalid changelog fragments.
+RC_OLD_PYTHON = 4  # Needs to be run on a newer version of Python.
+RC_COMMAND_FAILED = 5  # Problem occurred which prevented the execution of the command.


Test patch:
diff --git a/tests/functional/test_changelog_archive.py b/tests/functional/test_changelog_archive.py
index fab33d0..943beec 100644
--- a/tests/functional/test_changelog_archive.py
+++ b/tests/functional/test_changelog_archive.py
@@ -15,6 +15,7 @@ from unittest import mock
 from fixtures import collection_changelog  # noqa: F401; pylint: disable=unused-variable
 from fixtures import create_plugin
 
+from antsibull_changelog import constants as C
 from antsibull_changelog.config import PathsConfig
 
 
@@ -43,7 +44,10 @@ def test_changelog_release_keep_fragments(  # pylint: disable=redefined-outer-na
     collection_changelog.set_plugin_cache("1.0.0", {})
 
     # Release
-    assert collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"]) == 0
+    assert (
+        collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"])
+        == C.RC_SUCCESS
+    )
 
     diff = collection_changelog.diff()
     assert diff.added_dirs == []
@@ -83,7 +87,10 @@ Minor Changes
     )
 
     # Refresh
-    assert collection_changelog.run_tool("generate", ["-v", "--refresh-fragments"]) == 0
+    assert (
+        collection_changelog.run_tool("generate", ["-v", "--refresh-fragments"])
+        == C.RC_SUCCESS
+    )
 
     diff = collection_changelog.diff()
     assert diff.added_dirs == []
@@ -142,7 +149,10 @@ def test_changelog_release_remove_fragments(  # pylint: disable=redefined-outer-
     collection_changelog.set_plugin_cache("1.0.0", {})
 
     # Release
-    assert collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"]) == 0
+    assert (
+        collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"])
+        == C.RC_SUCCESS
+    )
 
     diff = collection_changelog.diff()
     assert diff.added_dirs == []
@@ -179,7 +189,10 @@ Minor Changes
     )
 
     # Refresh should be ignored
-    assert collection_changelog.run_tool("generate", ["-v", "--refresh-fragments"]) == 0
+    assert (
+        collection_changelog.run_tool("generate", ["-v", "--refresh-fragments"])
+        == C.RC_SUCCESS
+    )
     assert collection_changelog.diff().unchanged
 
     # Add fragment with same filename, but different content
@@ -193,7 +206,7 @@ Minor Changes
         collection_changelog.run_tool(
             "release", ["-v", "--version", "1.1.0", "--date", "2020-01-02"]
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = collection_changelog.diff()
@@ -251,7 +264,7 @@ Minor Changes
         collection_changelog.run_tool(
             "release", ["-v", "--version", "1.2.0", "--date", "2020-01-02"]
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = collection_changelog.diff()
@@ -322,7 +335,10 @@ def test_changelog_release_archive_fragments(  # pylint: disable=redefined-outer
     collection_changelog.set_plugin_cache("1.0.0", {})
 
     # Release
-    assert collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"]) == 0
+    assert (
+        collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"])
+        == C.RC_SUCCESS
+    )
 
     diff = collection_changelog.diff()
     assert diff.added_dirs == [".archive", ".archive/v1.0.0"]
@@ -373,7 +389,10 @@ Minor Changes
     )
 
     # Refresh
-    assert collection_changelog.run_tool("generate", ["-v", "--refresh-fragments"]) == 0
+    assert (
+        collection_changelog.run_tool("generate", ["-v", "--refresh-fragments"])
+        == C.RC_SUCCESS
+    )
 
     diff = collection_changelog.diff()
     assert diff.added_dirs == []
@@ -418,6 +437,6 @@ Minor Changes
         collection_changelog.run_tool(
             "generate", ["-v", "--refresh-fragments", "without-archives"]
         )
-        == 0
+        == C.RC_SUCCESS
     )
     assert collection_changelog.diff().unchanged
diff --git a/tests/functional/test_changelog_basic_ansible.py b/tests/functional/test_changelog_basic_ansible.py
index c22253e..629b603 100644
--- a/tests/functional/test_changelog_basic_ansible.py
+++ b/tests/functional/test_changelog_basic_ansible.py
@@ -15,6 +15,8 @@ from unittest import mock
 from fixtures import ansible_changelog  # noqa: F401; pylint: disable=unused-variable
 from fixtures import create_plugin
 
+from antsibull_changelog import constants as C
+
 
 def test_changelog_release_ansible_empty(  # pylint: disable=redefined-outer-name
     ansible_changelog,
@@ -51,7 +53,7 @@ sections:
             "release",
             ["-v", "--date", "2020-01-02", "--version", "2.10", "--codename", "meow"],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = ansible_changelog.diff()
@@ -95,7 +97,7 @@ This is the first proper release.
 """
     )
 
-    assert ansible_changelog.run_tool("generate", ["-v"]) == 0
+    assert ansible_changelog.run_tool("generate", ["-v"]) == C.RC_SUCCESS
     assert ansible_changelog.diff().unchanged
 
     # Version 2.10.1
@@ -107,7 +109,7 @@ This is the first proper release.
             "release",
             ["-v", "--date", "2020-02-29", "--version", "2.10.1", "--codename", "meow"],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = ansible_changelog.diff()
@@ -150,7 +152,7 @@ This is the first proper release.
 """
     )
 
-    assert ansible_changelog.run_tool("generate", ["-v", "--refresh"]) == 0
+    assert ansible_changelog.run_tool("generate", ["-v", "--refresh"]) == C.RC_SUCCESS
     assert ansible_changelog.diff().unchanged
 
 
@@ -233,7 +235,7 @@ sections:
             "release",
             ["-v", "--date", "2020-01-02", "--version", "2.10", "--codename", "meow"],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = ansible_changelog.diff()
@@ -319,7 +321,7 @@ New Modules
     )
 
     # Check that regenerate doesn't change anything
-    assert ansible_changelog.run_tool("generate", ["-v"]) == 0
+    assert ansible_changelog.run_tool("generate", ["-v"]) == C.RC_SUCCESS
     assert ansible_changelog.diff().unchanged
 
     # Update plugin descriptions
@@ -377,7 +379,7 @@ New Modules
 
     # Check that regenerate without --refresh changes
     # (since we specified always_refresh in config)
-    assert ansible_changelog.run_tool("generate", ["-v"]) == 0
+    assert ansible_changelog.run_tool("generate", ["-v"]) == C.RC_SUCCESS
 
     diff = ansible_changelog.diff()
     assert diff.added_dirs == []
@@ -510,7 +512,7 @@ New Modules
                 "woof",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = ansible_changelog.diff()
@@ -677,7 +679,7 @@ New Modules
                 "woof!",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = ansible_changelog.diff()
@@ -796,13 +798,13 @@ New Modules
                 "woof!!!",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     assert ansible_changelog.diff().unchanged
 
     # Lint fragments
-    assert ansible_changelog.run_tool("lint", ["-vv"]) == 0
+    assert ansible_changelog.run_tool("lint", ["-vv"]) == C.RC_SUCCESS
 
     # Add fragment with trivial section
     ansible_changelog.add_fragment_line("trivial.yml", "trivial", ["This is trivial."])
@@ -1043,7 +1045,7 @@ sections:
                     "meow",
                 ],
             )
-            == 0
+            == C.RC_SUCCESS
         )
 
         diff = ansible_changelog.diff()
@@ -1146,7 +1148,7 @@ New Modules
             ansible_changelog.run_tool(
                 "generate", ["-v", "--reload-plugins", "--use-ansible-doc"]
             )
-            == 0
+            == C.RC_SUCCESS
         )
 
         diff = ansible_changelog.diff()
diff --git a/tests/functional/test_changelog_basic_ansible_classic.py b/tests/functional/test_changelog_basic_ansible_classic.py
index cd7cd58..6e529e5 100644
--- a/tests/functional/test_changelog_basic_ansible_classic.py
+++ b/tests/functional/test_changelog_basic_ansible_classic.py
@@ -16,6 +16,8 @@ from unittest import mock
 from fixtures import ansible_changelog  # noqa: F401; pylint: disable=unused-variable
 from fixtures import create_plugin
 
+from antsibull_changelog import constants as C
+
 
 def test_changelog_release_ansible_empty(  # pylint: disable=redefined-outer-name
     ansible_changelog,
@@ -57,7 +59,7 @@ sections:
                     "meow",
                 ],
             )
-            == 0
+            == C.RC_SUCCESS
         )
 
         assert len(w) == 1
@@ -103,7 +105,7 @@ This is the first proper release.
 """
     )
 
-    assert ansible_changelog.run_tool("generate", ["-v"]) == 0
+    assert ansible_changelog.run_tool("generate", ["-v"]) == C.RC_SUCCESS
     assert ansible_changelog.diff().unchanged
 
     # Version 2.9.1
@@ -115,7 +117,7 @@ This is the first proper release.
             "release",
             ["-v", "--date", "2020-02-29", "--version", "2.9.1", "--codename", "meow"],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = ansible_changelog.diff()
@@ -158,7 +160,7 @@ This is the first proper release.
 """
     )
 
-    assert ansible_changelog.run_tool("generate", ["-v", "--refresh"]) == 0
+    assert ansible_changelog.run_tool("generate", ["-v", "--refresh"]) == C.RC_SUCCESS
     assert ansible_changelog.diff().unchanged
 
 
@@ -235,7 +237,7 @@ sections:
             "release",
             ["-v", "--date", "2020-01-02", "--version", "2.9", "--codename", "meow"],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = ansible_changelog.diff()
@@ -302,7 +304,7 @@ New Modules
     )
 
     # Check that regenerate doesn't change anything
-    assert ansible_changelog.run_tool("generate", ["-v"]) == 0
+    assert ansible_changelog.run_tool("generate", ["-v"]) == C.RC_SUCCESS
     assert ansible_changelog.diff().unchanged
 
     # Update plugin descriptions
@@ -360,7 +362,7 @@ New Modules
 
     # Check that regenerate without --refresh changes
     # (since we specified always_refresh in config)
-    assert ansible_changelog.run_tool("generate", ["-v"]) == 0
+    assert ansible_changelog.run_tool("generate", ["-v"]) == C.RC_SUCCESS
 
     diff = ansible_changelog.diff()
     assert diff.added_dirs == []
@@ -474,7 +476,7 @@ New Modules
                 "woof",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = ansible_changelog.diff()
@@ -629,7 +631,7 @@ New Modules
                 "woof!",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = ansible_changelog.diff()
@@ -732,13 +734,13 @@ New Modules
                 "woof!!!",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     assert ansible_changelog.diff().unchanged
 
     # Lint fragments
-    assert ansible_changelog.run_tool("lint", ["-vv"]) == 0
+    assert ansible_changelog.run_tool("lint", ["-vv"]) == C.RC_SUCCESS
 
 
 FAKE_PLUGINS = {
@@ -959,7 +961,7 @@ sections:
                     "meow",
                 ],
             )
-            == 0
+            == C.RC_SUCCESS
         )
 
         diff = ansible_changelog.diff()
@@ -1052,7 +1054,7 @@ New Modules
             ansible_changelog.run_tool(
                 "generate", ["-v", "--reload-plugins", "--use-ansible-doc"]
             )
-            == 0
+            == C.RC_SUCCESS
         )
 
         diff = ansible_changelog.diff()
diff --git a/tests/functional/test_changelog_basic_collection.py b/tests/functional/test_changelog_basic_collection.py
index 6897593..f832d96 100644
--- a/tests/functional/test_changelog_basic_collection.py
+++ b/tests/functional/test_changelog_basic_collection.py
@@ -16,6 +16,7 @@ from fixtures import collection_changelog  # noqa: F401; pylint: disable=unused-
 from fixtures import create_plugin
 
 import antsibull_changelog.ansible  # noqa: F401; pylint: disable=unused-variable
+from antsibull_changelog import constants as C
 from antsibull_changelog.config import TextFormat
 
 
@@ -29,7 +30,7 @@ def test_changelog_init(  # pylint: disable=redefined-outer-name
     )
     assert (
         collection_changelog.run_tool("init", [collection_changelog.paths.base_dir])
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = collection_changelog.diff()
@@ -69,7 +70,10 @@ def test_changelog_release_empty(  # pylint: disable=redefined-outer-name
     )
     collection_changelog.set_plugin_cache("1.0.0", {})
 
-    assert collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"]) == 0
+    assert (
+        collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"])
+        == C.RC_SUCCESS
+    )
 
     diff = collection_changelog.diff()
     assert diff.added_dirs == []
@@ -133,7 +137,9 @@ This is the first proper release\.
 """
     )
 
-    assert collection_changelog.run_tool("generate", ["-v", "--refresh"]) == 0
+    assert (
+        collection_changelog.run_tool("generate", ["-v", "--refresh"]) == C.RC_SUCCESS
+    )
     assert collection_changelog.diff().unchanged
 
     assert (
@@ -149,7 +155,7 @@ This is the first proper release\.
             "generate",
             ["-v", "--refresh", "--output", "extract.md", "--output-format", "md"],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = collection_changelog.diff()
@@ -180,7 +186,7 @@ This is the first proper release\.
         collection_changelog.run_tool(
             "release", ["-v", "--codename", "primetime", "--date", "2020-01-03"]
         )
-        == 0
+        == C.RC_SUCCESS
     )
     assert collection_changelog.diff().unchanged
 
@@ -196,7 +202,7 @@ This is the first proper release\.
                 "--update-existing",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
     diff = collection_changelog.diff()
     assert diff.added_dirs == []
@@ -257,7 +263,10 @@ This is the first proper release\.
     )
     collection_changelog.set_plugin_cache("1.1.0", {})
 
-    assert collection_changelog.run_tool("release", ["-v", "--date", "2020-02-29"]) == 0
+    assert (
+        collection_changelog.run_tool("release", ["-v", "--date", "2020-02-29"])
+        == C.RC_SUCCESS
+    )
 
     diff = collection_changelog.diff()
     assert diff.added_dirs == []
@@ -323,7 +332,9 @@ This is the first proper release\.
 """
     )
 
-    assert collection_changelog.run_tool("generate", ["-v", "--refresh"]) == 0
+    assert (
+        collection_changelog.run_tool("generate", ["-v", "--refresh"]) == C.RC_SUCCESS
+    )
     assert collection_changelog.diff().unchanged
 
 
@@ -384,7 +395,7 @@ def test_changelog_release_simple(  # pylint: disable=redefined-outer-name
     )
 
     # Lint fragments (should fail)
-    assert collection_changelog.run_tool("lint", ["-vv"]) == 3
+    assert collection_changelog.run_tool("lint", ["-vv"]) == C.RC_INVALID_FRAGMENT
 
     # Release (should fail)
     assert collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"]) == 3
@@ -394,10 +405,13 @@ def test_changelog_release_simple(  # pylint: disable=redefined-outer-name
     )
 
     # Lint fragments
-    assert collection_changelog.run_tool("lint", ["-vv"]) == 0
+    assert collection_changelog.run_tool("lint", ["-vv"]) == C.RC_SUCCESS
 
     # Release
-    assert collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"]) == 0
+    assert (
+        collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"])
+        == C.RC_SUCCESS
+    )
 
     diff = collection_changelog.diff()
     assert diff.added_dirs == []
@@ -481,7 +495,7 @@ New Modules
     )
 
     # Check that regenerate doesn't change anything
-    assert collection_changelog.run_tool("generate", ["-v"]) == 0
+    assert collection_changelog.run_tool("generate", ["-v"]) == C.RC_SUCCESS
     assert collection_changelog.diff().unchanged
 
     # Update plugin descriptions
@@ -525,17 +539,23 @@ New Modules
     )
 
     # Check that regenerate without --refresh* doesn't change anything
-    assert collection_changelog.run_tool("generate", ["-v"]) == 0
+    assert collection_changelog.run_tool("generate", ["-v"]) == C.RC_SUCCESS
     assert collection_changelog.diff().unchanged
 
     # Check that regenerate with --refresh-fragments does not change
-    assert collection_changelog.run_tool("generate", ["-v", "--refresh-fragments"]) == 0
+    assert (
+        collection_changelog.run_tool("generate", ["-v", "--refresh-fragments"])
+        == C.RC_SUCCESS
+    )
 
     diff = collection_changelog.diff()
     assert diff.unchanged
 
     # Check that regenerate with --refresh-plugins changes
-    assert collection_changelog.run_tool("generate", ["-v", "--refresh-plugins"]) == 0
+    assert (
+        collection_changelog.run_tool("generate", ["-v", "--refresh-plugins"])
+        == C.RC_SUCCESS
+    )
 
     diff = collection_changelog.diff()
     assert diff.added_dirs == []
@@ -655,7 +675,7 @@ New Modules
                 "1.1.0-beta-1",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = collection_changelog.diff()
@@ -816,7 +836,7 @@ New Modules
                 "-vvv",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     # Final release 1.1.0
@@ -831,7 +851,7 @@ New Modules
                 "1.1.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = collection_changelog.diff()
@@ -949,7 +969,7 @@ New Modules
                 "1.1.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     assert collection_changelog.diff().unchanged
@@ -1075,7 +1095,7 @@ New Modules
                 "1.2.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = collection_changelog.diff()
@@ -1270,7 +1290,7 @@ New Modules
                 "1.2.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     assert collection_changelog.diff().unchanged
@@ -1308,7 +1328,7 @@ New Modules
                 "1.1.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = collection_changelog.diff()
@@ -1392,7 +1412,7 @@ New Modules
                 "1.1.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = collection_changelog.diff()
@@ -1442,7 +1462,7 @@ New Modules
                 "1.0.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = collection_changelog.diff()
@@ -1681,7 +1701,7 @@ def test_changelog_release_simple_no_galaxy(  # pylint: disable=redefined-outer-
                 "yes",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = collection_changelog.diff()
@@ -2090,7 +2110,7 @@ def test_changelog_release_plugin_cache(  # pylint: disable=redefined-outer-name
 
         assert (
             collection_changelog.run_tool("release", ["-v", "--date", "2020-01-02"])
-            == 0
+            == C.RC_SUCCESS
         )
 
         diff = collection_changelog.diff()
@@ -2218,7 +2238,7 @@ New Roles
             collection_changelog.run_tool(
                 "generate", ["-v", "--reload-plugins", "--use-ansible-doc"]
             )
-            == 0
+            == C.RC_SUCCESS
         )
 
         diff = collection_changelog.diff()
diff --git a/tests/functional/test_changelog_basic_lint.py b/tests/functional/test_changelog_basic_lint.py
index b80509b..8b5efcd 100644
--- a/tests/functional/test_changelog_basic_lint.py
+++ b/tests/functional/test_changelog_basic_lint.py
@@ -15,6 +15,7 @@ from unittest import mock
 from fixtures import collection_changelog  # noqa: F401; pylint: disable=unused-variable
 from fixtures import create_plugin
 
+from antsibull_changelog import constants as C
 from antsibull_changelog.config import PathsConfig
 
 
@@ -39,14 +40,14 @@ def test_changelog_fragment_lint_correct(  # pylint: disable=redefined-outer-nam
 
     # Lint fragments
     rc, stdout, stderr = collection_changelog.run_tool_w_output("lint", [])
-    assert rc == 0
+    assert rc == C.RC_SUCCESS
     assert stdout == ""
 
     # Lint explicitly named fragment
     rc, stdout, stderr = collection_changelog.run_tool_w_output(
         "lint", ["changelogs/fragments/1.0.0.yml"]
     )
-    assert rc == 0
+    assert rc == C.RC_SUCCESS
     assert stdout == ""
 
 
@@ -93,7 +94,7 @@ def test_changelog_fragment_lint_broken(  # pylint: disable=redefined-outer-name
 
     # Lint fragments
     rc, stdout, stderr = collection_changelog.run_tool_w_output("lint", [])
-    assert rc == 3
+    assert rc == C.RC_INVALID_FRAGMENT
     assert (
         stdout
         == r"""
@@ -124,7 +125,7 @@ changelogs/fragments/wrong-category.yaml:0:0: invalid section: minor_change
     rc, stdout, stderr = collection_changelog.run_tool_w_output(
         "lint", ["changelogs/fragments/non-existing"]
     )
-    assert rc == 3
+    assert rc == C.RC_INVALID_FRAGMENT
     assert (
         stdout
         == r"""
diff --git a/tests/functional/test_changelog_basic_other.py b/tests/functional/test_changelog_basic_other.py
index e56c7ba..5d74ef6 100644
--- a/tests/functional/test_changelog_basic_other.py
+++ b/tests/functional/test_changelog_basic_other.py
@@ -17,20 +17,24 @@ from fixtures import other_changelog  # noqa: F401; pylint: disable=unused-varia
 from fixtures import create_plugin
 
 import antsibull_changelog.ansible  # noqa: F401; pylint: disable=unused-variable
+from antsibull_changelog import constants as C
 
 
 def test_changelog_init(  # pylint: disable=redefined-outer-name
     other_changelog,
 ):  # noqa: F811
     # If we do not specify --is-other-project, it should error out
-    assert other_changelog.run_tool("init", [other_changelog.paths.base_dir]) == 5
+    assert (
+        other_changelog.run_tool("init", [other_changelog.paths.base_dir])
+        == C.RC_COMMAND_FAILED
+    )
 
     # If we do specify it, it just work
     assert (
         other_changelog.run_tool(
             "init", [other_changelog.paths.base_dir, "--is-other-project"]
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = other_changelog.diff()
@@ -61,14 +65,17 @@ def test_changelog_release_empty(  # pylint: disable=redefined-outer-name
     )
 
     # If we do not pass --version, will fail
-    assert other_changelog.run_tool("release", ["-v", "--date", "2020-01-02"]) == 5
+    assert (
+        other_changelog.run_tool("release", ["-v", "--date", "2020-01-02"])
+        == C.RC_COMMAND_FAILED
+    )
 
     # If we pass --version, will succeed
     assert (
         other_changelog.run_tool(
             "release", ["-v", "--date", "2020-01-02", "--version", "1.0.0"]
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = other_changelog.diff()
@@ -111,7 +118,7 @@ This is the first proper release.
 """
     )
 
-    assert other_changelog.run_tool("generate", ["-v", "--refresh"]) == 0
+    assert other_changelog.run_tool("generate", ["-v", "--refresh"]) == C.RC_SUCCESS
     assert other_changelog.diff().unchanged
 
     assert (
@@ -127,7 +134,7 @@ This is the first proper release.
                 "1.0.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
     assert other_changelog.diff().unchanged
 
@@ -145,7 +152,7 @@ This is the first proper release.
                 "--update-existing",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
     diff = other_changelog.diff()
     assert diff.added_dirs == []
@@ -181,7 +188,7 @@ This is the first proper release.
         other_changelog.run_tool(
             "release", ["-v", "--date", "2020-02-29", "--version", "1.1.0"]
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = other_changelog.diff()
@@ -222,7 +229,7 @@ This is the first proper release.
 """
     )
 
-    assert other_changelog.run_tool("generate", ["-v", "--refresh"]) == 0
+    assert other_changelog.run_tool("generate", ["-v", "--refresh"]) == C.RC_SUCCESS
     assert other_changelog.diff().unchanged
 
 
@@ -245,14 +252,14 @@ def test_changelog_release_simple(  # pylint: disable=redefined-outer-name
     )
 
     # Lint fragments
-    assert other_changelog.run_tool("lint", ["-vv"]) == 0
+    assert other_changelog.run_tool("lint", ["-vv"]) == C.RC_SUCCESS
 
     # Release
     assert (
         other_changelog.run_tool(
             "release", ["-v", "--date", "2020-01-02", "--version", "1.0.0"]
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = other_changelog.diff()
@@ -310,7 +317,7 @@ Minor Changes
     )
 
     # Check that regenerate doesn't change anything
-    assert other_changelog.run_tool("generate", ["-v"]) == 0
+    assert other_changelog.run_tool("generate", ["-v"]) == C.RC_SUCCESS
     assert other_changelog.diff().unchanged
 
     # Add another fragment
@@ -319,17 +326,23 @@ Minor Changes
     )
 
     # Check that regenerate without --refresh* doesn't change anything
-    assert other_changelog.run_tool("generate", ["-v"]) == 0
+    assert other_changelog.run_tool("generate", ["-v"]) == C.RC_SUCCESS
     assert other_changelog.diff().unchanged
 
     # Check that regenerate with --refresh-fragments does not change
-    assert other_changelog.run_tool("generate", ["-v", "--refresh-fragments"]) == 0
+    assert (
+        other_changelog.run_tool("generate", ["-v", "--refresh-fragments"])
+        == C.RC_SUCCESS
+    )
 
     diff = other_changelog.diff()
     assert diff.unchanged
 
     # Check that regenerate with --refresh-plugins does not change
-    assert other_changelog.run_tool("generate", ["-v", "--refresh-plugins"]) == 0
+    assert (
+        other_changelog.run_tool("generate", ["-v", "--refresh-plugins"])
+        == C.RC_SUCCESS
+    )
 
     diff = other_changelog.diff()
     assert diff.unchanged
@@ -378,7 +391,7 @@ Minor Changes
                 "1.1.0-beta-1",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = other_changelog.diff()
@@ -463,7 +476,7 @@ Minor Changes
                 "-vvv",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     # Final release 1.1.0
@@ -478,7 +491,7 @@ Minor Changes
                 "1.1.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = other_changelog.diff()
@@ -565,7 +578,7 @@ Minor Changes
                 "1.1.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     assert other_changelog.diff().unchanged
@@ -587,7 +600,7 @@ Minor Changes
                 "1.2.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     diff = other_changelog.diff()
@@ -672,7 +685,7 @@ Minor Changes
                 "1.2.0",
             ],
         )
-        == 0
+        == C.RC_SUCCESS
     )
 
     assert other_changelog.diff().unchanged
@@ -716,7 +729,10 @@ def test_changelog_release_package_json(  # pylint: disable=redefined-outer-name
     )
 
     # Release
-    assert other_changelog.run_tool("release", ["-v", "--date", "2020-01-02"]) == 0
+    assert (
+        other_changelog.run_tool("release", ["-v", "--date", "2020-01-02"])
+        == C.RC_SUCCESS
+    )
 
     diff = other_changelog.diff()
     assert diff.added_dirs == []
@@ -806,7 +822,10 @@ license = "GPL-3.0-or-later"
     )
 
     # Release
-    assert other_changelog.run_tool("release", ["-v", "--date", "2020-01-02"]) == 0
+    assert (
+        other_changelog.run_tool("release", ["-v", "--date", "2020-01-02"])
+        == C.RC_SUCCESS
+    )
 
     diff = other_changelog.diff()
     assert diff.added_dirs == []
@@ -900,7 +919,10 @@ license = "GPL-3.0-or-later"
     )
 
     # Release
-    assert other_changelog.run_tool("release", ["-v", "--date", "2020-01-02"]) == 0
+    assert (
+        other_changelog.run_tool("release", ["-v", "--date", "2020-01-02"])
+        == C.RC_SUCCESS
+    )
 
     diff = other_changelog.diff()
     assert diff.added_dirs == []