diff --git a/docs/cli/index.md b/docs/cli/index.md index 44b33e75..305b37f2 100644 --- a/docs/cli/index.md +++ b/docs/cli/index.md @@ -11,40 +11,51 @@ - [Options](#options-1) - [--force](#--force) - [all](#all) + - [Options](#options-2) + - [--interactive, --non-interactive, --ci](#--interactive---non-interactive---ci) - [env](#env) + - [Options](#options-3) + - [--interactive, --non-interactive, --ci](#--interactive---non-interactive---ci-1) - [npm](#npm) - [poetry](#poetry) - [completions](#completions) - [install](#install) - - [Options](#options-2) + - [Options](#options-4) - [--shell ](#--shell-) - [uninstall](#uninstall) - - [Options](#options-3) + - [Options](#options-5) - [--shell ](#--shell--1) - [config](#config) - [version-prompt](#version-prompt) - [Arguments](#arguments) - [ENABLE](#enable) + - [deploy](#deploy) + - [Options](#options-6) + - [-C, --command ](#-c---command-) + - [--interactive, --non-interactive, --ci](#--interactive---non-interactive---ci-2) + - [-P, --path ](#-p---path-) + - [Arguments](#arguments-1) + - [ENVIRONMENT_NAME](#environment_name) - [doctor](#doctor) - - [Options](#options-4) + - [Options](#options-7) - [-c, --copy-to-clipboard](#-c---copy-to-clipboard) - [explore](#explore) - - [Arguments](#arguments-1) + - [Arguments](#arguments-2) - [NETWORK](#network) - [generate](#generate) - [client](#client) - - [Options](#options-5) + - [Options](#options-8) - [-o, --output ](#-o---output-) - [-l, --language ](#-l---language-) - - [Arguments](#arguments-2) + - [Arguments](#arguments-3) - [APP_SPEC_PATH_OR_DIR](#app_spec_path_or_dir) - [goal](#goal) - - [Options](#options-6) + - [Options](#options-9) - [--console](#--console) - - [Arguments](#arguments-3) + - [Arguments](#arguments-4) - [GOAL_ARGS](#goal_args) - [init](#init) - - [Options](#options-7) + - [Options](#options-10) - [-n, --name ](#-n---name-) - [-t, --template ](#-t---template-) - [--template-url ](#--template-url-) @@ -59,11 +70,11 @@ - [console](#console) - [explore](#explore-1) - [logs](#logs) - - [Options](#options-8) + - [Options](#options-11) - [--follow, -f](#--follow--f) - [--tail ](#--tail-) - [reset](#reset) - - [Options](#options-9) + - [Options](#options-12) - [--update, --no-update](#--update---no-update) - [start](#start) - [status](#status) @@ -120,6 +131,12 @@ Runs all bootstrap sub-commands in the current directory and immediate sub direc algokit bootstrap all [OPTIONS] ``` +### Options + + +### --interactive, --non-interactive, --ci +Enable/disable interactive prompts. If the CI environment variable is set, defaults to non-interactive + ### env Copies .env.template file to .env in the current working directory and prompts for any unspecified values. @@ -128,6 +145,12 @@ Copies .env.template file to .env in the current working directory and prompts f algokit bootstrap env [OPTIONS] ``` +### Options + + +### --interactive, --non-interactive, --ci +Enable/disable interactive prompts. If the CI environment variable is set, defaults to non-interactive + ### npm Runs npm install in the current working directory to install Node.js dependencies. @@ -221,6 +244,34 @@ algokit config version-prompt [OPTIONS] [[enable|disable]] ### ENABLE Optional argument +## deploy + +Deploy smart contracts from AlgoKit compliant repository. + +```shell +algokit deploy [OPTIONS] [ENVIRONMENT_NAME] +``` + +### Options + + +### -C, --command +Custom deploy command. If not provided, will load the deploy command from .algokit.toml file. + + +### --interactive, --non-interactive, --ci +Enable/disable interactive prompts. If the CI environment variable is set, defaults to non-interactive + + +### -P, --path +Specify the project directory. If not provided, current working directory will be used. + +### Arguments + + +### ENVIRONMENT_NAME +Optional argument + ## doctor Diagnose potential environment issues that may affect AlgoKit diff --git a/docs/features/deploy.md b/docs/features/deploy.md new file mode 100644 index 00000000..bce0948e --- /dev/null +++ b/docs/features/deploy.md @@ -0,0 +1,127 @@ +# AlgoKit Deploy Feature Documentation + +Deploy your smart contracts effortlessly to various networks with the AlgoKit Deploy feature. This feature is essential for automation in CI/CD pipelines and for seamless deployment to various Algorand network environments. + +## Usage + +```sh +$ algokit deploy [OPTIONS] [ENVIRONMENT_NAME] +``` + +This command deploys smart contracts from an AlgoKit compliant repository to the specified network. + +### Options + +- `--command, -C TEXT`: Specifies a custom deploy command. If this option is not provided, the deploy command will be loaded from the `.algokit.toml` file. +- `--interactive / --non-interactive, --ci`: Enables or disables the interactive prompt for mnemonics. When the CI environment variable is set, it defaults to non-interactive. +- `--path, -P DIRECTORY`: Specifies the project directory. If not provided, the current working directory will be used. +- `-h, --help`: Show this message and exit. + +## Environment files + +AlgoKit `deploy` employs both a general and network-specific environment file strategy. This allows you to set environment variables that are applicable across all networks and others that are specific to a given network. + +The general environment file (`.env`) should be placed at the root of your project. This file will be used to load environment variables that are common across deployments to all networks. + +For each network you're deploying to, you can optionally have a corresponding `.env.[network_name]` file. This file should contain environment variables specific to that network. Network-specific environment variables take precedence over general environment variables. + +The directory layout would look like this: + +```md +. +├── ... (your project files and directories) +├── .algokit.toml # Configuration file for AlgoKit +├── .env # (OPTIONAL) General environment variables common across all deployments +└── .env.[{mainnet|testnet|localnet|betanet|custom}] # (OPTIONAL) Environment variables specific to deployments to a network +``` + +> ⚠️ Please note that creating `.env` and `.env.[network_name]` files is only necessary if you're deploying to a custom network or if you want to override the default network configurations provided by AlgoKit. AlgoKit comes with predefined configurations for popular networks like `TestNet`, `MainNet`, `BetaNet`, or AlgoKit's `LocalNet`. + +The logic for loading environment variables is as follows: + +- If a `.env` file exists, the environment variables contained in it are loaded first. +- If a `.env.[network_name]` file exists, the environment variables in it are loaded, overriding any previously loaded values from the `.env` file for the same variables. + +## AlgoKit Configuration File + +AlgoKit uses a configuration file called `.algokit.toml` in the root of your project. The configuration file can be created using the `algokit init` command. This file will define the deployment commands for the various network environments that you want to target. + +Here's an example of what the `.algokit.toml` file might look like. When deploying it will prompt for the `DEPLOYER_MNEMONIC` secret unless it is already defined as an environment variable or is deploying to localnet. + +```toml +[algokit] +min_version = "v{lastest_version}" + +[deploy] +command = "poetry run python -m smart_contracts deploy" +environment_secrets = [ + "DEPLOYER_MNEMONIC", +] + +[deploy.localnet] +environment_secrets = [] +``` + +The `command` key under each `[deploy.{network_name}]` section should contain a string that represents the deployment command for that particular network. If a `command` key is not provided in a network-specific section, the command from the general `[deploy]` section will be used. + +The `environment_secrets` key should contain a list of names of environment variables that should be treated as secrets. This can be defined in the general `[deploy]` section, as well as in the network-specific sections. The environment-specific secrets will be added to the general secrets during deployment. + +The `[algokit]` section with the `min_version` key allows you to specify the minimum version of AlgoKit that the project requires. + +This way, you can define common deployment logic and environment secrets in the `[deploy]` section, and provide overrides or additions for specific environments in the `[deploy.{environment_name}]` sections. + +## Deploying to a Specific Network + +The command requires a `ENVIRONMENT` argument, which specifies the network environment to which the smart contracts will be deployed. Please note, the `environment` argument is case-sensitive. + +Example: + +```sh +$ algokit deploy testnet +``` + +This command deploys the smart contracts to the testnet. + +## Custom Project Directory + +By default, the deploy command looks for the `.algokit.toml` file in the current working directory. You can specify a custom project directory using the `--project-dir` option. + +Example: + +```sh +$ algokit deploy testnet --project-dir="path/to/project" +``` + +## Custom Deploy Command + +You can provide a custom deploy command using the `--custom-deploy-command` option. If this option is not provided, the deploy command will be loaded from the `.algokit.toml` file. + +Example: + +```sh +$ algokit deploy testnet --custom-deploy-command="your-custom-command" +``` + +## CI Mode + +By using the `--ci` or `--non-interactive` flag, you can skip the interactive prompt for mnemonics. + +This is useful in CI/CD environments where user interaction is not possible. When using this flag, you need to make sure that the mnemonics are set as environment variables. + +Example: + +```sh +$ algokit deploy testnet --ci +``` + +## Example of a Full Deployment + +```sh +$ algokit deploy testnet --custom-deploy-command="your-custom-command" +``` + +This example shows how to deploy smart contracts to the testnet using a custom deploy command. This also assumes that .algokit.toml file is present in the current working directory, and .env.testnet file is present in the current working directory and contains the required environment variables for deploying to TestNet environment. + +## Further Reading + +For in-depth details, visit the [deploy](../cli/index.md#deploy) section in the AlgoKit CLI reference documentation. diff --git a/poetry.lock b/poetry.lock index bc29dc18..941a5a40 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,9 +1,10 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "aiohttp" version = "3.8.4" description = "Async http client/server framework (asyncio)" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -112,6 +113,7 @@ speedups = ["Brotli", "aiodns", "cchardet"] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -126,6 +128,7 @@ frozenlist = ">=1.1.0" name = "alabaster" version = "0.7.13" description = "A configurable sidebar-enabled Sphinx theme" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -137,6 +140,7 @@ files = [ name = "algokit-client-generator" version = "1.0.2" description = "Algorand typed client Generator" +category = "main" optional = false python-versions = ">=3.10,<4.0" files = [ @@ -148,12 +152,13 @@ algokit-utils = ">=1.2.0,<2.0.0" [[package]] name = "algokit-utils" -version = "1.2.0" +version = "1.3.0" description = "Utilities for Algorand development for use by AlgoKit" +category = "main" optional = false python-versions = ">=3.10,<4.0" files = [ - {file = "algokit_utils-1.2.0-py3-none-any.whl", hash = "sha256:0f78f257991b5a3a0cfe0ccfdb20756ffc5780eaade6ca6775f1aafab2e59b8b"}, + {file = "algokit_utils-1.3.0-py3-none-any.whl", hash = "sha256:7167daa4412b74fe23ec4000193f32f1553e149786e8db7f0a8ca9f47ba37536"}, ] [package.dependencies] @@ -163,6 +168,7 @@ py-algorand-sdk = ">=2.2.0,<3.0.0" name = "allpairspy" version = "2.5.0" description = "Pairwise test combinations generator" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -182,6 +188,7 @@ test = ["pytest"] name = "anyio" version = "3.7.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -203,6 +210,7 @@ trio = ["trio (<0.22)"] name = "approval-utilities" version = "7.4.0" description = "Utilities for your production code that work well with approvaltests" +category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -214,6 +222,7 @@ files = [ name = "approvaltests" version = "7.4.0" description = "Assertion/verification library to aid testing" +category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -235,6 +244,7 @@ typing-extensions = ">=3.6.2" name = "async-timeout" version = "4.0.2" description = "Timeout context manager for asyncio programs" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -246,6 +256,7 @@ files = [ name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -264,6 +275,7 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte name = "babel" version = "2.12.1" description = "Internationalization utilities" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -275,6 +287,7 @@ files = [ name = "beautifulsoup4" version = "4.12.2" description = "Screen-scraping library" +category = "dev" optional = false python-versions = ">=3.6.0" files = [ @@ -293,6 +306,7 @@ lxml = ["lxml"] name = "black" version = "23.3.0" description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -342,6 +356,7 @@ uvloop = ["uvloop (>=0.15.2)"] name = "bleach" version = "6.0.0" description = "An easy safelist-based HTML-sanitizing tool." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -358,13 +373,14 @@ css = ["tinycss2 (>=1.1.0,<1.2)"] [[package]] name = "cachecontrol" -version = "0.13.0" +version = "0.13.1" description = "httplib2 caching for requests" +category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "CacheControl-0.13.0-py3-none-any.whl", hash = "sha256:4544a012a25cf0a73c53cd986f68b4f9c9f6b1df01d741c2923c3d56c66c7bda"}, - {file = "CacheControl-0.13.0.tar.gz", hash = "sha256:fd3fd2cb0ca66b9a6c1d56cc9709e7e49c63dbd19b1b1bcbd8d3f94cedfe8ce5"}, + {file = "cachecontrol-0.13.1-py3-none-any.whl", hash = "sha256:95dedbec849f46dda3137866dc28b9d133fc9af55f5b805ab1291833e4457aa4"}, + {file = "cachecontrol-0.13.1.tar.gz", hash = "sha256:f012366b79d2243a6118309ce73151bf52a38d4a5dac8ea57f09bd29087e506b"}, ] [package.dependencies] @@ -373,6 +389,7 @@ msgpack = ">=0.5.2" requests = ">=2.16.0" [package.extras] +dev = ["CacheControl[filecache,redis]", "black", "build", "cherrypy", "mypy", "pytest", "pytest-cov", "sphinx", "tox", "types-redis", "types-requests"] filecache = ["filelock (>=3.8.0)"] redis = ["redis (>=2.10.5)"] @@ -380,6 +397,7 @@ redis = ["redis (>=2.10.5)"] name = "certifi" version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -391,6 +409,7 @@ files = [ name = "cffi" version = "1.15.1" description = "Foreign Function Interface for Python calling C code." +category = "main" optional = false python-versions = "*" files = [ @@ -467,6 +486,7 @@ pycparser = "*" name = "cfgv" version = "3.3.1" description = "Validate configuration and produce human readable error messages." +category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -478,6 +498,7 @@ files = [ name = "charset-normalizer" version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -562,6 +583,7 @@ files = [ name = "click" version = "8.1.3" description = "Composable command line interface toolkit" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -576,6 +598,7 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "click-log" version = "0.4.0" description = "Logging integration for Click" +category = "dev" optional = false python-versions = "*" files = [ @@ -590,6 +613,7 @@ click = "*" name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -601,6 +625,7 @@ files = [ name = "copier" version = "7.1.0" description = "A library for rendering project templates." +category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -627,6 +652,7 @@ questionary = ">=1.8.1" name = "coverage" version = "7.2.7" description = "Code coverage measurement for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -702,6 +728,7 @@ toml = ["tomli"] name = "cryptography" version = "41.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -741,25 +768,38 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "cyclonedx-python-lib" -version = "2.7.1" +version = "4.0.1" description = "A library for producing CycloneDX SBOM (Software Bill of Materials) files." +category = "dev" optional = false -python-versions = ">=3.6,<4.0" +python-versions = ">=3.7,<4.0" files = [ - {file = "cyclonedx-python-lib-2.7.1.tar.gz", hash = "sha256:493bf2f30e26c48f305f745ed8580ce10d05a8d68d62a598fe95f05a0d9007dc"}, - {file = "cyclonedx_python_lib-2.7.1-py3-none-any.whl", hash = "sha256:fabc4c8baf722faeea01c3bbca83730e3489dfb37d85c6036baa67a9a7519d40"}, + {file = "cyclonedx_python_lib-4.0.1-py3-none-any.whl", hash = "sha256:907b64f00df85d727a425de86604768b248cf19285993729e04f17bec767f692"}, + {file = "cyclonedx_python_lib-4.0.1.tar.gz", hash = "sha256:878e33b8e0080c786f6cbd4c6f87ad610db65d6a3a686a5698415d9cfcd8925d"}, ] [package.dependencies] -packageurl-python = ">=0.9" -setuptools = ">=47.0.0" +packageurl-python = ">=0.11" +py-serializable = ">=0.11.1,<0.12.0" sortedcontainers = ">=2.4.0,<3.0.0" -toml = ">=0.10.0,<0.11.0" + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] [[package]] name = "distlib" version = "0.3.6" description = "Distribution utilities" +category = "dev" optional = false python-versions = "*" files = [ @@ -771,6 +811,7 @@ files = [ name = "docutils" version = "0.19" description = "Docutils -- Python Documentation Utilities" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -782,6 +823,7 @@ files = [ name = "dotty-dict" version = "1.3.1" description = "Dictionary wrapper for quick access to deeply nested keys." +category = "dev" optional = false python-versions = ">=3.5,<4.0" files = [ @@ -793,6 +835,7 @@ files = [ name = "dunamai" version = "1.17.0" description = "Dynamic version generation" +category = "main" optional = false python-versions = ">=3.5,<4.0" files = [ @@ -805,13 +848,14 @@ packaging = ">=20.9" [[package]] name = "empty-files" -version = "0.0.3" +version = "0.0.4" description = "Serves empty files of many types" +category = "dev" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7.1" files = [ - {file = "empty-files-0.0.3.tar.gz", hash = "sha256:87277db100a3bfdafc2ba18f6094cd37090e257058fb1c0b15873a89e1003149"}, - {file = "empty_files-0.0.3-py3-none-any.whl", hash = "sha256:ec464f7f88a028d4567b380d57983fc4ffb79147538626690cd94c33090cd216"}, + {file = "empty-files-0.0.4.tar.gz", hash = "sha256:e1a0862d79f9143343cc8623e39a4612ef39a23e2e6049fe443a78b51b4e74a5"}, + {file = "empty_files-0.0.4-py3-none-any.whl", hash = "sha256:74be100837ada478409ccb613f2a4429847f12d7f96651ae9e093c0d46917cfe"}, ] [package.dependencies] @@ -819,13 +863,14 @@ requests = "*" [[package]] name = "exceptiongroup" -version = "1.1.1" +version = "1.1.2" description = "Backport of PEP 654 (exception groups)" +category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, - {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, + {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, + {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"}, ] [package.extras] @@ -833,23 +878,25 @@ test = ["pytest (>=6)"] [[package]] name = "filelock" -version = "3.12.0" +version = "3.12.2" description = "A platform independent file lock." +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, - {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, + {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, + {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, ] [package.extras] -docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "frozenlist" version = "1.3.3" description = "A list-like structure which implements collections.abc.MutableSequence" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -933,6 +980,7 @@ files = [ name = "funcy" version = "2.0" description = "A fancy and practical functional tools" +category = "main" optional = false python-versions = "*" files = [ @@ -944,6 +992,7 @@ files = [ name = "gfm-toc" version = "0.0.7" description = "Simple and customizable way to generate TOC for Github Markdown files." +category = "dev" optional = false python-versions = "*" files = [ @@ -955,6 +1004,7 @@ files = [ name = "gitdb" version = "4.0.10" description = "Git Object Database" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -969,6 +1019,7 @@ smmap = ">=3.0.1,<6" name = "gitpython" version = "3.1.31" description = "GitPython is a Python library used to interact with Git repositories" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -983,6 +1034,7 @@ gitdb = ">=4.0.1,<5" name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -994,6 +1046,7 @@ files = [ name = "html2text" version = "2020.1.16" description = "Turn HTML into equivalent Markdown-structured text." +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1005,6 +1058,7 @@ files = [ name = "html5lib" version = "1.1" description = "HTML parser based on the WHATWG HTML specification" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1026,6 +1080,7 @@ lxml = ["lxml"] name = "httpcore" version = "0.16.3" description = "A minimal low-level HTTP client." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1037,16 +1092,17 @@ files = [ anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = "==1.*" +sniffio = ">=1.0.0,<2.0.0" [package.extras] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "httpx" version = "0.23.3" description = "The next generation HTTP client." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1062,14 +1118,15 @@ sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<13)"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "identify" version = "2.5.24" description = "File identification library for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1084,6 +1141,7 @@ license = ["ukkonen"] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1095,6 +1153,7 @@ files = [ name = "imagesize" version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1104,13 +1163,14 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.6.0" +version = "6.7.0" description = "Read metadata from Python packages" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"}, - {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"}, + {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, + {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, ] [package.dependencies] @@ -1119,12 +1179,13 @@ zipp = ">=0.5" [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] [[package]] name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1134,19 +1195,21 @@ files = [ [[package]] name = "invoke" -version = "1.7.3" +version = "2.1.3" description = "Pythonic task execution" +category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "invoke-1.7.3-py3-none-any.whl", hash = "sha256:d9694a865764dd3fd91f25f7e9a97fb41666e822bbb00e670091e3f43933574d"}, - {file = "invoke-1.7.3.tar.gz", hash = "sha256:41b428342d466a82135d5ab37119685a989713742be46e42a3a399d685579314"}, + {file = "invoke-2.1.3-py3-none-any.whl", hash = "sha256:51e86a08d964160e01c44eccd22f50b25842bd96a9c63c11177032594cb86740"}, + {file = "invoke-2.1.3.tar.gz", hash = "sha256:a3b15d52d50bbabd851b8a39582c772180b614000fa1612b4d92484d54d38c6b"}, ] [[package]] name = "jaraco-classes" version = "3.2.3" description = "Utility functions for Python class constructs" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1165,6 +1228,7 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec name = "jeepney" version = "0.8.0" description = "Low-level, pure Python DBus protocol wrapper." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1180,6 +1244,7 @@ trio = ["async_generator", "trio"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1197,6 +1262,7 @@ i18n = ["Babel (>=2.7)"] name = "jinja2-ansible-filters" version = "1.3.2" description = "A port of Ansible's jinja2 filters without requiring ansible core." +category = "main" optional = false python-versions = "*" files = [ @@ -1213,13 +1279,14 @@ test = ["pytest", "pytest-cov"] [[package]] name = "keyring" -version = "23.13.1" +version = "24.2.0" description = "Store and access your passwords safely." +category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "keyring-23.13.1-py3-none-any.whl", hash = "sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd"}, - {file = "keyring-23.13.1.tar.gz", hash = "sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678"}, + {file = "keyring-24.2.0-py3-none-any.whl", hash = "sha256:4901caaf597bfd3bbd78c9a0c7c4c29fcd8310dab2cffefe749e916b6527acd6"}, + {file = "keyring-24.2.0.tar.gz", hash = "sha256:ca0746a19ec421219f4d713f848fa297a661a8a8c1504867e55bfb5e09091509"}, ] [package.dependencies] @@ -1231,18 +1298,19 @@ SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} [package.extras] completion = ["shtab"] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] [[package]] name = "markdown-it-py" -version = "2.2.0" +version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" +category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "markdown-it-py-2.2.0.tar.gz", hash = "sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1"}, - {file = "markdown_it_py-2.2.0-py3-none-any.whl", hash = "sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30"}, + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, ] [package.dependencies] @@ -1255,13 +1323,14 @@ compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0 linkify = ["linkify-it-py (>=1,<3)"] plugins = ["mdit-py-plugins"] profiling = ["gprof2dot"] -rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1321,6 +1390,7 @@ files = [ name = "mdurl" version = "0.1.2" description = "Markdown URL utilities" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1332,6 +1402,7 @@ files = [ name = "more-itertools" version = "9.1.0" description = "More routines for operating on iterables, beyond itertools" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1343,6 +1414,7 @@ files = [ name = "mrjob" version = "0.7.4" description = "Python MapReduce framework" +category = "dev" optional = false python-versions = "*" files = [ @@ -1364,6 +1436,7 @@ ujson = ["ujson"] name = "msgpack" version = "1.0.5" description = "MessagePack serializer" +category = "main" optional = false python-versions = "*" files = [ @@ -1432,10 +1505,23 @@ files = [ {file = "msgpack-1.0.5.tar.gz", hash = "sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c"}, ] +[[package]] +name = "mslex" +version = "1.1.0" +description = "shlex for windows" +category = "main" +optional = false +python-versions = ">=3.5" +files = [ + {file = "mslex-1.1.0-py2.py3-none-any.whl", hash = "sha256:8826f4bb8d8c63402203d921dc8c2df0c7fec0d9c91d020ddf02fc9d0dce81bd"}, + {file = "mslex-1.1.0.tar.gz", hash = "sha256:7fe305fbdc9721283875e0b737fdb344374b761338a7f41af91875de278568e4"}, +] + [[package]] name = "multidict" version = "6.0.4" description = "multidict implementation" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1517,43 +1603,44 @@ files = [ [[package]] name = "mypy" -version = "1.3.0" +version = "1.4.1" description = "Optional static typing for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mypy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eb485cea53f4f5284e5baf92902cd0088b24984f4209e25981cc359d64448d"}, - {file = "mypy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c99c3ecf223cf2952638da9cd82793d8f3c0c5fa8b6ae2b2d9ed1e1ff51ba85"}, - {file = "mypy-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:550a8b3a19bb6589679a7c3c31f64312e7ff482a816c96e0cecec9ad3a7564dd"}, - {file = "mypy-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cbc07246253b9e3d7d74c9ff948cd0fd7a71afcc2b77c7f0a59c26e9395cb152"}, - {file = "mypy-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:a22435632710a4fcf8acf86cbd0d69f68ac389a3892cb23fbad176d1cddaf228"}, - {file = "mypy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6e33bb8b2613614a33dff70565f4c803f889ebd2f859466e42b46e1df76018dd"}, - {file = "mypy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d23370d2a6b7a71dc65d1266f9a34e4cde9e8e21511322415db4b26f46f6b8c"}, - {file = "mypy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:658fe7b674769a0770d4b26cb4d6f005e88a442fe82446f020be8e5f5efb2fae"}, - {file = "mypy-1.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6e42d29e324cdda61daaec2336c42512e59c7c375340bd202efa1fe0f7b8f8ca"}, - {file = "mypy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:d0b6c62206e04061e27009481cb0ec966f7d6172b5b936f3ead3d74f29fe3dcf"}, - {file = "mypy-1.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:76ec771e2342f1b558c36d49900dfe81d140361dd0d2df6cd71b3db1be155409"}, - {file = "mypy-1.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc95f8386314272bbc817026f8ce8f4f0d2ef7ae44f947c4664efac9adec929"}, - {file = "mypy-1.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:faff86aa10c1aa4a10e1a301de160f3d8fc8703b88c7e98de46b531ff1276a9a"}, - {file = "mypy-1.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8c5979d0deb27e0f4479bee18ea0f83732a893e81b78e62e2dda3e7e518c92ee"}, - {file = "mypy-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c5d2cc54175bab47011b09688b418db71403aefad07cbcd62d44010543fc143f"}, - {file = "mypy-1.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:87df44954c31d86df96c8bd6e80dfcd773473e877ac6176a8e29898bfb3501cb"}, - {file = "mypy-1.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:473117e310febe632ddf10e745a355714e771ffe534f06db40702775056614c4"}, - {file = "mypy-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:74bc9b6e0e79808bf8678d7678b2ae3736ea72d56eede3820bd3849823e7f305"}, - {file = "mypy-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:44797d031a41516fcf5cbfa652265bb994e53e51994c1bd649ffcd0c3a7eccbf"}, - {file = "mypy-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ddae0f39ca146972ff6bb4399f3b2943884a774b8771ea0a8f50e971f5ea5ba8"}, - {file = "mypy-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c4c42c60a8103ead4c1c060ac3cdd3ff01e18fddce6f1016e08939647a0e703"}, - {file = "mypy-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e86c2c6852f62f8f2b24cb7a613ebe8e0c7dc1402c61d36a609174f63e0ff017"}, - {file = "mypy-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f9dca1e257d4cc129517779226753dbefb4f2266c4eaad610fc15c6a7e14283e"}, - {file = "mypy-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:95d8d31a7713510685b05fbb18d6ac287a56c8f6554d88c19e73f724a445448a"}, - {file = "mypy-1.3.0-py3-none-any.whl", hash = "sha256:a8763e72d5d9574d45ce5881962bc8e9046bf7b375b0abf031f3e6811732a897"}, - {file = "mypy-1.3.0.tar.gz", hash = "sha256:e1f4d16e296f5135624b34e8fb741eb0eadedca90862405b1f1fde2040b9bd11"}, + {file = "mypy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:566e72b0cd6598503e48ea610e0052d1b8168e60a46e0bfd34b3acf2d57f96a8"}, + {file = "mypy-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca637024ca67ab24a7fd6f65d280572c3794665eaf5edcc7e90a866544076878"}, + {file = "mypy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dde1d180cd84f0624c5dcaaa89c89775550a675aff96b5848de78fb11adabcd"}, + {file = "mypy-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8c4d8e89aa7de683e2056a581ce63c46a0c41e31bd2b6d34144e2c80f5ea53dc"}, + {file = "mypy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:bfdca17c36ae01a21274a3c387a63aa1aafe72bff976522886869ef131b937f1"}, + {file = "mypy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7549fbf655e5825d787bbc9ecf6028731973f78088fbca3a1f4145c39ef09462"}, + {file = "mypy-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98324ec3ecf12296e6422939e54763faedbfcc502ea4a4c38502082711867258"}, + {file = "mypy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:141dedfdbfe8a04142881ff30ce6e6653c9685b354876b12e4fe6c78598b45e2"}, + {file = "mypy-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8207b7105829eca6f3d774f64a904190bb2231de91b8b186d21ffd98005f14a7"}, + {file = "mypy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:16f0db5b641ba159eff72cff08edc3875f2b62b2fa2bc24f68c1e7a4e8232d01"}, + {file = "mypy-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:470c969bb3f9a9efcedbadcd19a74ffb34a25f8e6b0e02dae7c0e71f8372f97b"}, + {file = "mypy-1.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5952d2d18b79f7dc25e62e014fe5a23eb1a3d2bc66318df8988a01b1a037c5b"}, + {file = "mypy-1.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:190b6bab0302cec4e9e6767d3eb66085aef2a1cc98fe04936d8a42ed2ba77bb7"}, + {file = "mypy-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9d40652cc4fe33871ad3338581dca3297ff5f2213d0df345bcfbde5162abf0c9"}, + {file = "mypy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01fd2e9f85622d981fd9063bfaef1aed6e336eaacca00892cd2d82801ab7c042"}, + {file = "mypy-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2460a58faeea905aeb1b9b36f5065f2dc9a9c6e4c992a6499a2360c6c74ceca3"}, + {file = "mypy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2746d69a8196698146a3dbe29104f9eb6a2a4d8a27878d92169a6c0b74435b6"}, + {file = "mypy-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae704dcfaa180ff7c4cfbad23e74321a2b774f92ca77fd94ce1049175a21c97f"}, + {file = "mypy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:43d24f6437925ce50139a310a64b2ab048cb2d3694c84c71c3f2a1626d8101dc"}, + {file = "mypy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c482e1246726616088532b5e964e39765b6d1520791348e6c9dc3af25b233828"}, + {file = "mypy-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43b592511672017f5b1a483527fd2684347fdffc041c9ef53428c8dc530f79a3"}, + {file = "mypy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34a9239d5b3502c17f07fd7c0b2ae6b7dd7d7f6af35fbb5072c6208e76295816"}, + {file = "mypy-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5703097c4936bbb9e9bce41478c8d08edd2865e177dc4c52be759f81ee4dd26c"}, + {file = "mypy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e02d700ec8d9b1859790c0475df4e4092c7bf3272a4fd2c9f33d87fac4427b8f"}, + {file = "mypy-1.4.1-py3-none-any.whl", hash = "sha256:45d32cec14e7b97af848bddd97d85ea4f0db4d5a149ed9676caa4eb2f7402bb4"}, + {file = "mypy-1.4.1.tar.gz", hash = "sha256:9bbcd9ab8ea1f2e1c8031c21445b511442cc45c89951e49bbf852cbb70755b1b"}, ] [package.dependencies] mypy-extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=3.10" +typing-extensions = ">=4.1.0" [package.extras] dmypy = ["psutil (>=4.0)"] @@ -1565,6 +1652,7 @@ reports = ["lxml"] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1576,6 +1664,7 @@ files = [ name = "nodeenv" version = "1.8.0" description = "Node.js virtual environment builder" +category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ @@ -1590,6 +1679,7 @@ setuptools = "*" name = "packageurl-python" version = "0.11.1" description = "A purl aka. Package URL parser and builder" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1606,6 +1696,7 @@ test = ["pytest"] name = "packaging" version = "23.1" description = "Core utilities for Python packages" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1617,6 +1708,7 @@ files = [ name = "pasteboard" version = "0.3.3" description = "Pasteboard - Python interface for reading from NSPasteboard (macOS clipboard)" +category = "main" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -1631,6 +1723,7 @@ files = [ name = "pastel" version = "0.2.1" description = "Bring colors to your terminal." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1642,6 +1735,7 @@ files = [ name = "pathspec" version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1653,6 +1747,7 @@ files = [ name = "pip" version = "23.1.2" description = "The PyPA recommended tool for installing Python packages." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1664,6 +1759,7 @@ files = [ name = "pip-api" version = "0.0.30" description = "An unofficial, importable pip API" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1676,18 +1772,19 @@ pip = "*" [[package]] name = "pip-audit" -version = "2.5.6" +version = "2.6.0" description = "A tool for scanning Python environments for known vulnerabilities" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pip_audit-2.5.6-py3-none-any.whl", hash = "sha256:7673bea690470024f1aec9be26055334cb987a530c6a431a31c347f66064e475"}, - {file = "pip_audit-2.5.6.tar.gz", hash = "sha256:04fc0ad1727674181bda243a457af5a73038ee691dd9b8afc71f7e9292ce3912"}, + {file = "pip_audit-2.6.0-py3-none-any.whl", hash = "sha256:49e97e3d6663d2ed0c00b7a7c468afcb816beb3988f32f8496d3fe3927cfd627"}, + {file = "pip_audit-2.6.0.tar.gz", hash = "sha256:6431c363efa80ef52c2599197c5b8a39ff8708ce316624b97fa35b5cdf493118"}, ] [package.dependencies] -CacheControl = {version = ">=0.12.0", extras = ["filecache"]} -cyclonedx-python-lib = ">=2.0,<2.5.0 || >2.5.0,<3.0" +CacheControl = {version = ">=0.13.0", extras = ["filecache"]} +cyclonedx-python-lib = ">=4.0,<5.0" html5lib = ">=1.1" packaging = ">=23.0.0" pip-api = ">=0.0.28" @@ -1695,18 +1792,18 @@ pip-requirements-parser = ">=32.0.0" requests = ">=2.31.0" rich = ">=12.4" toml = ">=0.10" -urllib3 = ">=1.26,<2.0" [package.extras] dev = ["build", "bump (>=1.3.2)", "pip-audit[doc,lint,test]"] doc = ["pdoc"] -lint = ["black (>=22.3.0)", "interrogate", "isort", "mypy", "ruff (<0.0.270)", "types-html5lib", "types-requests", "types-toml"] +lint = ["black (>=22.3.0)", "interrogate", "isort", "mypy", "ruff (<0.0.276)", "types-html5lib", "types-requests", "types-toml"] test = ["coverage[toml]", "pretend", "pytest", "pytest-cov"] [[package]] name = "pip-requirements-parser" version = "32.0.1" description = "pip requirements parser - a mostly correct pip requirements parsing library because it uses pip's own code." +category = "dev" optional = false python-versions = ">=3.6.0" files = [ @@ -1726,6 +1823,7 @@ testing = ["aboutcode-toolkit (>=6.0.0)", "black", "pytest (>=6,!=7.0.0)", "pyte name = "pkginfo" version = "1.9.6" description = "Query metadata from sdists / bdists / installed packages." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1738,28 +1836,30 @@ testing = ["pytest", "pytest-cov"] [[package]] name = "platformdirs" -version = "3.5.1" +version = "3.8.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"}, - {file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"}, + {file = "platformdirs-3.8.0-py3-none-any.whl", hash = "sha256:ca9ed98ce73076ba72e092b23d3c93ea6c4e186b3f1c3dad6edd98ff6ffcca2e"}, + {file = "platformdirs-3.8.0.tar.gz", hash = "sha256:b0cabcb11063d21a0b261d557acb0a9d2126350e63b70cdf7db6347baea456dc"}, ] [package.extras] -docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" -version = "1.0.0" +version = "1.2.0" description = "plugin and hook calling mechanisms for python" +category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, + {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, + {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, ] [package.extras] @@ -1770,6 +1870,7 @@ testing = ["pytest", "pytest-benchmark"] name = "plumbum" version = "1.8.2" description = "Plumbum: shell combinators library" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1789,6 +1890,7 @@ ssh = ["paramiko"] name = "poethepoet" version = "0.17.1" description = "A task runner that works well with poetry." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1807,6 +1909,7 @@ poetry-plugin = ["poetry (>=1.0,<2.0)"] name = "pre-commit" version = "2.21.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1825,6 +1928,7 @@ virtualenv = ">=20.10.0" name = "prompt-toolkit" version = "3.0.38" description = "Library for building powerful interactive command lines in Python" +category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -1837,13 +1941,14 @@ wcwidth = "*" [[package]] name = "py-algorand-sdk" -version = "2.2.0" +version = "2.3.0" description = "Algorand SDK in Python" +category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "py-algorand-sdk-2.2.0.tar.gz", hash = "sha256:50044aed40c5e0319a48d7f4fbc3cdbc3246703c10dd2ceebc06b546cddd8186"}, - {file = "py_algorand_sdk-2.2.0-py3-none-any.whl", hash = "sha256:a17cad8fb97d401522cf2dc415ef48e2ac4bf7bfa68ef1849e704bc800aa28e5"}, + {file = "py-algorand-sdk-2.3.0.tar.gz", hash = "sha256:6ccd9777007b3462f44fface7a7d040b6e21e03cede9319b0242d5498499889d"}, + {file = "py_algorand_sdk-2.3.0-py3-none-any.whl", hash = "sha256:a4e0e55a488daed6262c78b5358eb90bfd465758ee345e816bb603460341d816"}, ] [package.dependencies] @@ -1851,10 +1956,26 @@ msgpack = ">=1.0.0,<2" pycryptodomex = ">=3.6.0,<4" pynacl = ">=1.4.0,<2" +[[package]] +name = "py-serializable" +version = "0.11.1" +description = "Library for serializing and deserializing Python Objects to and from JSON and XML." +category = "dev" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "py-serializable-0.11.1.tar.gz", hash = "sha256:ba0e1287b9e4f645a5334f1913abd8e647e7250209f84f55dce3909498a6f586"}, + {file = "py_serializable-0.11.1-py3-none-any.whl", hash = "sha256:79e21f0672822e6200b15f45ce9f636e8126466f62dbd7d488c67313c72b5c3e"}, +] + +[package.dependencies] +defusedxml = ">=0.7.1,<0.8.0" + [[package]] name = "pyclip" version = "0.7.0" description = "Cross-platform clipboard utilities supporting both binary and text data." +category = "main" optional = false python-versions = "*" files = [ @@ -1873,6 +1994,7 @@ test = ["pytest"] name = "pycparser" version = "2.21" description = "C parser in Python" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1884,6 +2006,7 @@ files = [ name = "pycryptodomex" version = "3.18.0" description = "Cryptographic library for Python" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1925,6 +2048,7 @@ files = [ name = "pydantic" version = "1.10.8" description = "Data validation and settings management using python type hints" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1977,6 +2101,7 @@ email = ["email-validator (>=1.0.3)"] name = "pydash" version = "7.0.4" description = "The kitchen sink of Python utility libraries for doing \"stuff\" in a functional way. Based on the Lo-Dash Javascript library." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1994,6 +2119,7 @@ dev = ["Sphinx", "black", "build", "coverage", "docformatter", "flake8", "flake8 name = "pygments" version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2008,6 +2134,7 @@ plugins = ["importlib-metadata"] name = "pynacl" version = "1.5.0" description = "Python binding to the Networking and Cryptography (NaCl) library" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2027,18 +2154,19 @@ files = [ cffi = ">=1.4.1" [package.extras] -docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] +docs = ["sphinx (>=1.6.5)", "sphinx_rtd_theme"] tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] [[package]] name = "pyparsing" -version = "3.0.9" +version = "3.1.0" description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "dev" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, + {file = "pyparsing-3.1.0-py3-none-any.whl", hash = "sha256:d554a96d1a7d3ddaf7183104485bc19fd80543ad6ac5bdb6426719d766fb06c1"}, + {file = "pyparsing-3.1.0.tar.gz", hash = "sha256:edb662d6fe322d6e990b1594b5feaeadf806803359e3d4d42f11e295e588f0ea"}, ] [package.extras] @@ -2048,6 +2176,7 @@ diagrams = ["jinja2", "railroad-diagrams"] name = "pyperclip" version = "1.8.2" description = "A cross-platform clipboard module for Python. (Only handles plain text for now.)" +category = "dev" optional = false python-versions = "*" files = [ @@ -2056,13 +2185,14 @@ files = [ [[package]] name = "pytest" -version = "7.3.1" +version = "7.4.0" description = "pytest: simple powerful testing with Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, - {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, + {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, + {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, ] [package.dependencies] @@ -2074,12 +2204,13 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-cov" version = "4.1.0" description = "Pytest plugin for measuring coverage." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2098,6 +2229,7 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-httpx" version = "0.21.3" description = "Send responses to httpx." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2106,21 +2238,22 @@ files = [ ] [package.dependencies] -httpx = "==0.23.*" +httpx = ">=0.23.0,<0.24.0" pytest = ">=6.0,<8.0" [package.extras] -testing = ["pytest-asyncio (==0.20.*)", "pytest-cov (==4.*)"] +testing = ["pytest-asyncio (>=0.20.0,<0.21.0)", "pytest-cov (>=4.0.0,<5.0.0)"] [[package]] name = "pytest-mock" -version = "3.10.0" +version = "3.11.1" description = "Thin-wrapper around the mock package for easier use with pytest" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-mock-3.10.0.tar.gz", hash = "sha256:fbbdb085ef7c252a326fd8cdcac0aa3b1333d8811f131bdcc701002e1be7ed4f"}, - {file = "pytest_mock-3.10.0-py3-none-any.whl", hash = "sha256:f4c973eeae0282963eb293eb173ce91b091a79c1334455acfac9ddee8a1c784b"}, + {file = "pytest-mock-3.11.1.tar.gz", hash = "sha256:7f6b125602ac6d743e523ae0bfa71e1a697a2f5534064528c6ff84c2f7c2fc7f"}, + {file = "pytest_mock-3.11.1-py3-none-any.whl", hash = "sha256:21c279fff83d70763b05f8874cc9cfb3fcacd6d354247a976f9529d19f9acf39"}, ] [package.dependencies] @@ -2129,15 +2262,31 @@ pytest = ">=5.0" [package.extras] dev = ["pre-commit", "pytest-asyncio", "tox"] +[[package]] +name = "python-dotenv" +version = "1.0.0" +description = "Read key-value pairs from a .env file and set them as environment variables" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, + {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + [[package]] name = "python-gitlab" -version = "3.14.0" +version = "3.15.0" description = "Interact with GitLab API" +category = "dev" optional = false python-versions = ">=3.7.0" files = [ - {file = "python-gitlab-3.14.0.tar.gz", hash = "sha256:ef3b8960faeee9880f82b0872d807e3fab94ace12b0d2a8418a97875c8812d3c"}, - {file = "python_gitlab-3.14.0-py3-none-any.whl", hash = "sha256:da614c014c6860147783dde8c216218d8fc6bd83a8bd2e3929dcdf11b211aa58"}, + {file = "python-gitlab-3.15.0.tar.gz", hash = "sha256:c9e65eb7612a9fbb8abf0339972eca7fd7a73d4da66c9b446ffe528930aff534"}, + {file = "python_gitlab-3.15.0-py3-none-any.whl", hash = "sha256:8f8d1c0d387f642eb1ac7bf5e8e0cd8b3dd49c6f34170cee3c7deb7d384611f3"}, ] [package.dependencies] @@ -2150,13 +2299,14 @@ yaml = ["PyYaml (>=5.2)"] [[package]] name = "python-semantic-release" -version = "7.34.3" +version = "7.34.6" description = "Automatic Semantic Versioning for Python projects" +category = "dev" optional = false python-versions = "*" files = [ - {file = "python-semantic-release-7.34.3.tar.gz", hash = "sha256:ac62990d6c5510ae41abcae34c775ced7cba7b3ed9176578b7954eb956537dbb"}, - {file = "python_semantic_release-7.34.3-py3-none-any.whl", hash = "sha256:c3de866c4c00af45de0813efa2d37fc0a822946ce9111a3f059d011df06b6510"}, + {file = "python-semantic-release-7.34.6.tar.gz", hash = "sha256:e9b8fb788024ae9510a924136d573588415a16eeca31cc5240f2754a80a2e831"}, + {file = "python_semantic_release-7.34.6-py3-none-any.whl", hash = "sha256:7e3969ba4663d9b2087b02bf3ac140e202551377bf045c34e09bfe19753e19ab"}, ] [package.dependencies] @@ -2164,7 +2314,7 @@ click = ">=7,<9" click-log = ">=0.3,<1" dotty-dict = ">=1.3.0,<2" gitpython = ">=3.0.8,<4" -invoke = ">=1.4.1,<2" +invoke = ">=1.4.1,<3" packaging = "*" python-gitlab = ">=2,<4" requests = ">=2.25,<3" @@ -2183,6 +2333,7 @@ test = ["coverage (>=5,<6)", "mock (==1.3.0)", "pytest (>=7,<8)", "pytest-mock ( name = "pywin32" version = "306" description = "Python for Window Extensions" +category = "main" optional = false python-versions = "*" files = [ @@ -2204,19 +2355,21 @@ files = [ [[package]] name = "pywin32-ctypes" -version = "0.2.0" -description = "" +version = "0.2.2" +description = "A (partial) reimplementation of pywin32 using ctypes/cffi" +category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"}, - {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, + {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"}, + {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"}, ] [[package]] name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2264,26 +2417,27 @@ files = [ [[package]] name = "pyyaml-include" -version = "1.3" +version = "1.3.1" description = "Extending PyYAML with a custom constructor for including YAML files within YAML files" +category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" files = [ - {file = "pyyaml-include-1.3.tar.gz", hash = "sha256:f7fbeb8e71b50be0e6e07472f7c79dbfb1a15bade9c93a078369ff49e57e6771"}, - {file = "pyyaml_include-1.3-py3-none-any.whl", hash = "sha256:5142a0b0f93d9b1e5872d5a814f3681ffbc70638128ced1acfd9fb57da7825ca"}, + {file = "pyyaml-include-1.3.1.tar.gz", hash = "sha256:4cb3b4e1baae2ec251808fe1e8aed5d3d20699c541864c8e47ed866ab2f15039"}, + {file = "pyyaml_include-1.3.1-py3-none-any.whl", hash = "sha256:e58525721a2938d29c4046350f8aad86f848660a770c29605e6f2700925fa753"}, ] [package.dependencies] PyYAML = ">=5.1,<7.0" [package.extras] -all = ["toml"] toml = ["toml"] [[package]] name = "questionary" version = "1.10.0" description = "Python library to build pretty command line user prompts ⭐️" +category = "main" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -2299,13 +2453,14 @@ docs = ["Sphinx (>=3.3,<4.0)", "sphinx-autobuild (>=2020.9.1,<2021.0.0)", "sphin [[package]] name = "readme-renderer" -version = "37.3" +version = "40.0" description = "readme_renderer is a library for rendering \"readme\" descriptions for Warehouse" +category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "readme_renderer-37.3-py3-none-any.whl", hash = "sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343"}, - {file = "readme_renderer-37.3.tar.gz", hash = "sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273"}, + {file = "readme_renderer-40.0-py3-none-any.whl", hash = "sha256:e18feb2a1e7706f2865b81ebb460056d93fb29d69daa10b223c00faa7bd9a00a"}, + {file = "readme_renderer-40.0.tar.gz", hash = "sha256:9f77b519d96d03d7d7dce44977ba543090a14397c4f60de5b6eb5b8048110aa4"}, ] [package.dependencies] @@ -2320,6 +2475,7 @@ md = ["cmarkgfm (>=0.8.0)"] name = "requests" version = "2.31.0" description = "Python HTTP for Humans." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2341,6 +2497,7 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "requests-toolbelt" version = "1.0.0" description = "A utility belt for advanced users of python-requests" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2355,6 +2512,7 @@ requests = ">=2.0.1,<3.0.0" name = "rfc3986" version = "1.5.0" description = "Validating URI References per RFC 3986" +category = "main" optional = false python-versions = "*" files = [ @@ -2370,17 +2528,18 @@ idna2008 = ["idna"] [[package]] name = "rich" -version = "13.4.1" +version = "13.4.2" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +category = "dev" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.4.1-py3-none-any.whl", hash = "sha256:d204aadb50b936bf6b1a695385429d192bc1fdaf3e8b907e8e26f4c4e4b5bf75"}, - {file = "rich-13.4.1.tar.gz", hash = "sha256:76f6b65ea7e5c5d924ba80e322231d7cb5b5981aa60bfc1e694f1bc097fe6fe1"}, + {file = "rich-13.4.2-py3-none-any.whl", hash = "sha256:8f87bc7ee54675732fa66a05ebfe489e27264caeeff3728c945d25971b6485ec"}, + {file = "rich-13.4.2.tar.gz", hash = "sha256:d653d6bccede5844304c605d5aac802c7cf9621efd700b46c7ec2b51ea914898"}, ] [package.dependencies] -markdown-it-py = ">=2.2.0,<3.0.0" +markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" [package.extras] @@ -2388,34 +2547,36 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "ruff" -version = "0.0.257" +version = "0.0.275" description = "An extremely fast Python linter, written in Rust." +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.0.257-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:7280640690c1d0046b20e0eb924319a89d8e22925d7d232180ce31196e7478f8"}, - {file = "ruff-0.0.257-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:4582b73da61ab410ffda35b2987a6eacb33f18263e1c91810f0b9779ec4f41a9"}, - {file = "ruff-0.0.257-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5acae9878f1136893e266348acdb9d30dfae23c296d3012043816432a5abdd51"}, - {file = "ruff-0.0.257-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9f0912d045eee15e8e02e335c16d7a7f9fb6821aa5eb1628eeb5bbfa3d88908"}, - {file = "ruff-0.0.257-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a9542c34ee5298b31be6c6ba304f14b672dcf104846ee65adb2466d3e325870"}, - {file = "ruff-0.0.257-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3464f1ad4cea6c4b9325da13ae306bd22bf15d226e18d19c52db191b1f4355ac"}, - {file = "ruff-0.0.257-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a54bfd559e558ee0df2a2f3756423fe6a9de7307bc290d807c3cdf351cb4c24"}, - {file = "ruff-0.0.257-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3438fd38446e1a0915316f4085405c9feca20fe00a4b614995ab7034dbfaa7ff"}, - {file = "ruff-0.0.257-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:358cc2b547bd6451dcf2427b22a9c29a2d9c34e66576c693a6381c5f2ed3011d"}, - {file = "ruff-0.0.257-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:783390f1e94a168c79d7004426dae3e4ae2999cc85f7d00fdd86c62262b71854"}, - {file = "ruff-0.0.257-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:aaa3b5b6929c63a854b6bcea7a229453b455ab26337100b2905fae4523ca5667"}, - {file = "ruff-0.0.257-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4ecd7a84db4816df2dcd0f11c5365a9a2cf4fa70a19b3ac161b7b0bfa592959d"}, - {file = "ruff-0.0.257-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3db8d77d5651a2c0d307102d717627a025d4488d406f54c2764b21cfbe11d822"}, - {file = "ruff-0.0.257-py3-none-win32.whl", hash = "sha256:d2c8755fa4f6c5e5ec032ad341ca3beeecd16786e12c3f26e6b0cc40418ae998"}, - {file = "ruff-0.0.257-py3-none-win_amd64.whl", hash = "sha256:3cec07d6fecb1ebbc45ea8eeb1047b929caa2f7dfb8dd4b0e1869ff789326da5"}, - {file = "ruff-0.0.257-py3-none-win_arm64.whl", hash = "sha256:352f1bdb9b433b3b389aee512ffb0b82226ae1e25b3d92e4eaf0e7be6b1b6f6a"}, - {file = "ruff-0.0.257.tar.gz", hash = "sha256:fedfd06a37ddc17449203c3e38fc83fb68de7f20b5daa0ee4e60d3599b38bab0"}, + {file = "ruff-0.0.275-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:5e6554a072e7ce81eb6f0bec1cebd3dcb0e358652c0f4900d7d630d61691e914"}, + {file = "ruff-0.0.275-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:1cc599022fe5ffb143a965b8d659eb64161ab8ab4433d208777eab018a1aab67"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5206fc1cd8c1c1deadd2e6360c0dbcd690f1c845da588ca9d32e4a764a402c60"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c4e6468da26f77b90cae35319d310999f471a8c352998e9b39937a23750149e"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0dbdea02942131dbc15dd45f431d152224f15e1dd1859fcd0c0487b658f60f1a"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:22efd9f41af27ef8fb9779462c46c35c89134d33e326c889971e10b2eaf50c63"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c09662112cfa22d7467a19252a546291fd0eae4f423e52b75a7a2000a1894db"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80043726662144876a381efaab88841c88e8df8baa69559f96b22d4fa216bef1"}, + {file = "ruff-0.0.275-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5859ee543b01b7eb67835dfd505faa8bb7cc1550f0295c92c1401b45b42be399"}, + {file = "ruff-0.0.275-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c8ace4d40a57b5ea3c16555f25a6b16bc5d8b2779ae1912ce2633543d4e9b1da"}, + {file = "ruff-0.0.275-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8347fc16aa185aae275906c4ac5b770e00c896b6a0acd5ba521f158801911998"}, + {file = "ruff-0.0.275-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ec43658c64bfda44fd84bbea9da8c7a3b34f65448192d1c4dd63e9f4e7abfdd4"}, + {file = "ruff-0.0.275-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:508b13f7ca37274cceaba4fb3ea5da6ca192356323d92acf39462337c33ad14e"}, + {file = "ruff-0.0.275-py3-none-win32.whl", hash = "sha256:6afb1c4422f24f361e877937e2a44b3f8176774a476f5e33845ebfe887dd5ec2"}, + {file = "ruff-0.0.275-py3-none-win_amd64.whl", hash = "sha256:d9b264d78621bf7b698b6755d4913ab52c19bd28bee1a16001f954d64c1a1220"}, + {file = "ruff-0.0.275-py3-none-win_arm64.whl", hash = "sha256:a19ce3bea71023eee5f0f089dde4a4272d088d5ac0b675867e074983238ccc65"}, + {file = "ruff-0.0.275.tar.gz", hash = "sha256:a63a0b645da699ae5c758fce19188e901b3033ec54d862d93fcd042addf7f38d"}, ] [[package]] name = "secretstorage" version = "3.3.3" description = "Python bindings to FreeDesktop.org Secret Service API" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2431,6 +2592,7 @@ jeepney = ">=0.6" name = "semver" version = "2.13.0" description = "Python helper for Semantic Versioning (http://semver.org/)" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2440,13 +2602,14 @@ files = [ [[package]] name = "setuptools" -version = "67.8.0" +version = "68.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, - {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, + {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, + {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, ] [package.extras] @@ -2458,6 +2621,7 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs ( name = "shellingham" version = "1.5.0.post1" description = "Tool to Detect Surrounding Shell" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2469,6 +2633,7 @@ files = [ name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -2480,6 +2645,7 @@ files = [ name = "smmap" version = "5.0.0" description = "A pure Python implementation of a sliding window memory map manager" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2491,6 +2657,7 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2502,6 +2669,7 @@ files = [ name = "snowballstemmer" version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +category = "dev" optional = false python-versions = "*" files = [ @@ -2513,6 +2681,7 @@ files = [ name = "sortedcontainers" version = "2.4.0" description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +category = "dev" optional = false python-versions = "*" files = [ @@ -2524,6 +2693,7 @@ files = [ name = "soupsieve" version = "2.4.1" description = "A modern CSS selector implementation for Beautiful Soup." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2535,6 +2705,7 @@ files = [ name = "sphinx" version = "6.2.1" description = "Python documentation generator" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2569,6 +2740,7 @@ test = ["cython", "filelock", "html5lib", "pytest (>=4.6)"] name = "sphinx-click" version = "4.4.0" description = "Sphinx extension that automatically documents click applications" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2585,6 +2757,7 @@ sphinx = ">=2.0" name = "sphinxcontrib-applehelp" version = "1.0.4" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2600,6 +2773,7 @@ test = ["pytest"] name = "sphinxcontrib-devhelp" version = "1.0.2" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -2615,6 +2789,7 @@ test = ["pytest"] name = "sphinxcontrib-htmlhelp" version = "2.0.1" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2630,6 +2805,7 @@ test = ["html5lib", "pytest"] name = "sphinxcontrib-jsmath" version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -2644,6 +2820,7 @@ test = ["flake8", "mypy", "pytest"] name = "sphinxcontrib-qthelp" version = "1.0.3" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -2659,6 +2836,7 @@ test = ["pytest"] name = "sphinxcontrib-serializinghtml" version = "1.1.5" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -2674,6 +2852,7 @@ test = ["pytest"] name = "sphinxnotes-markdown-builder" version = "0.5.6" description = "sphinx builder that outputs markdown files, an active fork of clayrisser/sphinx-markdown-builder" +category = "dev" optional = false python-versions = "*" files = [ @@ -2692,6 +2871,7 @@ yapf = "*" name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -2703,6 +2883,7 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2714,6 +2895,7 @@ files = [ name = "tomlkit" version = "0.11.8" description = "Style preserving TOML library" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2725,6 +2907,7 @@ files = [ name = "tqdm" version = "4.65.0" description = "Fast, Extensible Progress Meter" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2745,6 +2928,7 @@ telegram = ["requests"] name = "twine" version = "3.8.0" description = "Collection of utilities for publishing packages on PyPI" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2766,19 +2950,21 @@ urllib3 = ">=1.26.0" [[package]] name = "typing-extensions" -version = "4.6.3" +version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"}, - {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"}, + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, ] [[package]] name = "unify" version = "0.5" description = "Modifies strings to all use the same (single/double) quote where possible." +category = "dev" optional = false python-versions = "*" files = [ @@ -2792,6 +2978,7 @@ untokenize = "*" name = "untokenize" version = "0.1.1" description = "Transforms tokens into original source code (while preserving whitespace)." +category = "dev" optional = false python-versions = "*" files = [ @@ -2800,48 +2987,51 @@ files = [ [[package]] name = "urllib3" -version = "1.26.16" +version = "2.0.3" description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7" files = [ - {file = "urllib3-1.26.16-py2.py3-none-any.whl", hash = "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f"}, - {file = "urllib3-1.26.16.tar.gz", hash = "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"}, + {file = "urllib3-2.0.3-py3-none-any.whl", hash = "sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1"}, + {file = "urllib3-2.0.3.tar.gz", hash = "sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.23.0" +version = "20.23.1" description = "Virtual Python Environment builder" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.23.0-py3-none-any.whl", hash = "sha256:6abec7670e5802a528357fdc75b26b9f57d5d92f29c5462ba0fbe45feacc685e"}, - {file = "virtualenv-20.23.0.tar.gz", hash = "sha256:a85caa554ced0c0afbd0d638e7e2d7b5f92d23478d05d17a76daeac8f279f924"}, + {file = "virtualenv-20.23.1-py3-none-any.whl", hash = "sha256:34da10f14fea9be20e0fd7f04aba9732f84e593dac291b757ce42e3368a39419"}, + {file = "virtualenv-20.23.1.tar.gz", hash = "sha256:8ff19a38c1021c742148edc4f81cb43d7f8c6816d2ede2ab72af5b84c749ade1"}, ] [package.dependencies] distlib = ">=0.3.6,<1" -filelock = ">=3.11,<4" -platformdirs = ">=3.2,<4" +filelock = ">=3.12,<4" +platformdirs = ">=3.5.1,<4" [package.extras] -docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.7.1)", "time-machine (>=2.9)"] +docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezer (>=0.4.6)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.8)", "time-machine (>=2.9)"] [[package]] name = "wcwidth" version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" +category = "main" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, ] @@ -2849,6 +3039,7 @@ files = [ name = "webencodings" version = "0.5.1" description = "Character encoding aliases for legacy web content" +category = "dev" optional = false python-versions = "*" files = [ @@ -2860,6 +3051,7 @@ files = [ name = "wheel" version = "0.40.0" description = "A built-package format for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2872,22 +3064,26 @@ test = ["pytest (>=6.0.0)"] [[package]] name = "yapf" -version = "0.33.0" +version = "0.40.1" description = "A formatter for Python code." +category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "yapf-0.33.0-py2.py3-none-any.whl", hash = "sha256:4c2b59bd5ffe46f3a7da48df87596877189148226ce267c16e8b44240e51578d"}, - {file = "yapf-0.33.0.tar.gz", hash = "sha256:da62bdfea3df3673553351e6246abed26d9fe6780e548a5af9e70f6d2b4f5b9a"}, + {file = "yapf-0.40.1-py3-none-any.whl", hash = "sha256:b8bfc1f280949153e795181768ca14ef43d7312629a06c43e7abd279323af313"}, + {file = "yapf-0.40.1.tar.gz", hash = "sha256:958587eb5c8ec6c860119a9c25d02addf30a44f75aa152a4220d30e56a98037c"}, ] [package.dependencies] +importlib-metadata = ">=6.6.0" +platformdirs = ">=3.5.1" tomli = ">=2.0.1" [[package]] name = "yarl" version = "1.9.2" description = "Yet another URL library" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2975,6 +3171,7 @@ multidict = ">=4.0" name = "zipp" version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2989,4 +3186,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "8f4dace5c0a8d7845db3f2b7e1f3e5584ad68f7cb678a00a17915d29d092e10a" +content-hash = "74632dc60807379a36128569ad4b1f3516f94fa1fdc7d0abce171bb078c56919" diff --git a/pyproject.toml b/pyproject.toml index f8af5366..c899716a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,13 +16,15 @@ pyclip = "^0.7.0" shellingham = "^1.5.0.post1" algokit-client-generator = "^1.0.2" tomli = { version = "^2.0.1", python = "<3.11" } +python-dotenv = "^1.0.0" # workaround for issue with copier dependency spec allowing major upgrade to pydantic v2 pydantic = "^1.10.2" +mslex = "^1.1.0" [tool.poetry.group.dev.dependencies] pytest = "^7.2.0" black = {extras = ["d"], version = "^23.1.0"} -ruff = "^0.0.257" +ruff = "^0.0.275" pip-audit = "^2.4.7" approvaltests = "^7.2.0" pytest-mock = "^3.10.0" diff --git a/src/algokit/cli/__init__.py b/src/algokit/cli/__init__.py index bff8ab61..c6650870 100644 --- a/src/algokit/cli/__init__.py +++ b/src/algokit/cli/__init__.py @@ -3,6 +3,7 @@ from algokit.cli.bootstrap import bootstrap_group from algokit.cli.completions import completions_group from algokit.cli.config import config_group +from algokit.cli.deploy import deploy_command from algokit.cli.doctor import doctor_command from algokit.cli.explore import explore_command from algokit.cli.generate import generate_group @@ -43,3 +44,4 @@ def algokit(*, skip_version_check: bool) -> None: algokit.add_command(init_command) algokit.add_command(localnet_group) algokit.add_command(generate_group) +algokit.add_command(deploy_command) diff --git a/src/algokit/cli/bootstrap.py b/src/algokit/cli/bootstrap.py index 287375e5..1ccf45e0 100644 --- a/src/algokit/cli/bootstrap.py +++ b/src/algokit/cli/bootstrap.py @@ -1,4 +1,5 @@ import logging +import os from pathlib import Path import click @@ -31,9 +32,15 @@ def bootstrap_group(*, force: bool) -> None: @bootstrap_group.command( "all", short_help="Runs all bootstrap sub-commands in the current directory and immediate sub directories." ) -def bootstrap_all() -> None: +@click.option( + "--interactive/--non-interactive", + " /--ci", # this aliases --non-interactive to --ci + default=lambda: "CI" not in os.environ, + help="Enable/disable interactive prompts. If the CI environment variable is set, defaults to non-interactive", +) +def bootstrap_all(*, interactive: bool) -> None: cwd = Path.cwd() - bootstrap_any_including_subdirs(cwd) + bootstrap_any_including_subdirs(cwd, ci_mode=not interactive) logger.info(f"Finished bootstrapping {cwd}") @@ -42,8 +49,14 @@ def bootstrap_all() -> None: short_help="Copies .env.template file to .env in the current working directory " "and prompts for any unspecified values.", ) -def env() -> None: - bootstrap_env(Path.cwd()) +@click.option( + "--interactive/--non-interactive", + " /--ci", # this aliases --non-interactive to --ci + default=lambda: "CI" not in os.environ, + help="Enable/disable interactive prompts. If the CI environment variable is set, defaults to non-interactive", +) +def env(*, interactive: bool) -> None: + bootstrap_env(Path.cwd(), ci_mode=not interactive) @bootstrap_group.command( diff --git a/src/algokit/cli/deploy.py b/src/algokit/cli/deploy.py new file mode 100644 index 00000000..4da4a8e6 --- /dev/null +++ b/src/algokit/cli/deploy.py @@ -0,0 +1,100 @@ +import logging +import os +import typing as t +from pathlib import Path + +import click + +from algokit.core import proc +from algokit.core.conf import ALGOKIT_CONFIG +from algokit.core.deploy import load_deploy_config, load_env_files, parse_command + +logger = logging.getLogger(__name__) + + +def _ensure_environment_secrets( + config_env: dict[str, str], environment_secrets: list[str], *, skip_mnemonics_prompts: bool +) -> None: + for key in environment_secrets: + if not config_env.get(key): + if skip_mnemonics_prompts: + raise click.ClickException(f"Error: missing {key} environment variable") + config_env[key] = click.prompt(key, hide_input=True) + + +class CommandParamType(click.types.StringParamType): + name = "command" + + def convert( + self, value: t.Any, param: click.Parameter | None, ctx: click.Context | None # noqa: ANN401 + ) -> list[str]: + str_value = super().convert(value=value, param=param, ctx=ctx) + try: + return parse_command(str_value) + except Exception as ex: + logger.debug(f"Failed to parse command string: {str_value}", exc_info=True) + raise click.BadParameter(str(ex), param=param, ctx=ctx) from ex + + +@click.command("deploy") +@click.argument("environment_name", default=None, required=False) +@click.option( + "--command", + "-C", + type=CommandParamType(), + default=None, + help="Custom deploy command. If not provided, will load the deploy command from .algokit.toml file.", +) +@click.option( + "--interactive/--non-interactive", + " /--ci", # this aliases --non-interactive to --ci + default=lambda: "CI" not in os.environ, + help="Enable/disable interactive prompts. If the CI environment variable is set, defaults to non-interactive", +) +@click.option( + "--path", + "-P", + type=click.Path(exists=True, readable=True, file_okay=False, resolve_path=True, path_type=Path), + default=".", + help="Specify the project directory. If not provided, current working directory will be used.", +) +def deploy_command( + *, + environment_name: str | None, + command: list[str] | None, + interactive: bool, + path: Path, +) -> None: + """Deploy smart contracts from AlgoKit compliant repository.""" + logger.debug(f"Deploying from project directory: {path}") + logger.debug("Loading deploy command from project config") + config = load_deploy_config(name=environment_name, project_dir=path) + if command: + config.command = command + elif not config.command: + if environment_name is None: + msg = f"No generic deploy command specified in '{ALGOKIT_CONFIG}' file." + else: + msg = ( + f"Deploy command for '{environment_name}' is not specified in '{ALGOKIT_CONFIG}' file, " + "and no generic command." + ) + raise click.ClickException(msg) + logger.info(f"Using deploy command: {' '.join(config.command)}") + # TODO: [future-note] do we want to walk up for env/config? + logger.info("Loading deployment environment variables...") + config_dotenv = load_env_files(environment_name, path) + # environment variables take precedence over those in .env* files + config_env = {**{k: v for k, v in config_dotenv.items() if v is not None}, **os.environ} + if config.environment_secrets: + _ensure_environment_secrets(config_env, config.environment_secrets, skip_mnemonics_prompts=not interactive) + logger.info("Deploying smart contracts from AlgoKit compliant repository 🚀") + try: + result = proc.run(config.command, cwd=path, env=config_env, stdout_log_level=logging.INFO) + except FileNotFoundError as ex: + raise click.ClickException(f"Failed to execute deploy command, '{config.command[0]}' wasn't found") from ex + except PermissionError as ex: + raise click.ClickException(f"Failed to execute deploy command '{config.command[0]}', permission denied") from ex + else: + if result.exit_code != 0: + raise click.ClickException(f"Deployment command exited with error code = {result.exit_code}") diff --git a/src/algokit/cli/init.py b/src/algokit/cli/init.py index 5c9797da..eee8e332 100644 --- a/src/algokit/cli/init.py +++ b/src/algokit/cli/init.py @@ -154,7 +154,7 @@ def validate_dir_name(context: click.Context, param: click.Parameter, value: str default=[], metavar=" ", ) -def init_command( +def init_command( # noqa: PLR0913 *, directory_name: str | None, template_name: str | None, @@ -287,7 +287,7 @@ def _maybe_bootstrap(project_path: Path, *, run_bootstrap: bool | None, use_defa # but if something goes wrong, we don't want to block try: project_minimum_algokit_version_check(project_path) - bootstrap_any_including_subdirs(project_path) + bootstrap_any_including_subdirs(project_path, ci_mode=False) except Exception as e: logger.error(f"Received an error while attempting bootstrap: {e}") logger.exception( diff --git a/src/algokit/core/bootstrap.py b/src/algokit/core/bootstrap.py index 841b98e6..16c45ac3 100644 --- a/src/algokit/core/bootstrap.py +++ b/src/algokit/core/bootstrap.py @@ -1,4 +1,5 @@ import logging +import os import platform import sys from collections.abc import Iterator @@ -6,32 +7,25 @@ from shutil import which import click - -if sys.version_info >= (3, 11): - import tomllib -else: - import tomli as tomllib from packaging import version from algokit.core import proc, questionary_extensions -from algokit.core.conf import get_current_package_version +from algokit.core.conf import ALGOKIT_CONFIG, get_algokit_config, get_current_package_version -ENV_TEMPLATE = ".env.template" -ALGOKIT_CONFIG = ".algokit.toml" +ENV_TEMPLATE_PATTERN = ".env*.template" logger = logging.getLogger(__name__) -def bootstrap_any(project_dir: Path) -> None: - env_path = project_dir / ENV_TEMPLATE +def bootstrap_any(project_dir: Path, *, ci_mode: bool) -> None: poetry_path = project_dir / "poetry.toml" pyproject_path = project_dir / "pyproject.toml" package_json_path = project_dir / "package.json" logger.debug(f"Checking {project_dir} for bootstrapping needs") - if env_path.exists(): + if next(project_dir.glob(ENV_TEMPLATE_PATTERN), None): logger.debug("Running `algokit bootstrap env`") - bootstrap_env(project_dir) + bootstrap_env(project_dir, ci_mode=ci_mode) if poetry_path.exists() or (pyproject_path.exists() and "[tool.poetry]" in pyproject_path.read_text("utf-8")): logger.debug("Running `algokit bootstrap poetry`") @@ -42,60 +36,75 @@ def bootstrap_any(project_dir: Path) -> None: bootstrap_npm(project_dir) -def bootstrap_any_including_subdirs(base_path: Path) -> None: - bootstrap_any(base_path) +def bootstrap_any_including_subdirs(base_path: Path, *, ci_mode: bool) -> None: + bootstrap_any(base_path, ci_mode=ci_mode) for sub_dir in sorted(base_path.iterdir()): # sort needed for test output ordering if sub_dir.is_dir(): if sub_dir.name.lower() in [".venv", "node_modules", "__pycache__"]: logger.debug(f"Skipping {sub_dir}") else: - bootstrap_any(sub_dir) - + bootstrap_any(sub_dir, ci_mode=ci_mode) -def bootstrap_env(project_dir: Path) -> None: - env_path = project_dir / ".env" - env_template_path = project_dir / ENV_TEMPLATE - if env_path.exists(): - logger.info(".env already exists; skipping bootstrap of .env") - return +def bootstrap_env(project_dir: Path, *, ci_mode: bool) -> None: + # List all .env*.template files in the directory + env_template_paths = sorted(project_dir.glob(ENV_TEMPLATE_PATTERN)) - logger.debug(f"{env_path} doesn't exist yet") - if not env_template_path.exists(): - logger.info("No .env or .env.template file; nothing to do here, skipping bootstrap of .env") + # If no template files found, log it + if not env_template_paths: + logger.info("No .env or .env.{network_name}.template files found; nothing to do here, skipping bootstrap.") return - logger.debug(f"{env_template_path} exists") - logger.info(f"Copying {env_template_path} to {env_path} and prompting for empty values") - # find all empty values in .env file and prompt the user for a value - with env_template_path.open(encoding="utf-8") as env_template_file, env_path.open( - mode="w", encoding="utf-8" - ) as env_file: - comment_lines: list[str] = [] - for line in env_template_file: - # strip newline character(s) from end of line for simpler handling - stripped_line = line.strip() - # if it is a comment line, keep it in var and continue - if stripped_line.startswith("#"): - comment_lines.append(line) - env_file.write(line) - # keep blank lines in output but don't accumulate them in comments - elif not stripped_line: - env_file.write(line) - else: - # lines not blank and not empty - var_name, *var_value = stripped_line.split("=", maxsplit=1) - # if it is an empty value, the user should be prompted for value with the comment line above - if var_value and not var_value[0]: - logger.info("".join(comment_lines)) - var_name = var_name.strip() - new_value = questionary_extensions.prompt_text(f"Please provide a value for {var_name}:") - env_file.write(f"{var_name}={new_value}\n") - else: - # this is a line with value, reset comment lines. + # Process each template file + for env_template_path in env_template_paths: + # Determine the output file name (strip .template suffix) + env_path = Path(env_template_path).with_suffix("") + + if env_path.exists(): + logger.info(f"{env_path.name} already exists; skipping bootstrap of {env_path.name}") + continue + + logger.debug(f"{env_path} doesn't exist yet") + logger.debug(f"{env_template_path} exists") + logger.info(f"Copying {env_template_path} to {env_path} and prompting for empty values") + + # find all empty values in .env file and prompt the user for a value + with Path(env_template_path).open(encoding="utf-8") as env_template_file, env_path.open( + mode="w", encoding="utf-8" + ) as env_file: + comment_lines: list[str] = [] + for line in env_template_file: + # strip newline character(s) from end of line for simpler handling + stripped_line = line.strip() + # if it is a comment line, keep it in var and continue + if stripped_line.startswith("#"): + comment_lines.append(line) + env_file.write(line) + # keep blank lines in output but don't accumulate them in comments + elif not stripped_line: env_file.write(line) - comment_lines = [] + else: + # lines not blank and not empty + var_name, *var_value = stripped_line.split("=", maxsplit=1) + # if it is an empty value, the user should be prompted for value with the comment line above + if var_value and not var_value[0]: + var_name = var_name.strip() + if not ci_mode: + logger.info("".join(comment_lines)) + new_value = questionary_extensions.prompt_text(f"Please provide a value for {var_name}:") + env_file.write(f"{var_name}={new_value}\n") + # In CI mode, we _don't_ prompt for values, because... it's CI + # we can omit the line entirely in the case of blank value, + # and just to be nice we can check to make sure the var is defined in the current + # env and if not, print a warning + # note that due to the multiple env files, this might be an aberrant warning as + # it might be for an .env.template that is not used in the current CI process? + elif var_name not in os.environ: + logger.warning(f"Prompt skipped for {var_name} due to CI mode, but this value is not set") + else: # this is a line with value + env_file.write(line) + comment_lines = [] def bootstrap_poetry(project_dir: Path) -> None: @@ -229,26 +238,16 @@ def _get_base_python_path() -> str | None: def get_min_algokit_version(project_dir: Path) -> str | None: + config = get_algokit_config(project_dir) + if config is None: + return None try: - config_path = project_dir / ALGOKIT_CONFIG - try: - config_text = config_path.read_text("utf-8") - except FileNotFoundError: - logger.debug(f"No {ALGOKIT_CONFIG} file found in the project directory.") - return None - - config = tomllib.loads(config_text) - - try: - min_version = config["algokit"]["min_version"] - except KeyError: - logger.debug(f"No 'min_version' specified in {ALGOKIT_CONFIG} file.") - return None - assert isinstance(min_version, str) - - return min_version + return str(config["algokit"]["min_version"]) + except KeyError: + logger.debug(f"No 'min_version' specified in {ALGOKIT_CONFIG} file.") + return None except Exception as ex: - logger.debug(f"Unexpected error inspecting AlgoKit config: {ex}") + logger.debug(f"Couldn't read algokit min_version from {ALGOKIT_CONFIG} file: {ex}", exc_info=True) return None diff --git a/src/algokit/core/conf.py b/src/algokit/core/conf.py index 0a7bd2ea..ec5878b3 100644 --- a/src/algokit/core/conf.py +++ b/src/algokit/core/conf.py @@ -1,9 +1,20 @@ +import logging import os import platform +import sys +import typing as t from importlib import metadata from pathlib import Path +if sys.version_info >= (3, 11): + import tomllib +else: + import tomli as tomllib + PACKAGE_NAME = "algokit" +ALGOKIT_CONFIG = ".algokit.toml" + +logger = logging.getLogger(__name__) def get_app_config_dir() -> Path: @@ -42,3 +53,27 @@ def _get_relative_app_path(base_dir: str) -> Path: def get_current_package_version() -> str: return metadata.version(PACKAGE_NAME) + + +def get_algokit_config(project_dir: Path) -> dict[str, t.Any] | None: + """ + Load and parse a TOML configuration file. Will never throw. + :param project_dir: Project directory path. + :return: A dictionary containing the configuration or None if not found. + """ + config_path = project_dir / ALGOKIT_CONFIG + logger.debug(f"Attempting to load project config from {config_path}") + try: + config_text = config_path.read_text("utf-8") + except FileNotFoundError: + logger.debug(f"No {ALGOKIT_CONFIG} file found in the project directory.") + return None + except Exception as ex: + logger.debug(f"Unexpected error reading {ALGOKIT_CONFIG} file: {ex}", exc_info=True) + return None + + try: + return tomllib.loads(config_text) + except Exception as ex: + logger.debug(f"Error parsing {ALGOKIT_CONFIG} file: {ex}", exc_info=True) + return None diff --git a/src/algokit/core/deploy.py b/src/algokit/core/deploy.py new file mode 100644 index 00000000..871386e7 --- /dev/null +++ b/src/algokit/core/deploy.py @@ -0,0 +1,95 @@ +import dataclasses +import logging +import platform +from pathlib import Path + +import click +import dotenv + +from algokit.core.conf import ALGOKIT_CONFIG, get_algokit_config + +logger = logging.getLogger(__name__) + + +def load_env_files(name: str | None, project_dir: Path) -> dict[str, str | None]: + """ + Load the deploy configuration for the given network. + :param name: Network name. + :param project_dir: Project directory path. + """ + general_env_path = project_dir / ".env" + result: dict[str, str | None] = {} + if general_env_path.exists(): + result = dotenv.dotenv_values(general_env_path, verbose=True) + if name is not None: + specific_env_path = project_dir / f".env.{name}" + if not specific_env_path.exists(): + raise click.ClickException(f"No such file: {specific_env_path}") + result |= dotenv.dotenv_values(specific_env_path, verbose=True) + return result + + +@dataclasses.dataclass(kw_only=True) +class DeployConfig: + command: list[str] | None = None + environment_secrets: list[str] | None = None + + +def load_deploy_config(name: str | None, project_dir: Path) -> DeployConfig: + """ + Load the deploy command for the given network/environment from .algokit.toml file. + :param name: Network or environment name. + :param project_dir: Project directory path. + :return: Deploy command. + """ + + # Load and parse the TOML configuration file + config = get_algokit_config(project_dir) + + deploy_config = DeployConfig() + + if config is None: + # in the case of no algokit toml file, we return the (empty) defaults + return deploy_config + + # ensure there is at least some config under [deploy] and that it's a dict type + # (which should implicitly exist even if only [deploy.{name}] exists) + match deploy_table := config.get("deploy"): + case dict(): + pass # expected case if there is a file with deploy config + case None: + return deploy_config # file has no deploy config, we return with (empty) defaults + case _: + raise click.ClickException(f"Bad data for deploy in '{ALGOKIT_CONFIG}' file: {deploy_table}") + + assert isinstance(deploy_table, dict) # because mypy is not all-knowing + + for tbl in [deploy_table, deploy_table.get(name)]: + match tbl: + case {"command": str(command)}: + try: + deploy_config.command = parse_command(command) + except Exception as ex: + raise click.ClickException(f"Failed to parse command '{command}': {ex}") from ex + case {"command": list(command_parts)}: + deploy_config.command = [str(x) for x in command_parts] + case {"command": bad_data}: + raise click.ClickException(f"Invalid data provided under 'command' key: {bad_data}") + match tbl: + case {"environment_secrets": list(env_names)}: + deploy_config.environment_secrets = [str(x) for x in env_names] + case {"environment_secrets": bad_data}: + raise click.ClickException(f"Invalid data provided under 'environment_secrets' key: {bad_data}") + + return deploy_config + + +def parse_command(command: str) -> list[str]: + if platform.system() == "Windows": + import mslex + + return mslex.split(command) + else: + import shlex + + return shlex.split(command) diff --git a/src/algokit/core/log_handlers.py b/src/algokit/core/log_handlers.py index c9d1adf3..d5f3235b 100644 --- a/src/algokit/core/log_handlers.py +++ b/src/algokit/core/log_handlers.py @@ -3,7 +3,7 @@ import sys from logging.handlers import RotatingFileHandler from types import TracebackType -from typing import Any +from typing import Any, ClassVar import click from click.globals import resolve_color_default @@ -27,7 +27,7 @@ class ClickHandler(logging.Handler): but they're kind of intertwined for our use case of actually displaying things to the user. """ - styles: dict[str, dict[str, Any]] = { + styles: ClassVar[dict[str, dict[str, Any]]] = { "critical": {"fg": "red", "bold": True}, "error": {"fg": "red"}, "warning": {"fg": "yellow"}, diff --git a/src/algokit/core/proc.py b/src/algokit/core/proc.py index 6a51ba7c..56dbb2a0 100644 --- a/src/algokit/core/proc.py +++ b/src/algokit/core/proc.py @@ -20,7 +20,7 @@ class RunResult: output: str -def run( +def run( # noqa: PLR0913 command: list[str], *, cwd: Path | None = None, diff --git a/src/algokit/core/typed_client_generation.py b/src/algokit/core/typed_client_generation.py index df653227..41d6e657 100644 --- a/src/algokit/core/typed_client_generation.py +++ b/src/algokit/core/typed_client_generation.py @@ -27,8 +27,8 @@ class ClientGenerator(abc.ABC): language: ClassVar[str] extension: ClassVar[str] - _by_language: dict[str, type["ClientGenerator"]] = {} - _by_extension: dict[str, type["ClientGenerator"]] = {} + _by_language: ClassVar[dict[str, type["ClientGenerator"]]] = {} + _by_extension: ClassVar[dict[str, type["ClientGenerator"]]] = {} def __init_subclass__(cls, language: str, extension: str) -> None: cls.language = language diff --git a/tests/bootstrap/test_bootstrap_all.py b/tests/bootstrap/test_bootstrap_all.py index e03770bf..b8606733 100644 --- a/tests/bootstrap/test_bootstrap_all.py +++ b/tests/bootstrap/test_bootstrap_all.py @@ -1,7 +1,6 @@ import pytest from _pytest.tmpdir import TempPathFactory -from algokit.core.bootstrap import ALGOKIT_CONFIG -from algokit.core.conf import get_current_package_version +from algokit.core.conf import ALGOKIT_CONFIG, get_current_package_version from approvaltests.pytest.py_test_namer import PyTestNamer from tests.utils.approvals import verify diff --git a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version.approved.txt b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version.approved.txt index 4d921124..2e16ac99 100644 --- a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version.approved.txt +++ b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version.approved.txt @@ -1 +1,2 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml Error: This template requires AlgoKit version 999.99.99 or higher, but you have AlgoKit version {current_version}. Please update AlgoKit. diff --git a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version_ignore_error.approved.txt b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version_ignore_error.approved.txt index e87d11d5..ac51e6ec 100644 --- a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version_ignore_error.approved.txt +++ b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_algokit_min_version_ignore_error.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml WARNING: This template requires AlgoKit version 999.99.99 or higher, but you have AlgoKit version {current_version}. Please update AlgoKit. DEBUG: Checking {current_working_directory} for bootstrapping needs Finished bootstrapping {current_working_directory} diff --git a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_empty.approved.txt b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_empty.approved.txt index d0a2e571..63a5f23a 100644 --- a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_empty.approved.txt +++ b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_empty.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Checking {current_working_directory} for bootstrapping needs Finished bootstrapping {current_working_directory} diff --git a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_env.approved.txt b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_env.approved.txt index 95f6a3d3..4dda6244 100644 --- a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_env.approved.txt +++ b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_env.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Checking {current_working_directory} for bootstrapping needs DEBUG: Running `algokit bootstrap env` diff --git a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[linux].approved.txt b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[linux].approved.txt index 839745e4..d8321bd0 100644 --- a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[linux].approved.txt +++ b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[linux].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Checking {current_working_directory} for bootstrapping needs DEBUG: Running `algokit bootstrap npm` diff --git a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[macOS].approved.txt b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[macOS].approved.txt index 839745e4..d8321bd0 100644 --- a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[macOS].approved.txt +++ b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[macOS].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Checking {current_working_directory} for bootstrapping needs DEBUG: Running `algokit bootstrap npm` diff --git a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[windows].approved.txt b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[windows].approved.txt index 37e1d3f5..eb34192c 100644 --- a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[windows].approved.txt +++ b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_npm[windows].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Checking {current_working_directory} for bootstrapping needs DEBUG: Running `algokit bootstrap npm` diff --git a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry.approved.txt b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry.approved.txt index 3e248e54..8a927642 100644 --- a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry.approved.txt +++ b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Checking {current_working_directory} for bootstrapping needs DEBUG: Running `algokit bootstrap poetry` diff --git a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry_via_pyproject.approved.txt b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry_via_pyproject.approved.txt index 3e248e54..8a927642 100644 --- a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry_via_pyproject.approved.txt +++ b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_poetry_via_pyproject.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Checking {current_working_directory} for bootstrapping needs DEBUG: Running `algokit bootstrap poetry` diff --git a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_skip_dirs.approved.txt b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_skip_dirs.approved.txt index e5e31c46..a68c27e0 100644 --- a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_skip_dirs.approved.txt +++ b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_skip_dirs.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Checking {current_working_directory} for bootstrapping needs DEBUG: Skipping {current_working_directory}/.venv diff --git a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_sub_dir.approved.txt b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_sub_dir.approved.txt index deff2854..b11814da 100644 --- a/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_sub_dir.approved.txt +++ b/tests/bootstrap/test_bootstrap_all.test_bootstrap_all_sub_dir.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Checking {current_working_directory} for bootstrapping needs DEBUG: Checking {current_working_directory}/empty_dir for bootstrapping needs diff --git a/tests/bootstrap/test_bootstrap_env.py b/tests/bootstrap/test_bootstrap_env.py index c42bfc1b..7636f031 100644 --- a/tests/bootstrap/test_bootstrap_env.py +++ b/tests/bootstrap/test_bootstrap_env.py @@ -1,6 +1,7 @@ import click import pytest from _pytest.tmpdir import TempPathFactory +from approvaltests.namer import NamerFactory from approvaltests.scrubbers.scrubbers import Scrubber from prompt_toolkit.input import PipeInput @@ -28,6 +29,46 @@ def test_bootstrap_env_no_files(tmp_path_factory: TempPathFactory) -> None: def test_bootstrap_env_dotenv_exists(tmp_path_factory: TempPathFactory) -> None: cwd = tmp_path_factory.mktemp("cwd") (cwd / ".env").touch() + (cwd / ".env.template").touch() + + result = invoke( + "bootstrap env", + cwd=cwd, + ) + + assert result.exit_code == 0 + verify(result.output) + + +@pytest.mark.parametrize( + "env_file_name", + [ + ".env.localnet.template", + ".env.template", + ".env.localnet", + ".env", + ], +) +def test_bootstrap_network_prefixed_envs(env_file_name: str, tmp_path_factory: TempPathFactory) -> None: + cwd = tmp_path_factory.mktemp("cwd") + (cwd / env_file_name).touch() + if not env_file_name.endswith(".template"): + (cwd / f"{env_file_name}.template").touch() + + result = invoke( + "bootstrap env", + cwd=cwd, + ) + + assert result.exit_code == 0 + verify(result.output, options=NamerFactory.with_parameters(env_file_name)) + + +def test_bootstrap_env_multiple_templates(tmp_path_factory: TempPathFactory) -> None: + cwd = tmp_path_factory.mktemp("cwd") + (cwd / ".env.template").touch() + (cwd / ".env.localnet.template").touch() + (cwd / ".env.testnet.template").touch() result = invoke( "bootstrap env", @@ -64,8 +105,8 @@ def test_bootstrap_env_dotenv_with_values(tmp_path_factory: TempPathFactory) -> TOKEN_4_WITH_NO_EQUALS_SIGN # another comment -TOKEN_5_SPECIAL_CHAR=* -""" # noqa: W291 +TOKEN_5_SPECIAL_CHAR=* +""" ) result = invoke( @@ -79,7 +120,7 @@ def test_bootstrap_env_dotenv_with_values(tmp_path_factory: TempPathFactory) -> @pytest.mark.mock_platform_system("Darwin") def test_bootstrap_env_dotenv_different_prompt_scenarios( - tmp_path_factory: TempPathFactory, mock_questionary_input: PipeInput + tmp_path_factory: TempPathFactory, mock_questionary_input: PipeInput, monkeypatch: pytest.MonkeyPatch ) -> None: cwd = tmp_path_factory.mktemp("cwd") (cwd / ".env.template").write_text( @@ -91,16 +132,18 @@ def test_bootstrap_env_dotenv_different_prompt_scenarios( TOKEN_2_WITH_MULTI_LINES_COMMENT= TOKEN_3=test value -TOKEN_4_WITH_SPACES = +TOKEN_4_WITH_SPACES = TOKEN_5_WITHOUT_COMMENT= TOKEN_WITH_NO_EQUALS_SIGN # another comment TOKEN_6_EMPTY_WITH_COMMENT= TOKEN_7_VALUE_WILL_BE_EMPTY= TOKEN_8 = value with spaces -TOKEN_8_SPECIAL_CHAR=* -""" # noqa: W291 +TOKEN_8_SPECIAL_CHAR=* +""" ) + # remove ci flag from env (when running in github actions) + monkeypatch.delenv("CI", raising=False) # provide values for tokens mock_questionary_input.send_text("test value for TOKEN_2_WITH_MULTI_LINES_COMMENT") diff --git a/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_different_prompt_scenarios.approved.txt b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_different_prompt_scenarios.approved.txt index 8edcd6dc..ea196028 100644 --- a/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_different_prompt_scenarios.approved.txt +++ b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_different_prompt_scenarios.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: {current_working_directory}/.env doesn't exist yet DEBUG: {current_working_directory}/.env.template exists @@ -33,4 +34,4 @@ TOKEN_WITH_NO_EQUALS_SIGN TOKEN_6_EMPTY_WITH_COMMENT=test value for TOKEN_6_EMPTY_WITH_COMMENT TOKEN_7_VALUE_WILL_BE_EMPTY= TOKEN_8 = value with spaces -TOKEN_8_SPECIAL_CHAR=* +TOKEN_8_SPECIAL_CHAR=* diff --git a/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_exists.approved.txt b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_exists.approved.txt index 9da720da..4287df7f 100644 --- a/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_exists.approved.txt +++ b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_exists.approved.txt @@ -1,2 +1,3 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. .env already exists; skipping bootstrap of .env diff --git a/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_missing_template_exists.approved.txt b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_missing_template_exists.approved.txt index 6179c5a3..49e3f94c 100644 --- a/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_missing_template_exists.approved.txt +++ b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_missing_template_exists.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: {current_working_directory}/.env doesn't exist yet DEBUG: {current_working_directory}/.env.template exists diff --git a/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_with_values.approved.txt b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_with_values.approved.txt index 848347cb..d3b04343 100644 --- a/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_with_values.approved.txt +++ b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_dotenv_with_values.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: {current_working_directory}/.env doesn't exist yet DEBUG: {current_working_directory}/.env.template exists @@ -14,4 +15,4 @@ TOKEN_3=test value with spaces TOKEN_4_WITH_NO_EQUALS_SIGN # another comment -TOKEN_5_SPECIAL_CHAR=* +TOKEN_5_SPECIAL_CHAR=* diff --git a/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_multiple_templates.approved.txt b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_multiple_templates.approved.txt new file mode 100644 index 00000000..3ae31ea5 --- /dev/null +++ b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_multiple_templates.approved.txt @@ -0,0 +1,11 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +DEBUG: No .algokit.toml file found in the project directory. +DEBUG: {current_working_directory}/.env.localnet doesn't exist yet +DEBUG: {current_working_directory}/.env.localnet.template exists +Copying {current_working_directory}/.env.localnet.template to {current_working_directory}/.env.localnet and prompting for empty values +DEBUG: {current_working_directory}/.env doesn't exist yet +DEBUG: {current_working_directory}/.env.template exists +Copying {current_working_directory}/.env.template to {current_working_directory}/.env and prompting for empty values +DEBUG: {current_working_directory}/.env.testnet doesn't exist yet +DEBUG: {current_working_directory}/.env.testnet.template exists +Copying {current_working_directory}/.env.testnet.template to {current_working_directory}/.env.testnet and prompting for empty values diff --git a/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_no_files.approved.txt b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_no_files.approved.txt index d9376151..243e6883 100644 --- a/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_no_files.approved.txt +++ b/tests/bootstrap/test_bootstrap_env.test_bootstrap_env_no_files.approved.txt @@ -1,3 +1,3 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. -DEBUG: {current_working_directory}/.env doesn't exist yet -No .env or .env.template file; nothing to do here, skipping bootstrap of .env +No .env or .env.{network_name}.template files found; nothing to do here, skipping bootstrap. diff --git a/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_env_dotenv_exists.approved.txt b/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_env_dotenv_exists.approved.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.approved.txt b/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.approved.txt new file mode 100644 index 00000000..4287df7f --- /dev/null +++ b/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.approved.txt @@ -0,0 +1,3 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +DEBUG: No .algokit.toml file found in the project directory. +.env already exists; skipping bootstrap of .env diff --git a/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.approved.txt b/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.approved.txt new file mode 100644 index 00000000..64291a77 --- /dev/null +++ b/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.approved.txt @@ -0,0 +1,3 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +DEBUG: No .algokit.toml file found in the project directory. +.env.localnet already exists; skipping bootstrap of .env.localnet diff --git a/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.template.approved.txt b/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.template.approved.txt new file mode 100644 index 00000000..6405284c --- /dev/null +++ b/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.localnet.template.approved.txt @@ -0,0 +1,5 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +DEBUG: No .algokit.toml file found in the project directory. +DEBUG: {current_working_directory}/.env.localnet doesn't exist yet +DEBUG: {current_working_directory}/.env.localnet.template exists +Copying {current_working_directory}/.env.localnet.template to {current_working_directory}/.env.localnet and prompting for empty values diff --git a/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.template.approved.txt b/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.template.approved.txt new file mode 100644 index 00000000..d855a692 --- /dev/null +++ b/tests/bootstrap/test_bootstrap_env.test_bootstrap_network_prefixed_envs..env.template.approved.txt @@ -0,0 +1,5 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +DEBUG: No .algokit.toml file found in the project directory. +DEBUG: {current_working_directory}/.env doesn't exist yet +DEBUG: {current_working_directory}/.env.template exists +Copying {current_working_directory}/.env.template to {current_working_directory}/.env and prompting for empty values diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[linux].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[linux].approved.txt index d7e42dfb..730e0036 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[linux].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[linux].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Installing npm dependencies DEBUG: Running 'npm install' in '{current_working_directory}' diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[macOS].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[macOS].approved.txt index d7e42dfb..730e0036 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[macOS].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[macOS].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Installing npm dependencies DEBUG: Running 'npm install' in '{current_working_directory}' diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[windows].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[windows].approved.txt index 7eae20e8..142f4ef0 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[windows].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_happy_path[windows].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Installing npm dependencies DEBUG: Running 'npm.cmd install' in '{current_working_directory}' diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[linux].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[linux].approved.txt index 4618a9f9..437d6c53 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[linux].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[linux].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Installing npm dependencies DEBUG: Running 'npm install' in '{current_working_directory}' diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[macOS].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[macOS].approved.txt index 4618a9f9..437d6c53 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[macOS].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[macOS].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Installing npm dependencies DEBUG: Running 'npm install' in '{current_working_directory}' diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[windows].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[windows].approved.txt index 59703785..72b8ec57 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[windows].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm[windows].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Installing npm dependencies DEBUG: Running 'npm.cmd install' in '{current_working_directory}' diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[linux].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[linux].approved.txt index e7c8f368..019f040e 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[linux].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[linux].approved.txt @@ -1,2 +1,3 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. {current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[macOS].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[macOS].approved.txt index e7c8f368..019f040e 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[macOS].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[macOS].approved.txt @@ -1,2 +1,3 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. {current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[windows].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[windows].approved.txt index e7c8f368..019f040e 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[windows].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_npm_and_package_file[windows].approved.txt @@ -1,2 +1,3 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. {current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[linux].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[linux].approved.txt index e7c8f368..019f040e 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[linux].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[linux].approved.txt @@ -1,2 +1,3 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. {current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[macOS].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[macOS].approved.txt index e7c8f368..019f040e 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[macOS].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[macOS].approved.txt @@ -1,2 +1,3 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. {current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm diff --git a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[windows].approved.txt b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[windows].approved.txt index e7c8f368..019f040e 100644 --- a/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[windows].approved.txt +++ b/tests/bootstrap/test_bootstrap_npm.test_bootstrap_npm_without_package_file[windows].approved.txt @@ -1,2 +1,3 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. {current_working_directory}/package.json doesn't exist; nothing to do here, skipping bootstrap of npm diff --git a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_with_poetry.approved.txt b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_with_poetry.approved.txt index 8ad86336..26cf7d13 100644 --- a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_with_poetry.approved.txt +++ b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_with_poetry.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Running 'poetry --version' in '{current_working_directory}' DEBUG: poetry: STDOUT diff --git a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry.approved.txt b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry.approved.txt index 718d8416..97f8eda8 100644 --- a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry.approved.txt +++ b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Running 'poetry --version' in '{current_working_directory}' Poetry not found; attempting to install it... diff --git a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_install.approved.txt b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_install.approved.txt index 9fb32d2f..887df346 100644 --- a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_install.approved.txt +++ b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_install.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Running 'poetry --version' in '{current_working_directory}' Poetry not found; attempting to install it... diff --git a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_poetry_path.approved.txt b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_poetry_path.approved.txt index a960d9d3..a0227240 100644 --- a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_poetry_path.approved.txt +++ b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_failed_poetry_path.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Running 'poetry --version' in '{current_working_directory}' Poetry not found; attempting to install it... diff --git a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[no_system_pythons].approved.txt b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[no_system_pythons].approved.txt index 0ee4e125..678604a2 100644 --- a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[no_system_pythons].approved.txt +++ b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[no_system_pythons].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Running 'poetry --version' in '{current_working_directory}' Poetry not found; attempting to install it... diff --git a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python3_only].approved.txt b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python3_only].approved.txt index d15efb6d..c28413d1 100644 --- a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python3_only].approved.txt +++ b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python3_only].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Running 'poetry --version' in '{current_working_directory}' Poetry not found; attempting to install it... diff --git a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_and_python3].approved.txt b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_and_python3].approved.txt index d15efb6d..c28413d1 100644 --- a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_and_python3].approved.txt +++ b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_and_python3].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Running 'poetry --version' in '{current_working_directory}' Poetry not found; attempting to install it... diff --git a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_only].approved.txt b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_only].approved.txt index 8eee9e91..7639ef69 100644 --- a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_only].approved.txt +++ b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path[python_only].approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Running 'poetry --version' in '{current_working_directory}' Poetry not found; attempting to install it... diff --git a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_install.approved.txt b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_install.approved.txt index 47ec5aef..d2000bab 100644 --- a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_install.approved.txt +++ b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_install.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Running 'poetry --version' in '{current_working_directory}' Poetry not found; attempting to install it... diff --git a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_poetry_path.approved.txt b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_poetry_path.approved.txt index e12d5d0b..fb9907ef 100644 --- a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_poetry_path.approved.txt +++ b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_failed_poetry_path.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Running 'poetry --version' in '{current_working_directory}' Poetry not found; attempting to install it... diff --git a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_or_pipx_module.approved.txt b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_or_pipx_module.approved.txt index 2edb12cb..db6ab3cc 100644 --- a/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_or_pipx_module.approved.txt +++ b/tests/bootstrap/test_bootstrap_poetry.test_bootstrap_poetry_without_poetry_or_pipx_path_or_pipx_module.approved.txt @@ -1,3 +1,4 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Running 'poetry --version' in '{current_working_directory}' Poetry not found; attempting to install it... diff --git a/tests/deploy/__init__.py b/tests/deploy/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/deploy/test_deploy.py b/tests/deploy/test_deploy.py new file mode 100644 index 00000000..564a1743 --- /dev/null +++ b/tests/deploy/test_deploy.py @@ -0,0 +1,374 @@ +import sys +from pathlib import Path + +import pytest +from _pytest.tmpdir import TempPathFactory +from algokit.core.conf import ALGOKIT_CONFIG +from pytest_mock import MockerFixture + +from tests.utils.approvals import verify +from tests.utils.click_invoker import invoke +from tests.utils.proc_mock import ProcMock + +PYTHON_EXECUTABLE = sys.executable +# need to use an escaped python executable path in config files for windows +PYTHON_EXECUTABLE_ESCAPED = PYTHON_EXECUTABLE.replace("\\", "\\\\") +# note: spaces around the string inside print are important, +# we need to test the usage of shlex.split vs str.split, to handle +# splitting inside quotes properly +TEST_PYTHON_COMMAND = "print(' test_command_invocation ')" + + +def test_algokit_config_empty_array(tmp_path_factory: TempPathFactory) -> None: + empty_array_config = """ +[deploy] +command = [] + """.strip() + + cwd = tmp_path_factory.mktemp("cwd") + (cwd / ALGOKIT_CONFIG).write_text(empty_array_config, encoding="utf-8") + (cwd / ".env").touch() + result = invoke(["deploy"], cwd=cwd) + + assert result.exit_code != 0 + verify(result.output) + + +def test_algokit_config_invalid_syntax(tmp_path_factory: TempPathFactory) -> None: + invalid_config = """ +{"dummy": "json"} + """.strip() + + cwd = tmp_path_factory.mktemp("cwd") + (cwd / ALGOKIT_CONFIG).write_text(invalid_config, encoding="utf-8") + (cwd / ".env").touch() + result = invoke(["deploy"], cwd=cwd) + + assert result.exit_code != 0 + verify(result.output) + + +def test_algokit_config_name_overrides(tmp_path_factory: TempPathFactory, proc_mock: ProcMock) -> None: + config_with_override = """ +[deploy] +command = "command_a" + +[deploy.localnet] +command = "command_b" + +[deploy.testnet] +command = "command_c" + """.strip() + cwd = tmp_path_factory.mktemp("cwd") + (cwd / ALGOKIT_CONFIG).write_text(config_with_override, encoding="utf-8") + (cwd / ".env").touch() + (cwd / ".env.localnet").touch() + (cwd / ".env.testnet").touch() + + proc_mock.set_output(["command_c"], ["picked testnet"]) + + result = invoke(["deploy", "testnet"], cwd=cwd) + + assert result.exit_code == 0 + verify(result.output) + + +def test_algokit_config_name_no_base(tmp_path_factory: TempPathFactory, proc_mock: ProcMock) -> None: + config_with_override = """ +[deploy.localnet] +command = "command_a" + +[deploy.testnet] +command = "command_b" + """.strip() + cwd = tmp_path_factory.mktemp("cwd") + (cwd / ALGOKIT_CONFIG).write_text(config_with_override, encoding="utf-8") + (cwd / ".env.localnet").touch() + (cwd / ".env.testnet").touch() + + proc_mock.set_output(["command_a"], ["picked localnet"]) + + result = invoke(["deploy", "localnet"], cwd=cwd) + + assert result.exit_code == 0 + verify(result.output) + + +def test_command_invocation_and_command_splitting(tmp_path: Path) -> None: + config_data = """ +[deploy] +command = ["not", "used"] + """.strip() + (tmp_path / ALGOKIT_CONFIG).write_text(config_data, encoding="utf-8") + result = invoke( + [ + "deploy", + "--command", + f'{PYTHON_EXECUTABLE} -c "{TEST_PYTHON_COMMAND}"', + ], + cwd=tmp_path, + ) + assert result.exit_code == 0 + verify(result.output.replace(PYTHON_EXECUTABLE, "")) + + +def test_command_splitting_from_config(tmp_path: Path) -> None: + # note: spaces around the string inside print are important, + # we need to test the usage of shlex.split vs str.split, to handle + # splitting inside quotes properly + config_data = rf""" +[deploy] +command = "{PYTHON_EXECUTABLE_ESCAPED} -c \"{TEST_PYTHON_COMMAND}\"" + """.strip() + (tmp_path / ALGOKIT_CONFIG).write_text(config_data, encoding="utf-8") + result = invoke("deploy", cwd=tmp_path) + assert result.exit_code == 0 + verify(result.output.replace(PYTHON_EXECUTABLE, "")) + + +def test_command_without_splitting_from_config(tmp_path: Path) -> None: + # note: spaces around the string inside print are important, + # we need to test the usage of shlex.split vs str.split, to handle + # splitting inside quotes properly + config_data = rf""" +[deploy] +command = ["{PYTHON_EXECUTABLE_ESCAPED}", "-c", "{TEST_PYTHON_COMMAND}"] + """.strip() + (tmp_path / ALGOKIT_CONFIG).write_text(config_data, encoding="utf-8") + result = invoke("deploy", cwd=tmp_path) + assert result.exit_code == 0 + verify(result.output.replace(PYTHON_EXECUTABLE, "")) + + +def test_command_not_found_and_no_config(proc_mock: ProcMock) -> None: + cmd = "gm" + proc_mock.should_fail_on([cmd]) + result = invoke(["deploy", "--command", cmd]) + assert result.exit_code != 0 + verify(result.output) + + +def test_command_not_executable(proc_mock: ProcMock) -> None: + cmd = "gm" + proc_mock.should_deny_on([cmd]) + result = invoke(["deploy", "--command", cmd]) + assert result.exit_code != 0 + verify(result.output) + + +def test_command_bad_exit_code(proc_mock: ProcMock) -> None: + cmd = "gm" + proc_mock.should_bad_exit_on([cmd], output=["it is not morning"]) + result = invoke(["deploy", "--command", cmd]) + assert result.exit_code != 0 + verify(result.output) + + +def test_algokit_env_name_missing(tmp_path_factory: TempPathFactory) -> None: + config_with_override = """ +[deploy.localnet] +command = "command_a" + """.strip() + cwd = tmp_path_factory.mktemp("cwd") + (cwd / ALGOKIT_CONFIG).write_text(config_with_override, encoding="utf-8") + (cwd / ".env").touch() + + result = invoke(["deploy", "localnet"], cwd=cwd) + + assert result.exit_code == 1 + verify(result.output) + + +def test_algokit_env_and_name_correct_set( + tmp_path_factory: TempPathFactory, proc_mock: ProcMock, monkeypatch: pytest.MonkeyPatch +) -> None: + env_config = """ +ENV_A=GENERIC_ENV_A +ENV_B=GENERIC_ENV_B +ENV_C=GENERIC_ENV_C + """.strip() + + env_name_config = """ +ENV_A=LOCALNET_ENV_A +ENV_B=LOCALNET_ENV_B + """.strip() + + monkeypatch.setenv("ENV_A", "ENVIRON_ENV_A") + + config_with_deploy_name = """ +[deploy] +command = "command_a" + +[deploy.localnet] +command = "command_b" + """.strip() + + cwd = tmp_path_factory.mktemp("cwd") + (cwd / ALGOKIT_CONFIG).write_text(config_with_deploy_name, encoding="utf-8") + (cwd / ".env").write_text(env_config, encoding="utf-8") + (cwd / ".env.localnet").write_text(env_name_config, encoding="utf-8") + + proc_mock.set_output(["command_b"], ["picked localnet"]) + + result = invoke(["deploy", "localnet"], cwd=cwd) + + assert proc_mock.called[0].env + passed_env_vars = proc_mock.called[0].env + + assert passed_env_vars["ENV_A"] == "ENVIRON_ENV_A" # os.environ is highest loading priority + assert passed_env_vars["ENV_B"] == "LOCALNET_ENV_B" # then .env.{name} + assert passed_env_vars["ENV_C"] == "GENERIC_ENV_C" # lastly .env + + verify(result.output) + + +def test_algokit_deploy_only_base_deploy_config(tmp_path_factory: TempPathFactory, proc_mock: ProcMock) -> None: + config_with_only_base_deploy = """ +[deploy] +command = "command_a" + """.strip() + + env_config = """ +ENV_A=GENERIC_ENV_A + """.strip() + + cwd = tmp_path_factory.mktemp("cwd") + (cwd / ALGOKIT_CONFIG).write_text(config_with_only_base_deploy, encoding="utf-8") + (cwd / ".env").write_text(env_config, encoding="utf-8") + + proc_mock.set_output(["command_a"], ["picked base deploy command"]) + + result = invoke(["deploy"], cwd=cwd) + + assert result.exit_code == 0 + assert proc_mock.called[0].env + passed_env_vars = proc_mock.called[0].env + + assert passed_env_vars["ENV_A"] == "GENERIC_ENV_A" + + verify(result.output) + + +def test_ci_flag_interactivity_mode_via_env( + tmp_path_factory: TempPathFactory, mocker: MockerFixture, monkeypatch: pytest.MonkeyPatch, proc_mock: ProcMock +) -> None: + monkeypatch.setenv("CI", "true") + cwd = tmp_path_factory.mktemp("cwd") + + mock_prompt = mocker.patch("click.prompt") + + config_with_only_base_deploy = """ +[deploy] +command = "command_a" +environment_secrets = [ + "DEPLOYER_MNEMONIC" +] + """.strip() + + cwd = tmp_path_factory.mktemp("cwd") + (cwd / ALGOKIT_CONFIG).write_text(config_with_only_base_deploy, encoding="utf-8") + (cwd / ".env").touch() + + proc_mock.set_output(["command_a"], ["picked base deploy command"]) + + result = invoke(["deploy"], cwd=cwd) + + mock_prompt.assert_not_called() + assert result.exit_code != 0 + + verify(result.output) + + +def test_ci_flag_interactivity_mode_via_cli( + tmp_path_factory: TempPathFactory, mocker: MockerFixture, proc_mock: ProcMock +) -> None: + cwd = tmp_path_factory.mktemp("cwd") + + mock_prompt = mocker.patch("click.prompt") + + config_with_only_base_deploy = """ +[deploy] +command = "command_a" +environment_secrets = [ + "DEPLOYER_MNEMONIC" +] + """.strip() + + cwd = tmp_path_factory.mktemp("cwd") + (cwd / ALGOKIT_CONFIG).write_text(config_with_only_base_deploy, encoding="utf-8") + (cwd / ".env").touch() + + proc_mock.set_output(["command_a"], ["picked base deploy command"]) + + result = invoke(["deploy", "--ci"], cwd=cwd) + + mock_prompt.assert_not_called() + assert result.exit_code != 0 + + verify(result.output) + + +# environment_secrets set +def test_secrets_prompting_via_stdin( + tmp_path_factory: TempPathFactory, mocker: MockerFixture, proc_mock: ProcMock, monkeypatch: pytest.MonkeyPatch +) -> None: + # ensure Github Actions CI env var is not overriding behavior + monkeypatch.delenv("CI", raising=False) + + # mock click.prompt + cwd = tmp_path_factory.mktemp("cwd") + + mock_prompt = mocker.patch("click.prompt", return_value="secret_value") + config_with_only_base_deploy = """ +[deploy] +command = "command_a" +environment_secrets = [ + "DEPLOYER_MNEMONIC" +] + """.strip() + + cwd = tmp_path_factory.mktemp("cwd") + (cwd / ALGOKIT_CONFIG).write_text(config_with_only_base_deploy, encoding="utf-8") + (cwd / ".env").touch() + proc_mock.set_output(["command_a"], ["picked base deploy command"]) + + result = invoke(["deploy"], cwd=cwd) + mock_prompt.assert_called_once() # ensure called + assert result.exit_code == 0 # ensure success + + # assert that entered value is passed to proc run + assert proc_mock.called[0].env + called_env = proc_mock.called[0].env + assert "DEPLOYER_MNEMONIC" in called_env + assert called_env["DEPLOYER_MNEMONIC"] == "secret_value" + + verify(result.output) + + +def test_deploy_custom_project_dir( + tmp_path_factory: TempPathFactory, + proc_mock: ProcMock, +) -> None: + cwd = tmp_path_factory.mktemp("cwd") + custom_folder = cwd / "custom_folder" + + custom_folder.mkdir() + (custom_folder / ALGOKIT_CONFIG).write_text( + """ +[deploy] +command = "command_a" + """.strip(), + encoding="utf-8", + ) + (custom_folder / ".env.testnet").touch() + proc_mock.set_output(["command_a"], ["picked base deploy command"]) + + input_answers = ["N"] + + # Below is needed for escpaing the backslash in the path on Windows + # Works on Linux as well since \\ doesnt exist in the path in such cases + path = str(custom_folder.absolute()).replace("\\", r"\\") + result = invoke(f"deploy testnet --path={path}", cwd=cwd, input="\n".join(input_answers)) + + assert result.exit_code == 0 + verify(result.output) diff --git a/tests/deploy/test_deploy.test_algokit_config_empty_array.approved.txt b/tests/deploy/test_deploy.test_algokit_config_empty_array.approved.txt new file mode 100644 index 00000000..19b23e52 --- /dev/null +++ b/tests/deploy/test_deploy.test_algokit_config_empty_array.approved.txt @@ -0,0 +1,4 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Error: No generic deploy command specified in '.algokit.toml' file. diff --git a/tests/deploy/test_deploy.test_algokit_config_invalid_syntax.approved.txt b/tests/deploy/test_deploy.test_algokit_config_invalid_syntax.approved.txt new file mode 100644 index 00000000..cda797f2 --- /dev/null +++ b/tests/deploy/test_deploy.test_algokit_config_invalid_syntax.approved.txt @@ -0,0 +1,5 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +DEBUG: Error parsing .algokit.toml file: Invalid statement (at line 1, column 1) +Error: No generic deploy command specified in '.algokit.toml' file. diff --git a/tests/deploy/test_deploy.test_algokit_config_name_no_base.approved.txt b/tests/deploy/test_deploy.test_algokit_config_name_no_base.approved.txt new file mode 100644 index 00000000..b9b24489 --- /dev/null +++ b/tests/deploy/test_deploy.test_algokit_config_name_no_base.approved.txt @@ -0,0 +1,8 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Using deploy command: command_a +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running 'command_a' in '{current_working_directory}' +command_a: picked localnet diff --git a/tests/deploy/test_deploy.test_algokit_config_name_overrides.approved.txt b/tests/deploy/test_deploy.test_algokit_config_name_overrides.approved.txt new file mode 100644 index 00000000..1cfaa68c --- /dev/null +++ b/tests/deploy/test_deploy.test_algokit_config_name_overrides.approved.txt @@ -0,0 +1,8 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Using deploy command: command_c +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running 'command_c' in '{current_working_directory}' +command_c: picked testnet diff --git a/tests/deploy/test_deploy.test_algokit_deploy_only_base_deploy_config.approved.txt b/tests/deploy/test_deploy.test_algokit_deploy_only_base_deploy_config.approved.txt new file mode 100644 index 00000000..459f1c32 --- /dev/null +++ b/tests/deploy/test_deploy.test_algokit_deploy_only_base_deploy_config.approved.txt @@ -0,0 +1,8 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Using deploy command: command_a +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running 'command_a' in '{current_working_directory}' +command_a: picked base deploy command diff --git a/tests/deploy/test_deploy.test_algokit_env_and_name_correct_set.approved.txt b/tests/deploy/test_deploy.test_algokit_env_and_name_correct_set.approved.txt new file mode 100644 index 00000000..775ab5bd --- /dev/null +++ b/tests/deploy/test_deploy.test_algokit_env_and_name_correct_set.approved.txt @@ -0,0 +1,8 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Using deploy command: command_b +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running 'command_b' in '{current_working_directory}' +command_b: picked localnet diff --git a/tests/deploy/test_deploy.test_algokit_env_name_missing.approved.txt b/tests/deploy/test_deploy.test_algokit_env_name_missing.approved.txt new file mode 100644 index 00000000..8c93d863 --- /dev/null +++ b/tests/deploy/test_deploy.test_algokit_env_name_missing.approved.txt @@ -0,0 +1,6 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Using deploy command: command_a +Loading deployment environment variables... +Error: No such file: {current_working_directory}/.env.localnet diff --git a/tests/deploy/test_deploy.test_ci_flag_interactivity_mode_via_cli.approved.txt b/tests/deploy/test_deploy.test_ci_flag_interactivity_mode_via_cli.approved.txt new file mode 100644 index 00000000..3a9704fb --- /dev/null +++ b/tests/deploy/test_deploy.test_ci_flag_interactivity_mode_via_cli.approved.txt @@ -0,0 +1,6 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Using deploy command: command_a +Loading deployment environment variables... +Error: Error: missing DEPLOYER_MNEMONIC environment variable diff --git a/tests/deploy/test_deploy.test_ci_flag_interactivity_mode_via_env.approved.txt b/tests/deploy/test_deploy.test_ci_flag_interactivity_mode_via_env.approved.txt new file mode 100644 index 00000000..3a9704fb --- /dev/null +++ b/tests/deploy/test_deploy.test_ci_flag_interactivity_mode_via_env.approved.txt @@ -0,0 +1,6 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Using deploy command: command_a +Loading deployment environment variables... +Error: Error: missing DEPLOYER_MNEMONIC environment variable diff --git a/tests/deploy/test_deploy.test_command_bad_exit_code.approved.txt b/tests/deploy/test_deploy.test_command_bad_exit_code.approved.txt new file mode 100644 index 00000000..bb9dfbfb --- /dev/null +++ b/tests/deploy/test_deploy.test_command_bad_exit_code.approved.txt @@ -0,0 +1,10 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +DEBUG: No .algokit.toml file found in the project directory. +Using deploy command: gm +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running 'gm' in '{current_working_directory}' +gm: it is not morning +Error: Deployment command exited with error code = -1 diff --git a/tests/deploy/test_deploy.test_command_invocation_and_command_splitting.approved.txt b/tests/deploy/test_deploy.test_command_invocation_and_command_splitting.approved.txt new file mode 100644 index 00000000..58a77be3 --- /dev/null +++ b/tests/deploy/test_deploy.test_command_invocation_and_command_splitting.approved.txt @@ -0,0 +1,8 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Using deploy command: -c print(' test_command_invocation ') +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running ' -c print(' test_command_invocation ')' in '{current_working_directory}' +: test_command_invocation diff --git a/tests/deploy/test_deploy.test_command_not_executable.approved.txt b/tests/deploy/test_deploy.test_command_not_executable.approved.txt new file mode 100644 index 00000000..001625e8 --- /dev/null +++ b/tests/deploy/test_deploy.test_command_not_executable.approved.txt @@ -0,0 +1,9 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +DEBUG: No .algokit.toml file found in the project directory. +Using deploy command: gm +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running 'gm' in '{current_working_directory}' +Error: Failed to execute deploy command 'gm', permission denied diff --git a/tests/deploy/test_deploy.test_command_not_found_and_no_config.approved.txt b/tests/deploy/test_deploy.test_command_not_found_and_no_config.approved.txt new file mode 100644 index 00000000..69c57c0c --- /dev/null +++ b/tests/deploy/test_deploy.test_command_not_found_and_no_config.approved.txt @@ -0,0 +1,9 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +DEBUG: No .algokit.toml file found in the project directory. +Using deploy command: gm +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running 'gm' in '{current_working_directory}' +Error: Failed to execute deploy command, 'gm' wasn't found diff --git a/tests/deploy/test_deploy.test_command_splitting_from_config.approved.txt b/tests/deploy/test_deploy.test_command_splitting_from_config.approved.txt new file mode 100644 index 00000000..58a77be3 --- /dev/null +++ b/tests/deploy/test_deploy.test_command_splitting_from_config.approved.txt @@ -0,0 +1,8 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Using deploy command: -c print(' test_command_invocation ') +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running ' -c print(' test_command_invocation ')' in '{current_working_directory}' +: test_command_invocation diff --git a/tests/deploy/test_deploy.test_command_without_splitting_from_config.approved.txt b/tests/deploy/test_deploy.test_command_without_splitting_from_config.approved.txt new file mode 100644 index 00000000..58a77be3 --- /dev/null +++ b/tests/deploy/test_deploy.test_command_without_splitting_from_config.approved.txt @@ -0,0 +1,8 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Using deploy command: -c print(' test_command_invocation ') +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running ' -c print(' test_command_invocation ')' in '{current_working_directory}' +: test_command_invocation diff --git a/tests/deploy/test_deploy.test_deploy_custom_project_dir.approved.txt b/tests/deploy/test_deploy.test_deploy_custom_project_dir.approved.txt new file mode 100644 index 00000000..9ed94852 --- /dev/null +++ b/tests/deploy/test_deploy.test_deploy_custom_project_dir.approved.txt @@ -0,0 +1,8 @@ +DEBUG: Deploying from project directory: {current_working_directory}/custom_folder +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/custom_folder/.algokit.toml +Using deploy command: command_a +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running 'command_a' in '{current_working_directory}/custom_folder' +command_a: picked base deploy command diff --git a/tests/deploy/test_deploy.test_secrets_prompting_via_stdin.approved.txt b/tests/deploy/test_deploy.test_secrets_prompting_via_stdin.approved.txt new file mode 100644 index 00000000..459f1c32 --- /dev/null +++ b/tests/deploy/test_deploy.test_secrets_prompting_via_stdin.approved.txt @@ -0,0 +1,8 @@ +DEBUG: Deploying from project directory: {current_working_directory} +DEBUG: Loading deploy command from project config +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml +Using deploy command: command_a +Loading deployment environment variables... +Deploying smart contracts from AlgoKit compliant repository 🚀 +DEBUG: Running 'command_a' in '{current_working_directory}' +command_a: picked base deploy command diff --git a/tests/generate/test_generate_client.py b/tests/generate/test_generate_client.py index 9497b2f7..c3badeb4 100644 --- a/tests/generate/test_generate_client.py +++ b/tests/generate/test_generate_client.py @@ -103,9 +103,11 @@ def test_generate_client_typescript( _normalize_output(result.output), options=NamerFactory.with_parameters(*options.split()), ) - assert proc_mock.called == [ - f"/bin/npx --yes {TYPESCRIPT_NPX_PACKAGE} generate -a {application_json} -o {expected_output_path}".split() - ] + assert len(proc_mock.called) == 1 + assert ( + proc_mock.called[0].command + == f"/bin/npx --yes {TYPESCRIPT_NPX_PACKAGE} generate -a {application_json} -o {expected_output_path}".split() + ) def test_npx_missing(application_json: Path, which_mock: WhichMock) -> None: diff --git a/tests/init/test_init.py b/tests/init/test_init.py index 9b465a2e..95c52c5a 100644 --- a/tests/init/test_init.py +++ b/tests/init/test_init.py @@ -68,7 +68,7 @@ def _set_blessed_templates(mocker: MockerFixture) -> None: @pytest.fixture(autouse=True) def _override_bootstrap(mocker: MockerFixture) -> None: - def bootstrap_mock(p: Path) -> None: + def bootstrap_mock(p: Path, *, ci_mode: bool) -> None: # noqa: ARG001 click.echo(f"Executed `algokit bootstrap all` in {p}") mocker.patch("algokit.cli.init.bootstrap_any_including_subdirs").side_effect = bootstrap_mock diff --git a/tests/init/test_init.test_init_ask_about_git.approved.txt b/tests/init/test_init.test_init_ask_about_git.approved.txt index 7e06150e..af2590f0 100644 --- a/tests/init/test_init.test_init_ask_about_git.approved.txt +++ b/tests/init/test_init.test_init_ask_about_git.approved.txt @@ -7,6 +7,7 @@ Starting template copy and render... No git tags found in template; using HEAD as ref DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp DEBUG: Running 'git rev-parse --show-toplevel' in '{current_working_directory}/myapp' diff --git a/tests/init/test_init.test_init_bootstrap_yes.approved.txt b/tests/init/test_init.test_init_bootstrap_yes.approved.txt index 8face1e2..41f14477 100644 --- a/tests/init/test_init.test_init_bootstrap_yes.approved.txt +++ b/tests/init/test_init.test_init_bootstrap_yes.approved.txt @@ -7,6 +7,7 @@ DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle No git tags found in template; using HEAD as ref Template render complete! ? Do you want to run `algokit bootstrap` for this new project? This will install and configure dependencies allowing it to be run immediately. (Y/n) +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp 🙌 Project initialized at `myapp`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_input_template_url.approved.txt b/tests/init/test_init.test_init_input_template_url.approved.txt index 1db68006..41c82588 100644 --- a/tests/init/test_init.test_init_input_template_url.approved.txt +++ b/tests/init/test_init.test_init_input_template_url.approved.txt @@ -30,6 +30,7 @@ Starting template copy and render... No git tags found in template; using HEAD as ref DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp 🙌 Project initialized at `myapp`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_minimal_interaction_required_yes_git_no_network.approved.txt b/tests/init/test_init.test_init_minimal_interaction_required_yes_git_no_network.approved.txt index d8b01169..1ea9f84e 100644 --- a/tests/init/test_init.test_init_minimal_interaction_required_yes_git_no_network.approved.txt +++ b/tests/init/test_init.test_init_minimal_interaction_required_yes_git_no_network.approved.txt @@ -7,6 +7,7 @@ Starting template copy and render... No git tags found in template; using HEAD as ref DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp DEBUG: Running 'git rev-parse --show-toplevel' in '{current_working_directory}/myapp' diff --git a/tests/init/test_init.test_init_no_interaction_required_defaults_no_git_no_network.approved.txt b/tests/init/test_init.test_init_no_interaction_required_defaults_no_git_no_network.approved.txt index 52f6921c..8b548537 100644 --- a/tests/init/test_init.test_init_no_interaction_required_defaults_no_git_no_network.approved.txt +++ b/tests/init/test_init.test_init_no_interaction_required_defaults_no_git_no_network.approved.txt @@ -6,6 +6,7 @@ Starting template copy and render... No git tags found in template; using HEAD as ref DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp 🙌 Project initialized at `myapp`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_no_interaction_required_no_git_no_network.approved.txt b/tests/init/test_init.test_init_no_interaction_required_no_git_no_network.approved.txt index 0f26fe91..afd21db7 100644 --- a/tests/init/test_init.test_init_no_interaction_required_no_git_no_network.approved.txt +++ b/tests/init/test_init.test_init_no_interaction_required_no_git_no_network.approved.txt @@ -6,6 +6,7 @@ Starting template copy and render... DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle No git tags found in template; using HEAD as ref Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp 🙌 Project initialized at `myapp`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_no_ide.approved.txt b/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_no_ide.approved.txt index df113cca..838b94f2 100644 --- a/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_no_ide.approved.txt +++ b/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_no_ide.approved.txt @@ -8,6 +8,7 @@ Starting template copy and render... DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle No git tags found in template; using HEAD as ref Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp 🙌 Project initialized at `myapp`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_vscode.approved.txt b/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_vscode.approved.txt index d80691ab..a39d7fc3 100644 --- a/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_vscode.approved.txt +++ b/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_vscode.approved.txt @@ -8,6 +8,7 @@ Starting template copy and render... DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle No git tags found in template; using HEAD as ref Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp 🙌 Project initialized at `myapp`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_vscode_and_readme.approved.txt b/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_vscode_and_readme.approved.txt index 7c5e5836..bad4cc37 100644 --- a/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_vscode_and_readme.approved.txt +++ b/tests/init/test_init.test_init_no_interaction_required_no_git_no_network_with_vscode_and_readme.approved.txt @@ -8,6 +8,7 @@ Starting template copy and render... DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle No git tags found in template; using HEAD as ref Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp 🙌 Project initialized at `myapp`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_project_name.approved.txt b/tests/init/test_init.test_init_project_name.approved.txt index 93864aa5..456f91a0 100644 --- a/tests/init/test_init.test_init_project_name.approved.txt +++ b/tests/init/test_init.test_init_project_name.approved.txt @@ -7,6 +7,7 @@ Starting template copy and render... No git tags found in template; using HEAD as ref DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/FAKE_PROJECT/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/FAKE_PROJECT 🙌 Project initialized at `FAKE_PROJECT`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_project_name_not_empty.approved.txt b/tests/init/test_init.test_init_project_name_not_empty.approved.txt index 93864aa5..456f91a0 100644 --- a/tests/init/test_init.test_init_project_name_not_empty.approved.txt +++ b/tests/init/test_init.test_init_project_name_not_empty.approved.txt @@ -7,6 +7,7 @@ Starting template copy and render... No git tags found in template; using HEAD as ref DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/FAKE_PROJECT/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/FAKE_PROJECT 🙌 Project initialized at `FAKE_PROJECT`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_project_name_reenter_folder_name.approved.txt b/tests/init/test_init.test_init_project_name_reenter_folder_name.approved.txt index 52dd61c0..b587a995 100644 --- a/tests/init/test_init.test_init_project_name_reenter_folder_name.approved.txt +++ b/tests/init/test_init.test_init_project_name_reenter_folder_name.approved.txt @@ -10,6 +10,7 @@ Starting template copy and render... No git tags found in template; using HEAD as ref DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/FAKE_PROJECT_2/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/FAKE_PROJECT_2 🙌 Project initialized at `FAKE_PROJECT_2`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_template_selection.approved.txt b/tests/init/test_init.test_init_template_selection.approved.txt index 02b2600c..99edbdaf 100644 --- a/tests/init/test_init.test_init_template_selection.approved.txt +++ b/tests/init/test_init.test_init_template_selection.approved.txt @@ -13,6 +13,7 @@ Starting template copy and render... No git tags found in template; using HEAD as ref DEBUG: final clone URL = https://github.com/robdmoore/copier-helloworld.git Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp 🙌 Project initialized at `myapp`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_use_existing_folder.approved.txt b/tests/init/test_init.test_init_use_existing_folder.approved.txt index 1a479e3d..4513be3f 100644 --- a/tests/init/test_init.test_init_use_existing_folder.approved.txt +++ b/tests/init/test_init.test_init_use_existing_folder.approved.txt @@ -8,6 +8,7 @@ Starting template copy and render... No git tags found in template; using HEAD as ref DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp 🙌 Project initialized at `myapp`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init.test_init_with_official_template_name_and_hash.approved.txt b/tests/init/test_init.test_init_with_official_template_name_and_hash.approved.txt index f02c99fe..58d3e901 100644 --- a/tests/init/test_init.test_init_with_official_template_name_and_hash.approved.txt +++ b/tests/init/test_init.test_init_with_official_template_name_and_hash.approved.txt @@ -3,6 +3,7 @@ DEBUG: project path = {current_working_directory}/myapp Starting template copy and render... DEBUG: final clone URL = https://github.com/algorandfoundation/algokit-beaker-default-template.git Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. Executed `algokit bootstrap all` in {current_working_directory}/myapp 🙌 Project initialized at `myapp`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/init/test_init_with_bootstrap.py b/tests/init/test_init_with_bootstrap.py index d14549e5..70729340 100644 --- a/tests/init/test_init_with_bootstrap.py +++ b/tests/init/test_init_with_bootstrap.py @@ -3,8 +3,7 @@ import click from _pytest.tmpdir import TempPathFactory -from algokit.core.bootstrap import ALGOKIT_CONFIG -from algokit.core.conf import get_current_package_version +from algokit.core.conf import ALGOKIT_CONFIG, get_current_package_version from approvaltests.scrubbers.scrubbers import Scrubber from prompt_toolkit.input import PipeInput diff --git a/tests/init/test_init_with_bootstrap.test_init_bootstrap_broken_poetry.approved.txt b/tests/init/test_init_with_bootstrap.test_init_bootstrap_broken_poetry.approved.txt index 811b6f80..30454fa9 100644 --- a/tests/init/test_init_with_bootstrap.test_init_bootstrap_broken_poetry.approved.txt +++ b/tests/init/test_init_with_bootstrap.test_init_bootstrap_broken_poetry.approved.txt @@ -8,6 +8,7 @@ Starting template copy and render... DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle No git tags found in template; using HEAD as ref Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. DEBUG: Checking {current_working_directory}/myapp for bootstrapping needs DEBUG: Running `algokit bootstrap poetry` diff --git a/tests/init/test_init_with_bootstrap.test_init_bootstrap_version_fail.approved.txt b/tests/init/test_init_with_bootstrap.test_init_bootstrap_version_fail.approved.txt index e71084e1..59a100ad 100644 --- a/tests/init/test_init_with_bootstrap.test_init_bootstrap_version_fail.approved.txt +++ b/tests/init/test_init_with_bootstrap.test_init_bootstrap_version_fail.approved.txt @@ -8,6 +8,7 @@ Starting template copy and render... DEBUG: final clone URL = {test_parent_directory}/copier-helloworld.bundle No git tags found in template; using HEAD as ref Template render complete! +DEBUG: Attempting to load project config from {current_working_directory}/myapp/.algokit.toml ERROR: Received an error while attempting bootstrap: This template requires AlgoKit version 999.99.99 or higher, but you have AlgoKit version {current_version}. Please update AlgoKit. ERROR: Bootstrap failed. Once any errors above are resolved, you can run `algokit bootstrap` in {current_working_directory}/myapp 🙌 Project initialized at `myapp`! For template specific next steps, consult the documentation of your selected template 🧐 diff --git a/tests/test_root.test_help.approved.txt b/tests/test_root.test_help.approved.txt index c7ca8e14..56658829 100644 --- a/tests/test_root.test_help.approved.txt +++ b/tests/test_root.test_help.approved.txt @@ -18,6 +18,7 @@ Commands: project root directory. completions Install and Uninstall AlgoKit shell integrations. config Configure AlgoKit settings. + deploy Deploy smart contracts from AlgoKit compliant repository. doctor Diagnose potential environment issues that may affect AlgoKit explore Explore the specified network in the browser using Dappflow. generate Generate code for an Algorand project. diff --git a/tests/utils/click_invoker.py b/tests/utils/click_invoker.py index f5030a70..20518081 100644 --- a/tests/utils/click_invoker.py +++ b/tests/utils/click_invoker.py @@ -21,11 +21,12 @@ class ClickInvokeResult: def invoke( - args: str, + args: str | list[str], *, cwd: Path | None = None, skip_version_check: bool = True, env: Mapping[str, str | None] | None = None, + input: str | None = None, # noqa: A002 ) -> ClickInvokeResult: from algokit.cli import algokit @@ -38,7 +39,10 @@ def invoke( test_args = "-v --no-color" if skip_version_check: test_args = f"{test_args} --skip-version-check" - result = runner.invoke(algokit, f"{test_args} {args}", env=env) + if isinstance(args, str): + result = runner.invoke(algokit, f"{test_args} {args}", env=env, input=input) + else: + result = runner.invoke(algokit, args=[*test_args.split(), *args], env=env, input=input) if result.exc_info and not isinstance(result.exc_info[1], SystemExit): logger.error("Click invocation error", exc_info=result.exc_info) output = normalize_path(result.stdout, str(cwd or prior_cwd), "{current_working_directory}") diff --git a/tests/utils/proc_mock.py b/tests/utils/proc_mock.py index 12c74e8a..bf8e9809 100644 --- a/tests/utils/proc_mock.py +++ b/tests/utils/proc_mock.py @@ -44,10 +44,16 @@ class CommandMockData: output_lines: list[str] = dataclasses.field(default_factory=lambda: ["STDOUT", "STDERR"]) +@dataclasses.dataclass(kw_only=True) +class PopenArgs: + command: list[str] + env: dict[str, str] | None + + class ProcMock: def __init__(self) -> None: self._mock_data: dict[tuple[str, ...], CommandMockData] = {} - self.called: list[list[str]] = [] + self.called: list[PopenArgs] = [] def _add_mock_data(self, cmd: list[str] | str, data: CommandMockData) -> None: cmd_list = tuple(cmd.split() if isinstance(cmd, str) else cmd) @@ -85,8 +91,8 @@ def should_bad_exit_on(self, cmd: list[str] | str, exit_code: int = -1, output: def set_output(self, cmd: list[str] | str, output: list[str]) -> None: self._add_mock_data(cmd, CommandMockData(output_lines=output)) - def popen(self, cmd: list[str], *_args: Any, **_kwargs: Any) -> PopenMock: - self.called.append(cmd) + def popen(self, cmd: list[str], env: dict[str, str] | None = None, *_args: Any, **_kwargs: Any) -> PopenMock: + self.called.append(PopenArgs(command=cmd, env=env)) for i in reversed(range(len(cmd))): prefix = cmd[: i + 1] try: diff --git a/tests/version_check/test_version_check.test_version_check_queries_github_when_cache_out_of_date.approved.txt b/tests/version_check/test_version_check.test_version_check_queries_github_when_cache_out_of_date.approved.txt index 1eea96ca..59d9cebe 100644 --- a/tests/version_check/test_version_check.test_version_check_queries_github_when_cache_out_of_date.approved.txt +++ b/tests/version_check/test_version_check.test_version_check_queries_github_when_cache_out_of_date.approved.txt @@ -2,4 +2,5 @@ DEBUG: 1234.56.78 found in cache {app_state}/last-version-check DEBUG: HTTP Request: GET https://api.github.com/repos/algorandfoundation/algokit-cli/releases/latest "HTTP/1.1 200 OK" DEBUG: Latest version tag: v{new_version} You are using AlgoKit version {current_version}, however version {new_version} is available. +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. diff --git a/tests/version_check/test_version_check.test_version_check_queries_github_when_no_cache.approved.txt b/tests/version_check/test_version_check.test_version_check_queries_github_when_no_cache.approved.txt index 1cbab9c8..a4a25d09 100644 --- a/tests/version_check/test_version_check.test_version_check_queries_github_when_no_cache.approved.txt +++ b/tests/version_check/test_version_check.test_version_check_queries_github_when_no_cache.approved.txt @@ -2,4 +2,5 @@ DEBUG: {app_state}/last-version-check inaccessible DEBUG: HTTP Request: GET https://api.github.com/repos/algorandfoundation/algokit-cli/releases/latest "HTTP/1.1 200 OK" DEBUG: Latest version tag: v{new_version} You are using AlgoKit version {current_version}, however version {new_version} is available. +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. diff --git a/tests/version_check/test_version_check.test_version_check_respects_disable_config.approved.txt b/tests/version_check/test_version_check.test_version_check_respects_disable_config.approved.txt index d64323b6..57893de5 100644 --- a/tests/version_check/test_version_check.test_version_check_respects_disable_config.approved.txt +++ b/tests/version_check/test_version_check.test_version_check_respects_disable_config.approved.txt @@ -1,2 +1,3 @@ DEBUG: Version prompt disabled +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. diff --git a/tests/version_check/test_version_check.test_version_check_respects_skip_option.approved.txt b/tests/version_check/test_version_check.test_version_check_respects_skip_option.approved.txt index 7c51cad3..4e14461c 100644 --- a/tests/version_check/test_version_check.test_version_check_respects_skip_option.approved.txt +++ b/tests/version_check/test_version_check.test_version_check_respects_skip_option.approved.txt @@ -1 +1,2 @@ +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory. diff --git a/tests/version_check/test_version_check.test_version_check_uses_cache.approved.txt b/tests/version_check/test_version_check.test_version_check_uses_cache.approved.txt index 2d7ca2e4..c7990176 100644 --- a/tests/version_check/test_version_check.test_version_check_uses_cache.approved.txt +++ b/tests/version_check/test_version_check.test_version_check_uses_cache.approved.txt @@ -1,3 +1,4 @@ DEBUG: 1234.56.78 found in cache {app_state}/last-version-check You are using AlgoKit version {current_version}, however version 1234.56.78 is available. +DEBUG: Attempting to load project config from {current_working_directory}/.algokit.toml DEBUG: No .algokit.toml file found in the project directory.