Explicit, strict and automatic project version management based on semantic versioning.

Overview

Explicit, strict and automatic project version management based on semantic versioning.

Getting started

End users

An end user of the project is a developer who develops a project that needs versioning such as API or libraries.

Semantic versioning

There is the semantic versioning. To make a long story short, it is versioning specification with major, minor and patch numbers telling us what the current version of a project is and how to react on its new versions' updates. Example of the project version following semantic versioning is 1.3.12 where the first digit is major number, the second digit is minor number, and the third digit is patch number.

These are the rules of increasing chose numbers:

  1. Increase major version when you make incompatible API changes.

    Before changes: 1.3.12
    After changes: 2.0.0
  2. Increase minor version when you add functionality in a backwards compatible manner.

    Before changes: 1.3.12
    After changes: 1.4.0
  3. Increase match version when you make backwards compatible bug fixes.

    Before changes: 1.3.12
    After changes: 1.3.13

You have probably seen semantic versioning in your programming language's packages such as JavaScript's axios (e.g. version 0.24.0) or Python requests (e.g. version 2.27.1).

Project version

project version is just a set of principles and automations for developers to maintain their projects. project version requires having a file named .project-version in the root directory containing a project version. With this file, developers declare single source of project version's truth.

If needed, project version must be reused only from the file in. On how to reuse it, check motivation chapter chapter below.

Motivation

There are the following principles and practices project version brings to you:

  1. There may be situations when you deployed the new version of an application but do not have deployment logs, or you deployed the new version of a application but logs tell nothing, or do not have Git information. In all the cases it may be useful to enter your application's runtime and check file .project-version to know the exact version which is related to the codebase.

    $ cat .project-version
    1.3.12
  2. Instead of using Git commit SHA or its short version for Docker images, you can use a project version.

    $ docker build --tag facebook/react:v$(cat .project-version) -f Dockerfile .
  3. Instead of using Git commit SHA or its short version for GitHub release version number, you can use a project version.

    on:
      push:
        branches:
          - master
      
       jobs:
        release:
          runs-on: [ubuntu-latest]
          outputs:
            project_version: ${{ steps.get_project_version.outputs.project_version }}
          steps:
            - uses: actions/[email protected]
            - name: Create Release
              uses: actions/[email protected]
              with:
                tag_name: $(cat .project-version)
                release_name: Release v$(cat .project-version)
  4. Instead of supporting package version (Python package, Gem or JAR) in a dedicated file, you can automatically use a project version. Python package with its setup.py for building packages is illustrated below:

    with open('.project-version', 'r') as project_version_file:
        project_version = project_version_file.read().strip()
    
        setup(
            version=project_version,
            name='project-version',
            ...
        )
  5. In case you manage an infrastructure as a code (e.g. Kubernetes), you may face challenges of supporting multiple major version of your project (e.g. HTTP API). Without automation, you should create new major version configurations manually.

    Let us consider the example where you have API's first version deployment configurations:

    $ ls deployment/
    ├── deployment
    │   ├── v1
    │   │   └── deployment.yaml
    │   │   └── ingress.yaml
    │   │   └── service.yaml
    
    $ cat /deployment/v1/deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      namespace: api-v1

    When it is time to create API's second version, you can simply copy previous version configurations and substitute v1 to v2.

    $ echo .project-version
    2.0.0
    $ export PROJECT_PREVIOUS_MAJOR_VERSION=$(($cat .project-version)-1); echo $PROJECT_MAJOR_VERSION
    1
    $ export PROJECT_MAJOR_VERSION=$(cut -d '.' -f 1 <<< "$(cat .project-version)"); echo $PROJECT_PREVIOUS_MAJOR_VERSION
    2
    $ cp -r deployment/v$PROJECT_PREVIOUS_MAJOR_VERSION deployment/v$PROJECT_MAJOR_VERSION
    $ find deployment/ -type f -exec sed -i \
          's/namespace: v$PROJECT_PREVIOUS_MAJOR_VERSION/namespace: v$PROJECT_MAJOR_VERSION/g' {} +

    After, you automatically get deployment configurations for the new version:

    $ ls deployment/
    ├── deployment
    │   ├── v1
    │   │   └── deployment.yaml
    │   │   └── ingress.yaml
    │   │   └── service.yaml
    │   ├── v2
    │   │   └── deployment.yaml
    │   │   └── ingress.yaml
    │   │   └── service.yaml
    
    $ cat /deployment/v2/deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      namespace: api-v2

Yes, all this approaches requires for a project version always be up-to-date and never corrupted. Luckly, those cases are covered with a set of automation scripts (command line interface) written in Python that helps to manage a project version. Discover them by checking usage chapter below.

