Repository: aboutcode-org/purldb (language: python)

Issue:
Create PURL services documentation
We should create and publish on RTD a comprehensive installation and usage documentation for the various PURL-based services of PurlDB. This should be backed by a publicly accessible demo system

- [x] https://github.com/nexB/purldb/issues/445 with PR in https://github.com/nexB/purldb/pull/456
- [x] https://github.com/nexB/purldb/issues/446 merged with https://github.com/nexB/purldb/pull/450
- [x] https://github.com/nexB/purldb/issues/448
- [x] https://github.com/nexB/purldb/issues/457 
Create PURL services documentation
We should create and publish on RTD a comprehensive installation and usage documentation for the various PURL-based services of PurlDB. This should be backed by a publicly accessible demo system

- [x] https://github.com/nexB/purldb/issues/445 with PR in https://github.com/nexB/purldb/pull/456
- [x] https://github.com/nexB/purldb/issues/446 merged with https://github.com/nexB/purldb/pull/450
- [x] https://github.com/nexB/purldb/issues/448
- [x] https://github.com/nexB/purldb/issues/457 


Discussion / hints:
We would need some doc for the purlcli and some doc for each of the endpoints 
@johnmhoran @AyanSinhaMahapatra is this something you guys could get started?
Overall we would need some doc in the same style and structure as ScanCode.io?
@pombredanne I just saw this.  Yes, I'd be happy to work with @AyanSinhaMahapatra on this -- we can start by finding a time to discuss general structure and content and see how the ScanCode.io RTD informs our work.  I'll also need to learn what the various endpoints do and how we use them.

Unless you suggest otherwise, I would like to get a bit more of my PURL CLI work out of the way first since I'm still wrestling with the `urls` command, have not yet fully changed the four existing commands to the SCTK-like data structure, and have more commands to add (`scan` and `git` -- and perhaps others?).  
Some status update:
- We created and published the API definitions documentation see code https://github.com/nexB/purldb/commit/cfc1c9676f9bb6a893bbb3ff573c726033e0e404
- This is deployed on public.purldb.io at `/api/docs` for the docs and the schema is at `/api/`. See the live API doc https://private.purldb.io/api/docs/ and schema https://private.purldb.io/api/schema

- We also updated the built-in documentation of end points accordingly

