Add documentation.

Move test.sh to the tools directory.
Move parameters and notifications to their own modules; even
though they are implemented as Jenkins properties, they make
more sense as separate entities in the job builder, because
that's they way they are specified in the YAML.  All three
modules that touch the properties xml object know how to
create it if it's missing.

Change-Id: I4b42ff10a93fd3ed98f632b58e47f3e0e45086d6
Reviewed-on: https://review.openstack.org/12741
Reviewed-by: Clark Boylan <clark.boylan@gmail.com>
Approved: James E. Blair <corvus@inaugust.com>
Tested-by: Jenkins
This commit is contained in:
James E. Blair 2012-09-11 00:53:26 +02:00 committed by Jenkins
parent 32128b37f9
commit ab7c6bc6c1
40 changed files with 1829 additions and 178 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@
config config
.tox .tox
.test .test
doc/build
doc/source/sourcecode

153
doc/Makefile Normal file
View File

@ -0,0 +1,153 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/JenkinsJobBuilder.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/JenkinsJobBuilder.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/JenkinsJobBuilder"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/JenkinsJobBuilder"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

7
doc/source/builders.rst Normal file
View File

@ -0,0 +1,7 @@
.. _builders:
Builders
========
.. automodule:: builders
:members:

243
doc/source/conf.py Normal file
View File

@ -0,0 +1,243 @@
# -*- coding: utf-8 -*-
#
# Jenkins Job Builder documentation build configuration file, created by
# sphinx-quickstart on Mon Sep 10 19:36:21 2012.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('../../jenkins_jobs/modules'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage',
'jenkins_jobs.sphinx.yaml']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Jenkins Job Builder'
copyright = u'2012, Jenkins Job Builder Maintainers'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
release = '1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'JenkinsJobBuilderdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'JenkinsJobBuilder.tex', u'Jenkins Job Builder Documentation',
u'Jenkins Job Builder Maintainers', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'jenkinsjobbuilder', u'Jenkins Job Builder Documentation',
[u'Jenkins Job Builder Maintainers'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'JenkinsJobBuilder', u'Jenkins Job Builder Documentation',
u'Jenkins Job Builder Maintainers', 'JenkinsJobBuilder', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

View File

@ -0,0 +1,194 @@
Configuration
=============
The job definitions for Jenkins Job Builder are kept in any number of
YAML files, in whatever way you would like to organize them. When you
invoke ``jenkins-jobs`` you may specify either the path of a single
YAML file, or a directory. If you choose a directory, all of the
.yaml (or .yml) files in that directory will be read, and all the jobs
they define will be created or updated.
Definitions
-----------
Jenkins Job Builder understands a few basic object types which are
described in the next sections.
.. _job:
Job
^^^
The most straightforward way to create a job is simply to define a
Job in YAML. It looks like this::
- job:
name: job-name
That's not very useful, so you'll want to add some actions such as
:ref:`builders`, and perhaps :ref:`publishers`. Those are described
later. There are a few basic optional fields for a Job definition::
- job:
name: job-name
project-type: freestyle
defaults: global
**project-type**
Defaults to "freestyle", but "maven" can also be specified.
**defaults**
Specifies a set of `Defaults`_ to use for this job, defaults to
''global''. If you have values that are common to all of your jobs,
create a ``global`` `Defaults`_ object to hold them, and no further
configuration of individual jobs is necessary. If some jobs
should not use the ``global`` defaults, use this field to specify a
different set of defaults.
Job Template
^^^^^^^^^^^^
If you need several jobs defined that are nearly identical, except
perhaps in their names, SCP targets, etc., then you may use a Job
Template to specify the particulars of the job, and then use a
`Project`_ to realize the job with appropriate variable substitution.
A Job Template has the same syntax as a `Job`_, but you may add
variables anywhere in the definition. Variables are indicated by
enclosing them in braces, e.g., ``{name}`` will substitute the
variable `name`. When using a variable in a string field, it is good
practice to wrap the entire string in quotes, even if the rules of
YAML syntax don't require it because the value of the variable may
require quotes after substitution.
You must include a variable in the ``name`` field of a Job Template
(otherwise, every instance would have the same name). For example::
- job-template:
name: '{name}-unit-tests'
Will not cause any job to be created in Jenkins, however, it will
define a template that you can use to create jobs with a `Project`_
definition. It's name will depend on what is supplied to the
`Project`_.
Project
^^^^^^^
The purpose of a project is to collect related jobs together, and
provide values for the variables in a `Job Template`_. It looks like
this::
- project:
name: project-name
jobs:
- {name}-unit-tests
Any number of arbitrarily named additional fields may be specified,
and they will be available for variable substitution in the job
template. Any job templates listed under ``jobs:`` will be realized
with those values. The example above would create the job called
'project-name-unit-tests' in Jenkins.
Job Group
^^^^^^^^^
If you have several Job Templates that should all be realized
together, you can define a Job Group to collect them. Simply use the
Job Group where you would normally use a `Job Template`_ and all of
the Job Templates in the Job Group will be realized. For example::
- job-template:
name: '{name}-python-26'
- job-template:
name: '{name}-python-27'
- job-group:
name: python-jobs
jobs:
- '{name}-python-26'
- '{name}-python-27'
- project:
name: foo
jobs:
- python-jobs
Would cause the jobs `foo-python-26` and `foo-python-27` to be created
in Jekins.
.. _macro:
Macro
^^^^^
Many of the actions of a `Job`_, such as builders or publishers, can
be defined as a Macro, and then that Macro used in the `Job`_
description. Builders are described later, but let's introduce a
simple one now to illustrate the Macro functionality. This snippet
will instruct Jenkins to execute "make test" as part of the job::
- job:
name: foo-test
builders:
- shell: 'make test'
If you wanted to define a macro (which won't save much typing in this
case, but could still be useful to centralize the definition of a
commonly repeated task), the configuration would look like::
- builder:
name: make-test
builders:
- shell: 'make test'
- job:
name: foo-test
builders:
- make-test
This allows you to create complex actions (and even sequences of
actions) in YAML that look like first-class Jenkins Job Builder
actions. Not every attribute supports Macros, check the documentation
for the action before you try to use a Macro for it.
Defaults
^^^^^^^^
Defaults collect job attributes (including actions) and will supply
those values when the job is created, unless superseded by a value in
the 'Job'_ definition. If a set of Defaults is specified with the
name ``global``, that will be used by all `Job`_ (and `Job Template`_)
definitions unless they specify a different Default object with the
``default`` attribute. For example::
- defaults:
name: global
description: 'Do not edit this job through the web!'
Will set the job description for every job created.
Modules
-------
The bulk of the job definitions come from the following modules.
.. toctree::
:maxdepth: 2
project_freestyle
project_maven
general
builders
notifications
parameters
properties
publishers
scm
triggers
wrappers
zuul

67
doc/source/extending.rst Normal file
View File

@ -0,0 +1,67 @@
.. _extending:
Extending
=========
Jenkins Job Builder is quite modular. It is easy to add new
attributes to existing components, a new module to support a Jenkins
plugin, or include locally defined methods to deal with an
idiosyncratic build system.
XML Processing
--------------
Most of the work of building XML from the YAML configuration file is
handled by individual functions that implement a single
characteristic. For example, see the
``jenkins_jobs/modules/builders.py`` file for the Python module that
implements the standard Jenkins builders. The ``shell`` function at
the top of the file implements the standard `Execute a shell` build
step. All of the YAML to XML functions in Jenkins Job Builder have
the same signature:
.. _component_interface:
.. py:function:: component(parser, xml_parent, data)
:noindex:
:arg YAMLParser parser: the jenkins jobs YAML parser
:arg Element xml_parent: this attribute's parent XML element
:arg dict data: the YAML data structure for this attribute and below
The function is expected to examine the YAML data structure and create
new XML nodes and attach them to the xml_parent element. This general
pattern is applied throughout the included modules.
.. _module:
Modules
-------
Nearly all of Jenkins Job Builder is implemented in modules. The main
program has no concept of builders, publishers, properties, or any
other aspects of job definition. Each of those building blocks is
defined in a module, and due to the use of setuptools entry points,
most modules are easily extensible with new components.
To add a new module, define a class that inherits from
:py:class:`jenkins_jobs.modules.base.Base`, and add it to the
``jenkins_jobs.modules`` entry point in your setup.py.
.. autoclass:: jenkins_jobs.modules.base.Base
:members:
:undoc-members:
:private-members:
.. _component:
Components
----------
Most of the standard modules supply a number of components, and it's
easy to provide your own components for use by those modules. For
instance, the Builders module provides several builders, such as the
`shell` builder as well as the `trigger_builds` builder. If you
wanted to add a new builder, all you need to do is write a function
that conforms to the :ref:`Component Interface <component_interface>`,
and then add that function to the appropriate entry point (via a
setup.py file).

10
doc/source/general.rst Normal file
View File

@ -0,0 +1,10 @@
.. _general:
General Job Configuration
=========================
.. automodule:: assignednode
:members:
.. automodule:: logrotate
:members:

34
doc/source/index.rst Normal file
View File

@ -0,0 +1,34 @@
.. Jenkins Job Builder documentation master file, created by
sphinx-quickstart on Mon Sep 10 19:36:21 2012.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Jenkins Job Builder
===================
Jenkins Job Builder takes simple descriptions of Jenkins_ jobs in
YAML_ format, and uses them to configure Jenkins. You can keep your
job descriptions in human readable text format in a version control
system to make changes and auditing easier. It also has a flexible
template system, so creating many similarly configured jobs is easy.
.. _Jenkins: http://jenkins-ci.org/
.. _YAML: http://www.yaml.org/
Contents:
.. toctree::
:maxdepth: 3
installation
configuration
extending
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -0,0 +1,72 @@
Installation
============
To install Jenkins Job Builder, run::
sudo setup.py install
The OpenStack project uses puppet to manage its infrastructure
systems, including Jenkins. If you use Puppet, you can use the
`OpenStack Jenkins module`__ to install Jenkins Job Builder.
__ https://github.com/openstack/openstack-ci-puppet/tree/master/modules/jenkins
Configuration File
------------------
After installation, you will need to create a configuration file. By
default, `jenkins-jobs` looks in
``/etc/jenkins_jobs/jenkins_jobs.ini`` but you may specify an
alternate location when running `jenkins-jobs`. The file should have
the following format::
[jenkins]
user=USERNAME
password=PASSWORD
url=JENKINS_URL
**user**
This should be the name of a user previously defined in Jenkins with
the permissions necessary to read, create, delete, and configure
jobs.
**password**
The API token for the user specified. You cat get this through the
Jenkins management interface under ``People`` -> username ->
``Configure`` and then click the ``Show API Token`` button.
**url**
The base URL for your Jenkins installation.
Running
-------
After it's installed and configured, you can invoke Jenkins Job
Builder by running ``jenkins-jobs``. You won't be able to do anything
useful just yet without a configuration which is discussed in the next
section). But you should be able to get help on the various commands
by running::
jenkins-jobs --help
jenkins-jobs update --help
jenkins-jobs test --help
(etc.)
Once you have a configuration defined, you can test it with::
jenkins-jobs test /path/to/config -o /path/to/output
That will write XML files to the output directory for all of the jobs
defined in the configuration directory. When you're satisfied, you
can run::
jenkins-jobs update /path/to/config
Which will upload the configurations to Jenkins if needed. Jenkins
Job Builder maintains a cache of previously configured jobs, so that
you can run that command as often as you like, and it will only update
the configuration in Jenkins if the defined configuration has changed
since the last time it was run. Note: if you modify a job directly in
Jenkins, jenkins-jobs will not know about it and will not update it.

View File

@ -0,0 +1,7 @@
.. _notifications:
Notifications
=============
.. automodule:: notifications
:members:

View File

@ -0,0 +1,7 @@
.. _parameters:
Parameters
==========
.. automodule:: parameters
:members:

View File

@ -0,0 +1,7 @@
.. _project_freestyle:
Freestyle Project
=================
.. automodule:: project_freestyle
:members:

View File

@ -0,0 +1,7 @@
.. _project_maven:
Maven Project
=============
.. automodule:: project_maven
:members:

View File

@ -0,0 +1,7 @@
.. _properties:
Properties
==========
.. automodule:: properties
:members:

View File

@ -0,0 +1,7 @@
.. _publishers:
Publishers
==========
.. automodule:: publishers
:members:

7
doc/source/scm.rst Normal file
View File

@ -0,0 +1,7 @@
.. _scm:
SCM
===
.. automodule:: scm
:members:

7
doc/source/triggers.rst Normal file
View File

@ -0,0 +1,7 @@
.. _triggers:
Triggers
========
.. automodule:: triggers
:members:

7
doc/source/wrappers.rst Normal file
View File

@ -0,0 +1,7 @@
.. _wrappers:
Wrappers
========
.. automodule:: wrappers
:members:

7
doc/source/zuul.rst Normal file
View File

@ -0,0 +1,7 @@
.. _zuul_doc:
Zuul
====
.. automodule:: zuul
:members:

View File

@ -12,10 +12,21 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# Jenkins Job module for assigned nodes
# To use add the folowing into your YAML: """
# assignednode: The Assigned Node section allows you to specify which Jenkins node (or
# - node: 'oneiric' named group) should run the specified job. It adds the ``node``
attribute to the :ref:`Job` definition.
Example::
job:
name: test_job
node: precise
That speficies that the job should be run on a Jenkins node or node group
named ``precise``.
"""
import xml.etree.ElementTree as XML import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base import jenkins_jobs.modules.base

View File

@ -19,14 +19,76 @@ import yaml
class Base(object): class Base(object):
"""
A base class for a Jenkins Job Builder Module.
The module is initialized before any YAML is parsed.
:arg ModuleRegistry registry: the global module registry.
"""
#: The sequence number for the module. Modules are invoked in the
#: order of their sequence number in order to produce consistently
#: ordered XML output.
sequence = 10 sequence = 10
def __init__(self, registry): def __init__(self, registry):
self.registry = registry self.registry = registry
def handle_data(self, parser):
"""This method is called before any XML is generated. By
overriding this method, the module may manipulate the YAML
data structure on the parser however it likes before any XML
is generated. If it has changed the data structure at all, it
must return ``True``, otherwise, it must return ``False``.
:arg YAMLParser parser: the global YAML Parser
:rtype: boolean
"""
return False
def gen_xml(self, parser, xml_parent, data):
"""Update the XML element tree based on YAML data. Override
this method to add elements to the XML output. Create new
Element objects and add them to the xml_parent. The YAML data
structure must not be modified.
:arg YAMLParser parser: the global YAML Parser
:arg Element xml_parent: the parent XML element
:arg dict data: the YAML data structure
"""
pass
def _dispatch(self, component_type, component_list_type, def _dispatch(self, component_type, component_list_type,
parser, xml_parent, parser, xml_parent,
component, template_data={}): component, template_data={}):
"""This is a private helper method that you can call from your
implementation of gen_xml. It allows your module to define a
type of component, and benefit from extensibility via Python
entry points and Jenkins Job Builder :ref:`Macros <macro>`.
:arg string component_type: the name of the component
(e.g., `builder`)
:arg string component_list_type: the plural name of the component
type (e.g., `builders`)
:arg YAMLParser parser: the global YMAL Parser
:arg Element xml_parent: the parent XML element
:arg dict template_data: values that should be interpolated into
the component definition
The value of `component_list_type` will be used to look up
possible implementations of the component type via entry
points (entry points provide a list of components, so it
should be plural) while `component_type` will be used to look
for macros (they are defined singularly, and should not be
plural).
See the Publishers module for a simple example of how to use
this method.
"""
if isinstance(component, dict): if isinstance(component, dict):
# The component is a sigleton dictionary of name: dict(args) # The component is a sigleton dictionary of name: dict(args)
name, component_data = component.items()[0] name, component_data = component.items()[0]

View File

@ -12,22 +12,65 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# Jenkins Job module for builders
# To use add the folowing into your YAML: """
# builders: Builders define actions that the Jenkins job should execute. Examples
# - 'gerrit_git_prep' include shell scripts or maven targets. The ``builders`` attribute in
# - 'python26' the :ref:`Job` definition accepts a list of builders to invoke. They
may be components defined below, locally defined macros (using the top
level definition of ``builder:``, or locally defined components found
via the ``jenkins_jobs.builders`` entry point.
**Component**: builders
:Macro: builder
:Entry Point: jenkins_jobs.builders
Example::
job:
name: test_job
builders:
- shell: "make test"
"""
import xml.etree.ElementTree as XML import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base import jenkins_jobs.modules.base
def shell(parser, xml_parent, data): def shell(parser, xml_parent, data):
"""yaml: shell
Execute a shell command.
:Parameter: the shell command to execute
Example::
builders:
- shell: "make test"
"""
shell = XML.SubElement(xml_parent, 'hudson.tasks.Shell') shell = XML.SubElement(xml_parent, 'hudson.tasks.Shell')
XML.SubElement(shell, 'command').text = data XML.SubElement(shell, 'command').text = data
def trigger_builds(parser, xml_parent, data): def trigger_builds(parser, xml_parent, data):
"""yaml: trigger-builds
Trigger builds of other jobs.
:arg str project: the Jenkins project to trigger
:arg str predefined-parameters:
key/value pairs to be passed to the job (optional)
Example::
builders:
- trigger-builds:
- project: "build_started"
predefined-parameters:
FOO="bar"
"""
tbuilder = XML.SubElement(xml_parent, tbuilder = XML.SubElement(xml_parent,
'hudson.plugins.parameterizedtrigger.TriggerBuilder') 'hudson.plugins.parameterizedtrigger.TriggerBuilder')
configs = XML.SubElement(tbuilder, 'configs') configs = XML.SubElement(tbuilder, 'configs')

View File

@ -12,13 +12,23 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# Jenkins Job module for logrotate
# To use add the folowing into your YAML: """
# logrotate: The Logrotate section allows you to automatically remove old build
# daysToKeep: 3 history. It adds the ``logrotate`` attribute to the :ref:`Job`
# numToKeep: 20 definition.
# artifactDaysToKeep: -1
# artifactNumToKeep: -1 Example::
job:
name: test_job
logrotate:
daysToKeep: 3
numToKeep: 20
artifactDaysToKeep: -1
artifactNumToKeep: -1
"""
import xml.etree.ElementTree as XML import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base import jenkins_jobs.modules.base

View File

@ -0,0 +1,74 @@
# Copyright 2012 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
The Notifications module allows you to configure Jenkins to notify
other applications about various build phases. It requires the
Jenkins notification plugin.
**Component**: notifications
:Macro: notification
:Entry Point: jenkins_jobs.notifications
Example::
job:
name: test_job
notifications:
- http:
url: http://example.com/jenkins_endpoint
"""
import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base
def http_endpoint(parser, xml_parent, data):
"""yaml: http
Defines an HTTP notification endpoint.
:arg str url: URL of the endpoint
Example::
notifications:
- http:
url: http://example.com/jenkins_endpoint
"""
endpoint_element = XML.SubElement(xml_parent,
'com.tikal.hudson.plugins.notification.Endpoint')
XML.SubElement(endpoint_element, 'protocol').text = 'HTTP'
XML.SubElement(endpoint_element, 'url').text = data['url']
class Notifications(jenkins_jobs.modules.base.Base):
sequence = 22
def gen_xml(self, parser, xml_parent, data):
properties = xml_parent.find('properties')
if properties is None:
properties = XML.SubElement(xml_parent, 'properties')
notifications = data.get('notifications', [])
if notifications:
notify_element = XML.SubElement(properties,
'com.tikal.hudson.plugins.notification.HudsonNotificationProperty')
endpoints_element = XML.SubElement(notify_element, 'endpoints')
for endpoint in notifications:
self._dispatch('notification', 'notifications',
parser, endpoints_element, endpoint)

View File

@ -0,0 +1,166 @@
# Copyright 2012 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
The Parameters module allows you to specify build parameters for a job.
**Component**: parameters
:Macro: parameter
:Entry Point: jenkins_jobs.parameters
Example::
job:
name: test_job
parameters:
- string:
name: FOO
default: bar
description: "A parameter named FOO, defaults to 'bar'."
"""
import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base
def base_param(parser, xml_parent, data, do_default, ptype):
pdef = XML.SubElement(xml_parent, ptype)
XML.SubElement(pdef, 'name').text = data['name']
XML.SubElement(pdef, 'description').text = data['description']
if do_default:
default = data.get('default', None)
if default:
XML.SubElement(pdef, 'defaultValue').text = default
else:
XML.SubElement(pdef, 'defaultValue')
def string_param(parser, xml_parent, data):
"""yaml: string
A string parameter.
:arg str name: the name of the parameter
:arg str default: the default value of the parameter (optional)
:arg str description: a description of the parameter (optional)
Example::
parameters:
- string:
name: FOO
default: bar
description: "A parameter named FOO, defaults to 'bar'."
"""
base_param(parser, xml_parent, data, True,
'hudson.model.StringParameterDefinition')
def bool_param(parser, xml_parent, data):
"""yaml: bool
A boolean parameter.
:arg str name: the name of the parameter
:arg str default: the default value of the parameter (optional)
:arg str description: a description of the parameter (optional)
Example::
parameters:
- bool:
name: FOO
default: false
description: "A parameter named FOO, defaults to 'false'."
"""
data['default'] = str(data.get('default', 'false')).lower()
base_param(parser, xml_parent, data, True,
'hudson.model.BooleanParameterDefinition')
def file_param(parser, xml_parent, data):
"""yaml: bool
A file parameter.
:arg str name: the target location for the file upload
:arg str description: a description of the parameter (optional)
Example::
parameters:
- file:
name: test.txt
description: "Upload test.txt."
"""
base_param(parser, xml_parent, data, False,
'hudson.model.FileParameterDefinition')
def text_param(parser, xml_parent, data):
"""yaml: string
A text parameter.
:arg str name: the name of the parameter
:arg str default: the default value of the parameter (optional)
:arg str description: a description of the parameter (optional)
Example::
parameters:
- text:
name: FOO
default: bar
description: "A parameter named FOO, defaults to 'bar'."
"""
base_param(parser, xml_parent, data, True,
'hudson.model.TextParameterDefinition')
def label_param(parser, xml_parent, data):
"""yaml: label
A node label parameter.
:arg str name: the name of the parameter
:arg str default: the default value of the parameter (optional)
:arg str description: a description of the parameter (optional)
Example::
parameters:
- label:
name: node
default: precise
description: "The node on which to run the job"
"""
base_param(parser, xml_parent, data, True,
'org.jvnet.jenkins.plugins.nodelabelparameter.LabelParameterDefinition')
class Parameters(jenkins_jobs.modules.base.Base):
sequence = 21
def gen_xml(self, parser, xml_parent, data):
properties = xml_parent.find('properties')
if properties is None:
properties = XML.SubElement(xml_parent, 'properties')
parameters = data.get('parameters', [])
if parameters:
pdefp = XML.SubElement(properties,
'hudson.model.ParametersDefinitionProperty')
pdefs = XML.SubElement(pdefp, 'parameterDefinitions')
for param in parameters:
self._dispatch('parameter', 'parameters',
parser, pdefs, param)

View File

@ -12,13 +12,21 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# Jenkins Job module for maven projects
# To use you add the following into your YAML: """
# maven: The Freestyle Project module handles creating freestyle Jenkins
# root_module: projects (i.e., those that do not use Maven). You may specify
# group_id: com.google.gerrit ``freestyle`` in the ``project-type`` attribute to the :ref:`Job`
# artifact_id: gerrit-parent definition if you wish, though it is the default, so you may omit
# goals: 'test' ``project-type`` altogether if you are creating a freestyle project.
Example::
job:
name: test_job
project-type: freestyle
"""
import xml.etree.ElementTree as XML import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base import jenkins_jobs.modules.base

View File

@ -12,13 +12,29 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# Jenkins Job module for maven projects
# To use you add the following into your YAML: """
# maven: The Maven Project module handles creating Maven Jenkins projects. To
# root_module: create a Maven project, specify ``maven`` in the ``project-type``
# group_id: com.google.gerrit attribute to the :ref:`Job` definition.
# artifact_id: gerrit-parent
# goals: 'test' It also requires a ``maven`` section in the :ref:`Job` definition.
All of the fields below are required, except ``root-pom``, whose
default is ``pom.xml``.
Example::
job:
name: doc_job
project-type: maven
maven:
root-module:
group-id: org.example.docs
artifact-id: example-guide
root-pom: doc/src/pom.xml
goals: "clean generate-sources"
"""
import xml.etree.ElementTree as XML import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base import jenkins_jobs.modules.base

View File

@ -12,14 +12,42 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# Jenkins Job module for job properties
# No additional YAML needed """
The Properties module supplies a wide range of options that are
implemented as Jenkins job properties.
**Component**: properties
:Macro: property
:Entry Point: jenkins_jobs.properties
Example::
job:
name: test_job
properties:
- github:
url: https://github.com/openstack-ci/jenkins-job-builder/
"""
import xml.etree.ElementTree as XML import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base import jenkins_jobs.modules.base
def github(parser, xml_parent, data): def github(parser, xml_parent, data):
"""yaml: github
Sets the GitHub URL for the project.
:arg str url: the GitHub URL
Example::
properties:
- github:
url: https://github.com/openstack-ci/jenkins-job-builder/
"""
github = XML.SubElement(xml_parent, github = XML.SubElement(xml_parent,
'com.coravy.hudson.plugins.github.GithubProjectProperty') 'com.coravy.hudson.plugins.github.GithubProjectProperty')
github_url = XML.SubElement(github, 'projectUrl') github_url = XML.SubElement(github, 'projectUrl')
@ -27,6 +55,20 @@ def github(parser, xml_parent, data):
def throttle(parser, xml_parent, data): def throttle(parser, xml_parent, data):
"""yaml: throttle
Throttles the number of builds for this job.
:arg int max-per-node: max concurrent builds per node (default 0)
:arg int max-total: max concurrent builds (default 0)
:arg bool enabled: whether throttling is enabled (default True)
:arg str option: TODO: describe throttleOption
Example::
properties:
- throttle:
max-total: 4
"""
throttle = XML.SubElement(xml_parent, throttle = XML.SubElement(xml_parent,
'hudson.plugins.throttleconcurrents.ThrottleJobProperty') 'hudson.plugins.throttleconcurrents.ThrottleJobProperty')
XML.SubElement(throttle, 'maxConcurrentPerNode').text = str( XML.SubElement(throttle, 'maxConcurrentPerNode').text = str(
@ -42,7 +84,27 @@ def throttle(parser, xml_parent, data):
XML.SubElement(throttle, 'throttleOption').text = data.get('option') XML.SubElement(throttle, 'throttleOption').text = data.get('option')
XML.SubElement(throttle, 'configVersion').text = '1' XML.SubElement(throttle, 'configVersion').text = '1'
def inject(parser, xml_parent, data): def inject(parser, xml_parent, data):
"""yaml: inject
Allows you to inject evironment variables into the build.
:arg str properties-file: file to read with properties (optional)
:arg str properties-content: key=value properties (optional)
:arg str script-file: file with script to run (optional)
:arg str script-content: script to run (optional)
:arg str groovy-content: groovy script to run (optional)
:arg bool load-from-master: load files from master (default false)
:arg bool enabled: injection enabled (default true)
:arg bool keep-system-variables: keep system variables (default true)
:arg bool keep-build-variables: keep build variable (default true)
Example::
properties:
- inject:
properties-content: FOO=bar
"""
inject = XML.SubElement(xml_parent, inject = XML.SubElement(xml_parent,
'EnvInjectJobProperty') 'EnvInjectJobProperty')
info = XML.SubElement(inject, 'info') info = XML.SubElement(inject, 'info')
@ -65,7 +127,17 @@ def inject(parser, xml_parent, data):
XML.SubElement(inject, 'keepBuildVariables').text = str( XML.SubElement(inject, 'keepBuildVariables').text = str(
data.get('keep-build-variables', 'true')).lower() data.get('keep-build-variables', 'true')).lower()
def authenticated_build(parser, xml_parent, data): def authenticated_build(parser, xml_parent, data):
"""yaml: authenticated-build
Specifies an authorization matrix where only authenticated users
may trigger a build.
Example::
properties:
- authenticated-build
"""
# TODO: generalize this # TODO: generalize this
if data: if data:
security = XML.SubElement(xml_parent, security = XML.SubElement(xml_parent,
@ -74,76 +146,14 @@ def authenticated_build(parser, xml_parent, data):
'hudson.model.Item.Build:authenticated' 'hudson.model.Item.Build:authenticated'
def base_param(parser, xml_parent, data, do_default, ptype):
pdef = XML.SubElement(xml_parent, ptype)
XML.SubElement(pdef, 'name').text = data['name']
XML.SubElement(pdef, 'description').text = data['description']
if do_default:
default = data.get('default', None)
if default:
XML.SubElement(pdef, 'defaultValue').text = default
else:
XML.SubElement(pdef, 'defaultValue')
def string_param(parser, xml_parent, data):
base_param(parser, xml_parent, data, True,
'hudson.model.StringParameterDefinition')
def bool_param(parser, xml_parent, data):
data['default'] = str(data.get('default', 'false')).lower()
base_param(parser, xml_parent, data, True,
'hudson.model.BooleanParameterDefinition')
def file_param(parser, xml_parent, data):
base_param(parser, xml_parent, data, False,
'hudson.model.FileParameterDefinition')
def text_param(parser, xml_parent, data):
base_param(parser, xml_parent, data, True,
'hudson.model.TextParameterDefinition')
def label_param(parser, xml_parent, data):
base_param(parser, xml_parent, data, True,
'org.jvnet.jenkins.plugins.nodelabelparameter.LabelParameterDefinition')
def http_endpoint(parser, xml_parent, data):
endpoint_element = XML.SubElement(xml_parent,
'com.tikal.hudson.plugins.notification.Endpoint')
XML.SubElement(endpoint_element, 'protocol').text = 'HTTP'
XML.SubElement(endpoint_element, 'url').text = data['url']
class Properties(jenkins_jobs.modules.base.Base): class Properties(jenkins_jobs.modules.base.Base):
sequence = 20 sequence = 20
def gen_xml(self, parser, xml_parent, data): def gen_xml(self, parser, xml_parent, data):
properties = XML.SubElement(xml_parent, 'properties') properties = xml_parent.find('properties')
if properties is None:
properties = XML.SubElement(xml_parent, 'properties')
for prop in data.get('properties', []): for prop in data.get('properties', []):
self._dispatch('property', 'properties', self._dispatch('property', 'properties',
parser, properties, prop) parser, properties, prop)
parameters = data.get('parameters', [])
if parameters:
pdefp = XML.SubElement(properties,
'hudson.model.ParametersDefinitionProperty')
pdefs = XML.SubElement(pdefp, 'parameterDefinitions')
for param in parameters:
self._dispatch('parameter', 'parameters',
parser, pdefs, param)
notifications = data.get('notifications', [])
if notifications:
notify_element = XML.SubElement(properties,
'com.tikal.hudson.plugins.notification.HudsonNotificationProperty')
endpoints_element = XML.SubElement(notify_element, 'endpoints')
for endpoint in notifications:
self._dispatch('notification', 'notifications',
parser, endpoints_element, endpoint)

View File

@ -12,14 +12,47 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# Jenkins Job module for coverage publishers
# No additional YAML needed """
Publishers define actions that the Jenkins job should perform after
the build is complete.
**Component**: publishers
:Macro: publisher
:Entry Point: jenkins_jobs.publishers
Example::
job:
name: test_job
publishers:
- scp:
site: 'example.com'
source: 'doc/build/html/**/*'
target_path: 'project'
"""
import xml.etree.ElementTree as XML import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base import jenkins_jobs.modules.base
def archive(parser, xml_parent, data): def archive(parser, xml_parent, data):
"""yaml: archive
Archive build artifacts
:arg str artifacts: path specifier for artifacts to archive
:arg str excludes: path specifier for artifacts to exclude
:arg bool latest_only: only keep the artifacts from the latest
successful build
Example::
publishers:
- archive:
artifacts: *.tar.gz
"""
archiver = XML.SubElement(xml_parent, 'hudson.tasks.ArtifactArchiver') archiver = XML.SubElement(xml_parent, 'hudson.tasks.ArtifactArchiver')
artifacts = XML.SubElement(archiver, 'artifacts') artifacts = XML.SubElement(archiver, 'artifacts')
artifacts.text = data['artifacts'] artifacts.text = data['artifacts']
@ -35,6 +68,20 @@ def archive(parser, xml_parent, data):
def trigger_parameterized_builds(parser, xml_parent, data): def trigger_parameterized_builds(parser, xml_parent, data):
"""yaml: trigger-parameterized-builds
Trigger parameterized builds of other jobs.
:arg str project: name of the job to trigger
:arg str predefined-parameters: parameters to pass to the other
job (optional)
:arg str condition: when to trigger the other job (default 'ALWAYS')
Example::
publishers:
- trigger-parameterized-builds:
project: other_job
"""
tbuilder = XML.SubElement(xml_parent, tbuilder = XML.SubElement(xml_parent,
'hudson.plugins.parameterizedtrigger.BuildTrigger') 'hudson.plugins.parameterizedtrigger.BuildTrigger')
configs = XML.SubElement(tbuilder, 'configs') configs = XML.SubElement(tbuilder, 'configs')
@ -59,6 +106,14 @@ def trigger_parameterized_builds(parser, xml_parent, data):
def coverage(parser, xml_parent, data): def coverage(parser, xml_parent, data):
"""yaml: coverage
Generate a cobertura coverage report.
Example::
publishers:
- coverage
"""
cobertura = XML.SubElement(xml_parent, cobertura = XML.SubElement(xml_parent,
'hudson.plugins.cobertura.CoberturaPublisher') 'hudson.plugins.cobertura.CoberturaPublisher')
XML.SubElement(cobertura, 'coberturaReportFile').text = '**/coverage.xml' XML.SubElement(cobertura, 'coberturaReportFile').text = '**/coverage.xml'
@ -114,18 +169,27 @@ def coverage(parser, xml_parent, data):
XML.SubElement(cobertura, 'sourceEncoding').text = 'ASCII' XML.SubElement(cobertura, 'sourceEncoding').text = 'ASCII'
# Jenkins Job module for publishing via ftp
# publish:
# site: 'docs.openstack.org'
# remote_dir: 'dest/dir'
# source_files: 'base/source/dir/**'
# remove_prefix: 'base/source/dir'
# excludes: '**/*.exludedfiletype'
#
# This will upload everything under $workspace/base/source/dir to
# docs.openstack.org $ftpdir/dest/dir exluding the excluded file type.
def ftp(parser, xml_parent, data): def ftp(parser, xml_parent, data):
"""yaml: ftp
Upload files via FTP.
:arg str site: name of the ftp site
:arg str target: destination directory
:arg str source: source path specifier
:arg str excludes: excluded file pattern (optional)
:arg str remove-prefix: prefix to remove from uploaded file paths
(optional)
Example::
publishers:
- ftp:
site: 'ftp.example.com'
target: 'dest/dir'
source: 'base/source/dir/**'
remove-prefix: 'base/source/dir'
excludes: '**/*.excludedfiletype'
"""
outer_ftp = XML.SubElement(xml_parent, outer_ftp = XML.SubElement(xml_parent,
'jenkins.plugins.publish__over__ftp.BapFtpPublisherPlugin') 'jenkins.plugins.publish__over__ftp.BapFtpPublisherPlugin')
XML.SubElement(outer_ftp, 'consolePrefix').text = 'FTP: ' XML.SubElement(outer_ftp, 'consolePrefix').text = 'FTP: '
@ -158,12 +222,18 @@ def ftp(parser, xml_parent, data):
'reference': '../..'}) 'reference': '../..'})
# Jenkins Job module for coverage publishers
# To use you add the following into your YAML:
# publisher:
# results: 'nosetests.xml'
def junit(parser, xml_parent, data): def junit(parser, xml_parent, data):
"""yaml: junit
Publish JUnit test results.
:arg str results: results filename
Example::
publishers:
- junit:
results: nosetests.xml
"""
junitresult = XML.SubElement(xml_parent, junitresult = XML.SubElement(xml_parent,
'hudson.tasks.junit.JUnitResultArchiver') 'hudson.tasks.junit.JUnitResultArchiver')
XML.SubElement(junitresult, 'testResults').text = data['results'] XML.SubElement(junitresult, 'testResults').text = data['results']
@ -192,6 +262,35 @@ def _violations_add_entry(xml_parent, name, data):
def violations(parser, xml_parent, data): def violations(parser, xml_parent, data):
"""yaml: violations
Publish code style violations.
The violations component accepts any number of dictionaries keyed
by the name of the violations system. The dictionary has the
following values:
:arg int min: sunny threshold
:arg int max: stormy threshold
:arg int unstable: unstable threshold
:arg str pattern: report filename pattern
Any system without a dictionary provided will use default values.
Valid systems are:
checkstyle, codenarc, cpd, cpplint, csslint, findbugs, fxcop,
gendarme, jcreport, jslint, pep8, pmd, pylint, simian, stylecop
Example::
publishers:
- violations:
pep8:
min: 0
max: 1
unstable: 1
pattern: '**/pep8.txt'
"""
violations = XML.SubElement(xml_parent, violations = XML.SubElement(xml_parent,
'hudson.plugins.violations.ViolationsPublisher') 'hudson.plugins.violations.ViolationsPublisher')
config = XML.SubElement(violations, 'config') config = XML.SubElement(violations, 'config')
@ -234,6 +333,27 @@ def violations(parser, xml_parent, data):
# keep_heirarchy: 'true' # keep_heirarchy: 'true'
def scp(parser, xml_parent, data): def scp(parser, xml_parent, data):
"""yaml: scp
Upload files via SCP
:arg str site: name of the scp site
:arg str target: destination directory
:arg str source: source path specifier
:arg bool keep-hierarchy: keep the file hierarchy when uploading
(default false)
:arg bool copy-after-failure: copy files even if the job fails
(default false)
:arg bool copy-console: copy the console log (default false); if
specified, omit 'target'
Example::
publishers:
- scp:
site: 'example.com'
target: 'dest/dir'
source: 'base/source/dir/**'
"""
site = data['site'] site = data['site']
scp = XML.SubElement(xml_parent, scp = XML.SubElement(xml_parent,
'be.certipost.hudson.plugin.SCPRepositoryPublisher') 'be.certipost.hudson.plugin.SCPRepositoryPublisher')

View File

@ -12,18 +12,47 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# Jenkins Job module for scm
# To use add the folowing into your YAML: """
# scm: The SCM module allows you to specify the source code location for the
# scm: 'true' project. It adds the ``scm`` attribute to the :ref:`Job` definition,
# or which accepts a single scm definiton.
# scm: 'false'
**Component**: scm
:Macro: scm
:Entry Point: jenkins_jobs.scm
Example::
job:
name: test_job
scm:
-git:
url: https://example.com/project.git
"""
import xml.etree.ElementTree as XML import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base import jenkins_jobs.modules.base
def git(self, xml_parent, data): def git(self, xml_parent, data):
"""yaml: git
Specifies the git SCM repository for this job.
:arg str url: URL of the git repository
:arg list(str) branches: list of branch specifiers to build
Example::
scm:
-git:
url: https://example.com/project.git
branches:
- master
- stable
"""
scm = XML.SubElement(xml_parent, scm = XML.SubElement(xml_parent,
'scm', {'class': 'hudson.plugins.git.GitSCM'}) 'scm', {'class': 'hudson.plugins.git.GitSCM'})
XML.SubElement(scm, 'configVersion').text = '2' XML.SubElement(scm, 'configVersion').text = '2'

View File

@ -12,42 +12,69 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# Jenkins Job module for gerrit triggers
# To use add the following into your YAML: """
# trigger: Triggers define what causes a jenkins job to start buliding.
# triggerOnPatchsetUploadedEvent: 'false'
# triggerOnChangeMergedEvent: 'false' **Component**: triggers
# triggerOnCommentAddedEvent: 'true' :Macro: trigger
# triggerOnRefUpdatedEvent: 'false' :Entry Point: jenkins_jobs.triggers
# triggerApprovalCategory: 'APRV'
# triggerApprovalValue: 1 Example::
# overrideVotes: 'true'
# gerritBuildSuccessfulVerifiedValue: 1 job:
# gerritBuildFailedVerifiedValue: -1 name: test_job
#
# failureMessage: 'This change was unable to be automatically merged triggers:
# with the current state of the repository. Please rebase your change - timed: '@daily'
# and upload a new patchset.' """
#
# projects:
# - projectCompareType: 'PLAIN'
# projectPattern: 'openstack/nova'
# branchCompareType: 'ANT'
# branchPattern: '**'
# - projectCompareType: 'PLAIN'
# projectPattern: 'openstack/glance'
# branchCompareType: 'ANT'
# branchPattern: '**'
# ...
#
# triggerApprovalCategory and triggerApprovalValue only required
# if triggerOnCommentAddedEvent: 'true'
import xml.etree.ElementTree as XML import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base import jenkins_jobs.modules.base
def gerrit(parser, xml_parent, data): def gerrit(parser, xml_parent, data):
"""yaml: gerrit
Trigger on a Gerrit event.
:arg bool triggerOnPatchsetUploadedEvent: Trigger on patchset upload
:arg bool triggerOnChangeMergedEvent: Trigger on change merged
:arg bool triggerOnCommentAddedEvent: Trigger on comment added
:arg bool triggerOnRefUpdatedEvent: Trigger on ref-updated
:arg str triggerApprovalCategory: Approval category for comment added
:arg int triggerApprovalValue: Approval value for comment added
:arg bool overrideVotes: Override default vote values
:arg int gerritBuildSuccessfulVerifiedValue: Successful ''Verified'' value
:arg int gerritBuildFailedVerifiedValue: Failed ''Verified'' value
:arg str failureMessage: Message to leave on failure
:arg list projects: list of projects to match
:Project: * **projectCompareType** (`str`) -- ''PLAIN'' or ''ANT''
* **projectPattern** (`str`) -- Project name pattern to match
* **branchComprareType** (`str`) -- ''PLAIN'' or ''ANT''
* **branchPattern** ('str') -- Branch name pattern to match
You may select one or more gerrit events upon which to trigger.
You must also supply at least one project and branch, optionally
more. If you select the comment-added trigger, you should alse
indicate which approval category and value you want to trigger the
job.
Example::
trigger:
- gerrit:
triggerOnCommentAddedEvent: true
triggerApprovalCategory: 'APRV'
triggerApprovalValue: 1
projects:
- projectCompareType: 'PLAIN'
projectPattern: 'test-project'
branchCompareType: 'ANT'
branchPattern: '**'
"""
projects = data['projects'] projects = data['projects']
gtrig = XML.SubElement(xml_parent, gtrig = XML.SubElement(xml_parent,
'com.sonyericsson.hudson.plugins.gerrit.trigger.' 'com.sonyericsson.hudson.plugins.gerrit.trigger.'
@ -94,26 +121,33 @@ def gerrit(parser, xml_parent, data):
XML.SubElement(gtrig, 'customUrl') XML.SubElement(gtrig, 'customUrl')
# Jenkins Job module for scm polling triggers
# To use add the following into your YAML:
# trigger:
# pollscm: '@midnight'
# or
# pollscm: '*/15 * * * *'
def pollscm(parser, xml_parent, data): def pollscm(parser, xml_parent, data):
"""yaml: pollscm
Poll the SCM to determine if there has been a change.
:Parameter: the polling interval (cron syntax)
Example:
trigger:
- pollscm: "\*/15 * * * \*"
"""
scmtrig = XML.SubElement(xml_parent, 'hudson.triggers.SCMTrigger') scmtrig = XML.SubElement(xml_parent, 'hudson.triggers.SCMTrigger')
XML.SubElement(scmtrig, 'spec').text = data XML.SubElement(scmtrig, 'spec').text = data
# Jenkins Job module for timed triggers
# To use add the following into your YAML:
# trigger:
# timed: '@midnight'
# or
# timed: '*/15 * * * *'
def timed(parser, xml_parent, data): def timed(parser, xml_parent, data):
"""yaml: pollscm
Poll the SCM to determine if there has been a change.
:Parameter: the polling interval (cron syntax)
Example:
trigger:
- pollscm: "@midnight"
"""
scmtrig = XML.SubElement(xml_parent, 'hudson.triggers.TimerTrigger') scmtrig = XML.SubElement(xml_parent, 'hudson.triggers.TimerTrigger')
XML.SubElement(scmtrig, 'spec').text = data XML.SubElement(scmtrig, 'spec').text = data

View File

@ -12,13 +12,43 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# Jenkins Job module for wrappers
"""
Wrappers can alter the way the build is run as well as the build output.
**Component**: wrappers
:Macro: wrapper
:Entry Point: jenkins_jobs.wrappers
Example::
job:
name: test_job
wrappers:
- timeout:
timeout: 90
fail: true
"""
import xml.etree.ElementTree as XML import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base import jenkins_jobs.modules.base
def timeout(parser, xml_parent, data): def timeout(parser, xml_parent, data):
"""yaml: timeout
Abort the build if it runs too long.
:arg int timeout: Abort the build after this number of minutes
:arg bool fail: Mark the build as failed (default false)
Example::
wrappers:
- timeout:
timeout: 90
fail: true
"""
twrapper = XML.SubElement(xml_parent, twrapper = XML.SubElement(xml_parent,
'hudson.plugins.build__timeout.BuildTimeoutWrapper') 'hudson.plugins.build__timeout.BuildTimeoutWrapper')
tminutes = XML.SubElement(twrapper, 'timeoutMinutes') tminutes = XML.SubElement(twrapper, 'timeoutMinutes')
@ -32,11 +62,27 @@ def timeout(parser, xml_parent, data):
def timestamps(parser, xml_parent, data): def timestamps(parser, xml_parent, data):
"""yaml: timestamps
Add timestamps to the console log.
Example::
wrappers:
- timestamps
"""
XML.SubElement(xml_parent, XML.SubElement(xml_parent,
'hudson.plugins.timestamper.TimestamperBuildWrapper') 'hudson.plugins.timestamper.TimestamperBuildWrapper')
def ansicolor(parser, xml_parent, data): def ansicolor(parser, xml_parent, data):
"""yaml: ansicolor
Translate ANSI color codes to HTML in the console log.
Example::
wrappers:
- ansicolor
"""
XML.SubElement(xml_parent, XML.SubElement(xml_parent,
'hudson.plugins.ansicolor.AnsiColorBuildWrapper') 'hudson.plugins.ansicolor.AnsiColorBuildWrapper')

View File

@ -12,11 +12,34 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# Jenkins Job module for Zuul """
The Zuul module adds triggers that configure jobs for use with Zuul_.
.. _Zuul: http://ci.openstack.org/zuul/
"""
def zuul():
"""yaml: zuul
Configure this job to be triggered by Zuul.
Example::
triggers:
- zuul
"""
def zuul_post():
"""yaml: zuul-post
Configure this post-merge job to be triggered by Zuul.
Example::
triggers:
- zuul-post
"""
import jenkins_jobs.modules.base import jenkins_jobs.modules.base
ZUUL_PARAMETERS = [ ZUUL_PARAMETERS = [
{'string': {'string':
{'description': 'Zuul provided key to link builds with Gerrit events', {'description': 'Zuul provided key to link builds with Gerrit events',

View File

137
jenkins_jobs/sphinx/yaml.py Normal file
View File

@ -0,0 +1,137 @@
# Copyright 2012 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Most of this code originated in sphinx.domains.python and
# sphinx.ext.autodoc and has been only slightly adapted for use in
# subclasses here.
# :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
# :license: BSD, see LICENSE for details.
import re
from sphinx.ext.autodoc import Documenter, FunctionDocumenter
from sphinx.domains.python import PyModulelevel
from sphinx import addnodes
from sphinx.locale import l_, _
yaml_sig_re = re.compile('yaml:\s*(.*)')
class PyYAMLFunction(PyModulelevel):
def handle_signature(self, sig, signode):
"""Transform a Python signature into RST nodes.
Return (fully qualified name of the thing, classname if any).
If inside a class, the current class name is handled intelligently:
* it is stripped from the displayed name if present
* it is added to the full name (return value) if not present
"""
name_prefix = None
name = sig
arglist = None
retann = None
# determine module and class name (if applicable), as well as full name
modname = self.options.get(
'module', self.env.temp_data.get('py:module'))
classname = self.env.temp_data.get('py:class')
fullname=name
signode['module'] = modname
signode['class'] = classname
signode['fullname'] = fullname
sig_prefix = self.get_signature_prefix(sig)
if sig_prefix:
signode += addnodes.desc_annotation(sig_prefix, sig_prefix)
if name_prefix:
signode += addnodes.desc_addname(name_prefix, name_prefix)
anno = self.options.get('annotation')
signode += addnodes.desc_name(name, name)
if not arglist:
if self.needs_arglist():
# for callables, add an empty parameter list
signode += addnodes.desc_parameterlist()
if retann:
signode += addnodes.desc_returns(retann, retann)
if anno:
signode += addnodes.desc_annotation(' ' + anno, ' ' + anno)
return fullname, name_prefix
_pseudo_parse_arglist(signode, arglist)
if retann:
signode += addnodes.desc_returns(retann, retann)
if anno:
signode += addnodes.desc_annotation(' ' + anno, ' ' + anno)
return fullname, name_prefix
def get_index_text(self, modname, name_cls):
return _('%s (in module %s)') % (name_cls[0], modname)
class YAMLFunctionDocumenter(FunctionDocumenter):
priority = FunctionDocumenter.priority + 10
objtype = 'yamlfunction'
directivetype = 'yamlfunction'
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
if not FunctionDocumenter.can_document_member(member, membername,
isattr, parent):
return False
if yaml_sig_re.match(member.__doc__):
return True
return False
def _find_signature(self, encoding=None):
docstrings = Documenter.get_doc(self, encoding, 2)
if len(docstrings) != 1:
return
doclines = docstrings[0]
setattr(self, '__new_doclines', doclines)
if not doclines:
return
# match first line of docstring against signature RE
match = yaml_sig_re.match(doclines[0])
if not match:
return
name = match.group(1)
# ok, now jump over remaining empty lines and set the remaining
# lines as the new doclines
i = 1
while i < len(doclines) and not doclines[i].strip():
i += 1
setattr(self, '__new_doclines', doclines[i:])
return name
def get_doc(self, encoding=None, ignore=1):
lines = getattr(self, '__new_doclines', None)
if lines is not None:
return [lines]
return Documenter.get_doc(self, encoding, ignore)
def format_signature(self):
result = self._find_signature()
self._name = result
return ''
def format_name(self):
return self._name
def setup(app):
app.add_autodocumenter(YAMLFunctionDocumenter)
app.add_directive_to_domain('py', 'yamlfunction', PyYAMLFunction)

5
setup.cfg Normal file
View File

@ -0,0 +1,5 @@
[build_sphinx]
all_files = 1
build-dir = doc/build
source-dir = doc/source

View File

@ -44,14 +44,14 @@ setup(name='jenkins_job_builder',
'authenticated_build', 'authenticated_build',
], ],
'jenkins_jobs.parameters': [ 'jenkins_jobs.parameters': [
'string=jenkins_jobs.modules.properties:string_param', 'string=jenkins_jobs.modules.parameters:string_param',
'bool=jenkins_jobs.modules.properties:bool_param', 'bool=jenkins_jobs.modules.parameters:bool_param',
'file=jenkins_jobs.modules.properties:file_param', 'file=jenkins_jobs.modules.parameters:file_param',
'text=jenkins_jobs.modules.properties:text_param', 'text=jenkins_jobs.modules.parameters:text_param',
'label=jenkins_jobs.modules.properties:label_param', 'label=jenkins_jobs.modules.parameters:label_param',
], ],
'jenkins_jobs.notifications': [ 'jenkins_jobs.notifications': [
'http=jenkins_jobs.modules.properties:http_endpoint', 'http=jenkins_jobs.modules.notifications:http_endpoint',
], ],
'jenkins_jobs.publishers': [ 'jenkins_jobs.publishers': [
'archive=jenkins_jobs.modules.publishers:archive', 'archive=jenkins_jobs.modules.publishers:archive',
@ -82,6 +82,8 @@ setup(name='jenkins_job_builder',
'builders=jenkins_jobs.modules.builders:Builders', 'builders=jenkins_jobs.modules.builders:Builders',
'logrotate=jenkins_jobs.modules.logrotate:LogRotate', 'logrotate=jenkins_jobs.modules.logrotate:LogRotate',
'properties=jenkins_jobs.modules.properties:Properties', 'properties=jenkins_jobs.modules.properties:Properties',
'parameters=jenkins_jobs.modules.parameters:Parameters',
'notifications=jenkins_jobs.modules.notifications:Notifications',
'publishers=jenkins_jobs.modules.publishers:Publishers', 'publishers=jenkins_jobs.modules.publishers:Publishers',
'scm=jenkins_jobs.modules.scm:SCM', 'scm=jenkins_jobs.modules.scm:SCM',
'triggers=jenkins_jobs.modules.triggers:Triggers', 'triggers=jenkins_jobs.modules.triggers:Triggers',

1
tools/test-requires Normal file
View File

@ -0,0 +1 @@
sphinx

View File

@ -4,6 +4,10 @@ envlist = pep8, pyflakes
[tox:jenkins] [tox:jenkins]
downloadcache = ~/cache/pip downloadcache = ~/cache/pip
[testenv]
deps = -r{toxinidir}/tools/pip-requires
-r{toxinidir}/tools/test-requires
[testenv:pep8] [testenv:pep8]
deps = pep8==1.2 deps = pep8==1.2
commands = pep8 --repeat --show-source --exclude=.venv,.tox,dist,doc,build . commands = pep8 --repeat --show-source --exclude=.venv,.tox,dist,doc,build .
@ -13,11 +17,9 @@ deps = pyflakes
commands = pyflakes jenkins_jobs jenkins-jobs setup.py commands = pyflakes jenkins_jobs jenkins-jobs setup.py
[testenv:compare-xml-old] [testenv:compare-xml-old]
deps = -r{toxinidir}/tools/pip-requires
commands = ./jenkins-jobs test -o .test/old/out/ .test/old/config/ commands = ./jenkins-jobs test -o .test/old/out/ .test/old/config/
[testenv:compare-xml-new] [testenv:compare-xml-new]
deps = -r{toxinidir}/tools/pip-requires
commands = ./jenkins-jobs test -o .test/new/out/ .test/new/config/ commands = ./jenkins-jobs test -o .test/new/out/ .test/new/config/
[testenv:venv] [testenv:venv]