Allow use of aliases defined previously inside included files

Anchors and aliases were expanded internally within JJB's yaml loading
calls so they were limited to individual documents. Now, included files
will have access to aliases of anchors already defined at previously
processed files.

Example:

- default:
    name: default-timeout-wrapper
    timeout: &timeout
      fail: true
      elastic-percentage: 150
      elastic-default-timeout: 90
      type: elastic

- wrapper: !include include002_1.yaml.inc

Previously was not possible to use '*timeout' alias inside
include002_1.yaml.inc file

Closes-Story: 2000173

Change-Id: Ic031ddbb0310bd11748183fbde9502735c3b7169
This commit is contained in:
Victor Seva 2015-02-20 12:37:29 +01:00
parent 6c6370bbff
commit 1191dcfccf
7 changed files with 75 additions and 6 deletions

View File

@ -319,9 +319,8 @@ For example:
The `anchors and aliases`_ are expanded internally within JJB's yaml loading
calls, and are limited to individual documents. That means you use the same
anchor name in separate files without collisions, but also means that you must
define the anchor in the same file that you intend to reference it.
calls and are not limited to individual documents. That means you can't use
the same anchor name in included files without collisions.
A simple example can be seen in the specs `full length example`_ with the
following being more representative of usage within JJB:

View File

@ -129,7 +129,31 @@ class OrderedConstructor(BaseConstructor):
data.update(mapping)
class LocalLoader(OrderedConstructor, yaml.Loader):
class LocalAnchorLoader(yaml.Loader):
"""Subclass for yaml.Loader which keeps Alias between calls"""
anchors = {}
def __init__(self, *args, **kwargs):
super(LocalAnchorLoader, self).__init__(*args, **kwargs)
self.anchors = LocalAnchorLoader.anchors
@classmethod
def reset_anchors(cls):
cls.anchors = {}
# override the default composer to skip resetting the anchors at the
# end of the current document
def compose_document(self):
# Drop the DOCUMENT-START event.
self.get_event()
# Compose the root node.
node = self.compose_node(None, None)
# Drop the DOCUMENT-END event.
self.get_event()
return node
class LocalLoader(OrderedConstructor, LocalAnchorLoader):
"""Subclass for yaml.Loader which handles the local tags 'include',
'include-raw' and 'include-raw-escaped' to specify a file to include data
from and whether to parse it as additional yaml, treat it as a data blob
@ -228,4 +252,5 @@ class LocalLoader(OrderedConstructor, yaml.Loader):
def load(stream, **kwargs):
LocalAnchorLoader.reset_anchors()
return yaml.load(stream, functools.partial(LocalLoader, **kwargs))

View File

@ -16,9 +16,9 @@
import os
from testtools import ExpectedException
from testtools.matchers import MismatchError
from testtools import TestCase
from testscenarios.testcase import TestWithScenarios
from yaml.composer import ComposerError
from jenkins_jobs import builder
from tests.base import get_scenarios, JsonTestCase, YamlTestCase
@ -40,7 +40,8 @@ class TestCaseLocalYamlInclude(TestWithScenarios, TestCase, JsonTestCase):
def test_yaml_snippet(self):
if os.path.basename(self.in_filename).startswith("exception_"):
with ExpectedException(MismatchError):
with ExpectedException(ComposerError,
"^found duplicate anchor .*"):
super(TestCaseLocalYamlInclude, self).test_yaml_snippet()
else:
super(TestCaseLocalYamlInclude, self).test_yaml_snippet()

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<actions/>
<description>&lt;!-- Managed by Jenkins Job Builder --&gt;</description>
<keepDependencies>false</keepDependencies>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<concurrentBuild>false</concurrentBuild>
<canRoam>true</canRoam>
<properties/>
<scm class="hudson.scm.NullSCM"/>
<builders/>
<publishers/>
<buildWrappers>
<hudson.plugins.build__timeout.BuildTimeoutWrapper>
<timeoutMinutes>3</timeoutMinutes>
<failBuild>true</failBuild>
<writingDescription>false</writingDescription>
<timeoutPercentage>150</timeoutPercentage>
<timeoutMinutesElasticDefault>90</timeoutMinutesElasticDefault>
<timeoutType>elastic</timeoutType>
</hudson.plugins.build__timeout.BuildTimeoutWrapper>
</buildWrappers>
</project>

View File

@ -0,0 +1,16 @@
# vim: sw=4 ts=4 et
- default:
name: default-timeout-wrapper
timeout: &timeout
fail: true
elastic-percentage: 150
elastic-default-timeout: 90
type: elastic
# include that uses timeout alias
- wrapper: !include include002_1.yaml.inc
- job:
name: test-job-1
wrappers:
!include include002.yaml.inc

View File

@ -0,0 +1 @@
- timeout-wrapper

View File

@ -0,0 +1,3 @@
name: timeout-wrapper
wrappers:
- timeout: *timeout