Merge pull request #1 from CTOTools-skills-code-agent/4.0.0.0/IIAA-XYZ-development-scripts-skill-001

IIAA-XYZ: add development-scripts agent skill
This commit is contained in:
2026-07-30 22:27:55 +03:00
committed by GitHub Enterprise
57 changed files with 2051 additions and 1 deletions
+55 -1
View File
@@ -1 +1,55 @@
# development-scripts # development-scripts
Agent Skill for shell script modules under a repository's `.scripts/` directory — the
`api/` + `lib/` split, the `--index.sh` bootstrap chain, Taskfile integration, and the shared
`loggers` and `base` foundation modules.
## Layout
```text
development-scripts/
├── SKILL.md # Entry point — routing, anatomy, naming, runtime flow
├── references/
│ ├── module-anatomy.md # Reader, validator, index files, implementations, wrappers
│ ├── shared-modules.md # loggers and base, and the logging bootstrap rule
│ ├── taskfile.md # Module and root Taskfile integration
│ ├── workflows.md # Create, change, validate
│ └── module-patterns.md # Module type and dependency decision guide
└── assets/
├── module-example-v1/ # Scaffold to copy for a new module
├── loggers/ # Working reference implementation
└── base/ # Working reference implementation
```
## The model
```text
<target-repository>/
Taskfile.yml
.scripts/
<module>/
api/ # public command wrappers — what users run
lib/ # implementation functions — what the code calls
Taskfile.yml # only when exposed through task
```
Commands run from the repository root:
```bash
./.scripts/<module>/api/<command>.sh --dry-run
task <module-alias>:<task-name> -- --dry-run
```
Every source path is repository-root-relative, and the bootstrap chain — reader, then
validator, then API index — guarantees an implementation function sees a fully-prepared
environment.
## Deploy
```bash
cd ../skill-manager/scripts
task deploy -- --skill-dir="$(cd ../../development-scripts && pwd)"
```
Built with the `skill-manager` skill, following the
[agentskills.io specification](https://agentskills.io/specification).
+198
View File
@@ -0,0 +1,198 @@
---
name: development-scripts
description: >
Create, refactor, review, document, and maintain shell script modules under a repository's
.scripts/ directory — the api/ + lib/ split, the --index.sh / --index-api.sh /
--env-vars-reader.sh / --env-vars-validator.sh bootstrap chain, module and root Taskfile.yml
integration, logging through the shared loggers module, and shared helpers from the base
module. Use when adding a new script module or a new command to an existing one; writing an
api/ wrapper or a lib/ implementation function; adding a CLI flag or a required environment
variable; wiring a module into task; debugging a script that produces no output, cannot find
a function, or unexpectedly loads .env; or reviewing shell module work for naming, sourcing
order, and secret-safety — even when the user only says ".scripts", "Taskfile", "task
runner", "shell module", or names a specific module like loggers or base.
license: Proprietary
metadata:
author: workspace-skills-code-agent
version: "1.0"
spec: agentskills.io/specification
compatibility: Requires bash. Taskfile (task) needed only for task-runner integration. Designed for Cline, Claude Code, GitHub Copilot, OpenAI Codex, and other compatible agent environments
---
# Repository Script Modules
Work rules for shell automation organised as modules under a repository's `.scripts/`
directory, with a strict public/private split and a fixed sourcing order.
The whole model rests on one idea: **`api/` is what people run, `lib/` is what the code
calls, and a single bootstrap chain guarantees that by the time an implementation function
runs, its environment has been read, validated, and its dependencies sourced.**
## Scope routing
Pick the reference that matches the change; do not load all of them.
| The change touches | Read |
|---|---|
| A reader, validator, implementation function, or `api/` wrapper | `references/module-anatomy.md` |
| The `loggers` or `base` module, or logging that produces no output | `references/shared-modules.md` |
| A module `Taskfile.yml` or the root `Taskfile.yml` | `references/taskfile.md` |
| Creating a module, changing one, or checking work before delivery | `references/workflows.md` |
| Deciding what kind of module something should be | `references/module-patterns.md` |
Copy-ready modules live in `assets/`: `module-example-v1/` is the scaffold for a new module;
`loggers/` and `base/` are working reference implementations.
## 1. Repository model
```text
<target-repository>/
Taskfile.yml # root task runner, includes module Taskfiles
.scripts/
<module>/
api/ # public command wrappers — what users run
lib/ # implementation functions — what the code calls
Taskfile.yml # only when the module is exposed through task
```
Commands always run **from the repository root**, never from inside the module:
```bash
./.scripts/<module>/api/<command>.sh [args]
task <module-alias>:<task-name> -- [args]
```
Every `.` source path in every file is written relative to the repository root
(`. ./.scripts/loggers/lib/--index-api.sh`). This is why running a script from inside its own
directory fails to find its dependencies — that is the convention working as designed, not a
bug to patch with `dirname "$0"`.
## 2. Module anatomy
```text
.scripts/<module>/
api/
<command-name>.sh
lib/
--env-vars-reader.sh # defaults + CLI flag parsing
--env-vars-validator.sh # required-input checks
--index-api.sh # sources dependencies + this module's implementations
--index.sh # full runtime bootstrap
-<command-name>.sh # one implementation function per command
Taskfile.yml # optional
```
| File | Responsibility |
|---|---|
| `api/<command>.sh` | Thin public entrypoint. Sources `lib/--index.sh`, calls one function. |
| `lib/-<command>.sh` | The command implementation function. |
| `lib/--index-api.sh` | Sources upstream module APIs, then this module's implementation files. |
| `lib/--index.sh` | Runtime bootstrap: reader, then validator, then API index. |
| `lib/--env-vars-reader.sh` | Exports defaults and parses CLI arguments into environment variables. |
| `lib/--env-vars-validator.sh` | Validates required variables, failing with an actionable log. |
| `Taskfile.yml` | Maps task names to `api/` scripts, forwarding `{{.CLI_ARGS}}`. |
Not every module has every file — a support-only library like `loggers` has no `api/` and no
`Taskfile.yml`. See `references/module-patterns.md`.
## 3. Standard runtime flow
```text
api/<command>.sh
└── source lib/--index.sh
├── source lib/--env-vars-reader.sh # defaults + CLI flags → env vars
├── source lib/--env-vars-validator.sh # required vars present?
└── source lib/--index-api.sh
├── source dependencies (loggers, base, …)
└── source lib/-<command>.sh # defines the function
└── call _<moduleNamespace>_<commandFunction>
```
**The order is load-bearing.** The reader runs before the validator so the validator has
something to check; both run before the API index so implementation functions see a
fully-prepared environment. Reordering produces failures that look like missing variables.
Arguments reach the reader because sourcing happens with the wrapper's own arguments still in
scope — this is why `api/` wrappers need no argument forwarding of their own.
## 4. Naming conventions
| Kind | Convention | Example |
|---|---|---|
| Module directory | lowercase kebab-case | `module-example-v1`, `repositories-nodejs` |
| Public command | lowercase kebab-case, action-oriented | `initialize-one.sh`, `find-many-by-query.sh` |
| Implementation file | single leading dash | `lib/-initialize-one.sh` |
| Index / lifecycle file | double leading dash | `lib/--index.sh`, `lib/--env-vars-reader.sh` |
| Function | `_<moduleNamespace>_<actionName>` | `_moduleExampleV1_initializeOne` |
| Environment variable | uppercase module prefix | `MODULE_EXAMPLE_V1_OUTPUT_DIR` |
Kebab-case module names convert to camelCase function namespaces:
| Module | Function prefix | Env prefix |
|---|---|---|
| `module-example-v1` | `_moduleExampleV1_` | `MODULE_EXAMPLE_V1_` |
| `repositories-nodejs` | `_repositoriesNodejs_` | `REPOSITORIES_NODEJS_` |
| `operation-utilities` | `_operationUtilities_` | `OPERATION_UTILITIES_` |
The dash count is not decoration — it is how you tell at a glance whether a file defines a
command (`-name.sh`) or wires the module together (`--name.sh`).
## 5. Non-negotiable rules
- **`api/` wrappers stay thin.** Source `lib/--index.sh`, call one function, nothing else. No
implementation, no argument parsing, no validation.
- **CLI flags are parsed only in `--env-vars-reader.sh`.** Never in an implementation file.
- **Every new `lib/-*.sh` gets added to `lib/--index-api.sh`.** Forgetting this is the most
common cause of "command not found" for a function that plainly exists.
- **Readers preserve already-exported values** — `export X="${X:-default}"` — so a caller can
override any setting before invoking the module.
- **Log through `_loggers_*` helpers, never raw `echo`.** Loggers write to `stderr`, keeping
`stdout` clean for real output.
- **Never log secrets.** Redact tokens, API keys, passwords, and kube config.
- **Quote variable expansions** unless word splitting is intended.
- **`return` non-zero from implementation functions; reserve `exit 1` for validators and
bootstrap.** An `exit` inside a sourced library kills the caller's shell.
## 6. Creating a module
Full walkthrough in `references/workflows.md`. The short path:
1. Copy `assets/module-example-v1/` to `.scripts/<new-module>/`.
2. Replace every `module-example-v1` path, the `MODULE_EXAMPLE_V1_` env prefix, and the
`_moduleExampleV1_` function prefix.
3. Add implementation files as `lib/-<command>.sh` and source them from `lib/--index-api.sh`.
4. Add `api/<command>.sh` wrappers for user-facing commands only.
5. Add a module `Taskfile.yml`, and a root include only if the namespace is stable.
6. Validate (section 7).
## 7. Validation
```bash
# Syntax-check every script in the module
find .scripts/<module> -name '*.sh' -print0 | xargs -0 -n1 bash -n
# Confirm task exposure resolves
task --list
# Run the command itself, from the repository root
./.scripts/<module>/api/<command>.sh --dry-run
```
`bash -n` catches syntax errors but **not** a missing entry in `--index-api.sh` — that only
surfaces at call time. Always run the command once, from the repository root, before
delivering. A dry-run flag is worth adding precisely so this check is cheap.
## 8. Mistakes to avoid
- Putting implementation logic into `api/*.sh`.
- Adding a `lib/-*.sh` file and forgetting to source it from `lib/--index-api.sh`.
- Parsing CLI flags in an implementation function instead of the reader.
- Sourcing `base/lib/--index.sh` from a library function — it reads `.env` and
environment-specific files as a side effect. Use `base/lib/--index-api.sh` when you only
need shared functions.
- Writing source paths relative to the script instead of the repository root.
- Using `exit` inside a sourced implementation function.
- Printing secrets, or documenting their values.
- Adding a root `Taskfile.yml` include for an experimental module.
- Assuming logging works because the code compiles — a logger whose level flags were never
exported is silent and returns 0. See `references/shared-modules.md` §3.
@@ -0,0 +1,11 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/base/lib/--index.sh
_base_localStorage_ensureExistance_fileDotEnv
@@ -0,0 +1,11 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/base/lib/--index.sh
_base_localStorage_readLinesFrom_fileDotEnv
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/base/lib/--index.sh
_base_localStorage_reset_fileDotEnv
@@ -0,0 +1,11 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/base/lib/--index.sh
_base_localStorage_saveEnvVariable2_fileDotEnv
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/base/lib/--index.sh
_base_localStorage_view_fileDotEnv
+75
View File
@@ -0,0 +1,75 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--env-vars-reader.sh
TMP_BASE_LIB_ENV_VARS_READER=".scripts/base/lib/--env-vars-reader.sh"
export LOCAL_OS_TYPE="darwin"
export LOCAL_CPU_TYPE="amd64"
export LOCAL_HOME_DIR=$(pwd)
export LOCAL_HOME_DIR_NAME=${PWD##*/}
export LOCAL_GIT_ROOT_DIR=$(dirname "${LOCAL_HOME_DIR}")
export LOCAL_CACHE_DIR_KUBE=".kube"
export LOCAL_FILE_DOT_ENV=".env"
# Pre-load CA_ENVIRONMENT from .env if not already set
if [ -z "${CA_ENVIRONMENT}" ] && [ -f "${LOCAL_FILE_DOT_ENV}" ]; then
export CA_ENVIRONMENT=$(grep '^CA_ENVIRONMENT=' "${LOCAL_FILE_DOT_ENV}" | cut -d'=' -f2- | tr -d '"' | tr -d "'")
fi
export LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT=".env-${CA_ENVIRONMENT}"
. ./.scripts/base/lib/-export-env-variables-from-file-dot-env.sh
_loggers_info "${CA_ENVIRONMENT}" "CA_ENVIRONMENT: ${CA_ENVIRONMENT}"
_loggers_info "${CA_ENVIRONMENT}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}"
_loggers_info "${CA_ENVIRONMENT}" "LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT: ${LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT}"
if
[ ! -e "${LOCAL_FILE_DOT_ENV}" ]
then
_loggers_error "${LOCAL_FILE_DOT_ENV}" "Missing ${LOCAL_FILE_DOT_ENV} file."
exit 1
else
set -o allexport
. "./${LOCAL_FILE_DOT_ENV}"
set +o allexport
fi
if
[ ! -e "${LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT}" ]
then
_loggers_error "${TMP_BASE_LIB_ENV_VARS_READER}" "Missing ${LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT} file."
exit 1
else
set -o allexport
. "./${LOCAL_FILE_DOT_ENV_CA_ENVIRONMENT}"
set +o allexport
fi
mkdir -p "${LOCAL_CACHE_DIR_KUBE}"
ALL_ARGS=("$@")
while [[ "$#" -gt 0 ]]; do
case $1 in
--local-os-type)
export LOCAL_OS_TYPE="$2"
;;
--local-cpu-type)
export LOCAL_CPU_TYPE="$2"
;;
--local-file-dot-env)
export LOCAL_FILE_DOT_ENV="$2"
;;
*) ;;
esac
shift
done
set -- "${ALL_ARGS[@]}"
+15
View File
@@ -0,0 +1,15 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/-ensure-env-var-ibm-user-email.sh
. ./.scripts/base/lib/-ensure-env-var-ibm-user-api-key.sh
_base_ensureEnvVarIbmUserEmail
_base_ensureEnvVarIbmUserApiKey
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/base/lib/-export-env-variable.sh
. ./.scripts/base/lib/-export-env-variables-from-file-dot-env.sh
. ./.scripts/base/lib/-export-env-variables-from-file.sh
. ./.scripts/base/lib/-get-env-variable-key-from-line.sh
. ./.scripts/base/lib/-get-env-variable-value-from-line.sh
. ./.scripts/base/lib/local-storage/--index-api.sh
. ./.scripts/base/lib/-log-env-vars.sh
. ./.scripts/base/lib/-prompt-for-env-var.sh
+24
View File
@@ -0,0 +1,24 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
#
# --> passed parameters are read & exported environment variables
#
. ./.scripts/base/lib/--env-vars-reader.sh
#
# --> required environment variables are validated for existance
#
. ./.scripts/base/lib/--env-vars-validator.sh
#
# --> Importing local shell packages
#
. ./.scripts/loggers/lib/--index-api.sh
#
# --> available functions are imported/exported
#
. ./.scripts/base/lib/--index-api.sh
# -------------------------------------------------------------------------------------
+41
View File
@@ -0,0 +1,41 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
set -e
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/local-storage/--index-api.sh
_base_ensureEnvVarIbmUserApiKey() {
local FUNCTION_NAME="_base_ensureEnvVarIbmUserApiKey"
local TMP_IBM_USER_API_KEY=""
if
[ -z "${IBM_USER_API_KEY}" ]
then
while
true
do
_loggers_emptyLine
read -rep $'Provide for IBM_USER_API_KEY environment variable! \n\n> ' TMP_IBM_USER_API_KEY
if
[ ! -z "${TMP_IBM_USER_API_KEY}" ]
then
export IBM_USER_API_KEY="${TMP_IBM_USER_API_KEY}"
export ENV_VAR_KEY="IBM_USER_API_KEY"
export ENV_VAR_VALUE="${IBM_USER_API_KEY}"
_base_localStorage_saveEnvVariable2_fileDotEnv
break
else
_loggers_emptyLine
_loggers_warn "${FUNCTION_NAME}" "Provided value can not be empty!"
fi
done
fi
_loggers_debug "${FUNCTION_NAME}" "IBM_USER_API_KEY: *REDACTED*"
}
+41
View File
@@ -0,0 +1,41 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
set -e
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/local-storage/--index-api.sh
_base_ensureEnvVarIbmUserEmail() {
local FUNCTION_NAME="_base_ensureEnvVarIbmUserEmail"
local TMP_IBM_USER_EMAIL=""
if
[ -z "${IBM_USER_EMAIL}" ]
then
while
true
do
_loggers_emptyLine
read -rep $'Provide for IBM_USER_EMAIL environment variable! \n\n> ' TMP_IBM_USER_EMAIL
if
[ ! -z "${TMP_IBM_USER_EMAIL}" ]
then
export IBM_USER_EMAIL="${TMP_IBM_USER_EMAIL}"
export ENV_VAR_KEY="IBM_USER_EMAIL"
export ENV_VAR_VALUE="${IBM_USER_EMAIL}"
_base_localStorage_saveEnvVariable2_fileDotEnv
break
else
_loggers_emptyLine
_loggers_warn "${FUNCTION_NAME}" "Provided value can not be empty!"
fi
done
fi
_loggers_debug "${FUNCTION_NAME}" "IBM_USER_EMAIL: ${IBM_USER_EMAIL}"
}
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
_base_ensure_evnVarKey() {
local FUNCTION_NAME="_base_ensure_evnVarKey"
_loggers_debug "${FUNCTION_NAME}"
while
true
do
if
[ ! -z "${ENV_VAR_KEY}" ]
then
break
fi
_loggers_emptyLine
read -rep $'Provide environment variable key! \n> ' TMP_ENV_VAR_KEY
if
[ -z "$TMP_ENV_VAR_KEY" ]
then
_loggers_errorX "${FUNCTION_NAME}" "Provided environment variable key can not be empty!"
else
export ENV_VAR_KEY="$TMP_ENV_VAR_KEY"
fi
_loggers_emptyLine
done
}
+34
View File
@@ -0,0 +1,34 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
_base_ensure_evnVarValue() {
local FUNCTION_NAME="_base_ensure_evnVarValue"
_loggers_debug "${FUNCTION_NAME}"
while
true
do
if
[ ! -z "${ENV_VAR_VALUE}" ]
then
break
fi
_loggers_emptyLine
read -rep $'Provide environment variable value! \n> ' TMP_ENV_VAR_VALUE
if
[ -z "${TMP_ENV_VAR_VALUE}" ]
then
_loggers_errorX "${FUNCTION_NAME}" "Provided environment variable value can not be empty!"
else
export ENV_VAR_VALUE="${TMP_ENV_VAR_VALUE}"
fi
_loggers_emptyLine
done
}
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
_base_exportEnvVariable() {
local FUNCTION_NAME="_base_exportEnvVariable"
local PARAM_ENV_VAR_KEY="${1}"
local PARAM_ENV_VAR_VALUE="${2}"
if
[ true ] &&
[ ! -z "${PARAM_ENV_VAR_KEY}" ] &&
[ ! -z "${PARAM_ENV_VAR_VALUE}" ]
then
_loggers_trace "${FUNCTION_NAME}" "PARAM_ENV_VAR_KEY: ${PARAM_ENV_VAR_KEY}"
_loggers_trace "${FUNCTION_NAME}" "PARAM_ENV_VAR_VALUE: ${PARAM_ENV_VAR_VALUE}"
printf -v "${PARAM_ENV_VAR_KEY}" "${PARAM_ENV_VAR_VALUE}"
export $PARAM_ENV_VAR_KEY
else
_loggers_warn "${FUNCTION_NAME}"
_loggers_warn "${FUNCTION_NAME}" "Missing one of passed parameters!"
_loggers_warn "${FUNCTION_NAME}" ""
_loggers_warn "${FUNCTION_NAME}" "PARAM_ENV_VAR_KEY: ${PARAM_ENV_VAR_KEY}"
_loggers_warn "${FUNCTION_NAME}" "PARAM_ENV_VAR_VALUE: ${PARAM_ENV_VAR_VALUE}"
fi
}
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/-export-env-variables-from-file.sh
_base_exportEnvVarsFrom_fileDotEnv() {
local FUNCTION_NAME="_base_exportEnvVarsFrom_fileDotEnv"
_loggers_debug "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}"
_base_exportEnvVariablesFrom_file "${LOCAL_FILE_DOT_ENV}"
}
+40
View File
@@ -0,0 +1,40 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh
. ./.scripts/base/lib/-export-env-variable.sh
. ./.scripts/base/lib/-get-env-variable-key-from-line.sh
. ./.scripts/base/lib/-get-env-variable-value-from-line.sh
_base_exportEnvVariablesFrom_file() {
local FUNCTION_NAME="_base_exportEnvVariablesFrom_file"
local FILE_RELATIVE_PATH=${1}
_loggers_trace "${FUNCTION_NAME}" "FILE_RELATIVE_PATH: ${FILE_RELATIVE_PATH}"
_base_localStorage_ensureExistance_file "${FILE_RELATIVE_PATH}"
while read TMP_FILE_ENV_LINE; do
if
[ ! -z "${TMP_FILE_ENV_LINE}" ]
then
local TMP_KEY=$(
_base_getEnvVariableKey_fromLine "${TMP_FILE_ENV_LINE}"
)
local TMP_VALUE=$(
_base_getEnvVariableValue_fromLine "${TMP_FILE_ENV_LINE}"
)
_base_exportEnvVariable "${TMP_KEY}" "${TMP_VALUE}"
fi
done <"${FILE_RELATIVE_PATH}"
}
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
_base_getEnvVariableKey_fromLine() {
local FUNCTION_NAME="_base_getEnvVariableKey_fromLine"
local PARAM_LINE="${1}"
_loggers_trace "${FUNCTION_NAME}" "PARAM_LINE: ${PARAM_LINE}"
local RET_VAL=$(
echo "${PARAM_LINE}" | awk -F "=" '{print $1}'
)
_loggers_trace "${FUNCTION_NAME}" "RET_VAL: ${RET_VAL}"
echo "${RET_VAL}"
}
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
_base_getEnvVariableValue_fromLine() {
local FUNCTION_NAME="_base_getEnvVariableValue_fromLine"
local TMP_LINE="${1}"
local RET_VAL=$(
echo $TMP_LINE | awk -F "=" '{print $2}'
)
RET_VAL=$(
echo "${RET_VAL}" | sed 's/^"\(.*\)"$/\1/'
)
_loggers_trace "${FUNCTION_NAME}" "RET_VAL: ${RET_VAL}"
echo "${RET_VAL}"
}
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
_base_logEnvVars() {
local FUNCTION_NAME="_base_logEnvVars"
_loggers_debug "${FUNCTION_NAME}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_OS_TYPE: ${LOCAL_OS_TYPE}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_CPU_TYPE: ${LOCAL_CPU_TYPE}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_HOME_DIR: ${LOCAL_HOME_DIR}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}"
}
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
set -e
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
prompt_for_env_var() {
local var_name="$1"
local function_name="${FUNCNAME[1]:-unknown_function}"
if [ -z "${!var_name}" ]; then
while true; do
_loggers_emptyLine
echo -e "Provide a value for ${var_name} environment variable!\n"
read -rep "> " tmp_value
if [ -n "${tmp_value}" ]; then
export "${var_name}=${tmp_value}"
export ENV_VAR_KEY="${var_name}"
export ENV_VAR_VALUE="${tmp_value}"
_base_localStorage_saveEnvVariable2_fileDotEnv
break
else
_loggers_emptyLine
_loggers_warn "${function_name}" "Provided value cannot be empty!"
fi
done
fi
_loggers_debug "${function_name}" "${var_name}: *REDACTED*"
}
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/base/lib/local-storage/-ensure-existance-file-dot-env.sh
. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh
. ./.scripts/base/lib/local-storage/-read-lines-from-file-dot-env.sh
. ./.scripts/base/lib/local-storage/-read-lines-from-file.sh
. ./.scripts/base/lib/local-storage/-reset-file-dot-env.sh
. ./.scripts/base/lib/local-storage/-reset-file.sh
. ./.scripts/base/lib/local-storage/-save-env-variable-2-file-dot-env.sh
. ./.scripts/base/lib/local-storage/-save-env-variable-2-file.sh
. ./.scripts/base/lib/local-storage/-view-file-dot-env.sh
. ./.scripts/base/lib/local-storage/-view-file.sh
@@ -0,0 +1,22 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh
_base_localStorage_ensureExistance_fileDotEnv() {
local FUNCTION_NAME="_base_localStorage_ensureExistance_fileDotEnv"
_loggers_debug "${FUNCTION_NAME}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV (absolute): ${LOCAL_HOME_DIR}/${LOCAL_FILE_DOT_ENV}"
_base_localStorage_ensureExistance_file "${LOCAL_FILE_DOT_ENV}"
}
+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
_base_localStorage_ensureExistance_file() {
local FUNCTION_NAME="_base_localStorage_ensureExistance_file"
# _loggers_info "${FUNCTION_NAME}"
local FILE_RELATIVE_PATH="${1}"
if
[ -z "${FILE_RELATIVE_PATH}" ]
then
_loggers_error "${FUNCTION_NAME}"
_loggers_error "${FUNCTION_NAME}" "Missing mandatory 1st paramter (FILE_RELATIVE_PATH)!"
_loggers_error "${FUNCTION_NAME}"
exit 1
fi
if
[ ! -e "${FILE_RELATIVE_PATH}" ]
then
touch "${FILE_RELATIVE_PATH}"
_loggers_warn "${FUNCTION_NAME}"
_loggers_warn "${FUNCTION_NAME}" "Was absent -> had to create!"
_loggers_warn "${FUNCTION_NAME}"
fi
}
@@ -0,0 +1,26 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh
_base_localStorage_readLinesFrom_fileDotEnv() {
local FUNCTION_NAME="_base_localStorage_readLinesFrom_fileDotEnv"
_loggers_debug "${FUNCTION_NAME}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV (absolute): ${LOCAL_HOME_DIR}/${LOCAL_FILE_DOT_ENV}"
local RET_VAL=$(
_base_localStorage_readLinesFrom_file "${LOCAL_FILE_DOT_ENV}"
)
_loggers_emptyLine
echo "${RET_VAL[@]}"
}
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh
_base_localStorage_readLinesFrom_file() {
local FUNCTION_NAME="_base_localStorage_readLinesFrom_file"
_loggers_debug "${FUNCTION_NAME}"
local FILE_RELATIVE_PATH="${1}"
_base_localStorage_ensureExistance_file "${FILE_RELATIVE_PATH}"
local RET_VAL=()
while
read -r TMP_FILE_LINE
do
if
[ ! -z "${TMP_FILE_LINE}" ]
then
RET_VAL+=($TMP_FILE_LINE)
fi
done <"${FILE_RELATIVE_PATH}"
echo "${RET_VAL[*]}"
}
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/local-storage/-reset-file.sh
_base_localStorage_reset_fileDotEnv() {
local FUNCTION_NAME="_base_localStorage_reset_fileDotEnv"
_loggers_debug "${FUNCTION_NAME}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV (absolute): ${LOCAL_HOME_DIR}/${LOCAL_FILE_DOT_ENV}"
_base_localStorage_reset_file "${LOCAL_FILE_DOT_ENV}"
}
+29
View File
@@ -0,0 +1,29 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
_base_localStorage_reset_file() {
local FUNCTION_NAME="_base_localStorage_reset_file"
_loggers_debug "${FUNCTION_NAME}"
local FILE_RELATIVE_PATH="${1}"
if
[ -z "${FILE_RELATIVE_PATH}" ]
then
_loggers_error "${FUNCTION_NAME}"
_loggers_error "${FUNCTION_NAME}" "Missing mandatory 1st paramter (FILE_RELATIVE_PATH)!"
_loggers_error "${FUNCTION_NAME}"
exit 1
fi
rm "${FILE_RELATIVE_PATH}"
touch "${FILE_RELATIVE_PATH}"
}
@@ -0,0 +1,22 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/local-storage/-save-env-variable-2-file.sh
_base_localStorage_saveEnvVariable2_fileDotEnv() {
local FUNCTION_NAME="_base_localStorage_saveEnvVariable2_fileDotEnv"
_loggers_debug "${FUNCTION_NAME}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV (absolute): ${LOCAL_HOME_DIR}/${LOCAL_FILE_DOT_ENV}"
_base_localStorage_saveEnvVariable2_file "${LOCAL_FILE_DOT_ENV}"
}
+62
View File
@@ -0,0 +1,62 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/-ensure-env-var-key.sh
. ./.scripts/base/lib/-ensure-env-var-value.sh
. ./.scripts/base/lib/-get-env-variable-key-from-line.sh
. ./.scripts/base/lib/local-storage/-ensure-existance-file.sh
. ./.scripts/base/lib/local-storage/-read-lines-from-file.sh
. ./.scripts/base/lib/local-storage/-reset-file.sh
_base_localStorage_saveEnvVariable2_file() {
local FUNCTION_NAME="_base_localStorage_saveEnvVariable2_file"
_loggers_debug "${FUNCTION_NAME}"
_base_ensure_evnVarKey
_base_ensure_evnVarValue
local FILE_RELATIVE_PATH="${1}"
_base_localStorage_ensureExistance_file "${FILE_RELATIVE_PATH}"
local PARAM_ENV_VAR_KEY="${ENV_VAR_KEY}"
local PARAM_ENV_VAR_VALUE="${ENV_VAR_VALUE}"
_loggers_debug "${FUNCTION_NAME}" "ENV_VAR_KEY: ${ENV_VAR_KEY}"
_loggers_debug "${FUNCTION_NAME}" "ENV_VAR_VALUE: ${ENV_VAR_VALUE}"
local FILE_LINES=$(cat "$FILE_RELATIVE_PATH")
_base_localStorage_reset_file "${FILE_RELATIVE_PATH}"
local TMP_KEY_STATUS=""
echo "$FILE_LINES" | while IFS= read -r FILE_LINE; do
local TMP_ENV_VAR_KEY=$(
_base_getEnvVariableKey_fromLine "${FILE_LINE}"
)
if
[ "${PARAM_ENV_VAR_KEY}" = "${TMP_ENV_VAR_KEY}" ]
then
echo "${PARAM_ENV_VAR_KEY}=\"${PARAM_ENV_VAR_VALUE}\"" >>"${FILE_RELATIVE_PATH}"
TMP_KEY_STATUS="REPLACED"
else
echo "${FILE_LINE}" >>"${FILE_RELATIVE_PATH}"
fi
done
if
[ ! "${TMP_KEY_STATUS}" = "REPLACED" ]
then
echo "${PARAM_ENV_VAR_KEY}=\"${PARAM_ENV_VAR_VALUE}\"" >>"${FILE_RELATIVE_PATH}"
fi
}
+25
View File
@@ -0,0 +1,25 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/local-storage/-ensure-existance-file-dot-env.sh
. ./.scripts/base/lib/local-storage/-view-file.sh
_base_localStorage_view_fileDotEnv() {
local FUNCTION_NAME="_base_localStorage_view_fileDotEnv"
_loggers_debug "${FUNCTION_NAME}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV: ${LOCAL_FILE_DOT_ENV}"
_loggers_info "${FUNCTION_NAME}" "LOCAL_FILE_DOT_ENV (absolute): ${LOCAL_HOME_DIR}/${LOCAL_FILE_DOT_ENV}"
_base_localStorage_ensureExistance_file "${LOCAL_FILE_DOT_ENV}"
_base_localStorage_view_file "${LOCAL_FILE_DOT_ENV}"
}
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/--index-api.sh
_base_localStorage_view_file() {
local FUNCTION_NAME="_base_localStorage_view_file"
_loggers_debug "${FUNCTION_NAME}"
local FILE_RELATIVE_PATH="${1}"
if
[ -z "${FILE_RELATIVE_PATH}" ]
then
_loggers_error "${FUNCTION_NAME}"
_loggers_error "${FUNCTION_NAME}" "Missing mandatory 1st paramter (FILE_RELATIVE_PATH)!"
_loggers_error "${FUNCTION_NAME}"
exit 1
fi
_loggers_emptyLine
cat "${FILE_RELATIVE_PATH}"
_loggers_emptyLine
}
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
#
# --> defaults preserve already-exported values so a caller can override
# any level before sourcing the loggers module
#
export LOGGER_TRAILING_NEW_LINE_ENABLED="${LOGGER_TRAILING_NEW_LINE_ENABLED:-TRUE}"
export LOGGER_IS_ENABLED_ERROR="${LOGGER_IS_ENABLED_ERROR:-true}"
export LOGGER_IS_ENABLED_INFO="${LOGGER_IS_ENABLED_INFO:-true}"
export LOGGER_IS_ENABLED_WARN="${LOGGER_IS_ENABLED_WARN:-true}"
export LOGGER_IS_ENABLED_DEBUG="${LOGGER_IS_ENABLED_DEBUG:-true}"
export LOGGER_IS_ENABLED_TRACE="${LOGGER_IS_ENABLED_TRACE:-false}"
export LOCAL_STRING_005_SPACES=" "
export LOCAL_STRING_010_SPACES="${LOCAL_STRING_005_SPACES}${LOCAL_STRING_005_SPACES}"
export LOCAL_STRING_050_SPACES="${LOCAL_STRING_010_SPACES}${LOCAL_STRING_010_SPACES}${LOCAL_STRING_010_SPACES}${LOCAL_STRING_010_SPACES}${LOCAL_STRING_010_SPACES}"
export LOCAL_STRING_070_SPACES="${LOCAL_STRING_050_SPACES}${LOCAL_STRING_010_SPACES}${LOCAL_STRING_010_SPACES}"
+25
View File
@@ -0,0 +1,25 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
#
# --> logger level flags and padding strings must exist before any logger
# function runs; the reader preserves already-exported values, so this
# is safe to source repeatedly and from any dependent module
#
. ./.scripts/loggers/lib/--env-vars-reader.sh
. ./.scripts/loggers/lib/-enable-trailing-new-line.sh
. ./.scripts/loggers/lib/-info.sh
. ./.scripts/loggers/lib/-trace.sh
. ./.scripts/loggers/lib/-debug.sh
. ./.scripts/loggers/lib/-error.sh
. ./.scripts/loggers/lib/-warn.sh
. ./.scripts/loggers/lib/-empty-line.sh
. ./.scripts/loggers/lib/-waiting-dot.sh
+12
View File
@@ -0,0 +1,12 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
#
# --> available functions are imported/exported
#
. ./.scripts/loggers/lib/--index-api.sh
# -------------------------------------------------------------------------------------
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/-enable-trailing-new-line.sh
_loggers_debug() {
_loggers_enableLoggerTrailingNewLine
if
[ "${LOGGER_IS_ENABLED_DEBUG}" = true ]
then
local TMP_1ST_PARAM="${1}${LOCAL_STRING_070_SPACES}"
TMP_1ST_PARAM="${TMP_1ST_PARAM:0:70}"
local TMP_LINE="# DEBUG # ${TMP_1ST_PARAM} # ${2}"
echo -e "\033[1;36m${TMP_LINE}\033[0m" >&2
fi
}
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/-enable-trailing-new-line.sh
_loggers_emptyLine() {
_loggers_enableLoggerTrailingNewLine
echo -e "" >&2
}
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
_loggers_enableLoggerTrailingNewLine() {
if
[ -z "$LOGGER_TRAILING_NEW_LINE_DISABLED" ]
then
echo "" >&2
export LOGGER_TRAILING_NEW_LINE_DISABLED="TRUE"
fi
}
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/-enable-trailing-new-line.sh
_loggers_error() {
_loggers_enableLoggerTrailingNewLine
if
[ "${LOGGER_IS_ENABLED_ERROR}" = true ]
then
local TMP_1ST_PARAM="${1}${LOCAL_STRING_070_SPACES}"
TMP_1ST_PARAM="${TMP_1ST_PARAM:0:70}"
local TMP_LINE="# ERROR # ${TMP_1ST_PARAM} # $2"
echo -e "\033[1;31m${TMP_LINE}\033[0m" >&2
fi
}
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/-enable-trailing-new-line.sh
_loggers_info() {
_loggers_enableLoggerTrailingNewLine
if
[ "${LOGGER_IS_ENABLED_INFO}" = true ]
then
local TMP_1ST_PARAM="${1}${LOCAL_STRING_070_SPACES}"
TMP_1ST_PARAM="${TMP_1ST_PARAM:0:70}"
local TMP_LINE="# INFO # ${TMP_1ST_PARAM} # ${2}"
echo -e "${TMP_LINE}" >&2
fi
}
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/-enable-trailing-new-line.sh
_loggers_trace() {
_loggers_enableLoggerTrailingNewLine
if
[ "${LOGGER_IS_ENABLED_TRACE}" = true ]
then
local TMP_1ST_PARAM="${1}${LOCAL_STRING_070_SPACES}"
TMP_1ST_PARAM="${TMP_1ST_PARAM:0:70}"
local TMP_LINE="# TRACE # ${TMP_1ST_PARAM} # $2"
echo -e "\033[0;94m${TMP_LINE}\033[0m" >&2
fi
}
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/-enable-trailing-new-line.sh
_loggers_waitingDot() {
echo -n "." >&2
export LOGGER_TRAILING_NEW_LINE_DISABLED=""
}
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
# -------------------------------------------------------------------------------------
# IBM Confidential
# 6949-70F, 6949-80D
# © Copyright IBM Corp. 2018, 2024
# US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
# -------------------------------------------------------------------------------------
. ./.scripts/loggers/lib/-enable-trailing-new-line.sh
_loggers_warn() {
_loggers_enableLoggerTrailingNewLine
if
[ "${LOGGER_IS_ENABLED_WARN}" = true ]
then
local TMP_1ST_PARAM="${1}${LOCAL_STRING_070_SPACES}"
TMP_1ST_PARAM="${TMP_1ST_PARAM:0:70}"
local TMP_LINE="# WARN # ${TMP_1ST_PARAM} # $2"
echo -e "\033[1;33m${TMP_LINE}\033[0m" >&2
fi
}
+13
View File
@@ -0,0 +1,13 @@
# `module-example-v1` Generic Scaffold
This is a generic reference scaffold for a new Cognitive Architect script module.
To adapt it:
1. Copy `module-example-v1/` into `.scripts/<new-module>/`.
2. Replace paths containing `module-example-v1`.
3. Replace environment prefix `MODULE_EXAMPLE_V1_`.
4. Replace function prefix `_moduleExampleV1_`.
5. Add public API wrappers and implementation files as needed.
6. Add a root `Taskfile.yml` include only if the module should be task-runner public.
7. Run `bash -n` against all generated `.sh` files.
+10
View File
@@ -0,0 +1,10 @@
# https://taskfile.dev
version: "3"
tasks:
initialize-one:
cmds:
- |
./.scripts/module-example-v1/api/initialize-one.sh {{.CLI_ARGS}}
silent: true
@@ -0,0 +1,5 @@
#!/bin/bash
. ./.scripts/module-example-v1/lib/--index.sh
_moduleExampleV1_initializeOne
@@ -0,0 +1,25 @@
#!/bin/bash
export MODULE_EXAMPLE_V1_NAME="${MODULE_EXAMPLE_V1_NAME:-default-name}"
export MODULE_EXAMPLE_V1_OUTPUT_DIR="${MODULE_EXAMPLE_V1_OUTPUT_DIR:-.tmp/module-example-v1}"
export MODULE_EXAMPLE_V1_DRY_RUN="${MODULE_EXAMPLE_V1_DRY_RUN:-false}"
ALL_ARGS=("$@")
while [[ "$#" -gt 0 ]]; do
case $1 in
--name)
export MODULE_EXAMPLE_V1_NAME="$2"
shift
;;
--output-dir)
export MODULE_EXAMPLE_V1_OUTPUT_DIR="$2"
shift
;;
--dry-run)
export MODULE_EXAMPLE_V1_DRY_RUN="true"
;;
*) ;;
esac
shift
done
set -- "${ALL_ARGS[@]}"
@@ -0,0 +1,8 @@
#!/bin/bash
. ./.scripts/loggers/lib/--index-api.sh
if [ -z "${MODULE_EXAMPLE_V1_NAME}" ]; then
_loggers_error "module-example-v1" "Missing required --name / MODULE_EXAMPLE_V1_NAME"
exit 1
fi
@@ -0,0 +1,6 @@
#!/bin/bash
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/--index-api.sh
. ./.scripts/module-example-v1/lib/-initialize-one.sh
+15
View File
@@ -0,0 +1,15 @@
#!/bin/bash
#
# --> passed parameters are read & exported environment variables
#
. ./.scripts/module-example-v1/lib/--env-vars-reader.sh
#
# --> required environment variables are validated for existence
#
. ./.scripts/module-example-v1/lib/--env-vars-validator.sh
#
# --> available functions are imported/exported
#
. ./.scripts/module-example-v1/lib/--index-api.sh
# -------------------------------------------------------------------------------------
@@ -0,0 +1,19 @@
#!/bin/bash
. ./.scripts/loggers/lib/--index-api.sh
_moduleExampleV1_initializeOne() {
local FUNCTION_NAME="_moduleExampleV1_initializeOne"
_loggers_info "${FUNCTION_NAME}" "Initializing module-example-v1"
_loggers_debug "${FUNCTION_NAME}" "Name: ${MODULE_EXAMPLE_V1_NAME}"
_loggers_debug "${FUNCTION_NAME}" "Output directory: ${MODULE_EXAMPLE_V1_OUTPUT_DIR}"
if [ "${MODULE_EXAMPLE_V1_DRY_RUN}" = "true" ]; then
_loggers_info "${FUNCTION_NAME}" "Dry run enabled; no files will be changed."
return 0
fi
mkdir -p "${MODULE_EXAMPLE_V1_OUTPUT_DIR}"
_loggers_info "${FUNCTION_NAME}" "Initialization complete."
}
+203
View File
@@ -0,0 +1,203 @@
# Module Anatomy
The four file types inside `lib/`, the `api/` wrapper, and the patterns each follows.
Read this when writing or changing a reader, a validator, an implementation function, or a
public wrapper.
---
## 1. `--env-vars-reader.sh` — defaults and CLI parsing
Responsibilities, in order:
1. export defaults, preserving any value already exported by the caller;
2. parse CLI flags into environment variables;
3. restore the positional arguments so later consumers still see them.
```bash
#!/bin/bash
export MODULE_EXAMPLE_V1_NAME="${MODULE_EXAMPLE_V1_NAME:-default-name}"
export MODULE_EXAMPLE_V1_OUTPUT_DIR="${MODULE_EXAMPLE_V1_OUTPUT_DIR:-.tmp/module-example-v1}"
export MODULE_EXAMPLE_V1_DRY_RUN="${MODULE_EXAMPLE_V1_DRY_RUN:-false}"
ALL_ARGS=("$@")
while [[ "$#" -gt 0 ]]; do
case $1 in
--name)
export MODULE_EXAMPLE_V1_NAME="$2"
shift
;;
--output-dir)
export MODULE_EXAMPLE_V1_OUTPUT_DIR="$2"
shift
;;
--dry-run)
export MODULE_EXAMPLE_V1_DRY_RUN="true"
;;
*) ;;
esac
shift
done
set -- "${ALL_ARGS[@]}"
```
Rules:
- Use a stable uppercase environment prefix per module.
- **Always use `${VAR:-default}`**, never a bare `export VAR=value`. A bare assignment
silently discards a caller's override, and the caller has no way to detect it. This is what
makes a reader safe to source more than once.
- Prefer explicit CLI flags over positional arguments.
- Defaults must be safe to run locally — a default that writes outside `.tmp/` or touches a
shared system is not a safe default.
- Never print secrets here.
The `ALL_ARGS` save/restore matters because `shift` consumes the arguments. Without the
`set --` at the end, anything sourced after the reader sees an empty argument list.
---
## 2. `--env-vars-validator.sh` — required inputs
```bash
#!/bin/bash
. ./.scripts/loggers/lib/--index-api.sh
if [ -z "${MODULE_EXAMPLE_V1_NAME}" ]; then
_loggers_error "module-example-v1" "Missing required --name / MODULE_EXAMPLE_V1_NAME"
exit 1
fi
```
Rules:
- Runs from `--index.sh`, after the reader and before the API index, so failures happen before
any implementation function is even defined.
- Use `_loggers_error` for the failure and `_loggers_info` for a usage hint.
- `exit 1` is correct **here** — the validator runs during bootstrap of a top-level command,
and stopping is the intent.
- Validate only what every command in the module needs. A variable that only one command
requires is validated inside that command's function, not globally — otherwise unrelated
commands fail on input they never use.
---
## 3. `--index-api.sh` — dependency and implementation wiring
```bash
#!/bin/bash
. ./.scripts/loggers/lib/--index-api.sh
. ./.scripts/base/lib/--index-api.sh
. ./.scripts/module-example-v1/lib/-initialize-one.sh
```
Rules:
- Upstream dependencies first, then this module's own implementation files.
- Source other modules' `--index-api.sh`, **not** their `--index.sh` — see
`references/shared-modules.md` §2.
- **Every implementation file must appear here.** A `lib/-*.sh` that is never sourced defines
nothing, and the failure surfaces as `command not found` for a function you can see on disk.
- Safe to source repeatedly. Sourcing defines functions; it should have no other side effect.
---
## 4. `--index.sh` — runtime bootstrap
```bash
#!/bin/bash
# --> passed parameters are read & exported environment variables
. ./.scripts/module-example-v1/lib/--env-vars-reader.sh
# --> required environment variables are validated for existence
. ./.scripts/module-example-v1/lib/--env-vars-validator.sh
# --> available functions are imported/exported
. ./.scripts/module-example-v1/lib/--index-api.sh
```
Rules:
- Exactly these three sources, in exactly this order.
- This is the module's **own** entrypoint, sourced by its `api/` wrappers. Other modules never
source it — they take `--index-api.sh`.
- A module with no required inputs may omit the validator, but keeping an empty one makes the
next required variable a one-line change.
---
## 5. Implementation functions — `lib/-<command>.sh`
```bash
#!/bin/bash
. ./.scripts/loggers/lib/--index-api.sh
_moduleExampleV1_initializeOne() {
local FUNCTION_NAME="_moduleExampleV1_initializeOne"
_loggers_info "${FUNCTION_NAME}" "Initializing module-example-v1"
_loggers_debug "${FUNCTION_NAME}" "Output directory: ${MODULE_EXAMPLE_V1_OUTPUT_DIR}"
if [ "${MODULE_EXAMPLE_V1_DRY_RUN}" = "true" ]; then
_loggers_info "${FUNCTION_NAME}" "Dry run enabled; no files will be changed."
return 0
fi
mkdir -p "${MODULE_EXAMPLE_V1_OUTPUT_DIR}"
_loggers_info "${FUNCTION_NAME}" "Initialization complete."
}
```
Rules:
- Open with `local FUNCTION_NAME="_<module>_<function>"` — every logger call takes it as the
first argument, which is what makes log output traceable to a specific function.
- One file, one primary function. Small private helpers may live alongside it.
- Use `_loggers_*` helpers, never raw `echo`, for status and errors.
- **`return` non-zero on failure; never `exit`.** The file is sourced, so `exit` terminates
the caller's shell — including an interactive one.
- Read configuration from the module's environment variables. Never re-parse `$@` here.
- Quote every expansion unless word splitting is deliberate.
- Never expose secret values in a log line.
---
## 6. `api/` wrappers
```bash
#!/bin/bash
. ./.scripts/module-example-v1/lib/--index.sh
_moduleExampleV1_initializeOne
```
That is the whole file. Rules:
- Source exactly `lib/--index.sh`, then call exactly one function.
- No implementation, no flag parsing, no validation, no argument forwarding.
- Arguments reach the reader automatically: sourcing happens while the wrapper's own `$@` is
still in scope, so `--env-vars-reader.sh` sees them without being passed anything.
- Create a wrapper only for a genuinely user-facing command. An internal helper stays in
`lib/` — every file in `api/` is a public interface someone may come to depend on.
---
## 7. Diagnosing a broken module
| Symptom | Cause |
|---|---|
| `command not found` for a function that exists on disk | Its file is missing from `lib/--index-api.sh` |
| No log output at all, exit code 0 | Logger level flags never exported — see `references/shared-modules.md` §3 |
| A flag is ignored | Not handled in `--env-vars-reader.sh`, or handled after the `set --` restore |
| Later sources see no arguments | Reader is missing the `ALL_ARGS` save/`set --` restore |
| `No such file or directory` for a `lib/` path | Run from inside the module instead of the repository root |
| `.env` loaded unexpectedly | Something sourced `base/lib/--index.sh` instead of `base/lib/--index-api.sh` |
| The shell exits on a handled error | `exit` used inside a sourced implementation function |
+66
View File
@@ -0,0 +1,66 @@
# Module Patterns
A decision guide for what kind of module you are building and how it should connect to the
others.
---
## 1. Module type
| Module type | Has `api/` | Has `Taskfile.yml` | Example |
|---|:---:|:---:|---|
| Support-only library | No | No | `loggers` |
| Shared foundation with public commands | Yes | Optional / no | `base` |
| Feature module | Yes | Usually yes | `kube`, `github`, `data-migration` |
| Wrapper around an external CLI | Yes | Usually yes | `helm`, `openshift`, `github` |
Pick the type before creating any file — it decides whether `api/` and `Taskfile.yml` exist at
all, and adding them later means reworking every consumer that has already started sourcing
the module.
A module with no user-facing command is a support library. Do not give it an `api/` directory
speculatively; every file in `api/` is a public interface someone may come to depend on.
---
## 2. Dependency sourcing
| You need | Source |
|---|---|
| Logging | `./.scripts/loggers/lib/--index-api.sh` |
| Shared base functions | `./.scripts/base/lib/--index-api.sh` |
| Another module's exported functions | that module's `lib/--index-api.sh` |
| Your own module's full runtime, from its `api/` wrapper | your `lib/--index.sh` |
The rule underneath: **`--index-api.sh` is the public edge between modules; `--index.sh` is a
module's own private entrypoint.** Sourcing another module's `--index.sh` runs its reader and
validator inside your command — importing its defaults, its required-input checks, and in
`base`'s case its `.env` loading. Symptoms show up as variables nobody set, or a validation
failure naming a module the user never invoked.
---
## 3. Command exposure
Three independent decisions, in increasing order of commitment:
1. **`lib/` only** — internal. Reachable from other modules that source your `--index-api.sh`.
2. **`api/<command>.sh`** — user-facing. Someone can run it directly from the repository root.
3. **Module `Taskfile.yml`** — discoverable through `task --list-all`.
4. **Root `Taskfile.yml` include** — a stable public namespace, effectively permanent.
Escalate only as far as the command genuinely needs. Each step is easy to add later and
disruptive to withdraw, because each one is a promise someone may already be relying on.
---
## 4. Common mistakes
- Putting full implementation logic into `api/*.sh`.
- Adding a `lib/-*.sh` file and forgetting to source it from `lib/--index-api.sh`.
- Parsing CLI flags in implementation files instead of `--env-vars-reader.sh`.
- Printing secrets in logs.
- Sourcing `base/lib/--index.sh` from a library function and unexpectedly loading `.env`.
- Adding root Taskfile includes for experimental modules.
- Giving a support-only library an `api/` directory it does not need.
- Mixing function prefixes inside one module after a rename.
+165
View File
@@ -0,0 +1,165 @@
# Shared Modules — `loggers` and `base`
The two foundation modules every other module depends on, and the bootstrap rule that decides
whether logging works at all.
Working implementations are in `assets/loggers/` and `assets/base/`.
---
## 1. `loggers` — support-only library
No `api/` commands, no `Taskfile.yml`. It exists to be sourced.
```text
.scripts/loggers/
lib/
--env-vars-reader.sh # level flags + padding strings
--index-api.sh # sources the reader, then every logger function
--index.sh
-debug.sh -error.sh -info.sh -trace.sh -warn.sh
-empty-line.sh -enable-trailing-new-line.sh -waiting-dot.sh
```
Consume it from any module:
```bash
. ./.scripts/loggers/lib/--index-api.sh
```
Available functions:
```bash
_loggers_info "${FUNCTION_NAME}" "message"
_loggers_debug "${FUNCTION_NAME}" "message"
_loggers_warn "${FUNCTION_NAME}" "message"
_loggers_error "${FUNCTION_NAME}" "message"
_loggers_trace "${FUNCTION_NAME}" "message"
_loggers_emptyLine
```
Levels are controlled by environment flags, defaulting to everything except trace:
```bash
LOGGER_IS_ENABLED_ERROR=true
LOGGER_IS_ENABLED_INFO=true
LOGGER_IS_ENABLED_WARN=true
LOGGER_IS_ENABLED_DEBUG=true
LOGGER_IS_ENABLED_TRACE=false
```
Export any of them before invoking a command to change verbosity for that run:
```bash
LOGGER_IS_ENABLED_DEBUG=false ./.scripts/<module>/api/<command>.sh
```
Rules:
1. Do not add `api/` wrappers to `loggers` without a real user-facing requirement.
2. Keep logger helpers small and side-effect-light.
3. Log to `stderr` — `stdout` stays clean so command output remains pipeable.
4. Dependent modules source the logger API directly.
---
## 2. `base` — shared foundation
Has public `api/` wrappers but no `Taskfile.yml`. Provides local environment handling and
local-storage helpers over `.env` files.
```text
.scripts/base/
api/
local-storage-ensure-existance-file-dot-env.sh
local-storage-read-lines-from-file-dot-env.sh
local-storage-reset-file-dot-env.sh
local-storage-save-env-variable-2-file-dot-env.sh
local-storage-view-file-dot-env.sh
lib/
--env-vars-reader.sh --env-vars-validator.sh
--index-api.sh --index.sh
-export-env-variable.sh
-export-env-variables-from-file-dot-env.sh
-export-env-variables-from-file.sh
-get-env-variable-key-from-line.sh
-get-env-variable-value-from-line.sh
-log-env-vars.sh
-prompt-for-env-var.sh
local-storage/
--index-api.sh
-ensure-existance-file.sh -ensure-existance-file-dot-env.sh
-read-lines-from-file.sh -read-lines-from-file-dot-env.sh
-reset-file.sh -reset-file-dot-env.sh
-save-env-variable-2-file.sh -save-env-variable-2-file-dot-env.sh
-view-file.sh -view-file-dot-env.sh
```
### Which entrypoint to source — this matters
```bash
# From another module, when you only need base's shared functions:
. ./.scripts/base/lib/--index-api.sh
# Only from base's own api/ wrappers:
. ./.scripts/base/lib/--index.sh
```
`base/lib/--index.sh` runs base's reader and validator, and **reads `.env` and
environment-specific files as a side effect**. Sourcing it from a library function pulls that
whole environment into an unrelated command — values appear that nobody set, and the failure
is hard to trace because nothing in the calling module mentions `.env`.
`--index-api.sh` defines functions and nothing else, which is why it is the correct dependency
edge between modules.
Rules:
1. Prefer `base/lib/--index-api.sh` from other modules.
2. Nested lib packages such as `lib/local-storage/` carry their own `--index-api.sh` and are
sourced from the parent's.
3. Never log secret values — redact tokens, API keys, passwords, kube config, credentials.
---
## 3. The logging bootstrap rule
**A logger function whose level flag is unset prints nothing and returns 0.**
Every `_loggers_*` function is guarded by its level flag:
```bash
if [ "${LOGGER_IS_ENABLED_INFO}" = true ]; then ... fi
```
An unset flag is not `true`, so the call is a silent no-op with a success exit code. Nothing
fails, nothing warns — the command simply produces no output, which reads like a bug in the
command rather than in its bootstrap.
Those flags are exported by `loggers/lib/--env-vars-reader.sh`. For logging to work, that
reader must have run before any logger call.
In the shipped `assets/loggers/`, `--index-api.sh` sources the reader itself, so any module
that sources the logger API gets working logging with no extra step. The reader uses
`${VAR:-default}` throughout, so it is safe to source repeatedly and a caller's override
still wins.
**If you are adapting an existing `loggers` module rather than using the shipped one, check
this first.** A `--index-api.sh` that sources only the logger function files, without the
reader, silences every module that depends on it — while `bash -n` passes and every command
exits 0.
Quick check in any repository:
```bash
grep -n 'env-vars-reader' .scripts/loggers/lib/--index-api.sh \
|| echo "WARNING: loggers API does not bootstrap its level flags — logging may be silent"
```
Direct test:
```bash
bash -c '. ./.scripts/loggers/lib/--index-api.sh; _loggers_info "check" "visible?"'
```
No output means the flags were never exported.
+76
View File
@@ -0,0 +1,76 @@
# Taskfile Integration
Exposing module commands through the `task` runner.
Add a module `Taskfile.yml` only when its commands should be discoverable through `task`. A
module that is only consumed by other modules does not need one.
---
## 1. Module `Taskfile.yml`
```yaml
# https://taskfile.dev
version: "3"
tasks:
initialize-one:
cmds:
- |
./.scripts/module-example-v1/api/initialize-one.sh {{.CLI_ARGS}}
silent: true
```
Rules:
1. Task names mirror the public `api/` command names, unless an alias is deliberate. A task
named differently from the script it runs makes `task --list` output impossible to map back
to files.
2. Forward `{{.CLI_ARGS}}` whenever the command accepts flags.
3. `silent: true` suppresses task's own command echo, so only the script's logger output
appears.
4. Invoke the `api/` wrapper — never a `lib/` file directly.
5. The path is repository-root-relative, matching how the scripts source their dependencies.
Arguments pass through after `--`:
```bash
task module-example-v1:initialize-one -- --name demo --dry-run
```
Without the `--`, task treats the flags as its own and the script never sees them.
---
## 2. Root `Taskfile.yml` include
```yaml
includes:
module-example-v1: ./.scripts/module-example-v1/Taskfile.yml
```
Rules:
1. Add a root include only for a module intended as a **stable public task namespace**. The
include name becomes a permanent user-facing prefix; renaming it later breaks every
documented command and every CI invocation.
2. Choose a short, clear namespace. Existing examples include `ca`, `kube`, `npmrc`,
`repos-local`, and `repos-local-nodejs`.
3. Do not add includes for experimental or in-progress modules — run them through their `api/`
path until the interface settles.
---
## 3. Verifying
```bash
# Every included namespace and task, with descriptions
task --list-all
# Confirm a specific task resolves and forwards arguments
task <module-alias>:<task-name> -- --dry-run
```
`task --list` shows only tasks carrying a `desc:`; `task --list-all` shows everything. A task
missing from `--list-all` means the root include is absent or its path is wrong.
+118
View File
@@ -0,0 +1,118 @@
# Workflows
Creating a module, changing an existing one, and the checks to run before delivering either.
---
## 1. Creating a new module
1. **Confirm the module name and namespace** — the kebab-case directory name, the
`_camelCase_` function prefix, and the `UPPER_SNAKE_` environment prefix all derive from it
and must agree.
2. **Inspect nearby modules** for a comparable pattern before designing a new one. Matching an
existing module beats inventing a variant.
3. **Copy the scaffold:**
```bash
cp -R assets/module-example-v1 .scripts/<new-module>
```
4. **Rename throughout** — every `module-example-v1` path, `MODULE_EXAMPLE_V1_`, and
`_moduleExampleV1_`:
```bash
cd .scripts/<new-module>
grep -rl 'module-example-v1\|MODULE_EXAMPLE_V1_\|_moduleExampleV1_' . | while read -r f; do
sed -i '' \
-e 's|module-example-v1|<new-module>|g' \
-e 's|MODULE_EXAMPLE_V1_|<NEW_MODULE>_|g' \
-e 's|_moduleExampleV1_|_<newModule>_|g' "$f"
done
grep -rn 'module-example-v1\|MODULE_EXAMPLE_V1_\|_moduleExampleV1_' . || echo "rename complete"
```
(`sed -i ''` is BSD/macOS; use `sed -i` on GNU.)
5. **Set the defaults and flags** in `lib/--env-vars-reader.sh`, using `${VAR:-default}`.
6. **Set the required-input checks** in `lib/--env-vars-validator.sh`.
7. **Write implementation files** as `lib/-<command>.sh`, one function each.
8. **Source every implementation file** from `lib/--index-api.sh`.
9. **Add `api/<command>.sh` wrappers** for user-facing commands only.
10. **Add a module `Taskfile.yml`**, and a root include only if the namespace is stable —
`references/taskfile.md`.
11. **Make scripts executable** where they will be invoked directly:
`chmod +x .scripts/<new-module>/api/*.sh`.
12. **Validate** — section 3.
13. **Update the repository's script documentation** if it has a memory bank or equivalent.
---
## 2. Changing an existing module
1. **Read `lib/--index.sh` and `lib/--index-api.sh` first.** They show what the module loads
and in what order, which determines where a change can safely go.
2. **Decide which layer the change belongs to:**
| The change is | It belongs in |
|---|---|
| A new user-facing command | `api/` + `lib/-<command>.sh` + `--index-api.sh` |
| New behaviour in an existing command | that command's `lib/-<command>.sh` |
| A new CLI flag or default | `--env-vars-reader.sh` |
| A new required input | `--env-vars-validator.sh` |
| Task-runner exposure | module `Taskfile.yml`, and the root include if public |
3. **Preserve the existing naming and function prefixes.** Consistency inside a module beats
matching a newer convention used elsewhere — mixed prefixes in one module are worse than an
old prefix used uniformly.
4. **Add every new `lib/-*.sh` to `--index-api.sh`** as you create it, not afterwards.
5. **Add `api/` wrappers only for user-facing commands**; internal helpers stay in `lib/`.
6. **Validate** — section 3.
7. **Update the script documentation** when public behaviour changes.
---
## 3. Validation checklist
- [ ] Public commands are under `api/`; reusable implementation is under `lib/`.
- [ ] `api/` wrappers are thin — source `lib/--index.sh`, call one function.
- [ ] `lib/--index.sh` sources reader, validator, API index, in that order.
- [ ] `lib/--index-api.sh` sources every implementation file the wrappers need.
- [ ] New CLI flags are parsed in `--env-vars-reader.sh`, using `${VAR:-default}`.
- [ ] Required variables are validated before use.
- [ ] Logs use `_loggers_*` helpers, and logging actually produces output.
- [ ] No secret values are printed or documented.
- [ ] Implementation functions `return` rather than `exit`.
- [ ] Taskfile entries invoke `./.scripts/<module>/api/<command>.sh {{.CLI_ARGS}}`.
- [ ] A root `Taskfile.yml` include was added only if intended.
- [ ] `bash -n` passes for every changed script.
- [ ] The command was actually run once from the repository root.
- [ ] Script documentation is updated when public behaviour changed.
---
## 4. Validation commands
```bash
# Syntax check every script in the module
find .scripts/<module> -name '*.sh' -print0 | xargs -0 -n1 bash -n
# Every implementation file is wired into the API index.
# Note the `--` before the pattern: implementation basenames start with a dash,
# which grep would otherwise parse as an option flag and report every file.
cd .scripts/<module>
for f in lib/-*.sh; do
case "$f" in lib/--*) continue;; esac
grep -qF -- "$(basename "$f")" lib/--index-api.sh || echo "NOT INDEXED: $f"
done
# Task exposure resolves
task --list-all
# Run it — the only check that proves the wiring works
./.scripts/<module>/api/<command>.sh --dry-run
```
`bash -n` proves a file parses. It does **not** prove a function is reachable, that a flag is
handled, or that logging is bootstrapped — all three fail silently at runtime while every
static check passes. The final run is the one that matters; a `--dry-run` flag exists to make
it cheap and safe.