Repository: ryancheley/the-well-maintained-test (language: python)

Issue:
Add details about questions
**Is your feature request related to a problem? Please describe.**
Listing out the questions is fine, but I'd like to see what Adam wrote about the importance of the questions

**Describe the solution you'd like**
Update the CLI to include Adam's description from his blog post

**Describe alternatives you've considered**
None

**Additional context**
None



Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 88ebad9..ef8d084 100644
--- a/README.md
+++ b/README.md
@@ -33,35 +33,51 @@ This will create a file called auth.json in your current directory containing th
 
     Usage: the-well-maintained-test [OPTIONS] COMMAND [ARGS]...
 
-    Programatically tries to answer the 12 questions from Adam Johnson's 
-    blog post https://adamj.eu/tech/2021/11/04/the-well-maintained-test/ URL is
-    a url to a github repository you'd like to check, for example:     the-well-
-    maintained-test 'https://github.com/ryancheley/the-well-maintained-test'
+    Programatically tries to answer the 12 questions from Adam Johnson's blog
+    post https://adamj.eu/tech/2021/11/04/the-well-maintained-test/ URL is a url
+    to a github repository you'd like to check, for example:
+
+        the-well-maintained-test url 'https://github.com/ryancheley/the-well-
+        maintained-test'
+
+    package is a package on pypi you'd like to check:
+
+        the-well-maintained-test package --name the-well-maintained-test
+
+    Note: URL is being deprecated and replaced with package starting in v0.9.0
 
     Options:
     --version  Show the version and exit.
     --help     Show this message and exit.
 
     Commands:
-    auth            Save authentication credentials to a JSON file
-    questions       List of questions tested
-    requirements    Loop over a requirements.txt file
-    url             url to a github repository you'd like to check
-
-
-    URL is a url to a github repository you'd like to check, for example:
-
-        the-well-maintained-test url 'https://github.com/ryancheley/the-well-maintained-test'
+    auth          Save authentication credentials to a JSON file
+    check         Check your GitHub API Usage Stats.
+    package       Name of a package on PyPi you'd like to check
+    questions     List of questions tested
+    requirements  Loop over a requirements.txt file
+    url           URL to a github repository you'd like to check.
 
 If you want to see what questions will be answered before running you you can pass 
 
     the-well-maintained-test questions
 
-If you want to see a single question
+If you want to see a single question and the original source from Adam Johnson's blog
 
     the-well-maintained-test questions -q 3
 
 
+    3. Is there a changelog?
+
+        A changelog, or a release notes page, is vital for our ability to update the package. The changelog is the main place for communication of breaking changes. (A case for changelogs is made at keepachangelog.com.)
+
+        Changelogs come in many forms: a single file, a documentation section, GitHub release descriptions, etc. Again, hopefully the package doesn’t make you hunt for it. 
+
+        Note that some projects “have a changelog”, but it has stopped being maintained since the project’s inception. So check that the changelog covers recent releases.
+
+    See https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#is-there-a-changelog for the original source.
+
+
 ## Development
 
 To contribute to this tool, first checkout the code. Then create a new virtual environment:
diff --git a/justfile b/justfile
index 3e9e175..54ffa82 100644
--- a/justfile
+++ b/justfile
@@ -14,7 +14,7 @@ coverage:
 
 # prunes remote branches from github
 prune:
-    git remote prune github
+    git remote prune origin
 
 # removes all but main and dev local branch
 gitclean:


Test patch:
diff --git a/src/the_well_maintained_test/cli.py b/src/the_well_maintained_test/cli.py
index a905804..46cbb08 100644
--- a/src/the_well_maintained_test/cli.py
+++ b/src/the_well_maintained_test/cli.py
@@ -1,4 +1,5 @@
 import json
+import time
 from os import system
 from pathlib import Path
 from urllib.parse import urlparse
@@ -6,6 +7,7 @@
 import click
 import pkg_resources
 import requests
+import toml
 from rich.console import Console
 from rich.padding import Padding
 from rich.prompt import Prompt
@@ -35,6 +37,8 @@
 answer_padding_style = (1, 0, 1, 4)
 special_answer_padding_style = (0, 0, 0, 4)
 warning_style = "bold red"
+answer_link_style = "white"
+answer_link_padding_style = (0, 0, 0, 4)
 
 try:  # pragma: no cover
     with open("auth.json") as f:
