From 373b72b92d7571a075a70e5a2d86e3696716412d Mon Sep 17 00:00:00 2001 From: Russell Bunch Date: Sat, 15 Apr 2023 02:30:05 -0500 Subject: [PATCH] Add Sphinx docs and GitHub Pages Add an initial Sphinx documentation framework and a GitHub workflow to auto-publish GitHub pages. --- .github/workflows/docs.yml | 50 +++++++++++++++ .gitignore | 3 + GNUmakefile | 6 ++ README.adoc | 120 ------------------------------------ docs/_static/csm.jpeg | Bin 0 -> 10473 bytes docs/_static/favicon.ico | Bin 0 -> 15406 bytes docs/conf.py | 61 +++++++++++++++++++ docs/index.rst | 21 +++++++ docs/libcsm.rst | 11 ++++ docs/versioning.rst | 122 +++++++++++++++++++++++++++++++++++++ libcsm/api.py | 17 ++++-- libcsm/cli.py | 0 libcsm/tests/test_api.py | 4 +- noxfile.py | 52 +++++++++------- pyproject.toml | 5 ++ 15 files changed, 324 insertions(+), 148 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 docs/_static/csm.jpeg create mode 100644 docs/_static/favicon.ico create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/libcsm.rst create mode 100644 docs/versioning.rst create mode 100644 libcsm/cli.py diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..2030d90 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,50 @@ +# Simple workflow for deploying static content to GitHub Pages +name: Deploy static content to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Single deploy job since we're just deploying + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - name: Install dependencies + run: | + pip install .[ci] + - name: Sphinx build + run: | + nox -e docs + - name: Setup Pages + uses: actions/configure-pages@v3 + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + # Upload entire repository + path: 'docs/_build/' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/.gitignore b/.gitignore index 0999f4d..1068e05 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,6 @@ ENV/ env.bak/ venv.bak/ .ruff_cache/ + +# Docs +/docs/_build/ diff --git a/GNUmakefile b/GNUmakefile index 9458349..64c4ea2 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -137,6 +137,7 @@ phonies+=rpm_build_source phonies+=rpm_package_source phonies+=ruff phonies+=synk +phonies+=docs all : prepare rpm @@ -158,10 +159,15 @@ help: @echo ' rpm_build_source Builds the SRPM.' @echo ' rpm_package_source Creates the RPM source tarball.' @echo '' + @echo ' docs Generate Python sphinx documentation.' clean: rm -rf build dist .ruff_cache +docs: + sphinx-build -b html ./docs ./docs/_build + + ############################################################################# # RPM targets ############################################################################# diff --git a/README.adoc b/README.adoc index ccb830d..4f3dba1 100644 --- a/README.adoc +++ b/README.adoc @@ -15,7 +15,6 @@ A library for Cray Systems Management. === Usage - ==== Building and using `libcsm` * With `pip` @@ -194,125 +193,6 @@ git+git://github.com/Cray-HPE/libcsm.git@v1.0.2#egg=libcsm git+git://github.com/Cray-HPE/libcsm.git@releases/tag/v1.0.1#egg=libcsm ---- -=== Versioning - -The version is derived from Git by the `setuptools_scm` Python module and follows https://peps.python.org/pep-0440/#abstract[PEP0440]'s version identification -and dependency specification for https://peps.python.org/pep-0440/#final-releases[final] and https://peps.python.org/pep-0440/#pre-releases[pre] releases. - -.All Git-Tags in this repository are prefixed with `v`. - -==== Classification - -The items below denote how stable, pre-release, and unstable versions are classified through -version strings. - -* **(stable) final release**: A git-tag following the `X.Y.Z` semver format is considered a final release version. -+ -[source,bash] ----- -# Format: -# {tag} -# X.Y.Z -# X - Major -# Y - Minor -# Z - Micro (a.k.a. patch) -0.1.2 ----- -* **(stable) post release**: A git-tag following the `X.Y.Z.postN` (where `N` is an integer), indicates a post-release. -These are seldom used, and are strictly for handling documentation, packaging, or other meta -updates after a release tag was already created where it isn't warranted to publish an -entirely new release. `1.0.0.post0` and `1.0.0` are considered the same version in this repository. `1.0.0.post1` would -produce an RPM with a release version of `2` (since our RPMs index their releases starting at `1`). -+ -[source,bash] ----- -# Format: -# {tag} -# X.Y.Z.postN -# X - Major -# Y - Minor -# Z - Micro (a.k.a. patch) -# Z - Post release [1-9]+ -0.1.2.post1 ----- -* **(unstable) pre-release**: A git-tag with an `a`(lpha), `b`(eta), or `r`(elease) `c`(andidate) annotation and an identification number `N` denotes a pre-release/preview. -+ -.These are rarely used for `libcsm`. -+ -[source,bash] ----- -# Format: -# {tag}[{a|b|rc}N] -0.1.2a1 -0.1.2b1 -0.1.2rc1 ----- -* **(unstable) development**: Development builds **auto-increment** the micro version (the `Z` in `X.Y.Z`) or pre-release version (the `N` in `X.Y.Z{[a|b|rc]N}`), and -then append a suffix based on whether the working directory was **clean**, **dirty**, or **mixed**. -** **clean**: When the version shows an appended `devN+{scm_letter}{revision_short_hash}`, that means there have been commits made since the previous git-tag. -+ -[source,bash] ----- -# Format: -# {next_version}.dev{distance}+{scm_letter}{revision_short_hash} - -# If the previous git-tag was 0.1.2: - 0.1.3.dev4+g818da8a - -# If the previous get-tag was a pre-release of 0.1.3a1: - 0.1.3a2.dev4+g818da8a ----- -** **dirty**: When the version shows an appended `.d{YYYYMMDD}` datestamp, that means there were modified/uncommitted changes in the working directory when the application was built. -+ -[source,bash] ----- -# Format: -# {next_version}.d(datestamp} - -# If the previous git-tag was 0.1.2: - 0.1.3.d20230123 - -# If the previous get-tag was a pre-release of 0.1.3a1: - 0.1.2a2.d20230123 ----- -** **mixed**: When the version shows a development tag with an appended datestamp, this means commits have been made but there were uncommitted changes present in the working directory when the application was built. -+ -[source,bash] ----- -# Format: -# {next_Version}.dev{distance}+{scm_letter}{revision_short_hash}.d{datestamp} - -# If the previous git-tag was 0.1.2: - 0.1.3.dev3+g3071655.d20230123 - -# If the previous get-tag was a pre-release of 0.1.3a1: - 0.1.3a2.dev3+g3071655.d20230123 ----- - -For more information about versioning, see https://github.com/pypa/setuptools_scm/#default-versioning-scheme[versioning scheme information]. - -==== Configuration - -The `setuptools_scm` module is configured by `pyproject.toml`. - -For more information regarding configuration of `setuptools_scm`, see https://github.com/pypa/setuptools_scm/#version-number-construction[version number construction]. - -==== Retrieving the Python Package Version at Runtime - -If at any point code within the module wants to print or be aware of the modules own version, it can. The following snippet demonstrates how to do this. - -[source,python] ----- -from importlib.metadata import version -from importlib.metadata import PackageNotFoundError - -try: - __version__ = version("libcsm") -except PackageNotFoundError: - # package is not installed - pass ----- - === Contributing The primary purpose of the `libcsm` module is to support CSM installation, upgrade, and operational procedures. This module serves as a place for offering functions and error handling to common tasks diff --git a/docs/_static/csm.jpeg b/docs/_static/csm.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..022399d1f6b23d7b8ade97d39ba167e6323265ce GIT binary patch literal 10473 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 version identification +and dependency specification for `final `_ and `pre `_ releases. + +.. note:: + All Git-Tags in this repository are prefixed with ``v``. + +Classification +-------------- + +The items below denote how stable, pre-release, and unstable versions are classified through +version strings. + +* **(stable) final release**: A git-tag following the ``X.Y.Z`` semver format is considered a final release version. + + .. code-block:: + + # Format: + # {tag} + # X.Y.Z + # X - Major + # Y - Minor + # Z - Micro (a.k.a. patch) + 0.1.2 + +* **(stable) post release**: A git-tag following the ``X.Y.Z.postN`` (where ``N`` is an integer), indicates a post-release. + These are seldom used, and are strictly for handling documentation, packaging, or other meta + updates after a release tag was already created where it isn't warranted to publish an + entirely new release. ``1.0.0.post0`` and ``1.0.0`` are considered the same version in this repository. ``1.0.0.post1`` would + produce an RPM with a release version of ``2`` (since our RPMs index their releases starting at ``1``). + + .. code-block:: + + # Format: + # {tag} + # X.Y.Z.postN + # X - Major + # Y - Minor + # Z - Micro (a.k.a. patch) + # Z - Post release [1-9]+ + 0.1.2.post1 + +* **(unstable) pre-release**: A git-tag with an alpha (``a``), beta (``b``), or release candidate (``rc``) annotation and an identification number ``N`` denotes a pre-release/preview. + + .. code-block:: + + # Format: + # {tag}[{a|b|rc}N] + 0.1.2a1 + 0.1.2b1 + 0.1.2rc1 + +* **(unstable) development**: Development builds **auto-increment** the micro version (the ``Z`` in ``X.Y.Z``) or pre-release version (the `N` in ``X.Y.Z{[a|b|rc]N}``), and + then append a suffix based on whether the working directory was **clean**, **dirty**, or **mixed**. + + * **clean**: When the version shows an appended ``devN+{scm_letter}{revision_short_hash}``, that means there have been commits made since the previous git-tag. + + .. code-block:: + + # Format: + # {next_version}.dev{distance}+{scm_letter}{revision_short_hash} + + # If the previous git-tag was 0.1.2: + 0.1.3.dev4+g818da8a + + # If the previous get-tag was a pre-release of 0.1.3a1: + 0.1.3a2.dev4+g818da8a + + * **dirty**: When the version shows an appended ``.d{YYYYMMDD}`` datestamp, that means there were modified/uncommitted changes in the working directory when the application was built. + + .. code-block:: + + # Format: + # {next_version}.d(datestamp} + + # If the previous git-tag was 0.1.2: + 0.1.3.d20230123 + + # If the previous get-tag was a pre-release of 0.1.3a1: + 0.1.2a2.d20230123 + + * **mixed**: When the version shows a development tag with an appended datestamp, this means commits have been made but there were uncommitted changes present in the working directory when the application was built. + + .. code-block:: + + # Format: + # {next_Version}.dev{distance}+{scm_letter}{revision_short_hash}.d{datestamp} + + # If the previous git-tag was 0.1.2: + 0.1.3.dev3+g3071655.d20230123 + + # If the previous get-tag was a pre-release of 0.1.3a1: + 0.1.3a2.dev3+g3071655.d20230123 + +.. note:: + For more information about versioning, see `versioning scheme information `_. + +Configuration +------------- + +The ``setuptools_scm`` module is configured by ``pyproject.toml``. + +.. note:: + For more information regarding configuration of ``setuptools_scm``, see `version number construction `_. + +Retrieving the Python Package Version at Runtime +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If at any point code within the module wants to print or be aware of the modules own version, it can. The following snippet demonstrates how to do this. + +.. code-block:: python + + from importlib.metadata import version + from importlib.metadata import PackageNotFoundError + + try: + __version__ = version("crucible") + except PackageNotFoundError: + # package is not installed + pass diff --git a/libcsm/api.py b/libcsm/api.py index 3ffb9a6..d87a021 100644 --- a/libcsm/api.py +++ b/libcsm/api.py @@ -38,11 +38,14 @@ class AuthException(Exception): """ - An exception for authorization problems from the api.Auth object. + An exception for authorization problems from the ``api.Auth`` object. """ def __init__(self, message) -> None: - """Initialize an AuthException class.""" + """ + Initializes the Exception. + :param message: Message to include in the Exception. + """ self.message = message super().__init__(self.message) @@ -52,12 +55,16 @@ class Auth: Class for handling CSM API credentials stored in Kubernetes secrets. The initialization of this class passes any provided arguments along to - kubernetes.config.load_kube_config, allowing a user to override the config + ``kubernetes.config.load_kube_config``, allowing a user to override the config location. """ def __init__(self, **kwargs) -> None: - """Initialize an Auth class.""" + """ + Initialize an Auth class. + + :param kwargs: + """ config.load_kube_config(**kwargs) self.core = client.CoreV1Api() self._token = None @@ -81,6 +88,8 @@ def _get_secret(self) -> dict: def refresh_token(self) -> None: """ Refresh the authentication token. + + :raises AuthException: if the Kubernetes configuration is invalid. """ del self.token credentials = self._get_secret() diff --git a/libcsm/cli.py b/libcsm/cli.py new file mode 100644 index 0000000..e69de29 diff --git a/libcsm/tests/test_api.py b/libcsm/tests/test_api.py index f4ae041..04083e8 100644 --- a/libcsm/tests/test_api.py +++ b/libcsm/tests/test_api.py @@ -40,7 +40,7 @@ @dataclass() class MockV1Secret: """ - A mock for kubernetes.client.models.v1_secret.V1Secret. + A mock for ``kubernetes.client.models.v1_secret.V1Secret`` """ id = b'foo-client' @@ -62,7 +62,7 @@ class TestApi: def test_object(self, *_) -> None: """ - Verify the Auth object can be created regardless of Kubernetes' state, + Verify the ``Auth`` object can be created regardless of Kubernetes' state, and that the token is not yet set. """ auth = api.Auth() diff --git a/noxfile.py b/noxfile.py index 8b937a7..e865ed1 100644 --- a/noxfile.py +++ b/noxfile.py @@ -51,7 +51,7 @@ if getattr(sys, "frozen", False) and hasattr( sys, "_MEIPASS" - ): # pragma: no cover +): # pragma: no cover project_root = sys._MEIPASS else: prog = __file__ @@ -59,31 +59,30 @@ COVERAGE_FAIL = 85 ERROR_ON_GENERATE = True -locations = "libcsm" -nox.options.sessions = "test", "lint", "cover" +locations = 'libcsm' +nox.options.sessions = 'test', 'docs', 'lint', 'cover' -@nox.session(python="3") +@nox.session(python='3') def test(session): """Default unit test session.""" - # Install all test dependencies, then install this package in-place. - session.install(".[test]") - session.install(".") + session.install('.[test]') + session.install('.') # Run pytest against the tests. session.run( - "pytest", - "--quiet", - "--cov=libcsm", - "--cov-append", - "--cov-report=", - f"--cov-fail-under={COVERAGE_FAIL}", + 'pytest', + '--quiet', + '--cov=libcsm', + '--cov-append', + '--cov-report=', + f'--cov-fail-under={COVERAGE_FAIL}', '.', success_codes=[0, 5], ) -@nox.session(python="3") +@nox.session(python='3') def lint(session): """Run flake8 linter and plugins.""" session.install(".[lint]") @@ -92,16 +91,25 @@ def lint(session): session.run("ruff", "check", "libcsm/") -@nox.session(python="3") +@nox.session(python='3') +def docs(session): + """Run flake8 linter and plugins.""" + session.install('setuptools_scm[toml]') + session.install('.') + session.install('.[docs]') + session.run('make', 'docs') + + +@nox.session(python='3') def cover(session): """Run the final coverage report.""" - session.install(".[test]") - session.install(".") + session.install('.[test]') + session.install('.') session.run( - "coverage", - "report", - "--show-missing", - f"--fail-under={COVERAGE_FAIL}", + 'coverage', + 'report', + '--show-missing', + f'--fail-under={COVERAGE_FAIL}', success_codes=[0, 5] ) - session.run("coverage", "erase") + session.run('coverage', 'erase') diff --git a/pyproject.toml b/pyproject.toml index f8722ad..fed9dd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,6 +61,11 @@ license = { file = 'LICENSE' } ci = [ 'nox~=2023.4.22', ] +docs = [ + 'sphinx~=6.1.3', + 'sphinx-copybutton~=0.5.2', + 'sphinx-autodoc-typehints~=1.23.0', +] lint = [ 'ruff~=0.0.280', ]