Expose buildset to the executor and url formatter

For github (and probably other providers) we really only have the option
of returning 1 url for the entire buildset, as opposed to 1 per build.
To make log uploading within that easier we really need a way to
globally identify all the different builds that belong to 1 change.

The zuul ref is already available however this is a concept that is
planned to be deprecated, so instead add a UUID parameter to the
buildset that we can pass through. This UUID is used to build the ref to
make migration easier.

Change-Id: I1cab8af5c9d7f6875591fbe4ac4e184b90f6ca12
Signed-off-by: Jamie Lennox <jamielennox@gmail.com>
diff --git a/zuul/model.py b/zuul/model.py
index 59f5531..612aa6f 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -1194,7 +1194,7 @@
         self.result = None
         self.next_build_set = None
         self.previous_build_set = None
-        self.ref = None
+        self.uuid = None
         self.commit = None
         self.zuul_url = None
         self.dependent_items = None
@@ -1210,6 +1210,13 @@
         self.layout = None
         self.tries = {}
 
+    @property
+    def ref(self):
+        # NOTE(jamielennox): The concept of buildset ref is to be removed and a
+        # buildset UUID identifier available instead. Currently the ref is
+        # checked to see if the BuildSet has been configured.
+        return 'Z' + self.uuid if self.uuid else None
+
     def __repr__(self):
         return '<BuildSet item: %s #builds: %s merge state: %s>' % (
             self.item,
@@ -1227,8 +1234,8 @@
                 items.append(next_item)
                 next_item = next_item.item_ahead
             self.dependent_items = items
-        if not self.ref:
-            self.ref = 'Z' + uuid4().hex
+        if not self.uuid:
+            self.uuid = uuid4().hex
         if self.merger_items is None:
             items = [self.item] + self.dependent_items
             items.reverse()
@@ -1309,6 +1316,9 @@
                 return project_config.merge_mode
         return MERGER_MERGE_RESOLVE
 
+    def getSafeAttributes(self):
+        return Attributes(uuid=self.uuid)
+
 
 class QueueItem(object):
     """Represents the position of a Change in a ChangeQueue.
@@ -1589,12 +1599,14 @@
         safe_change = self.change.getSafeAttributes()
         safe_pipeline = self.pipeline.getSafeAttributes()
         safe_tenant = self.pipeline.layout.tenant.getSafeAttributes()
+        safe_buildset = self.current_build_set.getSafeAttributes()
         safe_job = job.getSafeAttributes() if job else {}
         safe_build = build.getSafeAttributes() if build else {}
         try:
             url = url_pattern.format(change=safe_change,
                                      pipeline=safe_pipeline,
                                      tenant=safe_tenant,
+                                     buildset=safe_buildset,
                                      job=safe_job,
                                      build=safe_build)
         except KeyError as e: