diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..7fdea582c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pyc +*.egg-info diff --git a/example/ceilometer.yml b/example/ceilometer.yml new file mode 100644 index 000000000..a17dbc532 --- /dev/null +++ b/example/ceilometer.yml @@ -0,0 +1,80 @@ +- project: + name: ceilometer + github-org: stackforge + node: oneiric + + jobs: + - python-jobs + + +- job: + name: 'gate-ceilometer-python26-essex' + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: https://github.com/stackforge/ceilometer + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + # TODO: logrotate this job + #logrotate: + # daysToKeep: 28 + # numToKeep: -1 + # artifactDaysToKeep: -1 + # artifactNumToKeep: -1 + + triggers: + - zuul + + builders: + - gerrit_git_prep + - python26_essex + + # >= precise does not have python2.6 + node: oneiric + + +- job: + name: 'gate-ceilometer-python27-essex' + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: https://github.com/stackforge/ceilometer + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + # TODO: logrotate this job + #logrotate: + # daysToKeep: 28 + # numToKeep: -1 + # artifactDaysToKeep: -1 + # artifactNumToKeep: -1 + + triggers: + - zuul + + builders: + - gerrit_git_prep + - python27_essex + + node: oneiric diff --git a/example/cinder.yml b/example/cinder.yml new file mode 100644 index 000000000..5a0499eed --- /dev/null +++ b/example/cinder.yml @@ -0,0 +1,10 @@ +- project: + name: cinder + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - openstack-publish-jobs diff --git a/example/devstack-gate.yml b/example/devstack-gate.yml new file mode 100644 index 000000000..c26a1fe59 --- /dev/null +++ b/example/devstack-gate.yml @@ -0,0 +1,273 @@ +- job: + name: gate-devstack-gate-merge + project-type: freestyle + concurrent: true + node: precise + + properties: + - github: + url: https://github.com/openstack-ci/devstack-gate + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - gerrit_git_prep + + +- job: + name: gate-integration-tests-devstack-vm + project-type: freestyle + concurrent: true + node: devstack-precise + + properties: + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + parameters: + - label: + name: NODE_LABEL + description: Label of node to use for this build + default: devstack-precise + + wrappers: + - timeout: + timeout: 40 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - trigger-builds: + - project: devstack-update-inprogress + predefined_parameters: + DEVSTACK_NODE_NAME=${NODE_NAME} + - shell: | + #!/bin/bash -xe + # + # This job also gates devstack-gate, but in case a previous run fails, + # we need to always make sure that we're starting with the latest copy + # from master, before we start applying changes to it. If a previous run + # leaves a bad copy of the gate script, we may get stuck. + # + if [[ ! -e devstack-gate ]]; then + git clone https://review.openstack.org/p/openstack-ci/devstack-gate + else + cd devstack-gate + git remote update + git reset --hard + git clean -x -f + git checkout master + git reset --hard remotes/origin/master + git clean -x -f + cd .. + fi + - shell: | + #!/bin/bash -xe + export PYTHONUNBUFFERED=true + cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh + ./safe-devstack-vm-gate-wrap.sh + + publishers: + - archive: + artifacts: logs/* + - trigger-parameterized-builds: + - project: devstack-update-complete + when: complete + predefined_parameters: + DEVSTACK_NODE_NAME=${NODE_NAME} + + +- job: + name: gate-tempest-devstack-vm + project-type: freestyle + concurrent: true + node: devstack-precise + + properties: + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + parameters: + - label: + name: NODE_LABEL + description: Label of node to use for this build + default: devstack-precise + + wrappers: + - timeout: + timeout: 90 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - trigger-builds: + - project: devstack-update-inprogress + predefined_parameters: + DEVSTACK_NODE_NAME=${NODE_NAME} + - shell: | + #!/bin/bash -xe + # + # This job also gates devstack-gate, but in case a previous run fails, + # we need to always make sure that we're starting with the latest copy + # from master, before we start applying changes to it. If a previous run + # leaves a bad copy of the gate script, we may get stuck. + # + if [[ ! -e devstack-gate ]]; then + git clone https://review.openstack.org/p/openstack-ci/devstack-gate + else + cd devstack-gate + git remote update + git reset --hard + git clean -x -f + git checkout master + git reset --hard remotes/origin/master + git clean -x -f + cd .. + fi + - shell: | + #!/bin/bash -xe + export PYTHONUNBUFFERED=true + export DEVSTACK_GATE_TEMPEST=1 + cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh + ./safe-devstack-vm-gate-wrap.sh + + publishers: + - archive: + artifacts: logs/* + - trigger-parameterized-builds: + - project: devstack-update-complete + when: complete + predefined_parameters: + DEVSTACK_NODE_NAME=${NODE_NAME} + + +# Called by devstack jobs to alert that they have started so that the +# jenkins slave they are running on can be disabled. +- job: + name: devstack-update-inprogress + project-type: freestyle + concurrent: false + node: master + + properties: + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: 100 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + wrappers: + - timeout: + timeout: 10 + fail: true + - timestamps + + builders: + - shell: | + #!/bin/bash -xe + + if [[ ! -e devstack-gate ]]; then + git clone https://review.openstack.org/p/openstack-ci/devstack-gate + else + cd devstack-gate + git remote update + git pull --ff-only origin + cd .. + fi + - shell: | + #!/bin/bash -xe + export PYTHONUNBUFFERED=true + $WORKSPACE/devstack-gate/devstack-vm-inprogress.py $DEVSTACK_NODE_NAME + + +# Called by devstack jobs to alert that they have completed so that the +# jenkins slave may be deleted. +- job: + name: devstack-update-complete + project-type: freestyle + concurrent: false + node: master + + properties: + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: 100 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + wrappers: + - timeout: + timeout: 10 + fail: true + - timestamps + + builders: + - shell: | + #!/bin/bash -xe + + if [[ ! -e devstack-gate ]]; then + git clone https://review.openstack.org/p/openstack-ci/devstack-gate + else + cd devstack-gate + git remote update + git pull --ff-only origin + cd .. + fi + - shell: | + #!/bin/bash -xe + export PYTHONUNBUFFERED=true + $WORKSPACE/devstack-gate/devstack-vm-delete.py $DEVSTACK_NODE_NAME diff --git a/example/devstack.yml b/example/devstack.yml new file mode 100644 index 000000000..e78ddf03c --- /dev/null +++ b/example/devstack.yml @@ -0,0 +1,33 @@ +- job: + name: gate-devstack-merge + project-type: freestyle + concurrent: true + node: precise + + properties: + - github: + url: https://github.com/openstack-dev/devstack + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + # TODO: logrotate this job + #logrotate: + # daysToKeep: 28 + # numToKeep: -1 + # artifactDaysToKeep: -1 + # artifactNumToKeep: -1 + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - gerrit_git_prep diff --git a/example/gerrit-verification-status-plugin.yml b/example/gerrit-verification-status-plugin.yml new file mode 100644 index 000000000..264a1cded --- /dev/null +++ b/example/gerrit-verification-status-plugin.yml @@ -0,0 +1,35 @@ +- project: + name: gerrit-verification-status-plugin + github-org: openstack-ci + node: precise + + # TODO: standardize + #jobs: + #- gate-{name}-merge + +- job: + name: gate-gerrit-verification-status-plugin-merge + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: https://github.com/openstack-ci/gerrit-verification-status-plugin + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + triggers: + - zuul + + builders: + - gerrit_git_prep + + node: precise diff --git a/example/gerrit.yml b/example/gerrit.yml new file mode 100644 index 000000000..3f200cc28 --- /dev/null +++ b/example/gerrit.yml @@ -0,0 +1,159 @@ +- project: + name: gerrit + github-org: openstack-ci + node: precise + + # TODO: standardize + #jobs: + # - gate-{name}-merge + + +- job: + name: gate-gerrit-merge + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: https://github.com/openstack-ci/gerrit + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + triggers: + - zuul + + builders: + - gerrit_git_prep + + node: precise + + +- job: + name: check-gerrit-unittests + project-type: maven + concurrent: true + node: precise + + wrappers: + - timeout: + timeout: 40 + fail: true + + properties: + - github: + url: https://github.com/openstack-ci/gerrit + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + triggers: + - zuul + + prebuilders: + - gerrit_git_prep + - gerrit_preclean + + maven: + root_module: + group_id: com.google.gerrit + artifact_id: gerrit-parent + goals: 'clean package -Dgerrit.include-documentation=1 -X' + + postbuilders: + - gerrit_postrun + + publishers: + - war: + site: 'nova.openstack.org' + warfile: 'gerrit-war/target/gerrit*.war' + target: 'tarballs/ci/test/' + + +- job: + name: gate-gerrit-unittests + project-type: maven + concurrent: true + node: precise + + wrappers: + - timeout: + timeout: 40 + fail: true + + properties: + - github: + url: https://github.com/openstack-ci/gerrit + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + triggers: + - zuul + + prebuilders: + - gerrit_git_prep + - gerrit_preclean + + maven: + root_module: + group_id: com.google.gerrit + artifact_id: gerrit-parent + goals: 'clean package -Dgerrit.include-documentation=1 -X' + + postbuilders: + - gerrit_postrun + + +- job: + name: gerrit-package + project-type: maven + concurrent: true + node: precise + + wrappers: + - timeout: + timeout: 40 + fail: true + + properties: + - github: + url: https://github.com/openstack-ci/gerrit + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + triggers: + - zuul_post + + prebuilders: + - gerrit_git_prep + - gerrit_preclean + + maven: + root_module: + group_id: com.google.gerrit + artifact_id: gerrit-parent + goals: 'clean package -Dgerrit.include-documentation=1 -X' + + postbuilders: + - gerrit_postrun + + publishers: + - war: + site: 'nova.openstack.org' + warfile: 'gerrit-war/target/gerrit*.war' + target: 'tarballs/ci/' diff --git a/example/gerritbot.yml b/example/gerritbot.yml new file mode 100644 index 000000000..b5ba6b380 --- /dev/null +++ b/example/gerritbot.yml @@ -0,0 +1,90 @@ +- project: + name: gerritbot + github-org: openstack-ci + node: precise + doc-publisher-site: ci.openstack.org + tarball-publisher-site: ci.openstack.org + + jobs: + - gate-{name}-merge + - gate-{name}-pep8 + - gate-{name}-pyflakes + # TODO: standardize + #- '{name}-sdist-tarball' + #- '{name}-pypi' + +- job: + name: 'gerritbot-sdist-tarball' + project-type: freestyle + concurrent: true + node: precise + + properties: + - github: + url: 'https://github.com/openstack-ci/gerritbot' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + + triggers: + - zuul_post + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + builders: + - gerrit_git_prep + - shell: | + #!/bin/bash -xe + BRANCH=$GERRIT_REFNAME + BRANCH_PATH=`echo $BRANCH | tr / -` + + tox -v -evenv python setup.py sdist + cp dist/* dist/gerritbot-$BRANCH_PATH.tar.gz + + publishers: + - tarball: + project: 'gerritbot' + site: 'ci.openstack.org' + + +- job: + name: 'gerritbot-pypi' + concurrent: true + node: pypi + + properties: + - github: + url: 'https://github.com/openstack-ci/gerritbot' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + + triggers: + - zuul_post + + builders: + - gerrit_git_prep + - shell: tox -v -evenv python setup.py sdist upload + + publishers: + - tarball: + project: 'gerritbot' + site: 'ci.openstack.org' diff --git a/example/gerritlib.yml b/example/gerritlib.yml new file mode 100644 index 000000000..1e775c9e5 --- /dev/null +++ b/example/gerritlib.yml @@ -0,0 +1,45 @@ +- project: + name: gerritlib + github-org: openstack-ci + node: precise + doc-publisher-site: ci.openstack.org + tarball-publisher-site: ci.openstack.org + + jobs: + - gate-{name}-merge + - gate-{name}-pep8 + - gate-{name}-pyflakes + # TODO: standardize + #- '{name}-pypi' + +- job: + name: 'gerritlib-pypi' + concurrent: true + node: pypi + + properties: + - github: + url: 'https://github.com/openstack-ci/gerritlib' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul_post + + builders: + - gerrit_git_prep + - shell: tox -v -evenv python setup.py sdist upload + + publishers: + - tarball: + project: 'ci' + site: 'nova.openstack.org' diff --git a/example/glance.yml b/example/glance.yml new file mode 100644 index 000000000..7806057eb --- /dev/null +++ b/example/glance.yml @@ -0,0 +1,10 @@ +- project: + name: glance + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - openstack-publish-jobs diff --git a/example/heat.yml b/example/heat.yml new file mode 100644 index 000000000..85ba5c00d --- /dev/null +++ b/example/heat.yml @@ -0,0 +1,7 @@ +- project: + name: heat + github-org: heat-api + node: oneiric + + jobs: + - python-jobs diff --git a/example/horizon.yml b/example/horizon.yml new file mode 100644 index 000000000..92970a1b7 --- /dev/null +++ b/example/horizon.yml @@ -0,0 +1,43 @@ +- project: + name: horizon + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - openstack-publish-jobs + +- job: + name: gate-horizon-selenium + concurrent: true + node: precise + + properties: + - github: + url: https://github.com/openstack/horizon + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - gerrit_git_prep + - selenium diff --git a/example/jenkins-job-builder.yml b/example/jenkins-job-builder.yml new file mode 100644 index 000000000..29f395294 --- /dev/null +++ b/example/jenkins-job-builder.yml @@ -0,0 +1,34 @@ +- project: + name: jenkins-job-builder + github-org: openstack + node: precise + + # TODO: standardize + #jobs: + # - gate-{name}-merge + +- job: + name: gate-jenkins-job-builder-merge + concurrent: true + node: precise + + properties: + - github: + url: https://github.com/openstack-ci/jenkins-job-builder + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - gerrit_git_prep diff --git a/example/keystone.yml b/example/keystone.yml new file mode 100644 index 000000000..a1a0d9865 --- /dev/null +++ b/example/keystone.yml @@ -0,0 +1,10 @@ +- project: + name: keystone + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - openstack-publish-jobs diff --git a/example/macros.yml b/example/macros.yml new file mode 100644 index 000000000..8af5dcad1 --- /dev/null +++ b/example/macros.yml @@ -0,0 +1,115 @@ +- builder: + name: gerrit_git_prep + builders: + - shell: "/usr/local/jenkins/slave_scripts/gerrit-git-prep.sh review.openstack.org" + +- builder: + name: coverage + builders: + - shell: "/usr/local/jenkins/slave_scripts/run-cover.sh" + +- builder: + name: docs + builders: + - shell: "/usr/local/jenkins/slave_scripts/run-docs.sh" + +- builder: + name: maven_test + builders: + - shell: "mvn test" + +- builder: + name: maven_package + builders: + - shell: "mvn package" + +- builder: + name: gerrit_package + builders: + - shell: "/usr/local/jenkins/slave_scripts/package-gerrit.sh" + +- builder: + name: gerrit_preclean + #TODO: multiline: + builders: + - shell: "#!/bin/bash -xe\nrm -fr ~/.m2\nrm -fr ~/.java\n./tools/version.sh --release" + +- builder: + name: gerrit_postrun + builders: + - shell: "./tools/version.sh --reset" + +- builder: + name: pep8 + builders: + - shell: "set -o pipefail ; tox -v -epep8 | tee pep8.txt ; set +o pipefail" + +- builder: + name: pyflakes + builders: + - shell: "tox -v -epyflakes" + +- builder: + name: puppet_syntax + builders: + # TODO: remove blank line + - shell: | + + find . -iname *.pp | xargs puppet parser validate --modulepath=`pwd`/modules + for f in `find . -iname *.erb` ; do + erb -x -T '-' $f | ruby -c + done + +- builder: + name: selenium + builders: + - shell: "/usr/local/jenkins/slave_scripts/run-selenium.sh" + +- builder: + name: python26 + builders: + - shell: "/usr/local/jenkins/slave_scripts/run-tox.sh 26" + - something: + arg: value + +- builder: + name: python27 + builders: + - shell: "/usr/local/jenkins/slave_scripts/run-tox.sh 27" + +- builder: + name: python26_essex + builders: + - shell: "/usr/local/jenkins/slave_scripts/run-tox.sh 26-essex" + +- builder: + name: python27_essex + builders: + - shell: "/usr/local/jenkins/slave_scripts/run-tox.sh 27-essex" + +- builder: + name: tarball + builders: + - shell: "/usr/local/jenkins/slave_scripts/create-tarball.sh {project}" + +# ====================================================================== + +- publisher: + name: tarball + publishers: + - archive: + artifacts: 'dist/*.tar.gz' + - scp: + site: '{site}' + source: 'dist/*.tar.gz' + target: 'tarballs/{project}/' + +- publisher: + name: war + publishers: + - archive: + artifacts: '{warfile}' + - scp: + site: '{site}' + source: '{warfile}' + target: '{target}' diff --git a/example/mraas.yml b/example/mraas.yml new file mode 100644 index 000000000..e148cef2c --- /dev/null +++ b/example/mraas.yml @@ -0,0 +1,82 @@ +- project: + name: MRaaS + github-org: stackforge + node: precise + +- job: + name: gate-MRaaS-merge + concurrent: false + node: oneiric + + properties: + - github: + url: https://github.com/stackforge/MRaaS + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - gerrit: + triggerOnPatchsetUploadedEvent: 'false' + triggerOnChangeMergedEvent: 'false' + triggerOnCommentAddedEvent: 'true' + triggerOnRefUpdatedEvent: 'false' + triggerApprovalCategory: 'APRV' + triggerApprovalValue: 1 + failureMessage: 'This change was unable to be automatically merged with the current state of the repository. Please rebase your change and upload a new patchset.' + projects: + - projectCompareType: 'PLAIN' + projectPattern: 'stackforge/MRaaS' + branchCompareType: 'ANT' + branchPattern: '**' + + builders: + - gerrit_git_prep + + +- job: + name: check-MRaaS-merge + concurrent: false + node: oneiric + + properties: + - github: + url: https://github.com/stackforge/MRaaS + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - gerrit: + triggerOnPatchsetUploadedEvent: 'true' + triggerOnChangeMergedEvent: 'false' + triggerOnCommentAddedEvent: 'false' + triggerOnRefUpdatedEvent: 'false' + overrideVotes: 'true' + gerritBuildSuccessfulVerifiedValue: 1 + gerritBuildFailedVerifiedValue: -1 + failureMessage: 'This change was unable to be automatically merged with the current state of the repository. Please rebase your change and upload a new patchset.' + projects: + - projectCompareType: 'PLAIN' + projectPattern: 'stackforge/MRaaS' + branchCompareType: 'ANT' + branchPattern: '**' + + builders: + - gerrit_git_prep diff --git a/example/nova.yml b/example/nova.yml new file mode 100644 index 000000000..0dfd2a8eb --- /dev/null +++ b/example/nova.yml @@ -0,0 +1,12 @@ +- project: + name: nova + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - python-diablo-bitrot-jobs + - python-essex-bitrot-jobs + - openstack-publish-jobs diff --git a/example/openstack-ci-puppet.yml b/example/openstack-ci-puppet.yml new file mode 100644 index 000000000..668039061 --- /dev/null +++ b/example/openstack-ci-puppet.yml @@ -0,0 +1,63 @@ +- project: + name: ci-puppet + github-org: openstack + node: precise + + # TODO: standardize + #jobs: + # - gate-{name}-merge + +- job: + name: gate-ci-puppet-merge + concurrent: true + node: precise + + properties: + - github: + url: https://github.com/openstack/openstack-ci-puppet + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - gerrit_git_prep + + +- job: + name: gate-ci-puppet-syntax + concurrent: true + node: precise + + properties: + - github: + url: https://github.com/openstack/openstack-ci-puppet + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - gerrit_git_prep + - puppet_syntax + - pyflakes diff --git a/example/openstack-common.yml b/example/openstack-common.yml new file mode 100644 index 000000000..16b5005b9 --- /dev/null +++ b/example/openstack-common.yml @@ -0,0 +1,10 @@ +- project: + name: openstack-common + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - openstack-publish-jobs diff --git a/example/openstack-publish-jobs.yml b/example/openstack-publish-jobs.yml new file mode 100644 index 000000000..a78c53f35 --- /dev/null +++ b/example/openstack-publish-jobs.yml @@ -0,0 +1,87 @@ +- job-template: + name: '{name}-docs' + project-type: freestyle + concurrent: true + node: precise + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul_post + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + builders: + - gerrit_git_prep + - docs + + publishers: + - ftp: + site: '{doc-publisher-site}' + source: 'doc/build/html/**' + target: 'developer/{name}' + remove-prefix: 'doc/build/html' + excludes: '' + +- job-template: + name: '{name}-tarball' + project-type: freestyle + concurrent: true + node: precise + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul_post + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + builders: + - gerrit_git_prep + - tarball: + project: '{name}' + + publishers: + - tarball: + project: '{name}' + site: '{tarball-publisher-site}' + +- job-group: + name: openstack-publish-jobs + jobs: + - '{name}-docs' + - '{name}-tarball' diff --git a/example/pbr.yml b/example/pbr.yml new file mode 100644 index 000000000..6025e33eb --- /dev/null +++ b/example/pbr.yml @@ -0,0 +1,10 @@ +- project: + name: pbr + github-org: openstack-dev + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - pypi-jobs diff --git a/example/pypi-jobs.yml b/example/pypi-jobs.yml new file mode 100644 index 000000000..68fc96559 --- /dev/null +++ b/example/pypi-jobs.yml @@ -0,0 +1,85 @@ +- job-template: + name: '{name}-sdist-tarball' + project-type: freestyle + concurrent: true + node: precise + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul_post + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + builders: + - gerrit_git_prep + - shell: | + #!/bin/bash -xe + BRANCH=$GERRIT_REFNAME + BRANCH_PATH=`echo $BRANCH | tr / -` + + tox -v -evenv python setup.py sdist + cp dist/* dist/{name}-$BRANCH_PATH.tar.gz + + publishers: + - tarball: + project: '{name}' + site: '{tarball-publisher-site}' + + +- job-template: + name: '{name}-pypi' + project-type: freestyle + concurrent: true + node: pypi + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul_post + + builders: + - gerrit_git_prep + - shell: tox -v -evenv python setup.py sdist upload + + publishers: + - tarball: + project: '{name}' + site: '{tarball-publisher-site}' + +- job-group: + name: pypi-jobs + jobs: + - '{name}-docs' + - '{name}-sdist-tarball' + - '{name}-pypi' diff --git a/example/pypi-mirror.yml b/example/pypi-mirror.yml new file mode 100644 index 000000000..bed7e5808 --- /dev/null +++ b/example/pypi-mirror.yml @@ -0,0 +1,64 @@ +- project: + name: pypi-mirror + github-org: openstack-ci + node: precise + + # TODO: standardize + #jobs: + # - gate-{name}-merge + # - gate-{name}-pyflakes + +- job: + name: gate-pypi-mirror-merge + project-type: freestyle + concurrent: true + node: precise + + properties: + - github: + url: https://github.com/openstack-ci/pypi-mirror + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - gerrit_git_prep + +- job: + name: gate-pypi-mirror-pyflakes + project-type: freestyle + concurrent: true + node: precise + + properties: + - github: + url: https://github.com/openstack-ci/pypi-mirror + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - gerrit_git_prep + - pyflakes diff --git a/example/python-bitrot-jobs.yml b/example/python-bitrot-jobs.yml new file mode 100644 index 000000000..5b1d6fc22 --- /dev/null +++ b/example/python-bitrot-jobs.yml @@ -0,0 +1,140 @@ +- job-template: + name: 'periodic-{name}-python26-{branch-name}' + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + triggers: + - timed: '@daily' + + builders: + - python26 + + scm: + - git: + url: 'git://github.com/{github-org}/{name}.git' + branches: + - 'origin/{branch}' + + # >= precise does not have python2.6 + node: oneiric + + +- job-template: + name: 'periodic-{name}-python27-{branch-name}' + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + triggers: + - timed: '@daily' + + builders: + - python27 + + scm: + - git: + url: 'git://github.com/{github-org}/{name}.git' + branches: + - 'origin/{branch}' + + node: '{node}' + + +- job-template: + name: 'periodic-{name}-docs-{branch-name}' + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + triggers: + - timed: '@daily' + + builders: + - docs + + scm: + - git: + url: 'git://github.com/{github-org}/{name}.git' + branches: + - 'origin/{branch}' + + node: '{node}' + + +- job-group: + name: python-diablo-bitrot-jobs + branch: 'stable/diablo' + branch-name: 'stable-diablo' + node: oneiric + jobs: + - 'periodic-{name}-python26-{branch-name}' + - 'periodic-{name}-python27-{branch-name}' + - 'periodic-{name}-docs-{branch-name}' + +- job-group: + name: python-essex-bitrot-jobs + branch: 'stable/essex' + branch-name: 'stable-essex' + node: precise + jobs: + - 'periodic-{name}-python26-{branch-name}' + - 'periodic-{name}-python27-{branch-name}' + - 'periodic-{name}-docs-{branch-name}' diff --git a/example/python-cinderclient.yml b/example/python-cinderclient.yml new file mode 100644 index 000000000..d05a16f76 --- /dev/null +++ b/example/python-cinderclient.yml @@ -0,0 +1,10 @@ +- project: + name: python-cinderclient + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - pypi-jobs diff --git a/example/python-glanceclient.yml b/example/python-glanceclient.yml new file mode 100644 index 000000000..691737e26 --- /dev/null +++ b/example/python-glanceclient.yml @@ -0,0 +1,10 @@ +- project: + name: python-glanceclient + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - pypi-jobs diff --git a/example/python-jobs.yml b/example/python-jobs.yml new file mode 100644 index 000000000..20233bb8d --- /dev/null +++ b/example/python-jobs.yml @@ -0,0 +1,267 @@ +- job-template: + name: '{name}-coverage' + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + triggers: + - zuul_post + + builders: + - gerrit_git_prep + - coverage + + publishers: + - coverage + + node: '{node}' + + +- job-template: + name: 'gate-{name}-pep8' + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + triggers: + - zuul + + builders: + - gerrit_git_prep + - pep8 + + publishers: + - pep8 + + node: '{node}' + + +- job-template: + name: 'gate-{name}-python26' + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + triggers: + - zuul + + builders: + - gerrit_git_prep + - python26 + + # >= precise does not have python2.6 + node: oneiric + + +- job-template: + name: 'gate-{name}-python27' + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + parameters: + - label: + name: NODE_LABEL + description: Label of node to use for this build + default: '{node}' + + triggers: + - zuul + + builders: + - gerrit_git_prep + - python27 + + node: '{node}' + + +- job-template: + name: 'gate-{name}-merge' + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + triggers: + - zuul + + builders: + - gerrit_git_prep + + node: '{node}' + + +- job-template: + name: 'gate-{name}-docs' + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + triggers: + - zuul + + builders: + - gerrit_git_prep + - docs + + node: '{node}' + + +- job-template: + name: 'gate-{name}-pyflakes' + project-type: freestyle + concurrent: true + node: precise + + properties: + - github: + url: 'https://github.com/{github-org}/{name}' + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - gerrit_git_prep + - pyflakes + + +- job-group: + name: python-jobs + jobs: + - '{name}-coverage' + - 'gate-{name}-merge' + - 'gate-{name}-pep8' + - 'gate-{name}-python26' + - 'gate-{name}-python27' + - 'gate-{name}-docs' + # pyflakes isn't standard diff --git a/example/python-keystoneclient.yml b/example/python-keystoneclient.yml new file mode 100644 index 000000000..6d4f94d1c --- /dev/null +++ b/example/python-keystoneclient.yml @@ -0,0 +1,10 @@ +- project: + name: python-keystoneclient + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - pypi-jobs diff --git a/example/python-novaclient.yml b/example/python-novaclient.yml new file mode 100644 index 000000000..08ac2a3ab --- /dev/null +++ b/example/python-novaclient.yml @@ -0,0 +1,10 @@ +- project: + name: python-novaclient + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - pypi-jobs diff --git a/example/python-openstackclient.yml b/example/python-openstackclient.yml new file mode 100644 index 000000000..caac05c5a --- /dev/null +++ b/example/python-openstackclient.yml @@ -0,0 +1,10 @@ +- project: + name: python-openstackclient + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - pypi-jobs diff --git a/example/python-quantumclient.yml b/example/python-quantumclient.yml new file mode 100644 index 000000000..64c5c3f8d --- /dev/null +++ b/example/python-quantumclient.yml @@ -0,0 +1,10 @@ +- project: + name: python-quantumclient + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - pypi-jobs diff --git a/example/python-swiftclient.yml b/example/python-swiftclient.yml new file mode 100644 index 000000000..ab0e47b66 --- /dev/null +++ b/example/python-swiftclient.yml @@ -0,0 +1,10 @@ +- project: + name: python-swiftclient + github-org: openstack + node: precise + tarball-publisher-site: swift.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - pypi-jobs diff --git a/example/quantum.yml b/example/quantum.yml new file mode 100644 index 000000000..3bae88f7e --- /dev/null +++ b/example/quantum.yml @@ -0,0 +1,10 @@ +- project: + name: quantum + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - openstack-publish-jobs diff --git a/example/reddwarf.yml b/example/reddwarf.yml new file mode 100644 index 000000000..7786f8e6e --- /dev/null +++ b/example/reddwarf.yml @@ -0,0 +1,7 @@ +- project: + name: reddwarf + github-org: stackforge + node: oneiric + + jobs: + - python-jobs diff --git a/example/requirements.yml b/example/requirements.yml new file mode 100644 index 000000000..c0c01a942 --- /dev/null +++ b/example/requirements.yml @@ -0,0 +1,34 @@ +- project: + name: requirements + github-org: openstack + node: oneiric + + # TODO: standardize + #jobs: + # - gate-{name}-merge + +- job: + name: gate-requirements-merge + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + + properties: + - github: + url: https://github.com/openstack/requirements + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + triggers: + - zuul + + builders: + - gerrit_git_prep + + node: precise diff --git a/example/swift.yml b/example/swift.yml new file mode 100644 index 000000000..6faa2c651 --- /dev/null +++ b/example/swift.yml @@ -0,0 +1,10 @@ +- project: + name: swift + github-org: openstack + node: precise + tarball-publisher-site: nova.openstack.org + doc-publisher-site: docs.openstack.org + + jobs: + - python-jobs + - openstack-publish-jobs diff --git a/example/tempest.yml b/example/tempest.yml new file mode 100644 index 000000000..4f4739b0a --- /dev/null +++ b/example/tempest.yml @@ -0,0 +1,67 @@ +- project: + name: tempest + github-org: openstack + node: precise + + # TODO: standardize + #jobs: + # - gate-{name}-merge + # - gate-{name}-pep8 + +- job: + name: gate-tempest-merge + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: https://github.com/openstack-ci/tempest + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + triggers: + - zuul + + builders: + - gerrit_git_prep + + node: precise + +- job: + name: gate-tempest-pep8 + concurrent: true + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + properties: + - github: + url: https://github.com/openstack-ci/tempest + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + triggers: + - zuul + + builders: + - gerrit_git_prep + - pep8 + + publishers: + - pep8 + + node: precise diff --git a/example/zuul.yml b/example/zuul.yml new file mode 100644 index 000000000..bbe44c0b6 --- /dev/null +++ b/example/zuul.yml @@ -0,0 +1,79 @@ +- project: + name: zuul + github-org: openstack-ci + node: precise + jobs: + - python-jobs + # TODO: standardize these + #- gate-{name}-pyflakes + #- '{name}-docs + +- job: + name: gate-zuul-pyflakes + project-type: freestyle + concurrent: true + node: precise + + properties: + - github: + url: https://github.com/openstack-ci/zuul + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul + + builders: + - gerrit_git_prep + - pyflakes + + +- job: + name: zuul-docs + project-type: freestyle + concurrent: true + node: precise + + properties: + - github: + url: https://github.com/openstack-ci/zuul + - throttle: + max-per-node: 0 + max-total: 0 + option: project + enabled: false + + wrappers: + - timeout: + timeout: 30 + fail: true + - timestamps + + triggers: + - zuul_post + + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 + + builders: + - gerrit_git_prep + - docs + + publishers: + - scp: + site: '173.203.107.207' + source: 'doc/build/html/**/*' + target: 'ci/zuul' + keep-hierarchy: true diff --git a/jenkins-jobs b/jenkins-jobs new file mode 100755 index 000000000..6e74058f5 --- /dev/null +++ b/jenkins-jobs @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +import jenkins_jobs.builder +import argparse + +def main(): + parser = argparse.ArgumentParser() + subparser = parser.add_subparsers(help='update, test or delete job', + dest='command') + parser_update = subparser.add_parser('update') + parser_update.add_argument('path', help='Path to YAML file or directory') + parser_update.add_argument('name', help='name of job') + parser_test = subparser.add_parser('test') + parser_test.add_argument('path', help='Path to YAML file or directory') + parser_test.add_argument('-o', dest='output_dir', help='Path to output XML') + parser_test.add_argument('name', help='name of job', nargs='?') + parser_delete = subparser.add_parser('delete') + parser_delete.add_argument('name', help='name of job') + parser.add_argument('--conf', dest='conf', help='Configuration file') + options = parser.parse_args() + + if options.conf: + conf = options.conf + else: + conf = 'jenkins_jobs.ini' + + if not options.command == 'test': + conffp = open(conf, 'r') + config = ConfigParser.ConfigParser() + config.readfp(conffp) + else: + config = {} + + builder = jenkins_jobs.builder.Builder(config.get('jenkins','url'), + config.get('jenkins','user'), + config.get('jenkins','password')) + + if options.command == 'delete': + builder.delete_job() + elif options.command == 'update': + builder.update_job() + elif options.command == 'test': + builder.update_job(options.path, options.name, + output_dir=options.output_dir) + +if __name__ == '__main__': + main() diff --git a/jenkins_jobs.py b/jenkins_jobs.py deleted file mode 100644 index 92bce197a..000000000 --- a/jenkins_jobs.py +++ /dev/null @@ -1,279 +0,0 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. -# -# 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. - -# Manage jobs in Jenkins server - -import os -import argparse -import hashlib -import yaml -import xml.etree.ElementTree as XML -from xml.dom import minidom -import jenkins -import ConfigParser -from StringIO import StringIO -import re -import pkgutil - -import modules - -class JenkinsJobsException(Exception): pass - -parser = argparse.ArgumentParser() -subparser = parser.add_subparsers(help='update, test or delete job', dest='command') -parser_update = subparser.add_parser('update') -parser_update.add_argument('file', help='YAML file for update') -parser_update = subparser.add_parser('test') -parser_update.add_argument('file', help='YAML file for test') -parser_delete = subparser.add_parser('delete') -parser_delete.add_argument('name', help='name of job') -parser.add_argument('--conf', dest='conf', help='Configuration file') -options = parser.parse_args() - -if options.conf: - conf = options.conf -else: - conf = 'jenkins_jobs.ini' - -if not options.command == 'test': - conffp = open(conf, 'r') - config = ConfigParser.ConfigParser() - config.readfp(conffp) - -class YamlParser(object): - def __init__(self, yfile): - self.registry = ModuleRegistry() - self.data = yaml.load_all(yfile) - self.it = self.data.__iter__() - self.job_name = None - self.template_data = None - self.current = None - self.current_template = None - self.template_it = None - self.reading_template = False - self.eof = False - self.seek_next_xml() - - def process_template(self): - project_data = self.current['project'] - template_file = file('templates/' + project_data['template'] + '.yml', 'r') - template = template_file.read() - template_file.close() - values = self.current['values'].iteritems() - for key, value in values: - key = '@' + key.upper() + '@' - template = template.replace(key, value) - template_steam = StringIO(template) - self.template_data = yaml.load_all(template_steam) - self.template_it = self.template_data.__iter__() - self.reading_template = True - - def get_next_xml(self): - if not self.eof: - if self.reading_template: - data = XmlParser(self.current_template, self.registry) - self.job_name = self.current_template['main']['name'] - else: - data = XmlParser(self.current, self.registry) - self.job_name = self.current['main']['name'] - self.seek_next_xml() - return data - else: - raise JenkinsJobsException('End of file') - - def seek_next_xml(self): - if self.reading_template: - try: - self.current_template = self.template_it.next() - return - except StopIteration: - self.reading_template = False - try: - self.current = self.it.next() - except StopIteration: - self.eof = True - - if self.current.has_key('project'): - self.process_template() - self.current_template = self.template_it.next() - - def get_name(self): - return self.job_name - -class ModuleRegistry(object): - # TODO: make this extensible - - def __init__(self): - self.modules = [] - self.handlers = {} - - for importer, modname, ispkg in pkgutil.iter_modules(modules.__path__): - module = __import__('modules.'+modname, fromlist=['register']) - register = getattr(module, 'register', None) - if register: - register(self) - - def registerModule(self, mod): - self.modules.append(mod) - self.modules.sort(lambda a, b: cmp(a.sequence, b.sequence)) - - def registerHandler(self, category, name, method): - cat_dict = self.handlers.get(category, {}) - if not cat_dict: - self.handlers[category] = cat_dict - cat_dict[name] = method - - def getHandler(self, category, name): - return self.handlers[category][name] - -class XmlParser(object): - def __init__(self, data, registry): - self.data = data - self.registry = registry - self._build() - - def _build(self): - for module in self.registry.modules: - if hasattr(module, 'root_xml'): - element = module.root_xml(self.data) - if element is not None: - self.xml = element - - for module in self.registry.modules: - if hasattr(module, 'handle_data'): - module.handle_data(self.data) - - XML.SubElement(self.xml, 'actions') - description = XML.SubElement(self.xml, 'description') - description.text = "THIS JOB IS MANAGED BY PUPPET AND WILL BE OVERWRITTEN.\n\n\ -DON'T EDIT THIS JOB THROUGH THE WEB\n\n\ -If you would like to make changes to this job, please see:\n\n\ -https://github.com/openstack/openstack-ci-puppet\n\n\ -In modules/jenkins_jobs" - XML.SubElement(self.xml, 'keepDependencies').text = 'false' - if self.data['main'].get('disabled'): - XML.SubElement(self.xml, 'disabled').text = 'true' - else: - XML.SubElement(self.xml, 'disabled').text = 'false' - XML.SubElement(self.xml, 'blockBuildWhenDownstreamBuilding').text = 'false' - XML.SubElement(self.xml, 'blockBuildWhenUpstreamBuilding').text = 'false' - if self.data['main'].get('concurrent'): - XML.SubElement(self.xml, 'concurrentBuild').text = 'true' - else: - XML.SubElement(self.xml, 'concurrentBuild').text = 'false' - - for module in self.registry.modules: - if hasattr(module, 'gen_xml'): - module.gen_xml(self.xml, self.data) - - def md5(self): - return hashlib.md5(self.output()).hexdigest() - - # Pretty printing ideas from http://stackoverflow.com/questions/749796/pretty-printing-xml-in-python - pretty_text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL) - - def output(self): - out = minidom.parseString(XML.tostring(self.xml)).toprettyxml(indent=' ') - return self.pretty_text_re.sub('>\g<1></', out) - - -class CacheStorage(object): - def __init__(self): - self.cachefilename = os.path.expanduser('~/.jenkins_jobs_cache.yml') - try: - yfile = file(self.cachefilename, 'r') - except IOError: - self.data = {} - return - self.data = yaml.load(yfile) - yfile.close() - - def set(self, job, md5): - self.data[job] = md5 - yfile = file(self.cachefilename, 'w') - yaml.dump(self.data, yfile) - yfile.close() - - def is_cached(self, job): - if self.data.has_key(job): - return True - return False - - def has_changed(self, job, md5): - if self.data.has_key(job) and self.data[job] == md5: - return False - return True - -class Jenkins(object): - def __init__(self, url, user, password): - self.jenkins = jenkins.Jenkins(url, user, password) - - def update_job(self, job_name, xml): - if self.is_job(job_name): - self.jenkins.reconfig_job(job_name, xml) - else: - self.jenkins.create_job(job_name, xml) - - def is_job(self, job_name): - return self.jenkins.job_exists(job_name) - - def get_job_md5(self, job_name): - xml = self.jenkins.get_job_config(job_name) - return hashlib.md5(xml).hexdigest() - - def delete_job(self, job_name): - if self.is_job(job_name): - self.jenkins.delete_job(job_name) - -def delete_job(): - remote_jenkins = Jenkins(config.get('jenkins','url'), config.get('jenkins','user'), config.get('jenkins','password')) - remote_jenkins.delete_job(options.name) - -def update_job(test = False): - if os.path.isdir(options.file): - files_to_process = [os.path.join(options.file, f) - for f in os.listdir(options.file)] - else: - files_to_process = [options.file] - cache = CacheStorage() - if not test: - remote_jenkins = Jenkins(config.get('jenkins','url'), config.get('jenkins','user'), config.get('jenkins','password')) - for in_file in files_to_process: - yparse = YamlParser(open(in_file, 'r')) - while True: - try: - xml = yparse.get_next_xml() - job = yparse.get_name() - if test: - print xml.output() - continue - md5 = xml.md5() - if remote_jenkins.is_job(job) and not cache.is_cached(job): - old_md5 = remote_jenkins.get_job_md5(job) - cache.set(job, old_md5) - - if cache.has_changed(job, md5): - remote_jenkins.update_job(job, xml.output()) - cache.set(job, md5) - except JenkinsJobsException: - break - -if options.command == 'delete': - delete_job() -elif options.command == 'update': - update_job() -elif options.command == 'test': - update_job(True) - diff --git a/modules/__init__.py b/jenkins_jobs/__init__.py similarity index 100% rename from modules/__init__.py rename to jenkins_jobs/__init__.py diff --git a/jenkins_jobs/builder.py b/jenkins_jobs/builder.py new file mode 100644 index 000000000..80bddbbc5 --- /dev/null +++ b/jenkins_jobs/builder.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python +# Copyright (C) 2012 OpenStack, LLC. +# +# 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. + +# Manage jobs in Jenkins server + +import os +import hashlib +import yaml +import xml.etree.ElementTree as XML +from xml.dom import minidom +import jenkins +import ConfigParser +from StringIO import StringIO +import re +import pkgutil +import pkg_resources +import pprint +import sys + +class JenkinsJobsException(Exception): pass + +class YamlParser(object): + def __init__(self): + self.registry = ModuleRegistry() + self.data = {} + self.jobs = [] + + def parse(self, fn): + data = yaml.load(open(fn)) + for item in data: + cls, dfn = item.items()[0] + group = self.data.get(cls, {}) + name = dfn['name'] + group[name] = dfn + self.data[cls] = group + + def getJob(self, name): + return self.data.get('job', {}).get(name, None) + + def getJobGroup(self, name): + return self.data.get('job-group', {}).get(name, None) + + def getJobTemplate(self, name): + return self.data.get('job-template', {}).get(name, None) + + def generateXML(self): + changed = True + while changed: + changed = False + for module in self.registry.modules: + if hasattr(module, 'handle_data'): + if module.handle_data(self): + changed = True + + for job in self.data.get('job', {}).values(): + self.getXMLForJob(job) + for project in self.data.get('project', {}).values(): + for jobname in project.get('jobs', []): + job = self.getJob(jobname) + if job: + # Just naming an existing defined job + continue + # see if it's a job group + group = self.getJobGroup(jobname) + if group: + for group_jobname in group['jobs']: + job = self.getJob(group_jobname) + if job: + continue + template = self.getJobTemplate(group_jobname) + # Allow a group to override parameters set by a project + d = {} + d.update(project) + d.update(group) + # Except name, since the group's name is not useful + d['name'] = project['name'] + if template: + self.getXMLForTemplateJob(d, template) + continue + # see if it's a template + template = self.getJobTemplate(jobname) + if template: + self.getXMLForTemplateJob(project, template) + + def getXMLForTemplateJob(self, project, template): + s = yaml.dump(template, default_flow_style=False) + s = s.format(**project) + data = yaml.load(s) + self.getXMLForJob(data) + + def getXMLForJob(self, data): + kind = data.get('project-type', 'freestyle') + for ep in pkg_resources.iter_entry_points( + group='jenkins_jobs.projects', name=kind): + Mod = ep.load() + mod = Mod(self.registry) + xml = mod.root_xml(data) + self.gen_xml(xml, data) + job = XmlJob(xml, data['name']) + self.jobs.append(job) + break + + def gen_xml(self, xml, data): + XML.SubElement(xml, 'actions') + description = XML.SubElement(xml, 'description') + description.text = "THIS JOB IS MANAGED BY PUPPET AND WILL BE OVERWRITTEN.\n\n\ +DON'T EDIT THIS JOB THROUGH THE WEB\n\n\ +If you would like to make changes to this job, please see:\n\n\ +https://github.com/openstack/openstack-ci-puppet\n\n\ +In modules/jenkins_jobs" + XML.SubElement(xml, 'keepDependencies').text = 'false' + if data.get('disabled'): + XML.SubElement(xml, 'disabled').text = 'true' + else: + XML.SubElement(xml, 'disabled').text = 'false' + XML.SubElement(xml, 'blockBuildWhenDownstreamBuilding').text = 'false' + XML.SubElement(xml, 'blockBuildWhenUpstreamBuilding').text = 'false' + if data.get('concurrent'): + XML.SubElement(xml, 'concurrentBuild').text = 'true' + else: + XML.SubElement(xml, 'concurrentBuild').text = 'false' + + for module in self.registry.modules: + if hasattr(module, 'gen_xml'): + module.gen_xml(self, xml, data) + + +class ModuleRegistry(object): + # TODO: make this extensible + + def __init__(self): + self.modules = [] + self.handlers = {} + + for entrypoint in pkg_resources.iter_entry_points( + group='jenkins_jobs.modules'): + Mod = entrypoint.load() + mod = Mod(self) + self.modules.append(mod) + self.modules.sort(lambda a, b: cmp(a.sequence, b.sequence)) + + def registerHandler(self, category, name, method): + cat_dict = self.handlers.get(category, {}) + if not cat_dict: + self.handlers[category] = cat_dict + cat_dict[name] = method + + def getHandler(self, category, name): + return self.handlers[category][name] + +class XmlJob(object): + def __init__(self, xml, name): + self.xml = xml + self.name = name + + def md5(self): + return hashlib.md5(self.output()).hexdigest() + + # Pretty printing ideas from http://stackoverflow.com/questions/749796/pretty-printing-xml-in-python + pretty_text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL) + + def output(self): + out = minidom.parseString(XML.tostring(self.xml)).toprettyxml(indent=' ') + return self.pretty_text_re.sub('>\g<1></', out) + + +class CacheStorage(object): + def __init__(self): + self.cachefilename = os.path.expanduser('~/.jenkins_jobs_cache.yml') + try: + yfile = file(self.cachefilename, 'r') + except IOError: + self.data = {} + return + self.data = yaml.load(yfile) + yfile.close() + + def set(self, job, md5): + self.data[job] = md5 + yfile = file(self.cachefilename, 'w') + yaml.dump(self.data, yfile) + yfile.close() + + def is_cached(self, job): + if self.data.has_key(job): + return True + return False + + def has_changed(self, job, md5): + if self.data.has_key(job) and self.data[job] == md5: + return False + return True + +class Jenkins(object): + def __init__(self, url, user, password): + self.jenkins = jenkins.Jenkins(url, user, password) + + def update_job(self, job_name, xml): + if self.is_job(job_name): + self.jenkins.reconfig_job(job_name, xml) + else: + self.jenkins.create_job(job_name, xml) + + def is_job(self, job_name): + return self.jenkins.job_exists(job_name) + + def get_job_md5(self, job_name): + xml = self.jenkins.get_job_config(job_name) + return hashlib.md5(xml).hexdigest() + + def delete_job(self, job_name): + if self.is_job(job_name): + self.jenkins.delete_job(job_name) + +class Builder(object): + def __init__(self, jenkins_url, jenkins_user, jenkins_password): + self.jenkins = Jenkins(jenkins_url, jenkins_user, jenkins_password) + self.cache = CacheStorage() + + def delete_job(self): + self.jenkins.delete_job(options.name) + + def update_job(self, fn, name=None, output_dir=None): + if os.path.isdir(fn): + files_to_process = [os.path.join(fn, f) + for f in os.listdir(fn) + if (f.endswith('.yml') or f.endswith('.yaml'))] + else: + files_to_process = [fn] + parser = YamlParser() + for in_file in files_to_process: + parser.parse(in_file) + parser.generateXML() + + parser.jobs.sort(lambda a,b: cmp(a.name, b.name)) + for job in parser.jobs: + if name and job.name != name: + continue + if output_dir: + #print '='*70 + #print job.name + #print '-'*70 + if name: + print job.output() + continue + fn = os.path.join(output_dir, job.name) + f = open(fn, 'w') + f.write(job.output()) + f.close() + continue + md5 = job.md5() + if (remote_jenkins.is_job(job.nam) + and not self.cache.is_cached(job.name)): + old_md5 = remote_jenkins.get_job_md5(job.name) + self.cache.set(job.name, old_md5) + + if self.cache.has_changed(job.name, md5): + remote_jenkins.update_job(job.name, xml.output()) + self.cache.set(job.name, md5) + + + diff --git a/jenkins_jobs/modules/__init__.py b/jenkins_jobs/modules/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/modules/assignednode.py b/jenkins_jobs/modules/assignednode.py similarity index 65% rename from modules/assignednode.py rename to jenkins_jobs/modules/assignednode.py index b40f22226..6ce935f86 100644 --- a/modules/assignednode.py +++ b/jenkins_jobs/modules/assignednode.py @@ -1,5 +1,4 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. +# 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. @@ -19,18 +18,14 @@ # - node: 'oneiric' import xml.etree.ElementTree as XML +import jenkins_jobs.modules.base -def register(registry): - mod = AssignedNode() - registry.registerModule(mod) - - -class AssignedNode(object): +class AssignedNode(jenkins_jobs.modules.base.Base): sequence = 40 - def gen_xml(self, xml_parent, data): - node = data['assignednode']['node'] - XML.SubElement(xml_parent, 'assignedNode').text = node - XML.SubElement(xml_parent, 'canRoam').text = 'false' - + def gen_xml(self, parser, xml_parent, data): + node = data.get('node', None) + if node: + XML.SubElement(xml_parent, 'assignedNode').text = node + XML.SubElement(xml_parent, 'canRoam').text = 'false' diff --git a/jenkins_jobs/modules/base.py b/jenkins_jobs/modules/base.py new file mode 100644 index 000000000..ca377051e --- /dev/null +++ b/jenkins_jobs/modules/base.py @@ -0,0 +1,58 @@ +# 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. + +# Base class for a jenkins_jobs module + +import pkg_resources +import yaml + + +class Base(object): + sequence = 10 + + def __init__(self, registry): + self.registry = registry + + def _dispatch(self, component_type, component_list_type, + parser, xml_parent, + component, template_data={}): + if isinstance(component, dict): + # The component is a sigleton dictionary of name: dict(args) + name, component_data = component.items()[0] + if template_data: + # Template data contains values that should be interpolated + # into the component definition + s = yaml.dump(component_data, default_flow_style=False) + s = s.format(**template_data) + component_data = yaml.load(s) + else: + # The component is a simple string name, eg "run-tests" + name = component + component_data = {} + + # Look for a component function defined in an entry point + for ep in pkg_resources.iter_entry_points( + group='jenkins_jobs.{0}'.format(component_list_type), name=name): + func = ep.load() + func(parser, xml_parent, component_data) + else: + # Otherwise, see if it's defined as a macro + component = parser.data.get(component_type, {}).get(name) + if component: + for b in component[component_list_type]: + # Pass component_data in as template data to this function + # so that if the macro is invoked with arguments, + # the arguments are interpolated into the real defn. + self._dispatch(component_type, component_list_type, + parser, xml_parent, b, component_data) diff --git a/jenkins_jobs/modules/builders.py b/jenkins_jobs/modules/builders.py new file mode 100644 index 000000000..5697cff84 --- /dev/null +++ b/jenkins_jobs/modules/builders.py @@ -0,0 +1,63 @@ +# 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. + +# Jenkins Job module for builders +# To use add the folowing into your YAML: +# builders: +# - 'gerrit_git_prep' +# - 'python26' + +import xml.etree.ElementTree as XML +import jenkins_jobs.modules.base +import pkg_resources +import yaml + +def shell(parser, xml_parent, data): + shell = XML.SubElement(xml_parent, 'hudson.tasks.Shell') + XML.SubElement(shell, 'command').text = data + +def trigger_builds(parser, xml_parent, data): + tbuilder = XML.SubElement(xml_parent, + 'hudson.plugins.parameterizedtrigger.TriggerBuilder') + configs = XML.SubElement(tbuilder, 'configs') + for project_def in data: + tconfig = XML.SubElement(configs, + 'hudson.plugins.parameterizedtrigger.BlockableBuildTriggerConfig') + tconfigs = XML.SubElement(tconfig, 'configs') + if project_def.has_key('predefined_parameters'): + params = XML.SubElement(tconfigs, + 'hudson.plugins.parameterizedtrigger.PredefinedBuildParameters') + properties = XML.SubElement(params, 'properties') + properties.text = project_def['predefined_parameters'] + else: + tconfigs.set('class', 'java.util.Collections$EmptyList') + projects = XML.SubElement(tconfig, 'projects') + projects.text = project_def['project'] + condition = XML.SubElement(tconfig, 'condition') + condition.text = 'ALWAYS' + trigger_with_no_params = XML.SubElement(tconfig, 'triggerWithNoParameters') + trigger_with_no_params.text = 'false' + build_all_nodes_with_label = XML.SubElement(tconfig, 'buildAllNodesWithLabel') + build_all_nodes_with_label.text = 'false' + +class Builders(jenkins_jobs.modules.base.Base): + sequence = 60 + + def gen_xml(self, parser, xml_parent, data): + for alias in ['prebuilders', 'builders', 'postbuilders']: + if alias in data: + builders = XML.SubElement(xml_parent, alias) + for builder in data[alias]: + self._dispatch('builder', 'builders', + parser, builders, builder) diff --git a/modules/logrotate.py b/jenkins_jobs/modules/logrotate.py similarity index 78% rename from modules/logrotate.py rename to jenkins_jobs/modules/logrotate.py index 9721b7a79..46c9a7b62 100644 --- a/modules/logrotate.py +++ b/jenkins_jobs/modules/logrotate.py @@ -1,5 +1,4 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. +# 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. @@ -22,23 +21,16 @@ # artifactNumToKeep: -1 import xml.etree.ElementTree as XML +import jenkins_jobs.modules.base -def register(registry): - mod = LogRotate() - registry.registerModule(mod) - - -class LogRotate(object): +class LogRotate(jenkins_jobs.modules.base.Base): sequence = 10 - def handle_data(self, data): - self.data = data - - def gen_xml(self, xml_parent, data): - if self.data.has_key('logrotate'): + def gen_xml(self, parser, xml_parent, data): + if data.has_key('logrotate'): lr_xml = XML.SubElement(xml_parent, 'logRotator') - logrotate = self.data['logrotate'] + logrotate = data['logrotate'] lr_days = XML.SubElement(lr_xml, 'daysToKeep') lr_days.text = str(logrotate['daysToKeep']) lr_num = XML.SubElement(lr_xml, 'numToKeep') diff --git a/modules/project_freestyle.py b/jenkins_jobs/modules/project_freestyle.py similarity index 80% rename from modules/project_freestyle.py rename to jenkins_jobs/modules/project_freestyle.py index 72ce41214..b4c3b4697 100644 --- a/modules/project_freestyle.py +++ b/jenkins_jobs/modules/project_freestyle.py @@ -1,5 +1,4 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. +# 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. @@ -22,18 +21,12 @@ # goals: 'test' import xml.etree.ElementTree as XML +import jenkins_jobs.modules.base -def register(registry): - mod = Freestyle() - registry.registerModule(mod) - - -class Freestyle(object): +class Freestyle(jenkins_jobs.modules.base.Base): sequence = 0 def root_xml(self, data): - if 'maven' in data: - return None xml_parent = XML.Element('project') return xml_parent diff --git a/modules/project_maven.py b/jenkins_jobs/modules/project_maven.py similarity index 93% rename from modules/project_maven.py rename to jenkins_jobs/modules/project_maven.py index 0131c7d01..0b775c0d7 100644 --- a/modules/project_maven.py +++ b/jenkins_jobs/modules/project_maven.py @@ -1,5 +1,4 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. +# 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. @@ -22,14 +21,9 @@ # goals: 'test' import xml.etree.ElementTree as XML +import jenkins_jobs.modules.base - -def register(registry): - mod = Maven() - registry.registerModule(mod) - - -class Maven(object): +class Maven(jenkins_jobs.modules.base.Base): sequence = 0 def root_xml(self, data): diff --git a/jenkins_jobs/modules/properties.py b/jenkins_jobs/modules/properties.py new file mode 100644 index 000000000..f12e21d0f --- /dev/null +++ b/jenkins_jobs/modules/properties.py @@ -0,0 +1,117 @@ +# 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. + +# Jenkins Job module for job properties +# No additional YAML needed + +import xml.etree.ElementTree as XML +import jenkins_jobs.modules.base + +def github(parser, xml_parent, data): + github = XML.SubElement(xml_parent, + 'com.coravy.hudson.plugins.github.GithubProjectProperty') + github_url = XML.SubElement(github, 'projectUrl') + github_url.text = data['url'] + +def throttle(parser, xml_parent, data): + throttle = XML.SubElement(xml_parent, + 'hudson.plugins.throttleconcurrents.ThrottleJobProperty') + XML.SubElement(throttle, 'maxConcurrentPerNode').text = str( + data.get('max-per-node')) + XML.SubElement(throttle, 'maxConcurrentTotal').text = str( + data.get('max-total')) + # TODO: What's "categories"? + #XML.SubElement(throttle, 'categories') + if data.get('enabled', True): + XML.SubElement(throttle, 'throttleEnabled').text = 'true' + else: + XML.SubElement(throttle, 'throttleEnabled').text = 'false' + XML.SubElement(throttle, 'throttleOption').text = data.get('option') + XML.SubElement(throttle, 'configVersion').text = '1' + +def authenticated_build(parser, xml_parent, data): + # TODO: generalize this + if data: + security = XML.SubElement(xml_parent, + 'hudson.security.AuthorizationMatrixProperty') + XML.SubElement(security, 'permission').text = \ + '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): + 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): + sequence = 20 + + def gen_xml(self, parser, xml_parent, data): + properties = XML.SubElement(xml_parent, 'properties') + + for prop in data.get('properties', []): + self._dispatch('property', 'properties', + 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) + diff --git a/jenkins_jobs/modules/publishers.py b/jenkins_jobs/modules/publishers.py new file mode 100644 index 000000000..eaf8104cb --- /dev/null +++ b/jenkins_jobs/modules/publishers.py @@ -0,0 +1,290 @@ +# 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. + +# Jenkins Job module for coverage publishers +# No additional YAML needed + +import xml.etree.ElementTree as XML +import jenkins_jobs.modules.base + +def archive(parser, xml_parent, data): + archiver = XML.SubElement(xml_parent, 'hudson.tasks.ArtifactArchiver') + artifacts = XML.SubElement(archiver, 'artifacts') + artifacts.text = data['artifacts'] + if 'excludes' in data: + excludes = XML.SubElement(archiver, 'excludes') + excludes.text = data['excludes'] + latest = XML.SubElement(archiver, 'latestOnly') + latest_only = data.get('latest_only', False) + if latest_only: + latest.text = 'true' + else: + latest.text = 'false' + +def trigger_parameterized_builds(parser, xml_parent, data): + tbuilder = XML.SubElement(xml_parent, + 'hudson.plugins.parameterizedtrigger.BuildTrigger') + configs = XML.SubElement(tbuilder, 'configs') + for project_def in data: + tconfig = XML.SubElement(configs, + 'hudson.plugins.parameterizedtrigger.BuildTriggerConfig') + tconfigs = XML.SubElement(tconfig, 'configs') + if project_def.has_key('predefined_parameters'): + params = XML.SubElement(tconfigs, + 'hudson.plugins.parameterizedtrigger.PredefinedBuildParameters') + properties = XML.SubElement(params, 'properties') + properties.text = project_def['predefined_parameters'] + else: + tconfigs.set('class', 'java.util.Collections$EmptyList') + projects = XML.SubElement(tconfig, 'projects') + projects.text = project_def['project'] + condition = XML.SubElement(tconfig, 'condition') + condition.text = project_def.get('condition', 'ALWAYS') + trigger_with_no_params = XML.SubElement(tconfig, + 'triggerWithNoParameters') + trigger_with_no_params.text = 'false' + +def coverage(parser, xml_parent, data): + cobertura = XML.SubElement(xml_parent, + 'hudson.plugins.cobertura.CoberturaPublisher') + XML.SubElement(cobertura, 'coberturaReportFile').text = '**/coverage.xml' + XML.SubElement(cobertura, 'onlyStable').text = 'false' + healthy = XML.SubElement(cobertura, 'healthyTarget') + targets = XML.SubElement(healthy, 'targets', { + 'class':'enum-map', + 'enum-type':'hudson.plugins.cobertura.targets.CoverageMetric'}) + entry = XML.SubElement(targets, 'entry') + XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric' + ).text = 'CONDITIONAL' + XML.SubElement(entry, 'int').text = '70' + entry = XML.SubElement(targets, 'entry') + XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric' + ).text = 'LINE' + XML.SubElement(entry, 'int').text = '80' + entry = XML.SubElement(targets, 'entry') + XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric' + ).text = 'METHOD' + XML.SubElement(entry, 'int').text = '80' + unhealthy = XML.SubElement(cobertura, 'unhealthyTarget') + targets = XML.SubElement(unhealthy, 'targets', { + 'class':'enum-map', + 'enum-type':'hudson.plugins.cobertura.targets.CoverageMetric'}) + entry = XML.SubElement(targets, 'entry') + XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric' + ).text = 'CONDITIONAL' + XML.SubElement(entry, 'int').text = '0' + entry = XML.SubElement(targets, 'entry') + XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric' + ).text = 'LINE' + XML.SubElement(entry, 'int').text = '0' + entry = XML.SubElement(targets, 'entry') + XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric' + ).text = 'METHOD' + XML.SubElement(entry, 'int').text = '0' + failing = XML.SubElement(cobertura, 'failingTarget') + targets = XML.SubElement(failing, 'targets', { + 'class':'enum-map', + 'enum-type':'hudson.plugins.cobertura.targets.CoverageMetric'}) + entry = XML.SubElement(targets, 'entry') + XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric' + ).text = 'CONDITIONAL' + XML.SubElement(entry, 'int').text = '0' + entry = XML.SubElement(targets, 'entry') + XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric' + ).text = 'LINE' + XML.SubElement(entry, 'int').text = '0' + entry = XML.SubElement(targets, 'entry') + XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric' + ).text = 'METHOD' + XML.SubElement(entry, 'int').text = '0' + 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): + """ + Example XML: + <publishers> + <jenkins.plugins.publish__over__ftp.BapFtpPublisherPlugin> + <consolePrefix>FTP: </consolePrefix> + <delegate> + <publishers> + <jenkins.plugins.publish__over__ftp.BapFtpPublisher> + <configName>docs.openstack.org</configName> + <verbose>true</verbose> + <transfers> + <jenkins.plugins.publish__over__ftp.BapFtpTransfer> + <remoteDirectory></remoteDirectory> + <sourceFiles>openstack-identity-api/target/docbkx/webhelp/api/openstack-identity-service/2.0/**</sourceFiles> + <excludes>**/*.xml,**/null*</excludes> + <removePrefix>openstack-identity-api/target/docbkx/webhelp</removePrefix> + <remoteDirectorySDF>false</remoteDirectorySDF> + <flatten>false</flatten> + <cleanRemote>false</cleanRemote> + <asciiMode>false</asciiMode> + </jenkins.plugins.publish__over__ftp.BapFtpTransfer> + </transfers> + <useWorkspaceInPromotion>false</useWorkspaceInPromotion> + <usePromotionTimestamp>false</usePromotionTimestamp> + </jenkins.plugins.publish__over__ftp.BapFtpPublisher> + </publishers> + <continueOnError>false</continueOnError> + <failOnError>false</failOnError> + <alwaysPublishFromMaster>false</alwaysPublishFromMaster> + <hostConfigurationAccess class="jenkins.plugins.publish_over_ftp.BapFtpPublisherPlugin" reference="../.."/> + </delegate> + </jenkins.plugins.publish__over__ftp.BapFtpPublisherPlugin> + </publishers> + """ + outer_ftp = XML.SubElement(xml_parent, + 'jenkins.plugins.publish__over__ftp.BapFtpPublisherPlugin') + XML.SubElement(outer_ftp, 'consolePrefix').text = 'FTP: ' + delegate = XML.SubElement(outer_ftp, 'delegate') + publishers = XML.SubElement(delegate, 'publishers') + ftp = XML.SubElement(publishers, + 'jenkins.plugins.publish__over__ftp.BapFtpPublisher') + XML.SubElement(ftp, 'configName').text = data['site'] + XML.SubElement(ftp, 'verbose').text = 'true' + + transfers = XML.SubElement(ftp, 'transfers') + ftp_transfers = XML.SubElement(transfers, 'jenkins.plugins.publish__over__ftp.BapFtpTransfer') + XML.SubElement(ftp_transfers, 'remoteDirectory').text = data['target'] + XML.SubElement(ftp_transfers, 'sourceFiles').text = data['source'] + XML.SubElement(ftp_transfers, 'excludes').text = data['excludes'] + XML.SubElement(ftp_transfers, 'removePrefix').text = data['remove-prefix'] + XML.SubElement(ftp_transfers, 'remoteDirectorySDF').text = 'false' + XML.SubElement(ftp_transfers, 'flatten').text = 'false' + XML.SubElement(ftp_transfers, 'cleanRemote').text = 'false' + XML.SubElement(ftp_transfers, 'asciiMode').text = 'false' + + XML.SubElement(ftp, 'useWorkspaceInPromotion').text = 'false' + XML.SubElement(ftp, 'usePromotionTimestamp').text = 'false' + XML.SubElement(delegate, 'continueOnError').text = 'false' + XML.SubElement(delegate, 'failOnError').text = 'false' + XML.SubElement(delegate, 'alwaysPublishFromMaster').text = 'false' + XML.SubElement(delegate, 'hostConfigurationAccess', + {'class': 'jenkins.plugins.publish_over_ftp.BapFtpPublisherPlugin', + '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): + junitresult = XML.SubElement(xml_parent, + 'hudson.tasks.junit.JUnitResultArchiver') + XML.SubElement(junitresult, 'testResults').text = data['results'] + XML.SubElement(junitresult, 'keepLongStdio').text = "true" + XML.SubElement(junitresult, 'testDataPublishers') + + +def _pep8_add_entry(xml_parent, name): + entry = XML.SubElement(xml_parent, 'entry') + XML.SubElement(entry, 'string').text = name + tconfig = XML.SubElement(entry, 'hudson.plugins.violations.TypeConfig') + XML.SubElement(tconfig, 'type').text = name + XML.SubElement(tconfig, 'min').text = '10' + XML.SubElement(tconfig, 'max').text = '999' + XML.SubElement(tconfig, 'unstable').text = '999' + XML.SubElement(tconfig, 'usePattern').text = 'false' + XML.SubElement(tconfig, 'pattern') + +# Jenkins Job module for pep8 publishers +# No additional YAML needed + +def pep8(parser, xml_parent, data): + violations = XML.SubElement(xml_parent, + 'hudson.plugins.violations.ViolationsPublisher') + config = XML.SubElement(violations, 'config') + suppressions = XML.SubElement(config, 'suppressions', {'class':'tree-set'}) + XML.SubElement(suppressions, 'no-comparator') + configs = XML.SubElement(config, 'typeConfigs') + XML.SubElement(configs, 'no-comparator') + + _pep8_add_entry(configs, 'checkstyle') + _pep8_add_entry(configs, 'codenarc') + _pep8_add_entry(configs, 'cpd') + _pep8_add_entry(configs, 'cpplint') + _pep8_add_entry(configs, 'csslint') + _pep8_add_entry(configs, 'findbugs') + _pep8_add_entry(configs, 'fxcop') + _pep8_add_entry(configs, 'gendarme') + _pep8_add_entry(configs, 'jcreport') + _pep8_add_entry(configs, 'jslint') + + entry = XML.SubElement(configs, 'entry') + XML.SubElement(entry, 'string').text = 'pep8' + tconfig = XML.SubElement(entry, 'hudson.plugins.violations.TypeConfig') + XML.SubElement(tconfig, 'type').text = 'pep8' + XML.SubElement(tconfig, 'min').text = '0' + XML.SubElement(tconfig, 'max').text = '1' + XML.SubElement(tconfig, 'unstable').text = '1' + XML.SubElement(tconfig, 'usePattern').text = 'false' + XML.SubElement(tconfig, 'pattern').text = '**/pep8.txt' + + _pep8_add_entry(configs, 'pmd') + _pep8_add_entry(configs, 'pylint') + _pep8_add_entry(configs, 'simian') + _pep8_add_entry(configs, 'stylecop') + + XML.SubElement(config, 'limit').text = '100' + XML.SubElement(config, 'sourcePathPattern') + XML.SubElement(config, 'fauxProjectPath') + XML.SubElement(config, 'encoding').text = 'default' + +# Jenkins Job module for generic scp publishing +# To use you add the following into your YAML: +# publish: +# site: 'openstack-ci.openstack.org' +# source: 'doc/build/html/**/*' +# target_path: 'ci/zuul' +# keep_heirarchy: 'true' + +def scp(parser, xml_parent, data): + site = data['site'] + scp = XML.SubElement(xml_parent, + 'be.certipost.hudson.plugin.SCPRepositoryPublisher') + XML.SubElement(scp, 'siteName').text = site + entries = XML.SubElement(scp, 'entries') + entry = XML.SubElement(entries, 'be.certipost.hudson.plugin.Entry') + XML.SubElement(entry, 'filePath').text = data['target'] + XML.SubElement(entry, 'sourceFile').text = data['source'] + if data.get('keep-hierarchy', False): + XML.SubElement(entry, 'keepHierarchy').text = 'true' + else: + XML.SubElement(entry, 'keepHierarchy').text = 'false' + +class Publishers(jenkins_jobs.modules.base.Base): + sequence = 70 + + def gen_xml(self, parser, xml_parent, data): + publishers = XML.SubElement(xml_parent, 'publishers') + + for action in data.get('publishers', []): + self._dispatch('publisher', 'publishers', + parser, publishers, action) + + + diff --git a/jenkins_jobs/modules/scm.py b/jenkins_jobs/modules/scm.py new file mode 100644 index 000000000..470ce7de0 --- /dev/null +++ b/jenkins_jobs/modules/scm.py @@ -0,0 +1,72 @@ +# 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. + +# Jenkins Job module for scm +# To use add the folowing into your YAML: +# scm: +# scm: 'true' +# or +# scm: 'false' + +import xml.etree.ElementTree as XML +import jenkins_jobs.modules.base + +def git(self, xml_parent, data): + scm = XML.SubElement(xml_parent, + 'scm',{'class':'hudson.plugins.git.GitSCM'}) + XML.SubElement(scm, 'configVersion').text = '2' + user = XML.SubElement(scm, 'userRemoteConfigs') + huser = XML.SubElement(user, 'hudson.plugins.git.UserRemoteConfig') + XML.SubElement(huser, 'name').text = 'origin' + XML.SubElement(huser, 'refspec').text = \ + '+refs/heads/*:refs/remotes/origin/*' + XML.SubElement(huser, 'url').text = data['url'] + xml_branches = XML.SubElement(scm, 'branches') + branches = data.get('branches', ['**']) + for branch in branches: + bspec = XML.SubElement(xml_branches, 'hudson.plugins.git.BranchSpec') + XML.SubElement(bspec, 'name').text = branch + XML.SubElement(scm, 'disableSubmodules').text = 'false' + XML.SubElement(scm, 'recursiveSubmodules').text = 'false' + XML.SubElement(scm, 'doGenerateSubmoduleConfigurations').text = 'false' + XML.SubElement(scm, 'authorOrCommitter').text = 'false' + XML.SubElement(scm, 'clean').text = 'false' + XML.SubElement(scm, 'wipeOutWorkspace').text = 'true' + XML.SubElement(scm, 'pruneBranches').text = 'false' + XML.SubElement(scm, 'remotePoll').text = 'false' + XML.SubElement(scm, 'buildChooser', + {'class':'hudson.plugins.git.util.DefaultBuildChooser'}) + XML.SubElement(scm, 'gitTool').text = 'Default' + XML.SubElement(scm, 'submoduleCfg', {'class':'list'}) + XML.SubElement(scm, 'relativeTargetDir') + XML.SubElement(scm, 'reference') + XML.SubElement(scm, 'excludedRegions') + XML.SubElement(scm, 'excludedUsers') + XML.SubElement(scm, 'gitConfigName') + XML.SubElement(scm, 'gitConfigEmail') + XML.SubElement(scm, 'skipTag').text = 'false' + XML.SubElement(scm, 'scmName') + +class SCM(jenkins_jobs.modules.base.Base): + sequence = 30 + + def gen_xml(self, parser, xml_parent, data): + scms = data.get('scm', []) + if scms: + for scm in data.get('scm', []): + self._dispatch('scm', 'scm', + parser, xml_parent, scm) + else: + XML.SubElement(xml_parent, 'scm', {'class':'hudson.scm.NullSCM'}) + diff --git a/jenkins_jobs/modules/triggers.py b/jenkins_jobs/modules/triggers.py new file mode 100644 index 000000000..abaa2620a --- /dev/null +++ b/jenkins_jobs/modules/triggers.py @@ -0,0 +1,124 @@ +# 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. + +# Jenkins Job module for gerrit triggers +# To use add the following into your YAML: +# trigger: +# triggerOnPatchsetUploadedEvent: 'false' +# triggerOnChangeMergedEvent: 'false' +# triggerOnCommentAddedEvent: 'true' +# triggerOnRefUpdatedEvent: 'false' +# triggerApprovalCategory: 'APRV' +# triggerApprovalValue: 1 +# overrideVotes: 'true' +# gerritBuildSuccessfulVerifiedValue: 1 +# gerritBuildFailedVerifiedValue: -1 +# failureMessage: 'This change was unable to be automatically merged with the current state of the repository. Please rebase your change 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 jenkins_jobs.modules.base + +def gerrit(parser, xml_parent, data): + projects = data['projects'] + gtrig = XML.SubElement(xml_parent, + 'com.sonyericsson.hudson.plugins.gerrit.trigger.' + 'hudsontrigger.GerritTrigger') + XML.SubElement(gtrig, 'spec') + gprojects = XML.SubElement(gtrig, 'gerritProjects') + for project in projects: + gproj = XML.SubElement(gprojects, + 'com.sonyericsson.hudson.plugins.gerrit.' + 'trigger.hudsontrigger.data.GerritProject') + XML.SubElement(gproj, 'compareType').text = \ + project['projectCompareType'] + XML.SubElement(gproj, 'pattern').text = project['projectPattern'] + branches = XML.SubElement(gproj, 'branches') + gbranch = XML.SubElement(branches, 'com.sonyericsson.hudson.plugins.' + 'gerrit.trigger.hudsontrigger.data.Branch') + XML.SubElement(gbranch, 'compareType').text = \ + project['branchCompareType'] + XML.SubElement(gbranch, 'pattern').text = project['branchPattern'] + XML.SubElement(gtrig, 'silentMode').text = 'false' + XML.SubElement(gtrig, 'escapeQuotes').text = 'true' + XML.SubElement(gtrig, 'triggerOnPatchsetUploadedEvent').text = \ + data['triggerOnPatchsetUploadedEvent'] + XML.SubElement(gtrig, 'triggerOnChangeMergedEvent').text = \ + data['triggerOnChangeMergedEvent'] + XML.SubElement(gtrig, 'triggerOnCommentAddedEvent').text = \ + data['triggerOnCommentAddedEvent'] + XML.SubElement(gtrig, 'triggerOnRefUpdatedEvent').text = \ + data['triggerOnRefUpdatedEvent'] + if data.has_key('overrideVotes') and data['overrideVotes'] == 'true': + XML.SubElement(gtrig, 'gerritBuildSuccessfulVerifiedValue').text = \ + str(data['gerritBuildSuccessfulVerifiedValue']) + XML.SubElement(gtrig, 'gerritBuildFailedVerifiedValue').text = \ + str(data['gerritBuildFailedVerifiedValue']) + if data['triggerOnCommentAddedEvent'] == 'true': + XML.SubElement(gtrig, 'commentAddedTriggerApprovalCategory').text = \ + data['triggerApprovalCategory'] + XML.SubElement(gtrig, 'commentAddedTriggerApprovalValue').text = \ + str(data['triggerApprovalValue']) + XML.SubElement(gtrig, 'buildStartMessage') + XML.SubElement(gtrig, 'buildFailureMessage').text = data['failureMessage'] + XML.SubElement(gtrig, 'buildSuccessfulMessage') + XML.SubElement(gtrig, 'buildUnstableMessage') + 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): + scmtrig = XML.SubElement(xml_parent, 'hudson.triggers.SCMTrigger') + 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): + scmtrig = XML.SubElement(xml_parent, 'hudson.triggers.TimerTrigger') + XML.SubElement(scmtrig, 'spec').text = data + +class Triggers(jenkins_jobs.modules.base.Base): + sequence = 50 + + def gen_xml(self, parser, xml_parent, data): + triggers = data.get('triggers', []) + if not triggers: + return + + trig_e = XML.SubElement(xml_parent, 'triggers', {'class':'vector'}) + for trigger in triggers: + self._dispatch('trigger', 'triggers', + parser, trig_e, trigger) + diff --git a/jenkins_jobs/modules/wrappers.py b/jenkins_jobs/modules/wrappers.py new file mode 100644 index 000000000..e15513edd --- /dev/null +++ b/jenkins_jobs/modules/wrappers.py @@ -0,0 +1,51 @@ +# 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. + +# Jenkins Job module for wrappers + +import xml.etree.ElementTree as XML +import jenkins_jobs.modules.base + + +def timeout(parser, xml_parent, data): + twrapper = XML.SubElement(xml_parent, + 'hudson.plugins.build__timeout.BuildTimeoutWrapper') + tminutes = XML.SubElement(twrapper, 'timeoutMinutes') + tminutes.text = str(data['timeout']) + failbuild = XML.SubElement(twrapper, 'failBuild') + fail = data.get('fail', False) + if fail: + failbuild.text = 'true' + else: + failbuild.text = 'false' + +def timestamps(parser, xml_parent, data): + XML.SubElement(xml_parent, + 'hudson.plugins.timestamper.TimestamperBuildWrapper') + +def ansicolor(parser, xml_parent, data): + XML.SubElement(xml_parent, + 'hudson.plugins.ansicolor.AnsiColorBuildWrapper') + + +class Wrappers(jenkins_jobs.modules.base.Base): + sequence = 80 + + def gen_xml(self, parser, xml_parent, data): + wrappers = XML.SubElement(xml_parent, 'buildWrappers') + + for wrap in data.get('wrappers', []): + self._dispatch('wrapper', 'wrappers', + parser, wrappers, wrap) + diff --git a/jenkins_jobs/modules/zuul.py b/jenkins_jobs/modules/zuul.py new file mode 100644 index 000000000..338a50f07 --- /dev/null +++ b/jenkins_jobs/modules/zuul.py @@ -0,0 +1,85 @@ +# 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. + +# Jenkins Job module for Zuul + +import jenkins_jobs.modules.base + + +ZUUL_PARAMETERS = [ + {'string': + {'description': 'Zuul provided key to link builds with Gerrit events', + 'name': 'UUID'}}, + {'string': + {'description': 'Zuul provided project name', + 'name': 'GERRIT_PROJECT'}}, + {'string': + {'description': 'Zuul provided branch name', + 'name': 'GERRIT_BRANCH'}}, + {'string': + {'description': 'Zuul provided list of dependent changes to merge', + 'name': 'GERRIT_CHANGES'}}, + ] + +ZUUL_POST_PARAMETERS = [ + {'string': + {'description': 'Zuul provided key to link builds with Gerrit events', + 'name': 'UUID'}}, + {'string': + {'description': 'Zuul provided project name', + 'name': 'GERRIT_PROJECT'}}, + {'string': + {'description': 'Zuul provided ref name', + 'name': 'GERRIT_REFNAME'}}, + {'string': + {'description': 'Zuul provided old reference for ref-updated', + 'name': 'GERRIT_OLDREV'}}, + {'string': + {'description': 'Zuul provided new reference for ref-updated', + 'name': 'GERRIT_NEWREV'}}, + ] + +ZUUL_NOTIFICATIONS = [ + {'http': + {'url': 'http://127.0.0.1:8001/jenkins_endpoint'}} + ] + +class Zuul(jenkins_jobs.modules.base.Base): + sequence = 0 + + def handle_data(self, parser): + changed = False + jobs = (parser.data.get('job', {}).values() + + parser.data.get('job-template', {}).values()) + for job in jobs: + triggers = job.get('triggers') + if not triggers: + continue + + if ('zuul' not in job.get('triggers', []) and + 'zuul_post' not in job.get('triggers', [])): + continue + if 'parameters' not in job: + job['parameters'] = [] + if 'notifications' not in job: + job['notifications'] = [] + job['notifications'].extend(ZUUL_NOTIFICATIONS) + if 'zuul' in job.get('triggers', []): + job['parameters'].extend(ZUUL_PARAMETERS) + job['triggers'].remove('zuul') + if 'zuul_post' in job.get('triggers', []): + job['parameters'].extend(ZUUL_POST_PARAMETERS) + job['triggers'].remove('zuul_post') + changed = True + return changed diff --git a/modules/builders.py b/modules/builders.py deleted file mode 100644 index 61110df6d..000000000 --- a/modules/builders.py +++ /dev/null @@ -1,161 +0,0 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. -# -# 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. - -# Jenkins Job module for builders -# To use add the folowing into your YAML: -# builders: -# - 'gerrit_git_prep' -# - 'python26' - -import xml.etree.ElementTree as XML - - -def register(registry): - mod = Builders(registry) - registry.registerModule(mod) - - -class Builders(object): - sequence = 60 - - def __init__(self, registry): - self.registry = registry - for f in dir(self): - if not f.startswith('_builder_'): - continue - self.registry.registerHandler('builder', f[len('_builder_'):], - getattr(self, f)) - - def handle_data(self, data): - self.data = data - - def gen_xml(self, xml_parent, data): - for alias in ['prebuilders', 'builders', 'postbuilders']: - if alias in data: - builders = XML.SubElement(xml_parent, alias) - for builder in data[alias]: - if isinstance(builder, dict): - for key, value in builder.items(): - func = self.registry.getHandler('builder', key) - func(builders, value) - else: - func = self.registry.getHandler('builder', builder) - func(builders) - - def _add_script(self, xml_parent, script): - shell = XML.SubElement(xml_parent, 'hudson.tasks.Shell') - XML.SubElement(shell, 'command').text = script - - def _builder_coverage(self, xml_parent): - self._add_script(xml_parent, '/usr/local/jenkins/slave_scripts/run-cover.sh') - - def _builder_docs(self, xml_parent): - self._add_script(xml_parent, '/usr/local/jenkins/slave_scripts/run-docs.sh') - - def _builder_gerrit_git_prep(self, xml_parent): - self._add_script(xml_parent, '/usr/local/jenkins/slave_scripts/gerrit-git-prep.sh {site}'.format(site=self.data['main']['review_site'])) - - def _builder_maven_test(self, xml_parent): - self._add_script(xml_parent, 'mvn test') - - def _builder_maven_package(self, xml_parent): - self._add_script(xml_parent, 'mvn package') - - def _builder_gerrit_package(self, xml_parent): - self._add_script(xml_parent, - '/usr/local/jenkins/slave_scripts/package-gerrit.sh') - - def _builder_gerrit_preclean(self, xml_parent): - self._add_script(xml_parent, "#!/bin/bash -xe\n\ -rm -fr ~/.m2\n\ -rm -fr ~/.java\n\ -./tools/version.sh --release") - - def _builder_gerrit_postrun(self, xml_parent): - self._add_script(xml_parent, "./tools/version.sh --reset") - - def _builder_pep8(self, xml_parent): - self._add_script(xml_parent, 'set -o pipefail ; tox -v -epep8 | tee pep8.txt ; set +o pipefail') - - def _builder_pyflakes(self, xml_parent): - self._add_script(xml_parent, 'tox -v -epyflakes') - - def _builder_puppet_syntax(self, xml_parent): - self._add_script(xml_parent, """ -find . -iname *.pp | xargs puppet parser validate --modulepath=`pwd`/modules -for f in `find . -iname *.erb` ; do - erb -x -T '-' $f | ruby -c -done -""") - - def _builder_selenium(self, xml_parent): - self._add_script(xml_parent, '/usr/local/jenkins/slave_scripts/run-selenium.sh') - - def _builder_shell(self, xml_parent, data): - self._add_script(xml_parent, data) - - def _builder_trigger_builds(self, xml_parent, data): - tbuilder = XML.SubElement(xml_parent, 'hudson.plugins.parameterizedtrigger.TriggerBuilder') - configs = XML.SubElement(tbuilder, 'configs') - for project_def in data: - tconfig = XML.SubElement(configs, 'hudson.plugins.parameterizedtrigger.BlockableBuildTriggerConfig') - tconfigs = XML.SubElement(tconfig, 'configs') - if project_def.has_key('predefined_parameters'): - params = XML.SubElement(tconfigs, - 'hudson.plugins.parameterizedtrigger.PredefinedBuildParameters') - properties = XML.SubElement(params, 'properties') - properties.text = project_def['predefined_parameters'] - else: - tconfigs.set('class', 'java.util.Collections$EmptyList') - projects = XML.SubElement(tconfig, 'projects') - projects.text = project_def['project'] - condition = XML.SubElement(tconfig, 'condition') - condition.text = 'ALWAYS' - trigger_with_no_params = XML.SubElement(tconfig, 'triggerWithNoParameters') - trigger_with_no_params.text = 'false' - build_all_nodes_with_label = XML.SubElement(tconfig, 'buildAllNodesWithLabel') - build_all_nodes_with_label.text = 'false' - - def _builder_python26(self, xml_parent): - self._add_script(xml_parent, '/usr/local/jenkins/slave_scripts/run-tox.sh 26') - - def _builder_python27(self, xml_parent): - self._add_script(xml_parent, '/usr/local/jenkins/slave_scripts/run-tox.sh 27') - - def _builder_python26_essex(self, xml_parent): - self._add_script(xml_parent, '/usr/local/jenkins/slave_scripts/run-tox.sh 26-essex') - - def _builder_python27_essex(self, xml_parent): - self._add_script(xml_parent, '/usr/local/jenkins/slave_scripts/run-tox.sh 27-essex') - - def _builder_tarball(self, xml_parent): - self._add_script(xml_parent, - '/usr/local/jenkins/slave_scripts/create-tarball.sh %s' % self.data['main']['project']) - - def _builder_ppa(self, xml_parent): - self._add_script(xml_parent, 'rm -rf build dist.zip\n\ -mkdir build') - copy = XML.SubElement(xml_parent, 'hudson.plugins.copyartifact.CopyArtifact') - XML.SubElement(copy, 'projectName').text = '%s-tarball' % self.data['main']['project'] - XML.SubElement(copy, 'filter').text = 'dist/*.tar.gz' - XML.SubElement(copy, 'target').text = 'build' - selector = XML.SubElement(copy, 'selector', {'class':'hudson.plugins.copyartifact.StatusBuildSelector'}) - XML.SubElement(selector, 'parameterName').text = 'BUILD_SELECTOR' - self._add_script(xml_parent, '#!/bin/bash\n\ -\n\ -#export DO_UPLOAD="no"\n\ -export PROJECT="<%= project %>"\n\ -export GERRIT_REFNAME=$BRANCH\n\ -/usr/local/jenkins/slave_scripts/create-ppa-package.sh') diff --git a/modules/properties.py b/modules/properties.py deleted file mode 100644 index 964e17fbb..000000000 --- a/modules/properties.py +++ /dev/null @@ -1,90 +0,0 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. -# -# 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. - -# Jenkins Job module for job properties -# No additional YAML needed - -import xml.etree.ElementTree as XML - - -def register(registry): - mod = Properties() - registry.registerModule(mod) - - -class Properties(object): - sequence = 20 - - def handle_data(self, data): - self.data = data - - def gen_xml(self, xml_parent, data): - main = self.data['main'] - properties = XML.SubElement(xml_parent, 'properties') - if main.get('project'): - github = XML.SubElement(properties, 'com.coravy.hudson.plugins.github.GithubProjectProperty') - github_url = XML.SubElement(github, 'projectUrl') - github_url.text = "https://github.com/{org}/{project}".format( - org=main['github_org'], project=main['project']) - throttle = XML.SubElement(properties, 'hudson.plugins.throttleconcurrents.ThrottleJobProperty') - XML.SubElement(throttle, 'maxConcurrentPerNode').text = '0' - XML.SubElement(throttle, 'maxConcurrentTotal').text = '0' - #XML.SubElement(throttle, 'categories') - XML.SubElement(throttle, 'throttleEnabled').text = 'false' - XML.SubElement(throttle, 'throttleOption').text = 'project' - XML.SubElement(throttle, 'configVersion').text = '1' - if main.has_key('authenticatedBuild') and main['authenticatedBuild'] == 'true': - security = XML.SubElement(properties, 'hudson.security.AuthorizationMatrixProperty') - XML.SubElement(security, 'permission').text = 'hudson.model.Item.Build:authenticated' - self.do_parameters(properties) - self.do_notifications(properties) - - parameter_types = { - 'string': 'hudson.model.StringParameterDefinition', - 'bool': 'hudson.model.BooleanParameterDefinition', - 'file': 'hudson.model.FileParameterDefinition', - 'text': 'hudson.model.TextParameterDefinition', - 'label': 'org.jvnet.jenkins.plugins.nodelabelparameter.LabelParameterDefinition', - # Others require more work - } - - def do_parameters(self, xml_parent): - params = self.data.get('parameters', None) - if not params: - return - pdefp = XML.SubElement(xml_parent, 'hudson.model.ParametersDefinitionProperty') - pdefs = XML.SubElement(pdefp, 'parameterDefinitions') - for param in params: - ptype = self.parameter_types.get(param['type']) - pdef = XML.SubElement(pdefs, ptype) - XML.SubElement(pdef, 'name').text = param['name'] - XML.SubElement(pdef, 'description').text = param['description'] - if param['type'] != 'file': - default = param.get('default', None) - if default: - XML.SubElement(pdef, 'defaultValue').text = default - else: - XML.SubElement(pdef, 'defaultValue') - - def do_notifications(self, xml_parent): - endpoints = self.data.get('notification_endpoints', None) - if not endpoints: - return - notify_element = XML.SubElement(xml_parent, 'com.tikal.hudson.plugins.notification.HudsonNotificationProperty') - endpoints_element = XML.SubElement(notify_element, 'endpoints') - for ep in endpoints: - endpoint_element = XML.SubElement(endpoints_element, 'com.tikal.hudson.plugins.notification.Endpoint') - XML.SubElement(endpoint_element, 'protocol').text = ep['protocol'] - XML.SubElement(endpoint_element, 'url').text = ep['URL'] diff --git a/modules/publishers.py b/modules/publishers.py deleted file mode 100644 index a2022d75b..000000000 --- a/modules/publishers.py +++ /dev/null @@ -1,329 +0,0 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. -# -# 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. - -# Jenkins Job module for coverage publishers -# No additional YAML needed - -import xml.etree.ElementTree as XML - - -def register(registry): - mod = Publishers(registry) - registry.registerModule(mod) - - -class Publishers(object): - sequence = 70 - - def __init__(self, registry): - self.registry = registry - for f in dir(self): - if not f.startswith('_publisher_'): - continue - self.registry.registerHandler('publisher', f[len('_publisher_'):], - getattr(self, f)) - - def handle_data(self, data): - self.data = data - - def gen_xml(self, xml_parent, data): - publishers = XML.SubElement(xml_parent, 'publishers') - actions = self.data.get('post_build_actions', []) - for action in actions: - if isinstance(action, dict): - for key, value in action.items(): - func = self.registry.getHandler('publisher', key) - func(publishers, value) - else: - func = self.registry.getHandler('publisher', action) - func(publishers) - - def _publisher_archive(self, xml_parent, data): - archiver = XML.SubElement(xml_parent, 'hudson.tasks.ArtifactArchiver') - artifacts = XML.SubElement(archiver, 'artifacts') - artifacts.text = data['artifacts'] - if 'excludes' in data: - excludes = XML.SubElement(archiver, 'excludes') - excludes.text = data['excludes'] - latest = XML.SubElement(archiver, 'latestOnly') - latest_only = data.get('latest_only', False) - if latest_only: - latest.text = 'true' - else: - latest.text = 'false' - - def _publisher_trigger_parameterized_builds(self, xml_parent, data): - tbuilder = XML.SubElement(xml_parent, 'hudson.plugins.parameterizedtrigger.BuildTrigger') - configs = XML.SubElement(tbuilder, 'configs') - for project_def in data: - tconfig = XML.SubElement(configs, 'hudson.plugins.parameterizedtrigger.BuildTriggerConfig') - tconfigs = XML.SubElement(tconfig, 'configs') - if project_def.has_key('predefined_parameters'): - params = XML.SubElement(tconfigs, - 'hudson.plugins.parameterizedtrigger.PredefinedBuildParameters') - properties = XML.SubElement(params, 'properties') - properties.text = project_def['predefined_parameters'] - else: - tconfigs.set('class', 'java.util.Collections$EmptyList') - projects = XML.SubElement(tconfig, 'projects') - projects.text = project_def['project'] - condition = XML.SubElement(tconfig, 'condition') - condition.text = project_def.get('condition', 'ALWAYS') - trigger_with_no_params = XML.SubElement(tconfig, 'triggerWithNoParameters') - trigger_with_no_params.text = 'false' - - def _publisher_coverage(self, xml_parent): - cobertura = XML.SubElement(xml_parent, 'hudson.plugins.cobertura.CoberturaPublisher') - XML.SubElement(cobertura, 'coberturaReportFile').text = '**/coverage.xml' - XML.SubElement(cobertura, 'onlyStable').text = 'false' - healthy = XML.SubElement(cobertura, 'healthyTarget') - targets = XML.SubElement(healthy, 'targets', {'class':'enum-map','enum-type':'hudson.plugins.cobertura.targets.CoverageMetric'}) - entry = XML.SubElement(targets, 'entry') - XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric').text = 'CONDITIONAL' - XML.SubElement(entry, 'int').text = '70' - entry = XML.SubElement(targets, 'entry') - XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric').text = 'LINE' - XML.SubElement(entry, 'int').text = '80' - entry = XML.SubElement(targets, 'entry') - XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric').text = 'METHOD' - XML.SubElement(entry, 'int').text = '80' - unhealthy = XML.SubElement(cobertura, 'unhealthyTarget') - targets = XML.SubElement(unhealthy, 'targets', {'class':'enum-map','enum-type':'hudson.plugins.cobertura.targets.CoverageMetric'}) - entry = XML.SubElement(targets, 'entry') - XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric').text = 'CONDITIONAL' - XML.SubElement(entry, 'int').text = '0' - entry = XML.SubElement(targets, 'entry') - XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric').text = 'LINE' - XML.SubElement(entry, 'int').text = '0' - entry = XML.SubElement(targets, 'entry') - XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric').text = 'METHOD' - XML.SubElement(entry, 'int').text = '0' - failing = XML.SubElement(cobertura, 'failingTarget') - targets = XML.SubElement(failing, 'targets', {'class':'enum-map','enum-type':'hudson.plugins.cobertura.targets.CoverageMetric'}) - entry = XML.SubElement(targets, 'entry') - XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric').text = 'CONDITIONAL' - XML.SubElement(entry, 'int').text = '0' - entry = XML.SubElement(targets, 'entry') - XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric').text = 'LINE' - XML.SubElement(entry, 'int').text = '0' - entry = XML.SubElement(targets, 'entry') - XML.SubElement(entry, 'hudson.plugins.cobertura.targets.CoverageMetric').text = 'METHOD' - XML.SubElement(entry, 'int').text = '0' - 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 _publisher_ftp(self, xml_parent, data): - """ - Example XML: - <publishers> - <jenkins.plugins.publish__over__ftp.BapFtpPublisherPlugin> - <consolePrefix>FTP: </consolePrefix> - <delegate> - <publishers> - <jenkins.plugins.publish__over__ftp.BapFtpPublisher> - <configName>docs.openstack.org</configName> - <verbose>true</verbose> - <transfers> - <jenkins.plugins.publish__over__ftp.BapFtpTransfer> - <remoteDirectory></remoteDirectory> - <sourceFiles>openstack-identity-api/target/docbkx/webhelp/api/openstack-identity-service/2.0/**</sourceFiles> - <excludes>**/*.xml,**/null*</excludes> - <removePrefix>openstack-identity-api/target/docbkx/webhelp</removePrefix> - <remoteDirectorySDF>false</remoteDirectorySDF> - <flatten>false</flatten> - <cleanRemote>false</cleanRemote> - <asciiMode>false</asciiMode> - </jenkins.plugins.publish__over__ftp.BapFtpTransfer> - </transfers> - <useWorkspaceInPromotion>false</useWorkspaceInPromotion> - <usePromotionTimestamp>false</usePromotionTimestamp> - </jenkins.plugins.publish__over__ftp.BapFtpPublisher> - </publishers> - <continueOnError>false</continueOnError> - <failOnError>false</failOnError> - <alwaysPublishFromMaster>false</alwaysPublishFromMaster> - <hostConfigurationAccess class="jenkins.plugins.publish_over_ftp.BapFtpPublisherPlugin" reference="../.."/> - </delegate> - </jenkins.plugins.publish__over__ftp.BapFtpPublisherPlugin> - </publishers> - """ - outer_ftp = XML.SubElement(xml_parent, - 'jenkins.plugins.publish__over__ftp.BapFtpPublisherPlugin') - XML.SubElement(outer_ftp, 'consolePrefix').text = 'FTP: ' - delegate = XML.SubElement(outer_ftp, 'delegate') - publishers = XML.SubElement(delegate, 'publishers') - ftp = XML.SubElement(publishers, 'jenkins.plugins.publish__over__ftp.BapFtpPublisher') - XML.SubElement(ftp, 'configName').text = data['site'] - XML.SubElement(ftp, 'verbose').text = 'true' - - transfers = XML.SubElement(ftp, 'transfers') - ftp_transfers = XML.SubElement(transfers, 'jenkins.plugins.publish__over__ftp.BapFtpTransfer') - XML.SubElement(ftp_transfers, 'remoteDirectory').text = data['remote_dir'] - XML.SubElement(ftp_transfers, 'sourceFiles').text = data['source_files'] - XML.SubElement(ftp_transfers, 'excludes').text = data['excludes'] - XML.SubElement(ftp_transfers, 'removePrefix').text = data['remove_prefix'] - XML.SubElement(ftp_transfers, 'remoteDirectorySDF').text = 'false' - XML.SubElement(ftp_transfers, 'flatten').text = 'false' - XML.SubElement(ftp_transfers, 'cleanRemote').text = 'false' - XML.SubElement(ftp_transfers, 'asciiMode').text = 'false' - - XML.SubElement(ftp, 'useWorkspaceInPromotion').text = 'false' - XML.SubElement(ftp, 'usePromotionTimestamp').text = 'false' - XML.SubElement(delegate, 'continueOnError').text = 'false' - XML.SubElement(delegate, 'failOnError').text = 'false' - XML.SubElement(delegate, 'alwaysPublishFromMaster').text = 'false' - XML.SubElement(delegate, 'hostConfigurationAccess', - {'class': 'jenkins.plugins.publish_over_ftp.BapFtpPublisherPlugin', - 'reference': '../..'}) - - # Jenkins Job module for coverage publishers - # To use you add the following into your YAML: - # publisher: - # results: 'nosetests.xml' - - def _publisher_junit(self, xml_parent, data): - junitresult = XML.SubElement(xml_parent, - 'hudson.tasks.junit.JUnitResultArchiver') - XML.SubElement(junitresult, 'testResults').text = data['results'] - XML.SubElement(junitresult, 'keepLongStdio').text = "true" - XML.SubElement(junitresult, 'testDataPublishers') - - # Jenkins Job module for pep8 publishers - # No additional YAML needed - - def _pep8_add_entry(self, xml_parent, name): - entry = XML.SubElement(xml_parent, 'entry') - XML.SubElement(entry, 'string').text = name - tconfig = XML.SubElement(entry, 'hudson.plugins.violations.TypeConfig') - XML.SubElement(tconfig, 'type').text = name - XML.SubElement(tconfig, 'min').text = '10' - XML.SubElement(tconfig, 'max').text = '999' - XML.SubElement(tconfig, 'unstable').text = '999' - XML.SubElement(tconfig, 'usePattern').text = 'false' - XML.SubElement(tconfig, 'pattern') - - def _publisher_pep8(self, xml_parent): - violations = XML.SubElement(xml_parent, 'hudson.plugins.violations.ViolationsPublisher') - config = XML.SubElement(violations, 'config') - suppressions = XML.SubElement(config, 'suppressions', {'class':'tree-set'}) - XML.SubElement(suppressions, 'no-comparator') - configs = XML.SubElement(config, 'typeConfigs') - XML.SubElement(configs, 'no-comparator') - - self._pep8_add_entry(configs, 'checkstyle') - self._pep8_add_entry(configs, 'codenarc') - self._pep8_add_entry(configs, 'cpd') - self._pep8_add_entry(configs, 'cpplint') - self._pep8_add_entry(configs, 'csslint') - self._pep8_add_entry(configs, 'findbugs') - self._pep8_add_entry(configs, 'fxcop') - self._pep8_add_entry(configs, 'gendarme') - self._pep8_add_entry(configs, 'jcreport') - self._pep8_add_entry(configs, 'jslint') - - entry = XML.SubElement(configs, 'entry') - XML.SubElement(entry, 'string').text = 'pep8' - tconfig = XML.SubElement(entry, 'hudson.plugins.violations.TypeConfig') - XML.SubElement(tconfig, 'type').text = 'pep8' - XML.SubElement(tconfig, 'min').text = '0' - XML.SubElement(tconfig, 'max').text = '1' - XML.SubElement(tconfig, 'unstable').text = '1' - XML.SubElement(tconfig, 'usePattern').text = 'false' - XML.SubElement(tconfig, 'pattern').text = '**/pep8.txt' - - self._pep8_add_entry(configs, 'pmd') - self._pep8_add_entry(configs, 'pylint') - self._pep8_add_entry(configs, 'simian') - self._pep8_add_entry(configs, 'stylecop') - - XML.SubElement(config, 'limit').text = '100' - XML.SubElement(config, 'sourcePathPattern') - XML.SubElement(config, 'fauxProjectPath') - XML.SubElement(config, 'encoding').text = 'default' - - # Jenkins Job module for PPA publishers - # No additional YAML needed - - def _publisher_ppa(self, xml_parent): - archiver = XML.SubElement(xml_parent, 'hudson.tasks.ArtifactArchiver') - XML.SubElement(archiver, 'artifacts').text = 'build/*.dsc,build/*.tar.gz,build/*.changes' - XML.SubElement(archiver, 'latestOnly').text = 'false' - - # Jenkins Job module for tarball publishers - # To use you add the following into your YAML: - # publish: - # site: 'glance.openstack.org' - # dir: 'glance' - - def _publisher_tarball(self, xml_parent, data): - site = data['site'] - archiver = XML.SubElement(xml_parent, 'hudson.tasks.ArtifactArchiver') - XML.SubElement(archiver, 'artifacts').text = 'dist/*.tar.gz' - XML.SubElement(archiver, 'latestOnly').text = 'false' - scp = XML.SubElement(xml_parent, 'be.certipost.hudson.plugin.SCPRepositoryPublisher') - XML.SubElement(scp, 'siteName').text = site - entries = XML.SubElement(scp, 'entries') - entry = XML.SubElement(entries, 'be.certipost.hudson.plugin.Entry') - XML.SubElement(entry, 'filePath').text = 'tarballs/{proj}/'.format(proj=data['project']) - XML.SubElement(entry, 'sourceFile').text = 'dist/*.tar.gz' - XML.SubElement(entry, 'keepHierarchy').text = 'false' - - # Jenkins Job module for war publishers - # To use you add the following into your YAML: - # publish: - # site: 'nova.openstack.org' - # warfile: 'gerrit-war/target/gerrit*.war' - # target_path: 'tarballs/ci/' - - def _publisher_war(self, xml_parent, data): - site = data['site'] - archiver = XML.SubElement(xml_parent, 'hudson.tasks.ArtifactArchiver') - XML.SubElement(archiver, 'artifacts').text = data['warfile'] - XML.SubElement(archiver, 'latestOnly').text = 'false' - scp = XML.SubElement(xml_parent, 'be.certipost.hudson.plugin.SCPRepositoryPublisher') - XML.SubElement(scp, 'siteName').text = site - entries = XML.SubElement(scp, 'entries') - entry = XML.SubElement(entries, 'be.certipost.hudson.plugin.Entry') - XML.SubElement(entry, 'filePath').text = data['target_path'] - XML.SubElement(entry, 'sourceFile').text = data['warfile'] - XML.SubElement(entry, 'keepHierarchy').text = 'false' - - # Jenkins Job module for generic scp publishing - # To use you add the following into your YAML: - # publish: - # site: 'openstack-ci.openstack.org' - # source: 'doc/build/html/**/*' - # target_path: 'ci/zuul' - # keep_heirarchy: 'true' - - def _publisher_scp(self, xml_parent, data): - site = data['site'] - scp = XML.SubElement(xml_parent, 'be.certipost.hudson.plugin.SCPRepositoryPublisher') - XML.SubElement(scp, 'siteName').text = site - entries = XML.SubElement(scp, 'entries') - entry = XML.SubElement(entries, 'be.certipost.hudson.plugin.Entry') - XML.SubElement(entry, 'filePath').text = data['target_path'] - XML.SubElement(entry, 'sourceFile').text = data['source'] - XML.SubElement(entry, 'keepHierarchy').text = data['keep_heirarchy'] diff --git a/modules/scm.py b/modules/scm.py deleted file mode 100644 index 1b8ffbabc..000000000 --- a/modules/scm.py +++ /dev/null @@ -1,74 +0,0 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. -# -# 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. - -# Jenkins Job module for scm -# To use add the folowing into your YAML: -# scm: -# scm: 'true' -# or -# scm: 'false' - -import xml.etree.ElementTree as XML - - -def register(registry): - mod = SCM() - registry.registerModule(mod) - - -class SCM(object): - sequence = 30 - - def handle_data(self, data): - self.data = data - - def gen_xml(self, xml_parent, data): - main = self.data['main'] - scm_enabled = self.data['scm']['scm'] - if scm_enabled == 'true': - scm = XML.SubElement(xml_parent, 'scm', {'class':'hudson.plugins.git.GitSCM'}) - XML.SubElement(scm, 'configVersion').text = '2' - user = XML.SubElement(scm, 'userRemoteConfigs') - huser = XML.SubElement(user, 'hudson.plugins.git.UserRemoteConfig') - XML.SubElement(huser, 'name').text = 'origin' - XML.SubElement(huser, 'refspec').text = '+refs/heads/*:refs/remotes/origin/*' - XML.SubElement(huser, 'url').text = 'git://github.com/{org}/{project}.git'.format(org=main['github_org'], project=main['project']) - xml_branches = XML.SubElement(scm, 'branches') - branches = self.data['scm'].get('branches', ['**']) - for branch in branches: - bspec = XML.SubElement(xml_branches, 'hudson.plugins.git.BranchSpec') - XML.SubElement(bspec, 'name').text = branch - XML.SubElement(scm, 'disableSubmodules').text = 'false' - XML.SubElement(scm, 'recursiveSubmodules').text = 'false' - XML.SubElement(scm, 'doGenerateSubmoduleConfigurations').text = 'false' - XML.SubElement(scm, 'authorOrCommitter').text = 'false' - XML.SubElement(scm, 'clean').text = 'false' - XML.SubElement(scm, 'wipeOutWorkspace').text = 'true' - XML.SubElement(scm, 'pruneBranches').text = 'false' - XML.SubElement(scm, 'remotePoll').text = 'false' - XML.SubElement(scm, 'buildChooser', {'class':'hudson.plugins.git.util.DefaultBuildChooser'}) - XML.SubElement(scm, 'gitTool').text = 'Default' - XML.SubElement(scm, 'submoduleCfg', {'class':'list'}) - XML.SubElement(scm, 'relativeTargetDir') - XML.SubElement(scm, 'reference') - XML.SubElement(scm, 'excludedRegions') - XML.SubElement(scm, 'excludedUsers') - XML.SubElement(scm, 'gitConfigName') - XML.SubElement(scm, 'gitConfigEmail') - XML.SubElement(scm, 'skipTag').text = 'false' - XML.SubElement(scm, 'scmName') - else: - XML.SubElement(xml_parent, 'scm', {'class':'hudson.scm.NullSCM'}) - diff --git a/modules/triggers.py b/modules/triggers.py deleted file mode 100644 index 0e77dbc08..000000000 --- a/modules/triggers.py +++ /dev/null @@ -1,129 +0,0 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. -# -# 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. - -# Jenkins Job module for gerrit triggers -# To use add the following into your YAML: -# trigger: -# triggerOnPatchsetUploadedEvent: 'false' -# triggerOnChangeMergedEvent: 'false' -# triggerOnCommentAddedEvent: 'true' -# triggerOnRefUpdatedEvent: 'false' -# triggerApprovalCategory: 'APRV' -# triggerApprovalValue: 1 -# overrideVotes: 'true' -# gerritBuildSuccessfulVerifiedValue: 1 -# gerritBuildFailedVerifiedValue: -1 -# failureMessage: 'This change was unable to be automatically merged with the current state of the repository. Please rebase your change 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 - - -def register(registry): - mod = Triggers(registry) - registry.registerModule(mod) - - -class Triggers(object): - sequence = 50 - - def __init__(self, registry): - self.registry = registry - for f in dir(self): - if not f.startswith('_trigger_'): - continue - self.registry.registerHandler('trigger', f[len('_trigger_'):], - getattr(self, f)) - - def handle_data(self, data): - self.data = data - - def gen_xml(self, xml_parent, data): - actions = self.data.get('triggers', []) - if not actions: - return - triggers = XML.SubElement(xml_parent, 'triggers', {'class':'vector'}) - for action in actions: - if isinstance(action, dict): - for key, value in action.items(): - func = self.registry.getHandler('trigger', key) - func(triggers, value) - else: - func = self.registry.getHandler('trigger', action) - func(triggers) - - def _trigger_gerrit(self, xml_parent, data): - projects = data['projects'] - gtrig = XML.SubElement(xml_parent, 'com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.GerritTrigger') - XML.SubElement(gtrig, 'spec') - gprojects = XML.SubElement(gtrig, 'gerritProjects') - for project in projects: - gproj = XML.SubElement(gprojects, 'com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.GerritProject') - XML.SubElement(gproj, 'compareType').text = project['projectCompareType'] - XML.SubElement(gproj, 'pattern').text = project['projectPattern'] - branches = XML.SubElement(gproj, 'branches') - gbranch = XML.SubElement(branches, 'com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.Branch') - XML.SubElement(gbranch, 'compareType').text = project['branchCompareType'] - XML.SubElement(gbranch, 'pattern').text = project['branchPattern'] - XML.SubElement(gtrig, 'silentMode').text = 'false' - XML.SubElement(gtrig, 'escapeQuotes').text = 'true' - XML.SubElement(gtrig, 'triggerOnPatchsetUploadedEvent').text = data['triggerOnPatchsetUploadedEvent'] - XML.SubElement(gtrig, 'triggerOnChangeMergedEvent').text = data['triggerOnChangeMergedEvent'] - XML.SubElement(gtrig, 'triggerOnCommentAddedEvent').text = data['triggerOnCommentAddedEvent'] - XML.SubElement(gtrig, 'triggerOnRefUpdatedEvent').text = data['triggerOnRefUpdatedEvent'] - if data.has_key('overrideVotes') and data['overrideVotes'] == 'true': - XML.SubElement(gtrig, 'gerritBuildSuccessfulVerifiedValue').text = str(data['gerritBuildSuccessfulVerifiedValue']) - XML.SubElement(gtrig, 'gerritBuildFailedVerifiedValue').text = str(data['gerritBuildFailedVerifiedValue']) - if data['triggerOnCommentAddedEvent'] == 'true': - XML.SubElement(gtrig, 'commentAddedTriggerApprovalCategory').text = data['triggerApprovalCategory'] - XML.SubElement(gtrig, 'commentAddedTriggerApprovalValue').text = str(data['triggerApprovalValue']) - XML.SubElement(gtrig, 'buildStartMessage') - XML.SubElement(gtrig, 'buildFailureMessage').text = data['failureMessage'] - XML.SubElement(gtrig, 'buildSuccessfulMessage') - XML.SubElement(gtrig, 'buildUnstableMessage') - 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 _trigger_pollscm(self, xml_parent, data): - scmtrig = XML.SubElement(xml_parent, 'hudson.triggers.SCMTrigger') - 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 _trigger_timed(self, xml_parent, data): - scmtrig = XML.SubElement(xml_parent, 'hudson.triggers.TimerTrigger') - XML.SubElement(scmtrig, 'spec').text = data diff --git a/modules/wrappers.py b/modules/wrappers.py deleted file mode 100644 index bab009107..000000000 --- a/modules/wrappers.py +++ /dev/null @@ -1,53 +0,0 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. -# -# 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. - -# Jenkins Job module for wrappers - -import xml.etree.ElementTree as XML - -def register(registry): - mod = Wrappers() - registry.registerModule(mod) - - -class Wrappers(object): - sequence = 80 - - def gen_xml(self, xml_parent, data): - wrappers = XML.SubElement(xml_parent, 'buildWrappers') - - if 'timeout' in data['main']: - self._timeout(wrappers, data) - if 'ansicolor' in data['main']: - self._ansicolor(wrappers, data) - if 'timestamps' in data['main']: - self._timestamps(wrappers, data) - - def _timeout(self, xml_parent, data): - twrapper = XML.SubElement(xml_parent, 'hudson.plugins.build__timeout.BuildTimeoutWrapper') - tminutes = XML.SubElement(twrapper, 'timeoutMinutes') - tminutes.text = str(data['main']['timeout']) - failbuild = XML.SubElement(twrapper, 'failBuild') - fail = data['main'].get('timeout_fail', False) - if fail: - failbuild.text = 'true' - else: - failbuild.text = 'false' - - def _timestamps(self, xml_parent, data): - XML.SubElement(xml_parent, 'hudson.plugins.timestamper.TimestamperBuildWrapper') - - def _ansicolor(self, xml_parent, data): - XML.SubElement(xml_parent, 'hudson.plugins.ansicolor.AnsiColorBuildWrapper') diff --git a/modules/zuul.py b/modules/zuul.py deleted file mode 100644 index 54b59c373..000000000 --- a/modules/zuul.py +++ /dev/null @@ -1,79 +0,0 @@ -#! /usr/bin/env python -# Copyright (C) 2012 OpenStack, LLC. -# -# 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. - -# Jenkins Job module for Zuul - -ZUUL_PARAMETERS = [ - {'description': 'Zuul provided key to link builds with Gerrit events', - 'name': 'UUID', - 'type': 'string'}, - {'description': 'Zuul provided project name', - 'name': 'GERRIT_PROJECT', - 'type': 'string'}, - {'description': 'Zuul provided branch name', - 'name': 'GERRIT_BRANCH', - 'type': 'string'}, - {'description': 'Zuul provided list of dependent changes to merge', - 'name': 'GERRIT_CHANGES', - 'type': 'string'} - ] - -ZUUL_POST_PARAMETERS = [ - {'description': 'Zuul provided key to link builds with Gerrit events', - 'name': 'UUID', - 'type': 'string'}, - {'description': 'Zuul provided project name', - 'name': 'GERRIT_PROJECT', - 'type': 'string'}, - {'description': 'Zuul provided ref name', - 'name': 'GERRIT_REFNAME', - 'type': 'string'}, - {'description': 'Zuul provided old reference for ref-updated', - 'name': 'GERRIT_OLDREV', - 'type': 'string'}, - {'description': 'Zuul provided new reference for ref-updated', - 'name': 'GERRIT_NEWREV', - 'type': 'string'} - ] - -ZUUL_NOTIFICATIONS = [ - {'URL': 'http://127.0.0.1:8001/jenkins_endpoint', - 'protocol': 'HTTP'} - ] - - -def register(registry): - mod = Zuul() - registry.registerModule(mod) - - -class Zuul(object): - sequence = 0 - - def handle_data(self, data): - if ('zuul' not in data.get('triggers', []) and - 'zuul_post' not in data.get('triggers', [])): - return - if 'parameters' not in data: - data['parameters'] = [] - if 'notification_endpoints' not in data: - data['notification_endpoints'] = [] - data['notification_endpoints'].extend(ZUUL_NOTIFICATIONS) - if 'zuul' in data.get('triggers', []): - data['parameters'].extend(ZUUL_PARAMETERS) - data['triggers'].remove('zuul') - if 'zuul_post' in data.get('triggers', []): - data['parameters'].extend(ZUUL_POST_PARAMETERS) - data['triggers'].remove('zuul_post') diff --git a/projects/openstack/zuul.yml b/projects/openstack/zuul.yml index f7fc79f1d..2e04748bc 100644 --- a/projects/openstack/zuul.yml +++ b/projects/openstack/zuul.yml @@ -1,71 +1,62 @@ -project: - template: 'python_jobs' +#project: +# template: 'python_jobs' +# +#values: +# name: 'zuul' +# disabled: 'false' +# github_org: 'openstack-ci' +# review_site: 'review.openstack.org' +# node: 'precise' +# +#--- -values: - name: 'zuul' - disabled: 'false' - github_org: 'openstack-ci' - review_site: 'review.openstack.org' - node: 'precise' +- job: + name: gate-zuul-pyflakes + project-type: freestyle + concurrent: true + timeout: 20 + timeout_fail: true ---- -# pyflakes-gate -main: - name: 'gate-zuul-pyflakes' - review_site: 'review.openstack.org' - github_org: 'openstack-ci' - project: 'zuul' - concurrent: 'true' - timeout: 20 - timeout_fail: true + triggers: + - zuul -triggers: - - zuul + builders: + - gerrit_git_prep + - pyflakes -builders: - - gerrit_git_prep - - pyflakes + assignednode: + node: 'precise' -scm: - scm: 'false' +- job: + name: zuul-docs + project-type: freestyle + #review_site: 'review.openstack.org' + #github_org: 'openstack-ci' + #project: 'zuul' + #authenticatedBuild: 'false' + concurrent: true + timeout: 20 + timeout_fail: true -assignednode: - node: 'precise' + triggers: + - zuul_post ---- -# zuul-docs -main: - name: 'zuul-docs' - review_site: 'review.openstack.org' - github_org: 'openstack-ci' - project: 'zuul' - authenticatedBuild: 'false' - concurrent: 'true' - timeout: 20 - timeout_fail: true + logrotate: + daysToKeep: 28 + numToKeep: -1 + artifactDaysToKeep: -1 + artifactNumToKeep: -1 -triggers: - - zuul_post + builders: + - gerrit_git_prep + - docs -logrotate: - daysToKeep: 28 - numToKeep: -1 - artifactDaysToKeep: -1 - artifactNumToKeep: -1 + post_build_actions: + - scp: + site: '173.203.107.207' + source: 'doc/build/html/**/*' + target_path: 'ci/zuul' + keep_heirarchy: 'true' -builders: - - gerrit_git_prep - - docs - -post_build_actions: - - scp: - site: '173.203.107.207' - source: 'doc/build/html/**/*' - target_path: 'ci/zuul' - keep_heirarchy: 'true' - -scm: - scm: 'false' - -assignednode: - node: 'precise' + assignednode: + node: 'precise' diff --git a/setup.py b/setup.py new file mode 100644 index 000000000..94876b7c3 --- /dev/null +++ b/setup.py @@ -0,0 +1,90 @@ +# 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. + +from setuptools import find_packages +from setuptools import setup + +setup(name='jenkins_job_builder', + version='0.1', + description="Manage Jenkins jobs with YAML", + license='Apache License (2.0)', + author='Hewlett-Packard Development Company, L.P.', + author_email='openstack@lists.launchpad.net', + scripts=['jenkins-jobs'], + include_package_data=True, + zip_safe=False, + packages=find_packages(), + + entry_points = { + 'jenkins_jobs.projects': [ + 'freestyle=jenkins_jobs.modules.project_freestyle:Freestyle', + 'maven=jenkins_jobs.modules.project_maven:Maven', + ], + 'jenkins_jobs.builders': [ + 'shell=jenkins_jobs.modules.builders:shell', + 'trigger-builds=jenkins_jobs.modules.builders:trigger_builds', + ], + 'jenkins_jobs.properties': [ + 'github=jenkins_jobs.modules.properties:github', + 'throttle=jenkins_jobs.modules.properties:throttle', + 'authenticated-build=jenkins_jobs.modules.properties:' + 'authenticated_build', + ], + 'jenkins_jobs.parameters': [ + 'string=jenkins_jobs.modules.properties:string_param', + 'bool=jenkins_jobs.modules.properties:bool_param', + 'file=jenkins_jobs.modules.properties:file_param', + 'text=jenkins_jobs.modules.properties:text_param', + 'label=jenkins_jobs.modules.properties:label_param', + ], + 'jenkins_jobs.notifications': [ + 'http=jenkins_jobs.modules.properties:http_endpoint', + ], + 'jenkins_jobs.publishers': [ + 'archive=jenkins_jobs.modules.publishers:archive', + 'trigger-parameterized-builds=' + 'jenkins_jobs.modules.publishers:trigger_parameterized_builds', + 'coverage=jenkins_jobs.modules.publishers:coverage', + 'ftp=jenkins_jobs.modules.publishers:ftp', + 'junit=jenkins_jobs.modules.publishers:junit', + 'pep8=jenkins_jobs.modules.publishers:pep8', + 'scp=jenkins_jobs.modules.publishers:scp', + ], + 'jenkins_jobs.scm': [ + 'git=jenkins_jobs.modules.scm:git', + ], + 'jenkins_jobs.triggers': [ + 'gerrit=jenkins_jobs.modules.triggers:gerrit', + 'pollscm=jenkins_jobs.modules.triggers:pollscm', + 'timed=jenkins_jobs.modules.triggers:timed', + ], + 'jenkins_jobs.wrappers': [ + 'timeout=jenkins_jobs.modules.wrappers:timeout', + 'timestamps=jenkins_jobs.modules.wrappers:timestamps', + 'ansicolor=jenkins_jobs.modules.wrappers:ansicolor', + ], + 'jenkins_jobs.modules': [ + 'assignednode=jenkins_jobs.modules.assignednode:AssignedNode', + 'builders=jenkins_jobs.modules.builders:Builders', + 'logrotate=jenkins_jobs.modules.logrotate:LogRotate', + 'properties=jenkins_jobs.modules.properties:Properties', + 'publishers=jenkins_jobs.modules.publishers:Publishers', + 'scm=jenkins_jobs.modules.scm:SCM', + 'triggers=jenkins_jobs.modules.triggers:Triggers', + 'wrappers=jenkins_jobs.modules.wrappers:Wrappers', + 'zuul=jenkins_jobs.modules.zuul:Zuul', + ] + } + + ) diff --git a/test.sh b/test.sh index ce2bcb5d0..b5bec2a67 100755 --- a/test.sh +++ b/test.sh @@ -9,18 +9,19 @@ mkdir -p /tmp/jenkins_jobs_test/test if [ "$1" == "save" ] then - for x in `find projects/ -name *.yml` - do - echo $x - BASENAME=`basename $x` - python jenkins_jobs.py test $x > /tmp/jenkins_jobs_test/saved/$BASENAME.xml - done + rm -f /tmp/jenkins_jobs_test/saved/* + jenkins-jobs test -o /tmp/jenkins_jobs_test/saved/ example else - for x in `find projects/ -name *.yml` + rm -f /tmp/jenkins_jobs_test/test/* + jenkins-jobs test -o /tmp/jenkins_jobs_test/test/ example + for x in `(cd /tmp/jenkins_jobs_test/saved && find -type f)` do - echo $x - BASENAME=`basename $x` - python jenkins_jobs.py test $x > /tmp/jenkins_jobs_test/test/$BASENAME.xml + if ! diff -u /tmp/jenkins_jobs_test/saved/$x /tmp/jenkins_jobs_test/test/$x >/dev/null 2>&1 + then + echo "============================================================" + echo $x + echo "------------------------------------------------------------" + fi + diff -u /tmp/jenkins_jobs_test/saved/$x /tmp/jenkins_jobs_test/test/$x done - diff -r /tmp/jenkins_jobs_test/saved /tmp/jenkins_jobs_test/test fi