From 2a70af76f6963135f3a41057c064f90dcdcb65b2 Mon Sep 17 00:00:00 2001 From: thevickypedia Date: Thu, 10 Aug 2023 14:15:14 -0500 Subject: [PATCH] Get it to a better state --- README.md | 4 +++ changelog.rst | 4 +++ docs/README.html | 6 ++++ docs/_sources/README.md.txt | 4 +++ docs/genindex.html | 6 ++-- docs/index.html | 16 +++++++++- docs/objects.inv | Bin 460 -> 466 bytes docs/searchindex.js | 2 +- gitverse/__init__.py | 2 +- gitverse/releases.py | 60 +++++++++++++++++++++++++++--------- pyproject.toml | 2 +- 11 files changed, 85 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index eb0eab8..7d43002 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ [![GitHub last commit](https://img.shields.io/github/last-commit/thevickypedia/gitverse)](https://api.github.com/repos/thevickypedia/gitverse) # GitVerse +Get release notes or commit history from `GitHub` and format it into `reStructuredText`/`Markdown` files. ### Installation ```shell @@ -25,6 +26,9 @@ Generate release notes from releases tagged in GitHub ```shell gitverse-release ``` +> :bulb: Tries to get release notes, via GitHub API call. +> If failed, uses the commit message as notes for the associated release. +> This feature optionally takes `GIT_TOKEN` as an environment variable if it is generated for a personal repo. Generate commit history from git log #### Commit History diff --git a/changelog.rst b/changelog.rst index a700864..b0fa957 100644 --- a/changelog.rst +++ b/changelog.rst @@ -1,6 +1,10 @@ Commit History ============== +0.3.8 (08/10/2023) +------------------ +- Get it to a better state + 0.3.7 (08/10/2023) ------------------ - Generate release notes based on version tags diff --git a/docs/README.html b/docs/README.html index f50d39f..6fde154 100644 --- a/docs/README.html +++ b/docs/README.html @@ -54,6 +54,7 @@

Navigation

GitHub last commit

GitVerse

+

Get release notes or commit history from GitHub and format it into reStructuredText/Markdown files.

Installation

diff --git a/docs/_sources/README.md.txt b/docs/_sources/README.md.txt index eb0eab8..7d43002 100644 --- a/docs/_sources/README.md.txt +++ b/docs/_sources/README.md.txt @@ -13,6 +13,7 @@ [![GitHub last commit](https://img.shields.io/github/last-commit/thevickypedia/gitverse)](https://api.github.com/repos/thevickypedia/gitverse) # GitVerse +Get release notes or commit history from `GitHub` and format it into `reStructuredText`/`Markdown` files. ### Installation ```shell @@ -25,6 +26,9 @@ Generate release notes from releases tagged in GitHub ```shell gitverse-release ``` +> :bulb: Tries to get release notes, via GitHub API call. +> If failed, uses the commit message as notes for the associated release. +> This feature optionally takes `GIT_TOKEN` as an environment variable if it is generated for a personal repo. Generate commit history from git log #### Commit History diff --git a/docs/genindex.html b/docs/genindex.html index d353073..8080d0c 100644 --- a/docs/genindex.html +++ b/docs/genindex.html @@ -97,12 +97,14 @@

G

  • generator() (in module commits)
  • -
  • get_branches() (in module commits) +
  • get_api_releases() (in module releases)
  • -
  • get_commits() (in module commits) +
  • get_branches() (in module commits)
    • +
    • get_commits() (in module commits) +
    • get_dates() (in module releases)
    • get_gitlog() (in module commits) diff --git a/docs/index.html b/docs/index.html index 628301e..925ce03 100644 --- a/docs/index.html +++ b/docs/index.html @@ -74,6 +74,20 @@

      Welcome to GitVerse’s documentation! +
      +releases.get_api_releases() Dict[str, List[str]]
      +

      Get release notes via git api.

      +
      +
      Returns:
      +

      Returns release notes in the form of release version and description as key-value pairs gathered via GitHub API.

      +
      +
      Return type:
      +

      Dict[str, List[str]]

      +
      +
      +
      +
      releases.get_dates() Dict[str, int]
      @@ -118,7 +132,7 @@

      Welcome to GitVerse’s documentation!
      -releases.run_git_cmd(cmd: str) List[str]
      +releases.run_git_cmd(cmd: str, raw: bool = False) Union[str, List[str]]

      Run the git command.

      Parameters:
      diff --git a/docs/objects.inv b/docs/objects.inv index 27fd2c9bfa3332f6741635df0f04b278f1364658..3b12820368fd76f67d86f1dcc1473de361b1a615 100644 GIT binary patch delta 296 zcmV+@0oVS_1JVPKvw!5hnaLzFUDpCFX}W!_c`Je36QMYKW);@**2mI2k|xZPSqTaZ zMQwWL(kg~RE3yl%C60MvsA3h^c!SMt#R;WAsmnOtv}zsXP_$(UCSochnhlG%v>6z) zHNJ@z>Y^jj4{DT98%-FHKrO`F_=t{I4!KpLX<+MK0uOWAh<`k+8L4qs?i&8e5}QvT zB>Tsevzo6PEeh#yixHEZ*s%9p>CH3GqWd1WV0aDRhu8U+!{gKGKrHe-*Nmh);v)k= zo&~;vv5>e2F^B^wX#uiF$Eb&o{W6)czkC7l4$}RSKu}Maf4;sgab#PALfZFuleoG4 uQ>^LIal>aj`5}?}vcc|#cJ8oplUUdmsA1Jo^fB+e`u#I4A^8P$kJ*}-T$Nh@ delta 290 zcmV+-0p0%61Iz=EvwzHclW|6wu4{poG~K?|yp=%iiBKFqvkGf@>tpF1NfYMDtONyy zqBgyAX%$1E71@Q>634tSRIv(dyus$S;)GJ5)MXrRTD1;xDB7|F6ET$$&4xo<*$j-? z8sEeUb2Qk?BbwN-_gv}Ccb-M}JaEDA8om#&^Dl?Tr_+I0C!Rb otDXGF{k1`MLmNAHSh-0oYzx$|YAO1dcV2z|OiM_90jhV!*~yNPfB*mh diff --git a/docs/searchindex.js b/docs/searchindex.js index 4b118c7..3c4029c 100644 --- a/docs/searchindex.js +++ b/docs/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["README", "index"], "filenames": ["README.md", "index.rst"], "titles": ["GitVerse", "Welcome to GitVerse\u2019s documentation!"], "terms": {"pip": 0, "gener": [0, 1], "from": [0, 1], "github": 0, "git": [0, 1], "log": [0, 1], "debug": [0, 1], "enabl": 0, "mode": 0, "revers": [0, 1], "order": [0, 1], "b": 0, "gather": 0, "specif": 0, "branch": [0, 1], "us": 0, "default": [0, 1], "pass": [0, 1], "onli": 0, "f": 0, "write": [0, 1], "custom": 0, "filenam": [0, 1], "t": 0, "titl": [0, 1], "index": [0, 1], "line": [0, 1], "file": [0, 1], "_": 0, "rst": 0, "changelog": 0, "precommit": 0, "ensur": 0, "doc": 0, "creation": 0, "ar": 0, "run": [0, 1], "everi": 0, "requir": 0, "sphinx": 0, "5": 0, "1": 0, "pre": 0, "2": 0, "20": 0, "0": 0, "recommonmark": 0, "7": 0, "all": [0, 1], "http": 0, "org": 0, "project": 0, "thevickypedia": 0, "io": 0, "vignesh": 0, "sivanandha": 0, "rao": 0, "under": [0, 1], "mit": 0, "instal": 1, "usag": 1, "lint": 1, "pypi": 1, "packag": 1, "licens": 1, "copyright": 1, "releas": 1, "generate_snippet": 1, "list": 1, "str": 1, "snippet": 1, "base": 1, "inform": 1, "return": 1, "readi": 1, "load": 1, "markdown": 1, "type": 1, "get_dat": 1, "dict": 1, "int": 1, "get": 1, "timestamp": 1, "each": 1, "version": 1, "kei": 1, "valu": 1, "pair": 1, "get_releas": 1, "option": 1, "union": 1, "map": 1, "dictionari": 1, "none": 1, "noreturn": 1, "handler": 1, "function": 1, "note": 1, "paramet": 1, "name": 1, "where": 1, "ha": 1, "store": 1, "which": 1, "run_git_cmd": 1, "cmd": 1, "command": 1, "take": 1, "an": 1, "argument": 1, "output": 1, "split": 1, "commit": 1, "gitlog": 1, "trigger": 1, "convers": 1, "process": 1, "written": 1, "get_branch": 1, "avail": 1, "repo": 1, "get_commit": 1, "trunk": 1, "scan": 1, "number": 1, "get_gitlog": 1, "messag": 1, "exclud": 1, "merg": 1, "histori": 1, "msg": 1, "print": 1, "incom": 1, "light": 1, "green": 1, "error": 1, "bright": 1, "red": 1, "info": 1, "warn": 1, "yellow": 1, "util": 1, "get_release_not": 1, "pathlik": 1, "iter": 1, "test": 1, "thi": 1, "modul": 1, "sourc": 1, "particular": 1, "string": 1, "rst2dict": 1, "regular_dict": 1, "bool": 1, "fals": 1, "ordereddict": 1, "convert": 1, "python": 1, "filepath": 1, "boolean": 1, "flag": 1, "regular": 1, "arg": 1, "rst2html": 1, "src": 1, "dst": 1, "html": 1, "destin": 1, "A": 1, "wa": 1, "success": 1, "search": 1, "page": 1}, "objects": {"": [[1, 0, 0, "-", "commits"], [1, 0, 0, "-", "debugger"], [1, 0, 0, "-", "releases"]], "commits": [[1, 1, 1, "", "generator"], [1, 1, 1, "", "get_branches"], [1, 1, 1, "", "get_commits"], [1, 1, 1, "", "get_gitlog"], [1, 1, 1, "", "run"]], "debugger": [[1, 1, 1, "", "debug"], [1, 1, 1, "", "error"], [1, 1, 1, "", "info"], [1, 1, 1, "", "warning"]], "releases": [[1, 1, 1, "", "generate_snippets"], [1, 1, 1, "", "get_dates"], [1, 1, 1, "", "get_releases"], [1, 1, 1, "", "run"], [1, 1, 1, "", "run_git_cmd"]], "utils": [[1, 0, 0, "-", "rst"]], "utils.rst": [[1, 1, 1, "", "get_release_notes"], [1, 1, 1, "", "rst2dict"], [1, 1, 1, "", "rst2html"]]}, "objtypes": {"0": "py:module", "1": "py:function"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"]}, "titleterms": {"gitvers": [0, 1], "instal": 0, "usag": 0, "releas": 0, "note": 0, "tag": 0, "commit": 0, "histori": 0, "option": 0, "flag": 0, "sampl": 0, "lint": 0, "pypi": 0, "packag": 0, "runbook": 0, "licens": 0, "copyright": 0, "welcom": 1, "": 1, "document": 1, "read": 1, "me": 1, "releasenot": 1, "commithistori": 1, "debugg": 1, "rst": 1, "parser": 1, "indic": 1, "tabl": 1}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 56}}) \ No newline at end of file +Search.setIndex({"docnames": ["README", "index"], "filenames": ["README.md", "index.rst"], "titles": ["GitVerse", "Welcome to GitVerse\u2019s documentation!"], "terms": {"get": [0, 1], "from": [0, 1], "github": [0, 1], "format": 0, "restructuredtext": 0, "markdown": [0, 1], "file": [0, 1], "pip": 0, "gener": [0, 1], "bulb": 0, "tri": 0, "via": [0, 1], "api": [0, 1], "call": 0, "If": 0, "fail": 0, "us": 0, "messag": [0, 1], "associ": 0, "thi": [0, 1], "featur": 0, "take": [0, 1], "git_token": 0, "an": [0, 1], "environ": 0, "variabl": 0, "i": 0, "person": 0, "repo": [0, 1], "git": [0, 1], "log": [0, 1], "debug": [0, 1], "enabl": 0, "mode": 0, "revers": [0, 1], "order": [0, 1], "b": 0, "gather": [0, 1], "specif": 0, "branch": [0, 1], "default": [0, 1], "pass": [0, 1], "onli": 0, "f": 0, "write": [0, 1], "custom": 0, "filenam": [0, 1], "t": 0, "titl": [0, 1], "index": [0, 1], "line": [0, 1], "_": 0, "rst": 0, "changelog": 0, "precommit": 0, "ensur": 0, "doc": 0, "creation": 0, "ar": 0, "run": [0, 1], "everi": 0, "requir": 0, "sphinx": 0, "5": 0, "1": 0, "pre": 0, "2": 0, "20": 0, "0": 0, "recommonmark": 0, "7": 0, "all": [0, 1], "http": 0, "org": 0, "project": 0, "thevickypedia": 0, "io": 0, "vignesh": 0, "sivanandha": 0, "rao": 0, "under": [0, 1], "mit": 0, "instal": 1, "usag": 1, "lint": 1, "pypi": 1, "packag": 1, "licens": 1, "copyright": 1, "releas": 1, "generate_snippet": 1, "list": 1, "str": 1, "snippet": 1, "base": 1, "inform": 1, "return": 1, "readi": 1, "load": 1, "type": 1, "get_api_releas": 1, "dict": 1, "note": 1, "form": 1, "version": 1, "descript": 1, "kei": 1, "valu": 1, "pair": 1, "get_dat": 1, "int": 1, "timestamp": 1, "each": 1, "get_releas": 1, "option": 1, "union": 1, "map": 1, "dictionari": 1, "none": 1, "noreturn": 1, "handler": 1, "function": 1, "paramet": 1, "name": 1, "where": 1, "ha": 1, "store": 1, "which": 1, "run_git_cmd": 1, "cmd": 1, "raw": 1, "bool": 1, "fals": 1, "command": 1, "argument": 1, "output": 1, "split": 1, "commit": 1, "gitlog": 1, "trigger": 1, "convers": 1, "process": 1, "written": 1, "get_branch": 1, "avail": 1, "get_commit": 1, "trunk": 1, "scan": 1, "number": 1, "get_gitlog": 1, "exclud": 1, "merg": 1, "histori": 1, "msg": 1, "print": 1, "incom": 1, "light": 1, "green": 1, "error": 1, "bright": 1, "red": 1, "info": 1, "warn": 1, "yellow": 1, "util": 1, "get_release_not": 1, "pathlik": 1, "iter": 1, "test": 1, "modul": 1, "sourc": 1, "particular": 1, "string": 1, "rst2dict": 1, "regular_dict": 1, "ordereddict": 1, "convert": 1, "python": 1, "filepath": 1, "boolean": 1, "flag": 1, "regular": 1, "arg": 1, "rst2html": 1, "src": 1, "dst": 1, "html": 1, "destin": 1, "A": 1, "wa": 1, "success": 1, "search": 1, "page": 1}, "objects": {"": [[1, 0, 0, "-", "commits"], [1, 0, 0, "-", "debugger"], [1, 0, 0, "-", "releases"]], "commits": [[1, 1, 1, "", "generator"], [1, 1, 1, "", "get_branches"], [1, 1, 1, "", "get_commits"], [1, 1, 1, "", "get_gitlog"], [1, 1, 1, "", "run"]], "debugger": [[1, 1, 1, "", "debug"], [1, 1, 1, "", "error"], [1, 1, 1, "", "info"], [1, 1, 1, "", "warning"]], "releases": [[1, 1, 1, "", "generate_snippets"], [1, 1, 1, "", "get_api_releases"], [1, 1, 1, "", "get_dates"], [1, 1, 1, "", "get_releases"], [1, 1, 1, "", "run"], [1, 1, 1, "", "run_git_cmd"]], "utils": [[1, 0, 0, "-", "rst"]], "utils.rst": [[1, 1, 1, "", "get_release_notes"], [1, 1, 1, "", "rst2dict"], [1, 1, 1, "", "rst2html"]]}, "objtypes": {"0": "py:module", "1": "py:function"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"]}, "titleterms": {"gitvers": [0, 1], "instal": 0, "usag": 0, "releas": 0, "note": 0, "tag": 0, "commit": 0, "histori": 0, "option": 0, "flag": 0, "sampl": 0, "lint": 0, "pypi": 0, "packag": 0, "runbook": 0, "licens": 0, "copyright": 0, "welcom": 1, "": 1, "document": 1, "read": 1, "me": 1, "releasenot": 1, "commithistori": 1, "debugg": 1, "rst": 1, "parser": 1, "indic": 1, "tabl": 1}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 56}}) \ No newline at end of file diff --git a/gitverse/__init__.py b/gitverse/__init__.py index 53cefb5..167979a 100644 --- a/gitverse/__init__.py +++ b/gitverse/__init__.py @@ -1 +1 @@ -version = "1.0b" +version = "2.0a" diff --git a/gitverse/releases.py b/gitverse/releases.py index e15e340..0719aea 100644 --- a/gitverse/releases.py +++ b/gitverse/releases.py @@ -1,11 +1,11 @@ import os -import re import subprocess import time from datetime import datetime from typing import Dict, List, NoReturn, Union import click +import requests from gitverse import debugger from gitverse import version as pkg_version @@ -13,7 +13,32 @@ options = {'debug': False, 'reverse': False, 'start': 0.0} -def run_git_cmd(cmd: str) -> List[str]: +def get_api_releases() -> Dict[str, List[str]]: + """Get release notes via git api. + + Returns: + Dict[str, List[str]]: + Returns release notes in the form of release version and description as key-value pairs gathered via GitHub API. + """ + gh_token = os.getenv('GIT_TOKEN') or os.getenv('git_token') + if git_config := run_git_cmd(cmd=r"git config --get remote.origin.url | sed 's/.*\/\([^ ]*\/[^.]*\).*/\1/'", + raw=True): + owner, repo_name = git_config.split('/') + headers = {} + if gh_token: + headers['Authorization'] = f'Bearer {gh_token}' + response = requests.get(f'https://api.github.com/repos/{owner}/{repo_name}/releases', headers=headers) + if response.ok: + try: + return {resp['name']: resp['body'].splitlines() for resp in response.json()} + except requests.JSONDecodeError as error: + if options['debug']: + debugger.error(error) + elif options['debug']: + debugger.error(f"{response.status_code} - {response.text}") + + +def run_git_cmd(cmd: str, raw: bool = False) -> Union[str, List[str]]: """Run the git command. Args: @@ -24,7 +49,10 @@ def run_git_cmd(cmd: str) -> List[str]: Returns the output of the git command split by lines. """ try: - return subprocess.check_output(cmd, shell=True).decode(encoding='UTF-8').strip().splitlines() + output = subprocess.check_output(cmd, shell=True).decode(encoding='UTF-8').strip() + if raw: + return output + return output.splitlines() except (subprocess.CalledProcessError, subprocess.SubprocessError, Exception) as error: if options['debug']: if isinstance(error, subprocess.CalledProcessError): @@ -42,13 +70,9 @@ def get_dates() -> Dict[str, int]: Returns the release version and the timestamp as key-value pairs. """ if dates_values := run_git_cmd( - cmd='git for-each-ref --shell --format="ref=%(refname:short) dt=%(creatordate:format:%s)" "refs/tags/*"' + cmd='git tag --format "%(refname:short) %(creatordate:format:%s)"' ): - version_timestamps = {} - for line in dates_values: - ref, dt = re.search(r"ref='([^']+)'\s+dt='([^']+)'", line).groups() - version_timestamps[ref] = int(dt) - return version_timestamps + return {line.split()[0]: int(line.split()[1]) for line in dates_values} def get_releases() -> Union[List[Dict[str, Union[str, List[str], int, str]]], None]: @@ -72,14 +96,19 @@ def get_releases() -> Union[List[Dict[str, Union[str, List[str], int, str]]], No if tag.split()[0] in dates.keys(): current_version = tag.split()[0] version_updates[current_version] = { - "version": current_version, - "description": [' '.join(tag.split()[1:])], - "timestamp": dates[current_version], - "date": datetime.fromtimestamp(dates[current_version]).strftime("%m/%d/%Y") - } - else: + "version": current_version, + "description": [' '.join(tag.split()[1:])], + "timestamp": dates[current_version], + "date": datetime.fromtimestamp(dates[current_version]).strftime("%m/%d/%Y") + } + elif current_version: version_updates[current_version]['description'].append(tag.strip()) # adds next line to previous desc version_updates = list(version_updates.values()) + # Update release notes for each version, if available via GitHub API + if release_api := get_api_releases(): + for version_update in version_updates: + if api_description := release_api.get(version_update['version']): + version_update['description'] = api_description if options['reverse']: debugger.warning('Converting snippets to reverse order') if options['debug'] else None version_updates = sorted(version_updates, key=lambda x: x['timestamp'], reverse=True) @@ -121,6 +150,7 @@ def run(filename: str, title: str) -> NoReturn: filename: Name of the file that where the release notes has to be stored. title: Title under which the release notes has to be stored. """ + run_git_cmd(cmd="git pull") snippets = generate_snippets() if not snippets: return diff --git a/pyproject.toml b/pyproject.toml index 37301a3..2af399c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ classifiers = [ ] keywords = ["changelog", "automate", "commits", "releases"] requires-python = ">=3.8" -dependencies = ["click"] +dependencies = ["click", "requests"] [tool.setuptools] packages = ["gitverse"]