#838 fedora-messaging
Merged 4 years ago by msuchy. Opened 4 years ago by praiskup.

@@ -13,7 +13,11 @@

  from ..helpers import register_build_result, get_redis_logger, \

      local_file_logger, run_cmd, pkg_name_evr

  

- from ..msgbus import MsgBusStomp, MsgBusFedmsg

+ from ..msgbus import (

+         MsgBusStomp,

+         MsgBusFedmsg,

+         MsgBusFedoraMessaging,

+ )

  from ..sshcmd import SSHConnectionError

  

  
@@ -127,7 +131,10 @@

  

      def init_buses(self):

          for bus_config in self.opts.msg_buses:

-             self.msg_buses.append(MsgBusStomp(bus_config, self.log))

+             if bus_config.bus_type == 'stomp':

+                 self.msg_buses.append(MsgBusStomp(bus_config, self.log))

+             elif bus_config.bus_type == 'fedora-messaging':

+                 self.msg_buses.append(MsgBusFedoraMessaging(bus_config, self.log))

  

          if self.opts.fedmsg_enabled:

              self.msg_buses.append(MsgBusFedmsg(self.log))

file modified
+154 -82
@@ -2,10 +2,13 @@

  Message buses abstraction.

  """

  

+ import os

  import logging

  import copy

  import json

  

+ from copr_messaging import schema

+ 

  from .constants import BuildStatus

  

  try:
@@ -28,12 +31,118 @@

          return "[BUS '{0}'] {1}".format(self.extra['bus_id'], msg), kwargs

  

  

+ def message_from_worker_job(style, topic, job, who, ip, pid):

+     """

+     Compat wrapper generating message object for messages defined before we

+     switched to fedora-messaging jsonschema-aware model.  This can be removed

+     once we can exepect that people are using copr-messaging module (and thus

+     we can change message format without affecting the API).

+     """

+     if style == 'v1':

+         content = {

+             'user': job.submitter,

+             'copr': job.project_name,

+             'owner': job.project_owner,

+             'pkg': job.package_name,

+             'build': job.build_id,

+             'chroot': job.chroot,

+             'version': job.package_version,

+             'status': job.status,

+         }

+         content.update({'ip': ip, 'who': who, 'pid': pid})

+ 

+         message_types = {

+             'build.start': {

+                 'what': "build start: user:{user} copr:{copr}" \

+                         " pkg:{pkg} build:{build} ip:{ip} pid:{pid}",

+                 'class': schema.BuildChrootStartedV1,

+             },

+             'chroot.start': {

+                 'what': "chroot start: chroot:{chroot} user:{user}" \

+                         " copr:{copr} pkg:{pkg} build:{build} ip:{ip} pid:{pid}",

+                 'class': schema.BuildChrootEndedV1,

+             },

+             'build.end': {

+                 'what': "build end: user:{user} copr:{copr} build:{build}" \

+                         " pkg:{pkg} version:{version} ip:{ip} pid:{pid} status:{status}",

+                 'class': schema.BuildChrootStartedV1DontUse,

+             },

+         }

+ 

+         content['what'] = message_types[topic]['what'].format(**content)

+         message = message_types[topic]['class'](body=content)

+         return message

+ 

+     elif style == 'v1stomp':

+         und = '(undefined)'

+         content = {

+             'user':        getattr(job, 'submitter', und),

+             'copr':        getattr(job, 'project_name', und),

+             'owner':       getattr(job, 'project_owner', und),

+             'pkg':         getattr(job, 'package_name', und),

+             'build':       getattr(job, 'build_id', und),

+             'chroot':      getattr(job, 'chroot', und),

+             'version':     getattr(job, 'package_version', und),

+             'status':      getattr(job, 'status', und),

+         }

+ 

+         content['str_status'] = BuildStatus.string(content['status'])

+         content.update({'ip': ip, 'who': who, 'pid': pid})

+ 

+         msg_format = {

+             'build.start': {

+                 'keys': {

+                     'build': '{build}',

+                     'owner': '{owner}',

+                     'copr': '{copr}',

+                     'submitter': '{user}',

+                     'package': '{pkg}-{version}',

+                     'chroot': '{chroot}',

+                     'builder': '{ip}',

+                     'status': '{str_status}',

+                     'status_int': '{status}',

+                 },

+                 'class': schema.BuildChrootStartedV1Stomp,

+             },

+             'build.end': {

+                 'keys': {

+                     'build': '{build}',

+                     'owner': '{owner}',

+                     'copr': '{copr}',

+                     'submitter': '{user}',

+                     'package': '{pkg}-{version}',

+                     'chroot': '{chroot}',

+                     'builder': '{ip}',

+                     'status': '{str_status}',

+                     'status_int': '{status}',

+                 },

+                 'class': schema.BuildChrootEndedV1Stomp,

+             },

+             'chroot.start': {

+                 'keys': {

+                     'chroot': "{chroot}",

+                 },

+                 'class': schema.BuildChrootStartedV1StompDontUse,

+             },

+         }

+ 

+         body = {}

+         for key in msg_format[topic]['keys']:

+             body[key] = msg_format[topic]['keys'][key].format(**content)

+ 

+         return msg_format[topic]['class'](body=body)

+ 

+     raise NotImplementedError

+ 

+ 

  class MsgBus(object):

      """

      An "abstract" message bus class, don't instantiate!

      """

      messages = {}

  

+     style = 'v1'

+ 

      def __init__(self, opts, log=None):

          self.opts = opts

          # Fix bus_id soon enough.
@@ -49,59 +158,32 @@

          if hasattr(self.opts, 'messages'):

              self.messages.update(self.opts.messages)

  

- 

-     def _send(self, topic, body, headers):

+     def _send_message(self, message):

+         """

+         Send message from fedora_messaging.message.Message (or subclass) object.

+         The object is already validated.

+         """

          raise NotImplementedError

  

- 

-     def send(self, topic, body, headers=None):

+     def send_message(self, message):

          """

-         Send (dict) message over _send() method.

+         Validate and send message from fedora_messaging.message.Message (or

+         subclass) object.

          """

-         out_headers = copy.deepcopy(self.opts.headers)

-         if headers:

-             out_headers.update(copy.deepcopy(headers))

          try:

-             self._send(topic, body, out_headers)

+             message.validate()

+             self._send_message(message)

          # pylint: disable=W0703

-         except Exception as _:

+         except Exception:

              self.log.exception("Failed to publish message.")

  

- 

-     def announce_job(self, topic, job, **kwargs):

+     def announce_job(self, msg_type, job, who, ip, pid):

          """

-         Announce everywhere that a build process started now.

+         Compat thing to be removed;  future types of messages (v2+) should be

+         constructed at caller side, not in this class.

          """

-         if not topic in self.messages:

-             return

- 

- 

-         und = '(undefined)'

-         content = {

-             'user':        getattr(job, 'submitter', und),

-             'copr':        getattr(job, 'project_name', und),

-             'owner':       getattr(job, 'project_owner', und),

-             'pkg':         getattr(job, 'package_name', und),

-             'build':       getattr(job, 'build_id', und),

-             'chroot':      getattr(job, 'chroot', und),

-             'version':     getattr(job, 'package_version', und),

-             'status':      getattr(job, 'status', und),

-         }

- 

-         content['str_status'] = BuildStatus.string(content['status'])

-         content.update(kwargs)

- 

-         msg = {}

-         try:

-             for key in self.messages[topic]:

-                 msg[key] = self.messages[topic][key].format(**content)

-         # pylint: disable=W0703

-         except Exception as _:

-             self.log.exception("Failed to format '{0}' announcement."

-                                .format(topic))

-             return

- 

-         self.send(topic, msg)

+         msg = message_from_worker_job(self.style, msg_type, job, who, ip, pid)

+         self.send_message(msg)

  

  

  class StompListener(StompConnectionListener):
@@ -123,6 +205,8 @@

      default messages here!

      """

  

+     style = 'v1stomp'

+ 

      def connect(self):

          """

          connect (even repeatedly) to STOMP message bus
@@ -185,11 +269,22 @@

          self.connect()

  

  

-     def _send(self, topic, body, headers):

-         send_headers = copy.deepcopy(headers)

+     def _send_message(self, message):

+         topic = message.topic

+         body = message.body

+         send_headers = {}

          send_headers['topic'] = topic

+ 

+         destination = '{0}.{1}'.format(self.opts.destination, topic)

+ 

+         # backward compat (before we mistakenly sent everything to the same

+         # destination), drop once every consumer moved to copr-messaging module

+         # and thus we can expect them to consume fixed messages too.

+         if self.style == 'v1stomp':

+             destination = self.opts.destination

+ 

          self.conn.send(body=json.dumps(body), headers=send_headers,

-                        destination=self.opts.destination,

+                        destination=destination,

                         content_type='application/json')

  

  
@@ -197,21 +292,6 @@

      """

      Connect to fedmsg and send messages over it.

      """

-     messages = {

-         'build.start': {

-             'what': "build start: user:{user} copr:{copr}" \

-                     " pkg:{pkg} build:{build} ip:{ip} pid:{pid}",

-         },

-         'chroot.start': {

-             'what': "chroot start: chroot:{chroot} user:{user}" \

-                     " copr:{copr} pkg:{pkg} build:{build} ip:{ip} pid:{pid}",

-         },

-         'build.end': {

-             'what': "build end: user:{user} copr:{copr} build:{build}" \

-                     " pkg:{pkg} version:{version} ip:{ip} pid:{pid} status:{status}",

-         },

-     }

- 

      def __init__(self, log=None):

          # Hack to not require opts argument for now.

          opts = type('', (), {})
@@ -221,27 +301,19 @@

  

          fedmsg.init(name='relay_inbound', cert_prefix='copr', active=True)

  

-     def announce_job(self, topic, job, **kwargs):

-         """

-         Announce everywhere that a build process started now.

-         """

-         content = {

-             'user': job.submitter,

-             'copr': job.project_name,

-             'owner': job.project_owner,

-             'pkg': job.package_name,

-             'build': job.build_id,

-             'chroot': job.chroot,

-             'version': job.package_version,

-             'status': job.status,

-         }

-         content.update(kwargs)

+     def _send_message(self, message):

+         fedmsg.publish(modname='copr', topic=message.topic, msg=message.body)

  

-         if topic in self.messages:

-             for key in self.messages[topic]:

-                 content[key] = self.messages[topic][key].format(**content)

  

-         self.send(topic, content)

+ class MsgBusFedoraMessaging(MsgBus):

+     """

+     Connect to fedora-messaging AMQP bus and send messages over it.

+     """

+     def __init__(self, opts, log=None):

+         super(MsgBusFedoraMessaging, self).__init__(opts, log)

+         # note this is not thread safe, only one bus of this type!

+         os.environ['FEDORA_MESSAGING_CONF'] = opts.toml_config

  

-     def _send(self, topic, content, headers):

-         fedmsg.publish(modname='copr', topic=topic, msg=content)

+     def _send_message(self, message):

+         from fedora_messaging import api

+         api.publish(message)

@@ -0,0 +1,11 @@

+ """

+ Example configuration file for fedora-messaging AMQP bus.

+ """

+ 

+ bus_type = 'fedora-messaging'

+ 

+ bus_id = 'fm'

+ 

+ toml_config = '/etc/fedora-messaging/fedora.toml'

+ 

+ # vi: ft=python

backend/conf/msgbus-stomp.conf.example backend/conf/msgbus.conf.example
file renamed
+4 -33
@@ -1,9 +1,11 @@

  """

- Example configuration file for message bus.

