Universal Python client for `Jenkins <http://jenkins.io>`_
==========================================================
|Build status|
|Docs status|
|Coverage status|
|Version status|
|Downloads status|
.. |Build status|
image:: https://github.com/pbelskiy/ujenkins/workflows/Tests/badge.svg
.. |Docs status|
image:: https://readthedocs.org/projects/ujenkins/badge/?version=latest
.. |Coverage status|
image:: https://img.shields.io/coveralls/github/pbelskiy/ujenkins?label=Coverage
.. |Version status|
image:: https://img.shields.io/pypi/pyversions/ujenkins?label=Python
.. |Downloads status|
image:: https://img.shields.io/pypi/dm/ujenkins?color=1&label=Downloads
----
Python client for Jenkins which supports both sync and async syntax with same interface.
+--------------------------------------------+
| Comparison to other packages |
+-------------------+-------+-------+--------+
| Name | Sync | Async | Python |
+===================+=======+=======+========+
| `ujenkins`_ | YES | YES | 3.6+ |
+-------------------+-------+-------+--------+
| `aiojenkins`_ | NO | YES | 3.5+ |
+-------------------+-------+-------+--------+
| `python-jenkins`_ | YES | NO | 3.4+ |
+-------------------+-------+-------+--------+
| `jenkinsapi`_ | YES | NO | 3.4+ |
+-------------------+-------+-------+--------+
.. _ujenkins: https://github.com/pbelskiy/ujenkins
.. _aiojenkins: https://github.com/pbelskiy/aiojenkins
.. _python-jenkins: https://opendev.org/jjb/python-jenkins
.. _jenkinsapi: https://github.com/pycontribs/jenkinsapi
Installation
------------
Latest release from PyPI
.. code:: shell
pip3 install ujenkins
Or latest developing version
.. code:: shell
pip3 install git+https://github.com/pbelskiy/ujenkins
Usage
-----
Get Jenkins version using sync client:
.. code:: python
from ujenkins import JenkinsClient
def example():
client = JenkinsClient('http://server', 'user', 'password')
version = client.system.get_version()
print(version)
example()
With async client (be careful ``AsyncJenkinsClient`` must be called inside async function):
.. code:: python
import asyncio
from ujenkins import AsyncJenkinsClient
async def example():
client = AsyncJenkinsClient('http://server', 'user', 'password')
version = await client.system.get_version()
print(version)
await client.close()
asyncio.run(example())
Examples
--------
In all code examples below client instance is created by:
.. code:: python
from ujenkins import JenkinsClient
client = JenkinsClient('http://server', 'user', 'password')
Get timestamp of latest build
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: python
client.builds.get_info('job', 'lastBuild')['timestamp']
Get url of started build
~~~~~~~~~~~~~~~~~~~~~~~~
Be careful, ``JenkinsNotFoundError`` could be raise in case build with same arg already enqueued.
.. code:: python
item_id = client.builds.start('my_job')
while True:
time.sleep(5)
try:
info = client.queue.get_info(item_id)
print(info['executable']['url'])
break
except (KeyError, TypeError):
pass # wait for build will be started
Get all jobs
~~~~~~~~~~~~
Basically ``client.jobs.get()`` returns jobs from root (depth = 0), in case you
want receive all the jobs, there are few approaches for it.
1) Set needed depth, experimentally 10 is enough.
.. code-block:: python
jobs = client.jobs.get(depth=10)
Output:
.. code-block:: python
{'folder': {'_class': 'com.cloudbees.hudson.plugins.folder.Folder',
'jobs': [{'_class': 'hudson.model.FreeStyleProject',
'color': 'notbuilt',
'name': 'job_in_folder1',
'url': 'http://localhost:8080/job/folder/job/job_in_folder1/'},
{'_class': 'com.cloudbees.hudson.plugins.folder.Folder',
'jobs': [{'_class': 'hudson.model.FreeStyleProject',
'color': 'notbuilt',
'name': 'sub_job_in_subfolder',
'url': 'http://localhost:8080/job/folder/job/subfolder/job/sub_job_in_subfolder/'}],
'name': 'subfolder',
'url': 'http://localhost:8080/job/folder/job/subfolder/'}],
'name': 'folder',
'url': 'http://localhost:8080/job/folder/'},
'job': {'_class': 'hudson.model.FreeStyleProject',
'color': 'blue',
'name': 'job',
'url': 'http://localhost:8080/job/job/'}}
2) Or just write your code to recursively form it, example is below.
.. code:: python
def get_all_jobs(url: str = '', parent: str = '') -> Dict[str, dict]:
jobs = {}
for name, prop in client.jobs.get(url).items():
jobs[parent + name] = prop
if 'Folder' in prop.get('_class', ''):
jobs.update(get_all_jobs(prop['url'], parent + name + '/'))
return jobs
all_jobs = get_all_jobs()
Working with build artifacts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: python
# get content of artifact (bytes)
content = client.builds.get_artifact('my_job', 31, 'photo.jpg')
with open('/tmp/photo.jpg', 'wb') as f:
w.write(content)
# enumerate artifacts
artifacts = client.builds.get_list_artifacts('my_job', 31)
for artifact in artifacts:
# get content and manually save it
content = client.builds.get_artifact('my_job', 31, artifact['path'])
# or absolute url could be used for external download
print(artifact['url'])
# >> 'http://server/job/my_job/31/artifact/photo.jpg'
Documentation
-------------
`Read the Docs <https://ujenkins.readthedocs.io/en/latest/>`_
Testing
-------
Prerequisites: ``tox``
Then just run tox, all dependencies and checks will run automatically
::
tox
Contributing
------------
Any contributions are welcome!
Raw data
{
"_id": null,
"home_page": "https://github.com/pbelskiy/ujenkins",
"name": "ujenkins",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "jenkins",
"author": "Petr Belskiy",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/9a/ce/6489e0633981e2c3a4697240bfb74a1e530d41c9f446c3473ed95f6b4f0c/ujenkins-0.11.1.tar.gz",
"platform": null,
"description": "Universal Python client for `Jenkins <http://jenkins.io>`_\n==========================================================\n\n|Build status|\n|Docs status|\n|Coverage status|\n|Version status|\n|Downloads status|\n\n.. |Build status|\n image:: https://github.com/pbelskiy/ujenkins/workflows/Tests/badge.svg\n.. |Docs status|\n image:: https://readthedocs.org/projects/ujenkins/badge/?version=latest\n.. |Coverage status|\n image:: https://img.shields.io/coveralls/github/pbelskiy/ujenkins?label=Coverage\n.. |Version status|\n image:: https://img.shields.io/pypi/pyversions/ujenkins?label=Python\n.. |Downloads status|\n image:: https://img.shields.io/pypi/dm/ujenkins?color=1&label=Downloads\n\n----\n\nPython client for Jenkins which supports both sync and async syntax with same interface.\n\n+--------------------------------------------+\n| Comparison to other packages |\n+-------------------+-------+-------+--------+\n| Name | Sync | Async | Python |\n+===================+=======+=======+========+\n| `ujenkins`_ | YES | YES | 3.6+ |\n+-------------------+-------+-------+--------+\n| `aiojenkins`_ | NO | YES | 3.5+ |\n+-------------------+-------+-------+--------+\n| `python-jenkins`_ | YES | NO | 3.4+ |\n+-------------------+-------+-------+--------+\n| `jenkinsapi`_ | YES | NO | 3.4+ |\n+-------------------+-------+-------+--------+\n\n.. _ujenkins: https://github.com/pbelskiy/ujenkins\n.. _aiojenkins: https://github.com/pbelskiy/aiojenkins\n.. _python-jenkins: https://opendev.org/jjb/python-jenkins\n.. _jenkinsapi: https://github.com/pycontribs/jenkinsapi\n\nInstallation\n------------\n\nLatest release from PyPI\n\n.. code:: shell\n\n pip3 install ujenkins\n\nOr latest developing version\n\n.. code:: shell\n\n pip3 install git+https://github.com/pbelskiy/ujenkins\n\nUsage\n-----\n\nGet Jenkins version using sync client:\n\n.. code:: python\n\n from ujenkins import JenkinsClient\n\n def example():\n client = JenkinsClient('http://server', 'user', 'password')\n version = client.system.get_version()\n print(version)\n\n example()\n\nWith async client (be careful ``AsyncJenkinsClient`` must be called inside async function):\n\n.. code:: python\n\n import asyncio\n from ujenkins import AsyncJenkinsClient\n\n async def example():\n client = AsyncJenkinsClient('http://server', 'user', 'password')\n version = await client.system.get_version()\n print(version)\n await client.close()\n\n asyncio.run(example())\n\nExamples\n--------\n\nIn all code examples below client instance is created by:\n\n.. code:: python\n\n from ujenkins import JenkinsClient\n client = JenkinsClient('http://server', 'user', 'password')\n\nGet timestamp of latest build\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n client.builds.get_info('job', 'lastBuild')['timestamp']\n\nGet url of started build\n~~~~~~~~~~~~~~~~~~~~~~~~\n\nBe careful, ``JenkinsNotFoundError`` could be raise in case build with same arg already enqueued.\n\n.. code:: python\n\n item_id = client.builds.start('my_job')\n while True:\n time.sleep(5)\n try:\n info = client.queue.get_info(item_id)\n print(info['executable']['url'])\n break\n except (KeyError, TypeError):\n pass # wait for build will be started\n\nGet all jobs\n~~~~~~~~~~~~\n\nBasically ``client.jobs.get()`` returns jobs from root (depth = 0), in case you\nwant receive all the jobs, there are few approaches for it.\n\n1) Set needed depth, experimentally 10 is enough.\n\n.. code-block:: python\n\n jobs = client.jobs.get(depth=10)\n\nOutput:\n\n.. code-block:: python\n\n {'folder': {'_class': 'com.cloudbees.hudson.plugins.folder.Folder',\n 'jobs': [{'_class': 'hudson.model.FreeStyleProject',\n 'color': 'notbuilt',\n 'name': 'job_in_folder1',\n 'url': 'http://localhost:8080/job/folder/job/job_in_folder1/'},\n {'_class': 'com.cloudbees.hudson.plugins.folder.Folder',\n 'jobs': [{'_class': 'hudson.model.FreeStyleProject',\n 'color': 'notbuilt',\n 'name': 'sub_job_in_subfolder',\n 'url': 'http://localhost:8080/job/folder/job/subfolder/job/sub_job_in_subfolder/'}],\n 'name': 'subfolder',\n 'url': 'http://localhost:8080/job/folder/job/subfolder/'}],\n 'name': 'folder',\n 'url': 'http://localhost:8080/job/folder/'},\n 'job': {'_class': 'hudson.model.FreeStyleProject',\n 'color': 'blue',\n 'name': 'job',\n 'url': 'http://localhost:8080/job/job/'}}\n\n2) Or just write your code to recursively form it, example is below.\n\n.. code:: python\n\n def get_all_jobs(url: str = '', parent: str = '') -> Dict[str, dict]:\n jobs = {}\n\n for name, prop in client.jobs.get(url).items():\n jobs[parent + name] = prop\n if 'Folder' in prop.get('_class', ''):\n jobs.update(get_all_jobs(prop['url'], parent + name + '/'))\n\n return jobs\n\n all_jobs = get_all_jobs()\n\nWorking with build artifacts\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n # get content of artifact (bytes)\n content = client.builds.get_artifact('my_job', 31, 'photo.jpg')\n with open('/tmp/photo.jpg', 'wb') as f:\n w.write(content)\n\n # enumerate artifacts\n artifacts = client.builds.get_list_artifacts('my_job', 31)\n for artifact in artifacts:\n # get content and manually save it\n content = client.builds.get_artifact('my_job', 31, artifact['path'])\n\n # or absolute url could be used for external download\n print(artifact['url'])\n # >> 'http://server/job/my_job/31/artifact/photo.jpg'\n\nDocumentation\n-------------\n\n`Read the Docs <https://ujenkins.readthedocs.io/en/latest/>`_\n\nTesting\n-------\n\nPrerequisites: ``tox``\n\nThen just run tox, all dependencies and checks will run automatically\n\n::\n\n tox\n\nContributing\n------------\n\nAny contributions are welcome!\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Universal (sync/async) Python client for Jenkins",
"version": "0.11.1",
"project_urls": {
"Download": "https://pypi.org/project/ujenkins",
"Homepage": "https://github.com/pbelskiy/ujenkins"
},
"split_keywords": [
"jenkins"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5823180b975c87b697a9f95faeb8f06103c8ce51b39d40adf5d9e98477caa073",
"md5": "8a38f8c5e8aeb97e70798fdf72bd2be3",
"sha256": "df64d142ae36334cbbafbb385be8a897269988a1bf9932fb46f2be74587c0577"
},
"downloads": -1,
"filename": "ujenkins-0.11.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8a38f8c5e8aeb97e70798fdf72bd2be3",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 36498,
"upload_time": "2024-10-05T15:01:02",
"upload_time_iso_8601": "2024-10-05T15:01:02.392332Z",
"url": "https://files.pythonhosted.org/packages/58/23/180b975c87b697a9f95faeb8f06103c8ce51b39d40adf5d9e98477caa073/ujenkins-0.11.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "9ace6489e0633981e2c3a4697240bfb74a1e530d41c9f446c3473ed95f6b4f0c",
"md5": "09c361d50f0d2ae3957b0b8161649b6a",
"sha256": "cbfdc9a140a791a48645838b2c1e2c5bf7ed56f2f643854bfd7bdc242c567647"
},
"downloads": -1,
"filename": "ujenkins-0.11.1.tar.gz",
"has_sig": false,
"md5_digest": "09c361d50f0d2ae3957b0b8161649b6a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 18719,
"upload_time": "2024-10-05T15:01:04",
"upload_time_iso_8601": "2024-10-05T15:01:04.101394Z",
"url": "https://files.pythonhosted.org/packages/9a/ce/6489e0633981e2c3a4697240bfb74a1e530d41c9f446c3473ed95f6b4f0c/ujenkins-0.11.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-05 15:01:04",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "pbelskiy",
"github_project": "ujenkins",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "ujenkins"
}