Installation

Install using pip3:

$ pip3 install project-version

Usage

This chapter describes a set of automation scripts (command line interface) that help to manage a project version.

Version

Get the version of the package — project-version --version:

$ project-version --version
project-version, version 0.1.0

Help

Get the detailed description of all supported commands by the package — project-version --help:

$ project-version --help
Usage: project-version [OPTIONS] COMMAND [ARGS]...

  Project version command-line interface.

Options:
  --version  Show the version and exit.
  --help     Show this message and exit.

Commands:
  check  Check whether specified project version is increased properly.

Check

Check whether specified project version is increased properly — project-version check.

Parameters:

Argument Type Required Restrictions Description
provider String Yes One of: GitHub. A provider of hosting for software development and version control name.
organization String Yes - The provider's organization name.
repository String Yes - The provider's repository name.
base-branch String Yes - A branch to compare a project version with. Usually, a default branch.
head-branch String Yes - A branch to get its project version for comparison. Usually, a feature branch.
access-token String Yes - The provider's API access token.

Example of usage:

$ project-version check \
    --provider=GitHub \
    --organization=facebook \
    --repository=react \
    --base-branch=master \
    --head-branch=map-children-components \ 
    --access-token=ghp_0TI5LBBLNyKlT5Lv8eR6EIOB0hkopMqz5LWjNyKlZ1

Examples

Example of checking a project version on a pull request workflow:

---
name: Pull request workflow

on:
  pull_request_target:
    branches:
      - master

jobs:
  check-project-version:
    runs-on: [ubuntu-latest]
    steps:
      - uses: actions/[email protected]
      - name: Install project version
        run: pip3 install project-version
      - name: Check a project version
        run: |
          project-version check \
              --provider=GitHub \
              --organization=facebook \
              --repository=react \
              --base-branch=master \
              --head-branch=map-children-components \ 
              --access-token=${{ secrets.GIT_HUB_ACCESS_TOKEN }}

Example of bumping a project version on a pull request workflow:

---
name: Pull request workflow

on:
  pull_request_target:
    branches:
      - master

jobs:
  check-project-version:
    runs-on: [ubuntu-latest]
    steps:
      - uses: actions/[email protected]
      - name: Install project version
        run: pip3 install project-version
      - name: Bump project version if it is non-human pull request
        if: ${{ github.actor == 'dependabot[bot]' || github.actor == 'facebook-bot' }}
        run: |
          project-version bump \
              --provider=GitHub \
              --organization=facebook \
              --repository=react \
              --base-branch=master \
              --head-branch=map-children-components \ 
              --access-token=${{ secrets.GIT_HUB_ACCESS_TOKEN }}

Example of making a release based on a project version:

---
name: Master workflow

on:
  push:
    branches:
      - master

jobs:
  release:
    runs-on: [ubuntu-latest]
    outputs:
      project_version: ${{ steps.get_project_version.outputs.project_version }}
    steps:
      - uses: actions/[email protected]
      - name: Install project version
        run: pip3 install project-version
      - name: Get a version of the project
        id: get_project_version
        run: echo "::set-output name=project_version::$(cat .project-version)"
      - name: Release
        run: |
          project-version release \
              --provider=GitHub \
              --organization=facebook \
              --repository=react \
              --branch=master \
              --version=${{ steps.get_project_version.outputs.project_version }}

Contributing

Clone the project and install requirements:

$ git clone [email protected]:dmytrostriletskyi/accessify.git && cd accessify
$ make install-requirements

After changes, ensure the code quality remains the same:

$ make check-requirements-safety
$ make check-code-complexity
$ make check-code-quality
$ make check-yaml-standards

If you are new for the contribution, please read:

You might also like...
Project documentation with Markdown.

MkDocs Project documentation with Markdown. View the MkDocs documentation. Project release notes. Visit the MkDocs wiki for community resources, inclu

Your Project with Great Documentation.
Your Project with Great Documentation.

Read Latest Documentation - Browse GitHub Code Repository The only thing worse than documentation never written, is documentation written but never di

The project that powers MDN.

Kuma Kuma is the platform that powers MDN (developer.mozilla.org) Development Code: https://github.com/mdn/kuma Issues: P1 Bugs (to be fixed ASAP) P2

Software engineering course project. Secondhand trading system.

PigeonSale Software engineering course project. Secondhand trading system. Documentation API doumenatation: list of APIs Backend documentation: notes

Project created to help beginner programmers to study, despite the lack of internet!
Project created to help beginner programmers to study, despite the lack of internet!

Project created to help beginner programmers to study, despite the lack of internet!

