1# Copyright 2012 Hewlett-Packard Development Company, L.P.
2# Copyright 2012 Varnish Software AS
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16
17"""
18Builders define actions that the Jenkins job should execute.  Examples
19include shell scripts or maven targets.  The ``builders`` attribute in
20the :ref:`Job` definition accepts a list of builders to invoke.  They
21may be components defined below, locally defined macros (using the top
22level definition of ``builder:``, or locally defined components found
23via the ``jenkins_jobs.builders`` entry point.
24
25**Component**: builders
26  :Macro: builder
27  :Entry Point: jenkins_jobs.builders
28
29Example::
30
31  job:
32    name: test_job
33
34    builders:
35      - shell: "make test"
36
37"""
38
39import logging
40import sys
41import xml.etree.ElementTree as XML
42
43import six
44
45from jenkins_jobs.errors import is_sequence
46from jenkins_jobs.errors import InvalidAttributeError
47from jenkins_jobs.errors import JenkinsJobsException
48from jenkins_jobs.errors import MissingAttributeError
49import jenkins_jobs.modules.base
50import jenkins_jobs.modules.helpers as helpers
51import pkg_resources
52from jenkins_jobs.modules import hudson_model
53from jenkins_jobs.modules.publishers import ssh
54from jenkins_jobs.modules.publishers import cifs
55
56logger = logging.getLogger(__name__)
57
58
59def shell(registry, xml_parent, data):
60    """yaml: shell
61    Execute a shell command.
62
63    There are two ways of configuring the builder, with a plain string to
64    execute:
65
66    :arg str parameter: the shell command to execute
67
68    Or with a mapping that allows other parameters to be passed:
69
70    :arg str command: the shell command to execute
71    :arg int unstable-return:
72        the shell exit code to interpret as an unstable build result
73
74    Example:
75
76    .. literalinclude:: /../../tests/builders/fixtures/shell.yaml
77       :language: yaml
78
79    .. literalinclude::
80        /../../tests/builders/fixtures/shell-unstable-return.yaml
81       :language: yaml
82    """
83    shell = XML.SubElement(xml_parent, "hudson.tasks.Shell")
84    if isinstance(data, six.string_types):
85        XML.SubElement(shell, "command").text = data
86    else:
87        mappings = [
88            ("command", "command", None),
89            ("unstable-return", "unstableReturn", 0),
90        ]
91        helpers.convert_mapping_to_xml(shell, data, mappings, fail_required=True)
92
93
94def python(registry, xml_parent, data):
95    """yaml: python
96    Execute a python command. Requires the Jenkins :jenkins-plugins:`Python plugin
97    <python>`.
98
99    :arg str parameter: the python command to execute
100
101    Example:
102
103    .. literalinclude:: /../../tests/builders/fixtures/python.yaml
104       :language: yaml
105
106    """
107    python = XML.SubElement(xml_parent, "hudson.plugins.python.Python")
108    XML.SubElement(python, "command").text = data
109
110
111def copyartifact(registry, xml_parent, data):
112    """yaml: copyartifact
113
114    Copy artifact from another project. Requires the :jenkins-plugins:`Copy
115    Artifact plugin <copyartifact>`.
116
117    Please note using the multijob-build for which-build argument requires
118    the :jenkins-plugins:`Multijob plugin <jenkins-multijob-plugin>`
119
120    :arg str project: Project to copy from
121    :arg str filter: what files to copy
122    :arg str target: Target base directory for copy, blank means use workspace
123    :arg bool flatten: Flatten directories (default false)
124    :arg bool optional: If the artifact is missing (for any reason) and
125        optional is true, the build won't fail because of this builder
126        (default false)
127    :arg bool do-not-fingerprint: Disable automatic fingerprinting of copied
128        artifacts (default false)
129    :arg str which-build: which build to get artifacts from
130        (optional, default last-successful)
131
132        :which-build values:
133            * **last-successful**
134            * **last-completed**
135            * **specific-build**
136            * **last-saved**
137            * **upstream-build**
138            * **permalink**
139            * **workspace-latest**
140            * **build-param**
141            * **downstream-build**
142            * **multijob-build**
143
144    :arg str build-number: specifies the build number to get when
145        when specific-build is specified as which-build
146    :arg str permalink: specifies the permalink to get when
147        permalink is specified as which-build
148
149        :permalink values:
150            * **last**
151            * **last-stable**
152            * **last-successful**
153            * **last-failed**
154            * **last-unstable**
155            * **last-unsuccessful**
156
157    :arg bool stable: specifies to get only last stable build when
158        last-successful is specified as which-build
159    :arg bool fallback-to-last-successful: specifies to fallback to
160        last successful build when upstream-build is specified as which-build
161    :arg str param: specifies to use a build parameter to get the build when
162        build-param is specified as which-build
163    :arg str upstream-project-name: specifies the project name of downstream
164        when downstream-build is specified as which-build
165    :arg str upstream-build-number: specifies the number of the build to
166        find its downstream build when downstream-build is specified as
167        which-build
168    :arg str parameter-filters: Filter matching jobs based on these
169        parameters (optional)
170    :arg str exclude: Specify paths or patterns of artifacts to
171        exclude, even if specified in "Artifacts to copy". (default '')
172    :arg str result-var-suffix: The build number of the selected build
173        will be recorded into the variable named
174        COPYARTIFACT_BUILD_NUMBER_(SUFFIX)
175        for later build steps to reference. (default '')
176
177    Example:
178
179    .. literalinclude:: ../../tests/builders/fixtures/copy-artifact001.yaml
180       :language: yaml
181
182    Multijob Example:
183
184    .. literalinclude:: ../../tests/builders/fixtures/copy-artifact004.yaml
185       :language: yaml
186    """
187    t = XML.SubElement(xml_parent, "hudson.plugins.copyartifact.CopyArtifact")
188    mappings = [
189        # Warning: this only works with copy artifact version 1.26+,
190        # for copy artifact version 1.25- the 'projectName' element needs
191        # to be used instead of 'project'
192        ("project", "project", None),
193        ("filter", "filter", ""),
194        ("target", "target", ""),
195        ("flatten", "flatten", False),
196        ("optional", "optional", False),
197        ("do-not-fingerprint", "doNotFingerprintArtifacts", False),
198        ("parameter-filters", "parameters", ""),
199        ("exclude", "exclude", ""),
200        ("result-var-suffix", "resultVariableSuffix", ""),
201    ]
202    helpers.convert_mapping_to_xml(t, data, mappings, fail_required=True)
203    helpers.copyartifact_build_selector(t, data)
204
205
206def change_assembly_version(registry, xml_parent, data):
207    """yaml: change-assembly-version
208    Change the assembly version.
209    Requires the Jenkins :jenkins-plugins:`Change Assembly Version
210    <change-assembly-version-plugin>`.
211
212    :arg str version: Set the new version number for replace (default 1.0.0)
213    :arg str assemblyFile: The file name to search (default AssemblyInfo.cs)
214
215    Minimal Example:
216
217    .. literalinclude::
218        /../../tests/builders/fixtures/changeassemblyversion-minimal.yaml
219       :language: yaml
220
221    Full Example:
222
223    .. literalinclude::
224        /../../tests/builders/fixtures/changeassemblyversion-full.yaml
225       :language: yaml
226    """
227
228    cav_builder_tag = (
229        "org.jenkinsci.plugins.changeassemblyversion." "ChangeAssemblyVersion"
230    )
231    cav = XML.SubElement(xml_parent, cav_builder_tag)
232    mappings = [
233        ("version", "task", "1.0.0"),
234        ("assembly-file", "assemblyFile", "AssemblyInfo.cs"),
235    ]
236    helpers.convert_mapping_to_xml(cav, data, mappings, fail_required=True)
237
238
239def fingerprint(registry, xml_parent, data):
240    """yaml: fingerprint
241    Adds the ability to generate fingerprints as build steps instead of waiting
242    for a build to complete.
243
244    Requires the Jenkins :jenkins-plugins:`Fingerprint Plugin
245    <create-fingerprint>`.
246
247    :arg str targets: Files to fingerprint (default '')
248
249    Full Example:
250
251    .. literalinclude::
252        /../../tests/builders/fixtures/fingerprint-full.yaml
253       :language: yaml
254
255    Minimal Example:
256
257    .. literalinclude::
258        /../../tests/builders/fixtures/fingerprint-minimal.yaml
259       :language: yaml
260    """
261
262    fingerprint = XML.SubElement(
263        xml_parent, "hudson.plugins.createfingerprint.CreateFingerprint"
264    )
265    fingerprint.set("plugin", "create-fingerprint")
266
267    mapping = [("targets", "targets", "")]
268    helpers.convert_mapping_to_xml(fingerprint, data, mapping, fail_required=True)
269
270
271def ant(registry, xml_parent, data):
272    """yaml: ant
273    Execute an ant target. Requires the Jenkins :jenkins-plugins:`Ant Plugin
274    <ant>`.
275
276    To setup this builder you can either reference the list of targets
277    or use named parameters. Below is a description of both forms:
278
279    *1) Listing targets:*
280
281    After the ant directive, simply pass as argument a space separated list
282    of targets to build.
283
284    :Parameter: space separated list of Ant targets
285
286    Example to call two Ant targets:
287
288    .. literalinclude:: ../../tests/builders/fixtures/ant001.yaml
289       :language: yaml
290
291    The build file would be whatever the Jenkins Ant Plugin is set to use
292    per default (i.e build.xml in the workspace root).
293
294    *2) Using named parameters:*
295
296    :arg str targets: the space separated list of ANT targets.
297    :arg str buildfile: the path to the ANT build file.
298    :arg list properties: Passed to ant script using -Dkey=value (optional)
299    :arg str ant-name: the name of the ant installation,
300        (default 'default') (optional)
301    :arg str java-opts: java options for ant, can have multiples,
302        must be in quotes (optional)
303
304
305    Example specifying the build file too and several targets:
306
307    .. literalinclude:: ../../tests/builders/fixtures/ant002.yaml
308       :language: yaml
309    """
310    ant = XML.SubElement(xml_parent, "hudson.tasks.Ant")
311
312    if type(data) is str:
313        # Support for short form: -ant: "target"
314        data = {"targets": data}
315
316    mapping = [
317        ("targets", "targets", None),
318        ("buildfile", "buildFile", None),
319        ("ant-name", "antName", "default"),
320    ]
321    helpers.convert_mapping_to_xml(ant, data, mapping, fail_required=False)
322
323    mapping = []
324    for setting, value in sorted(data.items()):
325        if setting == "properties":
326            properties = value
327            prop_string = ""
328            for prop, val in properties.items():
329                prop_string += "%s=%s\n" % (prop, val)
330            mapping.append(("", "properties", prop_string))
331        if setting == "java-opts":
332            jopt_string = "\n".join(value)
333            mapping.append(("", "antOpts", jopt_string))
334
335    helpers.convert_mapping_to_xml(ant, data, mapping, fail_required=True)
336
337
338def trigger_remote(registry, xml_parent, data):
339    """yaml: trigger-remote
340    Trigger build of job on remote Jenkins instance.
341
342    Requires the Jenkins :jenkins-plugins:`Parameterized Remote Trigger Plugin
343    <Parameterized-Remote-Trigger>`
344
345    Please note that this plugin requires system configuration on the Jenkins
346    Master that is unavailable from individual job views; specifically, one
347    must add remote jenkins servers whose 'Display Name' field are what make up
348    valid fields on the `remote-jenkins-name` attribute below.
349
350    :arg str remote-jenkins-name: the remote Jenkins server (required)
351    :arg str job: the Jenkins project to trigger on the remote Jenkins server
352        (required)
353    :arg bool should-not-fail-build: if true, remote job failure will not lead
354        current job to fail (default false)
355    :arg bool prevent-remote-build-queue: if true, wait to trigger remote
356        builds until no other builds (default false)
357    :arg bool block: whether to wait for the trigger jobs to finish or not
358        (default true)
359    :arg str poll-interval: polling interval in seconds for checking statues of
360        triggered remote job, only necessary if current job is configured to
361        block (default 10)
362    :arg str connection-retry-limit: number of connection attempts to remote
363        Jenkins server before giving up. (default 5)
364    :arg bool enhanced-logging: if this option is enabled,
365        the console output of the remote job is also logged. (default false)
366    :arg str predefined-parameters: predefined parameters to send to the remote
367        job when triggering it (optional)
368    :arg str property-file: file in workspace of current job containing
369        additional parameters to be set on remote job
370        (optional)
371
372    Example:
373
374    .. literalinclude::
375        /../../tests/builders/fixtures/trigger-remote/trigger-remote001.yaml
376       :language: yaml
377    """
378    triggerr = XML.SubElement(
379        xml_parent,
380        "org.jenkinsci.plugins."
381        "ParameterizedRemoteTrigger."
382        "RemoteBuildConfiguration",
383    )
384
385    mappings = [
386        ("remote-jenkins-name", "remoteJenkinsName", None),
387        ("token", "token", ""),
388        ("job", "job", None),
389        ("should-not-fail-build", "shouldNotFailBuild", False),
390        ("poll-interval", "pollInterval", 10),
391        ("connection-retry-limit", "connectionRetryLimit", 5),
392        ("enhanced-logging", "enhancedLogging", False),
393        ("prevent-remote-build-queue", "preventRemoteBuildQueue", False),
394        ("block", "blockBuildUntilComplete", True),
395    ]
396    helpers.convert_mapping_to_xml(triggerr, data, mappings, fail_required=True)
397
398    mappings = []
399    if "predefined-parameters" in data:
400        parameters = data.get("predefined-parameters", "")
401        XML.SubElement(triggerr, "parameters").text = parameters
402        params_list = parameters.split("\n")
403
404        parameter_list = XML.SubElement(triggerr, "parameterList")
405        for param in params_list:
406            if param == "":
407                continue
408            tmp = XML.SubElement(parameter_list, "string")
409            tmp.text = param
410
411    if "property-file" in data and data["property-file"] != "":
412        mappings.append(("", "loadParamsFromFile", "true"))
413        mappings.append(("property-file", "parameterFile", None))
414    else:
415        mappings.append(("", "loadParamsFromFile", "false"))
416
417    mappings.append(("", "overrideAuth", "false"))
418
419    helpers.convert_mapping_to_xml(triggerr, data, mappings, fail_required=True)
420
421
422def trigger_builds(registry, xml_parent, data):
423    """yaml: trigger-builds
424    Trigger builds of other jobs.
425
426    Requires the Jenkins :jenkins-plugins:`Parameterized Trigger Plugin
427    <parameterized-trigger>`.
428
429    :arg list project: the Jenkins project to trigger
430    :arg str predefined-parameters: key/value pairs to be passed to the job
431        (optional)
432    :arg list bool-parameters:
433
434        :Bool:
435            * **name** (`str`) -- Parameter name
436            * **value** (`bool`) -- Value to set (default false)
437
438    :arg str property-file:
439        Pass properties from file to the other job (optional)
440    :arg bool property-file-fail-on-missing:
441        Don't trigger if any files are missing (default true)
442    :arg bool current-parameters: Whether to include the parameters passed
443        to the current build to the triggered job.
444    :arg str node-label-name: Define a name for the NodeLabel parameter to be
445        set. Used in conjunction with node-label. Requires NodeLabel Parameter
446        Plugin (optional)
447    :arg str node-label: Label of the nodes where build should be triggered.
448        Used in conjunction with node-label-name.  Requires NodeLabel Parameter
449        Plugin (optional)
450    :arg str restrict-matrix-project: Filter that restricts the subset
451        of the combinations that the triggered job will run (optional)
452    :arg bool svn-revision: Whether to pass the svn revision to the triggered
453        job (optional)
454    :arg dict git-revision: Passes git revision to the triggered job
455        (optional).
456
457        * **combine-queued-commits** (bool): Whether to combine queued git
458          hashes or not (default false)
459    :arg bool block: whether to wait for the triggered jobs to finish or not
460        (default false)
461    :arg dict block-thresholds: Fail builds and/or mark as failed or unstable
462        based on thresholds. Only apply if block parameter is true (optional)
463
464        :block-thresholds:
465            * **build-step-failure-threshold** (`str`) - build step failure
466              threshold, valid values are 'never', 'SUCCESS', 'UNSTABLE', or
467              'FAILURE'. (default 'FAILURE')
468            * **unstable-threshold** (`str`) - unstable threshold, valid
469              values are 'never', 'SUCCESS', 'UNSTABLE', or 'FAILURE'.
470              (default 'UNSTABLE')
471            * **failure-threshold** (`str`) - overall failure threshold, valid
472              values are 'never', 'SUCCESS', 'UNSTABLE', or 'FAILURE'.
473              (default 'FAILURE')
474
475    :arg bool same-node: Use the same node for the triggered builds that was
476        used for this build (optional)
477    :arg list parameter-factories: list of parameter factories
478
479        :Factory:
480            * **factory** (`str`) **filebuild** -- For every property file,
481              invoke one build
482            * **file-pattern** (`str`) -- File wildcard pattern
483            * **no-files-found-action** (`str`) -- Action to perform when
484              no files found. Valid values 'FAIL', 'SKIP', or 'NOPARMS'.
485              (default 'SKIP')
486
487        :Factory:
488            * **factory** (`str`) **binaryfile** -- For every matching
489              file, invoke one build
490            * **file-pattern** (`str`) -- Artifact ID of the artifact
491            * **no-files-found-action** (`str`) -- Action to perform when
492              no files found. Valid values 'FAIL', 'SKIP', or 'NOPARMS'.
493              (default 'SKIP')
494
495        :Factory:
496            * **factory** (`str`) **counterbuild** -- Invoke i=0...N builds
497            * **from** (`int`) -- Artifact ID of the artifact
498            * **to** (`int`) -- Version of the artifact
499            * **step** (`int`) -- Classifier of the artifact
500            * **parameters** (`str`) -- KEY=value pairs, one per line
501              (default '')
502            * **validation-fail** (`str`) -- Action to perform when
503              stepping validation fails. Valid values 'FAIL', 'SKIP', or
504              'NOPARMS'. (default 'FAIL')
505
506        :Factory:
507            * **factory** (`str`) **allnodesforlabel** -- Trigger a build
508              on all nodes having specific label. Requires NodeLabel
509              Parameter Plugin (optional)
510            * **name** (`str`) -- Name of the parameter to set (optional)
511            * **node-label** (`str`) -- Label of the nodes where build
512              should be triggered
513            * **ignore-offline-nodes** (`bool`) -- Don't trigger build on
514              offline nodes (default true)
515
516        :Factory:
517            * **factory** (`str`) **allonlinenodes** -- Trigger a build on
518              every online node. Requires NodeLabel Parameter Plugin (optional)
519
520    Examples:
521
522    Basic usage with yaml list of projects.
523
524    .. literalinclude::
525        /../../tests/builders/fixtures/trigger-builds/project-list.yaml
526       :language: yaml
527
528    Basic usage with passing svn revision through.
529
530    .. literalinclude:: /../../tests/builders/fixtures/trigger-builds001.yaml
531       :language: yaml
532
533    Basic usage with passing git revision through.
534
535    .. literalinclude:: /../../tests/builders/fixtures/trigger-builds006.yaml
536       :language: yaml
537
538    Example with all supported parameter factories.
539
540    .. literalinclude::
541        /../../tests/builders/fixtures/trigger-builds-configfactory-multi.yaml
542       :language: yaml
543    """
544    tbuilder = XML.SubElement(
545        xml_parent, "hudson.plugins.parameterizedtrigger." "TriggerBuilder"
546    )
547    configs = XML.SubElement(tbuilder, "configs")
548    for project_def in data:
549        if "project" not in project_def or project_def["project"] == "":
550            logger.debug("No project specified - skipping trigger-build")
551            continue
552        tconfig = XML.SubElement(
553            configs,
554            "hudson.plugins.parameterizedtrigger." "BlockableBuildTriggerConfig",
555        )
556        tconfigs = XML.SubElement(tconfig, "configs")
557        if project_def.get("current-parameters"):
558            XML.SubElement(
559                tconfigs,
560                "hudson.plugins.parameterizedtrigger." "CurrentBuildParameters",
561            )
562        if project_def.get("svn-revision"):
563            XML.SubElement(
564                tconfigs,
565                "hudson.plugins.parameterizedtrigger."
566                "SubversionRevisionBuildParameters",
567            )
568
569        if project_def.get("git-revision"):
570            helpers.append_git_revision_config(tconfigs, project_def["git-revision"])
571
572        if project_def.get("same-node"):
573            XML.SubElement(
574                tconfigs, "hudson.plugins.parameterizedtrigger." "NodeParameters"
575            )
576        if "property-file" in project_def:
577            params = XML.SubElement(
578                tconfigs, "hudson.plugins.parameterizedtrigger." "FileBuildParameters"
579            )
580            mapping = [
581                ("property-file", "propertiesFile", None),
582                ("property-file-fail-on-missing", "failTriggerOnMissing", True),
583            ]
584            helpers.convert_mapping_to_xml(
585                params, project_def, mapping, fail_required=True
586            )
587
588        if "predefined-parameters" in project_def:
589            params = XML.SubElement(
590                tconfigs,
591                "hudson.plugins.parameterizedtrigger." "PredefinedBuildParameters",
592            )
593            mapping = [("predefined-parameters", "properties", None)]
594            helpers.convert_mapping_to_xml(
595                params, project_def, mapping, fail_required=True
596            )
597
598        if "bool-parameters" in project_def:
599            params = XML.SubElement(
600                tconfigs, "hudson.plugins.parameterizedtrigger." "BooleanParameters"
601            )
602            configs = XML.SubElement(params, "configs")
603            for bool_param in project_def["bool-parameters"]:
604                param = XML.SubElement(
605                    configs,
606                    "hudson.plugins.parameterizedtrigger." "BooleanParameterConfig",
607                )
608                mapping = [("name", "name", None), ("value", "value", False)]
609                helpers.convert_mapping_to_xml(
610                    param, bool_param, mapping, fail_required=True
611                )
612
613        if "node-label-name" in project_def and "node-label" in project_def:
614            node = XML.SubElement(
615                tconfigs,
616                "org.jvnet.jenkins.plugins."
617                "nodelabelparameter.parameterizedtrigger."
618                "NodeLabelBuildParameter",
619            )
620            mapping = [
621                ("node-label-name", "name", None),
622                ("node-label", "nodeLabel", None),
623            ]
624            helpers.convert_mapping_to_xml(
625                node, project_def, mapping, fail_required=True
626            )
627
628        if "restrict-matrix-project" in project_def:
629            params = XML.SubElement(
630                tconfigs,
631                "hudson.plugins.parameterizedtrigger."
632                "matrix.MatrixSubsetBuildParameters",
633            )
634            mapping = [("restrict-matrix-project", "filter", None)]
635            helpers.convert_mapping_to_xml(
636                params, project_def, mapping, fail_required=True
637            )
638
639        if len(list(tconfigs)) == 0:
640            tconfigs.set("class", "java.util.Collections$EmptyList")
641
642        if "parameter-factories" in project_def:
643            fconfigs = XML.SubElement(tconfig, "configFactories")
644
645            supported_factories = [
646                "filebuild",
647                "binaryfile",
648                "counterbuild",
649                "allnodesforlabel",
650                "allonlinenodes",
651            ]
652            supported_actions = ["SKIP", "NOPARMS", "FAIL"]
653            for factory in project_def["parameter-factories"]:
654
655                if factory["factory"] not in supported_factories:
656                    raise InvalidAttributeError(
657                        "factory", factory["factory"], supported_factories
658                    )
659
660                if factory["factory"] == "filebuild":
661                    params = XML.SubElement(
662                        fconfigs,
663                        "hudson.plugins.parameterizedtrigger."
664                        "FileBuildParameterFactory",
665                    )
666                if factory["factory"] == "binaryfile":
667                    params = XML.SubElement(
668                        fconfigs,
669                        "hudson.plugins.parameterizedtrigger."
670                        "BinaryFileParameterFactory",
671                    )
672                    mapping = [("parameter-name", "parameterName", None)]
673                    helpers.convert_mapping_to_xml(
674                        params, factory, mapping, fail_required=True
675                    )
676
677                if (
678                    factory["factory"] == "filebuild"
679                    or factory["factory"] == "binaryfile"
680                ):
681                    mapping = [
682                        ("file-pattern", "filePattern", None),
683                        (
684                            "no-files-found-action",
685                            "noFilesFoundAction",
686                            "SKIP",
687                            supported_actions,
688                        ),
689                    ]
690                    helpers.convert_mapping_to_xml(
691                        params, factory, mapping, fail_required=True
692                    )
693
694                if factory["factory"] == "counterbuild":
695                    params = XML.SubElement(
696                        fconfigs,
697                        "hudson.plugins.parameterizedtrigger."
698                        "CounterBuildParameterFactory",
699                    )
700                    mapping = [
701                        ("from", "from", None),
702                        ("to", "to", None),
703                        ("step", "step", None),
704                        ("parameters", "paramExpr", ""),
705                        (
706                            "validation-fail",
707                            "validationFail",
708                            "FAIL",
709                            supported_actions,
710                        ),
711                    ]
712                    helpers.convert_mapping_to_xml(
713                        params, factory, mapping, fail_required=True
714                    )
715
716                if factory["factory"] == "allnodesforlabel":
717                    params = XML.SubElement(
718                        fconfigs,
719                        "org.jvnet.jenkins.plugins.nodelabelparameter."
720                        "parameterizedtrigger."
721                        "AllNodesForLabelBuildParameterFactory",
722                    )
723                    mapping = [
724                        ("name", "name", ""),
725                        ("node-label", "nodeLabel", None),
726                        ("ignore-offline-nodes", "ignoreOfflineNodes", True),
727                    ]
728                    helpers.convert_mapping_to_xml(
729                        params, factory, mapping, fail_required=True
730                    )
731
732                if factory["factory"] == "allonlinenodes":
733                    params = XML.SubElement(
734                        fconfigs,
735                        "org.jvnet.jenkins.plugins.nodelabelparameter."
736                        "parameterizedtrigger."
737                        "AllNodesBuildParameterFactory",
738                    )
739
740        projects = XML.SubElement(tconfig, "projects")
741        if isinstance(project_def["project"], list):
742            projects.text = ",".join(project_def["project"])
743        else:
744            projects.text = project_def["project"]
745
746        mapping = [
747            ("", "condition", "ALWAYS"),
748            ("", "triggerWithNoParameters", False),
749            ("", "buildAllNodesWithLabel", False),
750        ]
751        helpers.convert_mapping_to_xml(tconfig, {}, mapping, fail_required=True)
752
753        block = project_def.get("block", False)
754        if block:
755            block = XML.SubElement(tconfig, "block")
756            supported_thresholds = [
757                [
758                    "build-step-failure-threshold",
759                    "buildStepFailureThreshold",
760                    "FAILURE",
761                ],
762                ["unstable-threshold", "unstableThreshold", "UNSTABLE"],
763                ["failure-threshold", "failureThreshold", "FAILURE"],
764            ]
765            supported_threshold_values = [
766                "never",
767                hudson_model.SUCCESS["name"],
768                hudson_model.UNSTABLE["name"],
769                hudson_model.FAILURE["name"],
770            ]
771            thrsh = project_def.get("block-thresholds", False)
772            for toptname, txmltag, tvalue in supported_thresholds:
773                if thrsh:
774                    tvalue = thrsh.get(toptname, tvalue)
775                if tvalue.lower() == supported_threshold_values[0]:
776                    continue
777                if tvalue.upper() not in supported_threshold_values:
778                    raise InvalidAttributeError(
779                        toptname, tvalue, supported_threshold_values
780                    )
781                th = XML.SubElement(block, txmltag)
782                mapping = [
783                    ("name", "name", None),
784                    ("ordinal", "ordinal", None),
785                    ("color", "color", None),
786                    ("", "completeBuild", True),
787                ]
788                helpers.convert_mapping_to_xml(
789                    th,
790                    hudson_model.THRESHOLDS[tvalue.upper()],
791                    mapping,
792                    fail_required=True,
793                )
794
795    # If configs is empty, remove the entire tbuilder tree.
796    if len(configs) == 0:
797        logger.debug("Pruning empty TriggerBuilder tree.")
798        xml_parent.remove(tbuilder)
799
800
801def builders_from(registry, xml_parent, data):
802    """yaml: builders-from
803    Use builders from another project.
804
805    Requires the Jenkins :jenkins-plugins:`Template Project Plugin
806    <template-project>`.
807
808    :arg str projectName: the name of the other project
809
810    Example:
811
812    .. literalinclude:: ../../tests/builders/fixtures/builders-from.yaml
813       :language: yaml
814    """
815    pbs = XML.SubElement(xml_parent, "hudson.plugins.templateproject.ProxyBuilder")
816    mapping = [("", "projectName", data)]
817    helpers.convert_mapping_to_xml(pbs, {}, mapping, fail_required=True)
818
819
820def http_request(registry, xml_parent, data):
821    """yaml: http-request
822    This plugin sends a http request to an url with some parameters.
823
824    Requires the Jenkins :jenkins-plugins:`HTTP Request Plugin
825    <http_request>`.
826
827    :arg str url: Specify an URL to be requested (required)
828    :arg str mode: The http mode of the request (default GET)
829
830        :mode values:
831            * **GET**
832            * **POST**
833            * **PUT**
834            * **DELETE**
835            * **HEAD**
836    :arg str content-type: Add 'Content-type: foo' HTTP request headers
837        where foo is the http content-type the request is using.
838        (default NOT_SET)
839    :arg str accept-type: Add 'Accept: foo' HTTP request headers
840        where foo is the http content-type to accept (default NOT_SET)
841
842        :content-type and accept-type values:
843            * **NOT_SET**
844            * **TEXT_HTML**
845            * **APPLICATION_JSON**
846            * **APPLICATION_TAR**
847            * **APPLICATION_ZIP**
848            * **APPLICATION_OCTETSTREAM**
849    :arg str output-file: Name of the file in which to write response data
850        (default '')
851    :arg int time-out: Specify a timeout value in seconds (default 0)
852    :arg bool console-log: This allows you to turn off writing the response
853        body to the log (default false)
854    :arg bool pass-build: Should build parameters be passed to the URL
855        being called (default false)
856    :arg str valid-response-codes: Configure response code to mark an
857        execution as success. You can configure simple code such as "200"
858        or multiple codes separated by comma(',') e.g. "200,404,500"
859        Interval of codes should be in format From:To e.g. "100:399".
860        The default (as if empty) is to fail to 4xx and 5xx.
861        That means success from 100 to 399 "100:399"
862        To ignore any response code use "100:599". (default '')
863    :arg str valid-response-content: If set response must contain this string
864        to mark an execution as success (default '')
865    :arg str authentication-key: Authentication that will be used before this
866        request. Authentications are created in global configuration under a
867        key name that is selected here.
868    :arg list custom-headers: list of header parameters
869
870        :custom-header:
871            * **name** (`str`) -- Name of the header
872            * **value** (`str`) -- Value of the header
873
874    Example:
875
876    .. literalinclude:: ../../tests/builders/fixtures/http-request-minimal.yaml
877       :language: yaml
878
879    .. literalinclude::
880       ../../tests/builders/fixtures/http-request-full.yaml
881       :language: yaml
882    """
883
884    http_request = XML.SubElement(
885        xml_parent, "jenkins.plugins.http__request.HttpRequest"
886    )
887    http_request.set("plugin", "http_request")
888
889    valid_modes = ["GET", "POST", "PUT", "DELETE", "HEAD"]
890    valid_types = [
891        "NOT_SET",
892        "TEXT_HTML",
893        "APPLICATION_JSON",
894        "APPLICATION_TAR",
895        "APPLICATION_ZIP",
896        "APPLICATION_OCTETSTREAM",
897    ]
898
899    mappings = [
900        ("url", "url", None),
901        ("mode", "httpMode", "GET", valid_modes),
902        ("content-type", "contentType", "NOT_SET", valid_types),
903        ("accept-type", "acceptType", "NOT_SET", valid_types),
904        ("output-file", "outputFile", ""),
905        ("console-log", "consoleLogResponseBody", False),
906        ("pass-build", "passBuildParameters", False),
907        ("time-out", "timeout", 0),
908        ("valid-response-codes", "validResponseCodes", ""),
909        ("valid-response-content", "validResponseContent", ""),
910    ]
911    helpers.convert_mapping_to_xml(http_request, data, mappings, fail_required=True)
912
913    if "authentication-key" in data:
914        XML.SubElement(http_request, "authentication").text = data["authentication-key"]
915
916    if "custom-headers" in data:
917        customHeader = XML.SubElement(http_request, "customHeaders")
918        header_mappings = [("name", "name", None), ("value", "value", None)]
919        for customhead in data["custom-headers"]:
920            pair = XML.SubElement(customHeader, "pair")
921            helpers.convert_mapping_to_xml(
922                pair, customhead, header_mappings, fail_required=True
923            )
924
925
926def inject(registry, xml_parent, data):
927    """yaml: inject
928    Inject an environment for the job.
929
930    Requires the Jenkins :jenkins-plugins:`EnvInject Plugin <envinject>`.
931
932    :arg str properties-file: the name of the property file (optional)
933    :arg str properties-content: the properties content (optional)
934    :arg str script-file: the name of a script file to run (optional)
935    :arg str script-content: the script content (optional)
936
937    Example:
938
939    .. literalinclude:: ../../tests/builders/fixtures/inject.yaml
940       :language: yaml
941    """
942    eib = XML.SubElement(xml_parent, "EnvInjectBuilder")
943    info = XML.SubElement(eib, "info")
944    mapping = [
945        ("properties-file", "propertiesFilePath", None),
946        ("properties-content", "propertiesContent", None),
947        ("script-file", "scriptFilePath", None),
948        ("script-content", "scriptContent", None),
949    ]
950    helpers.convert_mapping_to_xml(info, data, mapping, fail_required=False)
951
952
953def kmap(registry, xml_parent, data):
954    """yaml: kmap
955    Publish mobile applications to your Keivox KMAP Private Mobile App Store.
956
957    Requires the Jenkins :jenkins-plugins:`Keivox KMAP Private Mobile App Store
958    Plugin <kmap-jenkins>`.
959
960    :arg str username: KMAP's user email with permissions to upload/publish
961        applications to KMAP (required)
962    :arg str password:  Password for the KMAP user uploading/publishing
963        applications (required)
964    :arg str url: KMAP's url. This url must always end with "/kmap-client/".
965        For example: http://testing.example.org/kmap-client/ (required)
966    :arg str categories: Categories' names. If you want to add the application
967        to more than one category, write the categories between commas.
968        (required)
969    :arg str file-path: Path to the application's file (required)
970    :arg str app-name: KMAP's application name (required)
971    :arg str bundle: Bundle indentifier (default '')
972    :arg str version: Application's version (required)
973    :arg str description: Application's description (default '')
974    :arg str icon-path: Path to the application's icon (default '')
975    :arg bool publish-optional: Publish application after it has been uploaded
976        to KMAP (default false)
977
978        :publish-optional:
979            * **groups** ('str') -- groups' names to publish the application
980                (default '')
981            * **users** ('str') -- users' names to publish the application
982                (default '')
983            * **notify-users** ('bool') -- Send notifications to the users and
984                groups when publishing the application (default false)
985
986    Minimal Example:
987
988    .. literalinclude:: ../../tests/builders/fixtures/kmap-minimal.yaml
989       :language: yaml
990
991    Full Example:
992
993    .. literalinclude:: ../../tests/builders/fixtures/kmap-full.yaml
994       :language: yaml
995    """
996    kmap = XML.SubElement(xml_parent, "org.jenkinsci.plugins.KmapJenkinsBuilder")
997
998    kmap.set("plugin", "kmap-jenkins")
999    publish = data.get("publish-optional", False)
1000
1001    mapping = [
1002        ("username", "username", None),
1003        ("password", "password", None),
1004        ("url", "kmapClient", None),
1005        ("categories", "categories", None),
1006        ("file-path", "filePath", None),
1007        ("app-name", "appName", None),
1008        ("bundle", "bundle", ""),
1009        ("version", "version", None),
1010        ("description", "description", ""),
1011        ("icon-path", "iconPath", ""),
1012    ]
1013    helpers.convert_mapping_to_xml(kmap, data, mapping, fail_required=True)
1014
1015    if publish is True:
1016        publish_optional = XML.SubElement(kmap, "publishOptional")
1017        publish_mapping = [
1018            ("groups", "teams", ""),
1019            ("users", "users", ""),
1020            ("notify-users", "sendNotifications", False),
1021        ]
1022        helpers.convert_mapping_to_xml(
1023            publish_optional, data, publish_mapping, fail_required=True
1024        )
1025
1026
1027def artifact_resolver(registry, xml_parent, data):
1028    """yaml: artifact-resolver
1029    Allows one to resolve artifacts from a maven repository like nexus
1030    (without having maven installed)
1031
1032    Requires the Jenkins :jenkins-plugins:`Repository Connector Plugin
1033    <repository-connector>`.
1034
1035    :arg bool fail-on-error: Whether to fail the build on error (default false)
1036    :arg bool repository-logging: Enable repository logging (default false)
1037    :arg str target-directory: Where to resolve artifacts to (required)
1038    :arg list artifacts: list of artifacts to resolve
1039
1040        :Artifact:
1041            * **group-id** (`str`) -- Group ID of the artifact (required)
1042            * **artifact-id** (`str`) -- Artifact ID of the artifact (required)
1043            * **version** (`str`) -- Version of the artifact (required)
1044            * **classifier** (`str`) -- Classifier of the artifact (default '')
1045            * **extension** (`str`) -- Extension of the artifact
1046              (default 'jar')
1047            * **target-file-name** (`str`) -- What to name the artifact
1048              (default '')
1049
1050    Minimal Example:
1051
1052    .. literalinclude::
1053        ../../tests/builders/fixtures/artifact-resolver-minimal.yaml
1054       :language: yaml
1055
1056    Full Example:
1057
1058    .. literalinclude::
1059        ../../tests/builders/fixtures/artifact-resolver-full.yaml
1060       :language: yaml
1061    """
1062    ar = XML.SubElement(
1063        xml_parent, "org.jvnet.hudson.plugins.repositoryconnector.ArtifactResolver"
1064    )
1065    mapping = [
1066        ("target-directory", "targetDirectory", None),
1067        ("fail-on-error", "failOnError", False),
1068        ("repository-logging", "enableRepoLogging", False),
1069        ("", "snapshotUpdatePolicy", "never"),
1070        ("", "releaseUpdatePolicy", "never"),
1071        ("", "snapshotChecksumPolicy", "warn"),
1072        ("", "releaseChecksumPolicy", "warn"),
1073    ]
1074    helpers.convert_mapping_to_xml(ar, data, mapping, fail_required=True)
1075
1076    artifact_top = XML.SubElement(ar, "artifacts")
1077    artifacts = data["artifacts"]
1078    artifacts_mapping = [
1079        ("group-id", "groupId", None),
1080        ("artifact-id", "artifactId", None),
1081        ("version", "version", None),
1082        ("classifier", "classifier", ""),
1083        ("extension", "extension", "jar"),
1084        ("target-file-name", "targetFileName", ""),
1085    ]
1086    for artifact in artifacts:
1087        rcartifact = XML.SubElement(
1088            artifact_top, "org.jvnet.hudson.plugins.repositoryconnector.Artifact"
1089        )
1090        helpers.convert_mapping_to_xml(
1091            rcartifact, artifact, artifacts_mapping, fail_required=True
1092        )
1093
1094
1095def doxygen(registry, xml_parent, data):
1096    """yaml: doxygen
1097    Builds doxygen HTML documentation.
1098
1099    Requires the Jenkins :jenkins-plugins:`Doxygen plugin <doxygen>`.
1100
1101    :arg str doxyfile: The doxyfile path (required)
1102    :arg str install: The doxygen installation to use (required)
1103    :arg bool ignore-failure: Keep executing build even on doxygen generation
1104        failure (default false)
1105    :arg bool unstable-warning: Mark the build as unstable if warnings are
1106        generated (default false)
1107
1108    Example:
1109
1110    .. literalinclude:: /../../tests/builders/fixtures/doxygen001.yaml
1111       :language: yaml
1112
1113    """
1114    doxygen = XML.SubElement(xml_parent, "hudson.plugins.doxygen.DoxygenBuilder")
1115    mappings = [
1116        ("doxyfile", "doxyfilePath", None),
1117        ("install", "installationName", None),
1118        ("ignore-failure", "continueOnBuildFailure", False),
1119        ("unstable-warning", "unstableIfWarnings", False),
1120    ]
1121    helpers.convert_mapping_to_xml(doxygen, data, mappings, fail_required=True)
1122
1123
1124def gradle(registry, xml_parent, data):
1125    """yaml: gradle
1126    Execute gradle tasks.
1127
1128    Requires the Jenkins :jenkins-plugins:`Gradle Plugin <gradle>`.
1129
1130    :arg str tasks: List of tasks to execute
1131    :arg str gradle-name: Use a custom gradle name (default '')
1132    :arg bool wrapper: use gradle wrapper (default false)
1133    :arg bool executable: make gradlew executable (default false)
1134    :arg list switches: Switches for gradle, can have multiples
1135    :arg bool use-root-dir: Whether to run the gradle script from the
1136        top level directory or from a different location (default false)
1137    :arg str root-build-script-dir: If your workspace has the
1138        top-level build.gradle in somewhere other than the module
1139        root directory, specify the path (relative to the module
1140        root) here, such as ${workspace}/parent/ instead of just
1141        ${workspace}.
1142    :arg str build-file: name of gradle build script (default 'build.gradle')
1143    :arg bool pass-system-properties: Pass all parameters as
1144        System properties (default false)
1145    :arg bool pass-project-properties: Pass all parameters as
1146        Project properties (default false)
1147
1148    Example:
1149
1150    .. literalinclude:: ../../tests/builders/fixtures/gradle.yaml
1151       :language: yaml
1152    """
1153    gradle = XML.SubElement(xml_parent, "hudson.plugins.gradle.Gradle")
1154
1155    XML.SubElement(gradle, "description").text = ""
1156
1157    mappings = [
1158        ("build-file", "buildFile", "build.gradle"),
1159        ("tasks", "tasks", None),
1160        ("root-build-script-dir", "rootBuildScriptDir", ""),
1161        ("gradle-name", "gradleName", ""),
1162        ("wrapper", "useWrapper", False),
1163        ("executable", "makeExecutable", False),
1164        ("use-root-dir", "fromRootBuildScriptDir", False),
1165        ("pass-system-properties", "passAllAsSystemProperties", False),
1166        ("pass-project-properties", "passAllAsProjectProperties", False),
1167    ]
1168    helpers.convert_mapping_to_xml(gradle, data, mappings, fail_required=True)
1169
1170    XML.SubElement(gradle, "switches").text = "\n".join(data.get("switches", []))
1171
1172
1173def _groovy_common_scriptSource(data):
1174    """Helper function to generate the XML element common to groovy builders."""
1175
1176    scriptSource = XML.Element("scriptSource")
1177    if "command" in data and "file" in data:
1178        raise JenkinsJobsException("Use just one of 'command' or 'file'")
1179
1180    if "command" in data:
1181        mapping = [("command", "command", None)]
1182        helpers.convert_mapping_to_xml(scriptSource, data, mapping, fail_required=True)
1183        scriptSource.set("class", "hudson.plugins.groovy.StringScriptSource")
1184    elif "file" in data:
1185        mapping = [("file", "scriptFile", None)]
1186        helpers.convert_mapping_to_xml(scriptSource, data, mapping, fail_required=True)
1187        scriptSource.set("class", "hudson.plugins.groovy.FileScriptSource")
1188    else:
1189        raise JenkinsJobsException("A groovy command or file is required")
1190
1191    return scriptSource
1192
1193
1194def groovy(registry, xml_parent, data):
1195    """yaml: groovy
1196    Execute a groovy script or command.
1197
1198    Requires the Jenkins :jenkins-plugins:`Groovy Plugin <groovy>`.
1199
1200    :arg str file: Groovy file to run. (Alternative: you can chose a command
1201        instead)
1202    :arg str command: Groovy command to run. (Alternative: you can chose a
1203        script file instead)
1204    :arg str version: Groovy version to use. (default '(Default)')
1205    :arg str parameters: Parameters for the Groovy executable. (default '')
1206    :arg str script-parameters: These parameters will be passed to the script.
1207        (default '')
1208    :arg str properties: Instead of passing properties using the -D parameter
1209        you can define them here. (default '')
1210    :arg str java-opts: Direct access to JAVA_OPTS. Properties allows only
1211        -D properties, while sometimes also other properties like -XX need to
1212        be setup. It can be done here. This line is appended at the end of
1213        JAVA_OPTS string. (default '')
1214    :arg str class-path: Specify script classpath here. Each line is one
1215        class path item. (default '')
1216
1217    Minimal Example:
1218
1219    .. literalinclude:: ../../tests/builders/fixtures/groovy-minimal.yaml
1220       :language: yaml
1221
1222
1223    Full Example:
1224
1225    .. literalinclude:: ../../tests/builders/fixtures/groovy-full.yaml
1226       :language: yaml
1227    """
1228
1229    root_tag = "hudson.plugins.groovy.Groovy"
1230    groovy = XML.SubElement(xml_parent, root_tag)
1231    groovy.append(_groovy_common_scriptSource(data))
1232
1233    mappings = [
1234        ("version", "groovyName", "(Default)"),
1235        ("parameters", "parameters", ""),
1236        ("script-parameters", "scriptParameters", ""),
1237        ("properties", "properties", ""),
1238        ("java-opts", "javaOpts", ""),
1239        ("class-path", "classPath", ""),
1240    ]
1241    helpers.convert_mapping_to_xml(groovy, data, mappings, fail_required=True)
1242
1243
1244def system_groovy(registry, xml_parent, data):
1245    """yaml: system-groovy
1246    Execute a system groovy script or command.
1247
1248    Requires the Jenkins :jenkins-plugins:`Groovy Plugin <groovy>`.
1249
1250    :arg str file: Groovy file to run. (Alternative: you can chose a command
1251        instead)
1252    :arg str command: Groovy command to run. (Alternative: you can choose a
1253        script file instead)
1254    :arg bool sandbox: Execute script inside of groovy sandbox (>=2.0)
1255        (default false)
1256    :arg str bindings: Define variable bindings (in the properties file
1257        format). Specified variables can be addressed from the script.
1258        (optional)
1259    :arg (list str) class-path: List of script class paths.
1260        (optional)
1261
1262    Examples:
1263
1264    .. literalinclude:: ../../tests/builders/fixtures/system-groovy001.yaml
1265       :language: yaml
1266    .. literalinclude:: ../../tests/builders/fixtures/system-groovy002.yaml
1267       :language: yaml
1268    """
1269    root_tag = "hudson.plugins.groovy.SystemGroovy"
1270    sysgroovy = XML.SubElement(xml_parent, root_tag)
1271    if "file" in data:
1272        scriptSource = _groovy_common_scriptSource(data)
1273    if "command" in data:
1274        scriptSource = XML.Element("source")
1275        scriptSource.set("class", "hudson.plugins.groovy.StringSystemScriptSource")
1276        script = XML.SubElement(scriptSource, "script")
1277        mapping = [("command", "script", None), ("sandbox", "sandbox", False)]
1278        helpers.convert_mapping_to_xml(script, data, mapping, fail_required=True)
1279        classpath = XML.SubElement(script, "classpath")
1280        classpaths = data.get("class-path", [])
1281        if isinstance(classpaths, str):
1282            classpaths = [classpaths]
1283        for path in classpaths:
1284            entry = XML.SubElement(classpath, "entry")
1285            XML.SubElement(entry, "url").text = path
1286    sysgroovy.append(scriptSource)
1287    mapping = [("bindings", "bindings", "")]
1288    helpers.convert_mapping_to_xml(sysgroovy, data, mapping, fail_required=True)
1289
1290
1291def batch(registry, xml_parent, data):
1292    """yaml: batch
1293    Execute a batch command.
1294
1295    :Parameter: the batch command to execute
1296
1297    Example:
1298
1299    .. literalinclude:: ../../tests/builders/fixtures/batch.yaml
1300       :language: yaml
1301    """
1302    batch = XML.SubElement(xml_parent, "hudson.tasks.BatchFile")
1303    XML.SubElement(batch, "command").text = data
1304
1305
1306def powershell(registry, xml_parent, data):
1307    """yaml: powershell
1308    Execute a powershell command.
1309
1310    Requires the :jenkins-plugins:`Powershell Plugin <powershell>`.
1311
1312    :Parameter: the powershell command to execute
1313
1314    Example:
1315
1316    .. literalinclude:: ../../tests/builders/fixtures/powershell.yaml
1317       :language: yaml
1318    """
1319    ps = XML.SubElement(xml_parent, "hudson.plugins.powershell.PowerShell")
1320    XML.SubElement(ps, "command").text = data
1321
1322
1323def msbuild(registry, xml_parent, data):
1324    """yaml: msbuild
1325    Build .NET project using msbuild.
1326
1327    Requires the Jenkins :jenkins-plugins:'MSBuild Plugin <msbuild>`.
1328
1329    :arg str msbuild-version: which msbuild configured in Jenkins to use
1330        (default '(Default)')
1331    :arg str solution-file: location of the solution file to build (required)
1332    :arg str extra-parameters: extra parameters to pass to msbuild (default '')
1333    :arg bool pass-build-variables: should build variables be passed
1334        to msbuild (default true)
1335    :arg bool continue-on-build-failure: should the build continue if
1336        msbuild returns an error (default false)
1337    :arg bool unstable-if-warnings: If set to true and warnings on compilation,
1338        the build will be unstable (>=1.20) (default false)
1339
1340    Full Example:
1341
1342    .. literalinclude:: ../../tests/builders/fixtures/msbuild-full.yaml
1343       :language: yaml
1344
1345    Minimal Example:
1346
1347    .. literalinclude:: ../../tests/builders/fixtures/msbuild-minimal.yaml
1348       :language: yaml
1349    """
1350    msbuilder = XML.SubElement(xml_parent, "hudson.plugins.msbuild.MsBuildBuilder")
1351    msbuilder.set("plugin", "msbuild")
1352
1353    mapping = [
1354        ("msbuild-version", "msBuildName", "(Default)"),
1355        ("solution-file", "msBuildFile", None),
1356        ("extra-parameters", "cmdLineArgs", ""),
1357        ("pass-build-variables", "buildVariablesAsProperties", True),
1358        ("continue-on-build-failure", "continueOnBuildFailure", False),
1359        ("unstable-if-warnings", "unstableIfWarnings", False),
1360    ]
1361    helpers.convert_mapping_to_xml(msbuilder, data, mapping, fail_required=True)
1362
1363
1364def create_builders(registry, step):
1365    dummy_parent = XML.Element("dummy")
1366    registry.dispatch("builder", dummy_parent, step)
1367    return list(dummy_parent)
1368
1369
1370def conditional_step(registry, xml_parent, data):
1371    """yaml: conditional-step
1372    Conditionally execute some build steps.
1373
1374    Requires the Jenkins :jenkins-plugins:`Conditional BuildStep Plugin
1375    <conditional-buildstep>`.
1376
1377    Depending on the number of declared steps, a `Conditional step (single)`
1378    or a `Conditional steps (multiple)` is created in Jenkins.
1379
1380    :arg str condition-kind: Condition kind that must be verified before the
1381        steps are executed. Valid values and their additional attributes are
1382        described in the conditions_ table.
1383    :arg str on-evaluation-failure: What should be the outcome of the build
1384        if the evaluation of the condition fails. Possible values are `fail`,
1385        `mark-unstable`, `run-and-mark-unstable`, `run` and `dont-run`.
1386        (default 'fail').
1387    :arg list steps: List of steps to run if the condition is verified. Items
1388        in the list can be any builder known by Jenkins Job Builder.
1389
1390    .. _conditions:
1391
1392    ================== ====================================================
1393    Condition kind     Description
1394    ================== ====================================================
1395    always             Condition is always verified
1396    never              Condition is never verified
1397    boolean-expression Run the step if the expression expends to a
1398                       representation of true
1399
1400                         :condition-expression: Expression to expand (required)
1401    build-cause        Run if the current build has a specific cause
1402
1403                         :cause: The cause why the build was triggered.
1404                           Following causes are supported -
1405
1406                           :USER_CAUSE: build was triggered by a manual
1407                             interaction. (default)
1408                           :SCM_CAUSE: build was triggered by a SCM change.
1409                           :TIMER_CAUSE: build was triggered by a timer.
1410                           :CLI_CAUSE: build was triggered by via CLI interface
1411                           :REMOTE_CAUSE: build was triggered via remote
1412                             interface.
1413                           :UPSTREAM_CAUSE: build was triggered by an upstream
1414                             project.
1415
1416                           Following supported if XTrigger plugin installed:
1417
1418                           :FS_CAUSE: build was triggered by a file system
1419                             change (FSTrigger Plugin).
1420                           :URL_CAUSE: build was triggered by a URL change
1421                             (URLTrigger Plugin)
1422                           :IVY_CAUSE: build triggered by an Ivy dependency
1423                             version has change (IvyTrigger Plugin)
1424                           :SCRIPT_CAUSE: build was triggered by a script
1425                             (ScriptTrigger Plugin)
1426                           :BUILDRESULT_CAUSE: build was triggered by a
1427                             result of another job (BuildResultTrigger Plugin)
1428                         :exclusive-cause: (bool) There might by multiple
1429                           causes causing a build to be triggered, with
1430                           this true, the cause must be the only one
1431                           causing this build this build to be triggered.
1432                           (default false)
1433    day-of-week        Only run on specific days of the week.
1434
1435                         :day-selector: Days you want the build to run on.
1436                           Following values are supported -
1437
1438                           :weekend: Saturday and Sunday (default).
1439                           :weekday: Monday - Friday.
1440                           :select-days: Selected days, defined by 'days'
1441                             below.
1442                           :days: True for days for which the build should
1443                             run. Definition needed only for 'select-days'
1444                             day-selector, at the same level as day-selector.
1445                             Define the days to run under this.
1446
1447                             :SUN: Run on Sunday (default false)
1448                             :MON: Run on Monday (default false)
1449                             :TUES: Run on Tuesday (default false)
1450                             :WED: Run on Wednesday (default false)
1451                             :THURS: Run on Thursday (default false)
1452                             :FRI: Run on Friday (default false)
1453                             :SAT: Run on Saturday (default false)
1454                         :use-build-time: (bool) Use the build time instead of
1455                           the the time that the condition is evaluated.
1456                           (default false)
1457    execution-node     Run only on selected nodes.
1458
1459                         :nodes: (list) List of nodes to execute on. (required)
1460    strings-match      Run the step if two strings match
1461
1462                         :condition-string1: First string (optional)
1463                         :condition-string2: Second string (optional)
1464                         :condition-case-insensitive: Case insensitive
1465                           (default false)
1466    current-status     Run the build step if the current build status is
1467                       within the configured range
1468
1469                         :condition-worst: Accepted values are SUCCESS,
1470                           UNSTABLE, FAILURE, NOT_BUILD, ABORTED
1471                           (default SUCCESS)
1472                         :condition-best: Accepted values are SUCCESS,
1473                           UNSTABLE, FAILURE, NOT_BUILD, ABORTED
1474                           (default SUCCESS)
1475
1476    shell              Run the step if the shell command succeed
1477
1478                         :condition-command: Shell command to execute
1479                           (optional)
1480    windows-shell      Similar to shell, except that commands will be
1481                       executed by cmd, under Windows
1482
1483                         :condition-command: Command to execute (optional)
1484    file-exists        Run the step if a file exists
1485
1486                         :condition-filename: Check existence of this file
1487                           (required)
1488                         :condition-basedir: If condition-filename is
1489                           relative, it will be considered relative to
1490                           either `workspace`, `artifact-directory`,
1491                           or `jenkins-home`. (default 'workspace')
1492    files-match        Run if one or more files match the selectors.
1493
1494                         :include-pattern: (list str) List of Includes
1495                           Patterns. Since the separator in the patterns is
1496                           hardcoded as ',', any use of ',' would need
1497                           escaping. (optional)
1498                         :exclude-pattern: (list str) List of Excludes
1499                           Patterns. Since the separator in the patterns is
1500                           hardcoded as ',', any use of ',' would need
1501                           escaping. (optional)
1502                         :condition-basedir: Accepted values are `workspace`,
1503                           `artifact-directory`, or `jenkins-home`.
1504                           (default 'workspace')
1505    num-comp           Run if the numerical comparison is true.
1506
1507                         :lhs: Left Hand Side. Must evaluate to a number.
1508                           (required)
1509                         :rhs: Right Hand Side. Must evaluate to a number.
1510                           (required)
1511                         :comparator: Accepted values are `less-than`,
1512                           `greater-than`, `equal`, `not-equal`,
1513                           `less-than-equal`, `greater-than-equal`.
1514                           (default 'less-than')
1515    regex-match        Run if the Expression matches the Label.
1516
1517                         :regex: The regular expression used to match the label
1518                           (optional)
1519                         :label: The label that will be tested by the regular
1520                           expression. (optional)
1521    time               Only run during a certain period of the day.
1522
1523                         :earliest-hour: Starting hour (default "09")
1524                         :earliest-min: Starting min (default "00")
1525                         :latest-hour: Ending hour (default "17")
1526                         :latest-min: Ending min (default "30")
1527                         :use-build-time: (bool) Use the build time instead of
1528                           the the time that the condition is evaluated.
1529                           (default false)
1530    not                Run the step if the inverse of the condition-operand
1531                       is true
1532
1533                         :condition-operand: Condition to evaluate.  Can be
1534                           any supported conditional-step condition. (required)
1535    and                Run the step if logical and of all conditional-operands
1536                       is true
1537
1538                         :condition-operands: (list) Conditions to evaluate.
1539                           Can be any supported conditional-step condition.
1540                           (required)
1541    or                 Run the step if logical or of all conditional-operands
1542                       is true
1543
1544                         :condition-operands: (list) Conditions to evaluate.
1545                           Can be any supported conditional-step condition.
1546                           (required)
1547    ================== ====================================================
1548
1549    Examples:
1550
1551    .. literalinclude::
1552        /../../tests/builders/fixtures/conditional-step-multiple-steps.yaml
1553       :language: yaml
1554    .. literalinclude::
1555        /../../tests/builders/fixtures/conditional-step-success-failure.yaml
1556       :language: yaml
1557    .. literalinclude::
1558        /../../tests/builders/fixtures/conditional-step-not-file-exists.yaml
1559       :language: yaml
1560    .. literalinclude::
1561        /../../tests/builders/fixtures/conditional-step-day-of-week001.yaml
1562       :language: yaml
1563    .. literalinclude::
1564        /../../tests/builders/fixtures/conditional-step-day-of-week003.yaml
1565       :language: yaml
1566    .. literalinclude::
1567        /../../tests/builders/fixtures/conditional-step-time.yaml
1568       :language: yaml
1569    .. literalinclude::
1570        /../../tests/builders/fixtures/conditional-step-regex-match.yaml
1571       :language: yaml
1572    .. literalinclude::
1573        /../../tests/builders/fixtures/conditional-step-or.yaml
1574       :language: yaml
1575    .. literalinclude::
1576        /../../tests/builders/fixtures/conditional-step-and.yaml
1577       :language: yaml
1578    """
1579
1580    def build_condition(cdata, cond_root_tag, condition_tag):
1581        kind = cdata["condition-kind"]
1582        ctag = XML.SubElement(cond_root_tag, condition_tag)
1583        core_prefix = "org.jenkins_ci.plugins.run_condition.core."
1584        logic_prefix = "org.jenkins_ci.plugins.run_condition.logic."
1585        if kind == "always":
1586            ctag.set("class", core_prefix + "AlwaysRun")
1587        elif kind == "never":
1588            ctag.set("class", core_prefix + "NeverRun")
1589        elif kind == "boolean-expression":
1590            ctag.set("class", core_prefix + "BooleanCondition")
1591            mapping = [("condition-expression", "token", None)]
1592            helpers.convert_mapping_to_xml(ctag, cdata, mapping, fail_required=True)
1593        elif kind == "build-cause":
1594            ctag.set("class", core_prefix + "CauseCondition")
1595            cause_list = (
1596                "USER_CAUSE",
1597                "SCM_CAUSE",
1598                "TIMER_CAUSE",
1599                "CLI_CAUSE",
1600                "REMOTE_CAUSE",
1601                "UPSTREAM_CAUSE",
1602                "FS_CAUSE",
1603                "URL_CAUSE",
1604                "IVY_CAUSE",
1605                "SCRIPT_CAUSE",
1606                "BUILDRESULT_CAUSE",
1607            )
1608            mapping = [
1609                ("cause", "buildCause", "USER_CAUSE", cause_list),
1610                ("exclusive-cause", "exclusiveCause", False),
1611            ]
1612            helpers.convert_mapping_to_xml(ctag, cdata, mapping, fail_required=True)
1613        elif kind == "day-of-week":
1614            ctag.set("class", core_prefix + "DayCondition")
1615            day_selector_class_prefix = core_prefix + "DayCondition$"
1616            day_selector_classes = {
1617                "weekend": day_selector_class_prefix + "Weekend",
1618                "weekday": day_selector_class_prefix + "Weekday",
1619                "select-days": day_selector_class_prefix + "SelectDays",
1620            }
1621            day_selector = cdata.get("day-selector", "weekend")
1622            if day_selector not in day_selector_classes:
1623                raise InvalidAttributeError(
1624                    "day-selector", day_selector, day_selector_classes
1625                )
1626            day_selector_tag = XML.SubElement(ctag, "daySelector")
1627            day_selector_tag.set("class", day_selector_classes[day_selector])
1628            if day_selector == "select-days":
1629                days_tag = XML.SubElement(day_selector_tag, "days")
1630                day_tag_text = (
1631                    "org.jenkins__ci.plugins.run__condition." "core.DayCondition_-Day"
1632                )
1633                inp_days = cdata.get("days") if cdata.get("days") else {}
1634                days = ["SUN", "MON", "TUES", "WED", "THURS", "FRI", "SAT"]
1635                for day_no, day in enumerate(days, 1):
1636                    day_tag = XML.SubElement(days_tag, day_tag_text)
1637                    mapping = [("", "day", day_no), (day, "selected", False)]
1638                    helpers.convert_mapping_to_xml(
1639                        day_tag, inp_days, mapping, fail_required=True
1640                    )
1641            mapping = [("use-build-time", "useBuildTime", False)]
1642            helpers.convert_mapping_to_xml(ctag, cdata, mapping, fail_required=True)
1643        elif kind == "execution-node":
1644            ctag.set("class", core_prefix + "NodeCondition")
1645            allowed_nodes_tag = XML.SubElement(ctag, "allowedNodes")
1646            for node in cdata["nodes"]:
1647                mapping = [("", "string", node)]
1648                helpers.convert_mapping_to_xml(
1649                    allowed_nodes_tag, cdata, mapping, fail_required=True
1650                )
1651        elif kind == "strings-match":
1652            ctag.set("class", core_prefix + "StringsMatchCondition")
1653            mapping = [
1654                ("condition-string1", "arg1", ""),
1655                ("condition-string2", "arg2", ""),
1656                ("condition-case-insensitive", "ignoreCase", False),
1657            ]
1658            helpers.convert_mapping_to_xml(ctag, cdata, mapping, fail_required=True)
1659        elif kind == "current-status":
1660            ctag.set("class", core_prefix + "StatusCondition")
1661            wr = XML.SubElement(ctag, "worstResult")
1662            wr_name = cdata.get("condition-worst", "SUCCESS")
1663            if wr_name not in hudson_model.THRESHOLDS:
1664                raise InvalidAttributeError(
1665                    "condition-worst", wr_name, hudson_model.THRESHOLDS.keys()
1666                )
1667            wr_threshold = hudson_model.THRESHOLDS[wr_name]
1668            mapping = [
1669                ("name", "name", None),
1670                ("ordinal", "ordinal", None),
1671                ("color", "color", "color"),
1672                ("complete", "completeBuild", None),
1673            ]
1674            helpers.convert_mapping_to_xml(
1675                wr, wr_threshold, mapping, fail_required=True
1676            )
1677            br = XML.SubElement(ctag, "bestResult")
1678            br_name = cdata.get("condition-best", "SUCCESS")
1679            if br_name not in hudson_model.THRESHOLDS:
1680                raise InvalidAttributeError(
1681                    "condition-best", br_name, hudson_model.THRESHOLDS.keys()
1682                )
1683            br_threshold = hudson_model.THRESHOLDS[br_name]
1684            mapping = [
1685                ("name", "name", None),
1686                ("ordinal", "ordinal", None),
1687                ("color", "color", "color"),
1688                ("complete", "completeBuild", None),
1689            ]
1690            helpers.convert_mapping_to_xml(
1691                br, br_threshold, mapping, fail_required=True
1692            )
1693        elif kind == "shell":
1694            ctag.set(
1695                "class",
1696                "org.jenkins_ci.plugins.run_condition.contributed." "ShellCondition",
1697            )
1698            mapping = [("condition-command", "command", "")]
1699            helpers.convert_mapping_to_xml(ctag, cdata, mapping, fail_required=True)
1700        elif kind == "windows-shell":
1701            ctag.set(
1702                "class",
1703                "org.jenkins_ci.plugins.run_condition.contributed."
1704                "BatchFileCondition",
1705            )
1706            mapping = [("condition-command", "command", "")]
1707            helpers.convert_mapping_to_xml(ctag, cdata, mapping, fail_required=True)
1708        elif kind == "file-exists" or kind == "files-match":
1709            if kind == "file-exists":
1710                ctag.set("class", core_prefix + "FileExistsCondition")
1711                mapping = [("condition-filename", "file", None)]
1712                helpers.convert_mapping_to_xml(ctag, cdata, mapping, fail_required=True)
1713            else:
1714                ctag.set("class", core_prefix + "FilesMatchCondition")
1715                XML.SubElement(ctag, "includes").text = ",".join(
1716                    cdata.get("include-pattern", "")
1717                )
1718                XML.SubElement(ctag, "excludes").text = ",".join(
1719                    cdata.get("exclude-pattern", "")
1720                )
1721            basedir_class_prefix = (
1722                "org.jenkins_ci.plugins.run_condition." "common.BaseDirectory$"
1723            )
1724            basedir_classes = {
1725                "workspace": basedir_class_prefix + "Workspace",
1726                "artifact-directory": basedir_class_prefix + "ArtifactsDir",
1727                "jenkins-home": basedir_class_prefix + "JenkinsHome",
1728            }
1729            basedir = cdata.get("condition-basedir", "workspace")
1730            if basedir not in basedir_classes:
1731                raise InvalidAttributeError(
1732                    "condition-basedir", basedir, basedir_classes
1733                )
1734            XML.SubElement(ctag, "baseDir").set("class", basedir_classes[basedir])
1735        elif kind == "num-comp":
1736            ctag.set("class", core_prefix + "NumericalComparisonCondition")
1737            mapping = [("lhs", "lhs", None), ("rhs", "rhs", None)]
1738            helpers.convert_mapping_to_xml(ctag, cdata, mapping, fail_required=True)
1739            comp_class_prefix = core_prefix + "NumericalComparisonCondition$"
1740            comp_classes = {
1741                "less-than": comp_class_prefix + "LessThan",
1742                "greater-than": comp_class_prefix + "GreaterThan",
1743                "equal": comp_class_prefix + "EqualTo",
1744                "not-equal": comp_class_prefix + "NotEqualTo",
1745                "less-than-equal": comp_class_prefix + "LessThanOrEqualTo",
1746                "greater-than-equal": comp_class_prefix + "GreaterThanOrEqualTo",
1747            }
1748            comp = cdata.get("comparator", "less-than")
1749            if comp not in comp_classes:
1750                raise InvalidAttributeError("comparator", comp, comp_classes)
1751            XML.SubElement(ctag, "comparator").set("class", comp_classes[comp])
1752        elif kind == "regex-match":
1753            ctag.set("class", core_prefix + "ExpressionCondition")
1754            mapping = [("regex", "expression", ""), ("label", "label", "")]
1755            helpers.convert_mapping_to_xml(ctag, cdata, mapping, fail_required=True)
1756        elif kind == "time":
1757            ctag.set("class", core_prefix + "TimeCondition")
1758            mapping = [
1759                ("earliest-hour", "earliestHours", "09"),
1760                ("earliest-min", "earliestMinutes", "00"),
1761                ("latest-hour", "latestHours", "17"),
1762                ("latest-min", "latestMinutes", "30"),
1763                ("use-build-time", "useBuildTime", False),
1764            ]
1765            helpers.convert_mapping_to_xml(ctag, cdata, mapping, fail_required=True)
1766        elif kind == "not":
1767            ctag.set("class", logic_prefix + "Not")
1768            try:
1769                notcondition = cdata["condition-operand"]
1770            except KeyError:
1771                raise MissingAttributeError("condition-operand")
1772            build_condition(notcondition, ctag, "condition")
1773        elif kind == "and" or "or":
1774            if kind == "and":
1775                ctag.set("class", logic_prefix + "And")
1776            else:
1777                ctag.set("class", logic_prefix + "Or")
1778            conditions_tag = XML.SubElement(ctag, "conditions")
1779            container_tag_text = (
1780                "org.jenkins__ci.plugins.run__condition." "logic.ConditionContainer"
1781            )
1782            try:
1783                conditions_list = cdata["condition-operands"]
1784            except KeyError:
1785                raise MissingAttributeError("condition-operands")
1786            for condition in conditions_list:
1787                conditions_container_tag = XML.SubElement(
1788                    conditions_tag, container_tag_text
1789                )
1790                build_condition(condition, conditions_container_tag, "condition")
1791
1792    cond_builder_tag = (
1793        "org.jenkinsci.plugins.conditionalbuildstep."
1794        "singlestep.SingleConditionalBuilder"
1795    )
1796    cond_builders_tag = (
1797        "org.jenkinsci.plugins.conditionalbuildstep." "ConditionalBuilder"
1798    )
1799    # A builder could be a macro, so it's required to create builders at first
1800    # to set `has_multiple_steps` flag correctly.
1801    edited_nodes = [
1802        edited_node
1803        for step in data["steps"]
1804        for edited_node in create_builders(registry, step)
1805    ]
1806    has_multiple_steps = len(edited_nodes) > 1
1807
1808    if has_multiple_steps:
1809        root_tag = XML.SubElement(xml_parent, cond_builders_tag)
1810        steps_parent = XML.SubElement(root_tag, "conditionalbuilders")
1811        condition_tag = "runCondition"
1812    else:
1813        root_tag = XML.SubElement(xml_parent, cond_builder_tag)
1814        steps_parent = root_tag
1815        condition_tag = "condition"
1816
1817    build_condition(data, root_tag, condition_tag)
1818    evaluation_classes_pkg = "org.jenkins_ci.plugins.run_condition"
1819    evaluation_classes = {
1820        "fail": evaluation_classes_pkg + ".BuildStepRunner$Fail",
1821        "mark-unstable": evaluation_classes_pkg + ".BuildStepRunner$Unstable",
1822        "run-and-mark-unstable": evaluation_classes_pkg
1823        + ".BuildStepRunner$RunUnstable",
1824        "run": evaluation_classes_pkg + ".BuildStepRunner$Run",
1825        "dont-run": evaluation_classes_pkg + ".BuildStepRunner$DontRun",
1826    }
1827    evaluation_class = evaluation_classes[data.get("on-evaluation-failure", "fail")]
1828    XML.SubElement(root_tag, "runner").set("class", evaluation_class)
1829    for edited_node in edited_nodes:
1830        if not has_multiple_steps:
1831            edited_node.set("class", edited_node.tag)
1832            edited_node.tag = "buildStep"
1833        steps_parent.append(edited_node)
1834
1835
1836def maven_builder(registry, xml_parent, data):
1837    """yaml: maven-builder
1838    Execute Maven3 builder
1839
1840    Allows your build jobs to deploy artifacts automatically to Artifactory.
1841
1842    Requires the Jenkins `Artifactory Plugin
1843    <https://www.jfrog.com/confluence/display/RTF/Jenkins+Artifactory+Plug-in>`_.
1844
1845    :arg str name: Name of maven installation from the configuration (required)
1846    :arg str pom: Location of pom.xml (default 'pom.xml')
1847    :arg str goals: Goals to execute (required)
1848    :arg str maven-opts: Additional options for maven (default '')
1849
1850    Example:
1851
1852    .. literalinclude:: /../../tests/builders/fixtures/maven-builder001.yaml
1853       :language: yaml
1854    """
1855    maven = XML.SubElement(xml_parent, "org.jfrog.hudson.maven3.Maven3Builder")
1856
1857    mapping = [
1858        ("name", "mavenName", None),
1859        ("goals", "goals", None),
1860        ("pom", "rootPom", "pom.xml"),
1861        ("maven-opts", "mavenOpts", ""),
1862    ]
1863    helpers.convert_mapping_to_xml(maven, data, mapping, fail_required=True)
1864
1865
1866def jira_issue_updater(registry, xml_parent, data):
1867    """yaml: jenkins-jira-issue-updater
1868    Updates issues in Atlassian JIRA as part of a Jenkins job.
1869
1870    Requires the Jenkins :jenkins-plugins:`Jira Issue Updater Plugin
1871    <jenkins-jira-issue-updater>`.
1872
1873    :arg str base-url: The base url of the rest API. (default '')
1874    :arg str username: The Jira username (required)
1875    :arg str password: The Jira password (required)
1876    :arg str jql: The JQL used to select the issues to update. (required)
1877    :arg str workflow: The Name of the workflow action to be executed.
1878        (default '')
1879    :arg str comment: The Jira comment to be added. (default '')
1880    :arg str custom-Id: The Jira custom field to be edited. (default '')
1881    :arg str custom-value: Jira custom field value. (default '')
1882    :arg bool fail-if-error: Fail this build if JQL returns error.
1883        ((default false)
1884    :arg bool fail-if-no-match: Fail this build if no issues are matched.
1885        (default false)
1886    :arg bool fail-if-no-connection: Fail this build if can't connect to Jira.
1887        (default false)
1888
1889    Minimal Example:
1890
1891    .. literalinclude::
1892        /../../tests/builders/fixtures/jenkins-jira-issue-updater-minimal.yaml
1893        :language: yaml
1894
1895    Full Example:
1896
1897    .. literalinclude::
1898        /../../tests/builders/fixtures/jenkins-jira-issue-updater-full.yaml
1899        :language: yaml
1900    """
1901    issue_updater = XML.SubElement(
1902        xml_parent, "info.bluefloyd.jenkins." "IssueUpdatesBuilder"
1903    )
1904    issue_updater.set("plugin", "jenkins-jira-issue-updater")
1905
1906    mapping = [
1907        ("base-url", "restAPIUrl", ""),
1908        ("username", "userName", None),
1909        ("password", "password", None),
1910        ("jql", "jql", None),
1911        ("workflow", "workflowActionName", ""),
1912        ("comment", "comment", ""),
1913        ("custom-Id", "customFieldId", ""),
1914        ("custom-value", "customFieldValue", ""),
1915        ("fail-if-error", "failIfJqlFails", False),
1916        ("fail-if-no-match", "failIfNoIssuesReturned", False),
1917        ("fail-if-no-connection", "failIfNoJiraConnection", False),
1918    ]
1919    helpers.convert_mapping_to_xml(issue_updater, data, mapping, fail_required=True)
1920
1921
1922def maven_target(registry, xml_parent, data):
1923    """yaml: maven-target
1924    Execute top-level Maven targets.
1925
1926    Requires the Jenkins :jenkins-plugins:`Config File Provider Plugin
1927    <config-file-provider>` for the Config File Provider "settings"
1928    and "global-settings" config.
1929
1930    :arg str goals: Goals to execute
1931    :arg str properties: Properties for maven, can have multiples
1932    :arg str pom: Location of pom.xml (default 'pom.xml')
1933    :arg bool private-repository: Use private maven repository for this
1934        job (default false)
1935    :arg str maven-version: Installation of maven which should be used
1936        (optional)
1937    :arg str java-opts: java options for maven, can have multiples,
1938        must be in quotes (optional)
1939    :arg str settings: Path to use as user settings.xml
1940        It is possible to provide a ConfigFileProvider settings file, such as
1941        see CFP Example below. (optional)
1942    :arg str settings-type: Type of settings file file|cfp. (default file)
1943    :arg str global-settings: Path to use as global settings.xml
1944        It is possible to provide a ConfigFileProvider settings file, such as
1945        see CFP Example below. (optional)
1946    :arg str global-settings-type: Type of settings file file|cfp. (default
1947        file)
1948
1949    Example:
1950
1951    .. literalinclude:: /../../tests/builders/fixtures/maven-target-doc.yaml
1952       :language: yaml
1953
1954    CFP Example:
1955
1956    .. literalinclude:: /../../tests/builders/fixtures/maven-target002.yaml
1957       :language: yaml
1958    """
1959    maven = XML.SubElement(xml_parent, "hudson.tasks.Maven")
1960    XML.SubElement(maven, "targets").text = data["goals"]
1961    prop_string = "\n".join(data.get("properties", []))
1962    XML.SubElement(maven, "properties").text = prop_string
1963
1964    mapping = [
1965        ("maven-version", "mavenName", None),
1966        ("pom", "pom", None),
1967        ("private-repository", "usePrivateRepository", False),
1968    ]
1969    helpers.convert_mapping_to_xml(maven, data, mapping, fail_required=False)
1970    if "java-opts" in data:
1971        javaoptions = " ".join(data.get("java-opts", []))
1972        XML.SubElement(maven, "jvmOptions").text = javaoptions
1973    helpers.config_file_provider_settings(maven, data)
1974
1975
1976def multijob(registry, xml_parent, data):
1977    """yaml: multijob
1978    Define a multijob phase.
1979
1980    Requires the Jenkins :jenkins-plugins:`Multijob Plugin
1981    <jenkins-multijob-plugin>`.
1982
1983    This builder may only be used in
1984    :py:class:`jenkins_jobs.modules.project_multijob.MultiJob` projects.
1985
1986    :arg str name: MultiJob phase name
1987    :arg str condition: when to trigger the other job.
1988        Can be: 'SUCCESSFUL', 'UNSTABLE', 'COMPLETED', 'FAILURE', 'ALWAYS'.
1989        (default 'SUCCESSFUL')
1990    :arg str execution-type: Define how to run jobs in a phase:
1991        sequentially or parallel.
1992        Can be: 'PARALLEL', 'SEQUENTIALLY'
1993        (default 'PARALLEL')
1994
1995    :arg list projects: list of projects to include in the MultiJob phase
1996
1997        :Project:
1998            * **name** (`str`) -- Project name
1999            * **alias** (`str`) -- Project alias, which will be shown
2000              in MultiJob Overview. Helpful when working with the same
2001              project multiple times with different configurations
2002            * **current-parameters** (`bool`) -- Pass current build
2003              parameters to the other job (default false)
2004            * **node-label-name** (`str`) -- Define a list of nodes
2005              on which the job should be allowed to be executed on.
2006              Requires NodeLabel Parameter Plugin (optional)
2007            * **node-label** (`str`) -- Define a label
2008              of 'Restrict where this project can be run' on the fly.
2009              Requires NodeLabel Parameter Plugin (optional)
2010            * **node-parameters** (`bool`) -- Use the same Node for
2011              the triggered builds that was used for this build. (optional)
2012            * **git-revision** (`bool`) -- Pass current git-revision
2013              to the other job (default false)
2014            * **property-file** (`str`) -- Pass properties from file
2015              to the other job (optional)
2016            * **predefined-parameters** (`str`) -- Pass predefined
2017              parameters to the other job (optional)
2018            * **abort-all-job** (`bool`) -- Kill allsubs job and the phase job,
2019              if this subjob is killed (default false)
2020            * **aggregate-results** (`bool`) -- Aggregate test results.
2021              (default false)
2022            * **enable-condition** (`str`) -- Condition to run the
2023              job in groovy script format (optional)
2024            * **kill-phase-on** (`str`) -- Stop the phase execution
2025              on specific job status. Can be 'FAILURE', 'UNSTABLE',
2026              'NEVER'. (optional)
2027            * **restrict-matrix-project** (`str`) -- Filter that
2028              restricts the subset of the combinations that the
2029              downstream project will run (optional)
2030            * **retry** (`dict`): Enable retry strategy (optional)
2031                :retry:
2032                    * **max-retry** (`int`) -- Max number of retries
2033                      (default 0)
2034                    * **strategy-path** (`str`) -- Parsing rules path
2035                      (required)
2036
2037    Example:
2038
2039    .. literalinclude:: /../../tests/builders/fixtures/multibuild.yaml
2040       :language: yaml
2041    """
2042    builder = XML.SubElement(
2043        xml_parent, "com.tikal.jenkins.plugins.multijob." "MultiJobBuilder"
2044    )
2045    conditions_available = ("SUCCESSFUL", "UNSTABLE", "COMPLETED", "FAILURE", "ALWAYS")
2046    job_execution_type_available = ("PARALLEL", "SEQUENTIALLY")
2047    mapping = [
2048        ("name", "phaseName", None),
2049        ("condition", "continuationCondition", "SUCCESSFUL", conditions_available),
2050        ("execution-type", "executionType", "PARALLEL", job_execution_type_available),
2051    ]
2052    helpers.convert_mapping_to_xml(builder, data, mapping, fail_required=True)
2053
2054    phaseJobs = XML.SubElement(builder, "phaseJobs")
2055
2056    kill_status_list = ("FAILURE", "UNSTABLE", "NEVER")
2057
2058    for project in data.get("projects", []):
2059        phaseJob = XML.SubElement(
2060            phaseJobs, "com.tikal.jenkins.plugins." "multijob.PhaseJobsConfig"
2061        )
2062        mapping = [
2063            ("name", "jobName", None),
2064            # Pass through the current build params
2065            ("current-parameters", "currParams", False),
2066        ]
2067        helpers.convert_mapping_to_xml(phaseJob, project, mapping, fail_required=True)
2068        # Pass through other params
2069        if project.get("alias"):
2070            mapping = [("alias", "jobAlias", None)]
2071            helpers.convert_mapping_to_xml(
2072                phaseJob, project, mapping, fail_required=True
2073            )
2074
2075        configs = XML.SubElement(phaseJob, "configs")
2076
2077        nodeLabelName = project.get("node-label-name")
2078        nodeLabel = project.get("node-label")
2079        if nodeLabelName and nodeLabel:
2080            node = XML.SubElement(
2081                configs,
2082                "org.jvnet.jenkins.plugins.nodelabelparameter."
2083                "parameterizedtrigger.NodeLabelBuildParameter",
2084            )
2085            mapping = [("", "name", nodeLabelName), ("", "nodeLabel", nodeLabel)]
2086            helpers.convert_mapping_to_xml(node, project, mapping, fail_required=True)
2087
2088        # Node parameter
2089        if project.get("node-parameters", False):
2090            XML.SubElement(
2091                configs, "hudson.plugins.parameterizedtrigger." "NodeParameters"
2092            )
2093
2094        # Git Revision
2095        if project.get("git-revision", False):
2096            param = XML.SubElement(
2097                configs, "hudson.plugins.git." "GitRevisionBuildParameters"
2098            )
2099            mapping = [("", "combineQueuedCommits", False)]
2100            helpers.convert_mapping_to_xml(param, project, mapping, fail_required=True)
2101
2102        # Properties File
2103        properties_file = project.get("property-file", False)
2104        if properties_file:
2105            param = XML.SubElement(
2106                configs, "hudson.plugins.parameterizedtrigger." "FileBuildParameters"
2107            )
2108            mapping = [
2109                ("", "propertiesFile", properties_file),
2110                ("", "failTriggerOnMissing", True),
2111            ]
2112            helpers.convert_mapping_to_xml(param, project, mapping, fail_required=True)
2113
2114        # Predefined Parameters
2115        predefined_parameters = project.get("predefined-parameters", False)
2116        if predefined_parameters:
2117            param = XML.SubElement(
2118                configs,
2119                "hudson.plugins.parameterizedtrigger." "PredefinedBuildParameters",
2120            )
2121            mapping = [("", "properties", predefined_parameters)]
2122            helpers.convert_mapping_to_xml(param, project, mapping, fail_required=True)
2123
2124        mapping = [
2125            ("abort-all-job", "abortAllJob", False),
2126            ("aggregate-results", "aggregatedTestResults", False),
2127        ]
2128        helpers.convert_mapping_to_xml(phaseJob, project, mapping, fail_required=True)
2129
2130        # Retry job
2131        retry = project.get("retry", False)
2132        if retry:
2133            max_retry = retry.get("max-retry", 0)
2134            mapping = [
2135                ("strategy-path", "parsingRulesPath", None),
2136                ("", "maxRetries", int(max_retry)),
2137                ("", "enableRetryStrategy", True),
2138            ]
2139            helpers.convert_mapping_to_xml(phaseJob, retry, mapping, fail_required=True)
2140        else:
2141            XML.SubElement(phaseJob, "enableRetryStrategy").text = "false"
2142
2143        # Restrict matrix jobs to a subset
2144        if project.get("restrict-matrix-project") is not None:
2145            subset = XML.SubElement(
2146                configs,
2147                "hudson.plugins.parameterizedtrigger."
2148                "matrix.MatrixSubsetBuildParameters",
2149            )
2150            mapping = [("restrict-matrix-project", "filter", None)]
2151            helpers.convert_mapping_to_xml(subset, project, mapping, fail_required=True)
2152
2153        # Enable Condition
2154        enable_condition = project.get("enable-condition")
2155        if enable_condition is not None:
2156            mapping = [
2157                ("", "enableCondition", True),
2158                ("", "condition", enable_condition),
2159            ]
2160            helpers.convert_mapping_to_xml(
2161                phaseJob, project, mapping, fail_required=True
2162            )
2163
2164        # Kill phase on job status
2165        kill_status = project.get("kill-phase-on")
2166        if kill_status is not None:
2167            kill_status = kill_status.upper()
2168            mapping = [
2169                ("", "killPhaseOnJobResultCondition", kill_status, kill_status_list)
2170            ]
2171            helpers.convert_mapping_to_xml(
2172                phaseJob, project, mapping, fail_required=True
2173            )
2174
2175
2176def config_file_provider(registry, xml_parent, data):
2177    """yaml: config-file-provider
2178    Provide configuration files (i.e., settings.xml for maven etc.)
2179    which will be copied to the job's workspace.
2180
2181    Requires the Jenkins :jenkins-plugins:`Config File Provider Plugin
2182    <config-file-provider>`.
2183
2184    :arg list files: List of managed config files made up of three
2185        parameters
2186
2187        :files:
2188            * **file-id** (`str`) -- The identifier for the managed config
2189              file
2190            * **target** (`str`) -- Define where the file should be created
2191              (default '')
2192            * **variable** (`str`) -- Define an environment variable to be
2193              used (default '')
2194            * **replace-tokens** (`bool`) -- Replace tokens in config file. For
2195              example "password: ${PYPI_JENKINS_PASS}" will be replaced with
2196              the global variable configured in Jenkins.
2197
2198    Full Example:
2199
2200    .. literalinclude::
2201        ../../tests/builders/fixtures/config-file-provider-full.yaml
2202       :language: yaml
2203
2204    Minimal Example:
2205
2206    .. literalinclude::
2207        ../../tests/builders/fixtures/config-file-provider-minimal.yaml
2208       :language: yaml
2209    """
2210    cfp = XML.SubElement(
2211        xml_parent, "org.jenkinsci.plugins.configfiles.builder." "ConfigFileBuildStep"
2212    )
2213    cfp.set("plugin", "config-file-provider")
2214    helpers.config_file_provider_builder(cfp, data)
2215
2216
2217def grails(registry, xml_parent, data):
2218    """yaml: grails
2219    Execute a grails build step.
2220
2221    Requires the :jenkins-plugins:`Jenkins Grails Plugin <grails>`.
2222
2223    :arg bool use-wrapper: Use a grails wrapper (default false)
2224    :arg str name: Select a grails installation to use (default '(Default)')
2225    :arg bool force-upgrade: Run 'grails upgrade --non-interactive'
2226        first (default false)
2227    :arg bool non-interactive: append --non-interactive to all build targets
2228        (default false)
2229    :arg str targets: Specify target(s) to run separated by spaces (required)
2230    :arg str server-port: Specify a value for the server.port system
2231        property (default '')
2232    :arg str work-dir: Specify a value for the grails.work.dir system
2233        property (default '')
2234    :arg str project-dir: Specify a value for the grails.project.work.dir
2235        system property (default '')
2236    :arg str base-dir: Specify a path to the root of the Grails
2237        project (default '')
2238    :arg str properties: Additional system properties to set (default '')
2239    :arg bool plain-output: append --plain-output to all build targets
2240        (default false)
2241    :arg bool stack-trace: append --stack-trace to all build targets
2242        (default false)
2243    :arg bool verbose: append --verbose to all build targets
2244        (default false)
2245    :arg bool refresh-dependencies: append --refresh-dependencies to all
2246        build targets (default false)
2247
2248    Full Example:
2249
2250    .. literalinclude:: ../../tests/builders/fixtures/grails-full.yaml
2251       :language: yaml
2252
2253    Minimal Example:
2254
2255    .. literalinclude:: ../../tests/builders/fixtures/grails-minimal.yaml
2256       :language: yaml
2257    """
2258    grails = XML.SubElement(xml_parent, "com.g2one.hudson.grails." "GrailsBuilder")
2259    grails.set("plugin", "grails")
2260
2261    mappings = [
2262        ("targets", "targets", None),
2263        ("name", "name", "(Default)"),
2264        ("work-dir", "grailsWorkDir", ""),
2265        ("project-dir", "projectWorkDir", ""),
2266        ("base-dir", "projectBaseDir", ""),
2267        ("server-port", "serverPort", ""),
2268        ("properties", "properties", ""),
2269        ("force-upgrade", "forceUpgrade", False),
2270        ("non-interactive", "nonInteractive", False),
2271        ("use-wrapper", "useWrapper", False),
2272        ("plain-output", "plainOutput", False),
2273        ("stack-trace", "stackTrace", False),
2274        ("verbose", "verbose", False),
2275        ("refresh-dependencies", "refreshDependencies", False),
2276    ]
2277    helpers.convert_mapping_to_xml(grails, data, mappings, fail_required=True)
2278
2279
2280def sbt(registry, xml_parent, data):
2281    """yaml: sbt
2282    Execute a sbt build step.
2283
2284    Requires the Jenkins :jenkins-plugins:`Sbt Plugin <sbt>`.
2285
2286    :arg str name: Select a sbt installation to use. If no name is
2287        provided, the first in the list of defined SBT builders will be
2288        used. (default to first in list)
2289    :arg str jvm-flags: Parameters to pass to the JVM (default '')
2290    :arg str actions: Select the sbt tasks to execute (default '')
2291    :arg str sbt-flags: Add flags to SBT launcher
2292        (default '-Dsbt.log.noformat=true')
2293    :arg str subdir-path: Path relative to workspace to run sbt in
2294        (default '')
2295
2296    Example:
2297
2298    .. literalinclude:: ../../tests/builders/fixtures/sbt.yaml
2299       :language: yaml
2300    """
2301    sbt = XML.SubElement(xml_parent, "org.jvnet.hudson.plugins." "SbtPluginBuilder")
2302    mappings = [
2303        ("name", "name", ""),
2304        ("jvm-flags", "jvmFlags", ""),
2305        ("sbt-flags", "sbtFlags", "-Dsbt.log.noformat=true"),
2306        ("actions", "actions", ""),
2307        ("subdir-path", "subdirPath", ""),
2308    ]
2309    helpers.convert_mapping_to_xml(sbt, data, mappings, fail_required=True)
2310
2311
2312def critical_block_start(registry, xml_parent, data):
2313    """yaml: critical-block-start
2314    Designate the start of a critical block. Must be used in conjunction with
2315    critical-block-end.
2316
2317    Must also add a build wrapper (exclusion), specifying the resources that
2318    control the critical block. Otherwise, this will have no effect.
2319
2320    Requires the Jenkins :jenkins-plugins:`Exclusion Plugin <Exclusion>`.
2321
2322    Example:
2323
2324    .. literalinclude::
2325        ../../tests/yamlparser/fixtures/critical_block_complete001.yaml
2326       :language: yaml
2327    """
2328    cbs = XML.SubElement(
2329        xml_parent, "org.jvnet.hudson.plugins.exclusion.CriticalBlockStart"
2330    )
2331    cbs.set("plugin", "Exclusion")
2332
2333
2334def critical_block_end(registry, xml_parent, data):
2335    """yaml: critical-block-end
2336    Designate the end of a critical block. Must be used in conjunction with
2337    critical-block-start.
2338
2339    Must also add a build wrapper (exclusion), specifying the resources that
2340    control the critical block. Otherwise, this will have no effect.
2341
2342    Requires the Jenkins :jenkins-plugins:`Exclusion Plugin <Exclusion>`.
2343
2344    Example:
2345
2346    .. literalinclude::
2347        ../../tests/yamlparser/fixtures/critical_block_complete001.yaml
2348       :language: yaml
2349    """
2350    cbs = XML.SubElement(
2351        xml_parent, "org.jvnet.hudson.plugins.exclusion.CriticalBlockEnd"
2352    )
2353    cbs.set("plugin", "Exclusion")
2354
2355
2356def publish_over_ssh(registry, xml_parent, data):
2357    """yaml: publish-over-ssh
2358    Send files or execute commands over SSH.
2359
2360    Requires the Jenkins :jenkins-plugins:`Publish over SSH Plugin
2361    <publish-over-ssh>`.
2362
2363    :arg str site: name of the ssh site
2364    :arg str target: destination directory
2365    :arg bool target-is-date-format: whether target is a date format. If true,
2366        raw text should be quoted (default false)
2367    :arg bool clean-remote: should the remote directory be deleted before
2368        transferring files (default false)
2369    :arg str source: source path specifier
2370    :arg str command: a command to execute on the remote server (optional)
2371    :arg int timeout: timeout in milliseconds for the Exec command (optional)
2372    :arg bool use-pty: run the exec command in pseudo TTY (default false)
2373    :arg str excludes: excluded file pattern (optional)
2374    :arg str remove-prefix: prefix to remove from uploaded file paths
2375        (optional)
2376    :arg bool fail-on-error: fail the build if an error occurs (default false)
2377
2378    Example:
2379
2380    .. literalinclude:: /../../tests/builders/fixtures/publish-over-ssh.yaml
2381       :language: yaml
2382    """
2383    ssh(registry, xml_parent, data)
2384
2385
2386def publish_over_cifs(registry, xml_parent, data):
2387    """yaml: publish-over-cifs
2388    Upload files via CIFS.
2389
2390    Requires the Jenkins :jenkins-plugins:`Publish over CIFS Plugin
2391    <publish-over-cifs>`.
2392
2393    :arg str site: name of the ssh site
2394    :arg str target: destination directory
2395    :arg bool target-is-date-format: whether target is a date format. If true,
2396        raw text should be quoted (default false)
2397    :arg bool clean-remote: should the remote directory be deleted before
2398        transferring files (default false)
2399    :arg str source: source path specifier
2400    :arg str excludes: excluded file pattern (optional)
2401    :arg str remove-prefix: prefix to remove from uploaded file paths
2402        (optional)
2403    :arg bool fail-on-error: fail the build if an error occurs (default false)
2404    :arg bool flatten: only create files on the server, don't create
2405        directories (default false)
2406
2407    Example:
2408
2409    .. literalinclude:: /../../tests/builders/fixtures/publish-over-cifs.yaml
2410       :language: yaml
2411    """
2412    cifs(registry, xml_parent, data)
2413
2414
2415def saltstack(parser, xml_parent, data):
2416    """yaml: saltstack
2417
2418    Send a message to Salt API.
2419
2420    Requires the Jenkins :jenkins-plugins:`saltstack plugin <saltstack>`.
2421
2422    :arg str servername: Salt master server name (required)
2423    :arg str authtype: Authentication type ('pam' or 'ldap', default 'pam')
2424    :arg str credentials: Credentials ID for which to authenticate to Salt
2425        master (required)
2426    :arg str target: Target minions (default '')
2427    :arg str targettype: Target type ('glob', 'pcre', 'list', 'grain',
2428        'pillar', 'nodegroup', 'range', or 'compound', default 'glob')
2429    :arg str function: Function to execute (default '')
2430    :arg str arguments: Salt function arguments (default '')
2431    :arg str kwarguments: Salt keyword arguments (default '')
2432    :arg bool saveoutput: Save Salt return data into environment variable
2433        (default false)
2434    :arg str clientinterface: Client interface type ('local', 'local-batch',
2435        or 'runner', default 'local')
2436    :arg bool wait: Wait for completion of command (default false)
2437    :arg str polltime: Number of seconds to wait before polling job completion
2438        status (default '')
2439    :arg str batchsize: Salt batch size, absolute value or %-age (default 100%)
2440    :arg str mods: Mods to runner (default '')
2441    :arg bool setpillardata: Set Pillar data (default false)
2442    :arg str pillarkey: Pillar key (default '')
2443    :arg str pillarvalue: Pillar value (default '')
2444
2445    Minimal Example:
2446
2447    .. literalinclude:: ../../tests/builders/fixtures/saltstack-minimal.yaml
2448       :language: yaml
2449
2450    Full Example:
2451
2452    .. literalinclude:: ../../tests/builders/fixtures/saltstack-full.yaml
2453       :language: yaml
2454    """
2455    saltstack = XML.SubElement(xml_parent, "com.waytta.SaltAPIBuilder")
2456
2457    supported_auth_types = ["pam", "ldap"]
2458    supported_target_types = [
2459        "glob",
2460        "pcre",
2461        "list",
2462        "grain",
2463        "pillar",
2464        "nodegroup",
2465        "range",
2466        "compound",
2467    ]
2468    supported_client_interfaces = ["local", "local-batch", "runner"]
2469
2470    mapping = [
2471        ("servername", "servername", None),
2472        ("credentials", "credentialsId", None),
2473        ("authtype", "authtype", "pam", supported_auth_types),
2474        ("target", "target", ""),
2475        ("targettype", "targettype", "glob", supported_target_types),
2476        ("clientinterface", "clientInterface", "local", supported_client_interfaces),
2477        ("function", "function", ""),
2478        ("arguments", "arguments", ""),
2479        ("kwarguments", "kwarguments", ""),
2480        ("setpillardata", "usePillar", False),
2481        ("pillarkey", "pillarkey", ""),
2482        ("pillarvalue", "pillarvalue", ""),
2483        ("wait", "blockbuild", False),
2484        ("polltime", "jobPollTime", ""),
2485        ("batchsize", "batchSize", "100%"),
2486        ("mods", "mods", ""),
2487        ("saveoutput", "saveEnvVar", False),
2488    ]
2489
2490    helpers.convert_mapping_to_xml(saltstack, data, mapping, fail_required=True)
2491
2492    clientInterface = data.get("clientinterface", "local")
2493    blockbuild = str(data.get("wait", False)).lower()
2494    jobPollTime = str(data.get("polltime", ""))
2495    batchSize = data.get("batchsize", "100%")
2496    mods = data.get("mods", "")
2497    usePillar = str(data.get("setpillardata", False)).lower()
2498
2499    # Build the clientInterfaces structure, based on the
2500    # clientinterface setting
2501    clientInterfaces = XML.SubElement(saltstack, "clientInterfaces")
2502    XML.SubElement(clientInterfaces, "nullObject").text = "false"
2503
2504    ci_attrib = {
2505        "class": "org.apache.commons.collections.map.ListOrderedMap",
2506        "serialization": "custom",
2507    }
2508    properties = XML.SubElement(clientInterfaces, "properties", ci_attrib)
2509
2510    lomElement = "org.apache.commons.collections.map.ListOrderedMap"
2511    listOrderedMap = XML.SubElement(properties, lomElement)
2512
2513    default = XML.SubElement(listOrderedMap, "default")
2514    ordered_map = XML.SubElement(listOrderedMap, "map")
2515
2516    insertOrder = XML.SubElement(default, "insertOrder")
2517
2518    ci_config = []
2519    if clientInterface == "local":
2520        ci_config = [
2521            ("blockbuild", blockbuild),
2522            ("jobPollTime", jobPollTime),
2523            ("clientInterface", clientInterface),
2524        ]
2525
2526    elif clientInterface == "local-batch":
2527        ci_config = [("batchSize", batchSize), ("clientInterface", clientInterface)]
2528
2529    elif clientInterface == "runner":
2530        ci_config = [("mods", mods), ("clientInterface", clientInterface)]
2531
2532        if usePillar == "true":
2533            ci_config.append(("usePillar", usePillar))
2534
2535            pillar_cfg = [
2536                ("pillarkey", data.get("pillarkey")),
2537                ("pillarvalue", data.get("pillarvalue")),
2538            ]
2539
2540    for emt, value in ci_config:
2541        XML.SubElement(insertOrder, "string").text = emt
2542        entry = XML.SubElement(ordered_map, "entry")
2543        XML.SubElement(entry, "string").text = emt
2544
2545        # Special handling when usePillar == true, requires additional
2546        # structure in the builder XML
2547        if emt != "usePillar":
2548            XML.SubElement(entry, "string").text = value
2549        else:
2550            jsonobj = XML.SubElement(entry, "net.sf.json.JSONObject")
2551            XML.SubElement(jsonobj, "nullObject").text = "false"
2552
2553            pillarProps = XML.SubElement(jsonobj, "properties", ci_attrib)
2554            XML.SubElement(pillarProps, "unserializable-parents")
2555
2556            pillarLom = XML.SubElement(pillarProps, lomElement)
2557
2558            pillarDefault = XML.SubElement(pillarLom, "default")
2559            pillarMap = XML.SubElement(pillarLom, "map")
2560            pillarInsertOrder = XML.SubElement(pillarDefault, "insertOrder")
2561
2562            for pemt, value in pillar_cfg:
2563                XML.SubElement(pillarInsertOrder, "string").text = pemt
2564                pillarEntry = XML.SubElement(pillarMap, "entry")
2565                XML.SubElement(pillarEntry, "string").text = pemt
2566                XML.SubElement(pillarEntry, "string").text = value
2567
2568
2569class Builders(jenkins_jobs.modules.base.Base):
2570    sequence = 60
2571
2572    component_type = "builder"
2573    component_list_type = "builders"
2574
2575    def gen_xml(self, xml_parent, data):
2576
2577        for alias in ["prebuilders", "builders", "postbuilders"]:
2578            if alias in data:
2579                builders = XML.SubElement(xml_parent, alias)
2580                for builder in data[alias]:
2581                    self.registry.dispatch("builder", builders, builder)
2582
2583        # Make sure freestyle projects always have a <builders> entry
2584        # or Jenkins v1.472 (at least) will NPE.
2585        project_type = data.get("project-type", "freestyle")
2586        if project_type in ("freestyle", "matrix") and "builders" not in data:
2587            XML.SubElement(xml_parent, "builders")
2588
2589
2590def shining_panda(registry, xml_parent, data):
2591    """yaml: shining-panda
2592    Execute a command inside various python environments.
2593
2594    Requires the Jenkins :jenkins-plugins:`ShiningPanda plugin
2595    <shiningpanda>`.
2596
2597    :arg str build-environment: Building environment to set up (required).
2598
2599        :build-environment values:
2600            * **python**: Use a python installation configured in Jenkins.
2601            * **custom**: Use a manually installed python.
2602            * **virtualenv**: Create a virtualenv
2603
2604    For the **python** environment
2605
2606    :arg str python-version: Name of the python installation to use.
2607        Must match one of the configured installations on server
2608        configuration (default 'System-CPython-2.7')
2609
2610    For the **custom** environment:
2611
2612    :arg str home: path to the home folder of the custom installation
2613        (required)
2614
2615    For the **virtualenv** environment:
2616
2617    :arg str python-version: Name of the python installation to use.
2618        Must match one of the configured installations on server
2619        configuration (default 'System-CPython-2.7')
2620    :arg str name: Name of this virtualenv. Two virtualenv builders with
2621        the same name will use the same virtualenv installation (optional)
2622    :arg bool clear: If true, delete and recreate virtualenv on each build.
2623        (default false)
2624    :arg bool use-distribute: if true use distribute, if false use
2625        setuptools. (default true)
2626    :arg bool system-site-packages: if true, give access to the global
2627        site-packages directory to the virtualenv. (default false)
2628
2629    Common to all environments:
2630
2631    :arg str nature: Nature of the command field. (default shell)
2632
2633        :nature values:
2634            * **shell**: execute the Command contents with default shell
2635            * **xshell**: like **shell** but performs platform conversion
2636              first
2637            * **python**: execute the Command contents with the Python
2638              executable
2639
2640    :arg str command: The command to execute
2641    :arg bool ignore-exit-code: mark the build as failure if any of the
2642        commands exits with a non-zero exit code. (default false)
2643
2644    Examples:
2645
2646    .. literalinclude::
2647        /../../tests/builders/fixtures/shining-panda-pythonenv.yaml
2648       :language: yaml
2649
2650    .. literalinclude::
2651        /../../tests/builders/fixtures/shining-panda-customenv.yaml
2652       :language: yaml
2653
2654    .. literalinclude::
2655        /../../tests/builders/fixtures/shining-panda-virtualenv.yaml
2656       :language: yaml
2657    """
2658
2659    pluginelementpart = "jenkins.plugins.shiningpanda.builders."
2660    buildenvdict = {
2661        "custom": "CustomPythonBuilder",
2662        "virtualenv": "VirtualenvBuilder",
2663        "python": "PythonBuilder",
2664    }
2665    envs = buildenvdict.keys()
2666
2667    try:
2668        buildenv = data["build-environment"]
2669    except KeyError:
2670        raise MissingAttributeError("build-environment")
2671
2672    if buildenv not in envs:
2673        raise InvalidAttributeError("build-environment", buildenv, envs)
2674
2675    t = XML.SubElement(xml_parent, "%s%s" % (pluginelementpart, buildenvdict[buildenv]))
2676
2677    if buildenv in ("python", "virtualenv"):
2678        python_mapping = [("python-version", "pythonName", "System-CPython-2.7")]
2679        helpers.convert_mapping_to_xml(t, data, python_mapping, fail_required=True)
2680
2681    if buildenv in "custom":
2682        custom_mapping = [("home", "home", None)]
2683        helpers.convert_mapping_to_xml(t, data, custom_mapping, fail_required=True)
2684    if buildenv in "virtualenv":
2685        virtualenv_mapping = [
2686            ("name", "home", ""),
2687            ("clear", "clear", False),
2688            ("use-distribute", "useDistribute", False),
2689            ("system-site-packages", "systemSitePackages", False),
2690        ]
2691        helpers.convert_mapping_to_xml(t, data, virtualenv_mapping, fail_required=True)
2692
2693    # Common arguments
2694    naturelist = ["shell", "xshell", "python"]
2695    mapping = [
2696        ("nature", "nature", "shell", naturelist),
2697        ("command", "command", ""),
2698        ("ignore-exit-code", "ignoreExitCode", False),
2699    ]
2700    helpers.convert_mapping_to_xml(t, data, mapping, fail_required=True)
2701
2702
2703def tox(registry, xml_parent, data):
2704    """yaml: tox
2705    Use tox to build a multi-configuration project.
2706
2707    Requires the Jenkins :jenkins-plugins:`ShiningPanda plugin
2708    <shiningpanda>`.
2709
2710    :arg str ini: The TOX configuration file path (default tox.ini)
2711    :arg bool recreate: If true, create a new environment each time (default
2712        false)
2713    :arg str toxenv-pattern: The pattern used to build the TOXENV environment
2714        variable. (optional)
2715
2716    Example:
2717
2718    .. literalinclude:: /../../tests/builders/fixtures/tox001.yaml
2719       :language: yaml
2720    """
2721    pluginelement = "jenkins.plugins.shiningpanda.builders.ToxBuilder"
2722    t = XML.SubElement(xml_parent, pluginelement)
2723    mappings = [("ini", "toxIni", "tox.ini"), ("recreate", "recreate", False)]
2724    helpers.convert_mapping_to_xml(t, data, mappings, fail_required=True)
2725    pattern = data.get("toxenv-pattern")
2726    if pattern:
2727        XML.SubElement(t, "toxenvPattern").text = pattern
2728
2729
2730def managed_script(registry, xml_parent, data):
2731    """yaml: managed-script
2732    This step allows you to reference and execute a centrally managed
2733    script within your build.
2734
2735    Requires the Jenkins :jenkins-plugins:`Managed Scripts Plugin
2736    <managed-scripts>`.
2737
2738    :arg str script-id: Id of script to execute (required)
2739    :arg str type: Type of managed file (default script)
2740
2741        :type values:
2742            * **batch**: Execute managed windows batch
2743            * **script**: Execute managed script
2744
2745    :arg list args: Arguments to be passed to referenced script
2746
2747    Example:
2748
2749    .. literalinclude:: /../../tests/builders/fixtures/managed-script.yaml
2750       :language: yaml
2751
2752    .. literalinclude:: /../../tests/builders/fixtures/managed-winbatch.yaml
2753       :language: yaml
2754    """
2755    step_type = data.get("type", "script").lower()
2756    if step_type == "script":
2757        step = "ScriptBuildStep"
2758        script_tag = "buildStepId"
2759    elif step_type == "batch":
2760        step = "WinBatchBuildStep"
2761        script_tag = "command"
2762    else:
2763        raise InvalidAttributeError("type", step_type, ["script", "batch"])
2764    ms = XML.SubElement(xml_parent, "org.jenkinsci.plugins.managedscripts." + step)
2765    mapping = [("script-id", script_tag, None)]
2766    helpers.convert_mapping_to_xml(ms, data, mapping, fail_required=True)
2767    args = XML.SubElement(ms, "buildStepArgs")
2768    for arg in data.get("args", []):
2769        XML.SubElement(args, "string").text = arg
2770
2771
2772def cmake(registry, xml_parent, data):
2773    """yaml: cmake
2774    Execute a CMake target.
2775
2776    Requires the Jenkins :jenkins-plugins:`CMake Plugin <cmakebuilder>`.
2777
2778    This builder is compatible with both versions 2.x and 1.x of the
2779    plugin. When specifying paramenters from both versions only the ones from
2780    the installed version in Jenkins will be used, and the rest will be
2781    ignored.
2782
2783    :arg str source-dir: the source code directory relative to the workspace
2784        directory. (required)
2785    :arg str build-type: Sets the "build type" option for CMake (default
2786        "Debug").
2787    :arg str preload-script: Path to a CMake preload script file. (optional)
2788    :arg str other-arguments: Other arguments to be added to the CMake
2789        call. (optional)
2790    :arg bool clean-build-dir: If true, delete the build directory before each
2791        build (default false).
2792
2793    :arg list generator: The makefile generator (default "Unix Makefiles").
2794
2795        :type Possible generators:
2796            * **Borland Makefiles**
2797            * **CodeBlocks - MinGW Makefiles**
2798            * **CodeBlocks - Unix Makefiles**
2799            * **Eclipse CDT4 - MinGW Makefiles**
2800            * **Eclipse CDT4 - NMake Makefiles**
2801            * **Eclipse CDT4 - Unix Makefiles**
2802            * **MSYS Makefiles**
2803            * **MinGW Makefiles**
2804            * **NMake Makefiles**
2805            * **Unix Makefiles**
2806            * **Visual Studio 6**
2807            * **Visual Studio 7 .NET 2003**
2808            * **Visual Studio 8 2005**
2809            * **Visual Studio 8 2005 Win64**
2810            * **Visual Studio 9 2008**
2811            * **Visual Studio 9 2008 Win64**
2812            * **Watcom WMake**
2813
2814    :Version 2.x: Parameters that available only to versions 2.x of the plugin
2815
2816        * **working-dir** (`str`): The directory where the project will be
2817          built in. Relative to the workspace directory. (optional)
2818        * **installation-name** (`str`): The CMake installation to be used on
2819          this builder. Use one defined in your Jenkins global configuration
2820          page (default "InSearchPath").
2821        * **build-tool-invocations** (`list`): list of build tool invocations
2822          that will happen during the build:
2823
2824            :Build tool invocations:
2825                * **use-cmake** (`str`) -- Whether to run the actual build tool
2826                    directly (by expanding ``$CMAKE_BUILD_TOOL``) or to have
2827                    cmake run the build tool (by invoking ``cmake --build
2828                    <dir>``) (default false).
2829                * **arguments** (`str`) -- Specify arguments to pass to the
2830                    build tool or cmake (separated by spaces). Arguments may
2831                    contain spaces if they are enclosed in double
2832                    quotes. (optional)
2833                * **environment-variables** (`str`) -- Specify extra
2834                    environment variables to pass to the build tool as
2835                    key-value pairs here. Each entry must be on its own line,
2836                    for example:
2837
2838                      ``DESTDIR=${WORKSPACE}/artifacts/dir``
2839
2840                      ``KEY=VALUE``
2841
2842    :Version 1.x: Parameters available only to versions 1.x of the plugin
2843
2844        * **build-dir** (`str`): The directory where the project will be built
2845          in.  Relative to the workspace directory. (optional)
2846        * **install-dir** (`str`): The directory where the project will be
2847          installed in, relative to the workspace directory. (optional)
2848        * **build-type** (`list`): Sets the "build type" option. A custom type
2849          different than the default ones specified on the CMake plugin can
2850          also be set, which will be automatically used in the "Other Build
2851          Type" option of the plugin. (default "Debug")
2852
2853            :Default types present in the CMake plugin:
2854                * **Debug**
2855                * **Release**
2856                * **RelWithDebInfo**
2857                * **MinSizeRel**
2858
2859        * **make-command** (`str`): The make command (default "make").
2860        * **install-command** (`arg`): The install command (default "make
2861          install").
2862        * **custom-cmake-path** (`str`): Path to cmake executable. (optional)
2863        * **clean-install-dir** (`bool`): If true, delete the install dir
2864          before each build (default false).
2865
2866    Example (Versions 2.x):
2867
2868    .. literalinclude::
2869        ../../tests/builders/fixtures/cmake/version-2.0/complete-2.x.yaml
2870       :language: yaml
2871
2872    Example (Versions 1.x):
2873
2874    .. literalinclude::
2875        ../../tests/builders/fixtures/cmake/version-1.10/complete-1.x.yaml
2876       :language: yaml
2877    """
2878
2879    BUILD_TYPES = ["Debug", "Release", "RelWithDebInfo", "MinSizeRel"]
2880    cmake = XML.SubElement(xml_parent, "hudson.plugins.cmake.CmakeBuilder")
2881
2882    mapping = [
2883        ("source-dir", "sourceDir", None),  # Required parameter
2884        ("generator", "generator", "Unix Makefiles"),
2885        ("clean-build-dir", "cleanBuild", False),
2886    ]
2887    helpers.convert_mapping_to_xml(cmake, data, mapping, fail_required=True)
2888
2889    info = registry.get_plugin_info("CMake plugin")
2890    # Note: Assume latest version of plugin is preferred config format
2891    version = pkg_resources.parse_version(info.get("version", str(sys.maxsize)))
2892
2893    if version >= pkg_resources.parse_version("2.0"):
2894        mapping_20 = [
2895            ("preload-script", "preloadScript", None),  # Optional parameter
2896            ("working-dir", "workingDir", ""),
2897            ("build-type", "buildType", "Debug"),
2898            ("installation-name", "installationName", "InSearchPath"),
2899            ("other-arguments", "toolArgs", ""),
2900        ]
2901        helpers.convert_mapping_to_xml(cmake, data, mapping_20, fail_required=False)
2902
2903        tool_steps = XML.SubElement(cmake, "toolSteps")
2904
2905        for step_data in data.get("build-tool-invocations", []):
2906            step = XML.SubElement(tool_steps, "hudson.plugins.cmake.BuildToolStep")
2907            step_mapping = [
2908                ("use-cmake", "withCmake", False),
2909                ("arguments", "args", ""),
2910                ("environment-variables", "vars", ""),
2911            ]
2912            helpers.convert_mapping_to_xml(
2913                step, step_data, step_mapping, fail_required=True
2914            )
2915
2916    else:
2917        mapping_10 = [
2918            ("preload-script", "preloadScript", ""),
2919            ("build-dir", "buildDir", ""),
2920            ("install-dir", "installDir", ""),
2921            ("make-command", "makeCommand", "make"),
2922            ("install-command", "installCommand", "make install"),
2923            ("other-arguments", "cmakeArgs", ""),
2924            ("custom-cmake-path", "projectCmakePath", ""),
2925            ("clean-install-dir", "cleanInstallDir", False),
2926        ]
2927        helpers.convert_mapping_to_xml(cmake, data, mapping_10, fail_required=True)
2928
2929        # The options buildType and otherBuildType work together on the CMake
2930        # plugin:
2931        #  * If the passed value is one of the predefined values, set buildType
2932        #    to it and otherBuildType to blank;
2933        #  * Otherwise, set otherBuildType to the value, and buildType to
2934        #    "Debug". The CMake plugin will ignore the buildType option.
2935        #
2936        # It is strange and confusing that the plugin author chose to do
2937        # something like that instead of simply passing a string "buildType"
2938        # option, so this was done to simplify it for the JJB user.
2939        build_type = XML.SubElement(cmake, "buildType")
2940        build_type.text = data.get("build-type", BUILD_TYPES[0])
2941        other_build_type = XML.SubElement(cmake, "otherBuildType")
2942
2943        if build_type.text not in BUILD_TYPES:
2944            other_build_type.text = build_type.text
2945            build_type.text = BUILD_TYPES[0]
2946        else:
2947            other_build_type.text = ""
2948
2949        # The plugin generates this tag, but there doesn't seem to be anything
2950        # that can be configurable by it. Let's keep it to maintain
2951        # compatibility:
2952        XML.SubElement(cmake, "builderImpl")
2953
2954
2955def dsl(registry, xml_parent, data):
2956    r"""yaml: dsl
2957    Process Job DSL
2958
2959    Requires the Jenkins :jenkins-plugins:`Job DSL plugin <job-dsl>`.
2960
2961    :arg str script-text: dsl script which is Groovy code (Required if targets
2962        is not specified)
2963    :arg str targets: Newline separated list of DSL scripts, located in the
2964        Workspace. Can use wildcards like 'jobs/\*/\*/\*.groovy' (Required
2965        if script-text is not specified)
2966    :arg str ignore-existing: Ignore previously generated jobs and views
2967    :arg str removed-job-action: Specifies what to do when a previously
2968        generated job is not referenced anymore, can be 'IGNORE', 'DISABLE',
2969        or 'DELETE' (default 'IGNORE')
2970    :arg str removed-view-action: Specifies what to do when a previously
2971        generated view is not referenced anymore, can be 'IGNORE' or 'DELETE'.
2972        (default 'IGNORE')
2973    :arg str lookup-strategy: Determines how relative job names in DSL
2974        scripts are interpreted, can be 'JENKINS_ROOT' or 'SEED_JOB'.
2975        (default 'JENKINS_ROOT')
2976    :arg str additional-classpath: Newline separated list of additional
2977        classpath entries for the Job DSL scripts. All entries must be
2978        relative to the workspace root, e.g. build/classes/main. (optional)
2979
2980    Example:
2981
2982    .. literalinclude:: /../../tests/builders/fixtures/dsl001.yaml
2983       :language: yaml
2984    .. literalinclude:: /../../tests/builders/fixtures/dsl002.yaml
2985       :language: yaml
2986
2987    """
2988
2989    dsl = XML.SubElement(xml_parent, "javaposse.jobdsl.plugin.ExecuteDslScripts")
2990
2991    if "target" in data:
2992        if "targets" not in data:
2993            logger.warning(
2994                "Converting from old format of 'target' to new "
2995                "name 'targets', please update your job "
2996                "definitions."
2997            )
2998            data["targets"] = data["target"]
2999        else:
3000            logger.warning(
3001                "Ignoring old argument 'target' in favour of new "
3002                "format argument 'targets', please remove old "
3003                "format."
3004            )
3005
3006    if data.get("script-text"):
3007        XML.SubElement(dsl, "scriptText").text = data.get("script-text")
3008        XML.SubElement(dsl, "usingScriptText").text = "true"
3009    elif data.get("targets"):
3010        XML.SubElement(dsl, "targets").text = data.get("targets")
3011        XML.SubElement(dsl, "usingScriptText").text = "false"
3012    else:
3013        raise MissingAttributeError(["script-text", "target"])
3014
3015    XML.SubElement(dsl, "ignoreExisting").text = str(
3016        data.get("ignore-existing", False)
3017    ).lower()
3018
3019    supportedJobActions = ["IGNORE", "DISABLE", "DELETE"]
3020    removedJobAction = data.get("removed-job-action", supportedJobActions[0])
3021    if removedJobAction not in supportedJobActions:
3022        raise InvalidAttributeError(
3023            "removed-job-action", removedJobAction, supportedJobActions
3024        )
3025    XML.SubElement(dsl, "removedJobAction").text = removedJobAction
3026
3027    supportedViewActions = ["IGNORE", "DELETE"]
3028    removedViewAction = data.get("removed-view-action", supportedViewActions[0])
3029    if removedViewAction not in supportedViewActions:
3030        raise InvalidAttributeError(
3031            "removed-view-action", removedViewAction, supportedViewActions
3032        )
3033    XML.SubElement(dsl, "removedViewAction").text = removedViewAction
3034
3035    supportedLookupActions = ["JENKINS_ROOT", "SEED_JOB"]
3036    lookupStrategy = data.get("lookup-strategy", supportedLookupActions[0])
3037    if lookupStrategy not in supportedLookupActions:
3038        raise InvalidAttributeError(
3039            "lookup-strategy", lookupStrategy, supportedLookupActions
3040        )
3041    XML.SubElement(dsl, "lookupStrategy").text = lookupStrategy
3042
3043    XML.SubElement(dsl, "additionalClasspath").text = data.get("additional-classpath")
3044
3045
3046def github_notifier(registry, xml_parent, data):
3047    """yaml: github-notifier
3048    Set pending build status on Github commit.
3049
3050    Requires the Jenkins :jenkins-plugins:`Github Plugin <github>`.
3051
3052    Example:
3053
3054    .. literalinclude:: /../../tests/builders/fixtures/github-notifier.yaml
3055       :language: yaml
3056    """
3057    XML.SubElement(xml_parent, "com.cloudbees.jenkins.GitHubSetCommitStatusBuilder")
3058
3059
3060def scan_build(registry, xml_parent, data):
3061    """yaml: scan-build
3062    This plugin allows you configure a build step that will execute the Clang
3063    scan-build static analysis tool against an XCode project.
3064
3065    The scan-build report has to be generated in the directory
3066    ``${WORKSPACE}/clangScanBuildReports`` for the publisher to find it.
3067
3068    Requires the Jenkins :jenkins-plugins:`Clang Scan-Build Plugin
3069    <clang-scanbuild>`.
3070
3071    :arg str target: Provide the exact name of the XCode target you wish to
3072        have compiled and analyzed (required)
3073    :arg str target-sdk: Set the simulator version of a currently installed SDK
3074        (default iphonesimulator)
3075    :arg str config: Provide the XCode config you wish to execute scan-build
3076        against (default Debug)
3077    :arg str clang-install-name: Name of clang static analyzer to use (default
3078        '')
3079    :arg str xcode-sub-path: Path of XCode project relative to the workspace
3080        (default '')
3081    :arg str workspace: Name of workspace (default '')
3082    :arg str scheme: Name of scheme (default '')
3083    :arg str scan-build-args: Additional arguments to clang scan-build
3084        (default --use-analyzer Xcode)
3085    :arg str xcode-build-args: Additional arguments to XCode (default
3086        -derivedDataPath $WORKSPACE/build)
3087    :arg str report-folder: Folder where generated reports are located
3088        (>=1.7) (default clangScanBuildReports)
3089
3090    Full Example:
3091
3092    .. literalinclude:: /../../tests/builders/fixtures/scan-build-full.yaml
3093       :language: yaml
3094
3095    Minimal Example:
3096
3097    .. literalinclude::
3098       /../../tests/builders/fixtures/scan-build-minimal.yaml
3099       :language: yaml
3100    """
3101    p = XML.SubElement(
3102        xml_parent, "jenkins.plugins.clangscanbuild.ClangScanBuildBuilder"
3103    )
3104    p.set("plugin", "clang-scanbuild")
3105
3106    mappings = [
3107        ("target", "target", None),
3108        ("target-sdk", "targetSdk", "iphonesimulator"),
3109        ("config", "config", "Debug"),
3110        ("clang-install-name", "clangInstallationName", ""),
3111        ("xcode-sub-path", "xcodeProjectSubPath", "myProj/subfolder"),
3112        ("workspace", "workspace", ""),
3113        ("scheme", "scheme", ""),
3114        ("scan-build-args", "scanbuildargs", "--use-analyzer Xcode"),
3115        ("xcode-build-args", "xcodebuildargs", "-derivedDataPath $WORKSPACE/build"),
3116        ("report-folder", "outputFolderName", "clangScanBuildReports"),
3117    ]
3118    helpers.convert_mapping_to_xml(p, data, mappings, fail_required=True)
3119
3120
3121def ssh_builder(registry, xml_parent, data):
3122    """yaml: ssh-builder
3123    Executes command on remote host
3124
3125    Requires the Jenkins :jenkins-plugins:`SSH plugin <ssh>`.
3126
3127    :arg str ssh-user-ip: user@ip:ssh_port of machine that was defined
3128        in jenkins according to SSH plugin instructions
3129    :arg str command: command to run on remote server
3130
3131    Example:
3132
3133    .. literalinclude:: /../../tests/builders/fixtures/ssh-builder.yaml
3134       :language: yaml
3135    """
3136    builder = XML.SubElement(xml_parent, "org.jvnet.hudson.plugins.SSHBuilder")
3137
3138    mapping = [("ssh-user-ip", "siteName", None), ("command", "command", None)]
3139    helpers.convert_mapping_to_xml(builder, data, mapping, fail_required=True)
3140
3141
3142def sonar(registry, xml_parent, data):
3143    """yaml: sonar
3144    Invoke standalone Sonar analysis.
3145
3146    Requires the Jenkins `Sonar Plugin
3147    <https://docs.sonarqube.org/latest/analysis/scan/sonarscanner-for-jenkins>`_.
3148
3149    :arg str sonar-name: Name of the Sonar installation.
3150    :arg str sonar-scanner: Name of the Sonar Scanner.
3151    :arg str task: Task to run. (default '')
3152    :arg str project: Path to Sonar project properties file. (default '')
3153    :arg str properties: Sonar configuration properties. (default '')
3154    :arg str java-opts: Java options for Sonnar Runner. (default '')
3155    :arg str additional-arguments: additional command line arguments
3156        (default '')
3157    :arg str jdk: JDK to use (inherited from the job if omitted). (optional)
3158
3159    Example:
3160
3161    .. literalinclude:: /../../tests/builders/fixtures/sonar.yaml
3162       :language: yaml
3163    """
3164    sonar = XML.SubElement(xml_parent, "hudson.plugins.sonar.SonarRunnerBuilder")
3165    sonar.set("plugin", "sonar")
3166    XML.SubElement(sonar, "installationName").text = data["sonar-name"]
3167    mappings = [
3168        ("scanner-name", "sonarScannerName", ""),
3169        ("task", "task", ""),
3170        ("project", "project", ""),
3171        ("properties", "properties", ""),
3172        ("java-opts", "javaOpts", ""),
3173        ("additional-arguments", "additionalArguments", ""),
3174    ]
3175    helpers.convert_mapping_to_xml(sonar, data, mappings, fail_required=True)
3176    if "jdk" in data:
3177        XML.SubElement(sonar, "jdk").text = data["jdk"]
3178
3179
3180def xcode(registry, xml_parent, data):
3181    """yaml: xcode
3182    This step allows you to execute an xcode build step.
3183
3184    Requires the Jenkins :jenkins-plugins:`Xcode Plugin <xcode-plugin>`.
3185
3186    :arg str developer-profile: the jenkins credential id for a
3187        ios developer profile. (optional)
3188    :arg bool clean-build: if true will delete the build directories
3189        before invoking the build. (default false)
3190    :arg bool clean-test-reports: UNKNOWN. (default false)
3191    :arg bool archive: if true will generate an xcarchive of the specified
3192        scheme. A workspace and scheme are are also needed for archives.
3193        (default false)
3194    :arg str configuration: This is the name of the configuration
3195        as defined in the Xcode project. (default 'Release')
3196    :arg str configuration-directory: The value to use for
3197        CONFIGURATION_BUILD_DIR setting. (default '')
3198    :arg str target: Leave empty for all targets. (default '')
3199    :arg str sdk: Leave empty for default SDK. (default '')
3200    :arg str symroot: Leave empty for default SYMROOT. (default '')
3201    :arg str project-path: Relative path within the workspace
3202        that contains the xcode project file(s). (default '')
3203    :arg str project-file: Only needed if there is more than one
3204        project file in the Xcode Project Directory. (default '')
3205    :arg str build-arguments: Extra commandline arguments provided
3206        to the xcode builder. (default '')
3207    :arg str schema: Only needed if you want to compile for a
3208        specific schema instead of a target. (default '')
3209    :arg str workspace: Only needed if you want to compile a
3210        workspace instead of a project. (default '')
3211    :arg str profile: The relative path to the mobileprovision to embed,
3212        leave blank for no embedded profile. (default '')
3213    :arg str codesign-id: Override the code signing identity specified
3214        in the project. (default '')
3215    :arg bool allow-failing: if true will prevent this build step from
3216        failing if xcodebuild exits with a non-zero return code. (default
3217        false)
3218    :arg str version-technical: The value to use for CFBundleVersion.
3219        Leave blank to use project's technical number. (default '')
3220    :arg str version-marketing: The value to use for
3221        CFBundleShortVersionString. Leave blank to use project's
3222        marketing number. (default '')
3223    :arg str ipa-export-method: The export method of the .app to generate the
3224        .ipa file.  Should be one in 'development', 'ad-hoc', 'enterprise',
3225        or 'app-store'. (default '')
3226    :arg str ipa-version: A pattern for the ipa file name. You may use
3227        ${VERSION} and ${BUILD_DATE} (yyyy.MM.dd) in this string.
3228        (default '')
3229    :arg str ipa-output: The output directory for the .ipa file,
3230        relative to the build directory. (default '')
3231    :arg bool compile-bitcode: recompile from Bitcode when exporting the
3232        application to IPA. (default true)
3233    :arg bool upload-bitcode: include Bitcode when exporting applications to
3234        IPA. (default true)
3235    :arg bool upload-symbols: include symbols when exporting applications to
3236        IPA. (default true)
3237    :arg development-team-id: The ID of the Apple development team to use to
3238        sign the IPA (default '')
3239    :arg str keychain-name: The globally configured keychain to unlock for
3240        this build. (default '')
3241    :arg str keychain-path: The path of the keychain to use to sign the IPA.
3242        (default '')
3243    :arg str keychain-password: The password to use to unlock the keychain.
3244        (default '')
3245    :arg str keychain-unlock: Unlocks the keychain during use.
3246        (default false)
3247    :arg str bundle-id: The bundle identifier (App ID) for this provisioning
3248        profile (default '')
3249    :arg str provisioning-profile-uuid: The UUID of the provisioning profile
3250        associated to this bundle identifier. (default '')
3251
3252    Example:
3253
3254    .. literalinclude:: /../../tests/builders/fixtures/xcode.yaml
3255       :language: yaml
3256    """
3257
3258    if data.get("developer-profile"):
3259        profile = XML.SubElement(xml_parent, "au.com.rayh." "DeveloperProfileLoader")
3260        mapping = [("developer-profile", "id", None)]
3261        helpers.convert_mapping_to_xml(profile, data, mapping, fail_required=False)
3262
3263    xcode = XML.SubElement(xml_parent, "au.com.rayh.XCodeBuilder")
3264
3265    mappings = [
3266        ("clean-build", "cleanBeforeBuild", False),
3267        ("clean-test-reports", "cleanTestReports", False),
3268        ("archive", "generateArchive", False),
3269        ("configuration", "configuration", "Release"),
3270        ("configuration-directory", "configurationBuildDir", ""),
3271        ("target", "target", ""),
3272        ("sdk", "sdk", ""),
3273        ("symroot", "symRoot", ""),
3274        ("project-path", "xcodeProjectPath", ""),
3275        ("project-file", "xcodeProjectFile", ""),
3276        ("build-arguments", "xcodebuildArguments", ""),
3277        ("schema", "xcodeSchema", ""),
3278        ("workspace", "xcodeWorkspaceFile", ""),
3279        ("profile", "embeddedProfileFile", ""),
3280        ("codesign-id", "codeSigningIdentity", ""),
3281        ("allow-failing", "allowFailingBuildResults", False),
3282    ]
3283    helpers.convert_mapping_to_xml(xcode, data, mappings, fail_required=True)
3284
3285    version = XML.SubElement(xcode, "provideApplicationVersion")
3286    version_technical = XML.SubElement(xcode, "cfBundleVersionValue")
3287    version_marketing = XML.SubElement(xcode, "cfBundleShortVersionStringValue")
3288
3289    if data.get("version-technical") or data.get("version-marketing"):
3290        version.text = "true"
3291        version_technical.text = data.get("version-technical", "")
3292        version_marketing.text = data.get("version-marketing", "")
3293    else:
3294        version.text = "false"
3295
3296    XML.SubElement(xcode, "buildIpa").text = str(
3297        bool(data.get("ipa-version")) or False
3298    ).lower()
3299
3300    valid_ipa_export_methods = ["", "ad-hoc", "app-store", "development"]
3301    mapping = [
3302        ("ipa-export-method", "ipaExportMethod", "", valid_ipa_export_methods),
3303        ("ipa-version", "ipaName", ""),
3304        ("ipa-output", "ipaOutputDirectory", ""),
3305        ("development-team-id", "developmentTeamID", ""),
3306        ("keychain-name", "keychainName", ""),
3307        ("keychain-path", "keychainPath", ""),
3308        ("keychain-password", "keychainPwd", ""),
3309        ("keychain-unlock", "unlockKeychain", False),
3310        ("compile-bitcode", "compileBitcode", True),
3311        ("upload-bitcode", "uploadBitcode", True),
3312        ("upload-symbols", "uploadSymbols", True),
3313    ]
3314    helpers.convert_mapping_to_xml(xcode, data, mapping, fail_required=True)
3315
3316    has_provisioning_profiles = bool(data.get("provisioning-profiles"))
3317    XML.SubElement(xcode, "manualSigning").text = str(
3318        has_provisioning_profiles or False
3319    ).lower()
3320    if has_provisioning_profiles:
3321        provisioning_profiles_xml = XML.SubElement(xcode, "provisioningProfiles")
3322        mapping = [
3323            ("bundle-id", "provisioningProfileAppId", ""),
3324            ("provisioning-profile-uuid", "provisioningProfileUUID", ""),
3325        ]
3326        for provisioning_profile in data.get("provisioning-profiles"):
3327            provisioning_profile_xml = XML.SubElement(
3328                provisioning_profiles_xml, "au.com.rayh.ProvisioningProfile"
3329            )
3330            helpers.convert_mapping_to_xml(
3331                provisioning_profile_xml,
3332                provisioning_profile,
3333                mapping,
3334                fail_required=True,
3335            )
3336
3337
3338def sonatype_clm(registry, xml_parent, data):
3339    """yaml: sonatype-clm
3340    Requires the Jenkins Sonatype CLM Plugin.
3341
3342    WARNING: This plugin appears to be deprecated. There does not seem
3343    to be any place where it is available for download.
3344
3345    Try the :py:yamlfunction:`nexus-artifact-uploader` plugin instead.
3346
3347    :arg str value: Select CLM application from a list of available CLM
3348        applications or specify CLM Application ID (default list)
3349    :arg str application-name: Determines the policy elements to associate
3350        with this build. (required)
3351    :arg str username: Username on the Sonatype CLM server. Leave empty to
3352        use the username configured at global level. (default '')
3353    :arg str password: Password on the Sonatype CLM server. Leave empty to
3354        use the password configured at global level. (default '')
3355    :arg bool fail-on-clm-server-failure: Controls the build outcome if there
3356        is a failure in communicating with the CLM server. (default false)
3357    :arg str stage: Controls the stage the policy evaluation will be run
3358        against on the CLM server. Valid stages: build, stage-release, release,
3359        operate. (default 'build')
3360    :arg str scan-targets: Pattern of files to include for scanning.
3361        (default '')
3362    :arg str module-excludes: Pattern of files to exclude. (default '')
3363    :arg str advanced-options: Options to be set on a case-by-case basis as
3364        advised by Sonatype Support. (default '')
3365
3366    Minimal Example:
3367
3368    .. literalinclude::
3369        /../../tests/builders/fixtures/sonatype-clm-minimal.yaml
3370       :language: yaml
3371
3372    Full Example:
3373
3374    .. literalinclude::
3375        /../../tests/builders/fixtures/sonatype-clm-full.yaml
3376       :language: yaml
3377    """
3378    clm = XML.SubElement(xml_parent, "com.sonatype.insight.ci.hudson.PreBuildScan")
3379    clm.set("plugin", "sonatype-clm-ci")
3380    SUPPORTED_VALUES = ["list", "manual"]
3381    SUPPORTED_STAGES = ["build", "stage-release", "release", "operate"]
3382
3383    application_select = XML.SubElement(clm, "applicationSelectType")
3384    application_mappings = [
3385        ("value", "value", "list", SUPPORTED_VALUES),
3386        ("application-name", "applicationId", None),
3387    ]
3388    helpers.convert_mapping_to_xml(
3389        application_select, data, application_mappings, fail_required=True
3390    )
3391
3392    path = XML.SubElement(clm, "pathConfig")
3393    path_mappings = [
3394        ("scan-targets", "scanTargets", ""),
3395        ("module-excludes", "moduleExcludes", ""),
3396        ("advanced-options", "scanProperties", ""),
3397    ]
3398    helpers.convert_mapping_to_xml(path, data, path_mappings, fail_required=True)
3399
3400    mappings = [
3401        ("fail-on-clm-server-failure", "failOnClmServerFailures", False),
3402        ("stage", "stageId", "build", SUPPORTED_STAGES),
3403        ("username", "username", ""),
3404        ("password", "password", ""),
3405    ]
3406    helpers.convert_mapping_to_xml(clm, data, mappings, fail_required=True)
3407
3408
3409def beaker(registry, xml_parent, data):
3410    """yaml: beaker
3411    Execute a beaker build step.
3412
3413    Requires the Jenkins :jenkins-plugins:`Beaker Builder Plugin
3414    <beaker-builder>`.
3415
3416    :arg str content: Run job from string
3417        (Alternative: you can choose a path instead)
3418    :arg str path: Run job from file
3419        (Alternative: you can choose a content instead)
3420    :arg bool download-logs: Download Beaker log files (default false)
3421
3422    Example:
3423
3424    .. literalinclude:: ../../tests/builders/fixtures/beaker-path.yaml
3425       :language: yaml
3426
3427    .. literalinclude:: ../../tests/builders/fixtures/beaker-content.yaml
3428       :language: yaml
3429    """
3430    beaker = XML.SubElement(
3431        xml_parent, "org.jenkinsci.plugins.beakerbuilder." "BeakerBuilder"
3432    )
3433    jobSource = XML.SubElement(beaker, "jobSource")
3434    if "content" in data and "path" in data:
3435        raise JenkinsJobsException("Use just one of 'content' or 'path'")
3436    elif "content" in data:
3437        jobSourceClass = "org.jenkinsci.plugins.beakerbuilder.StringJobSource"
3438        jobSource.set("class", jobSourceClass)
3439        XML.SubElement(jobSource, "jobContent").text = data["content"]
3440    elif "path" in data:
3441        jobSourceClass = "org.jenkinsci.plugins.beakerbuilder.FileJobSource"
3442        jobSource.set("class", jobSourceClass)
3443        XML.SubElement(jobSource, "jobPath").text = data["path"]
3444    else:
3445        raise JenkinsJobsException("Use one of 'content' or 'path'")
3446
3447    XML.SubElement(beaker, "downloadFiles").text = str(
3448        data.get("download-logs", False)
3449    ).lower()
3450
3451
3452def cloudformation(registry, xml_parent, data):
3453    """yaml: cloudformation
3454    Create cloudformation stacks before running a build and optionally
3455    delete them at the end.
3456
3457    Requires the Jenkins :jenkins-plugins:`AWS Cloudformation Plugin
3458    <jenkins-cloudformation-plugin>`.
3459
3460    :arg list name: The names of the stacks to create (required)
3461    :arg str description: Description of the stack (optional)
3462    :arg str recipe: The cloudformation recipe file (required)
3463    :arg list parameters: List of key/value pairs to pass
3464        into the recipe, will be joined together into a comma separated
3465        string (optional)
3466    :arg int timeout: Number of seconds to wait before giving up creating
3467        a stack (default 0)
3468    :arg str access-key: The Amazon API Access Key (required)
3469    :arg str secret-key: The Amazon API Secret Key (required)
3470    :arg int sleep: Number of seconds to wait before continuing to the
3471        next step (default 0)
3472    :arg str region: The region to run cloudformation in (required)
3473
3474        :region values:
3475            * **us-east-1**
3476            * **us-west-1**
3477            * **us-west-2**
3478            * **eu-central-1**
3479            * **eu-west-1**
3480            * **ap-southeast-1**
3481            * **ap-southeast-2**
3482            * **ap-northeast-1**
3483            * **sa-east-1**
3484
3485    Example:
3486
3487    .. literalinclude:: ../../tests/builders/fixtures/cloudformation.yaml
3488       :language: yaml
3489    """
3490    region_dict = helpers.cloudformation_region_dict()
3491    stacks = helpers.cloudformation_init(xml_parent, data, "CloudFormationBuildStep")
3492    for stack in data:
3493        helpers.cloudformation_stack(
3494            xml_parent, stack, "PostBuildStackBean", stacks, region_dict
3495        )
3496
3497
3498def jms_messaging(registry, xml_parent, data):
3499    """yaml: jms-messaging
3500    The JMS Messaging Plugin provides the following functionality:
3501     - A build trigger to submit jenkins jobs upon receipt
3502       of a matching message.
3503     - A builder that may be used to submit a message to the topic
3504       upon the completion of a job
3505     - A post-build action that may be used to submit a message to the topic
3506       upon the completion of a job
3507
3508
3509    JMS Messaging provider types supported:
3510        - ActiveMQ
3511        - FedMsg
3512
3513    Requires the Jenkins :jenkins-plugins:`JMS Messaging Plugin Pipeline Plugin
3514    <jms-messaging>`.
3515
3516    :arg str override-topic: If you need to override the default topic.
3517        (default '')
3518    :arg str provider-name: Name of message provider setup in the
3519        global config. (default '')
3520    :arg str msg-type: A message type
3521        (default 'CodeQualityChecksDone')
3522    :arg str msg-props: Message header to publish. (default '')
3523    :arg str msg-content: Message body to publish. (default '')
3524
3525
3526    Full Example:
3527
3528    .. literalinclude::
3529        ../../tests/builders/fixtures/jms-messaging-full.yaml
3530       :language: yaml
3531
3532    Minimal Example:
3533
3534    .. literalinclude::
3535        ../../tests/builders/fixtures/jms-messaging-minimal.yaml
3536       :language: yaml
3537    """
3538    helpers.jms_messaging_common(
3539        xml_parent, "com.redhat.jenkins.plugins.ci." "CIMessageBuilder", data
3540    )
3541
3542
3543def openshift_build_verify(registry, xml_parent, data):
3544    r"""yaml: openshift-build-verify
3545    Performs the equivalent of an 'oc get builds` command invocation for the
3546    provided buildConfig key provided; once the list of builds are obtained,
3547    the state of the latest build is inspected for up to a minute to see if
3548    it has completed successfully.
3549
3550    Requires the Jenkins :jenkins-plugins:`OpenShift Pipeline Plugin
3551    <openshift-pipeline>`.
3552
3553    :arg str api-url: this would be the value you specify if you leverage the
3554        --server option on the OpenShift `oc` command.
3555        (default '\https://openshift.default.svc.cluster.local')
3556    :arg str bld-cfg: The value here should be whatever was the output
3557        form `oc project` when you created the BuildConfig you
3558        want to run a Build on (default 'frontend')
3559    :arg str namespace: If you run `oc get bc` for the project listed in
3560        "namespace", that is the value you want to put here. (default 'test')
3561    :arg str auth-token: The value here is what you supply with the --token
3562        option when invoking the OpenShift `oc` command. (default '')
3563    :arg bool verbose: This flag is the toggle for
3564        turning on or off detailed logging in this plug-in. (default false)
3565
3566    Full Example:
3567
3568    .. literalinclude::
3569        ../../tests/builders/fixtures/openshift-build-verify001.yaml
3570       :language: yaml
3571
3572    Minimal Example:
3573
3574    .. literalinclude::
3575        ../../tests/builders/fixtures/openshift-build-verify002.yaml
3576       :language: yaml
3577    """
3578    osb = XML.SubElement(
3579        xml_parent, "com.openshift.jenkins.plugins.pipeline." "OpenShiftBuildVerifier"
3580    )
3581
3582    mapping = [
3583        # option, xml name, default value
3584        ("api-url", "apiURL", "https://openshift.default.svc.cluster.local"),
3585        ("bld-cfg", "bldCfg", "frontend"),
3586        ("namespace", "namespace", "test"),
3587        ("auth-token", "authToken", ""),
3588        ("verbose", "verbose", False),
3589    ]
3590    helpers.convert_mapping_to_xml(osb, data, mapping, fail_required=True)
3591
3592
3593def openshift_builder(registry, xml_parent, data):
3594    r"""yaml: openshift-builder
3595    Perform builds in OpenShift for the job.
3596
3597    Requires the Jenkins :jenkins-plugins:`OpenShift Pipeline Plugin
3598    <openshift-pipeline>`.
3599
3600    :arg str api-url: this would be the value you specify if you leverage the
3601        --server option on the OpenShift `oc` command.
3602        (default '\https://openshift.default.svc.cluster.local')
3603    :arg str bld-cfg: The value here should be whatever was the output
3604        form `oc project` when you created the BuildConfig you want to run a
3605        Build on (default 'frontend')
3606    :arg str namespace: If you run `oc get bc` for the project listed in
3607        "namespace", that is the value you want to put here. (default 'test')
3608    :arg str auth-token: The value here is what you supply with the --token
3609        option when invoking the OpenShift `oc` command. (default '')
3610    :arg str commit-ID: The value here is what you supply with the
3611        --commit option when invoking the
3612        OpenShift `oc start-build` command. (default '')
3613    :arg bool verbose: This flag is the toggle for
3614        turning on or off detailed logging in this plug-in. (default false)
3615    :arg str build-name: TThe value here is what you supply with the
3616        --from-build option when invoking the
3617        OpenShift `oc start-build` command. (default '')
3618    :arg bool show-build-logs: Indicates whether the build logs get dumped
3619        to the console of the Jenkins build. (default false)
3620
3621
3622    Full Example:
3623
3624    .. literalinclude:: ../../tests/builders/fixtures/openshift-builder001.yaml
3625       :language: yaml
3626
3627    Minimal Example:
3628
3629    .. literalinclude:: ../../tests/builders/fixtures/openshift-builder002.yaml
3630       :language: yaml
3631    """
3632    osb = XML.SubElement(
3633        xml_parent, "com.openshift.jenkins.plugins.pipeline." "OpenShiftBuilder"
3634    )
3635
3636    mapping = [
3637        # option, xml name, default value
3638        ("api-url", "apiURL", "https://openshift.default.svc.cluster.local"),
3639        ("bld-cfg", "bldCfg", "frontend"),
3640        ("namespace", "namespace", "test"),
3641        ("auth-token", "authToken", ""),
3642        ("commit-ID", "commitID", ""),
3643        ("verbose", "verbose", False),
3644        ("build-name", "buildName", ""),
3645        ("show-build-logs", "showBuildLogs", False),
3646    ]
3647    helpers.convert_mapping_to_xml(osb, data, mapping, fail_required=True)
3648
3649
3650def openshift_creator(registry, xml_parent, data):
3651    r"""yaml: openshift-creator
3652    Performs the equivalent of an oc create command invocation;
3653    this build step takes in the provided JSON or YAML text, and if it
3654    conforms to OpenShift schema, creates whichever
3655    OpenShift resources are specified.
3656
3657    Requires the Jenkins :jenkins-plugins:`OpenShift Pipeline Plugin
3658    <openshift-pipeline>`.
3659
3660    :arg str api-url: this would be the value you specify if you leverage the
3661        --server option on the OpenShift `oc` command.
3662        (default '\https://openshift.default.svc.cluster.local')
3663    :arg str jsonyaml: The JSON or YAML formatted text that conforms to
3664        the schema for defining the various OpenShift resources. (default '')
3665    :arg str namespace: If you run `oc get bc` for the project listed in
3666        "namespace", that is the value you want to put here. (default 'test')
3667    :arg str auth-token: The value here is what you supply with the --token
3668        option when invoking the OpenShift `oc` command. (default '')
3669    :arg bool verbose: This flag is the toggle for
3670        turning on or off detailed logging in this plug-in. (default false)
3671
3672    Full Example:
3673
3674    .. literalinclude::
3675        ../../tests/builders/fixtures/openshift-creator001.yaml
3676       :language: yaml
3677
3678    Minimal Example:
3679
3680    .. literalinclude::
3681        ../../tests/builders/fixtures/openshift-creator002.yaml
3682       :language: yaml
3683    """
3684    osb = XML.SubElement(
3685        xml_parent, "com.openshift.jenkins.plugins.pipeline." "OpenShiftCreator"
3686    )
3687
3688    mapping = [
3689        # option, xml name, default value
3690        ("api-url", "apiURL", "https://openshift.default.svc.cluster.local"),
3691        ("jsonyaml", "jsonyaml", ""),
3692        ("namespace", "namespace", "test"),
3693        ("auth-token", "authToken", ""),
3694        ("verbose", "verbose", False),
3695    ]
3696    helpers.convert_mapping_to_xml(osb, data, mapping, fail_required=True)
3697
3698
3699def openshift_dep_verify(registry, xml_parent, data):
3700    r"""yaml: openshift-dep-verify
3701    Determines whether the expected set of DeploymentConfig's,
3702    ReplicationController's, and active replicas are present based on prior
3703    use of the scaler (2) and deployer (3) steps
3704
3705    Requires the Jenkins :jenkins-plugins:`OpenShift Pipeline Plugin
3706    <openshift-pipeline>`.
3707
3708    :arg str api-url: this would be the value you specify if you leverage the
3709        --server option on the OpenShift `oc` command.
3710        (default \https://openshift.default.svc.cluster.local\)
3711    :arg str dep-cfg: The value here should be whatever was the output
3712        form `oc project` when you created the BuildConfig you want to run a
3713        Build on (default frontend)
3714    :arg str namespace: If you run `oc get bc` for the project listed in
3715        "namespace", that is the value you want to put here. (default test)
3716    :arg int replica-count: The value here should be whatever the number
3717        of pods you want started for the deployment. (default 0)
3718    :arg str auth-token: The value here is what you supply with the --token
3719        option when invoking the OpenShift `oc` command. (default '')
3720    :arg bool verbose: This flag is the toggle for
3721        turning on or off detailed logging in this plug-in. (default false)
3722
3723    Full Example:
3724
3725    .. literalinclude::
3726        ../../tests/builders/fixtures/openshift-dep-verify001.yaml
3727       :language: yaml
3728
3729    Minimal Example:
3730
3731    .. literalinclude::
3732        ../../tests/builders/fixtures/openshift-dep-verify002.yaml
3733       :language: yaml
3734    """
3735    osb = XML.SubElement(
3736        xml_parent,
3737        "com.openshift.jenkins.plugins.pipeline." "OpenShiftDeploymentVerifier",
3738    )
3739
3740    mapping = [
3741        # option, xml name, default value
3742        ("api-url", "apiURL", "https://openshift.default.svc.cluster.local"),
3743        ("dep-cfg", "depCfg", "frontend"),
3744        ("namespace", "namespace", "test"),
3745        ("replica-count", "replicaCount", 0),
3746        ("auth-token", "authToken", ""),
3747        ("verbose", "verbose", False),
3748    ]
3749    helpers.convert_mapping_to_xml(osb, data, mapping, fail_required=True)
3750
3751
3752def openshift_deployer(registry, xml_parent, data):
3753    r"""yaml: openshift-deployer
3754    Start a deployment in OpenShift for the job.
3755
3756    Requires the Jenkins :jenkins-plugins:`OpenShift Pipeline Plugin
3757    <openshift-pipeline>`.
3758
3759    :arg str api-url: this would be the value you specify if you leverage the
3760        --server option on the OpenShift `oc` command.
3761        (default '\https://openshift.default.svc.cluster.local')
3762    :arg str dep-cfg: The value here should be whatever was the output
3763        form `oc project` when you created the BuildConfig you want to run a
3764        Build on (default 'frontend')
3765    :arg str namespace: If you run `oc get bc` for the project listed in
3766        "namespace", that is the value you want to put here. (default 'test')
3767    :arg str auth-token: The value here is what you supply with the --token
3768        option when invoking the OpenShift `oc` command. (default '')
3769    :arg bool verbose: This flag is the toggle for
3770        turning on or off detailed logging in this plug-in. (default false)
3771
3772    Full Example:
3773
3774    .. literalinclude::
3775        ../../tests/builders/fixtures/openshift-deployer001.yaml
3776       :language: yaml
3777
3778    Minimal Example:
3779
3780    .. literalinclude::
3781        ../../tests/builders/fixtures/openshift-deployer002.yaml
3782       :language: yaml
3783    """
3784    osb = XML.SubElement(
3785        xml_parent, "com.openshift.jenkins.plugins.pipeline." "OpenShiftDeployer"
3786    )
3787
3788    mapping = [
3789        # option, xml name, default value
3790        ("api-url", "apiURL", "https://openshift.default.svc.cluster.local"),
3791        ("dep-cfg", "depCfg", "frontend"),
3792        ("namespace", "namespace", "test"),
3793        ("auth-token", "authToken", ""),
3794        ("verbose", "verbose", False),
3795    ]
3796    helpers.convert_mapping_to_xml(osb, data, mapping, fail_required=True)
3797
3798
3799def openshift_img_tagger(registry, xml_parent, data):
3800    r"""yaml: openshift-img-tagger
3801    Performs the equivalent of an oc tag command invocation in order to
3802    manipulate tags for images in OpenShift ImageStream's
3803
3804    Requires the Jenkins :jenkins-plugins:`OpenShift Pipeline Plugin
3805    <openshift-pipeline>`.
3806
3807    :arg str api-url: this would be the value you specify if you leverage the
3808        --server option on the OpenShift `oc` command.
3809        (default '\https://openshift.default.svc.cluster.local')
3810    :arg str test-tag: The equivalent to the name supplied to a
3811        `oc get service` command line invocation.
3812        (default 'origin-nodejs-sample:latest')
3813    :arg str prod-tag: The equivalent to the name supplied to a
3814        `oc get service` command line invocation.
3815        (default 'origin-nodejs-sample:prod')
3816    :arg str namespace: If you run `oc get bc` for the project listed in
3817        "namespace", that is the value you want to put here. (default 'test')
3818    :arg str auth-token: The value here is what you supply with the --token
3819        option when invoking the OpenShift `oc` command. (default '')
3820    :arg bool verbose: This flag is the toggle for
3821        turning on or off detailed logging in this plug-in. (default false)
3822
3823    Full Example:
3824
3825    .. literalinclude::
3826        ../../tests/builders/fixtures/openshift-img-tagger001.yaml
3827       :language: yaml
3828
3829    Minimal Example:
3830
3831    .. literalinclude::
3832        ../../tests/builders/fixtures/openshift-img-tagger002.yaml
3833       :language: yaml
3834    """
3835    osb = XML.SubElement(
3836        xml_parent, "com.openshift.jenkins.plugins.pipeline." "OpenShiftImageTagger"
3837    )
3838
3839    mapping = [
3840        # option, xml name, default value
3841        ("api-url", "apiURL", "https://openshift.default.svc.cluster.local"),
3842        ("test-tag", "testTag", "origin-nodejs-sample:latest"),
3843        ("prod-tag", "prodTag", "origin-nodejs-sample:prod"),
3844        ("namespace", "namespace", "test"),
3845        ("auth-token", "authToken", ""),
3846        ("verbose", "verbose", False),
3847    ]
3848    helpers.convert_mapping_to_xml(osb, data, mapping, fail_required=True)
3849
3850
3851def openshift_scaler(registry, xml_parent, data):
3852    r"""yaml: openshift-scaler
3853    Scale deployments in OpenShift for the job.
3854
3855    Requires the Jenkins :jenkins-plugins:`OpenShift Pipeline Plugin
3856    <openshift-pipeline>`.
3857
3858    :arg str api-url: this would be the value you specify if you leverage the
3859        --server option on the OpenShift `oc` command.
3860        (default '\https://openshift.default.svc.cluster.local')
3861    :arg str dep-cfg: The value here should be whatever was the output
3862        form `oc project` when you created the BuildConfig you want to run a
3863        Build on (default 'frontend')
3864    :arg str namespace: If you run `oc get bc` for the project listed in
3865        "namespace", that is the value you want to put here. (default 'test')
3866    :arg int replica-count: The value here should be whatever the number
3867        of pods you want started for the deployment. (default 0)
3868    :arg str auth-token: The value here is what you supply with the --token
3869        option when invoking the OpenShift `oc` command. (default '')
3870    :arg bool verbose: This flag is the toggle for
3871        turning on or off detailed logging in this plug-in. (default false)
3872
3873    Full Example:
3874
3875    .. literalinclude:: ../../tests/builders/fixtures/openshift-scaler001.yaml
3876       :language: yaml
3877
3878    Minimal Example:
3879
3880    .. literalinclude:: ../../tests/builders/fixtures/openshift-scaler002.yaml
3881       :language: yaml
3882    """
3883    osb = XML.SubElement(
3884        xml_parent, "com.openshift.jenkins.plugins.pipeline." "OpenShiftScaler"
3885    )
3886
3887    mapping = [
3888        # option, xml name, default value
3889        ("api-url", "apiURL", "https://openshift.default.svc.cluster.local"),
3890        ("dep-cfg", "depCfg", "frontend"),
3891        ("namespace", "namespace", "test"),
3892        ("replica-count", "replicaCount", 0),
3893        ("auth-token", "authToken", ""),
3894        ("verbose", "verbose", False),
3895    ]
3896    helpers.convert_mapping_to_xml(osb, data, mapping, fail_required=True)
3897
3898
3899def openshift_svc_verify(registry, xml_parent, data):
3900    r"""yaml: openshift-svc-verify
3901    Verify a service is up in OpenShift for the job.
3902
3903    Requires the Jenkins :jenkins-plugins:`OpenShift Pipeline Plugin
3904    <openshift-pipeline>`.
3905
3906    :arg str api-url: this would be the value you specify if you leverage the
3907        --server option on the OpenShift `oc` command.
3908        (default '\https://openshift.default.svc.cluster.local')
3909    :arg str svc-name: The equivalent to the name supplied to a
3910        `oc get service` command line invocation. (default 'frontend')
3911    :arg str namespace: If you run `oc get bc` for the project listed in
3912        "namespace", that is the value you want to put here. (default 'test')
3913    :arg str auth-token: The value here is what you supply with the --token
3914        option when invoking the OpenShift `oc` command. (default '')
3915    :arg bool verbose: This flag is the toggle for
3916        turning on or off detailed logging in this plug-in. (default false)
3917
3918    Full Example:
3919
3920    .. literalinclude::
3921        ../../tests/builders/fixtures/openshift-svc-verify001.yaml
3922       :language: yaml
3923
3924    Minimal Example:
3925
3926    .. literalinclude::
3927        ../../tests/builders/fixtures/openshift-svc-verify002.yaml
3928       :language: yaml
3929    """
3930    osb = XML.SubElement(
3931        xml_parent, "com.openshift.jenkins.plugins.pipeline." "OpenShiftServiceVerifier"
3932    )
3933
3934    mapping = [
3935        # option, xml name, default value
3936        ("api-url", "apiURL", "https://openshift.default.svc.cluster.local"),
3937        ("svc-name", "svcName", "frontend"),
3938        ("namespace", "namespace", "test"),
3939        ("auth-token", "authToken", ""),
3940        ("verbose", "verbose", False),
3941    ]
3942    helpers.convert_mapping_to_xml(osb, data, mapping, fail_required=True)
3943
3944
3945def runscope(registry, xml_parent, data):
3946    """yaml: runscope
3947    Execute a Runscope test.
3948
3949    Requires the Jenkins :jenkins-plugins:`Runscope Plugin <runscope>`.
3950
3951    :arg str test-trigger-url: Trigger URL for test. (required)
3952    :arg str access-token: OAuth Personal Access token. (required)
3953    :arg int timeout: Timeout for test duration in seconds. (default 60)
3954
3955    Minimal Example:
3956
3957    .. literalinclude:: /../../tests/builders/fixtures/runscope-minimal.yaml
3958       :language: yaml
3959
3960    Full Example:
3961
3962    .. literalinclude:: /../../tests/builders/fixtures/runscope-full.yaml
3963       :language: yaml
3964    """
3965    runscope = XML.SubElement(
3966        xml_parent, "com.runscope.jenkins.Runscope.RunscopeBuilder"
3967    )
3968    runscope.set("plugin", "runscope")
3969
3970    mapping = [
3971        ("test-trigger-url", "triggerEndPoint", None),
3972        ("access-token", "accessToken", None),
3973        ("timeout", "timeout", 60),
3974    ]
3975    helpers.convert_mapping_to_xml(runscope, data, mapping, fail_required=True)
3976
3977
3978def description_setter(registry, xml_parent, data):
3979    """yaml: description-setter
3980    This plugin sets the description for each build,
3981    based upon a RegEx test of the build log file.
3982
3983    Requires the Jenkins :jenkins-plugins:`Description Setter Plugin
3984    <description-setter>`.
3985
3986    :arg str regexp: A RegEx which is used to scan the build log file
3987        (default '')
3988    :arg str description: The description to set on the build (optional)
3989
3990    Example:
3991
3992    .. literalinclude::
3993        /../../tests/builders/fixtures/description-setter001.yaml
3994       :language: yaml
3995    """
3996
3997    descriptionsetter = XML.SubElement(
3998        xml_parent, "hudson.plugins.descriptionsetter.DescriptionSetterBuilder"
3999    )
4000    mapping = [("regexp", "regexp", "")]
4001    if "description" in data:
4002        mapping.append(("description", "description", None))
4003    helpers.convert_mapping_to_xml(descriptionsetter, data, mapping, fail_required=True)
4004
4005
4006def build_publish_docker_image(registry, xml_parent, data):
4007    """yaml: build-publish-docker-image
4008    Provides the ability to build projects with a Dockerfile and publish the
4009    resultant tagged image (repo) to the docker registry.
4010
4011    Requires the Jenkins :jenkins-plugins:`CloudBees Docker Build and Publish
4012    plugin <docker-build-publish>`.
4013
4014    :arg str docker-registry-url: URL to the Docker registry you are
4015        using (default '')
4016    :arg str image: Repository name to be applied to the resulting image
4017        in case of success (default '')
4018    :arg str docker-file-directory: Build step that sends a Dockerfile for
4019        building to docker host that used for this build run (default '')
4020    :arg bool push-on-success: Resulting docker image will be pushed to
4021        the registry (or registries) specified within the
4022        "Image" field (default false)
4023    :arg str push-credentials-id: Credentials to push to a private
4024        registry (default '')
4025    :arg bool clean-images: Option to clean local images (default false)
4026    :arg bool jenkins-job-delete: Attempt to remove images when jenkins
4027        deletes the run (default false)
4028    :arg str cloud: Cloud to use to build image (default '')
4029
4030    Minimal example:
4031
4032    .. literalinclude::
4033        /../../tests/builders/fixtures/build-publish-docker-image-minimal.yaml
4034
4035    Full example:
4036
4037    .. literalinclude::
4038        /../../tests/builders/fixtures/build-publish-docker-image-full.yaml
4039    """
4040    dbp = XML.SubElement(
4041        xml_parent,
4042        "com.nirima.jenkins.plugins.docker.builder" ".DockerBuilderPublisher",
4043    )
4044    dbp.set("plugin", "docker-plugin")
4045
4046    from_registry = XML.SubElement(dbp, "fromRegistry")
4047    from_registry.set("plugin", "docker-commons")
4048    from_registry_mapping = [("docker-registry-url", "url", "")]
4049    helpers.convert_mapping_to_xml(
4050        from_registry, data, from_registry_mapping, fail_required=False
4051    )
4052
4053    tags = XML.SubElement(dbp, "tags")
4054    XML.SubElement(tags, "string").text = data.get("image", "")
4055
4056    mapping = [
4057        ("docker-file-directory", "dockerFileDirectory", ""),
4058        ("push-on-success", "pushOnSuccess", False),
4059        ("push-credentials-id", "pushCredentialsId", ""),
4060        ("clean-images", "cleanImages", False),
4061        ("jenkins-job-delete", "cleanupWithJenkinsJobDelete", False),
4062        ("cloud", "cloud", ""),
4063    ]
4064    helpers.convert_mapping_to_xml(dbp, data, mapping, fail_required=False)
4065
4066
4067def docker_build_publish(parse, xml_parent, data):
4068    """yaml: docker-build-publish
4069    Provides the ability to build projects with a Dockerfile, and publish the
4070    resultant tagged image (repo) to the docker registry.
4071
4072    Requires the Jenkins :jenkins-plugins:`Docker build publish Plugin
4073    <docker-build-publish>`.
4074
4075    :arg str repo-name: Name of repository to push to.
4076    :arg str repo-tag: Tag for image. (default '')
4077    :arg dict server: The docker daemon (optional)
4078
4079        * **uri** (str): Define the docker server to use. (optional)
4080        * **credentials-id** (str): ID of credentials to use to connect
4081          (optional)
4082    :arg dict registry: Registry to push to
4083
4084        * **url** (str) repository url to use (optional)
4085        * **credentials-id** (str): ID of credentials to use to connect
4086          (optional)
4087    :arg bool no-cache: If build should be cached. (default false)
4088    :arg bool no-force-pull: Don't update the source image before building when
4089        it exists locally. (default false)
4090    :arg bool skip-build: Do not build the image. (default false)
4091    :arg bool skip-decorate: Do not decorate the build name. (default false)
4092    :arg bool skip-tag-latest: Do not tag this build as latest. (default false)
4093    :arg bool skip-push: Do not push. (default false)
4094    :arg str file-path: Path of the Dockerfile. (default '')
4095    :arg str build-context: Project root path for the build, defaults to the
4096        workspace if not specified. (default '')
4097    :arg bool create-fingerprint: If enabled, the plugin will create
4098        fingerprints after the build of each image. (default false)
4099    :arg str build-args: Additional build arguments passed to
4100        docker build (default '')
4101    :arg bool force-tag: Force tag replacement when tag already
4102        exists (default false)
4103
4104    Minimal example:
4105
4106    .. literalinclude:: /../../tests/builders/fixtures/docker-builder001.yaml
4107
4108    Full example:
4109
4110    .. literalinclude:: /../../tests/builders/fixtures/docker-builder002.yaml
4111    """
4112    db = XML.SubElement(xml_parent, "com.cloudbees.dockerpublish.DockerBuilder")
4113    db.set("plugin", "docker-build-publish")
4114
4115    mapping = [
4116        ("repo-name", "repoName", None),
4117        ("repo-tag", "repoTag", ""),
4118        ("no-cache", "noCache", False),
4119        ("no-force-pull", "noForcePull", False),
4120        ("skip-build", "skipBuild", False),
4121        ("skip-decorate", "skipDecorate", False),
4122        ("skip-tag-latest", "skipTagLatest", False),
4123        ("skip-push", "skipPush", False),
4124        ("file-path", "dockerfilePath", ""),
4125        ("build-context", "buildContext", ""),
4126        ("create-fingerprint", "createFingerprint", False),
4127        ("build-args", "buildAdditionalArgs", ""),
4128        ("force-tag", "forceTag", False),
4129    ]
4130    helpers.convert_mapping_to_xml(db, data, mapping, fail_required=True)
4131
4132    mapping = []
4133    if "server" in data:
4134        server = XML.SubElement(db, "server")
4135        server.set("plugin", "docker-commons")
4136        server_data = data["server"]
4137        if "credentials-id" in server_data:
4138            mapping.append(("credentials-id", "credentialsId", None))
4139
4140        if "uri" in server_data:
4141            mapping.append(("uri", "uri", None))
4142        helpers.convert_mapping_to_xml(server, server_data, mapping, fail_required=True)
4143
4144    mappings = []
4145    if "registry" in data:
4146        registry = XML.SubElement(db, "registry")
4147        registry.set("plugin", "docker-commons")
4148        registry_data = data["registry"]
4149        if "credentials-id" in registry_data:
4150            mappings.append(("credentials-id", "credentialsId", None))
4151
4152        if "url" in registry_data:
4153            mappings.append(("url", "url", None))
4154        helpers.convert_mapping_to_xml(
4155            registry, registry_data, mappings, fail_required=True
4156        )
4157
4158
4159def docker_pull_image(registry, xml_parent, data):
4160    """yaml: docker-pull-image
4161    Provides integration between Jenkins and Docker Hub, utilizing a
4162    Docker Hub hook to trigger one (or more) Jenkins job(s).
4163
4164    Requires the Jenkins :jenkins-plugins:`CloudBees Docker Hub Notification
4165    <dockerhub-notification>`.
4166
4167    :arg str image: Image ID on DockerHub (default '')
4168    :arg str docker-registry-url: URL to the Docker registry
4169        you are using (default '')
4170    :arg str credentials-id: Registry credentials (default '')
4171
4172    Minimal example:
4173
4174    .. literalinclude::
4175        /../../tests/builders/fixtures/docker-pull-image-minimal.yaml
4176
4177    Full example:
4178
4179    .. literalinclude::
4180        /../../tests/builders/fixtures/docker-pull-image-full.yaml
4181    """
4182    docker_pull_image = XML.SubElement(
4183        xml_parent,
4184        "org.jenkinsci.plugins.registry." "notification.DockerPullImageBuilder",
4185    )
4186    docker_pull_image.set("plugin", "dockerhub-notification")
4187    registry = XML.SubElement(docker_pull_image, "registry")
4188    registry.set("plugin", "docker-commons")
4189    mapping = [("image", "image", "")]
4190    helpers.convert_mapping_to_xml(
4191        docker_pull_image, data, mapping, fail_required=False
4192    )
4193    registry_mapping = [
4194        ("docker-registry-url", "url", ""),
4195        ("credentials-id", "credentialsId", ""),
4196    ]
4197    helpers.convert_mapping_to_xml(
4198        registry, data, registry_mapping, fail_required=False
4199    )
4200
4201
4202def build_name_setter(registry, xml_parent, data):
4203    """yaml: build-name-setter
4204    Define Build Name Setter options which allows your build name to be
4205    updated during the build process.
4206
4207    Requires the Jenkins :jenkins-plugins:`Build Name Setter Plugin
4208    <build-name-setter>`.
4209
4210    :arg str name: Filename to use for Build Name Setter, only used if
4211        file bool is true. (default 'version.txt')
4212    :arg str template: Macro Template string, only used if macro
4213        bool is true. (default '#${BUILD_NUMBER}')
4214    :arg bool file: Read from named file (default false)
4215    :arg bool macro: Read from macro template (default false)
4216    :arg bool macro-first: Insert macro first (default false)
4217
4218    File Example:
4219
4220    .. literalinclude::
4221        /../../tests/builders/fixtures/build-name-setter001.yaml
4222       :language: yaml
4223
4224    Macro Example:
4225
4226    .. literalinclude::
4227        /../../tests/builders/fixtures/build-name-setter002.yaml
4228       :language: yaml
4229    """
4230    build_name_setter = XML.SubElement(
4231        xml_parent, "org.jenkinsci.plugins.buildnameupdater.BuildNameUpdater"
4232    )
4233    mapping = [
4234        ("name", "buildName", "version.txt"),
4235        ("template", "macroTemplate", "#${BUILD_NUMBER}"),
4236        ("file", "fromFile", False),
4237        ("macro", "fromMacro", False),
4238        ("macro-first", "macroFirst", False),
4239    ]
4240    helpers.convert_mapping_to_xml(build_name_setter, data, mapping, fail_required=True)
4241
4242
4243def nexus_artifact_uploader(registry, xml_parent, data):
4244    """yaml: nexus-artifact-uploader
4245
4246    To upload result of a build as an artifact in Nexus without the need of
4247    Maven.
4248
4249    Requires the Jenkins :jenkins-plugins:`Nexus Artifact Uploader Plugin
4250    <nexus-artifact-uploader>`.
4251
4252    :arg str protocol: Protocol to use to connect to Nexus (default https)
4253    :arg str nexus_url: Nexus url (without protocol) (default '')
4254    :arg str nexus_user: Username to upload artifact to Nexus (default '')
4255    :arg str nexus_password: Password to upload artifact to Nexus
4256        (default '')
4257    :arg str group_id: GroupId to set for the artifact to upload
4258        (default '')
4259    :arg str artifact_id: ArtifactId to set for the artifact to upload
4260        (default '')
4261    :arg str version: Version to set for the artifact to upload
4262        (default '')
4263    :arg str packaging: Packaging to set for the artifact to upload
4264        (default '')
4265    :arg str type: Type to set for the artifact to upload (default '')
4266    :arg str classifier: Classifier to set for the artifact to upload
4267        (default '')
4268    :arg str repository: In which repository to upload the artifact
4269        (default '')
4270    :arg str file: File which will be the uploaded artifact (default '')
4271    :arg str credentials_id: Credentials to use (instead of password)
4272        (default '')
4273
4274    File Example:
4275
4276    .. literalinclude::
4277        /../../tests/builders/fixtures/nexus_artifact_uploader001.yaml
4278       :language: yaml
4279    """
4280    nexus_artifact_uploader = XML.SubElement(
4281        xml_parent, "sp.sd.nexusartifactuploader.NexusArtifactUploader"
4282    )
4283    mapping = [
4284        ("protocol", "protocol", "https"),
4285        ("nexus_url", "nexusUrl", ""),
4286        ("nexus_user", "nexusUser", ""),
4287        ("nexus_password", "nexusPassword", ""),
4288        ("group_id", "groupId", ""),
4289        ("artifact_id", "artifactId", ""),
4290        ("version", "version", ""),
4291        ("packaging", "packaging", ""),
4292        ("type", "type", ""),
4293        ("classifier", "classifier", ""),
4294        ("repository", "repository", ""),
4295        ("file", "file", ""),
4296        ("credentials_id", "credentialsId", ""),
4297    ]
4298    helpers.convert_mapping_to_xml(
4299        nexus_artifact_uploader, data, mapping, fail_required=True
4300    )
4301
4302
4303def nexus_iq_policy_evaluator(registry, xml_parent, data):
4304    """yaml: nexus-iq-policy-evaluator
4305    Integrates the Nexus Lifecycle into a Jenkins job.
4306    This function triggers 'Invokes Nexus Policy Evaluation'.
4307
4308    Requires the Jenkins :jenkins-plugins:`Nexus Platform Plugin
4309    <nexus-jenkins-plugin>`.
4310
4311    :arg str stage: Controls the stage the policy evaluation will be
4312        run against on the Nexus IQ Server (required)
4313
4314        :stage values:
4315            * **build**
4316            * **stage-release**
4317            * **release**
4318            * **operate**
4319    :arg dict application-type: Specifies an IQ Application (default manual)
4320
4321        :application-type values:
4322            * **manual**
4323            * **selected**
4324    :arg str application-id: Specify the IQ Application ID (required)
4325    :arg list scan-patterns: List of Ant-style patterns relative to the
4326        workspace root that denote files/archives to be scanned (default [])
4327    :arg bool fail-build-network-error: Controls the build outcome if there
4328        is a failure in communicating with the Nexus IQ Server (default false)
4329
4330    Minimal Example:
4331
4332    .. literalinclude::
4333        /../../tests/builders/fixtures/nexus-iq-policy-evaluator-minimal.yaml
4334       :language: yaml
4335
4336    Full Example:
4337
4338    .. literalinclude::
4339        /../../tests/builders/fixtures/nexus-iq-policy-evaluator-full.yaml
4340       :language: yaml
4341    """
4342    nexus_iq_policy_evaluator = XML.SubElement(
4343        xml_parent, "org.sonatype.nexus.ci.iq.IqPolicyEvaluatorBuildStep"
4344    )
4345
4346    format_dict = {
4347        "stage": "com__sonatype__nexus__ci__iq__IqPolicyEvaluator____iqStage",
4348        "fone": "com__sonatype__nexus__ci__iq__IqPolicyEvaluator"
4349        "____failBuildOnNetworkError",
4350    }
4351
4352    valid_stages = ["build", "release", "stage-release", "operate"]
4353    mapping = [
4354        ("stage", format_dict.get("stage"), None, valid_stages),
4355        ("fail-build-network-error", format_dict.get("fone"), False),
4356    ]
4357    helpers.convert_mapping_to_xml(
4358        nexus_iq_policy_evaluator, data, mapping, fail_required=True
4359    )
4360
4361    application_type_label = data.get("application-type", "manual").lower()
4362    application_type_label_dict = {
4363        "manual": "org.sonatype.nexus.ci.iq.ManualApplication",
4364        "selected": "org.sonatype.nexus.ci.iq.SelectedApplication",
4365    }
4366    if application_type_label not in application_type_label_dict:
4367        raise InvalidAttributeError(
4368            application_type_label,
4369            application_type_label,
4370            application_type_label_dict.keys(),
4371        )
4372
4373    application_type_tag = XML.SubElement(
4374        nexus_iq_policy_evaluator,
4375        "com__sonatype__nexus__ci__iq__IqPolicyEvaluator____iqApplication",
4376    )
4377    application_type_tag.set(
4378        "class", application_type_label_dict[application_type_label]
4379    )
4380
4381    mapping = [("application-id", "applicationId", None)]
4382    helpers.convert_mapping_to_xml(
4383        application_type_tag, data, mapping, fail_required=True
4384    )
4385
4386    scan_pattern_list = data.get("scan-patterns", [])
4387    iq_scan_pattern_tag = XML.SubElement(
4388        nexus_iq_policy_evaluator,
4389        "com__sonatype__nexus__ci__iq" "__IqPolicyEvaluator____iqScanPatterns",
4390    )
4391
4392    for scan_pattern in scan_pattern_list:
4393        scan_pattern_tag = XML.SubElement(
4394            iq_scan_pattern_tag, "org.sonatype.nexus.ci.iq.ScanPattern"
4395        )
4396        XML.SubElement(scan_pattern_tag, "scanPattern").text = scan_pattern
4397
4398
4399def nexus_repo_manager(registry, xml_parent, data):
4400    """yaml: nexus-repo-manager
4401    Allows for artifacts selected in Jenkins packages to be
4402    available in Nexus Repository Manager.
4403
4404    Requires the Jenkins :jenkins-plugins:`Nexus Platform Plugin
4405    <nexus-jenkins-plugin>`.
4406
4407    :arg str instance-id: The ID of the Nexus Instance (required)
4408    :arg str repo-id: The ID of the Nexus Repository (required)
4409
4410    Minimal Example:
4411
4412    .. literalinclude::
4413        /../../tests/builders/fixtures/nexus-repo-manager-minimal.yaml
4414       :language: yaml
4415    """
4416    nexus_repo_manager = XML.SubElement(
4417        xml_parent, "org.sonatype.nexus.ci." "nxrm.NexusPublisherBuildStep"
4418    )
4419    mapping = [
4420        ("instance-id", "nexusInstanceId", None),
4421        ("repo-id", "nexusRepositoryId", None),
4422    ]
4423    helpers.convert_mapping_to_xml(
4424        nexus_repo_manager, data, mapping, fail_required=True
4425    )
4426
4427
4428def ansible_playbook(parser, xml_parent, data):
4429    """yaml: ansible-playbook
4430    This plugin allows you to execute Ansible tasks as a job build step.
4431
4432    Requires the Jenkins :jenkins-plugins:`Ansible Plugin <ansible>`.
4433
4434    :arg str playbook: Path to the ansible playbook file. The path can be
4435        absolute or relative to the job workspace. (required)
4436    :arg str inventory-type: The inventory file form (default `path`)
4437
4438        :inventory-type values:
4439            * **path**
4440            * **content**
4441            * **do-not-specify**
4442
4443    :arg dict inventory: Inventory data, depends on inventory-type
4444
4445        :inventory-type == path:
4446            * **path** (`str`) -- Path to inventory file.
4447
4448        :inventory-type == content:
4449            * **content** (`str`) -- Content of inventory file.
4450            * **dynamic** (`bool`) -- Dynamic inventory is used (default false)
4451
4452    :arg str hosts: Further limit selected hosts to an additional pattern
4453        (default '')
4454    :arg str tags-to-run: Only run plays and tasks tagged with these values
4455        (default '')
4456    :arg str tags-to-skip: Only run plays and tasks whose tags do not match
4457        these values (default '')
4458    :arg str task-to-start-at: Start the playbook at the task matching this
4459        name (default '')
4460    :arg int workers: Specify number of parallel processes to use (default 5)
4461    :arg str credentials-id: The ID of credentials for the SSH connections.
4462        Only private key authentication is supported (default '')
4463    :arg str vault-credentials-id: The ID of credentials for the vault
4464        decryption (default '')
4465    :arg bool sudo: Run operations with sudo. It works only when the remote
4466        user is sudoer with nopasswd option (default false)
4467    :arg str sudo-user: Desired sudo user. "root" is used when this field is
4468        empty. (default '')
4469    :arg bool unbuffered-output: Skip standard output buffering for the ansible
4470        process. The ansible output is directly rendered into the Jenkins
4471        console. This option can be useful for long running operations.
4472        (default true)
4473    :arg bool colorized-output: Check this box to allow ansible to render ANSI
4474        color codes in the Jenkins console. (default false)
4475    :arg bool disable-host-key-checking: Check this box to disable the
4476        validation of the hosts SSH server keys. (>= 1.0) (default false)
4477    :arg str additional-parameters: Any additional parameters to pass to the
4478        ansible command. (default '')
4479    :arg list variables: List of extra variables to be passed to ansible.
4480        (optional)
4481
4482        :variable item:
4483            * **name** (`str`) -- Name of variable (required)
4484            * **value** (`str`) -- Desired value (default '')
4485            * **hidden** (`bool`) -- Hide variable in build log (default false)
4486
4487    Outdated Options for versions >= 1.0 of plugin:
4488
4489    :arg bool host-key-checking: Outdated, replaced with disable-host-key-checking.
4490        Check this box to enforce the validation of the hosts SSH server keys.
4491        (< 1.0) (default true)
4492
4493    Example:
4494
4495    .. literalinclude::
4496        /../../tests/builders/fixtures/ansible-playbook001.yaml
4497       :language: yaml
4498
4499    OR
4500
4501    .. literalinclude::
4502        /../../tests/builders/fixtures/ansible-playbook002.yaml
4503       :language: yaml
4504
4505    Example(s) versions < 1.0:
4506
4507    .. literalinclude::
4508        /../../tests/builders/fixtures/ansible-playbook005.yaml
4509       :language: yaml
4510    """
4511    plugin = XML.SubElement(
4512        xml_parent, "org.jenkinsci.plugins.ansible.AnsiblePlaybookBuilder"
4513    )
4514    try:
4515        XML.SubElement(plugin, "playbook").text = str(data["playbook"])
4516    except KeyError as ex:
4517        raise MissingAttributeError(ex)
4518
4519    inventory_types = ("path", "content", "do-not-specify")
4520    inventory_type = str(data.get("inventory-type", inventory_types[0])).lower()
4521
4522    inventory = XML.SubElement(plugin, "inventory")
4523    inv_data = data.get("inventory", {})
4524    if inventory_type == "path":
4525        inventory.set("class", "org.jenkinsci.plugins.ansible.InventoryPath")
4526        try:
4527            path = inv_data["path"]
4528        except KeyError:
4529            raise MissingAttributeError("inventory['path']")
4530        XML.SubElement(inventory, "path").text = path
4531    elif inventory_type == "content":
4532        inventory.set("class", "org.jenkinsci.plugins.ansible.InventoryContent")
4533        try:
4534            content = inv_data["content"]
4535        except KeyError:
4536            raise MissingAttributeError("inventory['content']")
4537        XML.SubElement(inventory, "content").text = content
4538        XML.SubElement(inventory, "dynamic").text = str(
4539            inv_data.get("dynamic", False)
4540        ).lower()
4541    elif inventory_type == "do-not-specify":
4542        inventory.set("class", "org.jenkinsci.plugins.ansible.InventoryDoNotSpecify")
4543    else:
4544        raise InvalidAttributeError("inventory-type", inventory_type, inventory_types)
4545    XML.SubElement(plugin, "limit").text = data.get("hosts", "")
4546    XML.SubElement(plugin, "tags").text = data.get("tags-to-run", "")
4547    XML.SubElement(plugin, "skippedTags").text = data.get("tags-to-skip", "")
4548    XML.SubElement(plugin, "startAtTask").text = data.get("task-to-start-at", "")
4549    XML.SubElement(plugin, "credentialsId").text = data.get("credentials-id", "")
4550    XML.SubElement(plugin, "vaultCredentialsId").text = data.get(
4551        "vault-credentials-id", ""
4552    )
4553    if data.get("sudo", False):
4554        XML.SubElement(plugin, "sudo").text = "true"
4555        XML.SubElement(plugin, "sudoUser").text = data.get("sudo-user", "")
4556    else:
4557        XML.SubElement(plugin, "sudo").text = "false"
4558    if data.get("become", False):
4559        XML.SubElement(plugin, "become").text = "true"
4560        XML.SubElement(plugin, "becomeUser").text = data.get("become-user", "")
4561    else:
4562        XML.SubElement(plugin, "become").text = "false"
4563    XML.SubElement(plugin, "forks").text = str(data.get("workers", "5"))
4564    XML.SubElement(plugin, "unbufferedOutput").text = str(
4565        data.get("unbuffered-output", True)
4566    ).lower()
4567    XML.SubElement(plugin, "colorizedOutput").text = str(
4568        data.get("colorized-output", False)
4569    ).lower()
4570    XML.SubElement(plugin, "disableHostKeyChecking").text = str(
4571        data.get("disable-host-key-checking", False)
4572    ).lower()
4573    XML.SubElement(plugin, "hostKeyChecking").text = str(
4574        data.get("host-key-checking", True)
4575    ).lower()
4576    XML.SubElement(plugin, "additionalParameters").text = str(
4577        data.get("additional-parameters", "")
4578    )
4579    # Following option is not available from UI
4580    XML.SubElement(plugin, "copyCredentialsInWorkspace").text = "false"
4581    variables = data.get("variables", [])
4582    if variables:
4583        if not is_sequence(variables):
4584            raise InvalidAttributeError(
4585                "variables", variables, "list(dict(name, value, hidden))"
4586            )
4587        variables_elm = XML.SubElement(plugin, "extraVars")
4588        for idx, values in enumerate(variables):
4589            if not hasattr(values, "keys"):
4590                raise InvalidAttributeError(
4591                    "variables[%s]" % idx, values, "dict(name, value, hidden)"
4592                )
4593            try:
4594                var_name = values["name"]
4595            except KeyError:
4596                raise MissingAttributeError("variables[%s]['name']" % idx)
4597            value_elm = XML.SubElement(
4598                variables_elm, "org.jenkinsci.plugins.ansible.ExtraVar"
4599            )
4600            XML.SubElement(value_elm, "key").text = var_name
4601            XML.SubElement(value_elm, "value").text = values.get("value", "")
4602            XML.SubElement(value_elm, "hidden").text = str(
4603                values.get("hidden", False)
4604            ).lower()
4605
4606
4607def nodejs(parser, xml_parent, data):
4608    """yaml: nodejs
4609    This plugin allows you to execute NodeJS scripts as a job build step.
4610
4611    Requires the Jenkins :jenkins-plugins:`NodeJS Plugin <nodejs>`.
4612
4613    :arg str name: NodeJS installation name
4614    :arg str script: NodeJS script (required)
4615    :arg str config-id: ID of npmrc config file, which is the
4616        last field (a 32-digit hexadecimal code) of the path of URL visible
4617        after you clicked the file under Jenkins Managed Files.
4618
4619    Minimal Example:
4620
4621    .. literalinclude::
4622        ../../tests/builders/fixtures/nodejs-minimal.yaml
4623       :language: yaml
4624
4625    Full Example:
4626
4627    .. literalinclude::
4628        ../../tests/builders/fixtures/nodejs-full.yaml
4629       :language: yaml
4630    """
4631    nodejs = XML.SubElement(
4632        xml_parent, "jenkins.plugins.nodejs.NodeJSCommandInterpreter"
4633    )
4634    mapping = [("script", "command", None)]
4635
4636    mapping_opt = [
4637        ("name", "nodeJSInstallationName", None),
4638        ("config-id", "configId", None),
4639    ]
4640
4641    helpers.convert_mapping_to_xml(nodejs, data, mapping, fail_required=True)
4642    helpers.convert_mapping_to_xml(nodejs, data, mapping_opt, fail_required=False)
4643
4644
4645def xunit(registry, xml_parent, data):
4646    """yaml: xunit
4647    Process tests results.
4648
4649    Requires the Jenkins :jenkins-plugins:`xUnit Plugin <xunit>`.
4650
4651    :arg str thresholdmode: Whether thresholds represents an absolute number
4652        of tests or a percentage. Either 'number' or 'percent'. (default
4653        'number')
4654    :arg list thresholds: Thresholds for both 'failed' and 'skipped' tests.
4655
4656        :threshold (`dict`): Threshold values to set, where missing, xUnit
4657            should default to an internal value of 0. Each test threshold
4658            should contain the following:
4659
4660            * **unstable** (`int`)
4661            * **unstablenew** (`int`)
4662            * **failure** (`int`)
4663            * **failurenew** (`int`)
4664
4665    :arg int test-time-margin: Give the report time margin value in ms, before
4666        to fail if not new unless the option **requireupdate** is set for the
4667        configured framework. (default 3000)
4668    :arg list types: Frameworks to configure, and options. Supports the
4669        following: ``aunit``, ``boosttest``, ``checktype``, ``cpptest``,
4670        ``cppunit``, ``ctest``, ``dotnettest``, ``embunit``, ``fpcunit``,
4671        ``gtest``, ``junit``, ``mstest``, ``nunit``, ``phpunit``, ``tusar``,
4672        ``unittest``, and ``valgrind``.
4673
4674        The 'custom' type is not supported.
4675
4676        :type (`dict`): each type can be configured using the following:
4677
4678            * **pattern** (`str`): An Ant pattern to look for Junit result
4679              files, relative to the workspace root (default '')
4680            * **requireupdate** (`bool`): fail the build whenever fresh tests
4681              results have not been found (default true).
4682            * **deleteoutput** (`bool`): delete temporary JUnit files
4683              (default true).
4684            * **skip-if-no-test-files** (`bool`): Skip parsing this xUnit type
4685              report if there are no test reports files (default false).
4686            * **stoponerror** (`bool`): Fail the build whenever an error occur
4687              during a result file processing (default true).
4688
4689    Minimal Example:
4690
4691    .. literalinclude::
4692        /../../tests/builders/fixtures/xunit-minimal.yaml
4693       :language: yaml
4694
4695    Full Example:
4696
4697    .. literalinclude::
4698        /../../tests/builders/fixtures/xunit-full.yaml
4699       :language: yaml
4700
4701    """
4702    info = registry.get_plugin_info("xunit")
4703    plugin_version = pkg_resources.parse_version(info.get("version", str(sys.maxsize)))
4704
4705    logger = logging.getLogger(__name__)
4706    xunit = XML.SubElement(xml_parent, "org.jenkinsci.plugins.xunit.XUnitBuilder")
4707    xunit.set("plugin", "xunit")
4708
4709    # Map our internal types to the XML element names used by Jenkins plugin
4710    types_to_plugin_types = {
4711        "aunit": "AUnitJunitHudsonTestType",
4712        "boosttest": "BoostTestJunitHudsonTestType",
4713        "checktype": "CheckType",
4714        "cpptest": "CppTestJunitHudsonTestType",
4715        "cppunit": "CppUnitJunitHudsonTestType",
4716        "ctest": "CTestType",
4717        "dotnettest": "XUnitDotNetTestType",  # since plugin v1.93
4718        "embunit": "EmbUnitType",  # since plugin v1.84
4719        "fpcunit": "FPCUnitJunitHudsonTestType",
4720        "gtest": "GoogleTestType",
4721        "junit": "JUnitType",
4722        "mstest": "MSTestJunitHudsonTestType",
4723        "nunit": "NUnitJunitHudsonTestType",
4724        "phpunit": "PHPUnitJunitHudsonTestType",
4725        "tusar": "TUSARJunitHudsonTestType",
4726        "unittest": "UnitTestJunitHudsonTestType",
4727        "valgrind": "ValgrindJunitHudsonTestType",
4728        # FIXME should implement the 'custom' type
4729    }
4730    implemented_types = types_to_plugin_types.keys()  # shortcut
4731
4732    # Unit framework we are going to generate xml for
4733    supported_types = []
4734
4735    for configured_type in data["types"]:
4736        type_name = next(iter(configured_type.keys()))
4737        if type_name not in implemented_types:
4738            logger.warning("Requested xUnit type '%s' is not yet supported", type_name)
4739        else:
4740            # Append for generation
4741            supported_types.append(configured_type)
4742
4743    # Generate XML for each of the supported framework types
4744    # Note: versions 3+ are now using the 'tools' sub-element instead of 'types'
4745    if plugin_version < pkg_resources.parse_version("3.0.0"):
4746        types_name = "types"
4747    else:
4748        types_name = "tools"
4749
4750    xmltypes = XML.SubElement(xunit, types_name)
4751    mappings = [
4752        ("pattern", "pattern", ""),
4753        ("requireupdate", "failIfNotNew", True),
4754        ("deleteoutput", "deleteOutputFiles", True),
4755        ("skip-if-no-test-files", "skipNoTestFiles", False),
4756        ("stoponerror", "stopProcessingIfError", True),
4757    ]
4758    for supported_type in supported_types:
4759        framework_name = next(iter(supported_type.keys()))
4760        xmlframework = XML.SubElement(xmltypes, types_to_plugin_types[framework_name])
4761
4762        helpers.convert_mapping_to_xml(
4763            xmlframework, supported_type[framework_name], mappings, fail_required=True
4764        )
4765
4766    xmlthresholds = XML.SubElement(xunit, "thresholds")
4767    for t in data.get("thresholds", []):
4768        if not ("failed" in t or "skipped" in t):
4769            logger.warning("Unrecognized threshold, should be 'failed' or 'skipped'")
4770            continue
4771        elname = (
4772            "org.jenkinsci.plugins.xunit.threshold.%sThreshold"
4773            % next(iter(t.keys())).title()
4774        )
4775        el = XML.SubElement(xmlthresholds, elname)
4776        for threshold_name, threshold_value in next(iter(t.values())).items():
4777            # Normalize and craft the element name for this threshold
4778            elname = "%sThreshold" % threshold_name.lower().replace("new", "New")
4779            XML.SubElement(el, elname).text = str(threshold_value)
4780
4781    # Whether to use percent of exact number of tests.
4782    # Thresholdmode is either:
4783    # - 1 : absolute (number of tests), default.
4784    # - 2 : relative (percentage of tests)
4785    thresholdmode = "1"
4786    if "percent" == data.get("thresholdmode", "number"):
4787        thresholdmode = "2"
4788    XML.SubElement(xunit, "thresholdMode").text = thresholdmode
4789
4790    extra_config = XML.SubElement(xunit, "extraConfiguration")
4791    XML.SubElement(extra_config, "testTimeMargin").text = str(
4792        data.get("test-time-margin", "3000")
4793    )
4794