diff --git a/.cicd-tools/bin/manifest.sh b/.cicd-tools/bin/manifest.sh new file mode 100755 index 0000000..140069d --- /dev/null +++ b/.cicd-tools/bin/manifest.sh @@ -0,0 +1,109 @@ +#!/bin/bash + +# Manifest file reader. +# Requires the jq binary: https://stedolan.github.io/jq/download/ + +# CICD-Tools script. + +set -eo pipefail + +# shellcheck source=./.cicd-tools/boxes/bootstrap/libraries/logging.sh +source "$(dirname -- "${BASH_SOURCE[0]}")/../boxes/bootstrap/libraries/logging.sh" + +manifest() { + local MANIFEST_FILE + _manifest_args "$@" +} + +_manifest_args() { + while getopts "m:" OPTION; do + case "$OPTION" in + m) + MANIFEST_FILE="${OPTARG}" + ;; + \?) + _manifest_usage + ;; + :) + _manifest_usage + ;; + *) + _manifest_usage + ;; + esac + done + shift $((OPTIND - 1)) + if [[ -z "${MANIFEST_FILE}" ]]; then + _manifest_usage + fi + _manifest_commands "$@" +} + +_manifest_commands() { + case "$1" in + security) + [[ -n "${2}" ]] && _manifest_usage + log "DEBUG" "MANIFEST > Reading security status from manifest." + _manifest_security + ;; + toolbox_url) + [[ -z "${2}" ]] && _manifest_usage + log "DEBUG" "MANIFEST > Reading toolbox url for '${2}' from manifest." + _manifest_toolbox_url "${2}" + ;; + toolbox_sha) + [[ -z "${2}" ]] && _manifest_usage + log "DEBUG" "MANIFEST > Reading toolbox checksum for '${2}' from manifest." + _manifest_toolbox_sha "${2}" + ;; + *) + _manifest_usage + ;; + esac +} + +_manifest_usage() { + log "ERROR" "manifest.sh -- interact with the CICD-Tools manifest file." + log "ERROR" "USAGE: manifest.sh -p [PATH TO MANIFEST] [COMMAND]" + log "ERROR" " COMMANDS:" + log "ERROR" " toolbox_url [VERSION] - Retrieves the URL of the given toolbox version." + log "ERROR" " toolbox_sha [FILENAME] - Retrieves the checksum of the given file." + log "ERROR" " security - Indicates if hash validation is enabled or disabled." + exit 127 +} + +_manifest_security() { + jq -rM ".disable_security" "${MANIFEST_FILE}" +} + +_manifest_toolbox_prefix() { + local REMOTE_SHA + local REMOTE_SOURCE + local REMOTE_PATH + REMOTE_SHA="$(jq -erM '.version' "${MANIFEST_FILE}")" + REMOTE_SOURCE="$(jq -erM '.source' "${MANIFEST_FILE}")" + REMOTE_PATH="$(jq -erM '.toolbox_path' "${MANIFEST_FILE}")" + echo "${REMOTE_SOURCE}/${REMOTE_SHA}/${REMOTE_PATH}" +} + +_manifest_toolbox_is_present() { + jq --arg version "${1}.tar.gz" -erM '.manifest[$version]' "${MANIFEST_FILE}" +} + +_manifest_toolbox_url() { + if ! _manifest_toolbox_is_present "${1}" > /dev/null; then + log "ERROR" "MANIFEST > Toolbox version '${1}' is not in the manifest." + exit 127 + fi + echo "$(_manifest_toolbox_prefix)/${1}.tar.gz" +} + +_manifest_toolbox_sha() { + if ! _manifest_toolbox_is_present "${1}" > /dev/null; then + log "ERROR" "MANIFEST > Toolbox version '${1}' is not in the manifest." + exit 127 + fi + jq --arg version "${1}.tar.gz" -erM '.manifest[$version]' "${MANIFEST_FILE}" +} + +manifest "$@" diff --git a/.cicd-tools/bin/toolbox.sh b/.cicd-tools/bin/toolbox.sh new file mode 100755 index 0000000..99744df --- /dev/null +++ b/.cicd-tools/bin/toolbox.sh @@ -0,0 +1,163 @@ +#!/bin/bash + +# Remote toolbox downloader. +# Requires gpg binary: https://gnupg.org/ + +# CICD-Tools script. + +set -eo pipefail + +TOOLBOX_PATH="$(pwd)/.cicd-tools" +TOOLBOX_REMOTES_FOLDER="boxes" +TOOLBOX_MANIFEST_FILE="${TOOLBOX_PATH}/manifest.json" + +# shellcheck source=./.cicd-tools/boxes/bootstrap/libraries/logging.sh +source "$(dirname -- "${BASH_SOURCE[0]}")/../boxes/bootstrap/libraries/logging.sh" + +# shellcheck source=./.cicd-tools/boxes/bootstrap/libraries/environment.sh +source "$(dirname -- "${BASH_SOURCE[0]}")/../boxes/bootstrap/libraries/environment.sh" \ + -o "DOWNLOAD_RETRIES DOWNLOAD_MAX_TIME" \ + -d "3 30" + +main() { + OPTIND=1 + + local MANIFEST_ASC + local MANIFEST_DISABLE_SECURITY="false" + local TARGET_TOOLBOX_VERSION + local TARGET_TOOLBOX_URL + local TEMP_DIRECTORY + + TEMP_DIRECTORY="$(mktemp -d)" + + _toolbox_args "$@" + _toolbox_manifest_download + _toolbox_manifest_load + _toolbox_box_download + _toolbox_box_checksum + _toolbox_box_install +} + +_toolbox_args() { + while getopts "b:m:r:t:" OPTION; do + case "$OPTION" in + b) + TARGET_TOOLBOX_VERSION="${OPTARG}" + TARGET_TOOLBOX_FILENAME="${TARGET_TOOLBOX_VERSION}.tar.gz" + ;; + m) + MANIFEST_ASC="${OPTARG}" + ;; + r) + DOWNLOAD_RETRIES="${OPTARG}" + ;; + t) + DOWNLOAD_MAX_TIME="${OPTARG}" + ;; + \?) + _toolbox_usage + ;; + :) + _toolbox_usage + ;; + *) + _toolbox_usage + ;; + esac + done + shift $((OPTIND - 1)) + + if [[ -z "${TARGET_TOOLBOX_VERSION}" ]] || + [[ -z "${MANIFEST_ASC}" ]]; then + _toolbox_usage + fi +} + +_toolbox_box_checksum() { + pushd "${TEMP_DIRECTORY}" >> /dev/null + if [[ "${MANIFEST_DISABLE_SECURITY}" == "false" ]]; then + if ! echo "${TARGET_TOOLBOX_SHA} ${TARGET_TOOLBOX_FILENAME}" | sha256sum -c; then + log "ERROR" "CHECKSUM > Hash of remote file does not match!" + log "ERROR" "CHECKSUM > Cannot proceed." + exit 127 + else + log "INFO" "CHECKSUM > Hash verification has passed." + fi + else + log "WARNING" "CHECKSUM > The manifest has DISABLED all checksum validation." + fi + cp "${TARGET_TOOLBOX_FILENAME}" "${TOOLBOX_PATH}/${TOOLBOX_REMOTES_FOLDER}" + popd >> /dev/null +} + +_toolbox_box_download() { + if [[ -f "${TOOLBOX_PATH}/${TOOLBOX_REMOTES_FOLDER}/${TARGET_TOOLBOX_FILENAME}" ]]; then + mv "${TOOLBOX_PATH}/${TOOLBOX_REMOTES_FOLDER}/${TARGET_TOOLBOX_FILENAME}" "${TEMP_DIRECTORY}" + log "INFO" "BOX > Toolbox Version ${TARGET_TOOLBOX_VERSION} has already been downloaded." + else + _toolbox_box_fetch + fi +} + +_toolbox_box_fetch() { + log "DEBUG" "BOX > Target Toolbox Version: ${TARGET_TOOLBOX_VERSION}" + log "DEBUG" "BOX > Target Toolbox SHA: ${TARGET_TOOLBOX_SHA}" + log "DEBUG" "BOX > Target Toolbox URL: ${TARGET_TOOLBOX_URL}" + + mkdir -p "${TOOLBOX_PATH}/${TOOLBOX_REMOTES_FOLDER}" + + pushd "${TEMP_DIRECTORY}" >> /dev/null + _toolbox_fetch "${TARGET_TOOLBOX_URL}" > "${TARGET_TOOLBOX_FILENAME}" + popd >> /dev/null + + log "INFO" "BOX > Remote toolbox retrieved." +} + +_toolbox_box_install() { + pushd "${TOOLBOX_PATH}/${TOOLBOX_REMOTES_FOLDER}" >> /dev/null + tar xvzf "${TARGET_TOOLBOX_FILENAME}" + log "DEBUG" "BOX > Toolbox Version ${TARGET_TOOLBOX_VERSION} has been installed to ${TOOLBOX_PATH}/${TOOLBOX_REMOTES_FOLDER}." + ln -sf "${TARGET_TOOLBOX_VERSION}" active + log "INFO" "BOX > Toolbox Version ${TARGET_TOOLBOX_VERSION} has been activated." + popd >> /dev/null +} + +_toolbox_fetch() { + # 1: url + log "DEBUG" "FETCH > URL: ${1}" + log "DEBUG" "FETCH > Retries: ${DOWNLOAD_RETRIES}" + log "DEBUG" "FETCH > Max Time: ${DOWNLOAD_MAX_TIME}" + + set -x + curl --fail \ + --location \ + --silent \ + --show-error \ + --retry "${DOWNLOAD_RETRIES}" \ + --retry-max-time "${DOWNLOAD_MAX_TIME}" \ + "${1}" + { set +x; } 2> /dev/null + + log "DEBUG" "FETCH > Fetch complete." +} + +_toolbox_manifest_download() { + gpg --yes --output "${TOOLBOX_MANIFEST_FILE}" --verify <(_toolbox_fetch "${MANIFEST_ASC}") + log "INFO" "MANIFEST > Remote manifest retrieved." +} + +_toolbox_manifest_load() { + TARGET_TOOLBOX_SHA="$(./.cicd-tools/bin/manifest.sh -m "${TOOLBOX_MANIFEST_FILE}" toolbox_sha "${TARGET_TOOLBOX_VERSION}")" + MANIFEST_DISABLE_SECURITY="$(./.cicd-tools/bin/manifest.sh -m "${TOOLBOX_MANIFEST_FILE}" security)" + TARGET_TOOLBOX_URL="$(./.cicd-tools/bin/manifest.sh -m "${TOOLBOX_MANIFEST_FILE}" toolbox_url "${TARGET_TOOLBOX_VERSION}")" + log "INFO" "MANIFEST > Remote manifest loaded." +} + +_toolbox_usage() { + log "ERROR" "toolbox.sh -- download a remote toolbox from the CICD-Tools manifest." + log "ERROR" "USAGE: toolbox.sh -b [TOOLBOX VERSION] -m [REMOTE MANIFEST URL]" + log "ERROR" " Optional: -r [OPTIONAL RETRY COUNT] -m [OPTIONAL MAX RETRY TIME]" + exit 127 +} + +main "$@" diff --git a/.cicd-tools/bin/verify.sh b/.cicd-tools/bin/verify.sh new file mode 100755 index 0000000..7441fff --- /dev/null +++ b/.cicd-tools/bin/verify.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# Remote gpg key verification. +# Requires gpg binary: https://gnupg.org/ + +# CICD-Tools script. + +set -eo pipefail + +# shellcheck source=./.cicd-tools/boxes/bootstrap/libraries/logging.sh +source "$(dirname -- "${BASH_SOURCE[0]}")/../boxes/bootstrap/libraries/logging.sh" + +main() { + local CICD_TOOLS_GPG_KEY + + _verify_args "$@" + _verify_check_key + _verify_trust_key +} + +_verify_args() { + while getopts "k:" OPTION; do + case "$OPTION" in + k) + CICD_TOOLS_GPG_KEY="${OPTARG}" + ;; + \?) + _toolbox_usage + ;; + :) + _toolbox_usage + ;; + *) + _toolbox_usage + ;; + esac + done + shift $((OPTIND - 1)) + + if [[ -z "${CICD_TOOLS_GPG_KEY}" ]]; then + _verify_usage + fi +} + +_verify_check_key() { + gpg \ + --verify "$(dirname -- "${BASH_SOURCE[0]}")/../pgp/verification.sign" \ + "$(dirname -- "${BASH_SOURCE[0]}")/../pgp/verification.txt" +} + +_verify_trust_key() { + echo "${CICD_TOOLS_GPG_KEY}:6:" | gpg --import-ownertrust +} + +_verify_usage() { + log "ERROR" "verify.sh -- verify the CICD-Tools gpg key." + log "ERROR" "USAGE: verify.sh -k [GPG KEY ID]" + exit 127 +} + +main "$@" diff --git a/.cicd-tools/boxes/bootstrap/commitizen/pre_bump.sh b/.cicd-tools/boxes/bootstrap/commitizen/pre_bump.sh new file mode 100755 index 0000000..e521bf5 --- /dev/null +++ b/.cicd-tools/boxes/bootstrap/commitizen/pre_bump.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Commitizen 'pre_bump_hook' script to make TOML quotes compatible with tomll. + +# Commitizen pre_bump_hook script only. + +set -eo pipefail + +main() { + # sed compatible with Linux and BSD + sed -i.bak "s,\"${CZ_PRE_NEW_VERSION}\",'${CZ_PRE_NEW_VERSION}',g" pyproject.toml + rm pyproject.toml.bak +} + +main diff --git a/.cicd-tools/boxes/bootstrap/libraries/colours.sh b/.cicd-tools/boxes/bootstrap/libraries/colours.sh new file mode 100644 index 0000000..984d4d2 --- /dev/null +++ b/.cicd-tools/boxes/bootstrap/libraries/colours.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# Library for reading the CICD-Tools manifest. + +# CICD_TOOLS_COLOUR_DISABLE: Optionally disable coloured messages. + +set -eo pipefail + +# shellcheck disable=SC2034 +colour() { + local PREFIX + local COMMAND + + local BLACK=0 + local RED=1 + local GREEN=2 + local YELLOW=3 + local BLUE=4 + local PURPLE=5 + local CYAN=6 + local WHITE=7 + + if [[ -z "${CICD_TOOLS_COLOUR_DISABLE}" ]]; then + PREFIX="_colour" + COMMAND="${PREFIX}_${1}" + if [[ $(type -t "${COMMAND}") == function ]]; then + shift + "${COMMAND}" "$@" + else + "${PREFIX}_usage" + fi + fi +} + +_colour_bg() { + tput setab "${!1}" 2> /dev/null +} + +_colour_bold() { + tput setab bold 2> /dev/null +} + +_colour_fg() { + tput setaf "${!1}" 2> /dev/null +} + +_colour_clear() { + tput sgr0 2> /dev/null +} + +_colour_usage() { + { + echo "colour.sh -- set the desired terminal colour." + echo "USAGE: colour.sh [COMMAND]" + echo " COMMANDS:" + echo " bg [BLACK|RED|GREEN|YELLOW|BLUE|PURPLE|CYAN|WHITE] -- set background colour" + echo " bold -- set bold text" + echo " fg [BLACK|RED|GREEN|YELLOW|BLUE|PURPLE|CYAN|WHITE] -- set foreground colour" + echo " clear -- set default terminal colours" + } >> /dev/stderr +} diff --git a/.cicd-tools/boxes/bootstrap/libraries/environment.sh b/.cicd-tools/boxes/bootstrap/libraries/environment.sh new file mode 100644 index 0000000..9fe520d --- /dev/null +++ b/.cicd-tools/boxes/bootstrap/libraries/environment.sh @@ -0,0 +1,92 @@ +#!/bin/bash + +# Library for enforcing optional and mandatory environment variables. + +set -eo pipefail + +# shellcheck source=/dev/null +source "$(dirname -- "${BASH_SOURCE[0]}")/logging.sh" + +environment() { + local MANDATORY=() + local OPTIONAL=() + local DEFAULTS=() + + log "DEBUG" "${BASH_SOURCE[0]} '$*'" + + _environment_args "$@" + _environment_defaults +} + +_environment_args() { + while getopts "m:o:d:" OPTION; do + case "$OPTION" in + m) + _environment_parse_mandatory "${OPTARG}" + ;; + o) + _environment_parse_optional "${OPTARG}" + ;; + d) + _environment_parse_defaults "${OPTARG}" + ;; + \?) + _environment_usage + ;; + :) + _environment_usage + ;; + esac + done + + if [[ "${#OPTIONAL[@]}" -ne "${#DEFAULTS[@]}" ]]; then + log "ERROR" "ENVIRONMENT > You must specify the same number of DEFAULT values and OPTIONAL environment variables!" + exit 127 + fi +} + +_environment_defaults() { + log "DEBUG" "ENVIRONMENT > Setting DEFAULT environment variable values." + local INDEX=-1 + for VARIABLE in "${DEFAULTS[@]}"; do + ((INDEX++)) || true + if [[ -z "${!OPTIONAL[${INDEX}]}" ]]; then + export "${OPTIONAL[${INDEX}]}" + eval "${OPTIONAL[${INDEX}]}"="${DEFAULTS[${INDEX}]}" + log "INFO" "ENVIRONMENT > Default: '${DEFAULTS[${INDEX}]}' is being used for: '${OPTIONAL[${INDEX}]}'." + fi + done +} + +_environment_parse_mandatory() { + log "DEBUG" "ENVIRONMENT > Parsing MANDATORY environment variables." + # shellcheck disable=SC2034 + IFS=' ' read -r -a MANDATORY <<< "${1}" + for VARIABLE in "${MANDATORY[@]}"; do + if [[ -z ${!VARIABLE} ]]; then + log "ERROR" "ENVIRONMENT > The environment variable '${VARIABLE}' is required!" + exit 127 + fi + done +} + +_environment_parse_optional() { + log "DEBUG" "ENVIRONMENT > Parsing OPTIONAL environment variables." + # shellcheck disable=SC2034 + IFS=' ' read -r -a OPTIONAL <<< "${1}" +} + +_environment_parse_defaults() { + log "DEBUG" "ENVIRONMENT > Parsing DEFAULT environment variable values." + # shellcheck disable=SC2034 + IFS=' ' read -r -a DEFAULTS <<< "${1}" +} + +_environment_usage() { + log "ERROR" "environment.sh -- enforce environment variables." + log "ERROR" "USAGE: source environment.sh -m [MANDATORY] -o [OPTIONAL] -d [DEFAULTS]" + log "ERROR" " Multiple items should be specified as space separated quoted strings." + exit 127 +} + +environment "$@" diff --git a/.cicd-tools/boxes/bootstrap/libraries/logging.sh b/.cicd-tools/boxes/bootstrap/libraries/logging.sh new file mode 100644 index 0000000..7011f77 --- /dev/null +++ b/.cicd-tools/boxes/bootstrap/libraries/logging.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# Library for logging functions and commands. +# The LOGGING_LEVEL environment variable controls verbosity. + +set -eo pipefail + +# shellcheck source=/dev/null +source "$(dirname -- "${BASH_SOURCE[0]}")/colours.sh" + +LOGGING_LEVEL=${LOGGING_LEVEL-"DEBUG"} + +function log() { + # USAGE: + # colour bg [CRITICAL|ERROR|WARNING|INFO|DEBUG] [MESSAGE CONTENTS] + + local LOGGING_SEVERITY_LEVELS=("DEBUG" "INFO" "WARNING" "ERROR" "CRITICAL") + + # shellcheck disable=SC2034 + local CRITICAL="RED" + # shellcheck disable=SC2034 + local ERROR="RED" + # shellcheck disable=SC2034 + local WARNING="YELLOW" + # shellcheck disable=SC2034 + local INFO="GREEN" + # shellcheck disable=SC2034 + local DEBUG="CYAN" + # shellcheck disable=SC2034 + + local LOGGING_MESSAGE_LEVEL="${1}" + local MESSAGE_CONTENT="${2}" + + if [[ -z "${!LOGGING_LEVEL}" ]] || + [[ -z "${MESSAGE_CONTENT}" ]]; then + log "ERROR" "Invalid logging statement!" + return 127 + fi + + if [[ "$(_log_get_severity_level "${LOGGING_MESSAGE_LEVEL}")" -ge "$(_log_get_severity_level "${LOGGING_LEVEL}")" ]]; then + echo "[$(date -u)] [$(colour fg "${!LOGGING_MESSAGE_LEVEL}")${LOGGING_MESSAGE_LEVEL}$(colour clear)] ${MESSAGE_CONTENT}" >> /dev/stderr + fi + +} + +function _log_get_severity_level() { + #1: The severity type as a string. + local LOGGIN_SEVERITY_LEVEL + for LOGGIN_SEVERITY_LEVEL in "${!LOGGING_SEVERITY_LEVELS[@]}"; do + if [[ "${LOGGING_SEVERITY_LEVELS["${LOGGIN_SEVERITY_LEVEL}"]}" = "${1}" ]]; then + echo "${LOGGIN_SEVERITY_LEVEL}" + fi + done +} diff --git a/.cicd-tools/boxes/bootstrap/libraries/tools.sh b/.cicd-tools/boxes/bootstrap/libraries/tools.sh new file mode 100644 index 0000000..9b2065f --- /dev/null +++ b/.cicd-tools/boxes/bootstrap/libraries/tools.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# Library for working with the CICD-Tools projects. + +set -eo pipefail + +# shellcheck source=/dev/null +source "$(dirname -- "${BASH_SOURCE[0]}")/logging.sh" + +cicd_tools() { + local PREFIX + local COMMAND + + PREFIX="_cicd_tools" + COMMAND="${PREFIX}_${1}" + if [[ $(type -t "${COMMAND}") == function ]]; then + shift + "${COMMAND}" "$@" + else + "${PREFIX}_usage" + fi +} + +_cicd_tools_is_template() { + [[ -f "cookiecutter.json" ]] +} + +_cicd_tools_config_value() { + # 1: The config file to parse. + # 2: The key of the value to extract. + + local CICD_TOOLS_CONFIG_FILE="${1}" + local CICD_TOOLS_KEY="${2}" + + log "DEBUG" "CONFIGURATION > extracting key: '${CICD_TOOLS_KEY}' from: '${CICD_TOOLS_CONFIG_FILE}'." + + REGEX="\"${2}\": \"([^\"]+)\"" + if [[ "$(cat "${CICD_TOOLS_CONFIG_FILE}")" =~ ${REGEX} ]]; then + log "DEBUG" "CONFIGURATION > found value: '${BASH_REMATCH[1]}'." + echo "${BASH_REMATCH[1]}" + else + log "ERROR" "CONFIGURATION > key: '${CICD_TOOLS_KEY}' not found in '${CICD_TOOLS_CONFIG_FILE}'." + return 127 + fi +} + +_cicd_tools_poetry() { + # @: A command and arguments to run in either directly, or through Poetry. + + if [[ "${POETRY_ACTIVE}" == "1" ]]; then + "$@" + else + poetry run "$@" + fi +} + +_cicd_tools_usage() { + log "ERROR" "tools.sh -- CICD-Tools project helpers." + log "ERROR" "USAGE: tools.sh [COMMAND]" + log "ERROR" " COMMANDS:" + log "ERROR" " is_template -- Evaluates whether the current context is a cookiecutter project." + log "ERROR" " config_value [JSON FILE PATH] [KEY] -- Reads the given JSON file, and returns the value of the given key." +} diff --git a/.cicd-tools/boxes/bootstrap/pre-commit/lint-ansible.sh b/.cicd-tools/boxes/bootstrap/pre-commit/lint-ansible.sh new file mode 100755 index 0000000..4bc651a --- /dev/null +++ b/.cicd-tools/boxes/bootstrap/pre-commit/lint-ansible.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Runs ansible-galaxy to install/update the dependencies if needed, and then runs ansible-lint on each active target folder's changes. + +# @: An array of folders to run ansible-lin on. + +# pre-commit script. + +set -eo pipefail + +# shellcheck source=/dev/null +source "$(dirname -- "${BASH_SOURCE[0]}")/../libraries/tools.sh" + +main() { + local TARGET_FOLDERS=${*-"."} + for TARGET in ${TARGET_FOLDERS}; do + log "INFO" "PRE-COMMIT > Moving to target folder: '${TARGET}' ..." + pushd "${TARGET}" >> /dev/null + log "DEBUG" "PRE-COMMIT > Executing 'ansible-lint' ..." + cicd_tools "poetry" ansible-lint + popd >> /dev/null + done +} + +main "$@" diff --git a/.cicd-tools/boxes/bootstrap/pre-commit/lint-github-workflow-header.sh b/.cicd-tools/boxes/bootstrap/pre-commit/lint-github-workflow-header.sh new file mode 100755 index 0000000..a7d9980 --- /dev/null +++ b/.cicd-tools/boxes/bootstrap/pre-commit/lint-github-workflow-header.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Verifies the correct headers are present on GitHub workflow files. + +# @: An array of GitHub workflow files to lint. + +# pre-commit script. + +set -eo pipefail + +# shellcheck source=/dev/null +source "$(dirname -- "${BASH_SOURCE[0]}")/../libraries/logging.sh" + +main() { + for WORKFLOW_FILE_PATH in "$@"; do + + log "INFO" "Checking header for: '${WORKFLOW_FILE_PATH}' ... " + + WORKFLOW_BASENAME="$(basename "${WORKFLOW_FILE_PATH}")" + + log "DEBUG" "Basename: '${WORKFLOW_BASENAME}' ... " + + if [[ "${WORKFLOW_BASENAME}" == job-* ]]; then + log "DEBUG" "Checking Job Header ..." + HEADER_NAME="$(echo "${WORKFLOW_BASENAME}" | cut -d. -f1)" + else + log "DEBUG" "Checking Workflow Header ..." + HEADER_NAME=".+-github-$(echo "${WORKFLOW_BASENAME}" | cut -d. -f1)" + fi + + if ! grep -E "^name: ${HEADER_NAME}$" "${WORKFLOW_FILE_PATH}" >> /dev/null; then + log "ERROR" "Incorrect Header on '${WORKFLOW_FILE_PATH}'" + log "ERROR" "EXPECTED PATTERN: ^${HEADER_NAME}$" + exit 127 + fi + + done +} + +main "$@" diff --git a/.cicd-tools/boxes/bootstrap/pre-commit/spelling-commit-message.sh b/.cicd-tools/boxes/bootstrap/pre-commit/spelling-commit-message.sh new file mode 100755 index 0000000..4d5ede7 --- /dev/null +++ b/.cicd-tools/boxes/bootstrap/pre-commit/spelling-commit-message.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Runs vale on the specified commit message file, with the Git content filtered out. + +# 1: The Docker image and tag to use. +# 2: The commit message file to lint. + +# pre-commit script. + +set -eo pipefail + +# shellcheck source=/dev/null +source "$(dirname -- "${BASH_SOURCE[0]}")/../libraries/logging.sh" + +main() { + local PRECOMMIT_GIT_COMMIT_MESSAGE_FILE + local PRECOMMIT_GIT_CONTENT_REGEX + local PRECOMMIT_VALE_DOCKER_IMAGE + + PRECOMMIT_GIT_COMMIT_MESSAGE_FILE="${2}" + PRECOMMIT_GIT_CONTENT_REGEX='/^#[[:blank:]]*.*$/d' + PRECOMMIT_VALE_DOCKER_IMAGE="${1}" + + log "DEBUG" "PRE_COMMIT > Docker Image: '${PRECOMMIT_VALE_DOCKER_IMAGE}'" + log "DEBUG" "PRE_COMMIT > Commit Message: '${PRECOMMIT_GIT_COMMIT_MESSAGE_FILE}'" + sed "${PRECOMMIT_GIT_CONTENT_REGEX}" "${PRECOMMIT_GIT_COMMIT_MESSAGE_FILE}" + log "DEBUG" "PRE_COMMIT > Running vale ..." + sed "${PRECOMMIT_GIT_CONTENT_REGEX}" "${PRECOMMIT_GIT_COMMIT_MESSAGE_FILE}" | + docker run -i --rm -v "$(pwd)":/mnt --workdir /mnt "${PRECOMMIT_VALE_DOCKER_IMAGE}" vale + log "INFO" "PRE-COMMIT > Commit message spelling has passed!" +} + +main "$@" diff --git a/.cicd-tools/boxes/bootstrap/schemas/cookiecutter.json b/.cicd-tools/boxes/bootstrap/schemas/cookiecutter.json new file mode 100644 index 0000000..663f2e6 --- /dev/null +++ b/.cicd-tools/boxes/bootstrap/schemas/cookiecutter.json @@ -0,0 +1,63 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "0.1.0", + "description": "CICD-Tools Cookiecutter Required Fields Schema", + "additionalProperties": true, + "minProperties": 10, + "required": [ + "github_handle", + "project_slug", + "project_name", + "_BRANCH_NAME_BASE", + "_BRANCH_NAME_DEVELOPMENT", + "_DOCKER_DEFAULT_CONTAINER", + "_GITHUB_CI_DEFAULT_CONCURRENCY", + "_GITHUB_CI_DEFAULT_PYTHON_VERSIONS", + "_GITHUB_CI_DEFAULT_VERBOSE_NOTIFICATIONS" + ], + "type": "object", + "uniqueItems": true, + "properties": { + "github_handle": { + "description": "The author's GitHub handle, used to create repository paths.", + "type": "string" + }, + "project_name": { + "description": "The plaintext name of the new project that will be templated.", + "type": "string" + }, + "project_slug": { + "description": "The slugified name of the new project that will be templated, used for the repository name.", + "type": "string" + }, + "_BRANCH_NAME_BASE": { + "description": "The name of the base branch that will be used in the templated repository.", + "type": "string" + }, + "_BRANCH_NAME_DEVELOPMENT": { + "description": "The name of the development branch that will be used in the templated repository.", + "type": "string" + }, + "_DOCKER_DEFAULT_CONTAINER": { + "description": "The container that will be used for the shellcheck, shfmt and other core binaries.", + "type": "string" + }, + "_GITHUB_CI_DEFAULT_CONCURRENCY": { + "description": "The default concurrency value that will be used for GitHub workflows.", + "type": "number" + }, + "_GITHUB_CI_DEFAULT_PYTHON_VERSIONS": { + "description": "The list of Python versions that will be used in GitHub workflows.", + "type": "array", + "contains": { + "pattern": "^3\\.[0-9]$", + "type": "string" + }, + "minContains": 1 + }, + "_GITHUB_CI_DEFAULT_VERBOSE_NOTIFICATIONS": { + "description": "The default verbosity of GitHub Action notifications.", + "type": "boolean" + } + } +} diff --git a/.cicd-tools/boxes/bootstrap/schemas/manifest.json b/.cicd-tools/boxes/bootstrap/schemas/manifest.json new file mode 100644 index 0000000..27cd7f9 --- /dev/null +++ b/.cicd-tools/boxes/bootstrap/schemas/manifest.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "0.1.0", + "description": "CICD-Tools Manifest Schema", + "additionalProperties": false, + "minProperties": 5, + "type": "object", + "uniqueItems": true, + "properties": { + "disable_security": { + "description": "Use hash validation to ensure downloaded content is trusted (highly recommended).", + "type": "boolean" + }, + "manifest": { + "description": "Trusted bundles and files available on this SHA of CICD-Tools.", + "type": "object", + "uniqueItems": true, + "properties": {}, + "patternProperties": { + "^[A-Za-z0-9\\.]$": { + "$ref": "#/definitions/ENTRY" + } + } + }, + "source": { + "description": "The download URL for CICD-Tools repository.", + "$ref": "#/definitions/URL" + }, + "toolbox_path": { + "description": "The path in the CICD-Tools repository to bundles.", + "type": "string" + }, + "version": { + "description": "The SHA identifier (Branch, Tag or Commit ID) of the CICD-Tools repository to use.", + "pattern": "^[A-Za-z]+$", + "type": "string" + } + }, + "definitions": { + "URL": { + "format": "uri", + "pattern": "^https?:\/\/" + }, + "ENTRY": { + "description": "A downloadable file in the manifest, with it's SHA256 sum.", + "format": "string" + } + } +} diff --git a/.cicd-tools/configuration/actionlint.yaml b/.cicd-tools/configuration/actionlint.yaml new file mode 100644 index 0000000..1627bf1 --- /dev/null +++ b/.cicd-tools/configuration/actionlint.yaml @@ -0,0 +1,4 @@ +--- +self-hosted-runner: + # Labels of self-hosted runner in array of string + labels: [] diff --git a/.cicd-tools/configuration/changelog.json b/.cicd-tools/configuration/changelog.json new file mode 100644 index 0000000..1a62ab6 --- /dev/null +++ b/.cicd-tools/configuration/changelog.json @@ -0,0 +1,21 @@ +{ + "options": { + "preset": { + "name": "conventionalcommits", + "types": [ + { "type": "feat", "section": "Features" }, + { "type": "feature", "section": "Features" }, + { "type": "fix", "section": "Bug Fixes" }, + { "type": "perf", "section": "Performance Improvements" }, + { "type": "revert", "section": "Reverts" }, + { "type": "docs", "section": "Documentation"}, + { "type": "style", "section": "Styles"}, + { "type": "chore", "section": "Miscellaneous Chores"}, + { "type": "refactor", "section": "Code Refactoring"}, + { "type": "test", "section": "Tests"}, + { "type": "build", "section": "Build System"}, + { "type": "ci", "section": "Continuous Integration"} + ] + } + } +} diff --git a/.cicd-tools/pgp/verification.sign b/.cicd-tools/pgp/verification.sign new file mode 100644 index 0000000..44bc538 --- /dev/null +++ b/.cicd-tools/pgp/verification.sign @@ -0,0 +1,7 @@ +-----BEGIN PGP SIGNATURE----- + +iHUEABYKAB0WIQTwenlkfpHlYaeGttDZAg9/7iDb8gUCZCkYCQAKCRDZAg9/7iDb +8nvIAQDTZImTu5eKtipUhlDA5TYXroyOhX0CZnwbEsS9ySNsmgEAqcXQZBeXW2FZ +VyKPtGiGe4bUvD+BJJPa6yjw35gS5wY= +=w1bO +-----END PGP SIGNATURE----- diff --git a/.cicd-tools/pgp/verification.txt b/.cicd-tools/pgp/verification.txt new file mode 100644 index 0000000..844c10f --- /dev/null +++ b/.cicd-tools/pgp/verification.txt @@ -0,0 +1 @@ +CICD-Tools Verified diff --git a/.github/actions/action-00-toolbox/action.yml b/.github/actions/action-00-toolbox/action.yml new file mode 100644 index 0000000..f5ed646 --- /dev/null +++ b/.github/actions/action-00-toolbox/action.yml @@ -0,0 +1,18 @@ +--- +name: action-00-toolbox +description: "Fetches the CICD-Tools toolbox." +author: niall@niallbyrne.ca + +inputs: + PROJECT_ROOT_PATH: + default: "." + description: "Optional, allows you to specify a path to the project's root." + required: false + +runs: + using: "composite" + steps: + - name: Toolbox - Install CICD-Tools Toolbox + uses: cicd-tools-org/cicd-tools/.github/actions/action-00-toolbox@master + with: + PROJECT_ROOT_PATH: ${{ inputs.PROJECT_ROOT_PATH }} diff --git a/.github/config/schemas/workflows/workflow-push.json b/.github/config/schemas/workflows/workflow-push.json new file mode 100644 index 0000000..a6c0d21 --- /dev/null +++ b/.github/config/schemas/workflows/workflow-push.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "0.1.0", + "description": "Ansible Workbench GitHub Push Workflow Schema", + "additionalProperties": false, + "required": [ + "ci_commit_spelling_rev_range", + "ci_commitizen_rev_range", + "ci_concurrency_limit", + "ci_extra_release_content", + "ci_python_versions", + "ci_trufflehog_extra_scan_args", + "ci_verbose_notifications" + ], + "type": "object", + "uniqueItems": true, + "properties": { + "ci_commit_spelling_rev_range": { + "description": "This is the fallback commit range for commit spelling checks. This should contain the id of the first correctly spelled commit in this repo, or HEAD for all commits.", + "type": "string" + }, + "ci_commitizen_rev_range": { + "description": "This is the fallback commit range for commitizen to lint. This should contain the id of the first linted commit in this repo, or HEAD for all commits.", + "type": "string" + }, + "ci_concurrency_limit": { + "description": "This controls the concurrency of each matrix instance in GitHub Actions.", + "type": "number" + }, + "ci_extra_release_content": { + "description": "This controls the concurrency of each matrix instance in GitHub Actions.", + "type": "array", + "contains": { + "type": "string" + } + }, + "ci_python_versions": { + "description": "This array contains the list of Python versions the workflow steps will execute on.", + "type": "array", + "contains": { + "pattern": "^3\\.[0-9]$", + "type": "string" + } + }, + "ci_trufflehog_extra_scan_args": { + "description": "This is a space separated list of extra arguments you can pass to the trufflehog binary.", + "type": "string" + }, + "ci_verbose_notifications": { + "description": "This enables success notifications for each job in the GitHub workflows.", + "type": "boolean" + } + } +} diff --git a/.github/config/workflows/workflow-push.json b/.github/config/workflows/workflow-push.json new file mode 100644 index 0000000..2bc7103 --- /dev/null +++ b/.github/config/workflows/workflow-push.json @@ -0,0 +1,12 @@ +{ + "ci_commit_spelling_rev_range": "HEAD", + "ci_commitizen_rev_range": "HEAD", + "ci_concurrency_limit": 4, + "ci_extra_release_content": [ + "## Customizable Text.", + "This message is appended to the changelog of your GitHub release." + ], + "ci_python_versions": ["3.9"], + "ci_trufflehog_extra_scan_args": "", + "ci_verbose_notifications": false +} diff --git a/.github/scripts/job-50-test-precommit.sh b/.github/scripts/job-50-test-precommit.sh new file mode 100755 index 0000000..5df396c --- /dev/null +++ b/.github/scripts/job-50-test-precommit.sh @@ -0,0 +1,135 @@ +#!/bin/bash + +# Performs tests on the pre-commit hooks. + +# Implementation: +# Templates implementing this script will likely also have to customize their .job-50-precommit.yml workflow. +# The API demonstrated here is more for example purposes. + +# 1: The name of a pre-commit test scenario. (See 'main' below.) +# TEST_PROJECT_NAME: The name of the rendered test project. + +# CI only script. + +set -eo pipefail + +scenario() { + + local TEMP_FILE + + test_commit_lint_fails() { + util "git_reset" + TEMP_FILE=$(util "create_tmp") + touch "${TEMP_FILE}" + git stage "${TEMP_FILE}" + git commit -m 'test - pre-commit: improperly formatted commit' || exit 0 + util "fail" + } + + test_commit_spelling_fails() { + util "git_reset" + TEMP_FILE=$(util "create_tmp") + touch "${TEMP_FILE}" + git stage "${TEMP_FILE}" + git commit -m 'test(PRE-COMMIT): ssspelling error' || exit 0 + util "fail" + } + + test_toml_lint_fails() { + util "git_reset" + sed -i.bak 's/authors =/ authors = /g' pyproject.toml + git stage pyproject.toml + git commit -m 'test(PRE-COMMIT): fail due to tomll' || exit 0 + util "fail" + } + + test_toml_lint_passes() { + util "git_reset" + sed -i.bak "s/python = '^3.9/python = '>=3.10.0,<4.0/g" pyproject.toml + git stage pyproject.toml + git commit -m 'test(PRE-COMMIT): upgrade python without issue' + } + + test_shell_lint_fails() { + util "git_reset" + TEMP_FILE=$(util "create_tmp") + echo -e "#!/bin/bash\nls *.bash" > "${TEMP_FILE}.sh" + git stage "${TEMP_FILE}.sh" + git commit -m 'test(PRE-COMMIT): fail due to shellcheck' || exit 0 + util "fail" + } + + test_shell_format_fails() { + util "git_reset" + TEMP_FILE=$(util "create_tmp") + echo -e "#!/bin/bash\nls bash_scripts;ls shell_scripts" > "${TEMP_FILE}.sh" + git stage "${TEMP_FILE}.sh" + git commit -m 'test(PRE-COMMIT): fail due to shfmt' || exit 0 + util "fail" + } + + test_workflow_lint_fails() { + util "git_reset" + find .github/workflows -type f -name '*.yml' -exec sed -i.bak 's/uses:/illegal-yaml-key:/g' {} \; + git stage .github + git commit -m 'test(PRE-COMMIT): fail due to actionlint' || exit 0 + util "fail" + } + + test_workflow_header_lint_fails() { + util "git_reset" + sed -i.bak 's,-github-workflow-push,-github-wrong-name,g' .github/workflows/workflow-push.yml + git stage .github + git commit -m 'test(PRE-COMMIT): fail due to workflow header lint' || exit 0 + util fail + } + + "$@" + +} + +util() { + + local COMMAND + local PREFIX + + _util_create_tmp() { + mktemp tmp.XXXXXXX + } + + _util_fail() { + echo "This commit should have failed." + exit 127 + } + + _util_git_reset() { + git reset HEAD + git clean -fd + git checkout . + } + + _util_unknown_command() { + echo "Unknown utility command: '${COMMAND}'" + exit 127 + } + + PREFIX="_util" + COMMAND="${PREFIX}_${1}" + if [[ $(type -t "${COMMAND}") == function ]]; then + shift + "${COMMAND}" "$@" + else + "${PREFIX}_unknown_command" + fi + +} + +main() { + + pushd "${TEST_PROJECT_NAME}" >> /dev/null + scenario "${1}" + popd >> /dev/null + +} + +main "$@" diff --git a/.github/scripts/step-setup-environment.sh b/.github/scripts/step-setup-environment.sh new file mode 100644 index 0000000..edb1753 --- /dev/null +++ b/.github/scripts/step-setup-environment.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# Configures environment variables for GitHub Actions. + +# Implementation: +# Projects implementing this script must set the required environment variables in the GitHub runner's environment context. +# +# BRANCH_OR_TAG: The current branch or tag being tested. +# CACHE_TTL: A unique CACHE value that determines the cache's TTL. (Default strategy: day of the month.) +# NOTIFICATION_LINK: Consumed by the notification script to provide a clickable link to the workflow run in GitHub. +# PROJECT_NAME: The slugified name of the template project. Should match the GitHub repository name. +# PROJECT_OWNER: The GitHub owner of the project. +# TEMPLATE_BRANCH_NAME_BASE: The name of the templated repository's default branch name. (Defaults to 'master'.) +# TEMPLATE_BRANCH_NAME_DEVELOPMENT: The name of the templated repository's development branch name. (Defaults to 'dev'.) + +# CI only script. + +set -eo pipefail + +WORKFLOW_NAME="${WORKFLOW_NAME:-""}" + +main() { + + PROJECT_NAME="smtp" + PROJECT_OWNER="niallbyrne_ca" + + BRANCH_OR_TAG="$(echo "${GITHUB_REF}" | sed -E 's,refs/heads/|refs/tags/,,g')" + WORKFLOW_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + + [[ "${WORKFLOW_NAME}" != "" ]] && WORKFLOW_NAME="-${WORKFLOW_NAME}" + + { + echo "BRANCH_OR_TAG=${BRANCH_OR_TAG}" + echo "CACHE_TTL=$(date +%d)" + echo "NOTIFICATION_LINK=${PROJECT_NAME}${WORKFLOW_NAME} [<${WORKFLOW_URL}|${BRANCH_OR_TAG}>]" + echo "PROJECT_NAME=${PROJECT_NAME}" + echo "PROJECT_OWNER=${PROJECT_OWNER}" + echo "TEMPLATE_BRANCH_NAME_BASE=${TEMPLATE_BRANCH_NAME_BASE-master}" + echo "TEMPLATE_BRANCH_NAME_DEVELOPMENT=${TEMPLATE_BRANCH_NAME_DEVELOPMENT-dev}" + } >> "${GITHUB_ENV}" + +} + +main "$@" diff --git a/.github/workflows/workflow-push.yml b/.github/workflows/workflow-push.yml new file mode 100644 index 0000000..116ee63 --- /dev/null +++ b/.github/workflows/workflow-push.yml @@ -0,0 +1,214 @@ +--- +name: smtp-github-workflow-push + +# Begin Cookiecutter Template Content + +on: + push: + schedule: + - cron: "0 6 * * 1" + workflow_dispatch: + +# secrets: +# SLACK_WEBHOOK: +# description: "Optional, enables Slack notifications." +# required: false + +jobs: + + configuration: + uses: cicd-tools-org/cicd-tools/.github/workflows/job-00-generic-read_json_file.yml@master + with: + JSON_FILE_PATH: ".github/config/workflows/workflow-push.json" + + start: + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-00-generic-notification.yml@master + with: + NOTIFICATION_EMOJI: ":vertical_traffic_light:" + NOTIFICATION_MESSAGE: "Workflow has started!" + + security: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-10-generic-security_scan_credentials.yml@master + with: + EXTRA_BINARY_ARGS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_trufflehog_extra_scan_args }} + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + markdown_links: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-30-generic-markdown_links.yml@master + with: + CONFIG_FILE: ".github/config/actions/gaurav-nelson-github-action-markdown-link-check.json" + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + pre-commit_hooks: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-50-poetry-test_basic_precommit_hooks.yml@master + with: + CHECK_CREDENTIALS: true + CHECK_TOML: true + CHECK_WORKFLOW: true + CONCURRENCY: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + PYTHON_VERSIONS: ${{ toJSON(fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_python_versions) }} + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + commit_lint: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-80-poetry-rev_range_command.yml@master + with: + COMMAND: | + poetry run cz check --rev-range "${PUSHED_COMMIT_REV_RANGE}" + COMMAND_NAME: "Commit Message Lint" + CONCURRENCY: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + PYTHON_VERSIONS: ${{ toJSON(fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_python_versions) }} + REV_RANGE: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_commitizen_rev_range }} + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + commit_spell_check: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-80-poetry-rev_range_command.yml@master + with: + COMMAND: | + CICD_COMMIT_MESSAGES_FILE="$(mktemp XXXXXXXX.git_history_file)" + git log --pretty=format:%s "${PUSHED_COMMIT_REV_RANGE}" > "${CICD_COMMIT_MESSAGES_FILE}" + poetry run pre-commit run --hook-stage commit-msg spelling-commit-message --commit-msg-filename "${CICD_COMMIT_MESSAGES_FILE}" + COMMAND_NAME: "Commit Message Spelling" + CONCURRENCY: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + PYTHON_VERSIONS: ${{ toJSON(fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_python_versions) }} + REV_RANGE: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_commit_spelling_rev_range }} + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + json_schema_lint: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-80-poetry-precommit_commit_stage_hook.yml@master + with: + CONCURRENCY: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + PRECOMMIT_HOOK_ID: "check-jsonschema" + PRECOMMIT_HOOK_NAME: "Workflow Config JSON Schema Linting" + PYTHON_VERSIONS: ${{ toJSON(fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_python_versions) }} + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + markdown_lint: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-80-poetry-precommit_commit_stage_hook.yml@master + with: + CONCURRENCY: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + PRECOMMIT_HOOK_ID: "lint-markdown" + PRECOMMIT_HOOK_NAME: "Markdown Linting" + PYTHON_VERSIONS: ${{ toJSON(fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_python_versions) }} + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + markdown_spelling: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-80-poetry-precommit_commit_stage_hook.yml@master + with: + CONCURRENCY: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + PRECOMMIT_HOOK_ID: "spelling-markdown" + PRECOMMIT_HOOK_NAME: "Markdown Spelling" + PYTHON_VERSIONS: ${{ toJSON(fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_python_versions) }} + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + shell_lint: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + strategy: + fail-fast: true + matrix: + hook: + - id: "format-shell" + name: "Shell Formatting" + - id: "lint-shell" + name: "Shell Linting" + max-parallel: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-80-poetry-precommit_commit_stage_hook.yml@master + with: + CONCURRENCY: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + PRECOMMIT_HOOK_ID: ${{ matrix.hook.id }} + PRECOMMIT_HOOK_NAME: ${{ matrix.hook.name }} + PYTHON_VERSIONS: ${{ toJSON(fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_python_versions) }} + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + toml_lint: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-80-poetry-precommit_commit_stage_hook.yml@master + with: + CONCURRENCY: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + PRECOMMIT_HOOK_ID: "format-toml" + PRECOMMIT_HOOK_NAME: "TOML Formatting" + PYTHON_VERSIONS: ${{ toJSON(fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_python_versions) }} + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + workflow_lint: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + strategy: + fail-fast: true + matrix: + hook: + - id: "lint-github-workflow" + name: "Workflow Linting" + - id: "lint-github-workflow-header" + name: "Workflow Header Linting" + max-parallel: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-80-poetry-precommit_commit_stage_hook.yml@master + with: + CONCURRENCY: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + PRECOMMIT_HOOK_ID: ${{ matrix.hook.id }} + PRECOMMIT_HOOK_NAME: ${{ matrix.hook.name }} + PYTHON_VERSIONS: ${{ toJSON(fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_python_versions) }} + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + yaml_lint: + needs: [configuration] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-80-poetry-precommit_commit_stage_hook.yml@master + with: + CONCURRENCY: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_concurrency_limit }} + PRECOMMIT_HOOK_ID: "yamllint" + PRECOMMIT_HOOK_NAME: "YAML Linting" + PYTHON_VERSIONS: ${{ toJSON(fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_python_versions) }} + VERBOSE_NOTIFICATIONS: ${{ fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_verbose_notifications }} + + create_release: + permissions: + contents: write + needs: [commit_lint, commit_spell_check, configuration, json_schema_lint, markdown_links, markdown_lint, markdown_spelling, pre-commit_hooks, security, shell_lint, start, toml_lint, workflow_lint, yaml_lint] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-99-poetry-create_release.yml@master + with: + JSON_APPENDED_CONTENT: ${{ toJSON(fromJSON(needs.configuration.outputs.JSON_FILE_DATA).ci_extra_release_content) }} + + success: + needs: [create_release] + secrets: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + uses: cicd-tools-org/cicd-tools/.github/workflows/job-00-generic-notification.yml@master + with: + NOTIFICATION_EMOJI: ":checkered_flag:" + NOTIFICATION_MESSAGE: "Workflow has completed successfully!" + +# End Cookiecutter Template Content diff --git a/.gitignore b/.gitignore index 30d74d2..eb3f120 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -test \ No newline at end of file +test.cicd-tools/boxes/* +!.cicd-tools/boxes/bootstrap diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..22e23b9 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,53 @@ +--- +default_install_hook_types: + - pre-commit + - commit-msg +repos: + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.22.0 + hooks: + - id: check-jsonschema + name: check-github-workflow-push-schema + files: "^\\.github/config/workflows/workflow-push.json$" + args: + - "--schemafile" + - ".github/config/schemas/workflows/workflow-push.json" + stages: [commit] + - repo: https://github.com/commitizen-tools/commitizen + rev: 3.2.2 + hooks: + - id: commitizen + stages: [commit-msg] + - repo: https://github.com/cicd-tools-org/pre-commit.git + rev: 0.2.0 + hooks: + - id: format-shell + args: + - "-w" + - "--indent=2" + - "-ci" + - "-sr" + - id: format-toml + - id: lint-github-workflow-header + - id: lint-github-workflow + - id: lint-markdown + args: + - "-c" + - ".markdownlint.yml" + - id: lint-shell + args: + - "--color=always" + - "--source-path=SCRIPTDIR" + - "--exclude=SC2317" + - "-x" + - id: security-credentials + - id: spelling-commit-message + - id: spelling-markdown + - repo: https://github.com/adrienverge/yamllint.git + rev: v1.32.0 + hooks: + - id: yamllint + args: + - "-c" + - "./.yamllint.yml" + stages: [commit] diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 0000000..1bf2f47 --- /dev/null +++ b/.vale.ini @@ -0,0 +1,10 @@ +StylesPath = ".vale" +Vocab = "smtp" + +[*] +BasedOnStyles = Vale +Vale.Terms = NO + +[*.md] +BasedOnStyles = Vale +Vale.Terms = YES diff --git a/.vale/Vocab/smtp/accept.txt b/.vale/Vocab/smtp/accept.txt new file mode 100644 index 0000000..e69de29 diff --git a/.vale/Vocab/smtp/reject.txt b/.vale/Vocab/smtp/reject.txt new file mode 100644 index 0000000..e69de29 diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..dbe971a --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,51 @@ +--- +# Based on ansible-lint config +extends: default + +ignore: | + .ansible/ + .cache/ + .idea/ + .mac_maker/ + ansible_role/ + collections/ + roles/ + +rules: + braces: + max-spaces-inside: 0 + level: error + brackets: + max-spaces-inside: 0 + level: error + colons: + max-spaces-after: -1 + level: error + commas: + max-spaces-after: -1 + level: error + indentation: + spaces: consistent + indent-sequences: true + level: error + comments: disable + comments-indentation: disable + document-start: + level: error + empty-lines: + max: 3 + level: error + hyphens: + level: error + key-duplicates: + level: error + line-length: disable + new-line-at-end-of-file: + level: error + new-lines: + type: unix + octal-values: + forbid-implicit-octal: true + trailing-spaces: + level: error + truthy: disable diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..c29e462 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,534 @@ +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. + +[[package]] +name = "argcomplete" +version = "3.1.6" +description = "Bash tab completion for argparse" +optional = false +python-versions = ">=3.8" +files = [ + {file = "argcomplete-3.1.6-py3-none-any.whl", hash = "sha256:71f4683bc9e6b0be85f2b2c1224c47680f210903e23512cfebfe5a41edfd883a"}, + {file = "argcomplete-3.1.6.tar.gz", hash = "sha256:3b1f07d133332547a53c79437527c00be48cca3807b1d4ca5cab1b26313386a6"}, +] + +[package.extras] +test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] + +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "commitizen" +version = "3.12.0" +description = "Python commitizen client tool" +optional = false +python-versions = ">=3.8" +files = [ + {file = "commitizen-3.12.0-py3-none-any.whl", hash = "sha256:082f4733409bc4f01f987467295f8393ceb16b42cc648cf2f5a7a754c6d594db"}, + {file = "commitizen-3.12.0.tar.gz", hash = "sha256:7c313f1f85f45c9acf1a70f1637deab5c388150ae8660a0037ac260e77bb1492"}, +] + +[package.dependencies] +argcomplete = ">=1.12.1,<3.2" +charset-normalizer = ">=2.1.0,<4" +colorama = ">=0.4.1,<0.5.0" +decli = ">=0.6.0,<0.7.0" +importlib_metadata = ">=4.13,<7" +jinja2 = ">=2.10.3" +packaging = ">=19" +pyyaml = ">=3.08" +questionary = ">=2.0,<3.0" +termcolor = ">=1.1,<3" +tomlkit = ">=0.5.3,<1.0.0" + +[[package]] +name = "decli" +version = "0.6.1" +description = "Minimal, easy-to-use, declarative cli tool" +optional = false +python-versions = ">=3.7" +files = [ + {file = "decli-0.6.1-py3-none-any.whl", hash = "sha256:7815ac58617764e1a200d7cadac6315fcaacc24d727d182f9878dd6378ccf869"}, + {file = "decli-0.6.1.tar.gz", hash = "sha256:ed88ccb947701e8e5509b7945fda56e150e2ac74a69f25d47ac85ef30ab0c0f0"}, +] + +[[package]] +name = "distlib" +version = "0.3.7" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, + {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, +] + +[[package]] +name = "filelock" +version = "3.13.1" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] + +[[package]] +name = "identify" +version = "2.5.31" +description = "File identification library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "identify-2.5.31-py2.py3-none-any.whl", hash = "sha256:90199cb9e7bd3c5407a9b7e81b4abec4bb9d249991c79439ec8af740afc6293d"}, + {file = "identify-2.5.31.tar.gz", hash = "sha256:7736b3c7a28233637e3c36550646fc6389bedd74ae84cb788200cc8e2dd60b75"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "importlib-metadata" +version = "6.8.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, + {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, +] + +[package.dependencies] +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 = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] + +[[package]] +name = "jinja2" +version = "3.1.2" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markupsafe" +version = "2.1.3" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, + {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, +] + +[[package]] +name = "nodeenv" +version = "1.8.0" +description = "Node.js virtual environment builder" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, +] + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "platformdirs" +version = "3.11.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, + {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, +] + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] + +[[package]] +name = "pre-commit" +version = "3.5.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"}, + {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "prompt-toolkit" +version = "3.0.36" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.6.2" +files = [ + {file = "prompt_toolkit-3.0.36-py3-none-any.whl", hash = "sha256:aa64ad242a462c5ff0363a7b9cfe696c20d55d9fc60c11fd8e632d064804d305"}, + {file = "prompt_toolkit-3.0.36.tar.gz", hash = "sha256:3e163f254bef5a03b146397d7c1963bd3e2812f0964bb9a24e6ec761fd28db63"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "questionary" +version = "2.0.1" +description = "Python library to build pretty command line user prompts ⭐️" +optional = false +python-versions = ">=3.8" +files = [ + {file = "questionary-2.0.1-py3-none-any.whl", hash = "sha256:8ab9a01d0b91b68444dff7f6652c1e754105533f083cbe27597c8110ecc230a2"}, + {file = "questionary-2.0.1.tar.gz", hash = "sha256:bcce898bf3dbb446ff62830c86c5c6fb9a22a54146f0f5597d3da43b10d8fc8b"}, +] + +[package.dependencies] +prompt_toolkit = ">=2.0,<=3.0.36" + +[[package]] +name = "setuptools" +version = "68.2.2" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, + {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "termcolor" +version = "2.3.0" +description = "ANSI color formatting for output in terminal" +optional = false +python-versions = ">=3.7" +files = [ + {file = "termcolor-2.3.0-py3-none-any.whl", hash = "sha256:3afb05607b89aed0ffe25202399ee0867ad4d3cb4180d98aaf8eefa6a5f7d475"}, + {file = "termcolor-2.3.0.tar.gz", hash = "sha256:b5b08f68937f138fe92f6c089b99f1e2da0ae56c52b78bf7075fd95420fd9a5a"}, +] + +[package.extras] +tests = ["pytest", "pytest-cov"] + +[[package]] +name = "tomlkit" +version = "0.12.3" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, + {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, +] + +[[package]] +name = "virtualenv" +version = "20.24.6" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.24.6-py3-none-any.whl", hash = "sha256:520d056652454c5098a00c0f073611ccbea4c79089331f60bf9d7ba247bb7381"}, + {file = "virtualenv-20.24.6.tar.gz", hash = "sha256:02ece4f56fbf939dbbc33c0715159951d6bf14aaf5457b092e4548e1382455af"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<4" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "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.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + +[[package]] +name = "wcwidth" +version = "0.2.10" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.10-py2.py3-none-any.whl", hash = "sha256:aec5179002dd0f0d40c456026e74a729661c9d468e1ed64405e3a6c2176ca36f"}, + {file = "wcwidth-0.2.10.tar.gz", hash = "sha256:390c7454101092a6a5e43baad8f83de615463af459201709556b6e4b1c861f97"}, +] + +[[package]] +name = "zipp" +version = "3.17.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, + {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.9" +content-hash = "b893b350029ed6d7d0f54d91f3cd31a16711cef8ff2454033fa8876d9ed8409e" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..ac54bdd --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,27 @@ +[build-system] +build-backend = 'poetry.core.masonry.api' +requires = ['poetry-core'] + +[tool] +[tool.commitizen] +bump_message = 'bump(RELEASE): $current_version → $new_version' +pre_bump_hooks = ['.cicd-tools/boxes/bootstrap/commitizen/pre_bump.sh'] +version = '0.1.0' +version_files = ['pyproject.toml:version'] +version_provider = 'poetry' + +[tool.poetry] +authors = ['Niall Byrne <9848926+niall-byrne@users.noreply.github.com>'] +description = '' +name = 'smtp' +readme = 'README.md' +version = '0.1.0' + +[tool.poetry.dependencies] +python = '^3.9' + +[tool.poetry.group] +[tool.poetry.group.dev] +[tool.poetry.group.dev.dependencies] +commitizen = '^3.12.0' +pre-commit = '^3.5.0'