+ Example configuration file for stomp message bus.

  """

  

  bus_id = 'ci_message_bus'

  

+ bus_type = 'stomp'

+ 

  # we use python-stomppy, see it's documentation for more info

  hosts = [

      ('bus1.example.com', '61613'),
@@ -21,40 +23,9 @@

  }

  

  # CA that signed our client key (optional)

- cacert = '/etc/pki/ca-trust/source/anchors/my-company.crt'

- 

- # headers which should be present in each message

- headers = {

-     'CI_TYPE': 'copr-service',

-     'copr_instance': 'development',

- }

+ cacert = '/etc/pki/ca-trust/source/anchors/company-ca.crt'

  

  # topic we want to write to on the bus (stomppy syntax)

  destination = "/topic/copr"

  

- # Define message templates.  Each message is identified by "key" (e.g.

- # 'build.start') and contains "key/value" pairs, while "values" are subject of

- # string substitution at the time message is generated.  Available substitutions

- # are:

- #   'user' (submitter), 'copr', 'owner', 'pkg', 'build' (id), 'chroot',

- #   'version' (pkg), 'ip' (of builder), 'who' (process name), 'pid' (of builder

- #   process), 'status' (status ID, see class BuildStatus), 'status_str'

- #   (user readable status)

- 

- messages = {

-     'build.start': {

-         'package': '{pkg}-{version}',

-         'chroot': '{chroot}',

-         'user': '{user}',

-     },

-     'build.end': {

-         'package': '{pkg}-{version}',

-         'chroot': '{chroot}',

-         'user': '{user}',

-     },

-     'chroot.start': {

-         'chroot': "{chroot}",

-     },

- }

- 

  # vi: ft=python

@@ -31,6 +31,7 @@

  BuildRequires: python3-daemon

  BuildRequires: python3-dateutil

  BuildRequires: python3-fedmsg

+ BuildRequires: python3-fedora-messaging

  BuildRequires: python3-humanize

  BuildRequires: python3-munch

  BuildRequires: python3-oslo-concurrency
@@ -63,6 +64,7 @@

  Requires:   python3-daemon

  Requires:   python3-dateutil

  Requires:   python3-fedmsg

+ Requires:   python3-fedora-messaging

  Requires:   python3-gobject

  Requires:   python3-humanize

  Requires:   python3-munch

file added
+339
@@ -0,0 +1,339 @@

+                     GNU GENERAL PUBLIC LICENSE

+                        Version 2, June 1991

+ 

+  Copyright (C) 1989, 1991 Free Software Foundation, Inc.,

+  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

+  Everyone is permitted to copy and distribute verbatim copies

+  of this license document, but changing it is not allowed.

+ 

+                             Preamble

+ 

+   The licenses for most software are designed to take away your

+ freedom to share and change it.  By contrast, the GNU General Public

+ License is intended to guarantee your freedom to share and change free

+ software--to make sure the software is free for all its users.  This

+ General Public License applies to most of the Free Software

+ Foundation's software and to any other program whose authors commit to

+ using it.  (Some other Free Software Foundation software is covered by

+ the GNU Lesser General Public License instead.)  You can apply it to

+ your programs, too.

+ 

+   When we speak of free software, we are referring to freedom, not

+ price.  Our General Public Licenses are designed to make sure that you

+ have the freedom to distribute copies of free software (and charge for

+ this service if you wish), that you receive source code or can get it

+ if you want it, that you can change the software or use pieces of it

+ in new free programs; and that you know you can do these things.

+ 

+   To protect your rights, we need to make restrictions that forbid

+ anyone to deny you these rights or to ask you to surrender the rights.

+ These restrictions translate to certain responsibilities for you if you

+ distribute copies of the software, or if you modify it.

+ 

+   For example, if you distribute copies of such a program, whether

+ gratis or for a fee, you must give the recipients all the rights that

+ you have.  You must make sure that they, too, receive or can get the

+ source code.  And you must show them these terms so they know their

+ rights.

+ 

+   We protect your rights with two steps: (1) copyright the software, and

+ (2) offer you this license which gives you legal permission to copy,

+ distribute and/or modify the software.

+ 

+   Also, for each author's protection and ours, we want to make certain

+ that everyone understands that there is no warranty for this free

+ software.  If the software is modified by someone else and passed on, we

+ want its recipients to know that what they have is not the original, so

+ that any problems introduced by others will not reflect on the original

+ authors' reputations.

+ 

+   Finally, any free program is threatened constantly by software

+ patents.  We wish to avoid the danger that redistributors of a free

+ program will individually obtain patent licenses, in effect making the

+ program proprietary.  To prevent this, we have made it clear that any

+ patent must be licensed for everyone's free use or not licensed at all.

+ 

+   The precise terms and conditions for copying, distribution and

+ modification follow.

+ 

+                     GNU GENERAL PUBLIC LICENSE

+    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+ 

+   0. This License applies to any program or other work which contains

+ a notice placed by the copyright holder saying it may be distributed

+ under the terms of this General Public License.  The "Program", below,

+ refers to any such program or work, and a "work based on the Program"

+ means either the Program or any derivative work under copyright law:

+ that is to say, a work containing the Program or a portion of it,

+ either verbatim or with modifications and/or translated into another

+ language.  (Hereinafter, translation is included without limitation in

+ the term "modification".)  Each licensee is addressed as "you".

+ 

+ Activities other than copying, distribution and modification are not

+ covered by this License; they are outside its scope.  The act of

+ running the Program is not restricted, and the output from the Program

+ is covered only if its contents constitute a work based on the

+ Program (independent of having been made by running the Program).

+ Whether that is true depends on what the Program does.

+ 

+   1. You may copy and distribute verbatim copies of the Program's

+ source code as you receive it, in any medium, provided that you

+ conspicuously and appropriately publish on each copy an appropriate

+ copyright notice and disclaimer of warranty; keep intact all the

+ notices that refer to this License and to the absence of any warranty;

+ and give any other recipients of the Program a copy of this License

+ along with the Program.

+ 

+ You may charge a fee for the physical act of transferring a copy, and

+ you may at your option offer warranty protection in exchange for a fee.

+ 

+   2. You may modify your copy or copies of the Program or any portion

+ of it, thus forming a work based on the Program, and copy and

+ distribute such modifications or work under the terms of Section 1

+ above, provided that you also meet all of these conditions:

+ 

+     a) You must cause the modified files to carry prominent notices

+     stating that you changed the files and the date of any change.

+ 

+     b) You must cause any work that you distribute or publish, that in

+     whole or in part contains or is derived from the Program or any

+     part thereof, to be licensed as a whole at no charge to all third

+     parties under the terms of this License.

+ 

+     c) If the modified program normally reads commands interactively

+     when run, you must cause it, when started running for such

+     interactive use in the most ordinary way, to print or display an

+     announcement including an appropriate copyright notice and a

+     notice that there is no warranty (or else, saying that you provide

+     a warranty) and that users may redistribute the program under

+     these conditions, and telling the user how to view a copy of this

+     License.  (Exception: if the Program itself is interactive but

+     does not normally print such an announcement, your work based on

+     the Program is not required to print an announcement.)

+ 

+ These requirements apply to the modified work as a whole.  If

+ identifiable sections of that work are not derived from the Program,

+ and can be reasonably considered independent and separate works in

+ themselves, then this License, and its terms, do not apply to those

+ sections when you distribute them as separate works.  But when you

+ distribute the same sections as part of a whole which is a work based

+ on the Program, the distribution of the whole must be on the terms of

+ this License, whose permissions for other licensees extend to the

+ entire whole, and thus to each and every part regardless of who wrote it.

+ 

+ Thus, it is not the intent of this section to claim rights or contest

+ your rights to work written entirely by you; rather, the intent is to

+ exercise the right to control the distribution of derivative or

+ collective works based on the Program.

+ 

+ In addition, mere aggregation of another work not based on the Program

+ with the Program (or with a work based on the Program) on a volume of

+ a storage or distribution medium does not bring the other work under

+ the scope of this License.

+ 

+   3. You may copy and distribute the Program (or a work based on it,

+ under Section 2) in object code or executable form under the terms of

+ Sections 1 and 2 above provided that you also do one of the following:

+ 

+     a) Accompany it with the complete corresponding machine-readable

+     source code, which must be distributed under the terms of Sections

+     1 and 2 above on a medium customarily used for software interchange; or,

+ 

+     b) Accompany it with a written offer, valid for at least three

+     years, to give any third party, for a charge no more than your

+     cost of physically performing source distribution, a complete

+     machine-readable copy of the corresponding source code, to be

+     distributed under the terms of Sections 1 and 2 above on a medium

+     customarily used for software interchange; or,

+ 

+     c) Accompany it with the information you received as to the offer

+     to distribute corresponding source code.  (This alternative is

+     allowed only for noncommercial distribution and only if you

+     received the program in object code or executable form with such

+     an offer, in accord with Subsection b above.)

+ 

+ The source code for a work means the preferred form of the work for

+ making modifications to it.  For an executable work, complete source

+ code means all the source code for all modules it contains, plus any

+ associated interface definition files, plus the scripts used to

+ control compilation and installation of the executable.  However, as a

+ special exception, the source code distributed need not include

+ anything that is normally distributed (in either source or binary

+ form) with the major components (compiler, kernel, and so on) of the

+ operating system on which the executable runs, unless that component

+ itself accompanies the executable.

+ 

+ If distribution of executable or object code is made by offering

+ access to copy from a designated place, then offering equivalent

+ access to copy the source code from the same place counts as

+ distribution of the source code, even though third parties are not

+ compelled to copy the source along with the object code.

+ 

+   4. You may not copy, modify, sublicense, or distribute the Program

+ except as expressly provided under this License.  Any attempt

+ otherwise to copy, modify, sublicense or distribute the Program is

+ void, and will automatically terminate your rights under this License.

+ However, parties who have received copies, or rights, from you under

+ this License will not have their licenses terminated so long as such

+ parties remain in full compliance.

+ 

+   5. You are not required to accept this License, since you have not

+ signed it.  However, nothing else grants you permission to modify or

+ distribute the Program or its derivative works.  These actions are

+ prohibited by law if you do not accept this License.  Therefore, by

+ modifying or distributing the Program (or any work based on the

+ Program), you indicate your acceptance of this License to do so, and

+ all its terms and conditions for copying, distributing or modifying

+ the Program or works based on it.

+ 

+   6. Each time you redistribute the Program (or any work based on the

+ Program), the recipient automatically receives a license from the

+ original licensor to copy, distribute or modify the Program subject to

+ these terms and conditions.  You may not impose any further

+ restrictions on the recipients' exercise of the rights granted herein.

+ You are not responsible for enforcing compliance by third parties to

+ this License.

+ 

+   7. If, as a consequence of a court judgment or allegation of patent

+ infringement or for any other reason (not limited to patent issues),

+ conditions are imposed on you (whether by court order, agreement or

+ otherwise) that contradict the conditions of this License, they do not

+ excuse you from the conditions of this License.  If you cannot

+ distribute so as to satisfy simultaneously your obligations under this

+ License and any other pertinent obligations, then as a consequence you

+ may not distribute the Program at all.  For example, if a patent

+ license would not permit royalty-free redistribution of the Program by

+ all those who receive copies directly or indirectly through you, then

+ the only way you could satisfy both it and this License would be to

+ refrain entirely from distribution of the Program.

+ 

+ If any portion of this section is held invalid or unenforceable under

+ any particular circumstance, the balance of the section is intended to

+ apply and the section as a whole is intended to apply in other

+ circumstances.

+ 

+ It is not the purpose of this section to induce you to infringe any

+ patents or other property right claims or to contest validity of any

+ such claims; this section has the sole purpose of protecting the

+ integrity of the free software distribution system, which is

+ implemented by public license practices.  Many people have made

+ generous contributions to the wide range of software distributed

+ through that system in reliance on consistent application of that

+ system; it is up to the author/donor to decide if he or she is willing

+ to distribute software through any other system and a licensee cannot

+ impose that choice.

+ 

+ This section is intended to make thoroughly clear what is believed to

+ be a consequence of the rest of this License.

+ 

+   8. If the distribution and/or use of the Program is restricted in

+ certain countries either by patents or by copyrighted interfaces, the

+ original copyright holder who places the Program under this License

+ may add an explicit geographical distribution limitation excluding

+ those countries, so that distribution is permitted only in or among

+ countries not thus excluded.  In such case, this License incorporates

+ the limitation as if written in the body of this License.

+ 

+   9. The Free Software Foundation may publish revised and/or new versions

+ of the General Public License from time to time.  Such new versions will

+ be similar in spirit to the present version, but may differ in detail to

+ address new problems or concerns.

+ 

+ Each version is given a distinguishing version number.  If the Program

+ specifies a version number of this License which applies to it and "any

+ later version", you have the option of following the terms and conditions

+ either of that version or of any later version published by the Free

+ Software Foundation.  If the Program does not specify a version number of

+ this License, you may choose any version ever published by the Free Software

+ Foundation.

+ 

+   10. If you wish to incorporate parts of the Program into other free

+ programs whose distribution conditions are different, write to the author

+ to ask for permission.  For software which is copyrighted by the Free

+ Software Foundation, write to the Free Software Foundation; we sometimes

+ make exceptions for this.  Our decision will be guided by the two goals

+ of preserving the free status of all derivatives of our free software and

+ of promoting the sharing and reuse of software generally.

+ 

+                             NO WARRANTY

+ 

+   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY

+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN

+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES

+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED

+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS

+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE

+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,

+ REPAIR OR CORRECTION.

+ 

+   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING

+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR

+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,

+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING

+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED

+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY

+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER

+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE

+ POSSIBILITY OF SUCH DAMAGES.

+ 

+                      END OF TERMS AND CONDITIONS

+ 

+             How to Apply These Terms to Your New Programs

+ 

+   If you develop a new program, and you want it to be of the greatest

+ possible use to the public, the best way to achieve this is to make it

+ free software which everyone can redistribute and change under these terms.

+ 

+   To do so, attach the following notices to the program.  It is safest

+ to attach them to the start of each source file to most effectively

+ convey the exclusion of warranty; and each file should have at least

+ the "copyright" line and a pointer to where the full notice is found.

+ 

+     <one line to give the program's name and a brief idea of what it does.>

+     Copyright (C) <year>  <name of author>

+ 

+     This program is free software; you can redistribute it and/or modify

+     it under the terms of the GNU General Public License as published by

+     the Free Software Foundation; either version 2 of the License, or

+     (at your option) any later version.

+ 

+     This program is distributed in the hope that it will be useful,

+     but WITHOUT ANY WARRANTY; without even the implied warranty of

+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+     GNU General Public License for more details.

+ 

+     You should have received a copy of the GNU General Public License along

+     with this program; if not, write to the Free Software Foundation, Inc.,

+     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

+ 

+ Also add information on how to contact you by electronic and paper mail.

+ 

+ If the program is interactive, make it output a short notice like this

+ when it starts in an interactive mode:

+ 

+     Gnomovision version 69, Copyright (C) year name of author

+     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.

+     This is free software, and you are welcome to redistribute it

+     under certain conditions; type `show c' for details.

+ 

+ The hypothetical commands `show w' and `show c' should show the appropriate

+ parts of the General Public License.  Of course, the commands you use may

+ be called something other than `show w' and `show c'; they could even be

+ mouse-clicks or menu items--whatever suits your program.

+ 

+ You should also get your employer (if you work as a programmer) or your

+ school, if any, to sign a "copyright disclaimer" for the program, if

+ necessary.  Here is a sample; alter the names:

+ 

+   Yoyodyne, Inc., hereby disclaims all copyright interest in the program

+   `Gnomovision' (which makes passes at compilers) written by James Hacker.

+ 

+   <signature of Ty Coon>, 1 April 1989

+   Ty Coon, President of Vice

+ 

+ This General Public License does not permit incorporating your program into

+ proprietary programs.  If your program is a subroutine library, you may

+ consider it more useful to permit linking proprietary applications with the

+ library.  If this is what you want to do, use the GNU Lesser General

+ Public License instead of this License.

file added
+10
@@ -0,0 +1,10 @@

+ Schema and tooling for Copr fedora-messaging

+ ============================================

+ 

+ Schemas for messages sent by Copr project, as described on

+ [fedora-messaging documentation page].

+ 

+ This package also provides several convenience methods for working with copr

+ messages, see docs.

+ 

+ [fedora-messaging documentation page]: https://fedora-messaging.readthedocs.io/en/latest/messages.html#schema

@@ -0,0 +1,72 @@

+ %global _description\

+ Schemas for messages sent by Copr project, as described on \

+ fedora-messaging documentation page \

+ https://fedora-messaging.readthedocs.io/en/latest/messages.html#schema \

+ \

+ Package also provides several convenience methods for working with \

+ copr messages.

+ 

+ Name:       {{{ git_dir_name }}}

+ Version:    {{{ git_dir_version }}}

+ Release:    1%{?dist}

+ Summary:    Abstraction for Copr messaging listeners/publishers

+ 

+ License:    GPLv2+

+ URL:        https://pagure.io/copr/copr

+ # Source is created by:

+ # git clone https://pagure.io/copr/copr.git

+ # git checkout {{{ cached_git_name_version }}}

+ # cd copr/fedora-messaging

+ # rpkg spec --sources

+ Source0:    {{{ git_dir_archive }}}

+ 

+ BuildArch:  noarch

+ 

+ Requires:      wget

+ 

+ 

+ BuildRequires: asciidoc

+ BuildRequires: libxslt

+ BuildRequires: util-linux

+ 

+ BuildRequires: python3-copr-common

+ BuildRequires: python3-devel

+ BuildRequires: python3-fedora-messaging

+ BuildRequires: python3-pytest

+ 

+ %description %_description

+ 

+ 

+ %package -n python3-%name

+ Summary: %summary

+ Provides: %name = %version

+ 

+ Requires: python3-copr-common

+ Requires: python3-fedora-messaging

+ 

+ %description -n python3-%name %_description

+ 

+ 

+ %prep

+ %setup -q

+ 

+ 

+ %build

+ %py3_build

+ 

+ 

+ %install

+ %py3_install

+ 

+ 

+ %check

+ ./runtests.sh

+ 

+ 

+ %files -n python3-%name

+ %python3_sitelib/copr_messaging

+ %python3_sitelib/copr_messaging*egg-info

+ 

+ 

+ %changelog

+ {{{ git_dir_changelog }}}

@@ -0,0 +1,15 @@

+ # Copyright (C) 2019  Red Hat, Inc.

+ #

+ # This program is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation; either version 2 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License along

+ # with this program; if not, write to the Free Software Foundation, Inc.,

+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

@@ -0,0 +1,73 @@

+ # Copyright (C) 2019  Red Hat, Inc.

+ #

+ # This program is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation; either version 2 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License along

+ # with this program; if not, write to the Free Software Foundation, Inc.,

+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

+ 

+ from fedora_messaging.message import Message

+ 

+ from .private.consumer import _GenericConsumer

+ from .schema import (

+         BuildChrootEnded,

+         BuildChrootEndedV1,

+         BuildChrootStarted,

+         BuildChrootStartedV1,

+         BuildChrootStartedV1DontUse,

+ )

+ 

+ 

+ def retype_message(message):

+     if type(message) == Message:

+         # This message might be actually originated from fedmsg, and the

+         # fedmsg->AMQP proxy made things wrong and the fedora-messaging

+         # tooling is unable to correctly instanitate it.

+         if message.topic.endswith('.copr.build.end'):

+             return BuildChrootEndedV1(body=message.body)

+         if message.topic.endswith('.copr.build.start'):

+             return BuildChrootStartedV1(body=message.body)

+         if message.topic.endswith('.copr.chroot.start'):

+             return BuildChrootStartedV1DontUse(body=message.body)

+ 

+     return message

+ 

+ 

+ class Consumer(_GenericConsumer):

+     """