@@ -50,10 +54,18 @@
 @click.version_option()
 def cli():  # pragma: no cover
     """
-    Programatically tries to answer the 12 questions from \
-        Adam Johnson's blog post https://adamj.eu/tech/2021/11/04/the-well-maintained-test/
+    Programatically tries to answer the 12 questions from Adam Johnson's
+    blog post https://adamj.eu/tech/2021/11/04/the-well-maintained-test/
     URL is a url to a github repository you'd like to check, for example:
-        the-well-maintained-test 'https://github.com/ryancheley/the-well-maintained-test'
+
+        the-well-maintained-test url 'https://github.com/ryancheley/the-well-maintained-test'
+
+    package is a package on pypi you'd like to check:
+
+        the-well-maintained-test package --name the-well-maintained-test
+
+    Note: URL is being deprecated and replaced with package starting in v0.9.0
+
     """
     pass
 
@@ -104,12 +116,12 @@ def auth(auth: str) -> None:  # pragma: no cover
     help="Show progress on test check",
 )
 def url(url: str, branch: str, progress: bool, output: str) -> None:  # pragma: no cover
-    "url to a github repository you'd like to check"
+    "URL to a github repository you'd like to check. This method will be deprecated in v0.9.0"
     if url[-1] == "/":
         url = url.strip("/")
 
-    with open(Path(pkg_resources.resource_filename(__name__, str(Path("data").joinpath("questions.json"))))) as file:
-        questions = json.load(file)
+    with open(Path(pkg_resources.resource_filename(__name__, str(Path("data").joinpath("questions.toml"))))) as file:
+        questions = toml.load(file)
 
     parse_object = urlparse(url)
     author = parse_object.path.split("/")[-2]
@@ -138,40 +150,57 @@ def url(url: str, branch: str, progress: bool, output: str) -> None:  # pragma:
         )
         console.rule()
 
-    console.print(questions.get("1"), style=question_style)
+    console.rule()
+
+    console.print(
+        Padding(
+            """
+            This method is going to be deprecated in v0.9.0.
+            Starting in v0.9.0 it will be an optional.
+            Please use --name instead
+            """,
+            answer_padding_style,
+            style=warning_style,
+        )
+    )
+
+    console.rule()
+    time.sleep(3)
+
+    console.print(questions.get("question").get("1").get("question_text"), style=question_style)
     console.print(Padding(production_ready_check(pypi_url), answer_padding_style, style=answer_style))
 
-    console.print(questions.get("2"), style=question_style)
+    console.print(questions.get("question").get("2").get("question_text"), style=question_style)
     console.print(Padding(documentation_exists(pypi_url), answer_padding_style, style=answer_style))
 
-    console.print(questions.get("3"), style=question_style)
+    console.print(questions.get("question").get("3").get("question_text"), style=question_style)
     console.print(Padding(change_log_check(changelog, release), answer_padding_style, style=answer_style))
 
-    console.print(questions.get("4"), style=question_style)
+    console.print(questions.get("question").get("4").get("question_text"), style=question_style)
     console.print(Padding(bug_responding(bugs_url, headers), answer_padding_style, style=answer_style))
 
-    console.print(questions.get("5"), style=question_style)
+    console.print(questions.get("question").get("5").get("question_text"), style=question_style)
     console.print(Padding(check_tests(tree_url, headers, progress), special_answer_padding_style, style=answer_style))
 
-    console.print(questions.get("6"), style=question_style)
+    console.print(questions.get("question").get("6").get("question_text"), style=question_style)
     console.print(Padding(language_check(pypi_url), answer_padding_style, style=answer_style))
 
-    console.print(questions.get("7"), style=question_style)
+    console.print(questions.get("question").get("7").get("question_text"), style=question_style)
     console.print(Padding(framework_check(pypi_url), answer_padding_style, style=answer_style))
 
-    console.print(questions.get("8"), style=question_style)
+    console.print(questions.get("question").get("8").get("question_text"), style=question_style)
     console.print(Padding(ci_setup(workflows_url, headers), answer_padding_style, style=answer_style))
 
-    console.print(questions.get("9"), style=question_style)
+    console.print(questions.get("question").get("9").get("question_text"), style=question_style)
     console.print(Padding(ci_passing(ci_status_url, headers), answer_padding_style, style=answer_style))
 
-    console.print(questions.get("10"), style=question_style)
+    console.print(questions.get("question").get("10").get("question_text"), style=question_style)
     console.print(Padding(well_used(api_url, headers), answer_padding_style, style=answer_style))
 
-    console.print(questions.get("11"), style=question_style)
+    console.print(questions.get("question").get("11").get("question_text"), style=question_style)
     console.print(Padding(commit_in_last_year(commits_url, headers), answer_padding_style, style=answer_style))
 
