Skip to content

Commit

Permalink
Update README (#94)
Browse files Browse the repository at this point in the history
* update README.md
  • Loading branch information
joelee2012 authored Oct 31, 2023
1 parent 753747c commit 59bceb4
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 83 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[![Unit Test](https://github.com/joelee2012/api4jenkins/actions/workflows/unittest.yml/badge.svg?branch=2.0)](https://github.com/joelee2012/api4jenkins/actions/workflows/unittest.yml)
[![Integration Test](https://github.com/joelee2012/api4jenkins/actions/workflows/integration.yml/badge.svg?branch=2.0)](https://github.com/joelee2012/api4jenkins/actions/workflows/integration.yml)
![CodeQL](https://github.com/joelee2012/api4jenkins/workflows/CodeQL/badge.svg?branch=2.0)
[![codecov](https://codecov.io/gh/joelee2012/api4jenkins/branch/2.0/graph/badge.svg?token=YGM4CIB149)](https://codecov.io/gh/joelee2012/api4jenkins)
[![Unit Test](https://github.com/joelee2012/api4jenkins/actions/workflows/unittest.yml/badge.svg?branch=main)](https://github.com/joelee2012/api4jenkins/actions/workflows/unittest.yml)
[![Integration Test](https://github.com/joelee2012/api4jenkins/actions/workflows/integration.yml/badge.svg?branch=main)](https://github.com/joelee2012/api4jenkins/actions/workflows/integration.yml)
![CodeQL](https://github.com/joelee2012/api4jenkins/workflows/CodeQL/badge.svg?branch=main)
[![codecov](https://codecov.io/gh/joelee2012/api4jenkins/branch/main/graph/badge.svg?token=YGM4CIB149)](https://codecov.io/gh/joelee2012/api4jenkins)
![PyPI](https://img.shields.io/pypi/v/api4jenkins)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/api4jenkins)
![PyPI - Wheel](https://img.shields.io/pypi/wheel/api4jenkins)
Expand Down Expand Up @@ -66,7 +66,7 @@ Finished: SUCCESS
False
>>> build.result
'SUCCESS'
```
```

Async example

Expand Down
37 changes: 17 additions & 20 deletions api4jenkins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@

from api4jenkins.mix import UrlMixIn

from .__version__ import (__author__, __author_email__, __copyright__,
__description__, __license__, __title__, __url__,
__version__)
from .credential import AsyncCredentials, Credentials
from .exceptions import AuthenticationError, ItemNotFoundError
from .exceptions import ItemNotFoundError
from .http import new_async_http_client, new_http_client
from .item import AsyncItem, Item
from .job import AsyncFolder, AsyncProject, Folder
Expand All @@ -35,7 +32,7 @@ class Jenkins(Item, UrlMixIn):
:param token: (optional) Boolean, Create user token when initialize instance and
revoke token once instance is destroied. useful when LDAP server refuse
username and password used too much often. Defaults to ``False``.
:param \*\*kwargs: other kwargs are same as `requests.Session.request <https://requests.readthedocs.io/en/latest/api/#requests.Session.request>`_
:param \*\*kwargs: other kwargs are same as `httpx.Client <https://www.python-httpx.org/api/#client>`_
Usage::
Expand Down Expand Up @@ -226,16 +223,16 @@ def _resolve_name(self, full_name):
parent, name = self._parse_name(full_name)
return Folder(self, self._name2url(parent)), name

def exists(self):
'''Check if Jenkins server is up
# def exists(self):
# '''Check if Jenkins server is up

:returns: True or False
'''
try:
self.handle_req('GET', '')
return True
except Exception as e:
return isinstance(e, (AuthenticationError, PermissionError))
# :returns: True or False
# '''
# try:
# self._request('HEAD', self.url)
# return True
# except Exception as e:
# return isinstance(e, (AuthenticationError, PermissionError))

@property
def crumb(self):
Expand Down Expand Up @@ -390,12 +387,12 @@ def _resolve_name(self, full_name):
parent, name = self._parse_name(full_name)
return AsyncFolder(self, self._name2url(parent)), name

async def exists(self):
try:
await self.handle_req('GET', '')
return True
except Exception as e:
return isinstance(e, (AuthenticationError, PermissionError))
# async def exists(self):
# try:
# await self._request('HEAD', self.url)
# return True
# except Exception as e:
# return isinstance(e, (AuthenticationError, PermissionError))

@property
async def crumb(self):
Expand Down
2 changes: 1 addition & 1 deletion api4jenkins/__version__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# encoding: utf-8
__version__ = '2.0.0'
__version__ = '2.0.1'
__title__ = 'api4jenkins'
__description__ = 'Jenkins Python Client'
__url__ = 'https://github.com/joelee2012/api4jenkins'
Expand Down
16 changes: 2 additions & 14 deletions api4jenkins/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,7 @@ class SlaveComputer(Node):


class KubernetesComputer(Node):

def exists(self):
try:
self.handle_req('GET', '')
return True
except ItemNotFoundError:
return False
pass


class DockerComputer(Node):
Expand Down Expand Up @@ -225,13 +219,7 @@ class AsyncSlaveComputer(AsyncNode):


class AsyncKubernetesComputer(AsyncNode):

async def exists(self):
try:
await self.handle_req('GET', '')
return True
except ItemNotFoundError:
return False
pass


class AsyncDockerComputer(AsyncNode):
Expand Down
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
httpx
sphinx
25 changes: 15 additions & 10 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,26 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os

import sys
from pathlib import Path

sys.path.insert(0, os.path.abspath('../../'))
repo_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(repo_root))
# -- Project information -----------------------------------------------------
import api4jenkins

project = 'api4jenkins'
copyright = '2023, Joe Lee'
author = 'Joe Lee'
about = {}
with open(repo_root.joinpath('api4jenkins', '__version__.py')) as f:
exec(f.read(), about)

# The full version, including alpha/beta/rc tags
release = api4jenkins.__version__
project = about['__title__']
copyright = about['__copyright__']
author = about['__author__']

# The full version, including alpha/beta/rc tags
release = about['__version__']

version = about['__version__']
# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
Expand All @@ -33,7 +38,7 @@
extensions = ["sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx.ext.todo",
"sphinx.ext.viewcode", ]
"sphinx.ext.viewcode",]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
Expand All @@ -54,6 +59,6 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# html_static_path = ['_static']

master_doc = 'index'
54 changes: 39 additions & 15 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ Jenkins Python Client
Features
--------

- Provides ``sync`` and ``async`` APIs
- Object oriented, each Jenkins item has corresponding class, easy to use and extend
- Base on `api/json`, easy to query/filter attribute of item
- Base on ``api/json``, easy to query/filter attribute of item
- Setup relationship between class just like Jenkins item
- Support api for almost every Jenkins item
- Pythonic
- Test with latest Jenkins LTS
- Test with latest `Jenkins LTS <https://www.jenkins.io/changelog-stable/>`_


Quick start
Expand All @@ -40,10 +41,11 @@ Quick start
Here is an example to create and build job, then monitor progressive output
until it's done.

Sync example::

>>> from api4jenkins import Jenkins
>>> j = Jenkins('http://127.0.0.1:8080/', auth=('admin', 'admin'))
>>> j.version
>>> client = Jenkins('http://127.0.0.1:8080/', auth=('admin', 'admin'))
>>> client.version
'2.176.2'
>>> xml = """<?xml version='1.1' encoding='UTF-8'?>
... <project>
Expand All @@ -53,21 +55,12 @@ until it's done.
... </hudson.tasks.Shell>
... </builders>
... </project>"""
>>> j.create_job('freestylejob', xml)
>>> job = j.get_job('freestylejob')
>>> print(job)
<FreeStyleProject: http://127.0.0.1:8080/job/freestylejob/>
>>> print(job.parent)
<Jenkins: http://127.0.0.1:8080/>
>>> print(job.jenkins)
<Jenkins: http://127.0.0.1:8080/>
>>> client.create_job('path/to/job', xml)
>>> import time
>>> item = job.build()
>>> item = client.build_job('path/to/job')
>>> while not item.get_build():
... time.sleep(1)
>>> build = item.get_build()
>>> print(build)
<FreeStyleBuild: http://127.0.0.1:8080/job/freestylejob/1/>
>>> for line in build.progressive_output():
... print(line)
...
Expand All @@ -84,6 +77,37 @@ until it's done.
'SUCCESS'


Async example::

import asyncio
import time
from api4jenkins import AsyncJenkins

async main():
client = AsyncJenkins('http://127.0.0.1:8080/', auth=('admin', 'admin'))
print(await client.version)
xml = """<?xml version='1.1' encoding='UTF-8'?>
<project>
<builders>
<hudson.tasks.Shell>
<command>echo $JENKINS_VERSION</command>
</hudson.tasks.Shell>
</builders>
</project>"""
await client.create_job('job', xml)
item = await client.build_job('job')
while not await item.get_build():
time.sleep(1)
build = await item.get_build()
async for line in build.progressive_output():
print(line)

print(await build.building)
print(await build.result)

asyncio.run(main())


.. toctree::
:maxdepth: 2
:caption: Contents:
Expand Down
2 changes: 1 addition & 1 deletion docs/source/user/example.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ object is destoried by garbage collection.

.. note::

Any parameter supported by `requests.Session.request <https://requests.readthedocs.io/en/latest/api/#requests.Session.request>`_
Any parameter supported by `httpx.Client <https://www.python-httpx.org/api/#client>`_
can be passed to initialize Jenkins object.

Now, we have a :class:`Jenkins <api4jenkins.Jenkins>` object `j`, let's check
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
author_email=about['__author_email__'],
packages=['api4jenkins'],
package_data={'': ['LICENSE']},
python_requires='>=3.7',
python_requires='>=3.8',
install_requires=requires,
license=about['__license__'],
keywords=["RESTAPI", "Jenkins"],
Expand Down
18 changes: 2 additions & 16 deletions tests/unit/test_jenkins.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import weakref

import pytest
from api4jenkins import Jenkins

from api4jenkins.exceptions import BadRequestError, ItemNotFoundError
from api4jenkins.item import new_item, snake
from api4jenkins.job import AsyncFolder, AsyncWorkflowJob, WorkflowJob, Folder
from api4jenkins.job import AsyncFolder, AsyncWorkflowJob, Folder, WorkflowJob


class TestJenkins:
Expand Down Expand Up @@ -125,12 +123,6 @@ def test__url2name_value_error(self, jenkins):
def test__name2url(self, jenkins, name, url_entry):
assert jenkins._name2url(name) == f'{jenkins.url}{url_entry}'

@pytest.mark.parametrize('status, exist', [(403, True), (200, True),
(404, False), (500, False)])
def test_exists(self, jenkins, respx_mock, status, exist):
respx_mock.get(jenkins.url).respond(status)
assert jenkins.exists() == exist

def test_iter_jobs(self, jenkins):
assert len(list(jenkins.iter(1))) == 5
assert len(list(jenkins)) == 5
Expand Down Expand Up @@ -285,12 +277,6 @@ async def test__name2url(self, async_jenkins, name, url_entry):
assert async_jenkins._name2url(
name) == f'{async_jenkins.url}{url_entry}'

@pytest.mark.parametrize('status, exist', [(403, True), (200, True),
(404, False), (500, False)])
async def test_exists(self, async_jenkins, respx_mock, status, exist):
respx_mock.get(async_jenkins.url).respond(status)
assert await async_jenkins.exists() == exist

async def test_iter_jobs(self, async_jenkins):
assert len([j async for j in async_jenkins]) == 5
assert len([j async for j in async_jenkins]) == 5
Expand Down

0 comments on commit 59bceb4

Please sign in to comment.