{"id":24282164,"url":"https://github.com/pbelskiy/ujenkins","last_synced_at":"2025-04-09T16:19:19.037Z","repository":{"id":41085614,"uuid":"393964666","full_name":"pbelskiy/ujenkins","owner":"pbelskiy","description":"Python client for Jenkins (sync + async)","archived":false,"fork":false,"pushed_at":"2025-03-15T14:19:21.000Z","size":174,"stargazers_count":20,"open_issues_count":5,"forks_count":10,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-09T16:19:11.746Z","etag":null,"topics":["jenkins","jenkins-python"],"latest_commit_sha":null,"homepage":"https://ujenkins.readthedocs.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pbelskiy.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-08T13:13:37.000Z","updated_at":"2025-03-15T14:19:25.000Z","dependencies_parsed_at":"2024-10-30T07:45:13.420Z","dependency_job_id":null,"html_url":"https://github.com/pbelskiy/ujenkins","commit_stats":{"total_commits":194,"total_committers":4,"mean_commits":48.5,"dds":"0.015463917525773141","last_synced_commit":"a53db7ad5b263f2b937f398c870fee2fbaf0d0c5"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pbelskiy%2Fujenkins","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pbelskiy%2Fujenkins/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pbelskiy%2Fujenkins/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pbelskiy%2Fujenkins/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pbelskiy","download_url":"https://codeload.github.com/pbelskiy/ujenkins/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248065281,"owners_count":21041872,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jenkins","jenkins-python"],"created_at":"2025-01-16T03:02:34.565Z","updated_at":"2025-04-09T16:19:19.018Z","avatar_url":"https://github.com/pbelskiy.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"Universal Python client for `Jenkins \u003chttp://jenkins.io\u003e`_\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\u0026label=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 = '') -\u003e 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        # \u003e\u003e 'http://server/job/my_job/31/artifact/photo.jpg'\n\nDocumentation\n-------------\n\n`Read the Docs \u003chttps://ujenkins.readthedocs.io/en/latest/\u003e`_\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","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpbelskiy%2Fujenkins","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpbelskiy%2Fujenkins","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpbelskiy%2Fujenkins/lists"}