Portfolio project for Code Institute Full Stack software development course.
Portfolio project for Code Institute Full Stack software development course.

Comic Sales tracker This project is the third milestone project for the Code Institute Diploma in Full Stack Software Development. You can see the fin

This is a small project written to help build documentation for projects in less time.

Documentation-Builder This is a small project written to help build documentation for projects in less time. About This project builds documentation f

freeCodeCamp Scientific Computing with Python Project for Certification.

Polygon_Area_Calculator freeCodeCamp Python Project freeCodeCamp Scientific Computing with Python Project for Certification. In this project you will

Python-samples - This project is to help someone need some practices when learning python language

Python-samples - This project is to help someone need some practices when learning python language

Comments
  • Bump click from 7.1.2 to 8.0.3

    Bump click from 7.1.2 to 8.0.3

    Bumps click from 7.1.2 to 8.0.3.

    Release notes

    Sourced from click's releases.

    8.0.3

    8.0.2

    8.0.1

    8.0.0

    New major versions of all the core Pallets libraries, including Click 8.0, have been released! :tada:

    This represents a significant amount of work, and there are quite a few changes. Be sure to carefully read the changelog, and use tools such as pip-compile and Dependabot to pin your dependencies and control your updates.

    8.0.0rc1

    8.0.0a1

    Changelog

    Sourced from click's changelog.

    Version 8.0.3

    Released 2021-10-10

    • Fix issue with Path(resolve_path=True) type creating invalid paths. :issue:2088
    • Importing readline does not cause the confirm() prompt to disappear when pressing backspace. :issue:2092
    • Any default values injected by invoke() are cast to the corresponding parameter's type. :issue:2089, 2090

    Version 8.0.2

    Released 2021-10-08

    • is_bool_flag is not set to True if is_flag is False. :issue:1925
    • Bash version detection is locale independent. :issue:1940
    • Empty default value is not shown for multiple=True. :issue:1969
    • Fix shell completion for arguments that start with a forward slash such as absolute file paths. :issue:1929
    • Path type with resolve_path=True resolves relative symlinks to be relative to the containing directory. :issue:1921
    • Completion does not skip Python's resource cleanup when exiting, avoiding some unexpected warning output. :issue:1738, 2017
    • Fix type annotation for type argument in prompt function. :issue:2062
    • Fix overline and italic styles, which were incorrectly added when adding underline. :pr:2058
    • An option with count=True will not show "[x>=0]" in help text. :issue:2072
    • Default values are not cast to the parameter type twice during processing. :issue:2085
    • Options with multiple and flag_value use the flag value instead of leaving an internal placeholder. :issue:2001

    Version 8.0.1

    Released 2021-05-19

    • Mark top-level names as exported so type checking understand imports in user projects. :issue:1879
    • Annotate Context.obj as Any so type checking allows all operations on the arbitrary object. :issue:1885

    ... (truncated)

    Commits
    • 41f5b7a Merge pull request #2096 from pallets/release-8.0.3
    • 90fb9f5 release version 8.0.3
    • ba0e9dd Merge pull request #2095 from pallets/invoke-cast-default
    • 662a30e invoke type casts default values
    • 3dde6c5 Merge pull request #2093 from alex-ball/patch-1
    • f31d564 click.confirm preserves prompt when readline is imported
    • 3737511 Merge pull request #2094 from pallets/path-resolve-symlink
    • c8ca29b use pathlib to resolve symlinks
    • 96146c9 Merge pull request #2087 from pallets/release-8.0.2
    • a14e7b0 release version 8.0.2
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 4
  • Bump pygithub from 1.54.1 to 1.55

    Bump pygithub from 1.54.1 to 1.55

    Bumps pygithub from 1.54.1 to 1.55.

    Release notes

    Sourced from pygithub's releases.

    v1.55

    Breaking Changes

    • Remove client_id/client_secret authentication (#1888) (901af8c8)
    • Adjust to Github API changes regarding emails (#1890) (2c77cfad)
      • This impacts what AuthenticatedUser.get_emails() returns
    • PublicKey.key_id could be int on Github Enterprise (#1894) (ad124ef4)
    • Export headers in GithubException (#1887) (ddd437a7)

    Bug Fixes & Improvements

    • Do not import from unpackaged paths in typing (#1926) (27ba7838)
    • Implement hash for CompletableGithubObject (#1922) (4faff23c)
    • Use property decorator to improve typing compatibility (#1925) (e4168109)
    • Fix :rtype: directive (#1927) (54b6a97b)
    • Update most URLs to docs.github.com (#1896) (babcbcd0)
    • Tighten asserts for new Permission tests (#1893) (5aab6f5d)
    • Adding attributes "maintain" and "triage" to class "Permissions" (#1810) (76879613)
    • Add default arguments to Workflow method type annotations (#1857) (7d6bac9e)
    • Re-raise the exception when failing to parse JSON (#1892) (916da53b)
    • Allow adding attributes at the end of the list (#1807) (0245b758)
    • Updating links to Github documentation for deploy keys (#1850) (c27fb919)
    • Update PyJWT Version to 2.0+ (#1891) (a68577b7)
    • Use right variable in both get_check_runs() (#1889) (3003e065)
    • fix bad assertions in github.Project.edit (#1817) (6bae9e5c)
    • Test repr() for PublicKey (#1879) (e0acd8f4)
    • Add support for deleting repository secrets (#1868) (696793de)
    • Switch repository secrets to using f-strings (#1867) (aa240304)
    • Manually fixing paths for codecov.io to cover all project files (#1813) (b2232c89)
    • Add missing links to project metadata (#1789) (64f532ae)
    • No longer show username and password examples (#1866) (55d98373)
    • Adding github actions secrets (#1681) (c90c050e)
    • fix get_user_issues (#1842) (7db1b0c9)
    • Switch all string addition to using f-strings (#1774) (290b6272)
    • Enabling connetion pool_size definition (a77d4f48)
    • Always define the session adapter (aaec0a0f)
    Changelog

    Sourced from pygithub's changelog.

    Version 1.55 (April 26, 2021)

    Breaking Changes

    • Remove client_id/client_secret authentication (#1888) (901af8c8)
    • Adjust to Github API changes regarding emails (#1890) (2c77cfad)
      • This impacts what AuthenticatedUser.get_emails() returns
    • PublicKey.key_id could be int on Github Enterprise (#1894) (ad124ef4)
    • Export headers in GithubException (#1887) (ddd437a7)

    Bug Fixes & Improvements

    • Do not import from unpackaged paths in typing (#1926) (27ba7838)
    • Implement hash for CompletableGithubObject (#1922) (4faff23c)
    • Use property decorator to improve typing compatibility (#1925) (e4168109)
    • Fix :rtype: directive (#1927) (54b6a97b)
    • Update most URLs to docs.github.com (#1896) (babcbcd0)
    • Tighten asserts for new Permission tests (#1893) (5aab6f5d)
    • Adding attributes "maintain" and "triage" to class "Permissions" (#1810) (76879613)
    • Add default arguments to Workflow method type annotations (#1857) (7d6bac9e)
    • Re-raise the exception when failing to parse JSON (#1892) (916da53b)
    • Allow adding attributes at the end of the list (#1807) (0245b758)
    • Updating links to Github documentation for deploy keys (#1850) (c27fb919)
    • Update PyJWT Version to 2.0+ (#1891) (a68577b7)
    • Use right variable in both get_check_runs() (#1889) (3003e065)
    • fix bad assertions in github.Project.edit (#1817) (6bae9e5c)
    • Test repr() for PublicKey (#1879) (e0acd8f4)
    • Add support for deleting repository secrets (#1868) (696793de)
    • Switch repository secrets to using f-strings (#1867) (aa240304)
    • Manually fixing paths for codecov.io to cover all project files (#1813) (b2232c89)
    • Add missing links to project metadata (#1789) (64f532ae)
    • No longer show username and password examples (#1866) (55d98373)
    • Adding github actions secrets (#1681) (c90c050e)
    • fix get_user_issues (#1842) (7db1b0c9)
    • Switch all string addition to using f-strings (#1774) (290b6272)
    • Enabling connection pool_size definition (a77d4f48)
    • Always define the session adapter (aaec0a0f)
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 1
  • Provide offline mode

    Provide offline mode

    Motivation

    All the commands in the project requires a provider's API key, hence do they job though HTTP calls. Almost all those calls are just to fetch a project version from a particular branch. Probably, some commands can use local .git folder to fetch needed information.

    opened by dmytrostriletskyi 0
Releases(v0.7.2)
Owner
Dmytro Striletskyi
Senior Software Engineer at Rocket
Dmytro Striletskyi
Pyoccur - Python package to operate on occurrences (duplicates) of elements in lists

pyoccur Python Occurrence Operations on Lists About Package A simple python package with 3 functions has_dup() get_dup() remove_dup() Currently the du

Ahamed Musthafa 6 Jan 07, 2023
Mayan EDMS is a document management system.

Mayan EDMS is a document management system. Its main purpose is to store, introspect, and categorize files, with a strong emphasis on preserving the contextual and business information of documents.

3 Oct 02, 2021
Swagger UI is a collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.

Introduction Swagger UI allows anyone — be it your development team or your end consumers — to visualize and interact with the API’s resources without

Swagger 23.2k Dec 29, 2022
✨ Real-life Data Analysis and Model Training Workshop by Global AI Hub.

🎓 Data Analysis and Model Training Course by Global AI Hub Syllabus: Day 1 What is Data? Multimedia Structured and Unstructured Data Data Types Data

Global AI Hub 71 Oct 28, 2022
A Json Schema Generator

JSON Schema Generator Author : Eru Michael About A Json Schema Generator. This is a generic program that: Reads a JSON file similar to what's present

1 Nov 10, 2021
Data Inspector is an open-source python library that brings 15++ types of different functions to make EDA, data cleaning easier.

Data Inspector Data Inspector is an open-source python library that brings 15 types of different functions to make EDA, data cleaning easier. Author:

Kazi Amit Hasan 38 Nov 24, 2022
Data science Python notebooks: Deep learning (TensorFlow, Theano, Caffe, Keras), scikit-learn, Kaggle, big data (Spark, Hadoop MapReduce, HDFS), matplotlib, pandas, NumPy, SciPy, Python essentials, AWS, and various command lines.

Data science Python notebooks: Deep learning (TensorFlow, Theano, Caffe, Keras), scikit-learn, Kaggle, big data (Spark, Hadoop MapReduce, HDFS), matplotlib, pandas, NumPy, SciPy, Python essentials, A

Donne Martin 24.5k Jan 09, 2023
An introduction course for Python provided by VetsInTech

Introduction to Python This is an introduction course for Python provided by VetsInTech. For every "boot camp", there usually is a pre-req, but becaus

Vets In Tech 2 Dec 02, 2021
A collection and example code of every topic you need to know about in the basics of Python.

The Python Beginners Guide: Master The Python Basics Tonight This guide is a collection of every topic you need to know about in the basics of Python.

Ahmed Baari 1 Dec 19, 2021
An ongoing curated list of OS X best applications, libraries, frameworks and tools to help developers set up their macOS Laptop.

macOS Development Setup Welcome to MacOS Local Development & Setup. An ongoing curated list of OS X best applications, libraries, frameworks and tools

Paul Veillard 3 Apr 03, 2022
The purpose of this project is to share knowledge on how awesome Streamlit is and can be

Awesome Streamlit The fastest way to build Awesome Tools and Apps! Powered by Python! The purpose of this project is to share knowledge on how Awesome

Marc Skov Madsen 1.5k Jan 07, 2023
Generate a backend and frontend stack using Python and json-ld, including interactive API documentation.

d4 - Base Project Generator Generate a backend and frontend stack using Python and json-ld, including interactive API documentation. d4? What is d4 fo

Markus Leist 3 May 03, 2022
A repository of links with advice related to grad school applications, research, phd etc

A repository of links with advice related to grad school applications, research, phd etc

Shaily Bhatt 946 Dec 30, 2022
Make posters from Markdown files.

MkPosters Create posters using Markdown. Supports icons, admonitions, and LaTeX mathematics. At the moment it is restricted to the specific layout of

Patrick Kidger 243 Dec 20, 2022
The project that powers MDN.

Kuma Kuma is the platform that powers MDN (developer.mozilla.org) Development Code: https://github.com/mdn/kuma Issues: P1 Bugs (to be fixed ASAP) P2

MDN Web Docs 1.9k Dec 26, 2022
Members: Thomas Longuevergne Program: Network Security Course: 1DV501 Date of submission: 2021-11-02

Mini-project report Members: Thomas Longuevergne Program: Network Security Course: 1DV501 Date of submission: 2021-11-02 Introduction This project was

1 Nov 08, 2021
Course Materials for Math 340

UBC Math 340 Materials This repository aims to be the one repository for which you can find everything you about Math 340. Lecture Notes Lecture Notes

2 Nov 25, 2021
A Sublime Text plugin to select a default syntax dialect

Default Syntax Chooser This Sublime Text 4 plugin provides the set_default_syntax_dialect command. This command manipulates a syntax file (e.g.: SQL.s

3 Jan 14, 2022
Code and pre-trained models for "ReasonBert: Pre-trained to Reason with Distant Supervision", EMNLP'2021

ReasonBERT Code and pre-trained models for ReasonBert: Pre-trained to Reason with Distant Supervision, EMNLP'2021 Pretrained Models The pretrained mod

SunLab-OSU 29 Dec 19, 2022
A clean customizable documentation theme for Sphinx

A clean customizable documentation theme for Sphinx

Pradyun Gedam 1.5k Jan 06, 2023