+     Helper.

+     """

+     def __call__(self, message):

+         message = retype_message(message)

+ 

+         message.validate()

+ 

+         if isinstance(message, BuildChrootStartedV1DontUse):

+             return

+ 

+         try:

+             if isinstance(message, BuildChrootStarted):

+                 self.build_chroot_started(message)

+                 return

+ 

+             if isinstance(message, BuildChrootEnded):

+                 self.build_chroot_ended(message)

+                 return

+         except NotImplementedError:

+             pass

+ 

+ 

+ class Printer(Consumer):

+     def build_chroot_started(self, message):

+         print("build_chroot_started(): {}".format(message))

+ 

+     def build_chroot_ended(self, message):

+         print("build_chroot_ended(): {}".format(message))

empty or binary file added
@@ -0,0 +1,23 @@

+ # Copyright (C) 2019  Red Hat, Inc.

+ #

+ # This program is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation; either version 2 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License along

+ # with this program; if not, write to the Free Software Foundation, Inc.,

+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

+ 

+ 

+ class _GenericConsumer(object):

+     def build_chroot_started(self, message):

+         raise NotImplementedError

+ 

+     def build_chroot_ended(self, message):

+         raise NotImplementedError

@@ -0,0 +1,166 @@

+ # Copyright (C) 2019  Red Hat, Inc.

+ #

+ # This program is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation; either version 2 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License along

+ # with this program; if not, write to the Free Software Foundation, Inc.,

+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

+ 

+ """

+ Private hierarchy of Copr messages.  This is for module-internal purposes only.

+ """

+ 

+ from fedora_messaging import message

+ 

+ class _CoprMessage(message.Message):

+     def __init__(self, *args, **kwargs):

+         if 'body' in kwargs:

+             body = kwargs.pop('body')

+             if 'msg' in body:

+                 body = body['msg']

+             kwargs['body'] = body

+ 

+         super(_CoprMessage, self).__init__(*args, **kwargs)

+ 

+     """

+     Base class that all Copr messages should inherit from.

+     """

+     def __str__(self):

+         return "Unspecified Copr message"

+ 

+     def _str_prefix(self):

+         return "Copr Message"

+ 

+ 

+ class _CoprProjectMessage(_CoprMessage):

+     def _str_prefix(self):

+         return '{0} in project "{1}"'.format(

+             super(_CoprProjectMessage, self)._str_prefix(),

+             self.project_full_name,

+         )

+ 

+     @property

+     def project_owner(self):

+         """

+         Owner name of the Copr project.  It may be either ``@groupname`` or

+         ``username`` (leading `at` sign indicates group).

+         """

+         raise NotImplementedError

+ 

+     @property

+     def project_name(self):

+         """

+         Name of the copr project.  Note that several owners may host project of

+         the same name at the same time.

+         """

+         raise NotImplementedError

+ 

+     @property

+     def project_full_name(self):

+         """

+         Project owner name + project name, separated by slash.

+         """

+         return '{0}/{1}'.format(self.project_owner, self.project_name)

+ 

+ 

+ class _BuildMessage(_CoprProjectMessage):

+     def _str_prefix(self):

+         return '{0}: build {1}'.format(

+             super(_BuildMessage, self)._str_prefix(),

+             self.build_id,

+         )

+ 

+     @property

+     def build_id(self):

+         """

+         Copr Build ID.

+ 

+         Note that one copr build (identified by this ID) generates several build

+         messages (namely for each :py:attr:`.chroot`, before build started and

+         after the build finished).

+         """

+         raise NotImplementedError

+ 

+     @property

+     def package_name(self):

+         """

+         *Name* of the *package* this message is related to

