Hello community,
here is the log from the commit of package openSUSE-release-tools for
openSUSE:Factory checked in at 2019-09-16 10:52:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/openSUSE-release-tools (Old)
and /work/SRC/openSUSE:Factory/.openSUSE-release-tools.new.7948 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openSUSE-release-tools"
Mon Sep 16 10:52:00 2019 rev:218 rq:730792 version:20190913.9d119079
Changes:
--------
---
/work/SRC/openSUSE:Factory/openSUSE-release-tools/openSUSE-release-tools.changes
2019-09-13 14:58:17.973277188 +0200
+++
/work/SRC/openSUSE:Factory/.openSUSE-release-tools.new.7948/openSUSE-release-tools.changes
2019-09-16 10:52:11.511158326 +0200
@@ -1,0 +2,53 @@
+Fri Sep 13 16:25:13 UTC 2019 - [email protected]
+
+- Update to version 20190913.9d119079:
+ * gocd: remove PackageHub15SP1.Manager42 as project is locked.
+
+-------------------------------------------------------------------
+Fri Sep 13 05:13:12 UTC 2019 - [email protected]
+
+- Update to version 20190913.d83c08a9:
+ * gocd: rabbit-openqa needs a config file installed
+
+-------------------------------------------------------------------
+Thu Sep 12 15:33:23 UTC 2019 - [email protected]
+
+- Update to version 20190912.9c45fc37:
+ * osclib/origin_listener: start additional listeners for remote origins.
+ * osclib/origin_listener: change skipping log message to mention origin.
+ * osclib/origin_listener: provide origin_updatable_map().
+
+-------------------------------------------------------------------
+Thu Sep 12 12:59:33 UTC 2019 - [email protected]
+
+- Update to version 20190912.f5a9538d:
+ * check_source: only log as info if we can't get build log. This needs a
more general solution but for now we'll reduce the level to not pollute the log
+
+-------------------------------------------------------------------
+Thu Sep 12 11:09:05 UTC 2019 - [email protected]
+
+- Update to version 20190912.6dd6428d:
+ * Move the monitors to a agent type of their own
+
+-------------------------------------------------------------------
+Thu Sep 12 09:23:42 UTC 2019 - [email protected]
+
+- Update to version 20190912.49029a0e:
+ * gocd/checkers: reduce Origin.Manager.Update frequency to weekly.
+ * gocd/monitors: provide OriginManagerUpdate pipelines for listener.
+ * osc-origin: update: provide --listen option.
+ * gocd: utilize `origin update` without the need to indicate a project.
+ * osc-origin: support invoking update without a project.
+ * osclib/origin: provide origin_updatable_map().
+ * osclib/origin: provide origin_updatable().
+ * dist/obs: provide OSRT:OriginUpdateSkip attribute definition.
+ * osc-origin: utilize osclib.core.RequestFuture.print_and_create().
+ * osclib/core: provide RequestFuture.print_and_create().
+ * osclib/core: provide RequestFuture.create_tolerant().
+ * osclib/core: provide project_attributes_list().
+ * osclib/core: project_attribute_list(): provide locked parameter.
+ * osclib/core: project_attribute_list(): drop value parameter.
+ * osclib/core: provide devel_projects().
+ * Move PubSubConsumer to osclib.PubSubConsumer to allow for proper import.
+
+-------------------------------------------------------------------
Old:
----
openSUSE-release-tools-20190911.d06fa8af.obscpio
New:
----
openSUSE-release-tools-20190913.9d119079.obscpio
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ openSUSE-release-tools.spec ++++++
--- /var/tmp/diff_new_pack.Eytaky/_old 2019-09-16 10:52:13.423158078 +0200
+++ /var/tmp/diff_new_pack.Eytaky/_new 2019-09-16 10:52:13.427158078 +0200
@@ -20,7 +20,7 @@
%define source_dir openSUSE-release-tools
%define announcer_filename factory-package-news
Name: openSUSE-release-tools
-Version: 20190911.d06fa8af
+Version: 20190913.9d119079
Release: 0
Summary: Tools to aid in staging and release work for openSUSE/SUSE
License: GPL-2.0-or-later AND MIT
++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.Eytaky/_old 2019-09-16 10:52:13.471158072 +0200
+++ /var/tmp/diff_new_pack.Eytaky/_new 2019-09-16 10:52:13.475158072 +0200
@@ -1,6 +1,6 @@
<servicedata>
<service name="tar_scm">
<param
name="url">https://github.com/openSUSE/openSUSE-release-tools.git</param>
- <param
name="changesrevision">f30964b69c48d26cc05086784532ff509e058ac0</param>
+ <param
name="changesrevision">bc377aa24366fef38f425e988b225a438af748e5</param>
</service>
</servicedata>
++++++ openSUSE-release-tools-20190911.d06fa8af.obscpio ->
openSUSE-release-tools-20190913.9d119079.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/PubSubConsumer.py
new/openSUSE-release-tools-20190913.9d119079/PubSubConsumer.py
--- old/openSUSE-release-tools-20190911.d06fa8af/PubSubConsumer.py
2019-09-11 12:46:39.000000000 +0200
+++ new/openSUSE-release-tools-20190913.9d119079/PubSubConsumer.py
1970-01-01 01:00:00.000000000 +0100
@@ -1,397 +0,0 @@
-import functools
-import logging
-import pika
-import ssl
-import sys
-import time
-from datetime import datetime
-
-class PubSubConsumer(object):
- """
- Based on
https://github.com/pika/pika/blob/master/examples/asynchronous_consumer_example.py
-
- This is an example consumer that will handle unexpected interactions
- with RabbitMQ such as channel and connection closures.
-
- If RabbitMQ closes the connection, it will reopen it. You should
- look at the output, as there are limited reasons why the connection may
- be closed, which usually are tied to permission related issues or
- socket timeouts.
-
- If the channel is closed, it will indicate a problem with one of the
- commands that were issued and that should surface in the output as well.
-
- """
-
- def __init__(self, amqp_prefix, logger):
- """Create a new instance of the consumer class, passing in the AMQP
- URL used to connect to RabbitMQ.
-
- :param str amqp_url: The AMQP url to connect with
-
- """
- self._connection = None
- self._channel = None
- self._closing = False
- self._consuming = False
- self._consumer_tag = None
- self._prefix = amqp_prefix
- self._timer_id = None
- self._run_until = None
- self.logger = logger
-
- def restart_timer(self):
- interval = 300
- if self._timer_id:
- self._connection.ioloop.remove_timeout(self._timer_id)
- else:
- # check the initial state on first timer hit
- # so be quick about it
- interval = 0
- self._timer_id = self._connection.ioloop.call_later(interval,
self.still_alive)
-
- def still_alive(self):
- # output something so gocd doesn't consider it stalled
- self.logger.info('Still alive: {}'.format(datetime.now().time()))
- if self._run_until and time.time() > self._run_until:
- self.stop()
- else:
- self.restart_timer()
-
- def connect(self):
- """This method connects to RabbitMQ, returning the connection handle.
- When the connection is established, the on_connection_open method
- will be invoked by pika.
-
- :rtype: pika.SelectConnection
-
- """
- self.logger.info('Connecting to %s', self._prefix)
- account = 'opensuse'
- server = 'rabbit.opensuse.org'
- if self._prefix == 'suse':
- account = 'suse'
- server = 'rabbit.suse.de'
- credentials = pika.PlainCredentials(account, account)
- context = ssl.create_default_context()
- ssl_options = pika.SSLOptions(context, server)
- parameters = pika.ConnectionParameters(server, 5671, '/', credentials,
ssl_options=ssl_options, socket_timeout=10)
- return pika.SelectConnection(parameters,
- on_open_callback=self.on_connection_open)
-
- def close_connection(self):
- """This method closes the connection to RabbitMQ."""
- self._consuming = False
- if self._connection.is_closing or self._connection.is_closed:
- self.logger.info('Connection is closing or already closed')
- else:
- self.logger.info('Closing connection')
- self._connection.close()
-
- def add_on_connection_close_callback(self):
- """This method adds an on close callback that will be invoked by pika
- when RabbitMQ closes the connection to the publisher unexpectedly.
-
- """
- self.logger.debug('Adding connection close callback')
- self._connection.add_on_close_callback(self.on_connection_closed)
-
- def on_connection_closed(self, connection, reason):
- """This method is invoked by pika when the connection to RabbitMQ is
- closed unexpectedly. Since it is unexpected, we will reconnect to
- RabbitMQ if it disconnects.
-
- :param pika.connection.Connection connection: The closed connection obj
- :param int reply_code: The server provided reply_code if given
- :param str reply_text: The server provided reply_text if given
-
- """
- self._channel = None
- if self._closing:
- self._connection.ioloop.stop()
- else:
- self.logger.warning('Connection closed, reopening in 5 seconds:
%s',
- reason)
- self._connection.ioloop.call_later(5, self.reconnect)
-
- def on_connection_open(self, unused_connection):
- """This method is called by pika once the connection to RabbitMQ has
- been established. It passes the handle to the connection object in
- case we need it, but in this case, we'll just mark it unused.
-
- :type unused_connection: pika.SelectConnection
-
- """
- self.logger.info('Connection opened')
- self.add_on_connection_close_callback()
- self.open_channel()
-
- def reconnect(self):
- """Will be invoked by the IOLoop timer if the connection is
- closed. See the on_connection_closed method.
-
- """
- # This is the old connection IOLoop instance, stop its ioloop
- self._connection.ioloop.stop()
-
- if not self._closing:
-
- # Create a new connection
- self._connection = self.connect()
-
- # There is now a new connection, needs a new ioloop to run
- self._connection.ioloop.start()
-
- def add_on_channel_close_callback(self):
- """This method tells pika to call the on_channel_closed method if
- RabbitMQ unexpectedly closes the channel.
-
- """
- self.logger.debug('Adding channel close callback')
- self._channel.add_on_close_callback(self.on_channel_closed)
-
- def on_channel_closed(self, channel, reason):
- """Invoked by pika when RabbitMQ unexpectedly closes the channel.
- Channels are usually closed if you attempt to do something that
- violates the protocol, such as re-declare an exchange or queue with
- different parameters. In this case, we'll close the connection
- to shutdown the object.
-
- :param pika.channel.Channel: The closed channel
- :param int reply_code: The numeric reason the channel was closed
- :param str reply_text: The text reason the channel was closed
-
- """
- self.logger.info('Channel %i was closed: %s',
- channel, reason)
- self._connection.close()
-
- def on_channel_open(self, channel):
- """This method is invoked by pika when the channel has been opened.
- The channel object is passed in so we can make use of it.
-
- Since the channel is now open, we'll declare the exchange to use.
-
- :param pika.channel.Channel channel: The channel object
-
- """
- self.logger.debug('Channel opened')
- self._channel = channel
- self.add_on_channel_close_callback()
- self.setup_exchange('pubsub')
-
- def setup_exchange(self, exchange_name):
- """Setup the exchange on RabbitMQ by invoking the Exchange.Declare RPC
- command. When it is complete, the on_exchange_declareok method will
- be invoked by pika.
-
- :param str|unicode exchange_name: The name of the exchange to declare
-
- """
- self.logger.debug('Declaring exchange %s', exchange_name)
- self._channel.exchange_declare(exchange_name,
- exchange_type='topic',
- callback=self.on_exchange_declareok,
- passive=True, durable=True)
-
- def on_exchange_declareok(self, unused_frame):
- """Invoked by pika when RabbitMQ has finished the Exchange.Declare RPC
- command.
-
- :param pika.Frame.Method unused_frame: Exchange.DeclareOk response
frame
-
- """
- self.logger.debug('Exchange declared')
- self._channel.queue_declare('', callback=self.on_queue_declareok,
exclusive=True)
-
- def on_queue_declareok(self, method_frame):
- """Method invoked by pika when the Queue.Declare RPC call made in
- setup_queue has completed. In this method we will bind the queue
- and exchange together with the routing key by issuing the Queue.Bind
- RPC command. When this command is complete, the on_bindok method will
- be invoked by pika.
-
- :param pika.frame.Method method_frame: The Queue.DeclareOk frame
-
- """
- self.queue_name = method_frame.method.queue
- self.routing_keys_to_bind = self.routing_keys()
- self.bind_queue_to_routing_key(self.routing_keys_to_bind.pop())
-
- def routing_keys(self):
- return ['#']
-
- def bind_queue_to_routing_key(self, key):
- self.logger.info('Binding %s to %s', key, self.queue_name)
- self._channel.queue_bind(self.queue_name, 'pubsub', routing_key=key,
callback=self.on_bindok)
-
- def add_on_cancel_callback(self):
- """Add a callback that will be invoked if RabbitMQ cancels the consumer
- for some reason. If RabbitMQ does cancel the consumer,
- on_consumer_cancelled will be invoked by pika.
-
- """
- self.logger.debug('Adding consumer cancellation callback')
- self._channel.add_on_cancel_callback(self.on_consumer_cancelled)
-
- def on_consumer_cancelled(self, method_frame):
- """Invoked by pika when RabbitMQ sends a Basic.Cancel for a consumer
- receiving messages.
-
- :param pika.frame.Method method_frame: The Basic.Cancel frame
-
- """
- self.logger.info('Consumer was cancelled remotely, shutting down: %r',
- method_frame)
- if self._channel:
- self._channel.close()
-
- def on_message(self, unused_channel, basic_deliver, properties, body):
- """Invoked by pika when a message is delivered from RabbitMQ. The
- channel is passed for your convenience. The basic_deliver object that
- is passed in carries the exchange, routing key, delivery tag and
- a redelivered flag for the message. The properties passed in is an
- instance of BasicProperties with the message properties and the body
- is the message that was sent.
-
- :param pika.channel.Channel unused_channel: The channel object
- :param pika.Spec.Basic.Deliver: basic_deliver method
- :param pika.Spec.BasicProperties: properties
- :param str|unicode body: The message body
-
- """
- self.logger.info('Received message # %s: %s %s',
- basic_deliver.delivery_tag,
basic_deliver.routing_key, body)
- self.acknowledge_message(basic_deliver.delivery_tag)
-
- def acknowledge_message(self, delivery_tag):
- """Acknowledge the message delivery from RabbitMQ by sending a
- Basic.Ack RPC method for the delivery tag.
-
- :param int delivery_tag: The delivery tag from the Basic.Deliver frame
-
- """
- self.logger.debug('Acknowledging message %s', delivery_tag)
- self._channel.basic_ack(delivery_tag)
-
- def on_cancelok(self, _unused_frame, userdata):
- """This method is invoked by pika when RabbitMQ acknowledges the
- cancellation of a consumer. At this point we will close the channel.
- This will invoke the on_channel_closed method once the channel has been
- closed, which will in-turn close the connection.
- :param pika.frame.Method _unused_frame: The Basic.CancelOk frame
- :param str|unicode userdata: Extra user data (consumer tag)
- """
- self._consuming = False
- self.logger.debug(
- 'RabbitMQ acknowledged the cancellation of the consumer: %s',
- userdata)
- self.close_channel()
-
- def close_channel(self):
- """Call to close the channel with RabbitMQ cleanly by issuing the
- Channel.Close RPC command.
- """
- self.logger.debug('Closing the channel')
- self._channel.close()
-
- def stop_consuming(self):
- """Tell RabbitMQ that you would like to stop consuming by sending the
- Basic.Cancel RPC command.
-
- """
- if self._channel:
- self.logger.debug('Sending a Basic.Cancel RPC command to RabbitMQ')
- cb = functools.partial(self.on_cancelok,
userdata=self._consumer_tag)
- self._channel.basic_cancel(self._consumer_tag, cb)
-
- def start_consuming(self):
- """This method sets up the consumer by first calling
- add_on_cancel_callback so that the object is notified if RabbitMQ
- cancels the consumer. It then issues the Basic.Consume RPC command
- which returns the consumer tag that is used to uniquely identify the
- consumer with RabbitMQ. We keep the value to use it when we want to
- cancel consuming. The on_message method is passed in as a callback pika
- will invoke when a message is fully received.
-
- """
- self.logger.debug('Issuing consumer related RPC commands')
- self.add_on_cancel_callback()
- self.restart_timer()
- self._consumer_tag = self._channel.basic_consume(self.queue_name,
- self.on_message,
- auto_ack=False)
- self._consuming = True
-
- def on_bindok(self, unused_frame):
- """Invoked by pika when the Queue.Bind method has completed. At this
- point we will start consuming messages by calling start_consuming
- which will invoke the needed RPC commands to start the process.
-
- :param pika.frame.Method unused_frame: The Queue.BindOk response frame
-
- """
- self.logger.debug('Queue bound')
- if len(self.routing_keys_to_bind):
- self.bind_queue_to_routing_key(self.routing_keys_to_bind.pop())
- else:
- self.start_consuming()
-
- def open_channel(self):
- """Open a new channel with RabbitMQ by issuing the Channel.Open RPC
- command. When RabbitMQ responds that the channel is open, the
- on_channel_open callback will be invoked by pika.
-
- """
- self.logger.debug('Creating a new channel')
- self._connection.channel(on_open_callback=self.on_channel_open)
-
- def run(self, runtime=None):
- """Run the example consumer by connecting to RabbitMQ and then
- starting the IOLoop to block and allow the SelectConnection to operate.
-
- """
- if runtime:
- self._run_until = time.time() + runtime
- self._connection = self.connect()
- self._connection.ioloop.start()
-
- def stop(self):
- """Cleanly shutdown the connection to RabbitMQ by stopping the consumer
- with RabbitMQ. When RabbitMQ confirms the cancellation, on_cancelok
- will be invoked by pika, which will then closing the channel and
- connection. The IOLoop is started again because this method is invoked
- when CTRL-C is pressed raising a KeyboardInterrupt exception. This
- exception stops the IOLoop which needs to be running for pika to
- communicate with RabbitMQ. All of the commands issued prior to starting
- the IOLoop will be buffered but not processed.
-
- """
- self.logger.debug('Stopping')
- if not self._closing:
- self._closing = True
- self.logger.debug('Stopping')
- if self._consuming:
- self.stop_consuming()
- #self._connection.ioloop.start()
- else:
- self._connection.ioloop.stop()
- self.logger.debug('Stopped')
-
-def main():
- LOG_FORMAT = ('%(levelname) -10s %(asctime)s %(name) -30s %(funcName) '
- '-35s %(lineno) -5d: %(message)s')
-
- logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)
- amqp_prefix = 'opensuse'
- if len(sys.argv) > 1:
- amqp_prefix = sys.argv[1]
- example = PubSubConsumer(amqp_prefix, logging.getLogger(__name__))
- try:
- example.run()
- except KeyboardInterrupt:
- example.stop()
-
-
-if __name__ == '__main__':
- main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/check_source.py
new/openSUSE-release-tools-20190913.9d119079/check_source.py
--- old/openSUSE-release-tools-20190911.d06fa8af/check_source.py
2019-09-11 12:46:39.000000000 +0200
+++ new/openSUSE-release-tools-20190913.9d119079/check_source.py
2019-09-13 18:24:23.000000000 +0200
@@ -249,7 +249,7 @@
self.logger.info(f'found missing whitelist for
warning: {entry}')
found_entries.add(entry)
except HTTPError as e:
- self.logger.error('ERROR in URL %s [%s]' % (url, e))
+ self.logger.info('ERROR in URL %s [%s]' % (url, e))
return found_entries
def is_devel_project(self, source_project, target_project):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/config/manager_42/README.txt
new/openSUSE-release-tools-20190913.9d119079/config/manager_42/README.txt
--- old/openSUSE-release-tools-20190911.d06fa8af/config/manager_42/README.txt
1970-01-01 01:00:00.000000000 +0100
+++ new/openSUSE-release-tools-20190913.9d119079/config/manager_42/README.txt
2019-09-13 18:24:23.000000000 +0200
@@ -0,0 +1 @@
+Create an OSRT:OriginManager config instead.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/config/manager_42/openSUSE:Backports:SLE-15-SP1.yml
new/openSUSE-release-tools-20190913.9d119079/config/manager_42/openSUSE:Backports:SLE-15-SP1.yml
---
old/openSUSE-release-tools-20190911.d06fa8af/config/manager_42/openSUSE:Backports:SLE-15-SP1.yml
2019-09-11 12:46:39.000000000 +0200
+++
new/openSUSE-release-tools-20190913.9d119079/config/manager_42/openSUSE:Backports:SLE-15-SP1.yml
1970-01-01 01:00:00.000000000 +0100
@@ -1,4 +0,0 @@
----
-from_prj: openSUSE:Backports:SLE-15-SP1
-project_preference_order:
- - openSUSE:Leap:15.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/dist/obs/OSRT:OriginUpdateSkip.xml
new/openSUSE-release-tools-20190913.9d119079/dist/obs/OSRT:OriginUpdateSkip.xml
---
old/openSUSE-release-tools-20190911.d06fa8af/dist/obs/OSRT:OriginUpdateSkip.xml
1970-01-01 01:00:00.000000000 +0100
+++
new/openSUSE-release-tools-20190913.9d119079/dist/obs/OSRT:OriginUpdateSkip.xml
2019-09-13 18:24:23.000000000 +0200
@@ -0,0 +1,5 @@
+<definition name="OriginUpdateSkip" namespace="OSRT">
+ <description>OriginManager skip updates</description>
+ <count>0</count>
+ <modifiable_by role="maintainer"/>
+</definition>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/gocd/checkers.opensuse.gocd.yaml
new/openSUSE-release-tools-20190913.9d119079/gocd/checkers.opensuse.gocd.yaml
---
old/openSUSE-release-tools-20190911.d06fa8af/gocd/checkers.opensuse.gocd.yaml
2019-09-11 12:46:39.000000000 +0200
+++
new/openSUSE-release-tools-20190913.9d119079/gocd/checkers.opensuse.gocd.yaml
2019-09-13 18:24:23.000000000 +0200
@@ -127,27 +127,6 @@
- staging-bot
tasks:
- script: ./leaper.py -A https://api.opensuse.org --verbose
project openSUSE:Maintenance maintenance_incident
- PackageHub15SP1.Manager42:
- group: openSUSE.Checkers
- lock_behavior: unlockWhenFinished
- timer:
- spec: 0 */30 * ? * *
- environment_variables:
- OSC_CONFIG: /home/go/config/oscrc-leaper
- materials:
- git:
- git: https://github.com/openSUSE/openSUSE-release-tools.git
- stages:
- - Run:
- approval: manual
- jobs:
- Run:
- timeout: 0
- resources:
- - staging-bot
- tasks:
- - script: ./manager_42.py -A https://api.opensuse.org -c
config/manager_42/openSUSE:Backports:SLE-15-SP1.yml
-
Factory.Staging.Report:
group: openSUSE.Checkers
lock_behavior: unlockWhenFinished
@@ -256,7 +235,7 @@
script:
git: https://github.com/openSUSE/openSUSE-release-tools.git
timer:
- spec: 0 0 7 ? * *
+ spec: 0 0 7 ? * SUN
only_on_changes: false
stages:
- Run:
@@ -269,6 +248,5 @@
mkdir -p $tempdir/.osc-plugins
ln -s $PWD/osc-origin.py $tempdir/.osc-plugins
ln -s $PWD/osclib $tempdir/.osc-plugins
- HOME=$tempdir osc -A https://api.opensuse.org origin -p
openSUSE:Leap:15.2 update
- HOME=$tempdir osc -A https://api.opensuse.org origin -p
openSUSE:Leap:15.2:NonFree update
+ HOME=$tempdir osc -A https://api.opensuse.org origin update
rm -rf $tempdir
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/gocd/checkers.suse.gocd.yaml
new/openSUSE-release-tools-20190913.9d119079/gocd/checkers.suse.gocd.yaml
--- old/openSUSE-release-tools-20190911.d06fa8af/gocd/checkers.suse.gocd.yaml
2019-09-11 12:46:39.000000000 +0200
+++ new/openSUSE-release-tools-20190913.9d119079/gocd/checkers.suse.gocd.yaml
2019-09-13 18:24:23.000000000 +0200
@@ -95,7 +95,7 @@
script:
git: https://github.com/openSUSE/openSUSE-release-tools.git
timer:
- spec: 0 0 7 ? * *
+ spec: 0 0 7 ? * SUN
only_on_changes: false
stages:
- Run:
@@ -108,7 +108,7 @@
mkdir -p $tempdir/.osc-plugins
ln -s $PWD/osc-origin.py $tempdir/.osc-plugins
ln -s $PWD/osclib $tempdir/.osc-plugins
- HOME=$tempdir osc -A https://api.suse.de origin -p
SUSE:SLE-15-SP2:GA update
+ HOME=$tempdir osc -A https://api.suse.de origin update
rm -rf $tempdir
S15.SP2.Staging.Bot.Regular:
group: SLE.Checkers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/gocd/checkers.suse.gocd.yaml.erb
new/openSUSE-release-tools-20190913.9d119079/gocd/checkers.suse.gocd.yaml.erb
---
old/openSUSE-release-tools-20190911.d06fa8af/gocd/checkers.suse.gocd.yaml.erb
2019-09-11 12:46:39.000000000 +0200
+++
new/openSUSE-release-tools-20190913.9d119079/gocd/checkers.suse.gocd.yaml.erb
2019-09-13 18:24:23.000000000 +0200
@@ -95,7 +95,7 @@
script:
git: https://github.com/openSUSE/openSUSE-release-tools.git
timer:
- spec: 0 0 7 ? * *
+ spec: 0 0 7 ? * SUN
only_on_changes: false
stages:
- Run:
@@ -108,7 +108,7 @@
mkdir -p $tempdir/.osc-plugins
ln -s $PWD/osc-origin.py $tempdir/.osc-plugins
ln -s $PWD/osclib $tempdir/.osc-plugins
- HOME=$tempdir osc -A https://api.suse.de origin -p
SUSE:SLE-15-SP2:GA update
+ HOME=$tempdir osc -A https://api.suse.de origin update
rm -rf $tempdir
S15.SP2.Staging.Bot.Regular:
group: SLE.Checkers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/gocd/monitors.gocd.yaml
new/openSUSE-release-tools-20190913.9d119079/gocd/monitors.gocd.yaml
--- old/openSUSE-release-tools-20190911.d06fa8af/gocd/monitors.gocd.yaml
2019-09-11 12:46:39.000000000 +0200
+++ new/openSUSE-release-tools-20190913.9d119079/gocd/monitors.gocd.yaml
2019-09-13 18:24:23.000000000 +0200
@@ -20,9 +20,10 @@
Run:
timeout: 0
resources:
- - staging-bot
+ - monitor
tasks:
- script: |-
+ install -D /home/go/config/openqa-client.conf
/home/go/.config/openqa/client.conf
export PYTHONPATH=$PWD/scripts
./scripts/gocd/rabbit-openqa.py -A https://api.opensuse.org
SUSE.openQA:
@@ -45,10 +46,11 @@
Run:
timeout: 0
resources:
- - staging-bot
+ - monitor
tasks:
# endless loop
- script: |-
+ install -D /home/go/config/openqa-client.conf
/home/go/.config/openqa/client.conf
export PYTHONPATH=$PWD/scripts
./scripts/gocd/rabbit-openqa.py -A https://api.suse.de
SUSE.Repo.Monitor:
@@ -71,7 +73,7 @@
Run:
timeout: 0
resources:
- - staging-bot
+ - monitor
tasks:
# endless loop
- script: |-
@@ -101,7 +103,7 @@
Run:
timeout: 0
resources:
- - staging-bot
+ - monitor
tasks:
# endless loop
- script: |-
@@ -111,3 +113,57 @@
git clone git://botmaster.suse.de/opensuse-repos.git
cd opensuse-repos
../scripts/gocd/rabbit-repoid.py -A https://api.opensuse.org
openSUSE:Factory openSUSE:Leap
+ openSUSE.OriginManagerUpdate:
+ group: Monitors
+ lock_behavior: unlockWhenFinished
+ timer:
+ spec: 0 */5 * ? * *
+ environment_variables:
+ OSC_CONFIG: /home/go/config/oscrc-origin-manager
+ materials:
+ script:
+ git: https://github.com/openSUSE/openSUSE-release-tools.git
+ stages:
+ - Run:
+ approval:
+ type: manual
+ jobs:
+ Run:
+ timeout: 0
+ resources:
+ - monitor
+ tasks:
+ - script: |-
+ tempdir=$(mktemp -d)
+ mkdir -p $tempdir/.osc-plugins
+ ln -s $PWD/osc-origin.py $tempdir/.osc-plugins
+ ln -s $PWD/osclib $tempdir/.osc-plugins
+ HOME=$tempdir osc -A https://api.opensuse.org origin update
--listen --listen-seconds 43200
+ rm -rf $tempdir
+ SUSE.OriginManagerUpdate:
+ group: Monitors
+ lock_behavior: unlockWhenFinished
+ timer:
+ spec: 0 */5 * ? * *
+ environment_variables:
+ OSC_CONFIG: /home/go/config/oscrc-origin-manager
+ materials:
+ script:
+ git: https://github.com/openSUSE/openSUSE-release-tools.git
+ stages:
+ - Run:
+ approval:
+ type: manual
+ jobs:
+ Run:
+ timeout: 0
+ resources:
+ - monitor
+ tasks:
+ - script: |-
+ tempdir=$(mktemp -d)
+ mkdir -p $tempdir/.osc-plugins
+ ln -s $PWD/osc-origin.py $tempdir/.osc-plugins
+ ln -s $PWD/osclib $tempdir/.osc-plugins
+ HOME=$tempdir osc -A https://api.suse.de origin update
--listen --listen-seconds 43200
+ rm -rf $tempdir
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/gocd/rabbit-openqa.py
new/openSUSE-release-tools-20190913.9d119079/gocd/rabbit-openqa.py
--- old/openSUSE-release-tools-20190911.d06fa8af/gocd/rabbit-openqa.py
2019-09-11 12:46:39.000000000 +0200
+++ new/openSUSE-release-tools-20190913.9d119079/gocd/rabbit-openqa.py
2019-09-13 18:24:23.000000000 +0200
@@ -19,7 +19,7 @@
from urllib.parse import quote_plus
import requests
-from PubSubConsumer import PubSubConsumer
+from osclib.PubSubConsumer import PubSubConsumer
class Project(object):
def __init__(self, name):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/gocd/rabbit-repoid.py
new/openSUSE-release-tools-20190913.9d119079/gocd/rabbit-repoid.py
--- old/openSUSE-release-tools-20190911.d06fa8af/gocd/rabbit-repoid.py
2019-09-11 12:46:39.000000000 +0200
+++ new/openSUSE-release-tools-20190913.9d119079/gocd/rabbit-repoid.py
2019-09-13 18:24:23.000000000 +0200
@@ -15,7 +15,7 @@
from lxml import etree as ET
from urllib.error import HTTPError
-from PubSubConsumer import PubSubConsumer
+from osclib.PubSubConsumer import PubSubConsumer
class Listener(PubSubConsumer):
def __init__(self, apiurl, amqp_prefix, namespaces):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/osc-origin.py
new/openSUSE-release-tools-20190913.9d119079/osc-origin.py
--- old/openSUSE-release-tools-20190911.d06fa8af/osc-origin.py 2019-09-11
12:46:39.000000000 +0200
+++ new/openSUSE-release-tools-20190913.9d119079/osc-origin.py 2019-09-13
18:24:23.000000000 +0200
@@ -19,14 +19,13 @@
from osclib.origin import origin_history
from osclib.origin import origin_potentials
from osclib.origin import origin_revision_state
+from osclib.origin import origin_updatable
from osclib.origin import origin_update
from osclib.sentry import sentry_init
from osclib.util import mail_send
from shutil import copyfile
import sys
import time
-import traceback
-from urllib.error import HTTPError
import yaml
OSRT_ORIGIN_LOOKUP_TTL = 60 * 60 * 24 * 7
@@ -36,6 +35,8 @@
@cmdln.option('--dry', action='store_true', help='perform a dry-run where
applicable')
@cmdln.option('--force-refresh', action='store_true', help='force refresh of
data')
@cmdln.option('--format', default='plain', help='output format')
[email protected]('--listen', action='store_true', help='listen to events')
[email protected]('--listen-seconds', help='number of seconds to listen to events')
@cmdln.option('--mail', action='store_true', help='mail report to
<confg:mail-release-list>')
@cmdln.option('--origins-only', action='store_true', help='list origins
instead of expanded config')
@cmdln.option('-p', '--project', help='project on which to operate')
@@ -63,7 +64,7 @@
osc origin potentials [--format json|yaml] PACKAGE
osc origin projects [--format json|yaml]
osc origin report [--diff] [--force-refresh] [--mail]
- osc origin update [PACKAGE...]
+ osc origin update [--listen] [--listen-seconds] [PACKAGE...]
"""
if len(args) == 0:
@@ -84,7 +85,7 @@
Cache.init()
apiurl = self.get_api_url()
- if command not in ['cron', 'projects']:
+ if command not in ['cron', 'projects', 'update']:
if not opts.project:
raise oscerr.WrongArgs('A project must be indicated.')
config = config_load(apiurl, opts.project)
@@ -345,28 +346,34 @@
body, None, dry=opts.dry)
def osrt_origin_update(apiurl, opts, *packages):
+ if opts.listen:
+ import logging
+ from osclib.origin_listener import OriginSourceChangeListener
+
+ logger = logging.getLogger()
+ logger.setLevel(logging.INFO)
+ listener = OriginSourceChangeListener(apiurl, logger, opts.project,
opts.dry)
+ try:
+ runtime = int(opts.listen_seconds) if opts.listen_seconds else None
+ listener.run(runtime=runtime)
+ except KeyboardInterrupt:
+ listener.stop()
+
+ return
+
+ if not opts.project:
+ for project in origin_updatable(apiurl):
+ opts.project = project
+ osrt_origin_update(apiurl, opts, *packages)
+
+ return
+
if len(packages) == 0:
packages = package_list_kind_filtered(apiurl, opts.project)
- return_value = 0
for package in packages:
- print('checking for updates to {}...'.format(package))
+ print('checking for updates to {}/{}...'.format(opts.project, package))
request_future = origin_update(apiurl, opts.project, package)
- if not request_future:
- continue
-
- print(request_future)
- if opts.dry:
- continue
-
- try:
- request_id = request_future.create()
- if request_id:
- print('-> created request {}'.format(request_id))
- except HTTPError:
- return_value = 1
- traceback.print_exc()
-
- if return_value != 0:
- sys.exit(return_value)
+ if request_future:
+ request_future.print_and_create(opts.dry)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/osclib/PubSubConsumer.py
new/openSUSE-release-tools-20190913.9d119079/osclib/PubSubConsumer.py
--- old/openSUSE-release-tools-20190911.d06fa8af/osclib/PubSubConsumer.py
1970-01-01 01:00:00.000000000 +0100
+++ new/openSUSE-release-tools-20190913.9d119079/osclib/PubSubConsumer.py
2019-09-13 18:24:23.000000000 +0200
@@ -0,0 +1,397 @@
+import functools
+import logging
+import pika
+import ssl
+import sys
+import time
+from datetime import datetime
+
+class PubSubConsumer(object):
+ """
+ Based on
https://github.com/pika/pika/blob/master/examples/asynchronous_consumer_example.py
+
+ This is an example consumer that will handle unexpected interactions
+ with RabbitMQ such as channel and connection closures.
+
+ If RabbitMQ closes the connection, it will reopen it. You should
+ look at the output, as there are limited reasons why the connection may
+ be closed, which usually are tied to permission related issues or
+ socket timeouts.
+
+ If the channel is closed, it will indicate a problem with one of the
+ commands that were issued and that should surface in the output as well.
+
+ """
+
+ def __init__(self, amqp_prefix, logger):
+ """Create a new instance of the consumer class, passing in the AMQP
+ URL used to connect to RabbitMQ.
+
+ :param str amqp_url: The AMQP url to connect with
+
+ """
+ self._connection = None
+ self._channel = None
+ self._closing = False
+ self._consuming = False
+ self._consumer_tag = None
+ self._prefix = amqp_prefix
+ self._timer_id = None
+ self._run_until = None
+ self.logger = logger
+
+ def restart_timer(self):
+ interval = 300
+ if self._timer_id:
+ self._connection.ioloop.remove_timeout(self._timer_id)
+ else:
+ # check the initial state on first timer hit
+ # so be quick about it
+ interval = 0
+ self._timer_id = self._connection.ioloop.call_later(interval,
self.still_alive)
+
+ def still_alive(self):
+ # output something so gocd doesn't consider it stalled
+ self.logger.info('Still alive: {}'.format(datetime.now().time()))
+ if self._run_until and time.time() > self._run_until:
+ self.stop()
+ else:
+ self.restart_timer()
+
+ def connect(self):
+ """This method connects to RabbitMQ, returning the connection handle.
+ When the connection is established, the on_connection_open method
+ will be invoked by pika.
+
+ :rtype: pika.SelectConnection
+
+ """
+ self.logger.info('Connecting to %s', self._prefix)
+ account = 'opensuse'
+ server = 'rabbit.opensuse.org'
+ if self._prefix == 'suse':
+ account = 'suse'
+ server = 'rabbit.suse.de'
+ credentials = pika.PlainCredentials(account, account)
+ context = ssl.create_default_context()
+ ssl_options = pika.SSLOptions(context, server)
+ parameters = pika.ConnectionParameters(server, 5671, '/', credentials,
ssl_options=ssl_options, socket_timeout=10)
+ return pika.SelectConnection(parameters,
+ on_open_callback=self.on_connection_open)
+
+ def close_connection(self):
+ """This method closes the connection to RabbitMQ."""
+ self._consuming = False
+ if self._connection.is_closing or self._connection.is_closed:
+ self.logger.info('Connection is closing or already closed')
+ else:
+ self.logger.info('Closing connection')
+ self._connection.close()
+
+ def add_on_connection_close_callback(self):
+ """This method adds an on close callback that will be invoked by pika
+ when RabbitMQ closes the connection to the publisher unexpectedly.
+
+ """
+ self.logger.debug('Adding connection close callback')
+ self._connection.add_on_close_callback(self.on_connection_closed)
+
+ def on_connection_closed(self, connection, reason):
+ """This method is invoked by pika when the connection to RabbitMQ is
+ closed unexpectedly. Since it is unexpected, we will reconnect to
+ RabbitMQ if it disconnects.
+
+ :param pika.connection.Connection connection: The closed connection obj
+ :param int reply_code: The server provided reply_code if given
+ :param str reply_text: The server provided reply_text if given
+
+ """
+ self._channel = None
+ if self._closing:
+ self._connection.ioloop.stop()
+ else:
+ self.logger.warning('Connection closed, reopening in 5 seconds:
%s',
+ reason)
+ self._connection.ioloop.call_later(5, self.reconnect)
+
+ def on_connection_open(self, unused_connection):
+ """This method is called by pika once the connection to RabbitMQ has
+ been established. It passes the handle to the connection object in
+ case we need it, but in this case, we'll just mark it unused.
+
+ :type unused_connection: pika.SelectConnection
+
+ """
+ self.logger.info('Connection opened')
+ self.add_on_connection_close_callback()
+ self.open_channel()
+
+ def reconnect(self):
+ """Will be invoked by the IOLoop timer if the connection is
+ closed. See the on_connection_closed method.
+
+ """
+ # This is the old connection IOLoop instance, stop its ioloop
+ self._connection.ioloop.stop()
+
+ if not self._closing:
+
+ # Create a new connection
+ self._connection = self.connect()
+
+ # There is now a new connection, needs a new ioloop to run
+ self._connection.ioloop.start()
+
+ def add_on_channel_close_callback(self):
+ """This method tells pika to call the on_channel_closed method if
+ RabbitMQ unexpectedly closes the channel.
+
+ """
+ self.logger.debug('Adding channel close callback')
+ self._channel.add_on_close_callback(self.on_channel_closed)
+
+ def on_channel_closed(self, channel, reason):
+ """Invoked by pika when RabbitMQ unexpectedly closes the channel.
+ Channels are usually closed if you attempt to do something that
+ violates the protocol, such as re-declare an exchange or queue with
+ different parameters. In this case, we'll close the connection
+ to shutdown the object.
+
+ :param pika.channel.Channel: The closed channel
+ :param int reply_code: The numeric reason the channel was closed
+ :param str reply_text: The text reason the channel was closed
+
+ """
+ self.logger.info('Channel %i was closed: %s',
+ channel, reason)
+ self._connection.close()
+
+ def on_channel_open(self, channel):
+ """This method is invoked by pika when the channel has been opened.
+ The channel object is passed in so we can make use of it.
+
+ Since the channel is now open, we'll declare the exchange to use.
+
+ :param pika.channel.Channel channel: The channel object
+
+ """
+ self.logger.debug('Channel opened')
+ self._channel = channel
+ self.add_on_channel_close_callback()
+ self.setup_exchange('pubsub')
+
+ def setup_exchange(self, exchange_name):
+ """Setup the exchange on RabbitMQ by invoking the Exchange.Declare RPC
+ command. When it is complete, the on_exchange_declareok method will
+ be invoked by pika.
+
+ :param str|unicode exchange_name: The name of the exchange to declare
+
+ """
+ self.logger.debug('Declaring exchange %s', exchange_name)
+ self._channel.exchange_declare(exchange_name,
+ exchange_type='topic',
+ callback=self.on_exchange_declareok,
+ passive=True, durable=True)
+
+ def on_exchange_declareok(self, unused_frame):
+ """Invoked by pika when RabbitMQ has finished the Exchange.Declare RPC
+ command.
+
+ :param pika.Frame.Method unused_frame: Exchange.DeclareOk response
frame
+
+ """
+ self.logger.debug('Exchange declared')
+ self._channel.queue_declare('', callback=self.on_queue_declareok,
exclusive=True)
+
+ def on_queue_declareok(self, method_frame):
+ """Method invoked by pika when the Queue.Declare RPC call made in
+ setup_queue has completed. In this method we will bind the queue
+ and exchange together with the routing key by issuing the Queue.Bind
+ RPC command. When this command is complete, the on_bindok method will
+ be invoked by pika.
+
+ :param pika.frame.Method method_frame: The Queue.DeclareOk frame
+
+ """
+ self.queue_name = method_frame.method.queue
+ self.routing_keys_to_bind = self.routing_keys()
+ self.bind_queue_to_routing_key(self.routing_keys_to_bind.pop())
+
+ def routing_keys(self):
+ return ['#']
+
+ def bind_queue_to_routing_key(self, key):
+ self.logger.info('Binding %s to %s', key, self.queue_name)
+ self._channel.queue_bind(self.queue_name, 'pubsub', routing_key=key,
callback=self.on_bindok)
+
+ def add_on_cancel_callback(self):
+ """Add a callback that will be invoked if RabbitMQ cancels the consumer
+ for some reason. If RabbitMQ does cancel the consumer,
+ on_consumer_cancelled will be invoked by pika.
+
+ """
+ self.logger.debug('Adding consumer cancellation callback')
+ self._channel.add_on_cancel_callback(self.on_consumer_cancelled)
+
+ def on_consumer_cancelled(self, method_frame):
+ """Invoked by pika when RabbitMQ sends a Basic.Cancel for a consumer
+ receiving messages.
+
+ :param pika.frame.Method method_frame: The Basic.Cancel frame
+
+ """
+ self.logger.info('Consumer was cancelled remotely, shutting down: %r',
+ method_frame)
+ if self._channel:
+ self._channel.close()
+
+ def on_message(self, unused_channel, basic_deliver, properties, body):
+ """Invoked by pika when a message is delivered from RabbitMQ. The
+ channel is passed for your convenience. The basic_deliver object that
+ is passed in carries the exchange, routing key, delivery tag and
+ a redelivered flag for the message. The properties passed in is an
+ instance of BasicProperties with the message properties and the body
+ is the message that was sent.
+
+ :param pika.channel.Channel unused_channel: The channel object
+ :param pika.Spec.Basic.Deliver: basic_deliver method
+ :param pika.Spec.BasicProperties: properties
+ :param str|unicode body: The message body
+
+ """
+ self.logger.info('Received message # %s: %s %s',
+ basic_deliver.delivery_tag,
basic_deliver.routing_key, body)
+ self.acknowledge_message(basic_deliver.delivery_tag)
+
+ def acknowledge_message(self, delivery_tag):
+ """Acknowledge the message delivery from RabbitMQ by sending a
+ Basic.Ack RPC method for the delivery tag.
+
+ :param int delivery_tag: The delivery tag from the Basic.Deliver frame
+
+ """
+ self.logger.debug('Acknowledging message %s', delivery_tag)
+ self._channel.basic_ack(delivery_tag)
+
+ def on_cancelok(self, _unused_frame, userdata):
+ """This method is invoked by pika when RabbitMQ acknowledges the
+ cancellation of a consumer. At this point we will close the channel.
+ This will invoke the on_channel_closed method once the channel has been
+ closed, which will in-turn close the connection.
+ :param pika.frame.Method _unused_frame: The Basic.CancelOk frame
+ :param str|unicode userdata: Extra user data (consumer tag)
+ """
+ self._consuming = False
+ self.logger.debug(
+ 'RabbitMQ acknowledged the cancellation of the consumer: %s',
+ userdata)
+ self.close_channel()
+
+ def close_channel(self):
+ """Call to close the channel with RabbitMQ cleanly by issuing the
+ Channel.Close RPC command.
+ """
+ self.logger.debug('Closing the channel')
+ self._channel.close()
+
+ def stop_consuming(self):
+ """Tell RabbitMQ that you would like to stop consuming by sending the
+ Basic.Cancel RPC command.
+
+ """
+ if self._channel:
+ self.logger.debug('Sending a Basic.Cancel RPC command to RabbitMQ')
+ cb = functools.partial(self.on_cancelok,
userdata=self._consumer_tag)
+ self._channel.basic_cancel(self._consumer_tag, cb)
+
+ def start_consuming(self):
+ """This method sets up the consumer by first calling
+ add_on_cancel_callback so that the object is notified if RabbitMQ
+ cancels the consumer. It then issues the Basic.Consume RPC command
+ which returns the consumer tag that is used to uniquely identify the
+ consumer with RabbitMQ. We keep the value to use it when we want to
+ cancel consuming. The on_message method is passed in as a callback pika
+ will invoke when a message is fully received.
+
+ """
+ self.logger.debug('Issuing consumer related RPC commands')
+ self.add_on_cancel_callback()
+ self.restart_timer()
+ self._consumer_tag = self._channel.basic_consume(self.queue_name,
+ self.on_message,
+ auto_ack=False)
+ self._consuming = True
+
+ def on_bindok(self, unused_frame):
+ """Invoked by pika when the Queue.Bind method has completed. At this
+ point we will start consuming messages by calling start_consuming
+ which will invoke the needed RPC commands to start the process.
+
+ :param pika.frame.Method unused_frame: The Queue.BindOk response frame
+
+ """
+ self.logger.debug('Queue bound')
+ if len(self.routing_keys_to_bind):
+ self.bind_queue_to_routing_key(self.routing_keys_to_bind.pop())
+ else:
+ self.start_consuming()
+
+ def open_channel(self):
+ """Open a new channel with RabbitMQ by issuing the Channel.Open RPC
+ command. When RabbitMQ responds that the channel is open, the
+ on_channel_open callback will be invoked by pika.
+
+ """
+ self.logger.debug('Creating a new channel')
+ self._connection.channel(on_open_callback=self.on_channel_open)
+
+ def run(self, runtime=None):
+ """Run the example consumer by connecting to RabbitMQ and then
+ starting the IOLoop to block and allow the SelectConnection to operate.
+
+ """
+ if runtime:
+ self._run_until = time.time() + runtime
+ self._connection = self.connect()
+ self._connection.ioloop.start()
+
+ def stop(self):
+ """Cleanly shutdown the connection to RabbitMQ by stopping the consumer
+ with RabbitMQ. When RabbitMQ confirms the cancellation, on_cancelok
+ will be invoked by pika, which will then closing the channel and
+ connection. The IOLoop is started again because this method is invoked
+ when CTRL-C is pressed raising a KeyboardInterrupt exception. This
+ exception stops the IOLoop which needs to be running for pika to
+ communicate with RabbitMQ. All of the commands issued prior to starting
+ the IOLoop will be buffered but not processed.
+
+ """
+ self.logger.debug('Stopping')
+ if not self._closing:
+ self._closing = True
+ self.logger.debug('Stopping')
+ if self._consuming:
+ self.stop_consuming()
+ #self._connection.ioloop.start()
+ else:
+ self._connection.ioloop.stop()
+ self.logger.debug('Stopped')
+
+def main():
+ LOG_FORMAT = ('%(levelname) -10s %(asctime)s %(name) -30s %(funcName) '
+ '-35s %(lineno) -5d: %(message)s')
+
+ logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)
+ amqp_prefix = 'opensuse'
+ if len(sys.argv) > 1:
+ amqp_prefix = sys.argv[1]
+ example = PubSubConsumer(amqp_prefix, logging.getLogger(__name__))
+ try:
+ example.run()
+ except KeyboardInterrupt:
+ example.stop()
+
+
+if __name__ == '__main__':
+ main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/osclib/core.py
new/openSUSE-release-tools-20190913.9d119079/osclib/core.py
--- old/openSUSE-release-tools-20190911.d06fa8af/osclib/core.py 2019-09-11
12:46:39.000000000 +0200
+++ new/openSUSE-release-tools-20190913.9d119079/osclib/core.py 2019-09-13
18:24:23.000000000 +0200
@@ -32,6 +32,7 @@
from osclib.conf import Config
from osclib.memoize import memoize
import subprocess
+import traceback
BINARY_REGEX =
r'(?:.*::)?(?P<filename>(?P<name>.*)-(?P<version>[^-]+)-(?P<release>[^-]+)\.(?P<arch>[^-\.]+))'
RPM_REGEX = BINARY_REGEX + r'\.rpm'
@@ -204,6 +205,17 @@
return project, package
+@memoize(session=True)
+def devel_projects(apiurl, project):
+ devel_projects = set()
+
+ root = search(apiurl, 'package', "@project='{}' and
devel/@project!=''".format(project))
+ for devel_project in root.xpath('package/devel/@project'):
+ if devel_project != project:
+ devel_projects.add(devel_project)
+
+ return sorted(devel_projects)
+
def request_age(request):
if isinstance(request, Request):
created = request.statehistory[0].when
@@ -652,14 +664,28 @@
return str(root.xpath('(//version)[last()]/text()')[0])
-def project_attribute_list(apiurl, attribute, value=None):
+def project_attribute_list(apiurl, attribute, locked=None):
xpath = 'attribute/@name="{}"'.format(attribute)
- if value is not None:
- xpath += '="{}"'.format(value)
-
root = search(apiurl, 'project', xpath)
- for project in root.findall('project'):
- yield project.get('name')
+ for project in root.xpath('project/@name'):
+ # Locked not exposed via OBS xpath engine.
+ if locked is not None and project_locked(apiurl, project) != locked:
+ continue
+
+ yield project
+
+# OBS xpath engine does not support multiple attribute queries nor negation. As
+# such both must be done client-side.
+def project_attributes_list(apiurl, attributes, attributes_not=None,
locked=None):
+ projects = set()
+
+ for attribute in attributes:
+ projects.update(project_attribute_list(apiurl, attribute, locked))
+
+ for attribute in attributes_not:
+ projects.difference_update(project_attribute_list(apiurl, attribute,
locked))
+
+ return list(projects)
@memoize(session=True)
def project_remote_list(apiurl):
@@ -976,6 +1002,23 @@
def create(self):
return self.create_function()
+ def create_tolerant(self):
+ try:
+ return self.create()
+ except HTTPError:
+ traceback.print_exc()
+
+ return False
+
+ def print_and_create(self, dry=False):
+ if dry:
+ print(self)
+ return None
+
+ request_id = self.create_tolerant()
+ print('{} = {}'.format(self, request_id))
+ return request_id
+
def __str__(self):
return self.description
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/osclib/origin.py
new/openSUSE-release-tools-20190913.9d119079/osclib/origin.py
--- old/openSUSE-release-tools-20190911.d06fa8af/osclib/origin.py
2019-09-11 12:46:39.000000000 +0200
+++ new/openSUSE-release-tools-20190913.9d119079/osclib/origin.py
2019-09-13 18:24:23.000000000 +0200
@@ -5,10 +5,12 @@
from osclib.conf import Config
from osclib.core import attribute_value_load
from osclib.core import devel_project_get
+from osclib.core import devel_projects
from osclib.core import entity_exists
from osclib.core import package_source_hash
from osclib.core import package_source_hash_history
from osclib.core import package_version
+from osclib.core import project_attributes_list
from osclib.core import project_remote_apiurl
from osclib.core import request_action_key
from osclib.core import request_action_list_source
@@ -629,3 +631,47 @@
target_project, package, message=message,
revision=action.src_rev)
return False
+
+@memoize(session=True)
+def origin_updatable(apiurl):
+ """ List of origin managed projects that can be updated. """
+ projects = project_attributes_list(apiurl, [
+ 'OSRT:OriginConfig',
+ ], [
+ 'OBS:Maintained', # Submitting maintenance updates not currently
supported.
+ 'OSRT:OriginUpdateSkip',
+ ], locked=False)
+
+ for project in projects:
+ updatable = False
+
+ # Look for at least one origin that allows automatic updates.
+ config = config_load(apiurl, project)
+ for origin, values in config_origin_generator(config['origins'],
skip_workarounds=True):
+ if values['automatic_updates']:
+ updatable = True
+ break
+
+ if not updatable:
+ projects.remove(project)
+
+ return projects
+
+@memoize(session=True)
+def origin_updatable_map(apiurl, pending=None):
+ origins = {}
+ for project in origin_updatable(apiurl):
+ config = config_load(apiurl, project)
+ for origin, values in config_origin_generator(config['origins'],
skip_workarounds=True):
+ if pending is not None and values['pending_submission_allow'] !=
pending:
+ continue
+
+ if origin == '<devel>':
+ for devel in devel_projects(apiurl, project):
+ origins.setdefault(devel, set())
+ origins[devel].add(project)
+ else:
+ origins.setdefault(origin, set())
+ origins[origin].add(project)
+
+ return origins
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/openSUSE-release-tools-20190911.d06fa8af/osclib/origin_listener.py
new/openSUSE-release-tools-20190913.9d119079/osclib/origin_listener.py
--- old/openSUSE-release-tools-20190911.d06fa8af/osclib/origin_listener.py
1970-01-01 01:00:00.000000000 +0100
+++ new/openSUSE-release-tools-20190913.9d119079/osclib/origin_listener.py
2019-09-13 18:24:23.000000000 +0200
@@ -0,0 +1,139 @@
+import json
+from osclib.core import package_kind
+from osclib.core import project_remote_list
+from osclib.origin import origin_updatable_map
+from osclib.origin import origin_update
+from osclib.PubSubConsumer import PubSubConsumer
+import threading
+
+
+class OriginSourceChangeListener(PubSubConsumer):
+ def __init__(self, apiurl, logger, project=None, dry=False):
+ self.apiurl = apiurl
+ self.project = project
+ self.dry = dry
+ self.listeners = {}
+
+ amqp_prefix = 'suse' if self.apiurl.endswith('suse.de') else 'opensuse'
+ super().__init__(amqp_prefix, logger)
+
+ def run(self, runtime=None):
+ super().run(runtime=runtime)
+
+ for listener in self.listeners.values():
+ listener.run(runtime=runtime)
+
+ def stop(self):
+ super().stop()
+
+ for listener in self.listeners.values():
+ listener.stop()
+
+ def start_consuming(self):
+ super().start_consuming()
+
+ self.check_remotes()
+
+ def routing_keys(self):
+ return [self._prefix + k for k in [
+ '.obs.package.update',
+ '.obs.request.create',
+ ]]
+
+ def on_message(self, unused_channel, method, properties, body):
+ super().on_message(unused_channel, method, properties, body)
+
+ payload = json.loads(body)
+ if method.routing_key == '{}.obs.package.update'.format(self._prefix):
+ self.on_message_package_update(payload)
+ elif method.routing_key ==
'{}.obs.request.create'.format(self._prefix):
+ self.on_message_request_create(payload)
+ else:
+ raise Exception('Unrequested message:
{}'.format(method.routing_key))
+
+ def on_message_package_update(self, payload):
+ origins = self.origin_updatable_map()
+ self.update_consider(origins, payload['project'], payload['package'])
+
+ def on_message_request_create(self, payload):
+ origins = self.origin_updatable_map(pending=True)
+ for action in payload['actions']:
+ # The following code demonstrates the quality of the data
structure.
+ # The base structure is inconsistent enough and yet the event data
+ # structure manages to be different from XML structure (for no
+ # reason) and even more inconsistent at that.
+ if action['type'] == 'delete':
+ if not action.get('targetpackage'):
+ continue
+
+ project = action['targetproject']
+ package = action['targetpackage']
+ elif action['type'] == 'maintenance_incident':
+ project = action['target_releaseproject']
+ if not action.get('targetpackage'):
+ package = action['sourcepackage']
+ else:
+ repository_suffix_length = len(project) + 1 #
package.project
+ package =
action['targetpackage'][:-repository_suffix_length]
+ elif action['type'] == 'maintenance_release':
+ project = action['targetproject']
+ repository_suffix_length = len(project) + 1 # package.project
+ package = action['sourcepackage'][:-repository_suffix_length]
+ elif action['type'] == 'submit':
+ project = action['targetproject']
+ package = action['targetpackage']
+ else:
+ # Unsupported action type.
+ continue
+
+ self.update_consider(origins, project, package)
+
+ def check_remotes(self):
+ origins = self.origin_updatable_map()
+ remotes = project_remote_list(self.apiurl)
+ for remote, apiurl in remotes.items():
+ for origin in origins:
+ if origin.startswith(remote + ':') and apiurl not in
self.listeners:
+ self.logger.info('starting remote listener due to {}
origin'.format(origin))
+ self.listeners[apiurl] =
OriginSourceChangeListenerRemote(apiurl, self, remote)
+ threading.Thread(target=self.listeners[apiurl].run).start()
+
+ def origin_updatable_map(self, pending=None):
+ return origin_updatable_map(self.apiurl, pending=pending)
+
+ def update_consider(self, origins, origin_project, package):
+ if origin_project not in origins:
+ self.logger.info('skipped irrelevant origin:
{}'.format(origin_project))
+ return
+
+ for project in origins[origin_project]:
+ if self.project and project != self.project:
+ self.logger.info('skipping filtered target project:
{}'.format(project))
+ continue
+
+ kind = package_kind(self.apiurl, project, package)
+ if kind == 'source':
+ request_future = origin_update(self.apiurl, project, package)
+ if request_future:
+ request_future.print_and_create(self.dry)
+ else:
+ # This eliminates the possibility for deletes by listener.
+ self.logger.info('skipped updating non-existant package
{}/{}'.format(project, package))
+
+class OriginSourceChangeListenerRemote(OriginSourceChangeListener):
+ def __init__(self, apiurl, parent, prefix):
+ self.parent = parent
+ self.prefix = prefix
+
+ super().__init__(apiurl, self.parent.logger)
+ self._run_until = self.parent._run_until
+
+ def check_remotes(self):
+ pass
+
+ def origin_updatable_map(self, pending=None):
+ return self.parent.origin_updatable_map(pending=pending)
+
+ def update_consider(self, origins, origin_project, package):
+ origin_project = '{}:{}'.format(self.prefix, origin_project)
+ self.parent.update_consider(origins, origin_project, package)
++++++ openSUSE-release-tools.obsinfo ++++++
--- /var/tmp/diff_new_pack.Eytaky/_old 2019-09-16 10:52:14.027158000 +0200
+++ /var/tmp/diff_new_pack.Eytaky/_new 2019-09-16 10:52:14.027158000 +0200
@@ -1,5 +1,5 @@
name: openSUSE-release-tools
-version: 20190911.d06fa8af
-mtime: 1568198799
-commit: d06fa8afb3cacc877feaf99e1698afdc363910ee
+version: 20190913.9d119079
+mtime: 1568391863
+commit: 9d119079582b04b205b4f6e8d500262a8feee07f