From 0c0a5a5aa310301aaacb0e31589a72fc4ee73ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Fri, 5 Jan 2024 23:35:12 +0100 Subject: [PATCH 1/8] PostmanCli Add new command PostmanCli able to pull/push postman collections. Better configuration loading management. # Breaking changes N/A # Bug fixes - fixed regression - global options passed to the command was not taken into account(--verbose, -no-color, --log-level, ...) # Binaries changes - new binary PostmanCli able to pull/push postman collections - all binaries are using - shopt -s lastpipe from bash-tools-framework headers change - bash-tools configuration loading improved with default configuration automatically created if missing from a template - POSTMAN_API_KEY configuration is automatically added to ~/.bash-tools/.env if missing # Updated Bash tools functions N/A # New Bash tools functions - BashTools::Conf::requireLoad # Documentation - [Postman documentation](src/Postman/Readme.md) # Validation/Tooling - bats headers now loads bash tools framework mandatory headers - updated github action actions/setup-python from 4 to 5 --- .github/workflows/lint-test.yml | 3 +- .github/workflows/precommit-autoupdate.yml | 2 +- .pre-commit-config.yaml | 15 +- .vscode/launch.json | 7 + bin/cli | 94 +- bin/dbImport | 94 +- bin/dbImportProfile | 94 +- bin/dbImportStream | 94 +- bin/dbQueryAllDatabases | 7 +- bin/dbScriptAllDatabases | 7 +- bin/doc | 107 +- bin/gitIsAncestorOf | 94 +- bin/gitIsBranch | 94 +- bin/gitRenameBranch | 94 +- bin/installRequirements | 94 +- bin/mysql2puml | 96 +- bin/postmanCli | 2077 +++++++++++++++++ bin/upgradeGithubRelease | 96 +- bin/waitForIt | 96 +- bin/waitForMysql | 96 +- conf/.env | 5 + ...I-01-Basic_no_auth_postman_collection.json | 89 + ...Advanced_with_auth_postman_collection.json | 311 +++ .../GithubAPI-postman_environment.json | 15 + .../Atlas.postman_environment.json | 279 +++ .../Data API.postman_environment.json | 51 + .../MongoDBDataAPI.postman_collection.json | 289 +++ conf/postmanCli/openApis.json | 17 + install | 94 +- src/BashTools/Conf/requireLoad.bats | 59 + src/BashTools/Conf/requireLoad.sh | 36 + .../Collection/getCollectionIdByName.bats | 55 + .../Collection/getCollectionIdByName.sh | 34 + src/Postman/Collection/getName.bats | 30 + src/Postman/Collection/getName.sh | 12 + .../testsData/githubBasic_collection.json | 112 + .../testsData/postmanCollections.json | 31 + .../postmanCollections_invalidFile.json | 31 + .../postmanCollections_invalidJsonFile.json | 31 + src/Postman/Commands/forEachCollection.bats | 185 ++ src/Postman/Commands/forEachCollection.sh | 55 + src/Postman/Commands/pullCollections.bats | 130 ++ src/Postman/Commands/pullCollections.sh | 44 + src/Postman/Commands/pullCommand.bats | 138 ++ src/Postman/Commands/pullCommand.sh | 30 + src/Postman/Commands/pushCollections.bats | 132 ++ src/Postman/Commands/pushCollections.sh | 41 + src/Postman/Commands/pushCommand.bats | 138 ++ src/Postman/Commands/pushCommand.sh | 30 + .../Model/checkIfValidCollectionRefs.bats | 41 + .../Model/checkIfValidCollectionRefs.sh | 24 + src/Postman/Model/getCollectionFileByRef.bats | 29 + src/Postman/Model/getCollectionFileByRef.sh | 14 + src/Postman/Model/getCollectionRefs.bats | 26 + src/Postman/Model/getCollectionRefs.sh | 14 + src/Postman/Model/getName.bats | 20 + src/Postman/Model/getName.sh | 13 + .../Model/getRelativeConfigDirectory.bats | 15 + .../Model/getRelativeConfigDirectory.sh | 15 + .../testsData/GithubAPI/githubAdvanced.json | 1 + .../testsData/GithubAPI/githubBasic.json | 1 + .../MicrosoftGraph/microsoftGraph.json | 1 + ...etCollectionRefs-collectionsNotObject.json | 16 + .../getCollectionRefs-missingCollections.json | 16 + ...getCollectionRefs-missingFileProperty.json | 16 + .../getCollectionRefs-missingName.json | 4 + .../getCollection-missingCollections.json | 3 + .../testsData/getCollection-missingName.json | 3 + .../Model/testsData/getCollectionError.json | 17 + .../Model/testsData/getCollectionInvalid.json | 17 + .../Model/testsData/getCollectionRefs.json | 17 + .../getCollections_expectedResult.json | 17 + .../pullMode/GithubAPI/notWritableFile.json | 0 .../testsData/pullMode/NotWritable/.gitkeep | 0 ...tCollectionRefs-collectionsWithErrors.json | 16 + .../pushMode/GithubAPI/missingInfoName.json | 1 + .../pushMode/GithubAPI/notValidJsonFile.json | 1 + ...tCollectionRefs-collectionsWithErrors.json | 20 + src/Postman/Model/validate.bats | 157 ++ src/Postman/Model/validate.sh | 112 + src/Postman/Readme.md | 44 + src/Postman/api.bats | 69 + src/Postman/api.sh | 96 + src/Postman/checkApiKey.bats | 33 + src/Postman/checkApiKey.sh | 14 + src/Postman/displayResponse.bats | 23 + src/Postman/displayResponse.sh | 17 + src/Postman/testsData/.env.keyEmpty | 0 src/Postman/testsData/.env.keyFound | 1 + src/Postman/testsData/.env.keyNotFound | 0 src/Postman/testsData/expectedResponseFile | 3 + src/Postman/testsData/responseFile | 1 + src/_binaries/DbImport/dbImportProfile.bats | 2 + src/_binaries/DbImport/dbImportStream.bats | 1 + .../dbQueryAllDatabases.bats | 1 + .../dbScriptAllDatabases.bats | 1 + src/_binaries/Git/gitIsAncestorOf.bats | 2 + src/_binaries/Git/gitRenameBranch.bats | 2 + src/_binaries/Git/upgradeGithubRelease.bats | 3 + src/_binaries/Postman/command.postmanCli.tpl | 79 + src/_binaries/Postman/postmanCli.bats | 35 + src/_binaries/Postman/postmanCli.sh | 30 + .../Postman/testsData/postmanCli.help.txt | 73 + src/_binaries/Utils/waitForIt.bats | 3 +- src/_binaries/Utils/waitForMysql.bats | 3 +- src/_includes/_initFrameworkVariables.tpl | 1 + src/batsHeaders.sh | 10 +- 107 files changed, 7014 insertions(+), 45 deletions(-) create mode 100755 bin/postmanCli create mode 100644 conf/postmanCli/GithubAPI/GitHubAPI-01-Basic_no_auth_postman_collection.json create mode 100644 conf/postmanCli/GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json create mode 100644 conf/postmanCli/GithubAPI/GithubAPI-postman_environment.json create mode 100644 conf/postmanCli/MongoDbData/Atlas.postman_environment.json create mode 100644 conf/postmanCli/MongoDbData/Data API.postman_environment.json create mode 100644 conf/postmanCli/MongoDbData/MongoDBDataAPI.postman_collection.json create mode 100644 conf/postmanCli/openApis.json create mode 100755 src/BashTools/Conf/requireLoad.bats create mode 100755 src/BashTools/Conf/requireLoad.sh create mode 100755 src/Postman/Collection/getCollectionIdByName.bats create mode 100755 src/Postman/Collection/getCollectionIdByName.sh create mode 100755 src/Postman/Collection/getName.bats create mode 100755 src/Postman/Collection/getName.sh create mode 100644 src/Postman/Collection/testsData/githubBasic_collection.json create mode 100644 src/Postman/Collection/testsData/postmanCollections.json create mode 100644 src/Postman/Collection/testsData/postmanCollections_invalidFile.json create mode 100644 src/Postman/Collection/testsData/postmanCollections_invalidJsonFile.json create mode 100755 src/Postman/Commands/forEachCollection.bats create mode 100755 src/Postman/Commands/forEachCollection.sh create mode 100755 src/Postman/Commands/pullCollections.bats create mode 100755 src/Postman/Commands/pullCollections.sh create mode 100755 src/Postman/Commands/pullCommand.bats create mode 100755 src/Postman/Commands/pullCommand.sh create mode 100755 src/Postman/Commands/pushCollections.bats create mode 100755 src/Postman/Commands/pushCollections.sh create mode 100755 src/Postman/Commands/pushCommand.bats create mode 100755 src/Postman/Commands/pushCommand.sh create mode 100755 src/Postman/Model/checkIfValidCollectionRefs.bats create mode 100755 src/Postman/Model/checkIfValidCollectionRefs.sh create mode 100755 src/Postman/Model/getCollectionFileByRef.bats create mode 100755 src/Postman/Model/getCollectionFileByRef.sh create mode 100755 src/Postman/Model/getCollectionRefs.bats create mode 100755 src/Postman/Model/getCollectionRefs.sh create mode 100755 src/Postman/Model/getName.bats create mode 100755 src/Postman/Model/getName.sh create mode 100755 src/Postman/Model/getRelativeConfigDirectory.bats create mode 100755 src/Postman/Model/getRelativeConfigDirectory.sh create mode 100644 src/Postman/Model/testsData/GithubAPI/githubAdvanced.json create mode 100644 src/Postman/Model/testsData/GithubAPI/githubBasic.json create mode 100644 src/Postman/Model/testsData/MicrosoftGraph/microsoftGraph.json create mode 100644 src/Postman/Model/testsData/configMode/getCollectionRefs-collectionsNotObject.json create mode 100644 src/Postman/Model/testsData/configMode/getCollectionRefs-missingCollections.json create mode 100644 src/Postman/Model/testsData/configMode/getCollectionRefs-missingFileProperty.json create mode 100644 src/Postman/Model/testsData/configMode/getCollectionRefs-missingName.json create mode 100644 src/Postman/Model/testsData/getCollection-missingCollections.json create mode 100644 src/Postman/Model/testsData/getCollection-missingName.json create mode 100644 src/Postman/Model/testsData/getCollectionError.json create mode 100644 src/Postman/Model/testsData/getCollectionInvalid.json create mode 100644 src/Postman/Model/testsData/getCollectionRefs.json create mode 100644 src/Postman/Model/testsData/getCollections_expectedResult.json create mode 100644 src/Postman/Model/testsData/pullMode/GithubAPI/notWritableFile.json create mode 100644 src/Postman/Model/testsData/pullMode/NotWritable/.gitkeep create mode 100644 src/Postman/Model/testsData/pullMode/getCollectionRefs-collectionsWithErrors.json create mode 100644 src/Postman/Model/testsData/pushMode/GithubAPI/missingInfoName.json create mode 100644 src/Postman/Model/testsData/pushMode/GithubAPI/notValidJsonFile.json create mode 100644 src/Postman/Model/testsData/pushMode/getCollectionRefs-collectionsWithErrors.json create mode 100755 src/Postman/Model/validate.bats create mode 100755 src/Postman/Model/validate.sh create mode 100644 src/Postman/Readme.md create mode 100755 src/Postman/api.bats create mode 100755 src/Postman/api.sh create mode 100755 src/Postman/checkApiKey.bats create mode 100755 src/Postman/checkApiKey.sh create mode 100755 src/Postman/displayResponse.bats create mode 100755 src/Postman/displayResponse.sh create mode 100644 src/Postman/testsData/.env.keyEmpty create mode 100644 src/Postman/testsData/.env.keyFound create mode 100644 src/Postman/testsData/.env.keyNotFound create mode 100644 src/Postman/testsData/expectedResponseFile create mode 100644 src/Postman/testsData/responseFile create mode 100644 src/_binaries/Postman/command.postmanCli.tpl create mode 100755 src/_binaries/Postman/postmanCli.bats create mode 100755 src/_binaries/Postman/postmanCli.sh create mode 100644 src/_binaries/Postman/testsData/postmanCli.help.txt diff --git a/.github/workflows/lint-test.yml b/.github/workflows/lint-test.yml index f92073a2..0c64883f 100644 --- a/.github/workflows/lint-test.yml +++ b/.github/workflows/lint-test.yml @@ -88,7 +88,7 @@ jobs: - name: Set up Python if: matrix.runPrecommitTests # kics-scan ignore-line - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 @@ -149,7 +149,6 @@ jobs: USER_ID=1000 \ GROUP_ID=1000 \ vendor/bash-tools-framework/bin/test \ - -vvv \ --vendor "${{matrix.vendor}}" \ --bash-version "${{matrix.bashTarVersion}}" \ --bash-base-image "${{matrix.bashImage}}" \ diff --git a/.github/workflows/precommit-autoupdate.yml b/.github/workflows/precommit-autoupdate.yml index 07fa3313..53ad0fa6 100644 --- a/.github/workflows/precommit-autoupdate.yml +++ b/.github/workflows/precommit-autoupdate.yml @@ -19,7 +19,7 @@ jobs: - name: Set up Python # kics-scan ignore-line - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 53f098ba..79766181 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,8 @@ repos: - id: end-of-file-fixer exclude: | (?x)( - .svg$ + .svg$| + ^src\/Postman\/Model\/testsData\/pullMode\/GithubAPI\/notWritableFile.json$ ) - id: trailing-whitespace - id: check-executables-have-shebangs @@ -34,13 +35,23 @@ repos: (?x)^( conf\/.vscode\/settings.json| .vscode\/settings.json| - .vscode\/launch.json + .vscode\/launch.json| + src\/Postman\/Collection\/testsData\/postmanCollections_invalidJsonFile.json| + src\/Postman\/Model\/testsData\/pushMode\/GithubAPI\/notValidJsonFile.json| + src\/Postman\/Model\/testsData\/getCollectionInvalid.json| + src\/Postman\/Model\/testsData\/pullMode\/GithubAPI\/notWritableFile.json )$ - repo: https://github.com/pre-commit/mirrors-prettier rev: v4.0.0-alpha.8 hooks: - id: prettier + exclude: | + (?x)^( + src\/Postman\/Collection\/testsData\/postmanCollections_invalidJsonFile.json| + src\/Postman\/Model\/testsData\/getCollectionInvalid.json| + src\/Postman\/Model\/testsData\/pushMode\/GithubAPI\/notValidJsonFile.json + )$ - repo: https://github.com/fchastanet/jumanjihouse-pre-commit-hooks rev: 3.0.2 diff --git a/.vscode/launch.json b/.vscode/launch.json index bbdc225b..23c1c722 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,6 +16,13 @@ "name": "Bash-Debug (mysql2puml)", "program": "bin/mysql2puml", "args": ["src/_binaries/DbImport/testsData/dump.sql"] + }, + { + "type": "bashdb", + "request": "launch", + "name": "Bash-Debug (postmanCli)", + "program": "bin/postmanCli", + "args": ["export", "--help"] } ] } diff --git a/bin/cli b/bin/cli index d021ed45..f6f44efb 100755 --- a/bin/cli +++ b/bin/cli @@ -686,6 +686,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -904,6 +994,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -912,6 +1003,7 @@ Env::requireLoad UI::requireTheme Linux::requireRealpathCommand Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir # @require Compiler::Facade::requireCommandBinDir @@ -1554,7 +1646,7 @@ cliCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/dbImport b/bin/dbImport index f509dcd5..093839f7 100755 --- a/bin/dbImport +++ b/bin/dbImport @@ -871,6 +871,96 @@ Version::checkMinimal() { } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -1191,6 +1281,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -1199,6 +1290,7 @@ Env::requireLoad UI::requireTheme Linux::requireRealpathCommand Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir Linux::requireExecutedAsUser @@ -2110,7 +2202,7 @@ dbImportCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/dbImportProfile b/bin/dbImportProfile index 465aa4e2..be0dc3ce 100755 --- a/bin/dbImportProfile +++ b/bin/dbImportProfile @@ -654,6 +654,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -993,6 +1083,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -1001,6 +1092,7 @@ Env::requireLoad UI::requireTheme Log::requireLoad Linux::requireRealpathCommand +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir Linux::requireExecutedAsUser @@ -1689,7 +1781,7 @@ dbImportProfileCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/dbImportStream b/bin/dbImportStream index 2d9eae23..e13e9a6b 100755 --- a/bin/dbImportStream +++ b/bin/dbImportStream @@ -781,6 +781,96 @@ Version::checkMinimal() { } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -1101,6 +1191,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -1109,6 +1200,7 @@ Env::requireLoad UI::requireTheme Linux::requireRealpathCommand Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir Linux::requireExecutedAsUser @@ -1922,7 +2014,7 @@ dbImportStreamCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/dbQueryAllDatabases b/bin/dbQueryAllDatabases index df79f2a6..ae0cb7e8 100755 --- a/bin/dbQueryAllDatabases +++ b/bin/dbQueryAllDatabases @@ -1142,6 +1142,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -1835,7 +1836,7 @@ dbQueryAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(specify\ the\ number\ of\ db\ to\ query\ in\ parallel) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: 1' + echo " Default value: 1" echo -e " ${__HELP_OPTION_COLOR}--bar${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-b${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 @@ -1846,7 +1847,7 @@ dbQueryAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(character\ to\ use\ to\ separate\ mysql\ column) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: |' + echo " Default value: |" echo echo -e "${__HELP_TITLE_COLOR}QUERY OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--from-dsn${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-f ${__HELP_NORMAL} {single}" @@ -1896,7 +1897,7 @@ dbQueryAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/dbScriptAllDatabases b/bin/dbScriptAllDatabases index c19ed4d2..006cb424 100755 --- a/bin/dbScriptAllDatabases +++ b/bin/dbScriptAllDatabases @@ -990,6 +990,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -1722,7 +1723,7 @@ dbScriptAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(specify\ the\ number\ of\ db\ to\ query\ in\ parallel) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: 1' + echo " Default value: 1" echo -e " ${__HELP_OPTION_COLOR}--bar${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-b${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 @@ -1750,7 +1751,7 @@ dbScriptAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(if\ output\ dir\ provided\,\ will\ log\ each\ db\ result\ to\ log\ file) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: none' + echo " Default value: none" echo ' Possible values: none|log' echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" @@ -1794,7 +1795,7 @@ dbScriptAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/doc b/bin/doc index 2578c0d1..aa5a2e9a 100755 --- a/bin/doc +++ b/bin/doc @@ -666,6 +666,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -886,19 +976,6 @@ UI::requireTheme() { UI::theme "${BASH_FRAMEWORK_THEME-default}" } -# @description remove ansi codes from input or files given as argument -# @arg $@ files:String[] the files to filter -# @exitcode * if one of the filter command fails -# @stdin you can use stdin as alternative to files argument -# @stdout the filtered content -# @see https://en.wikipedia.org/wiki/ANSI_escape_code -# shellcheck disable=SC2120 -Filters::removeAnsiCodes() { - # cspell:disable - sed -E 's/\x1b\[[0-9;]*[mGKHF]//g' "$@" - # cspell:enable -} - # @description Display message using skip color (yellow) # @arg $1 message:String the message to display Log::displaySkipped() { @@ -931,6 +1008,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -938,6 +1016,7 @@ fi Env::requireLoad UI::requireTheme Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir # @require Compiler::Facade::requireCommandBinDir @@ -1545,7 +1624,7 @@ docCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/gitIsAncestorOf b/bin/gitIsAncestorOf index 1efb5321..e06cffdb 100755 --- a/bin/gitIsAncestorOf +++ b/bin/gitIsAncestorOf @@ -472,6 +472,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -645,6 +735,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -652,6 +743,7 @@ fi Env::requireLoad UI::requireTheme Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir Linux::requireExecutedAsUser @@ -1282,7 +1374,7 @@ gitIsAncestorOfCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/gitIsBranch b/bin/gitIsBranch index 66ddc940..ca046c09 100755 --- a/bin/gitIsBranch +++ b/bin/gitIsBranch @@ -472,6 +472,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -645,6 +735,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -652,6 +743,7 @@ fi Env::requireLoad UI::requireTheme Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir Linux::requireExecutedAsUser @@ -1260,7 +1352,7 @@ gitIsBranchCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/gitRenameBranch b/bin/gitRenameBranch index 85ef9456..40a9f301 100755 --- a/bin/gitRenameBranch +++ b/bin/gitRenameBranch @@ -510,6 +510,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -667,6 +757,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -674,6 +765,7 @@ fi Env::requireLoad UI::requireTheme Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir Linux::requireExecutedAsUser @@ -1366,7 +1458,7 @@ gitRenameBranchCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/installRequirements b/bin/installRequirements index b1a0fea6..b5d0f779 100755 --- a/bin/installRequirements +++ b/bin/installRequirements @@ -513,6 +513,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -744,6 +834,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -752,6 +843,7 @@ Env::requireLoad UI::requireTheme Git::requireGitCommand Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir Linux::requireExecutedAsUser @@ -1331,7 +1423,7 @@ installRequirementsCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/mysql2puml b/bin/mysql2puml index 0076f7e8..aaa106cb 100755 --- a/bin/mysql2puml +++ b/bin/mysql2puml @@ -595,6 +595,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -835,6 +925,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -843,6 +934,7 @@ Env::requireLoad UI::requireTheme Linux::requireRealpathCommand Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir # @require Compiler::Facade::requireCommandBinDir @@ -1433,7 +1525,7 @@ mysql2pumlCommand() { # shellcheck disable=SC2054 helpArray=(header\ configuration\ of\ the\ plant\ uml\ file) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" @@ -1476,7 +1568,7 @@ mysql2pumlCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/postmanCli b/bin/postmanCli new file mode 100755 index 00000000..d7ad1294 --- /dev/null +++ b/bin/postmanCli @@ -0,0 +1,2077 @@ +#!/usr/bin/env bash +############################################################################### +# GENERATED FACADE FROM https://github.com/fchastanet/bash-tools/tree/master/src/_binaries/Postman/postmanCli.sh +# DO NOT EDIT IT +# @generated +############################################################################### +# shellcheck disable=SC2288,SC2034 +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/postmanCli +# VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. +# FACADE + +# ensure that no user aliases could interfere with +# commands used in this script +unalias -a || true +shopt -u expand_aliases + +# shellcheck disable=SC2034 +((failures = 0)) || true + +# Bash will remember & return the highest exit code in a chain of pipes. +# This way you can catch the error inside pipes, e.g. mysqldump | gzip +set -o pipefail +set -o errexit + +# Command Substitution can inherit errexit option since bash v4.4 +shopt -s inherit_errexit || true + +# if set, and job control is not active, the shell runs the last command +# of a pipeline not executed in the background in the current shell +# environment. +shopt -s lastpipe + +# a log is generated when a command fails +set -o errtrace + +# use nullglob so that (file*.php) will return an empty array if no file +# matches the wildcard +shopt -s nullglob + +# ensure regexp are interpreted without accentuated characters +export LC_ALL=POSIX + +export TERM=xterm-256color + +# avoid interactive install +export DEBIAN_FRONTEND=noninteractive +export DEBCONF_NONINTERACTIVE_SEEN=true + +# store command arguments for later usage +# shellcheck disable=SC2034 +declare -a BASH_FRAMEWORK_ARGV=("$@") +# shellcheck disable=SC2034 +declare -a ORIGINAL_BASH_FRAMEWORK_ARGV=("$@") + +# @see https://unix.stackexchange.com/a/386856 +# shellcheck disable=SC2317 +interruptManagement() { + # restore SIGINT handler + trap - INT + # ensure that Ctrl-C is trapped by this script and not by sub process + # report to the parent that we have indeed been interrupted + kill -s INT "$$" +} +trap interruptManagement INT +SCRIPT_NAME=${0##*/} +REAL_SCRIPT_FILE="$(readlink -e "$(realpath "${BASH_SOURCE[0]}")")" +if [[ -n "${EMBED_CURRENT_DIR}" ]]; then + CURRENT_DIR="${EMBED_CURRENT_DIR}" +else + CURRENT_DIR="$(cd "$(readlink -e "${REAL_SCRIPT_FILE%/*}")" && pwd -P)" +fi + +################################################ +# Temp dir management +################################################ + +KEEP_TEMP_FILES="${KEEP_TEMP_FILES:-0}" +export KEEP_TEMP_FILES + +# PERSISTENT_TMPDIR is not deleted by traps +PERSISTENT_TMPDIR="${TMPDIR:-/tmp}/bash-framework" +export PERSISTENT_TMPDIR +mkdir -p "${PERSISTENT_TMPDIR}" + +# shellcheck disable=SC2034 +TMPDIR="$(mktemp -d -p "${PERSISTENT_TMPDIR:-/tmp}" -t bash-framework-$$-XXXXXX)" +export TMPDIR + +# temp dir cleaning +# shellcheck disable=SC2317 +cleanOnExit() { + if [[ "${KEEP_TEMP_FILES:-0}" = "1" ]]; then + Log::displayInfo "KEEP_TEMP_FILES=1 temp files kept here '${TMPDIR}'" + elif [[ -n "${TMPDIR+xxx}" ]]; then + Log::displayDebug "KEEP_TEMP_FILES=0 removing temp files '${TMPDIR}'" + rm -Rf "${TMPDIR:-/tmp/fake}" >/dev/null 2>&1 + fi +} +trap cleanOnExit EXIT HUP QUIT ABRT TERM + +# @description concat each element of an array with a separator +# but wrapping text when line length is more than provided argument +# The algorithm will try not to cut the array element if it can. +# if an arg can be placed on current line it will be, +# otherwise current line is printed and arg is added to the new +# current line +# empty arg is interpreted as a new line. +# +# @arg $1 glue:String +# @arg $2 maxLineLength:int +# @arg $3 indentNextLine:int +# @arg $@ array:String[] +Array::wrap2() { + local glue="${1-}" + local -i glueLength="${#glue}" + shift || true + local -i maxLineLength=$1 + shift || true + local -i indentNextLine=$1 + shift || true + local indentStr="" + if ((indentNextLine > 0)); then + indentStr="$(head -c "${indentNextLine}" 0)); do + arg="$1" + shift || true + if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine + fi + echo + continue + fi + local textFirstLine + textFirstLine="$(echo "${arg}" | head -n 1)" + text="$(echo "${arg}" | sed -E '1d')" + ((textLength = ${#text})) || true + local textFirstLineNoAnsi + textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" + local -i textFirstLineNoAnsiLength=0 + ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true + + if ((isNewline == 0)); then + glueLength="${#glue}" + else + glueLength="0" + fi + if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine + fi + # restore current arg without considering first line + text="${arg}" + ((textLength = ${#text})) || true + else + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + currentLine+="${glue}" + ((currentLineLength += glueLength)) || true + fi + currentLine+="${textFirstLine}" + isNewline="0" + ((currentLineLength += ${#textFirstLine})) || true + fi + + for ((i = 0; i < textLength; i++)); do + currentChar="${text:${i}:1}" + + if [[ "${currentChar}" = $'\r' ]]; then + # ignore + true + elif [[ "${currentChar}" = "\x1b" ]]; then + isAnsiCode=1 + ansiCode+="${currentChar}" + elif ((isAnsiCode == 1)); then + ansiCode+="${currentChar}" + if [[ "${currentChar}" =~ [mGKHF] ]]; then + isAnsiCode=0 + echo -e "${ansiCode}" + elif [[ "${currentChar}" = $'\n' ]]; then + # invalid ansi code, ignore it + isAnsiCode=0 + ansiCode="" + fi + else + # non ansi code + if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then + nextLine + elif [[ "${currentChar}" = "\t" ]]; then + if ((currentLineLength + 2 <= maxLineLength)); then + currentLine+=" " + ((isNewline = 0)) || true + ((currentLineLength = currentLineLength + 2)) + else + nextLine + fi + else + currentLine+="${currentChar}" + ((isNewline = 0)) || true + ((++currentLineLength)) + fi + fi + done + done + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine + fi +} + +# @description ensure env files are loaded +# @arg $@ list of default files to load at the end +# @exitcode 1 if one of env files fails to load +# @stderr diagnostics information is displayed +# shellcheck disable=SC2120 +Env::requireLoad() { + local -a defaultFiles=("$@") + # get list of possible config files + local -a configFiles=() + if [[ -n "${BASH_FRAMEWORK_ENV_FILES[0]+1}" ]]; then + # BASH_FRAMEWORK_ENV_FILES is an array + configFiles+=("${BASH_FRAMEWORK_ENV_FILES[@]}") + fi + if [[ -f "$(pwd)/.framework-config" ]]; then + configFiles+=("$(pwd)/.framework-config") + fi + if [[ -f "${FRAMEWORK_ROOT_DIR}/.framework-config" ]]; then + configFiles+=("${FRAMEWORK_ROOT_DIR}/.framework-config") + fi + configFiles+=("${optionEnvFiles[@]}") + configFiles+=("${defaultFiles[@]}") + + for file in "${configFiles[@]}"; do + # shellcheck source=/.framework-config + CURRENT_LOADED_ENV_FILE="${file}" source "${file}" || { + Log::displayError "while loading config file: ${file}" + return 1 + } + done +} + +# @description create a temp file using default TMPDIR variable +# initialized in _includes/_commonHeader.sh +# @env TMPDIR String (default value /tmp) +# @arg $1 templateName:String template name to use(optional) +Framework::createTempFile() { + mktemp -p "${TMPDIR:-/tmp}" -t "${1:-}.XXXXXXXXXXXX" +} + +# @description Log namespace provides 2 kind of functions +# - Log::display* allows to display given message with +# given display level +# - Log::log* allows to log given message with +# given log level +# Log::display* functions automatically log the message too +# @see Env::requireLoad to load the display and log level from .env file + +# @description log level off +export __LEVEL_OFF=0 +# @description log level error +export __LEVEL_ERROR=1 +# @description log level warning +export __LEVEL_WARNING=2 +# @description log level info +export __LEVEL_INFO=3 +# @description log level success +export __LEVEL_SUCCESS=3 +# @description log level debug +export __LEVEL_DEBUG=4 + +# @description verbose level off +export __VERBOSE_LEVEL_OFF=0 +# @description verbose level info +export __VERBOSE_LEVEL_INFO=1 +# @description verbose level info +export __VERBOSE_LEVEL_DEBUG=2 +# @description verbose level info +export __VERBOSE_LEVEL_TRACE=3 + +# @description Display message using debug color (grey) +# @arg $1 message:String the message to display +Log::displayDebug() { + if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_DEBUG)); then + echo -e "${__DEBUG_COLOR}DEBUG - ${1}${__RESET_COLOR}" >&2 + fi + Log::logDebug "$1" +} + +# @description Display message using error color (red) +# @arg $1 message:String the message to display +Log::displayError() { + if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_ERROR)); then + echo -e "${__ERROR_COLOR}ERROR - ${1}${__RESET_COLOR}" >&2 + fi + Log::logError "$1" +} + +# @description Display message using info color (bg light blue/fg white) +# @arg $1 message:String the message to display +Log::displayInfo() { + local type="${2:-INFO}" + if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_INFO)); then + echo -e "${__INFO_COLOR}${type} - ${1}${__RESET_COLOR}" >&2 + fi + Log::logInfo "$1" "${type}" +} + +# @description Display message using warning color (yellow) +# @arg $1 message:String the message to display +Log::displayWarning() { + if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_WARNING)); then + echo -e "${__WARNING_COLOR}WARN - ${1}${__RESET_COLOR}" >&2 + fi + Log::logWarning "$1" +} + +# @description Display message using error color (red) and exit immediately with error status 1 +# @arg $1 message:String the message to display +Log::fatal() { + echo -e "${__ERROR_COLOR}FATAL - ${1}${__RESET_COLOR}" >&2 + Log::logFatal "$1" + exit 1 +} + +# @description activate or not Log::display* and Log::log* functions +# based on BASH_FRAMEWORK_DISPLAY_LEVEL and BASH_FRAMEWORK_LOG_LEVEL +# environment variables loaded by Env::requireLoad +# try to create log file and rotate it if necessary +# @noargs +# @set BASH_FRAMEWORK_LOG_LEVEL int to OFF level if BASH_FRAMEWORK_LOG_FILE is empty or not writable +# @env BASH_FRAMEWORK_DISPLAY_LEVEL int +# @env BASH_FRAMEWORK_LOG_LEVEL int +# @env BASH_FRAMEWORK_LOG_FILE String +# @env BASH_FRAMEWORK_LOG_FILE_MAX_ROTATION int do log rotation if > 0 +# @exitcode 0 always successful +# @stderr diagnostics information about log file is displayed +# @require Env::requireLoad +# @require UI::requireTheme +Log::requireLoad() { + if [[ -z "${BASH_FRAMEWORK_LOG_FILE:-}" ]]; then + BASH_FRAMEWORK_LOG_LEVEL=${__LEVEL_OFF} + export BASH_FRAMEWORK_LOG_LEVEL + fi + + if ((BASH_FRAMEWORK_LOG_LEVEL > __LEVEL_OFF)); then + if [[ ! -f "${BASH_FRAMEWORK_LOG_FILE}" ]]; then + if + ! mkdir -p "$(dirname "${BASH_FRAMEWORK_LOG_FILE}")" 2>/dev/null || + ! touch --no-create "${BASH_FRAMEWORK_LOG_FILE}" 2>/dev/null + then + BASH_FRAMEWORK_LOG_LEVEL=${__LEVEL_OFF} + echo -e "${__ERROR_COLOR}ERROR - File ${BASH_FRAMEWORK_LOG_FILE} is not writable${__RESET_COLOR}" >&2 + fi + elif [[ ! -w "${BASH_FRAMEWORK_LOG_FILE}" ]]; then + BASH_FRAMEWORK_LOG_LEVEL=${__LEVEL_OFF} + echo -e "${__ERROR_COLOR}ERROR - File ${BASH_FRAMEWORK_LOG_FILE} is not writable${__RESET_COLOR}" >&2 + fi + + fi + + if ((BASH_FRAMEWORK_LOG_LEVEL > __LEVEL_OFF)); then + # will always be created even if not in info level + Log::logMessage "INFO" "Logging to file ${BASH_FRAMEWORK_LOG_FILE} - Log level ${BASH_FRAMEWORK_LOG_LEVEL}" + if ((BASH_FRAMEWORK_LOG_FILE_MAX_ROTATION > 0)); then + Log::rotate "${BASH_FRAMEWORK_LOG_FILE}" "${BASH_FRAMEWORK_LOG_FILE_MAX_ROTATION}" + fi + fi +} + +# @description validate arguments before calling Postman::Commands::pullCollections +# @arg $1 modelFile:String model file containing the collections to be pulled +# @arg $@ list of collection references to pull (all if not provided) +# @stderr diagnostic logs +# @exitcode * if one of sub commands fails +Postman::Commands::pullCommand() { + local modelFile="$1" + shift || true + + Postman::Model::validate "${modelFile}" "pull" || return 1 + + local -a refs + # shellcheck disable=SC2154 + Postman::Model::getCollectionRefs "${modelFile}" refs || return 1 + if (($# > 0)); then + # shellcheck disable=SC2154 + Postman::Model::checkIfValidCollectionRefs "${modelFile}" refs "$@" || return 1 + refs=("$@") + fi + + if ((${#refs} == 0)); then + Log::displayError "No collection refs to pull" + return 1 + else + Log::displayDebug "Collection refs to pull ${refs[*]}" + Postman::Commands::pullCollections "${modelFile}" "${refs[@]}" || return 1 + fi +} + +# @description validate arguments before calling Postman::Commands::pushCollections +# @arg $1 modelFile:String model file containing the collections to be pushed +# @arg $@ list of collection references to push (all if not provided) +# @stderr diagnostic logs +# @exitcode * if one of sub commands fails +Postman::Commands::pushCommand() { + local modelFile="$1" + shift || true + + Postman::Model::validate "${modelFile}" "push" || return 1 + + local -a refs + # shellcheck disable=SC2154 + Postman::Model::getCollectionRefs "${modelFile}" refs || return 1 + if (($# > 0)); then + # shellcheck disable=SC2154 + Postman::Model::checkIfValidCollectionRefs "${modelFile}" refs "$@" || return 1 + refs=("$@") + fi + + if ((${#refs} == 0)); then + Log::displayError "No collection refs to push" + return 1 + else + Log::displayDebug "Collection refs to push ${refs[*]}" + Postman::Commands::pushCollections "${modelFile}" "${refs[@]}" || return 1 + fi +} + +# @description validates the model file and checks for file existence +# @arg $1 optionModelFile:String the model file to validate +# @arg $2 mode:Enum(pull|push|config) eg: pull/config don't check for file existence +# @exitcode 1 if file optionModelFile does not exists or invalid +# @stderr diagnostics information is displayed +Postman::Model::validate() { + local modelFile="$1" + local mode="$2" + + if ! Array::contains "${mode}" pull push config; then + Log::displayError "invalid mode ${mode}" + return 1 + fi + + # shellcheck disable=SC2154 + if [[ ! -f "${modelFile}" ]]; then + Log::displayError "File ${modelFile} does not exist" + return 1 + fi + + if ! jq -cre . &>/dev/null <"${modelFile}"; then + Log::displayError "File '${modelFile}' is not a valid json file" + return 1 + fi + local -i errorCount=0 + + # check name key presence + local name + name="$(jq -cre .name 2>/dev/null <"${modelFile}")" || { + Log::displayError "File '${modelFile}' - missing name property" + ((++errorCount)) + } + if [[ -z "${name}" ]]; then + Log::displayError "File '${modelFile}' name property cannot be empty" + ((++errorCount)) + fi + + # check collections key presence + local expr='.collections | if type=="object" then "yes" else "no" end' + if [[ "$(jq -cre "${expr}" <"${modelFile}")" = "no" ]]; then + Log::displayError "File '${modelFile}' - collections property is missing or is not an object" + ((++errorCount)) + else + local collectionJson + local -i index=0 + # shellcheck disable=SC2030 + jq -cre '.collections | to_entries | map(.value + {key: .key}) | .[]' "${modelFile}" | while IFS=$'\n' read -r collectionJson; do + local collectionFile collectionKey + local status=0 + collectionFile="$(jq -cre .file 2>/dev/null <<<"${collectionJson}")" || status=1 + if [[ "${status}" = 0 ]]; then + collectionKey="$(jq -cre .key 2>/dev/null <<<"${collectionJson}")" || status=1 + else + collectionKey="${index}" + fi + if [[ "${status}" = 1 ]]; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - missing file property" + ((++errorCount)) + else + local configDirectory + configDirectory="$(Postman::Model::getRelativeConfigDirectory "${modelFile}")" + collectionFile="${configDirectory}/${collectionFile}" + case "${mode}" in + push) + if [[ ! -f "${collectionFile}" ]]; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - collection file ${collectionFile} does not exists" + ((++errorCount)) + continue + fi + if [[ ! -r "${collectionFile}" ]]; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - collection file ${collectionFile} is not readable" + ((++errorCount)) + continue + fi + if ! jq -cre . &>/dev/null <"${collectionFile}"; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - collection file ${collectionFile} is not a valid json file" + ((++errorCount)) + continue + fi + if ! jq -cre .info.name &>/dev/null <"${collectionFile}"; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - collection file ${collectionFile} does not seem to be a valid collection file" + ((++errorCount)) + continue + fi + ;; + + pull) + if [[ -f "${collectionFile}" && ! -w "${collectionFile}" ]]; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - collection file ${collectionFile} is not writable" + ((++errorCount)) + continue + fi + if [[ ! -f "${collectionFile}" && ! -w "${configDirectory}" ]]; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - config directory ${configDirectory} is not writable" + ((++errorCount)) + continue + fi + ;; + *) ;; + # ignore + esac + fi + # TODO environment + ((++index)) + done + fi + + # shellcheck disable=SC2031 + ((errorCount == 0)) +} + +# @description draw a line with the character passed in parameter repeated depending on terminal width +# @arg $1 character:String character to use as separator (default value #) +UI::drawLine() { + local character="${1:-#}" + printf '%*s\n' "${COLUMNS:-$([[ -t 0 ]] && tput cols || echo)}" '' | tr ' ' "${character}" +} + +# @description load colors theme constants +# @warning if tty not opened, noColor theme will be chosen +# @arg $1 theme:String the theme to use (default, noColor) +# @arg $@ args:String[] +# @set __ERROR_COLOR String indicate error status +# @set __INFO_COLOR String indicate info status +# @set __SUCCESS_COLOR String indicate success status +# @set __WARNING_COLOR String indicate warning status +# @set __SKIPPED_COLOR String indicate skipped status +# @set __DEBUG_COLOR String indicate debug status +# @set __HELP_COLOR String indicate help status +# @set __TEST_COLOR String not used +# @set __TEST_ERROR_COLOR String not used +# @set __HELP_TITLE_COLOR String used to display help title in help strings +# @set __HELP_OPTION_COLOR String used to display highlight options in help strings +# +# @set __RESET_COLOR String reset default color +# +# @set __HELP_EXAMPLE String to remove +# @set __HELP_TITLE String to remove +# @set __HELP_NORMAL String to remove +# shellcheck disable=SC2034 +UI::theme() { + local theme="${1-default}" + if [[ ! "${theme}" =~ -force$ ]] && ! Assert::tty; then + theme="noColor" + fi + case "${theme}" in + default | default-force) + theme="default" + ;; + noColor) ;; + *) + Log::fatal "invalid theme provided" + ;; + esac + if [[ "${theme}" = "default" ]]; then + BASH_FRAMEWORK_THEME="default" + # check colors applicable https://misc.flogisoft.com/bash/tip_colors_and_formatting + __ERROR_COLOR='\e[31m' # Red + __INFO_COLOR='\e[44m' # white on lightBlue + __SUCCESS_COLOR='\e[32m' # Green + __WARNING_COLOR='\e[33m' # Yellow + __SKIPPED_COLOR='\e[33m' # Yellow + __DEBUG_COLOR='\e[37m' # Grey + __HELP_COLOR='\e[7;49;33m' # Black on Gold + __TEST_COLOR='\e[100m' # Light magenta + __TEST_ERROR_COLOR='\e[41m' # white on red + __HELP_TITLE_COLOR="\e[1;37m" # Bold + __HELP_OPTION_COLOR="\e[1;34m" # Blue + # Internal: reset color + __RESET_COLOR='\e[0m' # Reset Color + # shellcheck disable=SC2155,SC2034 + __HELP_EXAMPLE="$(echo -e "\e[2;97m")" + # shellcheck disable=SC2155,SC2034 + __HELP_TITLE="$(echo -e "\e[1;37m")" + # shellcheck disable=SC2155,SC2034 + __HELP_NORMAL="$(echo -e "\033[0m")" + else + BASH_FRAMEWORK_THEME="noColor" + # check colors applicable https://misc.flogisoft.com/bash/tip_colors_and_formatting + __ERROR_COLOR='' + __INFO_COLOR='' + __SUCCESS_COLOR='' + __WARNING_COLOR='' + __SKIPPED_COLOR='' + __DEBUG_COLOR='' + __HELP_COLOR='' + __TEST_COLOR='' + __TEST_ERROR_COLOR='' + __HELP_TITLE_COLOR='' + __HELP_OPTION_COLOR='' + # Internal: reset color + __RESET_COLOR='' + __HELP_EXAMPLE='' + __HELP_TITLE='' + __HELP_NORMAL='' + fi +} + +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + +# @description ensure COMMAND_BIN_DIR env var is set +# and PATH correctly prepared +# @noargs +# @set COMMAND_BIN_DIR string the directory where to find this command +# @set PATH string add directory where to find this command binary +Compiler::Facade::requireCommandBinDir() { + COMMAND_BIN_DIR="${CURRENT_DIR}" + Env::pathPrepend "${COMMAND_BIN_DIR}" +} + +# @description check if an element is contained in an array +# +# @arg $1 needle:String +# @arg $@ array:String[] +# @exitcode 0 if found +# @exitcode 1 otherwise +# @example +# Array::contains "${libPath}" "${__BASH_FRAMEWORK_IMPORTED_FILES[@]}" +Array::contains() { + local element + for element in "${@:2}"; do + [[ "${element}" = "$1" ]] && return 0 + done + return 1 +} + +# @description check if tty (interactive mode) is active +# @noargs +# @exitcode 1 if tty not active +# @env NON_INTERACTIVE if 1 consider as not interactive even if environment is interactive +# @env INTERACTIVE if 1 consider as interactive even if environment is not interactive +# @stderr diagnostic information + help if second argument is provided +Assert::tty() { + if [[ "${NON_INTERACTIVE:-0}" = "1" ]]; then + return 1 + fi + if [[ "${INTERACTIVE:-0}" = "1" ]]; then + return 0 + fi + [[ -t 1 || -t 2 ]] +} + +# @description prepend directories to the PATH environment variable +# @arg $@ args:String[] list of directories to prepend +# @set PATH update PATH with the directories prepended +Env::pathPrepend() { + local arg + for arg in "$@"; do + if [[ -d "${arg}" && ":${PATH}:" != *":${arg}:"* ]]; then + PATH="$(realpath "${arg}"):${PATH}" + fi + done +} + +# @description remove ansi codes from input or files given as argument +# @arg $@ files:String[] the files to filter +# @exitcode * if one of the filter command fails +# @stdin you can use stdin as alternative to files argument +# @stdout the filtered content +# @see https://en.wikipedia.org/wiki/ANSI_escape_code +# shellcheck disable=SC2120 +Filters::removeAnsiCodes() { + # cspell:disable + sed -E 's/\x1b\[[0-9;]*[mGKHF]//g' "$@" + # cspell:enable +} + +# @description log message to file +# @arg $1 message:String the message to display +Log::logDebug() { + if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_DEBUG)); then + Log::logMessage "${2:-DEBUG}" "$1" + fi +} + +# @description log message to file +# @arg $1 message:String the message to display +Log::logError() { + if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_ERROR)); then + Log::logMessage "${2:-ERROR}" "$1" + fi +} + +# @description log message to file +# @arg $1 message:String the message to display +Log::logFatal() { + Log::logMessage "${2:-FATAL}" "$1" +} + +# @description log message to file +# @arg $1 message:String the message to display +Log::logInfo() { + if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_INFO)); then + Log::logMessage "${2:-INFO}" "$1" + fi +} + +# @description Internal: common log message +# @example text +# [date]|[levelMsg]|message +# +# @example text +# 2020-01-19 19:20:21|ERROR |log error +# 2020-01-19 19:20:21|SKIPPED|log skipped +# +# @arg $1 levelMsg:String message's level description (eg: STATUS, ERROR, ...) +# @arg $2 msg:String the message to display +# @env BASH_FRAMEWORK_LOG_FILE String log file to use, do nothing if empty +# @env BASH_FRAMEWORK_LOG_LEVEL int log level log only if > OFF or fatal messages +# @stderr diagnostics information is displayed +# @require Env::requireLoad +# @require Log::requireLoad +Log::logMessage() { + local levelMsg="$1" + local msg="$2" + local date + + if [[ -n "${BASH_FRAMEWORK_LOG_FILE}" ]] && ((BASH_FRAMEWORK_LOG_LEVEL > __LEVEL_OFF)); then + date="$(date '+%Y-%m-%d %H:%M:%S')" + touch "${BASH_FRAMEWORK_LOG_FILE}" + printf "%s|%7s|%s\n" "${date}" "${levelMsg}" "${msg}" >>"${BASH_FRAMEWORK_LOG_FILE}" + fi +} + +# @description log message to file +# @arg $1 message:String the message to display +Log::logWarning() { + if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_WARNING)); then + Log::logMessage "${2:-WARNING}" "$1" + fi +} + +# @description To be called before logging in the log file +# @arg $1 file:string log file name +# @arg $2 maxLogFilesCount:int maximum number of log files +Log::rotate() { + local file="$1" + local maxLogFilesCount="${2:-5}" + + if [[ ! -f "${file}" ]]; then + Log::displaySkipped "Log file ${file} doesn't exist yet" + return 0 + fi + for i in $(seq $((maxLogFilesCount - 1)) -1 1); do + Log::displayInfo "Log rotation ${file}.${i} to ${file}.$((i + 1))" + mv "${file}."{"${i}","$((i + 1))"} &>/dev/null || true + done + if cp "${file}" "${file}.1" &>/dev/null; then + echo >"${file}" # reset log file + Log::displayInfo "Log rotation ${file} to ${file}.1" + fi +} + +# @description pull collections specified by modelFile +# @arg $1 modelFile:String model file containing the collections to be pulled +# @arg $@ list of collection references to pull (all if not provided) +# @stderr diagnostic logs +# @exitcode 2 if no refs specified +# @exitcode * if one of sub commands fails +Postman::Commands::pullCollections() { + local modelFile="$1" + shift || true + + # shellcheck disable=SC2317 + pullCollectionsCallback() { + local modelFile="$1" + # local postmanCollectionsFile="$2" + local collectionRef="$3" + local collectionFile="$4" + local collectionName="$5" + local postmanCollectionId="$6" + local postmanCollectionIdStatus="$7" + case "${postmanCollectionIdStatus}" in + 0) ;; # success, next statement will pull the collection + 2) return 2 ;; # name not found + 3) return 2 ;; # more than one collection + *) return 1 ;; # error parsing collection file from postman, stop + esac + if [[ -z "${postmanCollectionId}" ]]; then + Log::displayWarning "Collection '${collectionRef}' - pull skipped as not existing in your postman workspace" + else + local response + local statusCode="0" + Log::displayInfo "Pulling collection ${collectionRef} with id ${postmanCollectionId} from postman" + response="$(Postman::api pullCollection "${postmanCollectionId}" | jq -cre '.collection')" || statusCode=$? + if [[ "${statusCode}" = "0" ]]; then + echo "${response}" >"${collectionFile}" + Log::displaySuccess "Collection '${collectionName}' has been pulled successfully to '${collectionFile}'" + else + Log::displayError "Collection '${collectionName}' an error occured pulling the collection from postman" + fi + fi + } + Postman::Commands::forEachCollection "${modelFile}" pullCollectionsCallback "$@" +} + +# @description push collections specified by modelFile +# @arg $1 modelFile:String model file containing the collections to be pushed +# @arg $@ list of collection references to push (all if not provided) +# @stderr diagnostic logs +# @exitcode 2 if no refs specified +# @exitcode * if one of sub commands fails +Postman::Commands::pushCollections() { + local modelFile="$1" + shift || true + + # shellcheck disable=SC2317 + pushCollectionsCallback() { + local modelFile="$1" + # local postmanCollectionsFile="$2" + local collectionRef="$3" + local collectionFile="$4" + #local collectionName="$5" + local postmanCollectionId="$6" + local postmanCollectionIdStatus="$7" + case "${postmanCollectionIdStatus}" in + 0) ;; # success, next statement will update the collection + 2) ;; # name not found, next statement will create the collection + 3) return 2 ;; # more than one collection + *) return 1 ;; # error parsing collection file from postman, stop + esac + + if [[ -z "${postmanCollectionId}" ]]; then + Log::displayInfo "Creating collection '${collectionRef}'" + Postman::api createCollectionFromFile "${collectionFile}" + Log::displaySuccess "collection '${collectionRef}' has been created successfully" + else + Log::displayInfo "Updating collection '${collectionRef}' with id '${postmanCollectionId}'" + Postman::api updateCollectionFromFile "${collectionFile}" "${postmanCollectionId}" + Log::displaySuccess "collection '${collectionRef}' has been updated successfully" + fi + } + + Postman::Commands::forEachCollection "${modelFile}" pushCollectionsCallback "$@" +} + +# @description check that each collection references passed as parameter +# exists in the model file +# @arg $1 modelFile:String model file in which availableRefs have been retrieved +# @arg $2 availableRefs:&String[] list of known collection references +# @arg $3 modelCollectionRefs:&String[] list ofcollection references to check +Postman::Model::checkIfValidCollectionRefs() { + local modelFile="$1" + local -n availableRefs=$2 + shift 2 || true + local -a modelCollectionRefs=("$@") + + # shellcheck disable=SC2154 + Log::displayDebug "Checking collection refs using config ${modelFile}" + + local ref + for ref in "${modelCollectionRefs[@]}"; do + if ! Array::contains "${ref}" "${availableRefs[@]}"; then + Log::displayError "Collection ref '${ref}' is not known in '${modelFile}'" + return 1 + fi + done +} + +# @description get the list of collection references id from given config file +# @arg $1 configFile:String the config file to parse +# @arg $2 getCollectionRefs:&String[] (passed by reference) list of collection +# references +# @exitcode 1 - if jq parsing error, file not found or any other error +# @stderr jq error messages on failure +Postman::Model::getCollectionRefs() { + local configFile="$1" + local -n getCollectionRefs=$2 + # shellcheck disable=SC2034 + jq -cre '.collections | try keys[]' <"${configFile}" | readarray -t getCollectionRefs +} + +# @description config directory path relative to current execution directory +# @arg $1 configFile:String the config file +# @stdout the parent directory of config file relative to current execution directory +# @example +# executionPath=/home/wsl/bash-tools +# configPath=/home/wsl/bash-tools/conf/postmanCli/openApis.json +# result=conf/postmanCli +Postman::Model::getRelativeConfigDirectory() { + local configFile="$1" + local configDir + configDir="$(cd -- "$(dirname -- "${configFile}")" &>/dev/null && pwd -P)" + File::relativeToDir "${configDir}" "$(pwd -P)" +} + +# @description load color theme +# @noargs +# @env BASH_FRAMEWORK_THEME String theme to use +# @exitcode 0 always successful +UI::requireTheme() { + UI::theme "${BASH_FRAMEWORK_THEME-default}" +} + +# @description print the resolved path relative to DIR +# do not check for path existence +# @arg $1 srcFile:String the file to resolve +# @arg $2 relativeTo:String the directory +# @stdout the resolved path relative to DIR +File::relativeToDir() { + local srcFile="$1" + local relativeTo="$2" + + realpath -m --relative-to="${relativeTo}" "${srcFile}" +} + +# @description Display message using skip color (yellow) +# @arg $1 message:String the message to display +Log::displaySkipped() { + if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_INFO)); then + echo -e "${__SKIPPED_COLOR}SKIPPED - ${1}${__RESET_COLOR}" >&2 + fi + Log::logSkipped "$1" +} + +# @description Display message using success color (bg green/fg white) +# @arg $1 message:String the message to display +Log::displaySuccess() { + if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_INFO)); then + echo -e "${__SUCCESS_COLOR}SUCCESS - ${1}${__RESET_COLOR}" >&2 + fi + Log::logSuccess "$1" +} + +# @description apply callback on each collection specified by modelFile +# #### callback arguments +# - modelFile +# - postmanCollectionsFile +# - collectionRef +# - collectionFile +# - collectionName +# - postmanCollectionId +# - postmanCollectionIdStatus +# @arg $1 modelFile:String model file containing the collections to be processed +# @arg $2 callback:Function callback to apply on each collection selected +# @arg $@ list of collection references to process (all if not provided) +# @stderr diagnostic logs +# @exitcode 2 if no refs specified +# @exitcode * if one of sub commands fails +Postman::Commands::forEachCollection() { + local modelFile="$1" + local callback="$2" + shift 2 || true + local -a refs=("$@") + + if ((${#refs[@]} == 0)); then + return 2 + fi + + Postman::checkApiKey "${HOME}/.bash-tools/.env" || return 1 + local postmanCollectionsFile + postmanCollectionsFile="$(Framework::createTempFile "postmanCollections")" + # shellcheck disable=SC2154 + Log::displayDebug "Retrieving collections from postman in ${postmanCollectionsFile}" + Postman::api getCollections >"${postmanCollectionsFile}" || return 1 + + local collectionRef + for collectionRef in "${refs[@]}"; do + local collectionFile collectionName postmanCollectionId + Log::displayDebug "Retrieving collection file from collection reference ${collectionRef}" + collectionFile="$(Postman::Model::getCollectionFileByRef "${modelFile}" "${collectionRef}")" + Log::displayDebug "Retrieving collection name from collection file ${collectionFile}" + collectionName="$(Postman::Collection::getName "${collectionFile}")" + Log::displayDebug "Deducing postman collection id using ${postmanCollectionsFile} and collection name '${collectionName}'" + local postmanCollectionIdStatus="0" + postmanCollectionId="$(Postman::Collection::getCollectionIdByName "${postmanCollectionsFile}" "${collectionName}")" || status=$? + local status=0 + "${callback}" \ + "${modelFile}" "${postmanCollectionsFile}" \ + "${collectionRef}" "${collectionFile}" "${collectionName}" \ + "${postmanCollectionId}" "${postmanCollectionIdStatus}" || status=$? + case "${status}" in + 2 | 0) continue ;; + *) return 1 ;; + esac + done +} + +# @description call postman REST api +# @arg $1 action:String action to call +# @arg $@ args:String[] rest of arguments +# @exitcode 1 if invalid action +# @exitcode * curl error +# @env BASH_FRAMEWORK_ARGS_VERBOSE display curl response if verbose level is different than 0 +Postman::api() { + local action="$1" + shift || true + + getCollections() { + curl \ + -X GET https://api.getpostman.com/collections \ + --fail --silent --show-error \ + -H "X-Api-Key: ${POSTMAN_API_KEY}" + } + + getCollectionDataFromFile() { + local collectionFile="$1" + jq -cre -n \ + --slurpfile collection "${collectionFile}" \ + '{"collection": $collection[0]}' + } + + createCollectionFromFile() { + local collectionFile="$1" + local responseFile + responseFile="$(Framework::createTempFile)" + + local status=0 + getCollectionDataFromFile "${collectionFile}" | + curl \ + --request POST https://api.getpostman.com/collections \ + -o "${responseFile}" \ + --header 'Content-Type: application/json' \ + --header 'Accept: application/json' \ + --header "X-Api-Key: ${POSTMAN_API_KEY}" \ + --data @- \ + --fail --silent --show-error || status=$? + + Postman::displayResponse "createCollectionFromFile" "${responseFile}" + + return "${status}" + } + + updateCollectionFromFile() { + local collectionFile="$1" + local collectionId="$2" + local responseFile + responseFile="$(Framework::createTempFile)" + + local status=0 + getCollectionDataFromFile "${collectionFile}" | + curl \ + --request PUT "https://api.getpostman.com/collections/${collectionId}" \ + -o "${responseFile}" \ + --header 'Content-Type: application/json' \ + --header 'Accept: application/json' \ + --header "X-Api-Key: ${POSTMAN_API_KEY}" \ + --data @- \ + --fail --silent --show-error || status=$? + + Postman::displayResponse "updateCollectionFromFile" "${responseFile}" + + return "${status}" + } + + pullCollection() { + local collectionId="$1" + curl \ + -X GET "https://api.getpostman.com/collections/${collectionId}" \ + --fail --silent --show-error \ + -H "X-Api-Key: ${POSTMAN_API_KEY}" + } + + case "${action}" in + getCollections) + getCollections "$@" + ;; + createCollectionFromFile) + createCollectionFromFile "$@" + ;; + updateCollectionFromFile) + updateCollectionFromFile "$@" + ;; + pullCollection) + pullCollection "$@" + ;; + *) + Log::displayError "Unknown api action '${action}'" + return 1 + ;; + esac +} + +# @description log message to file +# @arg $1 message:String the message to display +Log::logSkipped() { + if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_INFO)); then + Log::logMessage "${2:-SKIPPED}" "$1" + fi +} + +# @description log message to file +# @arg $1 message:String the message to display +Log::logSuccess() { + if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_INFO)); then + Log::logMessage "${2:-SUCCESS}" "$1" + fi +} + +# @description retrieve the collection id +# associated to the given collection name +# from the postman collection file +# @arg $1 collectionFile:String +# @arg $2 collectionName:String +# @exitcode 1 if error while parsing the collection file +# @exitcode 2 if name not found +# @exitcode 3 if more than one collection matches that name +# @stderr details, on failure +# @stdout the collection id associated to a unique collection name +Postman::Collection::getCollectionIdByName() { + local collectionFile="$1" + local collectionName="$2" + local result + local errorCode="0" + result="$( + jq -cre --arg name "${collectionName}" \ + '.collections[] | select( .name == $name) | .id' 2>&1 <"${collectionFile}" + )" || errorCode="$?" + if [[ "${errorCode}" = "4" ]]; then + Log::displayWarning "collection name '${collectionName}' not found in '${collectionFile}'" + return 2 + elif [[ "${errorCode}" != "0" ]]; then + Log::displayError "Error while parsing '${collectionFile}' - error code ${errorCode} - ${result}" + return 1 + fi + if (($(wc -l <<<"${result}") > 1)); then + Log::displayError "More than one collection match the collection name '${collectionName}', please clean up your postman workspace" + return 3 + fi + echo "${result}" +} + +# @description retrieve the name of the collection file +# from the postman collection file +# @arg $1 collectionFile:String +# @exitcode 1 if error while parsing the collection file +# @exitcode * jq exit code, 4 for invalid file +# @stdout the collection name of the collection file +Postman::Collection::getName() { + local collectionFile="$1" + jq -cre '.info.name' <"${collectionFile}" +} + +# @description retrieve the file associated to the collection ref +# @arg $1 configFile:String the config file to parse +# @arg $2 ref:String the collection reference to get +# @stdout the file relative to current execution directory +# @exitcode 1 - if jq parsing error, file not found or any other error +Postman::Model::getCollectionFileByRef() { + local configFile="$1" + local ref="$2" + local file + file="$(jq -cre ".collections.${ref}.file" <"${configFile}")" || return 1 + echo "$(Postman::Model::getRelativeConfigDirectory "${configFile}")/${file}" +} + +# @description check if postman api key is set in .env file +# @arg $1 envFile:String .env file that should contain POSTMAN_API_KEY variable +# @stderr display warning message if postman api key is not filled +# @exitcode 0 always successful +Postman::checkApiKey() { + local envFile="$1" + + if grep -q '^POSTMAN_API_KEY=$' "${envFile}" 2>/dev/null || + ! grep -q '^POSTMAN_API_KEY=' "${envFile}" 2>/dev/null; then + Log::displayWarning "Please update POSTMAN_API_KEY in '${envFile}'" + fi +} + +# @description display curl response only if verbose mode is not off +# @arg $1 type:String type of response displayed +# @arg $2 responseFile:String file containing curl response +# @env BASH_FRAMEWORK_ARGS_VERBOSE +# @exitcode 1 if responseFile not found +Postman::displayResponse() { + local type="$1" + local responseFile="$2" + if ((BASH_FRAMEWORK_ARGS_VERBOSE > __VERBOSE_LEVEL_OFF)); then + (UI::drawLine >&2 "-") + (echo >&2 -e "${__DEBUG_COLOR}${type}${__RESET_COLOR}") + (cat >&2 "${responseFile}") + (echo >&2) + fi +} + +# FUNCTIONS + +facade_main_postmanClish() { +BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/.." && pwd -P)" +if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then + FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" +else + # if the directory does not exist yet, give a value to FRAMEWORK_ROOT_DIR + FRAMEWORK_ROOT_DIR="${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" +fi +FRAMEWORK_SRC_DIR="${FRAMEWORK_ROOT_DIR}/src" +FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" +FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" +FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" + +# @require BashTools::Conf::requireLoad +if [[ -f "${HOME}/.bash-tools/.env" ]]; then + export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") +fi +# REQUIRES +Env::requireLoad +UI::requireTheme +Log::requireLoad +BashTools::Conf::requireLoad +Compiler::Facade::requireCommandBinDir + +# @require Compiler::Facade::requireCommandBinDir + +declare -a BASH_FRAMEWORK_ARGV_FILTERED=() + +copyrightCallback() { + if [[ -z "${copyrightBeginYear}" ]]; then + copyrightBeginYear="$(date +%Y)" + fi + echo "Copyright (c) ${copyrightBeginYear}-now François Chastanet" +} + +# shellcheck disable=SC2317 # if function is overridden +updateArgListInfoVerboseCallback() { + BASH_FRAMEWORK_ARGV_FILTERED+=(--verbose) +} +# shellcheck disable=SC2317 # if function is overridden +updateArgListDebugVerboseCallback() { + BASH_FRAMEWORK_ARGV_FILTERED+=(-vv) +} +# shellcheck disable=SC2317 # if function is overridden +updateArgListTraceVerboseCallback() { + BASH_FRAMEWORK_ARGV_FILTERED+=(-vvv) +} +# shellcheck disable=SC2317 # if function is overridden +updateArgListEnvFileCallback() { :; } +# shellcheck disable=SC2317 # if function is overridden +updateArgListLogLevelCallback() { :; } +# shellcheck disable=SC2317 # if function is overridden +updateArgListDisplayLevelCallback() { :; } +# shellcheck disable=SC2317 # if function is overridden +updateArgListNoColorCallback() { + BASH_FRAMEWORK_ARGV_FILTERED+=(--no-color) +} +# shellcheck disable=SC2317 # if function is overridden +updateArgListThemeCallback() { :; } +# shellcheck disable=SC2317 # if function is overridden +updateArgListQuietCallback() { :; } + +# shellcheck disable=SC2317 # if function is overridden +optionHelpCallback() { + postmanCliCommand help + exit 0 +} + +# shellcheck disable=SC2317 # if function is overridden +optionVersionCallback() { + echo "${SCRIPT_NAME} version 1.0" + exit 0 +} + +# shellcheck disable=SC2317 # if function is overridden +optionEnvFileCallback() { + local envFile="$2" + Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" + if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then + Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" + exit 1 + fi +} + +# shellcheck disable=SC2317 # if function is overridden +optionInfoVerboseCallback() { + BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' + BASH_FRAMEWORK_ARGS_VERBOSE=${__VERBOSE_LEVEL_INFO} + echo "BASH_FRAMEWORK_DISPLAY_LEVEL=${__LEVEL_INFO}" >> "${overrideEnvFile}" +} + +# shellcheck disable=SC2317 # if function is overridden +optionDebugVerboseCallback() { + BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='-vv' + BASH_FRAMEWORK_ARGS_VERBOSE=${__VERBOSE_LEVEL_DEBUG} + echo "BASH_FRAMEWORK_DISPLAY_LEVEL=${__LEVEL_DEBUG}" >> "${overrideEnvFile}" +} + +# shellcheck disable=SC2317 # if function is overridden +optionTraceVerboseCallback() { + BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='-vvv' + BASH_FRAMEWORK_ARGS_VERBOSE=${__VERBOSE_LEVEL_TRACE} + echo "BASH_FRAMEWORK_DISPLAY_LEVEL=${__LEVEL_DEBUG}" >> "${overrideEnvFile}" +} + +getLevel() { + local levelName="$1" + case "${levelName^^}" in + OFF) + echo "${__LEVEL_OFF}" + ;; + ERR | ERROR) + echo "${__LEVEL_ERROR}" + ;; + WARN | WARNING) + echo "${__LEVEL_WARNING}" + ;; + INFO) + echo "${__LEVEL_INFO}" + ;; + DEBUG | TRACE) + echo "${__LEVEL_DEBUG}" + ;; + *) + Log::displayError "Command ${SCRIPT_NAME} - Invalid level ${level}" + return 1 + esac +} + +getVerboseLevel() { + local levelName="$1" + case "${levelName^^}" in + OFF) + echo "${__VERBOSE_LEVEL_OFF}" + ;; + ERR | ERROR | WARN | WARNING | INFO) + echo "${__VERBOSE_LEVEL_INFO}" + ;; + DEBUG) + echo "${__VERBOSE_LEVEL_DEBUG}" + ;; + TRACE) + echo "${__VERBOSE_LEVEL_TRACE}" + ;; + *) + Log::displayError "Command ${SCRIPT_NAME} - Invalid level ${level}" + return 1 + esac +} + +# shellcheck disable=SC2317 # if function is overridden +optionDisplayLevelCallback() { + local level="$2" + local logLevel verboseLevel + logLevel="$(getLevel "${level}")" + verboseLevel="$(getVerboseLevel "${level}")" + BASH_FRAMEWORK_ARGS_VERBOSE=${verboseLevel} + echo "BASH_FRAMEWORK_DISPLAY_LEVEL=${logLevel}" >> "${overrideEnvFile}" +} + +# shellcheck disable=SC2317 # if function is overridden +optionLogLevelCallback() { + local level="$2" + local logLevel verboseLevel + logLevel="$(getLevel "${level}")" + verboseLevel="$(getVerboseLevel "${level}")" + BASH_FRAMEWORK_ARGS_VERBOSE=${verboseLevel} + echo "BASH_FRAMEWORK_LOG_LEVEL=${logLevel}" >> "${overrideEnvFile}" +} + +# shellcheck disable=SC2317 # if function is overridden +optionLogFileCallback() { + local logFile="$2" + echo "BASH_FRAMEWORK_LOG_FILE='${logFile}'" >> "${overrideEnvFile}" +} + +# shellcheck disable=SC2317 # if function is overridden +optionQuietCallback() { + echo "BASH_FRAMEWORK_QUIET_MODE=1" >> "${overrideEnvFile}" +} + +# shellcheck disable=SC2317 # if function is overridden +optionNoColorCallback() { + UI::theme "noColor" +} + +# shellcheck disable=SC2317 # if function is overridden +optionThemeCallback() { + UI::theme "$2" +} + +displayConfig() { + echo "Config" + UI::drawLine "-" + local var + while read -r var; do + printf '%-40s = %s\n' "${var}" "$(declare -p "${var}" | sed -E -e 's/^[^=]+=(.*)/\1/')" + done < <(typeset -p | awk 'match($3, "^(BASH_FRAMEWORK_[^=]+)=", m) { print m[1] }' | sort) + exit 0 +} + +optionBashFrameworkConfigCallback() { + if [[ ! -f "$2" ]]; then + Log::fatal "Command ${SCRIPT_NAME} - Bash framework config file '$2' does not exists" + fi +} + +defaultFrameworkConfig="$( + cat <<'EOF' +# copied from src/_includes/.framework-config.default +# shellcheck disable=SC2034 + +REAL_SCRIPT_FILE="${REAL_SCRIPT_FILE:-$(readlink -e "$(realpath "${BASH_SOURCE[0]}")")}" +FRAMEWORK_ROOT_DIR="${FRAMEWORK_ROOT_DIR:-$(cd "$(readlink -e "${REAL_SCRIPT_FILE%/*}")/../.." && pwd -P)}" +FRAMEWORK_SRC_DIR="${FRAMEWORK_SRC_DIR:-${FRAMEWORK_ROOT_DIR}/src}" +FRAMEWORK_BIN_DIR="${FRAMEWORK_BIN_DIR:-${FRAMEWORK_ROOT_DIR}/bin}" +FRAMEWORK_VENDOR_DIR="${FRAMEWORK_VENDOR_DIR:-${FRAMEWORK_ROOT_DIR}/vendor}" +FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_VENDOR_BIN_DIR:-${FRAMEWORK_ROOT_DIR}/vendor/bin}" + +# describe the functions that will be skipped from being imported +FRAMEWORK_FUNCTIONS_IGNORE_REGEXP="${FRAMEWORK_FUNCTIONS_IGNORE_REGEXP:-^(Namespace::functions|Functions::myFunction|Namespace::requireSomething|Acquire::ForceIPv4)$}" +# describe the files that do not contain function to be imported +NON_FRAMEWORK_FILES_REGEXP="${NON_FRAMEWORK_FILES_REGEXP:-(^bin/|.framework-config|.bats$|/testsData/|^manualTests/|/_.sh$|/ZZZ.sh$|/__all.sh$|^src/_binaries|^src/_includes|^src/batsHeaders.sh$|^src/_standalone)}" +# describe the files that are allowed to not have an associated bats file +BATS_FILE_NOT_NEEDED_REGEXP="${BATS_FILE_NOT_NEEDED_REGEXP:-(^bin/|.framework-config|.bats$|/testsData/|^manualTests/|/_.sh$|/ZZZ.sh$|/__all.sh$|^src/batsHeaders.sh$|^src/_includes)}" +# describe the files that are allowed to not have a function matching the filename +FRAMEWORK_FILES_FUNCTION_MATCHING_IGNORE_REGEXP="${FRAMEWORK_FILES_FUNCTION_MATCHING_IGNORE_REGEXP:-^bin/|^\.framework-config$|\.tpl$|/testsData/|^manualTests/|\.bats$}" +# Source directories +if [[ ! -v FRAMEWORK_SRC_DIRS ]]; then + FRAMEWORK_SRC_DIRS=( + "${FRAMEWORK_ROOT_DIR}/src" + ) +fi + +# export here all the variables that will be used in your templates +export REPOSITORY_URL="${REPOSITORY_URL:-https://github.com/fchastanet/bash-tools-framework}" + +BASH_FRAMEWORK_THEME="${BASH_FRAMEWORK_THEME:-default}" +BASH_FRAMEWORK_LOG_LEVEL="${BASH_FRAMEWORK_LOG_LEVEL:-0}" +BASH_FRAMEWORK_DISPLAY_LEVEL="${BASH_FRAMEWORK_DISPLAY_LEVEL:-3}" +BASH_FRAMEWORK_LOG_FILE="${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/$(basename "$0").log}" +BASH_FRAMEWORK_LOG_FILE_MAX_ROTATION="${BASH_FRAMEWORK_LOG_FILE_MAX_ROTATION:-5}" +EOF +)" + +overrideEnvFile="$(Framework::createTempFile "overrideEnvFile")" + +commandOptionParseFinished() { + # load default template framework config + defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" + echo "${defaultFrameworkConfig}" > "${defaultEnvFile}" + local -a files=("${defaultEnvFile}") + if [[ -f "${envFile}" ]]; then + files+=("${envFile}") + fi + # shellcheck disable=SC2154 + if [[ -f "${optionBashFrameworkConfig}" ]]; then + files+=("${optionBashFrameworkConfig}") + fi + files+=("${overrideEnvFile}") + Env::requireLoad "${files[@]}" + Log::requireLoad + # shellcheck disable=SC2154 + if [[ "${optionConfig}" = "1" ]]; then + displayConfig + fi +} + +postmanCliCommand() { + local options_parse_cmd="$1" + shift || true + + if [[ "${options_parse_cmd}" = "parse" ]]; then + local -i options_parse_optionParsedCountOptionPostmanModelConfig + ((options_parse_optionParsedCountOptionPostmanModelConfig = 0)) || true + local -i options_parse_optionParsedCountOptionBashFrameworkConfig + ((options_parse_optionParsedCountOptionBashFrameworkConfig = 0)) || true + optionConfig="0" + local -i options_parse_optionParsedCountOptionConfig + ((options_parse_optionParsedCountOptionConfig = 0)) || true + optionInfoVerbose="0" + local -i options_parse_optionParsedCountOptionInfoVerbose + ((options_parse_optionParsedCountOptionInfoVerbose = 0)) || true + optionDebugVerbose="0" + local -i options_parse_optionParsedCountOptionDebugVerbose + ((options_parse_optionParsedCountOptionDebugVerbose = 0)) || true + optionTraceVerbose="0" + local -i options_parse_optionParsedCountOptionTraceVerbose + ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true + optionNoColor="0" + local -i options_parse_optionParsedCountOptionNoColor + ((options_parse_optionParsedCountOptionNoColor = 0)) || true + optionTheme="default" + local -i options_parse_optionParsedCountOptionTheme + ((options_parse_optionParsedCountOptionTheme = 0)) || true + optionHelp="0" + local -i options_parse_optionParsedCountOptionHelp + ((options_parse_optionParsedCountOptionHelp = 0)) || true + optionVersion="0" + local -i options_parse_optionParsedCountOptionVersion + ((options_parse_optionParsedCountOptionVersion = 0)) || true + optionQuiet="0" + local -i options_parse_optionParsedCountOptionQuiet + ((options_parse_optionParsedCountOptionQuiet = 0)) || true + local -i options_parse_optionParsedCountOptionLogLevel + ((options_parse_optionParsedCountOptionLogLevel = 0)) || true + local -i options_parse_optionParsedCountOptionLogFile + ((options_parse_optionParsedCountOptionLogFile = 0)) || true + local -i options_parse_optionParsedCountOptionDisplayLevel + ((options_parse_optionParsedCountOptionDisplayLevel = 0)) || true + local -i options_parse_argParsedCountArgCommand + ((options_parse_argParsedCountArgCommand = 0)) || true + local -i options_parse_argParsedCountCommandArgs + ((options_parse_argParsedCountCommandArgs = 0)) || true + # shellcheck disable=SC2034 + local -i options_parse_parsedArgIndex=0 + while (($# > 0)); do + local options_parse_arg="$1" + local argOptDefaultBehavior=0 + case "${options_parse_arg}" in + # Option 1/15 + # Option optionPostmanModelConfig --postman-model|-m variableType String min 0 max 1 authorizedValues '' regexp '' + --postman-model | -m) + shift + if (($# == 0)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" + return 1 + fi + if ((options_parse_optionParsedCountOptionPostmanModelConfig >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionPostmanModelConfig)) + # shellcheck disable=SC2034 + optionPostmanModelConfig="$1" + ;; + # Option 2/15 + # Option optionBashFrameworkConfig --bash-framework-config variableType String min 0 max 1 authorizedValues '' regexp '' + --bash-framework-config) + shift + if (($# == 0)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" + return 1 + fi + if ((options_parse_optionParsedCountOptionBashFrameworkConfig >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionBashFrameworkConfig)) + # shellcheck disable=SC2034 + optionBashFrameworkConfig="$1" + optionBashFrameworkConfigCallback "${options_parse_arg}" "${optionBashFrameworkConfig}" + ;; + # Option 3/15 + # Option optionConfig --config variableType Boolean min 0 max 1 authorizedValues '' regexp '' + --config) + # shellcheck disable=SC2034 + optionConfig="1" + if ((options_parse_optionParsedCountOptionConfig >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionConfig)) + ;; + # Option 4/15 + # Option optionInfoVerbose --verbose|-v variableType Boolean min 0 max 1 authorizedValues '' regexp '' + --verbose | -v) + # shellcheck disable=SC2034 + optionInfoVerbose="1" + if ((options_parse_optionParsedCountOptionInfoVerbose >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionInfoVerbose)) + optionInfoVerboseCallback "${options_parse_arg}" + updateArgListInfoVerboseCallback "${options_parse_arg}" + ;; + # Option 5/15 + # Option optionDebugVerbose -vv variableType Boolean min 0 max 1 authorizedValues '' regexp '' + -vv) + # shellcheck disable=SC2034 + optionDebugVerbose="1" + if ((options_parse_optionParsedCountOptionDebugVerbose >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionDebugVerbose)) + optionDebugVerboseCallback "${options_parse_arg}" + updateArgListDebugVerboseCallback "${options_parse_arg}" + ;; + # Option 6/15 + # Option optionTraceVerbose -vvv variableType Boolean min 0 max 1 authorizedValues '' regexp '' + -vvv) + # shellcheck disable=SC2034 + optionTraceVerbose="1" + if ((options_parse_optionParsedCountOptionTraceVerbose >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionTraceVerbose)) + optionTraceVerboseCallback "${options_parse_arg}" + updateArgListTraceVerboseCallback "${options_parse_arg}" + ;; + # Option 7/15 + # Option optionEnvFiles --env-file variableType StringArray min 0 max -1 authorizedValues '' regexp '' + --env-file) + shift + if (($# == 0)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" + return 1 + fi + ((++options_parse_optionParsedCountOptionEnvFiles)) + optionEnvFiles+=("$1") + optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" + updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" + ;; + # Option 8/15 + # Option optionNoColor --no-color variableType Boolean min 0 max 1 authorizedValues '' regexp '' + --no-color) + # shellcheck disable=SC2034 + optionNoColor="1" + if ((options_parse_optionParsedCountOptionNoColor >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionNoColor)) + optionNoColorCallback "${options_parse_arg}" + updateArgListNoColorCallback "${options_parse_arg}" + ;; + # Option 9/15 + # Option optionTheme --theme variableType String min 0 max 1 authorizedValues 'default|default-force|noColor' regexp '' + --theme) + shift + if (($# == 0)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" + return 1 + fi + if [[ ! "$1" =~ default|default-force|noColor ]]; then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - value '$1' is not part of authorized values(default|default-force|noColor)" + return 1 + fi + if ((options_parse_optionParsedCountOptionTheme >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionTheme)) + # shellcheck disable=SC2034 + optionTheme="$1" + optionThemeCallback "${options_parse_arg}" "${optionTheme}" + updateArgListThemeCallback "${options_parse_arg}" "${optionTheme}" + ;; + # Option 10/15 + # Option optionHelp --help|-h variableType Boolean min 0 max 1 authorizedValues '' regexp '' + --help | -h) + # shellcheck disable=SC2034 + optionHelp="1" + if ((options_parse_optionParsedCountOptionHelp >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionHelp)) + optionHelpCallback "${options_parse_arg}" + ;; + # Option 11/15 + # Option optionVersion --version variableType Boolean min 0 max 1 authorizedValues '' regexp '' + --version) + # shellcheck disable=SC2034 + optionVersion="1" + if ((options_parse_optionParsedCountOptionVersion >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionVersion)) + optionVersionCallback "${options_parse_arg}" + ;; + # Option 12/15 + # Option optionQuiet --quiet|-q variableType Boolean min 0 max 1 authorizedValues '' regexp '' + --quiet | -q) + # shellcheck disable=SC2034 + optionQuiet="1" + if ((options_parse_optionParsedCountOptionQuiet >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionQuiet)) + optionQuietCallback "${options_parse_arg}" + updateArgListQuietCallback "${options_parse_arg}" + ;; + # Option 13/15 + # Option optionLogLevel --log-level variableType String min 0 max 1 authorizedValues 'OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE' regexp '' + --log-level) + shift + if (($# == 0)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" + return 1 + fi + if [[ ! "$1" =~ OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE ]]; then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - value '$1' is not part of authorized values(OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE)" + return 1 + fi + if ((options_parse_optionParsedCountOptionLogLevel >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionLogLevel)) + # shellcheck disable=SC2034 + optionLogLevel="$1" + optionLogLevelCallback "${options_parse_arg}" "${optionLogLevel}" + updateArgListLogLevelCallback "${options_parse_arg}" "${optionLogLevel}" + ;; + # Option 14/15 + # Option optionLogFile --log-file variableType String min 0 max 1 authorizedValues '' regexp '' + --log-file) + shift + if (($# == 0)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" + return 1 + fi + if ((options_parse_optionParsedCountOptionLogFile >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionLogFile)) + # shellcheck disable=SC2034 + optionLogFile="$1" + optionLogFileCallback "${options_parse_arg}" "${optionLogFile}" + updateArgListLogFileCallback "${options_parse_arg}" "${optionLogFile}" + ;; + # Option 15/15 + # Option optionDisplayLevel --display-level variableType String min 0 max 1 authorizedValues 'OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE' regexp '' + --display-level) + shift + if (($# == 0)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" + return 1 + fi + if [[ ! "$1" =~ OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE ]]; then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - value '$1' is not part of authorized values(OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE)" + return 1 + fi + if ((options_parse_optionParsedCountOptionDisplayLevel >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionDisplayLevel)) + # shellcheck disable=SC2034 + optionDisplayLevel="$1" + optionDisplayLevelCallback "${options_parse_arg}" "${optionDisplayLevel}" + updateArgListDisplayLevelCallback "${options_parse_arg}" "${optionDisplayLevel}" + ;; + -*) + unknownOption "${options_parse_arg}" + ;; + *) + if ((0)); then + # Technical if - never reached + : + # Argument 1/2 + # Argument argCommand min 0 max 1 authorizedValues 'pull|push' regexp '' + elif ((options_parse_parsedArgIndex >= 0 && options_parse_parsedArgIndex < 1)); then + if [[ ! "${options_parse_arg}" =~ pull|push ]]; then + Log::displayError "Command ${SCRIPT_NAME} - Argument command - value '${options_parse_arg}' is not part of authorized values(pull|push)" + return 1 + fi + if ((options_parse_argParsedCountArgCommand >= 1)); then + Log::displayError "Command ${SCRIPT_NAME} - Argument command - Maximum number of argument occurrences reached(1)" + return 1 + fi + ((++options_parse_argParsedCountArgCommand)) + # shellcheck disable=SC2034 + argCommand="${options_parse_arg}" + # Argument 2/2 + # Argument commandArgs min 0 max -1 authorizedValues '' regexp '' + elif ((options_parse_parsedArgIndex >= 1)); then + ((++options_parse_argParsedCountCommandArgs)) + # shellcheck disable=SC2034 + commandArgs+=("${options_parse_arg}") + else + unknownOption "${options_parse_arg}" + fi + ((++options_parse_parsedArgIndex)) + ;; + esac + shift || true + done + commandOptionParseFinished + Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" + Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" + elif [[ "${options_parse_cmd}" = "help" ]]; then + echo -e "$(Array::wrap2 " " 80 0 "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" "Push/Pull postman collections of all the configured repositories")" + echo + + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" "${SCRIPT_NAME}" "[OPTIONS]" "[ARGUMENTS]")" + echo -e "$(Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ + "${SCRIPT_NAME}" \ + "[--postman-model|-m ]" "[--bash-framework-config ]" "[--config]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--no-color]" "[--theme ]" "[--help|-h]" "[--version]" "[--quiet|-q]" "[--log-level ]" "[--log-file ]" "[--display-level ]")" + echo + echo -e "${__HELP_TITLE_COLOR}ARGUMENTS:${__RESET_COLOR}" + echo -e " [${__HELP_OPTION_COLOR}command${__HELP_NORMAL} {single}]" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=($'\e[1;34mpull\n\n \xc2\xa0\xc2\xa0Pull collections from Postman back to repositories.\n\n \e[1;34mpush\n\n \xc2\xa0\xc2\xa0Push repositories collections to Postman.\n') + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " [${__HELP_OPTION_COLOR}commandArgs${__HELP_NORMAL} {list} (optional)]" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=($'list of postman collection\'s references to pull or push\n\n or no argument to pull or push all the collections') + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo + echo -e "${__HELP_TITLE_COLOR}PUSH/PULL OPTIONS:${__RESET_COLOR}" + echo -e " ${__HELP_OPTION_COLOR}--postman-model${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-m ${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=($'postmanCli model file to use\n\n Default value: /postmanCli.collections.json') + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo + echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" + echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(use\ alternate\ bash\ framework\ configuration.) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " ${__HELP_OPTION_COLOR}--config${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(Display\ configuration) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " ${__HELP_OPTION_COLOR}--verbose${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-v${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(info\ level\ verbose\ mode\ \(alias\ of\ --display-level\ INFO\)) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " ${__HELP_OPTION_COLOR}-vv${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(debug\ level\ verbose\ mode\ \(alias\ of\ --display-level\ DEBUG\)) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " ${__HELP_OPTION_COLOR}-vvv${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(trace\ level\ verbose\ mode\ \(alias\ of\ --display-level\ TRACE\)) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(Load\ the\ specified\ env\ file\ \(deprecated\,\ please\ use\ --bash-framework-config\ option\ instead\)) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " ${__HELP_OPTION_COLOR}--no-color${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(Produce\ monochrome\ output.\ alias\ of\ --theme\ noColor.) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " ${__HELP_OPTION_COLOR}--theme ${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo " Default value: default" + echo ' Possible values: default|default-force|noColor' + echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(Display\ this\ command\ help) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " ${__HELP_OPTION_COLOR}--version${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(Print\ version\ information\ and\ quit) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " ${__HELP_OPTION_COLOR}--quiet${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-q${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(quiet\ mode\,\ doesn\'t\ display\ any\ output) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(Set\ log\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE' + echo -e " ${__HELP_OPTION_COLOR}--log-file ${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(Set\ log\ file) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo -e " ${__HELP_OPTION_COLOR}--display-level ${__HELP_NORMAL} {single}" + local -a helpArray + # shellcheck disable=SC2054 + helpArray=(set\ display\ level) + echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" + echo ' Possible values: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE' + echo + echo -n -e "${__HELP_TITLE_COLOR}VERSION: ${__RESET_COLOR}" + echo '1.0' + echo + echo -e "${__HELP_TITLE_COLOR}AUTHOR:${__RESET_COLOR}" + echo '[François Chastanet](https://github.com/fchastanet)' + echo + echo -e "${__HELP_TITLE_COLOR}SOURCE FILE:${__RESET_COLOR}" + echo 'https://github.com/fchastanet/bash-tools/tree/master/src/_binaries/Postman/postmanCli.sh' + echo + echo -e "${__HELP_TITLE_COLOR}LICENSE:${__RESET_COLOR}" + echo 'MIT License' + echo + Array::wrap2 ' ' 76 4 "$(copyrightCallback)" + else + Log::displayError "Command ${SCRIPT_NAME} - Option command invalid: '${options_parse_cmd}'" + return 1 + fi +} +declare optionPostmanModelConfig="$(pwd -P)/postmanCli.collections.json" + +# shellcheck disable=SC2317 # if function is overridden +unknownOption() { + commandArgs+=("$1") +} + +eval "original_$(declare -f displayConfig | grep -v 'exit 0')" +displayConfig() { + Postman::Model::validate "${optionPostmanModelConfig}" "config" + original_displayConfig + UI::drawLine "-" + printf '%-40s = %s\n' "POSTMAN_API_KEY" "${POSTMAN_API_KEY:0:15}...(truncated)" + exit 0 +} +# call main +postmanCliCommand parse "$@" + +run() { + # shellcheck disable=SC2154 + case "${argCommand}" in + pull) + Postman::Commands::pullCommand "${optionPostmanModelConfig}" "${commandArgs[@]}" + ;; + push) + Postman::Commands::pushCommand "${optionPostmanModelConfig}" "${commandArgs[@]}" + ;; + *) + Log::displayError "Invalid command ${argCommand}" + exit 1 + ;; + esac +} + +if [[ "${BASH_FRAMEWORK_QUIET_MODE:-0}" = "1" ]]; then + run "$@" &>/dev/null +else + run "$@" +fi + +} + +facade_main_postmanClish "$@" diff --git a/bin/upgradeGithubRelease b/bin/upgradeGithubRelease index 165f13b2..a62e0ce6 100755 --- a/bin/upgradeGithubRelease +++ b/bin/upgradeGithubRelease @@ -654,6 +654,96 @@ Version::parse() { sed -En 's/[^0-9]*(([0-9]+\.)*[0-9]+).*/\1/p' "$@" | head -n1 } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -953,6 +1043,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -961,6 +1052,7 @@ Env::requireLoad UI::requireTheme Log::requireLoad Linux::requireJqCommand +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir # @require Compiler::Facade::requireCommandBinDir @@ -1641,7 +1733,7 @@ upgradeGithubReleaseCommand() { # shellcheck disable=SC2054 helpArray=($'The argument that will be provided to the currently installed binary\n\n to check the version of the software. \n\n See options constraints below.') echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: --version' + echo " Default value: --version" echo -e " ${__HELP_OPTION_COLOR}--current-version${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-c ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 @@ -1699,7 +1791,7 @@ upgradeGithubReleaseCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/waitForIt b/bin/waitForIt index 648b441c..2f525963 100755 --- a/bin/waitForIt +++ b/bin/waitForIt @@ -510,6 +510,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -674,6 +764,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -681,6 +772,7 @@ fi Env::requireLoad UI::requireTheme Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir # @require Compiler::Facade::requireCommandBinDir @@ -1359,7 +1451,7 @@ waitForItCommand() { # shellcheck disable=SC2054 helpArray=(Timeout\ in\ seconds\,\ zero\ for\ no\ timeout.) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: 15' + echo " Default value: 15" echo -e " ${__HELP_OPTION_COLOR}--host${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-i ${__HELP_NORMAL} {single} (mandatory)" local -a helpArray # shellcheck disable=SC2054 @@ -1422,7 +1514,7 @@ waitForItCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/waitForMysql b/bin/waitForMysql index 1ea344f0..4b7d479a 100755 --- a/bin/waitForMysql +++ b/bin/waitForMysql @@ -494,6 +494,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -658,6 +748,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -665,6 +756,7 @@ fi Env::requireLoad UI::requireTheme Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir # @require Compiler::Facade::requireCommandBinDir @@ -1335,7 +1427,7 @@ waitForMysqlCommand() { # shellcheck disable=SC2054 helpArray=(Timeout\ in\ seconds\,\ zero\ for\ no\ timeout.) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: 15' + echo " Default value: 15" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" @@ -1378,7 +1470,7 @@ waitForMysqlCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/conf/.env b/conf/.env index b63238c7..82eb07de 100755 --- a/conf/.env +++ b/conf/.env @@ -50,3 +50,8 @@ SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} # AWS Parameters # ----------------------------------------------------- S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= diff --git a/conf/postmanCli/GithubAPI/GitHubAPI-01-Basic_no_auth_postman_collection.json b/conf/postmanCli/GithubAPI/GitHubAPI-01-Basic_no_auth_postman_collection.json new file mode 100644 index 00000000..5da9b182 --- /dev/null +++ b/conf/postmanCli/GithubAPI/GitHubAPI-01-Basic_no_auth_postman_collection.json @@ -0,0 +1,89 @@ +{ + "info": { + "_postman_id": "b47cdd04-f4ea-4a96-8735-90efa20fee2d", + "name": "GitHub API - 1. Basic (no Auth)", + "description": "### What is GitHub?\n\n[GitHub](https://github.com/) is a popular code version control platform that over 73 million developers worldwide trust to organize their code bases.\n\nWhile you can interact with GitHub by clicking around their website, you can also interact with GitHub programmatically using their API. \n \nThis collection shows just a few of the many actions you can perform using the [GitHub REST API](https://docs.github.com/en/rest).\n\n### What is a repo?\n\nShort for \"repository\", a repo is simply a place where code is stored. You can think of a repo like a project folder.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "updatedAt": "2024-01-04T21:41:56.000Z", + "uid": "27246549-b47cdd04-f4ea-4a96-8735-90efa20fee2d", + "createdAt": "2024-01-02T23:37:53.000Z", + "lastUpdatedBy": "27246549" + }, + "item": [ + { + "name": "search repos", + "id": "a84e7139-cff4-4cb0-a2b5-cddd286c185e", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/search/repositories?q=postman&order=desc&per_page=30", + "host": ["{{baseUrl}}"], + "path": ["search", "repositories"], + "query": [ + {"key": "q", "value": "postman"}, + {"key": "order", "value": "desc"}, + {"key": "per_page", "value": "30"} + ] + }, + "description": "Searches repositories based on keywords `q`" + }, + "response": [], + "uid": "27246549-a84e7139-cff4-4cb0-a2b5-cddd286c185e" + }, + { + "name": "user info", + "id": "d97527a0-a93f-4146-a4ae-955c9f579838", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/users/:owner", + "host": ["{{baseUrl}}"], + "path": ["users", ":owner"], + "variable": [ + { + "key": "owner", + "value": "octocat", + "description": "username or organization name you would like information about" + } + ] + }, + "description": "Get information about the given user. \n\nMore detailed information is given if the requested user is the currently authorized user." + }, + "response": [], + "uid": "27246549-d97527a0-a93f-4146-a4ae-955c9f579838" + }, + { + "name": "user repos", + "id": "d54b66aa-77d6-45ae-acbd-b81592eefc0f", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/users/:owner/repos", + "host": ["{{baseUrl}}"], + "path": ["users", ":owner", "repos"], + "variable": [ + { + "key": "owner", + "value": "octocat", + "description": "username or organization name whose repos you would like to see" + } + ] + }, + "description": "Lists all public repos for a given user" + }, + "response": [], + "uid": "27246549-d54b66aa-77d6-45ae-acbd-b81592eefc0f" + } + ], + "event": [ + { + "listen": "prerequest", + "script": {"type": "text/javascript", "exec": [""]} + }, + {"listen": "test", "script": {"type": "text/javascript", "exec": [""]}} + ], + "variable": [{"key": "baseUrl", "value": "https://api.github.com"}] +} diff --git a/conf/postmanCli/GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json b/conf/postmanCli/GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json new file mode 100644 index 00000000..249c0cbb --- /dev/null +++ b/conf/postmanCli/GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json @@ -0,0 +1,311 @@ +{ + "info": { + "_postman_id": "758f8445-f82c-482c-a8a4-87f3e2f6566d", + "name": "GitHub API - 2. Advanced (with Auth)", + "description": "Create a fork of this collection to play around with advanced operations in the GitHub API, using authorization!\n\nThis collection shows just a few of the many actions you can perform using the [GitHub REST API](https://docs.github.com/en/rest).\n\n### Authorization\n\nWhile the GitHub API allows some public requests to be made by anyone, such as searching for repos, to do more advanced operations you will need to authorize your requests. In other words, you have to prove that you are allowed to make that request. You can't just go around deleting other people's code on GitHub!\n\nLearn more about Authorization in Postman [here in the Postman Learning Center](https://learning.postman.com/docs/sending-requests/authorization/](https://learning.postman.com/docs/sending-requests/authorization/).\n\n## Set up authorization\n\nTo authorize requests to the GitHub API using your GitHub account, follow these steps:\n\n1. Log in to GitHub and create a [Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token). Give your token the permission scopes you wish to use.\n2. In this collection's \"Variables\" tab, paste your token in the `CURRENT VALUE` column of \n `personalAccessToken` (Do NOT paste in the `INITIAL VALUE` column! This column is public if shared - keep your secrets secret!)\n3. Enter your GitHub username for the `username` variable\n4. Save your changes!\n \n\nOnce you've set up Auth on this collection `GitHub API - 2. Advanced (with Auth)`, it will apply to all the requests inside.\n\nAs you can see in the \"Authorization\" or (\"Auth\") tab of this collection, the values you provide to the variables in the steps above are used to authorize all request in this collection using Basic Auth. Neat!\n\n## Be careful!\n\nOnce authorized, you can make real changes to your actual GitHub account! **Be especially careful if making a request to update or delete a repo, as these changes will really happen without being asked 'are you sure?'**", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "updatedAt": "2024-01-04T21:41:54.000Z", + "uid": "27246549-758f8445-f82c-482c-a8a4-87f3e2f6566d", + "createdAt": "2024-01-02T23:37:51.000Z", + "lastUpdatedBy": "27246549" + }, + "item": [ + { + "name": "replace or update a file in repo", + "item": [ + { + "name": "1. base64 encode a file", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// globally import the btoa library to base64 encoding text", + "require(\"btoa\")", + "", + "// get response body", + "const body = pm.response.json()", + "", + "// retrieve file data", + "const { data: rawData } = body", + "", + "// encode plain text to base64", + "const encodedFileData = btoa(rawData)", + "", + "pm.collectionVariables.set('encodedFileData', encodedFileData)", + "" + ], + "type": "text/javascript" + } + } + ], + "id": "533d956d-9828-4b35-8dab-6d2c7994cc01", + "request": { + "method": "POST", + "header": [], + "body": {"mode": "file", "file": {"src": "IVfZVvvDp/test.md"}}, + "url": { + "raw": "postman-echo.com/post", + "host": ["postman-echo", "com"], + "path": ["post"] + } + }, + "response": [], + "uid": "27246549-533d956d-9828-4b35-8dab-6d2c7994cc01" + }, + { + "name": "2. replace or update file in repo", + "event": [ + { + "listen": "prerequest", + "script": {"exec": [""], "type": "text/javascript"} + }, + { + "listen": "test", + "script": {"exec": [""], "type": "text/javascript"} + } + ], + "id": "fb33abcc-8329-4fa9-9fbb-8e513f9307f6", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"message\": \"This file was added using the GitHub API!\",\n \"content\": \"{{encodedFileData}}\"\n}", + "options": {"raw": {"language": "json"}} + }, + "url": { + "raw": "{{baseUrl}}/repos/:owner/:repo/contents/:path", + "host": ["{{baseUrl}}"], + "path": ["repos", ":owner", ":repo", "contents", ":path"], + "variable": [ + { + "key": "owner", + "value": "clairefro", + "description": "user or org name" + }, + { + "key": "repo", + "value": "my-repo", + "description": "name of the repo " + }, + { + "key": "path", + "value": "foo.md", + "description": "path to the file to be uploaded/replaced\n" + } + ] + }, + "description": "**WARNING!** Running this request will overwrite an existing file if specified filepath already exists in the provided repo, if you have the proper authorization credentials. Proceed with caution!\n\n## Before making this request \nEncode the file you would like to upload from your computer into base64 using request #1 above. \n\nThat request will save the base64 encoded file to a colelction variable called `encodedFileData`, which will be sent in the body of this request.\n\nEdit the values in the `Params` tab in the request before sending." + }, + "response": [], + "uid": "27246549-fb33abcc-8329-4fa9-9fbb-8e513f9307f6" + } + ], + "id": "d22f764e-33c8-44ab-953e-21ced97d2022", + "description": "**WARNING!** Running #2 in this folder will overwrite an existing file if specified filepath already exists in the provided repo.\n\n## How to use\nTo upload or replace a file in a repo, the GitHub API requires a the contents of a file to be base64 encoded. \n\nThat is why this request is broken into two steps: \n\n1. Encode a file from your computer to base64 and save it to a collection variable called `encodedFileData`\n\n2. Include `encodedFileData` in the body of the request to the GitHub API\n\n```json\n{\n \"message\": \"My commit message\",\n \"content\": \"<>\"\n}\n```", + "uid": "27246549-d22f764e-33c8-44ab-953e-21ced97d2022" + }, + { + "name": "search repos", + "id": "2d2c4c2b-8f81-4ac6-85d2-ede1fef38430", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/search/repositories?q=postman&order=desc&per_page=30", + "host": ["{{baseUrl}}"], + "path": ["search", "repositories"], + "query": [ + {"key": "q", "value": "postman"}, + {"key": "order", "value": "desc"}, + {"key": "per_page", "value": "30"} + ] + }, + "description": "Searches repositories based on keywords `q`" + }, + "response": [], + "uid": "27246549-2d2c4c2b-8f81-4ac6-85d2-ede1fef38430" + }, + { + "name": "user info", + "id": "3e173fc6-3eab-42a4-9517-d670b7dd83c4", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/users/:owner", + "host": ["{{baseUrl}}"], + "path": ["users", ":owner"], + "variable": [ + { + "key": "owner", + "value": "octocat", + "description": "username or organization name you would like information about" + } + ] + }, + "description": "Get information about the given user.\n\nYou can see more detailed information if you make this request while authorized, such as the authorized user's private repos." + }, + "response": [], + "uid": "27246549-3e173fc6-3eab-42a4-9517-d670b7dd83c4" + }, + { + "name": "user repos", + "id": "74098d8d-76e2-42fc-8990-bd8bf209b1c4", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/users/:owner/repos", + "host": ["{{baseUrl}}"], + "path": ["users", ":owner", "repos"], + "variable": [ + { + "key": "owner", + "value": "octocat", + "description": "username or organization name whose repos you would like to see" + } + ] + }, + "description": "Lists repos for a given user.\n\nYou can see more detailed information if you make this request while authorized, such as the authorized user's private repos." + }, + "response": [], + "uid": "27246549-74098d8d-76e2-42fc-8990-bd8bf209b1c4" + }, + { + "name": "create an empty repo", + "id": "8b5db2c0-b51b-4dad-8e09-e67c3961b83d", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"i-made-this-repo-from-an-api\"\n}", + "options": {"raw": {"language": "json"}} + }, + "url": { + "raw": "{{baseUrl}}/user/repos", + "host": ["{{baseUrl}}"], + "path": ["user", "repos"] + }, + "description": "Creates a new repo with a given `name` for the authorized user" + }, + "response": [], + "uid": "27246549-8b5db2c0-b51b-4dad-8e09-e67c3961b83d" + }, + { + "name": "create a fork", + "id": "2ee8cb21-4b8b-4b75-b834-40b21d1bcd02", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"api-fork-test-hello-world\"\n}", + "options": {"raw": {"language": "json"}} + }, + "url": { + "raw": "{{baseUrl}}/repos/:owner/:repo/forks", + "host": ["{{baseUrl}}"], + "path": ["repos", ":owner", ":repo", "forks"], + "variable": [ + { + "key": "owner", + "value": "octocat", + "description": "owner of the repo you would like to fork" + }, + { + "key": "repo", + "value": "Hello-World", + "description": "name of the repo you would like to fork" + } + ] + }, + "description": "Forks a given `repo` from a given `owner` to a new repo called `name` in the authorized user's GitHub account.\n\nThis is usually the first step when you are going to make changes to someone else's code!" + }, + "response": [], + "uid": "27246549-2ee8cb21-4b8b-4b75-b834-40b21d1bcd02" + }, + { + "name": "update a repo", + "id": "97ce6844-387c-46ef-a51f-40442a3e6821", + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"updated-with-api\"\n}", + "options": {"raw": {"language": "json"}} + }, + "url": { + "raw": "{{baseUrl}}/repos/:owner/:repo", + "host": ["{{baseUrl}}"], + "path": ["repos", ":owner", ":repo"], + "variable": [ + { + "key": "owner", + "value": "clairefro", + "description": "your GitHub username" + }, + {"key": "repo", "value": "Hello-World"} + ] + }, + "description": "Updates data on a repo, such as `name`" + }, + "response": [], + "uid": "27246549-97ce6844-387c-46ef-a51f-40442a3e6821" + }, + { + "name": "delete repo", + "id": "3d639231-4dcd-4767-9d0c-f1283ce47a8a", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{baseUrl}}/repos/:owner/:repo", + "host": ["{{baseUrl}}"], + "path": ["repos", ":owner", ":repo"], + "variable": [ + { + "key": "owner", + "value": "clairefro", + "description": "your GitHub username" + }, + { + "key": "repo", + "value": "i-made-this-repo-from-an-api", + "description": "name of your repository" + } + ] + }, + "description": "**WARNING!** This will really delete your repo :)\n\nDeletes a given `repo` for given `owner`" + }, + "response": [], + "uid": "27246549-3d639231-4dcd-4767-9d0c-f1283ce47a8a" + } + ], + "auth": { + "type": "basic", + "basic": [ + {"key": "password", "value": "{{personalAccessToken}}", "type": "string"}, + {"key": "username", "value": "{{username}}", "type": "string"} + ] + }, + "event": [ + { + "listen": "prerequest", + "script": {"type": "text/javascript", "exec": [""]} + }, + {"listen": "test", "script": {"type": "text/javascript", "exec": [""]}} + ], + "variable": [ + {"key": "baseUrl", "value": "https://api.github.com"}, + { + "key": "personalAccessToken", + "value": "" + }, + {"key": "username", "value": ""}, + {"key": "encodedFileData", "value": ""} + ] +} diff --git a/conf/postmanCli/GithubAPI/GithubAPI-postman_environment.json b/conf/postmanCli/GithubAPI/GithubAPI-postman_environment.json new file mode 100644 index 00000000..e93da4f0 --- /dev/null +++ b/conf/postmanCli/GithubAPI/GithubAPI-postman_environment.json @@ -0,0 +1,15 @@ +{ + "id": "dbb0d011-6523-4dfa-b5d0-453f30b1cefa", + "name": "Github API", + "values": [ + { + "key": "token", + "value": "", + "type": "secret", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2023-12-25T18:02:03.041Z", + "_postman_exported_using": "Postman/10.21.9-231220-0601" +} diff --git a/conf/postmanCli/MongoDbData/Atlas.postman_environment.json b/conf/postmanCli/MongoDbData/Atlas.postman_environment.json new file mode 100644 index 00000000..dc88c4f3 --- /dev/null +++ b/conf/postmanCli/MongoDbData/Atlas.postman_environment.json @@ -0,0 +1,279 @@ +{ + "id": "5739feed-60b0-4a55-a6e5-ea3ac94af110", + "name": "Atlas", + "values": [ + { + "key": "base_url", + "value": "https://cloud.mongodb.com", + "enabled": true + }, + { + "key": "version", + "value": "v1.0", + "enabled": true + }, + { + "key": "ProjectID", + "value": "616d70c51ec022309622497a", + "enabled": true + }, + { + "key": "CLUSTER-NAME", + "value": "Cluster0", + "enabled": true + }, + { + "key": "databaseName", + "value": "", + "enabled": true + }, + { + "key": "dbUser", + "value": "", + "enabled": true + }, + { + "key": "ORG-ID", + "value": "", + "enabled": true + }, + { + "key": "API-key-pwd", + "value": "", + "enabled": true + }, + { + "key": "API-key-usr", + "value": "", + "enabled": true + }, + { + "key": "INVITATION_ID", + "value": "", + "enabled": true + }, + { + "key": "INVOICE-ID", + "value": "", + "enabled": true + }, + { + "key": "PROJECT_NAME", + "value": "", + "enabled": true + }, + { + "key": "TEAM-ID", + "value": "", + "enabled": true + }, + { + "key": "USER-ID", + "value": "", + "enabled": true + }, + { + "key": "PROJ-INVITATIO-ID", + "value": "", + "enabled": true + }, + { + "key": "TEAM-NAME", + "value": "", + "enabled": true + }, + { + "key": "SAMPLE-DATASET-ID", + "value": "", + "enabled": true + }, + { + "key": "CLOUD-PROVIDER", + "value": "", + "enabled": true + }, + { + "key": "CLUSTER-TIER", + "value": "", + "enabled": true + }, + { + "key": "INSTANCE-NAME", + "value": "", + "enabled": true + }, + { + "key": "ALERT-ID", + "value": "", + "enabled": true + }, + { + "key": "ALERT-CONFIG-ID", + "value": "", + "enabled": true + }, + { + "key": "DATABASE-NAME", + "value": "", + "enabled": true + }, + { + "key": "COLLECTION-NAME", + "value": "", + "enabled": true + }, + { + "key": "INDEX-ID", + "value": "", + "enabled": true + }, + { + "key": "SNAPSHOT-ID", + "value": "", + "enabled": true + }, + { + "key": "JOB-ID", + "value": "", + "enabled": true + }, + { + "key": "RESTORE-JOB-ID", + "value": "", + "enabled": true + }, + { + "key": "restoreJobId", + "value": "", + "enabled": true + }, + { + "key": "TARGET-CLUSTER-NAME", + "value": "", + "enabled": true + }, + { + "key": "TARGET-GROUP-ID", + "value": "", + "enabled": true + }, + { + "key": "targetGroupId", + "value": "", + "enabled": true + }, + { + "key": "clusterName", + "value": "", + "enabled": true + }, + { + "key": "RESTORE-ID", + "value": "", + "enabled": true + }, + { + "key": "ARCHIVE-ID", + "value": "", + "enabled": true + }, + { + "key": "CONTAINER-ID", + "value": "", + "enabled": true + }, + { + "key": "PEER-ID", + "value": "", + "enabled": true + }, + { + "key": "ENDPOINT-SERVICE-ID", + "value": "", + "enabled": true + }, + { + "key": "ENDPOINT-ID", + "value": "", + "enabled": true + }, + { + "key": "API-KEY-ID", + "value": "", + "enabled": true + }, + { + "key": "ACCESS-LIST-ENTRY", + "value": "", + "enabled": true + }, + { + "key": "IP-ADDRESS", + "value": "", + "enabled": true + }, + { + "key": "PROCESS-HOST", + "value": "", + "enabled": true + }, + { + "key": "PROCESS-PORT", + "value": "", + "enabled": true + }, + { + "key": "DISK-NAME", + "value": "", + "enabled": true + }, + { + "key": "HOSTNAME", + "value": "", + "enabled": true + }, + { + "key": "LOG-NAME", + "value": "", + "enabled": true + }, + { + "key": "USER-NAME", + "value": "", + "enabled": true + }, + { + "key": "ROLE-ID", + "value": "", + "enabled": true + }, + { + "key": "EVENT-ID", + "value": "", + "enabled": true + }, + { + "key": "DATA-LAKE-NAME", + "value": "", + "enabled": true + }, + { + "key": "VALIDATION-ID", + "value": "", + "enabled": true + }, + { + "key": "LIVE-MIGRATION-ID", + "value": "", + "enabled": true + }, + { + "key": "ROLE-NAME", + "value": "", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2024-01-04T12:18:13.332Z", + "_postman_exported_using": "Postman/10.21.11-240102-2003" +} diff --git a/conf/postmanCli/MongoDbData/Data API.postman_environment.json b/conf/postmanCli/MongoDbData/Data API.postman_environment.json new file mode 100644 index 00000000..ace2ad0d --- /dev/null +++ b/conf/postmanCli/MongoDbData/Data API.postman_environment.json @@ -0,0 +1,51 @@ +{ + "id": "2370db50-515e-4fd1-b337-6e4b90ef26e0", + "name": "Data API", + "values": [ + { + "key": "URL_ENDPOINT", + "value": "", + "type": "default", + "enabled": false + }, + { + "key": "API_KEY", + "value": "", + "type": "secret", + "enabled": true + }, + { + "key": "DATA_SOURCE", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "DATABASE", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "COLLECTION", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "CONTENT_TYPE", + "value": "", + "type": "default", + "enabled": true + }, + { + "key": "AUTH_PROVIDER", + "value": "anon-user", + "type": "default", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2024-01-04T12:18:18.264Z", + "_postman_exported_using": "Postman/10.21.11-240102-2003" +} diff --git a/conf/postmanCli/MongoDbData/MongoDBDataAPI.postman_collection.json b/conf/postmanCli/MongoDbData/MongoDBDataAPI.postman_collection.json new file mode 100644 index 00000000..116fe589 --- /dev/null +++ b/conf/postmanCli/MongoDbData/MongoDBDataAPI.postman_collection.json @@ -0,0 +1,289 @@ +{ + "info": { + "_postman_id": "62332564-addf-40c0-8ad7-537732d2d6f5", + "name": "MongoDB Data API", + "description": "This collection is an introduction to the [MongoDB Data API](https://www.mongodb.com/data-api/l). The Data API provides you with a REST-like access to your data in [MongoDB Atlas](https://www.mongodb.com/atlas), the database-as-a-service offering by MongoDB.\n\nYou can find the full documentation on the MongoDB Data API on the [documentation website](https://docs.atlas.mongodb.com/api/data-api-resources/#data-api-resources).\n\n## Getting Started\n\nTo test out the MongoDB Data API collection, start by [creating a free MongoDB Atlas cluster](https://docs.atlas.mongodb.com/tutorial/deploy-free-tier-cluster/).\n\nOnce you have a cluster, you can [fork this collection](https://www.postman.com/mongodb-devrel/workspace/mongodb-public/collection/17898583-25682080-e247-4d25-8e5c-1798461c7db4/fork) into your own workspace so you'll be able to use it with your own variables.\n\nOnce you have a cluster up and running, [enable the Data API](https://docs.atlas.mongodb.com/api/data-api/#1.-enable-the-data-api).\n\nFrom the Atlas UI, copy the URL endpoint provided for the Data API, and paste the value in your URL_ENDPOINT collection variable.\n\nStill in the Atlas UI, create a new API key, copy the value and paste it in the API_KEY collection variable.\n\nWith the [EJSON format](https://www.mongodb.com/docs/atlas/api/data-api/#extended-json-responses), you can benefit from MongoDB’s Extended JSON format, which preserves many data types that are normally not supported by JSON (such as ObjectID, Date, and more).\n\nFor writes, the {{CONTENT_TYPE}} variable is required and can be set to either `json` or `ejson`. This variable is used by Postman in the *Content-Type* header.\n\nFor reads, the Data API returns JSON by default, but can be changed to EJSON by setting the *Accept* header. You can set the {{CONTENT_TYPE}} variable to `json` or `ejson` to change the default behavior. Changing this variable will change the *Accept* header when Postman does a request to the Data API. The default content type returned by Atlas can also be changed in the Atlas Admin UI.\n\nFill in the other variables with the appropriate values for your cluster, database, and collection names.\n\nYou can now explore the various endpoints and see how to perform CRUD operations on your collection using the MongoDB Data API.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "updatedAt": "2024-01-04T21:41:57.000Z", + "uid": "27246549-62332564-addf-40c0-8ad7-537732d2d6f5", + "createdAt": "2024-01-04T21:41:57.000Z", + "lastUpdatedBy": "27246549" + }, + "item": [ + { + "name": "Insert Document", + "id": "84496d5f-a757-48c1-aac6-8de721eb3492", + "request": { + "method": "POST", + "header": [ + {"key": "Content-Type", "value": "application/{{CONTENT_TYPE}}"}, + {"key": "Access-Control-Request-Headers", "value": "*"}, + {"key": "api-key", "value": "{{API_KEY}}"} + ], + "body": { + "mode": "raw", + "raw": "{\n \"dataSource\": \"{{DATA_SOURCE}}\",\n \"database\": \"{{DATABASE}}\",\n \"collection\": \"{{COLLECTION}}\",\n \"document\": {\n \"name\": \"John Sample\",\n \"age\": 42\n }\n }" + }, + "url": { + "raw": "{{URL_ENDPOINT}}/action/insertOne", + "host": ["{{URL_ENDPOINT}}"], + "path": ["action", "insertOne"] + }, + "description": "Using the `/insertOne` endpoint, you can add a document to a collection. Use the `document` property in the request body to specify the document that should be created." + }, + "response": [], + "uid": "27246549-84496d5f-a757-48c1-aac6-8de721eb3492" + }, + { + "name": "Find Document", + "id": "32f57ee5-75f1-4077-8590-8316454b67eb", + "request": { + "method": "POST", + "header": [ + {"key": "Content-Type", "value": "application/{{CONTENT_TYPE}}"}, + {"key": "Access-Control-Request-Headers", "value": "*"}, + {"key": "api-key", "value": "{{API_KEY}}"}, + { + "key": "Accept", + "value": "application/{{CONTENT_TYPE}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"dataSource\": \"{{DATA_SOURCE}}\",\n \"database\": \"{{DATABASE}}\",\n \"collection\": \"{{COLLECTION}}\",\n \"filter\": { \"name\": \"John Sample\" }\n }" + }, + "url": { + "raw": "{{URL_ENDPOINT}}/action/findOne", + "host": ["{{URL_ENDPOINT}}"], + "path": ["action", "findOne"] + }, + "description": "Using the `/findOne` endpoint will let you retrieve a single document from a collection. Use the `filter` property in the request body to specify the search criteria. If more than one document matches the criteria, only the first match will be returned." + }, + "response": [], + "uid": "27246549-32f57ee5-75f1-4077-8590-8316454b67eb" + }, + { + "name": "Update Document", + "id": "99cfaadf-c730-4a43-9763-4ca7de68ebca", + "request": { + "method": "POST", + "header": [ + {"key": "Content-Type", "value": "application/{{CONTENT_TYPE}}"}, + {"key": "Access-Control-Request-Headers", "value": "*"}, + {"key": "api-key", "value": "{{API_KEY}}"} + ], + "body": { + "mode": "raw", + "raw": "{\n \"dataSource\": \"{{DATA_SOURCE}}\",\n \"database\": \"{{DATABASE}}\",\n \"collection\": \"{{COLLECTION}}\",\n \"filter\": { \"name\": \"John Sample\" },\n \"update\": { \"$set\": { \"age\": 24 } }\n }" + }, + "url": { + "raw": "{{URL_ENDPOINT}}/action/updateOne", + "host": ["{{URL_ENDPOINT}}"], + "path": ["action", "updateOne"] + }, + "description": "You can use the `/updateOne` endpoint to update a single record. Use the `filter` property in the request body to specify the search criteria. If more than one document matches the criteria, only the first match will be returned. Then use the `update` field to specify what should be updated. You should use one of the [update operators](https://docs.mongodb.com/manual/reference/operator/update-field/) to update your documents." + }, + "response": [], + "uid": "27246549-99cfaadf-c730-4a43-9763-4ca7de68ebca" + }, + { + "name": "Delete Document", + "id": "b5c75b8b-8f0b-4592-b7bd-a28d076963f9", + "request": { + "method": "POST", + "header": [ + {"key": "Content-Type", "value": "application/{{CONTENT_TYPE}}"}, + {"key": "Access-Control-Request-Headers", "value": "*"}, + {"key": "api-key", "value": "{{API_KEY}}"} + ], + "body": { + "mode": "raw", + "raw": "{\n \"dataSource\": \"{{DATA_SOURCE}}\",\n \"database\": \"{{DATABASE}}\",\n \"collection\": \"{{COLLECTION}}\",\n \"filter\": { \"name\": \"John Sample\" }\n }" + }, + "url": { + "raw": "{{URL_ENDPOINT}}/action/deleteOne", + "host": ["{{URL_ENDPOINT}}"], + "path": ["action", "deleteOne"] + }, + "description": "To delete a single document, use the `/deleteOne` endpoint. Use the `filter` property in the request body to specify the search criteria. If more than one document matches the criteria, only the first match will be deleted." + }, + "response": [], + "uid": "27246549-b5c75b8b-8f0b-4592-b7bd-a28d076963f9" + }, + { + "name": "Insert Multiple Documents", + "id": "72b9f29a-c49f-4d43-a697-7fa8fec33b0c", + "request": { + "method": "POST", + "header": [ + {"key": "Content-Type", "value": "application/{{CONTENT_TYPE}}"}, + {"key": "Access-Control-Request-Headers", "value": "*"}, + {"key": "api-key", "value": "{{API_KEY}}"} + ], + "body": { + "mode": "raw", + "raw": "{\n \"dataSource\": \"{{DATA_SOURCE}}\",\n \"database\": \"{{DATABASE}}\",\n \"collection\": \"{{COLLECTION}}\",\n \"documents\": [{\n \"name\": \"John Sample\",\n \"age\": 42\n },{\n \"name\": \"Mister Postman\",\n \"age\": 37\n },{\n \"name\": \"Miss MongoDB\",\n \"age\": 35\n }]\n }" + }, + "url": { + "raw": "{{URL_ENDPOINT}}/action/insertMany", + "host": ["{{URL_ENDPOINT}}"], + "path": ["action", "insertMany"] + }, + "description": "You can add more than one document at a time by using the `/insertMany` endpoint. In that case, you must use the `documents` property in the body of the request to specify the array of documents you want to insert into the collection." + }, + "response": [], + "uid": "27246549-72b9f29a-c49f-4d43-a697-7fa8fec33b0c" + }, + { + "name": "Find Multiple Documents", + "id": "e0f89f7f-2075-4e9c-b440-bca4e92802ce", + "request": { + "method": "POST", + "header": [ + {"key": "Content-Type", "value": "application/{{CONTENT_TYPE}}"}, + {"key": "Access-Control-Request-Headers", "value": "*"}, + {"key": "api-key", "value": "{{API_KEY}}"}, + { + "key": "Accept", + "value": "application/{{CONTENT_TYPE}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"dataSource\": \"{{DATA_SOURCE}}\",\n \"database\": \"{{DATABASE}}\",\n \"collection\": \"{{COLLECTION}}\",\n \"filter\": { \"age\": { \"$lt\": 40 } }\n }" + }, + "url": { + "raw": "{{URL_ENDPOINT}}/action/find", + "host": ["{{URL_ENDPOINT}}"], + "path": ["action", "find"] + }, + "description": "Using the `/find` endpoint, you can fetch multiple documents at once. Use the `filter` property in the body of the request to specify the criteria on which to filter. If you pass an empty object `{ }`, all the documents in the collection will be returned." + }, + "response": [], + "uid": "27246549-e0f89f7f-2075-4e9c-b440-bca4e92802ce" + }, + { + "name": "Update Multiple Documents", + "id": "f3c52a05-74f7-426d-ac73-45dde6465d88", + "request": { + "method": "POST", + "header": [ + {"key": "Content-Type", "value": "application/{{CONTENT_TYPE}}"}, + {"key": "Access-Control-Request-Headers", "value": "*"}, + {"key": "api-key", "value": "{{API_KEY}}"} + ], + "body": { + "mode": "raw", + "raw": "{\n \"dataSource\": \"{{DATA_SOURCE}}\",\n \"database\": \"{{DATABASE}}\",\n \"collection\": \"{{COLLECTION}}\",\n \"filter\": { \"age\": { \"$lt\": 40 } },\n \"update\": { \"$set\": { \"age\": 42 } }\n }" + }, + "url": { + "raw": "{{URL_ENDPOINT}}/action/updateMany", + "host": ["{{URL_ENDPOINT}}"], + "path": ["action", "updateMany"] + }, + "description": "Using `/updateMany`, you can update all the documents matching a specific `filter` specified in the body of the request. Use one of the [update operators](https://docs.mongodb.com/manual/reference/operator/update-field/) in the `update` field to update your documents." + }, + "response": [], + "uid": "27246549-f3c52a05-74f7-426d-ac73-45dde6465d88" + }, + { + "name": "Delete Many Documents", + "id": "f470b4ad-92c3-4c0c-8967-23174866d41f", + "request": { + "method": "POST", + "header": [ + {"key": "Content-Type", "value": "application/{{CONTENT_TYPE}}"}, + {"key": "Access-Control-Request-Headers", "value": "*"}, + {"key": "api-key", "value": "{{API_KEY}}"} + ], + "body": { + "mode": "raw", + "raw": "{\n \"dataSource\": \"{{DATA_SOURCE}}\",\n \"database\": \"{{DATABASE}}\",\n \"collection\": \"{{COLLECTION}}\",\n \"filter\": { }\n }" + }, + "url": { + "raw": "{{URL_ENDPOINT}}/action/deleteMany", + "host": ["{{URL_ENDPOINT}}"], + "path": ["action", "deleteMany"] + }, + "description": "You can use `/deleteMany` to delete multiple documents at once. Use the `filter` property to specify which documents to delete. \n \n**Warning**: Using `filter: { }` will delete all the documents in the collection. Use `/deleteMany` with care." + }, + "response": [], + "uid": "27246549-f470b4ad-92c3-4c0c-8967-23174866d41f" + }, + { + "name": "Run Aggregation Pipeline", + "id": "847dd9e9-460d-4d33-8604-f01bb793d58e", + "request": { + "method": "POST", + "header": [ + {"key": "Content-Type", "value": "application/{{CONTENT_TYPE}}"}, + {"key": "Access-Control-Request-Headers", "value": "*"}, + {"key": "api-key", "value": "{{API_KEY}}"}, + { + "key": "Accept", + "value": "application/{{CONTENT_TYPE}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"dataSource\": \"{{DATA_SOURCE}}\",\n \"database\": \"{{DATABASE}}\",\n \"collection\": \"{{COLLECTION}}\",\n \"pipeline\": [\n {\n \"$sort\": { \"age\": 1 }\n },\n {\n \"$limit\": 1\n }\n ]\n }" + }, + "url": { + "raw": "{{URL_ENDPOINT}}/action/aggregate", + "host": ["{{URL_ENDPOINT}}"], + "path": ["action", "aggregate"] + }, + "description": "You can even run [aggregation pipelines](https://docs.mongodb.com/manual/core/aggregation-pipeline/) with the Data API. To do so, use the `/aggregate` endpoint and specify your pipeline in the `pipeline` field of the request body." + }, + "response": [], + "uid": "27246549-847dd9e9-460d-4d33-8604-f01bb793d58e" + } + ], + "event": [ + { + "listen": "prerequest", + "script": {"type": "text/javascript", "exec": [""]} + }, + {"listen": "test", "script": {"type": "text/javascript", "exec": [""]}} + ], + "variable": [ + { + "id": "beb5c18f-08a5-4bb9-8589-43a0976139f8", + "key": "URL_ENDPOINT", + "value": "", + "type": "string" + }, + { + "id": "7f6ca5b6-c8d9-4dee-924c-88003bc8ceb9", + "key": "API_KEY", + "value": "" + }, + { + "id": "4138ae80-2ad5-45c8-8ab1-c49c1a67d4b4", + "key": "DATA_SOURCE", + "value": "", + "type": "string" + }, + { + "id": "77f04bd0-8993-4378-84bb-3938366a1ac3", + "key": "DATABASE", + "value": "", + "type": "string" + }, + { + "id": "ab1b4a7d-1ea9-4161-ad4f-d14aa4748d60", + "key": "COLLECTION", + "value": "", + "type": "string" + }, + { + "id": "2a51eb6a-742c-4ef7-b6c0-7a3b3e4ee582", + "key": "CONTENT_TYPE", + "value": "", + "type": "string" + } + ] +} diff --git a/conf/postmanCli/openApis.json b/conf/postmanCli/openApis.json new file mode 100644 index 00000000..1c0af712 --- /dev/null +++ b/conf/postmanCli/openApis.json @@ -0,0 +1,17 @@ +{ + "name": "Open Apis", + "collections": { + "githubBasic": { + "file": "GithubAPI/GitHubAPI-01-Basic_no_auth_postman_collection.json", + "environment": null + }, + "githubAdvanced": { + "file": "GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json", + "environment": null + }, + "mongoDbData": { + "file": "MongoDbData/MongoDBDataAPI.postman_collection.json", + "environment": null + } + } +} diff --git a/install b/install index 45bd41ab..2cf9a935 100755 --- a/install +++ b/install @@ -481,6 +481,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -645,6 +735,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi @@ -652,6 +743,7 @@ fi Env::requireLoad UI::requireTheme Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir Linux::requireExecutedAsUser @@ -1233,7 +1325,7 @@ installCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/src/BashTools/Conf/requireLoad.bats b/src/BashTools/Conf/requireLoad.bats new file mode 100755 index 00000000..a94dcdc5 --- /dev/null +++ b/src/BashTools/Conf/requireLoad.bats @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2154 +# shellcheck disable=SC2034 + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd -P)/batsHeaders.sh" +# shellcheck source=src/BashTools/Conf/requireLoad.sh +source "${rootDir}/src/BashTools/Conf/requireLoad.sh" + +setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + export HOME="${BATS_TEST_TMPDIR}/home" + export POSTMAN_API_KEY="fake" + export BASH_FRAMEWORK_THEME="noColor" + export bashToolsDefaultConfigTemplate="$(cat "${rootDir}/conf/.env")" +} + +function BashTools::Conf::requireLoad::envFileDoesNotExist { #@test + local status=0 + BashTools::Conf::requireLoad >"${BATS_TEST_TMPDIR}/result" 2>&1 || status=$? + [[ "${status}" = "0" ]] + run cat "${BATS_TEST_TMPDIR}/result" + assert_output "INFO - Configuration file '${HOME}/.bash-tools/.env' created" + [[ -z "${POSTMAN_API_KEY}" ]] +} + +function BashTools::Conf::requireLoad::envFileWithApiKeyExists { #@test + mkdir -p "${HOME}/.bash-tools" + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + sed -i -E -e 's/^POSTMAN_API_KEY=/POSTMAN_API_KEY=fake2/' "${HOME}/.bash-tools/.env" + local status=0 + BashTools::Conf::requireLoad >"${BATS_TEST_TMPDIR}/result" 2>&1 || status=$? + [[ "${status}" = "0" ]] + run cat "${BATS_TEST_TMPDIR}/result" + assert_output "" + [[ "${POSTMAN_API_KEY}" = "fake2" ]] +} + +function BashTools::Conf::requireLoad::envFileExistsMissingApiKey { #@test + mkdir -p "${HOME}/.bash-tools" + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + sed -i -E -e 's/^POSTMAN_API_KEY=//' "${HOME}/.bash-tools/.env" + local status=0 + BashTools::Conf::requireLoad >"${BATS_TEST_TMPDIR}/result" 2>&1 || status=$? + [[ "${status}" = "0" ]] + run cat "${BATS_TEST_TMPDIR}/result" + assert_output "" + [[ "$(grep '# Postman Parameters' "${HOME}/.bash-tools/.env" | wc -l)" = "2" ]] + [[ "${POSTMAN_API_KEY}" = "" ]] +} + +function BashTools::Conf::requireLoad::envFileImpossibleToLoad { #@test + mkdir -p "${HOME}/.bash-tools" + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + echo "return 12" >>"${HOME}/.bash-tools/.env" + run BashTools::Conf::requireLoad 2>&1 + assert_failure 1 + assert_output "ERROR - impossible to load '${HOME}/.bash-tools/.env'" +} diff --git a/src/BashTools/Conf/requireLoad.sh b/src/BashTools/Conf/requireLoad.sh new file mode 100755 index 00000000..9493ee08 --- /dev/null +++ b/src/BashTools/Conf/requireLoad.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +.INCLUDE "${BASH_TOOLS_ROOT_DIR}/conf/.env" +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} diff --git a/src/Postman/Collection/getCollectionIdByName.bats b/src/Postman/Collection/getCollectionIdByName.bats new file mode 100755 index 00000000..8a375b3b --- /dev/null +++ b/src/Postman/Collection/getCollectionIdByName.bats @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/Collection/getCollectionIdByName.sh +source "${rootDir}/src/Postman/Collection/getCollectionIdByName.sh" + +setup() { + export BASH_FRAMEWORK_THEME="noColor" +} + +function Postman::Collection::getCollectionIdByName::githubBasic { #@test + run Postman::Collection::getCollectionIdByName \ + "${BATS_TEST_DIRNAME}/testsData/postmanCollections.json" \ + "GitHub API - 1. Basic (no Auth)" + assert_output "b47cdd04-f4ea-4a96-8735-90efa20fee2d" + assert_lines_count 1 + assert_success +} + +function Postman::Collection::getCollectionIdByName::unknownName { #@test + run Postman::Collection::getCollectionIdByName \ + "${BATS_TEST_DIRNAME}/testsData/postmanCollections.json" \ + "Unknown API" + assert_output "WARN - collection name 'Unknown API' not found in '${BATS_TEST_DIRNAME}/testsData/postmanCollections.json'" + assert_lines_count 1 + assert_failure 2 +} + +function Postman::Collection::getCollectionIdByName::duplicatedName { #@test + run Postman::Collection::getCollectionIdByName \ + "${BATS_TEST_DIRNAME}/testsData/postmanCollections.json" \ + "GitHub API - 2. Advanced (with Auth)" + assert_output "ERROR - More than one collection match the collection name 'GitHub API - 2. Advanced (with Auth)', please clean up your postman workspace" + assert_lines_count 1 + assert_failure 3 +} + +function Postman::Collection::getCollectionIdByName::fileNotFound { #@test + run Postman::Collection::getCollectionIdByName \ + "${BATS_TEST_DIRNAME}/testsData/fileNotFound.json" \ + "GitHub API - 1. Basic (no Auth)" + assert_output --partial "ERROR - Error while parsing '${BATS_TEST_DIRNAME}/testsData/fileNotFound.json' - error code 1" + assert_lines_count 1 + assert_failure 1 +} + +function Postman::Collection::getCollectionIdByName::invalidCollectionsFile { #@test + run Postman::Collection::getCollectionIdByName \ + "${BATS_TEST_DIRNAME}/testsData/postmanCollections_invalidFile.json" \ + "GitHub API - 1. Basic (no Auth)" + assert_output --partial "ERROR - Error while parsing '${BATS_TEST_DIRNAME}/testsData/postmanCollections_invalidFile.json' - error code 5 - jq: error (at " + assert_lines_count 1 + assert_failure 1 +} diff --git a/src/Postman/Collection/getCollectionIdByName.sh b/src/Postman/Collection/getCollectionIdByName.sh new file mode 100755 index 00000000..9dc5a24e --- /dev/null +++ b/src/Postman/Collection/getCollectionIdByName.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# @description retrieve the collection id +# associated to the given collection name +# from the postman collection file +# @arg $1 collectionFile:String +# @arg $2 collectionName:String +# @exitcode 1 if error while parsing the collection file +# @exitcode 2 if name not found +# @exitcode 3 if more than one collection matches that name +# @stderr details, on failure +# @stdout the collection id associated to a unique collection name +Postman::Collection::getCollectionIdByName() { + local collectionFile="$1" + local collectionName="$2" + local result + local errorCode="0" + result="$( + jq -cre --arg name "${collectionName}" \ + '.collections[] | select( .name == $name) | .id' 2>&1 <"${collectionFile}" + )" || errorCode="$?" + if [[ "${errorCode}" = "4" ]]; then + Log::displayWarning "collection name '${collectionName}' not found in '${collectionFile}'" + return 2 + elif [[ "${errorCode}" != "0" ]]; then + Log::displayError "Error while parsing '${collectionFile}' - error code ${errorCode} - ${result}" + return 1 + fi + if (($(wc -l <<<"${result}") > 1)); then + Log::displayError "More than one collection match the collection name '${collectionName}', please clean up your postman workspace" + return 3 + fi + echo "${result}" +} diff --git a/src/Postman/Collection/getName.bats b/src/Postman/Collection/getName.bats new file mode 100755 index 00000000..2e715224 --- /dev/null +++ b/src/Postman/Collection/getName.bats @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/Collection/getName.sh +source "${rootDir}/src/Postman/Collection/getName.sh" + +function Postman::Collection::getName::simple { #@test + run Postman::Collection::getName \ + "${BATS_TEST_DIRNAME}/testsData/githubBasic_collection.json" + assert_output "GitHub API - 1. Basic (no Auth)" + assert_lines_count 1 + assert_success +} + +function Postman::Collection::getName::invalidJsonFile { #@test + run Postman::Collection::getName \ + "${BATS_TEST_DIRNAME}/testsData/postmanCollections_invalidJsonFile.json" 2>&1 + assert_lines_count 2 + assert_line --index 0 'jq: error (at :2): Cannot index string with string "info"' + assert_line --index 1 "parse error: Expected string key before ':' at line 2, column 16" + assert_failure 4 +} + +function Postman::Collection::getName::invalidFile { #@test + run Postman::Collection::getName \ + "${BATS_TEST_DIRNAME}/testsData/postmanCollections_invalidFile.json" + assert_output "null" + assert_failure 1 +} diff --git a/src/Postman/Collection/getName.sh b/src/Postman/Collection/getName.sh new file mode 100755 index 00000000..45173a83 --- /dev/null +++ b/src/Postman/Collection/getName.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# @description retrieve the name of the collection file +# from the postman collection file +# @arg $1 collectionFile:String +# @exitcode 1 if error while parsing the collection file +# @exitcode * jq exit code, 4 for invalid file +# @stdout the collection name of the collection file +Postman::Collection::getName() { + local collectionFile="$1" + jq -cre '.info.name' <"${collectionFile}" +} diff --git a/src/Postman/Collection/testsData/githubBasic_collection.json b/src/Postman/Collection/testsData/githubBasic_collection.json new file mode 100644 index 00000000..45a72655 --- /dev/null +++ b/src/Postman/Collection/testsData/githubBasic_collection.json @@ -0,0 +1,112 @@ +{ + "info": { + "_postman_id": "b47cdd04-f4ea-4a96-8735-90efa20fee2d", + "name": "GitHub API - 1. Basic (no Auth)", + "description": "### What is GitHub?\n\n[GitHub](https://github.com/) is a popular code version control platform that over 73 million developers worldwide trust to organize their code bases.\n\nWhile you can interact with GitHub by clicking around their website, you can also interact with GitHub programmatically using their API. \n \nThis collection shows just a few of the many actions you can perform using the [GitHub REST API](https://docs.github.com/en/rest).\n\n### What is a repo?\n\nShort for \"repository\", a repo is simply a place where code is stored. You can think of a repo like a project folder.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "updatedAt": "2024-01-04T11:47:40.000Z", + "uid": "27246549-b47cdd04-f4ea-4a96-8735-90efa20fee2d", + "createdAt": "2024-01-02T23:37:53.000Z", + "lastUpdatedBy": "27246549" + }, + "item": [ + { + "name": "search repos", + "id": "a84e7139-cff4-4cb0-a2b5-cddd286c185e", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/search/repositories?q=postman&order=desc&per_page=30", + "host": ["{{baseUrl}}"], + "path": ["search", "repositories"], + "query": [ + { + "key": "q", + "value": "postman" + }, + { + "key": "order", + "value": "desc" + }, + { + "key": "per_page", + "value": "30" + } + ] + }, + "description": "Searches repositories based on keywords `q`" + }, + "response": [], + "uid": "27246549-a84e7139-cff4-4cb0-a2b5-cddd286c185e" + }, + { + "name": "user info", + "id": "d97527a0-a93f-4146-a4ae-955c9f579838", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/users/:owner", + "host": ["{{baseUrl}}"], + "path": ["users", ":owner"], + "variable": [ + { + "key": "owner", + "value": "octocat", + "description": "username or organization name you would like information about" + } + ] + }, + "description": "Get information about the given user. \n\nMore detailed information is given if the requested user is the currently authorized user." + }, + "response": [], + "uid": "27246549-d97527a0-a93f-4146-a4ae-955c9f579838" + }, + { + "name": "user repos", + "id": "d54b66aa-77d6-45ae-acbd-b81592eefc0f", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/users/:owner/repos", + "host": ["{{baseUrl}}"], + "path": ["users", ":owner", "repos"], + "variable": [ + { + "key": "owner", + "value": "octocat", + "description": "username or organization name whose repos you would like to see" + } + ] + }, + "description": "Lists all public repos for a given user" + }, + "response": [], + "uid": "27246549-d54b66aa-77d6-45ae-acbd-b81592eefc0f" + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [""] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [""] + } + } + ], + "variable": [ + { + "key": "baseUrl", + "value": "https://api.github.com" + } + ] +} diff --git a/src/Postman/Collection/testsData/postmanCollections.json b/src/Postman/Collection/testsData/postmanCollections.json new file mode 100644 index 00000000..41d4dda3 --- /dev/null +++ b/src/Postman/Collection/testsData/postmanCollections.json @@ -0,0 +1,31 @@ +{ + "collections": [ + { + "id": "b47cdd04-f4ea-4a96-8735-90efa20fee2d", + "name": "GitHub API - 1. Basic (no Auth)", + "owner": "27246549", + "createdAt": "2024-01-02T23:37:53.000Z", + "updatedAt": "2024-01-04T11:47:40.000Z", + "uid": "27246549-b47cdd04-f4ea-4a96-8735-90efa20fee2d", + "isPublic": false + }, + { + "id": "758f8445-f82c-482c-a8a4-87f3e2f6566d", + "name": "GitHub API - 2. Advanced (with Auth)", + "owner": "27246549", + "createdAt": "2024-01-02T23:37:51.000Z", + "updatedAt": "2024-01-04T11:47:38.000Z", + "uid": "27246549-758f8445-f82c-482c-a8a4-87f3e2f6566d", + "isPublic": false + }, + { + "id": "758f8445-f82c-482c-a8a4-87f3e2f6566d", + "name": "GitHub API - 2. Advanced (with Auth)", + "owner": "27246549", + "createdAt": "2024-01-02T23:37:51.000Z", + "updatedAt": "2024-01-04T11:47:38.000Z", + "uid": "27246549-758f8445-f82c-482c-a8a4-87f3e2f6566d", + "isPublic": false + } + ] +} diff --git a/src/Postman/Collection/testsData/postmanCollections_invalidFile.json b/src/Postman/Collection/testsData/postmanCollections_invalidFile.json new file mode 100644 index 00000000..f679307a --- /dev/null +++ b/src/Postman/Collection/testsData/postmanCollections_invalidFile.json @@ -0,0 +1,31 @@ +{ + "collectionsInvalid": [ + { + "id": "b47cdd04-f4ea-4a96-8735-90efa20fee2d", + "name": "GitHub API - 1. Basic (no Auth)", + "owner": "27246549", + "createdAt": "2024-01-02T23:37:53.000Z", + "updatedAt": "2024-01-04T11:47:40.000Z", + "uid": "27246549-b47cdd04-f4ea-4a96-8735-90efa20fee2d", + "isPublic": false + }, + { + "id": "758f8445-f82c-482c-a8a4-87f3e2f6566d", + "name": "GitHub API - 2. Advanced (with Auth)", + "owner": "27246549", + "createdAt": "2024-01-02T23:37:51.000Z", + "updatedAt": "2024-01-04T11:47:38.000Z", + "uid": "27246549-758f8445-f82c-482c-a8a4-87f3e2f6566d", + "isPublic": false + }, + { + "id": "758f8445-f82c-482c-a8a4-87f3e2f6566d", + "name": "GitHub API - 2. Advanced (with Auth)", + "owner": "27246549", + "createdAt": "2024-01-02T23:37:51.000Z", + "updatedAt": "2024-01-04T11:47:38.000Z", + "uid": "27246549-758f8445-f82c-482c-a8a4-87f3e2f6566d", + "isPublic": false + } + ] +} diff --git a/src/Postman/Collection/testsData/postmanCollections_invalidJsonFile.json b/src/Postman/Collection/testsData/postmanCollections_invalidJsonFile.json new file mode 100644 index 00000000..3450e3a5 --- /dev/null +++ b/src/Postman/Collection/testsData/postmanCollections_invalidJsonFile.json @@ -0,0 +1,31 @@ + + "collections": [ + { + "id": "b47cdd04-f4ea-4a96-8735-90efa20fee2d", + "name": "GitHub API - 1. Basic (no Auth)", + "owner": "27246549", + "createdAt": "2024-01-02T23:37:53.000Z", + "updatedAt": "2024-01-04T11:47:40.000Z", + "uid": "27246549-b47cdd04-f4ea-4a96-8735-90efa20fee2d", + "isPublic": false + }, + { + "id": "758f8445-f82c-482c-a8a4-87f3e2f6566d", + "name": "GitHub API - 2. Advanced (with Auth)", + "owner": "27246549", + "createdAt": "2024-01-02T23:37:51.000Z", + "updatedAt": "2024-01-04T11:47:38.000Z", + "uid": "27246549-758f8445-f82c-482c-a8a4-87f3e2f6566d", + "isPublic": false + }, + { + "id": "758f8445-f82c-482c-a8a4-87f3e2f6566d", + "name": "GitHub API - 2. Advanced (with Auth)", + "owner": "27246549", + "createdAt": "2024-01-02T23:37:51.000Z", + "updatedAt": "2024-01-04T11:47:38.000Z", + "uid": "27246549-758f8445-f82c-482c-a8a4-87f3e2f6566d", + "isPublic": false + } + ] +} diff --git a/src/Postman/Commands/forEachCollection.bats b/src/Postman/Commands/forEachCollection.bats new file mode 100755 index 00000000..609b92fa --- /dev/null +++ b/src/Postman/Commands/forEachCollection.bats @@ -0,0 +1,185 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/Commands/forEachCollection.sh +source "${rootDir}/src/Postman/Commands/forEachCollection.sh" + +setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + export HOME="${BATS_TEST_TMPDIR}/home" + export BASH_FRAMEWORK_DISPLAY_LEVEL="${__LEVEL_DEBUG}" +} + +teardown() { + unstub_all +} + +function Postman::Commands::forEachCollection::noRefsSpecified { #@test + callback() { + echo "$@" + } + run Postman::Commands::forEachCollection modelFile callback 2>&1 + assert_failure 2 + assert_output "" +} + +function Postman::Commands::forEachCollection::collectionRefNotExisting { #@test + callback() { + echo "$@" + } + Postman::checkApiKey() { + echo "$@" >"${BATS_TEST_TMPDIR}/checkApiKey" + } + Postman::api() { + case "$1" in + getCollections) + echo "collection" + ;; + *) + echo "error" + ;; + esac + } + Postman::Model::getCollectionFileByRef() { + echo "$@" >"${BATS_TEST_TMPDIR}/getCollectionFileByRef" + echo "collectionFile" + } + Postman::Collection::getName() { + echo "$@" >"${BATS_TEST_TMPDIR}/getName" + echo "collectionName" + } + Postman::Collection::getCollectionIdByName() { + ( + echo "$1" + echo "${@:2}" + ) >"${BATS_TEST_TMPDIR}/getCollectionIdByName" + echo postmanCollectionId + } + run Postman::Commands::forEachCollection modelFile callback ref1 2>&1 + assert_lines_count 5 + assert_line --index 0 --partial "DEBUG - Retrieving collections from postman in /tmp" + assert_line --index 1 "DEBUG - Retrieving collection file from collection reference ref1" + assert_line --index 2 "DEBUG - Retrieving collection name from collection file collectionFile" + assert_line --index 3 --regexp "DEBUG - Deducing postman collection id using /tmp/[^ ]+ and collection name 'collectionName" + assert_line --index 4 --regexp "modelFile /tmp/[^ ]+ ref1 collectionFile collectionName postmanCollectionId 0" + assert_success + run cat "${BATS_TEST_TMPDIR}/checkApiKey" + assert_output "${HOME}/.bash-tools/.env" + run cat "${BATS_TEST_TMPDIR}/getCollectionFileByRef" + assert_output "modelFile ref1" + run cat "${BATS_TEST_TMPDIR}/getName" + assert_output "collectionFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionIdByName" + assert_lines_count 2 + assert_line --index 0 --regexp "^/tmp/" + assert_line --index 1 "collectionName" +} + +function Postman::Commands::forEachCollection::collectionRefIsPulled { #@test + callback() { + echo "$@" + } + Postman::checkApiKey() { + echo "$@" >"${BATS_TEST_TMPDIR}/checkApiKey" + } + Postman::api() { + case "$1" in + getCollections) + echo "collection" + ;; + *) + echo "error" + ;; + esac + } + Postman::Model::getCollectionFileByRef() { + echo "$@" >"${BATS_TEST_TMPDIR}/getCollectionFileByRef" + echo "${BATS_TEST_TMPDIR}/collectionFile" + } + Postman::Collection::getName() { + echo "$@" >"${BATS_TEST_TMPDIR}/getName" + echo "collectionName" + } + Postman::Collection::getCollectionIdByName() { + ( + echo "$1" + echo "${@:2}" + ) >"${BATS_TEST_TMPDIR}/getCollectionIdByName" + echo "collectionId" + } + + run Postman::Commands::forEachCollection modelFile callback ref1 2>&1 + assert_lines_count 5 + assert_line --index 0 --partial "DEBUG - Retrieving collections from postman in /tmp" + assert_line --index 1 "DEBUG - Retrieving collection file from collection reference ref1" + assert_line --index 2 --partial "DEBUG - Retrieving collection name from collection file /tmp" + assert_line --index 3 --regexp "DEBUG - Deducing postman collection id using /tmp/[^ ]+ and collection name 'collectionName" + assert_line --index 4 --regexp "modelFile /tmp/[^ ]+ ref1 /tmp/.+/collectionFile collectionName collectionId 0" + assert_success + run cat "${BATS_TEST_TMPDIR}/checkApiKey" + assert_output "${HOME}/.bash-tools/.env" + run cat "${BATS_TEST_TMPDIR}/getCollectionFileByRef" + assert_output "modelFile ref1" + run cat "${BATS_TEST_TMPDIR}/getName" + assert_output "${BATS_TEST_TMPDIR}/collectionFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionIdByName" + assert_lines_count 2 + assert_line --index 0 --regexp "^/tmp/" + assert_line --index 1 "collectionName" +} + +function Postman::Commands::forEachCollection::errorOnFirstRef { #@test + callback() { + echo "$@" + return 1 + } + Postman::checkApiKey() { + echo "$@" >"${BATS_TEST_TMPDIR}/checkApiKey" + } + Postman::api() { + case "$1" in + getCollections) + echo "collection1" + echo "collection2" + ;; + *) + echo "error" + ;; + esac + } + Postman::Model::getCollectionFileByRef() { + echo "$@" >"${BATS_TEST_TMPDIR}/getCollectionFileByRef" + echo "${BATS_TEST_TMPDIR}/collectionFile" + } + Postman::Collection::getName() { + echo "$@" >"${BATS_TEST_TMPDIR}/getName" + echo "collectionName" + } + Postman::Collection::getCollectionIdByName() { + ( + echo "$1" + echo "${@:2}" + ) >"${BATS_TEST_TMPDIR}/getCollectionIdByName" + echo "collectionId" + } + + run Postman::Commands::forEachCollection modelFile callback ref1 2>&1 + assert_lines_count 5 + assert_line --index 0 --partial "DEBUG - Retrieving collections from postman in /tmp" + assert_line --index 1 "DEBUG - Retrieving collection file from collection reference ref1" + assert_line --index 2 --partial "DEBUG - Retrieving collection name from collection file /tmp" + assert_line --index 3 --regexp "DEBUG - Deducing postman collection id using /tmp/[^ ]+ and collection name 'collectionName" + assert_line --index 4 --regexp "modelFile /tmp/[^ ]+ ref1 /tmp/.+/collectionFile collectionName collectionId 0" + assert_failure 1 + run cat "${BATS_TEST_TMPDIR}/checkApiKey" + assert_output "${HOME}/.bash-tools/.env" + run cat "${BATS_TEST_TMPDIR}/getCollectionFileByRef" + assert_output "modelFile ref1" + run cat "${BATS_TEST_TMPDIR}/getName" + assert_output "${BATS_TEST_TMPDIR}/collectionFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionIdByName" + assert_lines_count 2 + assert_line --index 0 --regexp "^/tmp/" + assert_line --index 1 "collectionName" +} diff --git a/src/Postman/Commands/forEachCollection.sh b/src/Postman/Commands/forEachCollection.sh new file mode 100755 index 00000000..1403041a --- /dev/null +++ b/src/Postman/Commands/forEachCollection.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +# @description apply callback on each collection specified by modelFile +# #### callback arguments +# - modelFile +# - postmanCollectionsFile +# - collectionRef +# - collectionFile +# - collectionName +# - postmanCollectionId +# - postmanCollectionIdStatus +# @arg $1 modelFile:String model file containing the collections to be processed +# @arg $2 callback:Function callback to apply on each collection selected +# @arg $@ list of collection references to process (all if not provided) +# @stderr diagnostic logs +# @exitcode 2 if no refs specified +# @exitcode * if one of sub commands fails +Postman::Commands::forEachCollection() { + local modelFile="$1" + local callback="$2" + shift 2 || true + local -a refs=("$@") + + if ((${#refs[@]} == 0)); then + return 2 + fi + + Postman::checkApiKey "${HOME}/.bash-tools/.env" || return 1 + local postmanCollectionsFile + postmanCollectionsFile="$(Framework::createTempFile "postmanCollections")" + # shellcheck disable=SC2154 + Log::displayDebug "Retrieving collections from postman in ${postmanCollectionsFile}" + Postman::api getCollections >"${postmanCollectionsFile}" || return 1 + + local collectionRef + for collectionRef in "${refs[@]}"; do + local collectionFile collectionName postmanCollectionId + Log::displayDebug "Retrieving collection file from collection reference ${collectionRef}" + collectionFile="$(Postman::Model::getCollectionFileByRef "${modelFile}" "${collectionRef}")" + Log::displayDebug "Retrieving collection name from collection file ${collectionFile}" + collectionName="$(Postman::Collection::getName "${collectionFile}")" + Log::displayDebug "Deducing postman collection id using ${postmanCollectionsFile} and collection name '${collectionName}'" + local postmanCollectionIdStatus="0" + postmanCollectionId="$(Postman::Collection::getCollectionIdByName "${postmanCollectionsFile}" "${collectionName}")" || status=$? + local status=0 + "${callback}" \ + "${modelFile}" "${postmanCollectionsFile}" \ + "${collectionRef}" "${collectionFile}" "${collectionName}" \ + "${postmanCollectionId}" "${postmanCollectionIdStatus}" || status=$? + case "${status}" in + 2 | 0) continue ;; + *) return 1 ;; + esac + done +} diff --git a/src/Postman/Commands/pullCollections.bats b/src/Postman/Commands/pullCollections.bats new file mode 100755 index 00000000..89949192 --- /dev/null +++ b/src/Postman/Commands/pullCollections.bats @@ -0,0 +1,130 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/Commands/forEachCollection.sh +source "${rootDir}/src/Postman/Commands/forEachCollection.sh" +# shellcheck source=src/Postman/Commands/pullCollections.sh +source "${rootDir}/src/Postman/Commands/pullCollections.sh" + +setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + export HOME="${BATS_TEST_TMPDIR}/home" + export BASH_FRAMEWORK_DISPLAY_LEVEL="${__LEVEL_DEBUG}" +} + +teardown() { + unstub_all +} + +function Postman::Commands::pullCollections::noRefsSpecified { #@test + run Postman::Commands::pullCollections modelFile 2>&1 + assert_failure 2 + assert_output "" +} + +function Postman::Commands::pullCollections::collectionRefNotExisting { #@test + Postman::checkApiKey() { + echo "$@" >"${BATS_TEST_TMPDIR}/checkApiKey" + } + Postman::api() { + case "$1" in + getCollections) + echo "collection" + ;; + *) + echo "error" + ;; + esac + } + Postman::Model::getCollectionFileByRef() { + echo "$@" >"${BATS_TEST_TMPDIR}/getCollectionFileByRef" + echo "collectionFile" + } + Postman::Collection::getName() { + echo "$@" >"${BATS_TEST_TMPDIR}/getName" + echo "collectionName" + } + Postman::Collection::getCollectionIdByName() { + ( + echo "$1" + echo "${@:2}" + ) >"${BATS_TEST_TMPDIR}/getCollectionIdByName" + } + run Postman::Commands::pullCollections modelFile ref1 2>&1 + assert_lines_count 5 + assert_line --index 0 --partial "DEBUG - Retrieving collections from postman in /tmp" + assert_line --index 1 "DEBUG - Retrieving collection file from collection reference ref1" + assert_line --index 2 "DEBUG - Retrieving collection name from collection file collectionFile" + assert_line --index 3 --regexp "DEBUG - Deducing postman collection id using /tmp/[^ ]+ and collection name 'collectionName" + assert_line --index 4 "WARN - Collection 'ref1' - pull skipped as not existing in your postman workspace" + assert_success + run cat "${BATS_TEST_TMPDIR}/checkApiKey" + assert_output "${HOME}/.bash-tools/.env" + run cat "${BATS_TEST_TMPDIR}/getCollectionFileByRef" + assert_output "modelFile ref1" + run cat "${BATS_TEST_TMPDIR}/getName" + assert_output "collectionFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionIdByName" + assert_lines_count 2 + assert_line --index 0 --regexp "^/tmp/" + assert_line --index 1 "collectionName" +} + +function Postman::Commands::pullCollections::collectionRefIsPulled { #@test + Postman::checkApiKey() { + echo "$@" >"${BATS_TEST_TMPDIR}/checkApiKey" + } + Postman::api() { + case "$1" in + getCollections) + echo "collection" + ;; + pullCollection) + echo "collection pulled" + ;; + *) + echo "error" + ;; + esac + } + Postman::Model::getCollectionFileByRef() { + echo "$@" >"${BATS_TEST_TMPDIR}/getCollectionFileByRef" + echo "${BATS_TEST_TMPDIR}/collectionFile" + } + Postman::Collection::getName() { + echo "$@" >"${BATS_TEST_TMPDIR}/getName" + echo "collectionName" + } + Postman::Collection::getCollectionIdByName() { + ( + echo "$1" + echo "${@:2}" + ) >"${BATS_TEST_TMPDIR}/getCollectionIdByName" + echo "collectionId" + } + stub jq \ + '-cre .collection : echo "collection exported from postman"' + + run Postman::Commands::pullCollections modelFile ref1 2>&1 + assert_lines_count 6 + assert_line --index 0 --partial "DEBUG - Retrieving collections from postman in /tmp" + assert_line --index 1 "DEBUG - Retrieving collection file from collection reference ref1" + assert_line --index 2 --partial "DEBUG - Retrieving collection name from collection file /tmp" + assert_line --index 3 --regexp "DEBUG - Deducing postman collection id using /tmp/[^ ]+ and collection name 'collectionName" + assert_line --index 4 "INFO - Pulling collection ref1 with id collectionId from postman" + assert_line --index 5 --regexp "SUCCESS - Collection 'collectionName' has been pulled successfully to '/tmp/[^']+'" + assert_success + run cat "${BATS_TEST_TMPDIR}/checkApiKey" + assert_output "${HOME}/.bash-tools/.env" + run cat "${BATS_TEST_TMPDIR}/getCollectionFileByRef" + assert_output "modelFile ref1" + run cat "${BATS_TEST_TMPDIR}/getName" + assert_output "${BATS_TEST_TMPDIR}/collectionFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionIdByName" + assert_lines_count 2 + assert_line --index 0 --regexp "^/tmp/" + assert_line --index 1 "collectionName" + run cat "${BATS_TEST_TMPDIR}/collectionFile" + assert_output "collection exported from postman" +} diff --git a/src/Postman/Commands/pullCollections.sh b/src/Postman/Commands/pullCollections.sh new file mode 100755 index 00000000..06d69030 --- /dev/null +++ b/src/Postman/Commands/pullCollections.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# @description pull collections specified by modelFile +# @arg $1 modelFile:String model file containing the collections to be pulled +# @arg $@ list of collection references to pull (all if not provided) +# @stderr diagnostic logs +# @exitcode 2 if no refs specified +# @exitcode * if one of sub commands fails +Postman::Commands::pullCollections() { + local modelFile="$1" + shift || true + + # shellcheck disable=SC2317 + pullCollectionsCallback() { + local modelFile="$1" + # local postmanCollectionsFile="$2" + local collectionRef="$3" + local collectionFile="$4" + local collectionName="$5" + local postmanCollectionId="$6" + local postmanCollectionIdStatus="$7" + case "${postmanCollectionIdStatus}" in + 0) ;; # success, next statement will pull the collection + 2) return 2 ;; # name not found + 3) return 2 ;; # more than one collection + *) return 1 ;; # error parsing collection file from postman, stop + esac + if [[ -z "${postmanCollectionId}" ]]; then + Log::displayWarning "Collection '${collectionRef}' - pull skipped as not existing in your postman workspace" + else + local response + local statusCode="0" + Log::displayInfo "Pulling collection ${collectionRef} with id ${postmanCollectionId} from postman" + response="$(Postman::api pullCollection "${postmanCollectionId}" | jq -cre '.collection')" || statusCode=$? + if [[ "${statusCode}" = "0" ]]; then + echo "${response}" >"${collectionFile}" + Log::displaySuccess "Collection '${collectionName}' has been pulled successfully to '${collectionFile}'" + else + Log::displayError "Collection '${collectionName}' an error occured pulling the collection from postman" + fi + fi + } + Postman::Commands::forEachCollection "${modelFile}" pullCollectionsCallback "$@" +} diff --git a/src/Postman/Commands/pullCommand.bats b/src/Postman/Commands/pullCommand.bats new file mode 100755 index 00000000..60698a77 --- /dev/null +++ b/src/Postman/Commands/pullCommand.bats @@ -0,0 +1,138 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/Commands/pullCommand.sh +source "${rootDir}/src/Postman/Commands/pullCommand.sh" + +function Postman::Commands::pullCommand::modelFileDoesNotExists { #@test + Postman::Model::validate() { + echo "$@" >"${BATS_TEST_TMPDIR}/output" + return 12 + } + run Postman::Commands::pullCommand modelFile 2>&1 + assert_failure 1 + assert_output "" + run cat "${BATS_TEST_TMPDIR}/output" + assert_output "modelFile pull" +} + +function Postman::Commands::pullCommand::getCollectionRefsFails { #@test + Postman::Model::validate() { + echo "$1" >"${BATS_TEST_TMPDIR}/validate" + return 0 + } + Postman::Model::getCollectionRefs() { + local modelFile="$1" + local -n getCollectionRefs=$2 + ( + echo "${modelFile}" + declare -p "${!getCollectionRefs}" + ) >"${BATS_TEST_TMPDIR}/getCollectionRefs" + return 11 + } + run Postman::Commands::pullCommand modelFile 2>&1 + assert_failure 1 + assert_output "" + run cat "${BATS_TEST_TMPDIR}/validate" + assert_output "modelFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionRefs" + assert_lines_count 2 + assert_line --index 0 "modelFile" + assert_line --index 1 "declare -a refs" +} + +function Postman::Commands::pullCommand::checkIfValidCollectionRefsFails { #@test + Postman::Model::validate() { + echo "$1" >"${BATS_TEST_TMPDIR}/validate" + return 0 + } + Postman::Model::getCollectionRefs() { + local modelFile="$1" + local -n getCollectionRefs=$2 + ( + echo "${modelFile}" + declare -p "${!getCollectionRefs}" + ) >"${BATS_TEST_TMPDIR}/getCollectionRefs" + } + Postman::Model::checkIfValidCollectionRefs() { + local modelFile="$1" + local -n getCollectionRefs=$2 + shift 2 || true + ( + echo "${modelFile}" + declare -p "${!getCollectionRefs}" + echo "$@" + ) >"${BATS_TEST_TMPDIR}/checkIfValidCollectionRefs" + return 10 + } + run Postman::Commands::pullCommand modelFile ref1 ref2 2>&1 + assert_failure 1 + assert_output "" + run cat "${BATS_TEST_TMPDIR}/validate" + assert_output "modelFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionRefs" + assert_lines_count 2 + assert_line --index 0 "modelFile" + assert_line --index 1 "declare -a refs" + run cat "${BATS_TEST_TMPDIR}/checkIfValidCollectionRefs" + assert_lines_count 3 + assert_line --index 0 "modelFile" + assert_line --index 1 "declare -a refs" + assert_line --index 2 "ref1 ref2" +} + +function Postman::Commands::pullCommand::getCollectionRefsEmpty { #@test + Postman::Model::validate() { + echo "$1" >"${BATS_TEST_TMPDIR}/validate" + return 0 + } + Postman::Model::getCollectionRefs() { + local modelFile="$1" + local -n getCollectionRefs=$2 + ( + echo "${modelFile}" + declare -p "${!getCollectionRefs}" + ) >"${BATS_TEST_TMPDIR}/getCollectionRefs" + } + run Postman::Commands::pullCommand modelFile 2>&1 + assert_failure 1 + assert_output "ERROR - No collection refs to pull" + run cat "${BATS_TEST_TMPDIR}/validate" + assert_output "modelFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionRefs" + assert_lines_count 2 + assert_line --index 0 "modelFile" + assert_line --index 1 "declare -a refs" +} + +function Postman::Commands::pullCommand::pullCollections { #@test + Postman::Model::validate() { + echo "$1" >"${BATS_TEST_TMPDIR}/validate" + return 0 + } + Postman::Model::getCollectionRefs() { + local modelFile="$1" + local -n getCollectionRefs=$2 + ( + echo "${modelFile}" + declare -p "${!getCollectionRefs}" + ) >"${BATS_TEST_TMPDIR}/getCollectionRefs" + getCollectionRefs=(ref1 ref2) + } + Postman::Commands::pullCollections() { + echo "$@" >"${BATS_TEST_TMPDIR}/pullCollections" + } + export BASH_FRAMEWORK_DISPLAY_LEVEL="${__LEVEL_DEBUG}" + run Postman::Commands::pullCommand modelFile 2>&1 + assert_success + assert_output "DEBUG - Collection refs to pull ref1 ref2" + run cat "${BATS_TEST_TMPDIR}/validate" + assert_output "modelFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionRefs" + assert_lines_count 2 + assert_line --index 0 "modelFile" + assert_line --index 1 "declare -a refs" + run cat "${BATS_TEST_TMPDIR}/pullCollections" + assert_output "modelFile ref1 ref2" +} diff --git a/src/Postman/Commands/pullCommand.sh b/src/Postman/Commands/pullCommand.sh new file mode 100755 index 00000000..139e91ec --- /dev/null +++ b/src/Postman/Commands/pullCommand.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# @description validate arguments before calling Postman::Commands::pullCollections +# @arg $1 modelFile:String model file containing the collections to be pulled +# @arg $@ list of collection references to pull (all if not provided) +# @stderr diagnostic logs +# @exitcode * if one of sub commands fails +Postman::Commands::pullCommand() { + local modelFile="$1" + shift || true + + Postman::Model::validate "${modelFile}" "pull" || return 1 + + local -a refs + # shellcheck disable=SC2154 + Postman::Model::getCollectionRefs "${modelFile}" refs || return 1 + if (($# > 0)); then + # shellcheck disable=SC2154 + Postman::Model::checkIfValidCollectionRefs "${modelFile}" refs "$@" || return 1 + refs=("$@") + fi + + if ((${#refs} == 0)); then + Log::displayError "No collection refs to pull" + return 1 + else + Log::displayDebug "Collection refs to pull ${refs[*]}" + Postman::Commands::pullCollections "${modelFile}" "${refs[@]}" || return 1 + fi +} diff --git a/src/Postman/Commands/pushCollections.bats b/src/Postman/Commands/pushCollections.bats new file mode 100755 index 00000000..549451ac --- /dev/null +++ b/src/Postman/Commands/pushCollections.bats @@ -0,0 +1,132 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/Commands/forEachCollection.sh +source "${rootDir}/src/Postman/Commands/forEachCollection.sh" +# shellcheck source=src/Postman/Commands/pushCollections.sh +source "${rootDir}/src/Postman/Commands/pushCollections.sh" + +setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + export HOME="${BATS_TEST_TMPDIR}/home" + export BASH_FRAMEWORK_DISPLAY_LEVEL="${__LEVEL_DEBUG}" +} + +teardown() { + unstub_all +} + +function Postman::Commands::pushCollections::noRefsSpecified { #@test + run Postman::Commands::pushCollections modelFile 2>&1 + assert_failure 2 + assert_output "" +} + +function Postman::Commands::pushCollections::collectionRefCreate { #@test + Postman::checkApiKey() { + echo "$@" >"${BATS_TEST_TMPDIR}/checkApiKey" + } + Postman::api() { + case "$1" in + getCollections) + echo "collection" + ;; + createCollectionFromFile) + echo "createCollectionFromFile" + ;; + *) + echo "error" + ;; + esac + } + Postman::Model::getCollectionFileByRef() { + echo "$@" >"${BATS_TEST_TMPDIR}/getCollectionFileByRef" + echo "collectionFile" + } + Postman::Collection::getName() { + echo "$@" >"${BATS_TEST_TMPDIR}/getName" + echo "collectionName" + } + Postman::Collection::getCollectionIdByName() { + ( + echo "$1" + echo "${@:2}" + ) >"${BATS_TEST_TMPDIR}/getCollectionIdByName" + } + run Postman::Commands::pushCollections modelFile ref1 2>&1 + assert_lines_count 7 + assert_line --index 0 --partial "DEBUG - Retrieving collections from postman in /tmp" + assert_line --index 1 "DEBUG - Retrieving collection file from collection reference ref1" + assert_line --index 2 "DEBUG - Retrieving collection name from collection file collectionFile" + assert_line --index 3 --regexp "DEBUG - Deducing postman collection id using /tmp/[^ ]+ and collection name 'collectionName" + assert_line --index 4 "INFO - Creating collection 'ref1'" + assert_line --index 5 "createCollectionFromFile" + assert_line --index 6 "SUCCESS - collection 'ref1' has been created successfully" + assert_success + run cat "${BATS_TEST_TMPDIR}/checkApiKey" + assert_output "${HOME}/.bash-tools/.env" + run cat "${BATS_TEST_TMPDIR}/getCollectionFileByRef" + assert_output "modelFile ref1" + run cat "${BATS_TEST_TMPDIR}/getName" + assert_output "collectionFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionIdByName" + assert_lines_count 2 + assert_line --index 0 --regexp "^/tmp/" + assert_line --index 1 "collectionName" +} + +function Postman::Commands::pushCollections::collectionRefUpdate { #@test + Postman::checkApiKey() { + echo "$@" >"${BATS_TEST_TMPDIR}/checkApiKey" + } + Postman::api() { + case "$1" in + getCollections) + echo "collection" + ;; + updateCollectionFromFile) + echo "updateCollectionFromFile" + ;; + *) + echo "error" + ;; + esac + } + Postman::Model::getCollectionFileByRef() { + echo "$@" >"${BATS_TEST_TMPDIR}/getCollectionFileByRef" + echo "collectionFile" + } + Postman::Collection::getName() { + echo "$@" >"${BATS_TEST_TMPDIR}/getName" + echo "collectionName" + } + Postman::Collection::getCollectionIdByName() { + ( + echo "$1" + echo "${@:2}" + ) >"${BATS_TEST_TMPDIR}/getCollectionIdByName" + echo "collectionId" + } + + run Postman::Commands::pushCollections modelFile ref1 2>&1 + assert_lines_count 7 + assert_line --index 0 --partial "DEBUG - Retrieving collections from postman in /tmp" + assert_line --index 1 "DEBUG - Retrieving collection file from collection reference ref1" + assert_line --index 2 "DEBUG - Retrieving collection name from collection file collectionFile" + assert_line --index 3 --regexp "DEBUG - Deducing postman collection id using /tmp/[^ ]+ and collection name 'collectionName" + assert_line --index 4 "INFO - Updating collection 'ref1' with id 'collectionId'" + assert_line --index 5 "updateCollectionFromFile" + assert_line --index 6 "SUCCESS - collection 'ref1' has been updated successfully" + assert_success + run cat "${BATS_TEST_TMPDIR}/checkApiKey" + assert_output "${HOME}/.bash-tools/.env" + run cat "${BATS_TEST_TMPDIR}/getCollectionFileByRef" + assert_output "modelFile ref1" + run cat "${BATS_TEST_TMPDIR}/getName" + assert_output "collectionFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionIdByName" + assert_lines_count 2 + assert_line --index 0 --regexp "^/tmp/" + assert_line --index 1 "collectionName" +} diff --git a/src/Postman/Commands/pushCollections.sh b/src/Postman/Commands/pushCollections.sh new file mode 100755 index 00000000..ac1dd3ec --- /dev/null +++ b/src/Postman/Commands/pushCollections.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# @description push collections specified by modelFile +# @arg $1 modelFile:String model file containing the collections to be pushed +# @arg $@ list of collection references to push (all if not provided) +# @stderr diagnostic logs +# @exitcode 2 if no refs specified +# @exitcode * if one of sub commands fails +Postman::Commands::pushCollections() { + local modelFile="$1" + shift || true + + # shellcheck disable=SC2317 + pushCollectionsCallback() { + local modelFile="$1" + # local postmanCollectionsFile="$2" + local collectionRef="$3" + local collectionFile="$4" + #local collectionName="$5" + local postmanCollectionId="$6" + local postmanCollectionIdStatus="$7" + case "${postmanCollectionIdStatus}" in + 0) ;; # success, next statement will update the collection + 2) ;; # name not found, next statement will create the collection + 3) return 2 ;; # more than one collection + *) return 1 ;; # error parsing collection file from postman, stop + esac + + if [[ -z "${postmanCollectionId}" ]]; then + Log::displayInfo "Creating collection '${collectionRef}'" + Postman::api createCollectionFromFile "${collectionFile}" + Log::displaySuccess "collection '${collectionRef}' has been created successfully" + else + Log::displayInfo "Updating collection '${collectionRef}' with id '${postmanCollectionId}'" + Postman::api updateCollectionFromFile "${collectionFile}" "${postmanCollectionId}" + Log::displaySuccess "collection '${collectionRef}' has been updated successfully" + fi + } + + Postman::Commands::forEachCollection "${modelFile}" pushCollectionsCallback "$@" +} diff --git a/src/Postman/Commands/pushCommand.bats b/src/Postman/Commands/pushCommand.bats new file mode 100755 index 00000000..a1ce405b --- /dev/null +++ b/src/Postman/Commands/pushCommand.bats @@ -0,0 +1,138 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/Commands/pushCommand.sh +source "${rootDir}/src/Postman/Commands/pushCommand.sh" + +function Postman::Commands::pushCommand::modelFileDoesNotExists { #@test + Postman::Model::validate() { + echo "$@" >"${BATS_TEST_TMPDIR}/output" + return 12 + } + run Postman::Commands::pushCommand modelFile 2>&1 + assert_failure 1 + assert_output "" + run cat "${BATS_TEST_TMPDIR}/output" + assert_output "modelFile push" +} + +function Postman::Commands::pushCommand::getCollectionRefsFails { #@test + Postman::Model::validate() { + echo "$1" >"${BATS_TEST_TMPDIR}/validate" + return 0 + } + Postman::Model::getCollectionRefs() { + local modelFile="$1" + local -n getCollectionRefs=$2 + ( + echo "${modelFile}" + declare -p "${!getCollectionRefs}" + ) >"${BATS_TEST_TMPDIR}/getCollectionRefs" + return 11 + } + run Postman::Commands::pushCommand modelFile 2>&1 + assert_failure 1 + assert_output "" + run cat "${BATS_TEST_TMPDIR}/validate" + assert_output "modelFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionRefs" + assert_lines_count 2 + assert_line --index 0 "modelFile" + assert_line --index 1 "declare -a refs" +} + +function Postman::Commands::pushCommand::checkIfValidCollectionRefsFails { #@test + Postman::Model::validate() { + echo "$1" >"${BATS_TEST_TMPDIR}/validate" + return 0 + } + Postman::Model::getCollectionRefs() { + local modelFile="$1" + local -n getCollectionRefs=$2 + ( + echo "${modelFile}" + declare -p "${!getCollectionRefs}" + ) >"${BATS_TEST_TMPDIR}/getCollectionRefs" + } + Postman::Model::checkIfValidCollectionRefs() { + local modelFile="$1" + local -n getCollectionRefs=$2 + shift 2 || true + ( + echo "${modelFile}" + declare -p "${!getCollectionRefs}" + echo "$@" + ) >"${BATS_TEST_TMPDIR}/checkIfValidCollectionRefs" + return 10 + } + run Postman::Commands::pushCommand modelFile ref1 ref2 2>&1 + assert_failure 1 + assert_output "" + run cat "${BATS_TEST_TMPDIR}/validate" + assert_output "modelFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionRefs" + assert_lines_count 2 + assert_line --index 0 "modelFile" + assert_line --index 1 "declare -a refs" + run cat "${BATS_TEST_TMPDIR}/checkIfValidCollectionRefs" + assert_lines_count 3 + assert_line --index 0 "modelFile" + assert_line --index 1 "declare -a refs" + assert_line --index 2 "ref1 ref2" +} + +function Postman::Commands::pushCommand::getCollectionRefsEmpty { #@test + Postman::Model::validate() { + echo "$1" >"${BATS_TEST_TMPDIR}/validate" + return 0 + } + Postman::Model::getCollectionRefs() { + local modelFile="$1" + local -n getCollectionRefs=$2 + ( + echo "${modelFile}" + declare -p "${!getCollectionRefs}" + ) >"${BATS_TEST_TMPDIR}/getCollectionRefs" + } + run Postman::Commands::pushCommand modelFile 2>&1 + assert_failure 1 + assert_output "ERROR - No collection refs to push" + run cat "${BATS_TEST_TMPDIR}/validate" + assert_output "modelFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionRefs" + assert_lines_count 2 + assert_line --index 0 "modelFile" + assert_line --index 1 "declare -a refs" +} + +function Postman::Commands::pushCommand::pushCollections { #@test + Postman::Model::validate() { + echo "$1" >"${BATS_TEST_TMPDIR}/validate" + return 0 + } + Postman::Model::getCollectionRefs() { + local modelFile="$1" + local -n getCollectionRefs=$2 + ( + echo "${modelFile}" + declare -p "${!getCollectionRefs}" + ) >"${BATS_TEST_TMPDIR}/getCollectionRefs" + getCollectionRefs=(ref1 ref2) + } + Postman::Commands::pushCollections() { + echo "$@" >"${BATS_TEST_TMPDIR}/pushCollections" + } + export BASH_FRAMEWORK_DISPLAY_LEVEL="${__LEVEL_DEBUG}" + run Postman::Commands::pushCommand modelFile 2>&1 + assert_success + assert_output "DEBUG - Collection refs to push ref1 ref2" + run cat "${BATS_TEST_TMPDIR}/validate" + assert_output "modelFile" + run cat "${BATS_TEST_TMPDIR}/getCollectionRefs" + assert_lines_count 2 + assert_line --index 0 "modelFile" + assert_line --index 1 "declare -a refs" + run cat "${BATS_TEST_TMPDIR}/pushCollections" + assert_output "modelFile ref1 ref2" +} diff --git a/src/Postman/Commands/pushCommand.sh b/src/Postman/Commands/pushCommand.sh new file mode 100755 index 00000000..204b9096 --- /dev/null +++ b/src/Postman/Commands/pushCommand.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# @description validate arguments before calling Postman::Commands::pushCollections +# @arg $1 modelFile:String model file containing the collections to be pushed +# @arg $@ list of collection references to push (all if not provided) +# @stderr diagnostic logs +# @exitcode * if one of sub commands fails +Postman::Commands::pushCommand() { + local modelFile="$1" + shift || true + + Postman::Model::validate "${modelFile}" "push" || return 1 + + local -a refs + # shellcheck disable=SC2154 + Postman::Model::getCollectionRefs "${modelFile}" refs || return 1 + if (($# > 0)); then + # shellcheck disable=SC2154 + Postman::Model::checkIfValidCollectionRefs "${modelFile}" refs "$@" || return 1 + refs=("$@") + fi + + if ((${#refs} == 0)); then + Log::displayError "No collection refs to push" + return 1 + else + Log::displayDebug "Collection refs to push ${refs[*]}" + Postman::Commands::pushCollections "${modelFile}" "${refs[@]}" || return 1 + fi +} diff --git a/src/Postman/Model/checkIfValidCollectionRefs.bats b/src/Postman/Model/checkIfValidCollectionRefs.bats new file mode 100755 index 00000000..d6f3e317 --- /dev/null +++ b/src/Postman/Model/checkIfValidCollectionRefs.bats @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=vendor/bash-tools-framework/src/Array/contains.sh +source "${FRAMEWORK_ROOT_DIR}/src/Array/contains.sh" +# shellcheck source=src/Postman/Model/checkIfValidCollectionRefs.sh +source "${rootDir}/src/Postman/Model/checkIfValidCollectionRefs.sh" + +setup() { + export BASH_FRAMEWORK_THEME="noColor" +} + +function Postman::Model::checkIfValidCollectionRefs::noArgs { #@test + local -a myRefs=(ref1 ref2) + run Postman::Model::checkIfValidCollectionRefs \ + "${BATS_TEST_DIRNAME}/testsData/getCollectionRefs.json" \ + myRefs + assert_output "" + assert_success +} + +function Postman::Model::checkIfValidCollectionRefs::firstRefInvalid { #@test + local -a myRefs=(ref1 ref2) + run Postman::Model::checkIfValidCollectionRefs \ + "${BATS_TEST_DIRNAME}/testsData/getCollectionRefs.json" \ + myRefs invalidRef ref2 + assert_output "ERROR - Collection ref 'invalidRef' is not known in '${BATS_TEST_DIRNAME}/testsData/getCollectionRefs.json'" + assert_lines_count 1 + assert_failure 1 +} + +function Postman::Model::checkIfValidCollectionRefs::secondRefInvalid { #@test + local -a myRefs=(ref1 ref2) + run Postman::Model::checkIfValidCollectionRefs \ + "${BATS_TEST_DIRNAME}/testsData/getCollectionRefs.json" \ + myRefs ref1 invalidRef + assert_output "ERROR - Collection ref 'invalidRef' is not known in '${BATS_TEST_DIRNAME}/testsData/getCollectionRefs.json'" + assert_lines_count 1 + assert_failure 1 +} diff --git a/src/Postman/Model/checkIfValidCollectionRefs.sh b/src/Postman/Model/checkIfValidCollectionRefs.sh new file mode 100755 index 00000000..778a08b3 --- /dev/null +++ b/src/Postman/Model/checkIfValidCollectionRefs.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# @description check that each collection references passed as parameter +# exists in the model file +# @arg $1 modelFile:String model file in which availableRefs have been retrieved +# @arg $2 availableRefs:&String[] list of known collection references +# @arg $3 modelCollectionRefs:&String[] list ofcollection references to check +Postman::Model::checkIfValidCollectionRefs() { + local modelFile="$1" + local -n availableRefs=$2 + shift 2 || true + local -a modelCollectionRefs=("$@") + + # shellcheck disable=SC2154 + Log::displayDebug "Checking collection refs using config ${modelFile}" + + local ref + for ref in "${modelCollectionRefs[@]}"; do + if ! Array::contains "${ref}" "${availableRefs[@]}"; then + Log::displayError "Collection ref '${ref}' is not known in '${modelFile}'" + return 1 + fi + done +} diff --git a/src/Postman/Model/getCollectionFileByRef.bats b/src/Postman/Model/getCollectionFileByRef.bats new file mode 100755 index 00000000..26193945 --- /dev/null +++ b/src/Postman/Model/getCollectionFileByRef.bats @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/Model/getCollectionFileByRef.sh +source "${rootDir}/src/Postman/Model/getCollectionFileByRef.sh" + +function Postman::Model::getCollectionFileByRef::githubBasic { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "dir" + } + run Postman::Model::getCollectionFileByRef \ + "${BATS_TEST_DIRNAME}/testsData/getCollectionRefs.json" \ + githubBasic + assert_output "dir/GithubAPI/githubBasic.json" + assert_success +} + +function Postman::Model::getCollectionFileByRef::unknownRef { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "Postman::Model::getRelativeConfigDirectory shouldn't have been called" + return 1 + } + run Postman::Model::getCollectionFileByRef \ + "${BATS_TEST_DIRNAME}/testsData/getCollectionRefs.json" \ + unknownRef + assert_output "" + assert_failure 1 +} diff --git a/src/Postman/Model/getCollectionFileByRef.sh b/src/Postman/Model/getCollectionFileByRef.sh new file mode 100755 index 00000000..1835f273 --- /dev/null +++ b/src/Postman/Model/getCollectionFileByRef.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# @description retrieve the file associated to the collection ref +# @arg $1 configFile:String the config file to parse +# @arg $2 ref:String the collection reference to get +# @stdout the file relative to current execution directory +# @exitcode 1 - if jq parsing error, file not found or any other error +Postman::Model::getCollectionFileByRef() { + local configFile="$1" + local ref="$2" + local file + file="$(jq -cre ".collections.${ref}.file" <"${configFile}")" || return 1 + echo "$(Postman::Model::getRelativeConfigDirectory "${configFile}")/${file}" +} diff --git a/src/Postman/Model/getCollectionRefs.bats b/src/Postman/Model/getCollectionRefs.bats new file mode 100755 index 00000000..66f40750 --- /dev/null +++ b/src/Postman/Model/getCollectionRefs.bats @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/Model/getCollectionRefs.sh +source "${rootDir}/src/Postman/Model/getCollectionRefs.sh" + +function Postman::Model::getCollectionRefs::get { #@test + local -a result + local status=0 + Postman::Model::getCollectionRefs \ + "${BATS_TEST_DIRNAME}/testsData/getCollectionRefs.json" \ + result || status=$? + [[ "${result[*]}" = "githubAdvanced githubBasic microsoftGraph" ]] + [[ "${status}" = "0" ]] +} + +function Postman::Model::getCollectionRefs::error { #@test + local -a result + local status=0 + Postman::Model::getCollectionRefs \ + "${BATS_TEST_DIRNAME}/testsData/getCollectionError.json" \ + result || status=$? + [[ "${result[*]}" = "" ]] + [[ "${status}" = "4" ]] +} diff --git a/src/Postman/Model/getCollectionRefs.sh b/src/Postman/Model/getCollectionRefs.sh new file mode 100755 index 00000000..849a2f3e --- /dev/null +++ b/src/Postman/Model/getCollectionRefs.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# @description get the list of collection references id from given config file +# @arg $1 configFile:String the config file to parse +# @arg $2 getCollectionRefs:&String[] (passed by reference) list of collection +# references +# @exitcode 1 - if jq parsing error, file not found or any other error +# @stderr jq error messages on failure +Postman::Model::getCollectionRefs() { + local configFile="$1" + local -n getCollectionRefs=$2 + # shellcheck disable=SC2034 + jq -cre '.collections | try keys[]' <"${configFile}" | readarray -t getCollectionRefs +} diff --git a/src/Postman/Model/getName.bats b/src/Postman/Model/getName.bats new file mode 100755 index 00000000..484ae953 --- /dev/null +++ b/src/Postman/Model/getName.bats @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/Model/getName.sh +source "${rootDir}/src/Postman/Model/getName.sh" + +function Postman::Model::getName::simple { #@test + run Postman::Model::getName \ + "${BATS_TEST_DIRNAME}/testsData/getCollectionRefs.json" + assert_output "Open Apis" + assert_success +} + +function Postman::Model::getName::error { #@test + run Postman::Model::getName \ + "${BATS_TEST_DIRNAME}/testsData/getCollectionError.json" + assert_output "" + assert_failure 1 +} diff --git a/src/Postman/Model/getName.sh b/src/Postman/Model/getName.sh new file mode 100755 index 00000000..77e16ea7 --- /dev/null +++ b/src/Postman/Model/getName.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# @description retrieve the name of the model json file +# @arg $1 modelFile:String +# @exitcode 1 if error while parsing model file +# @exitcode * jq exit code, 4 for invalid file +# @stdout model property name of model json file +Postman::Model::getName() { + local modelFile="$1" + local output + output="$(jq -cre .name <"${modelFile}")" || return 1 + echo "${output}" +} diff --git a/src/Postman/Model/getRelativeConfigDirectory.bats b/src/Postman/Model/getRelativeConfigDirectory.bats new file mode 100755 index 00000000..26527bcc --- /dev/null +++ b/src/Postman/Model/getRelativeConfigDirectory.bats @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=vendor/bash-tools-framework/src/File/relativeToDir.sh +source "${FRAMEWORK_ROOT_DIR}/src/File/relativeToDir.sh" +# shellcheck source=src/Postman/Model/getRelativeConfigDirectory.sh +source "${rootDir}/src/Postman/Model/getRelativeConfigDirectory.sh" + +function Postman::Model::getRelativeConfigDirectory::githubBasic { #@test + run Postman::Model::getRelativeConfigDirectory \ + "${BATS_TEST_DIRNAME}/testsData/getCollectionRefs.json" + assert_output "src/Postman/Model/testsData" + assert_success +} diff --git a/src/Postman/Model/getRelativeConfigDirectory.sh b/src/Postman/Model/getRelativeConfigDirectory.sh new file mode 100755 index 00000000..49a72182 --- /dev/null +++ b/src/Postman/Model/getRelativeConfigDirectory.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# @description config directory path relative to current execution directory +# @arg $1 configFile:String the config file +# @stdout the parent directory of config file relative to current execution directory +# @example +# executionPath=/home/wsl/bash-tools +# configPath=/home/wsl/bash-tools/conf/postmanCli/openApis.json +# result=conf/postmanCli +Postman::Model::getRelativeConfigDirectory() { + local configFile="$1" + local configDir + configDir="$(cd -- "$(dirname -- "${configFile}")" &>/dev/null && pwd -P)" + File::relativeToDir "${configDir}" "$(pwd -P)" +} diff --git a/src/Postman/Model/testsData/GithubAPI/githubAdvanced.json b/src/Postman/Model/testsData/GithubAPI/githubAdvanced.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/src/Postman/Model/testsData/GithubAPI/githubAdvanced.json @@ -0,0 +1 @@ +{} diff --git a/src/Postman/Model/testsData/GithubAPI/githubBasic.json b/src/Postman/Model/testsData/GithubAPI/githubBasic.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/src/Postman/Model/testsData/GithubAPI/githubBasic.json @@ -0,0 +1 @@ +{} diff --git a/src/Postman/Model/testsData/MicrosoftGraph/microsoftGraph.json b/src/Postman/Model/testsData/MicrosoftGraph/microsoftGraph.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/src/Postman/Model/testsData/MicrosoftGraph/microsoftGraph.json @@ -0,0 +1 @@ +{} diff --git a/src/Postman/Model/testsData/configMode/getCollectionRefs-collectionsNotObject.json b/src/Postman/Model/testsData/configMode/getCollectionRefs-collectionsNotObject.json new file mode 100644 index 00000000..797f16a3 --- /dev/null +++ b/src/Postman/Model/testsData/configMode/getCollectionRefs-collectionsNotObject.json @@ -0,0 +1,16 @@ +{ + "name": "Open Apis", + "missingCollections": [ + { + "environment": null + }, + { + "file": "GithubAPI/notWritableFile.json", + "environment": null + }, + { + "file": "NotWritable/notWritableFile.json", + "environment": null + } + ] +} diff --git a/src/Postman/Model/testsData/configMode/getCollectionRefs-missingCollections.json b/src/Postman/Model/testsData/configMode/getCollectionRefs-missingCollections.json new file mode 100644 index 00000000..5c9ecf4a --- /dev/null +++ b/src/Postman/Model/testsData/configMode/getCollectionRefs-missingCollections.json @@ -0,0 +1,16 @@ +{ + "name": "Open Apis", + "missingCollections": { + "missingFileProperty": { + "environment": null + }, + "fileNotWritable": { + "file": "GithubAPI/notWritableFile.json", + "environment": null + }, + "dirNotWritable": { + "file": "NotWritable/notWritableFile.json", + "environment": null + } + } +} diff --git a/src/Postman/Model/testsData/configMode/getCollectionRefs-missingFileProperty.json b/src/Postman/Model/testsData/configMode/getCollectionRefs-missingFileProperty.json new file mode 100644 index 00000000..2de6618d --- /dev/null +++ b/src/Postman/Model/testsData/configMode/getCollectionRefs-missingFileProperty.json @@ -0,0 +1,16 @@ +{ + "name": "Open Apis", + "collections": { + "missingFileProperty": { + "environment": null + }, + "fileNotWritable": { + "file": "GithubAPI/notWritableFile.json", + "environment": null + }, + "dirNotWritable": { + "file": "NotWritable/notWritableFile.json", + "environment": null + } + } +} diff --git a/src/Postman/Model/testsData/configMode/getCollectionRefs-missingName.json b/src/Postman/Model/testsData/configMode/getCollectionRefs-missingName.json new file mode 100644 index 00000000..34282ee6 --- /dev/null +++ b/src/Postman/Model/testsData/configMode/getCollectionRefs-missingName.json @@ -0,0 +1,4 @@ +{ + "nameMissing": "Open Apis", + "collections": {} +} diff --git a/src/Postman/Model/testsData/getCollection-missingCollections.json b/src/Postman/Model/testsData/getCollection-missingCollections.json new file mode 100644 index 00000000..ff3ba7b8 --- /dev/null +++ b/src/Postman/Model/testsData/getCollection-missingCollections.json @@ -0,0 +1,3 @@ +{ + "name": "Open Apis" +} diff --git a/src/Postman/Model/testsData/getCollection-missingName.json b/src/Postman/Model/testsData/getCollection-missingName.json new file mode 100644 index 00000000..2cb1460a --- /dev/null +++ b/src/Postman/Model/testsData/getCollection-missingName.json @@ -0,0 +1,3 @@ +{ + "collections": {} +} diff --git a/src/Postman/Model/testsData/getCollectionError.json b/src/Postman/Model/testsData/getCollectionError.json new file mode 100644 index 00000000..6f48b733 --- /dev/null +++ b/src/Postman/Model/testsData/getCollectionError.json @@ -0,0 +1,17 @@ +{ + "nameError": "Open Apis", + "NoCollections": { + "githubBasic": { + "file": "GithubAPI/GitHubAPI-01-Basic_no_auth_postman_collection.json", + "environment": null + }, + "githubAdvanced": { + "file": "GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json", + "environment": null + }, + "microsoftGraph": { + "file": "MicrosoftGraph/MicrosoftGraph-postman_collection.json", + "environment": null + } + } +} diff --git a/src/Postman/Model/testsData/getCollectionInvalid.json b/src/Postman/Model/testsData/getCollectionInvalid.json new file mode 100644 index 00000000..ed297b49 --- /dev/null +++ b/src/Postman/Model/testsData/getCollectionInvalid.json @@ -0,0 +1,17 @@ + + "nameError": "Open Apis", + "NoCollections": { + "githubBasic": { + "file": "GithubAPI/GitHubAPI-01-Basic_no_auth_postman_collection.json", + "environment": null + }, + "githubAdvanced": { + "file": "GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json", + "environment": null + }, + "microsoftGraph": { + "file": "MicrosoftGraph/MicrosoftGraph-postman_collection.json", + "environment": null + } + } +} diff --git a/src/Postman/Model/testsData/getCollectionRefs.json b/src/Postman/Model/testsData/getCollectionRefs.json new file mode 100644 index 00000000..b1d71240 --- /dev/null +++ b/src/Postman/Model/testsData/getCollectionRefs.json @@ -0,0 +1,17 @@ +{ + "name": "Open Apis", + "collections": { + "githubBasic": { + "file": "GithubAPI/githubBasic.json", + "environment": null + }, + "githubAdvanced": { + "file": "GithubAPI/githubAdvanced.json", + "environment": null + }, + "microsoftGraph": { + "file": "MicrosoftGraph/microsoftGraph.json", + "environment": null + } + } +} diff --git a/src/Postman/Model/testsData/getCollections_expectedResult.json b/src/Postman/Model/testsData/getCollections_expectedResult.json new file mode 100644 index 00000000..c7121a74 --- /dev/null +++ b/src/Postman/Model/testsData/getCollections_expectedResult.json @@ -0,0 +1,17 @@ +{ + "name": "Open Apis", + "collections": { + "githubBasic": { + "file": "GithubAPI/GitHubAPI-01-Basic_no_auth_postman_collection.json", + "environment": null + }, + "githubAdvanced": { + "file": "GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json", + "environment": null + }, + "microsoftGraph": { + "file": "MicrosoftGraph/MicrosoftGraph-postman_collection.json", + "environment": null + } + } +} diff --git a/src/Postman/Model/testsData/pullMode/GithubAPI/notWritableFile.json b/src/Postman/Model/testsData/pullMode/GithubAPI/notWritableFile.json new file mode 100644 index 00000000..e69de29b diff --git a/src/Postman/Model/testsData/pullMode/NotWritable/.gitkeep b/src/Postman/Model/testsData/pullMode/NotWritable/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/Postman/Model/testsData/pullMode/getCollectionRefs-collectionsWithErrors.json b/src/Postman/Model/testsData/pullMode/getCollectionRefs-collectionsWithErrors.json new file mode 100644 index 00000000..2de6618d --- /dev/null +++ b/src/Postman/Model/testsData/pullMode/getCollectionRefs-collectionsWithErrors.json @@ -0,0 +1,16 @@ +{ + "name": "Open Apis", + "collections": { + "missingFileProperty": { + "environment": null + }, + "fileNotWritable": { + "file": "GithubAPI/notWritableFile.json", + "environment": null + }, + "dirNotWritable": { + "file": "NotWritable/notWritableFile.json", + "environment": null + } + } +} diff --git a/src/Postman/Model/testsData/pushMode/GithubAPI/missingInfoName.json b/src/Postman/Model/testsData/pushMode/GithubAPI/missingInfoName.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/src/Postman/Model/testsData/pushMode/GithubAPI/missingInfoName.json @@ -0,0 +1 @@ +{} diff --git a/src/Postman/Model/testsData/pushMode/GithubAPI/notValidJsonFile.json b/src/Postman/Model/testsData/pushMode/GithubAPI/notValidJsonFile.json new file mode 100644 index 00000000..98232c64 --- /dev/null +++ b/src/Postman/Model/testsData/pushMode/GithubAPI/notValidJsonFile.json @@ -0,0 +1 @@ +{ diff --git a/src/Postman/Model/testsData/pushMode/getCollectionRefs-collectionsWithErrors.json b/src/Postman/Model/testsData/pushMode/getCollectionRefs-collectionsWithErrors.json new file mode 100644 index 00000000..02df20a6 --- /dev/null +++ b/src/Postman/Model/testsData/pushMode/getCollectionRefs-collectionsWithErrors.json @@ -0,0 +1,20 @@ +{ + "name": "Open Apis", + "collections": { + "missingFileProperty": { + "environment": null + }, + "fileMissing": { + "file": "GithubAPI/missingFile.json", + "environment": null + }, + "notValidJsonFile": { + "file": "GithubAPI/notValidJsonFile.json", + "environment": null + }, + "missingInfoName": { + "file": "GithubAPI/missingInfoName.json", + "environment": null + } + } +} diff --git a/src/Postman/Model/validate.bats b/src/Postman/Model/validate.bats new file mode 100755 index 00000000..77255f80 --- /dev/null +++ b/src/Postman/Model/validate.bats @@ -0,0 +1,157 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" +# shellcheck source=vendor/bash-tools-framework/src/Array/contains.sh +source "${FRAMEWORK_ROOT_DIR}/src/Array/contains.sh" +# shellcheck source=src/Postman/Model/validate.sh +source "${rootDir}/src/Postman/Model/validate.sh" + +setup() { + export BASH_FRAMEWORK_THEME="noColor" +} + +function Postman::Model::validate::missingMode { #@test + run Postman::Model::validate \ + "fileNotFound.json" "invalidMode" + assert_output "ERROR - invalid mode invalidMode" + assert_failure 1 + assert_lines_count 1 +} + +function Postman::Model::validate::invalidMode { #@test + run Postman::Model::validate \ + "fileNotFound.json" "invalidMode" + assert_output "ERROR - invalid mode invalidMode" + assert_failure 1 + assert_lines_count 1 +} + +function Postman::Model::validate::fileNotFound { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "$1" + } + run Postman::Model::validate \ + "fileNotFound.json" "push" + assert_output "ERROR - File fileNotFound.json does not exist" + assert_failure 1 + assert_lines_count 1 +} + +function Postman::Model::validate::fileInvalid { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "$1" + } + run Postman::Model::validate \ + "${BATS_TEST_DIRNAME}/testsData/getCollectionInvalid.json" "push" + assert_output "ERROR - File '${BATS_TEST_DIRNAME}/testsData/getCollectionInvalid.json' is not a valid json file" + assert_failure 1 + assert_lines_count 1 +} + +function Postman::Model::validate::missingName { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "$1" + } + run Postman::Model::validate \ + "${BATS_TEST_DIRNAME}/testsData/getCollection-missingName.json" "push" + assert_output "ERROR - File '${BATS_TEST_DIRNAME}/testsData/getCollection-missingName.json' - missing name property" + assert_failure 1 + assert_lines_count 1 +} + +function Postman::Model::validate::missingCollections { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "$1" + } + run Postman::Model::validate \ + "${BATS_TEST_DIRNAME}/testsData/getCollection-missingCollections.json" "push" + assert_output "ERROR - File '${BATS_TEST_DIRNAME}/testsData/getCollection-missingCollections.json' - collections property is missing or is not an object" + assert_failure 1 + assert_lines_count 1 +} + +function Postman::Model::validate::pushModeCollectionsWithErrors { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "${BATS_TEST_DIRNAME}/testsData/pushMode" + } + local file="${BATS_TEST_DIRNAME}/testsData/pushMode/getCollectionRefs-collectionsWithErrors.json" + run Postman::Model::validate \ + "${file}" "push" + + assert_failure 1 + assert_line --index 0 "ERROR - File '${file}' - collection 0 - missing file property" + assert_line --index 1 "ERROR - File '${file}' - collection fileMissing - collection file ${BATS_TEST_DIRNAME}/testsData/pushMode/GithubAPI/missingFile.json does not exists" + assert_line --index 2 "ERROR - File '${file}' - collection notValidJsonFile - collection file ${BATS_TEST_DIRNAME}/testsData/pushMode/GithubAPI/notValidJsonFile.json is not a valid json file" + assert_line --index 3 "ERROR - File '${file}' - collection missingInfoName - collection file ${BATS_TEST_DIRNAME}/testsData/pushMode/GithubAPI/missingInfoName.json does not seem to be a valid collection file" + + assert_lines_count 4 +} + +function Postman::Model::validate::pullModeCollectionsWithErrors { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "${BATS_TEST_DIRNAME}/testsData/pullMode" + } + local file="${BATS_TEST_DIRNAME}/testsData/pullMode/getCollectionRefs-collectionsWithErrors.json" + run Postman::Model::validate \ + "${file}" "pull" + + assert_failure 1 + assert_line --index 0 "ERROR - File '${file}' - collection 0 - missing file property" + assert_line --index 1 "ERROR - File '${file}' - collection fileNotWritable - collection file ${BATS_TEST_DIRNAME}/testsData/pullMode/GithubAPI/notWritableFile.json is not writable" + assert_line --index 2 "ERROR - File '${file}' - collection dirNotWritable - config directory ${BATS_TEST_DIRNAME}/testsData/pullMode is not writable" + + assert_lines_count 3 +} + +function Postman::Model::validate::configMode::collectionsNotObject { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "${BATS_TEST_DIRNAME}/testsData/configMode" + } + local file="${BATS_TEST_DIRNAME}/testsData/configMode/getCollectionRefs-collectionsNotObject.json" + run Postman::Model::validate \ + "${file}" "config" + + assert_failure 1 + assert_line --index 0 "ERROR - File '${file}' - collections property is missing or is not an object" + assert_lines_count 1 +} + +function Postman::Model::validate::configMode::missingCollections { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "${BATS_TEST_DIRNAME}/testsData/configMode" + } + local file="${BATS_TEST_DIRNAME}/testsData/configMode/getCollectionRefs-missingCollections.json" + run Postman::Model::validate \ + "${file}" "config" + + assert_failure 1 + assert_line --index 0 "ERROR - File '${file}' - collections property is missing or is not an object" + assert_lines_count 1 +} + +function Postman::Model::validate::configMode::missingFileProperty { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "${BATS_TEST_DIRNAME}/testsData/configMode" + } + local file="${BATS_TEST_DIRNAME}/testsData/configMode/getCollectionRefs-missingFileProperty.json" + run Postman::Model::validate \ + "${file}" "config" + + assert_failure 1 + assert_line --index 0 "ERROR - File '${file}' - collection 0 - missing file property" + assert_lines_count 1 +} + +function Postman::Model::validate::configMode::missingName { #@test + Postman::Model::getRelativeConfigDirectory() { + echo "${BATS_TEST_DIRNAME}/testsData/configMode" + } + local file="${BATS_TEST_DIRNAME}/testsData/configMode/getCollectionRefs-missingName.json" + run Postman::Model::validate \ + "${file}" "config" + + assert_failure 1 + assert_line --index 0 "ERROR - File '${file}' - missing name property" + assert_lines_count 1 +} diff --git a/src/Postman/Model/validate.sh b/src/Postman/Model/validate.sh new file mode 100755 index 00000000..a2f3402f --- /dev/null +++ b/src/Postman/Model/validate.sh @@ -0,0 +1,112 @@ +#!/bin/bash + +# @description validates the model file and checks for file existence +# @arg $1 optionModelFile:String the model file to validate +# @arg $2 mode:Enum(pull|push|config) eg: pull/config don't check for file existence +# @exitcode 1 if file optionModelFile does not exists or invalid +# @stderr diagnostics information is displayed +Postman::Model::validate() { + local modelFile="$1" + local mode="$2" + + if ! Array::contains "${mode}" pull push config; then + Log::displayError "invalid mode ${mode}" + return 1 + fi + + # shellcheck disable=SC2154 + if [[ ! -f "${modelFile}" ]]; then + Log::displayError "File ${modelFile} does not exist" + return 1 + fi + + if ! jq -cre . &>/dev/null <"${modelFile}"; then + Log::displayError "File '${modelFile}' is not a valid json file" + return 1 + fi + local -i errorCount=0 + + # check name key presence + local name + name="$(jq -cre .name 2>/dev/null <"${modelFile}")" || { + Log::displayError "File '${modelFile}' - missing name property" + ((++errorCount)) + } + if [[ -z "${name}" ]]; then + Log::displayError "File '${modelFile}' name property cannot be empty" + ((++errorCount)) + fi + + # check collections key presence + local expr='.collections | if type=="object" then "yes" else "no" end' + if [[ "$(jq -cre "${expr}" <"${modelFile}")" = "no" ]]; then + Log::displayError "File '${modelFile}' - collections property is missing or is not an object" + ((++errorCount)) + else + local collectionJson + local -i index=0 + # shellcheck disable=SC2030 + jq -cre '.collections | to_entries | map(.value + {key: .key}) | .[]' "${modelFile}" | while IFS=$'\n' read -r collectionJson; do + local collectionFile collectionKey + local status=0 + collectionFile="$(jq -cre .file 2>/dev/null <<<"${collectionJson}")" || status=1 + if [[ "${status}" = 0 ]]; then + collectionKey="$(jq -cre .key 2>/dev/null <<<"${collectionJson}")" || status=1 + else + collectionKey="${index}" + fi + if [[ "${status}" = 1 ]]; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - missing file property" + ((++errorCount)) + else + local configDirectory + configDirectory="$(Postman::Model::getRelativeConfigDirectory "${modelFile}")" + collectionFile="${configDirectory}/${collectionFile}" + case "${mode}" in + push) + if [[ ! -f "${collectionFile}" ]]; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - collection file ${collectionFile} does not exists" + ((++errorCount)) + continue + fi + if [[ ! -r "${collectionFile}" ]]; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - collection file ${collectionFile} is not readable" + ((++errorCount)) + continue + fi + if ! jq -cre . &>/dev/null <"${collectionFile}"; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - collection file ${collectionFile} is not a valid json file" + ((++errorCount)) + continue + fi + if ! jq -cre .info.name &>/dev/null <"${collectionFile}"; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - collection file ${collectionFile} does not seem to be a valid collection file" + ((++errorCount)) + continue + fi + ;; + + pull) + if [[ -f "${collectionFile}" && ! -w "${collectionFile}" ]]; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - collection file ${collectionFile} is not writable" + ((++errorCount)) + continue + fi + if [[ ! -f "${collectionFile}" && ! -w "${configDirectory}" ]]; then + Log::displayError "File '${modelFile}' - collection ${collectionKey} - config directory ${configDirectory} is not writable" + ((++errorCount)) + continue + fi + ;; + *) ;; + # ignore + esac + fi + # TODO environment + ((++index)) + done + fi + + # shellcheck disable=SC2031 + ((errorCount == 0)) +} diff --git a/src/Postman/Readme.md b/src/Postman/Readme.md new file mode 100644 index 00000000..23a3c9ae --- /dev/null +++ b/src/Postman/Readme.md @@ -0,0 +1,44 @@ +# PostmanCli + +## Commands + +### pull + +Pull Postman collections to repositories. + +### push + +Push repositories collections to Postman. + +**SUB-ARGUMENTS:** + +- list of postman collection's references to push or no argument to push all the + collections + +## Configuration + +```json +{ + "name": "Open Apis", + "collections": { + "githubBasic": { + "collection": "GithubAPI/GitHubAPI-01-Basic_no_auth_postman_collection.json", + "environment": null + }, + "githubAdvanced": { + "collection": "GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json", + "environment": null + }, + "microsoftGraph": { + "collection": "MicrosoftGraph/MicrosoftGraph-postman_collection.json", + "environment": null + } + } +} +``` + +## Algorithms + +### push-with-merge + +get each collection diff --git a/src/Postman/api.bats b/src/Postman/api.bats new file mode 100755 index 00000000..add09791 --- /dev/null +++ b/src/Postman/api.bats @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/api.sh +source "${rootDir}/src/Postman/api.sh" + +setup() { + export BASH_FRAMEWORK_THEME="noColor" + export POSTMAN_API_KEY='fake' +} + +teardown() { + unstub_all +} + +function Postman::api::noAction { #@test + run Postman::api + assert_output "ERROR - Unknown api action ''" + assert_failure 1 +} + +function Postman::api::invalidAction { #@test + run Postman::api invalidAction + assert_output "ERROR - Unknown api action 'invalidAction'" + assert_failure 1 +} + +function Postman::api::getCollections { #@test + stub curl \ + "-X GET https://api.getpostman.com/collections --fail --silent --show-error -H 'X-Api-Key: fake' : echo '{}'" + run Postman::api getCollections + assert_output "{}" + assert_success +} + +function Postman::api::createCollectionFromFile { #@test + Postman::displayResponse() { + cat "$2" + } + stub jq \ + '-cre -n --slurpfile collection collectionFilePath * : echo "{}"' + stub curl \ + "--request POST https://api.getpostman.com/collections -o * --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'X-Api-Key: fake' --data @- --fail --silent --show-error : echo 'result OK'" + run Postman::api createCollectionFromFile "collectionFilePath" + assert_output "result OK" + assert_success +} + +function Postman::api::updateCollectionFromFile { #@test + Postman::displayResponse() { + cat "$2" + } + stub jq \ + '-cre -n --slurpfile collection collectionFilePath * : echo "{}"' + stub curl \ + "--request PUT https://api.getpostman.com/collections/2 -o * --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'X-Api-Key: fake' --data @- --fail --silent --show-error : echo 'result OK'" + run Postman::api updateCollectionFromFile "collectionFilePath" 2 + assert_output "result OK" + assert_success +} + +function Postman::api::pullCollection { #@test + stub curl \ + "-X GET https://api.getpostman.com/collections/ --fail --silent --show-error -H 'X-Api-Key: fake' : echo '{}'" + run Postman::api pullCollection + assert_output "{}" + assert_success +} diff --git a/src/Postman/api.sh b/src/Postman/api.sh new file mode 100755 index 00000000..817f46bc --- /dev/null +++ b/src/Postman/api.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# @description call postman REST api +# @arg $1 action:String action to call +# @arg $@ args:String[] rest of arguments +# @exitcode 1 if invalid action +# @exitcode * curl error +# @env BASH_FRAMEWORK_ARGS_VERBOSE display curl response if verbose level is different than 0 +Postman::api() { + local action="$1" + shift || true + + getCollections() { + curl \ + -X GET https://api.getpostman.com/collections \ + --fail --silent --show-error \ + -H "X-Api-Key: ${POSTMAN_API_KEY}" + } + + getCollectionDataFromFile() { + local collectionFile="$1" + jq -cre -n \ + --slurpfile collection "${collectionFile}" \ + '{"collection": $collection[0]}' + } + + createCollectionFromFile() { + local collectionFile="$1" + local responseFile + responseFile="$(Framework::createTempFile)" + + local status=0 + getCollectionDataFromFile "${collectionFile}" | + curl \ + --request POST https://api.getpostman.com/collections \ + -o "${responseFile}" \ + --header 'Content-Type: application/json' \ + --header 'Accept: application/json' \ + --header "X-Api-Key: ${POSTMAN_API_KEY}" \ + --data @- \ + --fail --silent --show-error || status=$? + + Postman::displayResponse "createCollectionFromFile" "${responseFile}" + + return "${status}" + } + + updateCollectionFromFile() { + local collectionFile="$1" + local collectionId="$2" + local responseFile + responseFile="$(Framework::createTempFile)" + + local status=0 + getCollectionDataFromFile "${collectionFile}" | + curl \ + --request PUT "https://api.getpostman.com/collections/${collectionId}" \ + -o "${responseFile}" \ + --header 'Content-Type: application/json' \ + --header 'Accept: application/json' \ + --header "X-Api-Key: ${POSTMAN_API_KEY}" \ + --data @- \ + --fail --silent --show-error || status=$? + + Postman::displayResponse "updateCollectionFromFile" "${responseFile}" + + return "${status}" + } + + pullCollection() { + local collectionId="$1" + curl \ + -X GET "https://api.getpostman.com/collections/${collectionId}" \ + --fail --silent --show-error \ + -H "X-Api-Key: ${POSTMAN_API_KEY}" + } + + case "${action}" in + getCollections) + getCollections "$@" + ;; + createCollectionFromFile) + createCollectionFromFile "$@" + ;; + updateCollectionFromFile) + updateCollectionFromFile "$@" + ;; + pullCollection) + pullCollection "$@" + ;; + *) + Log::displayError "Unknown api action '${action}'" + return 1 + ;; + esac +} diff --git a/src/Postman/checkApiKey.bats b/src/Postman/checkApiKey.bats new file mode 100755 index 00000000..5ea34a81 --- /dev/null +++ b/src/Postman/checkApiKey.bats @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/checkApiKey.sh +source "${rootDir}/src/Postman/checkApiKey.sh" + +function Postman::checkApiKey::fileNotFound { #@test + run Postman::checkApiKey "fileNotFound" 2>&1 + assert_output "WARN - Please update POSTMAN_API_KEY in 'fileNotFound'" + assert_success +} + +function Postman::checkApiKey::keyNotFound { #@test + run Postman::checkApiKey \ + "${BATS_TEST_DIRNAME}/testsData/.env.keyNotFound" 2>&1 + assert_output "WARN - Please update POSTMAN_API_KEY in '${BATS_TEST_DIRNAME}/testsData/.env.keyNotFound'" + assert_success +} + +function Postman::checkApiKey::keyEmpty { #@test + run Postman::checkApiKey \ + "${BATS_TEST_DIRNAME}/testsData/.env.keyEmpty" 2>&1 + assert_output "WARN - Please update POSTMAN_API_KEY in '${BATS_TEST_DIRNAME}/testsData/.env.keyEmpty'" + assert_success +} + +function Postman::checkApiKey::keyFound { #@test + run Postman::checkApiKey \ + "${BATS_TEST_DIRNAME}/testsData/.env.keyFound" 2>&1 + assert_output "" + assert_success +} diff --git a/src/Postman/checkApiKey.sh b/src/Postman/checkApiKey.sh new file mode 100755 index 00000000..6f202084 --- /dev/null +++ b/src/Postman/checkApiKey.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# @description check if postman api key is set in .env file +# @arg $1 envFile:String .env file that should contain POSTMAN_API_KEY variable +# @stderr display warning message if postman api key is not filled +# @exitcode 0 always successful +Postman::checkApiKey() { + local envFile="$1" + + if grep -q '^POSTMAN_API_KEY=$' "${envFile}" 2>/dev/null || + ! grep -q '^POSTMAN_API_KEY=' "${envFile}" 2>/dev/null; then + Log::displayWarning "Please update POSTMAN_API_KEY in '${envFile}'" + fi +} diff --git a/src/Postman/displayResponse.bats b/src/Postman/displayResponse.bats new file mode 100755 index 00000000..20b08922 --- /dev/null +++ b/src/Postman/displayResponse.bats @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Postman/displayResponse.sh +source "${rootDir}/src/Postman/displayResponse.sh" + +function Postman::displayResponse::nonVerbose { #@test + export BASH_FRAMEWORK_ARGS_VERBOSE=0 + run Postman::displayResponse "type" "${BATS_TEST_DIRNAME}/testsData/responseFile" 2>&1 + assert_output "" + assert_success +} + +function Postman::displayResponse::verbose { #@test + export BASH_FRAMEWORK_ARGS_VERBOSE=1 + UI::drawLine() { + echo >&2 '----' + } + run Postman::displayResponse "type" "${BATS_TEST_DIRNAME}/testsData/responseFile" 2>&1 + assert_output "$(cat "${BATS_TEST_DIRNAME}/testsData/expectedResponseFile")" + assert_success +} diff --git a/src/Postman/displayResponse.sh b/src/Postman/displayResponse.sh new file mode 100755 index 00000000..0a39713c --- /dev/null +++ b/src/Postman/displayResponse.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# @description display curl response only if verbose mode is not off +# @arg $1 type:String type of response displayed +# @arg $2 responseFile:String file containing curl response +# @env BASH_FRAMEWORK_ARGS_VERBOSE +# @exitcode 1 if responseFile not found +Postman::displayResponse() { + local type="$1" + local responseFile="$2" + if ((BASH_FRAMEWORK_ARGS_VERBOSE > __VERBOSE_LEVEL_OFF)); then + (UI::drawLine >&2 "-") + (echo >&2 -e "${__DEBUG_COLOR}${type}${__RESET_COLOR}") + (cat >&2 "${responseFile}") + (echo >&2) + fi +} diff --git a/src/Postman/testsData/.env.keyEmpty b/src/Postman/testsData/.env.keyEmpty new file mode 100644 index 00000000..e69de29b diff --git a/src/Postman/testsData/.env.keyFound b/src/Postman/testsData/.env.keyFound new file mode 100644 index 00000000..a6949c1e --- /dev/null +++ b/src/Postman/testsData/.env.keyFound @@ -0,0 +1 @@ +POSTMAN_API_KEY=fake diff --git a/src/Postman/testsData/.env.keyNotFound b/src/Postman/testsData/.env.keyNotFound new file mode 100644 index 00000000..e69de29b diff --git a/src/Postman/testsData/expectedResponseFile b/src/Postman/testsData/expectedResponseFile new file mode 100644 index 00000000..fadd4a45 --- /dev/null +++ b/src/Postman/testsData/expectedResponseFile @@ -0,0 +1,3 @@ +---- +type +response diff --git a/src/Postman/testsData/responseFile b/src/Postman/testsData/responseFile new file mode 100644 index 00000000..77f6a3e1 --- /dev/null +++ b/src/Postman/testsData/responseFile @@ -0,0 +1 @@ +response diff --git a/src/_binaries/DbImport/dbImportProfile.bats b/src/_binaries/DbImport/dbImportProfile.bats index d7a483b6..413b6dfa 100755 --- a/src/_binaries/DbImport/dbImportProfile.bats +++ b/src/_binaries/DbImport/dbImportProfile.bats @@ -17,6 +17,8 @@ setup() { "${HOME}/.bash-tools/dbImportDumps" \ "${HOME}/.bash-tools/dbImportProfiles" cp "${BATS_TEST_DIRNAME}/testsData/dsn/"* "${HOME}/.bash-tools/dsn/" + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + touch "${HOME}/bin/mysql" "${HOME}/bin/mysqldump" "${HOME}/bin/mysqlshow" "${HOME}/bin/builtinCommandWrapper" chmod +x "${HOME}/bin/"* diff --git a/src/_binaries/DbImport/dbImportStream.bats b/src/_binaries/DbImport/dbImportStream.bats index 98070958..dc69b28e 100755 --- a/src/_binaries/DbImport/dbImportStream.bats +++ b/src/_binaries/DbImport/dbImportStream.bats @@ -19,6 +19,7 @@ setup() { cp "${BATS_TEST_DIRNAME}/testsData/dsn/"* "${HOME}/.bash-tools/dsn/" touch "${HOME}/bin/mysql" "${HOME}/bin/mysqldump" "${HOME}/bin/mysqlshow" "${HOME}/bin/builtinCommandWrapper" chmod +x "${HOME}/bin/"* + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" export BASH_FRAMEWORK_COMMAND="builtinCommandWrapper" diff --git a/src/_binaries/DbQueryAllDatabases/dbQueryAllDatabases.bats b/src/_binaries/DbQueryAllDatabases/dbQueryAllDatabases.bats index 6c2b68e7..7b6ad94c 100755 --- a/src/_binaries/DbQueryAllDatabases/dbQueryAllDatabases.bats +++ b/src/_binaries/DbQueryAllDatabases/dbQueryAllDatabases.bats @@ -17,6 +17,7 @@ setup() { cp "${BATS_TEST_DIRNAME}/testsData/pv" "${HOME}/bin" cp "${BATS_TEST_DIRNAME}/testsData/gawk" "${HOME}/bin" cp "${BATS_TEST_DIRNAME}/testsData/gawk" "${HOME}/bin/awk" + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" touch \ "${HOME}/bin/mysql" \ "${HOME}/bin/mysqldump" \ diff --git a/src/_binaries/DbScriptAllDatabases/dbScriptAllDatabases.bats b/src/_binaries/DbScriptAllDatabases/dbScriptAllDatabases.bats index 37ea83f9..38419764 100755 --- a/src/_binaries/DbScriptAllDatabases/dbScriptAllDatabases.bats +++ b/src/_binaries/DbScriptAllDatabases/dbScriptAllDatabases.bats @@ -15,6 +15,7 @@ setup() { "${HOME}/.bash-tools/dbQueries" \ "${HOME}/.bash-tools/dbScripts" cp "${BATS_TEST_DIRNAME}/testsData/pv" "${HOME}/bin" + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" touch \ "${HOME}/bin/mysqldump" \ "${HOME}/bin/mysqlshow" \ diff --git a/src/_binaries/Git/gitIsAncestorOf.bats b/src/_binaries/Git/gitIsAncestorOf.bats index 7bf21d62..fccb5199 100755 --- a/src/_binaries/Git/gitIsAncestorOf.bats +++ b/src/_binaries/Git/gitIsAncestorOf.bats @@ -9,6 +9,8 @@ setup() { export TMPDIR="${BATS_TEST_TMPDIR}" export HOME="${BATS_TEST_TMPDIR}/home" export BASH_FRAMEWORK_ENV_FILEPATH="${BATS_TEST_DIRNAME}/testsData/.env" + mkdir -p "${HOME}/.bash-tools" + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" } teardown() { diff --git a/src/_binaries/Git/gitRenameBranch.bats b/src/_binaries/Git/gitRenameBranch.bats index 31db7b8a..038d6caf 100755 --- a/src/_binaries/Git/gitRenameBranch.bats +++ b/src/_binaries/Git/gitRenameBranch.bats @@ -9,6 +9,8 @@ setup() { export TMPDIR="${BATS_TEST_TMPDIR}" export HOME="${BATS_TEST_TMPDIR}/home" + mkdir -p "${HOME}/.bash-tools" + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" mkdir "${BATS_TEST_TMPDIR}/gitRepo" mkdir "${BATS_TEST_TMPDIR}/gitRepoFake" diff --git a/src/_binaries/Git/upgradeGithubRelease.bats b/src/_binaries/Git/upgradeGithubRelease.bats index b31c84fa..0886d3e8 100755 --- a/src/_binaries/Git/upgradeGithubRelease.bats +++ b/src/_binaries/Git/upgradeGithubRelease.bats @@ -9,6 +9,9 @@ setup() { export TMPDIR="${BATS_TEST_TMPDIR}" export HOME="${BATS_TEST_TMPDIR}/home" export BASH_FRAMEWORK_ENV_FILEPATH="${BATS_TEST_DIRNAME}/testsData/.env" + mkdir -p "${HOME}/.bash-tools" + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + } teardown() { diff --git a/src/_binaries/Postman/command.postmanCli.tpl b/src/_binaries/Postman/command.postmanCli.tpl new file mode 100644 index 00000000..6f5a9151 --- /dev/null +++ b/src/_binaries/Postman/command.postmanCli.tpl @@ -0,0 +1,79 @@ +% +declare versionNumber="1.0" +declare commandFunctionName="postmanCliCommand" +declare help="Push/Pull postman collections of all the configured repositories" +declare copyrightBeginYear="2023" +# shellcheck disable=SC2016 +% + +.INCLUDE "$(dynamicTemplateDir _binaries/options/options.base.tpl)" +% + +NBSP="\xc2\xa0" +NBSP2="${NBSP}${NBSP}" +# shellcheck source=/dev/null +source <( + Options::generateGroup \ + --title "PUSH/PULL OPTIONS:" \ + --function-name groupPushPullFunction + + # shellcheck disable=SC2016 + Options::generateOption \ + --variable-type String \ + --help $'postmanCli model file to use\n + Default value: /postmanCli.collections.json' \ + --group groupPushPullFunction \ + --alt "--postman-model" \ + --alt "-m" \ + --variable-name "optionPostmanModelConfig" \ + --function-name optionPostmanModelConfigFunction + + Options::generateArg \ + --variable-name "argCommand" \ + --min 0 \ + --max 1 \ + --name "command" \ + --authorized-values 'pull|push' \ + --help \ + $'${__HELP_OPTION_COLOR}pull${__HELP_NORMAL}\n + ${NBSP2}Pull collections from Postman back to repositories.\n + ${__HELP_OPTION_COLOR}push${__HELP_NORMAL}\n + ${NBSP2}Push repositories collections to Postman.\n' \ + --function-name argCommandFunction + + Options::generateArg \ + --variable-name "commandArgs" \ + --min 0 \ + --max -1 \ + --name "commandArgs" \ + --help \ + $'list of postman collection\'s references to pull or push\n + or no argument to pull or push all the collections' \ + --function-name commandArgsFunction +) + +options+=( + optionPostmanModelConfigFunction + argCommandFunction + commandArgsFunction + --unknown-option-callback unknownOption + --unknown-argument-callback unknownOption +) + +Options::generateCommand "${options[@]}" +% +declare optionPostmanModelConfig="$(pwd -P)/postmanCli.collections.json" + +# shellcheck disable=SC2317 # if function is overridden +unknownOption() { + commandArgs+=("$1") +} + +eval "original_$(declare -f displayConfig | grep -v 'exit 0')" +displayConfig() { + Postman::Model::validate "${optionPostmanModelConfig}" "config" + original_displayConfig + UI::drawLine "-" + printf '%-40s = %s\n' "POSTMAN_API_KEY" "${POSTMAN_API_KEY:0:15}...(truncated)" + exit 0 +} diff --git a/src/_binaries/Postman/postmanCli.bats b/src/_binaries/Postman/postmanCli.bats new file mode 100755 index 00000000..f11e1fdf --- /dev/null +++ b/src/_binaries/Postman/postmanCli.bats @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/../.." && pwd)/batsHeaders.sh" + +setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + + export HOME="${BATS_TEST_TMPDIR}/home" + mkdir -p "${HOME}" + cp -R "${rootDir}/conf" "${HOME}/.bash-tools" +} + +function PostmanCli::display_help { #@test + testCommand "${binDir}/postmanCli" postmanCli.help.txt +} + +function PostmanCli::config { #@test + export COLUMNS=2 + run "${binDir}/postmanCli" --config -m "${rootDir}/conf/postmanCli/openApis.json" + assert_line --index 0 "Config" + assert_line --index 1 --regexp '^[-]+$' + assert_line --index 2 "BASH_FRAMEWORK_ARGV = ([0]=\"--config\" [1]=\"-m\" [2]=\"${rootDir}/conf/postmanCli/openApis.json\")" + assert_line --index 3 "BASH_FRAMEWORK_ARGV_FILTERED = ()" + assert_line --index 4 'BASH_FRAMEWORK_DISPLAY_LEVEL = "3"' + assert_line --index 5 "BASH_FRAMEWORK_ENV_FILES = ([0]=\"${HOME}/.bash-tools/.env\")" + assert_line --index 6 "BASH_FRAMEWORK_LOG_FILE = \"${TMPDIR}/logFile\"" + assert_line --index 7 'BASH_FRAMEWORK_LOG_FILE_MAX_ROTATION = "5"' + assert_line --index 8 'BASH_FRAMEWORK_LOG_LEVEL = "0"' + assert_line --index 9 'BASH_FRAMEWORK_THEME = "noColor"' + assert_line --index 10 --regexp '^[-]+$' + assert_line --index 11 'POSTMAN_API_KEY = ...(truncated)' + assert_lines_count 12 + +} diff --git a/src/_binaries/Postman/postmanCli.sh b/src/_binaries/Postman/postmanCli.sh new file mode 100755 index 00000000..d547a5bc --- /dev/null +++ b/src/_binaries/Postman/postmanCli.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# BIN_FILE=${BASH_TOOLS_ROOT_DIR}/bin/postmanCli +# VAR_RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR=.. +# FACADE + +.INCLUDE "$(dynamicTemplateDir _binaries/Postman/command.postmanCli.tpl)" +# call main +postmanCliCommand parse "$@" + +run() { + # shellcheck disable=SC2154 + case "${argCommand}" in + pull) + Postman::Commands::pullCommand "${optionPostmanModelConfig}" "${commandArgs[@]}" + ;; + push) + Postman::Commands::pushCommand "${optionPostmanModelConfig}" "${commandArgs[@]}" + ;; + *) + Log::displayError "Invalid command ${argCommand}" + exit 1 + ;; + esac +} + +if [[ "${BASH_FRAMEWORK_QUIET_MODE:-0}" = "1" ]]; then + run "$@" &>/dev/null +else + run "$@" +fi diff --git a/src/_binaries/Postman/testsData/postmanCli.help.txt b/src/_binaries/Postman/testsData/postmanCli.help.txt new file mode 100644 index 00000000..17c44e0e --- /dev/null +++ b/src/_binaries/Postman/testsData/postmanCli.help.txt @@ -0,0 +1,73 @@ +DESCRIPTION: +Push/Pull postman collections of all the configured repositories + +USAGE: postmanCli [OPTIONS] [ARGUMENTS] +USAGE: postmanCli [--postman-model|-m ] + [--bash-framework-config ] [--config] [--verbose|-v] [-vv] [-vvv] + [--env-file ] [--no-color] [--theme ] [--help|-h] [--version] + [--quiet|-q] [--log-level ] [--log-file ] + [--display-level ] + +ARGUMENTS: + [command {single}] + pull +   Pull collections from Postman back to repositories. + push +   Push repositories collections to Postman. + [commandArgs {list} (optional)] + list of postman collection's references to pull or push + or no argument to pull or push all the collections + +PUSH/PULL OPTIONS: + --postman-model, -m  {single} + postmanCli model file to use + Default value: /postmanCli.collections.json + +GLOBAL OPTIONS: + --bash-framework-config  {single} + use alternate bash framework configuration. + --config {single} + Display configuration + --verbose, -v {single} + info level verbose mode (alias of --display-level INFO) + -vv {single} + debug level verbose mode (alias of --display-level DEBUG) + -vvv {single} + trace level verbose mode (alias of --display-level TRACE) + --env-file  {list} (optional) + Load the specified env file (deprecated, please use --bash-framework-config + option instead) + --no-color {single} + Produce monochrome output. alias of --theme noColor. + --theme  {single} + choose color theme - default-force means colors will be produced even if com + mand is piped + Default value: default + Possible values: default|default-force|noColor + --help, -h {single} + Display this command help + --version {single} + Print version information and quit + --quiet, -q {single} + quiet mode, doesn't display any output + --log-level  {single} + Set log level + Possible values: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE + --log-file  {single} + Set log file + --display-level  {single} + set display level + Possible values: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE + +VERSION: 1.0 + +AUTHOR: +[François Chastanet](https://github.com/fchastanet) + +SOURCE FILE: +https://github.com/fchastanet/bash-tools/tree/master/src/_binaries/Postman/postmanCli.sh + +LICENSE: +MIT License + +Copyright (c) 2024-now François Chastanet diff --git a/src/_binaries/Utils/waitForIt.bats b/src/_binaries/Utils/waitForIt.bats index ace7ab59..583886a1 100755 --- a/src/_binaries/Utils/waitForIt.bats +++ b/src/_binaries/Utils/waitForIt.bats @@ -7,8 +7,9 @@ setup() { export TMPDIR="${BATS_TEST_TMPDIR}" export HOME="${BATS_TEST_TMPDIR}/home" - mkdir -p "${HOME}" + mkdir -p "${HOME}/.bash-tools" mkdir -p "${HOME}/bin" + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" export PATH="${HOME}/bin:${PATH}" } diff --git a/src/_binaries/Utils/waitForMysql.bats b/src/_binaries/Utils/waitForMysql.bats index 6bd011a9..400e640f 100755 --- a/src/_binaries/Utils/waitForMysql.bats +++ b/src/_binaries/Utils/waitForMysql.bats @@ -7,9 +7,10 @@ setup() { export TMPDIR="${BATS_TEST_TMPDIR}" export HOME="${BATS_TEST_TMPDIR}/home" - mkdir -p "${HOME}" + mkdir -p "${HOME}/.bash-tools" mkdir -p "${HOME}/bin" export PATH="${HOME}/bin:${PATH}" + cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" } teardown() { diff --git a/src/_includes/_initFrameworkVariables.tpl b/src/_includes/_initFrameworkVariables.tpl index 1bc562b1..69ea1622 100644 --- a/src/_includes/_initFrameworkVariables.tpl +++ b/src/_includes/_initFrameworkVariables.tpl @@ -12,6 +12,7 @@ FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" +# @require BashTools::Conf::requireLoad if [[ -f "${HOME}/.bash-tools/.env" ]]; then export BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") fi diff --git a/src/batsHeaders.sh b/src/batsHeaders.sh index 3793b251..58b7667d 100755 --- a/src/batsHeaders.sh +++ b/src/batsHeaders.sh @@ -11,6 +11,9 @@ load "${FRAMEWORK_ROOT_DIR}/vendor/bats-support/load.bash" load "${FRAMEWORK_ROOT_DIR}/vendor/bats-assert/load.bash" load "${FRAMEWORK_ROOT_DIR}/vendor/bats-mock-Flamefire/load.bash" +# shellcheck source=vendor/bash-tools-framework/src/_includes/_mandatoryHeader.sh +source "${FRAMEWORK_ROOT_DIR}/src/_includes/_mandatoryHeader.sh" + # shellcheck source=vendor/bash-tools-framework/src/_standalone/Bats/assert_lines_count.sh source "${FRAMEWORK_ROOT_DIR}/src/_standalone/Bats/assert_lines_count.sh" # shellcheck source=vendor/bash-tools-framework/src/Env/__all.sh @@ -72,9 +75,14 @@ Log::requireLoad testCommand() { local command="$1" local expectedOutputFile="$2" + shift 2 || true + local -a args=("$@") + if ((${#args} == 0)); then + args=(--help) + fi export INTERACTIVE=1 UI::theme default - run "${command}" --help + run "${command}" "${args[@]}" assert_success if [[ "${BATS_FIX_TEST}" = "1" && ! -f "${BATS_TEST_DIRNAME}/testsData/${expectedOutputFile}" ]]; then mkdir -p "${BATS_TEST_DIRNAME}/testsData" || true From c94f596ea435bc34fd88a44c510312a8239d53cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Sun, 7 Jan 2024 16:38:28 +0100 Subject: [PATCH 2/8] make pre-commit lighter --- .pre-commit-config.yaml | 6 ++---- bin/postmanCli | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 79766181..110b2335 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,7 @@ --- +default_install_hook_types: [pre-commit, pre-push] default_stages: [pre-commit, manual] +minimum_pre_commit_version: 3.5.0 repos: - repo: local hooks: @@ -108,10 +110,6 @@ repos: - id: plantuml - id: buildShFiles - id: buildShFilesGithubAction - - id: runUnitTests - args: [-r, src, -j, '1'] - # not manual as github will run UT with several versions of bash and arch - stages: [pre-commit] - id: megalinterCheckVersion - id: megalinterGithubAction diff --git a/bin/postmanCli b/bin/postmanCli index d7ad1294..b360eab6 100755 --- a/bin/postmanCli +++ b/bin/postmanCli @@ -163,8 +163,7 @@ Array::wrap2() { echo continue fi - local textFirstLine - textFirstLine="$(echo "${arg}" | head -n 1)" + local textFirstLine="${arg%%$'\n'*}" text="$(echo "${arg}" | sed -E '1d')" ((textLength = ${#text})) || true local textFirstLineNoAnsi From bf09d00f615f65259d2bd7e729eb482af44281ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Sun, 7 Jan 2024 16:41:11 +0100 Subject: [PATCH 3/8] upgraded github actions dependencies versions --- .github/workflows/docsify-gh-pages.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docsify-gh-pages.yml b/.github/workflows/docsify-gh-pages.yml index ce53e628..7d020447 100644 --- a/.github/workflows/docsify-gh-pages.yml +++ b/.github/workflows/docsify-gh-pages.yml @@ -16,6 +16,8 @@ permissions: contents: read pages: write id-token: write + # actions: read needed by actions/deploy-pages + actions: read # Allow one concurrent deployment concurrency: @@ -50,9 +52,10 @@ jobs: uses: actions/configure-pages@v2 - name: Upload artifact - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@v3 with: path: 'pages' + if-no-files-found: error # Deployment job deploy: From 031841c890615328a8c2415fc77d99346018ea8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Sun, 7 Jan 2024 16:48:04 +0100 Subject: [PATCH 4/8] added postmanCli to auto generated Commands.md --- Commands.tmpl.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Commands.tmpl.md b/Commands.tmpl.md index 90cae442..0867bb51 100644 --- a/Commands.tmpl.md +++ b/Commands.tmpl.md @@ -21,6 +21,8 @@ - [4.1.3. Example 2: connect to mysql container with root user](#413-example-2-connect-to-mysql-container-with-root-user) - [4.1.4. Example 3: connect to mysql server in order to execute a query](#414-example-3-connect-to-mysql-server-in-order-to-execute-a-query) - [4.1.5. Example 4: pipe sql command to mysql container](#415-example-4-pipe-sql-command-to-mysql-container) + - [4.1. bin/postmanCli](#41-binpostmancli) + - [4.1.1. Help](#411-help-1) - [5. Database tools](#5-database-tools) - [5.1. bin/dbQueryAllDatabases](#51-bindbqueryalldatabases) - [5.1.1. Help](#511-help) @@ -194,6 +196,14 @@ project-mysql //bin/bash -c 'mysql -h127.0.0.1 -uroot -proot -P3306' notice that as input is given to the command, tty option is not provided to docker exec +### 4.1. bin/postmanCli + +#### 4.1.1. Help + +```text +@@@postmanCli_help@@@ +``` + ## 5. Database tools ### 5.1. bin/dbQueryAllDatabases From 0bb6e5716a65e4d4b3e72a5ca78752f0c13c7143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Sun, 7 Jan 2024 23:08:10 +0100 Subject: [PATCH 5/8] fixed UT flakiness - using Bash::handlePipelineFailure - removed usage of Embeded binaries in dbScriptAllDatabases and dbQueryAllDatabases --- bin/cli | 2 +- bin/dbImport | 2 +- bin/dbImportProfile | 2 +- bin/dbImportStream | 2 +- bin/dbQueryAllDatabases | 97 ++++++++++++++++++- bin/dbScriptAllDatabases | 97 ++++++++++++++++++- bin/doc | 2 +- bin/gitIsAncestorOf | 2 +- bin/gitIsBranch | 2 +- bin/gitRenameBranch | 2 +- bin/installRequirements | 2 +- bin/mysql2puml | 4 +- bin/postmanCli | 53 +++++++++- bin/upgradeGithubRelease | 4 +- bin/waitForIt | 4 +- bin/waitForMysql | 4 +- install | 2 +- src/Postman/Model/validate.bats | 15 ++- src/Postman/api.bats | 2 + src/Postman/api.sh | 8 +- src/_binaries/Postman/command.postmanCli.tpl | 20 ++-- .../Postman/testsData/postmanCli.help.txt | 8 +- 22 files changed, 288 insertions(+), 48 deletions(-) diff --git a/bin/cli b/bin/cli index f6f44efb..b0abddf5 100755 --- a/bin/cli +++ b/bin/cli @@ -1646,7 +1646,7 @@ cliCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/dbImport b/bin/dbImport index 093839f7..a810f18f 100755 --- a/bin/dbImport +++ b/bin/dbImport @@ -2202,7 +2202,7 @@ dbImportCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/dbImportProfile b/bin/dbImportProfile index be0dc3ce..a9564c9d 100755 --- a/bin/dbImportProfile +++ b/bin/dbImportProfile @@ -1781,7 +1781,7 @@ dbImportProfileCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/dbImportStream b/bin/dbImportStream index e13e9a6b..1e34e5db 100755 --- a/bin/dbImportStream +++ b/bin/dbImportStream @@ -2014,7 +2014,7 @@ dbImportStreamCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/dbQueryAllDatabases b/bin/dbQueryAllDatabases index ae0cb7e8..b26beb15 100755 --- a/bin/dbQueryAllDatabases +++ b/bin/dbQueryAllDatabases @@ -750,6 +750,96 @@ Version::checkMinimal() { } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -1152,6 +1242,7 @@ Env::requireLoad UI::requireTheme Linux::requireRealpathCommand Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir # @require Compiler::Facade::requireCommandBinDir @@ -1836,7 +1927,7 @@ dbQueryAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(specify\ the\ number\ of\ db\ to\ query\ in\ parallel) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: 1" + echo ' Default value: 1' echo -e " ${__HELP_OPTION_COLOR}--bar${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-b${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 @@ -1847,7 +1938,7 @@ dbQueryAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(character\ to\ use\ to\ separate\ mysql\ column) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: |" + echo ' Default value: |' echo echo -e "${__HELP_TITLE_COLOR}QUERY OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--from-dsn${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-f ${__HELP_NORMAL} {single}" @@ -1897,7 +1988,7 @@ dbQueryAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/dbScriptAllDatabases b/bin/dbScriptAllDatabases index 006cb424..99c7e4ac 100755 --- a/bin/dbScriptAllDatabases +++ b/bin/dbScriptAllDatabases @@ -673,6 +673,96 @@ UI::theme() { fi } +bashToolsDefaultConfigTemplate="${bashToolsDefaultConfigTemplate:-$( + cat <<'EOF' +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOF +)}" + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + # @description ensure COMMAND_BIN_DIR env var is set # and PATH correctly prepared # @noargs @@ -999,6 +1089,7 @@ Env::requireLoad UI::requireTheme Linux::requireRealpathCommand Log::requireLoad +BashTools::Conf::requireLoad Compiler::Facade::requireCommandBinDir Linux::requireExecutedAsUser @@ -1723,7 +1814,7 @@ dbScriptAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(specify\ the\ number\ of\ db\ to\ query\ in\ parallel) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: 1" + echo ' Default value: 1' echo -e " ${__HELP_OPTION_COLOR}--bar${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-b${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 @@ -1751,7 +1842,7 @@ dbScriptAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(if\ output\ dir\ provided\,\ will\ log\ each\ db\ result\ to\ log\ file) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: none" + echo ' Default value: none' echo ' Possible values: none|log' echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" @@ -1795,7 +1886,7 @@ dbScriptAllDatabasesCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/doc b/bin/doc index aa5a2e9a..17f60051 100755 --- a/bin/doc +++ b/bin/doc @@ -1624,7 +1624,7 @@ docCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/gitIsAncestorOf b/bin/gitIsAncestorOf index e06cffdb..3c659635 100755 --- a/bin/gitIsAncestorOf +++ b/bin/gitIsAncestorOf @@ -1374,7 +1374,7 @@ gitIsAncestorOfCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/gitIsBranch b/bin/gitIsBranch index ca046c09..d0fae218 100755 --- a/bin/gitIsBranch +++ b/bin/gitIsBranch @@ -1352,7 +1352,7 @@ gitIsBranchCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/gitRenameBranch b/bin/gitRenameBranch index 40a9f301..f6471c78 100755 --- a/bin/gitRenameBranch +++ b/bin/gitRenameBranch @@ -1458,7 +1458,7 @@ gitRenameBranchCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/installRequirements b/bin/installRequirements index b5d0f779..1c5bb714 100755 --- a/bin/installRequirements +++ b/bin/installRequirements @@ -1423,7 +1423,7 @@ installRequirementsCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/mysql2puml b/bin/mysql2puml index aaa106cb..c5c6a79f 100755 --- a/bin/mysql2puml +++ b/bin/mysql2puml @@ -1525,7 +1525,7 @@ mysql2pumlCommand() { # shellcheck disable=SC2054 helpArray=(header\ configuration\ of\ the\ plant\ uml\ file) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" @@ -1568,7 +1568,7 @@ mysql2pumlCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/postmanCli b/bin/postmanCli index b360eab6..09f6440d 100755 --- a/bin/postmanCli +++ b/bin/postmanCli @@ -1152,6 +1152,8 @@ Postman::api() { responseFile="$(Framework::createTempFile)" local status=0 + # shellcheck disable=SC2034 + local -a pipeStatus=() getCollectionDataFromFile "${collectionFile}" | curl \ --request POST https://api.getpostman.com/collections \ @@ -1160,7 +1162,7 @@ Postman::api() { --header 'Accept: application/json' \ --header "X-Api-Key: ${POSTMAN_API_KEY}" \ --data @- \ - --fail --silent --show-error || status=$? + --fail --silent --show-error || Bash::handlePipelineFailure status pipeStatus Postman::displayResponse "createCollectionFromFile" "${responseFile}" @@ -1174,6 +1176,8 @@ Postman::api() { responseFile="$(Framework::createTempFile)" local status=0 + # shellcheck disable=SC2034 + local -a pipeStatus=() getCollectionDataFromFile "${collectionFile}" | curl \ --request PUT "https://api.getpostman.com/collections/${collectionId}" \ @@ -1182,7 +1186,7 @@ Postman::api() { --header 'Accept: application/json' \ --header "X-Api-Key: ${POSTMAN_API_KEY}" \ --data @- \ - --fail --silent --show-error || status=$? + --fail --silent --show-error || Bash::handlePipelineFailure status pipeStatus Postman::displayResponse "updateCollectionFromFile" "${responseFile}" @@ -1217,6 +1221,36 @@ Postman::api() { esac } +# @description ignore exit code 141 from simple command pipes +# @example use with: +# local resultingStatus=0 +# local -a originalPipeStatus=() +# cmd1 | cmd2 || Bash::handlePipelineFailure resultingStatus originalPipeStatus || true +# [[ "${resultingStatus}" = "0" ]] +# @arg $1 resultingStatusCode:&int (passed by reference) (optional) resulting status code +# @arg $2 originalStatus:int[] (passed by reference) (optional) copy of original PIPESTATUS array +# @env PIPESTATUS assuming that this function is called like in the example provided +# @see https://unix.stackexchange.com/a/709880/582856 +Bash::handlePipelineFailure() { + local -a pipeStatusBackup=("${PIPESTATUS[@]}") + local -n handlePipelineFailure_resultingStatusCode=$1 + local -n handlePipelineFailure_originalStatus=$2 + # shellcheck disable=SC2034 + handlePipelineFailure_originalStatus=("${pipeStatusBackup[@]}") + handlePipelineFailure_resultingStatusCode=0 + local statusCode + for statusCode in "${pipeStatusBackup[@]}"; do + if ((statusCode == 141)); then + return 0 + elif ((statusCode > 0)); then + # shellcheck disable=SC2034 + handlePipelineFailure_resultingStatusCode="${statusCode}" + break + fi + done + return "${handlePipelineFailure_resultingStatusCode}" +} + # @description log message to file # @arg $1 message:String the message to display Log::logSkipped() { @@ -1588,6 +1622,14 @@ commandOptionParseFinished() { displayConfig fi } +NBSP="\xc2\xa0" +NBSP2="${NBSP}${NBSP}" +argCommandHelp() { + echo -e "${__HELP_OPTION_COLOR}pull${__HELP_NORMAL}" + echo -e "${NBSP2}Pull collections from Postman back to repositories.\r" + echo -e "${__HELP_OPTION_COLOR}push${__HELP_NORMAL}" + echo -e "${NBSP2}Push repositories collections to Postman." +} postmanCliCommand() { local options_parse_cmd="$1" @@ -1921,8 +1963,8 @@ postmanCliCommand() { echo -e "${__HELP_TITLE_COLOR}ARGUMENTS:${__RESET_COLOR}" echo -e " [${__HELP_OPTION_COLOR}command${__HELP_NORMAL} {single}]" local -a helpArray - # shellcheck disable=SC2054 - helpArray=($'\e[1;34mpull\n\n \xc2\xa0\xc2\xa0Pull collections from Postman back to repositories.\n\n \e[1;34mpush\n\n \xc2\xa0\xc2\xa0Push repositories collections to Postman.\n') + # shellcheck disable=SC2054,SC2206 + mapfile -t helpArray < <(argCommandHelp) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " [${__HELP_OPTION_COLOR}commandArgs${__HELP_NORMAL} {list} (optional)]" local -a helpArray @@ -1978,7 +2020,7 @@ postmanCliCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray @@ -2032,6 +2074,7 @@ postmanCliCommand() { fi } declare optionPostmanModelConfig="$(pwd -P)/postmanCli.collections.json" +declare copyrightBeginYear="2023" # shellcheck disable=SC2317 # if function is overridden unknownOption() { diff --git a/bin/upgradeGithubRelease b/bin/upgradeGithubRelease index a62e0ce6..fe69d18d 100755 --- a/bin/upgradeGithubRelease +++ b/bin/upgradeGithubRelease @@ -1733,7 +1733,7 @@ upgradeGithubReleaseCommand() { # shellcheck disable=SC2054 helpArray=($'The argument that will be provided to the currently installed binary\n\n to check the version of the software. \n\n See options constraints below.') echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: --version" + echo ' Default value: --version' echo -e " ${__HELP_OPTION_COLOR}--current-version${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-c ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 @@ -1791,7 +1791,7 @@ upgradeGithubReleaseCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/waitForIt b/bin/waitForIt index 2f525963..8bb49f99 100755 --- a/bin/waitForIt +++ b/bin/waitForIt @@ -1451,7 +1451,7 @@ waitForItCommand() { # shellcheck disable=SC2054 helpArray=(Timeout\ in\ seconds\,\ zero\ for\ no\ timeout.) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: 15" + echo ' Default value: 15' echo -e " ${__HELP_OPTION_COLOR}--host${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-i ${__HELP_NORMAL} {single} (mandatory)" local -a helpArray # shellcheck disable=SC2054 @@ -1514,7 +1514,7 @@ waitForItCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/waitForMysql b/bin/waitForMysql index 4b7d479a..6f601176 100755 --- a/bin/waitForMysql +++ b/bin/waitForMysql @@ -1427,7 +1427,7 @@ waitForMysqlCommand() { # shellcheck disable=SC2054 helpArray=(Timeout\ in\ seconds\,\ zero\ for\ no\ timeout.) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: 15" + echo ' Default value: 15' echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" @@ -1470,7 +1470,7 @@ waitForMysqlCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/install b/install index 2cf9a935..b6784644 100755 --- a/install +++ b/install @@ -1325,7 +1325,7 @@ installCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo " Default value: default" + echo ' Default value: default' echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/src/Postman/Model/validate.bats b/src/Postman/Model/validate.bats index 77255f80..4747f4a3 100755 --- a/src/Postman/Model/validate.bats +++ b/src/Postman/Model/validate.bats @@ -11,6 +11,10 @@ setup() { export BASH_FRAMEWORK_THEME="noColor" } +teardown() { + chmod -R u+w "${BATS_TEST_TMPDIR}/pullMode" 2>/dev/null || true +} + function Postman::Model::validate::missingMode { #@test run Postman::Model::validate \ "fileNotFound.json" "invalidMode" @@ -89,17 +93,20 @@ function Postman::Model::validate::pushModeCollectionsWithErrors { #@test } function Postman::Model::validate::pullModeCollectionsWithErrors { #@test + cp -R "${BATS_TEST_DIRNAME}/testsData/pullMode" "${BATS_TEST_TMPDIR}" + chmod -w "${BATS_TEST_TMPDIR}/pullMode/GithubAPI/notWritableFile.json" + chmod -w "${BATS_TEST_TMPDIR}/pullMode" Postman::Model::getRelativeConfigDirectory() { - echo "${BATS_TEST_DIRNAME}/testsData/pullMode" + echo "${BATS_TEST_TMPDIR}/pullMode" } - local file="${BATS_TEST_DIRNAME}/testsData/pullMode/getCollectionRefs-collectionsWithErrors.json" + local file="${BATS_TEST_TMPDIR}/pullMode/getCollectionRefs-collectionsWithErrors.json" run Postman::Model::validate \ "${file}" "pull" assert_failure 1 assert_line --index 0 "ERROR - File '${file}' - collection 0 - missing file property" - assert_line --index 1 "ERROR - File '${file}' - collection fileNotWritable - collection file ${BATS_TEST_DIRNAME}/testsData/pullMode/GithubAPI/notWritableFile.json is not writable" - assert_line --index 2 "ERROR - File '${file}' - collection dirNotWritable - config directory ${BATS_TEST_DIRNAME}/testsData/pullMode is not writable" + assert_line --index 1 "ERROR - File '${file}' - collection fileNotWritable - collection file ${BATS_TEST_TMPDIR}/pullMode/GithubAPI/notWritableFile.json is not writable" + assert_line --index 2 "ERROR - File '${file}' - collection dirNotWritable - config directory ${BATS_TEST_TMPDIR}/pullMode is not writable" assert_lines_count 3 } diff --git a/src/Postman/api.bats b/src/Postman/api.bats index add09791..43e3b429 100755 --- a/src/Postman/api.bats +++ b/src/Postman/api.bats @@ -4,6 +4,8 @@ source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" # shellcheck source=src/Postman/api.sh source "${rootDir}/src/Postman/api.sh" +# shellcheck source=vendor/bash-tools-framework/src/Bash/handlePipelineFailure.sh +source "${FRAMEWORK_ROOT_DIR}/src/Bash/handlePipelineFailure.sh" setup() { export BASH_FRAMEWORK_THEME="noColor" diff --git a/src/Postman/api.sh b/src/Postman/api.sh index 817f46bc..f3980587 100755 --- a/src/Postman/api.sh +++ b/src/Postman/api.sh @@ -30,6 +30,8 @@ Postman::api() { responseFile="$(Framework::createTempFile)" local status=0 + # shellcheck disable=SC2034 + local -a pipeStatus=() getCollectionDataFromFile "${collectionFile}" | curl \ --request POST https://api.getpostman.com/collections \ @@ -38,7 +40,7 @@ Postman::api() { --header 'Accept: application/json' \ --header "X-Api-Key: ${POSTMAN_API_KEY}" \ --data @- \ - --fail --silent --show-error || status=$? + --fail --silent --show-error || Bash::handlePipelineFailure status pipeStatus Postman::displayResponse "createCollectionFromFile" "${responseFile}" @@ -52,6 +54,8 @@ Postman::api() { responseFile="$(Framework::createTempFile)" local status=0 + # shellcheck disable=SC2034 + local -a pipeStatus=() getCollectionDataFromFile "${collectionFile}" | curl \ --request PUT "https://api.getpostman.com/collections/${collectionId}" \ @@ -60,7 +64,7 @@ Postman::api() { --header 'Accept: application/json' \ --header "X-Api-Key: ${POSTMAN_API_KEY}" \ --data @- \ - --fail --silent --show-error || status=$? + --fail --silent --show-error || Bash::handlePipelineFailure status pipeStatus Postman::displayResponse "updateCollectionFromFile" "${responseFile}" diff --git a/src/_binaries/Postman/command.postmanCli.tpl b/src/_binaries/Postman/command.postmanCli.tpl index 6f5a9151..eb87dccf 100644 --- a/src/_binaries/Postman/command.postmanCli.tpl +++ b/src/_binaries/Postman/command.postmanCli.tpl @@ -2,15 +2,21 @@ declare versionNumber="1.0" declare commandFunctionName="postmanCliCommand" declare help="Push/Pull postman collections of all the configured repositories" -declare copyrightBeginYear="2023" # shellcheck disable=SC2016 % .INCLUDE "$(dynamicTemplateDir _binaries/options/options.base.tpl)" -% - NBSP="\xc2\xa0" NBSP2="${NBSP}${NBSP}" +argCommandHelp() { + echo -e "${__HELP_OPTION_COLOR}pull${__HELP_NORMAL}" + echo -e "${NBSP2}Pull collections from Postman back to repositories." $'\r' + echo -e "${__HELP_OPTION_COLOR}push${__HELP_NORMAL}" + echo -e "${NBSP2}Push repositories collections to Postman." +} + +% + # shellcheck source=/dev/null source <( Options::generateGroup \ @@ -28,17 +34,14 @@ source <( --variable-name "optionPostmanModelConfig" \ --function-name optionPostmanModelConfigFunction + argCommandHelp() { :; } Options::generateArg \ --variable-name "argCommand" \ --min 0 \ --max 1 \ --name "command" \ --authorized-values 'pull|push' \ - --help \ - $'${__HELP_OPTION_COLOR}pull${__HELP_NORMAL}\n - ${NBSP2}Pull collections from Postman back to repositories.\n - ${__HELP_OPTION_COLOR}push${__HELP_NORMAL}\n - ${NBSP2}Push repositories collections to Postman.\n' \ + --help argCommandHelp \ --function-name argCommandFunction Options::generateArg \ @@ -63,6 +66,7 @@ options+=( Options::generateCommand "${options[@]}" % declare optionPostmanModelConfig="$(pwd -P)/postmanCli.collections.json" +declare copyrightBeginYear="2023" # shellcheck disable=SC2317 # if function is overridden unknownOption() { diff --git a/src/_binaries/Postman/testsData/postmanCli.help.txt b/src/_binaries/Postman/testsData/postmanCli.help.txt index 17c44e0e..04c6028a 100644 --- a/src/_binaries/Postman/testsData/postmanCli.help.txt +++ b/src/_binaries/Postman/testsData/postmanCli.help.txt @@ -10,10 +10,8 @@ Push/Pull postman collections of all the configured repositories ARGUMENTS: [command {single}] - pull -   Pull collections from Postman back to repositories. - push -   Push repositories collections to Postman. + pull   Pull collections from Postman back to repositories. + push   Push repositories collections to Postman. [commandArgs {list} (optional)] list of postman collection's references to pull or push or no argument to pull or push all the collections @@ -70,4 +68,4 @@ https://github.com/fchastanet/bash-tools/tree/master/src/_binaries/Postman/postm LICENSE: MIT License -Copyright (c) 2024-now François Chastanet +Copyright (c) 2023-now François Chastanet From c96011d6b2f4527bd842afe67ca5808e209a6ae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Mon, 15 Jan 2024 02:26:55 +0100 Subject: [PATCH 6/8] improved help message --- bin/doc | 13 ++ bin/postmanCli | 210 ++++++++----------- src/_binaries/Postman/command.postmanCli.tpl | 22 +- 3 files changed, 109 insertions(+), 136 deletions(-) diff --git a/bin/doc b/bin/doc index 17f60051..a7bf684b 100755 --- a/bin/doc +++ b/bin/doc @@ -976,6 +976,19 @@ UI::requireTheme() { UI::theme "${BASH_FRAMEWORK_THEME-default}" } +# @description remove ansi codes from input or files given as argument +# @arg $@ files:String[] the files to filter +# @exitcode * if one of the filter command fails +# @stdin you can use stdin as alternative to files argument +# @stdout the filtered content +# @see https://en.wikipedia.org/wiki/ANSI_escape_code +# shellcheck disable=SC2120 +Filters::removeAnsiCodes() { + # cspell:disable + sed -E 's/\x1b\[[0-9;]*[mGKHF]//g' "$@" + # cspell:enable +} + # @description Display message using skip color (yellow) # @arg $1 message:String the message to display Log::displaySkipped() { diff --git a/bin/postmanCli b/bin/postmanCli index 09f6440d..65abd4b7 100755 --- a/bin/postmanCli +++ b/bin/postmanCli @@ -101,10 +101,12 @@ trap cleanOnExit EXIT HUP QUIT ABRT TERM # @description concat each element of an array with a separator # but wrapping text when line length is more than provided argument # The algorithm will try not to cut the array element if it can. -# if an arg can be placed on current line it will be, +# - if an arg can be placed on current line it will be, # otherwise current line is printed and arg is added to the new # current line -# empty arg is interpreted as a new line. +# - Empty arg is interpreted as a new line. +# - Add \r to arg in order to force break line and avoid following +# arg to be concatenated with current arg. # # @arg $1 glue:String # @arg $2 maxLineLength:int @@ -126,117 +128,102 @@ Array::wrap2() { return 0 fi - eatNextSpaces() { - if [[ "${currentChar}" != [[:space:]] ]]; then - ((i--)) || true - return 0 - fi - for (( ; i < textLength; i++)); do - if [[ "${text:${i}:1}" != [[:space:]] ]]; then - ((i--)) || true - break - fi - done - } printCurrentLine() { - echo -e "${currentLine}" | sed -E -e 's/[[:blank:]]*$//' + if ((isNewline == 0)) || ((previousLineEmpty == 1)); then + echo + fi ((isNewline = 1)) - currentLine="${indentStr}" + echo -en "${indentStr}" ((currentLineLength = indentNextLine)) || true } - nextLine() { - printCurrentLine - eatNextSpaces - } - local currentLine currentChar ansiCode - local -i isAnsiCode currentLineLength=0 isNewline=1 textLength=0 - local text="" - local arg="" - while (($# > 0)); do - arg="$1" - shift || true - if ((${#arg} == 0)) || [[ "${arg}" = $'\n' ]]; then - if ((isNewline == 0)); then - # isNewline = 0 means currentLine is not empty - printCurrentLine - fi - echo - continue - fi - local textFirstLine="${arg%%$'\n'*}" - text="$(echo "${arg}" | sed -E '1d')" - ((textLength = ${#text})) || true - local textFirstLineNoAnsi - textFirstLineNoAnsi="$(echo "${textFirstLine}" | Filters::removeAnsiCodes)" - local -i textFirstLineNoAnsiLength=0 - ((textFirstLineNoAnsiLength = ${#textFirstLineNoAnsi})) || true - - if ((isNewline == 0)); then - glueLength="${#glue}" + appendToCurrentLine() { + local text="$1" + local -i length=$2 + ((currentLineLength += length)) || true + ((isNewline = 0)) || true + if [[ "${text: -1}" = $'\r' ]]; then + text="${text:0:-1}" + echo -en "${text%%+([[:blank:]])}" + printCurrentLine else - glueLength="0" + echo -en "${text%%+([[:blank:]])}" fi - if ((currentLineLength + textFirstLineNoAnsiLength + glueLength > maxLineLength)); then - if ((isNewline == 0)); then - # isNewline = 0 means currentLine is not empty + } + + ( + local currentLine + local -i currentLineLength=0 isNewline=1 argLength=0 + local -a additionalLines + local -i previousLineEmpty=0 + local arg="" + + while (($# > 0)); do + arg="$1" + shift || true + + # replace tab by 2 spaces + arg="${arg//$'\t'/ }" + # remove trailing spaces + arg="${arg%[[:blank:]]}" + if [[ "${arg}" = $'\n' || -z "${arg}" ]]; then printCurrentLine + ((previousLineEmpty = 1)) + continue + else + if ((previousLineEmpty == 1)); then + printCurrentLine + fi + ((previousLineEmpty = 0)) || true fi - # restore current arg without considering first line - text="${arg}" - ((textLength = ${#text})) || true - else - if ((isNewline == 0)); then - # isNewline = 0 means currentLine is not empty - currentLine+="${glue}" - ((currentLineLength += glueLength)) || true + # convert eol to args + mapfile -t additionalLines <<<"${arg}" + if ((${#additionalLines[@]} > 1)); then + set -- "${additionalLines[@]}" "$@" + continue fi - currentLine+="${textFirstLine}" - isNewline="0" - ((currentLineLength += ${#textFirstLine})) || true - fi - for ((i = 0; i < textLength; i++)); do - currentChar="${text:${i}:1}" - - if [[ "${currentChar}" = $'\r' ]]; then - # ignore - true - elif [[ "${currentChar}" = "\x1b" ]]; then - isAnsiCode=1 - ansiCode+="${currentChar}" - elif ((isAnsiCode == 1)); then - ansiCode+="${currentChar}" - if [[ "${currentChar}" =~ [mGKHF] ]]; then - isAnsiCode=0 - echo -e "${ansiCode}" - elif [[ "${currentChar}" = $'\n' ]]; then - # invalid ansi code, ignore it - isAnsiCode=0 - ansiCode="" + ((argLength = ${#arg})) || true + + # empty arg + if ((argLength == 0)); then + if ((isNewline == 0)); then + # isNewline = 0 means currentLine is not empty + printCurrentLine fi + continue + fi + + if ((isNewline == 0)); then + glueLength="${#glue}" else - # non ansi code - if [[ "${currentChar}" = $'\n' ]] || ((currentLineLength == maxLineLength)); then - nextLine - elif [[ "${currentChar}" = "\t" ]]; then - if ((currentLineLength + 2 <= maxLineLength)); then - currentLine+=" " - ((isNewline = 0)) || true - ((currentLineLength = currentLineLength + 2)) - else - nextLine - fi + glueLength="0" + fi + if ((currentLineLength + argLength + glueLength > maxLineLength)); then + if ((argLength + glueLength > maxLineLength)); then + # arg is too long to even fit on one line + # we have to split the arg on current and next line + local -i remainingLineLength + ((remainingLineLength = maxLineLength - currentLineLength - glueLength)) + appendToCurrentLine "${glue:0:${glueLength}}${arg:0:${remainingLineLength}}" "$((glueLength + remainingLineLength))" + printCurrentLine + arg="${arg:${remainingLineLength}}" + # remove leading spaces + arg="${arg##[[:blank:]]}" + + set -- "${arg}" "$@" else - currentLine+="${currentChar}" - ((isNewline = 0)) || true - ((++currentLineLength)) + # the arg can fit on next line + printCurrentLine + appendToCurrentLine "${arg}" "${argLength}" fi + else + appendToCurrentLine "${glue:0:${glueLength}}${arg}" "$((glueLength + argLength))" fi done - done - if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then - printCurrentLine - fi + if [[ "${currentLine}" != "" ]] && [[ ! "${currentLine}" =~ ^[\ \t]+$ ]]; then + printCurrentLine + fi + ) | sed -E -e 's/[[:blank:]]+$//' } # @description ensure env files are loaded @@ -798,19 +785,6 @@ Env::pathPrepend() { done } -# @description remove ansi codes from input or files given as argument -# @arg $@ files:String[] the files to filter -# @exitcode * if one of the filter command fails -# @stdin you can use stdin as alternative to files argument -# @stdout the filtered content -# @see https://en.wikipedia.org/wiki/ANSI_escape_code -# shellcheck disable=SC2120 -Filters::removeAnsiCodes() { - # cspell:disable - sed -E 's/\x1b\[[0-9;]*[mGKHF]//g' "$@" - # cspell:enable -} - # @description log message to file # @arg $1 message:String the message to display Log::logDebug() { @@ -1622,14 +1596,6 @@ commandOptionParseFinished() { displayConfig fi } -NBSP="\xc2\xa0" -NBSP2="${NBSP}${NBSP}" -argCommandHelp() { - echo -e "${__HELP_OPTION_COLOR}pull${__HELP_NORMAL}" - echo -e "${NBSP2}Pull collections from Postman back to repositories.\r" - echo -e "${__HELP_OPTION_COLOR}push${__HELP_NORMAL}" - echo -e "${NBSP2}Push repositories collections to Postman." -} postmanCliCommand() { local options_parse_cmd="$1" @@ -1963,20 +1929,20 @@ postmanCliCommand() { echo -e "${__HELP_TITLE_COLOR}ARGUMENTS:${__RESET_COLOR}" echo -e " [${__HELP_OPTION_COLOR}command${__HELP_NORMAL} {single}]" local -a helpArray - # shellcheck disable=SC2054,SC2206 - mapfile -t helpArray < <(argCommandHelp) + # shellcheck disable=SC2054 + helpArray=($'\e[1;34mpull\r\n Pull collections from Postman back to repositories.\r\n\e[1;34mpush\r\n Push repositories collections to Postman.') echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " [${__HELP_OPTION_COLOR}commandArgs${__HELP_NORMAL} {list} (optional)]" local -a helpArray # shellcheck disable=SC2054 - helpArray=($'list of postman collection\'s references to pull or push\n\n or no argument to pull or push all the collections') + helpArray=($'list of postman collection\'s references to pull or push\r\nor no argument to pull or push all the collections') echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}PUSH/PULL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--postman-model${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-m ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 - helpArray=($'postmanCli model file to use\n\n Default value: /postmanCli.collections.json') + helpArray=($'postmanCli model file to use\r\nDefault value: /postmanCli.collections.json') echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" diff --git a/src/_binaries/Postman/command.postmanCli.tpl b/src/_binaries/Postman/command.postmanCli.tpl index eb87dccf..fcc11883 100644 --- a/src/_binaries/Postman/command.postmanCli.tpl +++ b/src/_binaries/Postman/command.postmanCli.tpl @@ -6,14 +6,6 @@ declare help="Push/Pull postman collections of all the configured repositories" % .INCLUDE "$(dynamicTemplateDir _binaries/options/options.base.tpl)" -NBSP="\xc2\xa0" -NBSP2="${NBSP}${NBSP}" -argCommandHelp() { - echo -e "${__HELP_OPTION_COLOR}pull${__HELP_NORMAL}" - echo -e "${NBSP2}Pull collections from Postman back to repositories." $'\r' - echo -e "${__HELP_OPTION_COLOR}push${__HELP_NORMAL}" - echo -e "${NBSP2}Push repositories collections to Postman." -} % @@ -26,22 +18,24 @@ source <( # shellcheck disable=SC2016 Options::generateOption \ --variable-type String \ - --help $'postmanCli model file to use\n - Default value: /postmanCli.collections.json' \ + --help $'postmanCli model file to use\r +Default value: /postmanCli.collections.json' \ --group groupPushPullFunction \ --alt "--postman-model" \ --alt "-m" \ --variable-name "optionPostmanModelConfig" \ --function-name optionPostmanModelConfigFunction - argCommandHelp() { :; } Options::generateArg \ --variable-name "argCommand" \ --min 0 \ --max 1 \ --name "command" \ --authorized-values 'pull|push' \ - --help argCommandHelp \ + --help $'${__HELP_OPTION_COLOR}pull${__HELP_NORMAL}\r + Pull collections from Postman back to repositories.\r +${__HELP_OPTION_COLOR}push${__HELP_NORMAL}\r + Push repositories collections to Postman.' \ --function-name argCommandFunction Options::generateArg \ @@ -50,8 +44,8 @@ source <( --max -1 \ --name "commandArgs" \ --help \ - $'list of postman collection\'s references to pull or push\n - or no argument to pull or push all the collections' \ + $'list of postman collection\'s references to pull or push\r +or no argument to pull or push all the collections' \ --function-name commandArgsFunction ) From dccf059b781b5455cb4b36001a54fee00f5bbc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Mon, 15 Jan 2024 18:16:28 +0100 Subject: [PATCH 7/8] fixed .github/workflows/precommit-autoupdate.yml permissions --- .github/workflows/precommit-autoupdate.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/precommit-autoupdate.yml b/.github/workflows/precommit-autoupdate.yml index 53ad0fa6..e6061bad 100644 --- a/.github/workflows/precommit-autoupdate.yml +++ b/.github/workflows/precommit-autoupdate.yml @@ -13,6 +13,9 @@ permissions: read-all jobs: auto-update: runs-on: ubuntu-22.04 + permissions: + pull-requests: write + contents: write steps: # kics-scan ignore-line - uses: actions/checkout@v4 From 7d7138ffe7d08db7164cc6811d3e6f70d697603c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Mon, 15 Jan 2024 21:50:24 +0100 Subject: [PATCH 8/8] fixed UT --- .cspell/softwares.txt | 6 + .jscpd.json | 5 +- .mega-linter.yml | 12 + Commands.tmpl.md | 8 +- bin/postmanCli | 15 +- ...Advanced_with_auth_postman_collection.json | 2 +- .../Atlas.postman_environment.json | 279 ------------------ ...> MongoDBDataAPI.postman_environment.json} | 0 src/Postman/Commands/pullCollections.sh | 2 +- .../Model/checkIfValidCollectionRefs.sh | 2 +- src/_binaries/Postman/command.postmanCli.tpl | 13 +- .../Postman/testsData/postmanCli.help.txt | 6 +- 12 files changed, 53 insertions(+), 297 deletions(-) delete mode 100644 conf/postmanCli/MongoDbData/Atlas.postman_environment.json rename conf/postmanCli/MongoDbData/{Data API.postman_environment.json => MongoDBDataAPI.postman_environment.json} (100%) diff --git a/.cspell/softwares.txt b/.cspell/softwares.txt index dc0199f7..666eb7e2 100644 --- a/.cspell/softwares.txt +++ b/.cspell/softwares.txt @@ -154,3 +154,9 @@ TRIVY KICS TRUFFLEHOG GRYPE +octocat +prerequest +slurpfile +EJSON +ejson +clairefro diff --git a/.jscpd.json b/.jscpd.json index ed84a6cf..bac9e1bc 100644 --- a/.jscpd.json +++ b/.jscpd.json @@ -25,6 +25,9 @@ "**/.idea/**", "**/report/**", "**/*.svg", - "**/testsData/**" + "**/testsData/**", + "conf/postmanCli/MongoDbData/MongoDBDataAPI.postman_collection.json", + "conf/postmanCli/GithubAPI/GitHubAPI-01-Basic_no_auth_postman_collection.json", + "conf/postmanCli/GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json" ] } diff --git a/.mega-linter.yml b/.mega-linter.yml index 8e0aba5e..aa5a1924 100644 --- a/.mega-linter.yml +++ b/.mega-linter.yml @@ -109,3 +109,15 @@ SPELL_LYCHEE_FILTER_REGEX_EXCLUDE: | ) JSON_ESLINT_PLUGIN_JSONC_FILE_NAME: .eslintrc.js +JSON_PRETTIER_FILTER_REGEX_EXCLUDE: | + (?x)( + ^src/Postman/Model/testsData/pushMode/GithubAPI/notValidJsonFile.json$| + ^src/Postman/Collection/testsData/postmanCollections_invalidJsonFile.json$| + ^src/Postman/Model/testsData/getCollectionInvalid.json$ + ) +JSON_ESLINT_PLUGIN_JSONC_FILTER_REGEX_EXCLUDE: | + (?x)( + ^src/Postman/Model/testsData/pushMode/GithubAPI/notValidJsonFile.json$| + ^src/Postman/Collection/testsData/postmanCollections_invalidJsonFile.json$| + ^src/Postman/Model/testsData/getCollectionInvalid.json$ + ) diff --git a/Commands.tmpl.md b/Commands.tmpl.md index 0867bb51..609c49a0 100644 --- a/Commands.tmpl.md +++ b/Commands.tmpl.md @@ -21,8 +21,8 @@ - [4.1.3. Example 2: connect to mysql container with root user](#413-example-2-connect-to-mysql-container-with-root-user) - [4.1.4. Example 3: connect to mysql server in order to execute a query](#414-example-3-connect-to-mysql-server-in-order-to-execute-a-query) - [4.1.5. Example 4: pipe sql command to mysql container](#415-example-4-pipe-sql-command-to-mysql-container) - - [4.1. bin/postmanCli](#41-binpostmancli) - - [4.1.1. Help](#411-help-1) + - [4.2. bin/postmanCli](#42-binpostmancli) + - [4.2.1. Help](#421-help) - [5. Database tools](#5-database-tools) - [5.1. bin/dbQueryAllDatabases](#51-bindbqueryalldatabases) - [5.1.1. Help](#511-help) @@ -196,9 +196,9 @@ project-mysql //bin/bash -c 'mysql -h127.0.0.1 -uroot -proot -P3306' notice that as input is given to the command, tty option is not provided to docker exec -### 4.1. bin/postmanCli +### 4.2. bin/postmanCli -#### 4.1.1. Help +#### 4.2.1. Help ```text @@@postmanCli_help@@@ diff --git a/bin/postmanCli b/bin/postmanCli index 65abd4b7..e4f6a122 100755 --- a/bin/postmanCli +++ b/bin/postmanCli @@ -907,7 +907,7 @@ Postman::Commands::pullCollections() { echo "${response}" >"${collectionFile}" Log::displaySuccess "Collection '${collectionName}' has been pulled successfully to '${collectionFile}'" else - Log::displayError "Collection '${collectionName}' an error occured pulling the collection from postman" + Log::displayError "Collection '${collectionName}' an error occurred pulling the collection from postman" fi fi } @@ -958,7 +958,7 @@ Postman::Commands::pushCollections() { # exists in the model file # @arg $1 modelFile:String model file in which availableRefs have been retrieved # @arg $2 availableRefs:&String[] list of known collection references -# @arg $3 modelCollectionRefs:&String[] list ofcollection references to check +# @arg $3 modelCollectionRefs:&String[] list of collection references to check Postman::Model::checkIfValidCollectionRefs() { local modelFile="$1" local -n availableRefs=$2 @@ -1929,8 +1929,8 @@ postmanCliCommand() { echo -e "${__HELP_TITLE_COLOR}ARGUMENTS:${__RESET_COLOR}" echo -e " [${__HELP_OPTION_COLOR}command${__HELP_NORMAL} {single}]" local -a helpArray - # shellcheck disable=SC2054 - helpArray=($'\e[1;34mpull\r\n Pull collections from Postman back to repositories.\r\n\e[1;34mpush\r\n Push repositories collections to Postman.') + # shellcheck disable=SC2054,SC2206 + mapfile -t helpArray < <(argCommandHelp) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" echo -e " [${__HELP_OPTION_COLOR}commandArgs${__HELP_NORMAL} {list} (optional)]" local -a helpArray @@ -2042,6 +2042,13 @@ postmanCliCommand() { declare optionPostmanModelConfig="$(pwd -P)/postmanCli.collections.json" declare copyrightBeginYear="2023" +argCommandHelp() { + echo "${__HELP_OPTION_COLOR}pull${__HELP_NORMAL}" $'\r' + echo " Pull collections from Postman back to repositories." $'\r' + echo "${__HELP_OPTION_COLOR}push${__HELP_NORMAL}" $'\r' + echo ' Push repositories collections to Postman.' +} + # shellcheck disable=SC2317 # if function is overridden unknownOption() { commandArgs+=("$1") diff --git a/conf/postmanCli/GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json b/conf/postmanCli/GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json index 249c0cbb..870a21d7 100644 --- a/conf/postmanCli/GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json +++ b/conf/postmanCli/GithubAPI/GitHubAPI-02-Advanced_with_auth_postman_collection.json @@ -96,7 +96,7 @@ } ] }, - "description": "**WARNING!** Running this request will overwrite an existing file if specified filepath already exists in the provided repo, if you have the proper authorization credentials. Proceed with caution!\n\n## Before making this request \nEncode the file you would like to upload from your computer into base64 using request #1 above. \n\nThat request will save the base64 encoded file to a colelction variable called `encodedFileData`, which will be sent in the body of this request.\n\nEdit the values in the `Params` tab in the request before sending." + "description": "**WARNING!** Running this request will overwrite an existing file if specified filepath already exists in the provided repo, if you have the proper authorization credentials. Proceed with caution!\n\n## Before making this request \nEncode the file you would like to upload from your computer into base64 using request #1 above. \n\nThat request will save the base64 encoded file to a collection variable called `encodedFileData`, which will be sent in the body of this request.\n\nEdit the values in the `Params` tab in the request before sending." }, "response": [], "uid": "27246549-fb33abcc-8329-4fa9-9fbb-8e513f9307f6" diff --git a/conf/postmanCli/MongoDbData/Atlas.postman_environment.json b/conf/postmanCli/MongoDbData/Atlas.postman_environment.json deleted file mode 100644 index dc88c4f3..00000000 --- a/conf/postmanCli/MongoDbData/Atlas.postman_environment.json +++ /dev/null @@ -1,279 +0,0 @@ -{ - "id": "5739feed-60b0-4a55-a6e5-ea3ac94af110", - "name": "Atlas", - "values": [ - { - "key": "base_url", - "value": "https://cloud.mongodb.com", - "enabled": true - }, - { - "key": "version", - "value": "v1.0", - "enabled": true - }, - { - "key": "ProjectID", - "value": "616d70c51ec022309622497a", - "enabled": true - }, - { - "key": "CLUSTER-NAME", - "value": "Cluster0", - "enabled": true - }, - { - "key": "databaseName", - "value": "", - "enabled": true - }, - { - "key": "dbUser", - "value": "", - "enabled": true - }, - { - "key": "ORG-ID", - "value": "", - "enabled": true - }, - { - "key": "API-key-pwd", - "value": "", - "enabled": true - }, - { - "key": "API-key-usr", - "value": "", - "enabled": true - }, - { - "key": "INVITATION_ID", - "value": "", - "enabled": true - }, - { - "key": "INVOICE-ID", - "value": "", - "enabled": true - }, - { - "key": "PROJECT_NAME", - "value": "", - "enabled": true - }, - { - "key": "TEAM-ID", - "value": "", - "enabled": true - }, - { - "key": "USER-ID", - "value": "", - "enabled": true - }, - { - "key": "PROJ-INVITATIO-ID", - "value": "", - "enabled": true - }, - { - "key": "TEAM-NAME", - "value": "", - "enabled": true - }, - { - "key": "SAMPLE-DATASET-ID", - "value": "", - "enabled": true - }, - { - "key": "CLOUD-PROVIDER", - "value": "", - "enabled": true - }, - { - "key": "CLUSTER-TIER", - "value": "", - "enabled": true - }, - { - "key": "INSTANCE-NAME", - "value": "", - "enabled": true - }, - { - "key": "ALERT-ID", - "value": "", - "enabled": true - }, - { - "key": "ALERT-CONFIG-ID", - "value": "", - "enabled": true - }, - { - "key": "DATABASE-NAME", - "value": "", - "enabled": true - }, - { - "key": "COLLECTION-NAME", - "value": "", - "enabled": true - }, - { - "key": "INDEX-ID", - "value": "", - "enabled": true - }, - { - "key": "SNAPSHOT-ID", - "value": "", - "enabled": true - }, - { - "key": "JOB-ID", - "value": "", - "enabled": true - }, - { - "key": "RESTORE-JOB-ID", - "value": "", - "enabled": true - }, - { - "key": "restoreJobId", - "value": "", - "enabled": true - }, - { - "key": "TARGET-CLUSTER-NAME", - "value": "", - "enabled": true - }, - { - "key": "TARGET-GROUP-ID", - "value": "", - "enabled": true - }, - { - "key": "targetGroupId", - "value": "", - "enabled": true - }, - { - "key": "clusterName", - "value": "", - "enabled": true - }, - { - "key": "RESTORE-ID", - "value": "", - "enabled": true - }, - { - "key": "ARCHIVE-ID", - "value": "", - "enabled": true - }, - { - "key": "CONTAINER-ID", - "value": "", - "enabled": true - }, - { - "key": "PEER-ID", - "value": "", - "enabled": true - }, - { - "key": "ENDPOINT-SERVICE-ID", - "value": "", - "enabled": true - }, - { - "key": "ENDPOINT-ID", - "value": "", - "enabled": true - }, - { - "key": "API-KEY-ID", - "value": "", - "enabled": true - }, - { - "key": "ACCESS-LIST-ENTRY", - "value": "", - "enabled": true - }, - { - "key": "IP-ADDRESS", - "value": "", - "enabled": true - }, - { - "key": "PROCESS-HOST", - "value": "", - "enabled": true - }, - { - "key": "PROCESS-PORT", - "value": "", - "enabled": true - }, - { - "key": "DISK-NAME", - "value": "", - "enabled": true - }, - { - "key": "HOSTNAME", - "value": "", - "enabled": true - }, - { - "key": "LOG-NAME", - "value": "", - "enabled": true - }, - { - "key": "USER-NAME", - "value": "", - "enabled": true - }, - { - "key": "ROLE-ID", - "value": "", - "enabled": true - }, - { - "key": "EVENT-ID", - "value": "", - "enabled": true - }, - { - "key": "DATA-LAKE-NAME", - "value": "", - "enabled": true - }, - { - "key": "VALIDATION-ID", - "value": "", - "enabled": true - }, - { - "key": "LIVE-MIGRATION-ID", - "value": "", - "enabled": true - }, - { - "key": "ROLE-NAME", - "value": "", - "enabled": true - } - ], - "_postman_variable_scope": "environment", - "_postman_exported_at": "2024-01-04T12:18:13.332Z", - "_postman_exported_using": "Postman/10.21.11-240102-2003" -} diff --git a/conf/postmanCli/MongoDbData/Data API.postman_environment.json b/conf/postmanCli/MongoDbData/MongoDBDataAPI.postman_environment.json similarity index 100% rename from conf/postmanCli/MongoDbData/Data API.postman_environment.json rename to conf/postmanCli/MongoDbData/MongoDBDataAPI.postman_environment.json diff --git a/src/Postman/Commands/pullCollections.sh b/src/Postman/Commands/pullCollections.sh index 06d69030..c5a332b8 100755 --- a/src/Postman/Commands/pullCollections.sh +++ b/src/Postman/Commands/pullCollections.sh @@ -36,7 +36,7 @@ Postman::Commands::pullCollections() { echo "${response}" >"${collectionFile}" Log::displaySuccess "Collection '${collectionName}' has been pulled successfully to '${collectionFile}'" else - Log::displayError "Collection '${collectionName}' an error occured pulling the collection from postman" + Log::displayError "Collection '${collectionName}' an error occurred pulling the collection from postman" fi fi } diff --git a/src/Postman/Model/checkIfValidCollectionRefs.sh b/src/Postman/Model/checkIfValidCollectionRefs.sh index 778a08b3..dc53a205 100755 --- a/src/Postman/Model/checkIfValidCollectionRefs.sh +++ b/src/Postman/Model/checkIfValidCollectionRefs.sh @@ -4,7 +4,7 @@ # exists in the model file # @arg $1 modelFile:String model file in which availableRefs have been retrieved # @arg $2 availableRefs:&String[] list of known collection references -# @arg $3 modelCollectionRefs:&String[] list ofcollection references to check +# @arg $3 modelCollectionRefs:&String[] list of collection references to check Postman::Model::checkIfValidCollectionRefs() { local modelFile="$1" local -n availableRefs=$2 diff --git a/src/_binaries/Postman/command.postmanCli.tpl b/src/_binaries/Postman/command.postmanCli.tpl index fcc11883..e46935a3 100644 --- a/src/_binaries/Postman/command.postmanCli.tpl +++ b/src/_binaries/Postman/command.postmanCli.tpl @@ -26,16 +26,14 @@ Default value: /postmanCli.collections.json' \ --variable-name "optionPostmanModelConfig" \ --function-name optionPostmanModelConfigFunction + argCommandHelp() { :; } Options::generateArg \ --variable-name "argCommand" \ --min 0 \ --max 1 \ --name "command" \ --authorized-values 'pull|push' \ - --help $'${__HELP_OPTION_COLOR}pull${__HELP_NORMAL}\r - Pull collections from Postman back to repositories.\r -${__HELP_OPTION_COLOR}push${__HELP_NORMAL}\r - Push repositories collections to Postman.' \ + --help argCommandHelp \ --function-name argCommandFunction Options::generateArg \ @@ -62,6 +60,13 @@ Options::generateCommand "${options[@]}" declare optionPostmanModelConfig="$(pwd -P)/postmanCli.collections.json" declare copyrightBeginYear="2023" +argCommandHelp() { + echo "${__HELP_OPTION_COLOR}pull${__HELP_NORMAL}" $'\r' + echo " Pull collections from Postman back to repositories." $'\r' + echo "${__HELP_OPTION_COLOR}push${__HELP_NORMAL}" $'\r' + echo ' Push repositories collections to Postman.' +} + # shellcheck disable=SC2317 # if function is overridden unknownOption() { commandArgs+=("$1") diff --git a/src/_binaries/Postman/testsData/postmanCli.help.txt b/src/_binaries/Postman/testsData/postmanCli.help.txt index 04c6028a..78dc41e6 100644 --- a/src/_binaries/Postman/testsData/postmanCli.help.txt +++ b/src/_binaries/Postman/testsData/postmanCli.help.txt @@ -10,8 +10,10 @@ Push/Pull postman collections of all the configured repositories ARGUMENTS: [command {single}] - pull   Pull collections from Postman back to repositories. - push   Push repositories collections to Postman. + pull + Pull collections from Postman back to repositories. + push + Push repositories collections to Postman. [commandArgs {list} (optional)] list of postman collection's references to pull or push or no argument to pull or push all the collections