-    console.print(questions.get("12"), style=question_style)
+    console.print(questions.get("question").get("12").get("question_text"), style=question_style)
     console.print(Padding(release_in_last_year(pypi_url), answer_padding_style, style=answer_style))
 
     if output == "html":
@@ -182,23 +211,39 @@ def url(url: str, branch: str, progress: bool, output: str) -> None:  # pragma:
 
 
 @cli.command()
+@click.option(
+    "-n",
+    "--name",
+    type=click.STRING,
+    help="Pass the name of the package to check",
+)
 @click.option(
     "-q",
     "--question",
-    type=click.STRING,
+    type=click.Choice(["all", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]),
     default="all",
     help="List of questions that are tested",
 )
-def questions(question: str) -> None:  # pragma: no cover
+def questions(name: str, question: str) -> None:  # pragma: no cover
     "List of questions tested"
-    with open(Path(pkg_resources.resource_filename(__name__, str(Path("data").joinpath("questions.json"))))) as file:
-        questions = json.load(file)
+    with open(Path(pkg_resources.resource_filename(__name__, str(Path("data").joinpath("questions.toml"))))) as file:
+        questions = toml.load(file)
 
     if question != "all":
-        console.print(questions.get(question), style=question_style)
+        console.print(questions.get("question").get(question).get("question_text"), style=question_style)
+        console.print(
+            Padding(questions.get("question").get(question).get("question_description"), answer_padding_style, style=answer_style)
+        )
+        question_link_verbiage = f'See {questions.get("question").get(question).get("question_link")} for the original source.'
+        console.print(question_link_verbiage, style=answer_link_style)
+        if name:
+            question_function = (
+                f"[bold green]function_name[/bold green]: {questions.get('question').get(question).get('question_function')}"
+            )
+            console.print(Padding(question_function, answer_padding_style, style=question_style + " italic"))
     else:
-        for _, v in questions.items():
-            console.print(v, style=question_style)
+        for _, v in questions.get("question").items():
+            console.print(v.get("question_text"), style=question_style)
 
 
 @cli.command()