@pombredanne @AyanSinhaMahapatra As noted a bit earlier in [purldb PR 436](https://github.com/nexB/purldb/pull/436), I've added details to the existing purldb-toolkit RTD page re the use of the four current PURLCLI tools, with a mix of command and output examples and several related notes.  The .rst is here:

https://github.com/nexB/purldb/blob/f49eff87ae9a4226584096498836de7d5015f6a2/purldb-toolkit/README.rst

The initial description above for this issue also says `This should be backed by a publicly accessible demo system`.  What is this?  Any examples or articles or a design doc?  
We would need some doc for the purlcli and some doc for each of the endpoints 
@johnmhoran @AyanSinhaMahapatra is this something you guys could get started?
Overall we would need some doc in the same style and structure as ScanCode.io?
@pombredanne I just saw this.  Yes, I'd be happy to work with @AyanSinhaMahapatra on this -- we can start by finding a time to discuss general structure and content and see how the ScanCode.io RTD informs our work.  I'll also need to learn what the various endpoints do and how we use them.

Unless you suggest otherwise, I would like to get a bit more of my PURL CLI work out of the way first since I'm still wrestling with the `urls` command, have not yet fully changed the four existing commands to the SCTK-like data structure, and have more commands to add (`scan` and `git` -- and perhaps others?).  
Some status update:
- We created and published the API definitions documentation see code https://github.com/nexB/purldb/commit/cfc1c9676f9bb6a893bbb3ff573c726033e0e404
- This is deployed on public.purldb.io at `/api/docs` for the docs and the schema is at `/api/`. See the live API doc https://private.purldb.io/api/docs/ and schema https://private.purldb.io/api/schema

- We also updated the built-in documentation of end points accordingly

@pombredanne @AyanSinhaMahapatra As noted a bit earlier in [purldb PR 436](https://github.com/nexB/purldb/pull/436), I've added details to the existing purldb-toolkit RTD page re the use of the four current PURLCLI tools, with a mix of command and output examples and several related notes.  The .rst is here:

https://github.com/nexB/purldb/blob/f49eff87ae9a4226584096498836de7d5015f6a2/purldb-toolkit/README.rst

The initial description above for this issue also says `This should be backed by a publicly accessible demo system`.  What is this?  Any examples or articles or a design doc?  

Fix patch:
diff --git a/README.rst b/README.rst
index 90eef783..9db5c8bd 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,6 @@
 The purldb
 ==========
-This repo consists of four main tools:
+This repo consists of these main tools:
 
 - PackageDB that is the reference model (based on ScanCode toolkit)
   that contains package data with purl (Package URLs) being a first
@@ -10,6 +10,8 @@ This repo consists of four main tools:
   matching
 - MatchCode.io that provides package matching functionalities for codebases
 - ClearCode that contains utilities to mine Clearlydefined for package data
+- purldb-toolkit CLI utility and library to use the PurlDB, its API and various
+  related libraries.
 
 These are designed to be used first for reference such that one can query for
 packages by purl and validate purl existence.
@@ -191,37 +193,3 @@ To run PurlDB and Matchcode.io with Docker:
 
   docker compose -f docker-compose.yml up -d
   docker compose -f docker-compose.matchcodeio.yml up -d
-
-Funding
--------
-
-This project was funded through the NGI Assure Fund https://nlnet.nl/assure, a
-fund established by NLnet https://nlnet.nl/ with financial support from the
-European Commission's Next Generation Internet programme, under the aegis of DG
-Communications Networks, Content and Technology under grant agreement No 957073.
-
-This project is also funded through grants from the Google Summer of Code
-program, continuing support and sponsoring from nexB Inc. and generous
-donations from multiple sponsors.
-
-
-License
--------
-
-Copyright (c) nexB Inc. and others. All rights reserved.
-
-purldb is a trademark of nexB Inc.
-
-SPDX-License-Identifier: Apache-2.0 AND CC-BY-SA-4.0
-
-purldb software is licensed under the Apache License version 2.0.
-
-purldb data is licensed collectively under CC-BY-SA-4.0.
-
-See https://www.apache.org/licenses/LICENSE-2.0 for the license text.
-
-See https://creativecommons.org/licenses/by-sa/4.0/legalcode for the license text.
-
-See https://github.com/nexB/purldb for support or download.
-
-See https://aboutcode.org for more information about nexB OSS projects.
diff --git a/docs/scripts/sphinx_build_link_check.sh b/docs/scripts/sphinx_build_link_check.sh
old mode 100644
new mode 100755
diff --git a/docs/source/getting-started/contribute.rst b/docs/source/getting-started/contribute.rst
index 1eedd60a..8f79b6e6 100644
--- a/docs/source/getting-started/contribute.rst
+++ b/docs/source/getting-started/contribute.rst
@@ -1,5 +1,5 @@
-Contirbute
-===========
+Contribute
+==========
 
 Documentation to support code and documentation contributions
 to purldb.
diff --git a/docs/source/how-to-guides/index.rst b/docs/source/how-to-guides/index.rst
index 47d33636..96414eb6 100644
--- a/docs/source/how-to-guides/index.rst
+++ b/docs/source/how-to-guides/index.rst
@@ -2,10 +2,7 @@ How-To-Guides
 =============
 
 Here are the various how-to guides across various purldb projects to guide you
-thourgh specifica use cases:
-
-- Code matching with Matchcode
-- Getting symbols from a package (or a PURL)
+through specific use cases:
 
 .. toctree::
    :maxdepth: 2
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 910f1208..927c1b06 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -65,6 +65,16 @@ How-To documents explain how to accomplish specific tasks.
 
 ----
 
+Miscellaneous
+-------------
+
+.. toctree::
+   :maxdepth: 2
+
+   miscellaneous/index
+
+----
+
 
 Indices and tables
 ==================
diff --git a/docs/source/miscellaneous/funding.rst b/docs/source/miscellaneous/funding.rst
new file mode 100644
index 00000000..2b269bb5
--- /dev/null
+++ b/docs/source/miscellaneous/funding.rst
@@ -0,0 +1,11 @@
+Funding
+=======
+
+This project was funded through the NGI Assure Fund https://nlnet.nl/assure, a
+fund established by NLnet https://nlnet.nl/ with financial support from the
+European Commission's Next Generation Internet programme, under the aegis of DG
+Communications Networks, Content and Technology under grant agreement No 957073.
+
+This project is also funded through grants from the Google Summer of Code
+program, continuing support and sponsoring from nexB Inc. and generous
+donations from multiple sponsors.
diff --git a/docs/source/miscellaneous/index.rst b/docs/source/miscellaneous/index.rst
new file mode 100644
index 00000000..b5a22d52
--- /dev/null
+++ b/docs/source/miscellaneous/index.rst
@@ -0,0 +1,9 @@
+Miscellaneous
+=============
+
+.. toctree::
+   :maxdepth: 2
+
+   testing
+   funding
+   license
diff --git a/docs/source/miscellaneous/license.rst b/docs/source/miscellaneous/license.rst
new file mode 100644
index 00000000..62dd2645
--- /dev/null
+++ b/docs/source/miscellaneous/license.rst
@@ -0,0 +1,20 @@
+License
+=======
+
+Copyright (c) nexB Inc. and others. All rights reserved.
+
+purldb is a trademark of nexB Inc.
+
+SPDX-License-Identifier: Apache-2.0 AND CC-BY-SA-4.0
+
+purldb software is licensed under the Apache License version 2.0.
+
+purldb data is licensed collectively under CC-BY-SA-4.0.
+
+See https://www.apache.org/licenses/LICENSE-2.0 for the license text.
+
+See https://creativecommons.org/licenses/by-sa/4.0/legalcode for the license text.
+
+See https://github.com/nexB/purldb for support or download.
+
+See https://aboutcode.org for more information about nexB OSS projects.
diff --git a/purldb-toolkit/README.rst b/purldb-toolkit/README.rst
index 4ac94a98..07ed9bf0 100644
--- a/purldb-toolkit/README.rst
+++ b/purldb-toolkit/README.rst
@@ -1,135 +1,543 @@
 purldb-toolkit
 ==============
 
-purldb-toolkit is command line utility and library to use the PurlDB, its API and various related libraries.
+.. contents:: :local:
+    :depth: 3
+
+purldb-toolkit is a command line utility and library to use the PurlDB, its API and various related libraries.
 
 The ``purlcli`` command acts as a client to the PurlDB REST API end point(s) to expose PURL services.
-It serves both as a tool, as a library and as an example on how to use the services programmatically.
+It serves as a tool, a library and an example of how to use the services programmatically.
+
 
- 
 Installation
 ------------
 
+.. code-block:: console
+
     pip install purldb-toolkit
 
 
 Usage
 -----
 
-Use this command to get basic help::
+Use this command to get basic help:
+
+.. code-block:: console
 
     $ purlcli --help
     Usage: purlcli [OPTIONS] COMMAND [ARGS]...
-    
-      Return information from a PURL.
-    
+
+    Return information from a PURL.
+
     Options:
-      --help  Show this message and exit.
-    
+    --help  Show this message and exit.
+
     Commands:
-      metadata  Given one or more PURLs, for each PURL, return a mapping of...
-      urls      Given one or more PURLs, for each PURL, return a list of all...
-      validate  Check the syntax of one or more PURLs.
-      versions  Given one or more PURLs, return a list of all known versions...
+    metadata  Given one or more PURLs, for each PURL, return a mapping of...
+    urls      Given one or more PURLs, for each PURL, return a list of all...
+    validate  Check the syntax and upstream repo status of one or more PURLs.
+    versions  Given one or more PURLs, return a list of all known versions...
 
 
 And the following subcommands:
 
-- Validate a PURL::
+``validate``: validate a PURL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
 
     $ purlcli validate --help
     Usage: purlcli validate [OPTIONS]
-    
-      Check the syntax of one or more PURLs.
-    
+
+      Check the syntax and upstream repo status of one or more PURLs.
+
     Options:
       --purl TEXT        PackageURL or PURL.
       --output FILENAME  Write validation output as JSON to FILE.  [required]
       --file FILENAME    Read a list of PURLs from a FILE, one per line.
       --help             Show this message and exit.
 
+Examples
+########
+
+**Submit multiple PURLs using the command line:**
+
+.. code-block:: console
+
+    purlcli validate --purl pkg:npm/canonical-path@1.0.0 --purl pkg:nginx/nginx@0.8.9 --output <path/to/output.json>
+
+*Sample output:*
+
+.. code-block:: json
+
+    {
+        "headers": [
+            {
+                "tool_name": "purlcli",
+                "tool_version": "0.2.0",
+                "options": {
+                    "command": "validate",
+                    "--purl": [
+                        "pkg:npm/canonical-path@1.0.0",
+                        "pkg:nginx/nginx@0.8.9"
+                    ],
+                    "--file": null,
+                    "--output": "<path/to/output.json>"
+                },
+                "errors": [],
+                "warnings": [
+                    "'check_existence' is not supported for 'pkg:nginx/nginx@0.8.9'"
+                ]
+            }
+        ],
+        "packages": [
+            {
+                "purl": "pkg:npm/canonical-path@1.0.0",
+                "valid": true,
+                "exists": true,
+                "message": "The provided Package URL is valid, and the package exists in the upstream repo."
+            },
+            {
+                "purl": "pkg:nginx/nginx@0.8.9",
+                "valid": true,
+                "exists": null,
+                "message": "The provided PackageURL is valid, but `check_existence` is not supported for this package type."
+            }
+        ]
+    }
+
+
+**Submit multiple PURLs using a .txt file:**
+
+.. code-block:: console
+
+    purlcli validate --file <path/to/output.txt> --output <path/to/output.json>
+
+*Sample input.txt:*
+
+.. code-block:: text
+
+    pkg:npm/canonical-path@1.0.0
+    pkg:nginx/nginx@0.8.9
+
+
+Details
+#######
+
+``validate`` calls the ``validate/`` endpoint of the `purldb API <https://public.purldb.io/api/>`_.
+
+See also https://public.purldb.io/api/docs/#/validate.
+
+
+----
+
+
+``versions``: collect package versions for a PURL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
 
-- Collect package versions for a PURL::
-      
     $ purlcli versions  --help
     Usage: purlcli versions [OPTIONS]
-    
+
       Given one or more PURLs, return a list of all known versions for each PURL.
-    
-      Version information is not needed in submitted PURLs and if included will be
-      removed before processing.
-    
+
     Options:
       --purl TEXT        PackageURL or PURL.
       --output FILENAME  Write versions output as JSON to FILE.  [required]
       --file FILENAME    Read a list of PURLs from a FILE, one per line.
       --help             Show this message and exit.
 
+Examples
+########
 
-- Collect package metadata for a PURL::
+**Submit multiple PURLs using the command line:**
+
+.. code-block:: console
+
+    purlcli versions --purl pkg:npm/canonical-path --purl pkg:nginx/nginx --output <path/to/output.json>
+
+*Sample output:*
+
+.. code-block:: json
+
+    {
+        "headers": [
+            {
+                "tool_name": "purlcli",
+                "tool_version": "0.2.0",
+                "options": {
+                    "command": "versions",
+                    "--purl": [
+                        "pkg:npm/canonical-path",
+                        "pkg:nginx/nginx"
+                    ],
+                    "--file": null,
+                    "--output": "<path/to/output.json>"
+                },
+                "errors": [],
+                "warnings": [
+                    "'pkg:nginx/nginx' not supported with `versions` command"
+                ]
+            }
+        ],
+        "packages": [
+            {
+                "purl": "pkg:npm/canonical-path@0.0.1",
+                "version": "0.0.1",
+                "release_date": "2013-12-19"
+            },
+            {
+                "purl": "pkg:npm/canonical-path@0.0.2",
+                "version": "0.0.2",
+                "release_date": "2013-12-19"
+            },
+            {
+                "purl": "pkg:npm/canonical-path@1.0.0",
+                "version": "1.0.0",
+                "release_date": "2018-10-24"
+            }
+        ]
+    }
+
+
+Details
+#######
+
+``versions`` calls ``versions()`` from `fetchcode/package_versions.py`.
+
+Version information is not needed in submitted PURLs and, if included, will be removed before processing.
+
+
+----
+
+
+``metadata``: collect package metadata for a PURL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
 
     $ purlcli metadata --help
     Usage: purlcli metadata [OPTIONS]
-    
+
       Given one or more PURLs, for each PURL, return a mapping of metadata fetched
       from the fetchcode package.py info() function.
-    
+
     Options:
       --purl TEXT        PackageURL or PURL.
       --output FILENAME  Write meta output as JSON to FILE.  [required]
       --file FILENAME    Read a list of PURLs from a FILE, one per line.
-      --unique           Return data only for unique PURLs.
       --help             Show this message and exit.
 
-
-- Collect package URLs for a PURL::
+Examples
+########
+
+**Submit multiple PURLs using the command line:**
+
+.. code-block:: console
+
+    purlcli metadata --purl pkg:openssl/openssl@3.0.6 --purl pkg:nginx/nginx@0.8.9 --purl pkg:gnu/glibc@2.38 --output <path/to/output.json>
+
+*Sample output:*
+
+.. code-block:: json
+
+    {
+        "headers": [
+            {
+                "tool_name": "purlcli",
+                "tool_version": "0.2.0",
+                "options": {
+                    "command": "metadata",
+                    "--purl": [
+                        "pkg:openssl/openssl@3.0.6",
+                        "pkg:nginx/nginx@0.8.9",
+                        "pkg:gnu/glibc@2.38"
+                    ],
+                    "--file": null,
+                    "--output": "<path/to/output.json>"
+                },
+                "errors": [],
+                "warnings": [
+                    "'check_existence' is not supported for 'pkg:openssl/openssl@3.0.6'",
+                    "'pkg:nginx/nginx@0.8.9' not supported with `metadata` command",
+                    "'check_existence' is not supported for 'pkg:gnu/glibc@2.38'"
+                ]
+            }
+        ],
+        "packages": [
+            {
+                "purl": "pkg:openssl/openssl@3.0.6",
+                "type": "openssl",
+                "namespace": null,
+                "name": "openssl",
+                "version": "3.0.6",
+                "qualifiers": {},
+                "subpath": null,
+                "primary_language": "C",
+                "description": null,
+                "release_date": "2022-10-11T12:39:09",
+                "parties": [],
+                "keywords": [],
+                "homepage_url": "https://www.openssl.org",
+                "download_url": "https://github.com/openssl/openssl/archive/refs/tags/openssl-3.0.6.tar.gz",
+                "api_url": "https://api.github.com/repos/openssl/openssl",
+                "size": null,
+                "sha1": null,
+                "md5": null,
+                "sha256": null,
+                "sha512": null,
+                "bug_tracking_url": "https://github.com/openssl/openssl/issues",
+                "code_view_url": "https://github.com/openssl/openssl",
+                "vcs_url": "git://github.com/openssl/openssl.git",
+                "copyright": null,
+                "license_expression": null,
+                "declared_license": "Apache-2.0",
+                "notice_text": null,
+                "root_path": null,
+                "dependencies": [],
+                "contains_source_code": null,
+                "source_packages": [],
+                "repository_homepage_url": null,
+                "repository_download_url": null,
+                "api_data_url": null
+            },
+            {
+                "purl": "pkg:gnu/glibc@2.38",
+                "type": "gnu",
+                "namespace": null,
+                "name": "glibc",
+                "version": "2.38",
+                "qualifiers": {},
+                "subpath": null,
+                "primary_language": null,
+                "description": null,
+                "release_date": "2023-07-31T17:34:00",
+                "parties": [],
+                "keywords": [],
+                "homepage_url": "https://ftp.gnu.org/pub/gnu/glibc/",
+                "download_url": "https://ftp.gnu.org/pub/gnu/glibc/glibc-2.38.tar.gz",
+                "api_url": null,
+                "size": null,
+                "sha1": null,
+                "md5": null,
+                "sha256": null,
+                "sha512": null,
+                "bug_tracking_url": null,
+                "code_view_url": null,
+                "vcs_url": null,
+                "copyright": null,
+                "license_expression": null,
+                "declared_license": null,
+                "notice_text": null,
+                "root_path": null,
+                "dependencies": [],
+                "contains_source_code": null,
+                "source_packages": [],
+                "repository_homepage_url": null,
+                "repository_download_url": null,
+                "api_data_url": null
+            }
+        ]
+    }
+
+
+Details
+#######
+
+``metadata`` calls ``info()`` from `fetchcode/package.py`.
+
+The intended output for each PURL type supported by the ``metadata`` command is
+
+- an input PURL with a version: output the metadata for the input version
+- an input PURL without a version: output a list of the metadata for all versions
+
+The output of the various PURL types currently supported in `fetchcode/package.py` varies from type to type at the moment -- the underlying functions will be updated as needed so that all produce the intended output for input PURLs with and without a version.
+
+
+----
+
+
+``urls``: collect package URLs for a PURL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
 
     $ purlcli urls --help
     Usage: purlcli urls [OPTIONS]
-    
+
       Given one or more PURLs, for each PURL, return a list of all known URLs
       fetched from the packageurl-python purl2url.py code.
-    
+
     Options:
       --purl TEXT        PackageURL or PURL.
       --output FILENAME  Write urls output as JSON to FILE.  [required]
       --file FILENAME    Read a list of PURLs from a FILE, one per line.
-      --unique           Return data only for unique PURLs.
       --head             Validate each URL's existence with a head request.
       --help             Show this message and exit.
 
-
-Funding
--------
-
-This project was funded through the NGI Assure Fund https://nlnet.nl/assure, a
-fund established by NLnet https://nlnet.nl/ with financial support from the
-European Commission's Next Generation Internet programme, under the aegis of DG
-Communications Networks, Content and Technology under grant agreement No 957073.
-
-This project is also funded through grants from the Google Summer of Code
-program, continuing support and sponsoring from nexB Inc. and generous
-donations from multiple sponsors.
-
-
-License
--------
-
-Copyright (c) nexB Inc. and others. All rights reserved.
-
-purldb is a trademark of nexB Inc.
-
-SPDX-License-Identifier: Apache-2.0 AND CC-BY-SA-4.0
-
-purldb software is licensed under the Apache License version 2.0.
-
-purldb data is licensed collectively under CC-BY-SA-4.0.
-
-See https://www.apache.org/licenses/LICENSE-2.0 for the license text.
-
-See https://creativecommons.org/licenses/by-sa/4.0/legalcode for the license text.
-
-See https://github.com/nexB/purldb for support or download.
-
-See https://aboutcode.org for more information about nexB OSS projects.
-
+Examples
+########
+
+**Submit multiple PURLs using the command line:**
+
+.. code-block:: console
+
+    purlcli urls --purl pkg:npm/canonical-path@1.0.0 --purl pkg:nginx/nginx@0.8.9 --purl pkg:rubygems/rails@7.0.0 --output <path/to/output.json>
+
+*Sample output:*
+
+.. code-block:: json
+
+    {
+        "headers": [
+            {
+                "tool_name": "purlcli",
+                "tool_version": "0.2.0",
+                "options": {
+                    "command": "urls",
+                    "--purl": [
+                        "pkg:npm/canonical-path@1.0.0",
+                        "pkg:nginx/nginx@0.8.9",
+                        "pkg:rubygems/rails@7.0.0"
+                    ],
+                    "--file": null,
+                    "--output": "<path/to/output.json>"
+                },
+                "errors": [],
+                "warnings": [
+                    "'pkg:nginx/nginx@0.8.9' not supported with `urls` command",
+                    "'check_existence' is not supported for 'pkg:rubygems/rails@7.0.0'"
+                ]
+            }
+        ],
+        "packages": [
+            {
+                "purl": "pkg:npm/canonical-path@1.0.0",
+                "download_url": "http://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz",
+                "inferred_urls": [
+                    "https://www.npmjs.com/package/canonical-path/v/1.0.0",
+                    "http://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz"
+                ],
+                "repository_download_url": null,
+                "repository_homepage_url": "https://www.npmjs.com/package/canonical-path/v/1.0.0"
+            },
+            {
+                "purl": "pkg:rubygems/rails@7.0.0",
+                "download_url": "https://rubygems.org/downloads/rails-7.0.0.gem",
+                "inferred_urls": [
+                    "https://rubygems.org/gems/rails/versions/7.0.0",
+                    "https://rubygems.org/downloads/rails-7.0.0.gem"
+                ],
+                "repository_download_url": null,
+                "repository_homepage_url": "https://rubygems.org/gems/rails/versions/7.0.0"
+            }
+        ]
+    }
+
+
+**Include head and get requests:**
+
+``--head``
+
+.. code-block:: console
+
+    purlcli urls --purl pkg:npm/canonical-path@1.0.0 --purl pkg:nginx/nginx@0.8.9 --purl pkg:rubygems/rails@7.0.0 --output <path/to/output.json> --head
+
+*Sample output:*
+
+.. code-block:: json
+
+    {
+        "headers": [
+            {
+                "tool_name": "purlcli",
+                "tool_version": "0.2.0",
+                "options": {
+                    "command": "urls",
+                    "--purl": [
+                        "pkg:npm/canonical-path@1.0.0",
+                        "pkg:nginx/nginx@0.8.9",
+                        "pkg:rubygems/rails@7.0.0"
+                    ],
+                    "--file": null,
+                    "--head": true,
+                    "--output": "<stdout>"
+                },
+                "errors": [],
+                "warnings": [
+                    "'pkg:nginx/nginx@0.8.9' not supported with `urls` command",
+                    "'check_existence' is not supported for 'pkg:rubygems/rails@7.0.0'"
+                ]
+            }
+        ],
+        "packages": [
+            {
+                "purl": "pkg:npm/canonical-path@1.0.0",
+                "download_url": {
+                    "url": "http://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz",
+                    "get_request_status_code": 200,
+                    "head_request_status_code": 301
+                },
+                "inferred_urls": [
+                    {
+                        "url": "https://www.npmjs.com/package/canonical-path/v/1.0.0",
+                        "get_request_status_code": 200,
+                        "head_request_status_code": 200
+                    },
+                    {
+                        "url": "http://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz",
+                        "get_request_status_code": 200,
+                        "head_request_status_code": 301
+                    }
+                ],
+                "repository_download_url": {
+                    "url": null,
+                    "get_request_status_code": "N/A",
+                    "head_request_status_code": "N/A"
+                },
+                "repository_homepage_url": {
+                    "url": "https://www.npmjs.com/package/canonical-path/v/1.0.0",
+                    "get_request_status_code": 200,
+                    "head_request_status_code": 200
+                }
+            },
+            {
+                "purl": "pkg:rubygems/rails@7.0.0",
+                "download_url": {
+                    "url": "https://rubygems.org/downloads/rails-7.0.0.gem",
+                    "get_request_status_code": 200,
+                    "head_request_status_code": 200
+                },
+                "inferred_urls": [
+                    {
+                        "url": "https://rubygems.org/gems/rails/versions/7.0.0",
+                        "get_request_status_code": 200,
+                        "head_request_status_code": 200
+                    },
+                    {
+                        "url": "https://rubygems.org/downloads/rails-7.0.0.gem",
+                        "get_request_status_code": 200,
+                        "head_request_status_code": 200
+                    }
+                ],
+                "repository_download_url": {
+                    "url": null,
+                    "get_request_status_code": "N/A",
+                    "head_request_status_code": "N/A"
+                },
+                "repository_homepage_url": {
+                    "url": "https://rubygems.org/gems/rails/versions/7.0.0",
+                    "get_request_status_code": 200,
+                    "head_request_status_code": 200
+                }
+            }
+        ]
+    }
+
+
+Details
+#######
+
+None atm.


Test patch:
diff --git a/docs/source/miscellaneous/testing.rst b/docs/source/miscellaneous/testing.rst
new file mode 100644
index 00000000..1d972a6d
--- /dev/null
+++ b/docs/source/miscellaneous/testing.rst
@@ -0,0 +1,31 @@
+Testing
+=======
+
+PURLdb
+------
+
+Run all PURLdb tests
+~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
+
+    make test
+
+
+purldb-toolkit
+--------------
+
+Run all purldb-toolkit non-live tests (i.e., no live network calls)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
+
+    DJANGO_SETTINGS_MODULE=purldb_project.settings pytest -vvs purldb-toolkit/tests/test_purlcli.py
+
+
+Run all purldb-toolkit live tests (i.e., check actual API endpoints etc.)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: console
+
+    DJANGO_SETTINGS_MODULE=purldb_project.settings pytest -vvs purldb-toolkit/tests/test_purlcli_live.py --run_live_fetch