+         [#footnote_may_be_unknown]_.

+         """

+         raise NotImplementedError

+ 

+     # TODO: from old messages, it's not possible to detect package's

+     # architecture (yes, chroot ... but that doesn't resolve noarch packages).

+ 

+     def _evr(self):

+         # return (epoch, version, release) triplet

+         raise NotImplementedError

+ 

+     @property

+     def package_version(self):

+         """

+         *Version* of the *package* [#footnote_may_be_unknown]_.  Returns `None`

+         if epoch is unset.

+         """

+         _, version, _ = self._evr()

+         return version

+ 

+     @property

+     def package_release(self):

+         """

+         *Release* of the *package* [#footnote_may_be_unknown]_.  Returns `None`

+         if epoch is unset.

+         """

+         _, _, release = self._evr()

+         return release

+ 

+     @property

+     def package_epoch(self):

+         """

+         *Epoch* of the *package* [#footnote_may_be_unknown]_.  Returns `None` if

+         epoch is unset.

+         """

+         epoch, _, _ = self._evr()

+         return epoch

+ 

+     @property

+     def package_full_name(self):

+         """

+         Full - human readable - package name (not meant to be parsed).

+         [#footnote_may_be_unknown]_.

+         """

+         if not self.package_name:

+             return None

+ 

+         (epoch, version, release) = self._evr()

+ 

+         return "{name}-{epoch}{version}-{release}".format(

+             name=self.package_name,

+             epoch=epoch + ":" if epoch else "",

+             version=version,

+             release=release,

+         )

+ 

+ 

+ class _BuildChrootMessage(_BuildMessage):

+     @property

+     def chroot(self):

+         """

+         Build chroot name this build is done in.  For example

+         ``fedora-rawhide-x86_64`` or ``epel-7-x86_64``.

+ 

+         When this is source build, the returned value is ``srpm-builds``.  Each

+         build (see :py:attr:`.build_id`) in copr needs to prepare sources first

+         (those are imported into copr dist-git) for the following binary-RPM

+         builds; so such source build might represent some SCM method execution,

+         or e.g. just act of downloading SRPM from a remote URL.

+         """

+         raise NotImplementedError

@@ -0,0 +1,145 @@

+ # Copyright (C) 2019  Red Hat, Inc.

+ #

+ # This program is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation; either version 2 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License along

+ # with this program; if not, write to the Free Software Foundation, Inc.,

+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

+ 

+ 

+ from copr_common.enums import StatusEnum

+ from .hierarchy import _BuildChrootMessage

+ 

+ class _PreFMBuildMessage(_BuildChrootMessage):

+     """ old obsoleted msg format """

+ 

+     """

+     This is 'copr.build.end' message schema.

+ 

+     This message is from the pre-fedora-messaging era.

+     """

+     body_schema = {

+         "id": "http://fedoraproject.org/message-schema/copr#",

+         "$schema": "http://json-schema.org/draft-04/schema#",

+         "description":

+             "Message sent by Copr build system",

+         "type": "object",

+         "required": [

+             "status",

+             "chroot",

+             "build",

+             "owner",

+             "copr",

+             "pkg",

+             "version",

+             "what",

+             "ip",

+             "who",

+             "user",

+             "pid",

+         ],

+         "properties": {

+             "status": {

+                 "type": "number",

+                 "description": "numerical representation of build status",

+             },

+             "chroot": {

+                 "type": "string",

+                 "description": "what chroot was this build run against, "

+                                "'srpm-builds' for source builds",

+             },

+             "owner": {

+                 "type": "string",

+                 "description":

+                     "owner (grup/user) of the project this build was done in",

+             },

+             "copr": {

+                 "type": "string",

+                 "description": "name of the project the build was built in",

+             },

+             "build": {

+                 "type": "number",

+                 "description": "build id",

+             },

+             "pkg": {

+                 "type": ['string', 'null'],

+                 "description": "Package name, null if unknown",

+             },

+             "version": {

+                 "type": ['string', 'null'],

+                 "description": "Package version, null if unknown",

+             },

+             "user": {

+                 "type": ['string', 'null'],

+                 "description": "Copr user who submitted the build, null if unknown",

+             },

+             "what": {

+                 "type": "string",

+                 "description": "combination of all the fields",

+             },

+             "ip": {

+                 "type": ["string", "null"],

+                 "description": "IP address (usually not public) of the builder",

+             },

+             "who": {

+                 "type": ['string'],

+                 "description": "what python module has sent this message",

+             },

+             "pid": {

+                 "type": 'number',

+                 "description": "process ID of the process on backend taking "

+                                "care of the task",

+             },

+         },

+     }

+ 

+     @property

+     def build_id(self):

+         return self.body['build']

+ 

+     @property

+     def project_name(self):

+         return str(self.body['copr'])

+ 

+     @property

+     def project_owner(self):

+         return str(self.body['owner'])

+ 

+     @property

+     def chroot(self):

+         return self.body['chroot']

+ 

+     @property

+     def status(self):

+         """

+         String representation of build chroot status.

+         """

+         return StatusEnum(self.body['status'])

+ 

+     @property

+     def package_name(self):

+         return self.body.get('pkg')

+ 

+     def _evr(self):

+         evr = self.body.get('version')

+         if not evr:

+             return (None, None, None)

+ 

+         e_v = evr .split(':', 1)

+         epoch = None

+         if len(e_v) == 1:

+             v_r = e_v[0]

+         else:

+             epoch = e_v[0]

+             v_r = e_v[1]

+ 

+         version, release = v_r.split('-', 1)

+         return (epoch, version, release)

@@ -0,0 +1,141 @@

+ # Copyright (C) 2019  Red Hat, Inc.

+ #

+ # This program is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation; either version 2 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License along

+ # with this program; if not, write to the Free Software Foundation, Inc.,

+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

+ 

+ 

+ """

+ TODO

+ """

+ 

+ import copy

+ 

+ from copr_common.enums import StatusEnum

+ 

+ from .hierarchy import _BuildChrootMessage

+ 

+ 

+ BODY_SCHEMA = {

+     "id": "http://fedoraproject.org/message-schema/copr#",

+     "$schema": "http://json-schema.org/draft-04/schema#",

+     "type": "object",

+     "required": [

+         "build",

+         "owner",

+         "copr",

+         "submitter",

+         "package",

+         "chroot",

+         "builder",

+         "status",

+         "status_int",

+     ],

+     "properties": {

+         "build": {

+             "type": "string",

+             "description": "build id as string",

+         },

+         "owner": {

+             "type": "string",

+             "description":

+                 "owner (grup/user) of the project this build was done in",

+         },

+         "copr": {

+             "type": "string",

+             "description": "name of the project the build was built in",

+         },

+         "submitter": {

+             "type": ["string", "null"],

+             "description": "who (copr user) submitted this build",

+         },

+         "package": {

+             "type": ['string', 'null'],

+             "description": "Package NVR, null if unknown",

+         },

+         "chroot": {

+             "type": "string",

+             "description": "what chroot was this build run against, "

+                            "'srpm-builds' for source builds",

+         },

+         "builder": {

+             "type": ["string", "null"],

+             "description": "IP address (usually not public) of the builder",

+         },

+         "status": {

+             "type": "string",

+             "description": "text representation of build status",

+         },

+         "status_int": {

+             "type": "string",

+             "description": "integer representation of build status",

+         },

+     },

+ }

+ 

+ 

+ class _OldStompChrootMessage(_BuildChrootMessage):

+     body_schema = copy.deepcopy(BODY_SCHEMA)

+     body_schema.update({

+         'description': 'hey!',

+     })

+ 

+     @property

+     def build_id(self):

+         return int(self.body['build'])

+ 

+     @property

+     def project_name(self):

+         return str(self.body['copr'])

+ 

+     @property

+     def project_owner(self):

+         return str(self.body['owner'])

+ 

+     @property

+     def chroot(self):

+         return self.body['chroot']

+ 

+     @property

+     def status(self):

+         """

+         String representation of build chroot status.

+         """

+         return StatusEnum(int(self.body['status_int']))

+ 

+     def _nevr(self):

+         nevr = self.body.get('package')

+         if nevr == 'None-None':

+             # compat hack, for mistakenly sent strings like this before

+             return (None, None, None, None)

+ 

+         nev, release = nevr.rsplit('-', 1)

+         name, e_v = nev.rsplit('-', 1)

+         e_v_list = e_v.split(':')

+         if len(e_v_list) == 1:

+             epoch = None

+             version = e_v_list[0]

+         else:

+             epoch = e_v_list[0]

+             version = e_v_list[1]

+ 

+         return (name, epoch, version, release)

+ 

+     def _evr(self):

+         _, epoch, version, release = self._nevr()

+         return (epoch, version, release)

+ 

+     @property

+     def package_name(self):

+         name, _, _, _ = self._nevr()

+         return name

@@ -0,0 +1,132 @@

+ # Copyright (C) 2019  Red Hat, Inc.

+ #

+ # This program is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation; either version 2 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License along

+ # with this program; if not, write to the Free Software Foundation, Inc.,

+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

+ 

+ """

+ This file contains schemas for messages sent by Copr project.

+ """

+ 

+ import copy

+ 

+ from copr_common.enums import StatusEnum

+ from fedora_messaging import message

+ 

+ from .private.hierarchy import _BuildChrootMessage

+ from .private.schema_old import _PreFMBuildMessage

+ from .private import schema_stomp_old

+ 

+ 

+ class BuildChrootEnded(_BuildChrootMessage):

+     """

+     Representation of a message sent by Copr build system right after some Copr

+     worker finished a build in a particular mock chroot.

+     """

+     @property

+     def status(self):

+         """

+         string representation of build status, e.g. ``succeeded``, ``failed``

+         """

+         raise NotImplementedError

+ 

+     def __str__(self):

+         return '{0}: chroot "{1}" ended as "{2}".'.format(

+             super(BuildChrootEnded, self)._str_prefix(),

+             self.chroot,

+             self.status,

+         )

+ 

+ 

+ class BuildChrootStarted(_BuildChrootMessage):

+     """

+     Representation of a message sent by Copr build system right before some Copr

+     worker starts working on a build in a particular mock chroot.

+     """

+     def __str__(self):

+         return '{0}: chroot "{1}" started.'.format(

+             super(BuildChrootStarted, self)._str_prefix(),

+             self.chroot,

+         )

+ 

+ 

+ class BuildChrootStartedV1(_PreFMBuildMessage, BuildChrootStarted):

+     """

+     schema for the old fedmsg-era 'copr.build.start' message

+     """

+     topic = 'copr.build.start'

+ 

+ 

+ class BuildChrootEndedV1(_PreFMBuildMessage, BuildChrootEnded):

+     """

+     schema for the old fedmsg-era 'copr.build.end' message

+     """

+     topic = 'copr.build.end'

+ 

+     @property

+     def status(self):

+         return StatusEnum(self.body['status'])

+ 

+ 

+ class BuildChrootStartedV1DontUse(_PreFMBuildMessage, BuildChrootStarted):

+     """

+     Schema for the old fedmsg-era 'copr.chroot.start' message, this message

+     duplicated the 'copr.build.start' message, so you should never use this.

+     """

+     topic = 'copr.chroot.start'

+ 

+ 

+ class BuildChrootStartedV1Stomp(schema_stomp_old._OldStompChrootMessage,

+                                 BuildChrootStarted):

+     topic = 'build.start'

+     body_schema = copy.deepcopy(schema_stomp_old.BODY_SCHEMA)

+     body_schema.update({

+         'description': ""

+     })

+ 

+ 

+ class BuildChrootStartedV1StompDontUse(message.Message):

+     topic = 'chroot.start'

+ 

+     body_schema = {

+         "id": "http://fedoraproject.org/message-schema/copr#",

+         "$schema": "http://json-schema.org/draft-04/schema#",

+         "description":

+             "Message sent by Copr build system when build in "

+             "concrete chroot started",

+         "type": "object",

+         "required": [

+             "chroot",

+         ],

+         "properties": {

+             "chroot": {

+                 "type": "string",

+                 "description": "what chroot was this build run against, "

+                                "'srpm-builds' for source builds",

+             },

+         },

+     }

+ 

+ 

+ class BuildChrootEndedV1Stomp(schema_stomp_old._OldStompChrootMessage,

+                               BuildChrootEnded):

+     topic = 'build.end'

+ 

+     body_schema = copy.deepcopy(schema_stomp_old.BODY_SCHEMA)

+     body_schema.update({

+         'description': ""

+     })

+ 

+     @property

+     def status(self):

+         return StatusEnum(int(self.body['status_int']))

@@ -0,0 +1,73 @@

+ # Copyright (C) 2019  Red Hat, Inc.

+ #

+ # This program is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation; either version 2 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License along

+ # with this program; if not, write to the Free Software Foundation, Inc.,

+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

+ 

+ import stomp

+ import json

+ 

+ from .schema import (

+         BuildChrootStartedV1,

+         BuildChrootEndedV1,

+         BuildChrootStartedV1DontUse,

+         BuildChrootStartedV1Stomp,

+         BuildChrootEndedV1Stomp,

+         BuildChrootStartedV1StompDontUse,

+ )

+ 

+ from .private.consumer import _GenericConsumer

+ 

+ 

+ def message_object_from_raw(headers, body):

+     destination = headers.get('destination')

+     topic = headers.get('topic')

+     body = json.loads(body)

+ 

+     if destination.endswith('.copr.build.end'):

+         return BuildChrootEndedV1(body=body)

+     if destination.endswith('.copr.build.start'):

+         return BuildChrootStartedV1(body=body)

+     if destination.endswith('.copr.chroot.start'):

+         return BuildChrootStartedV1DontUse(body=body)

+ 

+     if topic == 'build.start':

+         return BuildChrootStartedV1Stomp(body=body)

+     if topic == 'build.end':

+         return BuildChrootEndedV1Stomp(body=body)

+     if topic == 'chroot.start':

+         return BuildChrootStartedV1StompDontUse(body=body)

+ 

+ 

+ class Consumer(stomp.listener.ConnectionListener, _GenericConsumer):

+ 

+     def on_message(self, headers, body):

+         message = message_object_from_raw(headers, body)

+         message.validate()

+ 

+         if isinstance(message, BuildChrootStartedV1StompDontUse):

+             return

+ 

+         try:

+             if isinstance(message, BuildChrootStartedV1) or \

+                isinstance(message, BuildChrootStartedV1Stomp):

+                 self.build_chroot_started(message)

+                 return

+ 

+             if isinstance(message, BuildChrootEndedV1) or \

+                isinstance(message, BuildChrootEndedV1Stomp):

+                 self.build_chroot_ended(message)

+                 return

+ 

+         except NotImplementedError:

+             return

@@ -0,0 +1,15 @@

+ # Copyright (C) 2019  Red Hat, Inc.

+ #

+ # This program is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation; either version 2 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License along

+ # with this program; if not, write to the Free Software Foundation, Inc.,

+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

@@ -0,0 +1,286 @@

+ # Copyright (C) 2019  Red Hat, Inc.

+ #

+ # This program is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation; either version 2 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License along

+ # with this program; if not, write to the Free Software Foundation, Inc.,

+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

+ 

+ """Unit tests for the message schema."""

+ 

+ import copy

+ import unittest

+ 

+ from jsonschema import ValidationError

+ from .. import schema

+ 

+ 

+ class BuildChrootStartedV1Test(unittest.TestCase):

+     """A set of unit tests to ensure the schema works as expected."""

+ 

+     msg_class = schema.BuildChrootStartedV1

+     required_fields = ['status', 'what', 'chroot', 'ip', 'user', 'who',

+                        'pid', 'copr', 'version', 'build', 'owner', 'pkg']

+ 

+     def setUp(self):

+         self.fedmsg_message = {

+             "username": "copr",

+             "source_name": "datanommer",

+             "certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVUakNDQTdlZ0F3SUJBZ0lDQVBZd0RRWUpL\nb1pJaHZjTkFRRUZCUUF3Z2FBeEN6QUpCZ05WQkFZVEFsVlQKTVFzd0NRWURWUVFJRXdKT1F6RVFN\nQTRHQTFVRUJ4TUhVbUZzWldsbmFERVhNQlVHQTFVRUNoTU9SbVZrYjNKaApJRkJ5YjJwbFkzUXhE\nekFOQmdOVkJBc1RCbVpsWkcxelp6RVBNQTBHQTFVRUF4TUdabVZrYlhObk1ROHdEUVlEClZRUXBF\nd1ptWldSdGMyY3hKakFrQmdrcWhraUc5dzBCQ1FFV0YyRmtiV2x1UUdabFpHOXlZWEJ5YjJwbFkz\nUXUKYjNKbk1CNFhEVEUwTURReU16RTBNamsxTVZvWERUSTBNRFF5TURFME1qazFNVm93Z2R3eEN6\nQUpCZ05WQkFZVApBbFZUTVFzd0NRWURWUVFJRXdKT1F6RVFNQTRHQTFVRUJ4TUhVbUZzWldsbmFE\nRVhNQlVHQTFVRUNoTU9SbVZrCmIzSmhJRkJ5YjJwbFkzUXhEekFOQmdOVkJBc1RCbVpsWkcxelp6\nRXRNQ3NHQTFVRUF4TWtZMjl3Y2kxamIzQnkKTFdKbExtTnNiM1ZrTG1abFpHOXlZWEJ5YjJwbFkz\nUXViM0puTVMwd0t3WURWUVFwRXlSamIzQnlMV052Y0hJdApZbVV1WTJ4dmRXUXVabVZrYjNKaGNI\nSnZhbVZqZEM1dmNtY3hKakFrQmdrcWhraUc5dzBCQ1FFV0YyRmtiV2x1ClFHWmxaRzl5WVhCeWIy\ncGxZM1F1YjNKbk1JR2ZNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0R05BRENCaVFLQmdRQ2UKREs5VFQy\nM05BdTZPWTVGMnVVNHpMRW9Ld2k1RnRRTU5jVWV5eDdmOHJxMUZXaUxDWHBjWFhpU2tzUE1XV1NM\nWQo5SHNoa1pvM3ZjMHFSRXVBWDNweWRuM2VFRDA0UExrUmRlaWpvSXA5L0Y2YlZ3MmlLMDdXRmc5\nU2MwNlRsKzhSCld1RHNaeTQ1SVJKYXhCRTlJaHBYL0x2Y2JnQ1cvZmVHVGp5WG1iRHd0UUlEQVFB\nQm80SUJWekNDQVZNd0NRWUQKVlIwVEJBSXdBREF0QmdsZ2hrZ0JodmhDQVEwRUlCWWVSV0Z6ZVMx\nU1UwRWdSMlZ1WlhKaGRHVmtJRU5sY25ScApabWxqWVhSbE1CMEdBMVVkRGdRV0JCUm5lNTg0d3Bs\nWGYrZVE2K25zSTZCbm5BNENaRENCMVFZRFZSMGpCSUhOCk1JSEtnQlJyUUZyNUVnaUpXZWRaNVFY\nMUFoMEtUbjhVQUtHQnBxU0JvekNCb0RFTE1Ba0dBMVVFQmhNQ1ZWTXgKQ3pBSkJnTlZCQWdUQWs1\nRE1SQXdEZ1lEVlFRSEV3ZFNZV3hsYVdkb01SY3dGUVlEVlFRS0V3NUdaV1J2Y21FZwpVSEp2YW1W\namRERVBNQTBHQTFVRUN4TUdabVZrYlhObk1ROHdEUVlEVlFRREV3Wm1aV1J0YzJjeER6QU5CZ05W\nCkJDa1RCbVpsWkcxelp6RW1NQ1FHQ1NxR1NJYjNEUUVKQVJZWFlXUnRhVzVBWm1Wa2IzSmhjSEp2\nYW1WamRDNXYKY21lQ0NRRGpVQjVIVHhjZVJUQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFM\nQmdOVkhROEVCQU1DQjRBdwpEUVlKS29aSWh2Y05BUUVGQlFBRGdZRUFVazNlbjBYUXpDQm5IUlh4\nZDhyOHp2ZFAwVURvbEpiUysyTEl3Z3NDClJDMnNkZ1UwNGdFblYxdFpVTjNydEk1SzQ2MnpKT0JQ\nOFhQd3h4eUZMN1lOYmVtWTgyTG52Y1pHdzliMGdxTDMKdHNKbzllSFV5SXBZMG93TlVKdzgzU1Ax\neFJvb3NwVGJRK3BsNm9qdjVPNVpGZ1lBUG1yckRWZ0M4a2gzRlp4Rgp0SWc9Ci0tLS0tRU5EIENF\nUlRJRklDQVRFLS0tLS0K\n",

+             "i": 1,

+             "timestamp": 1561545908.0,

+             "msg_id": "2019-77336a2c-bbe1-4362-b466-32d6595d328b",

+             "crypto": "x509",

+             "topic": "org.fedoraproject.prod.copr.build.start",

+             "headers": {},

+             "signature": "kMANxtkdgupoXP5VAbyp6Hc//G+i4KGUhaRvlStb1uSNMRoUG+rqeNio4JXwez9C9ppT7oGezTAn\nSNfW2F0mt/XikqQrhpP3cOpE47327udgP+IwrP+WT3lZv1wH9LTpHj+eRgKmXNcCNUXYCWvCgGqi\nQ5PSpDcZsn+MJaCwP/M=\n",

+             "source_version": "0.9.0",

+             "msg": {

+                 "status": 3,

+                 "what": "build start: user:churchyard copr:python3.8 pkg:python-hypothesis build:945012 ip:172.25.93.20 pid:3762",

+                 "chroot": "fedora-rawhide-x86_64",

+                 "ip": "172.25.93.20",

+                 "user": "churchyard",

+                 "who": "backend.worker-23551-PC",

+                 "pid": 3762,

+                 "copr": "python3.8",

+                 "version": "4.23.8-1.fc31",

+                 "build": 945012,

+                 "owner": "@python",

+                 "pkg": "python-hypothesis"

+             }

+         }

+         self.build_id = 945012

+         self.name = "@python/python3.8"

+ 

+     def test_correct_messages(self):

+         """

+         Assert the message schema validates a correct message.

+         """

+         message = self.msg_class(body=self.fedmsg_message)

+         message.validate()

+ 

+     def test_missing_fields(self):

+         """Assert an exception is actually raised on validation failure."""

+         for key in self.required_fields:

+             body = copy.deepcopy(self.fedmsg_message)

+             del body['msg'][key]

+             message = self.msg_class(body=body)

+             self.assertRaises(ValidationError, message.validate)

+ 

+     def test_bad_type(self):

+         int_fields = ['status', 'build', 'pid']

+         for key in self.required_fields:

+             body = copy.deepcopy(self.fedmsg_message)

+ 

+             print(key)

+             if key in int_fields:

+                 body['msg'][key] = "str"

+             else:

+                 body['msg'][key] = 1

+ 

+             message = self.msg_class(body=body)

+             self.assertRaises(ValidationError, message.validate)

+ 

+     def test_str(self):

+         message = self.msg_class(body=self.fedmsg_message)

+         assert message.project_full_name == self.name

+         assert message.build_id == self.build_id

+ 

+     def test_no_wrap(self):

+         message = self.msg_class(body=self.fedmsg_message['msg'])

+         message.validate()

+ 

+     def test_nevr(self):

+         message = self.msg_class(body=self.fedmsg_message['msg'])

+         assert message.package_name == 'python-hypothesis'

+         assert message.package_version == '4.23.8'

+         assert message.package_release == '1.fc31'

+         assert message.package_epoch is None

+ 

+ 

+ class BuildChrootEndedV1Test(BuildChrootStartedV1Test):

+     msg_class = schema.BuildChrootEndedV1

+ 

+     def setUp(self):

+         self.fedmsg_message = {

+             "username": "copr",

+             "source_name": "datanommer",

+             "certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVUakNDQTdlZ0F3SUJBZ0lDQVBZd0RRWUpL\nb1pJaHZjTkFRRUZCUUF3Z2FBeEN6QUpCZ05WQkFZVEFsVlQKTVFzd0NRWURWUVFJRXdKT1F6RVFN\nQTRHQTFVRUJ4TUhVbUZzWldsbmFERVhNQlVHQTFVRUNoTU9SbVZrYjNKaApJRkJ5YjJwbFkzUXhE\nekFOQmdOVkJBc1RCbVpsWkcxelp6RVBNQTBHQTFVRUF4TUdabVZrYlhObk1ROHdEUVlEClZRUXBF\nd1ptWldSdGMyY3hKakFrQmdrcWhraUc5dzBCQ1FFV0YyRmtiV2x1UUdabFpHOXlZWEJ5YjJwbFkz\nUXUKYjNKbk1CNFhEVEUwTURReU16RTBNamsxTVZvWERUSTBNRFF5TURFME1qazFNVm93Z2R3eEN6\nQUpCZ05WQkFZVApBbFZUTVFzd0NRWURWUVFJRXdKT1F6RVFNQTRHQTFVRUJ4TUhVbUZzWldsbmFE\nRVhNQlVHQTFVRUNoTU9SbVZrCmIzSmhJRkJ5YjJwbFkzUXhEekFOQmdOVkJBc1RCbVpsWkcxelp6\nRXRNQ3NHQTFVRUF4TWtZMjl3Y2kxamIzQnkKTFdKbExtTnNiM1ZrTG1abFpHOXlZWEJ5YjJwbFkz\nUXViM0puTVMwd0t3WURWUVFwRXlSamIzQnlMV052Y0hJdApZbVV1WTJ4dmRXUXVabVZrYjNKaGNI\nSnZhbVZqZEM1dmNtY3hKakFrQmdrcWhraUc5dzBCQ1FFV0YyRmtiV2x1ClFHWmxaRzl5WVhCeWIy\ncGxZM1F1YjNKbk1JR2ZNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0R05BRENCaVFLQmdRQ2UKREs5VFQy\nM05BdTZPWTVGMnVVNHpMRW9Ld2k1RnRRTU5jVWV5eDdmOHJxMUZXaUxDWHBjWFhpU2tzUE1XV1NM\nWQo5SHNoa1pvM3ZjMHFSRXVBWDNweWRuM2VFRDA0UExrUmRlaWpvSXA5L0Y2YlZ3MmlLMDdXRmc5\nU2MwNlRsKzhSCld1RHNaeTQ1SVJKYXhCRTlJaHBYL0x2Y2JnQ1cvZmVHVGp5WG1iRHd0UUlEQVFB\nQm80SUJWekNDQVZNd0NRWUQKVlIwVEJBSXdBREF0QmdsZ2hrZ0JodmhDQVEwRUlCWWVSV0Z6ZVMx\nU1UwRWdSMlZ1WlhKaGRHVmtJRU5sY25ScApabWxqWVhSbE1CMEdBMVVkRGdRV0JCUm5lNTg0d3Bs\nWGYrZVE2K25zSTZCbm5BNENaRENCMVFZRFZSMGpCSUhOCk1JSEtnQlJyUUZyNUVnaUpXZWRaNVFY\nMUFoMEtUbjhVQUtHQnBxU0JvekNCb0RFTE1Ba0dBMVVFQmhNQ1ZWTXgKQ3pBSkJnTlZCQWdUQWs1\nRE1SQXdEZ1lEVlFRSEV3ZFNZV3hsYVdkb01SY3dGUVlEVlFRS0V3NUdaV1J2Y21FZwpVSEp2YW1W\namRERVBNQTBHQTFVRUN4TUdabVZrYlhObk1ROHdEUVlEVlFRREV3Wm1aV1J0YzJjeER6QU5CZ05W\nCkJDa1RCbVpsWkcxelp6RW1NQ1FHQ1NxR1NJYjNEUUVKQVJZWFlXUnRhVzVBWm1Wa2IzSmhjSEp2\nYW1WamRDNXYKY21lQ0NRRGpVQjVIVHhjZVJUQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFM\nQmdOVkhROEVCQU1DQjRBdwpEUVlKS29aSWh2Y05BUUVGQlFBRGdZRUFVazNlbjBYUXpDQm5IUlh4\nZDhyOHp2ZFAwVURvbEpiUysyTEl3Z3NDClJDMnNkZ1UwNGdFblYxdFpVTjNydEk1SzQ2MnpKT0JQ\nOFhQd3h4eUZMN1lOYmVtWTgyTG52Y1pHdzliMGdxTDMKdHNKbzllSFV5SXBZMG93TlVKdzgzU1Ax\neFJvb3NwVGJRK3BsNm9qdjVPNVpGZ1lBUG1yckRWZ0M4a2gzRlp4Rgp0SWc9Ci0tLS0tRU5EIENF\nUlRJRklDQVRFLS0tLS0K\n",

+             "i": 3,

+             "timestamp": 1561043053.0,

+             "msg_id": "2019-f916a75e-6a89-48e2-a4e5-53e71fef92fa",

+             "crypto": "x509",

+             "topic": "org.fedoraproject.prod.copr.build.end",

+             "headers": {},

+             "signature": "GWWEIfcVvLh59XWrYmDlJoRpxJ3DKYFBwAojVwWncbvfj3gVwJ33UHP5GJXTCsk+gvEUQdn07/Fs\nw9hGIfuiXlH7EjqOFvaiHIScq0VxLvwsManjbij9Ud8au9rLs9NkyS/pdLKq5QtwgXO9Y9LnsZB5\nyWURshXlLZsbZfq7fsE=\n",

+             "source_version": "0.9.0",

+             "msg": {

+                 "status": 0,

+                 "what": "build end: user:kbaig copr:test build:942697 pkg:tkn version:0.1.2-1.fc30 ip:172.25.91.143 pid:26197 status:0",

+                 "chroot": "fedora-29-x86_64",

+                 "ip": "172.25.91.143",

+                 "user": "kbaig",

+                 "who": "backend.worker-14783-PC",

+                 "pid": 26197,

+                 "copr": "test",

+                 "version": "0.1.2-1.fc30",

+                 "build": 942697,

+                 "owner": "kbaig",

+                 "pkg": "tkn"

+             }

+         }

+         self.build_id = 942697

+         self.name = "kbaig/test"

+ 

+     def test_nevr(self):

+         message = self.msg_class(body=self.fedmsg_message['msg'])

+         assert message.package_name == 'tkn'

+         assert message.package_version == '0.1.2'

+         assert message.package_release == '1.fc30'

+         assert message.package_epoch is None

+ 

+ 

+ class BuildChrootStartedV1DontUseTest(BuildChrootStartedV1Test):

+     msg_class = schema.BuildChrootStartedV1DontUse

+ 

+     def setUp(self):

+         self.fedmsg_message = {

+             "username": "copr",

+             "source_name": "datanommer",

+             "certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVUakNDQTdlZ0F3SUJBZ0lDQVBZd0RRWUpL\nb1pJaHZjTkFRRUZCUUF3Z2FBeEN6QUpCZ05WQkFZVEFsVlQKTVFzd0NRWURWUVFJRXdKT1F6RVFN\nQTRHQTFVRUJ4TUhVbUZzWldsbmFERVhNQlVHQTFVRUNoTU9SbVZrYjNKaApJRkJ5YjJwbFkzUXhE\nekFOQmdOVkJBc1RCbVpsWkcxelp6RVBNQTBHQTFVRUF4TUdabVZrYlhObk1ROHdEUVlEClZRUXBF\nd1ptWldSdGMyY3hKakFrQmdrcWhraUc5dzBCQ1FFV0YyRmtiV2x1UUdabFpHOXlZWEJ5YjJwbFkz\nUXUKYjNKbk1CNFhEVEUwTURReU16RTBNamsxTVZvWERUSTBNRFF5TURFME1qazFNVm93Z2R3eEN6\nQUpCZ05WQkFZVApBbFZUTVFzd0NRWURWUVFJRXdKT1F6RVFNQTRHQTFVRUJ4TUhVbUZzWldsbmFE\nRVhNQlVHQTFVRUNoTU9SbVZrCmIzSmhJRkJ5YjJwbFkzUXhEekFOQmdOVkJBc1RCbVpsWkcxelp6\nRXRNQ3NHQTFVRUF4TWtZMjl3Y2kxamIzQnkKTFdKbExtTnNiM1ZrTG1abFpHOXlZWEJ5YjJwbFkz\nUXViM0puTVMwd0t3WURWUVFwRXlSamIzQnlMV052Y0hJdApZbVV1WTJ4dmRXUXVabVZrYjNKaGNI\nSnZhbVZqZEM1dmNtY3hKakFrQmdrcWhraUc5dzBCQ1FFV0YyRmtiV2x1ClFHWmxaRzl5WVhCeWIy\ncGxZM1F1YjNKbk1JR2ZNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0R05BRENCaVFLQmdRQ2UKREs5VFQy\nM05BdTZPWTVGMnVVNHpMRW9Ld2k1RnRRTU5jVWV5eDdmOHJxMUZXaUxDWHBjWFhpU2tzUE1XV1NM\nWQo5SHNoa1pvM3ZjMHFSRXVBWDNweWRuM2VFRDA0UExrUmRlaWpvSXA5L0Y2YlZ3MmlLMDdXRmc5\nU2MwNlRsKzhSCld1RHNaeTQ1SVJKYXhCRTlJaHBYL0x2Y2JnQ1cvZmVHVGp5WG1iRHd0UUlEQVFB\nQm80SUJWekNDQVZNd0NRWUQKVlIwVEJBSXdBREF0QmdsZ2hrZ0JodmhDQVEwRUlCWWVSV0Z6ZVMx\nU1UwRWdSMlZ1WlhKaGRHVmtJRU5sY25ScApabWxqWVhSbE1CMEdBMVVkRGdRV0JCUm5lNTg0d3Bs\nWGYrZVE2K25zSTZCbm5BNENaRENCMVFZRFZSMGpCSUhOCk1JSEtnQlJyUUZyNUVnaUpXZWRaNVFY\nMUFoMEtUbjhVQUtHQnBxU0JvekNCb0RFTE1Ba0dBMVVFQmhNQ1ZWTXgKQ3pBSkJnTlZCQWdUQWs1\nRE1SQXdEZ1lEVlFRSEV3ZFNZV3hsYVdkb01SY3dGUVlEVlFRS0V3NUdaV1J2Y21FZwpVSEp2YW1W\namRERVBNQTBHQTFVRUN4TUdabVZrYlhObk1ROHdEUVlEVlFRREV3Wm1aV1J0YzJjeER6QU5CZ05W\nCkJDa1RCbVpsWkcxelp6RW1NQ1FHQ1NxR1NJYjNEUUVKQVJZWFlXUnRhVzVBWm1Wa2IzSmhjSEp2\nYW1WamRDNXYKY21lQ0NRRGpVQjVIVHhjZVJUQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFM\nQmdOVkhROEVCQU1DQjRBdwpEUVlKS29aSWh2Y05BUUVGQlFBRGdZRUFVazNlbjBYUXpDQm5IUlh4\nZDhyOHp2ZFAwVURvbEpiUysyTEl3Z3NDClJDMnNkZ1UwNGdFblYxdFpVTjNydEk1SzQ2MnpKT0JQ\nOFhQd3h4eUZMN1lOYmVtWTgyTG52Y1pHdzliMGdxTDMKdHNKbzllSFV5SXBZMG93TlVKdzgzU1Ax\neFJvb3NwVGJRK3BsNm9qdjVPNVpGZ1lBUG1yckRWZ0M4a2gzRlp4Rgp0SWc9Ci0tLS0tRU5EIENF\nUlRJRklDQVRFLS0tLS0K\n",

+             "i": 2,

+             "timestamp": 1561550552.0,

+             "msg_id": "2019-99461b95-66c1-4097-b4ec-ab2e3ba59047",

+             "crypto": "x509",

+             "topic": "org.fedoraproject.prod.copr.chroot.start",

+             "headers": {},

+             "signature": "S4N4QRS7IPAfrng3wwQWxQjjnCUcSQtAvbwZu4IPwVQs1uUv+gbSITIDblCVPCudPZ3yWL4ApP/L\nfNJepkUp/+mu0vDpRZQ+ZzOFSSIlemSaO8Ce1k8uymwbFhrU1L+7lMkY1Q+C4JCj/kXmn8Gs7hWF\noyrmQx0vAraBJc+ZIzQ=\n",

+             "source_version": "0.9.0",

+             "msg": {

+                 "status": 3,

+                 "what": "chroot start: chroot:fedora-29-aarch64 user:praiskup copr:ping pkg:dummy-pkg build:945056 ip:38.145.48.104 pid:9272",

+                 "chroot": "fedora-29-aarch64",

+                 "ip": "38.145.48.104",

+                 "user": "praiskup",

+                 "who": "backend.worker-23731-AARCH64",

+                 "pid": 9272,

+                 "copr": "ping",

+                 "version": "10:20190626_1356-0",

+                 "build": 945056,

+                 "owner": "praiskup",

+                 "pkg": "dummy-pkg"

+             }

+         }

+         self.build_id = 945056

+         self.name = "praiskup/ping"

+ 

+     def test_nevr(self):

+         message = self.msg_class(body=self.fedmsg_message['msg'])

+         assert message.package_name == "dummy-pkg"

+         assert message.package_version == "20190626_1356"

+         assert message.package_release == "0"

+         assert message.package_epoch == '10'

+ 

+ 

+ class BuildChrootStompOldStartTest(unittest.TestCase):

+     msg_class = schema.BuildChrootStartedV1Stomp

+ 

+     required = [

+         "build",

+         "owner",

+         "copr",

+         "submitter",

+         "package",

+         "chroot",

+         "builder",

+         "status",

+         "status_int",

+     ]

+ 

+     int_fields = [

+         'build',

+         'status_int'

+     ]

+ 

+     def setUp(self):

+         self.fedmsg_message = {

+             "build": "38492",

+             "owner": "praiskup",

+             "copr": "ping",

+             "submitter": "None",

+             "package": "None-None",

+             "chroot":

+             "srpm-builds",

+             "builder": "10.8.29.188",

+             "status": "SUCCEEDED",

+             "status_int": "1"

+         }

+         self.build_id = 38492

+         self.name = "praiskup/ping"

+ 

+     def test_correct_messages(self):

+         """

+         Assert the message schema validates a correct message.

+         """

+         message = self.msg_class(body=self.fedmsg_message)

+         message.validate()

+ 

+     def test_package(self):

+         message = self.msg_class(body=self.fedmsg_message)

+         message.validate()

+         assert message.status == "succeeded"

+ 

+     def test_nevr(self):

+         message = self.msg_class(body=self.fedmsg_message)

+         assert message.package_name == None

+         assert message.package_version == None

+         assert message.package_release == None

+         assert message.package_epoch is None

+ 

+ 

+ class BuildChrootStompOldEndTest(BuildChrootStompOldStartTest):

+     msg_class = schema.BuildChrootEndedV1Stomp

+ 

+     def setUp(self):

+         self.fedmsg_message = {

+             "build": "38492",

+             "owner": "praiskup",

+             "copr": "ping",

+             "submitter": "praiskup",

+             "package": "dummy-pkg-1:20190701_2127-0",

+             "chroot": "fedora-rawhide-x86_64",

+             "builder": "10.0.150.161",

+             "status": "SUCCEEDED",

+             "status_int": "1"

+         }

+         self.build_id = 38492

+         self.name = "praiskup/ping"

+ 

+     def test_nevr(self):

+         message = self.msg_class(body=self.fedmsg_message)

+         assert message.package_name == 'dummy-pkg'

+         assert message.package_version == '20190701_2127'

+         assert message.package_release == '0'

+         assert message.package_epoch == '1'

+ 

+ 

+ class BuildChrootStartedV1StompDontUseTest(unittest.TestCase):

+     msg_class = schema.BuildChrootStartedV1StompDontUse

+ 

+     def setUp(self):

+         self.fedmsg_message = {

+             "chroot": "fedora-29-x86_64"

+         }

+ 

+     def test_chroot(self):

+         msg = self.msg_class(body=self.fedmsg_message)

+         msg.validate()

@@ -0,0 +1,19 @@

+ # Minimal makefile for Sphinx documentation

+ #

+ 

+ # You can set these variables from the command line.

+ SPHINXOPTS    =

+ SPHINXBUILD   = sphinx-build

+ SOURCEDIR     = .

+ BUILDDIR      = _build

+ 

+ # Put it first so that "make" without argument is like "make help".

+ help:

+ 	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

+ 

+ .PHONY: help Makefile

+ 

+ # Catch-all target: route all unknown targets to Sphinx using the new

+ # "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).

+ %: Makefile

+ 	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 

\ No newline at end of file

@@ -0,0 +1,20 @@

+ .. _api:

+ 

+ Copr messaging API

+ ==================

+ 

+ .. autoclass:: copr_messaging.schema.BuildChrootStarted

+    :members: build_id, chroot,

+              package_full_name, project_full_name,

+              package_epoch, package_name, package_version, package_release,

+              project_owner, project_name

+ 

+ .. autoclass:: copr_messaging.schema.BuildChrootEnded

+    :members: status, build_id, chroot,

+              package_full_name, project_full_name,

+              package_epoch, package_name, package_version, package_release,

+              project_owner, project_name

+ 

+ .. [#footnote_may_be_unknown] Note that this information **may not** be known if

+     the message is triggered by source build (see method :meth:`.chroot` for

+     more info) -- in such case this attribute returns `None`.

file added
+201
@@ -0,0 +1,201 @@

+ # -*- coding: utf-8 -*-

+ #

+ # Configuration file for the Sphinx documentation builder.

+ #

+ # This file does only contain a selection of the most common options. For a

+ # full list see the documentation:

+ # http://www.sphinx-doc.org/en/master/config

+ 

+ # -- Path setup --------------------------------------------------------------

+ 

+ # If extensions (or modules to document with autodoc) are in another directory,

+ # add these directories to sys.path here. If the directory is relative to the

+ # documentation root, use os.path.abspath to make it absolute, like shown here.

+ #

+ import os

+ import sys

+ sys.path.insert(0, os.path.abspath('..'))

+ 

+ 

+ # -- Project information -----------------------------------------------------

+ 

+ project = 'copr-messaging'

+ copyright = '2019, Copr Team'

+ author = 'Copr Team'

+ 

+ # The short X.Y version

+ version = ''

+ # The full version, including alpha/beta/rc tags

+ release = ''

+ 

+ 

+ # -- General configuration ---------------------------------------------------

+ 

+ # If your documentation needs a minimal Sphinx version, state it here.

+ #

+ # needs_sphinx = '1.0'

+ 

+ # Add any Sphinx extension module names here, as strings. They can be

+ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom

+ # ones.

+ extensions = [

+     'sphinx.ext.autodoc',

+     'sphinx.ext.intersphinx',

+     'sphinx.ext.todo',

+     'sphinx.ext.viewcode',

+ ]

+ 

+ # Add any paths that contain templates here, relative to this directory.

+ templates_path = ['_templates']

+ 

+ # The suffix(es) of source filenames.

+ # You can specify multiple suffix as a list of string:

+ #

+ # source_suffix = ['.rst', '.md']

+ source_suffix = '.rst'

+ 

+ # The master toctree document.

+ master_doc = 'index'

+ 

+ # The language for content autogenerated by Sphinx. Refer to documentation

+ # for a list of supported languages.

+ #

+ # This is also used if you do content translation via gettext catalogs.

+ # Usually you set "language" from the command line for these cases.

+ language = None

+ 

+ # List of patterns, relative to source directory, that match files and

+ # directories to ignore when looking for source files.

+ # This pattern also affects html_static_path and html_extra_path.

+ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']

+ 

+ # The name of the Pygments (syntax highlighting) style to use.

+ pygments_style = 'sphinx'

+ 

+ 

+ # -- Options for HTML output -------------------------------------------------

+ 

+ # The theme to use for HTML and HTML Help pages.  See the documentation for

+ # a list of builtin themes.

+ #

+ 

+ # Use readthedocs theme if it is installed

+ # Ideally, we want to develop the documentation in the same theme

+ # that will be used in the production

+ try:

+     import sphinx_rtd_theme

+     html_theme = "sphinx_rtd_theme"

+     html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]

+ except ImportError:

+     print("Please install the readthedocs theme with:")

+     print("dnf install python*-sphinx_rtd_theme")

+ 

+ 

+ # Theme options are theme-specific and customize the look and feel of a theme

+ # further.  For a list of options available for each theme, see the

+ # documentation.

+ #

+ # html_theme_options = {}

+ 

+ # Add any paths that contain custom static files (such as style sheets) here,

+ # relative to this directory. They are copied after the builtin static files,

+ # so a file named "default.css" will overwrite the builtin "default.css".

+ #html_static_path = ['_static']

+ 

+ # Custom sidebar templates, must be a dictionary that maps document names

+ # to template names.

+ #

+ # The default sidebars (for documents that don't match any pattern) are

+ # defined by theme itself.  Builtin themes are using these templates by

+ # default: ``['localtoc.html', 'relations.html', 'sourcelink.html',

+ # 'searchbox.html']``.

+ #

+ # html_sidebars = {}

+ 

+ 

+ # -- Options for HTMLHelp output ---------------------------------------------

+ 

+ # Output file base name for HTML help builder.

+ htmlhelp_basename = 'copr-messagingdoc'

+ 

+ 

+ # -- Options for LaTeX output ------------------------------------------------

+ 

+ latex_elements = {

+     # The paper size ('letterpaper' or 'a4paper').

+     #

+     # 'papersize': 'letterpaper',

+ 

+     # The font size ('10pt', '11pt' or '12pt').

+     #

+     # 'pointsize': '10pt',

+ 

+     # Additional stuff for the LaTeX preamble.

+     #

+     # 'preamble': '',

+ 

+     # Latex figure (float) alignment

+     #

+     # 'figure_align': 'htbp',

+ }

+ 

+ # Grouping the document tree into LaTeX files. List of tuples

+ # (source start file, target name, title,

+ #  author, documentclass [howto, manual, or own class]).

+ latex_documents = [

+     (master_doc, 'copr-messaging.tex', 'copr-messaging Documentation',

+      'Copr Team', 'manual'),

+ ]

+ 

+ 

+ # -- Options for manual page output ------------------------------------------

+ 

+ # One entry per manual page. List of tuples

+ # (source start file, name, description, authors, manual section).

+ man_pages = [

+     (master_doc, 'copr-messaging', 'copr-messaging Documentation',

+      [author], 1)

+ ]

+ 

+ 

+ # -- Options for Texinfo output ----------------------------------------------

+ 

+ # Grouping the document tree into Texinfo files. List of tuples

+ # (source start file, target name, title, author,

+ #  dir menu entry, description, category)

+ texinfo_documents = [

+     (master_doc, 'copr-messaging', 'copr-messaging Documentation',

+      author, 'copr-messaging', 'One line description of project.',

+      'Miscellaneous'),

+ ]

+ 

+ 

+ # -- Options for Epub output -------------------------------------------------

+ 

+ # Bibliographic Dublin Core info.

+ epub_title = project

+ 

+ # The unique identifier of the text. This can be a ISBN number

+ # or the project homepage.

+ #

+ # epub_identifier = ''

+ 

+ # A unique identification for the text.

+ #

+ # epub_uid = ''

+ 

+ # A list of files that should not be packed into the epub file.

+ epub_exclude_files = ['search.html']

+ 

+ 

+ # -- Extension configuration -------------------------------------------------

+ 

+ # -- Options for intersphinx extension ---------------------------------------

+ 

+ # Example configuration for intersphinx: refer to the Python standard library.

+ intersphinx_mapping = {'https://docs.python.org/': None}

+ 

+ # -- Options for todo extension ----------------------------------------------

+ 

+ # If true, `todo` and `todoList` produce output, else they produce nothing.

+ todo_include_todos = False

@@ -0,0 +1,88 @@

+ .. _consuming:

+ 

+ How to consume Copr messages

+ ============================

+ 

+ Listening on fedora-messaging bus

+ ---------------------------------

+ 

+ .. todo:: 

+ 

+     For the simplest example, we should only say this:

+ 

+         $ fedora-messaging \

+             --conf /etc/fedora-messaging/fedora.toml \

+             consume --routing-key '#.copr.#'

+ 

+     The default behavior of python-fedora-messaging is that - if

+     copr-messaging package is installed - the messages are automatically retyped

+     to proper message class objects according to theirs topics.  But so far we

+     send messages to fedmsg -> that is proxied to fedora-messaging -> and such

+     proxied messages don't contain enough info for this to happen.

+ 

+ `Fedora Copr instance`_ sends messages to fedora-messaging AMQP bus, which makes

+ the messages available to general public.  The simplest way to consume Copr

+ messages from command-line is::

+ 

+     $ fedora-messaging \

+             --conf /etc/fedora-messaging/fedora.toml \

+             consume --routing-key '#.copr.#' \

+             --callback copr_messaging.fedora:Printer \

+     build_chroot_started(): Copr Message in project "loveshack/livhpc": build 958843: chroot "fedora-29-x86_64" started.

+     build_chroot_started(): Copr Message in project "loveshack/livhpc": build 958843: chroot "fedora-30-x86_64" started.

+     build_chroot_started(): Copr Message in project "loveshack/livhpc": build 958843: chroot "fedora-29-ppc64le" started.

+     build_chroot_ended(): Copr Message in project "decathorpe/xmlunit-pr": build 958393: chroot "fedora-rawhide-x86_64" ended as "failed".

+     build_chroot_started(): Copr Message in project "decathorpe/xmlunit-pr": build 958381: chroot "fedora-rawhide-x86_64" started.

+ 

+ One can make more customized consumer class by inheriting from the abstract

+ Consumer class::

+ 

+     $ cat consumer.py

+     from copr_messaging import fedora

+     class Consumer(fedora.Consumer):

+         def build_chroot_ended(self, message):

+             print(message) # or anything else with BuildChrootEnded object!

+         def build_chroot_started(self, message):

+             print(message) # BuildChrootStarted object

+     $ PYTHONPATH=`pwd` fedora-messaging \

+         --conf /etc/fedora-messaging/fedora.toml \

+         consume --callback consumer:Consumer --routing-key '#.copr.#'

+ 

+ See :class:`copr_messaging.schema.BuildChrootStarted` and

+ :class:`copr_messaging.schema.BuildChrootEnded` for more info about the message

+ API.

+ 

+ 

+ Listening on STOMP bus

+ ----------------------

+ 

+ This part doesn't apply to `Fedora Copr instance`_, so check that your instance

+ publishes on `STOMP bus`_ first.

+ 

+ Similarly to :class:`copr_messaging.fedora.Consumer`, there's

+ :class:`copr_messaging.stomp.Consumer` class having the same user API (share the

+ base class)::

+ 

+     $ cat consumer.py

+     #! /usr/bin/python3

+ 

+     import stomp

+     from copr_messaging.stomp import Consumer

+ 

+     class Listener(Consumer):

+         def build_chroot_ended(self, message):

+             # message is of BuildChrootStarted type

+             print(message) # or do anything else!

+ 

+     c = stomp.Connection(...)

+     c.set_listener('', Consumer())

+     c.set_ssl(...)

+     c.start()

+     c.connect(wait=True)

+     # check where your copr publishes

+     c.subscribe('/queue/Consumer.copr.*.VirtualTopic.devel.copr.build.*', 3)

+     c.disconnect()

+ 

+ 

+ .. _`Fedora Copr instance`: https://copr.fedorainfracloud.org/

+ .. _`STOMP bus`: https://stomp.github.io/

@@ -0,0 +1,29 @@

+ .. python-copr documentation master file, created by

+    sphinx-quickstart on Thu Sep  4 16:44:28 2014.

+    You can adapt this file completely to your liking, but it should at least

+    contain the root `toctree` directive.

+ 

+ About

+ =====

+ 

+ Schema definitions for messages sent by `Copr build system`_, and several

+ convenience classes/methods to make the message consuming easier.

+ 

+ .. toctree::

+    :caption: Contents:

+ 

+    installation

+    consuming

+    api

+ 

+ 

+ 

+ Indices and tables

+ ------------------

+ 

+ * :ref:`genindex`

+ * :ref:`modindex`

+ * :ref:`search`

+ 

+ 

+ .. _`Copr build system`: https://pagure.io/copr/copr

@@ -0,0 +1,15 @@

+ .. _installation:

+ 

+ 

+ Installation

+ ============

+ 

+ Installing into Fedora::

+ 

+     dnf install -y python3-copr-messaging

+ 

+ Installing from PyPI::

+ 

+     pip install copr-messaging

+ 

+ 

file added
+128
@@ -0,0 +1,128 @@

+ # python-copr-messaging pylint configuration

+ 

+ [MASTER]

+ 

+ # Pickle collected data for later comparisons.

+ persistent=no

+ 

+ extension-pkg-whitelist=SQLAlchemy

+ ignored-modules = SQLAlchemy

+ 

+ [MESSAGES CONTROL]

+ 

+ # Disable the message(s) with the given id(s).

+ disable=I0011,C0302,C0111,R0801,R0902,R0904,R0912,R0913,R0914,R0915,R0921,R0922,W0142,W0403,W0603,C1001,W0121,useless-else-on-loop,bad-whitespace,unpacking-non-sequence,superfluous-parens,cyclic-import

+ 

+ # list of disabled messages:

+ #...

+ 

+ [REPORTS]

+ 

+ # Set the output format. Available formats are text, parseable, colorized, msvs

+ # (visual studio) and html

+ output-format=text

+ 

+ # Tells whether to display a full report or only the messages

+ reports=no

+ 

+ 

+ [VARIABLES]

+ 

+ # A regular expression matching names used for dummy variables (i.e. not used).

+ dummy-variables-rgx=_|dummy

+ 

+ 

+ [BASIC]

+ 

+ # Regular expression which should only match correct module names

+ #module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$

+ module-rgx=([a-zA-Z_][a-zA-Z0-9_]+)$

+ 

+ # Regular expression which should only match correct module level names

+ const-rgx=(([a-zA-Z_][a-zA-Z0-9_]*)|(__.*__))$

+ 

+ # Regular expression which should only match correct class names

+ class-rgx=[a-zA-Z_][a-zA-Z0-9_]+$

+ 

+ # Regular expression which should only match correct function names

+ function-rgx=[a-z_][a-zA-Z0-9_]{,42}$

+ 

+ # Regular expression which should only match correct method names

+ method-rgx=[a-z_][a-zA-Z0-9_]{,42}$

+ 

+ # Regular expression which should only match correct instance attribute names

+ attr-rgx=[a-z_][a-zA-Z0-9_]{,30}$

+ 

+ # Regular expression which should only match correct argument names

+ argument-rgx=[a-z_][a-zA-Z0-9_]{,30}$

+ 

+ # Regular expression which should only match correct variable names

+ variable-rgx=[a-z_][a-zA-Z0-9_]{,30}$

+ 

+ # Regular expression which should only match correct list comprehension /

+ # generator expression variable names

+ inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$

+ 

+ # Regular expression which should only match correct class sttribute names

+ class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,42}|(__.*__))$

+ 

+ # Good variable names which should always be accepted, separated by a comma

+ good-names=i,j,k,ex,Run,_

+ 

+ # Bad variable names which should always be refused, separated by a comma

+ bad-names=foo,bar,baz,toto,tutu,tata

+ 

+ # List of builtins function names that should not be used, separated by a comma

+ bad-functions=apply,input

+ 

+ 

+ [DESIGN]

+ 

+ # Maximum number of arguments for function / method

+ max-args=10

+ 

+ # Maximum number of locals for function / method body

+ max-locals=20

+ 

+ # Maximum number of return / yield for function / method body

+ max-returns=6

+ 

+ # Maximum number of branch for function / method body

+ max-branchs=20

+ 

+ # Maximum number of statements in function / method body

+ max-statements=50

+ 

+ # Maximum number of parents for a class (see R0901).

+ max-parents=15

+ 

+ # Maximum number of attributes for a class (see R0902).

+ max-attributes=7

+ 

+ # Minimum number of public methods for a class (see R0903).

+ min-public-methods=1

+ 

+ # Maximum number of public methods for a class (see R0904).

+ max-public-methods=20

+ 

+ 

+ [CLASSES]

+ 

+ 

+ [FORMAT]

+ 

+ # Maximum number of characters on a single line.

+ max-line-length=120

+ 

+ # Maximum number of lines in a module

+ max-module-lines=1000

+ 

+ # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1

+ # tab).

+ indent-string='    '

+ 

+ 

+ [MISCELLANEOUS]

+ 

+ # List of note tags to take in consideration, separated by a comma.

+ notes=

@@ -0,0 +1,7 @@

+ #! /bin/sh

+ 

+ dir=$(dirname "$(readlink -f "$0")")

+ export PYTHONPATH=$dir:$dir/../common

+ cd "$dir"

+ python3 setup.py bdist_egg

+ pytest-3

file added
+75
@@ -0,0 +1,75 @@

+ #! /usr/bin/python3

+ #

+ # Copyright (C) 2019  Red Hat, Inc.

+ #

+ # This program is free software; you can redistribute it and/or modify

+ # it under the terms of the GNU General Public License as published by

+ # the Free Software Foundation; either version 2 of the License, or

+ # (at your option) any later version.

+ #

+ # This program is distributed in the hope that it will be useful,

+ # but WITHOUT ANY WARRANTY; without even the implied warranty of

+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ # GNU General Public License for more details.

+ #

+ # You should have received a copy of the GNU General Public License along

+ # with this program; if not, write to the Free Software Foundation, Inc.,

+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

+ 

+ import os

+ 

+ from setuptools import setup, find_packages

+ 

+ here = os.path.abspath(os.path.dirname(__file__))

+ with open(os.path.join(here, "README.md")) as fd:

+     README = fd.read()

+ 

+ __name__ = 'copr-messaging'

+ __description__ = "A schema and tooling for Copr fedora-messaging"

+ __author__ = "Copr team"

+ __author_email__ = "copr-devel@lists.fedorahosted.org"

+ __url__ = "https://pagure.io/copr/copr"

+ __version__ = "0.0"

+ 

+ __requires__ = [

+     'fedora-messaging',

+     'copr-common',

+ ]

+ 

+ setup(

+     name=__name__,

+     version=__version__,

+     description=__description__,

+     long_description=README,

+     url=__url__,

+ 

+     # Possible options are at https://pypi.python.org/pypi?%3Aaction=list_classifiers

+     classifiers=[

+         "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)",

+         "Programming Language :: Python :: 3.7",

+     ],

+     license="GPLv2+",

+     maintainer="Copr Team",

+     maintainer_email=__author_email__,

+     keywords="fedora",

+     packages=find_packages(

+         exclude=("copr_messaging.tests",

+                  "copr_messaging.tests.*")),

+     include_package_data=True,

+     zip_safe=False,

+     install_requires=["fedora_messaging"],

+     test_suite="copr_messaging.tests",

+     entry_points={

+         "fedora.messages": [

+             "copr.build.start=copr_messaging.schema:BuildChrootStartedV1",

+             "copr.build.end=copr_messaging.schema:BuildChrootEndedV1",

+ 

+             # TODO: drop those entry points;  these shouldn't be needed once

+             # all message consumers moved to `copr_messaging` module.

+             "copr.chroot.start=copr_messaging.schema:BuildChrootStartedV1DontUse",

+             "copr.unused.build.start=copr_messaging.schema:BuildChrootStartedV1Stomp",

+             "copr.unused.build.end=copr_messaging.schema:BuildChrootEndedV1Stomp",

+             "copr.unused.chroot.start=copr_messaging.schema:BuildChrootStartedV1StompDontUse",

+         ]

+     },

+ )

A lot of updates are still needed, but I'm submitting it to have something to discuss on meeting (and to have some backup).

Metadata Update from @praiskup:
- Pull-request tagged with: needs-work

4 years ago

1 new commit added

  • spec should provide python3-copr-messaging
4 years ago

@msuchy, we discussed a possibility to move copr_messaging under copr.messaging within copr PyPI package (and python-copr RPM package).

The negative would be that the copr pypi package would have to depend on fedora_messaging module, which brings a whole bunch of python stuff (even though user using client isn't probably interested in that).

There's probably several more or less ugly (or expensive) ways to make it happen; and I can discuss them more. But first ...

Do you think that (except for additional package review, and less nice copr_messaging vs copr.messaging name) there are other negatives? If not, I'd probably prefer to keep this separated entirely (message consumers don't have to install python-copr, and client users don't have to install python-copr-messaging). What do you think?

5 new commits added

  • validate message before sending to client
  • drop misleading comment
  • add stomp consumer
  • rename fedmsg.py to helpers.py
  • stomp to use topic (== destionation) as well
4 years ago

rebased onto d87f5337ababbc08d10e31471b9916d3a26f65ec

4 years ago

Metadata Update from @praiskup:
- Pull-request untagged with: needs-work

4 years ago

Build of copr-backend will fail for f28 because there's no python3-copr-messaging - because there's no python3-fedora-messaging (it's f29+). I don't think that matters to much, we are moving everything to F30+ anyways.

Metadata Update from @msuchy:
- Request assigned

4 years ago

I went briefly through and LGTM

[copr-build] with disabled EOL f28

rebased onto 2c4686b

4 years ago

Pull-Request has been merged by msuchy

4 years ago