@@ -246,3 +291,120 @@ def check(resource):  # pragma: no cover
     """
     message = get_github_api_rate_limits(headers, resource)
     console.print(Padding(message, answer_padding_style, style=answer_style))
+
+
+@cli.command()
+@click.option(
+    "-n",
+    "--name",
+    type=click.STRING,
+    help="Show progress on test check",
+)
+@click.option(
+    "-b",
+    "--branch",
+    type=click.STRING,
+    help="Branch to check",
+)
+@click.option(
+    "-p",
+    "--progress",
+    type=click.BOOL,
+    default=True,
+    help="Show progress on test check",
+)
+@click.option(
+    "-o",
+    "--output",
+    type=click.Choice(["html", "txt"]),
+    help="Show progress on test check",
+)
+def package(name: str, branch: str, progress: bool, output: str) -> None:  # pragma: no cover
+    """Name of a package on PyPi you'd like to check
+
+    Args:
+        name (str): [description]
+        branch (str): [description]
+        progress (bool): [description]
+        output (str): [description]
+    """
+    pypi_url = f"https://pypi.org/pypi/{name}/json"
+    project_urls = requests.get(pypi_url).json().get("info").get("project_urls")
+    for _, v in project_urls.items():
+        if urlparse(v).netloc == "github.com" and len(urlparse(v).path.split("/")) == 3:
+            url = v
+
+    "url to a github repository you'd like to check"
+    if url[-1] == "/":
+        url = url.strip("/")
+
+    with open(Path(pkg_resources.resource_filename(__name__, str(Path("data").joinpath("questions.toml"))))) as file:
+        questions = toml.load(file)
+
+    parse_object = urlparse(url)
+    author = parse_object.path.split("/")[-2]
+    package = parse_object.path.split("/")[-1]
+    api_url = f"https://api.github.com/repos/{author}/{package}"
+    if not branch:
+        default_branch = requests.get(api_url).json().get("default_branch")
+    else:
+        default_branch = branch
+    changelog_url = f"https://raw.githubusercontent.com/{author}/{package}/{default_branch}/CHANGELOG.md"
+    releases_url = f"https://www.github.com/{author}/{package}/releases"
+    commits_url = f"https://api.github.com/repos/{author}/{package}/commits/{default_branch}"
+    workflows_url = f"https://api.github.com/repos/{author}/{package}/actions/workflows"
+    ci_status_url = f"https://api.github.com/repos/{author}/{package}/actions/runs"
+    bugs_url = f"https://api.github.com/repos/{author}/{package}/issues?labels=bug"
+    changelog = requests.get(changelog_url, headers=headers)
+    release = requests.get(releases_url, headers=headers)
+    tree_url = f"https://api.github.com/repos/{author}/{package}/git/trees/{default_branch}?recursive=1"
+
+    vulnerabilities = get_vulnerabilities(pypi_url)
+    if vulnerabilities > 0:
+        console.rule("[bold red]Vulnerabilities detected!!!")
+        console.print(
+            Padding(f"There are {vulnerabilities} vulnerabilities in this package", answer_padding_style, style=warning_style)
+        )
+        console.rule()
+
+    console.print(questions.get("question").get("1").get("question_text"), style=question_style)
+    console.print(Padding(production_ready_check(pypi_url), answer_padding_style, style=answer_style))
+
+    console.print(questions.get("question").get("2").get("question_text"), style=question_style)
+    console.print(Padding(documentation_exists(pypi_url), answer_padding_style, style=answer_style))
+
+    console.print(questions.get("question").get("3").get("question_text"), style=question_style)
+    console.print(Padding(change_log_check(changelog, release), answer_padding_style, style=answer_style))
+
+    console.print(questions.get("question").get("4").get("question_text"), style=question_style)
+    console.print(Padding(bug_responding(bugs_url, headers), answer_padding_style, style=answer_style))
+
+    console.print(questions.get("question").get("5").get("question_text"), style=question_style)
+    console.print(Padding(check_tests(tree_url, headers, progress), special_answer_padding_style, style=answer_style))
+
+    console.print(questions.get("question").get("6").get("question_text"), style=question_style)
+    console.print(Padding(language_check(pypi_url), answer_padding_style, style=answer_style))
+
+    console.print(questions.get("question").get("7").get("question_text"), style=question_style)
+    console.print(Padding(framework_check(pypi_url), answer_padding_style, style=answer_style))
+
+    console.print(questions.get("question").get("8").get("question_text"), style=question_style)
+    console.print(Padding(ci_setup(workflows_url, headers), answer_padding_style, style=answer_style))
+
+    console.print(questions.get("question").get("9").get("question_text"), style=question_style)
+    console.print(Padding(ci_passing(ci_status_url, headers), answer_padding_style, style=answer_style))
+
+    console.print(questions.get("question").get("10").get("question_text"), style=question_style)
+    console.print(Padding(well_used(api_url, headers), answer_padding_style, style=answer_style))
+
+    console.print(questions.get("question").get("11").get("question_text"), style=question_style)
+    console.print(Padding(commit_in_last_year(commits_url, headers), answer_padding_style, style=answer_style))
+
+    console.print(questions.get("question").get("12").get("question_text"), style=question_style)
+    console.print(Padding(release_in_last_year(pypi_url), answer_padding_style, style=answer_style))
+
+    if output == "html":
+        console.save_html("output.html")
+
+    if output == "txt":
+        console.save_text("output.txt")
diff --git a/src/the_well_maintained_test/data/questions.toml b/src/the_well_maintained_test/data/questions.toml
new file mode 100644
index 0000000..d2f3312
--- /dev/null
+++ b/src/the_well_maintained_test/data/questions.toml
@@ -0,0 +1,119 @@
+[question]
+[question.1]
+question_text = "1. Is it described as “production ready”?"
+question_description = """
+We want to see evidence that the maintainers consider the software as ready for use in production.
+
+The documentation shouldn’t have any banners or wording implying a future stable release.
+
+The version number should not be a pre-release, alpha, beta, release candidate, etc. Note that some maintainers stick with a “zero version number” like 0.4.0, even when they consider the package production ready.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#is-it-described-as-production-ready"
+question_function = "production_ready_check"
+[question.2]
+question_text = "2. Is there sufficient documentation?"
+question_description = """
+If we can’t find information on what the package currently does, it seems doubtful the future will be easy.
+
+“Sufficient” varies based upon: the scope of the library, the ecosystem, and your preferences.
+
+Documentation comes in many forms: a README file, a documentation site, a wiki, blog posts, etc. Hopefully the package doesn’t make you hunt for it.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#is-there-sufficient-documentation"
+question_function = "documentation_exists"
+[question.3]
+question_text = "3. Is there a changelog?"
+question_description = """
+A changelog, or a release notes page, is vital for our ability to update the package. The changelog is the main place for communication of breaking changes. (A case for changelogs is made at keepachangelog.com.)
+
+Changelogs come in many forms: a single file, a documentation section, GitHub release descriptions, etc. Again, hopefully the package doesn’t make you hunt for it.
+
+Note that some projects “have a changelog”, but it has stopped being maintained since the project’s inception. So check that the changelog covers recent releases.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#is-there-a-changelog"
+question_function = "change_log_check"
+[question.4]
+question_text = "4. Is someone responding to bug reports?"
+question_description = """
+If recent bug reports have gone unanswered, it may be a sign that the package is no longer maintained. It’s worth ignoring any “spammy” open issues, and checking for recently closed issues since they are activity.
+
+Check for issues like “is this still maintained?”… the answer is probably “no”, per Betteridge's law of headlines.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#is-someone-responding-to-bug-reports"
+question_function = "bug_responding"
+[question.5]
+question_text = "5. Are there sufficient tests?"
+question_description = """
+Tests give us confidence that future changes will not result in bugs.
+
+Again, “sufficient” is context-dependent: testing norms in our language and ecosystem, ease of testing the functionality, and personal preferences.
+
+Measurement of test coverage is normally a sign that the tests are higher quality. With coverage, maintainers can at least tell when changes affect untested code.
+
+If there’s no proof of coverage, it’s worth opening a few test files, to check that they aren’t auto-created empty skeletons.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#are-there-sufficient-tests"
+question_function = "check_tests"
+[question.6]
+question_text = "6. Are the tests running with the latest <Language> version?"
+question_description = """
+Most programming languages iterate regularly. Python has annual releases, as does JavaScript (ECMAScript). If a package we’re considering doesn’t support the latest version, it may prevent us from upgrading.
+
+We can grant some leeway for very recent language versions. If Python 3.10 was released last Tuesday, we cannot expect every package to be up to date.
+
+Testing against a new language version can be an easy way to contribute. Often the new version only needs adding to the test matrix, although that may reveal some bugs.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#are-the-tests-running-with-the-latest-language-version"
+question_function = "language_check"
+[question.7]
+question_text = "7. Are the tests running with the latest <Integration> version?"
+question_description = """
+<Integration> here could mean a framework that the package is based on, like Django, or something the package interfaces with, like PostgreSQL. It could mean several things, in which case we can check them all.
+
+The same conditions apply as for the latest <Language> version. And again, adding tests for a new version may be an easy way to contribute.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#are-the-tests-running-with-the-latest-integration-version"
+question_function = "framework_check"
+[question.8]
+question_text = "8. Is there a Continuous Integration (CI) configuration?"
+question_description = """
+If there are tests, it’s likely there’s a CI system set up, such as GitHub Actions. We should check that this in place, and running correctly for recent changes.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#is-there-a-continuous-integration-ci-configuration"
+question_function = "ci_setup"
+[question.9]
+question_text = "9. Is the CI passing?"
+question_description = """
+Some projects configure CI but then ignore it or leave it unmaintained. CI may be failing, for one or more <Language> or <Framework> versions. If this has gone on for a while, it is a sign that maintenance is lagging.
+
+Sometimes CI failure is caused by a single small bug, so fixing it may be a quick contribution. It can also be the case that old versions of <Language> or <Integration>s can simply be dropped.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#is-the-ci-passing"
+question_function = "ci_passing"
+[question.10]
+question_text = "10. Does it seem relatively well used?"
+question_description = """
+We can guesstimate usage by checking recent download counts, and to a lesser extent, popularity metrics like GitHub’s “stars”. Many package indexes, like npm, show download counts on package pages. For PyPI, we can use pypistats.org.
+
+We can only compare usage relative to similar packages, popularity of any <Integration>s, and our <Language>. A particularly niche tool may see minimal usage, but it might still beat any “competitor” packages.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#does-it-seem-relatively-well-used"
+question_function = "well_used"
+[question.11]
+question_text = "11. Has there been a commit in the last year?"
+question_description = """
+Maintainers tend to abandon packages rather than explicitly mark them as unmaintained. So the probability of future maintenance drops off the longer a project has not seen a commit.
+
+We’d like to see at least one recent commit as a “sign of life”.
+
+Any cutoff is arbitrary, but a year aligns with most programming languages’ annual release cadence.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#has-there-been-a-commit-in-the-last-year"
+question_function = "commit_in_last_year"
+[question.12]
+question_text = "12. Has there been a release in the last year?"
+question_description = """
+A backlog of unreleased commits can also be a sign of inattention. Active maintainers may have permission to merge but not release, with the true “owner” of the project absent.
+"""
+question_link = "https://adamj.eu/tech/2021/11/04/the-well-maintained-test/#has-there-been-a-release-in-the-last-year"
+question_function = "release_in_last_year"