summaryrefslogtreecommitdiff
path: root/hacking
diff options
context:
space:
mode:
authorToshio Kuratomi <a.badger@gmail.com>2019-05-01 13:57:03 -0500
committerGitHub <noreply@github.com>2019-05-01 13:57:03 -0500
commit3161a91d7e4c8ae16bdc0563edf66d71e8424e69 (patch)
treed1676d7ead526f4b9199f9e02159da22aa61fc03 /hacking
parent5d4c73e197aef33b078b0ed38758ab82cc42dca9 (diff)
downloadansible-3161a91d7e4c8ae16bdc0563edf66d71e8424e69.tar.gz
Implement a framework for having common code for release scripts (#55893)
* Implement a framework for having common code for release scripts * Release scripts will go through hacking/build-ansible. build-ansible is a pluggable script which will set a directory that has common code for non-enduser scripts. It will then invoke the plugin which implements that subcommand. Uses straight.plugin for loading each sub-command. * We're going to add tools which are needed to test ansible (the changelog generation, for instance) so we need to include the pieces relevant to that in the tarball. * Add straight.plugin to the sanity test requirements for the same reason * Skip compile test just for build-ansible plugins which won't be run as part of sanity tests.
Diffstat (limited to 'hacking')
-rwxr-xr-xhacking/build-ansible76
-rw-r--r--hacking/build_library/__init__.py0
-rw-r--r--hacking/build_library/build_ansible/__init__.py0
-rw-r--r--[-rwxr-xr-x]hacking/build_library/build_ansible/command_plugins/porting_guide.py (renamed from hacking/porting-guide.py)35
-rw-r--r--[-rwxr-xr-x]hacking/build_library/build_ansible/command_plugins/release_announcement.py (renamed from hacking/release-announcement.py)59
-rw-r--r--hacking/build_library/build_ansible/commands.py50
6 files changed, 175 insertions, 45 deletions
diff --git a/hacking/build-ansible b/hacking/build-ansible
new file mode 100755
index 0000000000..69f98c6f48
--- /dev/null
+++ b/hacking/build-ansible
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+# coding: utf-8
+# PYTHON_ARGCOMPLETE_OK
+# Copyright: (c) 2019, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+import argparse
+import os.path
+import sys
+
+from straight.plugin import load
+
+try:
+ import argcomplete
+except ImportError:
+ argcomplete = None
+
+
+def set_sys_path(this_script=__file__):
+ """Add path to the common librarydirectory to :attr:`sys.path`"""
+ hacking_dir = os.path.dirname(this_script)
+ libdir = os.path.abspath(os.path.join(hacking_dir, 'build_library'))
+
+ if libdir not in sys.path:
+ sys.path.insert(0, libdir)
+
+
+set_sys_path()
+
+from build_ansible import commands
+
+
+def create_arg_parser(program_name):
+ """
+ Creates a command line argument parser
+
+ :arg program_name: The name of the script. Used in help texts
+ """
+ parser = argparse.ArgumentParser(prog=program_name,
+ description="Implements utilities to build Ansible")
+ return parser
+
+
+def main():
+ """
+ Main entrypoint of the script
+
+ "It all starts here"
+ """
+ subcommands = load('build_ansible.command_plugins', subclasses=commands.Command)
+
+ arg_parser = create_arg_parser(os.path.basename(sys.argv[0]))
+ subparsers = arg_parser.add_subparsers(title='Subcommands', dest='command',
+ help='for help use build-ansible SUBCOMMANDS -h')
+ subcommands.pipe('init_parser', subparsers.add_parser)
+
+ if argcomplete:
+ argcomplete.autocomplete(arg_parser)
+
+ args = arg_parser.parse_args(sys.argv[1:])
+
+ for subcommand in subcommands:
+ if subcommand.name == args.command:
+ sys.exit(subcommand.main(args))
+
+ print('Error: Select a subcommand')
+ arg_parser.print_usage()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/hacking/build_library/__init__.py b/hacking/build_library/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/hacking/build_library/__init__.py
diff --git a/hacking/build_library/build_ansible/__init__.py b/hacking/build_library/build_ansible/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/hacking/build_library/build_ansible/__init__.py
diff --git a/hacking/porting-guide.py b/hacking/build_library/build_ansible/command_plugins/porting_guide.py
index 61576f3455..efdb674f1c 100755..100644
--- a/hacking/porting-guide.py
+++ b/hacking/build_library/build_ansible/command_plugins/porting_guide.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python3
# coding: utf-8
# Copyright: (c) 2019, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
@@ -9,10 +8,14 @@ __metaclass__ = type
import argparse
+import os.path
import sys
from jinja2 import Environment, DictLoader
+# Pylint doesn't understand Python3 namespace modules.
+from ..commands import Command # pylint: disable=relative-beyond-top-level
+
PORTING_GUIDE_TEMPLATE = """
.. _porting_{{ ver }}_guide:
@@ -106,16 +109,6 @@ JINJA_ENV = Environment(
)
-def parse_args(args):
- parser = argparse.ArgumentParser(description="Generate a fresh porting guide template")
- parser.add_argument("--version", dest="version", type=str, required=True, action='store',
- help="Version of Ansible to write the porting guide for")
-
- args = parser.parse_args(args)
-
- return args
-
-
def generate_porting_guide(version):
template = JINJA_ENV.get_template('porting_guide')
@@ -133,13 +126,17 @@ def write_guide(version, guide_content):
out_file.write(guide_content)
-def main():
- args = parse_args(sys.argv[1:])
-
- guide_content = generate_porting_guide(args.version)
-
- write_guide(args.version, guide_content)
+class PortingGuideCommand(Command):
+ name = 'porting-guide'
+ @classmethod
+ def init_parser(cls, add_parser):
+ parser = add_parser(cls.name, description="Generate a fresh porting guide template")
+ parser.add_argument("--version", dest="version", type=str, required=True, action='store',
+ help="Version of Ansible to write the porting guide for")
-if __name__ == '__main__':
- main()
+ @staticmethod
+ def main(args):
+ guide_content = generate_porting_guide(args.version)
+ write_guide(args.version, guide_content)
+ return 0
diff --git a/hacking/release-announcement.py b/hacking/build_library/build_ansible/command_plugins/release_announcement.py
index cea3845a6c..a0ff09b482 100755..100644
--- a/hacking/release-announcement.py
+++ b/hacking/build_library/build_ansible/command_plugins/release_announcement.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python3
# coding: utf-8
# Copyright: (c) 2019, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
@@ -12,6 +11,7 @@ import argparse
import asyncio
import datetime
import hashlib
+import os.path
import sys
from collections import UserString
from distutils.version import LooseVersion
@@ -19,6 +19,10 @@ from distutils.version import LooseVersion
import aiohttp
from jinja2 import Environment, DictLoader
+# Pylint doesn't understand Python3 namespace modules.
+from ..commands import Command # pylint: disable=relative-beyond-top-level
+
+
# pylint: disable=
VERSION_FRAGMENT = """
{%- if versions | length > 1 %}
@@ -31,7 +35,7 @@ VERSION_FRAGMENT = """
"""
LONG_TEMPLATE = """
-{% set plural = True if versions | length == 1 else False %}
+{% set plural = False if versions | length == 1 else True %}
{% set latest_ver = (versions | sort(attribute='ver_obj'))[-1] %}
To: ansible-devel@googlegroups.com, ansible-project@googlegroups.com, ansible-announce@googlegroups.com
@@ -66,7 +70,7 @@ What's new in {{ version_str }}
{{ '-' * (14 + version_str | length) }}
{% filter wordwrap %}
-{% if plural %}This release is a{% else %}These releases are{% endif %} maintenance release{% if plural %}s{% endif %} containing numerous bugfixes. The full {% if versions | length <= 1 %} changelog is{% else %} changelogs are{% endif %} at:
+{% if plural %}These releases are{% else %}This release is a{% endif %} maintenance release{% if plural %}s{% endif %} containing numerous bugfixes. The full {% if plural %} changelogs are{% else %} changelog is{% endif %} at:
{% endfilter %}
@@ -116,15 +120,16 @@ Thanks!
# proper wrapping to occur
SHORT_TEMPLATE = """
+{% set plural = False if versions | length == 1 else True %}
@ansible
{{ version_str }}
-{% if versions | length > 1 %}
+{% if plural %}
have
{% else %}
has
{% endif %}
been released! Get
-{% if versions | length > 1 %}
+{% if plural %}
them
{% else %}
it
@@ -152,19 +157,7 @@ class VersionStr(UserString):
self.ver_obj = LooseVersion(string)
-def parse_args(args):
- parser = argparse.ArgumentParser(description="Generate email and twitter announcements"
- " from template")
- parser.add_argument("--version", dest="versions", type=str, required=True, action='append',
- help="Versions of Ansible to announce")
- parser.add_argument("--name", type=str, required=True, help="Real name to use on emails")
- parser.add_argument("--email-out", type=str, default="-",
- help="Filename to place the email announcement into")
- parser.add_argument("--twitter-out", type=str, default="-",
- help="Filename to place the twitter announcement into")
-
- args = parser.parse_args(args)
-
+def transform_args(args):
# Make it possible to sort versions in the jinja2 templates
new_versions = []
for version in args.versions:
@@ -285,15 +278,29 @@ def write_message(filename, message):
sys.stdout.write(message)
-def main():
- args = parse_args(sys.argv[1:])
+class ReleaseAnnouncementCommand(Command):
+ name = 'release-announcement'
+
+ @classmethod
+ def init_parser(cls, add_parser):
+ parser = add_parser(cls.name,
+ description="Generate email and twitter announcements from template")
- twitter_message = generate_short_message(args.versions)
- email_message = generate_long_message(args.versions, args.name)
+ parser.add_argument("--version", dest="versions", type=str, required=True, action='append',
+ help="Versions of Ansible to announce")
+ parser.add_argument("--name", type=str, required=True, help="Real name to use on emails")
+ parser.add_argument("--email-out", type=str, default="-",
+ help="Filename to place the email announcement into")
+ parser.add_argument("--twitter-out", type=str, default="-",
+ help="Filename to place the twitter announcement into")
- write_message(args.twitter_out, twitter_message)
- write_message(args.email_out, email_message)
+ @staticmethod
+ def main(args):
+ args = transform_args(args)
+ twitter_message = generate_short_message(args.versions)
+ email_message = generate_long_message(args.versions, args.name)
-if __name__ == '__main__':
- main()
+ write_message(args.twitter_out, twitter_message)
+ write_message(args.email_out, email_message)
+ return 0
diff --git a/hacking/build_library/build_ansible/commands.py b/hacking/build_library/build_ansible/commands.py
new file mode 100644
index 0000000000..363e8056fc
--- /dev/null
+++ b/hacking/build_library/build_ansible/commands.py
@@ -0,0 +1,50 @@
+# coding: utf-8
+# Copyright: (c) 2019, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+from abc import ABCMeta, abstractmethod, abstractproperty
+
+
+class Command:
+ """
+ Subcommands of :program:`build-ansible`.
+
+ This defines an interface that all subcommands must conform to. :program:`build-ansible` will
+ require that these things are present in order to proceed.
+ """
+ @staticmethod
+ @abstractproperty
+ def name():
+ """Name of the command. The same as the string is invoked with"""
+
+ @staticmethod
+ @abstractmethod
+ def init_parser(add_parser):
+ """
+ Initialize and register an argparse ArgumentParser
+
+ :arg add_parser: function which creates an ArgumentParser for the main program.
+
+ Implementations should first create an ArgumentParser using `add_parser` and then populate
+ it with the command line arguments that are needed.
+
+ .. seealso:
+ `add_parser` information in the :py:meth:`ArgumentParser.add_subparsers` documentation.
+ """
+
+ @staticmethod
+ @abstractmethod
+ def main(arguments):
+ """
+ Run the command
+
+ :arg arguments: The **parsed** command line args
+
+ This is the Command's entrypoint. The command line args are already parsed but from here
+ on, the command can do its work.
+ """